author | Tero Marttila <terom@fixme.fi> |
Sat, 07 Sep 2013 15:38:24 +0300 | |
changeset 81 | 3a2fdc820c41 |
parent 80 | 3aaac91a6654 |
child 82 | 6442e5c97b48 |
permissions | -rw-r--r-- |
27
ffcffe3024f1
sane defaults for published in urlitems inline form
Tero Marttila <terom@fixme.fi>
parents:
23
diff
changeset
|
1 |
import datetime |
41
4d38296d58a3
use sha1 names for image storage
Tero Marttila <terom@fixme.fi>
parents:
40
diff
changeset
|
2 |
import hashlib |
80
3aaac91a6654
move URLItem lookup to models URLItem.search()
Tero Marttila <terom@fixme.fi>
parents:
78
diff
changeset
|
3 |
import logging |
41
4d38296d58a3
use sha1 names for image storage
Tero Marttila <terom@fixme.fi>
parents:
40
diff
changeset
|
4 |
import os.path |
27
ffcffe3024f1
sane defaults for published in urlitems inline form
Tero Marttila <terom@fixme.fi>
parents:
23
diff
changeset
|
5 |
|
0
1fc671165892
django startproject/app skeleton
Tero Marttila <terom@paivola.fi>
parents:
diff
changeset
|
6 |
from django.db import models |
41
4d38296d58a3
use sha1 names for image storage
Tero Marttila <terom@fixme.fi>
parents:
40
diff
changeset
|
7 |
import django.core.files.storage |
2 | 8 |
from django.core.urlresolvers import reverse |
4
d56f48f6c94b
URL: show qrcode for URL in admin (using google charts)
Tero Marttila <terom@fixme.fi>
parents:
3
diff
changeset
|
9 |
import django.utils.http |
d56f48f6c94b
URL: show qrcode for URL in admin (using google charts)
Tero Marttila <terom@fixme.fi>
parents:
3
diff
changeset
|
10 |
from django.contrib.sites.models import get_current_site |
6
e821a59bf3a7
show published state for url items
Tero Marttila <terom@fixme.fi>
parents:
4
diff
changeset
|
11 |
from django.utils import timezone |
4
d56f48f6c94b
URL: show qrcode for URL in admin (using google charts)
Tero Marttila <terom@fixme.fi>
parents:
3
diff
changeset
|
12 |
|
80
3aaac91a6654
move URLItem lookup to models URLItem.search()
Tero Marttila <terom@fixme.fi>
parents:
78
diff
changeset
|
13 |
log = logging.getLogger('qrurls.models') |
3aaac91a6654
move URLItem lookup to models URLItem.search()
Tero Marttila <terom@fixme.fi>
parents:
78
diff
changeset
|
14 |
|
18
dd08de6f1fe3
user high error correction rate for qrcode
Tero Marttila <terom@fixme.fi>
parents:
17
diff
changeset
|
15 |
QRCODE_API = 'https://chart.googleapis.com/chart?cht=qr&chs={width}x{height}&chl={url}&chld=H' |
41
4d38296d58a3
use sha1 names for image storage
Tero Marttila <terom@fixme.fi>
parents:
40
diff
changeset
|
16 |
IMAGES_MEDIA = 'qrurls-images' |
4d38296d58a3
use sha1 names for image storage
Tero Marttila <terom@fixme.fi>
parents:
40
diff
changeset
|
17 |
|
4d38296d58a3
use sha1 names for image storage
Tero Marttila <terom@fixme.fi>
parents:
40
diff
changeset
|
18 |
class SecretFileSystemStorage (django.core.files.storage.FileSystemStorage) : |
4d38296d58a3
use sha1 names for image storage
Tero Marttila <terom@fixme.fi>
parents:
40
diff
changeset
|
19 |
""" |
4d38296d58a3
use sha1 names for image storage
Tero Marttila <terom@fixme.fi>
parents:
40
diff
changeset
|
20 |
Store files named by a sha1 hash of their contents. |
4d38296d58a3
use sha1 names for image storage
Tero Marttila <terom@fixme.fi>
parents:
40
diff
changeset
|
21 |
""" |
4d38296d58a3
use sha1 names for image storage
Tero Marttila <terom@fixme.fi>
parents:
40
diff
changeset
|
22 |
|
4d38296d58a3
use sha1 names for image storage
Tero Marttila <terom@fixme.fi>
parents:
40
diff
changeset
|
23 |
HASH = hashlib.sha1 |
4d38296d58a3
use sha1 names for image storage
Tero Marttila <terom@fixme.fi>
parents:
40
diff
changeset
|
24 |
|
4d38296d58a3
use sha1 names for image storage
Tero Marttila <terom@fixme.fi>
parents:
40
diff
changeset
|
25 |
def _hash (self, content) : |
4d38296d58a3
use sha1 names for image storage
Tero Marttila <terom@fixme.fi>
parents:
40
diff
changeset
|
26 |
"""Compute hash for given UploadedFile (as a hex string).""" |
4d38296d58a3
use sha1 names for image storage
Tero Marttila <terom@fixme.fi>
parents:
40
diff
changeset
|
27 |
hash = self.HASH() |
4d38296d58a3
use sha1 names for image storage
Tero Marttila <terom@fixme.fi>
parents:
40
diff
changeset
|
28 |
|
4d38296d58a3
use sha1 names for image storage
Tero Marttila <terom@fixme.fi>
parents:
40
diff
changeset
|
29 |
for chunk in content.chunks() : |
4d38296d58a3
use sha1 names for image storage
Tero Marttila <terom@fixme.fi>
parents:
40
diff
changeset
|
30 |
hash.update(chunk) |
4d38296d58a3
use sha1 names for image storage
Tero Marttila <terom@fixme.fi>
parents:
40
diff
changeset
|
31 |
|
4d38296d58a3
use sha1 names for image storage
Tero Marttila <terom@fixme.fi>
parents:
40
diff
changeset
|
32 |
return hash.hexdigest() |
4d38296d58a3
use sha1 names for image storage
Tero Marttila <terom@fixme.fi>
parents:
40
diff
changeset
|
33 |
|
4d38296d58a3
use sha1 names for image storage
Tero Marttila <terom@fixme.fi>
parents:
40
diff
changeset
|
34 |
def save (self, name, content) : |
66 | 35 |
"""Convert uploaded filename to a hash of the contents for storage.""" |
41
4d38296d58a3
use sha1 names for image storage
Tero Marttila <terom@fixme.fi>
parents:
40
diff
changeset
|
36 |
if name is None: |
4d38296d58a3
use sha1 names for image storage
Tero Marttila <terom@fixme.fi>
parents:
40
diff
changeset
|
37 |
name = content.name |
4d38296d58a3
use sha1 names for image storage
Tero Marttila <terom@fixme.fi>
parents:
40
diff
changeset
|
38 |
|
4d38296d58a3
use sha1 names for image storage
Tero Marttila <terom@fixme.fi>
parents:
40
diff
changeset
|
39 |
dirname, filename = os.path.split(name) |
4d38296d58a3
use sha1 names for image storage
Tero Marttila <terom@fixme.fi>
parents:
40
diff
changeset
|
40 |
basename, fileext = os.path.splitext(filename) |
4d38296d58a3
use sha1 names for image storage
Tero Marttila <terom@fixme.fi>
parents:
40
diff
changeset
|
41 |
|
4d38296d58a3
use sha1 names for image storage
Tero Marttila <terom@fixme.fi>
parents:
40
diff
changeset
|
42 |
# hash |
4d38296d58a3
use sha1 names for image storage
Tero Marttila <terom@fixme.fi>
parents:
40
diff
changeset
|
43 |
name = "%s/%s%s" % (dirname, self._hash(content), fileext) |
4d38296d58a3
use sha1 names for image storage
Tero Marttila <terom@fixme.fi>
parents:
40
diff
changeset
|
44 |
|
4d38296d58a3
use sha1 names for image storage
Tero Marttila <terom@fixme.fi>
parents:
40
diff
changeset
|
45 |
return super(SecretFileSystemStorage, self).save(name, content) |
0
1fc671165892
django startproject/app skeleton
Tero Marttila <terom@paivola.fi>
parents:
diff
changeset
|
46 |
|
2 | 47 |
class URL(models.Model): |
48 | 48 |
shorturl = models.SlugField(unique=True, |
49 |
help_text="Changing this will break existing QR-codes!") |
|
47
35a8e63648c8
clarify timezones used for URLItem.published, but no actual explicit per-URLFeed timezone..
Tero Marttila <terom@fixme.fi>
parents:
45
diff
changeset
|
50 |
publishing_time = models.TimeField(default=datetime.time(), |
35a8e63648c8
clarify timezones used for URLItem.published, but no actual explicit per-URLFeed timezone..
Tero Marttila <terom@fixme.fi>
parents:
45
diff
changeset
|
51 |
help_text="Default time to publish new URLItems (in timezone)") |
63
9d1184cdbd16
make URLFeed publishing_offset user-defineable in days
Tero Marttila <terom@fixme.fi>
parents:
56
diff
changeset
|
52 |
publishing_days = models.IntegerField(default=1, |
9d1184cdbd16
make URLFeed publishing_offset user-defineable in days
Tero Marttila <terom@fixme.fi>
parents:
56
diff
changeset
|
53 |
help_text="Default interval for publishing new URLItems") |
51
6f35a169ef01
Make URLImage title optional, use URLFeed title
Tero Marttila <terom@fixme.fi>
parents:
48
diff
changeset
|
54 |
title = models.CharField(max_length=1024, blank=True, null=True, |
6f35a169ef01
Make URLImage title optional, use URLFeed title
Tero Marttila <terom@fixme.fi>
parents:
48
diff
changeset
|
55 |
help_text="Text to display together with images.") |
2 | 56 |
|
3 | 57 |
class Meta: |
12 | 58 |
verbose_name = u"URL Feed" |
59 |
verbose_name_plural = u"URL Feeds" |
|
3 | 60 |
|
4
d56f48f6c94b
URL: show qrcode for URL in admin (using google charts)
Tero Marttila <terom@fixme.fi>
parents:
3
diff
changeset
|
61 |
def qrcode_img (self, size=512) : |
d56f48f6c94b
URL: show qrcode for URL in admin (using google charts)
Tero Marttila <terom@fixme.fi>
parents:
3
diff
changeset
|
62 |
return QRCODE_API.format( |
d56f48f6c94b
URL: show qrcode for URL in admin (using google charts)
Tero Marttila <terom@fixme.fi>
parents:
3
diff
changeset
|
63 |
width=size, height=size, |
d56f48f6c94b
URL: show qrcode for URL in admin (using google charts)
Tero Marttila <terom@fixme.fi>
parents:
3
diff
changeset
|
64 |
url=django.utils.http.urlquote(self.qrcode_url()), |
d56f48f6c94b
URL: show qrcode for URL in admin (using google charts)
Tero Marttila <terom@fixme.fi>
parents:
3
diff
changeset
|
65 |
) |
d56f48f6c94b
URL: show qrcode for URL in admin (using google charts)
Tero Marttila <terom@fixme.fi>
parents:
3
diff
changeset
|
66 |
|
d56f48f6c94b
URL: show qrcode for URL in admin (using google charts)
Tero Marttila <terom@fixme.fi>
parents:
3
diff
changeset
|
67 |
def qrcode_url (self) : |
22
28a72692b749
keep shorturl case sensitive, but warn if not uppercase
Tero Marttila <terom@paivola.fi>
parents:
21
diff
changeset
|
68 |
return 'HTTP://{domain}{url}'.format( |
28a72692b749
keep shorturl case sensitive, but warn if not uppercase
Tero Marttila <terom@paivola.fi>
parents:
21
diff
changeset
|
69 |
domain = get_current_site(None).domain.upper(), |
23 | 70 |
url = self.get_absolute_url(), |
22
28a72692b749
keep shorturl case sensitive, but warn if not uppercase
Tero Marttila <terom@paivola.fi>
parents:
21
diff
changeset
|
71 |
) |
4
d56f48f6c94b
URL: show qrcode for URL in admin (using google charts)
Tero Marttila <terom@fixme.fi>
parents:
3
diff
changeset
|
72 |
|
2 | 73 |
def get_absolute_url (self) : |
74 |
return reverse('shorturl', args=[self.shorturl]) |
|
75 |
||
47
35a8e63648c8
clarify timezones used for URLItem.published, but no actual explicit per-URLFeed timezone..
Tero Marttila <terom@fixme.fi>
parents:
45
diff
changeset
|
76 |
def now (self, now=None) : |
35a8e63648c8
clarify timezones used for URLItem.published, but no actual explicit per-URLFeed timezone..
Tero Marttila <terom@fixme.fi>
parents:
45
diff
changeset
|
77 |
""" |
35a8e63648c8
clarify timezones used for URLItem.published, but no actual explicit per-URLFeed timezone..
Tero Marttila <terom@fixme.fi>
parents:
45
diff
changeset
|
78 |
Return database-compatible concept of "now". |
35a8e63648c8
clarify timezones used for URLItem.published, but no actual explicit per-URLFeed timezone..
Tero Marttila <terom@fixme.fi>
parents:
45
diff
changeset
|
79 |
|
35a8e63648c8
clarify timezones used for URLItem.published, but no actual explicit per-URLFeed timezone..
Tero Marttila <terom@fixme.fi>
parents:
45
diff
changeset
|
80 |
All datetimes are strictly stored and compared as UTC. Any |
35a8e63648c8
clarify timezones used for URLItem.published, but no actual explicit per-URLFeed timezone..
Tero Marttila <terom@fixme.fi>
parents:
45
diff
changeset
|
81 |
timezone-aware logic should happen in the admin. |
35a8e63648c8
clarify timezones used for URLItem.published, but no actual explicit per-URLFeed timezone..
Tero Marttila <terom@fixme.fi>
parents:
45
diff
changeset
|
82 |
""" |
35a8e63648c8
clarify timezones used for URLItem.published, but no actual explicit per-URLFeed timezone..
Tero Marttila <terom@fixme.fi>
parents:
45
diff
changeset
|
83 |
if now : |
35a8e63648c8
clarify timezones used for URLItem.published, but no actual explicit per-URLFeed timezone..
Tero Marttila <terom@fixme.fi>
parents:
45
diff
changeset
|
84 |
return now |
35a8e63648c8
clarify timezones used for URLItem.published, but no actual explicit per-URLFeed timezone..
Tero Marttila <terom@fixme.fi>
parents:
45
diff
changeset
|
85 |
else : |
35a8e63648c8
clarify timezones used for URLItem.published, but no actual explicit per-URLFeed timezone..
Tero Marttila <terom@fixme.fi>
parents:
45
diff
changeset
|
86 |
return timezone.now() |
35a8e63648c8
clarify timezones used for URLItem.published, but no actual explicit per-URLFeed timezone..
Tero Marttila <terom@fixme.fi>
parents:
45
diff
changeset
|
87 |
|
35a8e63648c8
clarify timezones used for URLItem.published, but no actual explicit per-URLFeed timezone..
Tero Marttila <terom@fixme.fi>
parents:
45
diff
changeset
|
88 |
def active_item (self, now=None) : |
7
8202196630d3
better reporting of active/upcoming items
Tero Marttila <terom@fixme.fi>
parents:
6
diff
changeset
|
89 |
"""Currently published URLItem.""" |
47
35a8e63648c8
clarify timezones used for URLItem.published, but no actual explicit per-URLFeed timezone..
Tero Marttila <terom@fixme.fi>
parents:
45
diff
changeset
|
90 |
now = self.now(now) |
6
e821a59bf3a7
show published state for url items
Tero Marttila <terom@fixme.fi>
parents:
4
diff
changeset
|
91 |
|
16
523b3e9eddfa
fixbug modelget item upcoming
Tero Marttila <terom@fixme.fi>
parents:
12
diff
changeset
|
92 |
try : |
69
f7db1b752763
URL model: use self.urlitem_set to let orm caching work for item.shorturl (optimize one unneeded query on view)
Tero Marttila <terom@fixme.fi>
parents:
68
diff
changeset
|
93 |
return self.urlitem_set.filter(published__lt=now).order_by('-published')[0] |
16
523b3e9eddfa
fixbug modelget item upcoming
Tero Marttila <terom@fixme.fi>
parents:
12
diff
changeset
|
94 |
except IndexError : |
523b3e9eddfa
fixbug modelget item upcoming
Tero Marttila <terom@fixme.fi>
parents:
12
diff
changeset
|
95 |
return None |
6
e821a59bf3a7
show published state for url items
Tero Marttila <terom@fixme.fi>
parents:
4
diff
changeset
|
96 |
|
27
ffcffe3024f1
sane defaults for published in urlitems inline form
Tero Marttila <terom@fixme.fi>
parents:
23
diff
changeset
|
97 |
def upcoming_item (self, now=None) : |
47
35a8e63648c8
clarify timezones used for URLItem.published, but no actual explicit per-URLFeed timezone..
Tero Marttila <terom@fixme.fi>
parents:
45
diff
changeset
|
98 |
"""Next-up to-be-published URLItem.""" |
35a8e63648c8
clarify timezones used for URLItem.published, but no actual explicit per-URLFeed timezone..
Tero Marttila <terom@fixme.fi>
parents:
45
diff
changeset
|
99 |
now = self.now(now) |
7
8202196630d3
better reporting of active/upcoming items
Tero Marttila <terom@fixme.fi>
parents:
6
diff
changeset
|
100 |
|
16
523b3e9eddfa
fixbug modelget item upcoming
Tero Marttila <terom@fixme.fi>
parents:
12
diff
changeset
|
101 |
try : |
69
f7db1b752763
URL model: use self.urlitem_set to let orm caching work for item.shorturl (optimize one unneeded query on view)
Tero Marttila <terom@fixme.fi>
parents:
68
diff
changeset
|
102 |
return self.urlitem_set.filter(published__gt=now).order_by('published')[0] |
16
523b3e9eddfa
fixbug modelget item upcoming
Tero Marttila <terom@fixme.fi>
parents:
12
diff
changeset
|
103 |
except IndexError : |
523b3e9eddfa
fixbug modelget item upcoming
Tero Marttila <terom@fixme.fi>
parents:
12
diff
changeset
|
104 |
return None |
7
8202196630d3
better reporting of active/upcoming items
Tero Marttila <terom@fixme.fi>
parents:
6
diff
changeset
|
105 |
|
27
ffcffe3024f1
sane defaults for published in urlitems inline form
Tero Marttila <terom@fixme.fi>
parents:
23
diff
changeset
|
106 |
def last_item (self) : |
ffcffe3024f1
sane defaults for published in urlitems inline form
Tero Marttila <terom@fixme.fi>
parents:
23
diff
changeset
|
107 |
"""The last URLItem available.""" |
ffcffe3024f1
sane defaults for published in urlitems inline form
Tero Marttila <terom@fixme.fi>
parents:
23
diff
changeset
|
108 |
|
ffcffe3024f1
sane defaults for published in urlitems inline form
Tero Marttila <terom@fixme.fi>
parents:
23
diff
changeset
|
109 |
try : |
69
f7db1b752763
URL model: use self.urlitem_set to let orm caching work for item.shorturl (optimize one unneeded query on view)
Tero Marttila <terom@fixme.fi>
parents:
68
diff
changeset
|
110 |
return self.urlitem_set.order_by('-published')[0] |
27
ffcffe3024f1
sane defaults for published in urlitems inline form
Tero Marttila <terom@fixme.fi>
parents:
23
diff
changeset
|
111 |
except IndexError : |
ffcffe3024f1
sane defaults for published in urlitems inline form
Tero Marttila <terom@fixme.fi>
parents:
23
diff
changeset
|
112 |
return None |
ffcffe3024f1
sane defaults for published in urlitems inline form
Tero Marttila <terom@fixme.fi>
parents:
23
diff
changeset
|
113 |
|
56
96e1c616a955
move publishing schedule to URL model, make timetz aware
Tero Marttila <terom@fixme.fi>
parents:
51
diff
changeset
|
114 |
@property |
96e1c616a955
move publishing schedule to URL model, make timetz aware
Tero Marttila <terom@fixme.fi>
parents:
51
diff
changeset
|
115 |
def publishing_timetz (self) : |
96e1c616a955
move publishing schedule to URL model, make timetz aware
Tero Marttila <terom@fixme.fi>
parents:
51
diff
changeset
|
116 |
"""publishing_time, with tzinfo on the correct timezone.""" |
96e1c616a955
move publishing schedule to URL model, make timetz aware
Tero Marttila <terom@fixme.fi>
parents:
51
diff
changeset
|
117 |
return self.publishing_time.replace(tzinfo=timezone.get_current_timezone()) |
96e1c616a955
move publishing schedule to URL model, make timetz aware
Tero Marttila <terom@fixme.fi>
parents:
51
diff
changeset
|
118 |
|
63
9d1184cdbd16
make URLFeed publishing_offset user-defineable in days
Tero Marttila <terom@fixme.fi>
parents:
56
diff
changeset
|
119 |
@property |
9d1184cdbd16
make URLFeed publishing_offset user-defineable in days
Tero Marttila <terom@fixme.fi>
parents:
56
diff
changeset
|
120 |
def publishing_offset (self) : |
9d1184cdbd16
make URLFeed publishing_offset user-defineable in days
Tero Marttila <terom@fixme.fi>
parents:
56
diff
changeset
|
121 |
return datetime.timedelta(days=self.publishing_days) |
56
96e1c616a955
move publishing schedule to URL model, make timetz aware
Tero Marttila <terom@fixme.fi>
parents:
51
diff
changeset
|
122 |
|
96e1c616a955
move publishing schedule to URL model, make timetz aware
Tero Marttila <terom@fixme.fi>
parents:
51
diff
changeset
|
123 |
def publishing_schedule (self) : |
96e1c616a955
move publishing schedule to URL model, make timetz aware
Tero Marttila <terom@fixme.fi>
parents:
51
diff
changeset
|
124 |
"""Calculate initial URLItem.published values for feed.""" |
96e1c616a955
move publishing schedule to URL model, make timetz aware
Tero Marttila <terom@fixme.fi>
parents:
51
diff
changeset
|
125 |
|
96e1c616a955
move publishing schedule to URL model, make timetz aware
Tero Marttila <terom@fixme.fi>
parents:
51
diff
changeset
|
126 |
# following the last item in the queue |
96e1c616a955
move publishing schedule to URL model, make timetz aware
Tero Marttila <terom@fixme.fi>
parents:
51
diff
changeset
|
127 |
item = self.last_item() |
96e1c616a955
move publishing schedule to URL model, make timetz aware
Tero Marttila <terom@fixme.fi>
parents:
51
diff
changeset
|
128 |
|
96e1c616a955
move publishing schedule to URL model, make timetz aware
Tero Marttila <terom@fixme.fi>
parents:
51
diff
changeset
|
129 |
if item and item.published > self.now(): |
96e1c616a955
move publishing schedule to URL model, make timetz aware
Tero Marttila <terom@fixme.fi>
parents:
51
diff
changeset
|
130 |
# starting from the following day |
96e1c616a955
move publishing schedule to URL model, make timetz aware
Tero Marttila <terom@fixme.fi>
parents:
51
diff
changeset
|
131 |
date = item.published.date() + self.publishing_offset |
96e1c616a955
move publishing schedule to URL model, make timetz aware
Tero Marttila <terom@fixme.fi>
parents:
51
diff
changeset
|
132 |
else : |
96e1c616a955
move publishing schedule to URL model, make timetz aware
Tero Marttila <terom@fixme.fi>
parents:
51
diff
changeset
|
133 |
# defaults to today |
96e1c616a955
move publishing schedule to URL model, make timetz aware
Tero Marttila <terom@fixme.fi>
parents:
51
diff
changeset
|
134 |
date = self.now().date() |
96e1c616a955
move publishing schedule to URL model, make timetz aware
Tero Marttila <terom@fixme.fi>
parents:
51
diff
changeset
|
135 |
|
96e1c616a955
move publishing schedule to URL model, make timetz aware
Tero Marttila <terom@fixme.fi>
parents:
51
diff
changeset
|
136 |
return date, self.publishing_timetz, self.publishing_offset |
96e1c616a955
move publishing schedule to URL model, make timetz aware
Tero Marttila <terom@fixme.fi>
parents:
51
diff
changeset
|
137 |
|
96e1c616a955
move publishing schedule to URL model, make timetz aware
Tero Marttila <terom@fixme.fi>
parents:
51
diff
changeset
|
138 |
@classmethod |
96e1c616a955
move publishing schedule to URL model, make timetz aware
Tero Marttila <terom@fixme.fi>
parents:
51
diff
changeset
|
139 |
def apply_publishing_schedule (self, date, time, offset, count) : |
96e1c616a955
move publishing schedule to URL model, make timetz aware
Tero Marttila <terom@fixme.fi>
parents:
51
diff
changeset
|
140 |
"""Yield publishing times off given date/time to offset * count.""" |
96e1c616a955
move publishing schedule to URL model, make timetz aware
Tero Marttila <terom@fixme.fi>
parents:
51
diff
changeset
|
141 |
for index in xrange(0, count) : |
96e1c616a955
move publishing schedule to URL model, make timetz aware
Tero Marttila <terom@fixme.fi>
parents:
51
diff
changeset
|
142 |
yield datetime.datetime.combine(date + offset * index, time) |
96e1c616a955
move publishing schedule to URL model, make timetz aware
Tero Marttila <terom@fixme.fi>
parents:
51
diff
changeset
|
143 |
|
2 | 144 |
def __unicode__ (self) : |
145 |
return self.shorturl |
|
146 |
||
28
d1733c82c278
migration for previous commit
Tero Marttila <terom@fixme.fi>
parents:
27
diff
changeset
|
147 |
class URLImage(models.Model): |
41
4d38296d58a3
use sha1 names for image storage
Tero Marttila <terom@fixme.fi>
parents:
40
diff
changeset
|
148 |
image = models.ImageField(upload_to=IMAGES_MEDIA, storage=SecretFileSystemStorage()) |
66 | 149 |
name = models.CharField(max_length=512, blank=False) |
51
6f35a169ef01
Make URLImage title optional, use URLFeed title
Tero Marttila <terom@fixme.fi>
parents:
48
diff
changeset
|
150 |
title = models.CharField(max_length=1024, blank=True) |
30 | 151 |
uploaded = models.DateTimeField(auto_now_add=True) |
152 |
||
153 |
class Meta: |
|
154 |
verbose_name = u"URL Image" |
|
155 |
verbose_name_plural = u"URL Images" |
|
156 |
ordering = ['uploaded'] |
|
157 |
||
66 | 158 |
def save (self) : |
159 |
# keep real filename before saving with hash |
|
77
40e91c2d4579
fix bug where name would be set to hash when editing a urlimage
Tero Marttila <terom@fixme.fi>
parents:
72
diff
changeset
|
160 |
# but not when updating! |
40e91c2d4579
fix bug where name would be set to hash when editing a urlimage
Tero Marttila <terom@fixme.fi>
parents:
72
diff
changeset
|
161 |
if not self.name: |
40e91c2d4579
fix bug where name would be set to hash when editing a urlimage
Tero Marttila <terom@fixme.fi>
parents:
72
diff
changeset
|
162 |
self.name = self.image.name |
66 | 163 |
|
164 |
super(URLImage, self).save() |
|
165 |
||
32 | 166 |
def get_absolute_url (self) : |
167 |
return self.image.url |
|
168 |
||
30 | 169 |
def __unicode__ (self) : |
66 | 170 |
return "[%s] %s" % (self.uploaded.strftime("%Y-%m-%d"), self.name) |
28
d1733c82c278
migration for previous commit
Tero Marttila <terom@fixme.fi>
parents:
27
diff
changeset
|
171 |
|
2 | 172 |
class URLItem(models.Model): |
173 |
shorturl = models.ForeignKey(URL) |
|
68
182ac4b328ec
add index on URLItem.published
Tero Marttila <terom@fixme.fi>
parents:
66
diff
changeset
|
174 |
published = models.DateTimeField(db_index=True) # UTC |
32 | 175 |
|
176 |
# either-or |
|
177 |
url = models.URLField(blank=True) # populated from image |
|
178 |
image = models.ForeignKey(URLImage, null=True, blank=True) |
|
2 | 179 |
|
3 | 180 |
class Meta: |
181 |
verbose_name = u"URL Item" |
|
182 |
verbose_name_plural = u"URL Items" |
|
183 |
ordering = ['published'] |
|
184 |
||
80
3aaac91a6654
move URLItem lookup to models URLItem.search()
Tero Marttila <terom@fixme.fi>
parents:
78
diff
changeset
|
185 |
@classmethod |
81
3a2fdc820c41
drop separate shorturl_id= lookup key, match shorturl.isdigit()
Tero Marttila <terom@fixme.fi>
parents:
80
diff
changeset
|
186 |
def search (cls, shorturl=None, item_id=None, related=()) : |
80
3aaac91a6654
move URLItem lookup to models URLItem.search()
Tero Marttila <terom@fixme.fi>
parents:
78
diff
changeset
|
187 |
""" |
3aaac91a6654
move URLItem lookup to models URLItem.search()
Tero Marttila <terom@fixme.fi>
parents:
78
diff
changeset
|
188 |
Return the URLItem for a given shorturl, either the given specific one, |
3aaac91a6654
move URLItem lookup to models URLItem.search()
Tero Marttila <terom@fixme.fi>
parents:
78
diff
changeset
|
189 |
or the latest, from the database. |
3aaac91a6654
move URLItem lookup to models URLItem.search()
Tero Marttila <terom@fixme.fi>
parents:
78
diff
changeset
|
190 |
|
3aaac91a6654
move URLItem lookup to models URLItem.search()
Tero Marttila <terom@fixme.fi>
parents:
78
diff
changeset
|
191 |
Raises URLItem.NotFound |
3aaac91a6654
move URLItem lookup to models URLItem.search()
Tero Marttila <terom@fixme.fi>
parents:
78
diff
changeset
|
192 |
""" |
3aaac91a6654
move URLItem lookup to models URLItem.search()
Tero Marttila <terom@fixme.fi>
parents:
78
diff
changeset
|
193 |
# JOIN against shorturl, urlimage |
3aaac91a6654
move URLItem lookup to models URLItem.search()
Tero Marttila <terom@fixme.fi>
parents:
78
diff
changeset
|
194 |
url_item = cls.objects.select_related(*related) |
3aaac91a6654
move URLItem lookup to models URLItem.search()
Tero Marttila <terom@fixme.fi>
parents:
78
diff
changeset
|
195 |
|
81
3a2fdc820c41
drop separate shorturl_id= lookup key, match shorturl.isdigit()
Tero Marttila <terom@fixme.fi>
parents:
80
diff
changeset
|
196 |
if not shorturl: |
3a2fdc820c41
drop separate shorturl_id= lookup key, match shorturl.isdigit()
Tero Marttila <terom@fixme.fi>
parents:
80
diff
changeset
|
197 |
raise cls.DoesNotExist() |
3a2fdc820c41
drop separate shorturl_id= lookup key, match shorturl.isdigit()
Tero Marttila <terom@fixme.fi>
parents:
80
diff
changeset
|
198 |
elif shorturl.isdigit(): |
3a2fdc820c41
drop separate shorturl_id= lookup key, match shorturl.isdigit()
Tero Marttila <terom@fixme.fi>
parents:
80
diff
changeset
|
199 |
shorturl_id = int(shorturl) |
80
3aaac91a6654
move URLItem lookup to models URLItem.search()
Tero Marttila <terom@fixme.fi>
parents:
78
diff
changeset
|
200 |
url_item = url_item.filter(shorturl__id=shorturl_id) |
3aaac91a6654
move URLItem lookup to models URLItem.search()
Tero Marttila <terom@fixme.fi>
parents:
78
diff
changeset
|
201 |
else: |
81
3a2fdc820c41
drop separate shorturl_id= lookup key, match shorturl.isdigit()
Tero Marttila <terom@fixme.fi>
parents:
80
diff
changeset
|
202 |
url_item = url_item.filter(shorturl__shorturl=shorturl) |
80
3aaac91a6654
move URLItem lookup to models URLItem.search()
Tero Marttila <terom@fixme.fi>
parents:
78
diff
changeset
|
203 |
|
3aaac91a6654
move URLItem lookup to models URLItem.search()
Tero Marttila <terom@fixme.fi>
parents:
78
diff
changeset
|
204 |
# match for published items |
3aaac91a6654
move URLItem lookup to models URLItem.search()
Tero Marttila <terom@fixme.fi>
parents:
78
diff
changeset
|
205 |
now = timezone.now() |
3aaac91a6654
move URLItem lookup to models URLItem.search()
Tero Marttila <terom@fixme.fi>
parents:
78
diff
changeset
|
206 |
url_item = url_item.filter(published__lt=now).order_by('-published') |
3aaac91a6654
move URLItem lookup to models URLItem.search()
Tero Marttila <terom@fixme.fi>
parents:
78
diff
changeset
|
207 |
|
3aaac91a6654
move URLItem lookup to models URLItem.search()
Tero Marttila <terom@fixme.fi>
parents:
78
diff
changeset
|
208 |
log.info("Search URLItem @ %s", now) |
3aaac91a6654
move URLItem lookup to models URLItem.search()
Tero Marttila <terom@fixme.fi>
parents:
78
diff
changeset
|
209 |
|
3aaac91a6654
move URLItem lookup to models URLItem.search()
Tero Marttila <terom@fixme.fi>
parents:
78
diff
changeset
|
210 |
if item_id : |
3aaac91a6654
move URLItem lookup to models URLItem.search()
Tero Marttila <terom@fixme.fi>
parents:
78
diff
changeset
|
211 |
# specific, but still the published on |
3aaac91a6654
move URLItem lookup to models URLItem.search()
Tero Marttila <terom@fixme.fi>
parents:
78
diff
changeset
|
212 |
return url_item.get(id=int(item_id)) # raises DoesNotExist |
3aaac91a6654
move URLItem lookup to models URLItem.search()
Tero Marttila <terom@fixme.fi>
parents:
78
diff
changeset
|
213 |
else : |
3aaac91a6654
move URLItem lookup to models URLItem.search()
Tero Marttila <terom@fixme.fi>
parents:
78
diff
changeset
|
214 |
# most recent |
3aaac91a6654
move URLItem lookup to models URLItem.search()
Tero Marttila <terom@fixme.fi>
parents:
78
diff
changeset
|
215 |
try: |
3aaac91a6654
move URLItem lookup to models URLItem.search()
Tero Marttila <terom@fixme.fi>
parents:
78
diff
changeset
|
216 |
return url_item[0] |
3aaac91a6654
move URLItem lookup to models URLItem.search()
Tero Marttila <terom@fixme.fi>
parents:
78
diff
changeset
|
217 |
except IndexError: |
3aaac91a6654
move URLItem lookup to models URLItem.search()
Tero Marttila <terom@fixme.fi>
parents:
78
diff
changeset
|
218 |
raise DoesNotExist() |
3aaac91a6654
move URLItem lookup to models URLItem.search()
Tero Marttila <terom@fixme.fi>
parents:
78
diff
changeset
|
219 |
|
2 | 220 |
def get_absolute_url (self) : |
43
3b1f1a928283
rename qrurls image view to item view
Tero Marttila <terom@fixme.fi>
parents:
41
diff
changeset
|
221 |
if self.url : |
3b1f1a928283
rename qrurls image view to item view
Tero Marttila <terom@fixme.fi>
parents:
41
diff
changeset
|
222 |
return self.url |
44 | 223 |
elif self.shorturl and self.id : |
224 |
return reverse('shorturl_item', kwargs=dict(shorturl=self.shorturl, item_id=self.id)) |
|
35
acc1a366fa7c
move URLItem save() override to just get_absolute_url(), since we won't have an item_id at save() time when adding
Tero Marttila <terom@fixme.fi>
parents:
33
diff
changeset
|
225 |
else : |
44 | 226 |
return None |
47
35a8e63648c8
clarify timezones used for URLItem.published, but no actual explicit per-URLFeed timezone..
Tero Marttila <terom@fixme.fi>
parents:
45
diff
changeset
|
227 |
|
7
8202196630d3
better reporting of active/upcoming items
Tero Marttila <terom@fixme.fi>
parents:
6
diff
changeset
|
228 |
def published_age (self) : |
47
35a8e63648c8
clarify timezones used for URLItem.published, but no actual explicit per-URLFeed timezone..
Tero Marttila <terom@fixme.fi>
parents:
45
diff
changeset
|
229 |
now = self.shorturl.now() # UTC |
6
e821a59bf3a7
show published state for url items
Tero Marttila <terom@fixme.fi>
parents:
4
diff
changeset
|
230 |
|
e821a59bf3a7
show published state for url items
Tero Marttila <terom@fixme.fi>
parents:
4
diff
changeset
|
231 |
if now > self.published: |
e821a59bf3a7
show published state for url items
Tero Marttila <terom@fixme.fi>
parents:
4
diff
changeset
|
232 |
td = now - self.published |
e821a59bf3a7
show published state for url items
Tero Marttila <terom@fixme.fi>
parents:
4
diff
changeset
|
233 |
else : |
e821a59bf3a7
show published state for url items
Tero Marttila <terom@fixme.fi>
parents:
4
diff
changeset
|
234 |
td = self.published - now |
e821a59bf3a7
show published state for url items
Tero Marttila <terom@fixme.fi>
parents:
4
diff
changeset
|
235 |
|
e821a59bf3a7
show published state for url items
Tero Marttila <terom@fixme.fi>
parents:
4
diff
changeset
|
236 |
days, seconds = td.days, td.seconds |
e821a59bf3a7
show published state for url items
Tero Marttila <terom@fixme.fi>
parents:
4
diff
changeset
|
237 |
m, s = divmod(seconds, 60) |
e821a59bf3a7
show published state for url items
Tero Marttila <terom@fixme.fi>
parents:
4
diff
changeset
|
238 |
h, m = divmod(m, 60) |
7
8202196630d3
better reporting of active/upcoming items
Tero Marttila <terom@fixme.fi>
parents:
6
diff
changeset
|
239 |
|
9
ccb1736fba1a
consistent published_state prefix format
Tero Marttila <terom@fixme.fi>
parents:
7
diff
changeset
|
240 |
return (self.published < now), days, "{h}h {m}m {s}s".format(h=h, m=m, s=s) |
7
8202196630d3
better reporting of active/upcoming items
Tero Marttila <terom@fixme.fi>
parents:
6
diff
changeset
|
241 |
|
8202196630d3
better reporting of active/upcoming items
Tero Marttila <terom@fixme.fi>
parents:
6
diff
changeset
|
242 |
def published_state (self) : |
9
ccb1736fba1a
consistent published_state prefix format
Tero Marttila <terom@fixme.fi>
parents:
7
diff
changeset
|
243 |
date = self.published.strftime("%Y-%m-%d") |
ccb1736fba1a
consistent published_state prefix format
Tero Marttila <terom@fixme.fi>
parents:
7
diff
changeset
|
244 |
published, days, age = self.published_age() |
6
e821a59bf3a7
show published state for url items
Tero Marttila <terom@fixme.fi>
parents:
4
diff
changeset
|
245 |
|
9
ccb1736fba1a
consistent published_state prefix format
Tero Marttila <terom@fixme.fi>
parents:
7
diff
changeset
|
246 |
if published and days : |
ccb1736fba1a
consistent published_state prefix format
Tero Marttila <terom@fixme.fi>
parents:
7
diff
changeset
|
247 |
return "[{date}]".format(date=date) |
ccb1736fba1a
consistent published_state prefix format
Tero Marttila <terom@fixme.fi>
parents:
7
diff
changeset
|
248 |
elif published : |
ccb1736fba1a
consistent published_state prefix format
Tero Marttila <terom@fixme.fi>
parents:
7
diff
changeset
|
249 |
return "[{age}]".format(age=age) |
6
e821a59bf3a7
show published state for url items
Tero Marttila <terom@fixme.fi>
parents:
4
diff
changeset
|
250 |
elif days : |
9
ccb1736fba1a
consistent published_state prefix format
Tero Marttila <terom@fixme.fi>
parents:
7
diff
changeset
|
251 |
return "({when})".format(when=date) |
6
e821a59bf3a7
show published state for url items
Tero Marttila <terom@fixme.fi>
parents:
4
diff
changeset
|
252 |
else : |
9
ccb1736fba1a
consistent published_state prefix format
Tero Marttila <terom@fixme.fi>
parents:
7
diff
changeset
|
253 |
return "({age})".format(age=age) |
6
e821a59bf3a7
show published state for url items
Tero Marttila <terom@fixme.fi>
parents:
4
diff
changeset
|
254 |
|
72
ea7a5a5ce7d4
add Last-Modified to urlitem responses (redirect and html)
Tero Marttila <terom@fixme.fi>
parents:
69
diff
changeset
|
255 |
def last_modified (self) : |
ea7a5a5ce7d4
add Last-Modified to urlitem responses (redirect and html)
Tero Marttila <terom@fixme.fi>
parents:
69
diff
changeset
|
256 |
# XXX: this asumes that URLImage is never changed after publishing.. |
ea7a5a5ce7d4
add Last-Modified to urlitem responses (redirect and html)
Tero Marttila <terom@fixme.fi>
parents:
69
diff
changeset
|
257 |
return self.published |
ea7a5a5ce7d4
add Last-Modified to urlitem responses (redirect and html)
Tero Marttila <terom@fixme.fi>
parents:
69
diff
changeset
|
258 |
|
78
7e40b1d2be3e
move urlitem title logic to URLItem.title()
Tero Marttila <terom@fixme.fi>
parents:
77
diff
changeset
|
259 |
def title (self) : |
7e40b1d2be3e
move urlitem title logic to URLItem.title()
Tero Marttila <terom@fixme.fi>
parents:
77
diff
changeset
|
260 |
if self.image and self.image.title.strip() : |
7e40b1d2be3e
move urlitem title logic to URLItem.title()
Tero Marttila <terom@fixme.fi>
parents:
77
diff
changeset
|
261 |
return self.image.title |
7e40b1d2be3e
move urlitem title logic to URLItem.title()
Tero Marttila <terom@fixme.fi>
parents:
77
diff
changeset
|
262 |
else : |
7e40b1d2be3e
move urlitem title logic to URLItem.title()
Tero Marttila <terom@fixme.fi>
parents:
77
diff
changeset
|
263 |
return self.shorturl.title |
7e40b1d2be3e
move urlitem title logic to URLItem.title()
Tero Marttila <terom@fixme.fi>
parents:
77
diff
changeset
|
264 |
|
2 | 265 |
def __unicode__ (self) : |
9
ccb1736fba1a
consistent published_state prefix format
Tero Marttila <terom@fixme.fi>
parents:
7
diff
changeset
|
266 |
return u"{published_state} {url}".format( |
ccb1736fba1a
consistent published_state prefix format
Tero Marttila <terom@fixme.fi>
parents:
7
diff
changeset
|
267 |
published_state=self.published_state(), |
7
8202196630d3
better reporting of active/upcoming items
Tero Marttila <terom@fixme.fi>
parents:
6
diff
changeset
|
268 |
url=self.get_absolute_url(), |
8202196630d3
better reporting of active/upcoming items
Tero Marttila <terom@fixme.fi>
parents:
6
diff
changeset
|
269 |
) |
32 | 270 |