source: asadb/groups/models.py @ ab453af

space-accessstablestagetest-hooks
Last change on this file since ab453af was ac93a0c, checked in by Alex Dehnert <adehnert@…>, 14 years ago

Save submitter of a group startup form

  • Property mode set to 100644
File size: 12.7 KB
Line 
1from django.db import models
2from django.contrib.auth.models import User
3
4import datetime
5
6import settings
7
8# Create your models here.
9
10class ActiveGroupManager(models.Manager):
11    def get_query_set(self, ):
12        return super(ActiveGroupManager, self).get_query_set().filter(
13            group_status__slug='active',
14        )
15
16class Group(models.Model):
17    name = models.CharField(max_length=100)
18    abbreviation = models.CharField(max_length=10, blank=True)
19    description = models.TextField()
20    activity_category = models.ForeignKey('ActivityCategory', null=True, blank=True, )
21    group_class = models.ForeignKey('GroupClass')
22    group_status = models.ForeignKey('GroupStatus')
23    group_funding = models.ForeignKey('GroupFunding', null=True, blank=True, )
24    website_url = models.URLField()
25    constitution_url = models.CharField(max_length=200, blank=True)
26    meeting_times = models.TextField(blank=True)
27    advisor_name = models.CharField(max_length=100, blank=True)
28    num_undergrads = models.IntegerField(null=True, blank=True, )
29    num_grads = models.IntegerField(null=True, blank=True, )
30    num_community = models.IntegerField(null=True, blank=True, )
31    num_other = models.IntegerField(null=True, blank=True, )
32    group_email = models.EmailField(blank=True, )
33    officer_email = models.EmailField()
34    main_account_id = models.IntegerField(null=True, blank=True, )
35    funding_account_id = models.IntegerField(null=True, blank=True, )
36    athena_locker = models.CharField(max_length=20, blank=True)
37    recognition_date = models.DateField()
38    update_date = models.DateTimeField(editable=False, )
39    updater = models.CharField(max_length=30, editable=False, null=True, ) # match Django username field
40    _updater_set = False
41
42    objects = models.Manager()
43    active_groups = ActiveGroupManager()
44
45    def update_string(self, ):
46        updater = self.updater or "unknown"
47        return "%s by %s" % (self.update_date.strftime(settings.DATETIME_FORMAT_PYTHON), updater, )
48
49    def set_updater(self, who):
50        if hasattr(who, 'username'):
51            self.updater = who.username
52        else:
53            self.updater = who
54        self._updater_set = True
55
56    def save(self, ):
57        if not self._updater_set:
58            self.updater = None
59        self.update_date = datetime.datetime.now()
60        super(Group, self).save()
61
62    def viewable_notes(self, user):
63        return GroupNote.viewable_notes(self, user)
64
65    def officers(self, role=None, person=None, as_of="now",):
66        """Get the set of people holding some office.
67
68        If None is passed for role, person, or as_of, that field will not
69        be constrained. If as_of is "now" (default) the status will be
70        required to be current. If any of the three parameters are set
71        to another value, the corresponding filter will be applied.
72        """
73        office_holders = OfficeHolder.objects.filter(group=self,)
74        if role:
75            if isinstance(role, str):
76                office_holders = office_holders.filter(role__slug=role)
77            else:
78                office_holders = office_holders.filter(role=role)
79        if person:
80            office_holders = office_holders.filter(person=person)
81        if as_of:
82            if as_of == "now": as_of = datetime.datetime.now()
83            office_holders = office_holders.filter(start_time__lte=as_of, end_time__gte=as_of)
84        return office_holders
85
86    def __str__(self, ):
87        return self.name
88
89    class Meta:
90        ordering = ('name', )
91        permissions = (
92            ('view_group_private_info', 'View private group information'),
93            # ability to update normal group info or people
94            # this is weaker than change_group, which is the built-in
95            # permission that controls the admin interface
96            ('admin_group', 'Administer basic group information'),
97            ('view_signatories', 'View signatory information for all groups'),
98        )
99
100
101GROUP_STARTUP_STAGE_SUBMITTED = 10
102GROUP_STARTUP_STAGE_APPROVED = 20
103GROUP_STARTUP_STAGE_REJECTED = -10
104GROUP_STARTUP_STAGE = (
105    (GROUP_STARTUP_STAGE_SUBMITTED,     'submitted'),
106    (GROUP_STARTUP_STAGE_APPROVED,      'approved'),
107    (GROUP_STARTUP_STAGE_REJECTED,      'rejected'),
108)
109
110class GroupStartup(models.Model):
111    group = models.ForeignKey(Group)
112    stage = models.IntegerField(choices=GROUP_STARTUP_STAGE)
113    submitter = models.CharField(max_length=30, editable=False, )
114    create_officer_list = models.BooleanField()
115    create_group_list = models.BooleanField()
116    create_athena_locker = models.BooleanField()
117    president_name = models.CharField(max_length=50)
118    president_kerberos = models.CharField(max_length=8)
119    treasurer_name = models.CharField(max_length=50)
120    treasurer_kerberos = models.CharField(max_length=8)
121
122
123class GroupNote(models.Model):
124    author = models.CharField(max_length=30, ) # match Django username field
125    timestamp = models.DateTimeField(default=datetime.datetime.now, editable=False, )
126    body = models.TextField()
127    acl_read_group = models.BooleanField(default=True, help_text='Can the group read this note')
128    acl_read_offices = models.BooleanField(default=True, help_text='Can "offices" that interact with groups (SAO, CAC, and funding boards) read this note')
129    group = models.ForeignKey(Group)
130
131    def __str__(self, ):
132        return "Note by %s on %s" % (self.author, self.timestamp, )
133
134    @classmethod
135    def viewable_notes(cls, group, user):
136        notes = cls.objects.filter(group=group)
137        if not user.has_perm('groups.view_note_all'):
138            q = models.Q(pk=0)
139            if user.has_perm('groups.view_note_group', group):
140                q |= models.Q(acl_read_group=True)
141            if user.has_perm('groups.view_note_office'):
142                q |= models.Q(acl_read_offices=True)
143            notes = notes.filter(q)
144        return notes
145
146    class Meta:
147        permissions = (
148            ('view_note_group',     'View notes intended for the group to see', ),
149            ('view_note_office',    'View notes intended for "offices" to see', ),
150            ('view_note_all',       'View all notes', ),
151        )
152
153
154class OfficerRole(models.Model):
155    UNLIMITED = 10000
156
157    display_name = models.CharField(max_length=50)
158    slug = models.SlugField()
159    description = models.TextField()
160    max_count = models.IntegerField(default=UNLIMITED, help_text='Maximum number of holders of this role. Use %d for no limit.' % UNLIMITED)
161    require_student = models.BooleanField(default=False)
162    grant_user = models.ForeignKey(User, null=True, blank=True,
163        limit_choices_to={ 'username__endswith': '@SYSTEM'})
164    publicly_visible = models.BooleanField(default=True, help_text='Can everyone see the holders of this office.')
165
166    def max_count_str(self, ):
167        if self.max_count == self.UNLIMITED:
168            return "unlimited"
169        else:
170            return str(self.max_count)
171
172    def __str__(self, ):
173        return self.display_name
174
175    @classmethod
176    def getGrantUsers(cls, roles):
177        ret = set([role.grant_user for role in roles])
178        if None in ret: ret.remove(None)
179        return ret
180
181    @classmethod
182    def retrieve(cls, slug, ):
183        return cls.objects.get(slug=slug)
184
185
186class OfficeHolder_CurrentManager(models.Manager):
187    def get_query_set(self, ):
188        return super(OfficeHolder_CurrentManager, self).get_query_set().filter(
189            start_time__lte=datetime.datetime.now,
190            end_time__gte=datetime.datetime.now,
191        )
192
193class OfficeHolder(models.Model):
194    EXPIRE_OFFSET   = datetime.timedelta(seconds=1)
195    END_NEVER       = datetime.datetime.max
196
197    person = models.CharField(max_length=30)
198    role = models.ForeignKey('OfficerRole')
199    group = models.ForeignKey('Group')
200    start_time = models.DateTimeField(default=datetime.datetime.now)
201    end_time = models.DateTimeField(default=datetime.datetime.max)
202
203    objects = models.Manager()
204    current_holders = OfficeHolder_CurrentManager()
205
206    def expire(self, ):
207        self.end_time = datetime.datetime.now()-self.EXPIRE_OFFSET
208        self.save()
209
210    def __str__(self, ):
211        return "<OfficeHolder: person=%s, role=%s, group=%s, start_time=%s, end_time=%s>" % (
212            self.person, self.role, self.group, self.start_time, self.end_time, )
213
214    def __repr__(self, ):
215        return str(self)
216
217
218class PerGroupAuthz:
219    supports_anonymous_user = True
220    supports_inactive_user = True
221    supports_object_permissions = True
222
223    def authenticate(self, username=None, password=None, ):
224        return None # we don't do authn
225    def get_user(user_id, ):
226        return None # we don't do authn
227
228    def has_perm(self, user_obj, perm, obj=None, ):
229        print "Checking user %s for perm %s on obj %s" % (user_obj, perm, obj)
230        if not user_obj.is_active:
231            return False
232        if not user_obj.is_authenticated():
233            return False
234        if obj is None:
235            return False
236        # Great, we're active, authenticated, and not in a recursive call
237        # Check that we've got a reasonable object
238        if getattr(user_obj, 'is_system', False):
239            return False
240        if isinstance(obj, Group):
241            # Now we can do the real work
242            holders = obj.officers(person=user_obj.username).select_related('role__grant_user')
243            sys_users = OfficerRole.getGrantUsers([holder.role for holder in holders])
244            for sys_user in sys_users:
245                sys_user.is_system = True
246                if sys_user.has_perm(perm):
247                    print "While checking user %s for perm %s on obj %s: implicit user %s has perms" % (user_obj, perm, obj, sys_user, )
248                    return True
249        print "While checking user %s for perm %s on obj %s: no perms found (implicit: %s)" % (user_obj, perm, obj, sys_users)
250        return False
251
252
253
254class ActivityCategory(models.Model):
255    name = models.CharField(max_length=50)
256
257    def __str__(self, ):
258        return self.name
259
260    class Meta:
261        verbose_name_plural = "activity categories"
262
263
264class GroupClass(models.Model):
265    name = models.CharField(max_length=50)
266    slug = models.SlugField(unique=True, )
267    description = models.TextField()
268    gets_publicity = models.BooleanField(help_text="Gets publicity resources such as FYSM or Activities Midway")
269
270    def __str__(self, ):
271        return self.name
272
273    class Meta:
274        verbose_name_plural = "group classes"
275
276
277class GroupStatus(models.Model):
278    name = models.CharField(max_length=50)
279    slug = models.SlugField(unique=True, )
280    description = models.TextField()
281    is_active = models.BooleanField(default=True, help_text="This status represents an active group")
282
283    def __str__(self, ):
284        active = ""
285        if not self.is_active:
286            active = " (inactive)"
287        return "%s%s" % (self.name, active, )
288
289    class Meta:
290        verbose_name_plural= "group statuses"
291
292
293class GroupFunding(models.Model):
294    name = models.CharField(max_length=50)
295    slug = models.SlugField(unique=True, )
296    contact_email = models.EmailField()
297    funding_list = models.CharField(max_length=32, blank=True, help_text="List that groups receiving funding emails should be on. The database will attempt to make sure that ONLY those groups are on it.")
298
299    def __str__(self, ):
300        return "%s (%s)" % (self.name, self.contact_email, )
301
302
303class AthenaMoiraAccount_ActiveManager(models.Manager):
304    def get_query_set(self, ):
305        return super(AthenaMoiraAccount_ActiveManager, self).get_query_set().filter(del_date=None)
306
307class AthenaMoiraAccount(models.Model):
308    username = models.CharField(max_length=8)
309    mit_id = models.CharField(max_length=15)
310    first_name      = models.CharField(max_length=45)
311    last_name       = models.CharField(max_length=45)
312    account_class   = models.CharField(max_length=10)
313    mutable         = models.BooleanField(default=True)
314    add_date        = models.DateField(help_text="Date when this person was added to the dump.", )
315    del_date        = models.DateField(help_text="Date when this person was removed from the dump.", blank=True, null=True, )
316    mod_date        = models.DateField(help_text="Date when this person's record was last changed.", blank=True, null=True, )
317
318    objects = models.Manager()
319    active_accounts = AthenaMoiraAccount_ActiveManager()
320
321    def is_student(self, ):
322        # XXX: Is this... right?
323        return self.account_class == 'G' or self.account_class.isdigit()
324
325    def __str__(self, ):
326        if self.mutable:
327            mutable_str = ""
328        else:
329            mutable_str = " (immutable)"
330        return "<AthenaMoiraAccount: username=%s name='%s, %s' account_class=%s%s>" % (
331            self.username, self.last_name, self.first_name,
332            self.account_class, mutable_str,
333        )
334
335    def __repr__(self, ):
336        return str(self)
337
338    class Meta:
339        verbose_name = "Athena (Moira) account"
Note: See TracBrowser for help on using the repository browser.