class Topic(BaseIssue, getCreationBase('topic')): """A collection of issues unified categorically.""" polity = models.ForeignKey(Polity) class Meta: ordering = ["name"] def issues_open(self): issues = [issue for issue in self.issue_set.all() if issue.is_open()] return len(issues) def issues_voting(self): issues = [issue for issue in self.issue_set.all() if issue.is_voting()] return len(issues) def issues_closed(self): issues = [issue for issue in self.issue_set.all() if issue.is_closed()] return len(issues) def get_delegation(self, user): """Check if there is a delegation on this topic.""" if not user.is_authenticated(): return [] try: d = Delegate.objects.get(user=user, base_issue=self) return d.get_path() except Delegate.DoesNotExist: return self.polity.get_delegation(user) def new_comments(self): return Comment.objects.filter(issue__topics=self).order_by("-created")[:10]
class Polity(BaseIssue, getCreationBase('polity')): """A political entity. See the manual.""" parent = models.ForeignKey('Polity', help_text="Parent polity", **nullblank) members = models.ManyToManyField(User) officers = models.ManyToManyField(User, verbose_name=_("Officers"), related_name="officers") invite_threshold = models.IntegerField(default=3, verbose_name=_("Invite threshold"), help_text=_("How many members need to vouch for a new user before he can join.")) is_administrated = models.BooleanField(verbose_name=_("Are there officers?"), default=False, help_text=_("Is there a group of people who oversee the polity?")) is_listed = models.BooleanField(verbose_name=_("Publicly listed?"), default=True, help_text=_("Whether the polity is publicly listed or not.")) is_nonmembers_readable = models.BooleanField(verbose_name=_("Publicly viewable?"), default=True, help_text=_("Whether non-members can view the polity and its activities.")) is_newissue_only_officers = models.BooleanField(verbose_name=_("Can only officers make new issues?"), default=False, help_text=_("If this is checked, only officers can create new issues. If it's unchecked, any member can start a new issue.")) is_front_polity = models.BooleanField(verbose_name=_("Front polity?"), default=False, help_text=_("If checked, this polity will be displayed on the front page. The first created polity automatically becomes the front polity.")) def get_delegation(self, user): """Check if there is a delegation on this polity.""" if not user.is_authenticated(): return [] try: d = Delegate.objects.get(user=user, base_issue=self) return d.get_path() except Delegate.DoesNotExist: pass return [] def is_member(self, user): return user in self.members.all() def get_invite_threshold(self): return min(self.members.count(), self.invite_threshold) def get_topic_list(self, user): if user.is_anonymous() or UserProfile.objects.get(user=user).topics_showall: topics = Topic.objects.filter(polity=self).order_by('name') else: topics = [x.topic for x in UserTopic.objects.filter(user=user, topic__polity=self).order_by('topic__name')] return topics def agreements(self): return DocumentContent.objects.select_related('document').filter(status='accepted', document__polity_id=self.id).order_by('-issue__deadline_votes') def save(self, *args, **kwargs): polities = Polity.objects.all() if polities.count() == 0: self.is_front_polity = True elif self.is_front_polity: for frontpolity in polities.filter(is_front_polity=True).exclude(id=self.id): # Should never return more than 1 frontpolity.is_front_polity = False frontpolity.save() return super(Polity, self).save(*args, **kwargs)
class ChangeProposal(getCreationBase('change_proposal')): document = models.ForeignKey(Document) # Document to reference issue = models.ForeignKey(Issue) CHANGE_PROPOSAL_ACTION_CHOICES = ( ('NEW', 'New Agreement'), ('CHANGE', 'Change Agreement Text'), ('CHANGE_TITLE', 'Change Agreement Title'), ('RETIRE', 'Retire Agreement'), ) action = models.CharField(max_length=20, choices=CHANGE_PROPOSAL_ACTION_CHOICES) content = models.TextField(help_text='Content of document, or new title', **nullblank) def __unicode__(self): return 'Change Proposal: %s (content: "%s")' % (self.action, self.content_short()) def content_short(self): return trim(self.content, 30)
class Comment(getCreationBase('comment')): comment = models.TextField() issue = models.ForeignKey(Issue)
class Issue(BaseIssue, getCreationBase('issue')): SPECIAL_PROCESS_CHOICES = ( ('accepted_at_assembly', _('Accepted at assembly')), ('rejected_at_assembly', _('Rejected at assembly')), ) polity = models.ForeignKey(Polity) topics = models.ManyToManyField(Topic, verbose_name=_("Topics")) documentcontent = models.OneToOneField('DocumentContent', related_name='issue', **nullblank) deadline_discussions = models.DateTimeField(**nullblank) deadline_proposals = models.DateTimeField(**nullblank) deadline_votes = models.DateTimeField(**nullblank) majority_percentage = models.DecimalField(max_digits=5, decimal_places=2) ruleset = models.ForeignKey(PolityRuleset, verbose_name=_("Ruleset"), editable=True) is_processed = models.BooleanField(default=False) special_process = models.CharField(max_length='32', verbose_name=_("Special process"), choices=SPECIAL_PROCESS_CHOICES, default='', null=True, blank=True) class Meta: ordering = ["-deadline_votes"] def __unicode__(self): return self.name def apply_ruleset(self): now = datetime.now() if self.special_process: self.deadline_discussions = now self.deadline_proposals = now self.deadline_votes = now else: self.deadline_discussions = now + timedelta(seconds=self.ruleset.issue_discussion_time) self.deadline_proposals = self.deadline_discussions + timedelta(seconds=self.ruleset.issue_proposal_time) self.deadline_votes = self.deadline_proposals + timedelta(seconds=self.ruleset.issue_vote_time) self.majority_percentage = self.ruleset.issue_majority # Doesn't mechanically matter but should be official. def is_open(self): if not self.is_closed(): return True return False def is_voting(self): if not self.deadline_proposals or not self.deadline_votes: return False if datetime.now() > self.deadline_proposals and datetime.now() < self.deadline_votes: return True return False def is_closed(self): if not self.deadline_votes: return False if datetime.now() > self.deadline_votes: return True return False def get_delegation(self, user): """Check if there is a delegation on this topic.""" if not user.is_authenticated(): return [] try: d = Delegate.objects.get(user=user, base_issue=self) return d.get_path() except Delegate.DoesNotExist: for i in self.topics.all(): return i.get_delegation(user) def topics_str(self): return ', '.join(map(str, self.topics.all())) def proposed_documents(self): return self.document_set.filter(is_proposed=True) def user_documents(self, user): try: return self.document_set.filter(user=user) except TypeError: return [] def get_votes(self): votes = {} if self.is_closed(): votes["yes"] = sum([x.get_value() for x in self.vote_set.filter(value=1)]) votes["abstain"] = sum([x.get_value() for x in self.vote_set.filter(value=0)]) votes["no"] = -sum([x.get_value() for x in self.vote_set.filter(value=-1)]) else: votes["yes"] = -1 votes["abstain"] = -1 votes["no"] = -1 votes["total"] = sum([x.get_value() for x in self.vote_set.all()]) votes["count"] = self.vote_set.exclude(value=0).count() return votes def majority_reached(self): result = False if self.special_process == 'accepted_at_assembly': result = True else: votes = self.get_votes() if votes['count'] > 0: result = float(votes['yes']) / votes['count'] > float(self.majority_percentage) / 100 return result