diff --git a/mod/forum/amd/build/inpage_reply.min.js b/mod/forum/amd/build/inpage_reply.min.js index b25f8e1c809..33b572babbb 100644 --- a/mod/forum/amd/build/inpage_reply.min.js +++ b/mod/forum/amd/build/inpage_reply.min.js @@ -1 +1 @@ -define(["jquery","core/templates","core/notification","mod_forum/repository","mod_forum/selectors"],function(a,b,c,d,e){var f={THREADED:2,NESTED:3,FLAT_OLDEST_FIRST:1,FLAT_NEWEST_FIRST:-1},g=function(a){var b=a.find(e.post.inpageSubmitBtnText),c=a.find(e.post.loadingIconContainer),d=a.outerWidth();a.css("width",d),b.addClass("hidden"),c.removeClass("hidden")},h=function(a){var b=a.find(e.post.inpageSubmitBtnText),c=a.find(e.post.loadingIconContainer);a.css("width",""),b.removeClass("hidden"),c.addClass("hidden")},i=function(i){i.on("click",e.post.inpageSubmitBtn,function(j){j.preventDefault();var k,l=a(j.currentTarget),m=l.parent().find(e.post.inpageReplyButton),n=l.parents(e.post.inpageReplyForm).get(0),o=n.elements.post.value.trim(),p=n.elements.reply.value,q=n.elements.subject.value,r=l.parents(e.post.forumContent),s=parseInt(i.find(e.post.modeSelect).get(0).value);o.length&&(g(l),m.prop("disabled",!0),d.addDiscussionPost(p,q,o).then(function(a){var b=a.messages.reduce(function(a,b){return"success"==b.type&&(a+="

"+b.message+"

"),a},"");return c.addNotification({message:b,type:"success"}),a}).then(function(a){n.reset();var c=a.post;switch(k=c.id,s){case f.THREADED:return b.render("mod_forum/forum_discussion_threaded_post",c);case f.NESTED:return b.render("mod_forum/forum_discussion_nested_post",c);default:return b.render("mod_forum/forum_discussion_post",c)}}).then(function(a,c){var d;return s!=f.FLAT_OLDEST_FIRST&&s!=f.FLAT_NEWEST_FIRST||(d=r.parents(e.post.repliesContainer).children().get(0)),void 0==d&&(d=r.siblings(e.post.repliesContainer).children().get(0)),s==f.FLAT_NEWEST_FIRST?b.prependNodeContents(d,a,c):b.appendNodeContents(d,a,c)}).then(function(){return h(l),m.prop("disabled",!1),r.find(e.post.inpageReplyContent).hide()}).then(function(){location.href="#p"+k})["catch"](function(a){return h(l),m.prop("disabled",!1),c.exception(a)}))})};return{init:function(a){i(a)}}}); \ No newline at end of file +define(["jquery","core/templates","core/notification","mod_forum/repository","mod_forum/selectors"],function(a,b,c,d,e){var f={THREADED:2,NESTED:3,FLAT_OLDEST_FIRST:1,FLAT_NEWEST_FIRST:-1},g=function(a){var b=a.find(e.post.inpageSubmitBtnText),c=a.find(e.post.loadingIconContainer),d=a.outerWidth();a.css("width",d),b.addClass("hidden"),c.removeClass("hidden")},h=function(a){var b=a.find(e.post.inpageSubmitBtnText),c=a.find(e.post.loadingIconContainer);a.css("width",""),b.removeClass("hidden"),c.addClass("hidden")},i=function(i){i.on("click",e.post.inpageSubmitBtn,function(j){j.preventDefault();var k,l=a(j.currentTarget),m=l.parent().find(e.post.inpageReplyButton),n=l.parents(e.post.inpageReplyForm).get(0),o=n.elements.post.value.trim(),p=n.elements.reply.value,q=n.elements.subject.value,r=l.parents(e.post.forumContent),s=void 0!=n.elements.privatereply&&n.elements.privatereply.checked,t=parseInt(i.find(e.post.modeSelect).get(0).value);o.length&&(g(l),m.prop("disabled",!0),d.addDiscussionPost(p,q,o,s).then(function(a){var b=a.messages.reduce(function(a,b){return"success"==b.type&&(a+="

"+b.message+"

"),a},"");return c.addNotification({message:b,type:"success"}),a}).then(function(a){n.reset();var c=a.post;switch(k=c.id,t){case f.THREADED:return b.render("mod_forum/forum_discussion_threaded_post",c);case f.NESTED:return b.render("mod_forum/forum_discussion_nested_post",c);default:return b.render("mod_forum/forum_discussion_post",c)}}).then(function(a,c){var d;return t!=f.FLAT_OLDEST_FIRST&&t!=f.FLAT_NEWEST_FIRST||(d=r.parents(e.post.repliesContainer).children().get(0)),void 0==d&&(d=r.siblings(e.post.repliesContainer).children().get(0)),t==f.FLAT_NEWEST_FIRST?b.prependNodeContents(d,a,c):b.appendNodeContents(d,a,c)}).then(function(){return h(l),m.prop("disabled",!1),r.find(e.post.inpageReplyContent).hide()}).then(function(){location.href="#p"+k})["catch"](function(a){return h(l),m.prop("disabled",!1),c.exception(a)}))})};return{init:function(a){i(a)}}}); \ No newline at end of file diff --git a/mod/forum/amd/build/posts_list.min.js b/mod/forum/amd/build/posts_list.min.js index 8b4740c206e..644a0042e9f 100644 --- a/mod/forum/amd/build/posts_list.min.js +++ b/mod/forum/amd/build/posts_list.min.js @@ -1 +1 @@ -define(["jquery","core/templates","core/notification","mod_forum/selectors","mod_forum/inpage_reply"],function(a,b,c,d,e){var f=function(e){e.on("click",d.post.inpageReplyLink,function(e){if(e.preventDefault(),window.location.hash){var f=window.location.href.split("#")[0];history.pushState({},document.title,f)}var g=a(e.currentTarget).parents(d.post.forumCoreContent),h=g.find(d.post.forumSubject),i=a(e.currentTarget).parents(d.post.forumContent),j={postid:a(i).data("post-id"),reply_url:a(e.currentTarget).attr("href"),sesskey:M.cfg.sesskey,parentsubject:h.html()};if(i.find(d.post.inpageReplyContent).length){var k=i.find(d.post.inpageReplyContent);k.slideToggle(300),k.is(":visible")&&k.find("textarea").focus()}else b.render("mod_forum/inpage_reply",j).then(function(a,c){return b.appendNodeContents(g,a,c)}).then(function(){return i.find(d.post.inpageReplyContent).slideToggle(300).find("textarea").focus()}).fail(c.exception)})};return{init:function(a){f(a),e.init(a)}}}); \ No newline at end of file +define(["jquery","core/templates","core/notification","mod_forum/selectors","mod_forum/inpage_reply"],function(a,b,c,d,e){var f=function(e){e.on("click",d.post.inpageReplyLink,function(e){if(e.preventDefault(),window.location.hash){var f=window.location.href.split("#")[0];history.pushState({},document.title,f)}var g=a(e.currentTarget).parents(d.post.forumCoreContent),h=g.find(d.post.forumSubject),i=a(e.currentTarget).parents(d.post.forumContent),j={postid:a(i).data("post-id"),reply_url:a(e.currentTarget).attr("href"),sesskey:M.cfg.sesskey,parentsubject:h.html(),canreplyprivately:a(e.currentTarget).data("can-reply-privately")};if(i.find(d.post.inpageReplyContent).length){var k=i.find(d.post.inpageReplyContent);k.slideToggle(300),k.is(":visible")&&k.find("textarea").focus()}else b.render("mod_forum/inpage_reply",j).then(function(a,c){return b.appendNodeContents(g,a,c)}).then(function(){return i.find(d.post.inpageReplyContent).slideToggle(300).find("textarea").focus()}).fail(c.exception)})};return{init:function(a){f(a),e.init(a)}}}); \ No newline at end of file diff --git a/mod/forum/amd/build/repository.min.js b/mod/forum/amd/build/repository.min.js index b20b5325704..019d014aefe 100644 --- a/mod/forum/amd/build/repository.min.js +++ b/mod/forum/amd/build/repository.min.js @@ -1 +1 @@ -define(["core/ajax"],function(a){var b=function(b,c,d){var e={methodname:"mod_forum_set_subscription_state",args:{forumid:b,discussionid:c,targetstate:d}};return a.call([e])[0]},c=function(b,c,d){var e={methodname:"mod_forum_add_discussion_post",args:{postid:b,message:d,subject:c}};return a.call([e])[0]},d=function(b,c,d){var e={methodname:"mod_forum_toggle_favourite_state",args:{discussionid:c,targetstate:d}};return a.call([e])[0]},e=function(b,c,d){var e={methodname:"mod_forum_set_lock_state",args:{forumid:b,discussionid:c,targetstate:d}};return a.call([e])[0]},f=function(b,c,d){var e={methodname:"mod_forum_set_pin_state",args:{discussionid:c,targetstate:d}};return a.call([e])[0]};return{setDiscussionSubscriptionState:b,addDiscussionPost:c,setDiscussionLockState:e,setFavouriteDiscussionState:d,setPinDiscussionState:f}}); \ No newline at end of file +define(["core/ajax"],function(a){var b=function(b,c,d){var e={methodname:"mod_forum_set_subscription_state",args:{forumid:b,discussionid:c,targetstate:d}};return a.call([e])[0]},c=function(b,c,d,e){var f={methodname:"mod_forum_add_discussion_post",args:{postid:b,message:d,subject:c,options:[{name:"private",value:e}]}};return a.call([f])[0]},d=function(b,c,d){var e={methodname:"mod_forum_toggle_favourite_state",args:{discussionid:c,targetstate:d}};return a.call([e])[0]},e=function(b,c,d){var e={methodname:"mod_forum_set_lock_state",args:{forumid:b,discussionid:c,targetstate:d}};return a.call([e])[0]},f=function(b,c,d){var e={methodname:"mod_forum_set_pin_state",args:{discussionid:c,targetstate:d}};return a.call([e])[0]};return{setDiscussionSubscriptionState:b,addDiscussionPost:c,setDiscussionLockState:e,setFavouriteDiscussionState:d,setPinDiscussionState:f}}); \ No newline at end of file diff --git a/mod/forum/amd/src/inpage_reply.js b/mod/forum/amd/src/inpage_reply.js index 06decf40955..7b03f1d13ef 100644 --- a/mod/forum/amd/src/inpage_reply.js +++ b/mod/forum/amd/src/inpage_reply.js @@ -86,6 +86,7 @@ define([ var postid = form.elements.reply.value; var subject = form.elements.subject.value; var currentRoot = submitButton.parents(Selectors.post.forumContent); + var isprivatereply = form.elements.privatereply != undefined ? form.elements.privatereply.checked : false; var mode = parseInt(root.find(Selectors.post.modeSelect).get(0).value); var newid; @@ -93,7 +94,7 @@ define([ showSubmitButtonLoadingIcon(submitButton); allButtons.prop('disabled', true); - Repository.addDiscussionPost(postid, subject, message) + Repository.addDiscussionPost(postid, subject, message, isprivatereply) .then(function(context) { var message = context.messages.reduce(function(carry, message) { if (message.type == 'success') { diff --git a/mod/forum/amd/src/posts_list.js b/mod/forum/amd/src/posts_list.js index f04f640ea5d..e68c87e9024 100644 --- a/mod/forum/amd/src/posts_list.js +++ b/mod/forum/amd/src/posts_list.js @@ -59,7 +59,8 @@ define([ postid: $(currentRoot).data('post-id'), "reply_url": $(e.currentTarget).attr('href'), sesskey: M.cfg.sesskey, - parentsubject: currentSubject.html() + parentsubject: currentSubject.html(), + canreplyprivately: $(e.currentTarget).data('can-reply-privately') }; if (!currentRoot.find(Selectors.post.inpageReplyContent).length) { diff --git a/mod/forum/amd/src/repository.js b/mod/forum/amd/src/repository.js index e7d32afb27e..05331605da2 100644 --- a/mod/forum/amd/src/repository.js +++ b/mod/forum/amd/src/repository.js @@ -43,13 +43,17 @@ define(['core/ajax'], function(Ajax) { return Ajax.call([request])[0]; }; - var addDiscussionPost = function(postid, subject, message) { + var addDiscussionPost = function(postid, subject, message, isprivatereply) { var request = { methodname: 'mod_forum_add_discussion_post', args: { postid: postid, message: message, - subject: subject + subject: subject, + options: [{ + name: "private", + value: isprivatereply, + }] } }; return Ajax.call([request])[0]; diff --git a/mod/forum/classes/local/exporters/post.php b/mod/forum/classes/local/exporters/post.php index ea097b4aa8c..4528c602d8e 100644 --- a/mod/forum/classes/local/exporters/post.php +++ b/mod/forum/classes/local/exporters/post.php @@ -156,6 +156,11 @@ class post extends exporter { 'null' => NULL_ALLOWED, 'description' => 'Whether the user can control the read status of the post', ], + 'canreplyprivately' => [ + 'type' => PARAM_BOOL, + 'null' => NULL_ALLOWED, + 'description' => 'Whether the user can post a private reply', + ] ] ], 'urls' => [ @@ -355,6 +360,7 @@ class post extends exporter { $canreply = $capabilitymanager->can_reply_to_post($user, $discussion, $post); $canexport = $capabilitymanager->can_export_post($user, $post); $cancontrolreadstatus = $capabilitymanager->can_manually_control_post_read_status($user); + $canreplyprivately = $capabilitymanager->can_reply_privately_to_post($user, $post); $urlfactory = $this->related['urlfactory']; $viewurl = $canview ? $urlfactory->get_view_post_url_from_post($post) : null; @@ -417,7 +423,8 @@ class post extends exporter { 'split' => $cansplit, 'reply' => $canreply, 'export' => $canexport, - 'controlreadstatus' => $cancontrolreadstatus + 'controlreadstatus' => $cancontrolreadstatus, + 'canreplyprivately' => $canreplyprivately ], 'urls' => [ 'view' => $viewurl ? $viewurl->out(false) : null, diff --git a/mod/forum/templates/forum_discussion_post.mustache b/mod/forum/templates/forum_discussion_post.mustache index 5a5e28fb64a..791619fbd9c 100644 --- a/mod/forum/templates/forum_discussion_post.mustache +++ b/mod/forum/templates/forum_discussion_post.mustache @@ -257,6 +257,7 @@ role="menuitem" data-post-id="{{id}}" data-action="collapsible-link" + data-can-reply-privately="{{canreplyprivately}}" title="{{#str}} reply, mod_forum {{/str}}" > {{#str}} reply, mod_forum {{/str}} diff --git a/mod/forum/templates/inpage_reply.mustache b/mod/forum/templates/inpage_reply.mustache index da44f5e6757..82d33ace993 100644 --- a/mod/forum/templates/inpage_reply.mustache +++ b/mod/forum/templates/inpage_reply.mustache @@ -52,7 +52,13 @@ - diff --git a/mod/forum/tests/behat/inpage_reply.feature b/mod/forum/tests/behat/inpage_reply.feature index 6fa68bba61b..af697560adc 100644 --- a/mod/forum/tests/behat/inpage_reply.feature +++ b/mod/forum/tests/behat/inpage_reply.feature @@ -5,13 +5,15 @@ Feature: Students can reply to a discussion in page. Given the following "users" exist: | username | firstname | lastname | email | | student1 | Student | 1 | student1@example.com | + | teacher1 | Teacher | 1 | teacher1@example.com | And the following "courses" exist: | fullname | shortname | category | | Course 1 | C1 | 0 | And the following "course enrolments" exist: | user | course | role | | student1 | C1 | student | - And I log in as "admin" + | teacher1 | C1 | editingteacher | + And I log in as "teacher1" And I am on "Course 1" course homepage with editing mode on And I add a "Forum" to section "1" and I fill the form with: | Forum name | Test forum name | @@ -23,12 +25,23 @@ Feature: Students can reply to a discussion in page. | Subject | Discussion 2 | | Message | Discussion contents 2, first message | And I log out - And I log in as "student1" - And I am on "Course 1" course homepage Scenario: Confirm inpage replies work + Given I log in as "student1" + And I am on "Course 1" course homepage Given I reply "Discussion 2" post from "Test forum name" forum using an inpage reply with: | post | Discussion contents 1, third message | Then I should see "Discussion contents 1, third message" When I reload the page + Then I should see "Discussion contents 1, third message" + + Scenario: Confirm inpage replies work - private reply + Given I log in as "teacher1" + And I am on "Course 1" course homepage + And I reply "Discussion 2" post from "Test forum name" forum using an inpage reply with: + | post | Discussion contents 1, third message | + | privatereply | 1 | + Then I should see "Discussion contents 1, third message" + Then I should see "This post was made privately and is not visible to all users." + When I reload the page Then I should see "Discussion contents 1, third message" \ No newline at end of file diff --git a/mod/forum/tests/exporters_post_test.php b/mod/forum/tests/exporters_post_test.php index daf675a3b5e..425abc73f48 100644 --- a/mod/forum/tests/exporters_post_test.php +++ b/mod/forum/tests/exporters_post_test.php @@ -103,6 +103,7 @@ class mod_forum_exporters_post_testcase extends advanced_testcase { $canreply = true; $canexport = true; $cancontrolreadstatus = true; + $canreplyprivately = true; $capabilitymanager = new test_capability_manager( $canview, $canedit, @@ -110,7 +111,8 @@ class mod_forum_exporters_post_testcase extends advanced_testcase { $cansplit, $canreply, $canexport, - $cancontrolreadstatus + $cancontrolreadstatus, + $canreplyprivately ); $managerfactory = \mod_forum\local\container::get_manager_factory(); $entityfactory = \mod_forum\local\container::get_entity_factory(); @@ -412,6 +414,8 @@ class test_capability_manager extends capability_manager { private $export; /** @var bool $controlreadstatus Value for can_manually_control_post_read_status */ private $controlreadstatus; + /** @var bool $controlreadstatus Value for can_reply_privately_to_post */ + private $canreplyprivatelytopost; /** * Constructor. @@ -431,7 +435,8 @@ class test_capability_manager extends capability_manager { bool $split = true, bool $reply = true, bool $export = true, - bool $controlreadstatus = true + bool $controlreadstatus = true, + bool $canreplyprivatelytopost = true ) { $this->view = $view; $this->edit = $edit; @@ -440,6 +445,7 @@ class test_capability_manager extends capability_manager { $this->reply = $reply; $this->export = $export; $this->controlreadstatus = $controlreadstatus; + $this->canreplyprivatelytopost = $canreplyprivatelytopost; } /** @@ -522,4 +528,14 @@ class test_capability_manager extends capability_manager { public function can_manually_control_post_read_status(stdClass $user) : bool { return $this->controlreadstatus; } + + /** + * Override can_reply_privately_to_post + * @param stdClass $user + * @param post_entity $post + * @return bool + */ + public function can_reply_privately_to_post(stdClass $user, post_entity $post) : bool { + return $this->canreplyprivatelytopost; + } } diff --git a/mod/forum/tests/externallib_test.php b/mod/forum/tests/externallib_test.php index 6a1f8c281fd..3cfeb478d21 100644 --- a/mod/forum/tests/externallib_test.php +++ b/mod/forum/tests/externallib_test.php @@ -691,7 +691,8 @@ class mod_forum_external_testcase extends externallib_advanced_testcase { 'split' => 0, 'reply' => 1, 'export' => 0, - 'controlreadstatus' => 0 + 'controlreadstatus' => 0, + 'canreplyprivately' => 0 ], 'urls' => [ 'view' => $urlfactory->get_view_post_url_from_post_id($discussion1reply2->discussion, $discussion1reply2->id), @@ -743,7 +744,8 @@ class mod_forum_external_testcase extends externallib_advanced_testcase { 'split' => 0, 'reply' => 1, 'export' => 0, - 'controlreadstatus' => 0 + 'controlreadstatus' => 0, + 'canreplyprivately' => 0 ], 'urls' => [ 'view' => $urlfactory->get_view_post_url_from_post_id($discussion1reply1->discussion, $discussion1reply1->id),