1 | from django.db import models |
---|
2 | |
---|
3 | import datetime |
---|
4 | import os, errno |
---|
5 | |
---|
6 | import settings |
---|
7 | import groups.models |
---|
8 | from util.misc import log_and_ignore_failures, mkdir_p |
---|
9 | import util.previews |
---|
10 | |
---|
11 | class FYSM(models.Model): |
---|
12 | group = models.ForeignKey(groups.models.Group) |
---|
13 | display_name = models.CharField(max_length=50) |
---|
14 | year = models.IntegerField() |
---|
15 | website = models.URLField() |
---|
16 | join_url = models.URLField(help_text="""<p>If you have a specific web page for students interested in joining 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 about three or four sentences what your group does and why incoming freshmen should get involved.") |
---|
19 | logo = models.ImageField(upload_to='fysm/logos', blank=True, ) |
---|
20 | slide = models.ImageField(upload_to='fysm/slides', default="", help_text="Upload a slide 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 | class Meta: |
---|
34 | verbose_name = "FYSM submission" |
---|
35 | |
---|
36 | class FYSMCategory(models.Model): |
---|
37 | name = models.CharField(max_length=25) |
---|
38 | slug = models.SlugField() |
---|
39 | blurb = models.TextField() |
---|
40 | |
---|
41 | def __str__(self, ): |
---|
42 | return self.name |
---|
43 | |
---|
44 | class Meta: |
---|
45 | verbose_name = "FYSM category" |
---|
46 | verbose_name_plural = "FYSM categories" |
---|
47 | ordering = ['name', ] |
---|
48 | |
---|
49 | class FYSMView(models.Model): |
---|
50 | when = models.DateTimeField(default=datetime.datetime.now) |
---|
51 | fysm = models.ForeignKey(FYSM, null=True, blank=True, ) |
---|
52 | year = models.IntegerField(null=True, blank=True, ) |
---|
53 | page = models.CharField(max_length=20, blank=True, ) |
---|
54 | referer = models.URLField(verify_exists=False, null=True, ) |
---|
55 | user_agent = models.CharField(max_length=255) |
---|
56 | source_ip = models.IPAddressField() |
---|
57 | source_user = models.CharField(max_length=30, blank=True, ) |
---|
58 | |
---|
59 | @staticmethod |
---|
60 | @log_and_ignore_failures(logfile=settings.LOGFILE) |
---|
61 | def record_metric(request, fysm=None, year=None, page=None, ): |
---|
62 | record = FYSMView() |
---|
63 | record.fysm = fysm |
---|
64 | record.year = year |
---|
65 | record.page = page |
---|
66 | if 'HTTP_REFERER' in request.META: |
---|
67 | record.referer = request.META['HTTP_REFERER'] |
---|
68 | record.user_agent = request.META['HTTP_USER_AGENT'] |
---|
69 | record.source_ip = request.META['REMOTE_ADDR'] |
---|
70 | record.source_user = request.user.username |
---|
71 | record.save() |
---|
72 | |
---|
73 | class PagePreview(models.Model): |
---|
74 | update_time = models.DateTimeField(default=datetime.datetime.utcfromtimestamp(0)) |
---|
75 | url = models.URLField() |
---|
76 | image = models.ImageField(upload_to='page-previews', blank=True, ) |
---|
77 | |
---|
78 | never_updated = datetime.datetime.utcfromtimestamp(0) # Never updated |
---|
79 | update_interval = datetime.timedelta(hours=23) |
---|
80 | |
---|
81 | def image_filename(self, ): |
---|
82 | return os.path.join(settings.MEDIA_ROOT, self.image.name) |
---|
83 | |
---|
84 | |
---|
85 | @classmethod |
---|
86 | def allocate_page_preview(cls, filename, url, ): |
---|
87 | preview = PagePreview() |
---|
88 | preview.update_time = cls.never_updated |
---|
89 | preview.url = url |
---|
90 | preview.image = 'page-previews/%s.jpg' % (filename, ) |
---|
91 | image_filename = preview.image_filename() |
---|
92 | mkdir_p(os.path.dirname(image_filename)) |
---|
93 | try: |
---|
94 | os.symlink('no-preview.jpg', image_filename) |
---|
95 | except OSError as exc: |
---|
96 | if exc.errno == errno.EEXIST: |
---|
97 | pass |
---|
98 | else: raise |
---|
99 | preview.save() |
---|
100 | return preview |
---|
101 | |
---|
102 | def update_preview(self, ): |
---|
103 | self.update_time = datetime.datetime.now() |
---|
104 | self.save() |
---|
105 | failure = util.previews.generate_webpage_preview(self.url, self.image_filename(), ) |
---|
106 | if failure: |
---|
107 | self.update_time = self.never_updated |
---|
108 | self.save() |
---|
109 | |
---|
110 | @classmethod |
---|
111 | def previews_needing_updates(cls, interval=None, ): |
---|
112 | if interval is None: |
---|
113 | interval = cls.update_interval |
---|
114 | before = datetime.datetime.now() - interval |
---|
115 | return cls.objects.filter(update_time__lte=before) |
---|
116 | |
---|
117 | @classmethod |
---|
118 | def update_outdated_previews(cls, interval=None, ): |
---|
119 | previews = cls.previews_needing_updates(interval) |
---|
120 | now = datetime.datetime.now() |
---|
121 | update_list = [] |
---|
122 | previews_dict = {} |
---|
123 | for preview in previews: |
---|
124 | update_list.append((preview.url, preview.image_filename(), )) |
---|
125 | previews_dict[preview.url] = preview |
---|
126 | preview.update_time = now |
---|
127 | preview.save() |
---|
128 | failures = util.previews.generate_webpage_previews(update_list) |
---|
129 | for url, msg in failures: |
---|
130 | print "%s: %s" % (url, msg, ) |
---|
131 | preview = previews_dict[url] |
---|
132 | preview.update_time = cls.never_updated |
---|
133 | preview.save() |
---|