Skip to content

Commit

Permalink
Merge pull request #14 from NUS-Fintech-Society/feature/TAS-9-extend-…
Browse files Browse the repository at this point in the history
…user-model

Feature/TAS 9 Extend User Model
  • Loading branch information
gnimnix authored Feb 18, 2024
2 parents 58a7c6a + b5bfa1b commit 1d9efe1
Show file tree
Hide file tree
Showing 22 changed files with 251 additions and 16 deletions.
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ __pycache__/
local_settings.py
db.sqlite3
db.sqlite3-journal
media
uploads

# If your build process includes running collectstatic, then you probably don't need or want to include staticfiles/
# in your Git repository. Update and uncomment the following line accordingly.
Expand Down
16 changes: 14 additions & 2 deletions atlas_3/atlas_3/management/commands/seed_db.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
from django.core.management import BaseCommand
from django.contrib.auth.models import User

from random import choice

from authentication.models import AtlasUser


class Command(BaseCommand):
help = "Populates the database"
Expand All @@ -16,18 +20,26 @@ def add_arguments(self, parser):

def create_users(self, verbose=False):
User.objects.all().delete()
AtlasUser.objects.all().delete()

user = User.objects.create_superuser("admin", "[email protected]", "password")
user.save()
admin_profile = AtlasUser(user=user, department=choice(list(AtlasUser.DepartmentNames)), role=AtlasUser.Roles.ADMIN)
admin_profile.save()

if verbose:
self.stdout.write(f"Created superuser {user.username} {user.email}")
for i in range(1, 6):
self.stdout.write(f"Created admin profile {admin_profile}")
for i in range(5):
user = User.objects.create_user(
f"user{i}", f"user{i}@example.com", "password"
f"user{i + 1}", f"user{i + 1}@example.com", "password"
)
user.save()
profile = AtlasUser(user=user, department=choice(list(AtlasUser.DepartmentNames)))
profile.save()
if verbose:
self.stdout.write(f"Created user {user.username} {user.email}")
self.stdout.write(f"Created profile {profile}")

def handle(self, *args, **options):
self.stdout.write("Populating database...")
Expand Down
14 changes: 13 additions & 1 deletion atlas_3/atlas_3/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,9 @@
"django.contrib.staticfiles",
"corsheaders",
"ninja",
"django_extensions",
"atlas_3",
"authentication"
]

MIDDLEWARE = [
Expand Down Expand Up @@ -125,7 +127,17 @@
# Static files (CSS, JavaScript, Images)
# https://docs.djangoproject.com/en/5.0/howto/static-files/

STATIC_URL = "static/"
STATIC_URL = os.path.normpath(str((BASE_DIR / "assets/").resolve())) + "/"

STATIC_ROOT = "assets/"


# User uploaded files
# https://docs.djangoproject.com/en/5.0/topics/files/#managing-files

MEDIA_ROOT = os.path.normpath(str((BASE_DIR / "uploads/").resolve())) + "/"

MEDIA_URL = "uploads/"

# Default primary key field type
# https://docs.djangoproject.com/en/5.0/ref/settings/#default-auto-field
Expand Down
9 changes: 6 additions & 3 deletions atlas_3/atlas_3/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,14 +15,16 @@
2. Add a URL to urlpatterns: path('blog/', include('blog.urls'))
"""

from django.conf import settings
from django.conf.urls.static import static
from django.contrib import admin
from django.urls import include, path

from ninja import NinjaAPI

api = NinjaAPI(csrf=True)

api.add_router("auth/", "auth.api.router")
api.add_router("auth/", "authentication.api.router")


@api.get("/resource")
Expand All @@ -31,7 +33,8 @@ def resource(request):


urlpatterns = [
path("auth/", include("auth.urls")),
path("auth/", include("authentication.urls")),
path("admin/", admin.site.urls),
path("", api.urls),
]
] + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT) \
+ static(settings.STATIC_URL, document_root=settings.STATIC_ROOT)
3 changes: 0 additions & 3 deletions atlas_3/auth/models.py

This file was deleted.

3 changes: 0 additions & 3 deletions atlas_3/auth/tests.py

This file was deleted.

File renamed without changes.
2 changes: 2 additions & 0 deletions atlas_3/auth/admin.py → atlas_3/authentication/admin.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
from django.contrib import admin
from .models import AtlasUser

# Register your models here.
admin.site.register(AtlasUser)
File renamed without changes.
4 changes: 2 additions & 2 deletions atlas_3/auth/apps.py → atlas_3/authentication/apps.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
from django.apps import AppConfig


class AuthConfig(AppConfig):
class AuthenticationConfig(AppConfig):
default_auto_field = "django.db.models.BigAutoField"
name = "auth"
name = "authentication"
53 changes: 53 additions & 0 deletions atlas_3/authentication/migrations/0001_initial.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
# Generated by Django 5.0.2 on 2024-02-09 18:45

import django.db.models.deletion
from django.conf import settings
from django.db import migrations, models


class Migration(migrations.Migration):

initial = True

dependencies = [
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
]

operations = [
migrations.CreateModel(
name="AtlasUser",
fields=[
(
"id",
models.BigAutoField(
auto_created=True,
primary_key=True,
serialize=False,
verbose_name="ID",
),
),
(
"department",
models.CharField(
blank=True,
choices=[
("ML", "Machine Learning"),
("BC", "Blockchain"),
("SD", "Software Development"),
("QD", "Quant Department"),
("ER", "External Relations"),
("IA", "Internal Affairs"),
],
max_length=50,
),
),
(
"user",
models.OneToOneField(
on_delete=django.db.models.deletion.CASCADE,
to=settings.AUTH_USER_MODEL,
),
),
],
),
]
20 changes: 20 additions & 0 deletions atlas_3/authentication/migrations/0002_atlasuser_profile_pic.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
# Generated by Django 5.0.2 on 2024-02-10 06:01

from django.db import migrations, models


class Migration(migrations.Migration):

dependencies = [
("authentication", "0001_initial"),
]

operations = [
migrations.AddField(
model_name="atlasuser",
name="profile_pic",
field=models.ImageField(
default="profile/user/blank_profile.png", upload_to="profile/user/"
),
),
]
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
# Generated by Django 5.0.2 on 2024-02-10 08:34

import authentication.models
from django.db import migrations, models


class Migration(migrations.Migration):

dependencies = [
("authentication", "0002_atlasuser_profile_pic"),
]

operations = [
migrations.AddField(
model_name="atlasuser",
name="role",
field=models.CharField(
choices=[
("ADMIN", "Admin"),
("MEMBER", "Member"),
("APPLICANT", "Applicant"),
],
default="APPLICANT",
max_length=50,
),
),
migrations.AddField(
model_name="atlasuser",
name="telegram_handle",
field=models.CharField(blank=True, max_length=250),
),
migrations.AlterField(
model_name="atlasuser",
name="profile_pic",
field=models.ImageField(
default="profile/blank_profile.png",
upload_to=authentication.models.profile_pic_path,
),
),
]
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# Generated by Django 5.0.2 on 2024-02-10 10:41

from django.db import migrations


class Migration(migrations.Migration):

dependencies = [
("authentication", "0003_atlasuser_role_atlasuser_telegram_handle_and_more"),
]

operations = [
migrations.RenameField(
model_name="atlasuser",
old_name="profile_pic",
new_name="profile_picture",
),
]
File renamed without changes.
42 changes: 42 additions & 0 deletions atlas_3/authentication/models.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
from django.contrib.auth.models import User
from django.db import models
from django.utils.text import slugify
from django.utils.translation import gettext_lazy as _

from hashlib import sha1


def profile_pic_path(instance, filename: str) -> str:
"""
This function computes the path of where to store the profile picture
:param instance: An instance of AtlasUser based on the current user
:param filename: original filename
:return: relative path of profile picture from MEDIA_ROOT
"""
ext = filename.split('.')[-1]
return f"profile/{sha1(instance.user.username.encode()).hexdigest()}/{slugify(filename)}.{ext}"


# Create your models here.
class AtlasUser(models.Model):
class DepartmentNames(models.TextChoices):
MACHINE_LEARNING = "ML", _("Machine Learning")
BLOCKCHAIN = "BC", _("Blockchain")
SOFTWARE_DEVELOPMENT = "SD", _("Software Development")
QUANT_DEPARTMENT = "QD", _("Quant Department")
EXTERNAL_RELATIONS = "ER", _("External Relations")
INTERNAL_AFFAIRS = "IA", _("Internal Affairs")

class Roles(models.TextChoices):
ADMIN = "ADMIN", _("Admin")
MEMBER = "MEMBER", _("Member")
APPLICANT = "APPLICANT", _("Applicant")

user = models.OneToOneField(User, on_delete=models.CASCADE)
department = models.CharField(max_length=50, choices=DepartmentNames.choices, blank=True)
profile_picture = models.ImageField(upload_to=profile_pic_path, default='profile/blank_profile.png')
role = models.CharField(max_length=50, choices=Roles.choices, default=Roles.APPLICANT)
telegram_handle = models.CharField(max_length=250, blank=True)

def __str__(self):
return f"{self.user.username} in {self.get_department_display()} department"
37 changes: 37 additions & 0 deletions atlas_3/authentication/tests.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
from django.contrib.auth.models import User
from django.core.files.uploadedfile import SimpleUploadedFile
from django.test import TestCase

import os

from authentication.models import AtlasUser


# Create your tests here.
class AtlasUserModelTest(TestCase):
def setUp(self):
self.user = User.objects.create_user('test', email='[email protected]', password='password')
self.user.save()
self.deleteFiles = []

def tearDown(self):
parent_folders = set()
for file in self.deleteFiles:
parent_folders.add(os.path.abspath(os.path.dirname(file)))
os.remove(file)
for folder in parent_folders:
os.rmdir(folder)

def test_can_create_atlas_user(self):
atlas_user = AtlasUser(user=self.user, department=AtlasUser.DepartmentNames.SOFTWARE_DEVELOPMENT, role=AtlasUser.Roles.MEMBER)
atlas_user.save()
self.assertEqual(str(atlas_user), 'test in Software Development department')

def test_atlas_user_can_save_profile_picture(self):
atlas_user = AtlasUser(user=self.user, department=AtlasUser.DepartmentNames.SOFTWARE_DEVELOPMENT, role=AtlasUser.Roles.MEMBER)
atlas_user.save()
uploaded_file = SimpleUploadedFile('profile_picture.jpeg', open('./tests/assets/profile/profile_picture.jpeg', 'rb').read(), 'image/jpeg')
atlas_user.profile_picture = uploaded_file
atlas_user.save()
self.deleteFiles.append(atlas_user.profile_picture.path)
self.assertTrue(os.path.exists(atlas_user.profile_picture.path))
File renamed without changes.
File renamed without changes.
Binary file added atlas_3/tests/assets/profile/profile_picture.jpeg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added atlas_3/uploads/profile/blank_profile.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
4 changes: 3 additions & 1 deletion requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,6 @@ django-ninja~=1.1.0
psycopg2>=2.8.4
black~=24.1.1
django-cors-headers~=4.3.1
django-dotenv~=1.4.2
django-dotenv~=1.4.2
Pillow~=10.2.0
django-extensions~=3.2.3

0 comments on commit 1d9efe1

Please sign in to comment.