From 7836774fef8d2d25628bc90b91f16858d57ac69e Mon Sep 17 00:00:00 2001
From: Patrick Jentsch <p.jentsch@uni-bielefeld.de>
Date: Mon, 9 Jan 2023 08:45:47 +0100
Subject: [PATCH] Update AdminUserList

---
 app/admin/routes.py                           |  4 +-
 .../{UserList.js => AdminUserList.js}         |  7 +--
 app/static/js/ResourceLists/ResourceList.js   | 18 +++++---
 app/static/js/Utils.js                        | 44 +++++++++++++++++++
 app/templates/_scripts.html.j2                |  5 +--
 app/templates/admin/users.html.j2             |  7 +--
 6 files changed, 69 insertions(+), 16 deletions(-)
 rename app/static/js/ResourceLists/{UserList.js => AdminUserList.js} (93%)

diff --git a/app/admin/routes.py b/app/admin/routes.py
index b14c52fb..08f219ab 100644
--- a/app/admin/routes.py
+++ b/app/admin/routes.py
@@ -30,10 +30,10 @@ def index():
 
 @bp.route('/users')
 def users():
-    json_users = [x.to_json_serializeable(backrefs=True) for x in User.query.all()]
+    users = [x.to_json_serializeable(backrefs=True) for x in User.query.all()]
     return render_template(
         'admin/users.html.j2',
-        json_users=json_users,
+        users=users,
         title='Users'
     )
 
diff --git a/app/static/js/ResourceLists/UserList.js b/app/static/js/ResourceLists/AdminUserList.js
similarity index 93%
rename from app/static/js/ResourceLists/UserList.js
rename to app/static/js/ResourceLists/AdminUserList.js
index 841f08b7..2749b976 100644
--- a/app/static/js/ResourceLists/UserList.js
+++ b/app/static/js/ResourceLists/AdminUserList.js
@@ -1,7 +1,7 @@
-class UserList extends ResourceList {
+class AdminUserList extends ResourceList {
   static autoInit() {
-    for (let userListElement of document.querySelectorAll('.user-list:not(.no-autoinit)')) {
-      new UserList(userListElement);
+    for (let adminUserListElement of document.querySelectorAll('.admin-user-list:not(.no-autoinit)')) {
+      new AdminUserList(adminUserListElement);
     }
   }
 
@@ -95,6 +95,7 @@ class UserList extends ResourceList {
         ? 'view' : listActionElement.dataset.listAction;
     switch (listAction) {
       case 'delete': {
+        console.log('delete', itemId);
         Utils.deleteUserRequest(itemId);
         if (itemId === currentUserId) {window.location.href = '/';}
         break;
diff --git a/app/static/js/ResourceLists/ResourceList.js b/app/static/js/ResourceLists/ResourceList.js
index f2d917d2..7adc0e08 100644
--- a/app/static/js/ResourceLists/ResourceList.js
+++ b/app/static/js/ResourceLists/ResourceList.js
@@ -13,7 +13,7 @@ class ResourceList {
     PublicUserList.autoInit();
     SpaCyNLPPipelineModelList.autoInit();
     TesseractOCRPipelineModelList.autoInit();
-    UserList.autoInit();
+    AdminUserList.autoInit();
   }
 
   static defaultOptions = {
@@ -24,10 +24,18 @@ class ResourceList {
     }
   };
 
-  constructor(listContainerElement, options={}) {
-    if ('items' in options) {throw '"items" is not supported as an option, define it as a getter in the list class';}
-    if ('valueNames' in options) {throw '"valueNames" is not supported as an option, define it as a getter in the list class';}
-    let _options = _.merge({item: this.item, valueNames: this.valueNames}, ResourceList.defaultOptions, options);
+  constructor(listContainerElement, options = {}) {
+    if ('items' in options) {
+      throw '"items" is not supported as an option, define it as a getter in the list class';
+    }
+    if ('valueNames' in options) {
+      throw '"valueNames" is not supported as an option, define it as a getter in the list class';
+    }
+    let _options = Utils.mergeObjectsDeep(
+      {item: this.item, valueNames: this.valueNames},
+      ResourceList.defaultOptions,
+      options
+    );
     this.listContainerElement = listContainerElement;
     this.initListContainerElement();
     this.listjs = new List(listContainerElement, _options);
diff --git a/app/static/js/Utils.js b/app/static/js/Utils.js
index 235b4aa7..e7b4aa1b 100644
--- a/app/static/js/Utils.js
+++ b/app/static/js/Utils.js
@@ -12,6 +12,50 @@ class Utils {
     }
   }
 
+  static isObject(object) {
+    return object !== null && typeof object === 'object' && !Array.isArray(object);
+  }
+
+  static mergeObjectsDeep(...objects) {
+    let mergedObject = {};
+    if (objects.length === 0) {
+      return mergedObject;
+    }
+    if (objects.length === 1) {
+      if (!Utils.isObject(objects[0])) {
+        throw 'Cannot merge non-object';
+      }
+      return Utils.mergeObjectsDeep(mergedObject, objects[0]);
+    }
+    if (!Utils.isObject(objects[0]) || !Utils.isObject(objects[1])) {
+      throw 'Cannot merge non-object';
+    }
+    for (let key in objects[0]) {
+      if (objects[0].hasOwnProperty(key)) {
+        if (objects[1].hasOwnProperty(key)) {
+          if (Utils.isObject(objects[0][key]) && Utils.isObject(objects[1][key])) {
+            mergedObject[key] = Utils.mergeObjectsDeep(objects[0][key], objects[1][key]);
+          } else {
+            mergedObject[key] = objects[1][key];
+          }
+        } else {
+          mergedObject[key] = objects[0][key];
+        }
+      }
+    }
+    for (let key in objects[1]) {
+      if (objects[1].hasOwnProperty(key)) {
+        if (!objects[0].hasOwnProperty(key)) {
+          mergedObject[key] = objects[1][key];
+        }
+      }
+    }
+    if (objects.length === 2) {
+      return mergedObject;
+    }
+    return Utils.mergeObjectsDeep(mergedObject, ...objects.slice(2));
+  }
+
   static buildCorpusRequest(userId, corpusId) {
     return new Promise((resolve, reject) => {
       let corpus = app.data.users[userId].corpora[corpusId];
diff --git a/app/templates/_scripts.html.j2 b/app/templates/_scripts.html.j2
index 9552337f..17b0b7c6 100644
--- a/app/templates/_scripts.html.j2
+++ b/app/templates/_scripts.html.j2
@@ -1,7 +1,6 @@
 <script src="https://cdnjs.cloudflare.com/ajax/libs/fast-json-patch/3.1.1/fast-json-patch.min.js" integrity="sha512-5uDdefwnzyq4N+SkmMBmekZLZNmc6dLixvVxCdlHBfqpyz0N3bzLdrJ55OLm7QrZmgZuhLGgHLDtJwU6RZoFCA==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
 <script src="https://cdnjs.cloudflare.com/ajax/libs/list.js/2.3.1/list.min.js" integrity="sha512-93wYgwrIFL+b+P3RvYxi/WUFRXXUDSLCT2JQk9zhVGXuS2mHl2axj6d+R6pP+gcU5isMHRj1u0oYE/mWyt/RjA==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
-<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.21/lodash.min.js" integrity="sha512-WFN04846sdKMIP5LKNphMaWzU7YpMyCU245etK3g/2ARYbPK9Ub18eG+ljU96qKRCWh+quCY7yefSmlkQw1ANQ==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
-<script src="https://cdnjs.cloudflare.com/ajax/libs/socket.io/4.5.1/socket.io.min.js" integrity="sha512-mHO4BJ0ELk7Pb1AzhTi3zvUeRgq3RXVOu9tTRfnA6qOxGK4pG2u57DJYolI4KrEnnLTcH9/J5wNOozRTDaybXg==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
+<script src="https://cdnjs.cloudflare.com/ajax/libs/socket.io/4.5.4/socket.io.min.js" integrity="sha512-HTENHrkQ/P0NGDFd5nk6ibVtCkcM7jhr2c7GyvXp5O+4X6O5cQO9AhqFzM+MdeBivsX7Hoys2J7pp2wdgMpCvw==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
 {%- assets
   filters='rjsmin',
   output='gen/app.%(version)s.js',
@@ -25,10 +24,10 @@
   'js/ResourceLists/JobList.js',
   'js/ResourceLists/JobInputList.js',
   'js/ResourceLists/JobResultList.js',
-  'js/ResourceLists/UserList.js',
   'js/ResourceLists/PublicUserList.js',
   'js/ResourceLists/SpacyNLPPipelineModelList.js',
   'js/ResourceLists/TesseractOCRPipelineModelList.js',
+  'js/ResourceLists/AdminUserList.js',
   'js/XMLtoObject.js'
 %}
 <script src="{{ ASSET_URL }}"></script>
diff --git a/app/templates/admin/users.html.j2 b/app/templates/admin/users.html.j2
index 0594b842..c96024cf 100644
--- a/app/templates/admin/users.html.j2
+++ b/app/templates/admin/users.html.j2
@@ -11,7 +11,7 @@
     <div class="col s12">
       <div class="card">
         <div class="card-content">
-          <div class="user-list no-autoinit"></div>
+          <div class="admin-user-list no-autoinit" id="admin-user-list"></div>
         </div>
       </div>
     </div>
@@ -22,7 +22,8 @@
 {% block scripts %}
 {{ super() }}
 <script>
-  let userList = new UserList(document.querySelector('.user-list'));
-  userList.add({{ json_users|tojson }});
+  let adminUserListElement = document.querySelector('#admin-user-list');
+  let adminUserList = new AdminUserList(adminUserListElement);
+  adminUserList.add({{ users|tojson }});
 </script>
 {% endblock scripts %}
-- 
GitLab