From f972c13b81beabc9d9a8684153eb1b98ed12da17 Mon Sep 17 00:00:00 2001
From: Patrick Jentsch
Date: Wed, 11 Jan 2023 13:29:47 +0100
Subject: [PATCH 1/3] Fix contributionslists share toggle
---
app/models.py | 6 +
.../SpacyNLPPipelineModelList.js | 133 +++++++++++-------
.../TesseractOCRPipelineModelList.js | 121 ++++++++++------
app/static/js/Utils.js | 64 ++++-----
4 files changed, 196 insertions(+), 128 deletions(-)
diff --git a/app/models.py b/app/models.py
index 38c44020..d16bcfae 100644
--- a/app/models.py
+++ b/app/models.py
@@ -1331,6 +1331,8 @@ class Corpus(HashidMixin, db.Model):
@db.event.listens_for(Job, 'after_delete')
@db.event.listens_for(JobInput, 'after_delete')
@db.event.listens_for(JobResult, 'after_delete')
+@db.event.listens_for(SpaCyNLPPipelineModel, 'after_delete')
+@db.event.listens_for(TesseractOCRPipelineModel, 'after_delete')
def ressource_after_delete(mapper, connection, ressource):
jsonpatch = [{'op': 'remove', 'path': ressource.jsonpatch_path}]
room = f'users.{ressource.user_hashid}'
@@ -1344,6 +1346,8 @@ def ressource_after_delete(mapper, connection, ressource):
@db.event.listens_for(Job, 'after_insert')
@db.event.listens_for(JobInput, 'after_insert')
@db.event.listens_for(JobResult, 'after_insert')
+@db.event.listens_for(SpaCyNLPPipelineModel, 'after_insert')
+@db.event.listens_for(TesseractOCRPipelineModel, 'after_insert')
def ressource_after_insert_handler(mapper, connection, ressource):
value = ressource.to_json_serializeable()
for attr in mapper.relationships:
@@ -1360,6 +1364,8 @@ def ressource_after_insert_handler(mapper, connection, ressource):
@db.event.listens_for(Job, 'after_update')
@db.event.listens_for(JobInput, 'after_update')
@db.event.listens_for(JobResult, 'after_update')
+@db.event.listens_for(SpaCyNLPPipelineModel, 'after_update')
+@db.event.listens_for(TesseractOCRPipelineModel, 'after_update')
def ressource_after_update_handler(mapper, connection, ressource):
jsonpatch = []
for attr in db.inspect(ressource).attrs:
diff --git a/app/static/js/ResourceLists/SpacyNLPPipelineModelList.js b/app/static/js/ResourceLists/SpacyNLPPipelineModelList.js
index f3959a79..bf637cca 100644
--- a/app/static/js/ResourceLists/SpacyNLPPipelineModelList.js
+++ b/app/static/js/ResourceLists/SpacyNLPPipelineModelList.js
@@ -18,39 +18,33 @@ class SpaCyNLPPipelineModelList extends ResourceList {
});
app.getUser(this.userId).then((user) => {
this.add(Object.values(user.spacy_nlp_pipeline_models));
- for (let uncheckedCheckbox of this.listjs.list.querySelectorAll('input[data-checked="True"]')) {
- uncheckedCheckbox.setAttribute('checked', '');
- }
- if (user.role.name !== ('Administrator' || 'Contributor')) {
- for (let switchElement of this.listjs.list.querySelectorAll('.is_public')) {
- switchElement.setAttribute('disabled', '');
- }
- }
this.isInitialized = true;
});
}
get item() {
- return `
-
-
|
- ()
|
-
-
-
-
-
- |
-
- delete
- send
- |
-
- `.trim();
+ return (values) => {
+ return `
+
+
|
+ ()
|
+
+
+
+
+
+ |
+
+ delete
+ send
+ |
+
+ `.trim();
+ };
}
get valueNames() {
@@ -65,8 +59,7 @@ class SpaCyNLPPipelineModelList extends ResourceList {
'publishing-year',
'title',
'title-2',
- 'version',
- {name: 'is_public', attr: 'data-checked'}
+ 'version'
];
}
@@ -96,6 +89,7 @@ class SpaCyNLPPipelineModelList extends ResourceList {
}
mapResourceToValue(spaCyNLPPipelineModel) {
+ console.log(spaCyNLPPipelineModel);
return {
'id': spaCyNLPPipelineModel.id,
'creation-date': spaCyNLPPipelineModel.creation_date,
@@ -108,7 +102,7 @@ class SpaCyNLPPipelineModelList extends ResourceList {
'title': spaCyNLPPipelineModel.title,
'title-2': spaCyNLPPipelineModel.title,
'version': spaCyNLPPipelineModel.version,
- 'is_public': spaCyNLPPipelineModel.is_public ? 'True' : 'False'
+ 'is-public': spaCyNLPPipelineModel.is_public
};
}
@@ -117,14 +111,15 @@ class SpaCyNLPPipelineModelList extends ResourceList {
}
onChange(event) {
- let actionSwitchElement = event.target.closest('.list-action-trigger');
- let action = actionSwitchElement.dataset.listAction;
- let spaCyNLPPipelineModelElement = event.target.closest('tr');
- let spaCyNLPPipelineModelId = spaCyNLPPipelineModelElement.dataset.id;
- switch (action) {
+ let listItemElement = event.target.closest('.list-item[data-id]');
+ if (listItemElement === null) {return;}
+ let itemId = listItemElement.dataset.id;
+ let listActionElement = event.target.closest('.list-action-trigger[data-list-action]');
+ if (listActionElement === null) {return;}
+ let listAction = listActionElement.dataset.listAction;
+ switch (listAction) {
case 'share-request': {
- let is_public = actionSwitchElement.querySelector('input').checked;
- Utils.shareSpaCyNLPPipelineModelRequest(this.userId, spaCyNLPPipelineModelId, is_public);
+ Utils.spaCyNLPPipelineModelToggleIsPublicRequest(this.userId, itemId);
break;
}
default: {
@@ -134,24 +129,23 @@ class SpaCyNLPPipelineModelList extends ResourceList {
}
onClick(event) {
- if (event.target.closest('.action-switch')) {
- let userRole = app.data.users[this.userId].role.name;
- if (userRole !== ('Administrator' || 'Contributor')) {
- app.flash('You need the "Contributor" or "Administrator" role to perform this action.', 'error');
- }
- return;
+ let listItemElement = event.target.closest('.list-item[data-id]');
+ if (listItemElement === null) {return;}
+ let itemId = listItemElement.dataset.id;
+ let listActionElement = event.target.closest('.list-action-trigger[data-list-action]');
+ // ignore switch clicks, handle them by the onChange method instead
+ if (listActionElement.classList.contains('switch')) {
+ event.preventDefault();
+ this.onChange(event);
}
- let actionButtonElement = event.target.closest('.list-action-trigger');
- let action = actionButtonElement === null ? 'view' : actionButtonElement.dataset.listAction;
- let spaCyNLPPipelineModelElement = event.target.closest('tr');
- let spaCyNLPPipelineModelId = spaCyNLPPipelineModelElement.dataset.id;
- switch (action) {
+ let listAction = listActionElement === null ? 'view' : listActionElement.dataset.listAction;
+ switch (listAction) {
case 'delete-request': {
- Utils.deleteSpaCyNLPPipelineModelRequest(this.userId, spaCyNLPPipelineModelId);
+ Utils.deleteSpaCyNLPPipelineModelRequest(this.userId, itemId);
break;
}
case 'view': {
- window.location.href = `/contributions/spacy-nlp-pipeline-models/${spaCyNLPPipelineModelId}`;
+ window.location.href = `/contributions/spacy-nlp-pipeline-models/${itemId}`;
break;
}
default: {
@@ -159,4 +153,41 @@ class SpaCyNLPPipelineModelList extends ResourceList {
}
}
}
+
+ onPatch(patch) {
+ let re = new RegExp(`^/users/${this.userId}/spacy_nlp_pipeline_models/([A-Za-z0-9]*)`);
+ let filteredPatch = patch.filter(operation => re.test(operation.path));
+ for (let operation of filteredPatch) {
+ switch(operation.op) {
+ case 'add': {
+ let re = new RegExp(`^/users/${this.userId}/spacy_nlp_pipeline_models/([A-Za-z0-9]*)$`);
+ if (re.test(operation.path)) {this.add(operation.value);}
+ break;
+ }
+ case 'remove': {
+ let re = new RegExp(`^/users/${this.userId}/spacy_nlp_pipeline_models/([A-Za-z0-9]*)$`);
+ if (re.test(operation.path)) {
+ let [match, itemId] = operation.path.match(re);
+ this.remove(itemId);
+ }
+ break;
+ }
+ case 'replace': {
+ let re = new RegExp(`^/users/${this.userId}/spacy_nlp_pipeline_models/([A-Za-z0-9]*)/(is_public)$`);
+ if (re.test(operation.path)) {
+ let [match, itemId, valueName] = operation.path.match(re);
+ if (valueName === 'is_public') {
+ this.listjs.list.querySelector(`.list-item[data-id="${itemId}"] .is-public`).checked = operation.value;
+ valueName = 'is-public';
+ }
+ this.replace(itemId, valueName, operation.value);
+ }
+ break;
+ }
+ default: {
+ break;
+ }
+ }
+ }
+ }
}
diff --git a/app/static/js/ResourceLists/TesseractOCRPipelineModelList.js b/app/static/js/ResourceLists/TesseractOCRPipelineModelList.js
index c3bc6447..ad319041 100644
--- a/app/static/js/ResourceLists/TesseractOCRPipelineModelList.js
+++ b/app/static/js/ResourceLists/TesseractOCRPipelineModelList.js
@@ -31,26 +31,28 @@ class TesseractOCRPipelineModelList extends ResourceList {
}
get item() {
- return `
-
-
|
- ()
|
-
-
-
-
-
- |
-
- delete
- send
- |
-
- `.trim();
+ return (values) => {
+ return `
+
+
|
+ ()
|
+
+
+
+
+
+ |
+
+ delete
+ send
+ |
+
+ `.trim();
+ };
}
get valueNames() {
@@ -108,7 +110,7 @@ class TesseractOCRPipelineModelList extends ResourceList {
'title': tesseractOCRPipelineModel.title,
'title-2': tesseractOCRPipelineModel.title,
'version': tesseractOCRPipelineModel.version,
- 'is_public': tesseractOCRPipelineModel.is_public ? 'True' : 'False'
+ 'is-public': tesseractOCRPipelineModel.is_public
};
}
@@ -117,14 +119,15 @@ class TesseractOCRPipelineModelList extends ResourceList {
}
onChange(event) {
- let actionSwitchElement = event.target.closest('.list-action-trigger');
- let action = actionSwitchElement.dataset.listAction;
- let tesseractOCRPipelineModelElement = event.target.closest('tr');
- let tesseractOCRPipelineModelId = tesseractOCRPipelineModelElement.dataset.id;
- switch (action) {
+ let listItemElement = event.target.closest('.list-item[data-id]');
+ if (listItemElement === null) {return;}
+ let itemId = listItemElement.dataset.id;
+ let listActionElement = event.target.closest('.list-action-trigger[data-list-action]');
+ if (listActionElement === null) {return;}
+ let listAction = listActionElement.dataset.listAction;
+ switch (listAction) {
case 'share-request': {
- let is_public = actionSwitchElement.querySelector('input').checked;
- Utils.shareTesseractOCRPipelineModelRequest(this.userId, tesseractOCRPipelineModelId, is_public);
+ Utils.tesseractOCRPipelineModelToggleIsPublicRequest(this.userId, itemId);
break;
}
default: {
@@ -134,24 +137,23 @@ class TesseractOCRPipelineModelList extends ResourceList {
}
onClick(event) {
- if (event.target.closest('.action-switch')) {
- let userRole = app.data.users[this.userId].role.name;
- if (userRole !== ('Administrator' || 'Contributor')) {
- app.flash('You need the "Contributor" or "Administrator" role to perform this action.', 'error');
- }
- return;
+ let listItemElement = event.target.closest('.list-item[data-id]');
+ if (listItemElement === null) {return;}
+ let itemId = listItemElement.dataset.id;
+ let listActionElement = event.target.closest('.list-action-trigger[data-list-action]');
+ // ignore switch clicks, handle them by the onChange method instead
+ if (listActionElement.classList.contains('switch')) {
+ event.preventDefault();
+ this.onChange(event);
}
- let actionButtonElement = event.target.closest('.list-action-trigger');
- let action = actionButtonElement === null ? 'view' : actionButtonElement.dataset.listAction;
- let tesseractOCRPipelineModelElement = event.target.closest('tr');
- let tesseractOCRPipelineModelId = tesseractOCRPipelineModelElement.dataset.id;
- switch (action) {
+ let listAction = listActionElement === null ? 'view' : listActionElement.dataset.listAction;
+ switch (listAction) {
case 'delete-request': {
- Utils.deleteTesseractOCRPipelineModelRequest(this.userId, tesseractOCRPipelineModelId);
+ Utils.deleteTesseractOCRPipelineModelRequest(this.userId, itemId);
break;
}
case 'view': {
- window.location.href = `/contributions/tesseract-ocr-pipeline-models/${tesseractOCRPipelineModelId}`;
+ window.location.href = `/contributions/tesseract-ocr-pipeline-models/${itemId}`;
break;
}
default: {
@@ -159,4 +161,41 @@ class TesseractOCRPipelineModelList extends ResourceList {
}
}
}
+
+ onPatch(patch) {
+ let re = new RegExp(`^/users/${this.userId}/tesseract_ocr_pipeline_models/([A-Za-z0-9]*)`);
+ let filteredPatch = patch.filter(operation => re.test(operation.path));
+ for (let operation of filteredPatch) {
+ switch(operation.op) {
+ case 'add': {
+ let re = new RegExp(`^/users/${this.userId}/tesseract_ocr_pipeline_models/([A-Za-z0-9]*)$`);
+ if (re.test(operation.path)) {this.add(operation.value);}
+ break;
+ }
+ case 'remove': {
+ let re = new RegExp(`^/users/${this.userId}/tesseract_ocr_pipeline_models/([A-Za-z0-9]*)$`);
+ if (re.test(operation.path)) {
+ let [match, itemId] = operation.path.match(re);
+ this.remove(itemId);
+ }
+ break;
+ }
+ case 'replace': {
+ let re = new RegExp(`^/users/${this.userId}/tesseract_ocr_pipeline_models/([A-Za-z0-9]*)/(is_public)$`);
+ if (re.test(operation.path)) {
+ let [match, itemId, valueName] = operation.path.match(re);
+ if (valueName === 'is_public') {
+ this.listjs.list.querySelector(`.list-item[data-id="${itemId}"] .is-public`).checked = operation.value;
+ valueName = 'is-public';
+ }
+ this.replace(itemId, valueName, operation.value);
+ }
+ break;
+ }
+ default: {
+ break;
+ }
+ }
+ }
+ }
}
diff --git a/app/static/js/Utils.js b/app/static/js/Utils.js
index d00b613a..2e847477 100644
--- a/app/static/js/Utils.js
+++ b/app/static/js/Utils.js
@@ -563,7 +563,7 @@ class Utils {
});
}
- static shareTesseractOCRPipelineModelRequest(userId, tesseractOCRPipelineModelId, is_public) {
+ static tesseractOCRPipelineModelToggleIsPublicRequest(userId, tesseractOCRPipelineModelId, is_public) {
return new Promise((resolve, reject) => {
let tesseractOCRPipelineModel;
try {
@@ -572,28 +572,24 @@ class Utils {
tesseractOCRPipelineModel = {};
}
- let msg = '';
- if (is_public) {
- msg = `Model "${tesseractOCRPipelineModel?.title}" is now public`;
- } else {
- msg = `Model "${tesseractOCRPipelineModel?.title}" is now private`;
- }
fetch(`/contributions/tesseract-ocr-pipeline-models/${tesseractOCRPipelineModelId}/toggle-public-status`, {method: 'POST', headers: {Accept: 'application/json'}})
- .then(
- (response) => {
- if (response.status === 403) {app.flash('Forbidden', 'error'); reject(response);}
- app.flash(msg);
- resolve(response);
- },
- (response) => {
- app.flash('Something went wrong', 'error');
- reject(response);
- }
- );
+ .then(
+ (response) => {
+ if (response.status === 403) {
+ app.flash('Forbidden', 'error');
+ reject(response);
+ }
+ resolve(response);
+ },
+ (response) => {
+ app.flash('Something went wrong', 'error');
+ reject(response);
+ }
+ );
});
}
- static shareSpaCyNLPPipelineModelRequest(userId, spaCyNLPPipelineModelId, is_public) {
+ static spaCyNLPPipelineModelToggleIsPublicRequest(userId, spaCyNLPPipelineModelId) {
return new Promise((resolve, reject) => {
let spaCyNLPPipelineModel;
try {
@@ -602,24 +598,20 @@ class Utils {
spaCyNLPPipelineModel = {};
}
- let msg = '';
- if (is_public) {
- msg = `Model "${spaCyNLPPipelineModel?.title}" is now public`;
- } else {
- msg = `Model "${spaCyNLPPipelineModel?.title}" is now private`;
- }
fetch(`/contributions/spacy-nlp-pipeline-models/${spaCyNLPPipelineModelId}/toggle-public-status`, {method: 'POST', headers: {Accept: 'application/json'}})
- .then(
- (response) => {
- if (response.status === 403) {app.flash('Forbidden', 'error'); reject(response);}
- app.flash(msg);
- resolve(response);
- },
- (response) => {
- app.flash('Something went wrong', 'error');
- reject(response);
- }
- );
+ .then(
+ (response) => {
+ if (response.status === 403) {
+ app.flash('Forbidden', 'error');
+ reject(response);
+ }
+ resolve(response);
+ },
+ (response) => {
+ app.flash('Something went wrong', 'error');
+ reject(response);
+ }
+ );
});
}
}
From ce03201133268f6c2552930942f370aea4b89f93 Mon Sep 17 00:00:00 2001
From: Patrick Jentsch
Date: Wed, 11 Jan 2023 13:39:48 +0100
Subject: [PATCH 2/3] Remove debug message
---
app/static/js/ResourceLists/SpacyNLPPipelineModelList.js | 1 -
1 file changed, 1 deletion(-)
diff --git a/app/static/js/ResourceLists/SpacyNLPPipelineModelList.js b/app/static/js/ResourceLists/SpacyNLPPipelineModelList.js
index bf637cca..078ec90c 100644
--- a/app/static/js/ResourceLists/SpacyNLPPipelineModelList.js
+++ b/app/static/js/ResourceLists/SpacyNLPPipelineModelList.js
@@ -89,7 +89,6 @@ class SpaCyNLPPipelineModelList extends ResourceList {
}
mapResourceToValue(spaCyNLPPipelineModel) {
- console.log(spaCyNLPPipelineModel);
return {
'id': spaCyNLPPipelineModel.id,
'creation-date': spaCyNLPPipelineModel.creation_date,
From d462c1e4d6de7c7d31e6587edf51cdb7f94eb429 Mon Sep 17 00:00:00 2001
From: Patrick Jentsch
Date: Wed, 11 Jan 2023 13:47:09 +0100
Subject: [PATCH 3/3] Rename PublicUserList to UserList
---
app/static/js/ResourceLists/ResourceList.js | 2 +-
.../js/ResourceLists/{PublicUserList.js => UserList.js} | 6 +++---
app/templates/_scripts.html.j2 | 2 +-
3 files changed, 5 insertions(+), 5 deletions(-)
rename app/static/js/ResourceLists/{PublicUserList.js => UserList.js} (95%)
diff --git a/app/static/js/ResourceLists/ResourceList.js b/app/static/js/ResourceLists/ResourceList.js
index 7adc0e08..7fe7dec6 100644
--- a/app/static/js/ResourceLists/ResourceList.js
+++ b/app/static/js/ResourceLists/ResourceList.js
@@ -10,9 +10,9 @@ class ResourceList {
JobList.autoInit();
JobInputList.autoInit();
JobResultList.autoInit();
- PublicUserList.autoInit();
SpaCyNLPPipelineModelList.autoInit();
TesseractOCRPipelineModelList.autoInit();
+ UserList.autoInit();
AdminUserList.autoInit();
}
diff --git a/app/static/js/ResourceLists/PublicUserList.js b/app/static/js/ResourceLists/UserList.js
similarity index 95%
rename from app/static/js/ResourceLists/PublicUserList.js
rename to app/static/js/ResourceLists/UserList.js
index e6cfff34..d871ec31 100644
--- a/app/static/js/ResourceLists/PublicUserList.js
+++ b/app/static/js/ResourceLists/UserList.js
@@ -1,7 +1,7 @@
-class PublicUserList extends ResourceList {
+class UserList extends ResourceList {
static autoInit() {
- for (let publicUserListElement of document.querySelectorAll('.public-user-list:not(.no-autoinit)')) {
- new PublicUserList(publicUserListElement);
+ for (let publicUserListElement of document.querySelectorAll('.user-list:not(.no-autoinit)')) {
+ new UserList(publicUserListElement);
}
}
diff --git a/app/templates/_scripts.html.j2 b/app/templates/_scripts.html.j2
index 17b0b7c6..95406079 100644
--- a/app/templates/_scripts.html.j2
+++ b/app/templates/_scripts.html.j2
@@ -24,9 +24,9 @@
'js/ResourceLists/JobList.js',
'js/ResourceLists/JobInputList.js',
'js/ResourceLists/JobResultList.js',
- 'js/ResourceLists/PublicUserList.js',
'js/ResourceLists/SpacyNLPPipelineModelList.js',
'js/ResourceLists/TesseractOCRPipelineModelList.js',
+ 'js/ResourceLists/UserList.js',
'js/ResourceLists/AdminUserList.js',
'js/XMLtoObject.js'
%}