diff --git a/blitz_api/management/commands/import_members.py b/blitz_api/management/commands/import_members.py new file mode 100644 index 00000000..241337a2 --- /dev/null +++ b/blitz_api/management/commands/import_members.py @@ -0,0 +1,114 @@ +import csv +import datetime +import random +import string + +from io import StringIO +from colorama import Fore +from django.core.management import call_command +from tqdm import tqdm + +from blitz_api.models import User +from django.core.management.base import BaseCommand, CommandError + + +class Command(BaseCommand): + help = 'Import members "from new_members.csv" file' + + def add_arguments(self, parser): + + # Optional arguments + parser.add_argument( + '--notify', + action='store_true', + dest='notify', + help='Notify new user with his credentials', + ) + + def handle(self, *args, **options): + + notify = options['notify'] + + with open('new_members.csv') as csv_file: + csv_reader = csv.DictReader(csv_file) + + with tqdm(list(csv_reader), unit=' users', desc='Import users ', + bar_format="{l_bar}%s{bar}%s{r_bar}" % + (Fore.GREEN, Fore.RESET) + ) as pbar: + + nb_user_created = 0 + nb_user_updated = 0 + + for user_data in pbar: + + try: + + out = StringIO() + + nb_users = User.objects.all().count() + + letters_and_digits = \ + string.ascii_letters + string.digits + password = ''.join( + random.choice(letters_and_digits) + for i in range(10)) + + birthdate = datetime.datetime.strptime( + user_data["birthdate"], '%d/%m/%Y') + birthdate = birthdate.strftime('%Y-%m-%d') + + if notify: + + call_command( + 'create_member', + f'--first_name={user_data["first_name"]}', + f'--last_name={user_data["last_name"]}', + f'--birthdate={birthdate}', + f'--gender={user_data["first_name"]}', + f'--university={user_data["university"]}', + f'--academic_level=' + f'{user_data["academic_level"]}', + f'--academic_field=' + f'{user_data["academic_field"]}', + f'--email={user_data["email"]}', + f'--password={password}', + f'--membership={user_data["membership"]}', + '--notify', + stdout=out + ) + else: + + call_command( + 'create_member', + f'--first_name={user_data["first_name"]}', + f'--last_name={user_data["last_name"]}', + f'--birthdate={birthdate}', + f'--gender={user_data["first_name"]}', + f'--university={user_data["university"]}', + f'--academic_level=' + f'{user_data["academic_level"]}', + f'--academic_field=' + f'{user_data["academic_field"]}', + f'--email={user_data["email"]}', + f'--password={password}', + # No security on password + f'--membership={user_data["membership"]}', + stdout=out) + + if User.objects.all().count() - nb_users == 0: + nb_user_updated += 1 + else: + nb_user_created += 1 + + except CommandError as e: + self.stdout.write( + self.style.ERROR(f'{e}')) + + self.stdout.write( + self.style.SUCCESS( + f'Successfully created {nb_user_created} users')) + + self.stdout.write( + self.style.SUCCESS( + f'Successfully updated {nb_user_updated} users')) diff --git a/blitz_api/management/commands/create_member.py b/blitz_api/management/commands/offer_membership.py similarity index 52% rename from blitz_api/management/commands/create_member.py rename to blitz_api/management/commands/offer_membership.py index b91b5705..c68f5b97 100644 --- a/blitz_api/management/commands/create_member.py +++ b/blitz_api/management/commands/offer_membership.py @@ -36,6 +36,14 @@ def add_arguments(self, parser): help='Notify new user with his credentials', ) + # Optional arguments + parser.add_argument( + '--check_email', + action='store_true', + dest='check_email', + help='Check email new user', + ) + def handle(self, *args, **options): with transaction.atomic(): try: @@ -44,60 +52,37 @@ def handle(self, *args, **options): raise CommandError( 'Email "%s" is not a valid email' % options['email']) - if User.objects.filter(email__iexact=options['email']): - raise CommandError( - 'A user already exists with the email {0}'.format( - options['email'], - ) - ) + user = User.objects.filter(email__iexact=options['email']) - user = User.objects.create( - first_name=' '.join(options['first_name']), - last_name=' '.join(options['last_name']), - birthdate=options['birthdate'], - gender=options['gender'], - username=options['email'], - email=options['email'], - is_active=True, - tickets=1, - ) - user.set_password(options['password']) - - try: - university = Organization.objects.get(pk=options['university']) - user.university = university - user.save() - except Organization.DoesNotExist: - raise CommandError( - 'Organization "%s" does not exist' % options['university']) - - try: - academic_field = AcademicField.objects.get( - pk=options['academic_field']) - user.academic_field = academic_field - user.save() - except AcademicField.DoesNotExist: - raise CommandError('AcademicField "%s" does not exist' % - options['academic_field']) + if len(user) == 0: + if options['check_email']: + raise CommandError( + 'A user already exists with the email {0}'.format( + options['email'], + ) + ) + try: + user = User.create_user( + first_name=' '.join(options['first_name']), + last_name=' '.join(options['last_name']), + birthdate=options['birthdate'], + gender=options['gender'], + email=options['email'], + password=options['password'], + university=options['university'], + academic_level=options['academic_level'], + academic_field=options['academic_field'] + ) + except Exception as err: + raise CommandError(f'{err}') + else: + user = user[0] try: - academic_level = AcademicLevel.objects.get( - pk=options['academic_level']) - user.academic_level = academic_level - user.save() - except AcademicLevel.DoesNotExist: - raise CommandError('AcademicLevel "%s" does not exist' % - options['academic_level']) + user.offer_free_membership(options['membership']) - try: - membership = Membership.objects.get(pk=options['membership']) - user.membership = membership - end_date = datetime.datetime.now() + membership.duration - user.membership_end = end_date - user.save() - except Membership.DoesNotExist: - raise CommandError( - 'Membership "%s" does not exist' % options['membership']) + except Exception as err: + raise CommandError(f'{err}') if options['notify'] is True: try: diff --git a/blitz_api/models.py b/blitz_api/models.py index e5a8f946..5dda3f8e 100644 --- a/blitz_api/models.py +++ b/blitz_api/models.py @@ -1,4 +1,5 @@ import binascii +import datetime import os from django.conf import settings from django.db import models @@ -134,6 +135,82 @@ class User(AbstractUser): ) history = HistoricalRecords() + @classmethod + def create_user(cls, + first_name, + last_name, + birthdate, + gender, + email, + password, + academic_level=None, + university=None, + academic_field=None): + + user = User.objects.create( + first_name=first_name[:30], + last_name=last_name[:150], + birthdate=birthdate, + gender=gender, + username=email, + email=email, + is_active=True, + tickets=1, + ) + user.set_password(password) + + if university: + try: + university = Organization.objects.get(pk=university) + user.university = university + user.save() + except Organization.DoesNotExist: + raise ValueError( + 'Organization "%s" does not exist' % university) + + if academic_field: + try: + academic_field = AcademicField.objects.get( + pk=academic_field) + user.academic_field = academic_field + user.save() + except AcademicField.DoesNotExist: + raise ValueError('AcademicField "%s" does not exist' % + academic_field) + + if academic_level: + try: + academic_level = AcademicLevel.objects.get( + pk=academic_level) + user.academic_level = academic_level + user.save() + except AcademicLevel.DoesNotExist: + raise ValueError('AcademicLevel "%s" does not exist' % + academic_level) + + return user + + def offer_free_membership(self, membership): + from store.models import Membership + + if not self.membership: + try: + membership = Membership.objects.get(pk=membership) + self.membership = membership + except Membership.DoesNotExist: + raise ValueError( + 'Membership "%s" does not exist' % membership) + + today = timezone.now().date() + if self.membership_end and self.membership_end > today: + self.membership_end = \ + self.membership_end + self.membership.duration + else: + self.membership_end = ( + today + self.membership.duration + ) + self.save() + class TemporaryToken(Token): """Subclass of Token to add an expiration time.""" diff --git a/blitz_api/tests/tests_command_CreateMember.py b/blitz_api/tests/tests_command_CreateMember.py index 8350ebb1..65d53620 100644 --- a/blitz_api/tests/tests_command_CreateMember.py +++ b/blitz_api/tests/tests_command_CreateMember.py @@ -35,13 +35,13 @@ def setUpClass(cls): name="Level 1", ) - def test_create_member(self): + def test_offer_membership(self): out = StringIO() nb_users = User.objects.all().count() call_command( - 'create_member', + 'offer_membership', '--first_name=John', '--last_name=Doe', '--birthdate=1980-12-23', @@ -68,14 +68,14 @@ def test_create_member(self): self.assertEqual(user.username, 'test@test.ca') self.assertTrue(user.membership_end) - def test_create_member_with_bad_academic_field(self): + def test_offer_membership_with_bad_academic_field(self): out = StringIO() nb_users = User.objects.all().count() with self.assertRaises(CommandError) as e: call_command( - 'create_member', + 'offer_membership', '--first_name=John', '--last_name=Doe', '--birthdate=1980-12-23', @@ -97,14 +97,14 @@ def test_create_member_with_bad_academic_field(self): nb_users = User.objects.all().count() - nb_users self.assertEqual(nb_users, 0) - def test_create_member_with_bad_academic_level(self): + def test_offer_membership_with_bad_academic_level(self): out = StringIO() nb_users = User.objects.all().count() with self.assertRaises(CommandError) as e: call_command( - 'create_member', + 'offer_membership', '--first_name=John', '--last_name=Doe', '--birthdate=1980-12-23', @@ -126,14 +126,14 @@ def test_create_member_with_bad_academic_level(self): nb_users = User.objects.all().count() - nb_users self.assertEqual(nb_users, 0) - def test_create_member_with_bad_university(self): + def test_offer_membership_with_bad_university(self): out = StringIO() nb_users = User.objects.all().count() with self.assertRaises(CommandError) as e: call_command( - 'create_member', + 'offer_membership', '--first_name=John', '--last_name=Doe', '--birthdate=1980-12-23', @@ -155,14 +155,14 @@ def test_create_member_with_bad_university(self): nb_users = User.objects.all().count() - nb_users self.assertEqual(nb_users, 0) - def test_create_member_with_bad_membership(self): + def test_offer_membership_with_bad_membership(self): out = StringIO() nb_users = User.objects.all().count() with self.assertRaises(CommandError) as e: call_command( - 'create_member', + 'offer_membership', '--first_name=John', '--last_name=Doe', '--birthdate=1980-12-23', @@ -184,14 +184,14 @@ def test_create_member_with_bad_membership(self): nb_users = User.objects.all().count() - nb_users self.assertEqual(nb_users, 0) - def test_create_member_with_bad_email(self): + def test_offer_membership_with_bad_email(self): out = StringIO() nb_users = User.objects.all().count() with self.assertRaises(CommandError) as e: call_command( - 'create_member', + 'offer_membership', '--first_name=John', '--last_name=Doe', '--birthdate=1980-12-23', @@ -218,13 +218,13 @@ def test_create_member_with_bad_email(self): "EMAIL_SERVICE": True, } ) - def test_create_member_with_notification_active(self): + def test_offer_membership_with_notification_active(self): out = StringIO() nb_users = User.objects.all().count() call_command( - 'create_member', + 'offer_membership', '--first_name=John', '--last_name=Doe', '--birthdate=1980-12-23', @@ -252,14 +252,14 @@ def test_create_member_with_notification_active(self): "EMAIL_SERVICE": False, } ) - def test_create_member_with_fail_notification(self): + def test_offer_membership_with_fail_notification(self): out = StringIO() nb_users = User.objects.all().count() with self.assertRaises(CommandError) as e: call_command( - 'create_member', + 'offer_membership', '--first_name=John', '--last_name=Doe', '--birthdate=1980-12-23', diff --git a/requirements-dev.txt b/requirements-dev.txt index feeeffb3..76a92ece 100644 --- a/requirements-dev.txt +++ b/requirements-dev.txt @@ -2,4 +2,4 @@ pycodestyle==2.5.0 coveralls==1.8.2 responses==0.10.6 six==1.12.0 -awscli==1.16.257 +awscli==1.16.259 diff --git a/requirements.txt b/requirements.txt index bf462302..50dc7f51 100644 --- a/requirements.txt +++ b/requirements.txt @@ -21,3 +21,5 @@ django-safedelete==0.5.2 django-import-export==1.2.0 jsonfield==2.0.2 django-model-utils==3.2.0 +tqdm==4.36.1 +colorama==0.4.1