diff --git a/app/assets/images/pictograms/incognito-off.svg b/app/assets/images/pictograms/incognito-off.svg new file mode 100644 index 0000000..718453c --- /dev/null +++ b/app/assets/images/pictograms/incognito-off.svg @@ -0,0 +1 @@ + diff --git a/app/assets/images/pictograms/incognito.svg b/app/assets/images/pictograms/incognito.svg new file mode 100644 index 0000000..a06ebef --- /dev/null +++ b/app/assets/images/pictograms/incognito.svg @@ -0,0 +1 @@ + diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb index 6205d12..029951e 100644 --- a/app/controllers/application_controller.rb +++ b/app/controllers/application_controller.rb @@ -1,4 +1,6 @@ class ApplicationController < ActionController::Base + helper_method :current_user_disguised? + before_action :authenticate_user! class AccessForbidden < StandardError @@ -6,6 +8,10 @@ class ApplicationController < ActionController::Base protected + def current_user_disguised? + session[:revert_to_id].present? + end + def after_sign_in_path_for(scope) if current_user.at_least(:admin) users_path diff --git a/app/controllers/users_controller.rb b/app/controllers/users_controller.rb index 1305292..c026731 100644 --- a/app/controllers/users_controller.rb +++ b/app/controllers/users_controller.rb @@ -1,8 +1,13 @@ class UsersController < ApplicationController - before_action :find_user, only: [:show] - before_action do + helper_method :allow_disguise? + + before_action :find_user, only: [:show, :disguise] + before_action except: :revert do raise AccessForbidden unless current_user.at_least(:admin) end + before_action only: :revert do + raise AccessForbidden unless current_user_disguised? + end def index @users = User.all @@ -11,16 +16,35 @@ class UsersController < ApplicationController def show end + def disguise + raise ActionController::BadRequest unless allow_disguise?(@user) + session[:revert_to_id] = current_user.id + bypass_sign_in(@user) + redirect_to root_url + end + + def revert + @user = User.find(session.delete(:revert_to_id)) + bypass_sign_in(@user) + redirect_to users_url + end + # TODO: add #update to change user status - # TODO: add #become/#revert to change to user view # NOTE: limited actions availabe to :admin by design. Users are meant to # manage their accounts by themselves through registrations. In future :admin # may be allowed to sing-in as user and make changes there. + protected + + def allow_disguise?(user) + user&.confirmed? && (user != current_user) && !current_user_disguised? + end + private def find_user @user = User.find(params[:id]) end + end diff --git a/app/views/layouts/application.html.erb b/app/views/layouts/application.html.erb index 19a549b..1c875df 100644 --- a/app/views/layouts/application.html.erb +++ b/app/views/layouts/application.html.erb @@ -13,10 +13,15 @@
<% if user_signed_in? %> - <%= image_link_to t(:sign_out), "logout", destroy_user_session_path, - data: { turbo: true, turbo_method: :delete } %> - <%= image_link_to t(:profile), "account-wrench-outline", edit_user_registration_path, - current: :hide %> + <% if current_user_disguised? %> + <%= image_link_to t(:revert), "incognito-off", revert_users_path, + data: {turbo: true, turbo_method: :post} %> + <% else %> + <%= image_link_to t(:sign_out), "logout", destroy_user_session_path, + data: {turbo: true, turbo_method: :delete} %> + <% end %> + <%= image_link_to current_user.email, "account-wrench-outline", + edit_user_registration_path, current: :hide %> <% else %> <%= image_link_to t(:register), "account-plus-outline", new_user_registration_path, current: :hide %> diff --git a/app/views/users/index.html.erb b/app/views/users/index.html.erb index 30eaff6..01b532c 100644 --- a/app/views/users/index.html.erb +++ b/app/views/users/index.html.erb @@ -5,7 +5,7 @@ <%= User.human_attribute_name(:status).capitalize %> <%= User.human_attribute_name(:confirmed_at).capitalize %> <%= User.human_attribute_name(:created_at).capitalize %> UTC - + <%= t :actions %> @@ -17,7 +17,10 @@ <%= svg_tag "pictograms/checkbox-marked-outline" if user.confirmed_at.present? %> <%= user.created_at.to_fs(:db_without_sec) %> - + + <%= image_link_to t(".disguise"), "incognito", disguise_user_path(user), + data: {turbo: true, turbo_method: :post} if allow_disguise?(user) %> + <% end %> diff --git a/config/locales/en.yml b/config/locales/en.yml index 5cc0d71..fa9fd63 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -10,7 +10,7 @@ en: unconfirmed_email: Awaiting confirmation for users: index: - become: View as... + disguise: View as... passwords: edit: new_password: New password @@ -34,6 +34,7 @@ en: remember_me: Remember me layouts: application: + revert: Revert users: Users actions: Actions back: Back diff --git a/config/routes.rb b/config/routes.rb index 7fafc6c..4514ed7 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -2,7 +2,14 @@ Rails.application.routes.draw do devise_for :users, path: '', path_names: {registration: 'profile'}, controllers: {registrations: :registrations} - resources :users, only: [:index, :show] + resources :users, only: [:index, :show] do + member do + post :disguise + end + collection do + post :revert + end + end devise_scope :user do root to: "devise/sessions#new"