Skip to content

Commit

Permalink
quick save
Browse files Browse the repository at this point in the history
  • Loading branch information
SKairinos committed Dec 8, 2023
1 parent 64cb2e7 commit bc8c008
Show file tree
Hide file tree
Showing 4 changed files with 272 additions and 69 deletions.
3 changes: 2 additions & 1 deletion codeforlife/models/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
import typing as t
from datetime import timedelta

from django.core.exceptions import ObjectDoesNotExist
from django.db import models
from django.utils import timezone
from django.utils.translation import gettext_lazy as _
Expand Down Expand Up @@ -54,6 +55,7 @@ def delete(self, wait: t.Optional[timedelta] = None):
# Type hints for Django's runtime-generated fields.
id: int
pk: int
DoesNotExist: t.Type[ObjectDoesNotExist]

# Default for how long to wait before a model is deleted.
delete_wait = timedelta(days=3)
Expand Down Expand Up @@ -81,7 +83,6 @@ def delete(self, wait: t.Optional[timedelta] = None):
),
)

# pylint: disable-next=missing-class-docstring
class Meta(TypedModelMeta):
abstract = True

Expand Down
131 changes: 89 additions & 42 deletions codeforlife/user/models/student.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
from django.db.models import Q
from django.db.models.query import QuerySet
from django.utils.translation import gettext_lazy as _
from django_stubs_ext.db.models import TypedModelMeta

from ...models import AbstractModel
from . import class_student_join_request as _class_student_join_request
Expand All @@ -24,18 +25,47 @@
class Student(AbstractModel):
"""A user's student profile."""

class Manager(models.Manager): # pylint: disable=missing-class-docstring
def create(self, direct_login_key: str, **fields):
return super().create(
**fields,
direct_login_key=make_password(direct_login_key),
)
# pylint: disable-next=missing-class-docstring
class Manager(models.Manager["Student"]):
def create( # type: ignore[override]
self,
auto_gen_password: t.Optional[str] = None,
**fields,
):
"""Create a student.
Args:
auto_gen_password: The student's auto-generated password.
Returns:
A student instance.
"""

if auto_gen_password:
auto_gen_password = make_password(auto_gen_password)

return super().create(**fields, auto_gen_password=auto_gen_password)

def bulk_create( # type: ignore[override]
self,
students: t.Iterable["Student"],
*args,
**kwargs,
):
"""Bulk create students.
Args:
students: An iteration of student objects.
Returns:
A list of student instances.
"""

def bulk_create(self, students: t.Iterable["Student"], *args, **kwargs):
for student in students:
student.direct_login_key = make_password(
student.direct_login_key
)
if student.auto_gen_password:
student.auto_gen_password = make_password(
student.auto_gen_password
)

return super().bulk_create(students, *args, **kwargs)

Expand All @@ -60,6 +90,17 @@ def bulk_create_users(
*args,
**kwargs,
):
"""Bulk create users with student profiles.
Args:
student_users: A list of tuples where the first object is the
student profile and the second is the user whom the student
profile belongs to.
Returns:
A list of users that have been assigned their student profile.
"""

students = [student for (student, _) in student_users]
users = [user for (_, user) in student_users]

Expand All @@ -70,56 +111,62 @@ def bulk_create_users(

return _user.User.objects.bulk_create(users, *args, **kwargs)

def make_random_direct_login_key(self):
return _user.User.objects.make_random_password(
length=Student.direct_login_key.max_length
)

objects: Manager = Manager()
objects: Manager = Manager.from_queryset( # type: ignore[misc]
AbstractModel.QuerySet
)() # type: ignore[assignment]

user: "_user.User"
class_join_requests: QuerySet[
"_class_student_join_request.ClassStudentJoinRequest"
]
# class_join_requests: QuerySet[
# "_class_student_join_request.ClassStudentJoinRequest"
# ]

# Is this needed or can it be inferred from klass.
school: "_school.School" = models.ForeignKey(
"user.School",
related_name="students",
null=True,
# school: "_school.School" = models.ForeignKey(
# "user.School",
# related_name="students",
# null=True,
# editable=False,
# on_delete=models.CASCADE,
# )

# klass: "_class.Class" = models.ForeignKey(
# "user.Class",
# related_name="students",
# null=True,
# editable=False,
# on_delete=models.CASCADE,
# )

auto_gen_password = models.CharField(
_("automatically generated password"),
max_length=64,
editable=False,
on_delete=models.CASCADE,
)

klass: "_class.Class" = models.ForeignKey(
"user.Class",
related_name="students",
null=True,
editable=False,
on_delete=models.CASCADE,
)

second_password = models.CharField( # TODO: make nullable
_("secondary password"),
max_length=64, # investigate hash length
editable=False,
help_text=_(
"A unique key that allows a student to log directly into their"
"account." # TODO
"An auto-generated password that allows student to log directly"
" into their account."
),
validators=[MinLengthValidator(64)],
)

# TODO: add direct reference to teacher
# TODO: add meta constraint for school & direct_login_key

class Meta:
class Meta(TypedModelMeta):
verbose_name = _("student")
verbose_name_plural = _("students")
constraints = [
models.CheckConstraint(
check=(
Q(school__isnull=True, klass__isnull=True)
| Q(school__isnull=False, klass__isnull=False)
),
name="student__school_is_null_and_class_is_null",
name="student__school_and_klass",
),
models.CheckConstraint(
check=(
Q(school__isnull=False, auto_gen_password__isnull=False)
| Q(school__isnull=True, auto_gen_password__isnull=True)
),
name="student__auto_gen_password",
),
]
5 changes: 5 additions & 0 deletions codeforlife/user/models/teacher.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
from django.db import models
from django.db.models.query import QuerySet
from django.utils.translation import gettext_lazy as _
from django_stubs_ext.db.models import TypedModelMeta

from ...models import AbstractModel

Expand Down Expand Up @@ -64,3 +65,7 @@ def create_user(self, teacher: t.Dict[str, t.Any], **fields):
)

# TODO: add direct reference to students

class Meta(TypedModelMeta):
verbose_name = _("teacher")
verbose_name_plural = _("teachers")
Loading

0 comments on commit bc8c008

Please sign in to comment.