Coverage for website/members/api/v2/views.py: 78.57%

40 statements  

« prev     ^ index     » next       coverage.py v7.6.7, created at 2025-08-14 10:31 +0000

1"""API views of the activemembers app.""" 

2 

3from django.db.models import Prefetch, Q 

4from django.shortcuts import get_object_or_404 

5from django.utils import timezone 

6 

7from oauth2_provider.contrib.rest_framework import IsAuthenticatedOrTokenHasScope 

8from rest_framework import filters as framework_filters 

9from rest_framework.generics import ListAPIView, RetrieveAPIView, UpdateAPIView 

10 

11from members.api.v2 import filters 

12from members.api.v2.permissions import HasActiveMembership 

13from members.api.v2.serializers.member import ( 

14 MemberCurrentSerializer, 

15 MemberListSerializer, 

16 MemberSerializer, 

17) 

18from members.models import Member, Membership 

19from thaliawebsite.api.openapi import OAuthAutoSchema 

20from thaliawebsite.api.v2.permissions import IsAuthenticatedOrTokenHasScopeForMethod 

21from utils.media.services import fetch_thumbnails 

22 

23 

24class MemberListView(ListAPIView): 

25 """Returns an overview of all members.""" 

26 

27 serializer_class = MemberListSerializer 

28 

29 def get_queryset(self): 

30 today = timezone.now().date() 

31 return ( 

32 Member.objects.all() 

33 .select_related("profile") 

34 .prefetch_related( 

35 "membership_set", 

36 Prefetch( 

37 "membership_set", 

38 queryset=Membership.objects.filter( 

39 Q(until__isnull=True) | Q(until__gt=today), since__lte=today 

40 ).order_by("-since")[:1], 

41 to_attr="_current_membership", 

42 ), 

43 ) 

44 ) 

45 

46 def get_serializer(self, *args, **kwargs): 

47 if len(args) > 0: 

48 members = args[0] 

49 fetch_thumbnails([member.profile.photo for member in members]) 

50 return super().get_serializer(*args, **kwargs) 

51 

52 permission_classes = [IsAuthenticatedOrTokenHasScope, HasActiveMembership] 

53 required_scopes = ["members:read"] 

54 filter_backends = ( 

55 framework_filters.OrderingFilter, 

56 framework_filters.SearchFilter, 

57 filters.MembershipTypeFilter, 

58 filters.StartingYearFilter, 

59 filters.FormerMemberFilter, 

60 ) 

61 ordering_fields = ("first_name", "last_name", "username") 

62 search_fields = ( 

63 "profile__nickname", 

64 "profile__starting_year", 

65 "first_name", 

66 "last_name", 

67 "username", 

68 ) 

69 

70 

71class MemberDetailView(RetrieveAPIView): 

72 """Returns details of a member.""" 

73 

74 serializer_class = MemberSerializer 

75 queryset = Member.objects.all().prefetch_related( 

76 "membergroupmembership_set", "mentorship_set" 

77 ) 

78 permission_classes = [ 

79 IsAuthenticatedOrTokenHasScope, 

80 HasActiveMembership, 

81 ] 

82 required_scopes = ["members:read"] 

83 

84 

85class MemberCurrentView(MemberDetailView, UpdateAPIView): 

86 """Returns details of the authenticated member.""" 

87 

88 serializer_class = MemberCurrentSerializer 

89 schema = OAuthAutoSchema(operation_id_base="CurrentMember") 

90 permission_classes = [ 

91 IsAuthenticatedOrTokenHasScopeForMethod, 

92 ] 

93 required_scopes_per_method = { 

94 "GET": ["profile:read"], 

95 "PATCH": ["profile:write"], 

96 "PUT": ["profile:write"], 

97 } 

98 

99 def get_object(self): 

100 return get_object_or_404(self.get_queryset(), pk=self.request.user.pk)