diff --git a/.rubocop.yml b/.rubocop.yml index 8a110a22b..17c65164a 100644 --- a/.rubocop.yml +++ b/.rubocop.yml @@ -15,7 +15,7 @@ RSpec/DescribeClass: AllCops: Exclude: - db/schema.rb - TargetRubyVersion: 2.3.4 + TargetRubyVersion: 2.5.0 Naming/AccessorMethodName: Description: Check the naming of accessor methods for get_/set_. diff --git a/app/assets/stylesheets/minimal.scss b/app/assets/stylesheets/minimal.scss index a26fd21ce..fa1804397 100644 --- a/app/assets/stylesheets/minimal.scss +++ b/app/assets/stylesheets/minimal.scss @@ -24,6 +24,7 @@ @import 'live'; @import 'delete-confirm'; @import 'preact/onboarding-modal'; +@import 'tag-edit'; @import 'ltags/LiquidTags'; diff --git a/app/assets/stylesheets/tag-edit.scss b/app/assets/stylesheets/tag-edit.scss new file mode 100644 index 000000000..7b00877cf --- /dev/null +++ b/app/assets/stylesheets/tag-edit.scss @@ -0,0 +1,39 @@ + .tag-edit-form { + margin-bottom: 5em; + display: flex; + align-items: center; + justify-content: center; + } + .tag-edit-container { + margin-top: 5em; + max-width: 50%; + } + .tag-form-text-field { + height: 2em; + width: 20.5em; + text-align: left; + overflow-wrap: break-word; + font-size: 1em; + } + .tag-area-text { + height: 4em; + } + .tag-edit-submit { + margin-top: 5px; + background-color: #557de8; + color: white; + padding: 15px 20px; + text-align: center; + font-size: 16px; + } + .tag-edit-flash-success { + color: white; + background: #388019; + padding: 15px; + } + .tag-edit-flash-error { + color: white; + background: #ff0000; + padding: 15px 15px 15px 40px; + } + diff --git a/app/controllers/admin/tags_controller.rb b/app/controllers/admin/tags_controller.rb index f9306845d..9fe795169 100644 --- a/app/controllers/admin/tags_controller.rb +++ b/app/controllers/admin/tags_controller.rb @@ -1,19 +1,46 @@ module Admin class TagsController < Admin::ApplicationController - # To customize the behavior of this controller, - # simply overwrite any of the RESTful actions. For example: - # - # def index - # super - # @resources = Tag.all.paginate(10, params[:page]) - # end + def update + @tag = Tag.find(params[:id]) + if @tag.update(tag_params) && @tag.errors.messages.blank? && handle_moderators + flash[:notice] = "Tag successfully updated" + redirect_to "/admin/tags/#{@tag.id}" + else + render :new, locals: { page: Administrate::Page::Form.new(dashboard, @tag) } + end + end - # Define a custom finder by overriding the `find_resource` method: - # def find_resource(param) - # Tag.find_by!(slug: param) - # end + private - # See https://administrate-docs.herokuapp.com/customizing_controller_actions - # for more information + def convert_empty_string_to_nil + # Andy: nil plays nicely with our hex colors, whereas empty string doesn't + params[:tag][:text_color_hex] = nil if params[:tag][:text_color_hex] == "" + params[:tag][:bg_color_hex] = nil if params[:tag][:bg_color_hex] == "" + end + + def tag_params + accessible = %i[ + name + supported + alias_for + wiki_body_markdown + rules_markdown + short_summary + requires_approval + submission_template + submission_rules_headsup + pretty_name + bg_color_hex + text_color_hex + keywords_for_search + ] + convert_empty_string_to_nil + params.require(:tag).permit(accessible) + end + + def handle_moderators + user_ids = params[:tag][:tag_moderator_ids].split(",") + UserRoleService.new(nil).update_tag_moderators(user_ids.sort, @tag) + end end end diff --git a/app/controllers/admin/users_controller.rb b/app/controllers/admin/users_controller.rb index 4ca157c2c..c57a88f43 100644 --- a/app/controllers/admin/users_controller.rb +++ b/app/controllers/admin/users_controller.rb @@ -7,17 +7,12 @@ module Admin flash[:notice] = "User successfully updated" redirect_to "/admin/users/#{params[:id]}" else - render_with_errors(user) + render :new, locals: { page: Administrate::Page::Form.new(dashboard, user) } end end private - def render_with_errors(user) - flash.now[:notice] = user.errors.full_messages - render :new, locals: { page: Administrate::Page::Form.new(dashboard, user) } - end - def user_params accessible = %i[name email diff --git a/app/controllers/tags_controller.rb b/app/controllers/tags_controller.rb index b57714500..c25360b38 100644 --- a/app/controllers/tags_controller.rb +++ b/app/controllers/tags_controller.rb @@ -5,4 +5,46 @@ class TagsController < ApplicationController @tags_index = true @tags = Tag.all.order("hotness_score DESC").first(100) end + + def edit + @tag = Tag.find_by!(name: params[:tag]) + check_authorization + end + + def update + @tag = Tag.find_by!(id: params[:id]) + check_authorization + if @tag.errors.messages.blank? && @tag.update(tag_params) + flash[:success] = "Tag successfully updated! 👍 " + redirect_to "/t/#{@tag.name}/edit" + else + flash[:error] = @tag.errors.full_messages + render :edit + end + end + + private + + def check_authorization + raise unless current_user.has_role?(:super_admin) || current_user.has_role?(:tag_moderator, @tag) + end + + def convert_empty_string_to_nil + # Andy: nil plays nicely with our hex colors, whereas empty string doesn't + params[:tag][:text_color_hex] = nil if params[:tag][:text_color_hex] == "" + params[:tag][:bg_color_hex] = nil if params[:tag][:bg_color_hex] == "" + end + + def tag_params + accessible = %i[ + wiki_body_markdown + rules_markdown + short_summary + pretty_name + bg_color_hex + text_color_hex + ] + convert_empty_string_to_nil + params.require(:tag).permit(accessible) + end end diff --git a/app/dashboards/tag_dashboard.rb b/app/dashboards/tag_dashboard.rb index c4fd97bc4..3ee998001 100644 --- a/app/dashboards/tag_dashboard.rb +++ b/app/dashboards/tag_dashboard.rb @@ -11,6 +11,7 @@ class TagDashboard < Administrate::BaseDashboard id: Field::Number, name: Field::String, supported: Field::Boolean, + tag_moderator_ids: TagModeratorsField, wiki_body_markdown: Field::Text, wiki_body_html: Field::Text, rules_markdown: Field::Text, @@ -48,6 +49,7 @@ class TagDashboard < Administrate::BaseDashboard :id, :name, :supported, + :tag_moderator_ids, :alias_for, :wiki_body_markdown, :wiki_body_html, @@ -71,6 +73,7 @@ class TagDashboard < Administrate::BaseDashboard FORM_ATTRIBUTES = [ :name, :supported, + :tag_moderator_ids, :alias_for, :wiki_body_markdown, :rules_markdown, diff --git a/app/fields/tag_moderators_field.rb b/app/fields/tag_moderators_field.rb new file mode 100644 index 000000000..9ef208eb6 --- /dev/null +++ b/app/fields/tag_moderators_field.rb @@ -0,0 +1,7 @@ +require "administrate/field/base" + +class TagModeratorsField < Administrate::Field::Base + def to_s + data.join(",") + end +end diff --git a/app/models/comment.rb b/app/models/comment.rb index 99ade3413..2d0c57434 100644 --- a/app/models/comment.rb +++ b/app/models/comment.rb @@ -244,8 +244,7 @@ class Comment < ApplicationRecord end def wrap_timestamps_if_video_present! - return if commentable_type == 'PodcastEpisode' - return unless commentable.video.present? + return unless commentable_type != "PodcastEpisode" && commentable.video.present? self.processed_html = processed_html.gsub(/(([0-9]:)?)(([0-5][0-9]|[0-9])?):[0-5][0-9]/) {|s| "#{s}"} end diff --git a/app/models/role.rb b/app/models/role.rb index 8df406c67..ab7e4e1ec 100644 --- a/app/models/role.rb +++ b/app/models/role.rb @@ -13,7 +13,7 @@ class Role < ApplicationRecord in: %w( super_admin admin - moderator + tag_moderator trusted banned warned diff --git a/app/models/tag.rb b/app/models/tag.rb index 03a31d389..af8c1b253 100644 --- a/app/models/tag.rb +++ b/app/models/tag.rb @@ -1,12 +1,14 @@ class Tag < ActsAsTaggableOn::Tag acts_as_followable + resourcify mount_uploader :profile_image, ProfileImageUploader mount_uploader :social_image, ProfileImageUploader - validates :text_color_hex, format: /\A#([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})\z/, allow_blank: true - validates :bg_color_hex, format: /\A#([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})\z/, allow_blank: true - + validates :text_color_hex, + format: /\A#([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})\z/, allow_nil: true + validates :bg_color_hex, + format: /\A#([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})\z/, allow_nil: true validate :validate_alias before_validation :evaluate_markdown @@ -18,6 +20,10 @@ class Tag < ActsAsTaggableOn::Tag submission_template.gsub("PARAM_0", param_0) end + def tag_moderator_ids + User.with_role(:tag_moderator, self).map(&:id).sort + end + private def evaluate_markdown @@ -49,7 +55,7 @@ class Tag < ActsAsTaggableOn::Tag end def pound_it - text_color_hex&.prepend("#") unless text_color_hex&.starts_with?("#") - bg_color_hex&.prepend("#") unless bg_color_hex&.starts_with?("#") + text_color_hex&.prepend("#") unless text_color_hex&.starts_with?("#") || text_color_hex.blank? + bg_color_hex&.prepend("#") unless bg_color_hex&.starts_with?("#") || bg_color_hex.blank? end end diff --git a/app/services/user_role_service.rb b/app/services/user_role_service.rb index 459fea92a..8c0fd2627 100644 --- a/app/services/user_role_service.rb +++ b/app/services/user_role_service.rb @@ -1,8 +1,6 @@ class UserRoleService def initialize(user) @user = user - @bannable = nil - @warnable = nil end def check_for_roles(params) @@ -15,6 +13,22 @@ class UserRoleService new_roles?(params) end + def update_tag_moderators(user_ids, tag) + users = user_ids.map { |id| User.find(id) } + # Andy: Don't have to worry about comparing old and new values. + tag.tag_moderator_ids.each do |id| + User.find(id).remove_role(:tag_moderator, tag) + puts "removed #{id}" + end + users.each do |user| + user.add_role(:tag_moderator, tag) + puts "added #{user.id}" + end + rescue ActiveRecord::RecordNotFound + tag.errors[:moderator_ids] << ": user #{id} was not found" + return false + end + private def new_roles?(params) @@ -32,29 +46,22 @@ class UserRoleService def bannable?(params) if params[:banned] == "0" && !params[:reason_for_ban].blank? @user.errors[:banned] << "was not checked but had the reason filled out" - @bannable = false elsif params[:banned] == "1" && params[:reason_for_ban].blank? @user.errors[:reason_for_ban] << "can't be blank if banned is checked" - @bannable = false elsif params[:banned] == "1" ban(params[:reason_for_ban]) - @bannable = true else unban - @bannable = true end end def warnable?(params) if params[:warned] == "0" && !params[:reason_for_warning].blank? @user.errors[:warned] << "was not checked but had the reason filled out" - @warnable = false elsif params[:warned] == "1" && params[:reason_for_warning].blank? @user.errors[:reason_for_warning] << "can't be blank if warned is checked" - @warnable = false elsif params[:warned] == "1" give_warning(params[:reason_for_warning]) - @warnable = true end end @@ -80,10 +87,16 @@ class UserRoleService @user.remove_role :banned end + # Andy: Only give warning method b/c no need to remove warnings def give_warning(content) @user.add_role :warned create_or_update_note("warned", content) end - # Andy: no need to remove a warning from a user + + def validate_user_ids(user_ids) + user_ids.each do |id| + User.find(id) + end + end end diff --git a/app/views/fields/tag_moderators_field/_form.html.erb b/app/views/fields/tag_moderators_field/_form.html.erb new file mode 100644 index 000000000..4c5afbb01 --- /dev/null +++ b/app/views/fields/tag_moderators_field/_form.html.erb @@ -0,0 +1,7 @@ +
1,2,3
++ <%= flash[:success] %> +
+ <% elsif flash[:error] %> +