DEV: endpoint to reset community community-section (#21664)

In upcoming PRs, admins will be able to edit the Community section. We need an endpoint which allows resetting it to the default state.
This commit is contained in:
Krzysztof Kotlarek 2023-05-23 09:53:32 +10:00 committed by GitHub
parent 984a616204
commit 7ead8de232
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 148 additions and 14 deletions

View File

@ -50,6 +50,18 @@ class SidebarSectionsController < ApplicationController
render json: failed_json, status: 403
end
def reset
sidebar_section = SidebarSection.find_by(id: params[:id])
raise Discourse::InvalidParameters if !sidebar_section
@guardian.ensure_can_edit!(sidebar_section)
case sidebar_section.section_type
when "community"
sidebar_section.reset_community!
end
render_serialized(sidebar_section.reload, SidebarSectionSerializer)
end
def reorder
sidebar_section = SidebarSection.find_by(id: reorder_params["sidebar_section_id"])
@guardian.ensure_can_edit!(sidebar_section)

View File

@ -26,6 +26,33 @@ class SidebarSection < ActiveRecord::Base
scope :public_sections, -> { where("public") }
enum :section_type, { community: 0 }, scopes: false, suffix: true
def reset_community!
ActiveRecord::Base.transaction do
self.update!(title: "Community")
self.sidebar_section_links.destroy_all
community_urls =
SidebarUrl::COMMUNITY_SECTION_LINKS.map do |url_data|
"('#{url_data[:name]}', '#{url_data[:path]}', '#{url_data[:icon]}', '#{url_data[:segment]}', false, now(), now())"
end
result = DB.query <<~SQL
INSERT INTO sidebar_urls(name, value, icon, segment, external, created_at, updated_at)
VALUES #{community_urls.join(",")}
RETURNING sidebar_urls.id
SQL
sidebar_section_links =
result.map.with_index do |url, index|
"(-1, #{url.id}, 'SidebarUrl', #{self.id}, #{index}, now(), now())"
end
DB.query <<~SQL
INSERT INTO sidebar_section_links(user_id, linkable_id, linkable_type, sidebar_section_id, position, created_at, updated_at)
VALUES #{sidebar_section_links.join(",")}
SQL
end
end
private
def set_system_user_for_public_section

View File

@ -1,20 +1,47 @@
# frozen_string_literal: true
class SidebarUrl < ActiveRecord::Base
enum :segment, { primary: 0, secondary: 1 }, scopes: false, suffix: true
FULL_RELOAD_LINKS_REGEX = [%r{\A/my/[a-z_\-/]+\z}, %r{\A/safe-mode\z}]
MAX_ICON_LENGTH = 40
MAX_NAME_LENGTH = 80
MAX_VALUE_LENGTH = 200
COMMUNITY_SECTION_LINKS = [
{ name: "Everything", path: "/latest", icon: "layer-group", segment: "primary" },
{ name: "My Posts", path: "/my/activity", icon: "user", segment: "primary" },
{ name: "Review", path: "/review", icon: "flag", segment: "primary" },
{ name: "Admin", path: "/admin", icon: "wrench", segment: "primary" },
{ name: "Users", path: "/u", icon: "users", segment: "secondary" },
{ name: "About", path: "/about", icon: "info-circle", segment: "secondary" },
{ name: "FAQ", path: "/faq", icon: "question-circle", segment: "secondary" },
{ name: "Groups", path: "/g", icon: "user-friends", segment: "secondary" },
{ name: "Badges", path: "/badges", icon: "certificate", segment: "secondary" },
{
name: "Everything",
path: "/latest",
icon: "layer-group",
segment: SidebarUrl.segments["primary"],
},
{
name: "My Posts",
path: "/my/activity",
icon: "user",
segment: SidebarUrl.segments["primary"],
},
{ name: "Review", path: "/review", icon: "flag", segment: SidebarUrl.segments["primary"] },
{ name: "Admin", path: "/admin", icon: "wrench", segment: SidebarUrl.segments["primary"] },
{ name: "Users", path: "/u", icon: "users", segment: SidebarUrl.segments["secondary"] },
{
name: "About",
path: "/about",
icon: "info-circle",
segment: SidebarUrl.segments["secondary"],
},
{
name: "FAQ",
path: "/faq",
icon: "question-circle",
segment: SidebarUrl.segments["secondary"],
},
{ name: "Groups", path: "/g", icon: "user-friends", segment: SidebarUrl.segments["secondary"] },
{
name: "Badges",
path: "/badges",
icon: "certificate",
segment: SidebarUrl.segments["secondary"],
},
]
validates :icon, presence: true, length: { maximum: MAX_ICON_LENGTH }
@ -25,8 +52,6 @@ class SidebarUrl < ActiveRecord::Base
before_validation :remove_internal_hostname, :set_external
enum :segment, { primary: 0, secondary: 1 }, scopes: false, suffix: true
def path_validator
return true if !external?
raise ActionController::RoutingError.new("Not Found") if value !~ Discourse::Utils::URI_REGEXP

View File

@ -1594,6 +1594,7 @@ Discourse::Application.routes.draw do
resources :sidebar_sections, only: %i[index create update destroy]
post "/sidebar_sections/reorder" => "sidebar_sections#reorder"
put "/sidebar_sections/reset/:id" => "sidebar_sections#reset"
get "*url", to: "permalinks#show", constraints: PermalinkConstraint.new
end

View File

@ -2,16 +2,17 @@
module SidebarGuardian
def can_create_public_sidebar_section?
@user.staff?
@user.admin?
end
def can_edit_sidebar_section?(sidebar_section)
return @user.staff? if sidebar_section.public?
return @user.admin? if sidebar_section.public?
return @user.admin? if sidebar_section.section_type
is_my_own?(sidebar_section)
end
def can_delete_sidebar_section?(sidebar_section)
return @user.staff? if sidebar_section.public?
return @user.admin? if sidebar_section.public?
is_my_own?(sidebar_section)
end
end

View File

@ -3,10 +3,25 @@
RSpec.describe SidebarSection do
fab!(:user) { Fabricate(:user) }
fab!(:sidebar_section) { Fabricate(:sidebar_section, user: user) }
let(:community_section) do
SidebarSection.find_by(section_type: SidebarSection.section_types[:community])
end
it "uses system user for public sections" do
expect(sidebar_section.user_id).to eq(user.id)
sidebar_section.update!(public: true)
expect(sidebar_section.user_id).to eq(Discourse.system_user.id)
end
it "resets Community section to the default state" do
community_section.update!(title: "test")
community_section.sidebar_section_links.first.linkable.update!(name: "everything edited")
community_section.sidebar_section_links.last.destroy!
community_section.reset_community!
expect(community_section.reload.title).to eq("Community")
expect(community_section.sidebar_section_links.all.map { |link| link.linkable.name }).to eq(
["Everything", "My Posts", "Review", "Admin", "Users", "About", "FAQ", "Groups", "Badges"],
)
end
end

View File

@ -3,6 +3,7 @@
RSpec.describe SidebarSectionsController do
fab!(:user) { Fabricate(:user) }
fab!(:admin) { Fabricate(:admin) }
fab!(:moderator) { Fabricate(:moderator) }
describe "#index" do
fab!(:sidebar_section) { Fabricate(:sidebar_section, title: "private section", user: user) }
@ -100,6 +101,20 @@ RSpec.describe SidebarSectionsController do
expect(response.status).to eq(403)
end
it "does not allow moderator to create public section" do
sign_in(moderator)
post "/sidebar_sections.json",
params: {
title: "custom section",
public: true,
links: [
{ icon: "link", name: "categories", value: "/categories" },
{ icon: "address-book", name: "tags", value: "/tags" },
],
}
expect(response.status).to eq(403)
end
it "allows admin to create public section" do
sign_in(admin)
post "/sidebar_sections.json",
@ -334,5 +349,43 @@ RSpec.describe SidebarSectionsController do
expect(response.status).to eq(403)
end
it "doesn't allow moderator to delete public sidebar section" do
sign_in(moderator)
sidebar_section.update!(public: true)
delete "/sidebar_sections/#{sidebar_section.id}.json"
expect(response.status).to eq(403)
end
end
describe "#reset" do
let(:community_section) do
SidebarSection.find_by(section_type: SidebarSection.section_types[:community])
end
let(:everything_link) { community_section.sidebar_section_links.first }
it "doesn't allow user to reset community section" do
sign_in(user)
SidebarSection.any_instance.expects(:reset_community!).never
put "/sidebar_sections/reset/#{community_section.id}.json"
expect(response.status).to eq(403)
end
it "doesn't allow staff to reset community section" do
sign_in(moderator)
SidebarSection.any_instance.expects(:reset_community!).never
put "/sidebar_sections/reset/#{community_section.id}.json"
expect(response.status).to eq(403)
end
it "allows admins to reset community section to default" do
sign_in(admin)
SidebarSection.any_instance.expects(:reset_community!).once
put "/sidebar_sections/reset/#{community_section.id}.json"
expect(response.status).to eq(200)
expect(response.parsed_body["sidebar_section"]["id"]).to eq(community_section.id)
expect(response.parsed_body["sidebar_section"]["title"]).to eq(community_section.title)
end
end
end