X-Git-Url: https://git.ozlabs.org/?p=patchwork;a=blobdiff_plain;f=apps%2Fpatchwork%2Fmodels.py;h=f21d07322c544d3860a3128f65f76a7faa12b880;hp=7653e6c6ae518ebc3280d218b24ac2d26f4b6c2d;hb=41f19b6643b44768dc06561c992c04ed6148477d;hpb=3cc3a114ce469c67ac0a78f74cef786e724bc666 diff --git a/apps/patchwork/models.py b/apps/patchwork/models.py index 7653e6c..f21d073 100644 --- a/apps/patchwork/models.py +++ b/apps/patchwork/models.py @@ -26,7 +26,6 @@ from patchwork.parser import hash_patch import re import datetime, time -import string import random try: @@ -38,17 +37,18 @@ except ImportError: # Python 2.4 compatibility from email.MIMENonMultipart import MIMENonMultipart from email.Encoders import encode_7or8bit + from email.Parser import HeaderParser import email.Utils email.utils = email.Utils class Person(models.Model): email = models.CharField(max_length=255, unique = True) - name = models.CharField(max_length=255, null = True) - user = models.ForeignKey(User, null = True) + name = models.CharField(max_length=255, null = True, blank = True) + user = models.ForeignKey(User, null = True, blank = True) - def __str__(self): + def __unicode__(self): if self.name: - return '%s <%s>' % (self.name, self.email) + return u'%s <%s>' % (self.name, self.email) else: return self.email @@ -65,12 +65,17 @@ class Project(models.Model): listid = models.CharField(max_length=255, unique=True) listemail = models.CharField(max_length=200) - def __str__(self): + def __unicode__(self): return self.name + def is_editable(self, user): + if not user.is_authenticated(): + return False + return self in user.get_profile().maintainer_projects.all() + class UserProfile(models.Model): user = models.ForeignKey(User, unique = True) - primary_project = models.ForeignKey(Project, null = True) + primary_project = models.ForeignKey(Project, null = True, blank = True) maintainer_projects = models.ManyToManyField(Project, related_name = 'maintainer_project') send_email = models.BooleanField(default = False, @@ -83,16 +88,15 @@ class UserProfile(models.Model): def name(self): if self.user.first_name or self.user.last_name: names = filter(bool, [self.user.first_name, self.user.last_name]) - return ' '.join(names) + return u' '.join(names) return self.user.username def contributor_projects(self): submitters = Person.objects.filter(user = self.user) - return Project.objects \ - .filter(id__in = \ - Patch.objects.filter( - submitter__in = submitters) \ - .values('project_id').query) + return Project.objects.filter(id__in = + Patch.objects.filter( + submitter__in = submitters) + .values('project_id').query) def sync_person(self): @@ -111,8 +115,8 @@ class UserProfile(models.Model): qs = qs.filter(archived = False) \ .filter(delegate = self.user) \ - .filter(state__in = \ - State.objects.filter(action_required = True) \ + .filter(state__in = + State.objects.filter(action_required = True) .values('pk').query) return qs @@ -128,15 +132,23 @@ class UserProfile(models.Model): person.link_to_user(self.user) person.save() - def __str__(self): + def __unicode__(self): return self.name() +def _user_created_callback(sender, created, instance, **kwargs): + if not created: + return + profile = UserProfile(user = instance) + profile.save() + +models.signals.post_save.connect(_user_created_callback, sender = User) + class State(models.Model): name = models.CharField(max_length = 100) ordering = models.IntegerField(unique = True) action_required = models.BooleanField(default = True) - def __str__(self): + def __unicode__(self): return self.name class Meta: @@ -187,11 +199,12 @@ class Patch(models.Model): state = models.ForeignKey(State) archived = models.BooleanField(default = False) headers = models.TextField(blank = True) - content = models.TextField() + content = models.TextField(null = True, blank = True) + pull_url = models.CharField(max_length=255, null = True, blank = True) commit_ref = models.CharField(max_length=255, null = True, blank = True) - hash = HashField(null = True, db_index = True) + hash = HashField(null = True, blank = True) - def __str__(self): + def __unicode__(self): return self.name def comments(self): @@ -203,7 +216,7 @@ class Patch(models.Model): except: self.state = State.objects.get(ordering = 0) - if self.hash is None: + if self.hash is None and self.content is not None: self.hash = hash_patch(self.content).hexdigest() super(Patch, self).save() @@ -215,12 +228,7 @@ class Patch(models.Model): if self.submitter.user == user or self.delegate == user: return True - profile = user.get_profile() - return self.project in user.get_profile().maintainer_projects.all() - - def form(self): - f = PatchForm(instance = self, prefix = self.id) - return f + return self.project.is_editable(user) def filename(self): fname_re = re.compile('[^-_A-Za-z0-9\.]+') @@ -248,7 +256,6 @@ class Patch(models.Model): else: postscript = '' - responses = False for comment in Comment.objects.filter(patch = self) \ .exclude(msgid = self.msgid): body += comment.patch_responses() @@ -259,7 +266,8 @@ class Patch(models.Model): if postscript: body += '---\n' + postscript.strip() + '\n' - body += '\n' + self.content + if self.content: + body += '\n' + self.content mail = PatchMbox(body) mail['Subject'] = self.name @@ -301,7 +309,7 @@ class Comment(models.Model): re.M | re.I) def patch_responses(self): - return ''.join([ match.group(0) + '\n' for match in \ + return ''.join([ match.group(0) + '\n' for match in self.response_re.finditer(self.content)]) class Meta: @@ -319,7 +327,7 @@ class Bundle(models.Model): return self.patches.all().count() def ordered_patches(self): - return self.patches.order_by('bundlepatch__order'); + return self.patches.order_by('bundlepatch__order') def append_patch(self, patch): # todo: use the aggregate queries in django 1.1 @@ -354,7 +362,7 @@ class Bundle(models.Model): })) def mbox(self): - return '\n'.join([p.mbox().as_string(True) \ + return '\n'.join([p.mbox().as_string(True) for p in self.ordered_patches()]) class BundlePatch(models.Model): @@ -366,34 +374,35 @@ class BundlePatch(models.Model): unique_together = [('bundle', 'patch')] ordering = ['order'] -class UserPersonConfirmation(models.Model): - user = models.ForeignKey(User) +class EmailConfirmation(models.Model): + validity = datetime.timedelta(days = settings.CONFIRMATION_VALIDITY_DAYS) + type = models.CharField(max_length = 20, choices = [ + ('userperson', 'User-Person association'), + ('registration', 'Registration'), + ('optout', 'Email opt-out'), + ]) email = models.CharField(max_length = 200) + user = models.ForeignKey(User, null = True) key = HashField() - date = models.DateTimeField(default=datetime.datetime.now) + date = models.DateTimeField(default = datetime.datetime.now) active = models.BooleanField(default = True) - def confirm(self): - if not self.active: - return - person = None - try: - person = Person.objects.get(email__iexact = self.email) - except Exception: - pass - if not person: - person = Person(email = self.email) - - person.link_to_user(self.user) - person.save() + def deactivate(self): self.active = False self.save() + def is_valid(self): + return self.date + self.validity > datetime.datetime.now() + def save(self): max = 1 << 32 if self.key == '': str = '%s%s%d' % (self.user, self.email, random.randint(0, max)) self.key = self._meta.get_field('key').construct(str).hexdigest() - super(UserPersonConfirmation, self).save() + super(EmailConfirmation, self).save() +class EmailOptout(models.Model): + email = models.CharField(max_length = 200, primary_key = True) + def __unicode__(self): + return self.email