Hide keyboard shortcuts

Hot-keys on this page

r m x p   toggle line displays

j k   next/prev highlighted chunk

0   (zero) top of page

1   (one) first highlighted chunk

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

88

89

90

91

92

93

94

95

96

97

98

99

100

101

102

103

104

105

106

107

108

109

110

111

112

113

114

115

116

117

118

119

120

121

122

123

124

125

126

127

128

129

130

131

132

133

134

135

136

137

138

139

140

141

142

143

144

145

146

147

148

149

150

151

152

153

154

155

156

157

158

159

160

161

162

163

164

165

166

167

168

169

170

171

from typing import List 

 

from django.contrib.auth.models import AbstractUser 

from django.core.exceptions import ValidationError 

from django.db import models 

from django.db.models import Q 

from django.utils import timezone 

from django.utils.functional import cached_property 

from rest_framework.response import Response 

 

from backend_app.models.abstract.base import BaseModelSerializer, BaseModel 

from backend_app.models.abstract.base import BaseModelViewSet 

from backend_app.permissions.app_permissions import IsOwner, ReadOnly 

from backend_app.utils import get_user_level, OBJ_MODERATION_PERMISSIONS 

 

 

def validate(user, allow_sharing_personal_info): 

""" 

Custom validation to ensure that moderators, DRI and staff can't be "anonymous" on the plateform 

""" 

if ( 

get_user_level(user) >= OBJ_MODERATION_PERMISSIONS["moderator"] 

and not allow_sharing_personal_info 

): 

raise ValidationError( 

{ 

"allow_sharing_personal_info": "Users that are moderators, members of DRI or staff, must allow sharing of their 'identity', sorry." 

} 

) 

 

 

class User(AbstractUser): 

""" 

If you modify this model, don't forget to modify the command that handles its emptying for RGPD 

""" 

 

@cached_property 

def cached_groups(self) -> List[str]: 

out = ["authenticated_user"] 

for group in self.groups.all(): 

out.append(group.name) 

return out 

 

allow_sharing_personal_info = models.BooleanField(default=True, null=False) 

secondary_email = models.EmailField(null=True, blank=True) 

pseudo = models.CharField( 

blank=False, null=False, max_length=12, default="Anonymous42" 

) 

has_validated_cgu_rgpd = models.BooleanField(default=False, null=False) 

is_banned = models.BooleanField(default=False, null=False) 

 

# Handling of account deletion 

delete_next_time = models.BooleanField( 

default=False, null=False 

) # if true, the account will be deleted at midnight 

is_deleted = models.BooleanField(default=False, null=False) 

 

def save(self, *args, **kwargs): 

""" 

Custom save function to ensure consistency. 

""" 

 

# if the object is not created yet, we can't check to what groups it belongs 

if self.pk is not None: 

validate(self, self.allow_sharing_personal_info) 

return super().save(*args, **kwargs) 

 

 

class UserSerializer(BaseModelSerializer): 

def validate(self, attrs): 

""" 

Also validate at the serializer level to prevent error 500 

""" 

data = super().validate(attrs) 

aspi = data["allow_sharing_personal_info"] 

validate(self.get_user_from_request(), aspi) 

return data 

 

class Meta: 

model = User 

fields = BaseModelSerializer.Meta.fields + ( 

"username", 

"first_name", 

"last_name", 

"email", 

"allow_sharing_personal_info", 

"secondary_email", 

"pseudo", 

"delete_next_time", 

"is_staff", 

) 

read_only_fields = ("username", "first_name", "last_name", "email") 

 

 

class UserViewset(BaseModelViewSet): 

def list(self, request, *args, **kwargs): 

# Prevent the querying of all objects. 

return Response(list()) 

 

def retrieve(self, request, *args, **kwargs): 

# Custom behavior to return only the correct set of attributes depending 

# On allow_sharing_personal_info 

instance = self.get_object() 

serializer = self.get_serializer(instance) 

 

if instance == self.request.user or self.request.user.is_staff: 

out = serializer.data 

else: 

# serializer.data is a property we can't set it again, so we need a little trick for the output 

# First we copy all the values 

out = dict(serializer.data) 

# Then we "correct" them 

for key in [ 

"username", 

"first_name", 

"last_name", 

"email", 

"secondary_email", 

]: 

out[key] = None 

return Response(out) 

 

queryset = User.objects.all() 

permission_classes = (IsOwner | ReadOnly,) 

serializer_class = UserSerializer 

end_point_route = "users" 

 

 

SITE_INFORMATION_VARIANTS = ["info", "success", "warning", "error"] 

 

 

class SiteInformation(BaseModel): 

start = models.DateTimeField(null=False) 

end = models.DateTimeField(null=True) 

message = models.TextField(max_length=500) 

variant = models.CharField( 

max_length=10, 

choices=[(c, c) for c in SITE_INFORMATION_VARIANTS], 

default="info", 

null=False, 

blank=False, 

) 

should_notify = models.BooleanField(default=False, null=False) 

 

 

class SiteInformationSerializer(BaseModelSerializer): 

class Meta: 

model = SiteInformation 

fields = BaseModelSerializer.Meta.fields + ( 

"start", 

"end", 

"message", 

"variant", 

"should_notify", 

) 

 

 

class SiteInformationViewSet(BaseModelViewSet): 

permission_classes = (ReadOnly,) 

serializer_class = SiteInformationSerializer 

end_point_route = "information" 

 

def get_queryset(self): 

get = self.request.GET 

if "now" in get.keys(): 

now = timezone.now() 

return SiteInformation.objects.filter( 

Q(start__lte=now) & (Q(end__isnull=True) | Q(end__gte=now)) 

) 

else: 

return SiteInformation.objects.all()