summaryrefslogtreecommitdiff
path: root/ishtar_common
diff options
context:
space:
mode:
Diffstat (limited to 'ishtar_common')
-rw-r--r--ishtar_common/admin.py4
-rw-r--r--ishtar_common/forms_common.py4
-rw-r--r--ishtar_common/migrations/0236_auto_20240208_1635.py112
-rw-r--r--ishtar_common/models.py80
-rw-r--r--ishtar_common/models_common.py18
-rw-r--r--ishtar_common/templates/ishtar/sheet_document.html2
6 files changed, 210 insertions, 10 deletions
diff --git a/ishtar_common/admin.py b/ishtar_common/admin.py
index 50b6d05b3..e5cb1b67b 100644
--- a/ishtar_common/admin.py
+++ b/ishtar_common/admin.py
@@ -553,6 +553,7 @@ class IshtarSiteProfileAdmin(admin.ModelAdmin):
"mapping",
"preventive_operator",
"underwater",
+ "museum",
),
}),
(_("Advanced configuration"), {
@@ -1349,9 +1350,10 @@ class GeneralTypeAdmin(ChangeParentAdmin, ImportActionAdmin, ImportJSONActionAdm
general_models = [
models.SourceType,
models.AuthorType,
- models.LicenseType,
models.Language,
+ models.LicenseType,
models.PersonType,
+ models.ShootingAngle,
models_common.GeoProviderType,
models_common.GeoDataType,
models_common.GeoOriginType,
diff --git a/ishtar_common/forms_common.py b/ishtar_common/forms_common.py
index 7f37e86ce..e2597175b 100644
--- a/ishtar_common/forms_common.py
+++ b/ishtar_common/forms_common.py
@@ -1986,7 +1986,7 @@ class DocumentForm(forms.ModelForm, CustomForm, ManageOldType):
required=False,
)
licenses = widgets.Select2MultipleField(
- label=_("Licenses"), required=False, model=models.LicenseType
+ label=_("Rights of use / licenses"), required=False, model=models.LicenseType
)
tags = widgets.Select2MultipleField(
label=_("Tags"),
@@ -2367,7 +2367,7 @@ class DocumentSelect(HistorySelect):
language = forms.ChoiceField(label=_("Language"), choices=[])
isbn = forms.CharField(label=_("ISBN"))
issn = forms.CharField(label=_("ISSN"))
- licenses = forms.ChoiceField(label=_("License"), choices=[])
+ licenses = forms.ChoiceField(label=_("Rights of use / licenses"), choices=[])
comment = forms.CharField(label=_("Comment"))
additional_information = forms.CharField(label=_("Additional informations"))
diff --git a/ishtar_common/migrations/0236_auto_20240208_1635.py b/ishtar_common/migrations/0236_auto_20240208_1635.py
new file mode 100644
index 000000000..48b1060d6
--- /dev/null
+++ b/ishtar_common/migrations/0236_auto_20240208_1635.py
@@ -0,0 +1,112 @@
+# Generated by Django 2.2.24 on 2024-02-08 16:35
+
+import django.core.validators
+from django.db import migrations, models
+import django.db.models.deletion
+import ishtar_common.models_common
+import re
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('ishtar_common', '0235_default_geo_types'),
+ ]
+
+ operations = [
+ migrations.CreateModel(
+ name='ShootingAngle',
+ fields=[
+ ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
+ ('label', models.TextField(verbose_name='Label')),
+ ('txt_idx', models.TextField(help_text='The slug is the standardized version of the name. It contains only lowercase letters, numbers and hyphens. Each slug must be unique.', unique=True, validators=[django.core.validators.RegexValidator(re.compile('^[-a-zA-Z0-9_]+\\Z'), "Enter a valid 'slug' consisting of letters, numbers, underscores or hyphens.", 'invalid')], verbose_name='Textual ID')),
+ ('comment', models.TextField(blank=True, default='', verbose_name='Comment')),
+ ('available', models.BooleanField(default=True, verbose_name='Available')),
+ ('order', models.IntegerField(default=10, verbose_name='Order')),
+ ],
+ options={
+ 'verbose_name': 'Shooting angle',
+ 'verbose_name_plural': 'Shooting angles',
+ 'ordering': ('label',),
+ },
+ bases=(ishtar_common.models_common.Cached, models.Model),
+ ),
+ migrations.AlterModelOptions(
+ name='licensetype',
+ options={'ordering': ('parent__label', 'order', 'label'), 'verbose_name': 'License type', 'verbose_name_plural': 'License types'},
+ ),
+ migrations.AddField(
+ model_name='document',
+ name='copyright',
+ field=models.TextField(blank=True, default='', verbose_name='Copyright'),
+ ),
+ migrations.AddField(
+ model_name='document',
+ name='rights_owner',
+ field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='ishtar_common.Organization', verbose_name='Rights owner'),
+ ),
+ migrations.AddField(
+ model_name='historicaldocument',
+ name='copyright',
+ field=models.TextField(blank=True, default='', verbose_name='Copyright'),
+ ),
+ migrations.AddField(
+ model_name='historicaldocument',
+ name='rights_owner',
+ field=models.ForeignKey(blank=True, db_constraint=False, null=True, on_delete=django.db.models.deletion.DO_NOTHING, related_name='+', to='ishtar_common.Organization', verbose_name='Rights owner'),
+ ),
+ migrations.AddField(
+ model_name='historicalorganization',
+ name='museum_museofile_id',
+ field=models.TextField(blank=True, default='', verbose_name='Museofile id'),
+ ),
+ migrations.AddField(
+ model_name='licensetype',
+ name='order',
+ field=models.IntegerField(default=10, verbose_name='Order'),
+ ),
+ migrations.AddField(
+ model_name='licensetype',
+ name='parent',
+ field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='ishtar_common.LicenseType', verbose_name='Parent'),
+ ),
+ migrations.AddField(
+ model_name='organization',
+ name='museum_museofile_id',
+ field=models.TextField(blank=True, default='', verbose_name='Museofile id'),
+ ),
+ migrations.AlterField(
+ model_name='document',
+ name='licenses',
+ field=models.ManyToManyField(blank=True, to='ishtar_common.LicenseType', verbose_name='Rights of use / license'),
+ ),
+ migrations.AlterField(
+ model_name='gdprlog',
+ name='activity',
+ field=models.CharField(choices=[('DC', 'Directory consultation'), ('DE', 'Directory export'), ('PV', "Viewing a person's notice"), ('PE', "Exporting a person's notice"), ('PC', 'Person creation'), ('PM', 'Person modification'), ('Pm', 'Person merge'), ('PD', 'Person deletion'), ('AC', 'Admin - Directory consultation'), ('AV', 'Admin - Person view'), ('AM', 'Admin - Person modification'), ('AD', 'Admin - Person deletion')], max_length=2, verbose_name='Activity'),
+ ),
+ migrations.CreateModel(
+ name='BiographicalNote',
+ fields=[
+ ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
+ ('denomination', models.TextField(verbose_name='Denomination')),
+ ('last_name', models.TextField(blank=True, default='', verbose_name='Last name')),
+ ('first_name', models.TextField(blank=True, default='', verbose_name='First name')),
+ ('birth_year', models.PositiveIntegerField(blank=True, null=True, verbose_name='Year of birth')),
+ ('death_year', models.PositiveIntegerField(blank=True, null=True, verbose_name='Year of death')),
+ ('biography', models.TextField(blank=True, default='', verbose_name='Biography')),
+ ('biography_format', models.CharField(blank=True, choices=[('NO', 'None'), ('MD', 'Markdown'), ('HT', 'HTML')], default='NO', max_length=2, verbose_name='Biography format')),
+ ('person', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='ishtar_common.Person', verbose_name='Person')),
+ ],
+ ),
+ migrations.AddField(
+ model_name='document',
+ name='shooting_angle',
+ field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='ishtar_common.ShootingAngle', verbose_name='Shooting angle'),
+ ),
+ migrations.AddField(
+ model_name='historicaldocument',
+ name='shooting_angle',
+ field=models.ForeignKey(blank=True, db_constraint=False, null=True, on_delete=django.db.models.deletion.DO_NOTHING, related_name='+', to='ishtar_common.ShootingAngle', verbose_name='Shooting angle'),
+ ),
+ ]
diff --git a/ishtar_common/models.py b/ishtar_common/models.py
index c978b087b..bd457e970 100644
--- a/ishtar_common/models.py
+++ b/ishtar_common/models.py
@@ -24,6 +24,7 @@ from ipware import get_client_ip
import sys
from bs4 import BeautifulSoup
+import bleach
import copy
import datetime
import inspect
@@ -78,6 +79,7 @@ from django.template import Context, Template
from django.template.defaultfilters import slugify
from django.urls import reverse
from django.utils.functional import lazy
+from django.utils.safestring import mark_safe
from ishtar_common.data_importer import post_importer_action
from ishtar_common.utils import (
ugettext_lazy as _,
@@ -141,6 +143,8 @@ from ishtar_common.utils import (
from ishtar_common.models_common import (
GeneralType,
HierarchicalType,
+ OrderedHierarchicalType,
+ OrderedType,
BaseHistorizedItem,
LightHistorizedItem,
HistoricalRecords,
@@ -194,6 +198,8 @@ __all__ = [
"Regexp",
"ImportTarget",
"ItemKey",
+ "OrderedHierarchicalType",
+ "OrderedType",
"TargetKey",
"FormaterType",
"Import",
@@ -2612,6 +2618,7 @@ class Organization(Address, Merge, OwnPerms, BaseGenderedType, ValueGetter, Main
default="",
help_text=documentation_get_gender_values,
)
+ museum_museofile_id = models.TextField(_("Museofile id"), blank=True, default="")
cached_label = models.TextField(
_("Cached name"), blank=True, default="", db_index=True
)
@@ -3204,6 +3211,38 @@ class Person(Address, Merge, OwnPerms, ValueGetter, MainItem):
post_save.connect(cached_label_changed, sender=Person)
+TEXT_FORMAT = (
+ ("NO", _("None")),
+ ("MD", _("Markdown")),
+ ("HT", _("HTML")),
+)
+
+
+def text_format(text, text_format):
+ if text_format == "MD":
+ return mark_safe(markdown(text))
+ elif text_format == "HT":
+ return mark_safe(bleach.clean(text))
+ return text_format
+
+
+class BiographicalNote(models.Model):
+ denomination = models.TextField(_("Denomination"))
+ last_name = models.TextField(_("Last name"), blank=True, default="")
+ first_name = models.TextField(_("First name"), blank=True, default="")
+ birth_year = models.PositiveIntegerField(_("Year of birth"), blank=True, null=True)
+ death_year = models.PositiveIntegerField(_("Year of death"), blank=True, null=True)
+ biography = models.TextField(_("Biography"), blank=True, default="")
+ biography_format = models.CharField(
+ _("Biography format"), blank=True, default="NO", max_length=2, choices=TEXT_FORMAT
+ )
+ person = models.ForeignKey(Person, verbose_name=_("Person"), blank=True, null=True, on_delete=models.SET_NULL)
+
+ @property
+ def formatted_biography(self):
+ return text_format(self.biography, self.biography_format)
+
+
GDPR_ACTIVITY = (
("DC", _("Directory consultation")),
("DE", _("Directory export")),
@@ -3939,16 +3978,20 @@ post_save.connect(post_save_cache, sender=Format)
post_delete.connect(post_save_cache, sender=Format)
-class LicenseType(GeneralType):
+class LicenseType(OrderedHierarchicalType):
url = models.URLField(_("URL"), blank=True, null=True)
class Meta:
verbose_name = _("License type")
verbose_name_plural = _("License types")
- ordering = ("label",)
+ ordering = ("parent__label", "order", "label",)
ADMIN_SECTION = _("Documents")
+post_save.connect(post_save_cache, sender=LicenseType)
+post_delete.connect(post_save_cache, sender=LicenseType)
+
+
class DocumentTag(GeneralType):
SLUG = "documenttag"
@@ -3959,8 +4002,20 @@ class DocumentTag(GeneralType):
ADMIN_SECTION = _("Documents")
-post_save.connect(post_save_cache, sender=LicenseType)
-post_delete.connect(post_save_cache, sender=LicenseType)
+post_save.connect(post_save_cache, sender=DocumentTag)
+post_delete.connect(post_save_cache, sender=DocumentTag)
+
+
+class ShootingAngle(OrderedType):
+ class Meta:
+ verbose_name = _("Shooting angle")
+ verbose_name_plural = _("Shooting angles")
+ ordering = ("order", "label",)
+ ADMIN_SECTION = _("Documents")
+
+
+post_save.connect(post_save_cache, sender=ShootingAngle)
+post_delete.connect(post_save_cache, sender=ShootingAngle)
class Document(
@@ -4391,9 +4446,17 @@ class Document(
publishing_year = models.PositiveIntegerField(
_("Year of publication"), blank=True, null=True
)
+ rights_owner = models.ForeignKey(
+ Organization,
+ verbose_name=_("Rights owner"),
+ blank=True,
+ null=True,
+ on_delete=models.SET_NULL,
+ )
licenses = models.ManyToManyField(
- LicenseType, verbose_name=_("License"), blank=True
+ LicenseType, verbose_name=_("Rights of use / license"), blank=True
)
+ copyright = models.TextField(_("Copyright"), blank=True, default="")
tags = models.ManyToManyField(DocumentTag, verbose_name=_("Tags"), blank=True)
language = models.ForeignKey(
Language,
@@ -4439,6 +4502,13 @@ class Document(
null=True,
)
scale = models.CharField(_("Scale"), max_length=30, null=True, blank=True)
+ shooting_angle = models.ForeignKey(
+ ShootingAngle,
+ verbose_name=_("Shooting angle"),
+ on_delete=models.SET_NULL,
+ blank=True,
+ null=True,
+ )
authors = models.ManyToManyField(
Author, verbose_name=_("Authors"), related_name="documents",
blank=True
diff --git a/ishtar_common/models_common.py b/ishtar_common/models_common.py
index 928b22630..c6b1316e4 100644
--- a/ishtar_common/models_common.py
+++ b/ishtar_common/models_common.py
@@ -725,6 +725,17 @@ class GeneralType(Cached, models.Model):
item.generate_key()
+class OrderedModel(models.Model):
+ order = models.IntegerField(_("Order"), default=10)
+ class Meta:
+ abstract = True
+
+
+class OrderedType(OrderedModel, GeneralType):
+ class Meta:
+ abstract = True
+
+
class HierarchicalType(GeneralType):
parent = models.ForeignKey(
"self",
@@ -758,6 +769,11 @@ class HierarchicalType(GeneralType):
parent = parent.parent
+class OrderedHierarchicalType(OrderedModel, HierarchicalType):
+ class Meta:
+ abstract = True
+
+
class StatisticItem:
STATISTIC_MODALITIES = [] # example: "year", "operation_type__label"
STATISTIC_MODALITIES_OPTIONS = OrderedDict() # example:
@@ -3297,7 +3313,7 @@ class MainItem(ShortMenuItem, SerializeItem, SheetItem):
if not getattr(request.user, "ishtaruser", None):
return False
user = request.user
- return user.ishtaruser.has_right(action_name, request.session)\
+ return user.ishtaruser.has_right(action_name, request.session)
def get_extra_actions(self, request):
if not hasattr(self, "SLUG"):
diff --git a/ishtar_common/templates/ishtar/sheet_document.html b/ishtar_common/templates/ishtar/sheet_document.html
index e4ce47af5..304d13579 100644
--- a/ishtar_common/templates/ishtar/sheet_document.html
+++ b/ishtar_common/templates/ishtar/sheet_document.html
@@ -86,7 +86,7 @@
{% field_flex "Language" item.language %}
{% field_flex "ISBN" item.isbn %}
{% field_flex "ISSN" item.issn %}
- {% field_flex_multiple_obj "Licenses" item 'licenses' %}
+ {% field_flex_multiple_obj "Rights of use / licenses" item 'licenses' %}
{% endif %}
{% if item.source or item.source_free_input %}