Repository: DDMAL/CantusDB

Issue:
Source edit form
The source edit form needs to be implemented. This should be made accessible from every source detail page. 
An example is https://cantus.uwaterloo.ca/source/123654 and https://cantus.uwaterloo.ca/node/123654/edit


Discussion:

Resolving patch:
diff --git a/django/cantusdb_project/main_app/forms.py b/django/cantusdb_project/main_app/forms.py
--- a/django/cantusdb_project/main_app/forms.py
+++ b/django/cantusdb_project/main_app/forms.py
@@ -1,4 +1,5 @@
 from django import forms
+
 from .models import Chant, Office, Genre, Feast, Source, RismSiglum, Provenance, Century, Indexer
 from .widgets import *
 from django.contrib.auth import get_user_model
@@ -262,3 +263,90 @@ class Meta:
         queryset=Feast.objects.all().order_by("name"), required=False
     )
     feast.widget.attrs.update({"class": "form-control custom-select custom-select-sm"})
+
+class SourceEditForm(forms.ModelForm):
+    class Meta:
+        model = Source
+        fields = [
+            "title",
+            "rism_siglum",
+            "siglum",
+            "provenance",
+            "provenance_notes",
+            "full_source",
+            "date",
+            "century",
+            "cursus",
+            "melodies_entered_by",
+            "complete_inventory",
+            "summary",
+            "description",
+            "selected_bibliography",
+            "image_link",
+            "fragmentarium_id",
+            "dact_id",
+            "indexing_notes"
+        ]
+        widgets = {
+            "title": TextInputWidget(),
+            "rism_siglum": TextInputWidget(),
+            "siglum": TextInputWidget(),
+            "provenance_notes": TextInputWidget(),
+            "date": TextInputWidget(),
+            "summary": TextAreaWidget(),
+            "description": TextAreaWidget(),
+            "selected_bibliography": TextAreaWidget(),
+            "image_link": TextInputWidget(),
+            "fragmentarium_id": TextInputWidget(),
+            "dact_id": TextInputWidget(),
+            "indexing_notes": TextAreaWidget(),
+        }
+    
+    provenance = forms.ModelChoiceField(
+        queryset=Provenance.objects.all().order_by("name"), required=False
+    )
+    provenance.widget.attrs.update({"class": "form-control custom-select custom-select-sm"}) # what does this do? - this adds styling - TODO remove these comments
+    
+    century = forms.ModelChoiceField(
+        queryset=Century.objects.all().order_by("name"), required = False
+    )
+    century.widget.attrs.update({"class": "form-control custom-select custom-select-sm"}) # what does this do?
+
+    CHOICES_FULL_SOURCE = (
+        (None, "None"),
+        (True, "Full source"),
+        (False, "Fragment or Fragmented"),
+    )
+    full_source = forms.ChoiceField(
+        choices=CHOICES_FULL_SOURCE, required=False
+    )
+    full_source.widget.attrs.update({"class": "form-control custom-select custom-select-sm"}) # what does this do?
+
+    CHOICES_CURSUS = (
+        (None, "None"),
+        ("Monastic", "Monastic"),
+        ("Secular", "Secular"),
+    )
+    cursus = forms.ChoiceField(
+        choices=CHOICES_CURSUS, required=False
+    )
+    cursus.widget.attrs.update({"class": "form-control custom-select custom-select-sm"}) # what does this do?
+
+    current_editors = forms.ModelMultipleChoiceField(
+        queryset=get_user_model().objects.all().order_by("last_name")
+    )
+    current_editors.widget.attrs.update({"class": "form-control custom-select custom-select-sm"})
+
+    melodies_entered_by = forms.ModelMultipleChoiceField(
+        queryset=get_user_model().objects.all().order_by("last_name"), required = False
+    )
+    melodies_entered_by.widget.attrs.update({"class": "form-control custom-select custom-select-sm"})
+
+    CHOICES_COMPLETE_INV = (
+        (True, "complete inventory"),
+        (False, "partial inventory"),
+    )
+    complete_inventory = forms.ChoiceField(
+        choices=CHOICES_COMPLETE_INV, required=False
+    )
+    complete_inventory.widget.attrs.update({"class": "form-control custom-select custom-select-sm"}) # what does this do?
diff --git a/django/cantusdb_project/main_app/urls.py b/django/cantusdb_project/main_app/urls.py
--- a/django/cantusdb_project/main_app/urls.py
+++ b/django/cantusdb_project/main_app/urls.py
@@ -1,7 +1,7 @@
 from django.urls import path, include
 from main_app.views import *
 from main_app.views import views
-from main_app.views.source import SourceCreateView
+from main_app.views.source import SourceCreateView, SourceEditView
 from main_app.views.chant import ChantEditVolpianoView
 from django.contrib.auth import views as auth_views
 from main_app.views.user import UserDetailView, UserSourceListView
@@ -73,7 +73,12 @@
     path("users/<int:user_id>", UserDetailView.as_view(), name="user-detail"),
     path("my-sources/", UserSourceListView.as_view(), name="my-sources"),
     path('login/', auth_views.LoginView.as_view(redirect_authenticated_user=True), name="login"),
-    path('logout/', views.CustomLogoutView.as_view(), name="logout")
+    path('logout/', views.CustomLogoutView.as_view(), name="logout"),
+    path(
+        "edit-source/<int:source_id>", 
+        SourceEditView.as_view(), 
+        name="source-edit" # better name for this?
+    ),
 ]
 
 handler404 = 'main_app.views.views.handle404'
diff --git a/django/cantusdb_project/main_app/views/source.py b/django/cantusdb_project/main_app/views/source.py
--- a/django/cantusdb_project/main_app/views/source.py
+++ b/django/cantusdb_project/main_app/views/source.py
@@ -1,7 +1,7 @@
-from django.views.generic import DetailView, ListView, CreateView
+from django.views.generic import DetailView, ListView, CreateView, UpdateView
 from django.db.models import Q
-from main_app.models import Source, Provenance, Century
-from main_app.forms import SourceCreateForm
+from main_app.models import Source, Provenance, Century, Chant
+from main_app.forms import SourceCreateForm, SourceEditForm
 from django.contrib import messages
 from django.urls import reverse
 from django.contrib.auth.mixins import LoginRequiredMixin
@@ -240,3 +240,9 @@ def form_valid(self, form):
             return super().form_valid(form)
         else:
             return super().form_invalid(form)
+
+class SourceEditView(LoginRequiredMixin, UpdateView):
+    template_name = "source_edit.html"
+    model = Source
+    form_class = SourceEditForm 
+    pk_url_kwarg = "source_id"
\ No newline at end of file


Test patch: