From 428400df3f76dace23cfcd80cbe3e117150aba69 Mon Sep 17 00:00:00 2001
From: Patrick Jentsch <p.jentsch@uni-bielefeld.de>
Date: Thu, 9 Feb 2023 16:22:37 +0100
Subject: [PATCH] Add public switch without form

---
 app/corpora/routes.py                         | 40 +++++----
 .../js/RessourceDisplays/CorpusDisplay.js     | 11 +++
 app/static/js/Utils.js                        | 82 +++++++++++++++++++
 app/templates/corpora/corpus.html.j2          | 49 ++++-------
 4 files changed, 130 insertions(+), 52 deletions(-)

diff --git a/app/corpora/routes.py b/app/corpora/routes.py
index f2cbac63..79bdf4ab 100644
--- a/app/corpora/routes.py
+++ b/app/corpora/routes.py
@@ -63,19 +63,9 @@ def corpus(corpus_id):
             or current_user.is_following_corpus(corpus)
             or corpus.is_public):
         abort(403)
-    corpus_settings_form = ChangeCorpusSettingsForm(
-        data=corpus.to_json_serializeable(),
-        prefix='corpus-settings-form'
-    )
-    if corpus_settings_form.validate_on_submit():
-        corpus.is_public = corpus_settings_form.is_public.data
-        db.session.commit()
-        flash('Your changes have been saved')
-        return redirect(url_for('.corpus', corpus_id=corpus.id))
     if corpus.user == current_user:
         return render_template(
             'corpora/corpus.html.j2',
-            corpus_settings_form=corpus_settings_form,
             corpus=corpus,
             title='Corpus'
         )
@@ -89,18 +79,26 @@ def corpus(corpus_id):
         )
 
 
+@bp.route('/<hashid:corpus_id>/enable_is_public', methods=['POST'])
+@login_required
+def enable_corpus_is_public(corpus_id):
+    corpus = Corpus.query.get_or_404(corpus_id)
+    if not (corpus.user == current_user or current_user.is_administrator()):
+        abort(403)
+    corpus.is_public = True
+    db.session.commit()
+    return '', 204
 
-# @bp.route('/<hashid:corpus_id>/update')
-# @login_required
-# def update_corpus(corpus_id):
-#     corpus = Corpus.query.get_or_404(corpus_id)
-#     if not (corpus.user == current_user or current_user.is_administrator()):
-#         abort(403)
-#     return render_template(
-#         'corpora/update_corpus.html.j2',
-#         corpus=corpus,
-#         title='Corpus'
-#     )
+
+@bp.route('/<hashid:corpus_id>/disable_is_public', methods=['POST'])
+@login_required
+def disable_corpus_is_public(corpus_id):
+    corpus = Corpus.query.get_or_404(corpus_id)
+    if not (corpus.user == current_user or current_user.is_administrator()):
+        abort(403)
+    corpus.is_public = False
+    db.session.commit()
+    return '', 204
 
 
 @bp.route('/<hashid:corpus_id>', methods=['DELETE'])
diff --git a/app/static/js/RessourceDisplays/CorpusDisplay.js b/app/static/js/RessourceDisplays/CorpusDisplay.js
index af4da56a..6dd3dc72 100644
--- a/app/static/js/RessourceDisplays/CorpusDisplay.js
+++ b/app/static/js/RessourceDisplays/CorpusDisplay.js
@@ -12,12 +12,23 @@ class CorpusDisplay extends RessourceDisplay {
       .addEventListener('click', (event) => {
         Utils.deleteCorpusRequest(this.userId, this.corpusId);
       });
+    this.displayElement
+      .querySelector('.action-switch[data-action="toggle-is-public"]')
+      .addEventListener('click', (event) => {
+        if (event.target.tagName !== 'INPUT') {return;}
+        if (event.target.checked) {
+          Utils.enableCorpusIsPublicRequest(this.userId, this.corpusId);
+        } else {
+          Utils.disableCorpusIsPublicRequest(this.userId, this.corpusId);
+        }
+      });
   }
 
   init(user) {
     let corpus = user.corpora[this.corpusId];
     this.setCreationDate(corpus.creation_date);
     this.setDescription(corpus.description);
+    this.setIsPublic(corpus.is_public);
     this.setStatus(corpus.status);
     this.setTitle(corpus.title);
     this.setNumTokens(corpus.num_tokens);
diff --git a/app/static/js/Utils.js b/app/static/js/Utils.js
index d63be025..aee382a0 100644
--- a/app/static/js/Utils.js
+++ b/app/static/js/Utils.js
@@ -69,6 +69,88 @@ class Utils {
     return Utils.mergeObjectsDeep(mergedObject, ...objects.slice(2));
   }
 
+  static enableCorpusIsPublicRequest(userId, corpusId) {
+    return new Promise((resolve, reject) => {
+      let corpus;
+      try {
+        corpus = app.data.users[userId].corpora[corpusId];
+      } catch (error) {
+        corpus = {};
+      }
+
+      let modalElement = Utils.HTMLToElement(
+        `
+          <div class="modal">
+            <div class="modal-content">
+              <h4>Hier könnte eine Warnung stehen</h4>
+              <p></p>
+            </div>
+            <div class="modal-footer">
+              <a class="action-button btn modal-close waves-effect waves-light" data-action="cancel">Cancel</a>
+              <a class="action-button btn modal-close red waves-effect waves-light" data-action="confirm">Confirm</a>
+            </div>
+          </div>
+        `
+      );
+      document.querySelector('#modals').appendChild(modalElement);
+      let modal = M.Modal.init(
+        modalElement,
+        {
+          dismissible: false,
+          onCloseEnd: () => {
+            modal.destroy();
+            modalElement.remove();
+          }
+        }
+      );
+
+      let confirmElement = modalElement.querySelector('.action-button[data-action="confirm"]');
+      confirmElement.addEventListener('click', (event) => {
+        let corpusTitle = corpus?.title;
+        fetch(`/corpora/${corpusId}/enable_is_public`, {method: 'POST', headers: {Accept: 'application/json'}})
+          .then(
+            (response) => {
+              if (response.status === 403) {app.flash('Forbidden', 'error'); reject(response);}
+              if (response.status === 404) {app.flash('Not Found', 'error'); reject(response);}
+              app.flash(`Corpus "${corpusTitle}" is public now`, 'corpus');
+              resolve(response);
+            },
+            (response) => {
+              app.flash('Something went wrong', 'error');
+              reject(response);
+            }
+          );
+      });
+      modal.open();
+    });
+  }
+
+  static disableCorpusIsPublicRequest(userId, corpusId) {
+    return new Promise((resolve, reject) => {
+      let corpus;
+      try {
+        corpus = app.data.users[userId].corpora[corpusId];
+      } catch (error) {
+        corpus = {};
+      }
+
+      let corpusTitle = corpus?.title;
+      fetch(`/corpora/${corpusId}/disable_is_public`, {method: 'POST', headers: {Accept: 'application/json'}})
+        .then(
+          (response) => {
+            if (response.status === 403) {app.flash('Forbidden', 'error'); reject(response);}
+            if (response.status === 404) {app.flash('Not Found', 'error'); reject(response);}
+            app.flash(`Corpus "${corpusTitle}" is private now`, 'corpus');
+            resolve(response);
+          },
+          (response) => {
+            app.flash('Something went wrong', 'error');
+            reject(response);
+          }
+        );
+    });
+  }
+
   static buildCorpusRequest(userId, corpusId) {
     return new Promise((resolve, reject) => {
       let corpus;
diff --git a/app/templates/corpora/corpus.html.j2 b/app/templates/corpora/corpus.html.j2
index 5311e92b..1c2167ec 100644
--- a/app/templates/corpora/corpus.html.j2
+++ b/app/templates/corpora/corpus.html.j2
@@ -11,13 +11,6 @@
       <div class="row">
         <div class="col s8 m9 l10">
           <h1 id="title"><span class="corpus-title"></span></h1>
-          {% if not corpus.user == current_user %}
-          {% if current_user.is_following_corpus(corpus) %}
-          <a class="btn waves-effect waves-light" id="follow-corpus-request"><i class="material-icons left">add</i>Unfollow Corpus</a>
-          {% elif not current_user.is_following_corpus(corpus) %}
-          <a class="btn waves-effect waves-light" id="follow-corpus-request"><i class="material-icons left">add</i>Follow Corpus</a>
-          {% endif %}
-          {% endif %}
         </div>
         <div class="col s4 m3 l2 right-align">
           <p>&nbsp;</p>
@@ -64,11 +57,23 @@
             </div>
           </div>
         </div>
-        <div class="card-action right-align">
-          <a class="btn corpus-analyse-trigger disabled waves-effect waves-light" href="{{ url_for('corpora.analyse_corpus', corpus_id=corpus.id) }}"><i class="material-icons left">search</i>Analyze</a>
-          <a class="action-button btn disabled waves-effect waves-light" data-action="build-request"><i class="nopaque-icons left">K</i>Build</a>
-          <a class="btn disabled export-corpus-trigger waves-effect waves-light" href="{{ url_for('corpora.export_corpus', corpus_id=corpus.id) }}"><i class="material-icons left">import_export</i>Export</a>
-          <a class="action-button btn red waves-effect waves-light" data-action="delete-request"><i class="material-icons left">delete</i>Delete</a>
+        <div class="card-action">
+          <div class="left-align">
+            <div class="action-switch switch center-align" data-action="toggle-is-public">
+              <span class="share"></span>
+              <label>
+                <input class="corpus-is-public" {% if corpus.is_public %}checked{% endif %} type="checkbox">
+                <span class="lever"></span>
+                public
+              </label>
+            </div>
+          </div>
+          <div class="right-align">
+            <a class="btn corpus-analyse-trigger disabled waves-effect waves-light" href="{{ url_for('corpora.analyse_corpus', corpus_id=corpus.id) }}"><i class="material-icons left">search</i>Analyze</a>
+            <a class="action-button btn disabled waves-effect waves-light" data-action="build-request"><i class="nopaque-icons left">K</i>Build</a>
+            <a class="btn disabled export-corpus-trigger waves-effect waves-light" href="{{ url_for('corpora.export_corpus', corpus_id=corpus.id) }}"><i class="material-icons left">import_export</i>Export</a>
+            <a class="action-button btn red waves-effect waves-light" data-action="delete-request"><i class="material-icons left">delete</i>Delete</a>
+          </div>
         </div>
       </div>
     </div>
@@ -84,25 +89,7 @@
         </div>
       </div>
     </div>
-    {% if current_user.can(Permission.ADMINISTRATE) or current_user.hashid == corpus.user.hashid %}
-    <div class="col s12">
-      <form method="POST">
-      {{ corpus_settings_form.hidden_tag() }}
-        <div class="card">
-          <div class="card-content">
-            <span class="card-title" id="files">Corpus settings</span>
-            <br>
-            <p></p>
-            {{ wtf.render_field(corpus_settings_form.is_public) }}
-            <br>
-          </div>
-          <div class="card-action right-align">
-            {{ wtf.render_field(corpus_settings_form.submit, material_icon='send') }}
-          </div>
-        </div>
-      </form>
-    </div>
-    {% endif %}
+
     <div class="col s12">
       <div class="card">
         <div class="card-content">
-- 
GitLab