Skip to content

Commit

Permalink
Merge pull request #2055 from laws-africa/all-places
Browse files Browse the repository at this point in the history
All places
  • Loading branch information
longhotsummer authored Mar 22, 2024
2 parents c849ae9 + b5c0988 commit 00722f2
Show file tree
Hide file tree
Showing 17 changed files with 313 additions and 105 deletions.
16 changes: 16 additions & 0 deletions indigo_api/models/places.py
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,22 @@ def get_country_locality(cls, code):
return country, locality


class AllPlace:
"""A fake country that mimics a country but is used to represent all places in the system."""
place_code = code = iso = 'all'
name = _('All places')

@property
def country(self):
return self

@classmethod
def filter_works_queryset(cls, works, user):
if not user.is_superuser:
works = works.filter(country__in=user.editor.permitted_countries.all())
return works


@receiver(signals.post_save, sender=Country)
def post_save_country(sender, instance, **kwargs):
""" When a country is saved, make sure a PlaceSettings exists for it.
Expand Down
73 changes: 65 additions & 8 deletions indigo_app/forms/works.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
from cobalt import FrbrUri
from indigo.tasks import TaskBroker
from indigo_api.models import Work, VocabularyTopic, TaxonomyTopic, Amendment, Subtype, Locality, PublicationDocument, \
Commencement, Workflow, Task, Country, WorkAlias, ArbitraryExpressionDate
Commencement, Workflow, Task, Country, WorkAlias, ArbitraryExpressionDate, AllPlace
from indigo_app.forms.mixins import FormAsUrlMixin


Expand Down Expand Up @@ -741,6 +741,8 @@ class Facet:
class WorkFilterForm(forms.Form, FormAsUrlMixin):
q = forms.CharField()

place = forms.MultipleChoiceField()

assent_date_start = forms.DateField(input_formats=['%Y-%m-%d'])
assent_date_end = forms.DateField(input_formats=['%Y-%m-%d'])

Expand Down Expand Up @@ -810,6 +812,11 @@ def __init__(self, country, *args, **kwargs):
settings.INDIGO['EXTRA_DOCTYPES'].get(self.country.code, [])]
subtypes = [(s.abbreviation, s.name) for s in Subtype.objects.all()]
self.fields['subtype'] = forms.MultipleChoiceField(required=False, choices=doctypes + subtypes)
self.fields['place'].choices = [
(c.code, c.name) for c in Country.objects.all()
] + [
(loc.place_code, loc.name) for loc in Locality.objects.all()
]

def show_advanced_filters(self):
# Should we show the advanced options box by default?
Expand Down Expand Up @@ -837,6 +844,13 @@ def filter_queryset(self, queryset, exclude=None):
if uris:
queryset = queryset.filter(frbr_uri__in=uris)

if exclude != "place":
q = Q()
for place in self.cleaned_data.get('place', []):
country, locality = Country.get_country_locality(place)
q |= Q(country=country, locality=locality)
queryset = queryset.filter(q)

# filter by work in progress
if exclude != "work_in_progress":
work_in_progress_filter = self.cleaned_data.get('work_in_progress', [])
Expand Down Expand Up @@ -1054,7 +1068,7 @@ def facet(self, name, type, items):
items = [self.facet_item(name, value, count) for value, count in items]
return Facet(self.fields[name].label, name, type, items)

def work_facets(self, queryset, taxonomy_toc):
def work_facets(self, queryset, taxonomy_toc, places_toc):
work_facets = []
self.facet_subtype(work_facets, queryset)
self.facet_work_in_progress(work_facets, queryset)
Expand All @@ -1068,6 +1082,7 @@ def work_facets(self, queryset, taxonomy_toc):
self.facet_consolidation(work_facets, queryset)
self.facet_repeal(work_facets, queryset)
self.facet_taxonomy(taxonomy_toc, queryset)
self.facet_place(places_toc, queryset)
return work_facets

def document_facets(self, queryset):
Expand Down Expand Up @@ -1282,6 +1297,33 @@ def decorate(item):
for item in taxonomy_tree:
decorate(item)

def facet_place(self, place_tree, qs):
if not place_tree:
return

qs = self.filter_queryset(qs, exclude="place")

# count works per place
counts = {}
for row in qs.values("country__country__pk", "locality__code").annotate(count=Count("id")).order_by():
code = row["country__country__pk"].lower()
code = code + ("-" + row["locality__code"] if row["locality__code"] else "")
counts[code] = row["count"]

# fold the counts into the taxonomy tree
def decorate(item):
total = 0
for child in item.get('children', []):
total = total + decorate(child)
# count for this item
item['data']['count'] = counts.get(item["data"]["slug"])
# total of count for descendants
item['data']['total'] = total
return total + (item['data']['count'] or 0)

for item in place_tree:
decorate(item)


class WorkChooserForm(forms.Form):
country = forms.ModelChoiceField(queryset=Country.objects)
Expand Down Expand Up @@ -1319,7 +1361,22 @@ def clean_all_work_pks(self):
return self.cleaned_data.get('all_work_pks').split() or []


class WorkBulkUpdateForm(forms.Form):
class WorkBulkActionFormBase(forms.Form):
"""Base form for bulk work actions in the works listing view. Ensures that the works queryset is
limited to the appropriate country, locality and user permissions.
"""
works = forms.ModelMultipleChoiceField(queryset=Work.objects, required=True)

def __init__(self, country, locality, user, *args, **kwargs):
super().__init__(*args, **kwargs)

if country.place_code == 'all':
self.fields['works'].queryset = AllPlace.filter_works_queryset(self.fields['works'].queryset, user)
else:
self.fields['works'].queryset = self.fields['works'].queryset.filter(country=country, locality=locality)


class WorkBulkUpdateForm(WorkBulkActionFormBase):
save = forms.BooleanField(required=False)
works = forms.ModelMultipleChoiceField(queryset=Work.objects, required=False)
add_taxonomy_topics = forms.ModelMultipleChoiceField(
Expand All @@ -1339,10 +1396,10 @@ def save_changes(self):
work.taxonomy_topics.remove(*self.cleaned_data['del_taxonomy_topics'])


class WorkBulkApproveForm(forms.Form):
class WorkBulkApproveForm(WorkBulkActionFormBase):
TASK_CHOICES = [('', 'Create tasks'), ('block', _('Create and block tasks')), ('cancel', _('Create and cancel tasks'))]

works_in_progress = forms.ModelMultipleChoiceField(queryset=Work.objects, required=False)
works = forms.ModelMultipleChoiceField(queryset=Work.objects, required=False)
conversion_task_description = forms.CharField(required=False)
import_task_description = forms.CharField(required=False)
gazette_task_description = forms.CharField(required=False)
Expand All @@ -1358,7 +1415,7 @@ def __init__(self, *args, **kwargs):
broker_class = kwargs.pop('broker_class', TaskBroker)
super().__init__(*args, **kwargs)
if self.is_valid():
self.broker = broker_class(self.cleaned_data.get('works_in_progress', []))
self.broker = broker_class(self.cleaned_data.get('works', []))
self.add_amendment_task_description_fields()
self.full_clean()

Expand All @@ -1373,8 +1430,8 @@ def save_changes(self, request):
self.broker.create_tasks(request.user, self.cleaned_data)


class WorkBulkUnapproveForm(forms.Form):
approved_works = forms.ModelMultipleChoiceField(queryset=Work.objects, required=False)
class WorkBulkUnapproveForm(WorkBulkActionFormBase):
works = forms.ModelMultipleChoiceField(queryset=Work.objects, required=False)
unapprove = forms.BooleanField(required=False)


Expand Down
11 changes: 5 additions & 6 deletions indigo_app/js/components/TaxonomyTOC.vue
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
expand-all-btn-classes="btn btn-sm btn-secondary"
title-filter-clear-btn-classes="btn btn-sm btn-secondary"
title-filter-input-classes="form-field"
title-filter-placeholder="Filter by topic"
title-filter-placeholder="Filter..."
class="taxonomy-sidebar"
></la-table-of-contents-controller>
</template>
Expand All @@ -19,9 +19,9 @@
*/
export default {
name: 'TaxonomyTOC',
props: ['checkbox', 'selected'],
data () {
const taxonomy = JSON.parse(document.querySelector('#taxonomy_toc').textContent);
props: ['checkbox', 'selected', 'tree'],
data (self) {
const taxonomy = JSON.parse(document.querySelector(self.tree || '#taxonomy_toc').textContent);
const selected = (this.selected || '').split(' ');
// Set expanded state of current item and its parents
Expand All @@ -38,8 +38,7 @@ export default {
};
},
mounted () {
const toc = document.getElementsByTagName('la-table-of-contents-controller');
toc[0].addEventListener('itemRendered', (e) => {
this.$el.addEventListener('itemRendered', (e) => {
const tocItem = e.target;
if (!tocItem) return;
Expand Down
2 changes: 1 addition & 1 deletion indigo_app/templates/indigo_api/work_overview.html
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
hx-target="#work-approve-modal"
>
{% csrf_token %}
<input type="hidden" name="works_in_progress" value="{{ work.pk }}">
<input type="hidden" name="works" value="{{ work.pk }}">
<button
class="btn btn-success me-1"
data-bs-toggle="modal"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ <h5 class="modal-title">
>
{% csrf_token %}
{% for work in form.broker.works %}
<input type="hidden" name="works_in_progress" value="{{ work.pk }}">
<input type="hidden" name="works" value="{{ work.pk }}">
{% endfor %}
{% if form.broker.works %}
<div class="alert alert-warning">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ <h5 class="modal-title">
>
{% csrf_token %}
{% for work in approved_works %}
<input type="hidden" name="approved_works" value="{{ work.pk }}">
<input type="hidden" name="works" value="{{ work.pk }}">
{% endfor %}
<div class="alert alert-warning mb-3">
<p>Any documents will be unpublished.</p>
Expand Down
2 changes: 1 addition & 1 deletion indigo_app/templates/indigo_app/place/_work.html
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
<div class="border {% if work.work_in_progress %}bg-work-in-progress{% else %}bg-white{% endif %} mb-2">
<div class="d-flex p-2 pl-3 collapsed work-list-card-heading" id="work-heading-{{ work.pk }}"
data-component="WorkListCard"
hx-get="{% url 'place_works_work_detail' place=place.place_code pk=work.pk %}"
hx-get="{% url 'place_works_work_detail' place=work.place.place_code pk=work.pk %}"
hx-target="#work-detail-{{ work.pk }}"
hx-swap="innerHTML"
hx-trigger="click once"
Expand Down
2 changes: 1 addition & 1 deletion indigo_app/templates/indigo_app/place/_work_detail.html
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,7 @@
hx-swap="innerHTML"
>
{% csrf_token %}
<input type="hidden" name="works_in_progress" value="{{ work.pk }}">
<input type="hidden" name="works" value="{{ work.pk }}">
<button
class="btn btn-success btn-sm"
data-bs-toggle="modal"
Expand Down
13 changes: 11 additions & 2 deletions indigo_app/templates/indigo_app/place/_works_actions.html
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@
>
{% csrf_token %}
{% for work in works_in_progress %}
<input type="hidden" name="works_in_progress" value="{{ work.pk }}">
<input type="hidden" name="works" value="{{ work.pk }}">
{% endfor %}
<button
class="btn btn-sm btn-outline-secondary"
Expand All @@ -63,7 +63,7 @@
>
{% csrf_token %}
{% for work in approved_works %}
<input type="hidden" name="approved_works" value="{{ work.pk }}">
<input type="hidden" name="works" value="{{ work.pk }}">
{% endfor %}
<button
class="btn btn-sm btn-outline-secondary"
Expand All @@ -83,3 +83,12 @@
</div>
{% endblock actions %}
{% endif %}

{% if n_disallowed %}
<p class="alert alert-warning mt-2">
<i class="fas fa-exclamation-triangle"></i>
{% blocktrans trimmed %}
You do not have country permissions to update {{ n_disallowed }} of the selected works.
{% endblocktrans %}
</p>
{% endif %}
12 changes: 11 additions & 1 deletion indigo_app/templates/indigo_app/place/_works_facets.html
Original file line number Diff line number Diff line change
@@ -1,6 +1,16 @@
{% if places_toc %}
<div class="card mb-3">
<div class="card-body">
<div data-vue-component="TaxonomyTOC" data-checkbox="place" data-tree="#places_toc"
data-selected="{{ form.place.value|join:' ' }}"></div>
{{ places_toc|json_script:"places_toc" }}
</div>
</div>
{% endif %}
<div class="card mb-3">
<div class="card-body">
<div data-vue-component="TaxonomyTOC" data-checkbox="taxonomy_topic" data-selected="{{ form.taxonomy_topic.value|join:' ' }}"></div>
<div data-vue-component="TaxonomyTOC" data-checkbox="taxonomy_topic" data-tree="#taxonomy_toc"
data-selected="{{ form.taxonomy_topic.value|join:' ' }}"></div>
{{ taxonomy_toc|json_script:"taxonomy_toc" }}
</div>
</div>
Expand Down
2 changes: 1 addition & 1 deletion indigo_app/templates/indigo_app/place/_works_list.html
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@
<div>
<div class="btn-toolbar">
{% block work-list-actions %}
{% if perms.indigo_api.bulk_export_work %}
{% if download_xsl_url and perms.indigo_api.bulk_export_work %}
<a href="{{ download_xsl_url }}" class="btn btn-sm btn-outline-primary"><i class="fas fa-file-excel fa-fw me-1"></i>{% trans "Download to Excel" %}</a>
{% endif %}
{% endblock %}
Expand Down
24 changes: 13 additions & 11 deletions indigo_app/templates/indigo_app/place/works.html
Original file line number Diff line number Diff line change
Expand Up @@ -14,18 +14,20 @@
{% endblock %}
</div>

<div class="ms-3">
<div class="btn-group">
<a href="{% url 'new_work' place=place.place_code %}" class="btn btn-success">{% trans "Add new work" %}</a>
{% if perms.indigo_api.bulk_add_work %}
<button type="button" class="btn btn-success dropdown-toggle dropdown-toggle-split" data-bs-toggle="dropdown"></button>
<div class="dropdown-menu">
<a class="dropdown-item" href="{% url 'new_batch_work' place=place.place_code %}">{% trans "Batch add new works" %}</a>
<a class="dropdown-item" href="{% url 'update_batch_work' place=place.place_code %}">{% trans "Batch update works" %}</a>
</div>
{% endif %}
{% if place.place_code != "all" %}
<div class="ms-3">
<div class="btn-group">
<a href="{% url 'new_work' place=place.place_code %}" class="btn btn-success">{% trans "Add new work" %}</a>
{% if perms.indigo_api.bulk_add_work %}
<button type="button" class="btn btn-success dropdown-toggle dropdown-toggle-split" data-bs-toggle="dropdown"></button>
<div class="dropdown-menu">
<a class="dropdown-item" href="{% url 'new_batch_work' place=place.place_code %}">{% trans "Batch add new works" %}</a>
<a class="dropdown-item" href="{% url 'update_batch_work' place=place.place_code %}">{% trans "Batch update works" %}</a>
</div>
{% endif %}
</div>
</div>
</div>
{% endif %}
</div>
{% endblock %}

Expand Down
31 changes: 16 additions & 15 deletions indigo_app/templates/main.html
Original file line number Diff line number Diff line change
Expand Up @@ -36,22 +36,8 @@
{% if request.user.is_authenticated %}
<li class="nav-item"><a class="nav-link" href="/">{% trans "Home" %}</a></li>
<li class="nav-item"><a class="nav-link" href="{% url 'my_tasks' %}">{% trans "Tasks" %}</a></li>
<li class="nav-item"><a class="nav-link" href="{% url 'place_works' 'all' %}">{% trans "Works" %}</a></li>
{% endif %}
{% block navbar-help-menu %}
<li class="nav-item dropdown">
<a href="#" class="nav-link dropdown-toggle" data-bs-toggle="dropdown">{% trans "Help" %}</a>
<div class="dropdown-menu">
<a class="dropdown-item" href="{% url 'help' %}" target="_blank"><i class="fas fa-question fa-fw"></i> {% trans "Documentation" %}</a>
<a class="dropdown-item" href="mailto:[email protected]" target="_blank"><i class="fas fa-envelope fa-fw"></i> {% trans "Feedback" %}</a>

<div class="dropdown-divider"></div>
<a class="dropdown-item" href="https://github.com/laws-africa/indigo" target="_blank"><i class="fab fa-github fa-fw"></i> {% trans "Indigo on GitHub" %}</a>

<div class="dropdown-divider"></div>
<a class="dropdown-item" href="{% url 'terms_of_use' %}" target="_blank">{% trans "Terms of Use &amp; Privacy Policy" %}</a>
</div>
</li>
{% endblock %}
{% endblock %}
</ul>

Expand Down Expand Up @@ -81,6 +67,21 @@
<li class="nav-item not-logged-in"><a href="{% url 'account_login' %}?next={{ request.get_full_path|urlencode }}" class="nav-link bg-success"><i class="fas fa-sign-in-alt"></i> {% trans "Log in" %}</a></li>
{% endif %}
{% endblock %}
{% block navbar-help-menu %}
<li class="nav-item dropdown">
<a href="#" class="nav-link dropdown-toggle" data-bs-toggle="dropdown">{% trans "Help" %}</a>
<div class="dropdown-menu">
<a class="dropdown-item" href="{% url 'help' %}" target="_blank"><i class="fas fa-question fa-fw"></i> {% trans "Documentation" %}</a>
<a class="dropdown-item" href="mailto:[email protected]" target="_blank"><i class="fas fa-envelope fa-fw"></i> {% trans "Feedback" %}</a>

<div class="dropdown-divider"></div>
<a class="dropdown-item" href="https://github.com/laws-africa/indigo" target="_blank"><i class="fab fa-github fa-fw"></i> {% trans "Indigo on GitHub" %}</a>

<div class="dropdown-divider"></div>
<a class="dropdown-item" href="{% url 'terms_of_use' %}" target="_blank">{% trans "Terms of Use &amp; Privacy Policy" %}</a>
</div>
</li>
{% endblock %}
</ul>

</div>
Expand Down
Loading

0 comments on commit 00722f2

Please sign in to comment.