gremmie@1
|
1 """
|
gremmie@1
|
2 Models for the downloads application.
|
gremmie@1
|
3 """
|
gremmie@1
|
4 import os
|
gremmie@1
|
5
|
gremmie@1
|
6 import datetime
|
bgneal@1035
|
7 from django.contrib.auth.models import User
|
bgneal@1035
|
8 from django.core.urlresolvers import reverse
|
gremmie@1
|
9 from django.db import models
|
gremmie@1
|
10 from django.template.defaultfilters import filesizeformat
|
gremmie@1
|
11
|
bgneal@128
|
12 from core.markup import site_markup
|
bgneal@124
|
13
|
gremmie@1
|
14
|
gremmie@1
|
15 class Category(models.Model):
|
gremmie@1
|
16 """Downloads belong to categories."""
|
gremmie@1
|
17 title = models.CharField(max_length=64)
|
bgneal@241
|
18 slug = models.SlugField(max_length=64)
|
gremmie@1
|
19 description = models.TextField(blank=True)
|
bgneal@192
|
20 count = models.IntegerField(default=0, blank=True)
|
gremmie@1
|
21
|
gremmie@1
|
22 class Meta:
|
gremmie@1
|
23 verbose_name_plural = 'Categories'
|
gremmie@1
|
24 ordering = ('title', )
|
gremmie@1
|
25
|
gremmie@1
|
26 def __unicode__(self):
|
gremmie@1
|
27 return self.title
|
gremmie@1
|
28
|
gremmie@1
|
29
|
gremmie@1
|
30 def download_path(instance, filename):
|
gremmie@1
|
31 """
|
gremmie@1
|
32 Creates a path for a download. Uses the current date to avoid filename
|
gremmie@1
|
33 clashes. Uses the current microsecond also to make the directory name
|
gremmie@1
|
34 harder to guess.
|
gremmie@1
|
35 """
|
gremmie@1
|
36 now = datetime.datetime.now()
|
gremmie@1
|
37 parts = ['downloads']
|
bgneal@210
|
38 parts.extend([str(p) for p in (now.year, now.month, now.day)])
|
bgneal@210
|
39 parts.append(hex((now.hour * 3600 + now.minute * 60 + now.second) * 1000 + (
|
bgneal@210
|
40 now.microsecond / 1000))[2:])
|
gremmie@1
|
41 parts.append(filename)
|
gremmie@1
|
42 return os.path.join(*parts)
|
gremmie@1
|
43
|
gremmie@1
|
44
|
gremmie@1
|
45 class PublicDownloadManager(models.Manager):
|
gremmie@1
|
46 """The manager for all public downloads."""
|
bgneal@740
|
47 def get_queryset(self):
|
bgneal@740
|
48 return super(PublicDownloadManager, self).get_queryset().filter(
|
bgneal@190
|
49 is_public=True).select_related()
|
gremmie@1
|
50
|
gremmie@1
|
51
|
bgneal@204
|
52 class DownloadBase(models.Model):
|
bgneal@204
|
53 """Abstract model to collect common download fields."""
|
gremmie@1
|
54 title = models.CharField(max_length=128)
|
gremmie@1
|
55 category = models.ForeignKey(Category)
|
gremmie@1
|
56 description = models.TextField()
|
gremmie@1
|
57 html = models.TextField(blank=True)
|
gremmie@1
|
58 file = models.FileField(upload_to=download_path)
|
gremmie@1
|
59 user = models.ForeignKey(User)
|
bgneal@277
|
60 date_added = models.DateTimeField(db_index=True)
|
bgneal@1028
|
61 ip_address = models.GenericIPAddressField('IP Address')
|
bgneal@277
|
62 update_date = models.DateTimeField(db_index=True, blank=True)
|
bgneal@204
|
63
|
bgneal@204
|
64 class Meta:
|
bgneal@204
|
65 abstract = True
|
bgneal@204
|
66
|
bgneal@204
|
67 def size(self):
|
bgneal@661
|
68 try:
|
bgneal@661
|
69 return filesizeformat(self.file.size)
|
bgneal@661
|
70 except OSError:
|
bgneal@661
|
71 return '?'
|
bgneal@204
|
72
|
bgneal@1023
|
73 def save(self, *args, **kwargs):
|
bgneal@1023
|
74 if not self.pk:
|
bgneal@1023
|
75 self.date_added = datetime.datetime.now()
|
bgneal@1023
|
76 self.update_date = self.date_added
|
bgneal@1023
|
77 else:
|
bgneal@1023
|
78 self.update_date = datetime.datetime.now()
|
bgneal@1023
|
79
|
bgneal@1023
|
80 self.html = kwargs.pop('html', None)
|
bgneal@1023
|
81 if not self.html and self.description:
|
bgneal@1023
|
82 self.html = site_markup(self.description)
|
bgneal@1023
|
83 super(DownloadBase, self).save(*args, **kwargs)
|
bgneal@1023
|
84
|
bgneal@204
|
85
|
bgneal@204
|
86 class PendingDownload(DownloadBase):
|
bgneal@204
|
87 """This model represents pending downloads created by users. These pending
|
bgneal@204
|
88 downloads must be approved by an admin before they turn into "real"
|
bgneal@204
|
89 Downloads and are visible on site.
|
bgneal@204
|
90 """
|
bgneal@204
|
91 class Meta:
|
bgneal@204
|
92 ordering = ('date_added', )
|
bgneal@204
|
93
|
bgneal@204
|
94 def __unicode__(self):
|
bgneal@204
|
95 return self.title
|
bgneal@204
|
96
|
bgneal@204
|
97
|
bgneal@204
|
98 class Download(DownloadBase):
|
bgneal@204
|
99 """Model to represent a download."""
|
gremmie@1
|
100 hits = models.IntegerField(default=0)
|
gremmie@1
|
101 average_score = models.FloatField(default=0.0)
|
gremmie@1
|
102 total_votes = models.IntegerField(default=0)
|
gremmie@1
|
103 is_public = models.BooleanField(default=False, db_index=True)
|
gremmie@1
|
104
|
gremmie@1
|
105 # Managers:
|
gremmie@1
|
106 objects = models.Manager()
|
gremmie@1
|
107 public_objects = PublicDownloadManager()
|
gremmie@1
|
108
|
gremmie@1
|
109 def __unicode__(self):
|
gremmie@1
|
110 return self.title
|
gremmie@1
|
111
|
bgneal@14
|
112 def get_absolute_url(self):
|
bgneal@1035
|
113 return reverse('downloads-details', args=[str(self.pk)])
|
bgneal@14
|
114
|
gremmie@1
|
115 def vote(self, vote_value):
|
gremmie@1
|
116 """receives a vote_value and updates internal score accordingly"""
|
gremmie@1
|
117 total_score = self.average_score * self.total_votes
|
gremmie@1
|
118 total_score += vote_value
|
gremmie@1
|
119 self.total_votes += 1
|
gremmie@1
|
120 self.average_score = total_score / self.total_votes
|
gremmie@1
|
121 return self.average_score
|
gremmie@1
|
122
|
bgneal@221
|
123 def search_title(self):
|
bgneal@221
|
124 return self.title
|
bgneal@221
|
125
|
bgneal@221
|
126 def search_summary(self):
|
bgneal@221
|
127 return self.description
|
bgneal@221
|
128
|
gremmie@1
|
129
|
gremmie@1
|
130 class AllowedExtensionManager(models.Manager):
|
gremmie@1
|
131 def get_extension_list(self):
|
gremmie@1
|
132 return self.values_list('extension', flat=True)
|
gremmie@1
|
133
|
gremmie@1
|
134
|
gremmie@1
|
135 class AllowedExtension(models.Model):
|
gremmie@1
|
136 """Model to represent the list of allowed file extensions."""
|
bgneal@206
|
137 extension = models.CharField(max_length=8, help_text="e.g. .txt")
|
gremmie@1
|
138
|
gremmie@1
|
139 objects = AllowedExtensionManager()
|
gremmie@1
|
140
|
gremmie@1
|
141 def __unicode__(self):
|
gremmie@1
|
142 return self.extension
|
gremmie@1
|
143
|
gremmie@1
|
144 class Meta:
|
gremmie@1
|
145 ordering = ('extension', )
|
gremmie@1
|
146
|
gremmie@1
|
147
|
gremmie@1
|
148 class VoteRecord(models.Model):
|
gremmie@1
|
149 """Model to record the date that a user voted on a download."""
|
gremmie@1
|
150 download = models.ForeignKey(Download)
|
gremmie@1
|
151 user = models.ForeignKey(User)
|
gremmie@1
|
152 vote_date = models.DateTimeField(auto_now_add=True)
|
gremmie@1
|
153
|
gremmie@1
|
154 def __unicode__(self):
|
bgneal@192
|
155 return u"%s voted on '%s' on %s" % (
|
bgneal@412
|
156 self.user.username,
|
bgneal@412
|
157 self.download.title,
|
gremmie@1
|
158 self.vote_date.strftime('%b %d, %Y %H:%M:%S'))
|
gremmie@1
|
159
|
gremmie@1
|
160 class Meta:
|
gremmie@1
|
161 ordering = ('-vote_date', )
|