Support for access locked forum categories

This commit is contained in:
Kira 2019-04-21 20:28:11 -07:00
parent 379020d6b2
commit 8698bd4e39
11 changed files with 207 additions and 17 deletions

View File

@ -0,0 +1,47 @@
class ForumCategoriesController < ApplicationController
respond_to :html
before_action :admin_only
def index
@forum_cats = ForumCategory.paginate(params[:page], limit: 50, order: "forum_categories.order ASC, forum_categories.id ASC")
@new_cat = ForumCategory.new
@user_levels = [['Anyone', 0]] + User.level_hash.to_a
end
def create
@cat = ForumCategory.create(category_params)
if @cat.valid?
ModAction.log(:forum_category_create, {forum_category_id: @cat.id})
flash[:notice] = "Category created"
else
flash[:notice] = @cat.errors.full_messages.join('; ')
end
redirect_to forum_categories_path
end
def destroy
@cat = ForumCategory.find(params[:id])
@cat.destroy
ModAction.log(:forum_category_delete, {forum_category_id: @cat.id})
respond_with(@cat)
end
def update
@cat = ForumCategory.find(params[:id])
@cat.update(category_params)
if @cat.valid?
ModAction.log(:forum_category_update, {forum_category_id: @cat.id})
flash[:notice] = "Category updated"
else
flash[:notice] = @cat.errors.full_messages.join('; ')
end
redirect_to forum_categories_path
end
private
def category_params
params.require(:forum_category).permit([:name, :description, :can_create, :can_reply, :can_view, :order])
end
end

View File

@ -8,11 +8,11 @@ class ForumPostsController < ApplicationController
def new
if params[:topic_id]
@forum_topic = ForumTopic.find(params[:topic_id])
raise User::PrivilegeError.new unless @forum_topic.visible?(CurrentUser.user)
raise User::PrivilegeError.new unless @forum_topic.visible?(CurrentUser.user) && @forum_topic.can_reply?(CurrentUser.user)
end
if params[:post_id]
quoted_post = ForumPost.find(params[:post_id])
raise User::PrivilegeError.new unless quoted_post.topic.visible?(CurrentUser.user)
raise User::PrivilegeError.new unless quoted_post.topic.visible?(CurrentUser.user) && quoted_post.topic.can_reply?(CurrentUser.user)
end
@forum_post = ForumPost.new_reply(params)
respond_with(@forum_post)

View File

@ -1,6 +1,6 @@
module ForumTopicsHelper
def forum_topic_category_select(object, field)
select(object, field, ForumTopic.reverse_category_mapping.to_a)
select(object, field, ForumCategory.reverse_mapping)
end
def available_min_user_levels

View File

@ -0,0 +1,22 @@
class ForumCategory < ApplicationRecord
has_many :forum_topics, -> { order(id: :desc) }
validates_uniqueness_of :name, case_sensitive: false
after_destroy :reassign_topics
def reassign_topics
ForumTopic.where(category: @cat.id).update_all(category_id: 0)
end
def can_create_within?(user = CurrentUser.user)
user.level >= can_create
end
def self.reverse_mapping
order(:cat_order).all.map { |rec| [rec.name, rec.id] }
end
def self.ordered_categories
order(:cat_order)
end
end

View File

@ -17,6 +17,7 @@ class ForumPost < ApplicationRecord
validate :validate_topic_is_unlocked
validate :topic_id_not_invalid
validate :topic_is_not_restricted, :on => :create
validate :category_allows_replies, on: :create
before_destroy :validate_topic_is_unlocked
after_save :delete_topic_if_original_post
after_update(:if => ->(rec) {rec.updater_id != rec.creator_id}) do |rec|
@ -158,6 +159,13 @@ class ForumPost < ApplicationRecord
end
end
def category_allows_replies
if topic && !topic.can_rely?(creator)
errors[:topic] << "does not allow replies"
return false
end
end
def editable_by?(user)
(creator_id == user.id || user.is_moderator?) && visible?(user)
end

View File

@ -13,15 +13,17 @@ class ForumTopic < ApplicationRecord
belongs_to_creator
belongs_to_updater
belongs_to :category, class_name: "ForumCategory", foreign_key: :category_id
has_many :posts, -> {order("forum_posts.id asc")}, :class_name => "ForumPost", :foreign_key => "topic_id", :dependent => :destroy
has_one :original_post, -> {order("forum_posts.id asc")}, class_name: "ForumPost", foreign_key: "topic_id", inverse_of: :topic
has_many :subscriptions, :class_name => "ForumSubscription"
before_validation :initialize_is_deleted, :on => :create
validates_presence_of :title, :creator_id
validates_associated :original_post
validates_inclusion_of :category_id, :in => CATEGORIES.keys
validates_associated :category
validates_inclusion_of :min_level, :in => MIN_LEVELS.values
validates :title, :length => {:maximum => 255}
validate :category_allows_creation, on: :create
accepts_nested_attributes_for :original_post
after_update :update_orignal_post
after_save(:if => ->(rec) {rec.is_locked? && rec.saved_change_to_is_locked?}) do |rec|
@ -32,21 +34,21 @@ class ForumTopic < ApplicationRecord
extend ActiveSupport::Concern
module ClassMethods
def categories
CATEGORIES.values
end
def reverse_category_mapping
@reverse_category_mapping ||= CATEGORIES.invert
end
def for_category_id(cid)
where(:category_id => cid)
end
end
def category_name
CATEGORIES[category_id]
return '(Unknown)' unless category
category.name
end
def category_allows_creation
if category && !category.can_create_within?(creator)
errors[:category] << "doesn't allow new topics"
return false
end
end
end
@ -56,7 +58,7 @@ class ForumTopic < ApplicationRecord
end
def permitted
where("min_level <= ?", CurrentUser.level)
where("min_level <= ?", CurrentUser.level).joins(:category).where('forum_categories.can_view <= ?', CurrentUser.level)
end
def sticky_first
@ -148,7 +150,11 @@ class ForumTopic < ApplicationRecord
end
def visible?(user)
user.level >= min_level
user.level >= min_level && user.level >= category.can_view
end
def can_reply?(user = CurrentUser.user)
user.level >= category.can_reply
end
def create_mod_action_for_delete

View File

@ -0,0 +1,44 @@
<div id="c-forum-categories">
<div id="a-index">
<p>Note: If any levels are set to "Member", logged-out users will not be able to use that category. Use "Anyone" as
the default.</p>
<div class="box-section">
<h4>New Category</h4>
<%= simple_form_for(@new_cat) do |f| %>
<%= f.input :name %>
<%= f.input :description %>
<%= f.input :can_create, collection: @user_levels %>
<%= f.input :can_reply, collection: @user_levels %>
<%= f.input :can_view, collection: @user_levels %>
<%= f.button :submit, "Create" %>
<% end %>
</div>
<% @forum_cats.each do |fp| %>
<div class="box-section">
<h4><%= fp.name %></h4>
<%= simple_form_for(fp) do |f| %>
<%= f.input :name %>
<%= f.input :description %>
<%= f.input :can_create, collection: @user_levels, selected: fp.can_create %>
<%= f.input :can_reply, collection: @user_levels, selected: fp.can_reply %>
<%= f.input :can_view, collection: @user_levels, selected: fp.can_view %>
<%= f.button :submit, "Update" %>
<% end %>
<%= link_to "Delete", forum_category_path(id: fp.id), method: :delete, remote: true, 'data-confirm': 'Are you sure you want to delete this category?' %>
</div>
<% end %>
<div id="paginator">
<%= numbered_paginator(@forum_cats) %>
</div>
</div>
</div>
<% content_for(:secondary_links) do %>
<menu>
<%= subnav_link_to "Forum Topics", forum_posts_path %>
<%= subnav_link_to "Help", help_page_path(id: 'forum') %>
</menu>
<% end %>

View File

@ -8,7 +8,7 @@
<% if CurrentUser.is_moderator? %>
<%= link_to "Mod+", forum_topics_path(:search => {:mod_only => true}) %>,
<% end %>
<%= ForumTopic::CATEGORIES.map {|id, name| link_to_unless_current(name, forum_topics_path(:search => {:category_id => id}))}.join(", ").html_safe %>
<%= ForumCategory.ordered_categories.all.map {|rec| link_to_unless_current(rec.name, forum_topics_path(:search => {:category_id => rec.id}))}.join(", ").html_safe %>
</p>
<%= render "listing", :forum_topics => @forum_topics %>

View File

@ -176,6 +176,7 @@ Rails.application.routes.draw do
end
resource :visit, :controller => "forum_topic_visits"
end
resources :forum_categories
resources :help_pages, controller: "help", path: "help"
resources :ip_bans
resources :upload_whitelists do

View File

@ -0,0 +1,12 @@
class CreateForumCategories < ActiveRecord::Migration[5.2]
def change
create_table :forum_categories do |t|
t.string :name, null: false
t.text :description
t.integer :cat_order
t.integer :can_view, default: 20, null: false
t.integer :can_create, default: 20, null: false
t.integer :can_reply, default: 20, null: false
end
end
end

View File

@ -878,6 +878,40 @@ CREATE SEQUENCE public.favorites_id_seq
ALTER SEQUENCE public.favorites_id_seq OWNED BY public.favorites.id;
--
-- Name: forum_categories; Type: TABLE; Schema: public; Owner: -
--
CREATE TABLE public.forum_categories (
id bigint NOT NULL,
name character varying NOT NULL,
description text,
cat_order integer,
can_view integer DEFAULT 20 NOT NULL,
can_create integer DEFAULT 20 NOT NULL,
can_reply integer DEFAULT 20 NOT NULL
);
--
-- Name: forum_categories_id_seq; Type: SEQUENCE; Schema: public; Owner: -
--
CREATE SEQUENCE public.forum_categories_id_seq
START WITH 1
INCREMENT BY 1
NO MINVALUE
NO MAXVALUE
CACHE 1;
--
-- Name: forum_categories_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: -
--
ALTER SEQUENCE public.forum_categories_id_seq OWNED BY public.forum_categories.id;
--
-- Name: forum_post_votes; Type: TABLE; Schema: public; Owner: -
--
@ -2636,6 +2670,13 @@ ALTER TABLE ONLY public.favorite_groups ALTER COLUMN id SET DEFAULT nextval('pub
ALTER TABLE ONLY public.favorites ALTER COLUMN id SET DEFAULT nextval('public.favorites_id_seq'::regclass);
--
-- Name: forum_categories id; Type: DEFAULT; Schema: public; Owner: -
--
ALTER TABLE ONLY public.forum_categories ALTER COLUMN id SET DEFAULT nextval('public.forum_categories_id_seq'::regclass);
--
-- Name: forum_post_votes id; Type: DEFAULT; Schema: public; Owner: -
--
@ -3099,6 +3140,14 @@ ALTER TABLE ONLY public.favorites
ADD CONSTRAINT favorites_pkey PRIMARY KEY (id);
--
-- Name: forum_categories forum_categories_pkey; Type: CONSTRAINT; Schema: public; Owner: -
--
ALTER TABLE ONLY public.forum_categories
ADD CONSTRAINT forum_categories_pkey PRIMARY KEY (id);
--
-- Name: forum_post_votes forum_post_votes_pkey; Type: CONSTRAINT; Schema: public; Owner: -
--
@ -4760,6 +4809,7 @@ INSERT INTO "schema_migrations" (version) VALUES
('20190403174011'),
('20190409195837'),
('20190410022203'),
('20190413055451');
('20190413055451'),
('20190418093745');