From a07054af3045dd9a40c591cc07eb4e2e97f48e9a Mon Sep 17 00:00:00 2001 From: Huong Nguyen Date: Tue, 21 May 2024 10:05:46 +0700 Subject: [PATCH] MDL-81428 core: Display the correct status for the contact request --- .upgradenotes/MDL-81428-2024061009440935.yml | 12 +++++++ lang/en/message.php | 1 + lib/outputrenderers.php | 41 +++++++++++++++++++--- message/amd/build/toggle_contact_button.min.js | 2 +- message/amd/build/toggle_contact_button.min.js.map | 2 +- message/amd/src/toggle_contact_button.js | 26 +++++++++----- message/classes/helper.php | 9 ++++- ...tton.mustache => contact_request_sent.mustache} | 14 +++----- message/templates/remove_contact_button.mustache | 1 + .../behat/message_drawer_manage_contacts.feature | 19 ++++++++++ theme/boost/classes/output/core_renderer.php | 41 +++++++++++++++++++--- 11 files changed, 139 insertions(+), 29 deletions(-) create mode 100644 .upgradenotes/MDL-81428-2024061009440935.yml rewrite message/amd/build/toggle_contact_button.min.js.map (82%) copy message/templates/{remove_contact_button.mustache => contact_request_sent.mustache} (78%) diff --git a/.upgradenotes/MDL-81428-2024061009440935.yml b/.upgradenotes/MDL-81428-2024061009440935.yml new file mode 100644 index 00000000000..365aae650a4 --- /dev/null +++ b/.upgradenotes/MDL-81428-2024061009440935.yml @@ -0,0 +1,12 @@ +issueNumber: MDL-81428 +notes: + core_message: + - message: > + The `\core_message\helper::togglecontact_link_params` now accepts a new + optional param called `isrequested` to indicate the status of the + contact request + type: changed + - message: > + The `core_message/remove_contact_button` template is deprecated and will + be removed in the future version + type: deprecated diff --git a/lang/en/message.php b/lang/en/message.php index aac4d96aded..635cb4504b0 100644 --- a/lang/en/message.php +++ b/lang/en/message.php @@ -269,6 +269,7 @@ $string['viewfullnotification'] = 'View full notification'; $string['viewmessageswith'] = 'View messages with {$a}'; $string['viewnotificationresource'] = 'Go to: {$a}'; $string['viewunreadmessageswith'] = 'View unread messages with {$a}'; +$string['waitingforcontactaccept'] = 'Waiting for your approval'; $string['writeamessage'] = 'Write a message...'; $string['wouldliketocontactyou'] = 'Would like to contact you'; $string['you'] = 'You:'; diff --git a/lib/outputrenderers.php b/lib/outputrenderers.php index a9b10373f48..2093bb5da1f 100644 --- a/lib/outputrenderers.php +++ b/lib/outputrenderers.php @@ -4566,9 +4566,42 @@ EOD; if ($USER->id != $user->id) { $iscontact = \core_message\api::is_contact($USER->id, $user->id); - $contacttitle = $iscontact ? 'removefromyourcontacts' : 'addtoyourcontacts'; - $contacturlaction = $iscontact ? 'removecontact' : 'addcontact'; - $contactimage = $iscontact ? 'removecontact' : 'addcontact'; + $isrequested = \core_message\api::get_contact_requests_between_users($USER->id, $user->id); + $contacturlaction = ''; + $linkattributes = \core_message\helper::togglecontact_link_params( + $user, + $iscontact, + true, + !empty($isrequested), + ); + // If the user is not a contact. + if (!$iscontact) { + if ($isrequested) { + // We just need the first request. + $requests = array_shift($isrequested); + if ($requests->userid == $USER->id) { + // If the user has requested to be a contact. + $contacttitle = 'contactrequestsent'; + } else { + // If the user has been requested to be a contact. + $contacttitle = 'waitingforcontactaccept'; + } + $linkattributes = array_merge($linkattributes, [ + 'class' => 'disabled', + 'tabindex' => '-1', + ]); + } else { + // If the user is not a contact and has not requested to be a contact. + $contacttitle = 'addtoyourcontacts'; + $contacturlaction = 'addcontact'; + } + $contactimage = 'addcontact'; + } else { + // If the user is a contact. + $contacttitle = 'removefromyourcontacts'; + $contacturlaction = 'removecontact'; + $contactimage = 'removecontact'; + } $userbuttons['togglecontact'] = array( 'buttontype' => 'togglecontact', 'title' => get_string($contacttitle, 'message'), @@ -4579,7 +4612,7 @@ EOD; 'sesskey' => sesskey()) ), 'image' => $contactimage, - 'linkattributes' => \core_message\helper::togglecontact_link_params($user, $iscontact), + 'linkattributes' => $linkattributes, 'page' => $this->page ); } diff --git a/message/amd/build/toggle_contact_button.min.js b/message/amd/build/toggle_contact_button.min.js index d4e3aa74795..be5b7679336 100644 --- a/message/amd/build/toggle_contact_button.min.js +++ b/message/amd/build/toggle_contact_button.min.js @@ -5,6 +5,6 @@ * @copyright 2016 Ryan Wyllie * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ -define("core_message/toggle_contact_button",["jquery","core/ajax","core/templates","core/notification","core/custom_interaction_events"],(function($,Ajax,Templates,Notification,CustomEvents){var getUserId=function(element){return element.attr("data-userid")},getCurrentUserId=function(element){return element.attr("data-currentuserid")},displayTextLabel=function(element){return"1"==element.attr("data-display-text-label")},isLoading=function(element){return element.hasClass("loading")||element.attr("disabled")},sendRequest=function(element,request){return isLoading(element)?$.Deferred():(element.addClass("loading"),element.attr("disabled","disabled"),Ajax.call([request])[0].fail(Notification.exception).always((function(){element.removeClass("loading"),element.removeAttr("disabled")})))};return{enhance:function(element){(element=$(element)).children(".loading-icon").length||Templates.render("core/loading",{}).done((function(html,js){element.append(html,js)})),CustomEvents.define(element,[CustomEvents.events.activate]),element.on(CustomEvents.events.activate,(function(e,data){!function(element){return"1"==element.attr("data-is-contact")}(element)?function(element){if(!isLoading(element)){var request={methodname:"core_message_create_contact_request",args:{userid:getCurrentUserId(element),requesteduserid:getUserId(element)}};sendRequest(element,request).done((function(){!function(element){element.attr("data-is-contact","1")}(element);const templateContext={displaytextlabel:displayTextLabel(element)};Templates.render("message/remove_contact_button",templateContext).done((function(html,js){Templates.replaceNodeContents(element,html,js)}))}))}}(element):function(element){if(!isLoading(element)){var request={methodname:"core_message_delete_contacts",args:{userids:[getUserId(element)]}};sendRequest(element,request).done((function(){!function(element){element.attr("data-is-contact","0")}(element);const templateContext={displaytextlabel:displayTextLabel(element)};Templates.render("message/add_contact_button",templateContext).done((function(html,js){Templates.replaceNodeContents(element,html,js)}))}))}}(element),e.preventDefault(),data.originalEvent.preventDefault()}))}}})); +define("core_message/toggle_contact_button",["jquery","core/ajax","core/templates","core/notification","core/custom_interaction_events"],(function($,Ajax,Templates,Notification,CustomEvents){let isRequested=element=>"1"==element.attr("data-is-requested");var getUserId=function(element){return element.attr("data-userid")},getCurrentUserId=function(element){return element.attr("data-currentuserid")},displayTextLabel=function(element){return"1"==element.attr("data-display-text-label")},isLoading=function(element){return element.hasClass("loading")||element.attr("disabled")},sendRequest=function(element,request){return isLoading(element)?$.Deferred():(element.addClass("loading"),element.attr("disabled","disabled"),Ajax.call([request])[0].fail(Notification.exception).always((function(){element.removeClass("loading"),element.removeAttr("disabled")})))};return{enhance:function(element){(element=$(element)).children(".loading-icon").length||isRequested(element)||Templates.render("core/loading",{}).done((function(html,js){element.append(html,js)})),CustomEvents.define(element,[CustomEvents.events.activate]),element.on(CustomEvents.events.activate,(function(e,data){!function(element){return"1"==element.attr("data-is-contact")}(element)?isRequested(element)||function(element){if(!isLoading(element)){var request={methodname:"core_message_create_contact_request",args:{userid:getCurrentUserId(element),requesteduserid:getUserId(element)}};sendRequest(element,request).done((function(){!function(element){element.attr("data-is-requested","1")}(element),element.addClass("disabled");const templateContext={displaytextlabel:displayTextLabel(element)};Templates.render("message/contact_request_sent",templateContext).done((function(html,js){Templates.replaceNodeContents(element,html,js)}))}))}}(element):function(element){if(!isLoading(element)){var request={methodname:"core_message_delete_contacts",args:{userids:[getUserId(element)]}};sendRequest(element,request).done((function(){!function(element){element.attr("data-is-contact","0")}(element);const templateContext={displaytextlabel:displayTextLabel(element)};Templates.render("message/add_contact_button",templateContext).done((function(html,js){Templates.replaceNodeContents(element,html,js)}))}))}}(element),e.preventDefault(),data.originalEvent.preventDefault()}))}}})); //# sourceMappingURL=toggle_contact_button.min.js.map \ No newline at end of file diff --git a/message/amd/build/toggle_contact_button.min.js.map b/message/amd/build/toggle_contact_button.min.js.map dissimilarity index 82% index 2760ca1ea6d..afa87cb262b 100644 --- a/message/amd/build/toggle_contact_button.min.js.map +++ b/message/amd/build/toggle_contact_button.min.js.map @@ -1 +1 @@ -{"version":3,"file":"toggle_contact_button.min.js","sources":["../src/toggle_contact_button.js"],"sourcesContent":["// This file is part of Moodle - http://moodle.org/\n//\n// Moodle is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// Moodle is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with Moodle. If not, see .\n\n/**\n * Module to add/remove contact using ajax.\n *\n * @module core_message/toggle_contact_button\n * @copyright 2016 Ryan Wyllie \n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\ndefine(['jquery', 'core/ajax', 'core/templates', 'core/notification', 'core/custom_interaction_events'],\n function($, Ajax, Templates, Notification, CustomEvents) {\n\n /**\n * Check the state of the element, if the current user is a contact or not.\n *\n * @method isContact\n * @param {object} element jQuery object for the button\n * @return {bool}\n */\n var isContact = function(element) {\n return element.attr('data-is-contact') == '1';\n };\n\n /**\n * Record that the user is a contact.\n *\n * @method setContact\n * @param {object} element jQuery object for the button\n */\n var setContact = function(element) {\n element.attr('data-is-contact', '1');\n };\n\n /**\n * Record that the user is not a contact.\n *\n * @method setNotContact\n * @param {object} element jQuery object for the button\n */\n var setNotContact = function(element) {\n element.attr('data-is-contact', '0');\n };\n\n /**\n * Get the id for the user being viewed.\n *\n * @method getUserId\n * @param {object} element jQuery object for the button\n * @return {int}\n */\n var getUserId = function(element) {\n return element.attr('data-userid');\n };\n\n /**\n * Get the id for the logged in user.\n *\n * @method getUserId\n * @param {object} element jQuery object for the button\n * @return {int}\n */\n var getCurrentUserId = function(element) {\n return element.attr('data-currentuserid');\n };\n\n /**\n * Check whether a text label should be displayed or not.\n *\n * @method getUserId\n * @param {object} element jQuery object for the button\n * @return {int}\n */\n var displayTextLabel = function(element) {\n return element.attr('data-display-text-label') == '1';\n };\n\n /**\n * Check if this element is currently loading.\n *\n * @method isLoading\n * @param {object} element jQuery object for the button\n * @return {bool}\n */\n var isLoading = function(element) {\n return element.hasClass('loading') || element.attr('disabled');\n };\n\n /**\n * Sends an ajax request to the server and handles the element state\n * while the request is being performed.\n *\n * @method sendRequest\n * @param {object} element jQuery object for the button\n * @param {object} request Request hash to send\n * @return {object} jQuery promise\n */\n var sendRequest = function(element, request) {\n if (isLoading(element)) {\n return $.Deferred();\n }\n\n element.addClass('loading');\n element.attr('disabled', 'disabled');\n\n return Ajax.call([request])[0]\n .fail(Notification.exception)\n .always(function() {\n element.removeClass('loading');\n element.removeAttr('disabled');\n });\n };\n\n /**\n * Send a request to the server to add the current user as\n * a contact. The contents of the button are changed to the\n * remove contact button upon success.\n *\n * @method addContact\n * @param {object} element jQuery object for the button\n */\n var addContact = function(element) {\n if (isLoading(element)) {\n return;\n }\n\n var request = {\n methodname: 'core_message_create_contact_request',\n args: {\n userid: getCurrentUserId(element),\n requesteduserid: getUserId(element),\n }\n };\n sendRequest(element, request).done(function() {\n setContact(element);\n const templateContext = {\n 'displaytextlabel': displayTextLabel(element)\n };\n Templates.render('message/remove_contact_button', templateContext).done(function(html, js) {\n Templates.replaceNodeContents(element, html, js);\n });\n });\n };\n\n /**\n * Send a request to the server to remove the current user as\n * a contact. The contents of the button are changed to the\n * add contact button upon success.\n *\n * @method removeContact\n * @param {object} element jQuery object for the button\n */\n var removeContact = function(element) {\n if (isLoading(element)) {\n return;\n }\n\n var request = {\n methodname: 'core_message_delete_contacts',\n args: {\n userids: [getUserId(element)],\n }\n };\n\n sendRequest(element, request).done(function() {\n setNotContact(element);\n const templateContext = {\n 'displaytextlabel': displayTextLabel(element)\n };\n Templates.render('message/add_contact_button', templateContext).done(function(html, js) {\n Templates.replaceNodeContents(element, html, js);\n });\n });\n };\n\n /**\n * Enhances the given element with a loading gif and event handles to make\n * ajax requests to add or remove a contact where appropriate.\n *\n * @public\n * @method enhance\n * @param {object} element jQuery object for the button\n */\n var enhance = function(element) {\n element = $(element);\n\n if (!element.children('.loading-icon').length) {\n // Add the loading gif if it isn't already there.\n Templates.render('core/loading', {}).done(function(html, js) {\n element.append(html, js);\n });\n }\n\n CustomEvents.define(element, [CustomEvents.events.activate]);\n\n element.on(CustomEvents.events.activate, function(e, data) {\n if (isContact(element)) {\n removeContact(element);\n } else {\n addContact(element);\n }\n e.preventDefault();\n data.originalEvent.preventDefault();\n });\n };\n\n return {\n enhance: enhance\n };\n});\n"],"names":["define","$","Ajax","Templates","Notification","CustomEvents","getUserId","element","attr","getCurrentUserId","displayTextLabel","isLoading","hasClass","sendRequest","request","Deferred","addClass","call","fail","exception","always","removeClass","removeAttr","enhance","children","length","render","done","html","js","append","events","activate","on","e","data","isContact","methodname","args","userid","requesteduserid","setContact","templateContext","replaceNodeContents","addContact","userids","setNotContact","removeContact","preventDefault","originalEvent"],"mappings":";;;;;;;AAsBAA,4CAAO,CAAC,SAAU,YAAa,iBAAkB,oBAAqB,mCAC9D,SAASC,EAAGC,KAAMC,UAAWC,aAAcC,kBAwC3CC,UAAY,SAASC,gBACdA,QAAQC,KAAK,gBAUpBC,iBAAmB,SAASF,gBACrBA,QAAQC,KAAK,uBAUpBE,iBAAmB,SAASH,eACsB,KAA3CA,QAAQC,KAAK,4BAUpBG,UAAY,SAASJ,gBACdA,QAAQK,SAAS,YAAcL,QAAQC,KAAK,aAYnDK,YAAc,SAASN,QAASO,gBAC5BH,UAAUJ,SACHN,EAAEc,YAGbR,QAAQS,SAAS,WACjBT,QAAQC,KAAK,WAAY,YAElBN,KAAKe,KAAK,CAACH,UAAU,GACvBI,KAAKd,aAAae,WAClBC,QAAO,WACJb,QAAQc,YAAY,WACpBd,QAAQe,WAAW,uBAiGxB,CACHC,QAxBU,SAAShB,UACnBA,QAAUN,EAAEM,UAECiB,SAAS,iBAAiBC,QAEnCtB,UAAUuB,OAAO,eAAgB,IAAIC,MAAK,SAASC,KAAMC,IACrDtB,QAAQuB,OAAOF,KAAMC,OAI7BxB,aAAaL,OAAOO,QAAS,CAACF,aAAa0B,OAAOC,WAElDzB,QAAQ0B,GAAG5B,aAAa0B,OAAOC,UAAU,SAASE,EAAGC,OA/KzC,SAAS5B,eACqB,KAAnCA,QAAQC,KAAK,mBA+KZ4B,CAAU7B,SA3EL,SAASA,aAClBI,UAAUJ,cAIVO,QAAU,CACVuB,WAAY,sCACZC,KAAM,CACFC,OAAQ9B,iBAAiBF,SACzBiC,gBAAiBlC,UAAUC,WAGnCM,YAAYN,QAASO,SAASa,MAAK,YAvGtB,SAASpB,SACtBA,QAAQC,KAAK,kBAAmB,KAuG5BiC,CAAWlC,eACLmC,gBAAkB,kBACAhC,iBAAiBH,UAEzCJ,UAAUuB,OAAO,gCAAiCgB,iBAAiBf,MAAK,SAASC,KAAMC,IACnF1B,UAAUwC,oBAAoBpC,QAASqB,KAAMC,WA4D7Ce,CAAWrC,SA/CH,SAASA,aACrBI,UAAUJ,cAIVO,QAAU,CACVuB,WAAY,+BACZC,KAAM,CACFO,QAAS,CAACvC,UAAUC,YAI5BM,YAAYN,QAASO,SAASa,MAAK,YA5HnB,SAASpB,SACzBA,QAAQC,KAAK,kBAAmB,KA4H5BsC,CAAcvC,eACRmC,gBAAkB,kBACAhC,iBAAiBH,UAEzCJ,UAAUuB,OAAO,6BAA8BgB,iBAAiBf,MAAK,SAASC,KAAMC,IAChF1B,UAAUwC,oBAAoBpC,QAASqB,KAAMC,WA2B7CkB,CAAcxC,SAIlB2B,EAAEc,iBACFb,KAAKc,cAAcD"} \ No newline at end of file +{"version":3,"file":"toggle_contact_button.min.js","sources":["../src/toggle_contact_button.js"],"sourcesContent":["// This file is part of Moodle - http://moodle.org/\n//\n// Moodle is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// Moodle is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with Moodle. If not, see .\n\n/**\n * Module to add/remove contact using ajax.\n *\n * @module core_message/toggle_contact_button\n * @copyright 2016 Ryan Wyllie \n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\ndefine(['jquery', 'core/ajax', 'core/templates', 'core/notification', 'core/custom_interaction_events'],\n function($, Ajax, Templates, Notification, CustomEvents) {\n\n /**\n * Check the state of the element, if the current user is a contact or not.\n *\n * @method isContact\n * @param {object} element jQuery object for the button\n * @return {bool}\n */\n var isContact = function(element) {\n return element.attr('data-is-contact') == '1';\n };\n\n /**\n * Check the state of the element, if the current user has sent a contact request or not.\n *\n * @method isRequested\n * @param {object} element jQuery object for the button\n * @return {bool}\n */\n let isRequested = (element) => element.attr('data-is-requested') == '1';\n\n /**\n * Record that the user has sent a contact request.\n *\n * @method setContactRequested\n * @param {object} element jQuery object for the button\n */\n var setContactRequested = function(element) {\n element.attr('data-is-requested', '1');\n };\n\n /**\n * Record that the user is not a contact.\n *\n * @method setNotContact\n * @param {object} element jQuery object for the button\n */\n var setNotContact = function(element) {\n element.attr('data-is-contact', '0');\n };\n\n /**\n * Get the id for the user being viewed.\n *\n * @method getUserId\n * @param {object} element jQuery object for the button\n * @return {int}\n */\n var getUserId = function(element) {\n return element.attr('data-userid');\n };\n\n /**\n * Get the id for the logged in user.\n *\n * @method getUserId\n * @param {object} element jQuery object for the button\n * @return {int}\n */\n var getCurrentUserId = function(element) {\n return element.attr('data-currentuserid');\n };\n\n /**\n * Check whether a text label should be displayed or not.\n *\n * @method getUserId\n * @param {object} element jQuery object for the button\n * @return {int}\n */\n var displayTextLabel = function(element) {\n return element.attr('data-display-text-label') == '1';\n };\n\n /**\n * Check if this element is currently loading.\n *\n * @method isLoading\n * @param {object} element jQuery object for the button\n * @return {bool}\n */\n var isLoading = function(element) {\n return element.hasClass('loading') || element.attr('disabled');\n };\n\n /**\n * Sends an ajax request to the server and handles the element state\n * while the request is being performed.\n *\n * @method sendRequest\n * @param {object} element jQuery object for the button\n * @param {object} request Request hash to send\n * @return {object} jQuery promise\n */\n var sendRequest = function(element, request) {\n if (isLoading(element)) {\n return $.Deferred();\n }\n\n element.addClass('loading');\n element.attr('disabled', 'disabled');\n\n return Ajax.call([request])[0]\n .fail(Notification.exception)\n .always(function() {\n element.removeClass('loading');\n element.removeAttr('disabled');\n });\n };\n\n /**\n * Send a request to the server to add the current user as\n * a contact. The contents of the button are changed to the\n * remove contact button upon success.\n *\n * @method addContact\n * @param {object} element jQuery object for the button\n */\n var addContact = function(element) {\n if (isLoading(element)) {\n return;\n }\n\n var request = {\n methodname: 'core_message_create_contact_request',\n args: {\n userid: getCurrentUserId(element),\n requesteduserid: getUserId(element),\n }\n };\n sendRequest(element, request).done(function() {\n setContactRequested(element);\n element.addClass('disabled');\n const templateContext = {\n 'displaytextlabel': displayTextLabel(element)\n };\n Templates.render('message/contact_request_sent', templateContext).done(function(html, js) {\n Templates.replaceNodeContents(element, html, js);\n });\n });\n };\n\n /**\n * Send a request to the server to remove the current user as\n * a contact. The contents of the button are changed to the\n * add contact button upon success.\n *\n * @method removeContact\n * @param {object} element jQuery object for the button\n */\n var removeContact = function(element) {\n if (isLoading(element)) {\n return;\n }\n\n var request = {\n methodname: 'core_message_delete_contacts',\n args: {\n userids: [getUserId(element)],\n }\n };\n\n sendRequest(element, request).done(function() {\n setNotContact(element);\n const templateContext = {\n 'displaytextlabel': displayTextLabel(element)\n };\n Templates.render('message/add_contact_button', templateContext).done(function(html, js) {\n Templates.replaceNodeContents(element, html, js);\n });\n });\n };\n\n /**\n * Enhances the given element with a loading gif and event handles to make\n * ajax requests to add or remove a contact where appropriate.\n *\n * @public\n * @method enhance\n * @param {object} element jQuery object for the button\n */\n var enhance = function(element) {\n element = $(element);\n\n if (!element.children('.loading-icon').length && !isRequested(element)) {\n // Add the loading gif if it isn't already there.\n Templates.render('core/loading', {}).done(function(html, js) {\n element.append(html, js);\n });\n }\n\n CustomEvents.define(element, [CustomEvents.events.activate]);\n\n element.on(CustomEvents.events.activate, function(e, data) {\n if (isContact(element)) {\n removeContact(element);\n } else if (!isRequested(element)) {\n addContact(element);\n }\n e.preventDefault();\n data.originalEvent.preventDefault();\n });\n };\n\n return {\n enhance: enhance\n };\n});\n"],"names":["define","$","Ajax","Templates","Notification","CustomEvents","isRequested","element","attr","getUserId","getCurrentUserId","displayTextLabel","isLoading","hasClass","sendRequest","request","Deferred","addClass","call","fail","exception","always","removeClass","removeAttr","enhance","children","length","render","done","html","js","append","events","activate","on","e","data","isContact","methodname","args","userid","requesteduserid","setContactRequested","templateContext","replaceNodeContents","addContact","userids","setNotContact","removeContact","preventDefault","originalEvent"],"mappings":";;;;;;;AAsBAA,4CAAO,CAAC,SAAU,YAAa,iBAAkB,oBAAqB,mCAC9D,SAASC,EAAGC,KAAMC,UAAWC,aAAcC,kBAoB3CC,YAAeC,SAAiD,KAArCA,QAAQC,KAAK,yBA6BxCC,UAAY,SAASF,gBACdA,QAAQC,KAAK,gBAUpBE,iBAAmB,SAASH,gBACrBA,QAAQC,KAAK,uBAUpBG,iBAAmB,SAASJ,eACsB,KAA3CA,QAAQC,KAAK,4BAUpBI,UAAY,SAASL,gBACdA,QAAQM,SAAS,YAAcN,QAAQC,KAAK,aAYnDM,YAAc,SAASP,QAASQ,gBAC5BH,UAAUL,SACHN,EAAEe,YAGbT,QAAQU,SAAS,WACjBV,QAAQC,KAAK,WAAY,YAElBN,KAAKgB,KAAK,CAACH,UAAU,GACvBI,KAAKf,aAAagB,WAClBC,QAAO,WACJd,QAAQe,YAAY,WACpBf,QAAQgB,WAAW,uBAkGxB,CACHC,QAxBU,SAASjB,UACnBA,QAAUN,EAAEM,UAECkB,SAAS,iBAAiBC,QAAWpB,YAAYC,UAE1DJ,UAAUwB,OAAO,eAAgB,IAAIC,MAAK,SAASC,KAAMC,IACrDvB,QAAQwB,OAAOF,KAAMC,OAI7BzB,aAAaL,OAAOO,QAAS,CAACF,aAAa2B,OAAOC,WAElD1B,QAAQ2B,GAAG7B,aAAa2B,OAAOC,UAAU,SAASE,EAAGC,OAzLzC,SAAS7B,eACqB,KAAnCA,QAAQC,KAAK,mBAyLZ6B,CAAU9B,SAEFD,YAAYC,UA9Ef,SAASA,aAClBK,UAAUL,cAIVQ,QAAU,CACVuB,WAAY,sCACZC,KAAM,CACFC,OAAQ9B,iBAAiBH,SACzBkC,gBAAiBhC,UAAUF,WAGnCO,YAAYP,QAASQ,SAASa,MAAK,YAvGb,SAASrB,SAC/BA,QAAQC,KAAK,oBAAqB,KAuG9BkC,CAAoBnC,SACpBA,QAAQU,SAAS,kBACX0B,gBAAkB,kBACAhC,iBAAiBJ,UAEzCJ,UAAUwB,OAAO,+BAAgCgB,iBAAiBf,MAAK,SAASC,KAAMC,IAClF3B,UAAUyC,oBAAoBrC,QAASsB,KAAMC,WA4D7Ce,CAAWtC,SA/CH,SAASA,aACrBK,UAAUL,cAIVQ,QAAU,CACVuB,WAAY,+BACZC,KAAM,CACFO,QAAS,CAACrC,UAAUF,YAI5BO,YAAYP,QAASQ,SAASa,MAAK,YA7HnB,SAASrB,SACzBA,QAAQC,KAAK,kBAAmB,KA6H5BuC,CAAcxC,eACRoC,gBAAkB,kBACAhC,iBAAiBJ,UAEzCJ,UAAUwB,OAAO,6BAA8BgB,iBAAiBf,MAAK,SAASC,KAAMC,IAChF3B,UAAUyC,oBAAoBrC,QAASsB,KAAMC,WA2B7CkB,CAAczC,SAIlB4B,EAAEc,iBACFb,KAAKc,cAAcD"} \ No newline at end of file diff --git a/message/amd/src/toggle_contact_button.js b/message/amd/src/toggle_contact_button.js index 9ece821944f..47a825a942e 100644 --- a/message/amd/src/toggle_contact_button.js +++ b/message/amd/src/toggle_contact_button.js @@ -35,13 +35,22 @@ define(['jquery', 'core/ajax', 'core/templates', 'core/notification', 'core/cust }; /** - * Record that the user is a contact. + * Check the state of the element, if the current user has sent a contact request or not. * - * @method setContact + * @method isRequested + * @param {object} element jQuery object for the button + * @return {bool} + */ + let isRequested = (element) => element.attr('data-is-requested') == '1'; + + /** + * Record that the user has sent a contact request. + * + * @method setContactRequested * @param {object} element jQuery object for the button */ - var setContact = function(element) { - element.attr('data-is-contact', '1'); + var setContactRequested = function(element) { + element.attr('data-is-requested', '1'); }; /** @@ -144,11 +153,12 @@ define(['jquery', 'core/ajax', 'core/templates', 'core/notification', 'core/cust } }; sendRequest(element, request).done(function() { - setContact(element); + setContactRequested(element); + element.addClass('disabled'); const templateContext = { 'displaytextlabel': displayTextLabel(element) }; - Templates.render('message/remove_contact_button', templateContext).done(function(html, js) { + Templates.render('message/contact_request_sent', templateContext).done(function(html, js) { Templates.replaceNodeContents(element, html, js); }); }); @@ -196,7 +206,7 @@ define(['jquery', 'core/ajax', 'core/templates', 'core/notification', 'core/cust var enhance = function(element) { element = $(element); - if (!element.children('.loading-icon').length) { + if (!element.children('.loading-icon').length && !isRequested(element)) { // Add the loading gif if it isn't already there. Templates.render('core/loading', {}).done(function(html, js) { element.append(html, js); @@ -208,7 +218,7 @@ define(['jquery', 'core/ajax', 'core/templates', 'core/notification', 'core/cust element.on(CustomEvents.events.activate, function(e, data) { if (isContact(element)) { removeContact(element); - } else { + } else if (!isRequested(element)) { addContact(element); } e.preventDefault(); diff --git a/message/classes/helper.php b/message/classes/helper.php index 7e4634931c3..e3e1043eee2 100644 --- a/message/classes/helper.php +++ b/message/classes/helper.php @@ -309,14 +309,21 @@ class helper { * @param object $user User object. * @param bool $iscontact * @param bool $displaytextlabel Instructs whether to display a text label. + * @param bool $isrequested Whether the contact request is sent or not. * @return array */ - public static function togglecontact_link_params($user, $iscontact = false, bool $displaytextlabel = true) { + public static function togglecontact_link_params( + $user, + $iscontact = false, + bool $displaytextlabel = true, + bool $isrequested = false, + ) { global $USER; $params = array( 'data-currentuserid' => $USER->id, 'data-userid' => $user->id, 'data-is-contact' => $iscontact, + 'data-is-requested' => $isrequested, 'data-display-text-label' => $displaytextlabel, 'id' => 'toggle-contact-button', 'role' => 'button', diff --git a/message/templates/remove_contact_button.mustache b/message/templates/contact_request_sent.mustache similarity index 78% copy from message/templates/remove_contact_button.mustache copy to message/templates/contact_request_sent.mustache index 53800467ae8..6166223dfa9 100644 --- a/message/templates/remove_contact_button.mustache +++ b/message/templates/contact_request_sent.mustache @@ -1,27 +1,21 @@ {{! This file is part of Moodle - http://moodle.org/ - Moodle is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. - Moodle is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - You should have received a copy of the GNU General Public License along with Moodle. If not, see . }} {{! - @template core_message/remove_contact_button - + @template core_message/contact_request_sent Template for the contents of the add contact button on the user's profile page. - Context variables required for this template: * displaytextlabel - Whether to display text next to the action icon. - Example context (json): { "displaytextlabel": true @@ -29,11 +23,11 @@ }} {{^displaytextlabel}} - {{#pix}} t/removecontact, core, {{#str}} removefromyourcontacts, message {{/str}} {{/pix}} + {{#pix}} t/addcontact, core, {{#str}} contactrequestsent, message {{/str}} {{/pix}} {{/displaytextlabel}} {{#displaytextlabel}} - {{#pix}} t/removecontact, core {{/pix}} - {{#str}} removefromyourcontacts, message {{/str}} + {{#pix}} t/addcontact, core {{/pix}} + {{#str}} contactrequestsent, message {{/str}} {{/displaytextlabel}} {{> core/loading }} diff --git a/message/templates/remove_contact_button.mustache b/message/templates/remove_contact_button.mustache index 53800467ae8..d67c49fb804 100644 --- a/message/templates/remove_contact_button.mustache +++ b/message/templates/remove_contact_button.mustache @@ -15,6 +15,7 @@ along with Moodle. If not, see . }} {{! + @deprecated since Moodle 4.5 @template core_message/remove_contact_button Template for the contents of the add contact button on the user's profile page. diff --git a/message/tests/behat/message_drawer_manage_contacts.feature b/message/tests/behat/message_drawer_manage_contacts.feature index cd8cf1aef0f..7f50f91dc0a 100644 --- a/message/tests/behat/message_drawer_manage_contacts.feature +++ b/message/tests/behat/message_drawer_manage_contacts.feature @@ -59,6 +59,25 @@ Feature: Manage contacts And I click on "Contacts" "link" And I should see "Student 4" in the "//*[@data-section='contacts']" "xpath_element" + Scenario: Send a 'contact request' to someone to add a contact in the profile page + Given I am on the "student4" "user > profile" page logged in as student3 + And I should see "Add to contacts" + When I click on "Add to contacts" "link" + Then I should see "Contact request sent" + And I log out + And I am on the "student3" "user > profile" page logged in as student4 + And I should see "Waiting for your approval" + And I open messaging + And I click on "Contacts" "link" + And I click on "Requests" "link_or_button" + And I click on "Student 3 Would like to contact you" "link" + And I should see "Accept and add to contacts" + And I click on "Accept and add to contacts" "link_or_button" + And I should not see "Accept and add to contacts" + And I log out + And I am on the "student4" "user > profile" page logged in as student3 + And I should see "Remove from contacts" + Scenario: Decline a 'contact request' from someone Given I log in as "student1" Then I open messaging diff --git a/theme/boost/classes/output/core_renderer.php b/theme/boost/classes/output/core_renderer.php index b5811eef836..8e61bce3d9d 100644 --- a/theme/boost/classes/output/core_renderer.php +++ b/theme/boost/classes/output/core_renderer.php @@ -129,9 +129,42 @@ class core_renderer extends \core_renderer { if ($USER->id != $user->id) { $iscontact = \core_message\api::is_contact($USER->id, $user->id); - $contacttitle = $iscontact ? 'removefromyourcontacts' : 'addtoyourcontacts'; - $contacturlaction = $iscontact ? 'removecontact' : 'addcontact'; - $contactimage = $iscontact ? 'removecontact' : 'addcontact'; + $isrequested = \core_message\api::get_contact_requests_between_users($USER->id, $user->id); + $contacturlaction = ''; + $linkattributes = \core_message\helper::togglecontact_link_params( + $user, + $iscontact, + true, + !empty($isrequested), + ); + // If the user is not a contact. + if (!$iscontact) { + if ($isrequested) { + // We just need the first request. + $requests = array_shift($isrequested); + if ($requests->userid == $USER->id) { + // If the user has requested to be a contact. + $contacttitle = 'contactrequestsent'; + } else { + // If the user has been requested to be a contact. + $contacttitle = 'waitingforcontactaccept'; + } + $linkattributes = array_merge($linkattributes, [ + 'class' => 'disabled', + 'tabindex' => '-1', + ]); + } else { + // If the user is not a contact and has not requested to be a contact. + $contacttitle = 'addtoyourcontacts'; + $contacturlaction = 'addcontact'; + } + $contactimage = 'addcontact'; + } else { + // If the user is a contact. + $contacttitle = 'removefromyourcontacts'; + $contacturlaction = 'removecontact'; + $contactimage = 'removecontact'; + } $userbuttons['togglecontact'] = array( 'buttontype' => 'togglecontact', 'title' => get_string($contacttitle, 'message'), @@ -142,7 +175,7 @@ class core_renderer extends \core_renderer { 'sesskey' => sesskey()) ), 'image' => $contactimage, - 'linkattributes' => \core_message\helper::togglecontact_link_params($user, $iscontact), + 'linkattributes' => $linkattributes, 'page' => $this->page ); } -- 2.11.4.GIT