Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions main/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -331,6 +331,7 @@
else:
STATIC_ROOT = env("DJANGO_STATIC_ROOT")
MEDIA_ROOT = env("DJANGO_MEDIA_ROOT")

# Email
if env("EMAIL_HOST_USER"):
EMAIL_BACKEND = env("EMAIL_BACKEND")
Expand Down
5 changes: 2 additions & 3 deletions schema.graphql
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,6 @@ input BoolBaseFilterLookup {
input ChangePasswordInput {
oldPassword: String!
newPassword: String!
confirmNewPassword: String!
}

input ContentCreateInput {
Expand Down Expand Up @@ -201,10 +200,10 @@ input RegisterUserInput {
uuid: String!
token: String!
password: String!
confirmPassword: String!
firstName: String
lastName: String
department: DepartmentTypeEnum
profilePicture: Upload
}

input ResetUserPassword {
Expand Down Expand Up @@ -311,6 +310,7 @@ input UserFilter {
input UserMeInput {
firstName: String
lastName: String
profilePicture: Upload
}

type UserMeType {
Expand All @@ -330,7 +330,6 @@ input UserPasswordReset {
uuid: String!
token: String!
newPassword: String!
confirmNewPassword: String!
}

input UserPasswordResetTriggerInput {
Expand Down
1 change: 1 addition & 0 deletions user/admin.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ class UserAdmin(DjangoUserAdmin):
"first_name",
"last_name",
"department",
"profile_picture",
)
},
),
Expand Down
18 changes: 18 additions & 0 deletions user/migrations/0004_user_profile_picture.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# Generated by Django 5.1.6 on 2025-03-19 14:42

from django.db import migrations, models


class Migration(migrations.Migration):

dependencies = [
('user', '0003_rename_user_type_user_department'),
]

operations = [
migrations.AddField(
model_name='user',
name='profile_picture',
field=models.ImageField(blank=True, null=True, upload_to='profile_pictures/'),
),
]
1 change: 1 addition & 0 deletions user/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ class Department(models.IntegerChoices):
blank=True,
max_length=255,
)
profile_picture = models.ImageField(upload_to="profile_pictures/", blank=True, null=True)
department = models.PositiveSmallIntegerField(choices=Department.choices, null=True)

objects: CustomUserManager = CustomUserManager()
Expand Down
32 changes: 21 additions & 11 deletions user/serializers.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
send_account_creation_email_task,
send_password_reset_email_task,
)
from utils.file_check import validate_image_size


class LoginSerializer(serializers.Serializer):
Expand Down Expand Up @@ -76,20 +77,29 @@ def create(self, validated_data):
class UserRegisterSerializer(serializers.ModelSerializer):
uuid = serializers.CharField(required=True)
token = serializers.CharField(required=True)
confirm_password = serializers.CharField(write_only=True, required=True)

class Meta:
model = User
fields = ("uuid", "token", "password", "confirm_password", "first_name", "last_name", "department")
fields = (
"uuid",
"token",
"password",
"first_name",
"last_name",
"department",
"profile_picture",
)
extra_kwargs = {"password": {"write_only": True}}

def validate_password(self, password):
validate_password(password)
return password

def validate_profile_picture(self, profile_picture):
validate_image_size(profile_picture)
return profile_picture

def validate(self, attrs):
if attrs["password"] != attrs["confirm_password"]:
raise serializers.ValidationError(gettext("Passwords do not match."))
return {**attrs, "user": validate_token(attrs, TokenManager.account_registration_token_generator)}

def save(self, **_):
Expand All @@ -98,9 +108,10 @@ def save(self, **_):
user.first_name = self.validated_data["first_name"]
user.last_name = self.validated_data["last_name"]
user.department = self.validated_data["department"]
user.profile_picture = self.validated_data.get("profile_picture", None)
user.set_password(self.validated_data["password"])
user.is_active = True
user.save(update_fields=("first_name", "last_name", "department", "password", "is_active"))
user.save(update_fields=("first_name", "last_name", "department", "profile_picture", "password", "is_active"))
return user


Expand Down Expand Up @@ -197,15 +208,12 @@ class UserPasswordResetConfirmSerializer(serializers.Serializer):
uuid = serializers.CharField(required=True)
token = serializers.CharField(required=True)
new_password = serializers.CharField(required=True)
confirm_new_password = serializers.CharField(required=True)

def validate_new_password(self, password):
validate_password(password)
return password

def validate(self, attrs):
if attrs["new_password"] != attrs["confirm_new_password"]:
raise serializers.ValidationError(gettext("Passwords do not match."))
return {**attrs, "user": validate_token(attrs, TokenManager.password_reset_token_generator)}

def save(self, **_):
Expand All @@ -219,7 +227,6 @@ def save(self, **_):
class ChangePasswordSerializer(serializers.Serializer):
old_password = serializers.CharField(required=True)
new_password = serializers.CharField(required=True)
confirm_new_password = serializers.CharField(required=True)

def validate_old_password(self, password):
user = self.context["request"].user
Expand All @@ -230,8 +237,6 @@ def validate_old_password(self, password):
def validate(self, attrs):
if attrs["old_password"] == attrs["new_password"]:
raise serializers.ValidationError(gettext("New and old provided passwords are same"))
if attrs["new_password"] != attrs["confirm_new_password"]:
raise serializers.ValidationError(gettext("Passwords do not match."))
return attrs

def validate_new_password(self, password):
Expand All @@ -247,9 +252,14 @@ def save(self, **_):


class UpdateMeSerializer(serializers.ModelSerializer):
def validate_profile_picture(self, profile_picture):
validate_image_size(profile_picture)
return profile_picture

class Meta:
model = User
fields = (
"first_name",
"last_name",
"profile_picture",
)
7 changes: 7 additions & 0 deletions utils/file_check.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,3 +16,10 @@ def validate_file_type(file):
if extension.lower() not in allowed_extensions:
raise ValidationError("Only .pdf and .txt files are allowed.")
return file


def validate_image_size(image):
max_file_size = 2 * 1024 * 1024
if image.size > max_file_size:
raise ValidationError("Image size must be less than 2MB.")
return image
Loading