diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb index 1eced5531a2..275c6ee6560 100644 --- a/app/controllers/application_controller.rb +++ b/app/controllers/application_controller.rb @@ -269,13 +269,17 @@ def access_denied(options ={}) def admin_only_access_denied respond_to do |format| format.html do - flash[:error] = ts("Sorry, only an authorized admin can access the page you were trying to reach.") + flash[:error] = t("admin.access.page_access_denied") redirect_to root_path end format.json do - errors = [ts("Sorry, only an authorized admin can do that.")] + errors = [t("admin.access.action_access_denied")] render json: { errors: errors }, status: :forbidden end + format.js do + flash[:error] = t("admin.access.page_access_denied") + render js: "window.location.href = '#{root_path}';" + end end end diff --git a/app/controllers/archive_faqs_controller.rb b/app/controllers/archive_faqs_controller.rb index b97130558f8..8a8a8817ba2 100644 --- a/app/controllers/archive_faqs_controller.rb +++ b/app/controllers/archive_faqs_controller.rb @@ -1,14 +1,14 @@ class ArchiveFaqsController < ApplicationController - before_action :admin_only, except: [:index, :show] before_action :set_locale before_action :validate_locale, if: :logged_in_as_admin? before_action :require_language_id + before_action :default_locale_only, only: [:new, :create, :manage, :update_positions, :confirm_delete, :destroy] around_action :with_locale # GET /archive_faqs def index - @archive_faqs = ArchiveFaq.order('position ASC') + @archive_faqs = ArchiveFaq.order("position ASC") unless logged_in_as_admin? @archive_faqs = @archive_faqs.with_translations(I18n.locale) end @@ -40,6 +40,7 @@ def show end protected + def build_questions notice = "" num_to_build = params["num_questions"] ? params["num_questions"].to_i : @archive_faq.questions.count @@ -59,9 +60,10 @@ def build_questions end public + # GET /archive_faqs/new def new - @archive_faq = ArchiveFaq.new + @archive_faq = authorize ArchiveFaq.new 1.times { @archive_faq.questions.build(attributes: { question: "This is a temporary question", content: "This is temporary content", anchor: "ThisIsATemporaryAnchor"})} respond_to do |format| format.html # new.html.erb @@ -70,32 +72,34 @@ def new # GET /archive_faqs/1/edit def edit - @archive_faq = ArchiveFaq.find_by(slug: params[:id]) + @archive_faq = authorize ArchiveFaq.find_by(slug: params[:id]) + authorize :archive_faq, :full_access? if default_locale? build_questions end # GET /archive_faqs/manage def manage - @archive_faqs = ArchiveFaq.order('position ASC') + @archive_faqs = authorize ArchiveFaq.order("position ASC") end # POST /archive_faqs def create - @archive_faq = ArchiveFaq.new(archive_faq_params) - if @archive_faq.save - flash[:notice] = 'ArchiveFaq was successfully created.' - redirect_to(@archive_faq) - else - render action: "new" - end + @archive_faq = authorize ArchiveFaq.new(archive_faq_params) + if @archive_faq.save + flash[:notice] = t(".success") + redirect_to(@archive_faq) + else + render action: "new" + end end # PUT /archive_faqs/1 def update - @archive_faq = ArchiveFaq.find_by(slug: params[:id]) + @archive_faq = authorize ArchiveFaq.find_by(slug: params[:id]) + authorize :archive_faq, :full_access? if default_locale? if @archive_faq.update(archive_faq_params) - flash[:notice] = 'ArchiveFaq was successfully updated.' + flash[:notice] = t(".success") redirect_to(@archive_faq) else render action: "edit" @@ -104,9 +108,10 @@ def update # reorder FAQs def update_positions + authorize :archive_faq if params[:archive_faqs] @archive_faqs = ArchiveFaq.reorder_list(params[:archive_faqs]) - flash[:notice] = ts("Archive FAQs order was successfully updated.") + flash[:notice] = t(".success") elsif params[:archive_faq] params[:archive_faq].each_with_index do |id, position| ArchiveFaq.update(id, position: position + 1) @@ -149,6 +154,13 @@ def require_language_id redirect_to url_for(request.query_parameters.merge(language_id: @i18n_locale.to_s)) end + def default_locale_only + return if default_locale? + + flash[:error] = t("archive_faqs.default_locale_only") + redirect_to archive_faqs_path + end + # Setting I18n.locale directly is not thread safe def with_locale I18n.with_locale(@i18n_locale) { yield } @@ -156,18 +168,22 @@ def with_locale # GET /archive_faqs/1/confirm_delete def confirm_delete - @archive_faq = ArchiveFaq.find_by(slug: params[:id]) + @archive_faq = authorize ArchiveFaq.find_by(slug: params[:id]) end # DELETE /archive_faqs/1 def destroy - @archive_faq = ArchiveFaq.find_by(slug: params[:id]) + @archive_faq = authorize ArchiveFaq.find_by(slug: params[:id]) @archive_faq.destroy redirect_to(archive_faqs_path) end private + def default_locale? + @i18n_locale.to_s == I18n.default_locale.to_s + end + def archive_faq_params params.require(:archive_faq).permit( :title, diff --git a/app/controllers/inbox_controller.rb b/app/controllers/inbox_controller.rb index fb7a710f7e6..4191691060a 100644 --- a/app/controllers/inbox_controller.rb +++ b/app/controllers/inbox_controller.rb @@ -2,7 +2,7 @@ class InboxController < ApplicationController include BlockHelper before_action :load_user - before_action :check_ownership + before_action :check_ownership_or_admin before_action :load_commentable, only: :reply before_action :check_blocked, only: :reply @@ -13,6 +13,7 @@ def load_user end def show + authorize InboxComment if logged_in_as_admin? @inbox_total = @user.inbox_comments.with_bad_comments_removed.count @unread = @user.inbox_comments.with_bad_comments_removed.count_unread @filters = filter_params[:filters] || {} @@ -30,6 +31,7 @@ def reply end def update + authorize InboxComment if logged_in_as_admin? begin @inbox_comments = InboxComment.find(params[:inbox_comments]) if params[:read] diff --git a/app/controllers/known_issues_controller.rb b/app/controllers/known_issues_controller.rb index 4f6bbe6cd30..793daff088e 100644 --- a/app/controllers/known_issues_controller.rb +++ b/app/controllers/known_issues_controller.rb @@ -1,5 +1,4 @@ class KnownIssuesController < ApplicationController - before_action :admin_only, except: [:index] # GET /known_issues @@ -9,25 +8,24 @@ def index # GET /known_issues/1 def show - @known_issue = KnownIssue.find(params[:id]) + @known_issue = authorize KnownIssue.find(params[:id]) end # GET /known_issues/new def new - @known_issue = KnownIssue.new + @known_issue = authorize KnownIssue.new end # GET /known_issues/1/edit def edit - @known_issue = KnownIssue.find(params[:id]) + @known_issue = authorize KnownIssue.find(params[:id]) end # POST /known_issues def create - @known_issue = KnownIssue.new(known_issue_params) - + @known_issue = authorize KnownIssue.new(known_issue_params) if @known_issue.save - flash[:notice] = 'Known issue was successfully created.' + flash[:notice] = "Known issue was successfully created." redirect_to(@known_issue) else render action: "new" @@ -36,10 +34,9 @@ def create # PUT /known_issues/1 def update - @known_issue = KnownIssue.find(params[:id]) - + @known_issue = authorize KnownIssue.find(params[:id]) if @known_issue.update(known_issue_params) - flash[:notice] = 'Known issue was successfully updated.' + flash[:notice] = "Known issue was successfully updated." redirect_to(@known_issue) else render action: "edit" @@ -48,7 +45,7 @@ def update # DELETE /known_issues/1 def destroy - @known_issue = KnownIssue.find(params[:id]) + @known_issue = authorize KnownIssue.find(params[:id]) @known_issue.destroy redirect_to(known_issues_path) end diff --git a/app/controllers/questions_controller.rb b/app/controllers/questions_controller.rb index a00ef266972..4c82934805f 100644 --- a/app/controllers/questions_controller.rb +++ b/app/controllers/questions_controller.rb @@ -1,33 +1,34 @@ class QuestionsController < ApplicationController - before_action :load_archive_faq, except: [:index, :update_positions] + before_action :load_archive_faq, except: :update_positions # GET /archive_faq/:archive_faq_id/questions/manage def manage - @questions = @archive_faq.questions.order('position') + authorize :archive_faq, :full_access? + @questions = @archive_faq.questions.order("position") end # fetch archive_faq these questions belong to from db def load_archive_faq - @archive_faq = ArchiveFaq.find_by_slug(params[:archive_faq_id]) + @archive_faq = ArchiveFaq.find_by(slug: params[:archive_faq_id]) unless @archive_faq.present? - flash[:error] = ts("Sorry, we couldn't find the FAQ you were looking for." - ) + flash[:error] = t("questions.not_found") redirect_to root_path and return end end # Update the position number of questions within a archive_faq def update_positions + authorize :archive_faq, :full_access? if params[:questions] - @archive_faq = ArchiveFaq.find_by_slug(params[:archive_faq_id]) + @archive_faq = ArchiveFaq.find_by(slug: params[:archive_faq_id]) @archive_faq.reorder_list(params[:questions]) - flash[:notice] = ts("Question order has been successfully updated.") + flash[:notice] = t(".success") elsif params[:question] params[:question].each_with_index do |id, position| Question.update(id, position: position + 1) (@questions ||= []) << Question.find(id) end - flash[:notice] = ts("Question order has been successfully updated.") + flash[:notice] = t(".success") end respond_to do |format| format.html { redirect_to(@archive_faq) and return } diff --git a/app/controllers/tag_wranglings_controller.rb b/app/controllers/tag_wranglings_controller.rb index d6c269b8234..c3068d93a3e 100644 --- a/app/controllers/tag_wranglings_controller.rb +++ b/app/controllers/tag_wranglings_controller.rb @@ -8,33 +8,36 @@ class TagWranglingsController < ApplicationController def index @counts = tag_counts_per_category - unless params[:show].blank? - raise "Redshirt: Attempted to constantize invalid class initialize tag_wranglings_controller_index #{params[:show].classify}" unless Tag::USER_DEFINED.include?(params[:show].classify) + authorize :wrangling, :read_access? if logged_in_as_admin? + return if params[:show].blank? - params[:sort_column] = 'created_at' if !valid_sort_column(params[:sort_column], 'tag') - params[:sort_direction] = 'ASC' if !valid_sort_direction(params[:sort_direction]) + raise "Redshirt: Attempted to constantize invalid class initialize tag_wranglings_controller_index #{params[:show].classify}" unless Tag::USER_DEFINED.include?(params[:show].classify) - if params[:show] == "fandoms" - @media_names = Media.by_name.pluck(:name) - @page_subtitle = ts("fandoms") - end + params[:sort_column] = "created_at" unless valid_sort_column(params[:sort_column], "tag") + params[:sort_direction] = "ASC" unless valid_sort_direction(params[:sort_direction]) - type = params[:show].singularize.capitalize - @tags = TagQuery.new({ - type: type, - in_use: true, - unwrangleable: false, - unwrangled: true, - has_posted_works: true, - sort_column: params[:sort_column], - sort_direction: params[:sort_direction], - page: params[:page], - per_page: ArchiveConfig.ITEMS_PER_PAGE - }).search_results + if params[:show] == "fandoms" + @media_names = Media.by_name.pluck(:name) + @page_subtitle = t(".page_subtitle") end + + type = params[:show].singularize.capitalize + @tags = TagQuery.new({ + type: type, + in_use: true, + unwrangleable: false, + unwrangled: true, + has_posted_works: true, + sort_column: params[:sort_column], + sort_direction: params[:sort_direction], + page: params[:page], + per_page: ArchiveConfig.ITEMS_PER_PAGE + }).search_results end def wrangle + authorize :wrangling, :full_access? if logged_in_as_admin? + params[:page] = '1' if params[:page].blank? params[:sort_column] = 'name' if !valid_sort_column(params[:sort_column], 'tag') params[:sort_direction] = 'ASC' if !valid_sort_direction(params[:sort_direction]) diff --git a/app/controllers/tags_controller.rb b/app/controllers/tags_controller.rb index f7ae2d2b6e9..cdc5932ba12 100644 --- a/app/controllers/tags_controller.rb +++ b/app/controllers/tags_controller.rb @@ -56,12 +56,14 @@ def search flash_search_warnings(@tags) end - # if user is Admin or Tag Wrangler, show them details about the tag + # if user is admin with view access or Tag Wrangler, show them details about the tag # if user is not logged in or a regular user, show them # 1. the works, if the tag had been wrangled and we can redirect them to works using it or its canonical merger # 2. the tag, the works and the bookmarks using it, if the tag is unwrangled (because we can't redirect them # to the works controller) def show + authorize :wrangling, :read_access? if logged_in_as_admin? + @page_subtitle = @tag.name if @tag.is_a?(Banned) && !logged_in_as_admin? flash[:error] = ts('Please log in as admin') @@ -166,6 +168,8 @@ def show_hidden # GET /tags/new def new + authorize :wrangling if logged_in_as_admin? + @tag = Tag.new respond_to do |format| @@ -209,6 +213,8 @@ def create end def edit + authorize :wrangling, :read_access? if logged_in_as_admin? + @page_subtitle = ts('%{tag_name} - Edit', tag_name: @tag.name) if @tag.is_a?(Banned) && !logged_in_as_admin? @@ -241,6 +247,8 @@ def edit end def update + authorize :wrangling if logged_in_as_admin? + # update everything except for the synonym, # so that the associations are there to move when the synonym is created syn_string = params[:tag].delete(:syn_string) @@ -272,6 +280,8 @@ def update end def wrangle + authorize :wrangling, :read_access? if logged_in_as_admin? + @page_subtitle = ts('%{tag_name} - Wrangle', tag_name: @tag.name) @counts = {} @tag.child_types.map { |t| t.underscore.pluralize.to_sym }.each do |tag_type| @@ -303,6 +313,8 @@ def wrangle end def mass_update + authorize :wrangling if logged_in_as_admin? + params[:page] = '1' if params[:page].blank? params[:sort_column] = 'name' unless valid_sort_column(params[:sort_column], 'tag') params[:sort_direction] = 'ASC' unless valid_sort_direction(params[:sort_direction]) diff --git a/app/controllers/unsorted_tags_controller.rb b/app/controllers/unsorted_tags_controller.rb index fc6c8fd6c68..eef8ef17277 100644 --- a/app/controllers/unsorted_tags_controller.rb +++ b/app/controllers/unsorted_tags_controller.rb @@ -5,13 +5,17 @@ class UnsortedTagsController < ApplicationController before_action :check_permission_to_wrangle def index + authorize :wrangling, :read_access? if logged_in_as_admin? + @tags = UnsortedTag.page(params[:page]) @counts = tag_counts_per_category end def mass_update - unless params[:tags].blank? - params[:tags].delete_if {|tag_id, tag_type| tag_type.blank? } + authorize :wrangling if logged_in_as_admin? + + if params[:tags].present? + params[:tags].delete_if { |_, tag_type| tag_type.blank? } tags = UnsortedTag.where(id: params[:tags].keys) tags.each do |tag| new_type = params[:tags][tag.id.to_s] diff --git a/app/controllers/user_invite_requests_controller.rb b/app/controllers/user_invite_requests_controller.rb index daad6c7c58d..48bc411f4ee 100644 --- a/app/controllers/user_invite_requests_controller.rb +++ b/app/controllers/user_invite_requests_controller.rb @@ -55,10 +55,13 @@ def update params[:requests].each_pair do |id, quantity| unless quantity.blank? request = UserInviteRequest.find(id) + user = User.find(request.user_id) requested_total = request.quantity.to_i request.quantity = 0 request.save! - UserMailer.invite_request_declined(request.user_id, requested_total, request.reason).deliver_later + I18n.with_locale(user.preference.locale.iso) do + UserMailer.invite_request_declined(request.user_id, requested_total, request.reason).deliver_later + end end end flash[:notice] = 'All Requests were declined.' diff --git a/app/controllers/users_controller.rb b/app/controllers/users_controller.rb index fc180524aab..8cc10faa4c4 100644 --- a/app/controllers/users_controller.rb +++ b/app/controllers/users_controller.rb @@ -174,7 +174,9 @@ def changed_email if @user.save flash.now[:notice] = ts("Your email has been successfully updated") - UserMailer.change_email(@user.id, old_email, new_email).deliver_later + I18n.with_locale(@user.preference.locale.iso) do + UserMailer.change_email(@user.id, old_email, new_email).deliver_later + end else # Make sure that on failure, the form still shows the old email as the "current" one. @user.email = old_email diff --git a/app/controllers/wrangling_guidelines_controller.rb b/app/controllers/wrangling_guidelines_controller.rb index 230de7034eb..f015a185d68 100644 --- a/app/controllers/wrangling_guidelines_controller.rb +++ b/app/controllers/wrangling_guidelines_controller.rb @@ -3,7 +3,7 @@ class WranglingGuidelinesController < ApplicationController # GET /wrangling_guidelines def index - @wrangling_guidelines = WranglingGuideline.order('position ASC') + @wrangling_guidelines = WranglingGuideline.order("position ASC") end # GET /wrangling_guidelines/1 @@ -13,57 +13,64 @@ def show # GET /wrangling_guidelines/new def new + authorize :wrangling @wrangling_guideline = WranglingGuideline.new end # GET /wrangling_guidelines/1/edit def edit + authorize :wrangling @wrangling_guideline = WranglingGuideline.find(params[:id]) end # GET /wrangling_guidelines/manage def manage - @wrangling_guidelines = WranglingGuideline.order('position ASC') + authorize :wrangling + @wrangling_guidelines = WranglingGuideline.order("position ASC") end # POST /wrangling_guidelines def create + authorize :wrangling @wrangling_guideline = WranglingGuideline.new(wrangling_guideline_params) if @wrangling_guideline.save - flash[:notice] = ts('Wrangling Guideline was successfully created.') + flash[:notice] = t("wrangling_guidelines.create") redirect_to(@wrangling_guideline) else - render action: 'new' + render action: "new" end end # PUT /wrangling_guidelines/1 def update + authorize :wrangling @wrangling_guideline = WranglingGuideline.find(params[:id]) if @wrangling_guideline.update(wrangling_guideline_params) - flash[:notice] = ts('Wrangling Guideline was successfully updated.') + flash[:notice] = t("wrangling_guidelines.update") redirect_to(@wrangling_guideline) else - render action: 'edit' + render action: "edit" end end # reorder FAQs def update_positions + authorize :wrangling if params[:wrangling_guidelines] @wrangling_guidelines = WranglingGuideline.reorder_list(params[:wrangling_guidelines]) - flash[:notice] = ts('Wrangling Guidelines order was successfully updated.') + flash[:notice] = t("wrangling_guidelines.reorder") end redirect_to(wrangling_guidelines_path) end # DELETE /wrangling_guidelines/1 def destroy + authorize :wrangling @wrangling_guideline = WranglingGuideline.find(params[:id]) @wrangling_guideline.destroy - flash[:notice] = ts('Wrangling Guideline was successfully deleted.') + flash[:notice] = t("wrangling_guidelines.delete") redirect_to(wrangling_guidelines_path) end @@ -72,5 +79,4 @@ def destroy def wrangling_guideline_params params.require(:wrangling_guideline).permit(:title, :content) end - end diff --git a/app/mailers/user_mailer.rb b/app/mailers/user_mailer.rb index 0e487fb387d..ebe3070ebf9 100644 --- a/app/mailers/user_mailer.rb +++ b/app/mailers/user_mailer.rb @@ -92,22 +92,14 @@ def invitation_to_claim(invitation_id, archivist_login) end # Notifies a writer that their imported works have been claimed - def claim_notification(creator_id, claimed_work_ids, is_user=false) - if is_user - creator = User.find(creator_id) - locale = creator.preference.locale.iso - else - creator = ExternalAuthor.find(creator_id) - locale = I18n.default_locale - end + def claim_notification(creator_id, claimed_work_ids) + creator = User.find(creator_id) @external_email = creator.email @claimed_works = Work.where(id: claimed_work_ids) - I18n.with_locale(locale) do - mail( - to: creator.email, - subject: t("user_mailer.claim_notification.subject", app_name: ArchiveConfig.APP_SHORT_NAME) - ) - end + mail( + to: creator.email, + subject: default_i18n_subject(app_name: ArchiveConfig.APP_SHORT_NAME) + ) end # Sends a batched subscription notification @@ -170,12 +162,10 @@ def invite_request_declined(user_id, total, reason) @user = User.find(user_id) @total = total @reason = reason - I18n.with_locale(@user.preference.locale.iso) do - mail( - to: @user.email, - subject: t("user_mailer.invite_request_declined.subject", app_name: ArchiveConfig.APP_SHORT_NAME) - ) - end + mail( + to: @user.email, + subject: default_i18n_subject(app_name: ArchiveConfig.APP_SHORT_NAME) + ) end def collection_notification(collection_id, subject, message, email) @@ -235,12 +225,10 @@ def change_email(user_id, old_email, new_email) @user = User.find(user_id) @old_email = old_email @new_email = new_email - I18n.with_locale(@user.preference.locale.iso) do - mail( - to: @old_email, - subject: t("user_mailer.change_email.subject", app_name: ArchiveConfig.APP_SHORT_NAME) - ) - end + mail( + to: @old_email, + subject: default_i18n_subject(app_name: ArchiveConfig.APP_SHORT_NAME) + ) end ### WORKS NOTIFICATIONS ### diff --git a/app/models/external_author.rb b/app/models/external_author.rb index 9e10c901c92..e70005a00a9 100644 --- a/app/models/external_author.rb +++ b/app/models/external_author.rb @@ -131,7 +131,9 @@ def block_import def notify_user_of_claim(claimed_work_ids) # send announcement to user of the stories they have been given - UserMailer.claim_notification(self.id, claimed_work_ids).deliver_later + I18n.with_locale(self.user.preference.locale.iso) do + UserMailer.claim_notification(self.user_id, claimed_work_ids).deliver_later + end end def find_or_invite(archivist = nil) diff --git a/app/policies/archive_faq_policy.rb b/app/policies/archive_faq_policy.rb new file mode 100644 index 00000000000..87c8a7e9e3d --- /dev/null +++ b/app/policies/archive_faq_policy.rb @@ -0,0 +1,24 @@ +# frozen_string_literal: true + +class ArchiveFaqPolicy < ApplicationPolicy + TRANSLATION_ACCESS_ROLES = %w[superadmin docs support translation].freeze + # a subset of TRANSLATION_ACCESS_ROLES + FULL_ACCESS_ROLES = %w[superadmin docs support].freeze + + def translation_access? + user_has_roles?(TRANSLATION_ACCESS_ROLES) + end + + def full_access? + user_has_roles?(FULL_ACCESS_ROLES) + end + + alias edit? translation_access? + alias update? translation_access? + alias new? full_access? + alias create? full_access? + alias manage? full_access? + alias update_positions? full_access? + alias confirm_delete? full_access? + alias destroy? full_access? +end diff --git a/app/policies/inbox_comment_policy.rb b/app/policies/inbox_comment_policy.rb new file mode 100644 index 00000000000..8ec7d755b38 --- /dev/null +++ b/app/policies/inbox_comment_policy.rb @@ -0,0 +1,7 @@ +class InboxCommentPolicy < ApplicationPolicy + VIEW_INBOX_ROLES = %w[superadmin policy_and_abuse].freeze + + def show? + user_has_roles?(VIEW_INBOX_ROLES) + end +end diff --git a/app/policies/known_issue_policy.rb b/app/policies/known_issue_policy.rb new file mode 100644 index 00000000000..a74de07e65b --- /dev/null +++ b/app/policies/known_issue_policy.rb @@ -0,0 +1,16 @@ +# frozen_string_literal: true + +class KnownIssuePolicy < ApplicationPolicy + MANAGE_ROLES = %w[superadmin support].freeze + + def admin_index? + user_has_roles?(MANAGE_ROLES) + end + + alias destroy? admin_index? + alias edit? admin_index? + alias create? admin_index? + alias new? admin_index? + alias show? admin_index? + alias update? admin_index? +end diff --git a/app/policies/wrangling_policy.rb b/app/policies/wrangling_policy.rb index 40acf51c97a..ba17ced729c 100644 --- a/app/policies/wrangling_policy.rb +++ b/app/policies/wrangling_policy.rb @@ -2,13 +2,24 @@ class WranglingPolicy < ApplicationPolicy FULL_ACCESS_ROLES = %w[superadmin tag_wrangling].freeze + READ_ACCESS_ROLES = (FULL_ACCESS_ROLES + %w[policy_and_abuse]).freeze def full_access? user_has_roles?(FULL_ACCESS_ROLES) end + def read_access? + user_has_roles?(READ_ACCESS_ROLES) + end + alias create? full_access? alias destroy? full_access? + alias mass_update? full_access? alias show? full_access? alias report_csv? full_access? + alias new? full_access? + alias edit? full_access? + alias manage? full_access? + alias update? full_access? + alias update_positions? full_access? end diff --git a/app/views/admin/_admin_nav.html.erb b/app/views/admin/_admin_nav.html.erb index 8ee535467a1..e705ea49bb8 100644 --- a/app/views/admin/_admin_nav.html.erb +++ b/app/views/admin/_admin_nav.html.erb @@ -1,15 +1,16 @@ -

<%= ts("Admin Navigation") %>

+

<%= t(".landmark") %>

diff --git a/app/views/admin/_header.html.erb b/app/views/admin/_header.html.erb index 419db932728..9c7ae29136f 100644 --- a/app/views/admin/_header.html.erb +++ b/app/views/admin/_header.html.erb @@ -27,15 +27,21 @@ <% if policy(AdminPost).can_post? %>
  • <%= link_to t(".nav.posts.post_news"), new_admin_post_path %>
  • <% end %> -
  • <%= link_to t(".nav.posts.faqs"), archive_faqs_path %>
  • -
  • <%= link_to t(".nav.posts.known_issues"), known_issues_path %>
  • -
  • <%= link_to t(".nav.posts.wrangling_guidelines"), wrangling_guidelines_path %>
  • + <% if policy(ArchiveFaq).translation_access? %> +
  • <%= link_to t(".nav.posts.faqs"), archive_faqs_path %>
  • + <% end %> + <% if policy(KnownIssue).admin_index? %> +
  • <%= link_to t(".nav.posts.known_issues"), known_issues_path %>
  • + <% end %> + <% if policy(:wrangling).new? %> +
  • <%= link_to t(".nav.posts.wrangling_guidelines"), wrangling_guidelines_path %>
  • + <% end %> <% if policy(AdminBlacklistedEmail).index? %>
  • <%= link_to t(".nav.banned_emails"), admin_blacklisted_emails_path %>
  • <% end %> - + <% if policy(ModeratedWork).index? %>
  • <%= link_to t(".nav.spam"), admin_spam_index_path %>
  • <% end %> @@ -58,8 +64,9 @@ <% end %> -
  • <%= link_to t(".nav.wrangling"), tag_wranglings_path %>
  • - + <% if policy(:wrangling).full_access? %> +
  • <%= link_to t(".nav.wrangling"), tag_wranglings_path %>
  • + <% end %> <% if policy(Locale).index? %>
  • <%= link_to t(".nav.locales"), locales_path %>
  • <% end %> diff --git a/app/views/archive_faqs/_admin_index.html.erb b/app/views/archive_faqs/_admin_index.html.erb index cdb3395e593..d9cdc0bc9d1 100644 --- a/app/views/archive_faqs/_admin_index.html.erb +++ b/app/views/archive_faqs/_admin_index.html.erb @@ -1,31 +1,33 @@
    -

    <%= ts("Archive FAQ") %>

    +

    <%= t(".page_heading") %>

    -<%= render 'archive_faqs/filters' %> -<%= render 'admin/admin_nav' %> +<%= render "archive_faqs/filters" %> +<%= render "admin/admin_nav" %> -

    <%= ts("Manage Archive FAQs") %>

    +

    <%= t(".manage_faqs") %>

    <% @archive_faqs.each do |archive_faq| %>
    <%= link_to archive_faq.title, archive_faq %>
    -

    <%= ts("Created at %{date_created} and updated at %{date_updated}", :date_created => archive_faq.created_at, :date_updated => archive_faq.updated_at) %>

    +

    <%= t(".created_updated_date", date_created: l(archive_faq.created_at), date_updated: l(archive_faq.updated_at)) %>

    diff --git a/app/views/archive_faqs/index.html.erb b/app/views/archive_faqs/index.html.erb index 13f9c7afd9b..d59fc41fc74 100644 --- a/app/views/archive_faqs/index.html.erb +++ b/app/views/archive_faqs/index.html.erb @@ -1,4 +1,4 @@ -<% if logged_in_as_admin? %> +<% if policy(ArchiveFaq).translation_access? %> <%= render "admin_index" %> <% else %> <%= render "faq_index" %> diff --git a/app/views/archive_faqs/show.html.erb b/app/views/archive_faqs/show.html.erb index 44315e6dbb8..f99fa8f6f6f 100644 --- a/app/views/archive_faqs/show.html.erb +++ b/app/views/archive_faqs/show.html.erb @@ -1,5 +1,5 @@ -

    <%= link_to ts("Archive FAQ"), archive_faqs_path %> > <%= @archive_faq.title %>

    +

    <%= link_to t(".page_heading"), archive_faqs_path %> > <%= @archive_faq.title %>

    @@ -8,21 +8,24 @@ <% if @archive_faq.slug == "search-and-browse" %>

    - <%= ts("Our search engine has recently been updated, and this FAQ is based on our old version. We're working on bringing you more up-to-date information, but in the meantime, you can find out more in our %{elasticsearch_post}!", elasticsearch_post: link_to(ts("news post announcing the search and filter updates"), admin_post_path(10575))).html_safe %> + <%= t(".elasticsearch_update_notice_html", elasticsearch_news_link: link_to(t(".elasticsearch_news"), admin_post_path(10_575))) %>

    <% end %>
    - <% if logged_in_as_admin? %> + <% if policy(ArchiveFaq).translation_access? %>

    - Updated: <%=h @archive_faq.updated_at %> | <%= link_to 'Edit', edit_archive_faq_path(@archive_faq) %> + Updated: <%= h @archive_faq.updated_at %> + <% if Globalize.locale.to_s != "en" || policy(ArchiveFaq).full_access? -%> + | <%= link_to t(".edit"), edit_archive_faq_path(@archive_faq) %> + <% end %>

    <% end %> - <% if @archive_faq.questions.blank? %> -

    <%= ts("We're sorry, there are currently no entries in this category.") %>

    + <% if @archive_faq.questions.blank? %> +

    <%= t(".no_category_entries") %>

    <% else %>
    dir="rtl"<% end %> class="userstuff"> @@ -44,7 +47,7 @@ <% unless q.screencast.to_s == "" %>

    - <%= ts("Screencast") %>: <%= link_to q.question, q.screencast.to_s %> + <%= t(".screencast") %> <%= link_to q.question, q.screencast.to_s %>

    <% end %> <%= raw sanitize_field(q, :content) %> diff --git a/app/views/known_issues/index.html.erb b/app/views/known_issues/index.html.erb index acd5616f914..6d550cdb5e6 100644 --- a/app/views/known_issues/index.html.erb +++ b/app/views/known_issues/index.html.erb @@ -1,5 +1,5 @@ -<% if logged_in_as_admin? %> +<% if policy(KnownIssue).admin_index? %> <%= render :partial => "admin_index" %> <% else %>

    <%= ts("Known Issues") %>

    diff --git a/app/views/tag_wranglings/_wrangler_dashboard.html.erb b/app/views/tag_wranglings/_wrangler_dashboard.html.erb index 52610712eed..a1e0bcd38d7 100644 --- a/app/views/tag_wranglings/_wrangler_dashboard.html.erb +++ b/app/views/tag_wranglings/_wrangler_dashboard.html.erb @@ -1,39 +1,62 @@ -
    - - <% if @counts %> -
    + + <% end %> +
    +<% end %> diff --git a/app/views/users/_sidebar.html.erb b/app/views/users/_sidebar.html.erb index 429c8ebcc95..a6a8a0295d2 100644 --- a/app/views/users/_sidebar.html.erb +++ b/app/views/users/_sidebar.html.erb @@ -1,30 +1,30 @@
    " role="navigation region"> -

    <%= ts("Choices")%>

    +

    <%= t(".landmark.choices") %>

    -

    <%= ts("Pitch")%>

    +

    <%= t(".landmark.pitch") %>

    -<% if @user == current_user %> -

    <%= ts("Catch")%>

    +<% if @user == current_user || policy(:inbox_comment).show? %> +

    <%= t(".landmark.catch") %>

    <% end %> -

    <%= ts("Switch")%>

    +

    <%= t(".landmark.switch") %>

    diff --git a/app/views/wrangling_guidelines/index.html.erb b/app/views/wrangling_guidelines/index.html.erb index 20951c859a7..0b29d8943d7 100644 --- a/app/views/wrangling_guidelines/index.html.erb +++ b/app/views/wrangling_guidelines/index.html.erb @@ -1,5 +1,5 @@ -<% if logged_in_as_admin? %> +<% if policy(:wrangling).new? %> <%= render 'admin_index' %> <% else %>

    <%= ts('Wrangling Guidelines') %>

    diff --git a/app/views/wrangling_guidelines/show.html.erb b/app/views/wrangling_guidelines/show.html.erb index 42e5f2d57b5..4e7e04a6177 100644 --- a/app/views/wrangling_guidelines/show.html.erb +++ b/app/views/wrangling_guidelines/show.html.erb @@ -8,7 +8,7 @@
    - <% if logged_in_as_admin? %> + <% if policy(:wrangling).edit? %>

    Updated: <%=h @wrangling_guideline.updated_at %> | <%= link_to ts('Edit'), edit_wrangling_guideline_path(@wrangling_guideline) %> diff --git a/config/i18n-tasks.yml b/config/i18n-tasks.yml index 853290df404..0646f44702a 100644 --- a/config/i18n-tasks.yml +++ b/config/i18n-tasks.yml @@ -149,8 +149,6 @@ ignore_missing: - successfully_sent # should be feedbacks.create.successfully_sent # Files: app/controllers/languages_controller.rb and app/controllers/locales_controller.rb - successfully_added # should be languages.create.successfully_added and locales.create.successfully_added - # Files: app/views/admin/_admin_nav.html.erb and app/views/admin_posts/show.html.erb - - admin.admin_nav.delete # File: app/views/admin/admin_invitations/find.html.erb - admin.admin_invitations.find.find_email - admin.admin_invitations.find.find_token diff --git a/config/locales/controllers/en.yml b/config/locales/controllers/en.yml index 647293d6d83..ea56888e5be 100644 --- a/config/locales/controllers/en.yml +++ b/config/locales/controllers/en.yml @@ -1,6 +1,9 @@ --- en: admin: + access: + action_access_denied: Sorry, only an authorized admin can do that. + page_access_denied: Sorry, only an authorized admin can access the page you were trying to reach. admin_invitations: find: user_not_found: No results were found. Try another search. @@ -11,6 +14,14 @@ en: admin_users: destroy_user_creations: success: All creations by user %{login} have been deleted. + archive_faqs: + create: + success: Archive FAQ was successfully created. + default_locale_only: Sorry, this action is only available for English FAQs. + update: + success: Archive FAQ was successfully updated. + update_positions: + success: Archive FAQs order was successfully updated. blocked: users: create: @@ -99,6 +110,13 @@ en: muted: You have muted the user %{name}. destroy: unmuted: You have unmuted the user %{name}. + questions: + not_found: Sorry, we couldn't find the FAQ you were looking for. + update_positions: + success: Question order has been successfully updated. + tag_wranglings: + index: + page_subtitle: fandoms users: passwords: create: @@ -120,3 +138,8 @@ en: works: drafts: page_title: "%{username} - Drafts" + wrangling_guidelines: + create: Wrangling Guideline was successfully created. + delete: Wrangling Guideline was successfully deleted. + reorder: Wrangling Guidelines order was successfully updated. + update: Wrangling Guideline was successfully updated. diff --git a/config/locales/views/en.yml b/config/locales/views/en.yml index f33c121bb78..98566ffcc69 100644 --- a/config/locales/views/en.yml +++ b/config/locales/views/en.yml @@ -91,6 +91,17 @@ en: queue: Manage Queue requests: Manage Requests page_heading: Invite New Users + admin_nav: + ao3_news: AO3 News + archive_faq: Archive FAQ + faq: + reorder_questions: Reorder Questions + known_issues: Known Issues + landmark: Admin Navigation + news: + delete_post: Delete Post + post_ao3_news: Post AO3 News + wrangling_guidelines: Wrangling Guidelines admin_options: delete: bookmark: Delete Bookmark @@ -376,6 +387,24 @@ en: roles: heading: 'Your admin roles:' none: You currently have no admin roles assigned to you. + archive_faqs: + admin_index: + confirm_delete: Are you sure you want to delete this FAQ category? + created_updated_date: Created at %{date_created} and updated at %{date_updated} + delete: Delete + edit: Edit + manage_faqs: Manage Archive FAQs + new_faq_category: New FAQ Category + page_heading: Archive FAQ + reorder_faqs: Reorder FAQs + show: Show + show: + edit: Edit + elasticsearch_news: news post announcing the search and filter updates + elasticsearch_update_notice_html: Our search engine has recently been updated, and this FAQ is based on our old version. We're working on bringing you more up-to-date information, but in the meantime, you can find out more in our %{elasticsearch_news_link}! + no_category_entries: We're sorry, there are currently no entries in this category. + page_heading: Archive FAQ + screencast: 'Screencast:' blocked: block: Block unblock: Unblock @@ -1583,6 +1612,34 @@ en: show: last_wrangled_html: "%{wrangler_login} last wrangled at %{time}." tags_wrangled_csv: Tags Wrangled (CSV) + tag_wranglings: + wrangler_dashboard: + characters_by_fandom: Characters by fandom (%{count}) + fandoms_by_media: Fandoms by media (%{count}) + freeforms_by_fandom: Freeforms by fandom (%{count}) + new_tag: New Tag + relationships_by_fandom: Relationships by fandom (%{count}) + search_tags: Search Tags + tag_type: + character: Characters + fandom: Fandoms + freeform: Freeforms + merger: Mergers + relationship: Relationships + subtag: SubTags + tag_type_and_count: "%{tag_type} (%{count})" + unsorted_tags: Unsorted Tags (%{count}) + use_type: + bookmarks: Bookmarks + drafts: Drafts + external_works: External Works + private_bookmarks: Private Bookmarks + taggings_count: Taggings Count + works: Works + use_type_and_count: "%{use_type} (%{count})" + wranglers: Wranglers + wrangling_home: Wrangling Home + wrangling_tools: Wrangling Tools tags: index: about: @@ -1768,6 +1825,34 @@ en: privacy_policy: Privacy Policy tos: Terms of Service welcome_html: Hi! It looks like you've just logged in to AO3 for the first time. For help getting started on AO3, check out some %{new_user_tips_link} or browse through %{our_faqs_link}. + sidebar: + catch: + history: History + inbox: Inbox (%{inbox_number}) + statistics: Statistics + subscriptions: Subscriptions + choices: + all_pseuds: All Pseuds (%{pseud_number}) + dashboard: Dashboard + preferences: Preferences + profile: Profile + pseud_switcher: Pseud Switcher + pseuds: Pseuds + skins: Skins + landmark: + catch: Catch + choices: Choices + pitch: Pitch + switch: Switch + pitch: + collections: Collections (%{coll_number}) + drafts: Drafts (%{drafts_number}) + switch: + assignments: Assignments (%{assignment_number}) + claims: Claims (%{claim_number}) + co_creator_requests: Co-Creator Requests (%{count}) + related_works: Related Works (%{related_works_number}) + sign_ups: Sign-ups (%{signup_number}) works: adult: caution: This work could have adult content. If you continue, you have agreed that you are willing to see such content. diff --git a/features/admins/admin_post_faqs.feature b/features/admins/admin_post_faqs.feature index e30edfdd34d..918c6b19435 100644 --- a/features/admins/admin_post_faqs.feature +++ b/features/admins/admin_post_faqs.feature @@ -3,11 +3,11 @@ Feature: Admin Actions to Post FAQs As an an admin I want to be able to manage the archive FAQ - Scenario: Post and edit a FAQ + Scenario Outline: Authorized admin posts, edits and deletes a FAQ category When I go to the archive_faqs page Then I should see "Some commonly asked questions about the Archive are answered here" And I should not see "Some text" - When I am logged in as an admin + When I am logged in as a "" admin And I follow "Admin Posts" And I follow "Archive FAQ" within "#header" Then I should not see "Some text" @@ -17,7 +17,7 @@ Feature: Admin Actions to Post FAQs And I fill in "Category name*" with "New subsection" And I fill in "Anchor name*" with "whatisao3" And I press "Post" - Then I should see "ArchiveFaq was successfully created" + Then I should see "Archive FAQ was successfully created" When I go to the archive_faqs page And I follow "New subsection" Then I should see "Some text, that is sufficiently long to pass validation" within ".userstuff" @@ -26,10 +26,38 @@ Feature: Admin Actions to Post FAQs And I press "Post" Then I should see "New Content, yay" And I should not see "Some text" + When I go to the archive_faqs page + And I follow "Delete" + Then I should see "Are you sure you want to delete the FAQ Category" + When I press "Yes, Delete FAQ Category" + Then I should not see "New subsection" + + Examples: + | role | + | support | + | superadmin | + | docs | + + @javascript + Scenario Outline: Authorized admin deletes a FAQ question + Given 1 Archive FAQ with 1 question exists + And I am logged in as a "" admin + And I go to the archive_faqs page + And I follow "Edit" + And I follow "Remove Question" + And I press "Post" + Then I should see "Archive FAQ was successfully updated." + And I should see "We're sorry, there are currently no entries in this category." + + Examples: + | role | + | support | + | superadmin | + | docs | Scenario: Post a translated FAQ for a locale, then change the locale's code. Given basic languages - And I am logged in as a "translation" admin + And I am logged in as a "superadmin" admin # Post "en" FAQ When I go to the archive_faqs page @@ -39,23 +67,25 @@ Feature: Admin Actions to Post FAQs And I fill in "Category name*" with "New subsection" And I fill in "Anchor name*" with "whatisao3" And I press "Post" - Then I should see "ArchiveFaq was successfully created" + Then I should see "Archive FAQ was successfully created" # Translate FAQ to "de" - When I follow "Archive FAQ" + When I am logged in as a "translation" admin + And I follow "Admin Posts" + And I follow "Archive FAQ" And I select "Deutsch" from "Language:" And I press "Go" within "div#inner.wrapper" And I follow "Edit" And I fill in "Question*" with "Was ist AO3?" - And I fill in "Answer*" with "Einige Text, das ist lang genug, um die Überprüfung bestanden." + And I fill in "Answer*" with "Einiger Text, der lang genug ist, um die Überprüfung zu bestehen." And I fill in "Category name*" with "Neuer Abschnitt" And I check "Question translated" And I press "Post" - Then I should see "ArchiveFaq was successfully updated." + Then I should see "Archive FAQ was successfully updated." And I should not see "New subsection" And I should see "Neuer Abschnitt" And I should see "Was ist AO3?" - And I should see "Einige Text" + And I should see "Einiger Text" # Change locale "de" to "ger" When I go to the locales page @@ -83,4 +113,89 @@ Feature: Admin Actions to Post FAQs And I press "Go" within "div#inner.wrapper" And I follow "Neuer Abschnitt" Then I should see "Was ist AO3?" - And I should see "Einige Text" + And I should see "Einiger Text" + + Scenario: Links to create, reorder and delete FAQ categories are not shown for non-English language FAQs + Given basic languages + And 1 Archive FAQ exists + And I am logged in as a "superadmin" admin + When I go to the archive_faqs page + Then I should see "New FAQ Category" + And I should see "Reorder FAQs" + And I should see "Delete" + And I should see "Edit" + When I select "Deutsch" from "Language:" + And I press "Go" within "div#inner.wrapper" + Then I should not see "New FAQ Category" + And I should not see "Reorder FAQs" + And I should not see "Delete" + But I should see "Edit" + + @javascript + Scenario: Links to add, reorder and remove FAQ questions are not shown for non-English language FAQs + Given basic languages + And 1 Archive FAQ with 1 question exists + And I am logged in as a "superadmin" admin + When I go to the archive_faqs page + And I follow "Edit" + Then I should see "Reorder Questions" + And I should see "Remove Question" + And I should see "Add Question" + But I should not see "Question translated" + When I select "Deutsch" from "Language:" + And I press "Go" within "div#inner.wrapper" + And I follow "Edit" + Then I should not see "Reorder Questions" + And I should not see "Remove Question" + And I should not see "Add Question" + But I should see "Question translated" + + Scenario: Translation admins do not see links to edit English language FAQs + Given basic languages + And 1 Archive FAQ exists + And I am logged in as a "translation" admin + When I go to the archive_faqs page + Then I should not see "Edit" + And I should not see "New FAQ Category" + And I should not see "Reorder FAQs" + And I should not see "Delete" + When I follow "Show" + Then I should not see "Edit" within ".header" + But I should see "Updated:" within ".header" + When I go to the archive_faqs page + And I select "Deutsch" from "Language:" + And I press "Go" within "div#inner.wrapper" + Then I should see "Edit" + And I should not see "New FAQ Category" + And I should not see "Reorder FAQs" + And I should not see "Delete" + When I follow "Show" + Then I should see "Edit" within ".header" + And I should see "Updated:" within ".header" + + Scenario Outline: Links to create and edit FAQs are not shown to unauthorized admins + Given an archive FAQ category with the title "Very important FAQ" exists + And I am logged in as a "" admin + When I follow "Admin Posts" + Then I should not see "Archive FAQ" within "#header" + When I go to the archive_faqs page + Then I should not see "Edit" + And I should not see "New FAQ Category" + And I should not see "Reorder FAQs" + And I should not see "Delete" + But I should see "Available Categories" + When I follow "Very important FAQ" + Then I should not see "Edit" + And I should not see "Updated:" + + Examples: + | role | + | board | + | board_assistants_team | + | communications | + | development_and_membership | + | elections | + | legal | + | tag_wrangling | + | policy_and_abuse | + | open_doors | diff --git a/features/admins/admin_post_issues.feature b/features/admins/admin_post_issues.feature index fdfdb508fbe..cdedac3a957 100644 --- a/features/admins/admin_post_issues.feature +++ b/features/admins/admin_post_issues.feature @@ -3,9 +3,9 @@ Feature: Admin Actions to Post Known Issues As an an admin I want to be able to report known issues - Scenario: Post known issues - When I am logged in as an admin - And I follow "Admin Posts" + Scenario Outline: Authorized admin posts, edits, and deletes known issues + Given I am logged in as a "" admin + When I follow "Admin Posts" And I follow "Known Issues" within "#header" And I follow "make a new known issues post" And I fill in "known_issue_title" with "First known problem" @@ -18,15 +18,36 @@ Feature: Admin Actions to Post Known Issues And I follow "Known Issues" within "#header" And I follow "Show" Then I should see "First known problem" - - Scenario: Edit known issues - Given I have posted known issues When I edit known issues Then I should see "Known issue was successfully updated" And I should not see "First known problem" And I should see "This is a bit of a problem, and this is too" - - Scenario: Delete known issues - Given I have posted known issues When I delete known issues Then I should not see "First known problem" + + Examples: + | role | + | support | + | superadmin | + + Scenario Outline: Links to edit and create known issues are not shown to unauthorized admins + Given I have posted known issues + And I am logged in as a "" admin + When I follow "Admin Posts" + Then I should not see "Known Issues" within "#header" + When I go to the known issues page + Then I should not see "Edit" within ".actions" + + Examples: + | role | + | board | + | board_assistants_team | + | communications | + | development_and_membership | + | docs | + | elections | + | legal | + | translation | + | tag_wrangling | + | policy_and_abuse | + | open_doors | diff --git a/features/admins/admin_reorder_faq.feature b/features/admins/admin_reorder_faq.feature index d06f3d67a12..0073cb5dd60 100644 --- a/features/admins/admin_reorder_faq.feature +++ b/features/admins/admin_reorder_faq.feature @@ -5,7 +5,7 @@ Feature: Rearrange Archive FAQs I want to be able to reorder the FAQs Scenario: Rearrange FAQs - Given I am logged in as an admin + Given I am logged in as a "superadmin" admin And 3 Archive FAQs exist When I go to the FAQ reorder page And I fill in "archive_faqs_1" with "3" diff --git a/features/admins/admin_reorder_faq_questions.feature b/features/admins/admin_reorder_faq_questions.feature index 4f5c1b40ebe..2142bccc0ec 100644 --- a/features/admins/admin_reorder_faq_questions.feature +++ b/features/admins/admin_reorder_faq_questions.feature @@ -4,7 +4,7 @@ Feature: Admin Actions to re-order questions in a FAQ Category I want to be able to re-order the questions in a FAQ Category Scenario: Re-order the questions in a FAQ Category - Given I am logged in as an admin + Given I am logged in as a "superadmin" admin And I make a multi-question FAQ post When I go to the archive_faqs page And I follow "Standard FAQ Category" diff --git a/features/bookmarks/bookmark_indexing.feature b/features/bookmarks/bookmark_indexing.feature index 7bd9a41cd36..e32a131c35e 100644 --- a/features/bookmarks/bookmark_indexing.feature +++ b/features/bookmarks/bookmark_indexing.feature @@ -63,7 +63,7 @@ Feature: Bookmark Indexing Given a canonical fandom "Veronica Mars" And a canonical fandom "Veronica Mars (TV)" And bookmarks of external works and series tagged with the fandom tag "Veronica Mars" - And I am logged in as an admin + And I am logged in as a "tag_wrangling" admin When I syn the tag "Veronica Mars" to "Veronica Mars (TV)" And I go to the bookmarks tagged "Veronica Mars (TV)" Then I should see "BookmarkedExternalWork" diff --git a/features/importing/work_import.feature b/features/importing/work_import.feature index 15948aaa697..fa98e6e3866 100644 --- a/features/importing/work_import.feature +++ b/features/importing/work_import.feature @@ -355,3 +355,20 @@ Feature: Import Works And I should not see "This chapter is a draft and hasn't been posted yet!" When I follow "Next Chapter" Then I should not see "This chapter is a draft and hasn't been posted yet!" + + Scenario: Importing as an archivist for an existing Archive author should send translated claim email + Given a locale with translated emails + And the following activated users exist + | login | email | + | sam | sam@example.com | + | notsam | notsam@example.com | + And the user "sam" enables translated emails + And all emails have been delivered + When I import the mock work "http://import-site-without-tags" by "sam" with email "sam@example.com" and by "notsam" with email "notsam@example.com" + Then I should see import confirmation + And 1 email should be delivered to "sam@example.com" + And the email should contain claim information + And the email to "sam" should be translated + And 1 email should be delivered to "notsam@example.com" + And the email should contain claim information + And the email to "notsam" should be non-translated diff --git a/features/other_a/invite_request.feature b/features/other_a/invite_request.feature index 8d8a4f5725d..09f4ab3ad98 100644 --- a/features/other_a/invite_request.feature +++ b/features/other_a/invite_request.feature @@ -156,3 +156,21 @@ Feature: Invite requests When I follow "Delete" Then I should see "Invitation successfully destroyed" And "user1" should have "4" invitations + + Scenario: Translated email is sent when invitation request is declined by admin + Given a locale with translated emails + And invitations are required + And the user "user1" exists and is activated + And the user "notuser1" exists and is activated + And the user "user1" enables translated emails + And all emails have been delivered + When as "user1" I request some invites + And as "notuser1" I request some invites + And I view requests as an admin + And I press "Decline All" + Then "user1" should be emailed + And the email should have "Additional invitation request declined" in the subject + And the email to "user1" should be translated + Then "notuser1" should be emailed + And the email should have "Additional invitation request declined" in the subject + And the email to "notuser1" should be non-translated diff --git a/features/other_a/profile_edit.feature b/features/other_a/profile_edit.feature index 4f6186226ca..1f9e0e6b593 100644 --- a/features/other_a/profile_edit.feature +++ b/features/other_a/profile_edit.feature @@ -148,6 +148,17 @@ Scenario: Changing email address -- can't be the same as another user's And I should not see "foo@ao3.org" And I should see "bar@ao3.org" +Scenario: Changing email address -- Translated email is sent when user enables locale settings + Given a locale with translated emails + And the user "editname" enables translated emails + And all emails have been delivered + When I am logged in as "editname" + And I want to edit my profile + And I change my email + Then the email address "bar@ao3.org" should be emailed + And the email should have "Email changed" in the subject + And the email to email address "bar@ao3.org" should be translated + Scenario: Date of birth - under age When I enter a birthdate that shows I am under age diff --git a/features/step_definitions/admin_steps.rb b/features/step_definitions/admin_steps.rb index e20e50c1324..fa8e38d8926 100644 --- a/features/step_definitions/admin_steps.rb +++ b/features/step_definitions/admin_steps.rb @@ -102,8 +102,8 @@ click_button("Update") end -Given /^I have posted known issues$/ do - step %{I am logged in as an admin} +Given "I have posted known issues" do + step %{I am logged in as a super admin} step %{I follow "Admin Posts"} step %{I follow "Known Issues" within "#header"} step %{I follow "make a new known issues post"} @@ -223,6 +223,10 @@ allow(Comment).to receive(:per_page).and_return(amount) end +Given "an archive FAQ category with the title {string} exists" do |title| + FactoryBot.create(:archive_faq, title: title) +end + ### WHEN When /^I visit the last activities item$/ do @@ -272,9 +276,18 @@ click_button("Post") end -When /^(\d+) Archive FAQs? exists?$/ do |n| - (1..n.to_i).each do |i| - FactoryBot.create(:archive_faq, id: i) +When "{int} Archive FAQ(s) exist(s)" do |n| + (1..n).each do |i| + FactoryBot.create(:archive_faq, id: i, title: "The #{i} FAQ") + end +end + +When "{int} Archive FAQ(s) with {int} question(s) exist(s)" do |faqs, questions| + (1..faqs).each do |i| + archive_faq = FactoryBot.create(:archive_faq, id: i) + (1..questions).each do + FactoryBot.create(:question, archive_faq: archive_faq) + end end end @@ -286,8 +299,7 @@ Resque.enqueue(AdminSetting, :check_queue) end -When /^I edit known issues$/ do - step %{I am logged in as an admin} +When "I edit known issues" do step %{I follow "Admin Posts"} step %{I follow "Known Issues" within "#header"} step %{I follow "Edit"} @@ -296,8 +308,7 @@ step %{I press "Post"} end -When /^I delete known issues$/ do - step %{I am logged in as an admin} +When "I delete known issues" do step %{I follow "Admin Posts"} step %{I follow "Known Issues" within "#header"} step %{I follow "Delete"} diff --git a/features/step_definitions/email_custom_steps.rb b/features/step_definitions/email_custom_steps.rb index e03db12e2da..bb3cf14bb84 100644 --- a/features/step_definitions/email_custom_steps.rb +++ b/features/step_definitions/email_custom_steps.rb @@ -27,6 +27,12 @@ step(%{the email to "#{user}" should not contain "translation missing"}) # missing translations in the target language fall back to English end +Then "the email to email address {string} should be translated" do |email_address| + step(%{the email to email address "#{email_address}" should contain "Translated footer"}) + step(%{the email to email address "#{email_address}" should not contain "fan-run and fan-supported archive"}) # untranslated English text + step(%{the email to email address "#{email_address}" should not contain "translation missing"}) # missing translations in the target language fall back to English +end + Then "the last email to {string} should be translated" do |user| step(%{the last email to "#{user}" should contain "Translated footer"}) step(%{the last email to "#{user}" should not contain "fan-run and fan-supported archive"}) # untranslated English text @@ -44,6 +50,10 @@ expect(emails("to: \"#{email_for(@user.email)}\"")).not_to be_empty end +Then "the email address {string} should be emailed" do |email_address| + expect(emails("to: \"#{email_for(email_address)}\"")).not_to be_empty +end + Then "{string} should not be emailed" do |user| @user = User.find_by(login: user) expect(emails("to: \"#{email_for(@user.email)}\"")).to be_empty @@ -60,6 +70,16 @@ end end +Then "the email to email address {string} should contain {string}" do |email_address, text| + email = emails("to: \"#{email_for(email_address)}\"").first + if email.multipart? + expect(email.text_part.body).to match(text) + expect(email.html_part.body).to match(text) + else + expect(email.body).to match(text) + end +end + Then "the last email to {string} should contain {string}" do |user, text| @user = User.find_by(login: user) email = emails("to: \"#{email_for(@user.email)}\"").last @@ -82,6 +102,16 @@ end end +Then "the email to email address {string} should not contain {string}" do |email_address, text| + email = emails("to: \"#{email_for(email_address)}\"").first + if email.multipart? + expect(email.text_part.body).not_to match(text) + expect(email.html_part.body).not_to match(text) + else + expect(email.body).not_to match(text) + end +end + Then "the last email to {string} should not contain {string}" do |user, text| @user = User.find_by(login: user) email = emails("to: \"#{email_for(@user.email)}\"").last diff --git a/features/step_definitions/invite_steps.rb b/features/step_definitions/invite_steps.rb index 3011381e863..6adc74971ef 100644 --- a/features/step_definitions/invite_steps.rb +++ b/features/step_definitions/invite_steps.rb @@ -128,6 +128,16 @@ def invite(attributes = {}) step %{I press "Send Request"} end +When "as {string} I request some invites" do |user| + step %{I am logged in as "#{user}"} + step %{I go to my user page} + step %{I follow "Invitations"} + step %{I follow "Request invitations"} + step %{I fill in "How many invitations would you like? (max 10)" with "3"} + step %{I fill in "Please specify why you'd like them:" with "I want them for a friend"} + step %{I press "Send Request"} +end + When /^I view requests as an admin$/ do step %{I am logged in as an admin} step %{I follow "Invitations"} diff --git a/features/step_definitions/tag_steps.rb b/features/step_definitions/tag_steps.rb index 92d01d5d457..2d88ae3d455 100644 --- a/features/step_definitions/tag_steps.rb +++ b/features/step_definitions/tag_steps.rb @@ -197,7 +197,7 @@ end Given /^I have posted a Wrangling Guideline?(?: titled "([^\"]*)")?$/ do |title| - step %{I am logged in as an admin} + step %{I am logged in as a "tag_wrangling" admin} visit new_wrangling_guideline_path if title fill_in("Guideline text", with: "This is a page about how we wrangle things.") @@ -427,6 +427,11 @@ assert tag.type == tag_type end +Then "the {string} tag should be an unsorted tag" do |tagname| + tag = Tag.find_by(name: tagname) + expect(tag).to be_a(UnsortedTag) +end + Then(/^the "([^"]*)" tag should (be|not be) canonical$/) do |tagname, canonical| tag = Tag.find_by(name: tagname) expected = canonical == "be" diff --git a/features/step_definitions/work_import_steps.rb b/features/step_definitions/work_import_steps.rb index 25360c974f0..16701b894ca 100644 --- a/features/step_definitions/work_import_steps.rb +++ b/features/step_definitions/work_import_steps.rb @@ -72,6 +72,17 @@ def mock_external step %{I select "English" from "Choose a language"} end +When "I import the mock work {string} by {string} with email {string} and by {string} with email {string}" do |url, creator_name, creator_email, cocreator_name, cocreator_email| + step(%{I start importing "#{url}" with a mock website as an archivist}) + step(%{I check "Import for others ONLY with permission"}) + step(%{I fill in "external_author_name" with "#{creator_name}"}) + step(%{I fill in "external_author_email" with "#{creator_email}"}) + step(%{I fill in "external_coauthor_name" with "#{cocreator_name}"}) + step(%{I fill in "external_coauthor_email" with "#{cocreator_email}"}) + step(%{I check "Post without previewing"}) + step(%{I press "Import"}) +end + When /^I import "(.*)"( with a mock website)?$/ do |url, mock| step %{I start importing "#{url}"#{mock}} step %{I press "Import"} diff --git a/features/tags_and_wrangling/tag_wrangling.feature b/features/tags_and_wrangling/tag_wrangling.feature index 78a3532f65f..680d9822844 100644 --- a/features/tags_and_wrangling/tag_wrangling.feature +++ b/features/tags_and_wrangling/tag_wrangling.feature @@ -311,7 +311,7 @@ Feature: Tag wrangling Scenario: An admin can see the troubleshoot button on a tag page Given a canonical fandom "Cowboy Bebop" - And I am logged in as an admin + And I am logged in as a "tag_wrangling" admin When I view the tag "Cowboy Bebop" Then I should see "Troubleshoot" diff --git a/features/tags_and_wrangling/tag_wrangling_admin.feature b/features/tags_and_wrangling/tag_wrangling_admin.feature index 1d8982c1b34..9768229853b 100644 --- a/features/tags_and_wrangling/tag_wrangling_admin.feature +++ b/features/tags_and_wrangling/tag_wrangling_admin.feature @@ -11,7 +11,7 @@ Feature: Tag wrangling And I go to my bookmarks page And I go to my works page And I go to the work "Luncheon" - When I am logged in as an admin + When I am logged in as a "tag_wrangling" admin And I edit the tag "Amelie" And I fill in "Synonym of" with "Amélie" And I press "Save changes" @@ -34,7 +34,7 @@ Feature: Tag wrangling Scenario: Admin can rename a tag using Eastern characters - Given I am logged in as an admin + Given I am logged in as a "tag_wrangling" admin And a fandom exists with name: "先生", canonical: false When I edit the tag "先生" And I fill in "Name" with "てりやき" @@ -86,3 +86,87 @@ Feature: Tag wrangling Then I should see "Tags Wrangled (CSV)" When I follow "Tags Wrangled (CSV)" Then I should download a csv file with the header row "Name Last Updated Type Merger Fandoms Unwrangleable" + + Scenario Outline: Authorized admins have the tag wrangling item in the admin navbar + + Given I am logged in as a "" admin + Then I should see "Tag Wrangling" within "ul.admin.primary.navigation" + + Examples: + | role | + | superadmin | + | tag_wrangling | + + Scenario Outline: Unauthorized admins do not have the tag wrangling item in the admin navbar + + Given I am logged in as a "" admin + Then I should not see "Tag Wrangling" within "ul.admin.primary.navigation" + + Examples: + | role | + | board | + | board_assistants_team | + | communications | + | development_and_membership | + | docs | + | elections | + | legal | + | translation | + | support | + | policy_and_abuse | + | open_doors | + + Scenario Outline: Fully-authorized admins get the wrangling dashboard sidebar + + Given I am logged in as a "" admin + And basic tags + When I go to the tags page + Then I should see "Wrangling Tools" within "div#dashboard" + And I should see "Wranglers" within "div#dashboard" + And I should see "Search Tags" within "div#dashboard" + And I should see "New Tag" within "div#dashboard" + But I should not see "Wrangling Home" within "div#dashboard" + + Examples: + | role | + | superadmin | + | tag_wrangling | + + Scenario Outline: Read-authorized admins get a partial wrangling dashboard sidebar + + Given I am logged in as a "" admin + And basic tags + When I go to the tags page + Then I should see "Wrangling Tools" within "div#dashboard" + And I should see "Search Tags" within "div#dashboard" + But I should not see "Wranglers" within "div#dashboard" + And I should not see "New Tag" within "div#dashboard" + And I should not see "Wrangling Home" within "div#dashboard" + + Examples: + | role | + | policy_and_abuse | + + Scenario Outline: Unauthorized admins do not get the wrangling dashboard sidebar + + Given I am logged in as a "" admin + And basic tags + When I go to the tags page + Then I should not see "Wrangling Tools" + And I should not see "Wranglers" + And I should not see "Search Tags" + And I should not see "New Tag" + And I should not see "Wrangling Home" + + Examples: + | role | + | board | + | board_assistants_team | + | communications | + | development_and_membership | + | docs | + | elections | + | legal | + | translation | + | support | + | open_doors | diff --git a/features/tags_and_wrangling/tag_wrangling_characters.feature b/features/tags_and_wrangling/tag_wrangling_characters.feature index 9d65608c959..6c9c2e3561f 100644 --- a/features/tags_and_wrangling/tag_wrangling_characters.feature +++ b/features/tags_and_wrangling/tag_wrangling_characters.feature @@ -53,7 +53,7 @@ Scenario: character wrangling - syns, mergers, characters, autocompletes When I follow "Edit The First Doctor" Then I should not see "Make tag non-canonical and unhook all associations" - Given I am logged in as an admin + Given I am logged in as a "tag_wrangling" admin When I edit the tag "The First Doctor" Then I should see "Make tag non-canonical and unhook all associations" And I should see "The Doctor (1st)" @@ -129,7 +129,7 @@ Scenario: character wrangling - syns, mergers, characters, autocompletes When I follow "First Doctor" Then I should see "John Smith" And I should see "The Doctor" - When I am logged in as an admin + When I am logged in as a "tag_wrangling" admin And I edit the tag "First Doctor" And I fill in "Synonym of" with "First Doctor (DW)" And I press "Save changes" diff --git a/features/tags_and_wrangling/tag_wrangling_fandoms.feature b/features/tags_and_wrangling/tag_wrangling_fandoms.feature index 7ca8a94ceb9..a440ccfd39f 100644 --- a/features/tags_and_wrangling/tag_wrangling_fandoms.feature +++ b/features/tags_and_wrangling/tag_wrangling_fandoms.feature @@ -116,7 +116,7 @@ Scenario: fandoms wrangling - syns, mergers, autocompletes, metatags When I edit the tag "Stargate SG-1" Then I should see "Stargate SG-1: Ark of Truth" within "div#child_SubTag_associations_to_remove_checkboxes" And I should see "Stargate Franchise" within "div#parent_MetaTag_associations_to_remove_checkboxes" - When I am logged in as an admin + When I am logged in as a "tag_wrangling" admin And I edit the tag "Stargate SG-1" And I fill in "Synonym of" with "Stargate SG-1: Greatest Show in the Universe" And I press "Save changes" diff --git a/features/tags_and_wrangling/tag_wrangling_freeforms.feature b/features/tags_and_wrangling/tag_wrangling_freeforms.feature index 5f5e2a18627..f1a8786b92f 100644 --- a/features/tags_and_wrangling/tag_wrangling_freeforms.feature +++ b/features/tags_and_wrangling/tag_wrangling_freeforms.feature @@ -95,7 +95,7 @@ Scenario: freeforms wrangling - syns, mergers, autocompletes, metatags Then I should see "Tag was updated" When I follow "Alternate Universe Pirates" Then I should see "Alternate Universe Space Pirates" - When I am logged in as an admin + When I am logged in as a "tag_wrangling" admin And I edit the tag "Alternate Universe Pirates" And I fill in "Synonym of" with "Alternate Universe Pirrrates" And I press "Save changes" diff --git a/features/tags_and_wrangling/tag_wrangling_more.feature b/features/tags_and_wrangling/tag_wrangling_more.feature index 5856829cec0..95dbaca5136 100644 --- a/features/tags_and_wrangling/tag_wrangling_more.feature +++ b/features/tags_and_wrangling/tag_wrangling_more.feature @@ -221,7 +221,7 @@ Feature: Tag wrangling: assigning wranglers, using the filters on the Wranglers When I am logged in as a random user And I view the tag "Cowboy Bebop" Then I should see "Sorry, you don't have permission to access the page you were trying to reach." - When I am logged in as an admin + When I am logged in as a "tag_wrangling" admin And I view the tag "Cowboy Bebop" Then I should not see "Please log in as an admin" And I should see "Cowboy Bebop" diff --git a/features/tags_and_wrangling/tag_wrangling_relationships.feature b/features/tags_and_wrangling/tag_wrangling_relationships.feature index 5c49e38dabd..f9977998532 100644 --- a/features/tags_and_wrangling/tag_wrangling_relationships.feature +++ b/features/tags_and_wrangling/tag_wrangling_relationships.feature @@ -14,7 +14,7 @@ Scenario: relationship wrangling - syns, mergers, characters, autocompletes And a canonical character "Zoe Washburne" And a canonical character "Jack Harkness" And a canonical character "Ianto Jones" - And I am logged in as an admin + And I am logged in as a "tag_wrangling" admin And I follow "Tag Wrangling" # create a new canonical relationship from tag wrangling interface @@ -126,7 +126,7 @@ Scenario: relationship wrangling - syns, mergers, characters, autocompletes When I follow "Jack Harkness/Ianto Jones" Then I should see "Jack Harkness/Robot Ianto Jones" And I should see "Jack Harkness/Male Character" - When I am logged in as an admin + When I am logged in as a "tag_wrangling" admin And I edit the tag "Jack Harkness/Ianto Jones" And I fill in "Synonym of" with "Captain Jack Harkness/Ianto Jones" And I press "Save changes" @@ -270,7 +270,7 @@ Scenario: AO3-2147 Creating a new merger to a non-can tag while adding character And I should see "Testypants/Testyskirt" And the "Canonical" checkbox should be checked and disabled - When I am logged in as an admin + When I am logged in as a "tag_wrangling" admin And I edit the tag "Testing McTestypants/Testing McTestySkirt" And I fill in "Synonym of" with "Dame Tester/Sir Tester" And I press "Save changes" diff --git a/features/tags_and_wrangling/tag_wrangling_unsorted.feature b/features/tags_and_wrangling/tag_wrangling_unsorted.feature index dfc829f45fd..b95e004b62c 100644 --- a/features/tags_and_wrangling/tag_wrangling_unsorted.feature +++ b/features/tags_and_wrangling/tag_wrangling_unsorted.feature @@ -58,3 +58,49 @@ Feature: Tag Wrangling - Unsorted Tags When I select "UnsortedTag" from "tag_type" And I press "Save changes" Then I should see "Tag was updated." + + Scenario Outline: Editing unsorted tags as a fully authorized admin + Given an unsorted_tag exists with name: "Admin unsorted tag" + And I am logged in as a "" admin + When I go to the unsorted_tags page + And I select "Freeform" for the unsorted tag "Admin unsorted tag" + And I press "Update" + Then I should see "Tags were successfully sorted" + And the "Admin unsorted tag" tag should be a "Freeform" tag + + Examples: + | role | + | superadmin | + | tag_wrangling | + + Scenario Outline: Editing unsorted tags as a view-only admin + Given an unsorted_tag exists with name: "Admin unsorted tag" + And I am logged in as a "" admin + When I go to the unsorted_tags page + And I select "Freeform" for the unsorted tag "Admin unsorted tag" + And I press "Update" + Then I should see "Sorry, only an authorized admin can access the page you were trying to reach." + And the "Admin unsorted tag" tag should be an unsorted tag + + Examples: + | role | + | policy_and_abuse | + + Scenario Outline: Editing unsorted tags as an unauthorized admin + Given an unsorted_tag exists with name: "Admin unsorted tag" + And I am logged in as a "" admin + When I go to the unsorted_tags page + Then I should see "Sorry, only an authorized admin can access the page you were trying to reach." + + Examples: + | role | + | board | + | board_assistants_team | + | communications | + | development_and_membership | + | docs | + | elections | + | legal | + | translation | + | support | + | open_doors | diff --git a/features/tags_and_wrangling/wrangling_guidelines.feature b/features/tags_and_wrangling/wrangling_guidelines.feature index 138b246acac..837b0709ed2 100644 --- a/features/tags_and_wrangling/wrangling_guidelines.feature +++ b/features/tags_and_wrangling/wrangling_guidelines.feature @@ -6,7 +6,7 @@ Feature: Wrangling Guidelines Scenario: Post a Wrangling Guideline - Given I am logged in as an admin + Given I am logged in as a "tag_wrangling" admin And I am on the wrangling guidelines page And I follow "New Wrangling Guideline" And I fill in "Guideline text" with "This series of documents (Wrangling Guidelines) are intended to help tag wranglers remain consistent as they go about the business of wrangling tags by providing a set of formatting guidelines." @@ -29,7 +29,7 @@ Feature: Wrangling Guidelines Scenario: Reorder Wrangling Guidelines - Given I am logged in as an admin + Given I am logged in as a "tag_wrangling" admin And 3 Wrangling Guidelines exist When I go to the Wrangling Guidelines reorder page And I fill in "wrangling_guidelines_1" with "3" @@ -44,7 +44,7 @@ Feature: Wrangling Guidelines Scenario: Delete Wrangling Guideline - Given I am logged in as an admin + Given I am logged in as a "tag_wrangling" admin And I have posted a Wrangling Guideline titled "Relationship Tags" When I go to the Wrangling Guidelines page And I follow "Delete" diff --git a/spec/controllers/archive_faqs_controller_spec.rb b/spec/controllers/archive_faqs_controller_spec.rb index d7109cc5562..678a4c78508 100644 --- a/spec/controllers/archive_faqs_controller_spec.rb +++ b/spec/controllers/archive_faqs_controller_spec.rb @@ -6,6 +6,104 @@ include LoginMacros include RedirectExpectationHelper + fully_authorized_roles = %w[superadmin docs support] + + shared_examples "an action only fully authorized admins can access" do + before { fake_login_admin(admin) } + + context "with no role" do + let(:admin) { create(:admin, roles: []) } + + it "redirects with an error" do + subject + it_redirects_to_with_error(root_url, "Sorry, only an authorized admin can access the page you were trying to reach.") + end + end + + (Admin::VALID_ROLES - fully_authorized_roles).each do |role| + context "with role #{role}" do + let(:admin) { create(:admin, roles: [role]) } + + it "redirects with an error" do + subject + it_redirects_to_with_error(root_url, "Sorry, only an authorized admin can access the page you were trying to reach.") + end + end + end + + fully_authorized_roles.each do |role| + context "with role #{role}" do + let(:admin) { create(:admin, roles: [role]) } + + it "succeeds" do + subject + success + end + end + end + end + + translation_authorized_roles = %w[superadmin docs support translation] + + shared_examples "an action translation authorized admins can access" do + before { fake_login_admin(admin) } + + context "with no role" do + let(:admin) { create(:admin, roles: []) } + + it "redirects with an error" do + subject + it_redirects_to_with_error(root_url, "Sorry, only an authorized admin can access the page you were trying to reach.") + end + end + + (Admin::VALID_ROLES - translation_authorized_roles).each do |role| + context "with role #{role}" do + let(:admin) { create(:admin, roles: [role]) } + + it "redirects with an error" do + subject + it_redirects_to_with_error(root_url, "Sorry, only an authorized admin can access the page you were trying to reach.") + end + end + end + + translation_authorized_roles.each do |role| + context "with role #{role}" do + let(:admin) { create(:admin, roles: [role]) } + + it "succeeds" do + subject + success + end + end + end + end + + shared_examples "a non-English action that nobody can access" do + before { fake_login_admin(admin) } + + context "with no role" do + let(:admin) { create(:admin, roles: []) } + + it "redirects with an error" do + subject + it_redirects_to_with_error(archive_faqs_path, "Sorry, this action is only available for English FAQs.") + end + end + + Admin::VALID_ROLES.each do |role| + context "with role #{role}" do + let(:admin) { create(:admin, roles: [role]) } + + it "redirects with an error" do + subject + it_redirects_to_with_error(archive_faqs_path, "Sorry, this action is only available for English FAQs.") + end + end + end + end + let(:non_standard_locale) { create(:locale) } let(:user_locale) { create(:locale) } let(:user) do @@ -112,7 +210,8 @@ describe "GET #show" do it "raises a 404 for an invalid id" do params = { id: "angst", language_id: "en" } - expect { get :show, params: params }.to raise_error ActiveRecord::RecordNotFound + expect { get :show, params: params } + .to raise_exception(ActiveRecord::RecordNotFound) end end @@ -135,5 +234,155 @@ "The specified locale does not exist.") end end + + subject { patch :update, params: { id: faq, archive_faq: { title: "Changed" }, language_id: locale } } + let(:success) do + I18n.with_locale(locale) do + expect { faq.reload } + .to change { faq.title } + end + it_redirects_to_with_notice(faq, "Archive FAQ was successfully updated.") + end + + context "for the default locale" do + let(:locale) { "en" } + it_behaves_like "an action only fully authorized admins can access" + end + + context "for a non-default locale" do + let(:locale) { non_standard_locale.iso } + it_behaves_like "an action translation authorized admins can access" + end + end + + describe "GET #edit" do + subject { get :edit, params: { id: faq, language_id: locale } } + let(:faq) { create(:archive_faq) } + let(:success) do + expect(response).to render_template(:edit) + end + + context "for the default locale" do + let(:locale) { "en" } + it_behaves_like "an action only fully authorized admins can access" + end + + context "for a non-default locale" do + let(:locale) { non_standard_locale.iso } + it_behaves_like "an action translation authorized admins can access" + end + end + + describe "GET #new" do + subject { get :new, params: { language_id: locale } } + let(:success) do + expect(response).to render_template(:new) + end + + context "for the default locale" do + let(:locale) { "en" } + it_behaves_like "an action only fully authorized admins can access" + end + + context "for a non-default locale" do + let(:locale) { non_standard_locale.iso } + it_behaves_like "a non-English action that nobody can access" + end + end + + describe "POST #create" do + subject { post :create, params: { archive_faq: attributes_for(:archive_faq), language_id: locale } } + let(:success) do + expect(ArchiveFaq.count).to eq(1) + it_redirects_to_with_notice(assigns[:archive_faq], "Archive FAQ was successfully created.") + end + + context "for the default locale" do + let(:locale) { I18n.default_locale } + it_behaves_like "an action only fully authorized admins can access" + end + + context "for a non-default locale" do + let(:locale) { non_standard_locale.iso } + it_behaves_like "a non-English action that nobody can access" + end + end + + describe "GET #manage" do + subject { get :manage, params: { language_id: locale } } + let(:success) do + expect(response).to render_template(:manage) + end + + context "for the default locale" do + let(:locale) { "en" } + it_behaves_like "an action only fully authorized admins can access" + end + + context "for a non-default locale" do + let(:locale) { non_standard_locale.iso } + it_behaves_like "a non-English action that nobody can access" + end + end + + describe "POST #update_positions" do + subject { post :update_positions, params: { archive_faqs: [3, 1, 2], language_id: locale } } + let!(:faq1) { create(:archive_faq, position: 1) } + let!(:faq2) { create(:archive_faq, position: 2) } + let!(:faq3) { create(:archive_faq, position: 3) } + let(:success) do + expect(faq1.reload.position).to eq(3) + expect(faq2.reload.position).to eq(1) + expect(faq3.reload.position).to eq(2) + it_redirects_to_with_notice(archive_faqs_path, "Archive FAQs order was successfully updated.") + end + + context "for the default locale" do + let(:locale) { I18n.default_locale } + it_behaves_like "an action only fully authorized admins can access" + end + + context "for a non-default locale" do + let(:locale) { non_standard_locale.iso } + it_behaves_like "a non-English action that nobody can access" + end + end + + describe "GET #confirm_delete" do + subject { get :confirm_delete, params: { id: faq, language_id: locale } } + let(:faq) { create(:archive_faq) } + let(:success) do + expect(response).to render_template(:confirm_delete) + end + + context "for the default locale" do + let(:locale) { "en" } + it_behaves_like "an action only fully authorized admins can access" + end + + context "for a non-default locale" do + let(:locale) { non_standard_locale.iso } + it_behaves_like "a non-English action that nobody can access" + end + end + + describe "DELETE #destroy" do + subject { delete :destroy, params: { id: faq, language_id: locale } } + let(:faq) { create(:archive_faq) } + let(:success) do + expect { faq.reload } + .to raise_exception(ActiveRecord::RecordNotFound) + it_redirects_to(archive_faqs_path) + end + + context "for the default locale" do + let(:locale) { I18n.default_locale } + it_behaves_like "an action only fully authorized admins can access" + end + + context "for a non-default locale" do + let(:locale) { non_standard_locale.iso } + it_behaves_like "a non-English action that nobody can access" + end end end diff --git a/spec/controllers/inbox_controller_spec.rb b/spec/controllers/inbox_controller_spec.rb index 21815b1bbd7..9e29317db9e 100644 --- a/spec/controllers/inbox_controller_spec.rb +++ b/spec/controllers/inbox_controller_spec.rb @@ -19,6 +19,111 @@ "Sorry, you don't have permission to access the page you were trying to reach.") end + context "when logged in as an admin" do + context "when the admin does not have the correct authorization" do + context "when the admin has no role" do + let(:admin) { create(:admin, roles: []) } + + before { fake_login_admin(admin) } + + it "redirects with error" do + get :show, params: { user_id: user.login } + + it_redirects_to_with_error(root_path, "Sorry, only an authorized admin can access the page you were trying to reach.") + end + end + + (Admin::VALID_ROLES - %w[superadmin policy_and_abuse]).each do |role| + context "when the admin has the #{role} role" do + let(:admin) { create(:admin, roles: [role]) } + + before { fake_login_admin(admin) } + + it "redirects with error" do + get :show, params: { user_id: user.login } + + it_redirects_to_with_error(root_path, "Sorry, only an authorized admin can access the page you were trying to reach.") + end + end + end + end + + %w[superadmin policy_and_abuse].each do |role| + context "when the admin is authorized with the #{role} role" do + let(:admin) { create(:admin, roles: [role]) } + + before { fake_login_admin(admin) } + + it "renders the user inbox" do + get :show, params: { user_id: user.login } + expect(response).to render_template("show") + expect(assigns(:inbox_total)).to eq(0) + expect(assigns(:unread)).to eq(0) + end + + context "with unread comments" do + let!(:inbox_comments) do + Array.new(3) do |i| + create(:inbox_comment, user: user, created_at: Time.now.utc + i.days) + end + end + + it "renders non-zero unread count" do + get :show, params: { user_id: user.login } + expect(assigns(:inbox_comments)).to eq(inbox_comments.reverse) + expect(assigns(:inbox_total)).to eq(3) + expect(assigns(:unread)).to eq(3) + end + + it "renders oldest first" do + get :show, params: { user_id: user.login, filters: { date: "asc" } } + expect(assigns(:filters)[:date]).to eq("asc") + expect(assigns(:inbox_comments)).to eq(inbox_comments) + expect(assigns(:inbox_total)).to eq(3) + expect(assigns(:unread)).to eq(3) + end + end + + context "with 1 read and 1 unread" do + let!(:read_comment) { create(:inbox_comment, user: user, read: true) } + let!(:unread_comment) { create(:inbox_comment, user: user) } + + it "renders only unread" do + get :show, params: { user_id: user.login, filters: { read: "false" } } + expect(assigns(:filters)[:read]).to eq("false") + expect(assigns(:inbox_comments)).to eq([unread_comment]) + expect(assigns(:inbox_total)).to eq(2) + expect(assigns(:unread)).to eq(1) + end + end + + context "with 1 replied and 1 unreplied" do + let!(:replied_comment) { create(:inbox_comment, user: user, replied_to: true) } + let!(:unreplied_comment) { create(:inbox_comment, user: user) } + + it "renders only unreplied" do + get :show, params: { user_id: user.login, filters: { replied_to: "false" } } + expect(assigns(:filters)[:replied_to]).to eq("false") + expect(assigns(:inbox_comments)).to eq([unreplied_comment]) + expect(assigns(:inbox_total)).to eq(2) + expect(assigns(:unread)).to eq(2) + end + end + + context "with a deleted comment" do + let(:inbox_comment) { create(:inbox_comment, user: user) } + + it "excludes deleted comments" do + inbox_comment.feedback_comment.destroy! + get :show, params: { user_id: user.login } + expect(assigns(:inbox_total)).to eq(0) + expect(assigns(:unread)).to eq(0) + end + end + end + end + end + context "when logged in as the same user" do before { fake_login_known_user(user) } @@ -82,7 +187,7 @@ let(:inbox_comment) { create(:inbox_comment, user: user) } it "excludes deleted comments" do - inbox_comment.feedback_comment.destroy + inbox_comment.feedback_comment.destroy! get :show, params: { user_id: user.login } expect(assigns(:inbox_total)).to eq(0) expect(assigns(:unread)).to eq(0) @@ -149,92 +254,107 @@ end describe "PUT #update" do - before { fake_login_known_user(user) } - - context "with no comments selected" do - it "redirects to inbox with caution and a notice" do - put :update, params: { user_id: user.login, read: "yeah" } - it_redirects_to_with_caution_and_notice(user_inbox_path(user), - "Please select something first", - "Inbox successfully updated.") - end - - it "redirects to the previously viewed page if HTTP_REFERER is set, with a caution and a notice" do - @request.env['HTTP_REFERER'] = root_path - put :update, params: { user_id: user.login, read: "yeah" } - it_redirects_to_with_caution_and_notice(root_path, - "Please select something first", - "Inbox successfully updated.") + %w[superadmin policy_and_abuse].each do |role| + context "when logged in as an admin with the role #{role}" do + let(:admin) { create(:admin, roles: [role]) } + + before { fake_login_admin(admin) } + + it "redirects to root with error" do + put :update, params: { user_id: user.login } + it_redirects_to_with_error(root_path, "Sorry, only an authorized admin can access the page you were trying to reach.") + end end end - context "with unread comments" do - let!(:inbox_comment_1) { create(:inbox_comment, user: user) } - let!(:inbox_comment_2) { create(:inbox_comment, user: user) } - - it "marks all as read and redirects to inbox with a notice" do - parameters = { - user_id: user.login, - inbox_comments: [inbox_comment_1.id, inbox_comment_2.id], - read: "yeah" - } + context "when logged in as the comment receiver" do + before { fake_login_known_user(user) } - put :update, params: parameters - it_redirects_to_with_notice(user_inbox_path(user), "Inbox successfully updated.") + context "with no comments selected" do + it "redirects to inbox with caution and a notice" do + put :update, params: { user_id: user.login, read: "yeah" } + it_redirects_to_with_caution_and_notice(user_inbox_path(user), + "Please select something first", + "Inbox successfully updated.") + end - inbox_comment_1.reload - expect(inbox_comment_1.read).to be_truthy - inbox_comment_2.reload - expect(inbox_comment_2.read).to be_truthy + it "redirects to the previously viewed page if HTTP_REFERER is set, with a caution and a notice" do + @request.env["HTTP_REFERER"] = root_path + put :update, params: { user_id: user.login, read: "yeah" } + it_redirects_to_with_caution_and_notice(root_path, + "Please select something first", + "Inbox successfully updated.") + end end - it "marks one as read and redirects to inbox with a notice" do - put :update, params: { user_id: user.login, inbox_comments: [inbox_comment_1.id], read: "yeah" } - it_redirects_to_with_notice(user_inbox_path(user), "Inbox successfully updated.") + context "with unread comments" do + let!(:inbox_comment1) { create(:inbox_comment, user: user) } + let!(:inbox_comment2) { create(:inbox_comment, user: user) } + + it "marks all as read and redirects to inbox with a notice" do + parameters = { + user_id: user.login, + inbox_comments: [inbox_comment1.id, inbox_comment2.id], + read: "yeah" + } + + put :update, params: parameters + it_redirects_to_with_notice(user_inbox_path(user), "Inbox successfully updated.") + + inbox_comment1.reload + expect(inbox_comment1.read).to be_truthy + inbox_comment2.reload + expect(inbox_comment2.read).to be_truthy + end - inbox_comment_1.reload - expect(inbox_comment_1.read).to be_truthy - inbox_comment_2.reload - expect(inbox_comment_2.read).to be_falsy - end + it "marks one as read and redirects to inbox with a notice" do + put :update, params: { user_id: user.login, inbox_comments: [inbox_comment1.id], read: "yeah" } + it_redirects_to_with_notice(user_inbox_path(user), "Inbox successfully updated.") - it "deletes one and redirects to inbox with a notice" do - put :update, params: { user_id: user.login, inbox_comments: [inbox_comment_1.id], delete: "yeah" } - it_redirects_to_with_notice(user_inbox_path(user), "Inbox successfully updated.") + inbox_comment1.reload + expect(inbox_comment1.read).to be_truthy + inbox_comment2.reload + expect(inbox_comment2.read).to be_falsy + end - expect(InboxComment.find_by(id: inbox_comment_1.id)).to be_nil - inbox_comment_2.reload - expect(inbox_comment_2.read).to be_falsy + it "deletes one and redirects to inbox with a notice" do + put :update, params: { user_id: user.login, inbox_comments: [inbox_comment1.id], delete: "yeah" } + it_redirects_to_with_notice(user_inbox_path(user), "Inbox successfully updated.") + + expect(InboxComment.find_by(id: inbox_comment1.id)).to be_nil + inbox_comment2.reload + expect(inbox_comment2.read).to be_falsy + end end - end - context "with a read comment and redirects to inbox with a notice" do - let!(:inbox_comment) { create(:inbox_comment, user: user, read: true) } + context "with a read comment and redirects to inbox with a notice" do + let!(:inbox_comment) { create(:inbox_comment, user: user, read: true) } - it "marks as unread and redirects to inbox with a notice" do - put :update, params: { user_id: user.login, inbox_comments: [inbox_comment.id], unread: "yeah" } - it_redirects_to_with_notice(user_inbox_path(user), "Inbox successfully updated.") + it "marks as unread and redirects to inbox with a notice" do + put :update, params: { user_id: user.login, inbox_comments: [inbox_comment.id], unread: "yeah" } + it_redirects_to_with_notice(user_inbox_path(user), "Inbox successfully updated.") - inbox_comment.reload - expect(inbox_comment.read).to be_falsy - end + inbox_comment.reload + expect(inbox_comment.read).to be_falsy + end - it "marks as unread and returns a JSON response" do - parameters = { - user_id: user.login, - inbox_comments: [inbox_comment.id], - unread: "yeah", - format: "json" - } + it "marks as unread and returns a JSON response" do + parameters = { + user_id: user.login, + inbox_comments: [inbox_comment.id], + unread: "yeah", + format: "json" + } - put :update, params: parameters + put :update, params: parameters - inbox_comment.reload - expect(inbox_comment.read).to be_falsy + inbox_comment.reload + expect(inbox_comment.read).to be_falsy - parsed_body = JSON.parse(response.body, symbolize_names: true) - expect(parsed_body[:item_success_message]).to eq("Inbox successfully updated.") - expect(response).to have_http_status(:success) + parsed_body = JSON.parse(response.body, symbolize_names: true) + expect(parsed_body[:item_success_message]).to eq("Inbox successfully updated.") + expect(response).to have_http_status(:success) + end end end end diff --git a/spec/controllers/known_issues_controller_spec.rb b/spec/controllers/known_issues_controller_spec.rb new file mode 100644 index 00000000000..13b797656b9 --- /dev/null +++ b/spec/controllers/known_issues_controller_spec.rb @@ -0,0 +1,187 @@ +# frozen_string_literal: true + +require "spec_helper" + +describe KnownIssuesController do + include LoginMacros + include RedirectExpectationHelper + + allowed_roles = %w[superadmin support] + + shared_examples "denies access to unauthorized admins" do + context "when logged in as an admin with no role" do + let(:admin) { create(:admin) } + + it "redirects with an error" do + it_redirects_to_with_error(root_url, "Sorry, only an authorized admin can access the page you were trying to reach.") + end + end + + (Admin::VALID_ROLES - allowed_roles).each do |admin_role| + context "when logged in as an admin with role #{admin_role}" do + let(:admin) { create(:admin, roles: [admin_role]) } + + it "redirects with an error" do + it_redirects_to_with_error(root_url, "Sorry, only an authorized admin can access the page you were trying to reach.") + end + end + end + end + + describe "GET #show" do + let(:known_issue) { create(:known_issue) } + + it_behaves_like "denies access to unauthorized admins" do + before do + fake_login_admin(admin) + get :show, params: { id: known_issue.id } + end + end + + allowed_roles.each do |admin_role| + context "when logged in as an admin with role #{admin_role}" do + let(:admin) { create(:admin, roles: [admin_role]) } + + before do + fake_login_admin(admin) + end + + it "allows access" do + get :show, params: { id: known_issue.id } + expect(response).to have_http_status(:success) + end + end + end + end + + describe "GET #new" do + it_behaves_like "denies access to unauthorized admins" do + before do + fake_login_admin(admin) + get :new + end + end + + allowed_roles.each do |admin_role| + context "when logged in as an admin with role #{admin_role}" do + let(:admin) { create(:admin, roles: [admin_role]) } + + before do + fake_login_admin(admin) + end + + it "allows access" do + get :new + expect(response).to have_http_status(:success) + end + end + end + end + + describe "GET #edit" do + let(:known_issue) { create(:known_issue) } + + it_behaves_like "denies access to unauthorized admins" do + before do + fake_login_admin(admin) + get :edit, params: { id: known_issue.id } + end + end + + allowed_roles.each do |admin_role| + context "when logged in as an admin with role #{admin_role}" do + let(:admin) { create(:admin, roles: [admin_role]) } + + before do + fake_login_admin(admin) + end + + it "allows access" do + get :edit, params: { id: known_issue.id } + expect(response).to have_http_status(:success) + end + end + end + end + + describe "POST #create" do + let(:params) { { known_issue: attributes_for(:known_issue) } } + + it_behaves_like "denies access to unauthorized admins" do + before do + fake_login_admin(admin) + post :create, params: params + end + end + + allowed_roles.each do |admin_role| + context "when logged in as an admin with role #{admin_role}" do + let(:admin) { create(:admin, roles: [admin_role]) } + + before do + fake_login_admin(admin) + end + + it "creates a known issue" do + expect { post :create, params: params } + .to change { KnownIssue.count } + .by(1) + end + end + end + end + + describe "PUT #update" do + let(:known_issue) { create(:known_issue) } + let(:params) { { id: known_issue.id, known_issue: { title: "Brand new title" } } } + + it_behaves_like "denies access to unauthorized admins" do + before do + fake_login_admin(admin) + put :update, params: params + end + end + + allowed_roles.each do |admin_role| + context "when logged in as an admin with role #{admin_role}" do + let(:admin) { create(:admin, roles: [admin_role]) } + + before do + fake_login_admin(admin) + end + + it "updates the known issue successfully" do + put :update, params: params + expect(known_issue.reload.title).to eq("Brand new title") + end + end + end + end + + describe "DELETE #destroy" do + let(:known_issue) { create(:known_issue) } + + it_behaves_like "denies access to unauthorized admins" do + before do + fake_login_admin(admin) + delete :destroy, params: { id: known_issue.id } + end + end + + allowed_roles.each do |admin_role| + context "when logged in as an admin with role #{admin_role}" do + let(:admin) { create(:admin, roles: [admin_role]) } + + before do + fake_login_admin(admin) + end + + it "deletes the known issue" do + delete :destroy, params: { id: known_issue.id } + expect { known_issue.reload } + .to raise_exception(ActiveRecord::RecordNotFound) + end + end + end + end +end diff --git a/spec/controllers/questions_controller_spec.rb b/spec/controllers/questions_controller_spec.rb new file mode 100644 index 00000000000..8cf8e4086da --- /dev/null +++ b/spec/controllers/questions_controller_spec.rb @@ -0,0 +1,71 @@ +# frozen_string_literal: true + +require "spec_helper" + +describe QuestionsController do + include LoginMacros + include RedirectExpectationHelper + + fully_authorized_roles = %w[superadmin docs support] + + shared_examples "an action only fully authorized admins can access" do + before { fake_login_admin(admin) } + + context "with no role" do + let(:admin) { create(:admin, roles: []) } + + it "redirects with an error" do + subject + it_redirects_to_with_error(root_url, "Sorry, only an authorized admin can access the page you were trying to reach.") + end + end + + (Admin::VALID_ROLES - fully_authorized_roles).each do |role| + context "with role #{role}" do + let(:admin) { create(:admin, roles: [role]) } + + it "redirects with an error" do + subject + it_redirects_to_with_error(root_url, "Sorry, only an authorized admin can access the page you were trying to reach.") + end + end + end + + fully_authorized_roles.each do |role| + context "with role #{role}" do + let(:admin) { create(:admin, roles: [role]) } + + it "succeeds" do + subject + success + end + end + end + end + + describe "GET #manage" do + let(:faq) { create(:archive_faq) } + subject { get :manage, params: { archive_faq_id: faq } } + let(:success) do + expect(response).to render_template(:manage) + end + + it_behaves_like "an action only fully authorized admins can access" + end + + describe "POST #update_positions" do + let(:faq) { create(:archive_faq) } + let!(:question1) { create(:question, archive_faq: faq, position: 1) } + let!(:question2) { create(:question, archive_faq: faq, position: 2) } + let!(:question3) { create(:question, archive_faq: faq, position: 3) } + subject { post :update_positions, params: { archive_faq_id: faq, questions: [3, 1, 2] } } + let(:success) do + expect(question1.reload.position).to eq(3) + expect(question2.reload.position).to eq(1) + expect(question3.reload.position).to eq(2) + it_redirects_to_with_notice(faq, "Question order has been successfully updated.") + end + + it_behaves_like "an action only fully authorized admins can access" + end +end diff --git a/spec/controllers/tag_wranglings_controller_spec.rb b/spec/controllers/tag_wranglings_controller_spec.rb index 26d24190301..581a1772925 100644 --- a/spec/controllers/tag_wranglings_controller_spec.rb +++ b/spec/controllers/tag_wranglings_controller_spec.rb @@ -4,60 +4,144 @@ include LoginMacros include RedirectExpectationHelper - before do - fake_login - controller.current_user.roles << Role.new(name: "tag_wrangler") + full_access_roles = %w[superadmin tag_wrangling].freeze + read_access_roles = %w[superadmin policy_and_abuse tag_wrangling].freeze + + shared_examples "an action only authorized admins can access" do |authorized_roles:| + before do + fake_login_admin(admin) + end + + context "when logged in as an admin with no role" do + let(:admin) { create(:admin) } + + it "redirects with an error" do + subject + it_redirects_to_with_error(root_url, "Sorry, only an authorized admin can access the page you were trying to reach.") + end + end + + (Admin::VALID_ROLES - authorized_roles).each do |admin_role| + context "when logged in as an admin with role #{admin_role}" do + let(:admin) { create(:admin, roles: [admin_role]) } + + it "redirects with an error" do + subject + it_redirects_to_with_error(root_url, "Sorry, only an authorized admin can access the page you were trying to reach.") + end + end + end + + authorized_roles.each do |admin_role| + context "when logged in as an admin with role #{admin_role}" do + let(:admin) { create(:admin, roles: [admin_role]) } + + it "succeeds" do + subject + success + end + end + end end - shared_examples "set last wrangling activity" do - it "sets the last wrangling activity time to now", :frozen do - user = controller.current_user - expect(user.last_wrangling_activity.updated_at).to eq(Time.now.utc) + describe "GET #index" do + let(:success) { expect(response).to have_http_status(:success) } + + context "when the show parameter is absent" do + subject { get :index } + + it_behaves_like "an action only authorized admins can access", authorized_roles: read_access_roles + + context "when logged in as a tag wrangler" do + before do + fake_login_known_user(create(:tag_wrangler)) + end + + it "shows the wrangling tools page" do + subject + success + end + end + end + + context "when the show parameter is present" do + subject { get :index, params: { show: "fandoms" } } + + it_behaves_like "an action only authorized admins can access", authorized_roles: read_access_roles + + context "when logged in as a tag wrangler" do + before do + fake_login_known_user(create(:tag_wrangler)) + end + + it "shows the wrangling tools page" do + subject + success + end + end end end - describe "#wrangle" do - let(:page_options) { { page: 1, sort_column: "name", sort_direction: "ASC" } } + describe "POST #wrangle" do + shared_examples "set last wrangling activity" do + before do + fake_login_known_user(create(:tag_wrangler)) + subject + end + + it "sets the last wrangling activity time to now", :frozen do + user = controller.current_user + expect(user.last_wrangling_activity.updated_at).to eq(Time.now.utc) + end + end it "displays error when there are no fandoms to wrangle to" do + fake_login_known_user(create(:tag_wrangler)) character = create(:character) + page_options = { page: 1, sort_column: "name", sort_direction: "ASC" } post :wrangle, params: { fandom_string: "", selected_tags: [character.id] } it_redirects_to_with_error(tag_wranglings_path(page_options), "There were no Fandom tags!") end context "when making tags canonical" do + subject { post :wrangle, params: { canonicals: [tag1.id, tag2.id] } } let(:tag1) { create(:character) } let(:tag2) { create(:character) } - - before do - post :wrangle, params: { canonicals: [tag1.id, tag2.id] } + let(:success) do + expect(tag1.reload.canonical?).to be(true) + expect(tag2.reload.canonical?).to be(true) end - include_examples "set last wrangling activity" + it_behaves_like "set last wrangling activity" + it_behaves_like "an action only authorized admins can access", authorized_roles: full_access_roles end context "when assigning tags to a medium" do + subject { post :wrangle, params: { media: medium.name, selected_tags: [fandom1.id, fandom2.id] } } let(:fandom1) { create(:fandom, canonical: true) } let(:fandom2) { create(:fandom, canonical: true) } let(:medium) { create(:media) } - - before do - post :wrangle, params: { media: medium.name, selected_tags: [fandom1.id, fandom2.id] } + let(:success) do + expect(fandom1.medias).to include(medium) + expect(fandom2.medias).to include(medium) end - include_examples "set last wrangling activity" + it_behaves_like "set last wrangling activity" + it_behaves_like "an action only authorized admins can access", authorized_roles: full_access_roles end context "when adding tags to a fandom" do + subject { post :wrangle, params: { fandom_string: fandom.name, selected_tags: [tag1.id, tag2.id] } } let(:tag1) { create(:character) } let(:tag2) { create(:character) } let(:fandom) { create(:fandom, canonical: true) } - - before do - post :wrangle, params: { fandom_string: fandom.name, selected_tags: [tag1.id, tag2.id] } + let(:success) do + expect(tag1.fandoms).to include(fandom) + expect(tag2.fandoms).to include(fandom) end - include_examples "set last wrangling activity" + it_behaves_like "set last wrangling activity" + it_behaves_like "an action only authorized admins can access", authorized_roles: full_access_roles end end end diff --git a/spec/controllers/tags_controller_spec.rb b/spec/controllers/tags_controller_spec.rb index 9be54190b26..d5a174e9ab2 100644 --- a/spec/controllers/tags_controller_spec.rb +++ b/spec/controllers/tags_controller_spec.rb @@ -1,9 +1,12 @@ -require 'spec_helper' +require "spec_helper" describe TagsController do include LoginMacros include RedirectExpectationHelper + wrangling_full_access_roles = %w[superadmin tag_wrangling].freeze + wrangling_read_access_roles = (wrangling_full_access_roles + %w[policy_and_abuse]).freeze + let(:user) { create(:tag_wrangler) } before { fake_login_known_user(user) } @@ -14,6 +17,41 @@ end end + shared_examples "an action only authorized admins can access" do |authorized_roles:| + before { fake_login_admin(admin) } + + context "with no role" do + let(:admin) { create(:admin, roles: []) } + + it "redirects with an error" do + subject + it_redirects_to_with_error(root_url, "Sorry, only an authorized admin can access the page you were trying to reach.") + end + end + + (Admin::VALID_ROLES - authorized_roles).each do |role| + context "with role #{role}" do + let(:admin) { create(:admin, roles: [role]) } + + it "redirects with an error" do + subject + it_redirects_to_with_error(root_url, "Sorry, only an authorized admin can access the page you were trying to reach.") + end + end + end + + authorized_roles.each do |role| + context "with role #{role}" do + let(:admin) { create(:admin, roles: [role]) } + + it "succeeds" do + subject + success + end + end + end + end + describe "#create" do let(:tag_params) do { name: Faker::FunnyName.name, canonical: "0", type: "Character" } @@ -72,6 +110,13 @@ run_all_indexing_jobs end + subject { get :wrangle, params: { id: fandom.name, show: "freeforms", status: "unwrangled" } } + let(:success) do + expect(assigns(:tags)).to include(freeform1) + end + + it_behaves_like "an action only authorized admins can access", authorized_roles: wrangling_read_access_roles + it "includes unwrangled freeforms" do get :wrangle, params: { id: fandom.name, show: "freeforms", status: "unwrangled" } expect(assigns(:tags)).to include(freeform1) @@ -121,40 +166,35 @@ @character3 = FactoryBot.create(:character, canonical: false) @character2 = FactoryBot.create(:character, canonical: false, merger: @character3) @work = FactoryBot.create(:work, - fandom_string: "#{@fandom1.name}", - character_string: "#{@character1.name},#{@character2.name}", - freeform_string: "#{@freeform1.name}") + fandom_string: @fandom1.name.to_s, + character_string: "#{@character1.name},#{@character2.name}", + freeform_string: @freeform1.name.to_s) end it "should redirect to the wrangle action for that tag" do - expect(put :mass_update, params: { id: @fandom1.name, show: 'freeforms', status: 'unwrangled' }). - to redirect_to wrangle_tag_path(id: @fandom1.name, - show: 'freeforms', - status: 'unwrangled', - page: 1, - sort_column: 'name', - sort_direction: 'ASC') + expect(put(:mass_update, params: { id: @fandom1.name, show: "freeforms", status: "unwrangled" })) + .to redirect_to wrangle_tag_path(id: @fandom1.name, + show: "freeforms", + status: "unwrangled", + page: 1, + sort_column: "name", + sort_direction: "ASC") end - context "with one canonical fandom in the fandom string and a selected freeform" do - before do - put :mass_update, params: { id: @fandom1.name, show: 'freeforms', status: 'unwrangled', fandom_string: @fandom2.name, selected_tags: [@freeform1.id] } - end - - it "updates the tags successfully" do - get :wrangle, params: { id: @fandom1.name, show: 'freeforms', status: 'unwrangled' } - expect(assigns(:tags)).not_to include(@freeform1) - - @freeform1.reload - expect(@freeform1.fandoms).to include(@fandom2) - end + subject { put :mass_update, params: { id: @fandom1.name, show: "freeforms", status: "unwrangled", fandom_string: @fandom2.name, selected_tags: [@freeform1.id] } } + let(:success) do + get :wrangle, params: { id: @fandom1.name, show: "freeforms", status: "unwrangled" } + expect(assigns(:tags)).not_to include(@freeform1) - include_examples "set last wrangling activity" + @freeform1.reload + expect(@freeform1.fandoms).to include(@fandom2) end + it_behaves_like "an action only authorized admins can access", authorized_roles: wrangling_full_access_roles + context "with one canonical and one noncanonical fandoms in the fandom string and a selected freeform" do before do - put :mass_update, params: { id: @fandom1.name, show: 'freeforms', status: 'unwrangled', fandom_string: "#{@fandom2.name},#{@fandom3.name}", selected_tags: [@freeform1.id] } + put :mass_update, params: { id: @fandom1.name, show: "freeforms", status: "unwrangled", fandom_string: "#{@fandom2.name},#{@fandom3.name}", selected_tags: [@freeform1.id] } end it "updates the tags successfully" do @@ -168,7 +208,7 @@ context "with two canonical fandoms in the fandom string and a selected character" do before do - put :mass_update, params: { id: @fandom1.name, show: 'characters', status: 'unwrangled', fandom_string: "#{@fandom1.name},#{@fandom2.name}", selected_tags: [@character1.id] } + put :mass_update, params: { id: @fandom1.name, show: "characters", status: "unwrangled", fandom_string: "#{@fandom1.name},#{@fandom2.name}", selected_tags: [@character1.id] } end it "updates the tags successfully" do @@ -182,7 +222,7 @@ context "with a canonical fandom in the fandom string, a selected unwrangled character, and the same character to be made canonical" do before do - put :mass_update, params: { id: @fandom1.name, show: 'characters', status: 'unwrangled', fandom_string: "#{@fandom1.name}", selected_tags: [@character1.id], canonicals: [@character1.id] } + put :mass_update, params: { id: @fandom1.name, show: "characters", status: "unwrangled", fandom_string: @fandom1.name.to_s, selected_tags: [@character1.id], canonicals: [@character1.id] } end it "updates the tags successfully" do @@ -196,7 +236,7 @@ context "with a canonical fandom in the fandom string, a selected synonym character, and the same character to be made canonical" do before do - put :mass_update, params: { id: @fandom1.name, show: 'characters', status: 'unfilterable', fandom_string: "#{@fandom2.name}", selected_tags: [@character2.id], canonicals: [@character2.id] } + put :mass_update, params: { id: @fandom1.name, show: "characters", status: "unfilterable", fandom_string: @fandom2.name.to_s, selected_tags: [@character2.id], canonicals: [@character2.id] } end it "updates the tags successfully" do @@ -231,6 +271,41 @@ end end + describe "new" do + subject { get :new } + let(:success) do + expect(response).to have_http_status(:success) + end + + it_behaves_like "an action only authorized admins can access", authorized_roles: wrangling_full_access_roles + + context "when logged in as a tag wrangler" do + it "allows access" do + get :new + expect(response).to have_http_status(:success) + end + end + end + + describe "show" do + context "when showing a banned tag" do + let(:tag) { create(:banned) } + + subject { get :edit, params: { id: tag.name } } + let(:success) do + expect(response).to have_http_status(:success) + end + + it_behaves_like "an action only authorized admins can access", authorized_roles: wrangling_read_access_roles + + it "redirects with an error when not an admin" do + get :show, params: { id: tag.name } + it_redirects_to_with_error(tag_wranglings_path, + "Please log in as admin") + end + end + end + describe "show_hidden" do let(:work) { create(:work) } @@ -251,12 +326,17 @@ describe "edit" do context "when editing a banned tag" do - before do - @tag = FactoryBot.create(:banned) + let(:tag) { create(:banned) } + + subject { get :edit, params: { id: tag.name } } + let(:success) do + expect(response).to have_http_status(:success) end + it_behaves_like "an action only authorized admins can access", authorized_roles: wrangling_read_access_roles + it "redirects with an error when not an admin" do - get :edit, params: { id: @tag.name } + get :edit, params: { id: tag.name } it_redirects_to_with_error(tag_wranglings_path, "Please log in as admin") end @@ -299,16 +379,15 @@ end end - context "when logged in as an admin" do - it "succeeds and redirects to the edit page" do - fake_login_admin(create(:admin)) - put :update, params: { id: tag, tag: { syn_string: synonym.name }, commit: "Save changes" } - it_redirects_to_with_notice(edit_tag_path(tag), "Tag was updated.") - - tag.reload - expect(tag.merger_id).to eq(synonym.id) - end + subject { put :update, params: { id: tag, tag: { syn_string: synonym.name }, commit: "Save changes" } } + let(:success) do + it_redirects_to_with_notice(edit_tag_path(tag), "Tag was updated.") + tag.reload + expect(tag.merger_id).to eq(synonym.id) end + + it_behaves_like "an action only authorized admins can access", authorized_roles: wrangling_full_access_roles + end shared_examples "success message" do @@ -369,7 +448,7 @@ end context "when the associated tag has an invalid type" do - # NOTE This will enter the associated tag into the freeform_string + # NOTE: This will enter the associated tag into the freeform_string # field, which is not displayed on the form. This still might come up # in the extremely rare case where a tag wrangler loads the form, a # different tag wrangler goes in and changes the type of the tag being diff --git a/spec/controllers/unsorted_tags_controller_spec.rb b/spec/controllers/unsorted_tags_controller_spec.rb new file mode 100644 index 00000000000..4748903e243 --- /dev/null +++ b/spec/controllers/unsorted_tags_controller_spec.rb @@ -0,0 +1,63 @@ +# frozen_string_literal: true + +require "spec_helper" + +describe UnsortedTagsController do + include LoginMacros + include RedirectExpectationHelper + + describe "POST #mass_update" do + context "when accessing as a guest" do + before do + post :mass_update + end + + it "redirects with an error" do + it_redirects_to_with_error( + new_user_session_path, + "Sorry, you don't have permission to access the page you were trying to reach. Please log in." + ) + end + end + + context "when logged in as a non-tag-wrangler user" do + let(:user) { create(:user) } + + before do + fake_login_known_user(user) + post :mass_update + end + + it "redirects with an error" do + it_redirects_to_with_error( + user_path(user), + "Sorry, you don't have permission to access the page you were trying to reach." + ) + end + end + + context "when logged in as an admin with no roles" do + before do + fake_login_admin(create(:admin)) + post :mass_update + end + + it "redirects with an error" do + it_redirects_to_with_error(root_path, "Sorry, only an authorized admin can access the page you were trying to reach.") + end + end + + (Admin::VALID_ROLES - %w[superadmin tag_wrangling]).each do |admin_role| + context "when logged in as a #{admin_role} admin" do + before do + fake_login_admin(create(:admin, roles: [admin_role])) + post :mass_update + end + + it "redirects with an error" do + it_redirects_to_with_error(root_path, "Sorry, only an authorized admin can access the page you were trying to reach.") + end + end + end + end +end diff --git a/spec/controllers/wrangling_guidelines_controller_spec.rb b/spec/controllers/wrangling_guidelines_controller_spec.rb index f87eb72de2e..c66430023ac 100644 --- a/spec/controllers/wrangling_guidelines_controller_spec.rb +++ b/spec/controllers/wrangling_guidelines_controller_spec.rb @@ -7,14 +7,14 @@ let(:admin) { create(:admin) } describe "GET #index" do - let!(:guideline_1) { create(:wrangling_guideline, position: 9001) } - let!(:guideline_2) { create(:wrangling_guideline, position: 2) } - let!(:guideline_3) { create(:wrangling_guideline, position: 7) } + let!(:guideline1) { create(:wrangling_guideline, position: 9001) } + let!(:guideline2) { create(:wrangling_guideline, position: 2) } + let!(:guideline3) { create(:wrangling_guideline, position: 7) } it "renders" do get :index expect(response).to render_template("index") - expect(assigns(:wrangling_guidelines)).to eq([guideline_2, guideline_3, guideline_1]) + expect(assigns(:wrangling_guidelines)).to eq([guideline2, guideline3, guideline1]) end end @@ -39,13 +39,28 @@ it_redirects_to_with_notice(root_path, "I'm sorry, only an admin can look at that area") end - context "when logged in as admin" do - before { fake_login_admin(admin) } + %w[board communications translation policy_and_abuse docs support open_doors].each do |role| + context "when logged in as an admin with #{role} role" do + let(:admin) { create(:admin, roles: [role]) } - it "renders" do - get :new - expect(response).to render_template("new") - expect(assigns(:wrangling_guideline)).to be_a_new(WranglingGuideline) + it "redirects with error" do + fake_login_admin(admin) + get :new + it_redirects_to_with_error(root_url, "Sorry, only an authorized admin can access the page you were trying to reach.") + end + end + end + + %w[tag_wrangling superadmin].each do |role| + context "when logged in as an admin with #{role} role" do + let(:admin) { create(:admin, roles: [role]) } + + it "renders" do + fake_login_admin(admin) + get :new + expect(response).to render_template("new") + expect(assigns(:wrangling_guideline)).to be_a_new(WranglingGuideline) + end end end end @@ -61,15 +76,32 @@ it_redirects_to_with_notice(root_path, "I'm sorry, only an admin can look at that area") end - context "when logged in as admin" do - let(:guideline) { create(:wrangling_guideline) } + %w[board communications translation policy_and_abuse docs support open_doors].each do |role| + context "when logged in as an admin with #{role} role" do + let(:guideline) { create(:wrangling_guideline) } + let(:admin) { create(:admin, roles: [role]) } + + before { fake_login_admin(admin) } + + it "redirects with error" do + get :edit, params: { id: guideline.id } + it_redirects_to_with_error(root_url, "Sorry, only an authorized admin can access the page you were trying to reach.") + end + end + end + + %w[tag_wrangling superadmin].each do |role| + context "when logged in as an admin with #{role} role" do + let(:guideline) { create(:wrangling_guideline) } + let(:admin) { create(:admin, roles: [role]) } - before { fake_login_admin(admin) } + before { fake_login_admin(admin) } - it "renders" do - get :edit, params: { id: guideline.id } - expect(response).to render_template("edit") - expect(assigns(:wrangling_guideline)).to eq(guideline) + it "renders" do + get :edit, params: { id: guideline.id } + expect(response).to render_template("edit") + expect(assigns(:wrangling_guideline)).to eq(guideline) + end end end end @@ -85,17 +117,33 @@ it_redirects_to_with_notice(root_path, "I'm sorry, only an admin can look at that area") end - context "when logged in as admin" do - let!(:guideline_1) { create(:wrangling_guideline, position: 9001) } - let!(:guideline_2) { create(:wrangling_guideline, position: 2) } - let!(:guideline_3) { create(:wrangling_guideline, position: 7) } + %w[board communications translation policy_and_abuse docs support open_doors].each do |role| + context "when logged in as an admin with #{role} role" do + let(:admin) { create(:admin, roles: [role]) } + + before { fake_login_admin(admin) } + + it "redirects with error" do + get :manage + it_redirects_to_with_error(root_url, "Sorry, only an authorized admin can access the page you were trying to reach.") + end + end + end + + %w[tag_wrangling superadmin].each do |role| + context "when logged in as an admin with #{role} role" do + let!(:guideline1) { create(:wrangling_guideline, position: 9001) } + let!(:guideline2) { create(:wrangling_guideline, position: 2) } + let!(:guideline3) { create(:wrangling_guideline, position: 7) } + let(:admin) { create(:admin, roles: [role]) } - before { fake_login_admin(admin) } + before { fake_login_admin(admin) } - it "renders" do - get :manage - expect(response).to render_template("manage") - expect(assigns(:wrangling_guidelines)).to eq([guideline_2, guideline_3, guideline_1]) + it "renders" do + get :manage + expect(response).to render_template("manage") + expect(assigns(:wrangling_guidelines)).to eq([guideline2, guideline3, guideline1]) + end end end end @@ -111,24 +159,43 @@ it_redirects_to_with_notice(root_path, "I'm sorry, only an admin can look at that area") end - context "when logged in as admin" do - before { fake_login_admin(admin) } + %w[board communications translation policy_and_abuse docs support open_doors].each do |role| + context "when logged in as an admin with #{role} role" do + let(:admin) { create(:admin, roles: [role]) } - it "creates and redirects to new wrangling guideline" do - title = "Wrangling 101" - content = "JUST DO IT!" - post :create, params: { wrangling_guideline: { title: title, content: content } } + before { fake_login_admin(admin) } - guideline = WranglingGuideline.find_by_title(title) - expect(assigns(:wrangling_guideline)).to eq(guideline) - expect(assigns(:wrangling_guideline).content).to eq(sanitize_value("content", content)) - it_redirects_to_with_notice(wrangling_guideline_path(guideline), "Wrangling Guideline was successfully created.") + it "redirects with error" do + title = "Wrangling 101" + content = "JUST DO IT!" + post :create, params: { wrangling_guideline: { title: title, content: content } } + it_redirects_to_with_error(root_url, "Sorry, only an authorized admin can access the page you were trying to reach.") + end end + end - it "renders new if create fails" do - # Cannot save a content-free guideline - post :create, params: { wrangling_guideline: { title: "Wrangling 101" } } - expect(response).to render_template("new") + %w[tag_wrangling superadmin].each do |role| + context "when logged in as an admin with #{role} role" do + let(:admin) { create(:admin, roles: [role]) } + + before { fake_login_admin(admin) } + + it "creates and redirects to new wrangling guideline" do + title = "Wrangling 101" + content = "JUST DO IT!" + post :create, params: { wrangling_guideline: { title: title, content: content } } + + guideline = WranglingGuideline.find_by(title: title) + expect(assigns(:wrangling_guideline)).to eq(guideline) + expect(assigns(:wrangling_guideline).content).to eq(sanitize_value("content", content)) + it_redirects_to_with_notice(wrangling_guideline_path(guideline), "Wrangling Guideline was successfully created.") + end + + it "renders new if create fails" do + # Cannot save a content-free guideline + post :create, params: { wrangling_guideline: { title: "Wrangling 101" } } + expect(response).to render_template("new") + end end end end @@ -144,25 +211,44 @@ it_redirects_to_with_notice(root_path, "I'm sorry, only an admin can look at that area") end - context "when logged in as admin" do - let(:guideline) { create(:wrangling_guideline) } - - before { fake_login_admin(admin) } - - it "updates and redirects to updated wrangling guideline" do - title = "Wrangling 101" - expect(guideline.title).not_to eq(title) + %w[board communications translation policy_and_abuse docs support open_doors].each do |role| + context "when logged in as an admin with #{role} role" do + let(:guideline) { create(:wrangling_guideline) } + let(:admin) { create(:admin, roles: [role]) } - put :update, params: { id: guideline.id, wrangling_guideline: { title: title } } + before { fake_login_admin(admin) } - expect(assigns(:wrangling_guideline)).to eq(guideline) - expect(assigns(:wrangling_guideline).title).to eq(title) - it_redirects_to_with_notice(wrangling_guideline_path(guideline), "Wrangling Guideline was successfully updated.") + it "redirects with error" do + title = "Wrangling 101" + expect(guideline.title).not_to eq(title) + put :update, params: { id: guideline.id, wrangling_guideline: { title: title } } + it_redirects_to_with_error(root_url, "Sorry, only an authorized admin can access the page you were trying to reach.") + end end + end - it "renders edit if update fails" do - put :update, params: { id: guideline.id, wrangling_guideline: { title: nil } } - expect(response).to render_template("edit") + %w[tag_wrangling superadmin].each do |role| + context "when logged in as an admin with #{role} role" do + let(:guideline) { create(:wrangling_guideline) } + let(:admin) { create(:admin, roles: [role]) } + + before { fake_login_admin(admin) } + + it "updates and redirects to updated wrangling guideline" do + title = "Wrangling 101" + expect(guideline.title).not_to eq(title) + + put :update, params: { id: guideline.id, wrangling_guideline: { title: title } } + + expect(assigns(:wrangling_guideline)).to eq(guideline) + expect(assigns(:wrangling_guideline).title).to eq(title) + it_redirects_to_with_notice(wrangling_guideline_path(guideline), "Wrangling Guideline was successfully updated.") + end + + it "renders edit if update fails" do + put :update, params: { id: guideline.id, wrangling_guideline: { title: nil } } + expect(response).to render_template("edit") + end end end end @@ -178,25 +264,45 @@ it_redirects_to_with_notice(root_path, "I'm sorry, only an admin can look at that area") end - context "when logged in as admin" do - let!(:guideline_1) { create(:wrangling_guideline, position: 1) } - let!(:guideline_2) { create(:wrangling_guideline, position: 2) } - let!(:guideline_3) { create(:wrangling_guideline, position: 3) } - - before { fake_login_admin(admin) } + %w[board communications translation policy_and_abuse docs support open_doors].each do |role| + context "when logged in as an admin with #{role} role" do + let!(:guideline1) { create(:wrangling_guideline, position: 1) } + let!(:guideline2) { create(:wrangling_guideline, position: 2) } + let!(:guideline3) { create(:wrangling_guideline, position: 3) } + let(:admin) { create(:admin, roles: [role]) } - it "updates positions and redirects to index" do - expect(WranglingGuideline.order('position ASC')).to eq([guideline_1, guideline_2, guideline_3]) - post :update_positions, params: { wrangling_guidelines: [3, 2, 1] } + before { fake_login_admin(admin) } - expect(assigns(:wrangling_guidelines)).to eq(WranglingGuideline.order('position ASC')) - expect(assigns(:wrangling_guidelines)).to eq([guideline_3, guideline_2, guideline_1]) - it_redirects_to_with_notice(wrangling_guidelines_path, "Wrangling Guidelines order was successfully updated.") + it "redirects with error" do + expect(WranglingGuideline.order("position ASC")).to eq([guideline1, guideline2, guideline3]) + post :update_positions, params: { wrangling_guidelines: [3, 2, 1] } + it_redirects_to_with_error(root_url, "Sorry, only an authorized admin can access the page you were trying to reach.") + end end + end - it "redirects to index given no params" do - post :update_positions - it_redirects_to(wrangling_guidelines_path) + %w[tag_wrangling superadmin].each do |role| + context "when logged in as an admin with #{role} role" do + let!(:guideline1) { create(:wrangling_guideline, position: 1) } + let!(:guideline2) { create(:wrangling_guideline, position: 2) } + let!(:guideline3) { create(:wrangling_guideline, position: 3) } + let(:admin) { create(:admin, roles: [role]) } + + before { fake_login_admin(admin) } + + it "updates positions and redirects to index" do + expect(WranglingGuideline.order("position ASC")).to eq([guideline1, guideline2, guideline3]) + post :update_positions, params: { wrangling_guidelines: [3, 2, 1] } + + expect(assigns(:wrangling_guidelines)).to eq(WranglingGuideline.order("position ASC")) + expect(assigns(:wrangling_guidelines)).to eq([guideline3, guideline2, guideline1]) + it_redirects_to_with_notice(wrangling_guidelines_path, "Wrangling Guidelines order was successfully updated.") + end + + it "redirects to index given no params" do + post :update_positions + it_redirects_to(wrangling_guidelines_path) + end end end end @@ -212,15 +318,33 @@ it_redirects_to_with_notice(root_path, "I'm sorry, only an admin can look at that area") end - context "when logged in as admin" do - let(:guideline) { create(:wrangling_guideline) } + %w[board communications translation policy_and_abuse docs support open_doors].each do |role| + context "when logged in as an admin with #{role} role" do + let(:guideline) { create(:wrangling_guideline) } + let(:admin) { create(:admin, roles: [role]) } + + before { fake_login_admin(admin) } + + it "redirects with error" do + delete :destroy, params: { id: guideline.id } + + it_redirects_to_with_error(root_url, "Sorry, only an authorized admin can access the page you were trying to reach.") + end + end + end + + %w[tag_wrangling superadmin].each do |role| + context "when logged in as an admin with #{role} role" do + let(:guideline) { create(:wrangling_guideline) } + let(:admin) { create(:admin, roles: [role]) } - before { fake_login_admin(admin) } + before { fake_login_admin(admin) } - it "deletes and redirects to index" do - delete :destroy, params: { id: guideline.id } - expect(WranglingGuideline.find_by_id(guideline.id)).to be_nil - it_redirects_to_with_notice(wrangling_guidelines_path, "Wrangling Guideline was successfully deleted.") + it "deletes and redirects to index" do + delete :destroy, params: { id: guideline.id } + expect(WranglingGuideline.find_by(id: guideline.id)).to be_nil + it_redirects_to_with_notice(wrangling_guidelines_path, "Wrangling Guideline was successfully deleted.") + end end end end diff --git a/spec/mailers/user_mailer_spec.rb b/spec/mailers/user_mailer_spec.rb index f2fc7c3e5ef..b0f209dc798 100644 --- a/spec/mailers/user_mailer_spec.rb +++ b/spec/mailers/user_mailer_spec.rb @@ -149,7 +149,7 @@ title = "Façade" title2 = Faker::Book.title - subject(:email) { UserMailer.claim_notification(author.id, [work.id, work2.id], true) } + subject(:email) { UserMailer.claim_notification(author.id, [work.id, work2.id]) } let(:author) { create(:user) } let(:work) { create(:work, title: title, authors: [author.pseuds.first]) } diff --git a/test/mailers/previews/user_mailer_preview.rb b/test/mailers/previews/user_mailer_preview.rb index 19ae2739bb0..4310f51a96a 100644 --- a/test/mailers/previews/user_mailer_preview.rb +++ b/test/mailers/previews/user_mailer_preview.rb @@ -34,10 +34,24 @@ def feedback UserMailer.feedback(feedback.id) end - def claim_notification_registered + def claim_notification work = create(:work) creator_id = work.pseuds.first.user.id - UserMailer.claim_notification(creator_id, [work.id], true) + UserMailer.claim_notification(creator_id, [work.id]) + end + + def invite_request_declined + user = create(:user, :for_mailer_preview) + total = params[:total] || 1 + reason = "test reason" + UserMailer.invite_request_declined(user.id, total, reason) + end + + def change_email + user = create(:user, :for_mailer_preview) + old_email = user.email + new_email = "new_email" + UserMailer.change_email(user.id, old_email, new_email) end private