diff --git a/greenmine/profile/admin.py b/greenmine/profile/admin.py index fbe042d7..2cce23c8 100644 --- a/greenmine/profile/admin.py +++ b/greenmine/profile/admin.py @@ -12,5 +12,15 @@ admin.site.register(Profile, ProfileAdmin) class RoleAdmin(admin.ModelAdmin): list_display = ["name"] + filter_horizontal = ('permissions',) + + def formfield_for_manytomany(self, db_field, request=None, **kwargs): + if db_field.name == 'permissions': + qs = kwargs.get('queryset', db_field.rel.to.objects) + # Avoid a major performance hit resolving permission names which + # triggers a content_type load: + kwargs['queryset'] = qs.select_related('content_type') + return super(RoleAdmin, self).formfield_for_manytomany( + db_field, request=request, **kwargs) admin.site.register(Role, RoleAdmin) diff --git a/greenmine/profile/models.py b/greenmine/profile/models.py index 66d74c80..b80762d7 100644 --- a/greenmine/profile/models.py +++ b/greenmine/profile/models.py @@ -1,11 +1,13 @@ # -*- coding: utf-8 -*- from django.db import models -from django.db.models.signals import post_save +from django.db.models.signals import post_save, m2m_changed from django.dispatch import receiver from django.utils.translation import ugettext_lazy as _ from django.contrib.auth.models import User, Group +from greenmine.scrum.models import Project + class Profile(models.Model): user = models.OneToOneField("auth.User", related_name='profile') description = models.TextField(blank=True) @@ -34,6 +36,10 @@ if not hasattr(Group, 'role'): field = models.ForeignKey(Role, blank=False, null=False, related_name='groups') field.contribute_to_class(Group, 'role') +if not hasattr(Group, 'project'): + field = models.ForeignKey(Project, blank=False, null=False, related_name='groups') + field.contribute_to_class(Group, 'project') + @receiver(post_save, sender=User) def user_post_save(sender, instance, created, **kwargs): @@ -45,9 +51,16 @@ def user_post_save(sender, instance, created, **kwargs): @receiver(post_save, sender=Role) def role_post_save(sender, instance, **kwargs): - from greenmine.profile.services import RoleGroupsService - """ Recalculate projects groups """ + from greenmine.profile.services import RoleGroupsService + RoleGroupsService().replicate_role_on_all_projects(instance) + +@receiver(m2m_changed, sender=Role.permissions.through) +def role_m2m_changed(sender, instance, **kwargs): + """ + Recalculate projects groups + """ + from greenmine.profile.services import RoleGroupsService RoleGroupsService().replicate_role_on_all_projects(instance) diff --git a/greenmine/profile/services.py b/greenmine/profile/services.py index 308b4ca4..6df20e05 100644 --- a/greenmine/profile/services.py +++ b/greenmine/profile/services.py @@ -12,13 +12,13 @@ class RoleGroupsService(object): def replicate_all_roles_on_one_project(self, project): for role in Role.objects.all(): - group = Group(name="p%d-r%d" % (project.pk, role.pk), role=role) + group = Group(name="p%d-r%d" % (project.pk, role.pk), role=role, project=project) group.save() self._replicate_role_permissions_on_group(role, group) def _replicate_role_on_project_if_needed(self, role, project): if project.groups.filter(role=role).count() == 0: - group = Group(name="p%d-r%d" % (project.pk, role.pk), role=role) + group = Group(name="p%d-r%d" % (project.pk, role.pk), role=role, project=project) group.save() self._replicate_role_permissions_on_group(role, group) @@ -27,4 +27,3 @@ class RoleGroupsService(object): for permission in role.permissions.all(): group.permissions.add(permission) group.save() - diff --git a/greenmine/scrum/admin.py b/greenmine/scrum/admin.py index 96f63725..2c48c96f 100644 --- a/greenmine/scrum/admin.py +++ b/greenmine/scrum/admin.py @@ -2,48 +2,43 @@ from django.contrib import admin from guardian.admin import GuardedModelAdmin +import reversion -from greenmine.scrum.models import Project, ProjectExtras, \ - Milestone, UserStory, Change, ChangeAttachment, Task +from greenmine.scrum.models import Project, Milestone, UserStory, Change, \ + ChangeAttachment, Task -class ProjectAdmin(GuardedModelAdmin): +class ProjectAdmin(GuardedModelAdmin, reversion.VersionAdmin): list_display = ["name", "owner"] admin.site.register(Project, ProjectAdmin) -class ProjectExtrasAdmin(admin.ModelAdmin): - list_display = ["project"] - -admin.site.register(ProjectExtras, ProjectExtrasAdmin) - - -class MilestoneAdmin(admin.ModelAdmin): +class MilestoneAdmin(reversion.VersionAdmin): list_display = ["name", "project", "owner"] admin.site.register(Milestone, MilestoneAdmin) -class UserStoryAdmin(admin.ModelAdmin): +class UserStoryAdmin(reversion.VersionAdmin): list_display = ["ref", "milestone", "project", "owner"] admin.site.register(UserStory, UserStoryAdmin) -class ChangeAdmin(admin.ModelAdmin): +class ChangeAdmin(reversion.VersionAdmin): list_display = ["id", "change_type", "project", "owner"] admin.site.register(Change, ChangeAdmin) -class ChangeAttachmentAdmin(admin.ModelAdmin): +class ChangeAttachmentAdmin(reversion.VersionAdmin): list_display = ["id", "change", "owner"] admin.site.register(ChangeAttachment, ChangeAttachmentAdmin) -class TaskAdmin(admin.ModelAdmin): +class TaskAdmin(reversion.VersionAdmin): list_display = ["subject", "type", "user_story"] admin.site.register(Task, TaskAdmin) diff --git a/greenmine/scrum/models.py b/greenmine/scrum/models.py index 8149691b..e72cad6b 100644 --- a/greenmine/scrum/models.py +++ b/greenmine/scrum/models.py @@ -24,27 +24,6 @@ class ProjectManager(models.Manager): return self.get(slug=slug) -class ProjectExtras(models.Model): - task_parser_re = models.CharField(max_length=1000, blank=True, null=True, default=None) - sprints = models.IntegerField(default=1, blank=True, null=True) - show_burndown = models.BooleanField(default=False, blank=True) - show_burnup = models.BooleanField(default=False, blank=True) - show_sprint_burndown = models.BooleanField(default=False, blank=True) - total_story_points = models.FloatField(default=None, null=True) - - def get_task_parse_re(self): - re_str = settings.DEFAULT_TASK_PARSER_RE - if self.task_parser_re: - re_str = self.task_parser_re - return re.compile(re_str, flags=re.U+re.M) - - def parse_ustext(self, text): - rx = self.get_task_parse_re() - texts = rx.findall(text) - for text in texts: - yield text - - class Project(models.Model): uuid = models.CharField(max_length=40, unique=True, blank=True) name = models.CharField(max_length=250, unique=True) @@ -55,17 +34,19 @@ class Project(models.Model): modified_date = models.DateTimeField(auto_now_add=True) owner = models.ForeignKey("auth.User", related_name="projects") - groups = models.ManyToManyField('auth.Group', - related_name="projects", - null=True, - blank=True) public = models.BooleanField(default=True) markup = models.CharField(max_length=10, choices=MARKUP_TYPE, default='md') - extras = models.OneToOneField("ProjectExtras", related_name="project", null=True, default=None) last_us_ref = models.BigIntegerField(null=True, default=0) last_task_ref = models.BigIntegerField(null=True, default=0) + task_parser_re = models.CharField(max_length=1000, blank=True, null=True, default=None) + sprints = models.IntegerField(default=1, blank=True, null=True) + show_burndown = models.BooleanField(default=False, blank=True) + show_burnup = models.BooleanField(default=False, blank=True) + show_sprint_burndown = models.BooleanField(default=False, blank=True) + total_story_points = models.FloatField(default=None, null=True) + objects = ProjectManager() class Meta: @@ -120,13 +101,6 @@ class Project(models.Model): def __unicode__(self): return self.name - def get_extras(self): - if self.extras is None: - self.extras = ProjectExtras.objects.create() - self.__class__.objects.filter(pk=self.pk).update(extras=self.extras) - - return self.extras - def natural_key(self): return (self.slug,) diff --git a/greenmine/scrum/sigdispatch.py b/greenmine/scrum/sigdispatch.py index e3134f10..5bf7789b 100644 --- a/greenmine/scrum/sigdispatch.py +++ b/greenmine/scrum/sigdispatch.py @@ -6,8 +6,6 @@ from django.utils.translation import ugettext from django.template.loader import render_to_string from django.db.models.signals import post_save -from django.contrib.auth.models import User - from greenmine.base import signals from greenmine.base.utils.auth import set_token from greenmine.base.mail.tasks import send_mail, send_bulk_mail @@ -109,6 +107,7 @@ def mail_task_assigned(sender, task, user, **kwargs): subject = ugettext("Greenmine: task assigned") send_mail.delay(subject, template, [task.assigned_to.email]) + @receiver(post_save, sender=Project) def project_post_save(sender, instance, created, **kwargs): """