From 5f137ebb4836042b1d217b9074e6f0bf0ea8df2e Mon Sep 17 00:00:00 2001 From: quimmrc Date: Thu, 16 Jan 2025 10:19:59 +0100 Subject: [PATCH] attempt to implement collection modals --- fscollections/forms.py | 94 +++++++++++++++++++ fscollections/models.py | 8 +- fscollections/urls.py | 5 +- fscollections/views.py | 84 ++++++++++++++--- sounds/forms.py | 2 +- templates/collections/collections.html | 16 +++- .../collections/modal_collect_sound.html | 47 ++++++++++ templates/molecules/navbar_user_section.html | 3 + templates/sounds/sound.html | 5 + 9 files changed, 245 insertions(+), 19 deletions(-) create mode 100644 templates/collections/modal_collect_sound.html diff --git a/fscollections/forms.py b/fscollections/forms.py index e69de29bb..d3a11c239 100644 --- a/fscollections/forms.py +++ b/fscollections/forms.py @@ -0,0 +1,94 @@ +# +# Freesound is (c) MUSIC TECHNOLOGY GROUP, UNIVERSITAT POMPEU FABRA +# +# Freesound is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# Freesound is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +# +# Authors: +# See AUTHORS file. +# + +from django import forms +from fscollections.models import Collection + +#this class was aimed to perform similarly to BookmarkSound, however, at first the method to add a sound to a collection +#will be opening the search engine in a modal, looking for a sound in there and adding it to the actual collection page +#this can be found in edit pack -> add sounds +#class CollectSoundForm(forms.ModelForm): + +class CollectionSoundForm(forms.Form): + #list of existing collections + #add sound to collection from sound page + collection = forms.ChoiceField( + label=False, + choices=[], + required=True) + + new_collection_name = forms.ChoiceField( + label = False, + help_text=None, + required = False) + + use_last_collection = forms.BooleanField(widget=forms.HiddenInput(), required=False, initial=False) + user_collections = None + + NO_COLLECTION_CHOICE_VALUE = '-1' + NEW_COLLECTION_CHOICE_VALUE = '0' + + def __init__(self, *args, **kwargs): + self.user_collections = kwargs.pop('user_collections', False) + self.user_saving_sound = kwargs.pop('user_saving_sound', False) + self.sound_id = kwargs.pop('sound_id', False) + super().__init__(*args, **kwargs) + self.fields['collection'].choices = [(self.NO_COLLECTION_CHOICE_VALUE, '--- No collection ---'),#in this case this goes to bookmarks collection (might have to be created) + (self.NEW_COLLECTION_CHOICE_VALUE, 'Create a new collection...')] + \ + ([(collection.id, collection.name) for collection in self.user_collections] + if self.user_collections else[]) + + self.fields['new_collection_name'].widget.attrs['placeholder'] = "Fill in the name for the new collection" + self.fields['category'].widget.attrs = { + 'data-grey-items': f'{self.NO_CATEGORY_CHOICE_VALUE},{self.NEW_CATEGORY_CHOICE_VALUE}'} + #i don't fully understand what this last line of code does + + def save(self, *args, **kwargs): + collection_to_use = None + + if not self.cleaned_data['use_last_collection']: + if self.cleaned_data['collection'] == self.NO_COLLECTION_CHOICE_VALUE: + pass + elif self.cleaned_data['collection'] == self.NEW_COLLECTION_CHOICE_VALUE: + if self.cleaned_data['new_collection_name'] != "": + collection = \ + Collection(author=self.user_saving_bookmark, name=self.cleaned_data['new_collection_name']) + collection.save() + collection_to_use = collection + else: + collection_to_use = Collection.objects.get(id=self.cleaned_data['collection']) + else: #en aquest cas - SÍ estem fent servir l'última coleccio, NO estem creant una nova coleccio, NO estem agafant una coleccio existent i + # per tant ens trobem en un cas de NO COLLECTION CHOICE VALUE (no s'ha triat cap coleccio) + # si no es tria cap coleccio: l'usuari té alguna colecció? NO -> creem BookmarksCollection pels seus sons privats + # SI -> per defecte es posa a BookmarksCollection + try: + last_user_collection = \ + Collection.objects.filter(user=self.user_saving_bookmark).order_by('-created')[0] + # If user has a previous bookmark, use the same category (or use none if no category used in last + # bookmark) + collection_to_use = last_user_collection + except IndexError: + # This is first bookmark of the user + pass + + # If collection already exists, don't save it and return the existing one + collection, _ = Collection.objects.get_or_create( + name = collection_to_use.name, author=self.user_saving_bookmark) + return collection \ No newline at end of file diff --git a/fscollections/models.py b/fscollections/models.py index 14ca5a17d..8ef207ed6 100644 --- a/fscollections/models.py +++ b/fscollections/models.py @@ -26,13 +26,17 @@ class Collection(models.Model): author = models.ForeignKey(User, on_delete=models.CASCADE) - name = models.CharField(max_length=128, default="") #add restrictions - sounds = models.ManyToManyField(Sound, related_name="collections") #NOTE: before next migration pluralize sound(s) - check consequences in views + name = models.CharField(max_length=128, default="BookmarkCollection") #add restrictions + sounds = models.ManyToManyField(Sound, related_name="collections") created = models.DateTimeField(db_index=True, auto_now_add=True) description = models.TextField(max_length=500, default="") #NOTE: before next migration add a num_sounds attribute + #bookmarks = True or False depending on it being the BookmarkCollection for a user (the one created for the first sound without collection assigned) #contributors = delicate stuff #subcolletion_path = sth with tagsn and routing folders for downloads + #follow relation for users and collections (intersted but not owner nor contributor) + #sooner or later you'll need to start using forms for adding sounds to collections xd + def __str__(self): return f"{self.name}" diff --git a/fscollections/urls.py b/fscollections/urls.py index 63db75ba1..a58ab80e1 100644 --- a/fscollections/urls.py +++ b/fscollections/urls.py @@ -3,5 +3,8 @@ urlpatterns = [ path('',views.collections, name='collections'), - path('/', views.collections, name='collections') + path('/', views.collections, name='collections'), + path('//delete/', views.delete_sound_from_collection, name='delete-sound-from-collection'), + path('/add/', views.add_sound_to_collection, name='add-sound-to-collection'), + path('get_form_for_collection_sound//', views.get_form_for_collecting_sound, name="collection-add-form-for-sound") ] \ No newline at end of file diff --git a/fscollections/views.py b/fscollections/views.py index b077e60bb..f1b0ec83e 100644 --- a/fscollections/views.py +++ b/fscollections/views.py @@ -25,43 +25,101 @@ from django.urls import reverse from fscollections.models import Collection +from fscollections.forms import CollectionSoundForm from sounds.models import Sound +from sounds.views import add_sounds_modal_helper @login_required def collections(request, collection_id=None): user = request.user user_collections = Collection.objects.filter(author=user).order_by('-created') #first user collection should be on top - this would affect the if block + is_owner = False #if no collection id is provided for this URL, render the oldest collection in the webpage + #be careful when loading this url without having any collection for a user + #rn the relation user-collection only exists when you own the collection + if not collection_id: collection = user_collections.last() else: collection = get_object_or_404(Collection, id=collection_id) - + + if user == collection.author: + is_owner = True + tvars = {'collection': collection, - 'collections_for_user': user_collections} + 'collections_for_user': user_collections, + 'is_owner': is_owner} return render(request, 'collections/collections.html', tvars) -#upon creating a new user, create alongside a personal PRIVATE collection to store sounds +#NOTE: tbd - when a user wants to save a sound without having any collection, create a personal bookmarks collection -def add_sound_to_collection(request, sound_id, collection_id): +def add_sound_to_collection(request, sound_id, collection_id=None): sound = get_object_or_404(Sound, id=sound_id) - collection = get_object_or_404(Collection, id=collection_id, author=request.user) + if collection_id is None: + collection = Collection.objects.filter(author=request.user).order_by("created")[0] + else: + collection = get_object_or_404(Collection, id=collection_id, author=request.user) if sound.moderation_state=='OK': collection.sounds.add(sound) collection.save() - return True + return HttpResponseRedirect(reverse("collections", args=[collection.id])) else: return "sound not moderated or not collection owner" + -def delete_sound_from_collection(request, sound_id, collection_id): +def delete_sound_from_collection(request, collection_id, sound_id): + #this should work as in Packs - select several sounds and remove them all at once from the collection + #by now it works as in Bookmarks in terms of UI sound = get_object_or_404(Sound, id=sound_id) collection = get_object_or_404(Collection, id=collection_id, author=request.user) + collection.sounds.remove(sound) + collection.save() + return HttpResponseRedirect(reverse("collections", args=[collection.id])) - if sound in collection.sound.all(): - collection.sounds.remove(sound) - collection.save() - return True - else: - return "this sound is not in the collection" \ No newline at end of file +@login_required +def get_form_for_collecting_sound(request, sound_id): + user = request.user + sound = Sound.objects.get(id=sound_id) + + try: + last_collection = \ + Collection.objects.filter(author=request.user).order_by('-created')[0] + # If user has a previous bookmark, use the same category by default (or use none if no category used in last + # bookmark) + except IndexError: + last_collection = None + + user_collections = Collection.objects.filter(author=user).order_by('-created') + form = CollectionSoundForm(initial={'collection': last_collection.id if last_collection else CollectionSoundForm.NO_COLLECTION_CHOICE_VALUE}, + prefix=sound.id, + user_collections=user_collections) + + collections_already_containing_sound = Collection.objects.filter(author=user, collection__sounds=sound).distinct() + tvars = {'user': user, + 'sound': sound, + 'last_collection': last_collection, + 'collections': user_collections, + 'form': form, + 'collections_with_sound': collections_already_containing_sound} + print("NICE CHECKPOINT") + print(tvars) + + return render(request, 'modal_collect_sound.html', tvars) + + +#NOTE: there should be two methods to add a sound into a collection +#1: adding from the sound.html page through a "bookmark-like" button and opening a Collections modal +#2: from the collection.html page through a search-engine modal as done in Packs +""" +@login_required +def add_sounds_modal_for_collection(request, collection_id): + collection = get_object_or_404(Collection, id=collection_id) + tvars = add_sounds_modal_helper(request, username=collection.author.username) + tvars.update({ + 'modal_title': 'Add sounds to Collection', + 'help_text': 'Collections are great!', + }) + return render(request, 'sounds/modal_add_sounds.html', tvars) +""" \ No newline at end of file diff --git a/sounds/forms.py b/sounds/forms.py index 59e1b846e..ff2bc1f09 100644 --- a/sounds/forms.py +++ b/sounds/forms.py @@ -121,7 +121,7 @@ class PackEditForm(ModelForm): required=False) description = HtmlCleaningCharField(widget=forms.Textarea(attrs={'cols': 80, 'rows': 10}), help_text=HtmlCleaningCharField.make_help_text(), required=False) - + def clean_pack_sounds(self): pack_sounds = re.sub("[^0-9,]", "", self.cleaned_data['pack_sounds']) pack_sounds = re.sub(",+", ",", pack_sounds) diff --git a/templates/collections/collections.html b/templates/collections/collections.html index 0d47c6b2d..a3f8a2058 100644 --- a/templates/collections/collections.html +++ b/templates/collections/collections.html @@ -13,23 +13,35 @@

Your collections

    + {% if collections_for_user %} {% for col in collections_for_user %}
  • {{col.name}} · {{col.sounds.count}} sound{{col.sounds.count|pluralize}}
  • {% endfor %} + {% else %} + You don't have any collection yet... + {% endif %}
-

{{collection.name}}

+

{{collection.name}}

+ by {{collection.author.username}} +
Description: {% if collection.description %}{{collection.description}} {% endif %}
+
{% if collection.sounds.count > 0 %} {% for sound in collection.sounds.all %}
{% display_sound_small sound %} + {% if is_owner %} + + {% endif %}
{% endfor %} - {% else %} There aren't any sounds in this collection yet {% endif %} + {% else %} + There aren't any sounds in this collection yet + {% endif %}
diff --git a/templates/collections/modal_collect_sound.html b/templates/collections/modal_collect_sound.html new file mode 100644 index 000000000..b98dba422 --- /dev/null +++ b/templates/collections/modal_collect_sound.html @@ -0,0 +1,47 @@ +{% extends "molecules/modal_base.html" %} +{% load static %} +{% load bw_templatetags %} + +{% block id %}collectSoundModal{% endblock %} +{% block extra-class %}{% if request.user.is_authenticated %}modal-width-60{% endif %}{% endblock %} +{% block aria-label %}Collect sound modal{% endblock %} + +
+ {% if not request.user.is_authenticated %} +
+

Can't collect sound

+
+
+
To collect sounds, you need to be logged in with your Freesound account.
+ +
+ {% elif not sound_is_moderated_and_processed_ok %} +
+

Can't collect sound

+
+
+
This sound can't be collected because it has not yet been processed or moderated.
+ +
+ {% else %} +
+

Collect Sound

+
+
+ {% if collections%} +
+ {% bw_icon 'bookmark-filled' %}This sound is already in your collections under + {% for col in collections_with_sound %} + {{col.name}}{% if not forloop.last%},{% endif %} + {% endfor %} +
+ {% endif %} +
+ {{ form }} + +
+
+ {% endif %} +
+{% endblock%} + diff --git a/templates/molecules/navbar_user_section.html b/templates/molecules/navbar_user_section.html index c5b271da3..f878f0a46 100644 --- a/templates/molecules/navbar_user_section.html +++ b/templates/molecules/navbar_user_section.html @@ -18,6 +18,9 @@ + diff --git a/templates/sounds/sound.html b/templates/sounds/sound.html index c0af6107d..24c6accc2 100644 --- a/templates/sounds/sound.html +++ b/templates/sounds/sound.html @@ -75,6 +75,11 @@

{% bw_icon 'bookmark' %} + + +