diff --git a/KeRS/settings.py b/KeRS/settings.py index dd4bf9f..33a4a3a 100644 --- a/KeRS/settings.py +++ b/KeRS/settings.py @@ -15,7 +15,6 @@ import os # Build paths inside the project like this: os.path.join(BASE_DIR, ...) BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) - # Quick-start development settings - unsuitable for production # See https://docs.djangoproject.com/en/3.0/howto/deployment/checklist/ @@ -27,7 +26,6 @@ DEBUG = True ALLOWED_HOSTS = [] - # Application definition OWN_APPS = [ @@ -36,15 +34,13 @@ OWN_APPS = [ ] INSTALLED_APPS = [ - 'django.contrib.admin', - 'django.contrib.auth', - 'django.contrib.contenttypes', - 'django.contrib.sessions', - 'django.contrib.messages', - 'django.contrib.staticfiles', -] + OWN_APPS - - + 'django.contrib.admin', + 'django.contrib.auth', + 'django.contrib.contenttypes', + 'django.contrib.sessions', + 'django.contrib.messages', + 'django.contrib.staticfiles', + ] + OWN_APPS MIDDLEWARE = [ 'django.middleware.security.SecurityMiddleware', @@ -60,11 +56,11 @@ ROOT_URLCONF = 'KeRS.urls' TEMPLATES = [ { - 'BACKEND': 'django.template.backends.django.DjangoTemplates', - 'DIRS': [os.path.join(BASE_DIR, 'templates')] + 'BACKEND': 'django.template.backends.django.DjangoTemplates', + 'DIRS': [os.path.join(BASE_DIR, 'templates')] , 'APP_DIRS': True, - 'OPTIONS': { + 'OPTIONS': { 'context_processors': [ 'django.template.context_processors.debug', 'django.template.context_processors.request', @@ -77,22 +73,20 @@ TEMPLATES = [ WSGI_APPLICATION = 'KeRS.wsgi.application' - # Database # https://docs.djangoproject.com/en/3.0/ref/settings/#databases DATABASES = { 'default': { - 'ENGINE': 'django.db.backends.mysql', - 'NAME': 'kers', - 'USER': 'kers', + 'ENGINE': 'django.db.backends.mysql', + 'NAME': 'kers', + 'USER': 'kers', 'PASSWORD': 'kers', - 'HOST': '127.0.0.1', - 'PORT': '3306', + 'HOST': '127.0.0.1', + 'PORT': '3306', } } - # Password validation # https://docs.djangoproject.com/en/3.0/ref/settings/#auth-password-validators @@ -111,7 +105,6 @@ AUTH_PASSWORD_VALIDATORS = [ }, ] - # Internationalization # https://docs.djangoproject.com/en/3.0/topics/i18n/ @@ -125,8 +118,11 @@ USE_L10N = True USE_TZ = True - # Static files (CSS, JavaScript, Images) # https://docs.djangoproject.com/en/3.0/howto/static-files/ STATIC_URL = '/static/' + +# Custom stuff + +AUTH_USER_MODEL = 'users.CustomUser' diff --git a/events/migrations/0001_initial.py b/events/migrations/0001_initial.py index caeecc0..f50a5f5 100644 --- a/events/migrations/0001_initial.py +++ b/events/migrations/0001_initial.py @@ -1,5 +1,6 @@ -# Generated by Django 3.0.8 on 2020-07-21 20:00 +# Generated by Django 3.0.8 on 2020-07-21 21:36 +from django.conf import settings from django.db import migrations, models import django.db.models.deletion @@ -9,7 +10,7 @@ class Migration(migrations.Migration): initial = True dependencies = [ - ('users', '__first__'), + migrations.swappable_dependency(settings.AUTH_USER_MODEL), ] operations = [ @@ -27,7 +28,7 @@ class Migration(migrations.Migration): ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), ('shirt_size', models.CharField(choices=[('I', 'Interested'), ('A', 'Admitted'), ('D', 'Denied')], max_length=1)), ('event_id', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='events.Event')), - ('user_id', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='users.User')), + ('user_id', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)), ], ), ] diff --git a/events/models.py b/events/models.py index 6023ca4..04076f1 100644 --- a/events/models.py +++ b/events/models.py @@ -1,6 +1,6 @@ from django.db import models -from users.models import User +from users.models import CustomUser class Event(models.Model): @@ -15,5 +15,5 @@ class EventRegistration(models.Model): ('D', 'Denied'), ) event_id = models.ForeignKey(Event, on_delete=models.CASCADE) - user_id = models.ForeignKey(User, on_delete=models.CASCADE) + user_id = models.ForeignKey(CustomUser, on_delete=models.CASCADE) shirt_size = models.CharField(max_length=1, choices=REGISTRATION_STATE) diff --git a/requirements.txt b/requirements.txt index 1150930..6f5b4bd 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,4 +1,5 @@ asgiref==3.2.10 Django==3.0.8 +mysqlclient==2.0.1 pytz==2020.1 sqlparse==0.3.1 diff --git a/users/managers.py b/users/managers.py new file mode 100644 index 0000000..bdf2ec7 --- /dev/null +++ b/users/managers.py @@ -0,0 +1,33 @@ +from django.contrib.auth.base_user import BaseUserManager +from django.utils.translation import ugettext_lazy as _ + + +class CustomUserManager(BaseUserManager): + """ + Custom user model manager where email is the unique identifiers + for authentication instead of usernames. + """ + + def create_user(self, zeus_id, username, password=None, **extra_fields): + """ + Create and save a User with the given email and password. + """ + if zeus_id is None or username is None: + raise ValueError(_('The zeus_id and username must be set')) + user = self.model(zeus_id=zeus_id, username=username, password=password, **extra_fields) + user.set_password(password) + user.save() + return user + + def create_superuser(self, zeus_id, username, password, **extra_fields): + """ + Create and save a SuperUser with the given email and password. + """ + extra_fields.setdefault('is_staff', True) + extra_fields.setdefault('is_superuser', True) + + if extra_fields.get('is_staff') is not True: + raise ValueError(_('Superuser must have is_staff=True.')) + if extra_fields.get('is_superuser') is not True: + raise ValueError(_('Superuser must have is_superuser=True.')) + return self.create_user(zeus_id, username, password, **extra_fields) diff --git a/users/migrations/0001_initial.py b/users/migrations/0001_initial.py index 463055b..b68ad10 100644 --- a/users/migrations/0001_initial.py +++ b/users/migrations/0001_initial.py @@ -1,6 +1,7 @@ -# Generated by Django 3.0.8 on 2020-07-21 20:03 +# Generated by Django 3.0.8 on 2020-07-21 22:48 from django.db import migrations, models +import django.utils.timezone class Migration(migrations.Migration): @@ -8,17 +9,28 @@ class Migration(migrations.Migration): initial = True dependencies = [ + ('auth', '0011_update_proxy_permissions'), ] operations = [ migrations.CreateModel( - name='User', + name='CustomUser', fields=[ ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('password', models.CharField(max_length=128, verbose_name='password')), + ('last_login', models.DateTimeField(blank=True, null=True, verbose_name='last login')), + ('is_superuser', models.BooleanField(default=False, help_text='Designates that this user has all permissions without explicitly assigning them.', verbose_name='superuser status')), ('zeus_id', models.IntegerField()), - ('username', models.CharField(max_length=255)), + ('is_staff', models.BooleanField(default=False)), + ('username', models.CharField(max_length=50, unique=True)), ('student_number', models.CharField(max_length=255)), - ('real_name', models.CharField(max_length=255)), + ('real_name', models.CharField(max_length=100)), + ('date_joined', models.DateTimeField(default=django.utils.timezone.now)), + ('groups', models.ManyToManyField(blank=True, help_text='The groups this user belongs to. A user will get all permissions granted to each of their groups.', related_name='user_set', related_query_name='user', to='auth.Group', verbose_name='groups')), + ('user_permissions', models.ManyToManyField(blank=True, help_text='Specific permissions for this user.', related_name='user_set', related_query_name='user', to='auth.Permission', verbose_name='user permissions')), ], + options={ + 'abstract': False, + }, ), ] diff --git a/users/migrations/0002_auto_20200721_2249.py b/users/migrations/0002_auto_20200721_2249.py new file mode 100644 index 0000000..2d53721 --- /dev/null +++ b/users/migrations/0002_auto_20200721_2249.py @@ -0,0 +1,18 @@ +# Generated by Django 3.0.8 on 2020-07-21 22:49 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('users', '0001_initial'), + ] + + operations = [ + migrations.AlterField( + model_name='customuser', + name='zeus_id', + field=models.IntegerField(null=True, unique=True), + ), + ] diff --git a/users/models.py b/users/models.py index ea16066..4277ec7 100644 --- a/users/models.py +++ b/users/models.py @@ -1,8 +1,24 @@ +from django.contrib.auth.base_user import AbstractBaseUser from django.db import models +from django.contrib.auth.models import User, PermissionsMixin +from django.utils import timezone + +from users.managers import CustomUserManager -class User(models.Model): - zeus_id = models.IntegerField() - username = models.CharField(max_length=255) # zeus username +class CustomUser(AbstractBaseUser, PermissionsMixin): + zeus_id = models.IntegerField(unique=True, null=True) + is_staff = models.BooleanField(default=False) + username = models.CharField(max_length=50, unique=True) # zeus username student_number = models.CharField(max_length=255) - real_name = models.CharField(max_length=255) + real_name = models.CharField(max_length=100) + + date_joined = models.DateTimeField(default=timezone.now) + + USERNAME_FIELD = 'username' + REQUIRED_FIELDS = ['zeus_id'] + + objects = CustomUserManager() + + def __str__(self): + return self.username