397 lines
14 KiB
Ruby
397 lines
14 KiB
Ruby
|
|
# For exporting to Excel CSV format
|
||
|
|
require 'csv'
|
||
|
|
|
||
|
|
class ChallengeSignupsController < ApplicationController
|
||
|
|
include ExportsHelper
|
||
|
|
|
||
|
|
before_action :users_only, except: [:summary]
|
||
|
|
before_action :load_collection, except: [:index]
|
||
|
|
before_action :load_challenge, except: [:index]
|
||
|
|
before_action :load_signup_from_id, only: [:show, :edit, :update, :destroy, :confirm_delete]
|
||
|
|
before_action :allowed_to_destroy, only: [:destroy, :confirm_delete]
|
||
|
|
before_action :signup_owner_only, only: [:edit, :update]
|
||
|
|
before_action :maintainer_or_signup_owner_only, only: [:show]
|
||
|
|
before_action :check_signup_open, only: [:new, :create, :edit, :update]
|
||
|
|
before_action :check_pseud_ownership, only: [:create, :update]
|
||
|
|
before_action :check_signup_in_collection, only: [:show, :edit, :update, :destroy, :confirm_delete]
|
||
|
|
|
||
|
|
def load_challenge
|
||
|
|
@challenge = @collection.challenge
|
||
|
|
no_challenge and return unless @challenge
|
||
|
|
end
|
||
|
|
|
||
|
|
def no_challenge
|
||
|
|
flash[:error] = ts("What challenge did you want to sign up for?")
|
||
|
|
redirect_to collection_path(@collection) rescue redirect_to '/'
|
||
|
|
false
|
||
|
|
end
|
||
|
|
|
||
|
|
def check_signup_open
|
||
|
|
signup_closed and return unless (@challenge.signup_open || @collection.user_is_maintainer?(current_user))
|
||
|
|
end
|
||
|
|
|
||
|
|
def signup_closed
|
||
|
|
flash[:error] = ts("Sign-up is currently closed: please contact a moderator for help.")
|
||
|
|
redirect_to @collection rescue redirect_to '/'
|
||
|
|
false
|
||
|
|
end
|
||
|
|
|
||
|
|
def signup_closed_owner?
|
||
|
|
@collection.challenge_type == "GiftExchange" && !@challenge.signup_open && @collection.user_is_owner?(current_user)
|
||
|
|
end
|
||
|
|
|
||
|
|
def signup_owner_only
|
||
|
|
not_signup_owner and return unless @challenge_signup.pseud.user == current_user || signup_closed_owner?
|
||
|
|
end
|
||
|
|
|
||
|
|
def maintainer_or_signup_owner_only
|
||
|
|
not_allowed(@collection) and return unless (@challenge_signup.pseud.user == current_user || @collection.user_is_maintainer?(current_user))
|
||
|
|
end
|
||
|
|
|
||
|
|
def not_signup_owner
|
||
|
|
flash[:error] = ts("You can't edit someone else's sign-up!")
|
||
|
|
redirect_to @collection
|
||
|
|
false
|
||
|
|
end
|
||
|
|
|
||
|
|
def allowed_to_destroy
|
||
|
|
@challenge_signup.user_allowed_to_destroy?(current_user) || not_allowed(@collection)
|
||
|
|
end
|
||
|
|
|
||
|
|
def load_signup_from_id
|
||
|
|
@challenge_signup = ChallengeSignup.find(params[:id])
|
||
|
|
no_signup and return unless @challenge_signup
|
||
|
|
end
|
||
|
|
|
||
|
|
def no_signup
|
||
|
|
flash[:error] = ts("What sign-up did you want to work on?")
|
||
|
|
redirect_to collection_path(@collection) rescue redirect_to '/'
|
||
|
|
false
|
||
|
|
end
|
||
|
|
|
||
|
|
def check_pseud_ownership
|
||
|
|
if params[:challenge_signup][:pseud_id] && (pseud = Pseud.find(params[:challenge_signup][:pseud_id]))
|
||
|
|
# either you have to own the pseud, OR you have to be a mod editing after signups are closed and NOT changing the pseud
|
||
|
|
unless current_user.pseuds.include?(pseud) || (@challenge_signup && @challenge_signup.pseud == pseud && signup_closed_owner?)
|
||
|
|
flash[:error] = ts("You can't sign up with that pseud.")
|
||
|
|
redirect_to root_path and return
|
||
|
|
end
|
||
|
|
end
|
||
|
|
end
|
||
|
|
|
||
|
|
def check_signup_in_collection
|
||
|
|
unless @challenge_signup.collection_id == @collection.id
|
||
|
|
flash[:error] = ts("Sorry, that sign-up isn't associated with that collection.")
|
||
|
|
redirect_to @collection
|
||
|
|
end
|
||
|
|
end
|
||
|
|
|
||
|
|
#### ACTIONS
|
||
|
|
|
||
|
|
def index
|
||
|
|
if params[:user_id] && (@user = User.find_by(login: params[:user_id]))
|
||
|
|
if current_user == @user
|
||
|
|
@challenge_signups = @user.challenge_signups.order_by_date
|
||
|
|
render action: :index and return
|
||
|
|
else
|
||
|
|
flash[:error] = ts("You aren't allowed to see that user's sign-ups.")
|
||
|
|
redirect_to '/' and return
|
||
|
|
end
|
||
|
|
else
|
||
|
|
load_collection
|
||
|
|
load_challenge if @collection
|
||
|
|
return false unless @challenge
|
||
|
|
end
|
||
|
|
|
||
|
|
# using respond_to in order to provide Excel output
|
||
|
|
# see ExportsHelper for export_csv method
|
||
|
|
respond_to do |format|
|
||
|
|
format.html {
|
||
|
|
if @challenge.user_allowed_to_see_signups?(current_user)
|
||
|
|
@challenge_signups = @collection.signups.joins(:pseud)
|
||
|
|
if params[:query]
|
||
|
|
@query = params[:query]
|
||
|
|
@challenge_signups = @challenge_signups.where("pseuds.name LIKE ?", '%' + params[:query] + '%')
|
||
|
|
end
|
||
|
|
@challenge_signups = @challenge_signups.order("pseuds.name").paginate(page: params[:page], per_page: ArchiveConfig.ITEMS_PER_PAGE)
|
||
|
|
elsif params[:user_id] && (@user = User.find_by(login: params[:user_id]))
|
||
|
|
@challenge_signups = @collection.signups.by_user(current_user)
|
||
|
|
else
|
||
|
|
not_allowed(@collection)
|
||
|
|
end
|
||
|
|
}
|
||
|
|
format.csv {
|
||
|
|
if (@collection.gift_exchange? && @challenge.user_allowed_to_see_signups?(current_user)) ||
|
||
|
|
(@collection.prompt_meme? && @collection.user_is_maintainer?(current_user))
|
||
|
|
csv_data = self.send("#{@challenge.class.name.underscore}_to_csv")
|
||
|
|
filename = "#{@collection.name}_signups_#{Time.now.strftime('%Y-%m-%d-%H%M')}.csv"
|
||
|
|
send_csv_data(csv_data, filename)
|
||
|
|
else
|
||
|
|
flash[:error] = ts("You aren't allowed to see the CSV summary.")
|
||
|
|
redirect_to collection_path(@collection) rescue redirect_to '/' and return
|
||
|
|
end
|
||
|
|
}
|
||
|
|
end
|
||
|
|
end
|
||
|
|
|
||
|
|
def summary
|
||
|
|
@summary = ChallengeSignupSummary.new(@collection)
|
||
|
|
|
||
|
|
if @collection.signups.count < (ArchiveConfig.ANONYMOUS_THRESHOLD_COUNT/2)
|
||
|
|
flash.now[:notice] = ts("Summary does not appear until at least %{count} sign-ups have been made!", count: ((ArchiveConfig.ANONYMOUS_THRESHOLD_COUNT/2)))
|
||
|
|
elsif @collection.signups.count > ArchiveConfig.MAX_SIGNUPS_FOR_LIVE_SUMMARY
|
||
|
|
# too many signups in this collection to show the summary page "live"
|
||
|
|
modification_time = @summary.cached_time
|
||
|
|
|
||
|
|
# The time is always written alongside the cache, so if the time is
|
||
|
|
# missing, then the cache must be missing as well -- and we want to
|
||
|
|
# generate it. We also want to generate it if signups are open and it was
|
||
|
|
# last generated more than an hour ago.
|
||
|
|
if modification_time.nil? ||
|
||
|
|
(@collection.challenge.signup_open? && modification_time < 1.hour.ago)
|
||
|
|
|
||
|
|
# Touch the cache so that we don't try to generate the summary a second
|
||
|
|
# time on subsequent page loads.
|
||
|
|
@summary.touch_cache
|
||
|
|
|
||
|
|
# Generate the cache of the summary in the background.
|
||
|
|
@summary.enqueue_for_generation
|
||
|
|
end
|
||
|
|
else
|
||
|
|
# generate it on the fly
|
||
|
|
@tag_type = @summary.tag_type
|
||
|
|
@summary_tags = @summary.summary
|
||
|
|
@generated_live = true
|
||
|
|
end
|
||
|
|
end
|
||
|
|
|
||
|
|
def show
|
||
|
|
unless @challenge_signup.valid?
|
||
|
|
flash[:error] = ts("This sign-up is invalid. Please check your sign-ups for a duplicate or edit to fix any other problems.")
|
||
|
|
end
|
||
|
|
end
|
||
|
|
|
||
|
|
protected
|
||
|
|
def build_prompts
|
||
|
|
notice = ""
|
||
|
|
@challenge.class::PROMPT_TYPES.each do |prompt_type|
|
||
|
|
num_to_build = params["num_#{prompt_type}"] ? params["num_#{prompt_type}"].to_i : @challenge.required(prompt_type)
|
||
|
|
if num_to_build < @challenge.required(prompt_type)
|
||
|
|
notice += ts("You must submit at least %{required} #{prompt_type}. ", required: @challenge.required(prompt_type))
|
||
|
|
num_to_build = @challenge.required(prompt_type)
|
||
|
|
elsif num_to_build > @challenge.allowed(prompt_type)
|
||
|
|
notice += ts("You can only submit up to %{allowed} #{prompt_type}. ", allowed: @challenge.allowed(prompt_type))
|
||
|
|
num_to_build = @challenge.allowed(prompt_type)
|
||
|
|
elsif params["num_#{prompt_type}"]
|
||
|
|
notice += ts("Set up %{num} #{prompt_type.pluralize}. ", num: num_to_build)
|
||
|
|
end
|
||
|
|
num_existing = @challenge_signup.send(prompt_type).count
|
||
|
|
num_existing.upto(num_to_build-1) do
|
||
|
|
@challenge_signup.send(prompt_type).build
|
||
|
|
end
|
||
|
|
end
|
||
|
|
unless notice.blank?
|
||
|
|
flash[:notice] = notice
|
||
|
|
end
|
||
|
|
end
|
||
|
|
|
||
|
|
public
|
||
|
|
def new
|
||
|
|
if (@challenge_signup = ChallengeSignup.in_collection(@collection).by_user(current_user).first)
|
||
|
|
flash[:notice] = ts("You are already signed up for this challenge. You can edit your sign-up below.")
|
||
|
|
redirect_to edit_collection_signup_path(@collection, @challenge_signup)
|
||
|
|
else
|
||
|
|
@challenge_signup = ChallengeSignup.new
|
||
|
|
build_prompts
|
||
|
|
end
|
||
|
|
end
|
||
|
|
|
||
|
|
def edit
|
||
|
|
build_prompts
|
||
|
|
end
|
||
|
|
|
||
|
|
def create
|
||
|
|
@challenge_signup = ChallengeSignup.new(challenge_signup_params)
|
||
|
|
|
||
|
|
@challenge_signup.pseud = current_user.default_pseud unless @challenge_signup.pseud
|
||
|
|
@challenge_signup.collection = @collection
|
||
|
|
# we check validity first to prevent saving tag sets if invalid
|
||
|
|
if @challenge_signup.valid? && @challenge_signup.save
|
||
|
|
flash[:notice] = ts('Sign-up was successfully created.')
|
||
|
|
redirect_to collection_signup_path(@collection, @challenge_signup)
|
||
|
|
else
|
||
|
|
render action: :new
|
||
|
|
end
|
||
|
|
end
|
||
|
|
|
||
|
|
def update
|
||
|
|
if @challenge_signup.update(challenge_signup_params)
|
||
|
|
flash[:notice] = ts('Sign-up was successfully updated.')
|
||
|
|
redirect_to collection_signup_path(@collection, @challenge_signup)
|
||
|
|
else
|
||
|
|
render action: :edit
|
||
|
|
end
|
||
|
|
end
|
||
|
|
|
||
|
|
def confirm_delete
|
||
|
|
end
|
||
|
|
|
||
|
|
def destroy
|
||
|
|
unless @challenge.signup_open || @collection.user_is_maintainer?(current_user)
|
||
|
|
flash[:error] = ts("You cannot delete your sign-up after sign-ups are closed. Please contact a moderator for help.")
|
||
|
|
else
|
||
|
|
@challenge_signup.destroy
|
||
|
|
flash[:notice] = ts("Challenge sign-up was deleted.")
|
||
|
|
end
|
||
|
|
if @collection.user_is_maintainer?(current_user) && !@collection.prompt_meme?
|
||
|
|
redirect_to collection_signups_path(@collection)
|
||
|
|
elsif @collection.prompt_meme?
|
||
|
|
redirect_to collection_requests_path(@collection)
|
||
|
|
else
|
||
|
|
redirect_to @collection
|
||
|
|
end
|
||
|
|
end
|
||
|
|
|
||
|
|
|
||
|
|
protected
|
||
|
|
|
||
|
|
def request_to_array(type, request)
|
||
|
|
any_types = TagSet::TAG_TYPES.select {|type| request && request.send("any_#{type}")}
|
||
|
|
any_types.map! { |type| ts("Any %{type}", type: type.capitalize) }
|
||
|
|
tags = request.nil? ? [] : request.tag_set.tags.map {|tag| tag.name}
|
||
|
|
rarray = [(tags + any_types).join(", ")]
|
||
|
|
|
||
|
|
if @challenge.send("#{type}_restriction").optional_tags_allowed
|
||
|
|
rarray << (request.nil? ? "" : request.optional_tag_set.tags.map {|tag| tag.name}.join(", "))
|
||
|
|
end
|
||
|
|
|
||
|
|
if @challenge.send("#{type}_restriction").title_allowed
|
||
|
|
rarray << (request.nil? ? "" : sanitize_field(request, :title))
|
||
|
|
end
|
||
|
|
|
||
|
|
if @challenge.send("#{type}_restriction").description_allowed
|
||
|
|
description = (request.nil? ? "" : sanitize_field(request, :description))
|
||
|
|
# Didn't find a way to get Excel 2007 to accept line breaks
|
||
|
|
# withing a field; not even when the row delimiter is set to
|
||
|
|
# \r\n and linebreaks within the field are only \n. :-(
|
||
|
|
#
|
||
|
|
# Thus stripping linebreaks.
|
||
|
|
rarray << description.gsub(/[\n\r]/, " ")
|
||
|
|
end
|
||
|
|
|
||
|
|
rarray << (request.nil? ? "" : request.url) if
|
||
|
|
@challenge.send("#{type}_restriction").url_allowed
|
||
|
|
|
||
|
|
return rarray
|
||
|
|
end
|
||
|
|
|
||
|
|
|
||
|
|
def gift_exchange_to_csv
|
||
|
|
header = ["Pseud", "Email", "Sign-up URL"]
|
||
|
|
|
||
|
|
%w(request offer).each do |type|
|
||
|
|
@challenge.send("#{type.pluralize}_num_allowed").times do |i|
|
||
|
|
header << "#{type.capitalize} #{i+1} Tags"
|
||
|
|
header << "#{type.capitalize} #{i+1} Optional Tags" if
|
||
|
|
@challenge.send("#{type}_restriction").optional_tags_allowed
|
||
|
|
header << "#{type.capitalize} #{i+1} Title" if
|
||
|
|
@challenge.send("#{type}_restriction").title_allowed
|
||
|
|
header << "#{type.capitalize} #{i+1} Description" if
|
||
|
|
@challenge.send("#{type}_restriction").description_allowed
|
||
|
|
header << "#{type.capitalize} #{i+1} URL" if
|
||
|
|
@challenge.send("#{type}_restriction").url_allowed
|
||
|
|
end
|
||
|
|
end
|
||
|
|
|
||
|
|
csv_array = []
|
||
|
|
csv_array << header
|
||
|
|
|
||
|
|
@collection.signups.each do |signup|
|
||
|
|
row = [signup.pseud.name, signup.pseud.user.email,
|
||
|
|
collection_signup_url(@collection, signup)]
|
||
|
|
|
||
|
|
%w(request offer).each do |type|
|
||
|
|
@challenge.send("#{type.pluralize}_num_allowed").times do |i|
|
||
|
|
row += request_to_array(type, signup.send(type.pluralize)[i])
|
||
|
|
end
|
||
|
|
end
|
||
|
|
csv_array << row
|
||
|
|
end
|
||
|
|
|
||
|
|
csv_array
|
||
|
|
end
|
||
|
|
|
||
|
|
|
||
|
|
def prompt_meme_to_csv
|
||
|
|
header = ["Pseud", "Sign-up URL", "Tags"]
|
||
|
|
header << "Optional Tags" if @challenge.request_restriction.optional_tags_allowed
|
||
|
|
header << "Title" if @challenge.request_restriction.title_allowed
|
||
|
|
header << "Description" if @challenge.request_restriction.description_allowed
|
||
|
|
header << "URL" if @challenge.request_restriction.url_allowed
|
||
|
|
|
||
|
|
csv_array = []
|
||
|
|
csv_array << header
|
||
|
|
@collection.prompts.where(type: "Request").each do |request|
|
||
|
|
row =
|
||
|
|
if request.anonymous?
|
||
|
|
["(Anonymous)", ""]
|
||
|
|
else
|
||
|
|
[request.challenge_signup.pseud.name,
|
||
|
|
collection_signup_url(@collection, request.challenge_signup)]
|
||
|
|
end
|
||
|
|
csv_array << (row + request_to_array("request", request))
|
||
|
|
end
|
||
|
|
|
||
|
|
csv_array
|
||
|
|
end
|
||
|
|
|
||
|
|
private
|
||
|
|
|
||
|
|
def challenge_signup_params
|
||
|
|
params.require(:challenge_signup).permit(
|
||
|
|
:pseud_id,
|
||
|
|
requests_attributes: nested_prompt_params,
|
||
|
|
offers_attributes: nested_prompt_params
|
||
|
|
)
|
||
|
|
end
|
||
|
|
|
||
|
|
def nested_prompt_params
|
||
|
|
[
|
||
|
|
:id,
|
||
|
|
:title,
|
||
|
|
:url,
|
||
|
|
:any_fandom,
|
||
|
|
:any_character,
|
||
|
|
:any_relationship,
|
||
|
|
:any_freeform,
|
||
|
|
:any_category,
|
||
|
|
:any_rating,
|
||
|
|
:any_archive_warning,
|
||
|
|
:anonymous,
|
||
|
|
:description,
|
||
|
|
:_destroy,
|
||
|
|
tag_set_attributes: [
|
||
|
|
:id,
|
||
|
|
:updated_at,
|
||
|
|
:character_tagnames,
|
||
|
|
:relationship_tagnames,
|
||
|
|
:freeform_tagnames,
|
||
|
|
:category_tagnames,
|
||
|
|
:rating_tagnames,
|
||
|
|
:archive_warning_tagnames,
|
||
|
|
:fandom_tagnames,
|
||
|
|
character_tagnames: [],
|
||
|
|
relationship_tagnames: [],
|
||
|
|
freeform_tagnames: [],
|
||
|
|
category_tagnames: [],
|
||
|
|
rating_tagnames: [],
|
||
|
|
archive_warning_tagnames: [],
|
||
|
|
fandom_tagnames: [],
|
||
|
|
],
|
||
|
|
optional_tag_set_attributes: [
|
||
|
|
:tagnames
|
||
|
|
]
|
||
|
|
]
|
||
|
|
end
|
||
|
|
end
|