source: asadb/forms/models.py @ 549c9e9

space-accessstablestage
Last change on this file since 549c9e9 was 549c9e9, checked in by Alex Dehnert <adehnert@…>, 13 years ago

Describe FYSM images more

Specify preferred filetypes and the logo resolution.

  • Property mode set to 100644
File size: 10.0 KB
Line 
1from django.db import models
2
3import datetime
4import os, errno
5
6import settings
7import groups.models
8from util.misc import log_and_ignore_failures, mkdir_p
9import util.previews
10
11class FYSM(models.Model):
12    group = models.ForeignKey(groups.models.Group, db_index=True, )
13    display_name = models.CharField(max_length=50, help_text="""Form of your name suitable for display (for example, don't end your name with ", MIT")""")
14    year = models.IntegerField(db_index=True, )
15    website = models.URLField()
16    join_url = models.URLField(verbose_name="recruiting URL", help_text="""<p>If you have a specific web page for recruiting new members of your group, you can link to it here. It will be used as the destination for most links about your group (join link on the main listing page and when clicking on the slide, but not the "website" link on the slide page). If you do not have such a page, use your main website's URL.</p>""")
17    contact_email = models.EmailField(help_text="Give an address for students interested in joining the group to email (e.g., an officers list)")
18    description = models.TextField(help_text="Explain, in no more than 400 characters (including spaces), what your group does and why incoming students should get involved.")
19    logo = models.ImageField(upload_to='fysm/logos', blank=True, help_text="Upload a logo (JPG, GIF, or PNG) to display on the main FYSM page as well as the group detail page. This will be scaled to be 100px wide.")
20    slide = models.ImageField(upload_to='fysm/slides', default="", help_text="Upload a slide (JPG, GIF, or PNG) to display on the group detail page. This will be scaled to be at most 600x600 pixels. We recommend making it exactly that size.")
21    tags = models.CharField(max_length=100, blank=True, help_text="Specify some free-form, comma-delimited tags for your group", )
22    categories = models.ManyToManyField('FYSMCategory', blank=True, help_text="Put your group into whichever of our categories seem applicable.", )
23    join_preview = models.ForeignKey('PagePreview', null=True, )
24
25    def save(self, *args, **kwargs):
26        if self.join_preview is None or self.join_url != self.join_preview.url:
27            self.join_preview = PagePreview.allocate_page_preview(
28                filename='fysm/%d/group%d'%(self.year, self.group.pk, ),
29                url=self.join_url,
30            )
31        super(FYSM, self).save(*args, **kwargs) # Call the "real" save() method.
32
33    def __str__(self, ):
34        return "%s (%d)" % (self.display_name, self.year, )
35
36    class Meta:
37        verbose_name = "FYSM submission"
38
39class FYSMCategory(models.Model):
40    name = models.CharField(max_length=25)
41    slug = models.SlugField(unique=True, )
42    blurb = models.TextField()
43
44    def __str__(self, ):
45        return self.name
46
47    class Meta:
48        verbose_name = "FYSM category"
49        verbose_name_plural = "FYSM categories"
50        ordering = ['name', ]
51
52class FYSMView(models.Model):
53    when = models.DateTimeField(default=datetime.datetime.now)
54    fysm = models.ForeignKey(FYSM, null=True, blank=True, )
55    year = models.IntegerField(null=True, blank=True, )
56    page = models.CharField(max_length=20, blank=True, )
57    referer = models.URLField(verify_exists=False, null=True, )
58    user_agent = models.CharField(max_length=255)
59    source_ip = models.IPAddressField()
60    source_user = models.CharField(max_length=30, blank=True, )
61
62    @staticmethod
63    @log_and_ignore_failures(logfile=settings.LOGFILE)
64    def record_metric(request, fysm=None, year=None, page=None, ):
65        record = FYSMView()
66        record.fysm = fysm
67        record.year = year
68        record.page = page
69        if 'HTTP_REFERER' in request.META:
70            record.referer = request.META['HTTP_REFERER']
71        record.user_agent = request.META['HTTP_USER_AGENT']
72        record.source_ip = request.META['REMOTE_ADDR']
73        record.source_user = request.user.username
74        record.save()
75
76class PagePreview(models.Model):
77    update_time = models.DateTimeField(default=datetime.datetime.utcfromtimestamp(0))
78    url = models.URLField()
79    image = models.ImageField(upload_to='page-previews', blank=True, )
80
81    never_updated = datetime.datetime.utcfromtimestamp(0) # Never updated
82    update_interval = datetime.timedelta(hours=23)
83
84    def image_filename(self, ):
85        return os.path.join(settings.MEDIA_ROOT, self.image.name)
86
87
88    @classmethod
89    def allocate_page_preview(cls, filename, url, ):
90        preview = PagePreview()
91        preview.update_time = cls.never_updated
92        preview.url = url
93        preview.image = 'page-previews/%s.jpg' % (filename, )
94        image_filename = preview.image_filename()
95        mkdir_p(os.path.dirname(image_filename))
96        try:
97            os.symlink('no-preview.jpg', image_filename)
98        except OSError as exc:
99            if exc.errno == errno.EEXIST:
100                pass
101            else: raise
102        preview.save()
103        return preview
104
105    def update_preview(self, ):
106        self.update_time = datetime.datetime.now()
107        self.save()
108        failure = util.previews.generate_webpage_preview(self.url, self.image_filename(), )
109        if failure:
110            self.update_time = self.never_updated
111            self.save()
112
113    @classmethod
114    def previews_needing_updates(cls, interval=None, ):
115        if interval is None:
116            interval = cls.update_interval
117        before = datetime.datetime.now() - interval
118        return cls.objects.filter(update_time__lte=before)
119
120    @classmethod
121    def update_outdated_previews(cls, interval=None, ):
122        previews = cls.previews_needing_updates(interval)
123        now = datetime.datetime.now()
124        update_list = []
125        previews_dict = {}
126        for preview in previews:
127            update_list.append((preview.url, preview.image_filename(), ))
128            previews_dict[preview.url] = preview
129            preview.update_time = now
130            preview.save()
131        failures = util.previews.generate_webpage_previews(update_list)
132        for url, msg in failures:
133            print "%s: %s" % (url, msg, )
134            preview = previews_dict[url]
135            preview.update_time = cls.never_updated
136            preview.save()
137
138
139class GroupConfirmationCycle(models.Model):
140    name = models.CharField(max_length=30)
141    slug = models.SlugField(unique=True, )
142    create_date = models.DateTimeField(default=datetime.datetime.now)
143
144    def __unicode__(self, ):
145        return u"GroupConfirmationCycle %d: %s" % (self.id, self.name, )
146
147    @classmethod
148    def latest(cls, ):
149        return cls.objects.order_by('-create_date')[0]
150
151
152class GroupMembershipUpdate(models.Model):
153    update_time = models.DateTimeField(default=datetime.datetime.utcfromtimestamp(0))
154    updater_name = models.CharField(max_length=30)
155    updater_title = models.CharField(max_length=30, help_text="You need not hold any particular title in the group, but we like to know who is completing the form.")
156   
157    group = models.ForeignKey(groups.models.Group, help_text="If your group does not appear in the list above, then please email asa-exec@mit.edu.", db_index=True, )
158    group_email = models.EmailField(help_text="The text of the law will be automatically distributed to your members via this list, in order to comply with the law.")
159    officer_email = models.EmailField()
160
161    membership_definition = models.TextField()
162    num_undergrads = models.IntegerField()
163    num_grads = models.IntegerField()
164    num_alum = models.IntegerField()
165    num_other_affiliate = models.IntegerField()
166    num_other = models.IntegerField()
167
168    membership_list = models.TextField(help_text="Member emails on separate lines (Athena usernames where applicable)")
169
170    email_preface = models.TextField(blank=True, help_text="If you would like, you may add text here that will preface the text of the policies when it is sent out to the group membership list provided above.")
171
172    hazing_statement = "By checking this, I hereby affirm that I have read and understand Chapter 269: Sections 17, 18, and 19 of Massachusetts Law. I furthermore attest that I have provided the appropriate address or will otherwise distribute to group members, pledges, and/or applicants, copies of Massachusetts Law 269: 17, 18, 19 and that our organization, group, or team agrees to comply with the provisions of that law. (See below for text.)"
173    no_hazing = models.BooleanField(help_text=hazing_statement)
174
175    discrimination_statement = "By checking this, I hereby affirm that I have read and understand the MIT Non-Discrimination Policy.  I furthermore attest that our organization, group, or team agrees to not discriminate against individuals on the basis of race, color, sex, sexual orientation, gender identity, religion, disability, age, genetic information, veteran status, ancestry, or national or ethnic origin."
176    no_discrimination = models.BooleanField(help_text=discrimination_statement)
177
178    def __unicode__(self, ):
179        return "GroupMembershipUpdate for %s" % (self.group, )
180
181
182VALID_UNSET         = 0
183VALID_AUTOVALIDATED = 10
184VALID_OVERRIDDEN    = 20    # confirmed by an admin
185VALID_AUTOREJECTED      = -10
186VALID_HANDREJECTED      = -20
187VALID_CHOICES = (
188    (VALID_UNSET,           "unvalidated"),
189    (VALID_AUTOVALIDATED,   "autovalidated"),
190    (VALID_OVERRIDDEN,      "hand-validated"),
191    (VALID_AUTOREJECTED,    "autorejected"),
192    (VALID_HANDREJECTED,    "hand-rejected"),
193)
194
195class PersonMembershipUpdate(models.Model):
196    update_time = models.DateTimeField(default=datetime.datetime.utcfromtimestamp(0))
197    username = models.CharField(max_length=30)
198    cycle = models.ForeignKey(GroupConfirmationCycle, db_index=True, )
199    deleted = models.DateTimeField(default=None, null=True, blank=True, )
200    valid = models.IntegerField(choices=VALID_CHOICES, default=VALID_UNSET)
201    groups = models.ManyToManyField(groups.models.Group, help_text="By selecting a group here, you indicate that you are an active member of the group in question.<br>If your group does not appear in the list above, then please email asa-exec@mit.edu.<br>")
202
203    def __unicode__(self, ):
204        return "PersonMembershipUpdate for %s" % (self.username, )
Note: See TracBrowser for help on using the repository browser.