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

Merge Staging into Production, 2023-Aug-02 edition #922

Merged
merged 25 commits into from
Aug 4, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
823330c
docker-compose.yml: add 'restart: always' to all containers
jacobdgm Jul 31, 2023
450ec68
update formatting to comply with Black
jacobdgm Jul 31, 2023
bc7d144
chant detail: concordances summary: fix Portuguese Early Music initia…
jacobdgm Jul 31, 2023
853e30b
remove noindex from templates
jacobdgm Jul 31, 2023
545c11b
Merge pull request #900 from jacobdgm/issue-899
jacobdgm Jul 31, 2023
0b78a99
Merge pull request #902 from jacobdgm/issue-901
jacobdgm Jul 31, 2023
49420ff
Merge pull request #904 from jacobdgm/issue-466
jacobdgm Jul 31, 2023
1a50c0b
Merge pull request #906 from DDMAL/develop
jacobdgm Aug 1, 2023
cf7c1b7
content overview: add tabs for models and display all objects
lucasmarchd01 Aug 1, 2023
cc3dcc2
update import statements
lucasmarchd01 Aug 1, 2023
b2be67f
global: update all normal links on site to underline when hovered over
jacobdgm Aug 1, 2023
8c995ed
Chant Search page: remove spacing below full text in each cell
jacobdgm Aug 1, 2023
5e0df4a
admin: increase source title widget length
lucasmarchd01 Aug 1, 2023
c44bdda
Merge pull request #911 from jacobdgm/formatting
jacobdgm Aug 2, 2023
d1221a3
write tests for content overview page
lucasmarchd01 Aug 2, 2023
a65efad
Merge pull request #908 from lucasmarchd01/content-overview-pagination
jacobdgm Aug 2, 2023
9e708d0
Chant Create: prevent getting suggested chants after Cantus ID of 909000
jacobdgm Aug 2, 2023
f1bce72
Change widget width for title in source admin area
lucasmarchd01 Aug 2, 2023
3ad6876
Merge pull request #919 from jacobdgm/issue-912z
jacobdgm Aug 2, 2023
76cd30f
Merge pull request #913 from lucasmarchd01/admin-source-widget
jacobdgm Aug 2, 2023
ca28644
Merge pull request #921 from DDMAL/develop
jacobdgm Aug 2, 2023
fb5b8eb
add content overview to permissions test suite
lucasmarchd01 Aug 2, 2023
a09d269
write content-overview permissions tests for default and editor
lucasmarchd01 Aug 2, 2023
7e72fec
Merge pull request #923 from lucasmarchd01/content-overview-test-suite
jacobdgm Aug 2, 2023
aa280f1
Merge pull request #924 from DDMAL/develop
jacobdgm Aug 2, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
1 change: 1 addition & 0 deletions django/cantusdb_project/main_app/forms.py
Original file line number Diff line number Diff line change
Expand Up @@ -826,6 +826,7 @@ class Meta:
widget=AdminTextInputWidget,
help_text="Full Manuscript Identification (City, Archive, Shelf-mark)",
)
title.widget.attrs.update({"style": "width: 610px;"})

siglum = forms.CharField(
required=True,
Expand Down
4 changes: 2 additions & 2 deletions django/cantusdb_project/main_app/templates/chant_search.html
Original file line number Diff line number Diff line change
Expand Up @@ -233,9 +233,9 @@ <h3>Search Chants</h3>
{% else %}
<b><a href="{% url 'sequence-detail' chant.id %}">{{ chant.incipit|default:"" }}</a></b>
{% endif %}
<p>
<div>
{{ chant.manuscript_full_text_std_spelling|default:""|truncatewords_html:100 }}
</p>
</div>
</td>
<td class="text-wrap" style="text-align:center">
{% if chant.feast__id %}
Expand Down
149 changes: 84 additions & 65 deletions django/cantusdb_project/main_app/templates/content_overview.html
Original file line number Diff line number Diff line change
Expand Up @@ -5,79 +5,98 @@

<div class="mr-3 p-3 col-md-12 mx-auto bg-white rounded">
<h3>Content Overview</h3>
<table class="table table-sm small table-bordered">
<small>Displaying the <b>50</b> most recently updated objects</small>
<div style="height:10px;"></div>
<thead>
<tr>
<th scope="col" class="text-wrap" style="text-align:center">Title / Manuscript Full Text / Name</th>
<th scope="col" class="text-wrap" style="text-align:center">Type</th>
<th scope="col" class="text-wrap" style="text-align:center">Creation Date</th>
<th scope="col" class="text-wrap" style="text-align:center">Creator</th>
<th scope="col" class="text-wrap" style="text-align:center">Last Updated Date</th>
<th scope="col" class="text-wrap" style="text-align:center">Last Updated By</th>
<th scope="col" class="text-wrap" style="text-align:center">Operations</th>
</tr>
</thead>
<tbody>
{% for object in objects %}

<div class="row justify-content-center">
{% for model_name in models %}
<div class="col-auto">
{% if model_name == selected_model_name %}
<b>{{ model_name|capfirst }}</b>
{% else %}
<a href="?model={{ model_name }}">{{ model_name|capfirst }}</a>
{% endif %}
</div>
{% endfor %}
</div>
<div style="height:10px;"></div>
{% if selected_model_name %}
<table class="table table-sm small table-bordered">
<small>Displaying {{ page_obj.start_index }}-{{ page_obj.end_index }} of <b>{{ page_obj.paginator.count }}
{{ selected_model_name|capfirst }}</b></small>
<thead>
<tr>
{% if object.title %}
<td class="text-wrap" style="text-align:center">
<a href="{{ object.get_absolute_url }}"><b>{{ object.title|truncatechars:30 }}</b></a>
</td>
{% elif object.manuscript_full_text_std_spelling %}
<td class="text-wrap" style="text-align:center">
<a href="{{ object.get_absolute_url }}"><b>{{ object.manuscript_full_text_std_spelling|truncatechars:30 }}</b></a>
</td>
{% elif object.name %}
<th scope="col" class="text-wrap" style="text-align:center">Title / Manuscript Full Text / Name</th>
<th scope="col" class="text-wrap" style="text-align:center">Type</th>
<th scope="col" class="text-wrap" style="text-align:center">Creation Date</th>
<th scope="col" class="text-wrap" style="text-align:center">Creator</th>
<th scope="col" class="text-wrap" style="text-align:center">Last Updated Date</th>
<th scope="col" class="text-wrap" style="text-align:center">Last Updated By</th>
<th scope="col" class="text-wrap" style="text-align:center">Operations</th>
</tr>
</thead>
<tbody>
{% for object in page_obj %}
<tr>
{% if object.title %}
<td class="text-wrap" style="text-align:center">
<a href="{{ object.get_absolute_url }}"><b>{{ object.title|truncatechars:30 }}</b></a>
</td>
{% elif object.manuscript_full_text_std_spelling %}
<td class="text-wrap" style="text-align:center">
<a href="{{ object.get_absolute_url }}"><b>{{ object.manuscript_full_text_std_spelling|truncatechars:30 }}</b></a>
</td>
{% elif object.name %}
<td class="text-wrap" style="text-align:center">
{% if object|classname == "Notation" or object|classname == "Segment" or object|classname == "RismSiglum" %}
<b>{{ object.name|truncatechars:30 }}
{% else %}
<a href="{{ object.get_absolute_url }}"><b>{{ object.name|truncatechars:30 }}</b></a>
{% endif %}
</td>
{% elif object.full_name %}
<td class="text-wrap" style="text-align:center">
<a href="{{ object.get_absolute_url }}"><b>{{ object.full_name }}</b></a>
</td>
{% else %}
<td class="text-wrap" style="text-align:center">
<a href="{{ object.get_absolute_url }}"><b>{{ object|classname }} Object</b></a>
</td>
{% endif %}
<td class="text-wrap" style="text-align:center">{{ object|classname }}</td>
<td class="text-wrap" style="text-align:center">{{ object.date_created|date:'Y-m-d H:i' }}</td>
<td class="text-wrap" style="text-align:center">
{% if object|classname == "Notation" or object|classname == "Provenance" or object|classname == "Segment" %}
<b>{{ object.name|truncatechars:30 }}
{% if object.created_by is None %}
{{ object.created_by }}
{% else %}
<a href="{{ object.get_absolute_url }}"><b>{{ object.name|truncatechars:30 }}</b></a>
<a href="{% url 'admin:users_user_change' object.created_by.id %}">
{{ object.created_by }}
</a>
{% endif %}
</td>
{% elif object.full_name %}
<td class="text-wrap" style="text-align:center">{{ object.date_updated|date:'Y-m-d H:i' }}</td>
<td class="text-wrap" style="text-align:center">
<a href="{{ object.get_absolute_url }}"><b>{{ object.full_name }}</b></a>
{% if object.last_updated_by is None %}
{{ object.last_updated_by }}
{% else %}
<a href="{% url 'admin:users_user_change' object.last_updated_by.id %}">
{{ object.last_updated_by }}
</a>
{% endif %}
</td>
{% else %}
<td class="text-wrap" style="text-align:center">
<a href="{{ object.get_absolute_url }}"><b>{{ object|classname }} Object</b></a>
{% with class=object|classname %}
<a href={% url class|admin_url_name:"change" object.id %}><b>Edit</b></a>
|
<a href={% url class|admin_url_name:"delete" object.id %}><b>Delete</b></a>
{% endwith %}
</td>
{% endif %}
<td class="text-wrap" style="text-align:center">{{ object|classname }}</td>
<td class="text-wrap" style="text-align:center">{{ object.date_created|date:'Y-m-d H:i' }}</td>
<td class="text-wrap" style="text-align:center">
{% if object.created_by is None %}
{{ object.created_by }}
{% else %}
<a href="{% url 'admin:users_user_change' object.created_by.id %}">
{{ object.created_by }}
</a>
{% endif %}
</td>
<td class="text-wrap" style="text-align:center">{{ object.date_updated|date:'Y-m-d H:i' }}</td>
<td class="text-wrap" style="text-align:center">
{% if object.last_updated_by is None %}
{{ object.last_updated_by }}
{% else %}
<a href="{% url 'admin:users_user_change' object.last_updated_by.id %}">
{{ object.last_updated_by }}
</a>
{% endif %}
</td>
<td class="text-wrap" style="text-align:center">
{% with class=object|classname %}
<a href={% url class|admin_url_name:"change" object.id %}><b>Edit</b></a>
|
<a href={% url class|admin_url_name:"delete" object.id %}><b>Delete</b></a>
{% endwith %}
</td>
</tr>
{% endfor %}
</tbody>
</table>
</tr>
{% endfor %}
</tbody>
</table>
{% include "pagination.html" %}
{% else %}
<div style="height:10px;"></div>
Please select a model from the tabs to view the most recently updated objects.
{% endif %}
</div>
{% endblock %}
2 changes: 0 additions & 2 deletions django/cantusdb_project/main_app/templates/full_index.html
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,6 @@
<html>

<head>
<!-- prevent search engines from indexing the staging website, remove for production -->
<meta name="robots" content="noindex">
<!-- Bootstrap CSS -->
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.5.0/css/bootstrap.min.css"
integrity="sha384-9aIt2nRpC12Uk9gS9baDl411NQApFmC26EwAOH8WgZl5MYYxFfc+NcPb1dKGj7Sk" crossorigin="anonymous">
Expand Down
89 changes: 89 additions & 0 deletions django/cantusdb_project/main_app/tests/test_views.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
make_fake_genre,
make_fake_office,
make_fake_provenance,
make_fake_notation,
make_fake_rism_siglum,
make_fake_segment,
make_fake_sequence,
Expand Down Expand Up @@ -156,6 +157,10 @@ def test_permissions_project_manager(self):
response = self.client.get(f"/edit-source/{source.id}")
self.assertEqual(response.status_code, 200)

# ContentOverview
response = self.client.get(reverse("content-overview"))
self.assertEqual(response.status_code, 200)

def test_permissions_contributor(self):
contributor = Group.objects.get(name="contributor")
contributor.user_set.add(self.user)
Expand Down Expand Up @@ -245,6 +250,9 @@ def test_permissions_contributor(self):
response = self.client.get(f"/edit-source/{assigned_source.id}")
self.assertEqual(response.status_code, 403)

response = self.client.get(reverse("content-overview"))
self.assertEqual(response.status_code, 403)

def test_permissions_editor(self):
editor = Group.objects.get(name="editor")
editor.user_set.add(self.user)
Expand Down Expand Up @@ -334,6 +342,9 @@ def test_permissions_editor(self):
response = self.client.get(f"/edit-source/{assigned_source.id}")
self.assertEqual(response.status_code, 200)

response = self.client.get(reverse("content-overview"))
self.assertEqual(response.status_code, 403)

def test_permissions_default(self):
self.client.login(email="test@test.com", password="pass")

Expand Down Expand Up @@ -366,6 +377,9 @@ def test_permissions_default(self):
response = self.client.get(f"/edit-source/{source.id}")
self.assertEqual(response.status_code, 403)

response = self.client.get(reverse("content-overview"))
self.assertEqual(response.status_code, 403)


class CenturyDetailViewTest(TestCase):
def test_view_url_path(self):
Expand Down Expand Up @@ -5132,3 +5146,78 @@ def test_indexer_redirect_bad(self):
reverse("redirect-indexer", args=[example_bad_indexer_id])
)
self.assertEqual(response_1.status_code, 404)


class ContentOverviewTest(TestCase):
@classmethod
def setUpTestData(cls):
Group.objects.create(name="project manager")

def setUp(self):
self.user = get_user_model().objects.create(email="test@test.com")
self.user.set_password("pass")
self.user.save()
self.client = Client()

project_manager = Group.objects.get(name="project manager")
project_manager.user_set.add(self.user)
self.client.login(email="test@test.com", password="pass")

def test_templates_used(self):
response = self.client.get(reverse("content-overview"))
self.assertTemplateUsed(response, "base.html")
self.assertTemplateUsed(response, "content_overview.html")

def test_project_manager_permission(self):
response = self.client.get(reverse("content-overview"))
self.assertEqual(response.status_code, 200)

def test_content_overview_view_with_login_required(self):
self.client.logout()
response = self.client.get(reverse("content-overview"))
self.assertRedirects(response, "/login/?next=/content-overview/")

def test_content_overview_view_for_non_project_manager(self):
user = get_user_model().objects.create(email="non_project_manager@test.com")
user.set_password("pass")
user.save()
self.client.login(email="non_project_manager@test.com", password="pass")

response = self.client.get(reverse("content-overview"))
self.assertEqual(response.status_code, 403)

def test_content_overview_view_selected_model(self):
response = self.client.get(reverse("content-overview"), {"model": "sources"})
self.assertEqual(response.status_code, 200)

self.assertIsNotNone(response.context["models"])
models = response.context["models"]
self.assertIsNotNone(response.context["page_obj"])
page_obj = response.context["page_obj"]
self.assertEqual(response.context["selected_model_name"], "sources")

def test_source_selected_model(self):
source = make_fake_source(title="Test Source")
chant = make_fake_chant(incipit="Test Chant")
response = self.client.get(reverse("content-overview"), {"model": "sources"})
self.assertContains(response, f"<b>Sources</b>", html=True)
self.assertContains(
response,
f'<a href="?model=chants">Chants</a>',
html=True,
)
self.assertContains(response, "Test Source", html=True)
self.assertNotContains(response, "Test Chant", html=True)

def test_chant_selected_model(self):
source = make_fake_source(title="Test Source")
chant = make_fake_chant(manuscript_full_text_std_spelling="Test Chant")
response = self.client.get(reverse("content-overview"), {"model": "chants"})
self.assertContains(response, f"<b>Chants</b>", html=True)
self.assertContains(
response,
f'<a href="?model=sources">Sources</a>',
html=True,
)
self.assertContains(response, "Test Chant", html=True)
self.assertNotContains(response, "Test Source", html=True)
8 changes: 7 additions & 1 deletion django/cantusdb_project/main_app/views/chant.py
Original file line number Diff line number Diff line change
Expand Up @@ -350,7 +350,7 @@ def get_context_data(self, **kwargs):
},
{
"name": "Portuguese Early Music Database",
"initialism": "MMMO",
"initialism": "PEM",
"base_url": "https://pemdatabase.eu",
"results_url": f"https://pemdatabase.eu/id/{chant.cantus_id}",
"results_count": len(
Expand Down Expand Up @@ -1182,6 +1182,12 @@ def get_suggested_chants(self):
cantus_id = latest_chant.cantus_id
if cantus_id is None:
return None
if cantus_id == "909000":
# 909000 is the Cantus ID for "Gloria patri", the most common Cantus ID in the
# database by about a factor of ~10 compared to the second most common Cantus ID.
# It takes too long to calculate suggested chants for this Cantus ID, and the
# results aren't particularly useful anyways.
return None

suggested_chants = next_chants(cantus_id, display_unpublished=True)

Expand Down