Prepare for API v1 (PR #570)

This commit is contained in:
wvengen 2018-10-13 20:16:35 +02:00 committed by GitHub
parent d9ae0d11b0
commit fd96b6ccc1
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
21 changed files with 536 additions and 217 deletions

View file

@ -0,0 +1,148 @@
# Controller concern for authentication methods
#
# Split off from main +ApplicationController+ to allow e.g.
# Doorkeeper to use it too.
module Concerns::Auth
extend ActiveSupport::Concern
protected
def current_user
# check if there is a valid session and return the logged-in user (its object)
if session[:user_id] && params[:foodcoop]
# for shared-host installations. check if the cookie-subdomain fits to request.
@current_user ||= User.undeleted.find_by_id(session[:user_id]) if session[:scope] == FoodsoftConfig.scope
end
end
def deny_access
session[:return_to] = request.original_url
redirect_to root_url, alert: I18n.t('application.controller.error_denied', sign_in: ActionController::Base.helpers.link_to(t('application.controller.error_denied_sign_in'), login_path))
end
private
def login(user)
session[:user_id] = user.id
session[:scope] = FoodsoftConfig.scope # Save scope in session to not allow switching between foodcoops with one account
session[:locale] = user.locale
end
def login_and_redirect_to_return_to(user, *args)
login user
if session[:return_to].present?
redirect_to_url = session[:return_to]
session[:return_to] = nil
else
redirect_to_url = root_url
end
redirect_to redirect_to_url, *args
end
def logout
session[:user_id] = nil
session[:return_to] = nil
expire_access_tokens
end
def authenticate(role = 'any')
# Attempt to retrieve authenticated user from controller instance or session...
if !current_user
# No user at all: redirect to login page.
logout
session[:return_to] = request.original_url
redirect_to_login :alert => I18n.t('application.controller.error_authn')
else
# We have an authenticated user, now check role...
# Roles gets the user through his memberships.
hasRole = case role
when 'admin' then current_user.role_admin?
when 'finance' then current_user.role_finance?
when 'article_meta' then current_user.role_article_meta?
when 'pickups' then current_user.role_pickups?
when 'suppliers' then current_user.role_suppliers?
when 'orders' then current_user.role_orders?
when 'finance_or_orders' then (current_user.role_finance? || current_user.role_orders?)
when 'pickups_or_orders' then (current_user.role_pickups? || current_user.role_orders?)
when 'any' then true # no role required
else false # any unknown role will always fail
end
if hasRole
current_user
else
deny_access
end
end
end
def authenticate_admin
authenticate('admin')
end
def authenticate_finance
authenticate('finance')
end
def authenticate_article_meta
authenticate('article_meta')
end
def authenticate_pickups
authenticate('pickups')
end
def authenticate_suppliers
authenticate('suppliers')
end
def authenticate_orders
authenticate('orders')
end
def authenticate_finance_or_orders
authenticate('finance_or_orders')
end
def authenticate_pickups_or_orders
authenticate('pickups_or_orders')
end
# checks if the current_user is member of given group.
# if fails the user will redirected to startpage
def authenticate_membership_or_admin(group_id = params[:id])
@group = Group.find(group_id)
unless @group.member?(@current_user) || @current_user.role_admin?
redirect_to root_path, alert: I18n.t('application.controller.error_members_only')
end
end
def authenticate_or_token(prefix, role = 'any')
if not params[:token].blank?
begin
TokenVerifier.new(prefix).verify(params[:token])
rescue ActiveSupport::MessageVerifier::InvalidSignature
redirect_to root_path, alert: I18n.t('application.controller.error_token')
end
else
authenticate(role)
end
end
# Expires any access tokens for the current user (unless they have the 'offline_access' scope)
# @see https://github.com/doorkeeper-gem/doorkeeper/issues/71#issuecomment-5471317
def expire_access_tokens
return unless @current_user
Doorkeeper::AccessToken.transaction do
token_scope = Doorkeeper::AccessToken.where(revoked_at: nil, resource_owner_id: @current_user.id)
token_scope.each do |token|
token.destroy! unless token.scopes.include?('offline_access')
end
end
end
# Redirect to the login page, used in authenticate, plugins can override this.
def redirect_to_login(options={})
redirect_to login_url, options
end
end

View file

@ -0,0 +1,36 @@
# Controller concern to handle foodcoop scope
#
# Includes a +before_filter+ for selecting foodcoop from url.
#
module Concerns::FoodcoopScope
extend ActiveSupport::Concern
included do
before_filter :select_foodcoop
end
private
# Set config and database connection for each request
# It uses the subdomain to select the appropriate section in the config files
# Use this method as a before filter (first filter!) in ApplicationController
def select_foodcoop
return unless FoodsoftConfig[:multi_coop_install]
foodcoop = params[:foodcoop]
if foodcoop.blank?
FoodsoftConfig.select_default_foodcoop
redirect_to root_url
elsif FoodsoftConfig.allowed_foodcoop? foodcoop
FoodsoftConfig.select_foodcoop foodcoop
else
raise ActionController::RoutingError.new 'Foodcoop Not Found'
end
end
# Always stay in foodcoop url scope
def default_url_options(options = {})
super().merge({foodcoop: FoodsoftConfig.scope})
end
end

View file

@ -0,0 +1,51 @@
module Concerns::Locale
extend ActiveSupport::Concern
included do
before_filter :set_locale
end
def explicitly_requested_language
params[:locale]
end
def user_settings_language
current_user&.locale
end
def session_language
session[:locale]
end
def browser_language
request.env['HTTP_ACCEPT_LANGUAGE'] ? request.env['HTTP_ACCEPT_LANGUAGE'].scan(/^[a-z]{2}/).first : nil
end
def default_language
FoodsoftConfig[:default_locale] || ::I18n.default_locale
end
private
def select_language_according_to_priority
language = explicitly_requested_language || session_language || user_settings_language
language ||= browser_language unless FoodsoftConfig[:ignore_browser_locale]
language.presence&.to_sym unless language.blank?
end
def available_locales
::I18n.available_locales
end
def set_locale
if available_locales.include?(select_language_according_to_priority)
::I18n.locale = select_language_according_to_priority
else
::I18n.locale = default_language
end
locale = session[:locale] = ::I18n.locale
logger.info("Set locale to #{locale}")
end
end