# encoding: utf-8
#
# = Account Controller
#
# == Actions
# L = login required
# R = root required
# V = has view
# P = prefetching allowed
#
# ==== Sign-up
# signup:: (. V P) Create new account.
# verify:: (. V .) Verify new account.
# reverify:: (. V .) If verify fails(?)
# send_verify:: (. . .) Callback used by reverify.
# welcome:: (. V .) Welcome page after signup and verify.
#
# ==== Login
# login:: (. V P)
# logout_user:: (. V .)
# email_new_password:: (. V .)
# show_alert:: (. V .)
#
# ==== Preferences
# prefs:: (L V P)
# profile:: (L V P)
# remove_image:: (L . .)
# no_email:: (L V .)
#
# ==== Admin utilities
# turn_admin_on:: (R . .)
# turn_admin_off:: (R . .)
# add_user_to_group:: (R V .)
# create_alert:: (R V .)
# manager:: (R V .)
# destroy_user:: (R . .)
#
# ==== Testing
# test_autologin:: (L V .)
# test_flash:: (. . .)
#
# :all_norobots:
#
################################################################################
class AccountController < ApplicationController
before_filter :login_required, :except => [
:email_new_password,
:login,
:logout_user,
:reverify,
:send_verify,
:show_alert,
:signup,
:test_flash,
:verify,
:welcome,
]
before_filter :disable_link_prefetching, :except => [
:login,
:signup,
:prefs,
:profile,
]
##############################################################################
#
# :section: Sign-up
#
##############################################################################
def signup # :nologin: :prefetch:
if request.method != :post
@new_user = User.new
else
theme = params['new_user']['theme']
login = params['new_user']['login']
valid_themes = CSS + ["NULL"]
if !valid_themes.member?(theme) or (login == 'test_denied')
if !theme.blank?
# I'm guessing this has something to do with spammer/hacker trying
# to automate creation of accounts?
AccountMailer.deliver_denied(params['new_user'])
end
redirect_back_or_default(:action => :welcome)
else
@new_user = User.new(params['new_user'])
@new_user.created = now = Time.now
@new_user.modified = now
@new_user.last_login = now
@new_user.admin = false
@new_user.created_here = true
@new_user.rows = 5
@new_user.columns = 3
@new_user.mailing_address = ''
@new_user.notes = ''
if !@new_user.save
flash_object_errors(@new_user)
else
group = UserGroup.create_user(@new_user)
Transaction.post_user(
:id => @new_user,
:name => @new_user.name,
:email => @new_user.email,
:login => @new_user.login,
:group => group
)
flash_notice :runtime_signup_success.t
AccountMailer.deliver_verify(@new_user)
redirect_back_or_default(:action => :welcome)
end
end
end
end
def verify # :nologin:
id = params['id']
auth_code = params['auth_code']
user = User.find(id)
# This will happen legitimately whenever a non-verified user tries to
# login. The user just gets redirected here instead of being properly
# logged in. "auth_code" will be missing.
if auth_code != user.auth_code
@unverified_user = user
render(:action => "reverify")
# If already logged in and verified, just send to "welcome" page.
elsif @user == user
redirect_to(:action => :welcome)
# If user is already verified, send them back to the login page. (If
# someone grabs a user's verify email, they could theoretically use it to
# log in any time they wanted to. This makes it a one-time use.)
elsif user.verified
flash_warning(:runtime_reverify_already_verified.t)
redirect_to(:action => :login)
# If not already verified, and the code checks out, then mark account
# "verified", log user in, and display the "you're verified" page.
else
@user = user
@user.last_login = now = Time.now
@user.verified = now
@user.save
set_session_user(@user)
Transaction.put_user(
:id => @user,
:set_verify => @user.verified
)
end
end
# This action is never actually used. It's template is rendered by verify.
def reverify # :nologin:
raise "This action should never occur!"
end
# This is used by the "reverify" page to re-send the verification email.
def send_verify # :nologin:
user = User.find(params[:id])
AccountMailer.deliver_verify(user)
flash_notice :runtime_reverify_sent.t
redirect_back_or_default(:action => :welcome)
end
# This is the welcome page for new users who just created an account.
def welcome # :nologin:
end
##############################################################################
#
# :section: Login
#
##############################################################################
def login # :nologin: :prefetch:
if request.method != :post
@login = ""
@remember = true
else
@login = params['user_login'].to_s
@password = params['user_password'].to_s
@remember = params['user'] && params['user']['remember_me'] == '1'
user = User.authenticate(@login, @password)
user ||= User.authenticate(@login, @password.strip)
if !user
flash_error :runtime_login_failed.t
elsif !user.verified
@unverified_user = user
render(:action => 'reverify')
else
logger.warn("%s, %s, %s" % [user.login, params['user_login'], params['user_password']])
flash_notice :runtime_login_success.t
@user = user
@user.last_login = now = Time.now
@user.modified = now
@user.save
set_session_user(@user)
if @remember
set_autologin_cookie(@user)
else
clear_autologin_cookie
end
redirect_back_or_default(:action => :welcome)
end
end
end
def email_new_password # :nologin:
if request.method != :post
@new_user = User.new
else
@login = params['new_user']['login']
@new_user = User.find(:first, :conditions =>
[ "login = ? OR name = ? OR email = ?", @login, @login, @login ])
if @new_user.nil?
flash_error :runtime_email_new_password_failed.t(:user => @login)
else
password = String.random(10)
@new_user.change_password(password)
if @new_user.save
flash_notice :runtime_email_new_password_success.t
AccountMailer.deliver_new_password(@new_user, password)
render(:action => "login")
else
flash_object_errors(@new_user)
end
end
end
end
def logout_user # :nologin:
@user = set_session_user(nil)
clear_autologin_cookie
end
def show_alert # :nologin:
if !@user
redirect_back_or_default(:action => :welcome)
elsif !@user.alert || !@user.alert_type
flash_warning :user_alert_missing.t
redirect_back_or_default(:action => :welcome)
elsif request.method == :get
@back = session['return-to']
# render alert
elsif request.method == :post
if params[:commit] == :user_alert_okay.l
@user.alert = nil
@user.save
else
@user.alert_next_showing = Time.now + 1.day
@user.save
end
if !params[:back].blank?
redirect_to(params[:back])
else
redirect_to('/')
end
end
end
##############################################################################
#
# :section: Preferences
#
##############################################################################
def prefs # :prefetch:
@licenses = License.current_names_and_ids(@user.license)
if request.method == :post
# Make sure password matches confirmation.
if password = params['user']['password']
if password == params['user']['password_confirmation']
@user.change_password(password)
else
@user.errors.add(:password, :runtime_prefs_password_no_match.t)
end
end
xargs = {}
for type, arg, post in [
[ :str, :login, true ],
[ :str, :email, true ],
[ :str, :locale, true ],
[ :int, :license_id, true ],
[ :str, :votes_anonymous, true ],
[ :bool, :keep_filenames, true ],
[ :str, :location_format, true ],
[ :bool, :email_html, true ],
[ :str, :theme ],
[ :int, :rows ],
[ :int, :columns ],
[ :bool, :alternate_rows ],
[ :bool, :alternate_columns ],
[ :bool, :vertical_layout ],
[ :bool, :email_comments_owner ],
[ :bool, :email_comments_response ],
[ :bool, :email_comments_all ],
[ :bool, :email_observations_consensus ],
[ :bool, :email_observations_naming ],
[ :bool, :email_observations_all ],
[ :bool, :email_names_admin ],
[ :bool, :email_names_author ],
[ :bool, :email_names_editor ],
[ :bool, :email_names_reviewer ],
[ :bool, :email_names_all ],
[ :bool, :email_locations_admin ],
[ :bool, :email_locations_author ],
[ :bool, :email_locations_editor ],
[ :bool, :email_locations_all ],
[ :bool, :email_general_feature ],
[ :bool, :email_general_commercial ],
[ :bool, :email_general_question ],
# [ :str, :email_digest ],
[ :str, :thumbnail_size ],
[ :str, :image_size ],
]
val = params[:user][arg]
val = case type
when :str ; val.to_s
when :int ; val.to_i
when :bool ; val == '1'
end
if @user.send(arg) != val
@user.send("#{arg}=", val)
arg = arg.to_s.sub(/_id/, '')
xargs[:"set_#{arg}"] = val if post
end
end
legal_name_change = @user.legal_name_change
if !@user.changed
flash_notice(:runtime_no_changes.t)
redirect_back_or_default(:controller => :observer, :action => :index)
elsif !@user.errors.empty? || !@user.save
flash_object_errors(@user)
else
if legal_name_change
Image.update_copyright_holder(*legal_name_change, @user)
end
if !xargs.empty?
xargs[:id] = @user
Transaction.put_user(xargs)
end
flash_notice(:runtime_prefs_success.t)
redirect_back_or_default(:controller => :observer, :action => :index)
end
end
end
def profile # :prefetch:
@licenses = License.current_names_and_ids(@user.license)
if request.method != :post
@place_name = @user.location ? @user.location.display_name : ""
@copyright_holder = @user.legal_name
@copyright_year = Time.now.year
@upload_license_id = @user.license.id
else
xargs = {}
for arg in [:name, :notes, :mailing_address]
val = params[:user][arg].to_s
if @user.send(arg) != val
@user.send("#{arg}=", val)
xargs[:"set_#{arg}"] = val
end
end
# Make sure the given location exists before accepting it.
@place_name = params['user']['place_name'].to_s
if !@place_name.blank?
location = Location.search_by_name(@place_name)
if !location
need_to_create_location = true
elsif @user.location != location
@user.location = location
xargs[:set_location] = location
@place_name = location.display_name
end
elsif @user.location
@user.location = nil
xargs[:set_location] = 0
end
# Check if we need to upload an image.
upload = params['user']['upload_image']
if !upload.blank?
if upload.respond_to?(:original_filename)
name = upload.original_filename.force_encoding('utf-8')
else
name = nil
end
date = Time.local(params['date']['copyright_year'])
license = License.safe_find(params['upload']['license_id'])
holder = params['copyright_holder']
image = Image.new(
:image => upload,
:user => @user,
:when => date,
:copyright_holder => holder,
:license => license
)
if !image.save
flash_object_errors(image)
elsif !image.process_image
logger.error('Unable to upload image')
name = image.original_name
name = '???' if name.empty?
flash_error(:runtime_profile_invalid_image.t(:name => name))
flash_object_errors(image)
else
Transaction.post_image(
:id => image,
:date => date,
:url => image.original_url,
:copyright_holder => holder,
:license => license
)
@user.image = image
xargs[:set_image] = image
name = image.original_name
name = "##{image.id}" if name.empty?
flash_notice(:runtime_profile_uploaded_image.t(:name => name))
end
end
legal_name_change = @user.legal_name_change
if !@user.changed
flash_notice(:runtime_no_changes.t)
redirect_to(:controller => 'observer', :action => 'show_user', :id => @user.id)
elsif !@user.save
flash_object_errors(@user)
else
if legal_name_change
Image.update_copyright_holder(*legal_name_change, @user)
end
if !xargs.empty?
xargs[:id] = @user
Transaction.put_user(xargs)
end
if need_to_create_location
flash_notice(:runtime_profile_must_define.t)
redirect_to(:controller => 'location', :action => 'create_location',
:where => @place_name, :set_user => @user.id)
else
flash_notice(:runtime_profile_success.t)
redirect_to(:controller => 'observer', :action => 'show_user', :id => @user.id)
end
end
end
end
def remove_image
if @user && @user.image
@user.update_attributes(:image => nil)
Transaction.put_user(:id => @user, :set_image => 0)
flash_notice(:runtime_profile_removed_image.t)
end
redirect_to(:controller => 'observer', :action => 'show_user', :id => @user.id)
end
def no_email_comments_owner; no_email('comments_owner'); end
def no_email_comments_response; no_email('comments_response'); end
def no_email_comments_all; no_email('comments_all'); end
def no_email_observations_consensus; no_email('observations_consensus'); end
def no_email_observations_naming; no_email('observations_naming'); end
def no_email_observations_all; no_email('observations_all'); end
def no_email_names_admin; no_email('names_admin'); end
def no_email_names_author; no_email('names_author'); end
def no_email_names_editor; no_email('names_editor'); end
def no_email_names_reviewer; no_email('names_reviewer'); end
def no_email_names_all; no_email('names_all'); end
def no_email_locations_admin; no_email('locations_admin'); end
def no_email_locations_author; no_email('locations_author'); end
def no_email_locations_editor; no_email('locations_editor'); end
def no_email_locations_all; no_email('locations_all'); end
def no_email_general_feature; no_email('general_feature'); end
def no_email_general_commercial; no_email('general_commercial'); end
def no_email_general_question; no_email('general_question'); end
# These are the old email flags, renamed in favor of more consistent ones.
alias_method :no_comment_email, :no_email_comments_owner
alias_method :no_comment_response_email, :no_email_comments_response
alias_method :no_commercial_email, :no_email_general_commercial
alias_method :no_consensus_change_email, :no_email_observations_consensus
alias_method :no_feature_email, :no_email_general_feature
alias_method :no_name_change_email, :no_email_names_author
alias_method :no_name_proposal_email, :no_email_observations_naming
alias_method :no_question_email, :no_email_general_question
def no_email(type)
if check_permission!(params[:id])
method = "email_#{type}="
prefix = "no_email_#{type}"
success = "#{prefix}_success".to_sym
@note = "#{prefix}_note".to_sym
set_val = "set_#{type}".to_sym
@user.send(method, false)
if @user.save
flash_notice(success.t(:name => @user.unique_text_name))
render(:action => :no_email)
else
# Probably should write a better error message here...
flash_object_errors(@user)
redirect_to(:controller => :observer, :action => :list_rss_logs)
end
else
redirect_to(:controller => :observer, :action => :list_rss_logs)
end
end
##############################################################################
#
# :section: Admin utilities
#
##############################################################################
def turn_admin_on # :root:
if @user && @user.admin && !is_in_admin_mode?
session[:admin] = true
end
redirect_back_or_default(:controller => :observer, :action => :index)
end
def turn_admin_off # :root:
session[:admin] = nil
redirect_back_or_default(:controller => :observer, :action => :index)
end
def add_user_to_group # :root:
redirect = true
if is_in_admin_mode?
if request.method == :post
user_name = params['user_name'].to_s
group_name = params['group_name'].to_s
user = User.find_by_login(user_name)
group = UserGroup.find_by_name(group_name)
flash_error :add_user_to_group_no_user.t(:user => user_name) if !user
flash_error :add_user_to_group_no_group.t(:group => group_name) if !group
if user && group
if user.user_groups.member?(group)
flash_warning :add_user_to_group_already. \
t(:user => user_name, :group => group_name)
else
user.user_groups << group
Transaction.put_user_group(
:id => group,
:add_user => user
)
flash_notice :add_user_to_group_success. \
t(:user => user_name, :group => group_name)
end
end
else
redirect = false
end
else
flash_error :permission_denied.t
end
if redirect
redirect_back_or_default(:controller => 'observer', :action => 'index')
end
end
def create_alert # :root:
redirect = true
id = params[:id]
@user2 = User.find(id)
if is_in_admin_mode?
if request.method == :get
# render form
redirect = false
elsif request.method == :post
if params[:commit] == :user_alert_save.l
@user2.alert_type = params[:user2][:alert_type]
@user2.alert_notes = params[:user2][:alert_notes]
if params[:user2][:alert_type].blank?
flash_error :user_alert_missing_type.t
@user2.errors.add(:alert_type)
redirect = false
else
@user2.alert_created = now = Time.now
@user2.alert_next_showing = now
@user2.alert_user_id = @user.id
@user2.save
flash_notice :user_alert_saved.t(:user => @user2.login)
end
else
@user2.alert = nil
@user2.save
flash_notice :user_alert_deleted.t(:user => @user2.login)
end
end
end
if redirect
redirect_to(:controller => :observer, :action => :show_user, :id => id)
end
end
def manager # :root:
if is_in_admin_mode?
@users = []
# Search for users by id(s).
if !params[:ids].blank?
for id in params[:ids].split(/[, ]+/)
if user = User.safe_find(id.to_i)
@users << user
else
flash_error(:account_manager_not_found.t(:str => "##{id}"))
end
end
end
# Search for users by login, name and email.
if !params[:login].blank?
@users += User.find(:all, :conditions => "login like '%#{params[:login]}%'")
end
if !params[:name].blank?
@users += User.find(:all, :conditions => "name like '%#{params[:name]}%'")
end
if !params[:email].blank?
@users += User.find(:all, :conditions => "email like '%#{params[:email]}%'")
end
# Modify user records.
for user in @users
id = user.id
any_changes = false
# Correct typos in an email address.
old_email = user.email.to_s
new_email = params["email_#{id}"].to_s
if !new_email.blank? and old_email != new_email
user.email = new_email
any_changes = true
flash_notice(:account_manager_changed_email.t(:user => user.login, :email => new_email))
end
# Reset a password.
password = params["password_#{id}"].to_s
if !password.blank?
user.change_password(password)
flash_notice(:account_manager_changed_password.t(:user => user.login, :password => password))
end
# Verify an account.
old_verified = user.verified
new_verified = params["verified_#{id}"].to_s
if !old_verified && !new_verified.blank?
user.verified = Time.now
any_changes = true
flash_notice(:account_manager_verified_user.t(:user => user.login))
end
user.save if any_changes
end
else
flash_error :permission_denied.t
redirect_to(:controller => :observer, :action => :index)
end
end
# This is messy, but the new User#erase_user method makes a pretty good
# stab at the problem.
def destroy_user # :root:
if is_in_admin_mode?
id = params['id']
if !id.blank?
user = User.safe_find(id)
if user
Transaction.delete_user(:id => user)
User.erase_user(id)
end
end
end
redirect_back_or_default('/')
end
##############################################################################
#
# :section: Testing
#
##############################################################################
# This is used to test the autologin feature.
def test_autologin
end
# This is used to test the flash error mechanism in the unit tests.
def test_flash # :nologin:
notice = params[:notice]
warning = params[:warning]
error = params[:error]
redirect = params[:redirect]
flash_notice(notice) if notice
flash_warning(warning) if warning
flash_error(error) if error
if redirect
redirect_to(redirect)
else
render(:text => '', :layout => true)
end
end
end