Commit 17b25bd2 authored by Bob Van Landuyt's avatar Bob Van Landuyt

Make the user dropdown reusable

We will reuse the the dropdown, but exclude some menu items based on
permissions.

So moving the menu to a partial, and adding checks for each menu item here.
parent 82eeb72c
...@@ -23,9 +23,31 @@ module UsersHelper ...@@ -23,9 +23,31 @@ module UsersHelper
profile_tabs.include?(tab) profile_tabs.include?(tab)
end end
def current_user_menu_items
@current_user_menu_items ||= get_current_user_menu_items
end
def current_user_menu?(item)
current_user_menu_items.include?(item)
end
private private
def get_profile_tabs def get_profile_tabs
[:activity, :groups, :contributed, :projects, :snippets] [:activity, :groups, :contributed, :projects, :snippets]
end end
def get_current_user_menu_items
items = [:help, :sign_out]
if can?(current_user, :read_user, current_user)
items << :profile
end
if can?(current_user, :update_user, current_user)
items << :settings
end
items
end
end end
...@@ -8,6 +8,8 @@ class UserPolicy < BasePolicy ...@@ -8,6 +8,8 @@ class UserPolicy < BasePolicy
rule { ~restricted_public_level }.enable :read_user rule { ~restricted_public_level }.enable :read_user
rule { ~anonymous }.enable :read_user rule { ~anonymous }.enable :read_user
rule { user_is_self | admin }.enable :destroy_user rule { ~subject_ghost & (user_is_self | admin) }.policy do
rule { subject_ghost }.prevent :destroy_user enable :destroy_user
enable :update_user
end
end end
- return unless current_user
%ul
%li.current-user
.user-name.bold
= current_user.name
= current_user.to_reference
%li.divider
- if current_user_menu?(:profile)
%li
= link_to s_("CurrentUser|Profile"), current_user, class: 'profile-link', data: { user: current_user.username }
- if current_user_menu?(:settings)
%li
= link_to s_("CurrentUser|Settings"), profile_path
- if current_user_menu?(:help)
%li
= link_to _("Help"), help_path
- if current_user_menu?(:help) || current_user_menu?(:settings) || current_user_menu?(:profile)
%li.divider
- if current_user_menu?(:sign_out)
%li
= link_to _("Sign out"), destroy_user_session_path, class: "sign-out-link"
...@@ -53,22 +53,7 @@ ...@@ -53,22 +53,7 @@
= image_tag avatar_icon_for_user(current_user, 23), width: 23, height: 23, class: "header-user-avatar qa-user-avatar" = image_tag avatar_icon_for_user(current_user, 23), width: 23, height: 23, class: "header-user-avatar qa-user-avatar"
= sprite_icon('angle-down', css_class: 'caret-down') = sprite_icon('angle-down', css_class: 'caret-down')
.dropdown-menu-nav.dropdown-menu-align-right .dropdown-menu-nav.dropdown-menu-align-right
%ul = render 'layouts/header/current_user_dropdown'
%li.current-user
.user-name.bold
= current_user.name
@#{current_user.username}
%li.divider
%li
= link_to "Profile", current_user, class: 'profile-link', data: { user: current_user.username }
%li
= link_to "Settings", profile_path
- if current_user
%li
= link_to "Help", help_path
%li.divider
%li
= link_to "Sign out", destroy_user_session_path, class: "sign-out-link"
- if header_link?(:admin_impersonation) - if header_link?(:admin_impersonation)
%li.impersonation %li.impersonation
= link_to admin_impersonation_path, class: 'impersonation-btn', method: :delete, title: "Stop impersonation", aria: { label: 'Stop impersonation' }, data: { toggle: 'tooltip', placement: 'bottom', container: 'body' } do = link_to admin_impersonation_path, class: 'impersonation-btn', method: :delete, title: "Stop impersonation", aria: { label: 'Stop impersonation' }, data: { toggle: 'tooltip', placement: 'bottom', container: 'body' } do
......
...@@ -2,12 +2,15 @@ module QA ...@@ -2,12 +2,15 @@ module QA
module Page module Page
module Menu module Menu
class Main < Page::Base class Main < Page::Base
view 'app/views/layouts/header/_current_user_dropdown.html.haml' do
element :user_sign_out_link, 'link_to _("Sign out")'
element :settings_link, 'link_to s_("CurrentUser|Settings")'
end
view 'app/views/layouts/header/_default.html.haml' do view 'app/views/layouts/header/_default.html.haml' do
element :navbar element :navbar
element :user_avatar element :user_avatar
element :user_menu, '.dropdown-menu-nav' element :user_menu, '.dropdown-menu-nav'
element :user_sign_out_link, 'link_to "Sign out"'
element :settings_link, 'link_to "Settings"'
end end
view 'app/views/layouts/nav/_dashboard.html.haml' do view 'app/views/layouts/nav/_dashboard.html.haml' do
......
...@@ -27,4 +27,29 @@ describe UsersHelper do ...@@ -27,4 +27,29 @@ describe UsersHelper do
expect(tabs).to include(:activity, :groups, :contributed, :projects, :snippets) expect(tabs).to include(:activity, :groups, :contributed, :projects, :snippets)
end end
end end
describe '#current_user_menu_items' do
subject(:items) { helper.current_user_menu_items }
before do
allow(helper).to receive(:current_user).and_return(user)
allow(helper).to receive(:can?).and_return(false)
end
it 'includes all default items' do
expect(items).to include(:help, :sign_out)
end
it 'includes the profile tab if the user can read themself' do
expect(helper).to receive(:can?).with(user, :read_user, user) { true }
expect(items).to include(:profile)
end
it 'includes the settings tab if the user can update themself' do
expect(helper).to receive(:can?).with(user, :read_user, user) { true }
expect(items).to include(:profile)
end
end
end end
...@@ -10,28 +10,36 @@ describe UserPolicy do ...@@ -10,28 +10,36 @@ describe UserPolicy do
it { is_expected.to be_allowed(:read_user) } it { is_expected.to be_allowed(:read_user) }
end end
describe "destroying a user" do shared_examples 'changing a user' do |ability|
context "when a regular user tries to destroy another regular user" do context "when a regular user tries to destroy another regular user" do
it { is_expected.not_to be_allowed(:destroy_user) } it { is_expected.not_to be_allowed(ability) }
end end
context "when a regular user tries to destroy themselves" do context "when a regular user tries to destroy themselves" do
let(:current_user) { user } let(:current_user) { user }
it { is_expected.to be_allowed(:destroy_user) } it { is_expected.to be_allowed(ability) }
end end
context "when an admin user tries to destroy a regular user" do context "when an admin user tries to destroy a regular user" do
let(:current_user) { create(:user, :admin) } let(:current_user) { create(:user, :admin) }
it { is_expected.to be_allowed(:destroy_user) } it { is_expected.to be_allowed(ability) }
end end
context "when an admin user tries to destroy a ghost user" do context "when an admin user tries to destroy a ghost user" do
let(:current_user) { create(:user, :admin) } let(:current_user) { create(:user, :admin) }
let(:user) { create(:user, :ghost) } let(:user) { create(:user, :ghost) }
it { is_expected.not_to be_allowed(:destroy_user) } it { is_expected.not_to be_allowed(ability) }
end end
end end
describe "destroying a user" do
it_behaves_like 'changing a user', :destroy_user
end
describe "updating a user" do
it_behaves_like 'changing a user', :update_user
end
end end
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment