summaryrefslogtreecommitdiff
path: root/main/models.py
diff options
context:
space:
mode:
Diffstat (limited to 'main/models.py')
-rw-r--r--main/models.py118
1 files changed, 57 insertions, 61 deletions
diff --git a/main/models.py b/main/models.py
index b5cd8638..9156fb51 100644
--- a/main/models.py
+++ b/main/models.py
@@ -1,52 +1,17 @@
from django.db import models
-from django.core.validators import RegexValidator
+from django.db.models.signals import pre_save
from django.contrib.auth.models import User
from django.contrib.sites.models import Site
from django.forms import ValidationError
-from main.utils import cache_function, make_choice
+from .fields import PositiveBigIntegerField, PGPKeyField
+from .utils import cache_function, make_choice, set_created_field
from packages.models import PackageRelation
-from packages.models import Signoff as PackageSignoff
from datetime import datetime
from itertools import groupby
import pytz
-class PositiveBigIntegerField(models.BigIntegerField):
- _south_introspects = True
-
- def get_internal_type(self):
- return "BigIntegerField"
-
- def formfield(self, **kwargs):
- defaults = {'min_value': 0}
- defaults.update(kwargs)
- return super(PositiveBigIntegerField, self).formfield(**defaults)
-
-class PGPKeyField(models.CharField):
- _south_introspects = True
-
- def to_python(self, value):
- if value == '':
- return None
- value = super(PGPKeyField, self).to_python(value)
- # remove all spaces
- value = value.replace(' ', '')
- # prune prefixes, either 0x or 2048R/ type
- if value.startswith('0x'):
- value = value[2:]
- value = value.split('/')[-1]
- return value
-
- def formfield(self, **kwargs):
- # override so we don't set max_length form field attribute
- return models.Field.formfield(self, **kwargs)
-
-def validate_pgp_key_length(value):
- if len(value) not in (8, 16, 40):
- raise ValidationError(
- u'Ensure this value has 8, 16, or 40 characters (it has %d).' % len(value),
- 'pgp_key_value')
class UserProfile(models.Model):
notify = models.BooleanField(
@@ -66,10 +31,8 @@ class UserProfile(models.Model):
help_text="Required field")
other_contact = models.CharField(max_length=100, null=True, blank=True)
pgp_key = PGPKeyField(max_length=40, null=True, blank=True,
- verbose_name="PGP key", validators=[RegexValidator(r'^[0-9A-F]+$',
- "Ensure this value consists of only hex characters.", 'hex_char'),
- validate_pgp_key_length],
- help_text="PGP Key ID or fingerprint (8, 16, or 40 hex digits)")
+ verbose_name="PGP key fingerprint",
+ help_text="consists of 40 hex digits; use `gpg --fingerprint`")
website = models.CharField(max_length=200, null=True, blank=True)
yob = models.IntegerField("Year of birth", null=True, blank=True)
location = models.CharField(max_length=50, null=True, blank=True)
@@ -82,12 +45,26 @@ class UserProfile(models.Model):
help_text="Ideally 125px by 125px")
user = models.OneToOneField(User, related_name='userprofile')
allowed_repos = models.ManyToManyField('Repo', blank=True)
+ latin_name = models.CharField(max_length=255, null=True, blank=True,
+ help_text="Latin-form name; used only for non-Latin full names")
class Meta:
db_table = 'user_profiles'
verbose_name = 'Additional Profile Data'
verbose_name_plural = 'Additional Profile Data'
+ def get_absolute_url(self):
+ # TODO: this is disgusting. find a way to consolidate this logic with
+ # public.views.userlist among other places, and make some constants or
+ # something so we aren't using copies of string names everywhere.
+ group_names = self.user.groups.values_list('name', flat=True)
+ if "Developers" in group_names:
+ prefix = "developers"
+ elif "Trusted Users" in group_names:
+ prefix = "trustedusers"
+ else:
+ prefix = "fellows"
+ return '/%s/#%s' % (prefix, self.user.username)
class TodolistManager(models.Manager):
def incomplete(self):
@@ -98,6 +75,10 @@ class PackageManager(models.Manager):
"""Used by dev dashboard."""
return self.filter(flag_date__isnull=False)
+ def signed(self):
+ """Used by dev dashboard."""
+ return self.filter(pgp_signature__isnull=False)
+
def normal(self):
return self.select_related('arch', 'repo')
@@ -105,13 +86,15 @@ class Donor(models.Model):
name = models.CharField(max_length=255, unique=True)
visible = models.BooleanField(default=True,
help_text="Should we show this donor on the public page?")
+ created = models.DateTimeField()
def __unicode__(self):
return self.name
class Meta:
db_table = 'donors'
- ordering = ['name']
+ ordering = ('name',)
+ get_latest_by = 'when'
class Arch(models.Model):
name = models.CharField(max_length=255, unique=True)
@@ -158,12 +141,12 @@ class Package(models.Model):
on_delete=models.PROTECT)
arch = models.ForeignKey(Arch, related_name="packages",
on_delete=models.PROTECT)
- pkgname = models.CharField(max_length=255, db_index=True)
+ pkgname = models.CharField(max_length=255)
pkgbase = models.CharField(max_length=255, db_index=True)
pkgver = models.CharField(max_length=255)
pkgrel = models.CharField(max_length=255)
epoch = models.PositiveIntegerField(default=0)
- pkgdesc = models.CharField(max_length=255, null=True)
+ pkgdesc = models.TextField(null=True)
url = models.CharField(max_length=255, null=True)
filename = models.CharField(max_length=255)
compressed_size = PositiveBigIntegerField()
@@ -178,10 +161,12 @@ class Package(models.Model):
flag_date = models.DateTimeField(null=True)
objects = PackageManager()
+
class Meta:
db_table = 'packages'
ordering = ('pkgname',)
get_latest_by = 'last_update'
+ unique_together = (('pkgname', 'repo', 'arch'),)
def __unicode__(self):
return self.pkgname
@@ -204,21 +189,19 @@ class Package(models.Model):
def is_signed(self):
return bool(self.pgp_signature)
- @property
- def maintainers(self):
- return User.objects.filter(
- package_relations__pkgbase=self.pkgbase,
- package_relations__type=PackageRelation.MAINTAINER)
+ _maintainers = None
@property
- def signoffs(self):
- return PackageSignoff.objects.select_related('user').filter(
- pkgbase=self.pkgbase, pkgver=self.pkgver, pkgrel=self.pkgrel,
- epoch=self.epoch, arch=self.arch, repo=self.repo)
+ def maintainers(self):
+ if self._maintainers is None:
+ self._maintainers = User.objects.filter(
+ package_relations__pkgbase=self.pkgbase,
+ package_relations__type=PackageRelation.MAINTAINER)
+ return self._maintainers
- def approved_for_signoff(self):
- count = self.signoffs.filter(revoked__isnull=True).count()
- return count >= PackageSignoff.REQUIRED
+ @maintainers.setter
+ def maintainers(self, maintainers):
+ self._maintainers = maintainers
@cache_function(300)
def applicable_arches(self):
@@ -460,12 +443,17 @@ class Todolist(models.Model):
def __unicode__(self):
return self.name
+ _packages = None
+
@property
def packages(self):
- # select_related() does not use LEFT OUTER JOIN for nullable ForeignKey
- # fields. That is why we need to explicitly list the ones we want.
- return TodolistPkg.objects.select_related(
- 'pkg__repo', 'pkg__arch').filter(list=self).order_by('pkg')
+ if not self._packages:
+ # select_related() does not use LEFT OUTER JOIN for nullable
+ # ForeignKey fields. That is why we need to explicitly list the
+ # ones we want.
+ self._packages = TodolistPkg.objects.select_related(
+ 'pkg__repo', 'pkg__arch').filter(list=self).order_by('pkg')
+ return self._packages
@property
def package_names(self):
@@ -478,10 +466,16 @@ class Todolist(models.Model):
def get_absolute_url(self):
return '/todo/%i/' % self.id
+ def get_full_url(self, proto='https'):
+ '''get a URL suitable for things like email including the domain'''
+ domain = Site.objects.get_current().domain
+ return '%s://%s%s' % (proto, domain, self.get_absolute_url())
+
class TodolistPkg(models.Model):
list = models.ForeignKey(Todolist)
pkg = models.ForeignKey(Package)
complete = models.BooleanField(default=False)
+
class Meta:
db_table = 'todolist_pkgs'
unique_together = (('list','pkg'),)
@@ -499,5 +493,7 @@ post_save.connect(refresh_latest, sender=Package,
dispatch_uid="main.models")
pre_save.connect(set_todolist_fields, sender=Todolist,
dispatch_uid="main.models")
+pre_save.connect(set_created_field, sender=Donor,
+ dispatch_uid="main.models")
# vim: set ts=4 sw=4 et: