diff --git a/client/html/tag_edit.tpl b/client/html/tag_edit.tpl
index 65bd187..e57ac79 100644
--- a/client/html/tag_edit.tpl
+++ b/client/html/tag_edit.tpl
@@ -3,23 +3,51 @@
- <% if (ctx.canEditNames || ctx.canEditCategory || ctx.canEditImplications || ctx.canEditSuggestions) { %>
+ <% if (ctx.canEditAnything) { %>
diff --git a/client/js/controllers/tag_controller.js b/client/js/controllers/tag_controller.js
index 0f8dfae..1eaca6f 100644
--- a/client/js/controllers/tag_controller.js
+++ b/client/js/controllers/tag_controller.js
@@ -25,6 +25,7 @@ class TagController {
this._view = new TagView({
tag: tag,
section: section,
+ canEditAnything: api.hasPrivilege('tags:edit'),
canEditNames: api.hasPrivilege('tags:edit:names'),
canEditCategory: api.hasPrivilege('tags:edit:category'),
canEditImplications: api.hasPrivilege('tags:edit:implications'),
@@ -53,11 +54,21 @@ class TagController {
_evtChange(e) {
this._view.clearMessages();
this._view.disableForm();
- e.detail.tag.names = e.detail.names;
- e.detail.tag.category = e.detail.category;
- e.detail.tag.implications = e.detail.implications;
- e.detail.tag.suggestions = e.detail.suggestions;
- e.detail.tag.description = e.detail.description;
+ if (e.detail.names !== undefined) {
+ e.detail.tag.names = e.detail.names;
+ }
+ if (e.detail.category !== undefined) {
+ e.detail.tag.category = e.detail.category;
+ }
+ if (e.detail.implications !== undefined) {
+ e.detail.tag.implications = e.detail.implications;
+ }
+ if (e.detail.suggestions !== undefined) {
+ e.detail.tag.suggestions = e.detail.suggestions;
+ }
+ if (e.detail.description !== undefined) {
+ e.detail.tag.description = e.detail.description;
+ }
e.detail.tag.save().then(() => {
this._view.showSuccess('Tag saved.');
this._view.enableForm();
diff --git a/client/js/models/post.js b/client/js/models/post.js
index 16d11ca..fb60683 100644
--- a/client/js/models/post.js
+++ b/client/js/models/post.js
@@ -4,12 +4,7 @@ const api = require('../api.js');
const tags = require('../tags.js');
const events = require('../events.js');
const CommentList = require('./comment_list.js');
-
-function _arraysDiffer(source1, source2) {
- return (
- [...source1].filter(value => !source2.includes(value)).length > 0 ||
- [...source2].filter(value => !source1.includes(value)).length > 0);
-}
+const misc = require('../util/misc.js');
class Post extends events.EventTarget {
constructor() {
@@ -111,13 +106,13 @@ class Post extends events.EventTarget {
if (this._safety !== this._orig._safety) {
detail.safety = this._safety;
}
- if (_arraysDiffer(this._flags, this._orig._flags)) {
+ if (misc.arraysDiffer(this._flags, this._orig._flags)) {
detail.flags = this._flags;
}
- if (_arraysDiffer(this._tags, this._orig._tags)) {
+ if (misc.arraysDiffer(this._tags, this._orig._tags)) {
detail.tags = this._tags;
}
- if (_arraysDiffer(this._relations, this._orig._relations)) {
+ if (misc.arraysDiffer(this._relations, this._orig._relations)) {
detail.relations = this._relations;
}
diff --git a/client/js/models/tag.js b/client/js/models/tag.js
index 8d65141..32db964 100644
--- a/client/js/models/tag.js
+++ b/client/js/models/tag.js
@@ -2,16 +2,21 @@
const api = require('../api.js');
const events = require('../events.js');
+const misc = require('../util/misc.js');
class Tag extends events.EventTarget {
constructor() {
super();
+ this._orig = {};
+
this._origName = null;
- this._names = null;
this._category = null;
this._description = null;
- this._suggestions = null;
- this._implications = null;
+
+ this._names = [];
+ this._suggestions = [];
+ this._implications = [];
+
this._postCount = null;
this._creationTime = null;
this._lastEditTime = null;
@@ -48,13 +53,25 @@ class Tag extends events.EventTarget {
}
save() {
- const detail = {
- names: this.names,
- category: this.category,
- description: this.description,
- implications: this.implications,
- suggestions: this.suggestions,
- };
+ const detail = {};
+
+ // send only changed fields to avoid user privilege violation
+ if (misc.arraysDiffer(this._names, this._orig._names)) {
+ detail.names = this._names;
+ }
+ if (this._category !== this._orig._category) {
+ detail.category = this._category;
+ }
+ if (this._description !== this._orig._description) {
+ detail.description = this._description;
+ }
+ if (misc.arraysDiffer(this._implications, this._orig._implications)) {
+ detail.implications = this._implications;
+ }
+ if (misc.arraysDiffer(this._suggestions, this._orig._suggestions)) {
+ detail.suggestions = this._suggestions;
+ }
+
let promise = this._origName ?
api.put('/tag/' + this._origName, detail) :
api.post('/tags', detail);
@@ -104,15 +121,20 @@ class Tag extends events.EventTarget {
}
_updateFromResponse(response) {
- this._origName = response.names ? response.names[0] : null;
- this._names = response.names;
- this._category = response.category;
- this._description = response.description;
- this._implications = response.implications;
- this._suggestions = response.suggestions;
- this._creationTime = response.creationTime;
- this._lastEditTime = response.lastEditTime;
- this._postCount = response.usages;
+ const map = {
+ _origName: response.names ? response.names[0] : null,
+ _names: response.names,
+ _category: response.category,
+ _description: response.description,
+ _implications: response.implications,
+ _suggestions: response.suggestions,
+ _creationTime: response.creationTime,
+ _lastEditTime: response.lastEditTime,
+ _postCount: response.usages,
+ };
+
+ Object.assign(this, map);
+ Object.assign(this._orig, map);
}
};
diff --git a/client/js/util/misc.js b/client/js/util/misc.js
index 7bcd632..4bf0e1a 100644
--- a/client/js/util/misc.js
+++ b/client/js/util/misc.js
@@ -244,6 +244,12 @@ function escapeHtml(unsafe) {
.replace(/'/g, ''');
}
+function arraysDiffer(source1, source2) {
+ return (
+ [...source1].filter(value => !source2.includes(value)).length > 0 ||
+ [...source2].filter(value => !source1.includes(value)).length > 0);
+}
+
module.exports = {
range: range,
formatUrlParameters: formatUrlParameters,
@@ -259,4 +265,5 @@ module.exports = {
escapeHtml: escapeHtml,
makeCssName: makeCssName,
splitByWhitespace: splitByWhitespace,
+ arraysDiffer: arraysDiffer,
};
diff --git a/client/js/views/tag_edit_view.js b/client/js/views/tag_edit_view.js
index 35e0e8a..515b4ad 100644
--- a/client/js/views/tag_edit_view.js
+++ b/client/js/views/tag_edit_view.js
@@ -79,13 +79,26 @@ class TagEditView extends events.EventTarget {
this.dispatchEvent(new CustomEvent('submit', {
detail: {
tag: this._tag,
- names: misc.splitByWhitespace(this._namesFieldNode.value),
- category: this._categoryFieldNode.value,
- implications: misc.splitByWhitespace(
- this._implicationsFieldNode.value),
- suggestions: misc.splitByWhitespace(
- this._suggestionsFieldNode.value),
- description: this._descriptionFieldNode.value,
+
+ names: this._namesFieldNode ?
+ misc.splitByWhitespace(this._namesFieldNode.value) :
+ undefined,
+
+ category: this._categoryFieldNode ?
+ this._categoryFieldNode.value :
+ undefined,
+
+ implications: this._implicationsFieldNode ?
+ misc.splitByWhitespace(this._implicationsFieldNode.value) :
+ undefined,
+
+ suggestions: this._suggestionsFieldNode ?
+ misc.splitByWhitespace(this._suggestionsFieldNode.value) :
+ undefined,
+
+ description: this._descriptionFieldNode ?
+ this._descriptionFieldNode.value :
+ undefined,
},
}));
}