Skip to content

Commit

Permalink
Masquerading as a user
Browse files Browse the repository at this point in the history
This adds a route that admins can go to that will put them in a mode where they
masquerade as the user they provided. They can then browse hound as if they were
that user, and then click "Stop Masquerading" to return to their own account.

Also add an administrate sidebar partial since we now have more than just
administrate in the admin namespace, we need to exclude it from the sidebar
manually since administrate does not provide a way to exclude it.

There's some work to solve this but hasn't been merged yet.
thoughtbot/administrate#514

https://trello.com/c/h9VtPK6F/800-as-an-admin-i-would-like-to-masquerade-as-a-user-so-that-i-may-help-debug-issues-that-they-are-running-into
  • Loading branch information
Jake and Derrick authored and jakecraige committed Mar 31, 2017
1 parent eaaf9ed commit 2042bbc
Show file tree
Hide file tree
Showing 10 changed files with 123 additions and 6 deletions.
8 changes: 8 additions & 0 deletions app/controllers/admin/application_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,16 @@ module Admin
class ApplicationController < Administrate::ApplicationController
before_action :authenticate_admin

helper_method :sidebar_resources

private

def sidebar_resources
Administrate::Namespace.new(namespace).resources.select do |resource|
DashboardManifest::DASHBOARDS.include?(resource)
end
end

def authenticate_admin
unless github_admin?
redirect_to :root
Expand Down
17 changes: 17 additions & 0 deletions app/controllers/admin/masquerades_controller.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
# frozen_string_literal: true
module Admin
class MasqueradesController < Admin::ApplicationController
def show
requested_user = User.find_by(username: params[:username])
session[:masqueraded_user_id] = requested_user.id

redirect_to repos_path
end

def destroy
session.delete(:masqueraded_user_id)

redirect_to repos_path
end
end
end
18 changes: 15 additions & 3 deletions app/controllers/application_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ class ApplicationController < ActionController::Base
before_action :capture_campaign_params
before_action :authenticate

helper_method :current_user, :signed_in?
helper_method :current_user, :signed_in?, :masquerading?

private

Expand Down Expand Up @@ -40,16 +40,28 @@ def signed_in?
end

def current_user
@current_user ||= User.where(remember_token: session[:remember_token]).first
@_current_user ||= find_user_or_masqerade
end

def analytics
@analytics ||= Analytics.new(current_user, session[:campaign_params])
@_analytics ||= Analytics.new(current_user, session[:campaign_params])
end

def masquerading?
session[:masqueraded_user_id]
end

protected

def verified_request?
super || valid_authenticity_token?(session, request.headers["X-XSRF-TOKEN"])
end

def find_user_or_masqerade
if masquerading?
User.find_by(id: session[:masqueraded_user_id])
else
User.find_by(remember_token: session[:remember_token])
end
end
end
6 changes: 6 additions & 0 deletions app/views/admin/application/_sidebar.html.haml
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
%ul.sidebar__list
- sidebar_resources.each do |resource|
%li
= link_to display_resource_name(resource),
[namespace, resource],
class: "sidebar__link sidebar__link--#{nav_link_state(resource)}"
7 changes: 6 additions & 1 deletion app/views/application/_header.haml
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,12 @@
.avatar{ style: "background-image: url('#{avatar}')" }
%span= current_user.username
%li
= link_to t("sign_out"), sign_out_path, class: "sign-out"
- if masquerading?
= link_to t("stop_masquerading"),
admin_masquerade_path(current_user.username),
method: :delete
- else
= link_to t("sign_out"), sign_out_path, class: "sign-out"
- else
%li
= link_to "Pricing", root_path(anchor: "pricing"), class: "pricing"
Expand Down
1 change: 1 addition & 0 deletions config/locales/en.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ en:
syncing_repos: "Loading..."
authenticate: "Sign In with GitHub"
sign_out: "Sign Out"
stop_masquerading: "Stop Masquerading"
active_repos: "Active repos"
search_placeholder: "Search by repo"
pending_status: "Hound is busy reviewing changes..."
Expand Down
1 change: 1 addition & 0 deletions config/routes.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
resources dashboard_resource
end

resources :masquerades, param: :username, only: [:show, :destroy]
root controller: DashboardManifest::ROOT_DASHBOARD, action: :index
end

Expand Down
3 changes: 1 addition & 2 deletions spec/controllers/subscriptions_controller_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -104,9 +104,8 @@
repos: repos,
token: "TEST_USER_TOKEN",
)
users = class_double(User, first: user)
allow(RepoActivator).to receive(:new).and_return(repo_activator)
allow(User).to receive(:where).and_return(users)
allow(User).to receive(:find_by).and_return(user)

put :update, params: { repo_id: 1 }

Expand Down
25 changes: 25 additions & 0 deletions spec/features/admin_masquerades_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
# frozen_string_literal: true
require "rails_helper"

feature "Admin masquerades as user" do
scenario "admin sees user repos and can stop masquerading" do
repo = create(:repo)
admin = create(:user, username: "admin", token: "admin")
user = create(:user, repos: [repo], username: "admin", token: "user")
stub_const("Hound::ADMIN_GITHUB_USERNAMES", ["admin"])

sign_in_as(admin, "admin")
visit admin_masquerade_path(user.username)

expect(current_path).to eq(repos_path)
within "header .account" do
expect(page).to have_text(user.username)
end

click_on "Stop Masquerading"

within "header .account" do
expect(page).to have_text(admin.username)
end
end
end
43 changes: 43 additions & 0 deletions spec/requests/admin/masquerades_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
# frozen_string_literal: true
require "rails_helper"

describe "GET /masqerades?username=:username" do
context "as an admin" do
it "redirects to repos as the maqueraded user" do
admin = create(:user, username: "admin", token: "admin-token")
user = create(:user, username: "us3rn4me", token: "user-token")
stub_const("Hound::ADMIN_GITHUB_USERNAMES", ["admin"])

sign_in_as(admin)
get admin_masquerade_path(username: user.username)

expect(response).to redirect_to(repos_path)
follow_redirect!
expect(response.body).to include("us3rn4me")
expect(session[:masqueraded_user_id]).to eq(user.id)
expect(session[:remember_token]).to eq(admin.remember_token)
end
end

context "as a non-admin user" do
it "redirects to root and does not masquerade as user" do
non_admin = create(:user, token: "non-admin-token")
user = create(:user, username: "us3rn4me", token: "user-token")

sign_in_as(non_admin)
get admin_masquerade_path(username: user.username)

expect(response).to redirect_to(root_path)
follow_redirect!
expect(response.body).not_to include("us3rn4me")
expect(session[:masqueraded_user_id]).to be_nil
expect(session[:remember_token]).to eq(non_admin.remember_token)
end
end

def sign_in_as(user)
stub_oauth(username: user.username, email: user.email, token: user.token)
get "/auth/github"
follow_redirect!
end
end

0 comments on commit 2042bbc

Please sign in to comment.