FEATURE: list category moderators on the about page (#7916)

https://meta.discourse.org/t/category-group-review-moderation/116478?u=osama
This commit is contained in:
Osama Sayegh 2019-07-31 16:46:58 +03:00 committed by GitHub
parent 8a6ee09008
commit 13e74151a9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 112 additions and 2 deletions

View File

@ -16,6 +16,14 @@ export default Discourse.Route.extend({
});
result.about.admins = activeAdmins;
result.about.moderators = activeModerators;
const { category_moderators: categoryModerators } = result.about;
if (categoryModerators && categoryModerators.length) {
categoryModerators.forEach((obj, index) => {
const category = this.site.categories.findBy("id", obj.category_id);
result.about.category_moderators[index].category = category;
});
}
return result.about;
});
},

View File

@ -57,6 +57,19 @@
connectorTagName='section'
args=(hash model=model)}}
{{#if model.category_moderators.length}}
{{#each model.category_moderators as |cm|}}
<section class='about category-moderators'>
<h3>{{category-link cm.category}}{{i18n "about.moderators"}}</h3>
<div class='users'>
{{#each cm.moderators as |m|}}
{{user-info user=m}}
{{/each}}
</div>
<div class='clearfix'></div>
</section>
{{/each}}
{{/if}}
<section class='about stats'>
<h3>{{d-icon "far-chart-bar"}} {{i18n 'about.stats'}}</h3>

View File

@ -4,9 +4,14 @@
max-width: 700px;
.about-page & {
max-width: unset;
section:not(.admins):not(.moderators) {
section:not(.admins):not(.moderators):not(.category-moderators) {
max-width: 700px;
}
.about.category-moderators {
.badge-wrapper.bullet .badge-category {
color: $primary;
}
}
}
.mobile-view & {
font-size: $font-0;

View File

@ -11,7 +11,7 @@ class AboutController < ApplicationController
def index
return redirect_to path('/login') if SiteSetting.login_required? && current_user.nil?
@about = About.new
@about = About.new(current_user)
@title = "#{I18n.t("js.about.simple_title")} - #{SiteSetting.title}"
respond_to do |format|
format.html do

View File

@ -1,6 +1,16 @@
# frozen_string_literal: true
class About
class CategoryMods
include ActiveModel::Serialization
attr_reader :category_id, :moderators
def initialize(category_id, moderators)
@category_id = category_id
@moderators = moderators
end
end
include ActiveModel::Serialization
include StatsCacheable
@ -15,6 +25,10 @@ class About
About.new.stats
end
def initialize(user = nil)
@user = user
end
def version
Discourse::VERSION::STRING
end
@ -66,4 +80,24 @@ class About
}
end
def category_moderators
category_ids = Guardian.new(@user).allowed_category_ids
return [] if category_ids.blank?
results = DB.query(<<~SQL, category_ids: category_ids)
SELECT c.id category_id, array_agg(gu.user_id) user_ids
FROM categories c
JOIN group_users gu
ON gu.group_id = reviewable_by_group_id
WHERE c.id IN (:category_ids)
GROUP BY c.id
SQL
moderators = {}
User.where(id: results.map(&:user_ids).flatten).each do |user|
moderators[user.id] = user
end
moderators
results.map do |row|
CategoryMods.new(row.category_id, row.user_ids.map { |id| moderators[id] })
end
end
end

View File

@ -6,8 +6,15 @@ class AboutSerializer < ApplicationSerializer
attributes :title, :last_seen_at
end
class AboutCategoryModsSerializer < ApplicationSerializer
attributes :category_id
has_many :moderators, serializer: UserAboutSerializer, embed: :objects
end
has_many :moderators, serializer: UserAboutSerializer, embed: :objects
has_many :admins, serializer: UserAboutSerializer, embed: :objects
has_many :category_moderators, serializer: AboutCategoryModsSerializer, embed: :objects
attributes :stats,
:description,

View File

@ -274,6 +274,7 @@ en:
stats: "Site Statistics"
our_admins: "Our Admins"
our_moderators: "Our Moderators"
moderators: "Moderators"
stat:
all_time: "All Time"
last_7_days: "Last 7"

View File

@ -8,4 +8,46 @@ describe About do
include_examples 'stats cachable'
end
describe "#category_moderators" do
let(:user) { Fabricate(:user) }
let(:public_cat_moderator) { Fabricate(:user) }
let(:private_cat_moderator) { Fabricate(:user) }
let(:common_moderator) { Fabricate(:user) }
let(:public_group) do
group = Fabricate(:public_group)
group.add(public_cat_moderator)
group.add(common_moderator)
group
end
let(:private_group) do
group = Fabricate(:group)
group.add(private_cat_moderator)
group.add(common_moderator)
group
end
let!(:public_cat) { Fabricate(:category, reviewable_by_group: public_group) }
let!(:private_cat) { Fabricate(:private_category, group: private_group, reviewable_by_group: private_group) }
it "lists moderators of the category that the current user can see" do
results = About.new(private_cat_moderator).category_moderators
expect(results.map(&:category_id)).to contain_exactly(public_cat.id, private_cat.id)
expect(results.map(&:moderators).flatten.map(&:id).uniq).to contain_exactly(
public_cat_moderator.id,
common_moderator.id,
private_cat_moderator.id
)
[public_cat_moderator, user, nil].each do |u|
results = About.new(u).category_moderators
expect(results.map(&:category_id)).to contain_exactly(public_cat.id)
expect(results.map(&:moderators).flatten.map(&:id)).to contain_exactly(
public_cat_moderator.id,
common_moderator.id
)
end
end
end
end