-
Notifications
You must be signed in to change notification settings - Fork 6
/
Copy pathsource.py
220 lines (199 loc) · 8.21 KB
/
source.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
from django.db import models
from main_app.models import BaseModel, Segment
from django.contrib.auth import get_user_model
class Source(BaseModel):
cursus_choices = [("Monastic", "Monastic"), ("Secular", "Secular")]
source_status_choices = [
(
"Editing process (not all the fields have been proofread)",
"Editing process (not all the fields have been proofread)",
),
("Published / Complete", "Published / Complete"),
("Published / Proofread pending", "Published / Proofread pending"),
("Unpublished / Editing process", "Unpublished / Editing process"),
("Unpublished / Indexing process", "Unpublished / Indexing process"),
("Unpublished / Proofread pending", "Unpublished / Proofread pending"),
("Unpublished / Proofreading process", "Unpublished / Proofreading process"),
("Unpublished / No indexing activity", "Unpublished / No indexing activity"),
]
# The old Cantus uses two fields to jointly control the access to sources.
# Here in the new Cantus, we only use one field, and there are two levels: published and unpublished.
# Published sources are available to the public.
# Unpublished sources are hidden from the list and cannot be accessed by URL until the user logs in.
published = models.BooleanField(blank=False, null=False, default=False)
title = models.CharField(
max_length=255,
blank=True,
null=True,
help_text="Full Source Identification (City, Archive, Shelf-mark)",
)
# the siglum field as implemented on the old Cantus is composed of both the RISM siglum and the shelfmark
# it is a human-readable ID for a source
siglum = models.CharField(
max_length=63,
null=True,
blank=True,
help_text="RISM-style siglum + Shelf-mark (e.g. GB-Ob 202).",
)
holding_institution = models.ForeignKey(
"Institution",
on_delete=models.PROTECT,
null=True,
blank=True,
)
shelfmark = models.CharField(
max_length=255,
blank=False,
null=False,
help_text=(
"Primary Cantus Database identifier for the source "
"(e.g. library shelfmark, DACT ID, etc.)"
),
default="[No Shelfmark]",
)
name = models.CharField(
max_length=255,
blank=True,
null=True,
help_text="A colloquial or commonly-used name for the source",
)
provenance = models.ForeignKey(
"Provenance",
on_delete=models.PROTECT,
help_text="If the origin is unknown, select a location where the source was "
"used later in its lifetime and provide details in the "
'"Provenance notes" field.',
null=True,
blank=True,
related_name="sources",
)
provenance_notes = models.TextField(
blank=True,
null=True,
help_text="More exact indication of the provenance (if necessary)",
)
class SourceCompletenessChoices(models.IntegerChoices):
FULL_SOURCE = 1, "Complete (or mostly complete)"
FRAGMENTED = 4, "Fragmented"
FRAGMENT = 2, "Fragment"
RECONSTRUCTION = 3, "Reconstruction"
source_completeness = models.IntegerField(
choices=SourceCompletenessChoices.choices,
default=SourceCompletenessChoices.FULL_SOURCE,
verbose_name="Complete Source/Fragment",
)
full_source = models.BooleanField(blank=True, null=True)
date = models.CharField(
blank=True,
null=True,
max_length=63,
help_text='Date of the source, if known (e.g. "1541")',
)
century = models.ManyToManyField("Century", related_name="sources", blank=True)
notation = models.ManyToManyField("Notation", related_name="sources", blank=True)
cursus = models.CharField(
blank=True, null=True, choices=cursus_choices, max_length=63
)
current_editors = models.ManyToManyField(
get_user_model(), related_name="sources_user_can_edit", blank=True
)
######
# The following six fields have nothing to do with user permissions,
# instead they give credit to users who are indexers and are displayed
# on the user detail page as sources the user has contributed to.
inventoried_by = models.ManyToManyField(
get_user_model(), related_name="inventoried_sources", blank=True
)
full_text_entered_by = models.ManyToManyField(
get_user_model(), related_name="entered_full_text_for_sources", blank=True
)
melodies_entered_by = models.ManyToManyField(
get_user_model(), related_name="entered_melody_for_sources", blank=True
)
description_entered_by = models.ManyToManyField(
get_user_model(), related_name="entered_description_for_sources", blank=True
)
proofreaders = models.ManyToManyField(
get_user_model(), related_name="proofread_sources", blank=True
)
other_editors = models.ManyToManyField(
get_user_model(), related_name="edited_sources", blank=True
)
######
segment = models.ForeignKey(
"Segment", on_delete=models.PROTECT, blank=True, null=True
)
segment_m2m = models.ManyToManyField(
"Segment", blank=True, related_name="sources", verbose_name="Segments"
)
source_status = models.CharField(
blank=True, null=True, choices=source_status_choices, max_length=255
)
complete_inventory = models.BooleanField(blank=True, null=True)
summary = models.TextField(blank=True, null=True)
liturgical_occasions = models.TextField(blank=True, null=True)
description = models.TextField(blank=True, null=True)
selected_bibliography = models.TextField(blank=True, null=True)
image_link = models.URLField(
blank=True,
null=True,
help_text="HTTP link to the image gallery of the source.",
)
indexing_notes = models.TextField(blank=True, null=True)
indexing_date = models.TextField(blank=True, null=True)
json_info = models.JSONField(blank=True, null=True)
fragmentarium_id = models.CharField(
max_length=15, blank=True, null=True, verbose_name="fragmentarium ID"
)
dact_id = models.CharField(
max_length=15, blank=True, null=True, verbose_name="DACT ID"
)
exists_on_cantus_ultimus = models.BooleanField(
blank=False, null=False, default=False
)
class ProductionMethodChoices(models.IntegerChoices):
MANUSCRIPT = 1, "Manuscript"
PRINT = 2, "Print"
production_method = models.IntegerField(
default=ProductionMethodChoices.MANUSCRIPT,
choices=ProductionMethodChoices.choices,
verbose_name="Manuscript/Print",
)
# number_of_chants and number_of_melodies are used for rendering the source-list page (perhaps among other places)
# they are automatically recalculated in main_app.signals.update_source_chant_count and
# main_app.signals.update_source_melody_count every time a chant or sequence is saved or deleted
number_of_chants = models.IntegerField(blank=True, null=True)
number_of_melodies = models.IntegerField(blank=True, null=True)
def __str__(self):
return self.heading
def save(self, *args, **kwargs):
# when creating a source, assign it to "CANTUS Database" segment by default
if not self.segment:
cantus_db_segment = Segment.objects.get(name="CANTUS Database")
self.segment = cantus_db_segment
super().save(*args, **kwargs)
@property
def heading(self) -> str:
title = []
if holdinst := self.holding_institution:
city = f"{holdinst.city}," if holdinst.city else ""
title.append(city)
title.append(f"{holdinst.name},")
else:
title.append("Cantus")
title.append(self.shelfmark)
if self.name:
title.append(f'("{self.name}")')
return " ".join(title)
@property
def short_heading(self) -> str:
title = []
if holdinst := self.holding_institution:
if holdinst.siglum and holdinst.siglum != "XX-NN":
title.append(f"{holdinst.siglum}")
else:
title.append("Cantus")
else:
title.append("Cantus")
title.append(self.shelfmark)
return " ".join(title)