diff --git a/django/cantusdb_project/main_app/admin/__init__.py b/django/cantusdb_project/main_app/admin/__init__.py
index 6c0fac619..49a75893d 100644
--- a/django/cantusdb_project/main_app/admin/__init__.py
+++ b/django/cantusdb_project/main_app/admin/__init__.py
@@ -4,7 +4,7 @@
from main_app.admin.feast import FeastAdmin
from main_app.admin.genre import GenreAdmin
from main_app.admin.notation import NotationAdmin
-from main_app.admin.office import OfficeAdmin
+from main_app.admin.service import ServiceAdmin
from main_app.admin.provenance import ProvenanceAdmin
from main_app.admin.segment import SegmentAdmin
from main_app.admin.sequence import SequenceAdmin
diff --git a/django/cantusdb_project/main_app/admin/chant.py b/django/cantusdb_project/main_app/admin/chant.py
index 425ca9e12..e5524468b 100644
--- a/django/cantusdb_project/main_app/admin/chant.py
+++ b/django/cantusdb_project/main_app/admin/chant.py
@@ -12,7 +12,7 @@ def get_queryset(self, request):
return (
super()
.get_queryset(request)
- .select_related("source__holding_institution", "genre", "office")
+ .select_related("source__holding_institution", "genre", "service")
)
@admin.display(description="Source Siglum")
@@ -36,7 +36,7 @@ def get_source_siglum(self, obj):
list_filter = (
"genre",
- "office",
+ "service",
)
exclude = EXCLUDE + (
"col1",
diff --git a/django/cantusdb_project/main_app/admin/office.py b/django/cantusdb_project/main_app/admin/office.py
deleted file mode 100644
index d31d56534..000000000
--- a/django/cantusdb_project/main_app/admin/office.py
+++ /dev/null
@@ -1,11 +0,0 @@
-from django.contrib import admin
-
-from main_app.admin.base_admin import BaseModelAdmin
-from main_app.forms import AdminOfficeForm
-from main_app.models import Office
-
-
-@admin.register(Office)
-class OfficeAdmin(BaseModelAdmin):
- search_fields = ("name",)
- form = AdminOfficeForm
diff --git a/django/cantusdb_project/main_app/admin/sequence.py b/django/cantusdb_project/main_app/admin/sequence.py
index 1f2f0909f..252e1515f 100644
--- a/django/cantusdb_project/main_app/admin/sequence.py
+++ b/django/cantusdb_project/main_app/admin/sequence.py
@@ -11,7 +11,7 @@ def get_queryset(self, request):
return (
super()
.get_queryset(request)
- .select_related("source__holding_institution", "genre", "office")
+ .select_related("source__holding_institution", "genre", "service")
)
@admin.display(description="Source Siglum")
@@ -34,7 +34,7 @@ def get_source_siglum(self, obj):
list_display = ("incipit", "get_source_siglum", "genre")
list_filter = (
"genre",
- "office",
+ "service",
)
raw_id_fields = (
"source",
diff --git a/django/cantusdb_project/main_app/admin/service.py b/django/cantusdb_project/main_app/admin/service.py
new file mode 100644
index 000000000..77ad37858
--- /dev/null
+++ b/django/cantusdb_project/main_app/admin/service.py
@@ -0,0 +1,11 @@
+from django.contrib import admin
+
+from main_app.admin.base_admin import BaseModelAdmin
+from main_app.forms import AdminServiceForm
+from main_app.models import Service
+
+
+@admin.register(Service)
+class ServiceAdmin(BaseModelAdmin):
+ search_fields = ("name",)
+ form = AdminServiceForm
diff --git a/django/cantusdb_project/main_app/forms.py b/django/cantusdb_project/main_app/forms.py
index 9e4807f43..e1f6e11f8 100644
--- a/django/cantusdb_project/main_app/forms.py
+++ b/django/cantusdb_project/main_app/forms.py
@@ -2,7 +2,7 @@
from django.contrib.auth.forms import ReadOnlyPasswordHashField
from .models import (
Chant,
- Office,
+ Service,
Genre,
Notation,
Feast,
@@ -37,9 +37,9 @@ class NameModelChoiceField(forms.ModelChoiceField):
"""
A custom ModelChoiceField that overrides the label_from_instance method
to display the object's name attribute instead of str(object).
- This field is specifically designed for handling genre and office objects.
+ This field is specifically designed for handling genre and service objects.
Rather than displaying the name along with its description, sometimes we
- only want the shorthand notation for the genre and office objects.
+ only want the shorthand notation for the genre and service objects.
(Eg. [AV] Antiphon verse --> AV)
"""
@@ -78,7 +78,7 @@ class Meta:
"marginalia",
"folio",
"c_sequence",
- "office",
+ "service",
"genre",
"position",
"cantus_id",
@@ -113,7 +113,7 @@ class Meta:
"marginalia": TextInputWidget(),
# folio: defined below (required)
# c_sequence: defined below (required)
- "office": autocomplete.ModelSelect2(url="office-autocomplete"),
+ "service": autocomplete.ModelSelect2(url="service-autocomplete"),
"genre": autocomplete.ModelSelect2(url="genre-autocomplete"),
"position": TextInputWidget(),
"cantus_id": TextInputWidget(),
@@ -284,7 +284,7 @@ class Meta:
"folio",
"c_sequence",
"feast",
- "office",
+ "service",
"genre",
"position",
"cantus_id",
@@ -318,7 +318,7 @@ class Meta:
# folio: defined below (required)
# c_sequence: defined below (required)
"feast": autocomplete.ModelSelect2(url="feast-autocomplete"),
- "office": autocomplete.ModelSelect2(url="office-autocomplete"),
+ "service": autocomplete.ModelSelect2(url="service-autocomplete"),
"genre": autocomplete.ModelSelect2(url="genre-autocomplete"),
"position": TextInputWidget(),
"cantus_id": TextInputWidget(),
@@ -591,10 +591,10 @@ class Meta:
label="Sequence",
)
- # We use NameModelChoiceField here so the dropdown list of office/mass displays the name
+ # We use NameModelChoiceField here so the dropdown list of service/mass displays the name
# instead of [name] + description
- office = NameModelChoiceField(
- queryset=Office.objects.all().order_by("name"),
+ service = NameModelChoiceField(
+ queryset=Service.objects.all().order_by("name"),
required=False,
)
# We use NameModelChoiceField here so the dropdown list of genres displays the name
@@ -639,9 +639,9 @@ class Meta:
name.widget.attrs.update({"style": "width: 400px;"})
-class AdminOfficeForm(forms.ModelForm):
+class AdminServiceForm(forms.ModelForm):
class Meta:
- model = Office
+ model = Service
fields = "__all__"
name = forms.CharField(required=True, widget=TextInputWidget)
@@ -678,10 +678,10 @@ class Meta:
"chant_range": VolpianoAreaWidget(),
}
- # We use NameModelChoiceField here so the dropdown list of office/mass displays the name
+ # We use NameModelChoiceField here so the dropdown list of service/mass displays the name
# instead of [name] + description
- office = NameModelChoiceField(
- queryset=Office.objects.all().order_by("name"),
+ service = NameModelChoiceField(
+ queryset=Service.objects.all().order_by("name"),
required=False,
)
# We use NameModelChoiceField here so the dropdown list of genres displays the name
diff --git a/django/cantusdb_project/main_app/management/commands/update_cached_concordances.py b/django/cantusdb_project/main_app/management/commands/update_cached_concordances.py
index 47015a58b..7c0fb2ebc 100644
--- a/django/cantusdb_project/main_app/management/commands/update_cached_concordances.py
+++ b/django/cantusdb_project/main_app/management/commands/update_cached_concordances.py
@@ -62,7 +62,7 @@ def get_concordances() -> list[dict]:
"source",
"feast",
"genre",
- "office",
+ "service",
).values(
"id",
"source_id",
@@ -72,7 +72,7 @@ def get_concordances() -> list[dict]:
"incipit",
"feast__name",
"genre__name",
- "office__name",
+ "service__name",
"position",
"cantus_id",
"image_link",
@@ -112,7 +112,7 @@ def make_chant_dict(chant: dict) -> dict:
"incipit": chant["incipit"],
"feast": chant["feast__name"],
"genre": chant["genre__name"],
- "office": chant["office__name"],
+ "service": chant["service__name"],
"position": chant["position"],
"cantus_id": chant["cantus_id"],
"image": chant["image_link"],
diff --git a/django/cantusdb_project/main_app/migrations/0027_rename_office_service_rename_office_chant_service_and_more.py b/django/cantusdb_project/main_app/migrations/0027_rename_office_service_rename_office_chant_service_and_more.py
new file mode 100644
index 000000000..01120ca14
--- /dev/null
+++ b/django/cantusdb_project/main_app/migrations/0027_rename_office_service_rename_office_chant_service_and_more.py
@@ -0,0 +1,29 @@
+# Generated by Django 4.2.11 on 2024-08-07 17:10
+
+from django.conf import settings
+from django.db import migrations
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ migrations.swappable_dependency(settings.AUTH_USER_MODEL),
+ ("main_app", "0026_source_segment_m2m"),
+ ]
+
+ operations = [
+ migrations.RenameModel(
+ old_name="Office",
+ new_name="Service",
+ ),
+ migrations.RenameField(
+ model_name="chant",
+ old_name="office",
+ new_name="service",
+ ),
+ migrations.RenameField(
+ model_name="sequence",
+ old_name="office",
+ new_name="service",
+ ),
+ ]
diff --git a/django/cantusdb_project/main_app/models/__init__.py b/django/cantusdb_project/main_app/models/__init__.py
index ef755c898..ea1149eca 100644
--- a/django/cantusdb_project/main_app/models/__init__.py
+++ b/django/cantusdb_project/main_app/models/__init__.py
@@ -5,7 +5,7 @@
from main_app.models.feast import Feast
from main_app.models.genre import Genre
from main_app.models.notation import Notation
-from main_app.models.office import Office
+from main_app.models.service import Service
from main_app.models.provenance import Provenance
from main_app.models.segment import Segment
from main_app.models.sequence import Sequence
diff --git a/django/cantusdb_project/main_app/models/base_chant.py b/django/cantusdb_project/main_app/models/base_chant.py
index 7885f538a..ea208a0d1 100644
--- a/django/cantusdb_project/main_app/models/base_chant.py
+++ b/django/cantusdb_project/main_app/models/base_chant.py
@@ -56,8 +56,8 @@ class Meta:
image_link = models.URLField(blank=True, null=True)
json_info = models.JSONField(null=True, blank=True)
marginalia = models.CharField(max_length=63, null=True, blank=True)
- office = models.ForeignKey(
- "Office", on_delete=models.PROTECT, null=True, blank=True
+ service = models.ForeignKey(
+ "Service", on_delete=models.PROTECT, null=True, blank=True
)
position = models.CharField(max_length=63, null=True, blank=True)
diff --git a/django/cantusdb_project/main_app/models/chant.py b/django/cantusdb_project/main_app/models/chant.py
index 2c5986eb0..4091a2aec 100644
--- a/django/cantusdb_project/main_app/models/chant.py
+++ b/django/cantusdb_project/main_app/models/chant.py
@@ -28,7 +28,7 @@ def index_components(self) -> dict:
source = self.source.title if self.source else None
genre = self.genre.name if self.genre else None
feast = self.feast.name if self.feast else None
- office = self.office.name if self.office else None
+ service = self.service.name if self.service else None
return {
"A": (
" ".join(
@@ -38,7 +38,7 @@ def index_components(self) -> dict:
)
)
),
- "B": (" ".join(filter(None, [genre, feast, office]))),
+ "B": (" ".join(filter(None, [genre, feast, service]))),
}
def related_chants_by_cantus_id(self) -> QuerySet:
diff --git a/django/cantusdb_project/main_app/models/office.py b/django/cantusdb_project/main_app/models/service.py
similarity index 93%
rename from django/cantusdb_project/main_app/models/office.py
rename to django/cantusdb_project/main_app/models/service.py
index a4e2ff87d..34c4d119f 100644
--- a/django/cantusdb_project/main_app/models/office.py
+++ b/django/cantusdb_project/main_app/models/service.py
@@ -2,7 +2,7 @@
from main_app.models import BaseModel
-class Office(BaseModel):
+class Service(BaseModel):
name = models.CharField(max_length=3)
description = models.TextField()
diff --git a/django/cantusdb_project/main_app/templates/browse_chants.html b/django/cantusdb_project/main_app/templates/browse_chants.html
index dfdb6c020..8b9245520 100644
--- a/django/cantusdb_project/main_app/templates/browse_chants.html
+++ b/django/cantusdb_project/main_app/templates/browse_chants.html
@@ -99,8 +99,8 @@
Browse Chants
{% endif %}
- {% if chant.office %}
- {{ chant.office.name|default:"" }}
+ {% if chant.service %}
+ {{ chant.service.name|default:"" }}
{% endif %}
diff --git a/django/cantusdb_project/main_app/templates/chant_create.html b/django/cantusdb_project/main_app/templates/chant_create.html
index 18fa5fe89..36363a6f1 100644
--- a/django/cantusdb_project/main_app/templates/chant_create.html
+++ b/django/cantusdb_project/main_app/templates/chant_create.html
@@ -70,9 +70,9 @@ Create Chant
diff --git a/django/cantusdb_project/main_app/templates/chant_detail.html b/django/cantusdb_project/main_app/templates/chant_detail.html
index c885385e7..e83585a83 100644
--- a/django/cantusdb_project/main_app/templates/chant_detail.html
+++ b/django/cantusdb_project/main_app/templates/chant_detail.html
@@ -77,11 +77,11 @@ {{ chant.incipit }}
{% endif %}
- {% if chant.office %}
+ {% if chant.service %}
{% endif %}
@@ -351,8 +351,8 @@ List of melodies
{{ chant.c_sequence }}
-
- {{ chant.office.name|default_if_none:"" }}
+
+ {{ chant.service.name|default_if_none:"" }}
{{ chant.genre.name|default_if_none:"" }}
{{ chant.position|default_if_none:"" }}
@@ -385,8 +385,8 @@ List of melodies
{{ chant.c_sequence }}
-
- {{ chant.office.name|default_if_none:"" }}
+
+ {{ chant.service.name|default_if_none:"" }}
{{ chant.genre.name|default_if_none:"" }}
{{ chant.position|default_if_none:"" }}
@@ -424,8 +424,8 @@ List of melodies
{{ chant.c_sequence }}
-
- {{ chant.office.name|default_if_none:"" }}
+
+ {{ chant.service.name|default_if_none:"" }}
{{ chant.genre.name|default_if_none:"" }}
{{ chant.position|default_if_none:"" }}
diff --git a/django/cantusdb_project/main_app/templates/chant_edit.html b/django/cantusdb_project/main_app/templates/chant_edit.html
index a7751507d..038eef616 100644
--- a/django/cantusdb_project/main_app/templates/chant_edit.html
+++ b/django/cantusdb_project/main_app/templates/chant_edit.html
@@ -77,8 +77,8 @@
@@ -421,8 +421,8 @@
-
- {{ chant.office.name|default_if_none:"" }}
+
+ {{ chant.service.name|default_if_none:"" }}
{{ chant.genre.name|default_if_none:"" }}
@@ -462,8 +462,8 @@
-
- {{ chant.office.name|default_if_none:"" }}
+
+ {{ chant.service.name|default_if_none:"" }}
{{ chant.genre.name|default_if_none:"" }}
diff --git a/django/cantusdb_project/main_app/templates/chant_search.html b/django/cantusdb_project/main_app/templates/chant_search.html
index a14de48ec..601bd380a 100644
--- a/django/cantusdb_project/main_app/templates/chant_search.html
+++ b/django/cantusdb_project/main_app/templates/chant_search.html
@@ -54,11 +54,11 @@ Search Chants
- {% if chant.office %}
- {{ chant.office.name }}
+ {% if chant.service %}
+ {{ chant.service.name }}
{% endif %}
diff --git a/django/cantusdb_project/main_app/templates/chant_seq_by_cantus_id.html b/django/cantusdb_project/main_app/templates/chant_seq_by_cantus_id.html
index f1a678dfd..19543c760 100644
--- a/django/cantusdb_project/main_app/templates/chant_seq_by_cantus_id.html
+++ b/django/cantusdb_project/main_app/templates/chant_seq_by_cantus_id.html
@@ -52,9 +52,9 @@
{{ chant.incipit }}
{% endif %}
- {% if chant.office %}
-
- {{ chant.office.name }}
+ {% if chant.service %}
+
+ {{ chant.service.name }}
{% endif %}
diff --git a/django/cantusdb_project/main_app/templates/full_inventory.html b/django/cantusdb_project/main_app/templates/full_inventory.html
index 46b58012c..07ee1827e 100644
--- a/django/cantusdb_project/main_app/templates/full_inventory.html
+++ b/django/cantusdb_project/main_app/templates/full_inventory.html
@@ -65,8 +65,8 @@ Cantus Inventory:
-
- {{ chant.office.name|default_if_none:"" }}
+
+ {{ chant.service.name|default_if_none:"" }}
diff --git a/django/cantusdb_project/main_app/templates/office_detail.html b/django/cantusdb_project/main_app/templates/service_detail.html
similarity index 67%
rename from django/cantusdb_project/main_app/templates/office_detail.html
rename to django/cantusdb_project/main_app/templates/service_detail.html
index 78d4d223c..8c4f14f80 100644
--- a/django/cantusdb_project/main_app/templates/office_detail.html
+++ b/django/cantusdb_project/main_app/templates/service_detail.html
@@ -1,7 +1,7 @@
{% extends "base.html" %}
{% block title %}
- {{ office.name }} | Cantus Database
+ {{ service.name }} | Cantus Database
{% endblock %}
{% block content %}
@@ -9,7 +9,7 @@
{% include "global_search_bar.html" %}
- {{ office.name }}
- {{ office.description }}
+ {{ service.name }}
+ {{ service.description }}
{% endblock %}
diff --git a/django/cantusdb_project/main_app/templates/office_list.html b/django/cantusdb_project/main_app/templates/service_list.html
similarity index 81%
rename from django/cantusdb_project/main_app/templates/office_list.html
rename to django/cantusdb_project/main_app/templates/service_list.html
index 1629ae2d0..19e6871c4 100644
--- a/django/cantusdb_project/main_app/templates/office_list.html
+++ b/django/cantusdb_project/main_app/templates/service_list.html
@@ -19,12 +19,12 @@ Service Abbreviations
- {% for office in offices %}
+ {% for service in services %}
- {{ office.name }}
+ {{ service.name }}
- {{ office.description }}
+ {{ service.description }}
{% endfor %}
diff --git a/django/cantusdb_project/main_app/templates/source_edit.html b/django/cantusdb_project/main_app/templates/source_edit.html
index 51bb130be..4f9678726 100644
--- a/django/cantusdb_project/main_app/templates/source_edit.html
+++ b/django/cantusdb_project/main_app/templates/source_edit.html
@@ -286,7 +286,7 @@ {{ source.siglum }}
- {{ chant.office.name|default:"" }}
+ {{ chant.service.name|default:"" }}
{{ chant.genre.name|default:"" }}
diff --git a/django/cantusdb_project/main_app/tests/make_fakes.py b/django/cantusdb_project/main_app/tests/make_fakes.py
index 6e97c08ca..613fce9c9 100644
--- a/django/cantusdb_project/main_app/tests/make_fakes.py
+++ b/django/cantusdb_project/main_app/tests/make_fakes.py
@@ -9,7 +9,7 @@
from main_app.models.genre import Genre
from main_app.models.institution import Institution
from main_app.models.notation import Notation
-from main_app.models.office import Office
+from main_app.models.service import Service
from main_app.models.project import Project
from main_app.models.provenance import Provenance
from main_app.models.segment import Segment
@@ -138,7 +138,7 @@ def make_fake_chant(
source=None,
marginalia=None,
folio=None,
- office=None,
+ service=None,
genre=None,
position=None,
c_sequence=None,
@@ -164,8 +164,8 @@ def make_fake_chant(
if folio is None:
# two digits and one letter
folio = faker.bothify("##?")
- if office is None:
- office = make_fake_office()
+ if service is None:
+ service = make_fake_service()
if genre is None:
genre = make_fake_genre()
if position is None:
@@ -202,7 +202,7 @@ def make_fake_chant(
marginalia=marginalia,
folio=folio,
c_sequence=c_sequence,
- office=office,
+ service=service,
genre=genre,
position=position,
cantus_id=cantus_id,
@@ -282,13 +282,13 @@ def make_fake_notation() -> Notation:
return notation
-def make_fake_office() -> Office:
- """Generates a fake Office object."""
- office = Office.objects.create(
+def make_fake_service() -> Service:
+ """Generates a fake Service object."""
+ service = Service.objects.create(
name=faker.lexify(text="??"),
description=faker.sentence(),
)
- return office
+ return service
def make_fake_provenance() -> Provenance:
diff --git a/django/cantusdb_project/main_app/tests/test_functions.py b/django/cantusdb_project/main_app/tests/test_functions.py
index de4774f1d..240f51d98 100644
--- a/django/cantusdb_project/main_app/tests/test_functions.py
+++ b/django/cantusdb_project/main_app/tests/test_functions.py
@@ -210,7 +210,7 @@ def test_concordances_structure(self):
"incipit",
"feast",
"genre",
- "office",
+ "service",
"position",
"cantus_id",
"image",
@@ -261,7 +261,7 @@ def test_concordances_values(self):
("incipit", chant.incipit),
("feast", chant.feast.name),
("genre", chant.genre.name),
- ("office", chant.office.name),
+ ("service", chant.service.name),
("position", chant.position),
("cantus_id", chant.cantus_id),
("image", chant.image_link),
diff --git a/django/cantusdb_project/main_app/tests/test_models.py b/django/cantusdb_project/main_app/tests/test_models.py
index bdadf3bbb..91c57392a 100644
--- a/django/cantusdb_project/main_app/tests/test_models.py
+++ b/django/cantusdb_project/main_app/tests/test_models.py
@@ -6,7 +6,7 @@
Chant,
Feast,
Genre,
- Office,
+ Service,
Sequence,
Source,
)
@@ -15,7 +15,7 @@
make_fake_chant,
make_fake_feast,
make_fake_genre,
- make_fake_office,
+ make_fake_service,
make_fake_sequence,
make_fake_source,
)
@@ -82,7 +82,7 @@ def test_index_components(self):
"B": (
" ".join(
filter(
- None, [chant.genre.name, chant.feast.name, chant.office.name]
+ None, [chant.genre.name, chant.feast.name, chant.service.name]
)
)
),
@@ -318,25 +318,25 @@ def test_absolute_url(self):
self.assertEqual(genre.get_absolute_url(), absolute_url)
-class OfficeModelTest(TestCase):
+class ServiceModelTest(TestCase):
@classmethod
def setUpTestData(cls):
- make_fake_office()
+ make_fake_service()
def test_object_string_representation(self):
- office = Office.objects.first()
- self.assertEqual(str(office), f"[{office.name}] {office.description}")
+ service = Service.objects.first()
+ self.assertEqual(str(service), f"[{service.name}] {service.description}")
def test_display_name(self):
- office = Office.objects.first()
- display_name = office.display_name
- name_str = office.__str__()
+ service = Service.objects.first()
+ display_name = service.display_name
+ name_str = service.__str__()
self.assertEqual(display_name, name_str)
def test_absolute_url(self):
- office = Office.objects.first()
- absolute_url = reverse("office-detail", args=[str(office.id)])
- self.assertEqual(office.get_absolute_url(), absolute_url)
+ service = Service.objects.first()
+ absolute_url = reverse("service-detail", args=[str(service.id)])
+ self.assertEqual(service.get_absolute_url(), absolute_url)
class SequenceModelTest(TestCase):
diff --git a/django/cantusdb_project/main_app/tests/test_views.py b/django/cantusdb_project/main_app/tests/test_views.py
index 140feadf6..6f8d5eda3 100644
--- a/django/cantusdb_project/main_app/tests/test_views.py
+++ b/django/cantusdb_project/main_app/tests/test_views.py
@@ -24,7 +24,7 @@
Feast,
Genre,
Notation,
- Office,
+ Service,
Provenance,
Segment,
Sequence,
@@ -38,7 +38,7 @@
make_fake_feast,
make_fake_genre,
make_fake_notation,
- make_fake_office,
+ make_fake_service,
make_fake_provenance,
make_fake_segment,
make_fake_sequence,
@@ -931,12 +931,12 @@ def test_published_vs_unpublished(self):
)
self.assertEqual(len(response.context["chants"]), 0)
- def test_search_by_office(self):
+ def test_search_by_service(self):
source = make_fake_source(published=True)
- office = make_fake_office()
- chant = Chant.objects.create(source=source, office=office)
- search_term = office.id
- response = self.client.get(reverse("chant-search"), {"office": search_term})
+ service = make_fake_service()
+ chant = Chant.objects.create(source=source, service=service)
+ search_term = service.id
+ response = self.client.get(reverse("chant-search"), {"service": search_term})
context_chant_id = response.context["chants"][0].id
self.assertEqual(chant.id, context_chant_id)
@@ -1261,16 +1261,16 @@ def test_order_by_incipit_global_search(self):
last_result_incipit = descending_results[1].incipit
self.assertEqual(last_result_incipit, chant_1.incipit)
- def test_order_by_office(self):
- # currently, office sort works by ID rather than by name
- office_1 = make_fake_office()
- office_2 = make_fake_office()
- assert office_1.id < office_2.id
+ def test_order_by_service(self):
+ # currently, service sort works by ID rather than by name
+ service_1 = make_fake_service()
+ service_2 = make_fake_service()
+ assert service_1.id < service_2.id
chant_1 = make_fake_chant(
- office=office_1, manuscript_full_text_std_spelling="hocus"
+ service=service_1, manuscript_full_text_std_spelling="hocus"
)
chant_2 = make_fake_chant(
- office=office_2, manuscript_full_text_std_spelling="pocus"
+ service=service_2, manuscript_full_text_std_spelling="pocus"
)
search_term = "ocu"
@@ -1280,7 +1280,7 @@ def test_order_by_office(self):
{
"keyword": search_term,
"op": "contains",
- "order": "office",
+ "order": "service",
"sort": "asc",
},
)
@@ -1295,7 +1295,7 @@ def test_order_by_office(self):
{
"keyword": search_term,
"op": "contains",
- "order": "office",
+ "order": "service",
"sort": "desc",
},
)
@@ -1305,16 +1305,16 @@ def test_order_by_office(self):
last_result_incipit = descending_results[1].incipit
self.assertEqual(last_result_incipit, chant_1.incipit)
- def test_order_by_office_global_search(self):
- # currently, office sort works by ID rather than by name
- office_1 = make_fake_office()
- office_2 = make_fake_office()
- assert office_1.id < office_2.id
+ def test_order_by_service_global_search(self):
+ # currently, service sort works by ID rather than by name
+ service_1 = make_fake_service()
+ service_2 = make_fake_service()
+ assert service_1.id < service_2.id
chant_1 = make_fake_chant(
- office=office_1, manuscript_full_text_std_spelling="fluffy"
+ service=service_1, manuscript_full_text_std_spelling="fluffy"
)
chant_2 = make_fake_chant(
- office=office_2, manuscript_full_text_std_spelling="fluster"
+ service=service_2, manuscript_full_text_std_spelling="fluster"
)
search_term = "flu"
@@ -1322,7 +1322,7 @@ def test_order_by_office_global_search(self):
reverse("chant-search"),
{
"search_bar": search_term,
- "order": "office",
+ "order": "service",
"sort": "asc",
},
)
@@ -1336,7 +1336,7 @@ def test_order_by_office_global_search(self):
reverse("chant-search"),
{
"search_bar": search_term,
- "order": "office",
+ "order": "service",
"sort": "desc",
},
)
@@ -1845,7 +1845,7 @@ def test_column_header_links(self):
# these are the 9 column headers users can order by:
shelfmark = "glum-01"
fulltext = "so it begins"
- office = make_fake_office()
+ service = make_fake_service()
genre = make_fake_genre()
cantus_id = make_random_string(6, "0123456789")
mode = make_random_string(1, "0123456789*?")
@@ -1859,7 +1859,7 @@ def test_column_header_links(self):
position = make_random_string(1)
chant = make_fake_chant(
manuscript_full_text_std_spelling=fulltext,
- office=office,
+ service=service,
genre=genre,
cantus_id=cantus_id,
mode=mode,
@@ -1885,7 +1885,7 @@ def test_column_header_links(self):
query_keys_and_values = {
"op": "contains",
"keyword": search_term,
- "office": office.id,
+ "service": service.id,
"genre": genre.id,
"cantus_id": cantus_id,
"mode": mode,
@@ -1917,7 +1917,7 @@ def test_column_header_links(self):
orderings = (
"siglum",
"incipit",
- "office",
+ "service",
"genre",
"cantus_id",
"mode",
@@ -2030,28 +2030,28 @@ def test_feast_column(self):
f'{feast_name} ', html
)
- def test_office_column(self):
+ def test_service_column(self):
source = make_fake_source(published=True)
- office = make_fake_office()
- office_name = office.name
- office_description = office.description
- url = office.get_absolute_url()
+ service = make_fake_service()
+ service_name = service.name
+ service_description = service.description
+ url = service.get_absolute_url()
fulltext = "manuscript full text"
search_term = "full"
chant = make_fake_chant(
source=source,
manuscript_full_text_std_spelling=fulltext,
- office=office,
+ service=service,
)
response = self.client.get(
reverse("chant-search"), {"keyword": search_term, "op": "contains"}
)
html = str(response.content)
- self.assertIn(office_name, html)
- self.assertIn(office_description, html)
+ self.assertIn(service_name, html)
+ self.assertIn(service_description, html)
self.assertIn(url, html)
self.assertIn(
- f'{office_name} ', html
+ f'{service_name} ', html
)
def test_genre_column(self):
@@ -2236,13 +2236,13 @@ def test_published_vs_unpublished(self):
response = self.client.get(reverse("chant-search-ms", args=[source.id]))
self.assertEqual(response.status_code, 403)
- def test_search_by_office(self):
+ def test_search_by_service(self):
source = make_fake_source()
- office = make_fake_office()
- chant = Chant.objects.create(source=source, office=office)
- search_term = office.id
+ service = make_fake_service()
+ chant = Chant.objects.create(source=source, service=service)
+ search_term = service.id
response = self.client.get(
- reverse("chant-search-ms", args=[source.id]), {"office": search_term}
+ reverse("chant-search-ms", args=[source.id]), {"service": search_term}
)
context_chant_id = response.context["chants"][0].id
self.assertEqual(chant.id, context_chant_id)
@@ -2499,17 +2499,17 @@ def test_order_by_incipit(self):
last_result_incipit = descending_results[1].incipit
self.assertEqual(last_result_incipit, chant_1.incipit)
- def test_order_by_office(self):
+ def test_order_by_service(self):
source = make_fake_source()
- # currently, office sort works by ID rather than by name
- office_1 = make_fake_office()
- office_2 = make_fake_office()
- assert office_1.id < office_2.id
+ # currently, service sort works by ID rather than by name
+ service_1 = make_fake_service()
+ service_2 = make_fake_service()
+ assert service_1.id < service_2.id
chant_1 = make_fake_chant(
- office=office_1, manuscript_full_text_std_spelling="hocus", source=source
+ service=service_1, manuscript_full_text_std_spelling="hocus", source=source
)
chant_2 = make_fake_chant(
- office=office_2, manuscript_full_text_std_spelling="pocus", source=source
+ service=service_2, manuscript_full_text_std_spelling="pocus", source=source
)
search_term = "ocu"
@@ -2519,7 +2519,7 @@ def test_order_by_office(self):
{
"keyword": search_term,
"op": "contains",
- "order": "office",
+ "order": "service",
"sort": "asc",
},
)
@@ -2534,7 +2534,7 @@ def test_order_by_office(self):
{
"keyword": search_term,
"op": "contains",
- "order": "office",
+ "order": "service",
"sort": "desc",
},
)
@@ -2818,7 +2818,7 @@ def test_column_header_links(self):
shelfmark = "glum-01"
full_text = "this is a full text that begins with the search term"
search_term = "this is a fu"
- office = make_fake_office()
+ service = make_fake_service()
genre = make_fake_genre()
cantus_id = make_random_string(6, "0123456789")
mode = make_random_string(1, "0123456789*?")
@@ -2831,7 +2831,7 @@ def test_column_header_links(self):
feast = make_fake_feast()
position = make_random_string(1)
chant = make_fake_chant(
- office=office,
+ service=service,
genre=genre,
cantus_id=cantus_id,
mode=mode,
@@ -2856,7 +2856,7 @@ def test_column_header_links(self):
query_keys_and_values = {
"op": "contains",
"keyword": search_term,
- "office": office.id,
+ "service": service.id,
"genre": genre.id,
"cantus_id": cantus_id,
"mode": mode,
@@ -2877,7 +2877,7 @@ def test_column_header_links(self):
# for each orderable column, check that 'asc' flips to 'desc', and vice versa
orderings = (
"incipit",
- "office",
+ "service",
"genre",
"cantus_id",
"mode",
@@ -2991,29 +2991,29 @@ def test_feast_column(self):
f'{feast_name} ', html
)
- def test_office_column(self):
+ def test_service_column(self):
source = make_fake_source(published=True)
- office = make_fake_office()
- office_name = office.name
- office_description = office.description
- url = office.get_absolute_url()
+ service = make_fake_service()
+ service_name = service.name
+ service_description = service.description
+ url = service.get_absolute_url()
fulltext = "manuscript full text"
search_term = "full"
chant = make_fake_chant(
source=source,
manuscript_full_text_std_spelling=fulltext,
- office=office,
+ service=service,
)
response = self.client.get(
reverse("chant-search-ms", args=[source.id]),
{"keyword": search_term, "op": "contains"},
)
html = str(response.content)
- self.assertIn(office_name, html)
- self.assertIn(office_description, html)
+ self.assertIn(service_name, html)
+ self.assertIn(service_description, html)
self.assertIn(url, html)
self.assertIn(
- f'{office_name} ', html
+ f'{service_name} ', html
)
def test_genre_column(self):
@@ -3354,12 +3354,12 @@ def test_volpiano_signal(self):
self.assertEqual(chant_2.volpiano_intervals, "1-12-23-34-45-56-67-78-8")
def test_initial_values(self):
- # create a chant with a known folio, feast, office, c_sequence and image_link
+ # create a chant with a known folio, feast, service, c_sequence and image_link
source: Source = make_fake_source()
folio: str = "001r"
sequence: int = 1
feast: Feast = make_fake_feast()
- office: Office = make_fake_office()
+ service: Service = make_fake_service()
image_link: str = "https://www.youtube.com/watch?v=9bZkp7q19f0"
self.client.post(
reverse("chant-create", args=[source.id]),
@@ -3368,12 +3368,12 @@ def test_initial_values(self):
"folio": folio,
"c_sequence": str(sequence),
"feast": feast.id,
- "office": office.id,
+ "service": service.id,
"image_link": image_link,
},
)
with patch("requests.get", mock_requests_get):
- # when we request the Chant Create page, the same folio, feast, office and image_link should
+ # when we request the Chant Create page, the same folio, feast, service and image_link should
# be preselected, and c_sequence should be incremented by 1.
response = self.client.get(
reverse("chant-create", args=[source.id]),
@@ -3387,9 +3387,9 @@ def test_initial_values(self):
with self.subTest(subtest="test initial value of feast feild"):
self.assertEqual(observed_initial_feast, feast.id)
- observed_initial_office: int = response.context["form"].initial["office"]
- with self.subTest(subtest="test initial value of office field"):
- self.assertEqual(observed_initial_office, office.id)
+ observed_initial_service: int = response.context["form"].initial["service"]
+ with self.subTest(subtest="test initial value of service field"):
+ self.assertEqual(observed_initial_service, service.id)
observed_initial_sequence: int = response.context["form"].initial["c_sequence"]
with self.subTest(subtest="test initial value of c_sequence field"):
@@ -4145,66 +4145,66 @@ def test_context(self):
self.assertEqual(genre, response.context["genre"])
-class OfficeListViewTest(TestCase):
- OFFICE_COUNT = 10
+class ServiceListViewTest(TestCase):
+ SERVICE_COUNT = 10
def setUp(self):
- for _ in range(self.OFFICE_COUNT):
- make_fake_office()
+ for _ in range(self.SERVICE_COUNT):
+ make_fake_service()
def test_view_url_path(self):
- response = self.client.get("/offices/")
+ response = self.client.get("/services/")
self.assertEqual(response.status_code, 200)
def test_view_url_reverse_name(self):
- response = self.client.get(reverse("office-list"))
+ response = self.client.get(reverse("service-list"))
self.assertEqual(response.status_code, 200)
def test_url_and_templates(self):
- response = self.client.get(reverse("office-list"))
+ response = self.client.get(reverse("service-list"))
self.assertEqual(response.status_code, 200)
self.assertTemplateUsed(response, "base.html")
- self.assertTemplateUsed(response, "office_list.html")
+ self.assertTemplateUsed(response, "service_list.html")
def test_context(self):
- response = self.client.get(reverse("office-list"))
- offices = response.context["offices"]
- # the list view should contain all offices
- self.assertEqual(offices.count(), self.OFFICE_COUNT)
+ response = self.client.get(reverse("service-list"))
+ services = response.context["services"]
+ # the list view should contain all services
+ self.assertEqual(services.count(), self.SERVICE_COUNT)
-class OfficeDetailViewTest(TestCase):
+class ServiceDetailViewTest(TestCase):
def setUp(self):
for _ in range(10):
- make_fake_office()
+ make_fake_service()
def test_view_url_path(self):
- for office in Office.objects.all():
- response = self.client.get(f"/office/{office.id}")
+ for service in Service.objects.all():
+ response = self.client.get(f"/service/{service.id}")
self.assertEqual(response.status_code, 200)
def test_view_url_reverse_name(self):
- for office in Office.objects.all():
- response = self.client.get(reverse("office-detail", args=[office.id]))
+ for service in Service.objects.all():
+ response = self.client.get(reverse("service-detail", args=[service.id]))
self.assertEqual(response.status_code, 200)
def test_view_context_data(self):
- for office in Office.objects.all():
- response = self.client.get(reverse("office-detail", args=[office.id]))
- self.assertTrue("office" in response.context)
- self.assertEqual(office, response.context["office"])
+ for service in Service.objects.all():
+ response = self.client.get(reverse("service-detail", args=[service.id]))
+ self.assertTrue("service" in response.context)
+ self.assertEqual(service, response.context["service"])
def test_url_and_templates(self):
- office = make_fake_office()
- response = self.client.get(reverse("office-detail", args=[office.id]))
+ service = make_fake_service()
+ response = self.client.get(reverse("service-detail", args=[service.id]))
self.assertEqual(response.status_code, 200)
self.assertTemplateUsed(response, "base.html")
- self.assertTemplateUsed(response, "office_detail.html")
+ self.assertTemplateUsed(response, "service_detail.html")
def test_context(self):
- office = make_fake_office()
- response = self.client.get(reverse("office-detail", args=[office.id]))
- self.assertEqual(office, response.context["office"])
+ service = make_fake_service()
+ response = self.client.get(reverse("service-detail", args=[service.id]))
+ self.assertEqual(service, response.context["service"])
class ProvenanceDetailViewTest(TestCase):
@@ -4956,21 +4956,21 @@ def test_feast_column(self):
self.assertIn(feast_name, html)
self.assertIn(feast_description, html)
- def test_office_column(self):
+ def test_service_column(self):
source = make_fake_source(published=True)
- office = make_fake_office()
- office_name = office.name
- office_description = office.description
+ service = make_fake_service()
+ service_name = service.name
+ service_description = service.description
fulltext = "manuscript full text"
make_fake_chant(
source=source,
manuscript_full_text_std_spelling=fulltext,
- office=office,
+ service=service,
)
response = self.client.get(reverse("source-inventory", args=[source.id]))
html = str(response.content)
- self.assertIn(office_name, html)
- self.assertIn(office_description, html)
+ self.assertIn(service_name, html)
+ self.assertIn(service_description, html)
def test_genre_column(self):
source = make_fake_source(published=True)
@@ -5133,7 +5133,7 @@ def test_json_melody_fields(self):
"volpiano",
"mode",
"feast",
- "office",
+ "service",
"genre",
"position",
"chantlink",
@@ -5619,7 +5619,7 @@ def test_structure(self):
"incipit": "some string"
"feast": "some string"
"genre": "some string"
- "office": "some string"
+ "service": "some string"
"position": "some string"
"cantus_id": "some string"
"image": "some string"
@@ -5665,7 +5665,7 @@ def test_structure(self):
"incipit",
"feast",
"genre",
- "office",
+ "service",
"position",
"cantus_id",
"image",
@@ -5688,7 +5688,7 @@ def test_values(self):
"incipit": chant.incipit,
"feast": chant.feast.name,
"genre": chant.genre.name,
- "office": chant.office.name,
+ "service": chant.service.name,
"position": chant.position,
"mode": chant.mode,
"image": chant.image_link,
@@ -5709,7 +5709,7 @@ def test_values(self):
chant.incipit = None
chant.feast = None
chant.genre = None
- chant.office = None
+ chant.service = None
chant.position = None
chant.mode = None
chant.image_link = None
@@ -5775,7 +5775,7 @@ def test_content(self):
"sequence",
"incipit",
"feast",
- "office",
+ "service",
"genre",
"position",
"cantus_id",
@@ -5898,7 +5898,7 @@ def test_chant_redirect(self):
)
expected_url = reverse("chant-detail", args=[example_chant_id])
- self.assertEqual(response_1.status_code, 302)
+ self.assertEqual(response_1.status_code, 301)
self.assertEqual(response_1.url, expected_url)
def test_source_redirect(self):
@@ -5914,7 +5914,7 @@ def test_source_redirect(self):
)
expected_url = reverse("source-detail", args=[example_source_id])
- self.assertEqual(response_1.status_code, 302)
+ self.assertEqual(response_1.status_code, 301)
self.assertEqual(response_1.url, expected_url)
def test_sequence_redirect(self):
@@ -5929,7 +5929,7 @@ def test_sequence_redirect(self):
)
expected_url = reverse("sequence-detail", args=[example_sequence_id])
- self.assertEqual(response_1.status_code, 302)
+ self.assertEqual(response_1.status_code, 301)
self.assertEqual(response_1.url, expected_url)
def test_article_redirect(self):
@@ -5945,7 +5945,7 @@ def test_article_redirect(self):
)
expected_url = reverse("article-detail", args=[example_article_id])
- self.assertEqual(response_1.status_code, 302)
+ self.assertEqual(response_1.status_code, 301)
self.assertEqual(response_1.url, expected_url)
def test_indexer_redirect(self):
@@ -5962,7 +5962,7 @@ def test_indexer_redirect(self):
)
expected_url = reverse("user-detail", args=[example_matching_user_id])
- self.assertEqual(response_1.status_code, 302)
+ self.assertEqual(response_1.status_code, 301)
self.assertEqual(response_1.url, expected_url)
def test_bad_redirect(self):
@@ -6005,7 +6005,7 @@ def test_indexer_redirect_good(self):
)
expected_url = reverse("user-detail", args=[example_matching_user_id])
- self.assertEqual(response_1.status_code, 302)
+ self.assertEqual(response_1.status_code, 301)
self.assertEqual(response_1.url, expected_url)
def test_indexer_redirect_bad(self):
@@ -6033,7 +6033,7 @@ def test_document_redirects(self):
for path in old_document_paths:
# each path should redirect to the new path
response = self.client.get(path)
- self.assertEqual(response.status_code, 302)
+ self.assertEqual(response.status_code, 301)
# In Aug 2023, Jacob struggled to get the following lines to work -
# I was getting 404s when I expected 200s. This final step would be nice
# to test properly - if a future developer who is cleverer than me can
@@ -6382,7 +6382,7 @@ def test_concordance_items(self):
expected_items: ItemsView = {
"siglum": chant.source.short_heading,
"folio": chant.folio,
- "office__name": chant.office.name,
+ "service__name": chant.service.name,
"genre__name": chant.genre.name,
"position": chant.position,
"feast__name": chant.feast.name,
diff --git a/django/cantusdb_project/main_app/urls.py b/django/cantusdb_project/main_app/urls.py
index 864383e11..4769faade 100644
--- a/django/cantusdb_project/main_app/urls.py
+++ b/django/cantusdb_project/main_app/urls.py
@@ -26,6 +26,8 @@
redirect_chants,
redirect_genre,
redirect_office,
+ redirect_offices,
+ redirect_office_id,
redirect_source_inventory,
csv_export_redirect_from_old_path,
redirect_search,
@@ -61,9 +63,9 @@
from main_app.views.notation import (
NotationDetailView,
)
-from main_app.views.office import (
- OfficeListView,
- OfficeDetailView,
+from main_app.views.service import (
+ ServiceListView,
+ ServiceDetailView,
)
from main_app.views.provenance import (
ProvenanceDetailView,
@@ -94,7 +96,7 @@
AllUsersAutocomplete,
CenturyAutocomplete,
FeastAutocomplete,
- OfficeAutocomplete,
+ ServiceAutocomplete,
GenreAutocomplete,
DifferentiaAutocomplete,
ProvenanceAutocomplete,
@@ -260,22 +262,32 @@
NotationDetailView.as_view(),
name="notation-detail",
),
- # office
+ # service
path(
- "offices/",
- OfficeListView.as_view(),
- name="office-list",
+ "services/",
+ ServiceListView.as_view(),
+ name="service-list",
),
path(
- "office/",
- OfficeDetailView.as_view(),
- name="office-detail",
+ "service/",
+ ServiceDetailView.as_view(),
+ name="service-detail",
),
path(
"office/",
redirect_office,
name="redirect-office",
),
+ path(
+ "offices/",
+ redirect_offices,
+ name="redirect-office",
+ ),
+ path(
+ "office/",
+ redirect_office_id,
+ name="redirect-office-id",
+ ),
# provenance
path(
"provenance/",
@@ -530,9 +542,9 @@
name="provenance-autocomplete",
),
path(
- "office-autocomplete/",
- OfficeAutocomplete.as_view(),
- name="office-autocomplete",
+ "service-autocomplete/",
+ ServiceAutocomplete.as_view(),
+ name="service-autocomplete",
),
path(
"genre-autocomplete/",
diff --git a/django/cantusdb_project/main_app/views/api.py b/django/cantusdb_project/main_app/views/api.py
index 8c66b2a9c..48f4da16e 100644
--- a/django/cantusdb_project/main_app/views/api.py
+++ b/django/cantusdb_project/main_app/views/api.py
@@ -41,7 +41,7 @@ def ajax_melody_list(request, cantus_id) -> JsonResponse:
"""
chants: QuerySet[Chant] = (
Chant.objects.filter(cantus_id=cantus_id)
- .select_related("source__holding_institution", "feast", "genre", "office")
+ .select_related("source__holding_institution", "feast", "genre", "service")
.exclude(volpiano=None)
.order_by("id")
)
@@ -54,7 +54,7 @@ def ajax_melody_list(request, cantus_id) -> JsonResponse:
"source__holding_institution__siglum",
"source__shelfmark",
"folio",
- "office__name",
+ "service__name",
"genre__name",
"position",
"feast__name",
@@ -113,7 +113,7 @@ def csv_export(request, source_id):
entries = source.sequence_set.order_by("id")
else:
entries = source.chant_set.order_by("id").select_related(
- "feast", "office", "genre"
+ "feast", "service", "genre"
)
response = HttpResponse(content_type="text/csv")
@@ -129,7 +129,7 @@ def csv_export(request, source_id):
"sequence",
"incipit",
"feast",
- "office",
+ "service",
"genre",
"position",
"cantus_id",
@@ -152,7 +152,7 @@ def csv_export(request, source_id):
for entry in entries:
feast = entry.feast.name if entry.feast else ""
- office = entry.office.name if entry.office else ""
+ service = entry.service.name if entry.service else ""
genre = entry.genre.name if entry.genre else ""
diff_db = entry.diff_db.id if entry.diff_db else ""
@@ -166,7 +166,7 @@ def csv_export(request, source_id):
entry.c_sequence if entry.c_sequence is not None else entry.s_sequence,
entry.incipit,
feast,
- office,
+ service,
genre,
entry.position,
entry.cantus_id,
@@ -327,7 +327,7 @@ def ajax_search_bar(request, search_term):
chants = Chant.objects.filter(incipit__istartswith=search_term).order_by("id")
chants = chants.select_related(
- "source__holding_institution", "genre", "feast", "office"
+ "source__holding_institution", "genre", "feast", "service"
)
display_unpublished: bool = request.user.is_authenticated
@@ -346,7 +346,7 @@ def ajax_search_bar(request, search_term):
"mode",
"source__holding_institution__siglum",
"source__shelfmark",
- "office__name",
+ "service__name",
"folio",
"c_sequence",
)
@@ -376,7 +376,7 @@ def json_melody_export(request, cantus_id: str) -> JsonResponse:
"volpiano",
"mode",
"feast__id",
- "office__id",
+ "service__id",
"genre__id",
"position",
]
@@ -421,7 +421,7 @@ def standardize_dict_for_json_melody_export(
"volpiano": "volpiano",
"mode": "mode",
"feast__id": "feast", # <-
- "office__id": "office", # <-
+ "service__id": "service", # <-
"genre__id": "genre", # <-
"position": "position",
}
@@ -532,7 +532,7 @@ def build_json_cid_dictionary(chant, request) -> dict:
"incipit": chant.incipit if chant.incipit else "",
"feast": chant.feast.name if chant.feast else "",
"genre": chant.genre.name if chant.genre else "",
- "office": chant.office.name if chant.office else "",
+ "service": chant.service.name if chant.service else "",
"position": chant.position if chant.position else "",
"cantus_id": chant.cantus_id if chant.cantus_id else "",
"image": chant.image_link if chant.image_link else "",
diff --git a/django/cantusdb_project/main_app/views/autocomplete.py b/django/cantusdb_project/main_app/views/autocomplete.py
index 47c3b8ac2..1e0c1f014 100644
--- a/django/cantusdb_project/main_app/views/autocomplete.py
+++ b/django/cantusdb_project/main_app/views/autocomplete.py
@@ -7,7 +7,7 @@
Differentia,
Feast,
Genre,
- Office,
+ Service,
Institution,
Provenance,
)
@@ -66,14 +66,14 @@ def get_queryset(self):
return qs
-class OfficeAutocomplete(autocomplete.Select2QuerySetView):
+class ServiceAutocomplete(autocomplete.Select2QuerySetView):
def get_result_label(self, result):
return f"{result.name} - {result.description}"
def get_queryset(self):
if not self.request.user.is_authenticated:
- return Office.objects.none()
- qs = Office.objects.all().order_by("name")
+ return Service.objects.none()
+ qs = Service.objects.all().order_by("name")
if self.q:
qs = qs.filter(
Q(name__istartswith=self.q) | Q(description__icontains=self.q)
diff --git a/django/cantusdb_project/main_app/views/chant.py b/django/cantusdb_project/main_app/views/chant.py
index 28591abd9..3f76a56eb 100644
--- a/django/cantusdb_project/main_app/views/chant.py
+++ b/django/cantusdb_project/main_app/views/chant.py
@@ -40,7 +40,7 @@
Genre,
Source,
Sequence,
- Office,
+ Service,
)
from main_app.permissions import (
user_can_edit_chants_in_source,
@@ -70,9 +70,9 @@
"feast__id",
"feast__description",
"feast__name",
- "office__id",
- "office__description",
- "office__name",
+ "service__id",
+ "service__description",
+ "service__name",
"genre__id",
"genre__description",
"genre__name",
@@ -82,7 +82,7 @@
"id",
"genre",
"feast",
- "office",
+ "service",
"source",
"source__holding_institution__siglum",
"source__shelfmark",
@@ -118,7 +118,7 @@ def get_feast_selector_options(source: Source) -> list[tuple[str, int, str]]:
"""
folios_feasts_iter: Iterator[tuple[Optional[str], int, str]] = (
source.chant_set.exclude(feast=None)
- .select_related("feast", "genre", "office")
+ .select_related("feast", "genre", "service")
.values_list("folio", "feast_id", "feast__name")
.order_by("folio", "c_sequence")
.iterator()
@@ -186,7 +186,7 @@ class ChantDetailView(DetailView):
def get_queryset(self) -> QuerySet:
qs = super().get_queryset()
return qs.select_related(
- "source__holding_institution", "office", "genre", "feast"
+ "source__holding_institution", "service", "genre", "feast"
)
def get_context_data(self, **kwargs):
@@ -222,7 +222,7 @@ def get_context_data(self, **kwargs):
# source navigation section
chants_in_source = chant.source.chant_set.select_related(
- "source__holding_institution", "feast", "genre", "office"
+ "source__holding_institution", "feast", "genre", "service"
)
context["folios"] = (
chants_in_source.values_list("folio", flat=True)
@@ -278,10 +278,10 @@ def dispatch(self, request, *args, **kwargs):
def get_queryset(self):
chant_set = Chant.objects.filter(cantus_id=self.cantus_id).select_related(
- "source__holding_institution", "office", "genre", "feast"
+ "source__holding_institution", "service", "genre", "feast"
)
sequence_set = Sequence.objects.filter(cantus_id=self.cantus_id).select_related(
- "source__holding_institution", "office", "genre", "feast"
+ "source__holding_institution", "service", "genre", "feast"
)
display_unpublished = self.request.user.is_authenticated
if not display_unpublished:
@@ -309,7 +309,7 @@ class ChantSearchView(ListView):
If no ``GET`` parameters, returns empty queryset
``GET`` parameters:
- ``office``: Filters by Office of Chant
+ ``service``: Filters by Service of Chant
``genre``: Filters by Genre of Chant
``cantus_id``: Filters by the Cantus ID field of Chant
``mode``: Filters by mode of Chant
@@ -329,7 +329,9 @@ def get_context_data(self, **kwargs) -> dict:
context = super().get_context_data(**kwargs)
# Add to context a QuerySet of dicts with id and name of each Genre
context["genres"] = Genre.objects.all().order_by("name").values("id", "name")
- context["offices"] = Office.objects.all().order_by("name").values("id", "name")
+ context["services"] = (
+ Service.objects.all().order_by("name").values("id", "name")
+ )
context["order"] = self.request.GET.get("order")
context["sort"] = self.request.GET.get("sort")
@@ -346,9 +348,9 @@ def get_context_data(self, **kwargs) -> dict:
if search_keyword:
search_parameters.append(f"keyword={search_keyword}")
context["keyword"] = search_keyword
- search_office: Optional[str] = self.request.GET.get("office")
- if search_office:
- search_parameters.append(f"office={search_office}")
+ search_service: Optional[str] = self.request.GET.get("service")
+ if search_service:
+ search_parameters.append(f"service={search_service}")
search_genre: Optional[str] = self.request.GET.get("genre")
if search_genre:
search_parameters.append(f"genre={search_genre}")
@@ -399,10 +401,10 @@ def get_queryset(self) -> QuerySet:
sequence_set = Sequence.objects.filter(source__published=True)
chant_set = chant_set.select_related(
- "source__holding_institution", "feast", "office", "genre"
+ "source__holding_institution", "feast", "service", "genre"
)
sequence_set = sequence_set.select_related(
- "source__holding_institution", "feast", "office", "genre"
+ "source__holding_institution", "feast", "service", "genre"
)
search_bar_term_contains_digits = any(
@@ -435,8 +437,8 @@ def get_queryset(self) -> QuerySet:
# The field names should be keys in the "GET" QueryDict if the search button has been
# clicked, even if the user put nothing into the search form and hit "apply" immediately.
# In that case, we return all chants + seqs filtered by the search form.
- if office_id := self.request.GET.get("office"):
- q_obj_filter &= Q(office__id=office_id)
+ if service_id := self.request.GET.get("service"):
+ q_obj_filter &= Q(service__id=service_id)
if genre_id := self.request.GET.get("genre"):
q_obj_filter &= Q(genre__id=int(genre_id))
@@ -467,10 +469,10 @@ def get_queryset(self) -> QuerySet:
# Filter the QuerySet with Q object
chant_set = chant_set.filter(q_obj_filter).select_related(
- "source__holding_institution", "feast", "office", "genre"
+ "source__holding_institution", "feast", "service", "genre"
)
sequence_set = sequence_set.filter(q_obj_filter).select_related(
- "source__holding_institution", "feast", "office", "genre"
+ "source__holding_institution", "feast", "service", "genre"
)
# Finally, do keyword searching over the querySet
@@ -508,7 +510,7 @@ def get_queryset(self) -> QuerySet:
order_param_options = (
"incipit",
- "office",
+ "service",
"genre",
"cantus_id",
"mode",
@@ -553,7 +555,7 @@ def get_context_data(self, **kwargs):
if self.request.GET.get("source"):
context["source"] = Source.objects.get(
id=self.request.GET.get("source")
- ).select_related("holding_institution", "feast", "office", "genre")
+ ).select_related("holding_institution", "feast", "service", "genre")
return context
@@ -567,7 +569,7 @@ class ChantSearchMSView(ListView):
If no ``GET`` parameters, returns empty queryset
``GET`` parameters:
- ``office``: Filters by the office/mass of Chant
+ ``service``: Filters by the service/mass of Chant
``genre``: Filters by Genre of Chant
``cantus_id``: Filters by the Cantus ID field of Chant
``mode``: Filters by mode of Chant
@@ -594,7 +596,9 @@ def get_context_data(self, **kwargs):
context["source"] = source
# Add to context a QuerySet of dicts with id and name of each Genre
context["genres"] = Genre.objects.all().order_by("name").values("id", "name")
- context["offices"] = Office.objects.all().order_by("name").values("id", "name")
+ context["services"] = (
+ Service.objects.all().order_by("name").values("id", "name")
+ )
context["order"] = self.request.GET.get("order")
context["sort"] = self.request.GET.get("sort")
# This is searching in a specific source, pass the source into context
@@ -608,9 +612,9 @@ def get_context_data(self, **kwargs):
search_keyword = self.request.GET.get("keyword")
if search_keyword:
search_parameters.append(f"keyword={search_keyword}")
- search_office = self.request.GET.get("office")
- if search_office:
- search_parameters.append(f"office={search_office}")
+ search_service = self.request.GET.get("service")
+ if search_service:
+ search_parameters.append(f"service={search_service}")
search_genre = self.request.GET.get("genre")
if search_genre:
search_parameters.append(f"genre={search_genre}")
@@ -653,8 +657,8 @@ def get_queryset(self) -> QuerySet:
# Create a Q object to filter the QuerySet of Chants
q_obj_filter = Q()
# For every GET parameter other than incipit, add to the Q object
- if office_id := self.request.GET.get("office"):
- q_obj_filter &= Q(office__id=office_id)
+ if service_id := self.request.GET.get("service"):
+ q_obj_filter &= Q(service__id=service_id)
if genre_id := self.request.GET.get("genre"):
q_obj_filter &= Q(genre__id=int(genre_id))
@@ -684,7 +688,7 @@ def get_queryset(self) -> QuerySet:
"cantus_id",
"mode",
"feast",
- "office",
+ "service",
}:
order = order_value
elif order_value == "has_fulltext":
@@ -707,7 +711,7 @@ def get_queryset(self) -> QuerySet:
# Filter the QuerySet with Q object
queryset = queryset.select_related(
- "source__holding_institution", "feast", "office", "genre"
+ "source__holding_institution", "feast", "service", "genre"
).filter(q_obj_filter)
# Fetch only the values necessary for rendering the template
queryset = queryset.only(*ONLY_FIELDS)
@@ -790,7 +794,7 @@ def get_initial(self):
}
latest_folio = latest_chant.folio if latest_chant.folio else "001r"
latest_feast = latest_chant.feast.id if latest_chant.feast else ""
- latest_office = latest_chant.office.id if latest_chant.office else ""
+ latest_service = latest_chant.service.id if latest_chant.service else ""
latest_seq = (
latest_chant.c_sequence if latest_chant.c_sequence is not None else 0
)
@@ -798,7 +802,7 @@ def get_initial(self):
return {
"folio": latest_folio,
"feast": latest_feast,
- "office": latest_office,
+ "service": latest_service,
"c_sequence": latest_seq + 1,
"image_link": latest_image,
}
@@ -822,7 +826,7 @@ def get_suggested_feasts(self):
current_feast = latest_chant.feast
chants_that_end_current_feast = Chant.objects.filter(
is_last_chant_in_feast=True, feast=current_feast
- ).select_related("next_chant__feast", "feast", "genre", "office")
+ ).select_related("next_chant__feast", "feast", "genre", "service")
next_chants = [chant.next_chant for chant in chants_that_end_current_feast]
next_feasts = [
chant.feast
@@ -1000,7 +1004,7 @@ def get_queryset(self):
# get all chants in the specified source
chants = source.chant_set.select_related(
- "feast", "office", "genre", "source__holding_institution"
+ "feast", "service", "genre", "source__holding_institution"
)
if not source.chant_set.exists():
# return empty queryset
@@ -1051,7 +1055,7 @@ def get_context_data(self, **kwargs):
context["source"] = source
chants_in_source = source.chant_set.select_related(
- "feast", "genre", "office", "source__holding_institution"
+ "feast", "genre", "service", "source__holding_institution"
)
# the following code block is sort of obsolete because if there is no Chant
@@ -1104,7 +1108,7 @@ def get_context_data(self, **kwargs):
# need to render a list of chants, ordered by c_sequence and grouped by feast
context["feasts_current_folio"] = get_chants_with_feasts(
self.queryset.select_related(
- "feast", "genre", "office", "source__holding_institution"
+ "feast", "genre", "service", "source__holding_institution"
).order_by("c_sequence")
)
diff --git a/django/cantusdb_project/main_app/views/office.py b/django/cantusdb_project/main_app/views/office.py
deleted file mode 100644
index 1052faec2..000000000
--- a/django/cantusdb_project/main_app/views/office.py
+++ /dev/null
@@ -1,17 +0,0 @@
-from django.views.generic import DetailView, ListView
-
-from main_app.models import Office
-
-
-class OfficeDetailView(DetailView):
- model = Office
- context_object_name = "office"
- template_name = "office_detail.html"
-
-
-class OfficeListView(ListView):
- model = Office
- queryset = Office.objects.order_by("name")
- paginate_by = 100
- context_object_name = "offices"
- template_name = "office_list.html"
diff --git a/django/cantusdb_project/main_app/views/redirect.py b/django/cantusdb_project/main_app/views/redirect.py
index ff4593274..6a6cd0b4c 100644
--- a/django/cantusdb_project/main_app/views/redirect.py
+++ b/django/cantusdb_project/main_app/views/redirect.py
@@ -16,7 +16,7 @@
def csv_export_redirect_from_old_path(request, source_id):
- return redirect(reverse("csv-export", args=[source_id]))
+ return redirect(reverse("csv-export", args=[source_id]), permanent=True)
def redirect_node_url(request, pk: int) -> HttpResponse:
@@ -37,12 +37,12 @@ def redirect_node_url(request, pk: int) -> HttpResponse:
user_id = get_user_id_from_old_indexer_id(pk)
if get_user_id_from_old_indexer_id(pk) is not None:
- return redirect("user-detail", user_id)
+ return redirect("user-detail", user_id, permanent=True)
for rec_type, view in NODE_TYPES_AND_VIEWS:
if record_exists(rec_type, pk):
# if an object is found, a redirect() call to the appropriate view is returned
- return redirect(view, pk)
+ return redirect(view, pk, permanent=True)
# if it reaches the end of the types with finding an existing object, a 404 will be returned
raise Http404("No record found matching the /node/ query.")
@@ -60,14 +60,14 @@ def redirect_indexer(request, pk: int) -> HttpResponse:
"""
user_id = get_user_id_from_old_indexer_id(pk)
if get_user_id_from_old_indexer_id(pk) is not None:
- return redirect("user-detail", user_id)
+ return redirect("user-detail", user_id, permanent=True)
raise Http404("No indexer found matching the query.")
def redirect_office(request) -> HttpResponse:
"""
- Redirects from office/ (à la OldCantus) to offices/ (à la NewCantus)
+ Redirects from office/ (à la OldCantus) to services/ (à la NewCantus)
Args:
request
@@ -75,7 +75,34 @@ def redirect_office(request) -> HttpResponse:
Returns:
HttpResponse
"""
- return redirect("office-list")
+ return redirect("service-list", permanent=True)
+
+
+def redirect_offices(request) -> HttpResponse:
+ """
+ Redirects old URL for offices/ to services/
+
+ Args:
+ request
+
+ Returns:
+ HttpResponse
+ """
+ return redirect("service-list", permanent=True)
+
+
+def redirect_office_id(request, pk: int) -> HttpResponse:
+ """
+ Redirects from the old URL pattern 'office/ to the new URL patern 'service/'
+
+ Args:
+ request
+ pk: The ID of the service
+
+ Returns:
+ HttpResponse
+ """
+ return redirect(reverse("service-detail", args=[pk]), permanent=True)
def redirect_genre(request) -> HttpResponse:
@@ -88,7 +115,7 @@ def redirect_genre(request) -> HttpResponse:
Returns:
HttpResponse
"""
- return redirect("genre-list")
+ return redirect("genre-list", permanent=True)
def redirect_search(request: HttpRequest) -> HttpResponse:
@@ -143,7 +170,7 @@ def redirect_documents(request) -> HttpResponse:
new_path = mapping[old_path]
except KeyError as exc:
raise Http404 from exc
- return redirect(new_path)
+ return redirect(new_path, permanent=True)
def redirect_chants(request) -> HttpResponse:
diff --git a/django/cantusdb_project/main_app/views/service.py b/django/cantusdb_project/main_app/views/service.py
new file mode 100644
index 000000000..902175542
--- /dev/null
+++ b/django/cantusdb_project/main_app/views/service.py
@@ -0,0 +1,17 @@
+from django.views.generic import DetailView, ListView
+
+from main_app.models import Service
+
+
+class ServiceDetailView(DetailView):
+ model = Service
+ context_object_name = "service"
+ template_name = "service_detail.html"
+
+
+class ServiceListView(ListView):
+ model = Service
+ queryset = Service.objects.order_by("name")
+ paginate_by = 100
+ context_object_name = "services"
+ template_name = "service_list.html"
diff --git a/django/cantusdb_project/main_app/views/site_stats.py b/django/cantusdb_project/main_app/views/site_stats.py
index fd547b545..a58516856 100644
--- a/django/cantusdb_project/main_app/views/site_stats.py
+++ b/django/cantusdb_project/main_app/views/site_stats.py
@@ -7,7 +7,7 @@
Sequence,
Source,
Feast,
- Office,
+ Service,
Provenance,
Genre,
Notation,
@@ -60,7 +60,7 @@ def content_overview(request):
Chant,
Feast,
Sequence,
- Office,
+ Service,
Provenance,
Genre,
Notation,
diff --git a/django/cantusdb_project/main_app/views/source.py b/django/cantusdb_project/main_app/views/source.py
index 208eabec8..3878ba958 100644
--- a/django/cantusdb_project/main_app/views/source.py
+++ b/django/cantusdb_project/main_app/views/source.py
@@ -82,7 +82,7 @@ def get_queryset(self):
search_text = self.request.GET.get("search_text")
# get all chants in the specified source
- chants = source.chant_set.select_related("feast", "office", "genre")
+ chants = source.chant_set.select_related("feast", "service", "genre")
# filter the chants with optional search params
if feast_id:
chants = chants.filter(feast__id=feast_id)
@@ -186,7 +186,7 @@ def get_context_data(self, **kwargs):
if source.segment and source.segment_id == BOWER_SEGMENT_ID:
# if this is a sequence source
- sequences = source.sequence_set.select_related("genre", "office")
+ sequences = source.sequence_set.select_related("genre", "service")
context["sequences"] = sequences.order_by("s_sequence")
context["folios"] = (
sequences.values_list("folio", flat=True).distinct().order_by("folio")
@@ -481,7 +481,7 @@ def get_context_data(self, **kwargs):
queryset = (
source.chant_set.annotate(record_type=Value("chant"))
.order_by("folio", "c_sequence")
- .select_related("feast", "office", "genre", "diff_db")
+ .select_related("feast", "service", "genre", "diff_db")
)
context["source"] = source
diff --git a/django/cantusdb_project/static/js/chant_detail.js b/django/cantusdb_project/static/js/chant_detail.js
index 176c8327c..0a672cb48 100644
--- a/django/cantusdb_project/static/js/chant_detail.js
+++ b/django/cantusdb_project/static/js/chant_detail.js
@@ -76,7 +76,7 @@ function loadMelodies(cantusId) {
const chantCell = newRow.getElementsByTagName("td")[0];
chantCell.innerHTML += ' ';
if (chant.folio) { chantCell.innerHTML += `${chant.folio} | ` } else { chantCell.innerHTML += '' }
- if (chant.office__name) { chantCell.innerHTML += `${chant.office__name} ` } else { chantCell.innerHTML += '' }
+ if (chant.service__name) { chantCell.innerHTML += `${chant.service__name} ` } else { chantCell.innerHTML += '' }
if (chant.genre__name) { chantCell.innerHTML += `${chant.genre__name} ` } else { chantCell.innerHTML += '' }
if (chant.position) { chantCell.innerHTML += `${chant.position}` } else { chantCell.innerHTML += '' }
chantCell.innerHTML += ' ';
diff --git a/django/cantusdb_project/static/js/chant_search.js b/django/cantusdb_project/static/js/chant_search.js
index 9774e2f20..962c8344d 100644
--- a/django/cantusdb_project/static/js/chant_search.js
+++ b/django/cantusdb_project/static/js/chant_search.js
@@ -6,7 +6,7 @@ window.addEventListener("load", function () {
// Make sure the select components keep their values across multiple GET requests
// so the user can "drill down" on what they want
const opFilter = document.getElementById("opFilter");
- const officeFilter = document.getElementById("officeFilter");
+ const serviceFilter = document.getElementById("serviceFilter");
const genreFilter = document.getElementById("genreFilter");
const melodiesFilter = document.getElementById("melodiesFilter");
const keywordField = document.getElementById("keywordSearch");
@@ -17,8 +17,8 @@ window.addEventListener("load", function () {
if (urlParams.has("op")) {
opFilter.value = urlParams.get("op");
}
- if (urlParams.has("office")) {
- officeFilter.value = urlParams.get("office");
+ if (urlParams.has("service")) {
+ serviceFilter.value = urlParams.get("service");
}
if (urlParams.has("genre")) {
genreFilter.value = urlParams.get("genre");
diff --git a/django/cantusdb_project/templates/base.html b/django/cantusdb_project/templates/base.html
index b6f1f6b19..3a9faac8e 100644
--- a/django/cantusdb_project/templates/base.html
+++ b/django/cantusdb_project/templates/base.html
@@ -251,7 +251,7 @@