Skip to content

Commit

Permalink
Add flows and permissions for whip reports and annotations
Browse files Browse the repository at this point in the history
  • Loading branch information
ajparsons committed Dec 20, 2024
1 parent 144da6a commit 9524add
Show file tree
Hide file tree
Showing 7 changed files with 506 additions and 6 deletions.
170 changes: 170 additions & 0 deletions src/votes/forms.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,170 @@
from enum import StrEnum
from typing import Type

from django import forms
from django.http import Http404, HttpRequest

from .consts import EvidenceType, WhipDirection, WhipPriority
from .models import (
AgreementAnnotation,
Division,
DivisionAnnotation,
Membership,
Organization,
UserPersonLink,
VoteAnnotation,
WhipReport,
)


def enum_to_choices(en: Type[StrEnum]) -> list[tuple[str, str]]:
return [(enum_.value, enum_.value.title().replace("_", " ")) for enum_ in en]


class DecisionIdMixin:
@classmethod
def from_decision_id(cls, decision_id: int):
return cls(initial={"decision_id": decision_id})


class WhipForm(forms.Form, DecisionIdMixin):
title = "Whip Reporting Form"
desc = "This form is for recording the whip, or party instructions for a division."
party = forms.ModelChoiceField(
queryset=Organization.objects.filter(classification="party"),
label="Select a Party",
empty_label="Choose a Party",
widget=forms.Select(attrs={"class": "form-control"}),
)
whip_direction = forms.ChoiceField(
choices=enum_to_choices(WhipDirection),
widget=forms.Select(attrs={"class": "form-control"}),
)
whip_priority = forms.ChoiceField(
choices=enum_to_choices(WhipPriority),
widget=forms.Select(attrs={"class": "form-control"}),
)
evidence_type = forms.ChoiceField(
choices=enum_to_choices(EvidenceType),
widget=forms.Select(attrs={"class": "form-control"}),
)
evidence_detail = forms.CharField(
widget=forms.Textarea(attrs={"class": "form-control"}), required=False
)

def save(self, request: HttpRequest, decision_id: int):
model = WhipReport(
division_id=decision_id,
party_id=self.cleaned_data["party"].id,
whip_direction=self.cleaned_data["whip_direction"],
whip_priority=self.cleaned_data["whip_priority"],
evidence_type=self.cleaned_data["evidence_type"],
evidence_detail=self.cleaned_data["evidence_detail"],
)
model.save()


class RepWhipForm(forms.Form, DecisionIdMixin):
title = "Whip Reporting Form"
desc = "This form is for representatives to self-report the whip for their party."

whip_direction = forms.ChoiceField(
choices=enum_to_choices(WhipDirection),
widget=forms.Select(attrs={"class": "form-control"}),
)
whip_strength = forms.ChoiceField(
choices=enum_to_choices(WhipPriority),
widget=forms.Select(attrs={"class": "form-control"}),
)

def save(self, request: HttpRequest, decision_id: int):
division = Division.objects.get(id=decision_id)
person_id = request.POST.get("person_id")
# get membership for date
membership = Membership.objects.filter(
person_id=person_id,
start_date__lte=division.date,
end_date__gte=division.date,
chamber=division.chamber,
).first()
current_party = membership.party_id if membership else None
if not current_party:
return Http404("No party found for this person on this date")

model = WhipReport(
division_id=decision_id,
whip_direction=self.cleaned_data["whip_direction"],
party_id=current_party,
whip_priority=self.cleaned_data["whip_strength"],
evidence_type=EvidenceType.REP,
)
model.save()


class BaseAnnotationForm(forms.Form, DecisionIdMixin):
detail = forms.CharField(
required=False, widget=forms.Textarea(attrs={"class": "form-control"})
)
link = forms.URLField(
required=False, widget=forms.TextInput(attrs={"class": "form-control"})
)


class DivisionAnnotationForm(BaseAnnotationForm):
title = "Division Annotation Form"
desc = "This form is for adding annotations (links) to divisions."

def save(self, request: HttpRequest, decision_id: int):
model = DivisionAnnotation(
division_id=decision_id,
detail=self.cleaned_data["detail"],
link=self.cleaned_data["link"],
)
model.save()


class AgreementAnnotationForm(BaseAnnotationForm):
title = "Agreement Annotation Form"
desc = "This form is for adding annotations (links) to agreements."

def save(self, request: HttpRequest, decision_id: int):
model = AgreementAnnotation(
agreement_id=decision_id,
detail=self.cleaned_data["detail"],
link=self.cleaned_data["link"],
)
model.save()


class OpenRepAnnotationForm(BaseAnnotationForm):
title = "Vote Annotation Form"
desc = "This form is for adding annotations to votes for any person."
person_id = forms.IntegerField(
widget=forms.TextInput(attrs={"class": "form-control"})
)

def save(self, request: HttpRequest, decision_id: int):
model = VoteAnnotation(
division_id=decision_id,
person_id=self.cleaned_data["person_id"],
detail=self.cleaned_data["detail"],
link=self.cleaned_data["link"],
)
model.save()


class RepAnnotationForm(BaseAnnotationForm):
title = "Vote Annotation Form"
desc = "This form is for adding annotations to votes made by the logged-in user."

def save(self, request: HttpRequest, decision_id: int):
link = UserPersonLink.objects.get(user=request.user)
if not link:
return Http404("No link found for this user")
model = VoteAnnotation(
division_id=decision_id,
person_id=link.person_id,
detail=self.cleaned_data["detail"],
link=self.cleaned_data["link"],
)
model.save()
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# Generated by Django 4.2.15 on 2024-12-20 21:15

from django.db import migrations


class Migration(migrations.Migration):

dependencies = [
('votes', '0011_whipreport_evidence_detai_whipreport_evidence_type_and_more'),
]

operations = [
migrations.RenameField(
model_name='whipreport',
old_name='evidence_detai',
new_name='evidence_detail',
),
]
5 changes: 4 additions & 1 deletion src/votes/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -355,6 +355,9 @@ class Organization(DjangoVoteModel):
org_memberships: DummyOneToMany["Membership"] = related_name("organization")
party_memberships: DummyOneToMany["Membership"] = related_name("on_behalf_of")

def __str__(self) -> str:
return self.name


class OrgMembershipCount(DjangoVoteModel):
chamber_slug: ChamberSlug
Expand Down Expand Up @@ -1285,7 +1288,7 @@ class WhipReport(DjangoVoteModel):
whip_direction: WhipDirection
whip_priority: WhipPriority
evidence_type: EvidenceType
evidence_detai: TextField = field(default="", blank=True)
evidence_detail: TextField = field(default="", blank=True)


class DivisionAnnotation(DjangoVoteModel):
Expand Down
37 changes: 34 additions & 3 deletions src/votes/templates/votes/decision.html
Original file line number Diff line number Diff line change
Expand Up @@ -69,18 +69,40 @@ <h2>Motion</h2>
</p>
{% endif %}
{% with decision.get_annotations as annotations %}
{% if annotations %}
{% if annotations or can_add_annotations %}
<h2>Annotations</h2>
<ul>
{% for annotation in annotations %}<li>{{ annotation.html|safe }}</li>{% endfor %}
</ul>
{% if can_add_annotations %}
{% if decision.decision_type == "Division" %}
<p>
<a href="{% url 'forms' 'division_annotation' decision.id %}">Add an annotation</a>
</p>
{% elif decision.decision_type == "Agreement" %}
<p>
<a href="{% url 'forms' 'agreement_annotation' decision.id %}">Add an annotation</a>
</p>
{% endif %}
{% endif %}
{% endif %}
{% endwith %}
{% if decision.decision_type == "Division" %}
{% with decision.whip_report_df as whip_report_df %}
{% if whip_report_df is not None %}
{% if whip_report_df is not None or can_report_whip or can_report_self_whip %}
<h2>Whip reports</h2>
{% style_df whip_report_df %}
{% if whip_report_df is not None %}
{% style_df whip_report_df %}
{% endif %}
{% if can_report_whip %}
<p>
<a href="{% url 'forms' 'whip' decision.id %}">Report whip info</a>
</p>
{% elif can_report_self_whip %}
<p>
<a href="{% url 'forms' 'rep_whip' decision.id %}">Report your whip</a>
</p>
{% endif %}
{% endif %}
{% endwith %}
{% endif %}
Expand All @@ -101,6 +123,15 @@ <h2>Voting breakdown</h2>
<h2>Party voting breakdown</h2>
{% style_df decision.party_breakdown_df "For motion percentage" "Party turnout" %}
<h2>Voting list</h2>
{% if can_add_annotations %}
<p>
<a href="{% url 'forms' 'open_rep_annotation' decision.id %}">Add a vote annotation</a>
</p>
{% elif can_add_self_annotations %}
<p>
<a href="{% url 'forms' 'rep_annotation' decision.id %}">Add your vote annotation</a>
</p>
{% endif %}
{% style_df decision.votes_df "Party alignment" %}
{% elif decision.decision_type == "Agreement" %}
{% featureflag pg.ADVANCED_INFO %}
Expand Down
15 changes: 15 additions & 0 deletions src/votes/templates/votes/forms.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
{% extends "votes/base.html" %}

{% block content.inner %}
<h1>{{ form.title }}</h1>
<p>{{ form.desc }}</p>
<p>
{{ decision.chamber.name }} {{ decision.decision_type }}: <a href="{{ decision.url }}">{{ decision.safe_decision_name }}</a>.
{% if form.errors %}<div class="alert alert-danger" role="alert">{{ form.errors }}</div>{% endif %}
<form method="post">
{% csrf_token %}
{{ form }}
<!-- Submit Button -->
<button type="submit" class="btn btn-primary">Submit</button>
</form>
{% endblock content.inner %}
Loading

0 comments on commit 9524add

Please sign in to comment.