Skip to content

Commit

Permalink
finalize adding phone number and mail to user
Browse files Browse the repository at this point in the history
  • Loading branch information
magsyg committed Sep 14, 2023
1 parent f7bb910 commit 9090bc7
Show file tree
Hide file tree
Showing 6 changed files with 130 additions and 50 deletions.
81 changes: 57 additions & 24 deletions backend/samfundet/serializers.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,8 @@
from .models.utils.fields import SerializerPhoneNumberField

from .models.billig import BilligEvent, BilligTicketGroup, BilligPriceGroup
from .models.recruitment import (Recruitment, RecruitmentPosition, RecruitmentAdmission)
from .models.recruitment import (Recruitment, RecruitmentPosition,
RecruitmentAdmission)
from .models.event import (Event, EventGroup, EventCustomTicket)
from .models.general import (
Tag,
Expand Down Expand Up @@ -48,12 +49,15 @@ class Meta:
class ImageSerializer(serializers.ModelSerializer):
# Read only tags used in frontend.
tags = TagSerializer(many=True, read_only=True)
url = serializers.SerializerMethodField(method_name='get_url', read_only=True)
url = serializers.SerializerMethodField(method_name='get_url',
read_only=True)

# Write only fields for posting new images.
file = serializers.FileField(write_only=True, required=True)
# Comma separated tag string "tag_a,tag_b" is automatically parsed to list of tag models.
tag_string = serializers.CharField(write_only=True, allow_blank=True, required=False)
tag_string = serializers.CharField(write_only=True,
allow_blank=True,
required=False)

class Meta:
model = Image
Expand All @@ -67,7 +71,9 @@ def create(self, validated_data: dict) -> Event:
file = validated_data.pop('file')
if 'tag_string' in validated_data:
tag_names = validated_data.pop('tag_string').split(',')
tags = [Tag.objects.get_or_create(name=name)[0] for name in tag_names]
tags = [
Tag.objects.get_or_create(name=name)[0] for name in tag_names
]
else:
tags = []
image = Image.objects.create(
Expand All @@ -93,7 +99,10 @@ class BilligPriceGroupSerializer(serializers.ModelSerializer):

class Meta:
model = BilligPriceGroup
fields = ['id', 'name', 'can_be_put_on_card', 'membership_needed', 'netsale', 'price']
fields = [
'id', 'name', 'can_be_put_on_card', 'membership_needed', 'netsale',
'price'
]


class BilligTicketGroupSerializer(serializers.ModelSerializer):
Expand Down Expand Up @@ -140,7 +149,8 @@ class EventListSerializer(serializers.ListSerializer):
Speedup fetching of billig events for lists serialization
"""

def to_representation(self, events: list[Event] | QuerySet[Event]) -> list[str]:
def to_representation(self,
events: list[Event] | QuerySet[Event]) -> list[str]:
# Prefetch related/billig for speed
if hasattr(events, 'prefetch_related'):
events = events.prefetch_related('custom_tickets')
Expand Down Expand Up @@ -178,7 +188,8 @@ def create(self, validated_data: dict) -> Event:
and sets it in the new event. Read/write only fields enable
us to use the same serializer for both reading and writing.
"""
validated_data['image'] = Image.objects.get(pk=validated_data['image_id'])
validated_data['image'] = Image.objects.get(
pk=validated_data['image_id'])
event = Event(**validated_data)
event.save()
return event
Expand Down Expand Up @@ -219,8 +230,7 @@ class LoginSerializer(serializers.Serializer):
# This will be used when the DRF browsable API is enabled.
style={'input_type': 'password'},
trim_whitespace=False,
write_only=True
)
write_only=True)

def validate(self, attrs: dict) -> dict:
# Inherited function.
Expand All @@ -230,7 +240,9 @@ def validate(self, attrs: dict) -> dict:

if username and password:
# Try to authenticate the user using Django auth framework.
user = authenticate(request=self.context.get('request'), username=username, password=password)
user = authenticate(request=self.context.get('request'),
username=username,
password=password)
if not user:
# If we don't have a regular user, raise a ValidationError.
msg = 'Access denied: wrong username or password.'
Expand All @@ -256,29 +268,40 @@ class RegisterSerializer(serializers.Serializer):
"""
username = serializers.CharField(label='Username', write_only=True)
email = serializers.EmailField(label='Email', write_only=True)
phone_number = SerializerPhoneNumberField(label='Phone Number', write_only=True)
phone_number = serializers.RegexField(
label='Phonenumber',
regex=r'^[\+]?[(]?[0-9]{3}[)]?[-\s\.]?[0-9]{3}[-\s\.]?[0-9]{4,6}$',
write_only=True)
firstname = serializers.CharField(label='First name', write_only=True)
lastname = serializers.CharField(label='Last name', write_only=True)
password = serializers.CharField(
label='Password',
# This will be used when the DRF browsable API is enabled.
style={'input_type': 'password'},
trim_whitespace=False,
write_only=True
)
write_only=True)

def validate(self, attrs: dict) -> dict:
# Inherited function.
# Take username and password from request.
username = attrs.get('username')
email = attrs.get('email')
phone_number = attrs.get('phone_number')
firstname = attrs.get('firstname')
lastname = attrs.get('lastname')
password = attrs.get('password')

if username and password:
# Try to authenticate the user using Django auth framework.
user = User.objects.create_user(first_name=firstname, last_name=lastname, username=username, password=password)
user = authenticate(request=self.context.get('request'), username=username, password=password)
user = User.objects.create_user(first_name=firstname,
last_name=lastname,
username=username,
email=email,
phone_number=phone_number,
password=password)
user = authenticate(request=self.context.get('request'),
username=username,
password=password)
else:
msg = 'Both "username" and "password" are required.'
raise serializers.ValidationError(msg, code='authorization')
Expand Down Expand Up @@ -312,9 +335,12 @@ class Meta:
class UserSerializer(serializers.ModelSerializer):
groups = GroupSerializer(many=True, read_only=True)
profile = ProfileSerializer(many=False, read_only=True)
permissions = serializers.SerializerMethodField(method_name='get_permissions', read_only=True)
object_permissions = serializers.SerializerMethodField(method_name='get_object_permissions', read_only=True)
user_preference = serializers.SerializerMethodField(method_name='get_user_preference', read_only=True)
permissions = serializers.SerializerMethodField(
method_name='get_permissions', read_only=True)
object_permissions = serializers.SerializerMethodField(
method_name='get_object_permissions', read_only=True)
user_preference = serializers.SerializerMethodField(
method_name='get_user_preference', read_only=True)

class Meta:
model = User
Expand All @@ -327,26 +353,32 @@ def get_permissions(self, user: User) -> list[str]:
def _permission_to_str(permission: Permission) -> str:
return f'{permission.content_type.app_label}.{permission.codename}'

def _obj_permission_to_obj(self, obj_perm: UserObjectPermission | GroupObjectPermission) -> dict[str, str]:
def _obj_permission_to_obj(
self, obj_perm: UserObjectPermission | GroupObjectPermission
) -> dict[str, str]:
perm_obj = {
'obj_pk': obj_perm.object_pk,
'permission': self._permission_to_str(permission=obj_perm.permission),
'permission':
self._permission_to_str(permission=obj_perm.permission),
}
return perm_obj

def get_object_permissions(self, user: User) -> list[dict[str, str]]:
# Collect user-level and group-level object permissions.
user_object_perms_qs = UserObjectPermission.objects.filter(user=user)
group_object_perms_qs = GroupObjectPermission.objects.filter(group__in=user.groups.all())
group_object_perms_qs = GroupObjectPermission.objects.filter(
group__in=user.groups.all())

perm_objs = []
for obj_perm in itertools.chain(user_object_perms_qs, group_object_perms_qs):
for obj_perm in itertools.chain(user_object_perms_qs,
group_object_perms_qs):
perm_objs.append(self._obj_permission_to_obj(obj_perm=obj_perm))

return perm_objs

def get_user_preference(self, user: User) -> dict:
user_preference, _created = UserPreference.objects.get_or_create(user=user)
user_preference, _created = UserPreference.objects.get_or_create(
user=user)
return UserPreferenceSerializer(user_preference, many=False).data


Expand Down Expand Up @@ -419,7 +451,8 @@ class Meta:

class SaksdokumentSerializer(serializers.ModelSerializer):
# Read only url file path used in frontend
url = serializers.SerializerMethodField(method_name='get_url', read_only=True)
url = serializers.SerializerMethodField(method_name='get_url',
read_only=True)
# Write only field for posting new document
file = serializers.FileField(write_only=True, required=False)

Expand Down
79 changes: 58 additions & 21 deletions backend/samfundet/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -144,7 +144,8 @@ class EventPerDayView(APIView):

def get(self, request: Request) -> Response:
# Fetch and serialize events
events = Event.objects.filter(start_dt__gt=timezone.now()).order_by('start_dt')
events = Event.objects.filter(
start_dt__gt=timezone.now()).order_by('start_dt')
serialized = EventSerializer(events, many=True).data

# Organize in date dictionary
Expand All @@ -162,7 +163,8 @@ class EventsUpcomingView(APIView):

def get(self, request: Request) -> Response:
events = event_query(request.query_params)
events = events.filter(start_dt__gt=timezone.now()).order_by('start_dt')
events = events.filter(
start_dt__gt=timezone.now()).order_by('start_dt')
return Response(data=EventSerializer(events, many=True).data)


Expand Down Expand Up @@ -287,7 +289,8 @@ class LoginView(APIView):
permission_classes = [AllowAny]

def post(self, request: Request) -> Response:
serializer = LoginSerializer(data=self.request.data, context={'request': self.request})
serializer = LoginSerializer(data=self.request.data,
context={'request': self.request})
serializer.is_valid(raise_exception=True)
user = serializer.validated_data['user']
login(request=request, user=user)
Expand Down Expand Up @@ -319,7 +322,9 @@ class RegisterView(APIView):
permission_classes = [AllowAny]

def post(self, request: Request) -> Response:
serializer = RegisterSerializer(data=self.request.data, context={'request': self.request})
serializer = RegisterSerializer(data=self.request.data,
context={'request': self.request})
print(self.request.data)
serializer.is_valid(raise_exception=True)
user = serializer.validated_data['user']
login(request=request, user=user)
Expand Down Expand Up @@ -384,48 +389,70 @@ def post(self, request: Request) -> Response:
group_name = request.data.get('group_name')

if not username or not group_name:
return Response({'error': 'Username and group_name fields are required.'}, status=status.HTTP_400_BAD_REQUEST)
return Response(
{'error': 'Username and group_name fields are required.'},
status=status.HTTP_400_BAD_REQUEST)

try:
user = User.objects.get(username=username)
except User.DoesNotExist:
return Response({'error': 'User not found.'}, status=status.HTTP_404_NOT_FOUND)
return Response({'error': 'User not found.'},
status=status.HTTP_404_NOT_FOUND)

try:
group = Group.objects.get(name=group_name)
except Group.DoesNotExist:
return Response({'error': 'Group not found.'}, status=status.HTTP_404_NOT_FOUND)
return Response({'error': 'Group not found.'},
status=status.HTTP_404_NOT_FOUND)

if request.user.has_perm('auth.change_group', group):
user.groups.add(group)
else:
return Response({'error': 'You do not have permission to add users to this group.'}, status=status.HTTP_403_FORBIDDEN)
return Response(
{
'error':
'You do not have permission to add users to this group.'
},
status=status.HTTP_403_FORBIDDEN)

return Response({'message': f"User '{username}' added to group '{group_name}'."}, status=status.HTTP_200_OK)
return Response(
{'message': f"User '{username}' added to group '{group_name}'."},
status=status.HTTP_200_OK)

def delete(self, request: Request) -> Response:
username = request.data.get('username')
group_name = request.data.get('group_name')

if not username or not group_name:
return Response({'error': 'Username and group_name fields are required.'}, status=status.HTTP_400_BAD_REQUEST)
return Response(
{'error': 'Username and group_name fields are required.'},
status=status.HTTP_400_BAD_REQUEST)

try:
user = User.objects.get(username=username)
except User.DoesNotExist:
return Response({'error': 'User not found.'}, status=status.HTTP_404_NOT_FOUND)
return Response({'error': 'User not found.'},
status=status.HTTP_404_NOT_FOUND)

try:
group = Group.objects.get(name=group_name)
except Group.DoesNotExist:
return Response({'error': 'Group not found.'}, status=status.HTTP_404_NOT_FOUND)
return Response({'error': 'Group not found.'},
status=status.HTTP_404_NOT_FOUND)

if request.user.has_perm('auth.change_group', group):
user.groups.remove(group)
else:
return Response({'error': 'You do not have permission to remove users from this group.'}, status=status.HTTP_403_FORBIDDEN)
return Response(
{
'error':
'You do not have permission to remove users from this group.'
},
status=status.HTTP_403_FORBIDDEN)

return Response({'message': f"User '{username}' removed from '{group_name}'."}, status=status.HTTP_200_OK)
return Response(
{'message': f"User '{username}' removed from '{group_name}'."},
status=status.HTTP_200_OK)


# =============================== #
Expand Down Expand Up @@ -476,7 +503,8 @@ def list(self, request: Request) -> Response:
recruitment_id = request.query_params.get('recruitment')

if not recruitment_id:
return Response({'error': 'A recruitment parameter is required'}, status=status.HTTP_400_BAD_REQUEST)
return Response({'error': 'A recruitment parameter is required'},
status=status.HTTP_400_BAD_REQUEST)

recruitment = get_object_or_404(Recruitment, id=recruitment_id)

Expand All @@ -486,7 +514,9 @@ def list(self, request: Request) -> Response:
)

# check permissions for each admission
admissions = get_objects_for_user(user=request.user, perms=['view_recruitmentadmission'], klass=admissions)
admissions = get_objects_for_user(user=request.user,
perms=['view_recruitmentadmission'],
klass=admissions)

serializer = self.get_serializer(admissions, many=True)
return Response(serializer.data)
Expand All @@ -506,21 +536,26 @@ def list(self, request: Request) -> Response:
recruitment_id = request.query_params.get('recruitment')

if not gang_id:
return Response({'error': 'A gang parameter is required'}, status=status.HTTP_400_BAD_REQUEST)
return Response({'error': 'A gang parameter is required'},
status=status.HTTP_400_BAD_REQUEST)

if not recruitment_id:
return Response({'error': 'A recruitment parameter is required'}, status=status.HTTP_400_BAD_REQUEST)
return Response({'error': 'A recruitment parameter is required'},
status=status.HTTP_400_BAD_REQUEST)

gang = get_object_or_404(Gang, id=gang_id)
recruitment = get_object_or_404(Recruitment, id=recruitment_id)

admissions = RecruitmentAdmission.objects.filter(
recruitment_position__gang=gang,
recruitment=recruitment # only include admissions related to the specified recruitment
recruitment=
recruitment # only include admissions related to the specified recruitment
)

# check permissions for each admission
admissions = get_objects_for_user(user=request.user, perms=['view_recruitmentadmission'], klass=admissions)
admissions = get_objects_for_user(user=request.user,
perms=['view_recruitmentadmission'],
klass=admissions)

serializer = self.get_serializer(admissions, many=True)
return Response(serializer.data)
Expand All @@ -534,4 +569,6 @@ def get_queryset(self) -> Response:
"""
Returns all active recruitment positions.
"""
return RecruitmentPosition.objects.filter(recruitment__visible_from__lte=timezone.now(), recruitment__actual_application_deadline__gte=timezone.now())
return RecruitmentPosition.objects.filter(
recruitment__visible_from__lte=timezone.now(),
recruitment__actual_application_deadline__gte=timezone.now())
Loading

0 comments on commit 9090bc7

Please sign in to comment.