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, }, })); }