Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow arbitrary properties to be saved against a session/stage/authority combination #194

Merged
merged 4 commits into from
Oct 16, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions ceuk-marking/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,12 @@
progress.AuthorityContactCSVView.as_view(),
name="authority_contacts_report",
),
# properties
path(
"authorities/properties/<name>/<stage>/",
marking.SectionPropertiesView.as_view(),
name="authority_properties",
),
# stats
path(
"stats/",
Expand Down
23 changes: 23 additions & 0 deletions crowdsourcer/admin.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@
Response,
ResponseType,
Section,
SessionProperties,
SessionPropertyValues,
)


Expand Down Expand Up @@ -144,3 +146,24 @@ class SectionAdmin(admin.ModelAdmin):
@admin.register(MarkingSession)
class MarkingSessionAdmin(admin.ModelAdmin):
pass


@admin.register(SessionProperties)
class SessionPropertiesAdmin(admin.ModelAdmin):
list_display = (
"label",
"marking_session",
"stage",
)

list_filter = ["marking_session", "stage"]


@admin.register(SessionPropertyValues)
class SessionPropertyValuesAdmin(admin.ModelAdmin):
list_display = (
"property",
"authority",
)
list_filter = ["property__marking_session", "property__stage"]
search_fields = ["authority__name"]
28 changes: 28 additions & 0 deletions crowdsourcer/fixtures/session_properties.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
[
{
"model": "crowdsourcer.sessionproperties",
"pk": 1,
"fields": {
"marking_session": 1,
"stage": 1,
"property_type": "text",
"name": "first_property",
"label": "First Mark Property",
"active": true,
"order": 1
}
},
{
"model": "crowdsourcer.sessionproperties",
"pk": 2,
"fields": {
"marking_session": 1,
"stage": 2,
"property_type": "text",
"name": "ror_property",
"label": "Right of Reply Property",
"active": true,
"order": 1
}
}
]
21 changes: 21 additions & 0 deletions crowdsourcer/forms.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
Select,
Textarea,
TextInput,
URLField,
formset_factory,
inlineformset_factory,
)
Expand Down Expand Up @@ -551,3 +552,23 @@ class VolunteerDeactivateForm(Form):
def __init__(self, stage_choices, **kwargs):
super().__init__(**kwargs)
self.fields["stage"].choices = stage_choices


class SessionPropertyForm(Form):
def __init__(self, properties: {}, **kwargs):
super().__init__(**kwargs)

for prop in properties:
if prop.property_type == "url":
self.fields[prop.name] = URLField(
label=prop.label,
help_text=prop.description,
required=False,
)
else:
self.fields[prop.name] = CharField(
label=prop.label,
help_text=prop.description,
required=False,
widget=Textarea,
)
94 changes: 94 additions & 0 deletions crowdsourcer/migrations/0057_sessionproperties_sessionproperty.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
# Generated by Django 4.2.15 on 2024-10-07 09:38

from django.db import migrations, models
import django.db.models.deletion


class Migration(migrations.Migration):

dependencies = [
("crowdsourcer", "0056_assigned_created_assigned_last_update_and_more"),
]

operations = [
migrations.CreateModel(
name="SessionProperties",
fields=[
(
"id",
models.BigAutoField(
auto_created=True,
primary_key=True,
serialize=False,
verbose_name="ID",
),
),
(
"name",
models.CharField(help_text="Keyname in database", max_length=200),
),
("label", models.CharField(help_text="Form label", max_length=200)),
(
"description",
models.TextField(
blank=True,
help_text="Displayed under field to describe content",
null=True,
),
),
(
"property_type",
models.CharField(
choices=[("text", "Text"), ("url", "URL")], max_length=200
),
),
("active", models.BooleanField(default=True)),
("order", models.IntegerField(default=0)),
(
"marking_session",
models.ForeignKey(
on_delete=django.db.models.deletion.CASCADE,
to="crowdsourcer.markingsession",
),
),
(
"stage",
models.ForeignKey(
null=True,
on_delete=django.db.models.deletion.SET_NULL,
to="crowdsourcer.responsetype",
),
),
],
),
migrations.CreateModel(
name="SessionPropertyValues",
fields=[
(
"id",
models.BigAutoField(
auto_created=True,
primary_key=True,
serialize=False,
verbose_name="ID",
),
),
("value", models.TextField()),
(
"authority",
models.ForeignKey(
null=True,
on_delete=django.db.models.deletion.SET_NULL,
to="crowdsourcer.publicauthority",
),
),
(
"property",
models.ForeignKey(
on_delete=django.db.models.deletion.CASCADE,
to="crowdsourcer.sessionproperties",
),
),
],
),
]
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
# Generated by Django 4.2.15 on 2024-10-16 09:16

from django.db import migrations


class Migration(migrations.Migration):

dependencies = [
("crowdsourcer", "0057_sessionproperties_sessionproperty"),
]

operations = [
migrations.AlterModelOptions(
name="sessionproperties",
options={"verbose_name_plural": "Session Properties"},
),
migrations.AlterModelOptions(
name="sessionpropertyvalues",
options={"verbose_name_plural": "Session Property Values"},
),
]
42 changes: 42 additions & 0 deletions crowdsourcer/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,48 @@ def __str__(self):
return self.label


class SessionProperties(models.Model):
"""Used to define extra properties that can be added as part of marking"""

PROPERTY_TYPES = [
("text", "Text"),
("url", "URL"),
]

marking_session = models.ForeignKey(MarkingSession, on_delete=models.CASCADE)
stage = models.ForeignKey("ResponseType", null=True, on_delete=models.SET_NULL)
name = models.CharField(max_length=200, help_text="Keyname in database")
label = models.CharField(max_length=200, help_text="Form label")
description = models.TextField(
help_text="Displayed under field to describe content", null=True, blank=True
)
property_type = models.CharField(max_length=200, choices=PROPERTY_TYPES)
active = models.BooleanField(default=True)
order = models.IntegerField(default=0)

def __str__(self):
return f"{self.label} ({self.marking_session}, {self.stage})"

class Meta:
verbose_name_plural = "Session Properties"


class SessionPropertyValues(models.Model):
"""For storing extra session properties"""

authority = models.ForeignKey(
"PublicAuthority", null=True, on_delete=models.SET_NULL
)
property = models.ForeignKey(SessionProperties, on_delete=models.CASCADE)
value = models.TextField()

def __str__(self):
return f"{self.property} {self.authority} - {self.value}"

class Meta:
verbose_name_plural = "Session Property Values"


class Section(models.Model):
"""Used to group questions with a similar theme"""

Expand Down
38 changes: 38 additions & 0 deletions crowdsourcer/templates/crowdsourcer/authority_properties.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
{% extends 'crowdsourcer/base.html' %}

{% load crowdsourcer_tags django_bootstrap5 %}

{% block content %}
{% if show_login %}
<h1 class="mb-4">Sign in</h1>
<a href="{% url 'login' %}">Sign in</a>
{% else %}
<p class="mb-4">
<a href="{{ back_link }}">Return to section list</a>
</p>
<h1 class="mb-4">Optional Information</h1>
{% if message %}
<h3 class="mb-4 mb-md-5 text-success">
{{ message }}
</h3>
{% endif %}

<form action="" method="POST">
{% if form.total_error_count > 0 %}
<div class="mb-4">
<div class="col-md-7 text-danger">
<strong>Changes Not Saved</strong>. There were some errors which are highlighted in red below.
</div>
</div>
{% endif %}

{% csrf_token %}
{% bootstrap_form form %}

<div class="sticky-bottom py-3 bg-white border-top" style="margin-top: -1px;">
<input type="submit" class="btn btn-primary" value="Save answers">
</div>
</form>

{% endif %}
{% endblock %}
Original file line number Diff line number Diff line change
Expand Up @@ -40,5 +40,14 @@ <h1 class="mb-4">Sections</h1>
{% endfor %}
</tbody>
</table>

{% if has_properties %}
<div class="my-5" style="max-width: 40rem">
<h2 class="mb-3 h4">Help us by providing optional feedback</h2>
<p>Help us improve the Scorecards process next year by answering a few optional questions. Your answers will have no effect on your council’s score.</p>
<a href="{% session_url "authority_properties" authority_name "Right of Reply" %}" class="btn btn-outline-primary">Complete optional questions</a>
</div>
{% endif %}

{% endif %}
{% endblock %}
Loading
Loading