gremmie@1: """ gremmie@1: Models for the downloads application. gremmie@1: """ gremmie@1: import os gremmie@1: gremmie@1: import datetime gremmie@1: from django.db import models gremmie@1: from django.contrib.auth.models import User gremmie@1: from django.template.defaultfilters import filesizeformat gremmie@1: bgneal@128: from core.markup import site_markup bgneal@124: gremmie@1: gremmie@1: class Category(models.Model): gremmie@1: """Downloads belong to categories.""" gremmie@1: title = models.CharField(max_length=64) bgneal@241: slug = models.SlugField(max_length=64) gremmie@1: description = models.TextField(blank=True) bgneal@192: count = models.IntegerField(default=0, blank=True) gremmie@1: gremmie@1: class Meta: gremmie@1: verbose_name_plural = 'Categories' gremmie@1: ordering = ('title', ) gremmie@1: gremmie@1: def __unicode__(self): gremmie@1: return self.title gremmie@1: gremmie@1: gremmie@1: def download_path(instance, filename): gremmie@1: """ gremmie@1: Creates a path for a download. Uses the current date to avoid filename gremmie@1: clashes. Uses the current microsecond also to make the directory name gremmie@1: harder to guess. gremmie@1: """ gremmie@1: now = datetime.datetime.now() gremmie@1: parts = ['downloads'] bgneal@210: parts.extend([str(p) for p in (now.year, now.month, now.day)]) bgneal@210: parts.append(hex((now.hour * 3600 + now.minute * 60 + now.second) * 1000 + ( bgneal@210: now.microsecond / 1000))[2:]) gremmie@1: parts.append(filename) gremmie@1: return os.path.join(*parts) gremmie@1: gremmie@1: gremmie@1: class PublicDownloadManager(models.Manager): gremmie@1: """The manager for all public downloads.""" bgneal@740: def get_queryset(self): bgneal@740: return super(PublicDownloadManager, self).get_queryset().filter( bgneal@190: is_public=True).select_related() gremmie@1: gremmie@1: bgneal@204: class DownloadBase(models.Model): bgneal@204: """Abstract model to collect common download fields.""" gremmie@1: title = models.CharField(max_length=128) gremmie@1: category = models.ForeignKey(Category) gremmie@1: description = models.TextField() gremmie@1: html = models.TextField(blank=True) gremmie@1: file = models.FileField(upload_to=download_path) gremmie@1: user = models.ForeignKey(User) bgneal@277: date_added = models.DateTimeField(db_index=True) bgneal@1028: ip_address = models.GenericIPAddressField('IP Address') bgneal@277: update_date = models.DateTimeField(db_index=True, blank=True) bgneal@204: bgneal@204: class Meta: bgneal@204: abstract = True bgneal@204: bgneal@204: def size(self): bgneal@661: try: bgneal@661: return filesizeformat(self.file.size) bgneal@661: except OSError: bgneal@661: return '?' bgneal@204: bgneal@1023: def save(self, *args, **kwargs): bgneal@1023: if not self.pk: bgneal@1023: self.date_added = datetime.datetime.now() bgneal@1023: self.update_date = self.date_added bgneal@1023: else: bgneal@1023: self.update_date = datetime.datetime.now() bgneal@1023: bgneal@1023: self.html = kwargs.pop('html', None) bgneal@1023: if not self.html and self.description: bgneal@1023: self.html = site_markup(self.description) bgneal@1023: super(DownloadBase, self).save(*args, **kwargs) bgneal@1023: bgneal@204: bgneal@204: class PendingDownload(DownloadBase): bgneal@204: """This model represents pending downloads created by users. These pending bgneal@204: downloads must be approved by an admin before they turn into "real" bgneal@204: Downloads and are visible on site. bgneal@204: """ bgneal@204: class Meta: bgneal@204: ordering = ('date_added', ) bgneal@204: bgneal@204: def __unicode__(self): bgneal@204: return self.title bgneal@204: bgneal@204: bgneal@204: class Download(DownloadBase): bgneal@204: """Model to represent a download.""" gremmie@1: hits = models.IntegerField(default=0) gremmie@1: average_score = models.FloatField(default=0.0) gremmie@1: total_votes = models.IntegerField(default=0) gremmie@1: is_public = models.BooleanField(default=False, db_index=True) gremmie@1: gremmie@1: # Managers: gremmie@1: objects = models.Manager() gremmie@1: public_objects = PublicDownloadManager() gremmie@1: gremmie@1: def __unicode__(self): gremmie@1: return self.title gremmie@1: bgneal@14: @models.permalink bgneal@14: def get_absolute_url(self): bgneal@23: return ('downloads-details', [str(self.id)]) bgneal@14: gremmie@1: def vote(self, vote_value): gremmie@1: """receives a vote_value and updates internal score accordingly""" gremmie@1: total_score = self.average_score * self.total_votes gremmie@1: total_score += vote_value gremmie@1: self.total_votes += 1 gremmie@1: self.average_score = total_score / self.total_votes gremmie@1: return self.average_score gremmie@1: bgneal@221: def search_title(self): bgneal@221: return self.title bgneal@221: bgneal@221: def search_summary(self): bgneal@221: return self.description bgneal@221: gremmie@1: gremmie@1: class AllowedExtensionManager(models.Manager): gremmie@1: def get_extension_list(self): gremmie@1: return self.values_list('extension', flat=True) gremmie@1: gremmie@1: gremmie@1: class AllowedExtension(models.Model): gremmie@1: """Model to represent the list of allowed file extensions.""" bgneal@206: extension = models.CharField(max_length=8, help_text="e.g. .txt") gremmie@1: gremmie@1: objects = AllowedExtensionManager() gremmie@1: gremmie@1: def __unicode__(self): gremmie@1: return self.extension gremmie@1: gremmie@1: class Meta: gremmie@1: ordering = ('extension', ) gremmie@1: gremmie@1: gremmie@1: class VoteRecord(models.Model): gremmie@1: """Model to record the date that a user voted on a download.""" gremmie@1: download = models.ForeignKey(Download) gremmie@1: user = models.ForeignKey(User) gremmie@1: vote_date = models.DateTimeField(auto_now_add=True) gremmie@1: gremmie@1: def __unicode__(self): bgneal@192: return u"%s voted on '%s' on %s" % ( bgneal@412: self.user.username, bgneal@412: self.download.title, gremmie@1: self.vote_date.strftime('%b %d, %Y %H:%M:%S')) gremmie@1: gremmie@1: class Meta: gremmie@1: ordering = ('-vote_date', )