|
1
|
|
|
from django.db import models |
|
2
|
|
|
|
|
3
|
|
|
from dry_rest_permissions.generics import allow_staff_or_superuser |
|
4
|
|
|
|
|
5
|
|
|
# class GroupManager(models.Manager): |
|
6
|
|
|
# # TODO: Determine whether 'memberships' fields needs to be retrieved every time or not... |
|
7
|
|
|
# def get_queryset(self): |
|
8
|
|
|
# return super(GroupManager, self).get_queryset().prefetch_related('memberships') |
|
9
|
|
|
|
|
10
|
|
|
|
|
11
|
|
|
class Group(models.Model): |
|
12
|
|
|
######################### |
|
13
|
|
|
# Constants and choices # |
|
14
|
|
|
######################### |
|
15
|
|
|
ADMINISTRATOR_RANK = 10 |
|
16
|
|
|
|
|
17
|
|
|
VIS_PUBLIC = 'public' |
|
18
|
|
|
VIS_PRIVATE = 'private' |
|
19
|
|
|
VISIBILITY_CHOICES = ( |
|
20
|
|
|
(VIS_PUBLIC, 'Anyone can see the group'), |
|
21
|
|
|
(VIS_PRIVATE, 'Group is not visible') |
|
22
|
|
|
) |
|
23
|
|
|
|
|
24
|
|
|
TYPE_BASIC = 'basic' |
|
25
|
|
|
TYPE_CURSUS = 'cursus' |
|
26
|
|
|
TYPE_ASSO = 'association' |
|
27
|
|
|
TYPE_PROMO = 'school_promotion' |
|
28
|
|
|
TYPE_SCHOOL = 'school' |
|
29
|
|
|
TYPE_CHOICES = ( |
|
30
|
|
|
(TYPE_BASIC, 'Simple group'), |
|
31
|
|
|
(TYPE_CURSUS, 'Cursus or department'), |
|
32
|
|
|
(TYPE_ASSO, 'Association'), |
|
33
|
|
|
(TYPE_PROMO, 'School promotion'), |
|
34
|
|
|
(TYPE_SCHOOL, 'School') |
|
35
|
|
|
) |
|
36
|
|
|
|
|
37
|
|
|
########## |
|
38
|
|
|
# Fields # |
|
39
|
|
|
########## |
|
40
|
|
|
name = models.CharField(max_length=254) |
|
41
|
|
|
visibility = models.CharField(max_length=64, choices=VISIBILITY_CHOICES, default=VIS_PRIVATE) |
|
42
|
|
|
type = models.CharField(max_length=64, choices=TYPE_CHOICES, default=TYPE_BASIC) |
|
43
|
|
|
|
|
44
|
|
|
# The school responsible of the group in case of admin conflict (can be null for non-school-related groups) |
|
45
|
|
|
resp_school = models.ForeignKey('School', null=True, blank=True, on_delete=models.SET_NULL) |
|
46
|
|
|
|
|
47
|
|
|
# The permission a member has upon joining |
|
48
|
|
|
# A value of -1 means that no one can join the group. |
|
49
|
|
|
# A value of 0 means that anyone can request to join the group |
|
50
|
|
|
default_member_rank = models.SmallIntegerField(default=-1) |
|
51
|
|
|
# Invite new members on the group |
|
52
|
|
|
req_rank_invite = models.SmallIntegerField(default=1) |
|
53
|
|
|
# Remove a member from the group |
|
54
|
|
|
req_rank_kick = models.SmallIntegerField(default=ADMINISTRATOR_RANK) |
|
55
|
|
|
# Upgrade someone rank 0 to rank 1 |
|
56
|
|
|
req_rank_accept_join_requests = models.SmallIntegerField(default=1) |
|
57
|
|
|
# Upgrade other users (up to $yourRank - 1) |
|
58
|
|
|
req_rank_promote = models.SmallIntegerField(default=ADMINISTRATOR_RANK) |
|
59
|
|
|
# Downgrade someone (to rank 1 minimum) |
|
60
|
|
|
req_rank_demote = models.SmallIntegerField(default=ADMINISTRATOR_RANK) |
|
61
|
|
|
# Modify group description |
|
62
|
|
|
req_rank_modify_group_infos = models.SmallIntegerField(default=ADMINISTRATOR_RANK) |
|
63
|
|
|
|
|
64
|
|
|
# Related fields: |
|
65
|
|
|
# - invited_users (model User) |
|
66
|
|
|
# - memberships (model UserGroup) |
|
67
|
|
|
|
|
68
|
|
|
# objects = GroupManager() |
|
69
|
|
|
|
|
70
|
|
|
@property |
|
71
|
|
|
def subgroups(self): |
|
72
|
|
|
return [ga.subgroup for ga in self.subgroups.filter(validated=True).select_related('subgroup')] |
|
73
|
|
|
|
|
74
|
|
|
################# |
|
75
|
|
|
# Model methods # |
|
76
|
|
|
################# |
|
77
|
|
|
def can_anyone_join(self): |
|
78
|
|
|
return self.default_member_rank >= 0 |
|
79
|
|
|
|
|
80
|
|
|
def __str__(self): |
|
81
|
|
|
return "%s (%s)" % (self.name, self.get_type_display()) |
|
82
|
|
|
|
|
83
|
|
|
############### |
|
84
|
|
|
# Permissions # |
|
85
|
|
|
############### |
|
86
|
|
|
|
|
87
|
|
|
# Perms for admin site |
|
88
|
|
|
def has_perm(self, perm, obj=None): |
|
89
|
|
|
return True |
|
90
|
|
|
|
|
91
|
|
|
def has_module_perms(self, app_label): |
|
92
|
|
|
return True |
|
93
|
|
|
|
|
94
|
|
|
# DRY Permissions |
|
95
|
|
|
@staticmethod |
|
96
|
|
|
def has_read_permission(request): |
|
97
|
|
|
""" |
|
98
|
|
|
All groups are visible by default. |
|
99
|
|
|
""" |
|
100
|
|
|
return True |
|
101
|
|
|
|
|
102
|
|
|
def has_object_read_permission(self, request): |
|
103
|
|
|
""" |
|
104
|
|
|
Public groups are visible by everybody. Private groups are only visible by members. |
|
105
|
|
|
""" |
|
106
|
|
|
return self.visibility == Group.VIS_PUBLIC or request.user.is_group_member(self) |
|
107
|
|
|
|
|
108
|
|
|
@staticmethod |
|
109
|
|
|
def has_write_permission(request): |
|
110
|
|
|
return True |
|
111
|
|
|
|
|
112
|
|
|
@staticmethod |
|
113
|
|
|
@allow_staff_or_superuser |
|
114
|
|
|
def has_create_permission(request): |
|
115
|
|
|
""" |
|
116
|
|
|
Everybody can create a private group. For other types, user must be school admin or sigma admin. |
|
117
|
|
|
""" |
|
118
|
|
|
from sigma_core.models.school import School |
|
119
|
|
|
group_type = request.data.get('type', None) |
|
120
|
|
|
if group_type == Group.TYPE_BASIC: |
|
121
|
|
|
return True |
|
122
|
|
|
|
|
123
|
|
|
resp_school = request.data.get('resp_school', None) |
|
124
|
|
|
try: |
|
125
|
|
|
school = School.objects.get(pk=resp_school) |
|
126
|
|
|
except School.DoesNotExist: |
|
127
|
|
|
school = None |
|
128
|
|
|
return school is not None and request.user.has_group_admin_perm(school) |
|
129
|
|
|
|
|
130
|
|
|
@allow_staff_or_superuser |
|
131
|
|
|
def has_object_write_permission(self, request): |
|
132
|
|
|
return request.user.has_group_admin_perm(self) |
|
133
|
|
|
|
|
134
|
|
|
@allow_staff_or_superuser |
|
135
|
|
|
def has_object_update_permission(self, request): |
|
136
|
|
|
""" |
|
137
|
|
|
Only group's admins and Sigma admins can edit a group. |
|
138
|
|
|
""" |
|
139
|
|
|
return request.user.can_modify_group_infos(self) |
|
140
|
|
|
|
|
141
|
|
|
@allow_staff_or_superuser |
|
142
|
|
|
def has_object_invite_permission(self, request): |
|
143
|
|
|
return request.user.can_invite(self) |
|
144
|
|
|
|
|
145
|
|
|
|
|
146
|
|
|
class GroupAcknowledgment(models.Model): |
|
147
|
|
|
subgroup = models.ForeignKey(Group, related_name='group_parents') |
|
148
|
|
|
parent_group = models.ForeignKey(Group, related_name='subgroups') |
|
149
|
|
|
validated = models.BooleanField(default=False) |
|
150
|
|
|
created = models.DateTimeField(auto_now_add=True) |
|
151
|
|
|
updated = models.DateTimeField(auto_now=True) |
|
152
|
|
|
|
|
153
|
|
|
def __str__(self): |
|
154
|
|
|
if self.validated: |
|
155
|
|
|
return "Group %s acknowledged by Group %s" % (self.subgroup.__str__(), self.parent_group.__str__()) |
|
156
|
|
|
else: |
|
157
|
|
|
return "Group %s awaiting for acknowledgment by Group %s since %s" % (self.subgroup.__str__(), self.parent_group.__str__(), self.created.strftime("%Y-%m-%d %H:%M")) |
|
158
|
|
|
|