diff --git a/client/src/components/rooms/RoomGroupWidget.vue b/client/src/components/rooms/RoomGroupWidget.vue index 51774a53..6508b25b 100644 --- a/client/src/components/rooms/RoomGroupWidget.vue +++ b/client/src/components/rooms/RoomGroupWidget.vue @@ -2,7 +2,7 @@
- {{name}} - {{year}} + {{name}}
@@ -11,7 +11,7 @@ import Group from '@/components/icons/Group.vue'; export default { - props: ['name', 'year'], + props: ['name'], components: { Group diff --git a/client/src/graphql/gql/fragments/schoolClassParts.gql b/client/src/graphql/gql/fragments/schoolClassParts.gql index 0476f76b..f43491e4 100644 --- a/client/src/graphql/gql/fragments/schoolClassParts.gql +++ b/client/src/graphql/gql/fragments/schoolClassParts.gql @@ -1,5 +1,4 @@ fragment SchoolClassParts on SchoolClassNode { id name - year } diff --git a/server/Benutzer.sample.csv b/server/Benutzer.sample.csv new file mode 100644 index 00000000..aa94ae06 --- /dev/null +++ b/server/Benutzer.sample.csv @@ -0,0 +1,9 @@ +Vorname,Nachname,Klassen,Rolle,Email +Dwight,Schrute,Scranton Branch,Schüler,dwight@dundermifflin.com +Michael,Scott,"Scranton Branch,Stanford Branch",Lehrer,michael@dundermifflin.com +Jim,Halpert,Scranton Branch,Schüler,jim@dundermifflin.com +Pam,Beasley,Scranton Branch,Schüler,pam@dundermifflin.com +Karen,Filippelli,Stanford Branch,Schüler,karen@dundermifflin.com +Oscar,Martinez,Scranton Branch,Schüler,oscar@dundermifflin.com +Meredith,Palmer,Scranton Branch,Schüler,meredith@dundermifflin.com +Ryan,Howard,Scranton Branch,Schüler,ryan@dundermifflin.com diff --git a/server/core/management/commands/import_users.py b/server/core/management/commands/import_users.py new file mode 100644 index 00000000..16b9be3c --- /dev/null +++ b/server/core/management/commands/import_users.py @@ -0,0 +1,48 @@ +import csv + +from django.core.management import BaseCommand +import os +from django.conf import settings + +from users.models import User, SchoolClass, Role, UserRole + + +class Command(BaseCommand): + def add_arguments(self, parser): + parser.add_argument('csv_file') + + def handle(self, *args, **options): + self.stdout.write('Importing from {}!'.format(options['csv_file'])) + dir_path = settings.BASE_DIR + rel_path = options['csv_file'] + abs_path = os.path.join(dir_path, rel_path) + try: + with open(abs_path) as f: + reader = csv.DictReader(f) + for row in reader: + email = row['Email'].lower() + school_class_names = [c.strip() for c in row['Klassen'].split(',')] + first_name = row['Vorname'] + last_name = row['Nachname'] + + self.stdout.write("Creating user {} {}, {}".format(first_name, last_name, email)) + + user, created = User.objects.get_or_create(email=email, username=email) + user.first_name = first_name + user.last_name = last_name + user.save() + + if row['Rolle'] == 'Lehrer': + self.stdout.write("Assigning teacher role") + teacher = Role.objects.get(key='teacher') + UserRole.objects.get_or_create(user=user, role=teacher) + + self.stdout.write("Adding to class(es) {}".format(', '.join(school_class_names))) + for school_class_name in school_class_names: + school, _ = SchoolClass.objects.get_or_create(name=school_class_name) + user.school_classes.add(school) + + self.stdout.write("") + + except Exception as e: + self.stdout.write(e) diff --git a/server/core/tests/test_import.py b/server/core/tests/test_import.py new file mode 100644 index 00000000..c4c19f8a --- /dev/null +++ b/server/core/tests/test_import.py @@ -0,0 +1,18 @@ +from django.test import TestCase, Client +from django.core import management + +from users.models import User, Role + + +class ImportUsersTestCase(TestCase): + def test_import(self): + Role.objects.create_default_roles() + + management.call_command('import_users', 'Benutzer.sample.csv') + + self.assertEqual(User.objects.count(), 8) + + michael = User.objects.get(email='michael@dundermifflin.com') + self.assertEqual(michael.first_name, 'Michael') + self.assertEqual(michael.school_classes.count(), 2) + self.assertTrue(michael.has_perm('users.can_manage_school_class_content')) diff --git a/server/users/admin.py b/server/users/admin.py index 773c16f0..c1f96794 100644 --- a/server/users/admin.py +++ b/server/users/admin.py @@ -15,8 +15,7 @@ class RoleInline(admin.TabularInline): @admin.register(SchoolClass) class SchoolClassAdmin(admin.ModelAdmin): - list_display = ('id', 'name', 'year') - list_filter = ('year',) + list_display = ('id', 'name') @admin.register(Role) @@ -37,13 +36,17 @@ class CustomUserAdmin(UserAdmin): add_form = CustomUserCreationForm form = CustomUserChangeForm model = User - list_display = ('username', 'first_name', 'last_name',) + list_display = ('username', 'first_name', 'last_name', 'school_classes_list') + list_filter = ('school_classes',) inlines = [ SchoolClassInline, RoleInline, ] + def school_classes_list(self, obj): + return ', '.join([s.name for s in obj.school_classes.all()]) + # fieldsets = UserAdmin.fieldsets + ( # (None, {'fields': ('school_classes',)}), # ) diff --git a/server/users/factories.py b/server/users/factories.py index a91ca864..3c07c478 100644 --- a/server/users/factories.py +++ b/server/users/factories.py @@ -17,7 +17,6 @@ class SchoolClassFactory(factory.django.DjangoModelFactory): model = SchoolClass name = factory.Sequence(lambda n: '{}{}{}'.format(random.choice(class_types), '18', class_suffix[n % len(class_suffix)])) - year = factory.LazyAttribute(lambda x: random.choice([2017, 2018, 2019])) is_deleted = False @factory.post_generation diff --git a/server/users/inputs.py b/server/users/inputs.py index 7956b03b..586b7094 100644 --- a/server/users/inputs.py +++ b/server/users/inputs.py @@ -5,7 +5,6 @@ from graphene import InputObjectType class SchoolClassInput(InputObjectType): id = graphene.ID() name = graphene.String() - year = graphene.Int() class PasswordUpdateInput(InputObjectType): diff --git a/server/users/migrations/0005_auto_20190703_0955.py b/server/users/migrations/0005_auto_20190703_0955.py new file mode 100644 index 00000000..6f37518b --- /dev/null +++ b/server/users/migrations/0005_auto_20190703_0955.py @@ -0,0 +1,22 @@ +# Generated by Django 2.0.6 on 2019-07-03 09:55 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('users', '0004_user_avatar_url'), + ] + + operations = [ + migrations.RemoveField( + model_name='schoolclass', + name='year', + ), + migrations.AlterField( + model_name='user', + name='email', + field=models.EmailField(max_length=254, unique=True, verbose_name='email address'), + ), + ] diff --git a/server/users/migrations/0006_auto_20190703_0959.py b/server/users/migrations/0006_auto_20190703_0959.py new file mode 100644 index 00000000..e56790a4 --- /dev/null +++ b/server/users/migrations/0006_auto_20190703_0959.py @@ -0,0 +1,18 @@ +# Generated by Django 2.0.6 on 2019-07-03 09:59 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('users', '0005_auto_20190703_0955'), + ] + + operations = [ + migrations.AlterField( + model_name='schoolclass', + name='name', + field=models.CharField(max_length=100, unique=True), + ), + ] diff --git a/server/users/models.py b/server/users/models.py index 6cc3ac78..c25c4eaa 100644 --- a/server/users/models.py +++ b/server/users/models.py @@ -13,6 +13,7 @@ DEFAULT_SCHOOL_ID = 1 class User(AbstractUser): last_module = models.ForeignKey('books.Module', related_name='+', on_delete=models.SET_NULL, null=True) avatar_url = models.CharField(max_length=254, blank=True, default='') + email = models.EmailField(_('email address'), unique=True) def get_role_permissions(self): perms = set() @@ -43,14 +44,12 @@ class User(AbstractUser): class SchoolClass(models.Model): - name = models.CharField(max_length=100, blank=False, null=False) - year = models.PositiveIntegerField(blank=False, null=False, - validators=[MinValueValidator(1900), MaxValueValidator(2200)]) + name = models.CharField(max_length=100, blank=False, null=False, unique=True) is_deleted = models.BooleanField(blank=False, null=False, default=False) users = models.ManyToManyField(get_user_model(), related_name='school_classes') def __str__(self): - return 'SchoolClass {}-{}-{}'.format(self.id, self.name, self.year) + return 'SchoolClass {}-{}'.format(self.id, self.name) def is_user_in_schoolclass(self, user): return user.is_superuser or user.school_classes.filter(pk=self.id).count() > 0 diff --git a/server/users/services.py b/server/users/services.py index b075cc2d..efc0f011 100644 --- a/server/users/services.py +++ b/server/users/services.py @@ -21,7 +21,6 @@ def create_users(data=None): SchoolClassFactory( users=[teacher] + students, - year='2018', name='skillbox' ) teacher2 = UserFactory(username='teacher2') @@ -30,7 +29,6 @@ def create_users(data=None): UserRole.objects.create(user=student_second_class, role=student_role) SchoolClassFactory( users=[teacher2, student_second_class], - year='2018', name='second_class' ) @@ -59,5 +57,4 @@ def create_users(data=None): SchoolClassFactory( users=students + [teacher], name=school_class.get('class'), - year='2018' )