From 2464bb87316d11f8d1ae2b2d9c18d03bbbe469fc Mon Sep 17 00:00:00 2001 From: mutantsan Date: Tue, 11 Apr 2023 17:40:45 +0300 Subject: [PATCH] add ajax reload option, rework subject getters --- README.md | 7 +++ ckanext/comments/assets/js/comments-thread.js | 45 +++++++++++++++---- ckanext/comments/logic/schema.py | 8 ++-- ckanext/comments/model/thread.py | 16 +++++-- ckanext/comments/subject.py | 17 +++++++ setup.cfg | 2 +- 6 files changed, 78 insertions(+), 17 deletions(-) create mode 100644 ckanext/comments/subject.py diff --git a/README.md b/README.md index cb010f3..c233995 100644 --- a/README.md +++ b/README.md @@ -86,8 +86,15 @@ ckanext.comments.mobile_depth_threshold = 3 # Include default thread implementation on the dataset page # (optional, default: false). ckanext.comments.enable_default_dataset_comments = true + +# Register custom getter for a subject by providing a path to a function +# ckanext.comments.subject.{self.subject_type}_getter = path +# The function must accept an ID and return a model object +ckanext.comments.subject.question_getter = ckanext.msf_ask_question.model.question_getter ``` + + ## API ### `comments_thread_create` diff --git a/ckanext/comments/assets/js/comments-thread.js b/ckanext/comments/assets/js/comments-thread.js index 2d0e6b2..3eded83 100644 --- a/ckanext/comments/assets/js/comments-thread.js +++ b/ckanext/comments/assets/js/comments-thread.js @@ -5,6 +5,7 @@ ckan.module("comments-thread", function ($) { options: { subjectId: null, subjectType: null, + ajaxReload: null, }, initialize: function () { $.proxyAll(this, /_on/); @@ -23,7 +24,7 @@ ckan.module("comments-thread", function ($) { this.$(".comment-actions .edit-comment").on("click", this._onEditComment); this.$(".comment-actions .save-comment").on("click", this._onSaveComment); this.$(".comment-footer").on("click", this._onFooterClick); - this.$(".comment-form").on("submit", this._onSubmit); + this.$(".comment-form").off("submit").on("submit", this._onSubmit); }, teardown: function () { this.$(".comment-action.remove-comment").off( @@ -35,7 +36,7 @@ ckan.module("comments-thread", function ($) { this._onApproveComment ); - this.$("comment-form").off("sumbit", this._onSubmit); + this.$(".comment-form").off("submit", this._onSubmit); }, _onFooterClick: function (e) { if (e.target.classList.contains("cancel-reply")) { @@ -52,6 +53,7 @@ ckan.module("comments-thread", function ($) { }, _onRemoveComment: function (e) { var id = e.currentTarget.dataset.id; + var ajaxReload = this.options.ajaxReload; this.sandbox.client.call( "POST", @@ -59,13 +61,21 @@ ckan.module("comments-thread", function ($) { { id: id, }, - function () { - window.location.reload(); + function (e) { + if (ajaxReload) { + $(".modal").modal("hide"); + + $(document).trigger("comments:changed"); + } else { + window.location.reload(); + } } ); }, _onApproveComment: function (e) { var id = e.currentTarget.dataset.id; + var ajaxReload = this.options.ajaxReload; + this.sandbox.client.call( "POST", "comments_comment_approve", @@ -73,11 +83,14 @@ ckan.module("comments-thread", function ($) { id: id, }, function () { - window.location.reload(); + if (ajaxReload) { + $(document).trigger("comments:changed"); + } else { + window.location.reload(); + } } ); }, - _disableActiveReply: function () { $(".comment .reply-textarea-wrapper").remove(); }, @@ -140,6 +153,8 @@ ckan.module("comments-thread", function ($) { var notify = this.sandbox.notify; var _ = this.sandbox.translate; var content = target.closest(".comment").find(".comment-body textarea"); + var ajaxReload = this.options.ajaxReload; + this.sandbox.client.call( "POST", "comments_comment_update", @@ -148,7 +163,11 @@ ckan.module("comments-thread", function ($) { content: content.val(), }, function () { - window.location.reload(); + if (ajaxReload) { + $(document).trigger("comments:changed"); + } else { + window.location.reload(); + } }, function (err) { console.log(err); @@ -170,14 +189,24 @@ ckan.module("comments-thread", function ($) { this._saveComment({ content: data.get("content"), create_thread: true }); }, _saveComment: function (data) { + if (!data.content) { + return; + } + data.subject_id = this.options.subjectId; data.subject_type = this.options.subjectType; + var ajaxReload = this.options.ajaxReload; + this.sandbox.client.call( "POST", "comments_comment_create", data, function () { - window.location.reload(); + if (ajaxReload) { + $(document).trigger("comments:changed"); + } else { + window.location.reload(); + } } ); }, diff --git a/ckanext/comments/logic/schema.py b/ckanext/comments/logic/schema.py index e3c579e..5bb3d9f 100644 --- a/ckanext/comments/logic/schema.py +++ b/ckanext/comments/logic/schema.py @@ -3,14 +3,14 @@ @validator_args -def thread_create(not_empty, one_of): +def thread_create(not_empty, unicode_safe): return { "subject_id": [ not_empty, ], "subject_type": [ not_empty, - one_of(["package", "resource", "user", "group"]), + unicode_safe, ], } @@ -36,14 +36,14 @@ def thread_delete(not_empty): @validator_args -def comment_create(not_empty, one_of, default, boolean_validator, ignore_missing): +def comment_create(not_empty, unicode_safe, one_of, default, boolean_validator, ignore_missing): return { "subject_id": [ not_empty, ], "subject_type": [ not_empty, - one_of(["package", "resource", "user", "group"]), + unicode_safe, ], "content": [ not_empty, diff --git a/ckanext/comments/model/thread.py b/ckanext/comments/model/thread.py index 9e5d857..292e33b 100644 --- a/ckanext/comments/model/thread.py +++ b/ckanext/comments/model/thread.py @@ -3,11 +3,13 @@ import logging from datetime import datetime from typing import TYPE_CHECKING, Callable, Optional, Union, cast +from werkzeug.utils import import_string from sqlalchemy import Column, DateTime, Text from sqlalchemy.orm import Query import ckan.model as model +import ckan.plugins.toolkit as tk from ckan.model.types import make_uuid from ckanext.comments.exceptions import UnsupportedSubjectType @@ -47,12 +49,18 @@ def comments(self) -> Query: return Comment.by_thread(self.id) def get_subject(self) -> Optional[Subject]: - try: + getter = import_string( + tk.config.get(f"ckanext.comments.subject.{self.subject_type}_getter"), + True, + ) + + if not getter and self.subject_type in self._subject_getters: getter = self._subject_getters[self.subject_type] - except KeyError: - log.error("Unknown subject type: %s", self.subject_type) + + if not getter: raise UnsupportedSubjectType(self.subject_type) - return getter(self.subject_id) + + return getter(self.subject_id) # type: ignore @classmethod def for_subject( diff --git a/ckanext/comments/subject.py b/ckanext/comments/subject.py new file mode 100644 index 0000000..f766596 --- /dev/null +++ b/ckanext/comments/subject.py @@ -0,0 +1,17 @@ +import ckan.model as model + + +def package_getter(id: str): + return model.Package.get(id) + + +def resource_getter(id: str): + return model.Resource.get(id) + + +def user_getter(id: str): + return model.User.get(id) + + +def group_getter(id: str): + return model.Group.get(id) diff --git a/setup.cfg b/setup.cfg index 953d24b..fe59d0b 100644 --- a/setup.cfg +++ b/setup.cfg @@ -1,6 +1,6 @@ [metadata] name = ckanext-comments -version = 0.2.0 +version = 0.3.0 description = long_description = file: README.md long_description_content_type = text/markdown