FEATURE: Allow group moderators to add/remove staff notes (#10252)

FEATURE: Allow group moderators to add/remove staff notes (#10252)

  • FEATURE: Allow group moderators to add/remove staff notes
diff --git a/app/assets/javascripts/discourse/app/lib/transform-post.js b/app/assets/javascripts/discourse/app/lib/transform-post.js
index 2f80877..e2dd44b 100644
--- a/app/assets/javascripts/discourse/app/lib/transform-post.js
+++ b/app/assets/javascripts/discourse/app/lib/transform-post.js
@@ -121,6 +121,7 @@ export default function transformPost(
     currentUser && (currentUser.id === post.user_id || currentUser.staff);
   postAtts.canArchiveTopic = !!details.can_archive_topic;
   postAtts.canCloseTopic = !!details.can_close_topic;
+  postAtts.canEditStaffNotes = !!details.can_edit_staff_notes;
   postAtts.canReplyAsNewTopic = !!details.can_reply_as_new_topic;
   postAtts.canReviewTopic = !!details.can_review_topic;
   postAtts.canPublishPage =
diff --git a/app/assets/javascripts/discourse/app/widgets/post-admin-menu.js b/app/assets/javascripts/discourse/app/widgets/post-admin-menu.js
index ec32910..5dbad8b 100644
--- a/app/assets/javascripts/discourse/app/widgets/post-admin-menu.js
+++ b/app/assets/javascripts/discourse/app/widgets/post-admin-menu.js
@@ -52,7 +52,7 @@ export function buildManageButtons(attrs, currentUser, siteSettings) {
     contents.push(buttonAtts);
   }
 
-  if (currentUser.staff) {
+  if (attrs.canEditStaffNotes) {
     if (attrs.noticeType) {
       contents.push({
         icon: "user-shield",
diff --git a/app/assets/javascripts/discourse/app/widgets/post-menu.js b/app/assets/javascripts/discourse/app/widgets/post-menu.js
index d014a67..b985948 100644
--- a/app/assets/javascripts/discourse/app/widgets/post-menu.js
+++ b/app/assets/javascripts/discourse/app/widgets/post-menu.js
@@ -332,7 +332,7 @@ registerButton(
 );
 
 registerButton("admin", attrs => {
-  if (!attrs.canManage && !attrs.canWiki) {
+  if (!attrs.canManage && !attrs.canWiki && !attrs.canEditStaffNotes) {
     return;
   }
   return {
diff --git a/app/assets/stylesheets/desktop/topic-post.scss b/app/assets/stylesheets/desktop/topic-post.scss
index 4a06c3b..dbb2c43 100644
--- a/app/assets/stylesheets/desktop/topic-post.scss
+++ b/app/assets/stylesheets/desktop/topic-post.scss
@@ -6,9 +6,11 @@
   margin-left: 0;
 }
 
-.topic-post:first-child {
-  nav.post-controls .post-admin-menu {
-    bottom: -125px;
+.staff {
+  .topic-post:first-child {
+    nav.post-controls .post-admin-menu {
+      bottom: -125px;
+    }
   }
 }
 
diff --git a/app/controllers/posts_controller.rb b/app/controllers/posts_controller.rb
index 63ef5bb..09cde3a 100644
--- a/app/controllers/posts_controller.rb
+++ b/app/controllers/posts_controller.rb
@@ -474,9 +474,8 @@ class PostsController < ApplicationController
   end
 
   def notice
-    raise Discourse::NotFound unless guardian.is_staff?
-
     post = find_post_from_params
+    raise Discourse::NotFound unless guardian.can_edit_staff_notes?(post.topic)
 
     if params[:notice].present?
       post.custom_fields[Post::NOTICE_TYPE] = Post.notices[:custom]
diff --git a/app/serializers/topic_view_details_serializer.rb b/app/serializers/topic_view_details_serializer.rb
index 8ea9611..e996722 100644
--- a/app/serializers/topic_view_details_serializer.rb
+++ b/app/serializers/topic_view_details_serializer.rb
@@ -18,7 +18,8 @@ class TopicViewDetailsSerializer < ApplicationSerializer
      :can_edit_tags,
      :can_publish_page,
      :can_close_topic,
-     :can_archive_topic]
+     :can_archive_topic,
+     :can_edit_staff_notes]
   end
 
   attributes(
@@ -136,13 +137,12 @@ class TopicViewDetailsSerializer < ApplicationSerializer
     !scope.can_edit?(object.topic) && scope.can_edit_tags?(object.topic)
   end
 
-  def include_can_close_topic?
-    scope.can_close_topic?(object.topic)
-  end
-
-  def include_can_archive_topic?
-    scope.can_archive_topic?(object.topic)
+  def can_perform_action_available_to_group_moderators?
+    @can_perform_action_available_to_group_moderators ||= scope.can_perform_action_available_to_group_moderators?(object.topic)
   end
+  alias :include_can_close_topic? :can_perform_action_available_to_group_moderators?
+  alias :include_can_archive_topic? :can_perform_action_available_to_group_moderators?
+  alias :include_can_edit_staff_notes? :can_perform_action_available_to_group_moderators?
 
   def include_can_publish_page?
     scope.can_publish_page?(object.topic)
diff --git a/lib/guardian/topic_guardian.rb b/lib/guardian/topic_guardian.rb
index e1ff410..5a0f9b5 100644
--- a/lib/guardian/topic_guardian.rb
+++ b/lib/guardian/topic_guardian.rb
@@ -216,5 +216,6 @@ module TopicGuardian
   end
   alias :can_archive_topic? :can_perform_action_available_to_group_moderators?
   alias :can_close_topic? :can_perform_action_available_to_group_moderators?
+  alias :can_edit_staff_notes? :can_perform_action_available_to_group_moderators?
 
 end
diff --git a/spec/components/guardian_spec.rb b/spec/components/guardian_spec.rb
index 3082c18..b200a24 100644
--- a/spec/components/guardian_spec.rb
+++ b/spec/components/guardian_spec.rb
@@ -1779,6 +1779,28 @@ describe Guardian do
     end
   end
 
+  context "can_edit_staff_notes?" do
+    it 'returns false with a nil object' do
+      expect(Guardian.new(user).can_edit_staff_notes?(nil)).to eq(false)
+    end
+
+    it 'returns true for a staff user' do
+      expect(Guardian.new(moderator).can_edit_staff_notes?(topic)).to eq(true)
+    end
+
+    it 'returns false for a regular user' do
+      expect(Guardian.new(user).can_edit_staff_notes?(topic)).to eq(false)
+    end
+
+    it 'returns true for a group member with reviewable status' do
+      SiteSetting.enable_category_group_moderation = true
+      group = Fabricate(:group)
+      GroupUser.create!(group_id: group.id, user_id: user.id)
+      topic.category.update!(reviewable_by_group_id: group.id)
+      expect(Guardian.new(user).can_edit_staff_notes?(topic)).to eq(true)
+    end
+  end
+
   context "can_create_topic?" do
     it 'returns true for staff user' do
       expect(Guardian.new(moderator).can_create_topic?(topic)).to eq(true)
diff --git a/spec/requests/posts_controller_spec.rb b/spec/requests/posts_controller_spec.rb
index 6ccc738..65d11dd 100644
--- a/spec/requests/posts_controller_spec.rb
+++ b/spec/requests/posts_controller_spec.rb
@@ -1795,11 +1795,9 @@ describe PostsController do
   end
 
   describe "#notice" do
-    before do
+    it 'can create and remove notices as a moderator' do
       sign_in(moderator)
-    end
 
-    it 'can create and remove notices' do
       put "/posts/#{public_post.id}/notice.json", params: { notice: "Hello *world*!\n\nhttps://github.com/discourse/discourse" }
 
       expect(response.status).to eq(200)
@@ -1815,6 +1813,52 @@ describe PostsController do
       expect(public_post.custom_fields[Post::NOTICE_TYPE]).to eq(nil)
       expect(public_post.custom_fields[Post::NOTICE_ARGS]).to eq(nil)
     end
+
+    describe 'group moderators' do
+      fab!(:group_user) { Fabricate(:group_user) }
+      let(:user) { group_user.user }
+      let(:group) { group_user.group }
+
+      before do
+        SiteSetting.enable_category_group_moderation = true
+        topic.category.update!(reviewable_by_group_id: group.id)
+
+        sign_in(user)
+      end
+
+      it 'can create and remove notices as a group moderator' do
+        put "/posts/#{public_post.id}/notice.json", params: { notice: "Hello *world*!\n\nhttps://github.com/discourse/discourse" }
+
+        expect(response.status).to eq(200)
+        public_post.reload
+        expect(public_post.custom_fields[Post::NOTICE_TYPE]).to eq(Post.notices[:custom])
+        expect(public_post.custom_fields[Post::NOTICE_ARGS]).to include('<p>Hello <em>world</em>!</p>')
+        expect(public_post.custom_fields[Post::NOTICE_ARGS]).not_to include('onebox')
+
+        put "/posts/#{public_post.id}/notice.json", params: { notice: nil }
+
+        expect(response.status).to eq(200)
+        public_post.reload
+        expect(public_post.custom_fields[Post::NOTICE_TYPE]).to eq(nil)

[... diff too long, it was truncated ...]

GitHub sha: 7ab56584

1 Like

This commit appears in #10252 which was merged by jbrw.

This commit has been mentioned on Discourse Meta. There might be relevant details there:

https://meta.discourse.org/t/category-group-review-moderation/116478/56