From 78789c02ed03236ad107683da0a6f180d33d6af9 Mon Sep 17 00:00:00 2001 From: Tris Forster Date: Fri, 21 Jun 2024 15:42:09 +1000 Subject: [PATCH] Minor UI Tweaks --- .gitignore | 1 + TODO.md | 19 +++++ ...lection_settings_alter_document_doctype.py | 23 ++++++ app/library/models.py | 8 +- .../templates/library/document_annotate.html | 4 +- .../templates/library/storage_browser.html | 12 +++ .../templates/library/work_detail.html | 78 +++++++++---------- .../library/work_parts_fragment.html | 6 +- app/library/urls.py | 3 + app/library/views/__init__.py | 25 +++++- 10 files changed, 128 insertions(+), 51 deletions(-) create mode 100644 TODO.md create mode 100644 app/library/migrations/0015_collection_settings_alter_document_doctype.py create mode 100644 app/library/templates/library/storage_browser.html diff --git a/.gitignore b/.gitignore index 67709bf..189d8b8 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,7 @@ __pycache__ *.pyc *.sqlite3 +*.swp credentials.json credentials local_settings.py diff --git a/TODO.md b/TODO.md new file mode 100644 index 0000000..cc992ab --- /dev/null +++ b/TODO.md @@ -0,0 +1,19 @@ +## Polyphonic TODO + +## Core interface + +* Shift from crispy forms to native component templates +* Make long running calls async (Django 5) +* Deprecate Django 4 portions + +### Library App + +* Remove music tags and replace with strings vn1 -> 'Violin 1' +* GDrive selector +* Move upload to modal from 'Upload' button +* Tagging app - migrate to AlpineJS +* Allow other tags (movements, sections, pieces) + +### Submissions App + +* None currently pending diff --git a/app/library/migrations/0015_collection_settings_alter_document_doctype.py b/app/library/migrations/0015_collection_settings_alter_document_doctype.py new file mode 100644 index 0000000..999e512 --- /dev/null +++ b/app/library/migrations/0015_collection_settings_alter_document_doctype.py @@ -0,0 +1,23 @@ +# Generated by Django 5.0.6 on 2024-06-18 05:57 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('library', '0014_auto_20230223_1422'), + ] + + operations = [ + migrations.AddField( + model_name='collection', + name='settings', + field=models.JSONField(default=dict, help_text='Storage specific settings'), + ), + migrations.AlterField( + model_name='document', + name='doctype', + field=models.PositiveSmallIntegerField(choices=[(1, 'PDF'), (2, 'Audio'), (3, 'Video'), (4, 'Misc')], default=1), + ), + ] diff --git a/app/library/models.py b/app/library/models.py index acb5cbc..26a362c 100644 --- a/app/library/models.py +++ b/app/library/models.py @@ -86,14 +86,14 @@ class ProjectItem(models.Model): def __str__(self): return f"<{self.project_id}:{slugify(self.work.name)}>" - + class Collection(models.Model): """ A logical collection of works, typically owned by an organisation or person (physical or virtual) """ name = models.CharField(max_length=255, help_text="Name of the collection") - prefix = models.SlugField(max_length=30, default="default", + prefix = models.CharField(max_length=255, default="default", help_text="Folder to store works in") administrators = models.ManyToManyField('auth.User', related_name="collections", help_text="Administrators for this collection") @@ -103,6 +103,8 @@ class Collection(models.Model): help_text="User storage for documents") notes = models.TextField(blank=True, help_text="Publicly visible notes about collection and loans policy (markdown format)") + settings = models.JSONField(default=dict, blank=True, + help_text="Storage specific settings") nonce = models.SmallIntegerField(default=1, help_text="Increment this to reset the authentication links") @@ -405,4 +407,4 @@ class Section(models.Model): return "all" def __str__(self): - return self.name \ No newline at end of file + return self.name diff --git a/app/library/templates/library/document_annotate.html b/app/library/templates/library/document_annotate.html index 204066e..64dc371 100644 --- a/app/library/templates/library/document_annotate.html +++ b/app/library/templates/library/document_annotate.html @@ -139,7 +139,7 @@ crossorigin="anonymous"> {{ json_data|json_script:"data" }} -{% endblock %} \ No newline at end of file +{% endblock %} diff --git a/app/library/templates/library/storage_browser.html b/app/library/templates/library/storage_browser.html new file mode 100644 index 0000000..baef259 --- /dev/null +++ b/app/library/templates/library/storage_browser.html @@ -0,0 +1,12 @@ +{% load path_filters %} +
+

Listing for {{ collection }}

+ +
diff --git a/app/library/templates/library/work_detail.html b/app/library/templates/library/work_detail.html index 068528a..0d6cc32 100644 --- a/app/library/templates/library/work_detail.html +++ b/app/library/templates/library/work_detail.html @@ -25,46 +25,46 @@ {% endfor %}

{% firstof work.composer "Unattributed" %}{% if work.edition %} - {{ work.edition }}{% endif %}

-
-

{{ work.notes }}

- -

- - - - - - - - - - -
Location:{{ work.collection }} [{{ work.identifier }}]Orchestration:{{ work.orchestration }}
Running time:{% firstof work.duration 'Unknown' %}Licence:{{ work.get_licence_display }}
- {% for meta in work.meta %} - - {{ meta.get_name_display }}: - {{ meta.value }} - - {% endfor %} -
- - {% if work.parent %} -

From {{ work.parent.name }} - {{ work.parent.composer }} -

- {% endif %} - - {% if work.related_works.count %} -

Related

- - {% endif %} -
+
+

{{ work.notes }}

+ +

+ + + + + + + + + + +
Location:{{ work.collection }} [{{ work.identifier }}]Orchestration:{{ work.orchestration }}
Running time:{% firstof work.duration 'Unknown' %}Licence:{{ work.get_licence_display }}
+ {% for meta in work.meta %} + + {{ meta.get_name_display }}: + {{ meta.value }} + + {% endfor %} +
+ + {% if work.parent %} +

From {{ work.parent.name }} - {{ work.parent.composer }} +

+ {% endif %} + + {% if work.related_works.count %} +

Related

+ + {% endif %} +

@@ -79,8 +79,6 @@ {% endfor %}

-
-

@@ -206,4 +204,4 @@ {% endblock %} -{% endblock %} \ No newline at end of file +{% endblock %} diff --git a/app/library/templates/library/work_parts_fragment.html b/app/library/templates/library/work_parts_fragment.html index 0f510f1..62464a5 100644 --- a/app/library/templates/library/work_parts_fragment.html +++ b/app/library/templates/library/work_parts_fragment.html @@ -1,10 +1,11 @@

{{ work.name }}

-
+
{% for tag, name in work.digital_parts %} -{{ name }} +{{ name }} {% endfor %}
+

More details... diff --git a/app/library/urls.py b/app/library/urls.py index 3e2cb82..34f5051 100644 --- a/app/library/urls.py +++ b/app/library/urls.py @@ -35,10 +35,13 @@ urlpatterns = [ path('collections//docs//annotate', views.DocumentAnnotateView.as_view(), name="document_annotate"), path('collections//download//', views.PartDownloadView.as_view(), name="part_download"), + path('collections//browse', views.StorageBrowserView.as_view(), name="storage_browser"), + path('collections//browse/', views.StorageBrowserView.as_view(), name="storage_browser_folder"), #path('api/', include(router.urls)) path('api/collections/', api.CollectionExportView.as_view(), name="collection_export"), path('api/collections//works/', api.WorkExportView.as_view(), name="work_export"), path('api/collections//import', api.WorkImportView.as_view(), name="work_import"), path('api/collections//bulk_import', api.CollectionImportView.as_view(), name="collection_import"), + ] diff --git a/app/library/views/__init__.py b/app/library/views/__init__.py index a021b22..ddf5ef0 100644 --- a/app/library/views/__init__.py +++ b/app/library/views/__init__.py @@ -1,4 +1,5 @@ from django.shortcuts import get_object_or_404, redirect, resolve_url +from django.views.generic import TemplateView from django.views.generic.detail import DetailView, SingleObjectMixin, View from django.views.generic.list import ListView, MultipleObjectMixin from django.views.generic.edit import CreateView, FormView, UpdateView, DeleteView @@ -18,6 +19,7 @@ import re from interface.views import EnsembleMixin, ProjectMixin, AuthorizedResourceMixin from interface.models import Project +from interface.utils import signed_url from library.models import Collection, Work, Document, Section from library.music_tags import MUSIC_TAGS, MusicTag, auto_tag from library import forms, models @@ -416,9 +418,11 @@ class DocumentDownloadView(DocumentMixin, SingleObjectMixin, View): self.args = args self.object = self.get_object() - #response = FileResponse(self.object.upload, content_type="application/pdf") - #return response - return redirect(self.object.upload.url) + if request.GET.get('method') == 'direct': + return redirect(self.object.upload.url) + + response = FileResponse(self.object.upload.open('rb'), content_type="application/pdf") + return response class DocumentAnnotateView(DocumentMixin, DetailView): template_name = 'library/document_annotate.html' @@ -446,6 +450,8 @@ class DocumentAnnotateView(DocumentMixin, DetailView): for part in data['document'].sections.all(): pages.append((part.tag, part.start, part.end)) + data['url'] = signed_url('document_download', collection=data['collection'].pk, pk=data['document'].pk) + data['json_data'] = {'pageTags': pages, 'instruments': dict(MUSIC_TAGS)} return data @@ -479,4 +485,15 @@ class PartDownloadView(CollectionMixin, SingleObjectMixin, View): def get_object(self): - return Section.objects.filter(doc__work__collection=self.collection).select_related('doc', 'doc__work').get(pk=self.kwargs['section']) \ No newline at end of file + return Section.objects.filter(doc__work__collection=self.collection).select_related('doc', 'doc__work').get(pk=self.kwargs['section']) + + +class StorageBrowserView(CollectionMixin, TemplateView): + template_name = "library/storage_browser.html" + + def get_context_data(self, **kwargs): + data = super().get_context_data(**kwargs) + folder = self.kwargs.get('folder') or data['collection'].prefix + data['folders'], data['files'] = data['collection'].storage.instance().listdir(folder) + return data +