Skip to content

Commit

Permalink
Bulk publish labels (#1141)
Browse files Browse the repository at this point in the history
  • Loading branch information
shapiromatron authored Dec 4, 2024
1 parent bdd47bb commit 38fbf72
Show file tree
Hide file tree
Showing 10 changed files with 135 additions and 40 deletions.
26 changes: 26 additions & 0 deletions hawc/apps/assessment/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -1379,6 +1379,9 @@ def save(self, *args, **kwargs):
def get_nested_name(self) -> str:
return "<root-node>" if self.is_root() else f"{'━ ' * (self.depth - 1)}{self.name}"

def get_labelled_items_url(self):
return reverse("assessment:labeled-items", args=(self.assessment_id,)) + f"?label={self.id}"

def get_absolute_url(self):
return reverse("assessment:label-htmx", args=(self.pk, "read"))

Expand All @@ -1388,6 +1391,29 @@ def get_edit_url(self):
def get_delete_url(self):
return reverse("assessment:label-htmx", args=(self.pk, "delete"))

def can_change_published(self) -> tuple[bool, str]:
"""Check that the item can be published or unpublished
Returns:
tuple[bool, str]: boolean, status message if false
"""
next = not self.published
if next:
if self.depth == 1:
# any depth of 1 tag can be published
return True, ""
parent_published = self.get_parent().published
return (
parent_published,
"" if parent_published else "Parent must be published to publish child",
)
else:
all_unpublished = all(child.published is False for child in self.get_children())
return (
all_unpublished,
"" if all_unpublished else "All children must be unpublished to unpublish",
)


class LabeledItem(models.Model):
objects = managers.LabeledItemManager()
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{% if anchor_tag %}
<a class="{% if not big %} tny {% endif %} {{extra_classes}} label m-1" href="{% url 'assessment:labeled-items' assessment.pk %}?label={{label.pk}}" style="background-color: {{label.color}}; color: {{label.text_color}};" title="{{label.description}}">{{label.name}}</a>
<a class="{% if not big %} tny {% endif %} {{extra_classes}} label m-1" href="{{label.get_labelled_items_url}}" style="background-color: {{label.color}}; color: {{label.text_color}};" title="{{label.description}}">{{label.name}}</a>
{% else %}
<div class="{% if not big %} tny {% endif %} {{extra_classes}} label m-1" label_url="{% url 'assessment:labeled-items' assessment.pk %}?label={{label.pk}}" style="background-color: {{label.color}}; color: {{label.text_color}};" title="{{label.description}}">{{label.name}}</div>
<div class="{% if not big %} tny {% endif %} {{extra_classes}} label m-1" label_url="{{label.get_labelled_items_url}}" style="background-color: {{label.color}}; color: {{label.text_color}};" title="{{label.description}}">{{label.name}}</div>
{% endif %}
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
<div class="row">
{% widthratio object.depth 10 20 as marginLeft %}
<i class="fa fa-spinner fa-spin htmx-indicator align-self-start m-1" id="spinner-{{object.pk}}" aria-hidden="true"></i>
<p class="label align-self-start mt-0" style="background-color: {{object.color}}; color: {{object.text_color}}; {% if object.depth > 0 %} margin-left: {{ marginLeft|add:"-4" }}rem;{% endif %}" label_url="{% url 'assessment:labeled-items' assessment.pk %}?label={{object.id}}">{{object.name}}</p>
<p class="label align-self-start mt-0" style="background-color: {{object.color}}; color: {{object.text_color}}; {% if object.depth > 0 %} margin-left: {{ marginLeft|add:"-4" }}rem;{% endif %}" label_url="{{object.get_labelled_items_url}}">{{object.name}}</p>
<div class="card mx-3 d-inline-block align-self-start {{ object.published|yesno:'border-success text-success,text-muted' }}" title="{{ object.published|yesno:'Published,Unpublished' }}">
<p class="m-0"><i class="fa fa-{{ object.published|yesno:'eye,eye-slash' }} px-1"></i></p>
</div>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,5 @@
<span class="fa fa-spin fa-spinner float-right htmx-indicator"></span>
</div>
</form>
{% if can_update_message %}<span class="text-danger">{{can_update_message}}</span>{% endif %}
</td>
62 changes: 28 additions & 34 deletions hawc/apps/assessment/templates/assessment/published_items.html
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,8 @@ <h2>Modify published items</h2>
<h3>Studies</h3>
<p class="help-text">View all <a href="{% url 'study:list' assessment.id %}">studies</a>.</p>
<table class="table table-sm table-bordered">
<thread>
<tr>
<th>Published</th>
<th>Study</th>
</tr>
</thread>
{% bs4_colgroup '20,80' %}
{% bs4_thead 'Published,Study' %}
<tbody>
{% for study in studies %}
<tr>
Expand All @@ -38,12 +34,8 @@ <h3>Studies</h3>
<h3>Visuals</h3>
<p class="help-text">View all <a href="{% url 'summary:visualization_list' assessment.id %}">visuals</a>.</p>
<table class="table table-sm table-bordered">
<thread>
<tr>
<th>Published</th>
<th>Visual</th>
</tr>
</thread>
{% bs4_colgroup '20,80' %}
{% bs4_thead 'Published,Visual' %}
<tbody>
{% for dp in datapivots %}
{% if forloop.first %}
Expand Down Expand Up @@ -82,12 +74,8 @@ <h3>Visuals</h3>
<h3>Summary tables</h3>
<p class="help-text">View all <a href="{% url 'summary:tables_list' assessment.id %}">tables</a>.</p>
<table class="table table-sm table-bordered">
<thread>
<tr>
<th>Published</th>
<th>Summary tables</th>
</tr>
</thread>
{% bs4_colgroup '20,80' %}
{% bs4_thead 'Published,Table' %}
<tbody>
{% for table in summarytables %}
<tr>
Expand All @@ -101,17 +89,11 @@ <h3>Summary tables</h3>
{% endfor %}
</tbody>
</table>
</div>
<div class='col-xl-4'>
<h3>Datasets</h3>
<p class="help-text">View all <a href="{{assessment.get_absolute_url}}">datasets</a>.</p>
<table class="table table-sm table-bordered">
<thread>
<tr>
<th>Published</th>
<th>Dataset</th>
</tr>
</thread>
{% bs4_colgroup '20,80' %}
{% bs4_thead 'Published,Dataset' %}
<tbody>
{% for dataset in datasets %}
<tr>
Expand All @@ -125,17 +107,11 @@ <h3>Datasets</h3>
{% endfor %}
</tbody>
</table>
</div>
<div class='col-xl-4'>
<h3>Attachments</h3>
<p class="help-text">View all <a href="{{assessment.get_absolute_url}}">attachments</a>.</p>
<table class="table table-sm table-bordered">
<thread>
<tr>
<th>Published</th>
<th>Assessment Attachments</th>
</tr>
</thread>
{% bs4_colgroup '20,80' %}
{% bs4_thead 'Published,Assessment Attachments' %}
<tbody>
{% for attachment in attachments %}
<tr>
Expand All @@ -149,6 +125,24 @@ <h3>Attachments</h3>
{% endfor %}
</tbody>
</table>
<h3>Labels</h3>
<p class="help-text">View all <a href="{% url 'assessment:manage-labels' assessment.id %}">labels</a>. All parent labels must be published in order to publish a child label. All children must be unpublished to unpublish a parent label.</p>
<table class="table table-sm table-bordered">
{% bs4_colgroup '20,80' %}
{% bs4_thead 'Published,Label' %}
<tbody>
{% for label in labels %}
<tr>
{% include 'assessment/fragments/publish_item_td.html' with name="label" object=label %}
<td><a href="{{label.get_labelled_items_url}}">{{label.get_nested_name}}</a></td>
</tr>
{% empty %}
<tr>
<td colspan="2"><i>No labels exist.</i></td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
</div>
{% endblock content %}
19 changes: 17 additions & 2 deletions hawc/apps/assessment/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -817,6 +817,7 @@ class PublishedItemsChecklist(HtmxViewSet):
"dataset": apps.get_model("assessment", "Dataset"),
"summarytable": apps.get_model("summary", "SummaryTable"),
"attachment": apps.get_model("assessment", "Attachment"),
"label": models.Label,
}

@action(permission=can_edit, htmx_only=False)
Expand All @@ -830,13 +831,25 @@ def list(self, request: HttpRequest, *args, **kwargs):
@action(permission=can_edit, methods={"post"})
def update_item(self, request: HttpRequest, *args, **kwargs):
instance = self.get_instance(request.item, kwargs["type"], kwargs["object_id"])
self.perform_update(request, instance)
can_update, can_update_message = self.can_update(instance)
if can_update:
self.perform_update(request, instance)
return render(
request,
"assessment/fragments/publish_item_td.html",
{"name": kwargs["type"], "object": instance, "assessment": request.item.assessment},
{
"name": kwargs["type"],
"object": instance,
"assessment": request.item.assessment,
"can_update_message": can_update_message,
},
)

def can_update(self, instance) -> tuple[bool, str]:
if hasattr(instance, "can_change_published"):
return instance.can_change_published()
return True, ""

def get_instance(self, item, type: str, object_id: int):
Model = self.model_lookups.get(type)
if not Model:
Expand Down Expand Up @@ -884,6 +897,7 @@ def get_list_context_data(self, user, assessment):
attachments = apps.get_model("assessment", "Attachment").objects.get_attachments(
assessment, False
)
labels = models.Label.get_assessment_qs(assessment.pk, include_root=False)
return {
"assessment": assessment,
"breadcrumbs": crumbs,
Expand All @@ -893,6 +907,7 @@ def get_list_context_data(self, user, assessment):
"datasets": datasets,
"summarytables": summarytables,
"attachments": attachments,
"labels": labels,
}


Expand Down
3 changes: 3 additions & 0 deletions hawc/apps/summary/templates/summary/visual_detail_prisma.html
Original file line number Diff line number Diff line change
Expand Up @@ -7,17 +7,20 @@
{% block content %}
<div class='d-flex'>
<h2>{{object.title}}</h2>
{% include "assessment/fragments/label_indicators.html" %}
{% include "common/unpublished_badge.html" %}
{% if obj_perms.edit %}
{% actions %}
<span class="dropdown-header">Visualization editing</span>
<a class="dropdown-item" href="{% url 'summary:visualization_update' assessment.pk object.slug %}">Update</a>
<a class="dropdown-item" href="{% url 'summary:visualization_delete' assessment.pk object.slug %}">Delete</a>
{% include "assessment/components/label_modal_button.html" with icon=False %}
{% endactions %}
{% endif %}
</div>
<div id='visualization'></div>
<p>{{object.caption|safe}}</p>
{% include "assessment/components/label_modal.html" with modal_id="label-modal" %}
{% endblock %}

{% block extrajs %}
Expand Down
8 changes: 8 additions & 0 deletions tests/data/fixtures/db.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -598,6 +598,14 @@
fields:
app_label: udf
model: tagudfcontent
- model: contenttypes.contenttype
fields:
app_label: assessment
model: label
- model: contenttypes.contenttype
fields:
app_label: assessment
model: labeleditem
- model: auth.permission
fields:
name: Can access Wagtail admin
Expand Down
37 changes: 37 additions & 0 deletions tests/hawc/apps/assessment/test_models.py
Original file line number Diff line number Diff line change
Expand Up @@ -60,3 +60,40 @@ def test_get_peer_review_status_display(self):

obj = models.AssessmentDetail(peer_review_status=constants.PeerReviewType.OTHER)
assert obj.get_peer_review_status_display() == ""


@pytest.mark.django_db
class TestLabel:
def test_get_labelled_items_url(self):
assessment = models.Assessment.objects.get(id=1)
root = models.Label.get_assessment_root(assessment.id)
root.add_child(name="test", published=False, assessment=assessment)
assert "/labeled-items/" in root.get_labelled_items_url()

def test_can_change_published(self):
assessment = models.Assessment.objects.get(id=1)
root = models.Label.get_assessment_root(assessment.id)
a = root.add_child(name="a", published=False, assessment=assessment)
a1 = a.add_child(name="a1", published=False, assessment=assessment)

# can change parent but not child
status, _ = a.can_change_published()
assert status is True
status, _ = a1.can_change_published()
assert status is False
a.published = True
a.save()

# can change child now
status, _ = a.can_change_published()
assert status is True
status, _ = a1.can_change_published()
assert status is True
a1.published = True
a1.save()

# can change child but not parent
status, _ = a.can_change_published()
assert status is False
status, _ = a1.can_change_published()
assert status is True
13 changes: 12 additions & 1 deletion tests/hawc/apps/assessment/test_views.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
from pytest_django.asserts import assertTemplateUsed

from hawc.apps.assessment.forms import ContactForm
from hawc.apps.assessment.models import Assessment
from hawc.apps.assessment.models import Assessment, Label
from hawc.apps.myuser.models import HAWCUser
from hawc.apps.study.models import Study

Expand Down Expand Up @@ -388,6 +388,17 @@ def test_updates_item(self):
study.refresh_from_db()
assert study.published is False

def test_publish_label(self):
label = Label.objects.get(id=2)
assert label.published is True
url = reverse("assessment:publish-update", args=(1, "label", label.id))
pm = get_client("pm", api=False, htmx=True)
pm.post(url)
label.refresh_from_db()
assert label.published is False
label.published = True
label.save()


@pytest.mark.django_db
class TestUpdateSession:
Expand Down

0 comments on commit 38fbf72

Please sign in to comment.