class CollectionItemsController < ApplicationController before_action :load_collection before_action :load_user, only: [:update_multiple] before_action :load_collectible_item, only: [:new, :create] before_action :check_parent_visible, only: [:new] before_action :users_only, only: [:new] cache_sweeper :collection_sweeper def index # TODO: AO3-6507 Refactor to use send instead of case statements. if @collection && @collection.user_is_maintainer?(current_user) @collection_items = @collection.collection_items.include_for_works @collection_items = case params[:status] when "approved" @collection_items.approved_by_both when "rejected_by_collection" @collection_items.rejected_by_collection when "rejected_by_user" @collection_items.rejected_by_user when "unreviewed_by_user" @collection_items.invited_by_collection else @collection_items.unreviewed_by_collection end elsif params[:user_id] && (@user = User.find_by(login: params[:user_id])) && @user == current_user @collection_items = CollectionItem.for_user(@user).includes(:collection).merge(Collection.with_attached_icon) @collection_items = case params[:status] when "approved" @collection_items.approved_by_both when "rejected_by_collection" @collection_items.rejected_by_collection when "rejected_by_user" @collection_items.rejected_by_user when "unreviewed_by_collection" @collection_items.approved_by_user.unreviewed_by_collection else @collection_items.unreviewed_by_user end else flash[:error] = ts("You don't have permission to see that, sorry!") redirect_to collections_path and return end sort = "created_at DESC" @collection_items = @collection_items.order(sort).paginate page: params[:page], per_page: ArchiveConfig.ITEMS_PER_PAGE end def load_collectible_item if params[:work_id] @item = Work.find(params[:work_id]) elsif params[:bookmark_id] @item = Bookmark.find(params[:bookmark_id]) end end def check_parent_visible check_visibility_for(@item) end def load_user unless @collection @user = User.find_by(login: params[:user_id]) end end def new end def create unless params[:collection_names] flash[:error] = ts("What collections did you want to add?") redirect_to(request.env["HTTP_REFERER"] || root_path) and return end unless @item flash[:error] = ts("What did you want to add to a collection?") redirect_to(request.env["HTTP_REFERER"] || root_path) and return end if !current_user.archivist && @item.respond_to?(:allow_collection_invitation?) && !@item.allow_collection_invitation? flash[:error] = t(".invitation_not_sent", default: "This item could not be invited.") redirect_to(@item) and return end # for each collection name # see if it exists, is open, and isn't already one of this item's collections # add the collection and save # if there are errors, add them to errors new_collections = [] invited_collections = [] unapproved_collections = [] errors = [] params[:collection_names].split(',').map {|name| name.strip}.uniq.each do |collection_name| collection = Collection.find_by(name: collection_name) if !collection errors << ts("%{name}, because we couldn't find a collection with that name. Make sure you are using the one-word name, and not the title.", name: collection_name) elsif @item.collections.include?(collection) if @item.rejected_collections.include?(collection) errors << ts("%{collection_title}, because the %{object_type}'s owner has rejected the invitation.", collection_title: collection.title, object_type: @item.class.name.humanize.downcase) else errors << ts("%{collection_title}, because this item has already been submitted.", collection_title: collection.title) end elsif collection.closed? && !collection.user_is_maintainer?(User.current_user) errors << ts("%{collection_title} is closed to new submissions.", collection_title: collection.title) elsif (collection.anonymous? || collection.unrevealed?) && !current_user.is_author_of?(@item) errors << ts("%{collection_title}, because you don't own this item and the collection is anonymous or unrevealed.", collection_title: collection.title) elsif !current_user.is_author_of?(@item) && !collection.user_is_maintainer?(current_user) errors << ts("%{collection_title}, either you don't own this item or are not a moderator of the collection.", collection_title: collection.title) elsif @item.is_a?(Work) && @item.anonymous? && !current_user.is_author_of?(@item) errors << ts("%{collection_title}, because you don't own this item and the item is anonymous.", collection_title: collection.title) # add the work to a collection, and try to save it elsif @item.add_to_collection(collection) && @item.save(validate: false) # approved_by_user? and approved_by_collection? are both true. # This is will be true for archivists adding works to collections they maintain # or creators adding their works to a collection with auto-approval. if @item.approved_collections.include?(collection) new_collections << collection # if the current_user is a maintainer of the collection then approved_by_user must have been false (which means # the current_user isn't the owner of the item), then the maintainer is attempting to invite this work to # their collection elsif collection.user_is_maintainer?(current_user) invited_collections << collection # otherwise the current_user is the owner of the item and approved_by_COLLECTION was false (which means the # current_user isn't a collection_maintainer), so the item owner is attempting to add their work to a moderated # collection else unapproved_collections << collection end else errors << ts("Something went wrong trying to add collection %{name}, sorry!", name: collection_name) end end # messages to the user unless errors.empty? flash[:error] = ts("We couldn't add your submission to the following collection(s): ") + "
" end flash[:notice] = "" unless new_collections.empty? && unapproved_collections.empty? unless new_collections.empty? flash[:notice] = ts("Added to collection(s): %{collections}.", collections: new_collections.collect(&:title).join(", ")) end unless invited_collections.empty? invited_collections.each do |needs_user_approval| flash[:notice] ||= "" flash[:notice] = t(".invited_to_collections_html", invited_link: view_context.link_to(t(".invited"), collection_items_path(needs_user_approval, status: :unreviewed_by_user)), collection_title: needs_user_approval.title) end end unless unapproved_collections.empty? flash[:notice] ||= "" flash[:notice] += ts(" You have submitted your work to #{unapproved_collections.size > 1 ? "moderated collections (%{all_collections}). It will not become a part of those collections" : "the moderated collection '%{all_collections}'. It will not become a part of the collection"} until it has been approved by a moderator.", all_collections: unapproved_collections.map { |f| f.title }.join(', ')) end flash[:notice] = (flash[:notice]).html_safe unless flash[:notice].blank? flash[:error] = (flash[:error]).html_safe unless flash[:error].blank? redirect_to(@item) end def update_multiple if @collection&.user_is_maintainer?(current_user) update_multiple_with_params( allowed_items: @collection.collection_items, update_params: collection_update_multiple_params, success_path: collection_items_path(@collection) ) elsif @user && @user == current_user update_multiple_with_params( allowed_items: CollectionItem.for_user(@user), update_params: user_update_multiple_params, success_path: user_collection_items_path(@user) ) else flash[:error] = ts("You don't have permission to do that, sorry!") redirect_to(@collection || @user) end end # The main work performed by update_multiple. Uses the passed-in parameters # to update, and only updates items that can be found in allowed_items (which # should be a relation on CollectionItems). When all items are successfully # updated, redirects to success_path. def update_multiple_with_params(allowed_items:, update_params:, success_path:) # Collect any failures so that we can display errors: @collection_items = [] # Make sure that the keys are integers so that we can look up the # parameters by ID. update_params.transform_keys!(&:to_i) # By using where() here and updating each item individually, instead of # using allowed_items.update(update_params.keys, update_params.values) -- # which uses find() under the hood -- we ensure that we'll fail silently if # the user tries to update an item they're not allowed to. allowed_items.where(id: update_params.keys).each do |item| item_data = update_params[item.id] if item_data[:remove] == "1" next unless item.user_allowed_to_destroy?(current_user) @collection_items << item unless item.destroy else @collection_items << item unless item.update(item_data) end end if @collection_items.empty? flash[:notice] = ts("Collection status updated!") redirect_to success_path else render action: "index" end end private def user_update_multiple_params allowed = %i[user_approval_status remove] params.slice(:collection_items).permit(collection_items: allowed). require(:collection_items) end def collection_update_multiple_params allowed = %i[collection_approval_status unrevealed anonymous remove] params.slice(:collection_items).permit(collection_items: allowed). require(:collection_items) end end