Merge branch 'master' into feature/add-communities-page

# Conflicts:
#	Gemfile.lock
#	package.json
#	yarn.lock
This commit is contained in:
Adam Hoyle 2022-09-10 16:10:08 +01:00
commit 7e5cbe87ed
527 changed files with 147625 additions and 149175 deletions

View file

@ -0,0 +1,12 @@
module Account
class DeletionsController < ApplicationController
layout "site"
before_action :authorize_web
before_action :set_locale
authorize_resource :class => false
def show; end
end
end

View file

@ -0,0 +1,64 @@
class AccountsController < ApplicationController
include SessionMethods
include UserMethods
layout "site"
before_action :authorize_web
before_action :set_locale
authorize_resource :class => false
before_action :check_database_readable
before_action :check_database_writable, :only => [:update]
before_action :allow_thirdparty_images, :only => [:edit, :update]
def edit
@tokens = current_user.oauth_tokens.authorized
append_content_security_policy_directives(
:form_action => %w[accounts.google.com *.facebook.com login.live.com github.com meta.wikimedia.org]
)
if errors = session.delete(:user_errors)
errors.each do |attribute, error|
current_user.errors.add(attribute, error)
end
end
@title = t ".title"
end
def update
@tokens = current_user.oauth_tokens.authorized
append_content_security_policy_directives(
:form_action => %w[accounts.google.com *.facebook.com login.live.com github.com meta.wikimedia.org]
)
user_params = params.require(:user).permit(:display_name, :new_email, :pass_crypt, :pass_crypt_confirmation, :auth_provider)
if params[:user][:auth_provider].blank? ||
(params[:user][:auth_provider] == current_user.auth_provider &&
params[:user][:auth_uid] == current_user.auth_uid)
update_user(current_user, user_params)
if current_user.errors.count.zero?
redirect_to edit_account_path
else
render :edit
end
else
session[:new_user_settings] = user_params.to_h
redirect_to auth_url(params[:user][:auth_provider], params[:user][:auth_uid]), :status => :temporary_redirect
end
end
def destroy
current_user.soft_destroy!
session.delete(:user)
session_expires_automatically
flash[:notice] = t ".success"
redirect_to root_path
end
end

View file

@ -1,12 +1,13 @@
module Api
class ChangesetCommentsController < ApiController
before_action :check_api_writable
before_action :check_api_readable, :except => [:create]
before_action :authorize
authorize_resource
before_action :require_public_data, :only => [:create]
before_action :check_api_writable
before_action :check_api_readable, :except => [:create]
before_action :set_request_formats
around_action :api_call_handle_error
around_action :api_call_timeout
@ -23,7 +24,7 @@ module Api
# Find the changeset and check it is valid
changeset = Changeset.find(id)
raise OSM::APIChangesetNotYetClosedError, changeset if changeset.is_open?
raise OSM::APIChangesetNotYetClosedError, changeset if changeset.open?
# Add a comment to the changeset
comment = changeset.comments.create(:changeset => changeset,
@ -41,6 +42,11 @@ module Api
# Return a copy of the updated changeset
@changeset = changeset
render "api/changesets/changeset"
respond_to do |format|
format.xml
format.json
end
end
##
@ -61,6 +67,11 @@ module Api
# Return a copy of the updated changeset
@changeset = comment.changeset
render "api/changesets/changeset"
respond_to do |format|
format.xml
format.json
end
end
##
@ -81,6 +92,11 @@ module Api
# Return a copy of the updated changeset
@changeset = comment.changeset
render "api/changesets/changeset"
respond_to do |format|
format.xml
format.json
end
end
end
end

View file

@ -4,14 +4,14 @@ module Api
class ChangesetsController < ApiController
require "xml/libxml"
before_action :check_api_writable, :only => [:create, :update, :upload, :subscribe, :unsubscribe]
before_action :check_api_readable, :except => [:create, :update, :upload, :download, :query, :subscribe, :unsubscribe]
before_action :authorize, :only => [:create, :update, :upload, :close, :subscribe, :unsubscribe]
authorize_resource
before_action :require_public_data, :only => [:create, :update, :upload, :close, :subscribe, :unsubscribe]
before_action :check_api_writable, :only => [:create, :update, :upload, :subscribe, :unsubscribe]
before_action :check_api_readable, :except => [:create, :update, :upload, :download, :query, :subscribe, :unsubscribe]
before_action :set_request_formats, :only => [:download]
before_action :set_request_formats, :except => [:create, :close, :upload]
around_action :api_call_handle_error
around_action :api_call_timeout, :except => [:upload]
@ -42,6 +42,11 @@ module Api
@changeset = Changeset.find(params[:id])
@include_discussion = params[:include_discussion].presence
render "changeset"
respond_to do |format|
format.xml
format.json
end
end
##
@ -171,6 +176,11 @@ module Api
# preload users, tags and comments, and render result
@changesets = changesets.preload(:user, :changeset_tags, :comments)
render "changesets"
respond_to do |format|
format.xml
format.json
end
end
##
@ -191,6 +201,11 @@ module Api
check_changeset_consistency(@changeset, current_user)
@changeset.update_from(new_changeset, current_user)
render "changeset"
respond_to do |format|
format.xml
format.json
end
end
##
@ -212,6 +227,11 @@ module Api
# Return a copy of the updated changeset
@changeset = changeset
render "changeset"
respond_to do |format|
format.xml
format.json
end
end
##
@ -233,6 +253,11 @@ module Api
# Return a copy of the updated changeset
@changeset = changeset
render "changeset"
respond_to do |format|
format.xml
format.json
end
end
private
@ -307,11 +332,11 @@ module Api
times = time.split(",")
raise OSM::APIBadUserInput, "bad time range" if times.size != 2
from, to = times.collect { |t| Time.parse(t) }
from, to = times.collect { |t| Time.parse(t).utc }
changesets.where("closed_at >= ? and created_at <= ?", from, to)
else
# if there is no comma, assume its a lower limit on time
changesets.where("closed_at >= ?", Time.parse(time))
changesets.where("closed_at >= ?", Time.parse(time).utc)
end
# stupid Time seems to throw both of these for bad parsing, so
# we have to catch both and ensure the correct code path is taken.
@ -329,7 +354,7 @@ module Api
changesets
else
changesets.where("closed_at >= ? and num_changes <= ?",
Time.now.getutc, Changeset::MAX_ELEMENTS)
Time.now.utc, Changeset::MAX_ELEMENTS)
end
end
@ -341,7 +366,7 @@ module Api
changesets
else
changesets.where("closed_at < ? or num_changes > ?",
Time.now.getutc, Changeset::MAX_ELEMENTS)
Time.now.utc, Changeset::MAX_ELEMENTS)
end
end

View file

@ -1,8 +1,9 @@
module Api
class MapController < ApiController
before_action :check_api_readable
authorize_resource :class => false
before_action :check_api_readable
around_action :api_call_handle_error, :api_call_timeout
before_action :set_request_formats

View file

@ -4,13 +4,13 @@ module Api
class NodesController < ApiController
require "xml/libxml"
before_action :check_api_writable, :only => [:create, :update, :delete]
before_action :check_api_readable, :except => [:create, :update, :delete]
before_action :authorize, :only => [:create, :update, :delete]
authorize_resource
before_action :require_public_data, :only => [:create, :update, :delete]
before_action :check_api_writable, :only => [:create, :update, :delete]
before_action :check_api_readable, :except => [:create, :update, :delete]
around_action :api_call_handle_error, :api_call_timeout
before_action :set_request_formats, :except => [:create, :update, :delete]

View file

@ -1,12 +1,12 @@
module Api
class NotesController < ApiController
before_action :check_api_readable
before_action :setup_user_auth, :only => [:create, :comment, :show]
before_action :check_api_writable, :only => [:create, :comment, :close, :reopen, :destroy]
before_action :setup_user_auth, :only => [:create, :show]
before_action :authorize, :only => [:close, :reopen, :destroy, :comment]
authorize_resource
before_action :check_api_writable, :only => [:create, :comment, :close, :reopen, :destroy]
before_action :set_locale
around_action :api_call_handle_error, :api_call_timeout
@ -277,16 +277,16 @@ module Api
# Add any date filter
if params[:from]
begin
from = Time.parse(params[:from])
from = Time.parse(params[:from]).utc
rescue ArgumentError
raise OSM::APIBadUserInput, "Date #{params[:from]} is in a wrong format"
end
begin
to = if params[:to]
Time.parse(params[:to])
Time.parse(params[:to]).utc
else
Time.now
Time.now.utc
end
rescue ArgumentError
raise OSM::APIBadUserInput, "Date #{params[:to]} is in a wrong format"
@ -361,7 +361,7 @@ module Api
elsif closed_since.positive?
notes.where(:status => "open")
.or(notes.where(:status => "closed")
.where(notes.arel_table[:closed_at].gt(Time.now - closed_since.days)))
.where(notes.arel_table[:closed_at].gt(Time.now.utc - closed_since.days)))
else
notes.where(:status => "open")
end

View file

@ -5,13 +5,13 @@ module Api
class OldController < ApiController
require "xml/libxml"
before_action :check_api_readable
before_action :check_api_writable, :only => [:redact]
before_action :setup_user_auth, :only => [:history, :version]
before_action :authorize, :only => [:redact]
authorize_resource
before_action :check_api_readable
before_action :check_api_writable, :only => [:redact]
around_action :api_call_handle_error, :api_call_timeout
before_action :lookup_old_element, :except => [:history]
before_action :lookup_old_element_versions, :only => [:history]

View file

@ -1,9 +1,11 @@
module Api
class PermissionsController < ApiController
before_action :check_api_readable
authorize_resource :class => false
before_action :check_api_readable
before_action :setup_user_auth
before_action :set_request_formats
around_action :api_call_handle_error, :api_call_timeout
# External apps that use the api are able to query which permissions
@ -21,6 +23,11 @@ module Api
else
[]
end
respond_to do |format|
format.xml
format.json
end
end
end
end

View file

@ -2,13 +2,13 @@ module Api
class RelationsController < ApiController
require "xml/libxml"
before_action :check_api_writable, :only => [:create, :update, :delete]
before_action :check_api_readable, :except => [:create, :update, :delete]
before_action :authorize, :only => [:create, :update, :delete]
authorize_resource
before_action :require_public_data, :only => [:create, :update, :delete]
before_action :check_api_writable, :only => [:create, :update, :delete]
before_action :check_api_readable, :except => [:create, :update, :delete]
around_action :api_call_handle_error, :api_call_timeout
before_action :set_request_formats, :except => [:create, :update, :delete]

View file

@ -1,8 +1,9 @@
module Api
class TracepointsController < ApiController
before_action :check_api_readable
authorize_resource
before_action :check_api_readable
around_action :api_call_handle_error, :api_call_timeout
# Get an XML response containing a list of tracepoints that have been uploaded

View file

@ -1,13 +1,13 @@
module Api
class TracesController < ApiController
before_action :check_database_readable, :except => [:show, :data]
before_action :check_database_writable, :only => [:create, :update, :destroy]
before_action :authorize_web
before_action :set_locale
before_action :authorize
authorize_resource
before_action :check_database_readable, :except => [:show, :data]
before_action :check_database_writable, :only => [:create, :update, :destroy]
before_action :check_api_readable, :only => [:show, :data]
before_action :check_api_writable, :only => [:create, :update, :destroy]
before_action :offline_error, :only => [:create, :destroy, :data]
@ -54,6 +54,8 @@ module Api
send_data(trace.xml_file.read, :filename => "#{trace.id}.xml", :type => request.format.to_s, :disposition => "attachment")
elsif request.format == Mime[:gpx]
send_data(trace.xml_file.read, :filename => "#{trace.id}.gpx", :type => request.format.to_s, :disposition => "attachment")
elsif trace.file.attached?
redirect_to rails_blob_path(trace.file, :disposition => "attachment")
else
send_file(trace.trace_name, :filename => "#{trace.id}#{trace.extension_name}", :type => trace.mime_type, :disposition => "attachment")
end
@ -97,12 +99,6 @@ module Api
# Sanitise the user's filename
name = file.original_filename.gsub(/[^a-zA-Z0-9.]/, "_")
# Get a temporary filename...
filename = "/tmp/#{rand}"
# ...and save the uploaded file to that location
File.open(filename, "wb") { |f| f.write(file.read) }
# Create the trace object, falsely marked as already
# inserted to stop the import daemon trying to load it
trace = Trace.new(
@ -110,40 +106,14 @@ module Api
:tagstring => tags,
:description => description,
:visibility => visibility,
:inserted => true,
:inserted => false,
:user => current_user,
:timestamp => Time.now.getutc
:timestamp => Time.now.utc,
:file => file
)
if trace.valid?
Trace.transaction do
begin
# Save the trace object
trace.save!
# Rename the temporary file to the final name
FileUtils.mv(filename, trace.trace_name)
rescue StandardError
# Remove the file as we have failed to update the database
FileUtils.rm_f(filename)
# Pass the exception on
raise
end
begin
# Clear the inserted flag to make the import daemon load the trace
trace.inserted = false
trace.save!
rescue StandardError
# Remove the file as we have failed to update the database
FileUtils.rm_f(trace.trace_name)
# Pass the exception on
raise
end
end
end
# Save the trace object
trace.save!
# Finally save the user's preferred privacy level
if pref = current_user.preferences.where(:k => "gps.trace.visibility").first

View file

@ -1,12 +1,12 @@
module Api
class UsersController < ApiController
before_action :check_api_readable
before_action :disable_terms_redirect, :only => [:details]
before_action :setup_user_auth, :only => [:show, :index]
before_action :authorize, :only => [:details, :gpx_files]
authorize_resource
before_action :check_api_readable
around_action :api_call_handle_error
before_action :lookup_user_by_id, :only => [:show]

View file

@ -2,13 +2,13 @@ module Api
class WaysController < ApiController
require "xml/libxml"
before_action :check_api_writable, :only => [:create, :update, :delete]
before_action :check_api_readable, :except => [:create, :update, :delete]
before_action :authorize, :only => [:create, :update, :delete]
authorize_resource
before_action :require_public_data, :only => [:create, :update, :delete]
before_action :check_api_writable, :only => [:create, :update, :delete]
before_action :check_api_readable, :except => [:create, :update, :delete]
around_action :api_call_handle_error, :api_call_timeout
before_action :set_request_formats, :except => [:create, :update, :delete]

View file

@ -31,9 +31,8 @@ class ApiController < ApplicationController
# as XML for backwards compatibility - all other formats are discarded
# which will result in a 406 Not Acceptable response being sent
formats = mimetypes.map do |mime|
if mime.symbol == :xml then :xml
if mime.symbol == :xml || mime == "*/*" then :xml
elsif mime.symbol == :json then :json
elsif mime == "*/*" then :xml
end
end
else
@ -53,8 +52,13 @@ class ApiController < ApplicationController
# handle authenticate pass/fail
unless current_user
# no auth, the user does not exist or the password was wrong
response.headers["WWW-Authenticate"] = "Basic realm=\"#{realm}\""
render :plain => errormessage, :status => :unauthorized
if Settings.basic_auth_support
response.headers["WWW-Authenticate"] = "Basic realm=\"#{realm}\""
render :plain => errormessage, :status => :unauthorized
else
render :plain => errormessage, :status => :forbidden
end
false
end
end
@ -76,11 +80,13 @@ class ApiController < ApplicationController
report_error t("oauth.permissions.missing"), :forbidden
elsif current_user
head :forbidden
else
elsif Settings.basic_auth_support
realm = "Web Password"
errormessage = "Couldn't authenticate you"
response.headers["WWW-Authenticate"] = "Basic realm=\"#{realm}\""
render :plain => errormessage, :status => :unauthorized
else
render :plain => errormessage, :status => :forbidden
end
end
@ -95,13 +101,14 @@ class ApiController < ApplicationController
# from the authorize method, but can be called elsewhere if authorisation
# is optional.
def setup_user_auth
logger.info " setup_user_auth"
# try and setup using OAuth
if doorkeeper_token&.accessible?
self.current_user = User.find(doorkeeper_token.resource_owner_id)
elsif Authenticator.new(self, [:token]).allow?
# self.current_user setup by OAuth
else
username, passwd = get_auth_data # parse from headers
elsif Settings.basic_auth_support
username, passwd = auth_data # parse from headers
# authenticate per-scheme
self.current_user = if username.nil?
nil # no authentication provided - perhaps first connect (client should retry after 401)
@ -110,6 +117,8 @@ class ApiController < ApplicationController
else
User.authenticate(:username => username, :password => passwd) # basic auth
end
# log if we have authenticated using basic auth
logger.info "Authenticated as user #{current_user.id} using basic authentication" if current_user
end
# have we identified the user?

View file

@ -161,7 +161,7 @@ class ApplicationController < ActionController::Base
response.headers["Error"] = message
if request.headers["X-Error-Format"]&.casecmp("xml")&.zero?
result = OSM::API.new.get_xml_doc
result = OSM::API.new.xml_doc
result.root.name = "osmError"
result.root << (XML::Node.new("status") << "#{Rack::Utils.status_code(status)} #{Rack::Utils::HTTP_STATUS_CODES[status]}")
result.root << (XML::Node.new("message") << message)
@ -349,7 +349,7 @@ class ApplicationController < ActionController::Base
elsif current_user
set_locale
respond_to do |format|
format.html { redirect_to :controller => "errors", :action => "forbidden" }
format.html { redirect_to :controller => "/errors", :action => "forbidden" }
format.any { report_error t("application.permission_denied"), :forbidden }
end
elsif request.get?
@ -363,7 +363,7 @@ class ApplicationController < ActionController::Base
end
# extract authorisation credentials from headers, returns user = nil if none
def get_auth_data
def auth_data
if request.env.key? "X-HTTP_AUTHORIZATION" # where mod_rewrite might have put it
authdata = request.env["X-HTTP_AUTHORIZATION"].to_s.split
elsif request.env.key? "REDIRECT_X_HTTP_AUTHORIZATION" # mod_fcgi

View file

@ -8,7 +8,7 @@ module SessionMethods
def auth_url(provider, uid, referer = nil)
params = { :provider => provider }
params[:openid_url] = openid_expand_url(uid) if provider == "openid"
params[:openid_url] = uid if provider == "openid"
if referer.nil?
params[:origin] = request.path
@ -20,23 +20,6 @@ module SessionMethods
auth_path(params)
end
##
# special case some common OpenID providers by applying heuristics to
# try and come up with the correct URL based on what the user entered
def openid_expand_url(openid_url)
if openid_url.nil?
nil
elsif openid_url.match(%r{(.*)gmail.com(/?)$}) || openid_url.match(%r{(.*)googlemail.com(/?)$})
# Special case gmail.com as it is potentially a popular OpenID
# provider and, unlike yahoo.com, where it works automatically, Google
# have hidden their OpenID endpoint somewhere obscure this making it
# somewhat less user friendly.
"https://www.google.com/accounts/o8/id"
else
openid_url
end
end
##
# process a successful login
def successful_login(user, referer = nil)

View file

@ -0,0 +1,47 @@
module UserMethods
extend ActiveSupport::Concern
private
##
# update a user's details
def update_user(user, params)
user.display_name = params[:display_name]
user.new_email = params[:new_email]
unless params[:pass_crypt].empty? && params[:pass_crypt_confirmation].empty?
user.pass_crypt = params[:pass_crypt]
user.pass_crypt_confirmation = params[:pass_crypt_confirmation]
end
if params[:auth_provider].nil? || params[:auth_provider].blank?
user.auth_provider = nil
user.auth_uid = nil
end
if user.save
session[:fingerprint] = user.fingerprint
if user.new_email.blank? || user.new_email == user.email
flash[:notice] = t "accounts.update.success"
else
user.email = user.new_email
if user.valid?
flash[:notice] = t "accounts.update.success_confirm_needed"
begin
UserMailer.email_confirm(user, user.tokens.create).deliver_later
rescue StandardError
# Ignore errors sending email
end
else
current_user.errors.add(:new_email, current_user.errors[:email])
current_user.errors.add(:email, [])
end
user.restore_email!
end
end
end
end

View file

@ -25,7 +25,7 @@ class ConfirmationsController < ApplicationController
render_unknown_user token.user.display_name
else
user = token.user
user.status = "active"
user.activate
user.email_valid = true
flash[:notice] = gravatar_status_message(user) if gravatar_enable(user)
user.save!
@ -93,10 +93,10 @@ class ConfirmationsController < ApplicationController
current_user.tokens.delete_all
session[:user] = current_user.id
session[:fingerprint] = current_user.fingerprint
redirect_to user_account_path(current_user)
redirect_to edit_account_path
elsif token
flash[:error] = t "confirmations.confirm_email.failure"
redirect_to user_account_path(token.user)
redirect_to edit_account_path
else
flash[:error] = t "confirmations.confirm_email.unknown_token"
end

View file

@ -60,9 +60,8 @@ class DiaryEntriesController < ApplicationController
@title = t "diary_entries.edit.title"
@diary_entry = DiaryEntry.find(params[:id])
if current_user != @diary_entry.user
redirect_to diary_entry_path(@diary_entry.user, @diary_entry)
elsif params[:diary_entry] && @diary_entry.update(entry_params)
if current_user != @diary_entry.user ||
(params[:diary_entry] && @diary_entry.update(entry_params))
redirect_to diary_entry_path(@diary_entry.user, @diary_entry)
else
set_map_location

View file

@ -21,7 +21,7 @@ class ExportController < ApplicationController
format = params[:mapnik_format]
scale = params[:mapnik_scale]
redirect_to "https://render.openstreetmap.org/cgi-bin/export?bbox=#{bbox}&scale=#{scale}&format=#{format}"
redirect_to "https://render.openstreetmap.org/cgi-bin/export?bbox=#{bbox}&scale=#{scale}&format=#{format}", :allow_other_host => true
end
end

View file

@ -17,9 +17,9 @@ class FriendshipsController < ApplicationController
friendship = Friendship.new
friendship.befriender = current_user
friendship.befriendee = @new_friend
if current_user.is_friends_with?(@new_friend)
if current_user.friends_with?(@new_friend)
flash[:warning] = t "friendships.make_friend.already_a_friend", :name => @new_friend.display_name
elsif current_user.friendships.where("created_at >= ?", Time.now.getutc - 1.hour).count >= current_user.max_friends_per_hour
elsif current_user.friendships.where("created_at >= ?", Time.now.utc - 1.hour).count >= current_user.max_friends_per_hour
flash.now[:error] = t "friendships.make_friend.limit_exceeded"
elsif friendship.save
flash[:notice] = t "friendships.make_friend.success", :name => @new_friend.display_name
@ -42,7 +42,7 @@ class FriendshipsController < ApplicationController
if @friend
if request.post?
if current_user.is_friends_with?(@friend)
if current_user.friends_with?(@friend)
Friendship.where(:befriender => current_user, :befriendee => @friend).delete_all
flash[:notice] = t "friendships.remove_friend.success", :name => @friend.display_name
else

View file

@ -18,9 +18,8 @@ class GeocoderController < ApplicationController
@sources.push "geonames_reverse" if Settings.key?(:geonames_username)
elsif @params[:query]
case @params[:query]
when /^\d{5}(-\d{4})?$/
@sources.push "osm_nominatim"
when /^(GIR 0AA|[A-PR-UWYZ]([0-9]{1,2}|([A-HK-Y][0-9]|[A-HK-Y][0-9]([0-9]|[ABEHMNPRV-Y]))|[0-9][A-HJKS-UW])\s*[0-9][ABD-HJLNP-UW-Z]{2})$/i
when /^\d{5}(-\d{4})?$/,
/^(GIR 0AA|[A-PR-UWYZ]([0-9]{1,2}|([A-HK-Y][0-9]|[A-HK-Y][0-9]([0-9]|[ABEHMNPRV-Y]))|[0-9][A-HJKS-UW])\s*[0-9][ABD-HJLNP-UW-Z]{2})$/i
@sources.push "osm_nominatim"
when /^[A-Z]\d[A-Z]\s*\d[A-Z]\d$/i
@sources.push "ca_postcode"
@ -168,7 +167,8 @@ class GeocoderController < ApplicationController
render :action => "results"
rescue StandardError => e
@error = "Error contacting nominatim.openstreetmap.org: #{e}"
host = URI(Settings.nominatim_url).host
@error = "Error contacting #{host}: #{e}"
render :action => "error"
end
@ -232,7 +232,8 @@ class GeocoderController < ApplicationController
render :action => "results"
rescue StandardError => e
@error = "Error contacting nominatim.openstreetmap.org: #{e}"
host = URI(Settings.nominatim_url).host
@error = "Error contacting #{host}: #{e}"
render :action => "error"
end
@ -291,22 +292,19 @@ class GeocoderController < ApplicationController
if query = params[:query]
query.strip!
if latlon = query.match(/^([NS])\s*(\d{1,3}(\.\d*)?)\W*([EW])\s*(\d{1,3}(\.\d*)?)$/).try(:captures) # [NSEW] decimal degrees
params.merge!(nsew_to_decdeg(latlon)).delete(:query)
elsif latlon = query.match(/^(\d{1,3}(\.\d*)?)\s*([NS])\W*(\d{1,3}(\.\d*)?)\s*([EW])$/).try(:captures) # decimal degrees [NSEW]
if latlon = query.match(/^([NS])\s*(\d{1,3}(\.\d*)?)\W*([EW])\s*(\d{1,3}(\.\d*)?)$/).try(:captures) || # [NSEW] decimal degrees
query.match(/^(\d{1,3}(\.\d*)?)\s*([NS])\W*(\d{1,3}(\.\d*)?)\s*([EW])$/).try(:captures) # decimal degrees [NSEW]
params.merge!(nsew_to_decdeg(latlon)).delete(:query)
elsif latlon = query.match(/^([NS])\s*(\d{1,3})°?\s*(\d{1,3}(\.\d*)?)?[']?\W*([EW])\s*(\d{1,3})°?\s*(\d{1,3}(\.\d*)?)?[']?$/).try(:captures) # [NSEW] degrees, decimal minutes
params.merge!(ddm_to_decdeg(latlon)).delete(:query)
elsif latlon = query.match(/^(\d{1,3})°?\s*(\d{1,3}(\.\d*)?)?[']?\s*([NS])\W*(\d{1,3})°?\s*(\d{1,3}(\.\d*)?)?[']?\s*([EW])$/).try(:captures) # degrees, decimal minutes [NSEW]
elsif latlon = query.match(/^([NS])\s*(\d{1,3})°?(?:\s*(\d{1,3}(\.\d*)?)?[']?)?\W*([EW])\s*(\d{1,3})°?(?:\s*(\d{1,3}(\.\d*)?)?[']?)?$/).try(:captures) || # [NSEW] degrees, decimal minutes
query.match(/^(\d{1,3})°?(?:\s*(\d{1,3}(\.\d*)?)?[']?)?\s*([NS])\W*(\d{1,3})°?(?:\s*(\d{1,3}(\.\d*)?)?[']?)?\s*([EW])$/).try(:captures) # degrees, decimal minutes [NSEW]
params.merge!(ddm_to_decdeg(latlon)).delete(:query)
elsif latlon = query.match(/^([NS])\s*(\d{1,3})°?\s*(\d{1,2})[']?\s*(\d{1,3}(\.\d*)?)?["″]?\W*([EW])\s*(\d{1,3})°?\s*(\d{1,2})[']?\s*(\d{1,3}(\.\d*)?)?["″]?$/).try(:captures) # [NSEW] degrees, minutes, decimal seconds
params.merge!(dms_to_decdeg(latlon)).delete(:query)
elsif latlon = query.match(/^(\d{1,3})°?\s*(\d{1,2})[']?\s*(\d{1,3}(\.\d*)?)?["″]\s*([NS])\W*(\d{1,3})°?\s*(\d{1,2})[']?\s*(\d{1,3}(\.\d*)?)?["″]?\s*([EW])$/).try(:captures) # degrees, minutes, decimal seconds [NSEW]
elsif latlon = query.match(/^([NS])\s*(\d{1,3})°?\s*(\d{1,2})[']?(?:\s*(\d{1,3}(\.\d*)?)?["″]?)?\W*([EW])\s*(\d{1,3})°?\s*(\d{1,2})[']?(?:\s*(\d{1,3}(\.\d*)?)?["″]?)?$/).try(:captures) || # [NSEW] degrees, minutes, decimal seconds
query.match(/^(\d{1,3})°?\s*(\d{1,2})[']?(?:\s*(\d{1,3}(\.\d*)?)?["″]?)?\s*([NS])\W*(\d{1,3})°?\s*(\d{1,2})[']?(?:\s*(\d{1,3}(\.\d*)?)?["″]?)?\s*([EW])$/).try(:captures) # degrees, minutes, decimal seconds [NSEW]
params.merge!(dms_to_decdeg(latlon)).delete(:query)
elsif latlon = query.match(/^\s*([+-]?\d+(\.\d*)?)\s*[\s,]\s*([+-]?\d+(\.\d*)?)\s*$/)
elsif latlon = query.match(/^([+-]?\d+(\.\d*)?)(?:\s+|\s*,\s*)([+-]?\d+(\.\d*)?)$/)
params.merge!(:lat => latlon[1].to_f, :lon => latlon[3].to_f).delete(:query)
params[:latlon_digits] = true unless params[:whereami]
@ -331,11 +329,11 @@ class GeocoderController < ApplicationController
def ddm_to_decdeg(captures)
begin
Float(captures[0])
lat = captures[3].casecmp("s").zero? ? -(captures[0].to_f + captures[1].to_f / 60) : captures[0].to_f + captures[1].to_f / 60
lon = captures[7].casecmp("w").zero? ? -(captures[4].to_f + captures[5].to_f / 60) : captures[4].to_f + captures[5].to_f / 60
lat = captures[3].casecmp("s").zero? ? -(captures[0].to_f + (captures[1].to_f / 60)) : captures[0].to_f + (captures[1].to_f / 60)
lon = captures[7].casecmp("w").zero? ? -(captures[4].to_f + (captures[5].to_f / 60)) : captures[4].to_f + (captures[5].to_f / 60)
rescue StandardError
lat = captures[0].casecmp("s").zero? ? -(captures[1].to_f + captures[2].to_f / 60) : captures[1].to_f + captures[2].to_f / 60
lon = captures[4].casecmp("w").zero? ? -(captures[5].to_f + captures[6].to_f / 60) : captures[5].to_f + captures[6].to_f / 60
lat = captures[0].casecmp("s").zero? ? -(captures[1].to_f + (captures[2].to_f / 60)) : captures[1].to_f + (captures[2].to_f / 60)
lon = captures[4].casecmp("w").zero? ? -(captures[5].to_f + (captures[6].to_f / 60)) : captures[5].to_f + (captures[6].to_f / 60)
end
{ :lat => lat, :lon => lon }
end
@ -343,11 +341,11 @@ class GeocoderController < ApplicationController
def dms_to_decdeg(captures)
begin
Float(captures[0])
lat = captures[4].casecmp("s").zero? ? -(captures[0].to_f + (captures[1].to_f + captures[2].to_f / 60) / 60) : captures[0].to_f + (captures[1].to_f + captures[2].to_f / 60) / 60
lon = captures[9].casecmp("w").zero? ? -(captures[5].to_f + (captures[6].to_f + captures[7].to_f / 60) / 60) : captures[5].to_f + (captures[6].to_f + captures[7].to_f / 60) / 60
lat = captures[4].casecmp("s").zero? ? -(captures[0].to_f + ((captures[1].to_f + (captures[2].to_f / 60)) / 60)) : captures[0].to_f + ((captures[1].to_f + (captures[2].to_f / 60)) / 60)
lon = captures[9].casecmp("w").zero? ? -(captures[5].to_f + ((captures[6].to_f + (captures[7].to_f / 60)) / 60)) : captures[5].to_f + ((captures[6].to_f + (captures[7].to_f / 60)) / 60)
rescue StandardError
lat = captures[0].casecmp("s").zero? ? -(captures[1].to_f + (captures[2].to_f + captures[3].to_f / 60) / 60) : captures[1].to_f + (captures[2].to_f + captures[3].to_f / 60) / 60
lon = captures[5].casecmp("w").zero? ? -(captures[6].to_f + (captures[7].to_f + captures[8].to_f / 60) / 60) : captures[6].to_f + (captures[7].to_f + captures[8].to_f / 60) / 60
lat = captures[0].casecmp("s").zero? ? -(captures[1].to_f + ((captures[2].to_f + (captures[3].to_f / 60)) / 60)) : captures[1].to_f + ((captures[2].to_f + (captures[3].to_f / 60)) / 60)
lon = captures[5].casecmp("w").zero? ? -(captures[6].to_f + ((captures[7].to_f + (captures[8].to_f / 60)) / 60)) : captures[6].to_f + ((captures[7].to_f + (captures[8].to_f / 60)) / 60)
end
{ :lat => lat, :lon => lon }
end

View file

@ -11,9 +11,20 @@ class IssueCommentsController < ApplicationController
comment = @issue.comments.build(issue_comment_params)
comment.user = current_user
comment.save!
notice = t(".comment_created")
reassign_issue(@issue) if params[:reassign]
redirect_to @issue, :notice => notice
if params[:reassign]
reassign_issue(@issue)
flash[:notice] = t ".issue_reassigned"
if current_user.has_role? @issue.assigned_role
redirect_to @issue
else
redirect_to issues_path(:status => "open")
end
else
flash[:notice] = t(".comment_created")
redirect_to @issue
end
end
private

View file

@ -24,9 +24,9 @@ class MessagesController < ApplicationController
@message = Message.new(message_params)
@message.recipient = @user
@message.sender = current_user
@message.sent_on = Time.now.getutc
@message.sent_on = Time.now.utc
if current_user.sent_messages.where("sent_on >= ?", Time.now.getutc - 1.hour).count >= current_user.max_messages_per_hour
if current_user.sent_messages.where("sent_on >= ?", Time.now.utc - 1.hour).count >= current_user.max_messages_per_hour
flash.now[:error] = t ".limit_exceeded"
render :action => "new"
elsif @message.save
@ -121,11 +121,7 @@ class MessagesController < ApplicationController
referer = safe_referer(params[:referer]) if params[:referer]
if referer
redirect_to referer
else
redirect_to :action => :inbox
end
redirect_to referer || { :action => :inbox }
end
rescue ActiveRecord::RecordNotFound
@title = t "messages.no_such_message.title"

View file

@ -3,12 +3,13 @@ class Oauth2AuthorizationsController < Doorkeeper::AuthorizationsController
prepend_before_action :authorize_web
before_action :set_locale
before_action :allow_all_form_action, :only => [:new]
authorize_resource :class => false
def new
override_content_security_policy_directives(:form_action => []) if Settings.csp_enforce || Settings.key?(:csp_report_url)
private
super
def allow_all_form_action
override_content_security_policy_directives(:form_action => []) if Settings.csp_enforce || Settings.key?(:csp_report_url)
end
end

View file

@ -66,7 +66,7 @@ class OauthController < ApplicationController
@redirect_url.query += "&oauth_verifier=#{@token.verifier}" unless @token.oauth10?
redirect_to @redirect_url.to_s
redirect_to @redirect_url.to_s, :allow_other_host => true
end
else
@token.invalidate!

View file

@ -46,7 +46,7 @@ class PasswordsController < ApplicationController
if params[:user]
current_user.pass_crypt = params[:user][:pass_crypt]
current_user.pass_crypt_confirmation = params[:user][:pass_crypt_confirmation]
current_user.status = "active" if current_user.status == "pending"
current_user.activate if current_user.may_activate?
current_user.email_valid = true
if current_user.save

View file

@ -26,7 +26,7 @@ class PreferencesController < ApplicationController
flash[:notice] = { :partial => "preferences/update_success_flash" }
redirect_to preferences_path
else
flash[:error] = t ".failure"
flash.now[:error] = t ".failure"
render :edit
end
end

View file

@ -36,7 +36,7 @@ class ProfilesController < ApplicationController
flash[:notice] = t ".success"
redirect_to user_path(current_user)
else
flash[:error] = t ".failure"
flash.now[:error] = t ".failure"
render :edit
end
end

View file

@ -28,7 +28,8 @@ class ReportsController < ApplicationController
redirect_to helpers.reportable_url(@report.issue.reportable), :notice => t(".successful_report")
else
redirect_to new_report_path(:reportable_type => @report.issue.reportable_type, :reportable_id => @report.issue.reportable_id), :notice => t(".provide_details")
flash.now[:notice] = t(".provide_details")
render :action => "new"
end
end

View file

@ -12,9 +12,7 @@ class SessionsController < ApplicationController
authorize_resource :class => false
def new
append_content_security_policy_directives(
:form_action => %w[*]
)
override_content_security_policy_directives(:form_action => []) if Settings.csp_enforce || Settings.key?(:csp_report_url)
session[:referer] = safe_referer(params[:referer]) if params[:referer]
end
@ -40,11 +38,7 @@ class SessionsController < ApplicationController
referer = safe_referer(params[:referer]) if params[:referer]
if referer
redirect_to referer
else
redirect_to :controller => "site", :action => "index"
end
redirect_to referer || { :controller => "site", :action => "index" }
end
end

View file

@ -7,6 +7,7 @@ class SiteController < ApplicationController
before_action :redirect_browse_params, :only => :index
before_action :redirect_map_params, :only => [:index, :edit, :export]
before_action :require_oauth, :only => [:index]
before_action :require_user, :only => [:id]
before_action :update_totp, :only => [:index]
authorize_resource :class => false

View file

@ -28,7 +28,7 @@ class TracesController < ApplicationController
@title = if target_user.nil?
t ".public_traces"
elsif current_user && current_user == target_user
t ".my_traces"
t ".my_gps_traces"
else
t ".public_traces_from", :user => target_user.display_name
end
@ -99,12 +99,8 @@ class TracesController < ApplicationController
logger.info(params[:trace][:gpx_file].class.name)
if params[:trace][:gpx_file].respond_to?(:read)
begin
@trace = do_create(params[:trace][:gpx_file], params[:trace][:tagstring],
params[:trace][:description], params[:trace][:visibility])
rescue StandardError => e
logger.debug e
end
@trace = do_create(params[:trace][:gpx_file], params[:trace][:tagstring],
params[:trace][:description], params[:trace][:visibility])
if @trace.id
flash[:notice] = t ".trace_uploaded"
@ -123,7 +119,7 @@ class TracesController < ApplicationController
:description => params[:trace][:description],
:visibility => params[:trace][:visibility],
:inserted => false, :user => current_user,
:timestamp => Time.now.getutc)
:timestamp => Time.now.utc)
@trace.valid?
@trace.errors.add(:gpx_file, "can't be blank")
@ -141,6 +137,8 @@ class TracesController < ApplicationController
send_data(trace.xml_file.read, :filename => "#{trace.id}.xml", :type => request.format.to_s, :disposition => "attachment")
elsif request.format == Mime[:gpx]
send_data(trace.xml_file.read, :filename => "#{trace.id}.gpx", :type => request.format.to_s, :disposition => "attachment")
elsif trace.file.attached?
redirect_to rails_blob_path(trace.file, :disposition => "attachment")
else
send_file(trace.trace_name, :filename => "#{trace.id}#{trace.extension_name}", :type => trace.mime_type, :disposition => "attachment")
end
@ -217,8 +215,12 @@ class TracesController < ApplicationController
if trace.visible? && trace.inserted?
if trace.public? || (current_user && current_user == trace.user)
expires_in 7.days, :private => !trace.public?, :public => trace.public?
send_file(trace.large_picture_name, :filename => "#{trace.id}.gif", :type => "image/gif", :disposition => "inline")
if trace.icon.attached?
redirect_to rails_blob_path(trace.image, :disposition => "inline")
else
expires_in 7.days, :private => !trace.public?, :public => trace.public?
send_file(trace.large_picture_name, :filename => "#{trace.id}.gif", :type => "image/gif", :disposition => "inline")
end
else
head :forbidden
end
@ -234,8 +236,12 @@ class TracesController < ApplicationController
if trace.visible? && trace.inserted?
if trace.public? || (current_user && current_user == trace.user)
expires_in 7.days, :private => !trace.public?, :public => trace.public?
send_file(trace.icon_picture_name, :filename => "#{trace.id}_icon.gif", :type => "image/gif", :disposition => "inline")
if trace.icon.attached?
redirect_to rails_blob_path(trace.icon, :disposition => "inline")
else
expires_in 7.days, :private => !trace.public?, :public => trace.public?
send_file(trace.icon_picture_name, :filename => "#{trace.id}_icon.gif", :type => "image/gif", :disposition => "inline")
end
else
head :forbidden
end
@ -252,62 +258,29 @@ class TracesController < ApplicationController
# Sanitise the user's filename
name = file.original_filename.gsub(/[^a-zA-Z0-9.]/, "_")
# Get a temporary filename...
filename = "/tmp/#{rand}"
# ...and save the uploaded file to that location
File.open(filename, "wb") { |f| f.write(file.read) }
# Create the trace object, falsely marked as already
# inserted to stop the import daemon trying to load it
# Create the trace object
trace = Trace.new(
:name => name,
:tagstring => tags,
:description => description,
:visibility => visibility,
:inserted => true,
:inserted => false,
:user => current_user,
:timestamp => Time.now.getutc
:timestamp => Time.now.utc,
:file => file
)
if trace.valid?
Trace.transaction do
begin
# Save the trace object
trace.save!
# Rename the temporary file to the final name
FileUtils.mv(filename, trace.trace_name)
rescue StandardError
# Remove the file as we have failed to update the database
FileUtils.rm_f(filename)
# Pass the exception on
raise
end
begin
# Clear the inserted flag to make the import daemon load the trace
trace.inserted = false
trace.save!
rescue StandardError
# Remove the file as we have failed to update the database
FileUtils.rm_f(trace.trace_name)
# Pass the exception on
raise
end
# Save the trace object
if trace.save
# Finally save the user's preferred privacy level
if pref = current_user.preferences.where(:k => "gps.trace.visibility").first
pref.v = visibility
pref.save
else
current_user.preferences.create(:k => "gps.trace.visibility", :v => visibility)
end
end
# Finally save the user's preferred privacy level
if pref = current_user.preferences.where(:k => "gps.trace.visibility").first
pref.v = visibility
pref.save
else
current_user.preferences.create(:k => "gps.trace.visibility", :v => visibility)
end
trace
end

View file

@ -32,7 +32,7 @@ class UserBlocksController < ApplicationController
end
def edit
params[:user_block_period] = ((@user_block.ends_at - Time.now.getutc) / 1.hour).ceil.to_s
params[:user_block_period] = ((@user_block.ends_at - Time.now.utc) / 1.hour).ceil.to_s
end
def create
@ -41,7 +41,7 @@ class UserBlocksController < ApplicationController
:user => @user,
:creator => current_user,
:reason => params[:user_block][:reason],
:ends_at => Time.now.getutc + @block_period.hours,
:ends_at => Time.now.utc + @block_period.hours,
:needs_view => params[:user_block][:needs_view]
)
@ -62,7 +62,7 @@ class UserBlocksController < ApplicationController
flash[:error] = t(".only_creator_can_edit")
redirect_to :action => "edit"
elsif @user_block.update(
:ends_at => Time.now.getutc + @block_period.hours,
:ends_at => Time.now.utc + @block_period.hours,
:reason => params[:user_block][:reason],
:needs_view => params[:user_block][:needs_view]
)

View file

@ -1,5 +1,6 @@
class UsersController < ApplicationController
include SessionMethods
include UserMethods
layout "site"
@ -11,11 +12,10 @@ class UsersController < ApplicationController
authorize_resource
before_action :require_self, :only => [:account]
before_action :check_database_writable, :only => [:new, :account, :go_public]
before_action :check_database_writable, :only => [:new, :go_public]
before_action :require_cookies, :only => [:new]
before_action :lookup_user_by_name, :only => [:set_status, :destroy]
before_action :allow_thirdparty_images, :only => [:show, :account]
before_action :allow_thirdparty_images, :only => [:show]
def terms
@legale = params[:legale] || OSM.ip_to_country(request.remote_ip) || Settings.default_legale
@ -28,7 +28,7 @@ class UsersController < ApplicationController
if current_user&.terms_agreed?
# Already agreed to terms, so just show settings
redirect_to user_account_path(current_user)
redirect_to edit_account_path
elsif current_user.nil? && session[:new_user].nil?
redirect_to login_path(:referer => request.fullpath)
end
@ -46,7 +46,7 @@ class UsersController < ApplicationController
referer = safe_referer(params[:referer]) if params[:referer]
redirect_to referer || user_account_path(current_user)
redirect_to referer || edit_account_path
elsif params[:decline]
redirect_to t("users.terms.declined")
else
@ -55,8 +55,8 @@ class UsersController < ApplicationController
elsif current_user
unless current_user.terms_agreed?
current_user.consider_pd = params[:user][:consider_pd]
current_user.tou_agreed = Time.now.getutc
current_user.terms_agreed = Time.now.getutc
current_user.tou_agreed = Time.now.utc
current_user.terms_agreed = Time.now.utc
current_user.terms_seen = true
flash[:notice] = t "users.new.terms accepted" if current_user.save
@ -64,7 +64,7 @@ class UsersController < ApplicationController
referer = safe_referer(params[:referer]) if params[:referer]
redirect_to referer || user_account_path(current_user)
redirect_to referer || edit_account_path
else
self.current_user = session.delete(:new_user)
@ -73,8 +73,8 @@ class UsersController < ApplicationController
current_user.description = "" if current_user.description.nil?
current_user.creation_ip = request.remote_ip
current_user.languages = http_accept_language.user_preferred_languages
current_user.terms_agreed = Time.now.getutc
current_user.tou_agreed = Time.now.getutc
current_user.terms_agreed = Time.now.utc
current_user.tou_agreed = Time.now.utc
current_user.terms_seen = true
if current_user.auth_uid.blank?
@ -83,7 +83,7 @@ class UsersController < ApplicationController
end
if current_user.save
flash[:piwik_goal] = PIWIK["goals"]["signup"] if defined?(PIWIK)
flash[:matomo_goal] = Settings.matomo["goals"]["signup"] if defined?(Settings.matomo)
referer = welcome_path
@ -114,36 +114,11 @@ class UsersController < ApplicationController
end
end
def account
@tokens = current_user.oauth_tokens.authorized
append_content_security_policy_directives(
:form_action => %w[accounts.google.com *.facebook.com login.live.com github.com meta.wikimedia.org]
)
if request.post?
if params[:user][:auth_provider].blank? ||
(params[:user][:auth_provider] == current_user.auth_provider &&
params[:user][:auth_uid] == current_user.auth_uid)
update_user(current_user, params)
redirect_to user_account_url(current_user) if current_user.errors.count.zero?
else
session[:new_user_settings] = params
redirect_to auth_url(params[:user][:auth_provider], params[:user][:auth_uid]), :status => :temporary_redirect
end
elsif errors = session.delete(:user_errors)
errors.each do |attribute, error|
current_user.errors.add(attribute, error)
end
end
@title = t "users.account.title"
end
def go_public
current_user.data_public = true
current_user.save
flash[:notice] = t "users.go_public.flash success"
redirect_to user_account_path(current_user)
redirect_to edit_account_path
end
def new
@ -161,11 +136,7 @@ class UsersController < ApplicationController
if current_user
# The user is logged in already, so don't show them the signup
# page, instead send them to the home page
if @referer
redirect_to @referer
else
redirect_to :controller => "site", :action => "index"
end
redirect_to @referer || { :controller => "site", :action => "index" }
elsif params.key?(:auth_provider) && params.key?(:auth_uid)
self.current_user = User.new(:email => params[:email],
:email_confirmation => params[:email],
@ -189,8 +160,6 @@ class UsersController < ApplicationController
Rails.logger.info "create: #{session[:referer]}"
current_user.status = "pending"
if current_user.auth_provider.present? && current_user.pass_crypt.empty?
# We are creating an account with external authentication and
# no password was specified so create a random one
@ -227,15 +196,19 @@ class UsersController < ApplicationController
##
# sets a user's status
def set_status
@user.status = params[:status]
@user.save
@user.activate! if params[:event] == "activate"
@user.confirm! if params[:event] == "confirm"
@user.unconfirm! if params[:event] == "unconfirm"
@user.hide! if params[:event] == "hide"
@user.unhide! if params[:event] == "unhide"
@user.unsuspend! if params[:event] == "unsuspend"
redirect_to user_path(:display_name => params[:display_name])
end
##
# delete a user, marking them as deleted and removing personal data
# destroy a user, marking them as deleted and removing personal data
def destroy
@user.delete
@user.soft_destroy!
redirect_to user_path(:display_name => params[:display_name])
end
@ -293,12 +266,12 @@ class UsersController < ApplicationController
session[:user_errors] = current_user.errors.as_json
redirect_to user_account_path(current_user)
redirect_to edit_account_path
elsif session[:new_user]
session[:new_user].auth_provider = provider
session[:new_user].auth_uid = uid
session[:new_user].status = "active" if email_verified && email == session[:new_user].email
session[:new_user].activate if email_verified && email == session[:new_user].email
redirect_to :action => "terms"
else
@ -340,54 +313,6 @@ class UsersController < ApplicationController
private
##
# update a user's details
def update_user(user, params)
user.display_name = params[:user][:display_name]
user.new_email = params[:user][:new_email]
unless params[:user][:pass_crypt].empty? && params[:user][:pass_crypt_confirmation].empty?
user.pass_crypt = params[:user][:pass_crypt]
user.pass_crypt_confirmation = params[:user][:pass_crypt_confirmation]
end
if params[:user][:auth_provider].nil? || params[:user][:auth_provider].blank?
user.auth_provider = nil
user.auth_uid = nil
end
if user.save
session[:fingerprint] = user.fingerprint
if user.new_email.blank? || user.new_email == user.email
flash[:notice] = t "users.account.flash update success"
else
user.email = user.new_email
if user.valid?
flash[:notice] = t "users.account.flash update success confirm needed"
begin
UserMailer.email_confirm(user, user.tokens.create).deliver_later
rescue StandardError
# Ignore errors sending email
end
else
current_user.errors.add(:new_email, current_user.errors[:email])
current_user.errors.add(:email, [])
end
user.restore_email!
end
end
end
##
# require that the user in the URL is the logged in user
def require_self
head :forbidden if params[:display_name] != current_user.display_name
end
##
# ensure that there is a "user" instance variable
def lookup_user_by_name