Fix copy, fix styles on server

This commit is contained in:
Christian Cueni 2019-11-07 10:12:43 +01:00
parent 26734df6ef
commit e2f5c0b3f0
20 changed files with 165 additions and 82 deletions

2
.gitignore vendored
View File

@ -43,5 +43,3 @@ server/media/
.coverage .coverage
# Cypress screenshots
client/cypress/screenshots

4
client/.gitignore vendored
View File

@ -13,3 +13,7 @@ cypress/videos
*.ntvs* *.ntvs*
*.njsproj *.njsproj
*.sln *.sln
# Cypress
cypress/screenshots
cypress/videos

View File

@ -8985,8 +8985,7 @@
}, },
"ansi-regex": { "ansi-regex": {
"version": "2.1.1", "version": "2.1.1",
"bundled": true, "bundled": true
"optional": true
}, },
"aproba": { "aproba": {
"version": "1.2.0", "version": "1.2.0",
@ -9004,13 +9003,11 @@
}, },
"balanced-match": { "balanced-match": {
"version": "1.0.0", "version": "1.0.0",
"bundled": true, "bundled": true
"optional": true
}, },
"brace-expansion": { "brace-expansion": {
"version": "1.1.11", "version": "1.1.11",
"bundled": true, "bundled": true,
"optional": true,
"requires": { "requires": {
"balanced-match": "^1.0.0", "balanced-match": "^1.0.0",
"concat-map": "0.0.1" "concat-map": "0.0.1"
@ -9023,18 +9020,15 @@
}, },
"code-point-at": { "code-point-at": {
"version": "1.1.0", "version": "1.1.0",
"bundled": true, "bundled": true
"optional": true
}, },
"concat-map": { "concat-map": {
"version": "0.0.1", "version": "0.0.1",
"bundled": true, "bundled": true
"optional": true
}, },
"console-control-strings": { "console-control-strings": {
"version": "1.1.0", "version": "1.1.0",
"bundled": true, "bundled": true
"optional": true
}, },
"core-util-is": { "core-util-is": {
"version": "1.0.2", "version": "1.0.2",
@ -9137,8 +9131,7 @@
}, },
"inherits": { "inherits": {
"version": "2.0.3", "version": "2.0.3",
"bundled": true, "bundled": true
"optional": true
}, },
"ini": { "ini": {
"version": "1.3.5", "version": "1.3.5",
@ -9148,7 +9141,6 @@
"is-fullwidth-code-point": { "is-fullwidth-code-point": {
"version": "1.0.0", "version": "1.0.0",
"bundled": true, "bundled": true,
"optional": true,
"requires": { "requires": {
"number-is-nan": "^1.0.0" "number-is-nan": "^1.0.0"
} }
@ -9161,20 +9153,17 @@
"minimatch": { "minimatch": {
"version": "3.0.4", "version": "3.0.4",
"bundled": true, "bundled": true,
"optional": true,
"requires": { "requires": {
"brace-expansion": "^1.1.7" "brace-expansion": "^1.1.7"
} }
}, },
"minimist": { "minimist": {
"version": "0.0.8", "version": "0.0.8",
"bundled": true, "bundled": true
"optional": true
}, },
"minipass": { "minipass": {
"version": "2.2.4", "version": "2.2.4",
"bundled": true, "bundled": true,
"optional": true,
"requires": { "requires": {
"safe-buffer": "^5.1.1", "safe-buffer": "^5.1.1",
"yallist": "^3.0.0" "yallist": "^3.0.0"
@ -9191,7 +9180,6 @@
"mkdirp": { "mkdirp": {
"version": "0.5.1", "version": "0.5.1",
"bundled": true, "bundled": true,
"optional": true,
"requires": { "requires": {
"minimist": "0.0.8" "minimist": "0.0.8"
} }
@ -9264,8 +9252,7 @@
}, },
"number-is-nan": { "number-is-nan": {
"version": "1.0.1", "version": "1.0.1",
"bundled": true, "bundled": true
"optional": true
}, },
"object-assign": { "object-assign": {
"version": "4.1.1", "version": "4.1.1",
@ -9275,7 +9262,6 @@
"once": { "once": {
"version": "1.4.0", "version": "1.4.0",
"bundled": true, "bundled": true,
"optional": true,
"requires": { "requires": {
"wrappy": "1" "wrappy": "1"
} }
@ -9351,8 +9337,7 @@
}, },
"safe-buffer": { "safe-buffer": {
"version": "5.1.1", "version": "5.1.1",
"bundled": true, "bundled": true
"optional": true
}, },
"safer-buffer": { "safer-buffer": {
"version": "2.1.2", "version": "2.1.2",
@ -9382,7 +9367,6 @@
"string-width": { "string-width": {
"version": "1.0.2", "version": "1.0.2",
"bundled": true, "bundled": true,
"optional": true,
"requires": { "requires": {
"code-point-at": "^1.0.0", "code-point-at": "^1.0.0",
"is-fullwidth-code-point": "^1.0.0", "is-fullwidth-code-point": "^1.0.0",
@ -9400,7 +9384,6 @@
"strip-ansi": { "strip-ansi": {
"version": "3.0.1", "version": "3.0.1",
"bundled": true, "bundled": true,
"optional": true,
"requires": { "requires": {
"ansi-regex": "^2.0.0" "ansi-regex": "^2.0.0"
} }
@ -9439,13 +9422,11 @@
}, },
"wrappy": { "wrappy": {
"version": "1.0.2", "version": "1.0.2",
"bundled": true, "bundled": true
"optional": true
}, },
"yallist": { "yallist": {
"version": "3.0.2", "version": "3.0.2",
"bundled": true, "bundled": true
"optional": true
} }
} }
}, },
@ -11428,8 +11409,7 @@
"ansi-regex": { "ansi-regex": {
"version": "2.1.1", "version": "2.1.1",
"bundled": true, "bundled": true,
"dev": true, "dev": true
"optional": true
}, },
"aproba": { "aproba": {
"version": "1.2.0", "version": "1.2.0",
@ -11450,14 +11430,12 @@
"balanced-match": { "balanced-match": {
"version": "1.0.0", "version": "1.0.0",
"bundled": true, "bundled": true,
"dev": true, "dev": true
"optional": true
}, },
"brace-expansion": { "brace-expansion": {
"version": "1.1.11", "version": "1.1.11",
"bundled": true, "bundled": true,
"dev": true, "dev": true,
"optional": true,
"requires": { "requires": {
"balanced-match": "^1.0.0", "balanced-match": "^1.0.0",
"concat-map": "0.0.1" "concat-map": "0.0.1"
@ -11472,20 +11450,17 @@
"code-point-at": { "code-point-at": {
"version": "1.1.0", "version": "1.1.0",
"bundled": true, "bundled": true,
"dev": true, "dev": true
"optional": true
}, },
"concat-map": { "concat-map": {
"version": "0.0.1", "version": "0.0.1",
"bundled": true, "bundled": true,
"dev": true, "dev": true
"optional": true
}, },
"console-control-strings": { "console-control-strings": {
"version": "1.1.0", "version": "1.1.0",
"bundled": true, "bundled": true,
"dev": true, "dev": true
"optional": true
}, },
"core-util-is": { "core-util-is": {
"version": "1.0.2", "version": "1.0.2",
@ -11602,8 +11577,7 @@
"inherits": { "inherits": {
"version": "2.0.3", "version": "2.0.3",
"bundled": true, "bundled": true,
"dev": true, "dev": true
"optional": true
}, },
"ini": { "ini": {
"version": "1.3.5", "version": "1.3.5",
@ -11615,7 +11589,6 @@
"version": "1.0.0", "version": "1.0.0",
"bundled": true, "bundled": true,
"dev": true, "dev": true,
"optional": true,
"requires": { "requires": {
"number-is-nan": "^1.0.0" "number-is-nan": "^1.0.0"
} }
@ -11630,7 +11603,6 @@
"version": "3.0.4", "version": "3.0.4",
"bundled": true, "bundled": true,
"dev": true, "dev": true,
"optional": true,
"requires": { "requires": {
"brace-expansion": "^1.1.7" "brace-expansion": "^1.1.7"
} }
@ -11638,14 +11610,12 @@
"minimist": { "minimist": {
"version": "0.0.8", "version": "0.0.8",
"bundled": true, "bundled": true,
"dev": true, "dev": true
"optional": true
}, },
"minipass": { "minipass": {
"version": "2.3.5", "version": "2.3.5",
"bundled": true, "bundled": true,
"dev": true, "dev": true,
"optional": true,
"requires": { "requires": {
"safe-buffer": "^5.1.2", "safe-buffer": "^5.1.2",
"yallist": "^3.0.0" "yallist": "^3.0.0"
@ -11664,7 +11634,6 @@
"version": "0.5.1", "version": "0.5.1",
"bundled": true, "bundled": true,
"dev": true, "dev": true,
"optional": true,
"requires": { "requires": {
"minimist": "0.0.8" "minimist": "0.0.8"
} }
@ -11745,8 +11714,7 @@
"number-is-nan": { "number-is-nan": {
"version": "1.0.1", "version": "1.0.1",
"bundled": true, "bundled": true,
"dev": true, "dev": true
"optional": true
}, },
"object-assign": { "object-assign": {
"version": "4.1.1", "version": "4.1.1",
@ -11758,7 +11726,6 @@
"version": "1.4.0", "version": "1.4.0",
"bundled": true, "bundled": true,
"dev": true, "dev": true,
"optional": true,
"requires": { "requires": {
"wrappy": "1" "wrappy": "1"
} }
@ -11844,8 +11811,7 @@
"safe-buffer": { "safe-buffer": {
"version": "5.1.2", "version": "5.1.2",
"bundled": true, "bundled": true,
"dev": true, "dev": true
"optional": true
}, },
"safer-buffer": { "safer-buffer": {
"version": "2.1.2", "version": "2.1.2",
@ -11881,7 +11847,6 @@
"version": "1.0.2", "version": "1.0.2",
"bundled": true, "bundled": true,
"dev": true, "dev": true,
"optional": true,
"requires": { "requires": {
"code-point-at": "^1.0.0", "code-point-at": "^1.0.0",
"is-fullwidth-code-point": "^1.0.0", "is-fullwidth-code-point": "^1.0.0",
@ -11901,7 +11866,6 @@
"version": "3.0.1", "version": "3.0.1",
"bundled": true, "bundled": true,
"dev": true, "dev": true,
"optional": true,
"requires": { "requires": {
"ansi-regex": "^2.0.0" "ansi-regex": "^2.0.0"
} }
@ -11945,14 +11909,12 @@
"wrappy": { "wrappy": {
"version": "1.0.2", "version": "1.0.2",
"bundled": true, "bundled": true,
"dev": true, "dev": true
"optional": true
}, },
"yallist": { "yallist": {
"version": "3.0.3", "version": "3.0.3",
"bundled": true, "bundled": true,
"dev": true, "dev": true
"optional": true
} }
} }
}, },

View File

@ -149,7 +149,7 @@ export default {
) { ) {
try { try {
if (success) { if (success) {
window.location.href = '/set-password/done/'; window.location.href = '/registration/set-password/done/';
} else { } else {
errors.forEach(function(error) { errors.forEach(function(error) {
switch (error.field) { switch (error.field) {

View File

@ -1,6 +1,6 @@
<template> <template>
<div class="no-class public-page"> <div class="no-class public-page">
<h1 class="public-page__title">Sie sind keiner Klasse zugeteilt.</h1> <h1 class="public-page__title">Sie sind keiner Klasse zugeteilt</h1>
<p>Sie können myskillbox nur verwenden wenn Sie in einer Klasse zugeteilt sind.</p> <p>Sie können mySkillbox nur verwenden wenn Sie in einer Klasse zugeteilt sind. Aktuell kann Sie nur der mySkillbox-Support einer Klasse zuteilen.</p>
</div> </div>
</template> </template>

View File

@ -25,6 +25,8 @@ $base-font-size: 15px;
$space: 10px; $space: 10px;
$color-brand: #17A887;
body { body {
font-family: $font-family; font-family: $font-family;
font-size: $base-font-size; font-size: $base-font-size;
@ -117,6 +119,13 @@ input[type=text], input[type=password], input[type=email], select {
margin-bottom: 52px; margin-bottom: 52px;
line-height: 1.5rem; line-height: 1.5rem;
font-size: 1.125rem; font-size: 1.125rem;
a {
color: $color-brand;
font-family: 'Montserrat', Arial, sans-serif;
font-size: 18px;
font-weight: 300;
}
} }
.reset__form label { .reset__form label {

View File

@ -0,0 +1,12 @@
{% extends 'base.html' %}
{% load i18n %}
{% block title %}{% trans 'Sie haben es geschafft' %}{% endblock %}
{% block body %}
<div class="reset">
<h2 class="reset__heading">{% trans 'Sie haben es geschafft' %}</h2>
<p class="reset__text">{% trans 'Ihr Passwort wurde erfolgreich gespeichert. Sie können sich nun anmelden.' %}</p>
<p class="reset__text"><a href="/login">{% trans 'Jetzt anmelden' %}</a></p>
</div>
{% endblock %}

View File

@ -0,0 +1,17 @@
<!-- templates/registration/password_reset_confirm.html -->
{% extends 'base.html' %}
{% load i18n %}
{% block title %}{% trans 'Setzen Sie Ihr Passwort' %}{% endblock %}
{% block body %}
<div class="reset">
<h2 class="reset__heading">{% trans 'Geben Sie ein persönliches Passwort ein:' %}</h2>
<p class="reset__text">{% trans 'Kein Problem! Geben Sie Ihre E-Mail-Adresse ein und erhalten Sie weitere Anweisungen.' %}</p>
<form method="post" class="mt-1 reset__form">
{% csrf_token %}
{{ form.as_p }}
<button type="submit" name="action">{% trans 'Passwort speichern' %}</button>
</form>
</div>
{% endblock %}

View File

@ -0,0 +1,12 @@
<!-- templates/registration/password_reset_form.html -->
{% extends 'base.html' %}
{% load i18n %}
{% block title %}{% trans 'Schauen Sie in Ihr Postfach' %}{% endblock %}
{% block body %}
<div class="reset">
<h2 class="reset__heading">{% trans 'Schauen Sie in Ihr Postfach' %}</h2>
<p class="reset__text">{% trans 'Wir haben ein E-Mail mit allen weiteren Anweisungen an Sie verschickt. Die E-Mail sollte in Kürze bei Ihnen ankommen.' %}</p>
</div>
{% endblock %}

View File

@ -0,0 +1,12 @@
{% load i18n %}{% autoescape off %}
{% blocktrans %}Sie erhalten diese E-Mail, um Ihr Passwort auf mySkillbox initial zu setzen.{% endblocktrans %}
{% trans "Bitte öffnen Sie folgende Seite, um Ihr neues Passwort einzugeben:" %}
{% block reset_link %}
{{ protocol }}://{{ domain }}{% url 'set_password_confirm' uidb64=uid token=token %}
{% endblock %}
{% trans "Ihr Benutzername lautet:" %} {{ user.get_username }}
{% trans "Ihr mySkillbox Team" %}
{% endautoescape %}

View File

@ -0,0 +1,21 @@
<!-- templates/registration/password_reset_form.html -->
{% extends 'base.html' %}
{% load i18n %}
{% block title %}{% trans 'Willkommen bei mySkillbox' %}{% endblock %}
{% block body %}
<div class="reset">
<h2 class="reset__heading">{% trans 'Willkommen bei Myskillbox' %}</h2>
<p class="reset__text">{% trans 'Bevor Sie mySkillbox verwenden können, müssen Sie Ihre E-Mail-Adresse bestätigen und ein persönliches Passwort festlegen.' %}</p>
<form method="post" class="mt-1 reset__form">
{% csrf_token %}
<div>
<label for="id_email">{% trans 'Geben Sie als erstes hier Ihre E-Mail-Adresse ein:' %}</label>
{{ form.email }}
</div>
<button class="btn mt-1" type="submit" name="action">{% trans 'E-Mail bestätigen' %}</button>
<input type="hidden" name="next" value="{{ next }}"/>
</form>
</div>
{% endblock %}

View File

@ -0,0 +1 @@
Myskillbox: E-Mail bestätigen und Passwort setzen

View File

@ -1,5 +1,5 @@
{% load i18n %}{% autoescape off %} {% load i18n %}{% autoescape off %}
{% blocktrans %}Sie erhalten diese E-Mail, um Ihr Passwort auf {{ site_name }} initial zu setzen.{% endblocktrans %} {% blocktrans %}Sie erhalten diese E-Mail, um Ihr Passwort auf mySkillbox initial zu setzen.{% endblocktrans %}
{% trans "Bitte öffnen Sie folgende Seite, um Ihr neues Passwort einzugeben:" %} {% trans "Bitte öffnen Sie folgende Seite, um Ihr neues Passwort einzugeben:" %}
{% block reset_link %} {% block reset_link %}

View File

@ -8,7 +8,8 @@ from wagtail.admin import urls as wagtailadmin_urls
from wagtail.core import urls as wagtail_urls from wagtail.core import urls as wagtail_urls
from core import views from core import views
from core.views import SetPasswordView, SetPasswordDoneView, SetPasswordConfirmView, SetPasswordCompleteView from core.views import LegacySetPasswordView, LegacySetPasswordDoneView, LegacySetPasswordConfirmView,\
LegacySetPasswordCompleteView, SetPasswordView, SetPasswordDoneView, SetPasswordConfirmView, SetPasswordCompleteView
urlpatterns = [ urlpatterns = [
# django admin # django admin
@ -16,11 +17,20 @@ urlpatterns = [
url(r'^accounts/', include('django.contrib.auth.urls')), url(r'^accounts/', include('django.contrib.auth.urls')),
url(r'^statistics/', include('statistics.urls', namespace='statistics')), url(r'^statistics/', include('statistics.urls', namespace='statistics')),
# legacy - will be removed
# set password # set password
path('welcome/', SetPasswordView.as_view(), name='set_password'), path('welcome/', LegacySetPasswordView.as_view(), name='set_password'),
path('set-password/done/', SetPasswordDoneView.as_view(), name='set_password_done'), path('set-password/done/', LegacySetPasswordDoneView.as_view(), name='set_password_done'),
path('set-password/<uidb64>/<token>/', SetPasswordConfirmView.as_view(), name='set_password_confirm'), path('set-password/<uidb64>/<token>/', LegacySetPasswordConfirmView.as_view(), name='set_password_confirm'),
path('set-password/complete/', SetPasswordCompleteView.as_view(), name='set_password_complete'), path('set-password/complete/', LegacySetPasswordCompleteView.as_view(), name='set_password_complete'),
# set password upon registration
path('registration/welcome/', SetPasswordView.as_view(), name='registration_set_password'),
path('registration/set-password/done/', SetPasswordDoneView.as_view(), name='registration_set_password_done'),
path('registration/set-password/<uidb64>/<token>/', SetPasswordConfirmView.as_view(),
name='registration_set_password_confirm'),
path('registration/set-password/complete/', SetPasswordCompleteView.as_view(),
name='registration_set_password_complete'),
# wagtail # wagtail
url(r'^cms/', include(wagtailadmin_urls)), url(r'^cms/', include(wagtailadmin_urls)),

View File

@ -27,6 +27,31 @@ def home(request):
class SetPasswordView(PasswordResetView): class SetPasswordView(PasswordResetView):
email_template_name = 'registration/registration_set_password_email.html'
subject_template_name = 'registration/registration_set_password_subject.txt'
success_url = reverse_lazy('registration_set_password_done')
template_name = 'registration/registration_set_password_form.html'
title = _('Password setzen')
class SetPasswordDoneView(PasswordResetDoneView):
template_name = 'registration/registration_set_password_done.html'
title = _('Password setzen versandt')
class SetPasswordConfirmView(PasswordResetConfirmView):
success_url = reverse_lazy('registration_set_password_complete')
template_name = 'registration/registration_set_password_confirm.html'
title = _('Gib ein Passwort ein')
class SetPasswordCompleteView(PasswordResetCompleteView):
template_name = 'registration/registration_set_password_complete.html'
title = _('Passwort setzen erfolgreich')
# legacy
class LegacySetPasswordView(PasswordResetView):
email_template_name = 'registration/set_password_email.html' email_template_name = 'registration/set_password_email.html'
subject_template_name = 'registration/set_password_subject.txt' subject_template_name = 'registration/set_password_subject.txt'
success_url = reverse_lazy('set_password_done') success_url = reverse_lazy('set_password_done')
@ -34,17 +59,17 @@ class SetPasswordView(PasswordResetView):
title = _('Password setzen') title = _('Password setzen')
class SetPasswordDoneView(PasswordResetDoneView): class LegacySetPasswordDoneView(PasswordResetDoneView):
template_name = 'registration/set_password_done.html' template_name = 'registration/set_password_done.html'
title = _('Password setzen versandt') title = _('Password setzen versandt')
class SetPasswordConfirmView(PasswordResetConfirmView): class LegacySetPasswordConfirmView(PasswordResetConfirmView):
success_url = reverse_lazy('set_password_complete') success_url = reverse_lazy('set_password_complete')
template_name = 'registration/set_password_confirm.html' template_name = 'registration/set_password_confirm.html'
title = _('Gib ein Passwort ein') title = _('Gib ein Passwort ein')
class SetPasswordCompleteView(PasswordResetCompleteView): class LegacySetPasswordCompleteView(PasswordResetCompleteView):
template_name = 'registration/set_password_complete.html' template_name = 'registration/set_password_complete.html'
title = _('Passwort setzen erfolgreich') title = _('Passwort setzen erfolgreich')

View File

@ -74,12 +74,12 @@ class RegistrationTests(TestCase):
def test_user_can_register_as_teacher(self): def test_user_can_register_as_teacher(self):
self._assert_user_registration(0, self.email, RoleManager.TEACHER_KEY) self._assert_user_registration(0, self.email, RoleManager.TEACHER_KEY)
school_classes = SchoolClass.objects.filter(name__startswith='Meine Gruppe') school_classes = SchoolClass.objects.filter(name__startswith='Meine Klasse')
self.assertEqual(len(school_classes), 0) self.assertEqual(len(school_classes), 0)
result = self.make_register_mutation(self.first_name, self.last_name, self.email, self.teacher_license_type.key) result = self.make_register_mutation(self.first_name, self.last_name, self.email, self.teacher_license_type.key)
self.assertTrue(result.get('data').get('registration').get('success')) self.assertTrue(result.get('data').get('registration').get('success'))
self._assert_user_registration(1, self.email, RoleManager.TEACHER_KEY) self._assert_user_registration(1, self.email, RoleManager.TEACHER_KEY)
school_classes = SchoolClass.objects.filter(name__startswith='Meine Gruppe') school_classes = SchoolClass.objects.filter(name__startswith='Meine Klasse')
self.assertEqual(len(school_classes), 1) self.assertEqual(len(school_classes), 1)
user = User.objects.get(email=self.email) user = User.objects.get(email=self.email)
self.assertTrue(school_classes[0].is_user_in_schoolclass(user)) self.assertTrue(school_classes[0].is_user_in_schoolclass(user))

View File

@ -76,8 +76,8 @@ class SchoolClass(models.Model):
@classmethod @classmethod
def generate_default_group_name(cls): def generate_default_group_name(cls):
prefix = 'Meine Gruppe' prefix = 'Meine Klasse'
prefix_regex = r'Meine Gruppe (\d+)' prefix_regex = r'Meine Klasse (\d+)'
initial_default_group = '{} 1'.format(prefix) initial_default_group = '{} 1'.format(prefix)
my_group_filter = cls.objects.filter(name__startswith=prefix).order_by('-pk') my_group_filter = cls.objects.filter(name__startswith=prefix).order_by('-pk')

View File

@ -25,19 +25,19 @@ from users.models import SchoolClass
class SchoolClasses(TestCase): class SchoolClasses(TestCase):
def setUp(self): def setUp(self):
self.prefix = 'Meine Gruppe' self.prefix = 'Meine Klasse'
def test_default_class_name_initial(self): def test_default_class_name_initial(self):
class_name = SchoolClass.generate_default_group_name() class_name = SchoolClass.generate_default_group_name()
self.assertEqual('{} 1'.format(self.prefix), class_name) self.assertEqual('{} 1'.format(self.prefix), class_name)
def test_default_class_name_initial_with_similar_existing(self): def test_default_class_name_initial_with_similar_existing(self):
SchoolClass.objects.create(name='{} abc212'.format('Meine Gruppe')) SchoolClass.objects.create(name='{} abc212'.format(self.prefix))
class_name = SchoolClass.generate_default_group_name() class_name = SchoolClass.generate_default_group_name()
self.assertEqual('{} 1'.format(self.prefix), class_name) self.assertEqual('{} 1'.format(self.prefix), class_name)
def test_default_class_name_if_existing(self): def test_default_class_name_if_existing(self):
SchoolClass.objects.create(name='{} 1'.format('Meine Gruppe')) SchoolClass.objects.create(name='{} 1'.format(self.prefix))
SchoolClass.objects.create(name='{} 10'.format('Meine Gruppe')) SchoolClass.objects.create(name='{} 10'.format(self.prefix))
class_name = SchoolClass.generate_default_group_name() class_name = SchoolClass.generate_default_group_name()
self.assertEqual('{} 11'.format(self.prefix), class_name) self.assertEqual('{} 11'.format(self.prefix), class_name)