418 lines
13 KiB
Ruby
418 lines
13 KiB
Ruby
class UsersController < ApplicationController
|
|
cache_sweeper :pseud_sweeper
|
|
|
|
before_action :check_user_status, only: [:edit, :update, :change_username, :changed_username]
|
|
before_action :load_user, except: [:activate, :delete_confirmation, :index]
|
|
before_action :check_ownership, except: [:activate, :change_username, :changed_username, :delete_confirmation, :edit, :index, :show, :update]
|
|
before_action :check_ownership_or_admin, only: [:change_username, :changed_username, :edit, :update]
|
|
skip_before_action :store_location, only: [:end_first_login]
|
|
|
|
def load_user
|
|
Rails.logger.info "DEBUG params: #{params.inspect}"
|
|
@user = User.find_by!(login: params[:id])
|
|
@check_ownership_of = @user
|
|
end
|
|
|
|
def index
|
|
flash.keep
|
|
redirect_to controller: :people, action: :index
|
|
end
|
|
|
|
# GET /users/1
|
|
def show
|
|
@page_subtitle = @user.login
|
|
@status = @user.statuses.last
|
|
visible = visible_items(current_user)
|
|
@works = visible[:works].order('revised_at DESC').limit(ArchiveConfig.NUMBER_OF_ITEMS_VISIBLE_IN_DASHBOARD)
|
|
@series = visible[:series].order('updated_at DESC').limit(ArchiveConfig.NUMBER_OF_ITEMS_VISIBLE_IN_DASHBOARD)
|
|
@bookmarks = visible[:bookmarks].order('updated_at DESC').limit(ArchiveConfig.NUMBER_OF_ITEMS_VISIBLE_IN_DASHBOARD)
|
|
if current_user.respond_to?(:subscriptions)
|
|
@subscription = current_user.subscriptions.where(subscribable_id: @user.id,
|
|
subscribable_type: 'User').first ||
|
|
current_user.subscriptions.build(subscribable: @user)
|
|
end
|
|
end
|
|
|
|
# GET /users/1/edit
|
|
def edit
|
|
@page_subtitle = t(".browser_title")
|
|
authorize @user.profile if logged_in_as_admin?
|
|
end
|
|
|
|
def change_email
|
|
@page_subtitle = t(".browser_title")
|
|
end
|
|
|
|
def change_password
|
|
@page_subtitle = t(".browser_title")
|
|
end
|
|
|
|
def change_username
|
|
authorize @user if logged_in_as_admin?
|
|
@page_subtitle = t(".browser_title")
|
|
end
|
|
|
|
def changed_password
|
|
unless params[:password] && reauthenticate
|
|
render(:change_password) && return
|
|
end
|
|
|
|
@user.password = params[:password]
|
|
@user.password_confirmation = params[:password_confirmation]
|
|
|
|
if @user.save
|
|
flash[:notice] = ts("Your password has been changed. To protect your account, you have been logged out of all active sessions. Please log in with your new password.")
|
|
@user.create_log_item(action: ArchiveConfig.ACTION_PASSWORD_CHANGE)
|
|
|
|
redirect_to(user_profile_path(@user)) && return
|
|
else
|
|
render(:change_password) && return
|
|
end
|
|
end
|
|
|
|
def changed_username
|
|
authorize @user if logged_in_as_admin?
|
|
render(:change_username) && return if params[:new_login].blank?
|
|
|
|
@new_login = params[:new_login]
|
|
|
|
unless logged_in_as_admin? || @user.valid_password?(params[:password])
|
|
flash[:error] = t(".user.incorrect_password")
|
|
render(:change_username) && return
|
|
end
|
|
|
|
if @new_login == @user.login
|
|
flash.now[:error] = t(".new_username_must_be_different")
|
|
render :change_username and return
|
|
end
|
|
|
|
old_login = @user.login
|
|
@user.login = @new_login
|
|
@user.ticket_number = params[:ticket_number]
|
|
|
|
if @user.save
|
|
if logged_in_as_admin?
|
|
flash[:notice] = t(".admin.successfully_updated")
|
|
redirect_to admin_user_path(@user)
|
|
else
|
|
I18n.with_locale(@user.preference.locale_for_mails) do
|
|
UserMailer.change_username(@user, old_login).deliver_later
|
|
end
|
|
|
|
flash[:notice] = t(".user.successfully_updated")
|
|
redirect_to @user
|
|
end
|
|
else
|
|
@user.reload
|
|
render :change_username
|
|
end
|
|
end
|
|
|
|
def activate
|
|
if params[:id].blank?
|
|
flash[:error] = ts('Your activation key is missing.')
|
|
redirect_to root_path
|
|
|
|
return
|
|
end
|
|
|
|
@user = User.find_by(confirmation_token: params[:id])
|
|
|
|
unless @user
|
|
flash[:error] = ts("Your activation key is invalid. If you didn't activate within #{AdminSetting.current.days_to_purge_unactivated * 7} days, your account was deleted. Please sign up again, or contact support via the link in our footer for more help.").html_safe
|
|
redirect_to root_path
|
|
|
|
return
|
|
end
|
|
|
|
if @user.active?
|
|
flash[:error] = ts("Your account has already been activated.")
|
|
redirect_to @user
|
|
|
|
return
|
|
end
|
|
|
|
@user.activate
|
|
|
|
flash[:notice] = ts("Account activation complete! Please log in.")
|
|
|
|
@user.create_log_item(action: ArchiveConfig.ACTION_ACTIVATE)
|
|
|
|
# assign over any external authors that belong to this user
|
|
external_authors = []
|
|
external_authors << ExternalAuthor.find_by(email: @user.email)
|
|
@invitation = @user.invitation
|
|
external_authors << @invitation.external_author if @invitation
|
|
external_authors.compact!
|
|
|
|
unless external_authors.empty?
|
|
external_authors.each do |external_author|
|
|
external_author.claim!(@user)
|
|
end
|
|
|
|
flash[:notice] += ts(" We found some works already uploaded to the Archive of Our Own that we think belong to you! You'll see them on your homepage when you've logged in.")
|
|
end
|
|
|
|
redirect_to(new_user_session_path)
|
|
end
|
|
|
|
def update
|
|
authorize @user.profile if logged_in_as_admin?
|
|
if @user.profile.update(profile_params)
|
|
if logged_in_as_admin? && @user.profile.ticket_url.present?
|
|
link = view_context.link_to("Ticket ##{@user.profile.ticket_number}", @user.profile.ticket_url)
|
|
AdminActivity.log_action(current_admin, @user, action: "edit profile", summary: link)
|
|
end
|
|
flash[:notice] = ts('Your profile has been successfully updated')
|
|
redirect_to user_profile_path(@user)
|
|
else
|
|
render :edit
|
|
end
|
|
end
|
|
|
|
def confirm_change_email
|
|
@page_subtitle = t(".browser_title")
|
|
|
|
render :change_email and return unless reauthenticate
|
|
|
|
if params[:new_email].blank?
|
|
flash.now[:error] = t("users.confirm_change_email.blank_email")
|
|
render :change_email and return
|
|
end
|
|
|
|
@new_email = params[:new_email]
|
|
|
|
# Please note: This comparison is not technically correct. According to
|
|
# RFC 5321, the local part of an email address is case sensitive, while the
|
|
# domain is case insensitive. That said, all major email providers treat
|
|
# the local part as case insensitive, so it would probably cause more
|
|
# confusion if we did this correctly.
|
|
#
|
|
# Also, email addresses are validated on the client, and will only contain
|
|
# a limited subset of ASCII, so we don't need to do a unicode casefolding pass.
|
|
if @new_email.downcase == @user.email.downcase
|
|
flash.now[:error] = t("users.confirm_change_email.same_as_current")
|
|
render :change_email and return
|
|
end
|
|
|
|
if @new_email.downcase != params[:email_confirmation].downcase
|
|
flash.now[:error] = t("users.confirm_change_email.nonmatching_email")
|
|
render :change_email and return
|
|
end
|
|
|
|
old_email = @user.email
|
|
@user.email = @new_email
|
|
return if @user.valid?(:update)
|
|
|
|
# Make sure that on failure, the form doesn't show the new invalid email as the current one
|
|
@user.email = old_email
|
|
render :change_email
|
|
end
|
|
|
|
def changed_email
|
|
new_email = params[:new_email]
|
|
|
|
old_email = @user.email
|
|
@user.email = new_email
|
|
|
|
if @user.save
|
|
I18n.with_locale(@user.preference.locale_for_mails) 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
|
|
end
|
|
|
|
render :change_email
|
|
end
|
|
|
|
# GET /users/1/reconfirm_email?confirmation_token=abcdef
|
|
def reconfirm_email
|
|
confirmed_user = User.confirm_by_token(params[:confirmation_token])
|
|
|
|
if confirmed_user.errors.empty?
|
|
flash[:notice] = t(".success")
|
|
else
|
|
flash[:error] = t(".invalid_token")
|
|
end
|
|
|
|
redirect_to change_email_user_path(@user)
|
|
end
|
|
|
|
# DELETE /users/1
|
|
# DELETE /users/1.xml
|
|
def destroy
|
|
@hide_dashboard = true
|
|
@works = @user.works.where(posted: true)
|
|
@sole_owned_collections = @user.sole_owned_collections
|
|
|
|
if @works.empty? && @sole_owned_collections.empty?
|
|
@user.wipeout_unposted_works
|
|
@user.destroy_empty_series
|
|
|
|
@user.destroy
|
|
flash[:notice] = ts('You have successfully deleted your account.')
|
|
|
|
redirect_to(delete_confirmation_path)
|
|
elsif params[:coauthor].blank? && params[:sole_author].blank?
|
|
@sole_authored_works = @user.sole_authored_works
|
|
@coauthored_works = @user.coauthored_works
|
|
|
|
render('delete_preview') && return
|
|
elsif params[:coauthor] || params[:sole_author]
|
|
destroy_author
|
|
end
|
|
end
|
|
|
|
def delete_confirmation
|
|
end
|
|
|
|
def end_first_login
|
|
@user.preference.update_attribute(:first_login, false)
|
|
|
|
respond_to do |format|
|
|
format.html { redirect_to(@user) && return }
|
|
format.js
|
|
end
|
|
end
|
|
|
|
def end_banner
|
|
@user.preference.update_attribute(:banner_seen, true)
|
|
|
|
respond_to do |format|
|
|
format.html { redirect_to(request.env['HTTP_REFERER'] || root_path) && return }
|
|
format.js
|
|
end
|
|
end
|
|
|
|
def end_tos_prompt
|
|
@user.update_attribute(:accepted_tos_version, @current_tos_version)
|
|
head :no_content
|
|
end
|
|
|
|
private
|
|
|
|
def reauthenticate
|
|
if params[:password_check].blank?
|
|
return wrong_password!(params[:new_email],
|
|
t("users.confirm_change_email.blank_password"),
|
|
t("users.changed_password.blank_password"))
|
|
end
|
|
|
|
if @user.valid_password?(params[:password_check])
|
|
true
|
|
else
|
|
wrong_password!(params[:new_email],
|
|
t("users.confirm_change_email.wrong_password_html", contact_support_link: helpers.link_to(t("users.confirm_change_email.contact_support"), new_feedback_report_path)),
|
|
t("users.changed_password.wrong_password"))
|
|
end
|
|
end
|
|
|
|
def wrong_password!(condition, if_true, if_false)
|
|
flash.now[:error] = condition ? if_true : if_false
|
|
@wrong_password = true
|
|
|
|
false
|
|
end
|
|
|
|
def visible_items(current_user)
|
|
# NOTE: When current_user is nil, we use .visible_to_all, otherwise we use
|
|
# .visible_to_registered_user.
|
|
visible_method = current_user.nil? && current_admin.nil? ? :visible_to_all : :visible_to_registered_user
|
|
|
|
visible_works = @user.works.send(visible_method)
|
|
visible_series = @user.series.send(visible_method)
|
|
visible_bookmarks = @user.bookmarks.send(visible_method)
|
|
|
|
visible_works = visible_works.revealed.non_anon
|
|
visible_series = visible_series.exclude_anonymous
|
|
@fandoms = if @user == User.orphan_account
|
|
[]
|
|
else
|
|
Fandom.select("tags.*, count(DISTINCT works.id) as work_count").
|
|
joins(:filtered_works).group("tags.id").merge(visible_works).
|
|
where(filter_taggings: { inherited: false }).
|
|
order('work_count DESC').load
|
|
end
|
|
|
|
{
|
|
works: visible_works,
|
|
series: visible_series,
|
|
bookmarks: visible_bookmarks
|
|
}
|
|
end
|
|
|
|
def destroy_author
|
|
@sole_authored_works = @user.sole_authored_works
|
|
@coauthored_works = @user.coauthored_works
|
|
|
|
if params[:cancel_button]
|
|
flash[:notice] = ts('Account deletion canceled.')
|
|
redirect_to user_profile_path(@user)
|
|
|
|
return
|
|
end
|
|
|
|
if params[:coauthor] == 'keep_pseud' || params[:coauthor] == 'orphan_pseud'
|
|
# Orphans co-authored works.
|
|
|
|
pseuds = @user.pseuds
|
|
works = @coauthored_works
|
|
|
|
# We change the pseud to the default orphan pseud if use_default is true.
|
|
use_default = params[:use_default] == 'true' || params[:coauthor] == 'orphan_pseud'
|
|
|
|
Creatorship.orphan(pseuds, works, use_default)
|
|
|
|
elsif params[:coauthor] == 'remove'
|
|
# Removes user as an author from co-authored works
|
|
|
|
@coauthored_works.each do |w|
|
|
w.remove_author(@user)
|
|
end
|
|
end
|
|
|
|
if params[:sole_author] == 'keep_pseud' || params[:sole_author] == 'orphan_pseud'
|
|
# Orphans works where user is the sole author.
|
|
|
|
pseuds = @user.pseuds
|
|
works = @sole_authored_works
|
|
|
|
# We change the pseud to default orphan pseud if use_default is true.
|
|
use_default = params[:use_default] == 'true' || params[:sole_author] == 'orphan_pseud'
|
|
|
|
Creatorship.orphan(pseuds, works, use_default)
|
|
Collection.orphan(pseuds, @sole_owned_collections, default: use_default)
|
|
elsif params[:sole_author] == 'delete'
|
|
# Deletes works where user is sole author
|
|
@sole_authored_works.each(&:destroy)
|
|
|
|
# Deletes collections where user is sole author
|
|
@sole_owned_collections.each(&:destroy)
|
|
end
|
|
|
|
@works = @user.works.where(posted: true)
|
|
|
|
if @works.blank?
|
|
@user.wipeout_unposted_works
|
|
@user.destroy_empty_series
|
|
|
|
@user.destroy
|
|
|
|
flash[:notice] = ts('You have successfully deleted your account.')
|
|
redirect_to(delete_confirmation_path)
|
|
else
|
|
flash[:error] = ts('Sorry, something went wrong! Please try again.')
|
|
redirect_to(@user)
|
|
end
|
|
end
|
|
|
|
private
|
|
|
|
def profile_params
|
|
params.require(:profile_attributes).permit(
|
|
:title, :about_me, :ticket_number
|
|
)
|
|
end
|
|
end
|