From aa65305c7f6dd7bcb3c432e8a0b419d029232827 Mon Sep 17 00:00:00 2001 From: Nitzan Raz Date: Thu, 18 May 2023 18:19:02 +0300 Subject: [PATCH] Timeline view --- djang/versions/forms.py | 46 +++++++++++++++++++ .../migrations/0002_alter_law_name.py | 17 +++++++ .../migrations/0003_alter_revision_name.py | 17 +++++++ djang/versions/models.py | 14 +++++- djang/versions/templates/versions/slider.html | 9 ++++ .../versions/templates/versions/timeline.html | 29 ++++++++++++ .../templates/versions/version_compare.html | 2 +- djang/versions/urls.py | 1 + djang/versions/views.py | 32 ++++++++++++- 9 files changed, 162 insertions(+), 5 deletions(-) create mode 100644 djang/versions/migrations/0002_alter_law_name.py create mode 100644 djang/versions/migrations/0003_alter_revision_name.py create mode 100644 djang/versions/templates/versions/slider.html create mode 100644 djang/versions/templates/versions/timeline.html diff --git a/djang/versions/forms.py b/djang/versions/forms.py index 704e491..0713090 100644 --- a/djang/versions/forms.py +++ b/djang/versions/forms.py @@ -2,6 +2,43 @@ from .models import Law, Revision +class SliderWidget(forms.Widget): + template_name = "versions/slider.html" + + def __init__(self): + super().__init__() + self.disabled = True + + def get_context(self, name, value, attrs): + ret = super().get_context(name, value, attrs) + if not self.disabled: + ret["widget"]["steps"] = self.steps + ret["widget"]["min"] = self.min + ret["widget"]["max"] = self.max + return ret + + def set_law(self, law): + self.law = law + revisions = law.revision_set.filter(effective_date_start__isnull=False) + if not revisions.exists(): + self.disabled = True + return + + self.disabled = False + + revisions = revisions.order_by("effective_date_start").values( + "effective_date_start" + ) + dates = [r["effective_date_start"] for r in revisions] + earliest = dates[0] + latest = dates[-1] + steps = dates + + self.min = earliest.strftime("%s") + self.max = latest.strftime("%s") + self.steps = [{"value": s.strftime("%s"), "label": s} for s in steps] + + class RevisionModelChoiceField(forms.ModelChoiceField): def __init__(self, *args, **kwargs): kwargs["queryset"] = None @@ -37,3 +74,12 @@ def __init__(self, law, *args, **kwargs): self.law = law self.fields["version_a"].set_law(law) self.fields["version_b"].set_law(law) + + +class TimelineForm(forms.Form): + timey = forms.IntegerField(widget=SliderWidget()) + + def __init__(self, law, *args, **kwargs): + super().__init__(*args, **kwargs) + self.law = law + self.fields["timey"].widget.set_law(law) diff --git a/djang/versions/migrations/0002_alter_law_name.py b/djang/versions/migrations/0002_alter_law_name.py new file mode 100644 index 0000000..388a204 --- /dev/null +++ b/djang/versions/migrations/0002_alter_law_name.py @@ -0,0 +1,17 @@ +# Generated by Django 4.2 on 2023-05-18 11:51 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + dependencies = [ + ("versions", "0001_initial"), + ] + + operations = [ + migrations.AlterField( + model_name="law", + name="name", + field=models.CharField(max_length=250), + ), + ] diff --git a/djang/versions/migrations/0003_alter_revision_name.py b/djang/versions/migrations/0003_alter_revision_name.py new file mode 100644 index 0000000..3761f55 --- /dev/null +++ b/djang/versions/migrations/0003_alter_revision_name.py @@ -0,0 +1,17 @@ +# Generated by Django 4.2 on 2023-05-18 11:51 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + dependencies = [ + ("versions", "0002_alter_law_name"), + ] + + operations = [ + migrations.AlterField( + model_name="revision", + name="name", + field=models.CharField(max_length=251), + ), + ] diff --git a/djang/versions/models.py b/djang/versions/models.py index 877c4a5..ee40d4e 100644 --- a/djang/versions/models.py +++ b/djang/versions/models.py @@ -1,4 +1,5 @@ from django.db import models +from datetime import date class Law(models.Model): @@ -6,7 +7,7 @@ class Law(models.Model): wiki_page_id = models.IntegerField(unique=True) knesset_id = models.IntegerField(unique=True, null=True) akn_id = models.IntegerField(unique=True, null=True) - name = models.CharField(max_length=50) + name = models.CharField(max_length=250) # revisions: Can be calculated @@ -17,7 +18,16 @@ class Revision(models.Model): akn_id = models.IntegerField( unique=True, null=True ) # TODO do we need these both here and above? - name = models.CharField(max_length=51) + name = models.CharField(max_length=251) effective_date_start = models.DateField(null=True) effective_date_end = models.DateField(null=True) # source_text - will do later + + @classmethod + def get_by_law_and_epoch(cls, law, epoch): + d = date.fromtimestamp(epoch) + return ( + law.revision_set.filter(effective_date_start__lte=d) + .order_by("-effective_date_start") + .first() + ) diff --git a/djang/versions/templates/versions/slider.html b/djang/versions/templates/versions/slider.html new file mode 100644 index 0000000..1391156 --- /dev/null +++ b/djang/versions/templates/versions/slider.html @@ -0,0 +1,9 @@ +{% if not widget.disabled %} +
{# to match the slider and the datalist #} + + + {% for step in widget.steps %} + + {% endfor %} + +{% endif %} diff --git a/djang/versions/templates/versions/timeline.html b/djang/versions/templates/versions/timeline.html new file mode 100644 index 0000000..ff1da52 --- /dev/null +++ b/djang/versions/templates/versions/timeline.html @@ -0,0 +1,29 @@ +{% extends 'versions/base.html' %} +{% block content %} + + +
+

Law comparison

+

{{ law.name }}

+
+
+
+ {{ form.as_p }} + +
+
+
+
{{ output | safe | linebreaks }}
+
+
+
+{% endblock content %} + diff --git a/djang/versions/templates/versions/version_compare.html b/djang/versions/templates/versions/version_compare.html index e02e75a..751a4e2 100644 --- a/djang/versions/templates/versions/version_compare.html +++ b/djang/versions/templates/versions/version_compare.html @@ -2,7 +2,7 @@ {% block content %}

Law comparison

-

{{ law.name }}

+

{{ law.name }} (timeline)

diff --git a/djang/versions/urls.py b/djang/versions/urls.py index 3edaa9b..44bc9fd 100644 --- a/djang/versions/urls.py +++ b/djang/versions/urls.py @@ -24,4 +24,5 @@ urlpatterns = [ path("", views.LawChooseView.as_view(), name="home"), path("compare/", views.VersionCompareView.as_view(), name="compare"), + path("timeline/", views.VersionTimelineView.as_view(), name="timeline"), ] diff --git a/djang/versions/views.py b/djang/versions/views.py index 5412a4a..a3b129a 100644 --- a/djang/versions/views.py +++ b/djang/versions/views.py @@ -3,8 +3,8 @@ from django.views.generic.edit import FormView from .models import Law, Revision -from .forms import CompareForm -from .services.diff import diff +from .forms import CompareForm, TimelineForm +from .services.diff import diff, get_content # Create your views here. @@ -50,3 +50,31 @@ def get_form_kwargs(self): ret["law"] = law return ret + + +class VersionTimelineView(FormView): + template_name = "versions/timeline.html" + form_class = TimelineForm + + def get_context_data(self, **kwargs): + ret = super().get_context_data(**kwargs) + form = self.get_form() + + if form.law: + ret["law"] = form.law + + if form.is_valid(): + revision = Revision.get_by_law_and_epoch( + form.law, form.cleaned_data["timey"] + ) + ret["output"] = get_content(revision) + + return ret + + def get_form_kwargs(self): + ret = super().get_form_kwargs() + ret["data"] = self.request.GET + pk = self.kwargs.get("pk") + law = Law.objects.get(pk=pk) + ret["law"] = law + return ret