diff options
author | Étienne Loks <etienne.loks@iggdrasil.net> | 2024-04-16 16:41:46 +0200 |
---|---|---|
committer | Étienne Loks <etienne.loks@iggdrasil.net> | 2024-04-16 16:41:46 +0200 |
commit | 6e95beabf26ddd3d8de69e34dfbfb97bc1625d80 (patch) | |
tree | 364c2688b46f47d3ee9243e70cbaf5485e177b0f /ishtar_common | |
parent | 303a62efae3d3f568545c682649a29de1fb7fc83 (diff) | |
download | Ishtar-6e95beabf26ddd3d8de69e34dfbfb97bc1625d80.tar.bz2 Ishtar-6e95beabf26ddd3d8de69e34dfbfb97bc1625d80.zip |
🗃️ museum module: new db fields, add admin
Diffstat (limited to 'ishtar_common')
-rw-r--r-- | ishtar_common/admin.py | 4 | ||||
-rw-r--r-- | ishtar_common/forms_common.py | 4 | ||||
-rw-r--r-- | ishtar_common/migrations/0236_auto_20240208_1635.py | 112 | ||||
-rw-r--r-- | ishtar_common/models.py | 80 | ||||
-rw-r--r-- | ishtar_common/models_common.py | 18 | ||||
-rw-r--r-- | ishtar_common/templates/ishtar/sheet_document.html | 2 |
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 %} |