From e74043ae678b63bbd95a58e2e71acc96263594c6 Mon Sep 17 00:00:00 2001 From: Tris Forster Date: Mon, 20 Feb 2023 10:28:38 +1100 Subject: [PATCH] Fixed work create and some security issues --- app/library/forms.py | 2 +- .../migrations/0012_auto_20230220_1013.py | 33 ++++++++++++++++++ app/library/models.py | 6 ++-- app/library/views/__init__.py | 34 +++++++++---------- app/library/views/api.py | 11 +++--- 5 files changed, 60 insertions(+), 26 deletions(-) create mode 100644 app/library/migrations/0012_auto_20230220_1013.py diff --git a/app/library/forms.py b/app/library/forms.py index d992a6e..abb90dc 100644 --- a/app/library/forms.py +++ b/app/library/forms.py @@ -9,7 +9,7 @@ class WorkCreateForm(forms.ModelForm, BaseForm): class Meta: model = Work - fields = ['name', 'composer', 'edition', 'code', 'running_time', 'notes'] + fields = ['name', 'composer', 'edition', 'code', 'orchestration', 'licence', 'running_time', 'notes'] class PlaylistAddForm(forms.Form): work = forms.ModelChoiceField(queryset=Work.objects.all()) diff --git a/app/library/migrations/0012_auto_20230220_1013.py b/app/library/migrations/0012_auto_20230220_1013.py new file mode 100644 index 0000000..30a2afe --- /dev/null +++ b/app/library/migrations/0012_auto_20230220_1013.py @@ -0,0 +1,33 @@ +# Generated by Django 3.2.7 on 2023-02-19 23:13 + +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + ('library', '0011_section_page'), + ] + + operations = [ + migrations.RemoveField( + model_name='orchestration', + name='ensemble', + ), + migrations.AddField( + model_name='orchestration', + name='collection', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='custom_orchestrations', to='library.collection'), + ), + migrations.AlterField( + model_name='work', + name='original_parts', + field=models.JSONField(blank=True, default=dict, help_text='Original printed parts (IMSLP format)'), + ), + migrations.AlterField( + model_name='work', + name='running_time', + field=models.DurationField(blank=True, help_text='Running time in mm:ss format', null=True), + ), + ] diff --git a/app/library/models.py b/app/library/models.py index 56b5c2f..156c0d6 100644 --- a/app/library/models.py +++ b/app/library/models.py @@ -33,7 +33,9 @@ class Orchestration(models.Model): Stores a list of instrument codes as a single entry (space delimited). Can be global or ensemble specific """ - ensemble = models.ForeignKey('interface.Ensemble', on_delete=models.CASCADE, related_name="orchestrations", null=True, blank=True) + # TODO: change ensemble to collection + #ensemble = models.ForeignKey('interface.Ensemble', on_delete=models.CASCADE, related_name="orchestrations", null=True, blank=True) + collection = models.ForeignKey('Collection', on_delete=models.CASCADE, related_name="custom_orchestrations", null=True, blank=True) name = models.CharField(max_length=100) instruments = models.TextField() @@ -181,7 +183,7 @@ class Work(models.Model): max_projects = models.IntegerField(default=1, help_text="How many active projects can this work be attached to") # Extra info - running_time = models.DurationField(null=True, blank=True, help_text="Running time in seconds") + running_time = models.DurationField(null=True, blank=True, help_text="Running time in mm:ss format") notes = models.TextField(blank=True) # Allocation to projects diff --git a/app/library/views/__init__.py b/app/library/views/__init__.py index 6ae03be..3580277 100644 --- a/app/library/views/__init__.py +++ b/app/library/views/__init__.py @@ -161,7 +161,7 @@ class WorkListView(CollectionMixin, ListView): def get_works(self): collections = CollectionMixin.get_queryset(self) - return Work.objects.filter(collection__in=collections).order_by('name').distinct().select_related('collection') + return Work.objects.filter(collection__in=collections).select_related('collection') def get_context_data(self, *args, **kwargs): data = super(WorkListView, self).get_context_data(*args, **kwargs) @@ -180,15 +180,16 @@ class WorkListView(CollectionMixin, ListView): else: works = works.filter(Q(name__contains=q) | Q(composer__contains=q) | Q(meta_info__value__contains=q)) - return works.order_by('name', 'pk') + return works.order_by('name', 'composer', 'edition', 'pk') class CollectionWorkListView(WorkListView): def get_works(self): - works = Work.objects.filter(collection=self.kwargs['collection']).distinct() + works = Work.objects.filter(collection=self.kwargs['collection']) - loan_count = Count('project_items', Q(project_items__checkout__lte=now(), project_items__returned=None)) - works = works.annotate(loan_count=loan_count) + if self.request.is_admin: + loan_count = Count('project_items', Q(project_items__checkout__lte=now(), project_items__returned=None)) + works = works.annotate(loan_count=loan_count) return works def get_context_data(self, *args, **kwargs): @@ -202,6 +203,12 @@ class WorkAddView(CollectionMixin, FormView): title = "Add a new work" + def get_form(self, form_class=None): + form = super().get_form(form_class) + qs = models.Orchestration.objects.filter(Q(collection=None) | Q(collection=self.collection)) + form.fields['orchestration'].queryset = qs.order_by('-collection_id', 'pk') + return form + def form_valid(self, form): work = form.save(commit=False) #work.ensemble_id = self.request.ensemble_id @@ -219,19 +226,12 @@ class WorkAddView(CollectionMixin, FormView): else: return redirect('work_detail', collection=self.collection.pk, pk=work.pk) -class WorkMixin(object): - - def get_queryset(self): - if self.request.is_admin: - return Work.objects.all() - - return Work.objects.filter(collection__allowed_ensembles__ensemble=self.request.ensemble_id) - -class WorkDetailView(CollectionMixin, WorkMixin, DetailView): +class WorkDetailView(CollectionMixin, DetailView): pass -class WorkUpdateView(CollectionMixin, WorkMixin, UpdateView): - fields = ['name', 'composer', 'edition', 'code', 'licence', 'max_projects', 'running_time', 'notes'] +class WorkUpdateView(CollectionMixin, UpdateView): + #fields = ['name', 'composer', 'edition', 'code', 'orchestration', 'licence', 'max_projects', 'running_time', 'notes'] + form_class = forms.WorkCreateForm template_name = 'interface/default_form.html' def get_success_url(self): @@ -266,7 +266,7 @@ class WorkAddToProject(ProjectMixin, FormView): -class WorkPartSetView(EnsembleMixin, DetailView): +class WorkPartSetView(CollectionMixin, DetailView): template_name = "library/work_partset.html" def post(self, request, *args, **kwargs): diff --git a/app/library/views/api.py b/app/library/views/api.py index 03b2e53..3a1fd2a 100644 --- a/app/library/views/api.py +++ b/app/library/views/api.py @@ -32,8 +32,7 @@ class WorkExportView(EnsembleMixin, WorkMixin, View): """ -from library.views import WorkMixin -from interface.views import EnsembleMixin +from interface.views import AuthorizedResourceMixin from rest_framework import routers, serializers, viewsets @@ -168,25 +167,25 @@ class CollectionSerializer(serializers.Serializer): from rest_framework import generics -class CollectionExportView(generics.RetrieveAPIView): +class CollectionExportView(AuthorizedResourceMixin, generics.RetrieveAPIView): serializer_class = CollectionSerializer def get_queryset(self): return Collection.objects.filter(administrators=self.request.user) -class WorkExportView(generics.RetrieveAPIView): +class WorkExportView(AuthorizedResourceMixin, generics.RetrieveAPIView): serializer_class = WorkSerializer def get_queryset(self): return Work.objects.filter(collection__administrators=self.request.user) -class WorkImportView(generics.CreateAPIView): +class WorkImportView(AuthorizedResourceMixin, generics.CreateAPIView): serializer_class = WorkSerializer def perform_create(self, serializer): serializer.save(collection_id=self.kwargs['pk']) -class CollectionImportView(generics.CreateAPIView): +class CollectionImportView(AuthorizedResourceMixin, generics.CreateAPIView): serializer_class = CollectionSerializer def perform_create(self, serializer):