From 516b4c124831296a9280b9f04abcd865492eea1e Mon Sep 17 00:00:00 2001 From: Robert Speicher Date: Fri, 19 Jun 2015 16:31:36 -0400 Subject: [PATCH] Allow Admin to filter users by 2FA status --- app/models/user.rb | 17 ++++++--- app/views/admin/users/index.html.haml | 8 +++++ spec/features/admin/admin_users_spec.rb | 40 +++++++++++++++++++++ spec/models/user_spec.rb | 46 +++++++++++++++++++------ 4 files changed, 97 insertions(+), 14 deletions(-) diff --git a/app/models/user.rb b/app/models/user.rb index a2e2d220b3a..57a36a73ac5 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -193,11 +193,13 @@ class User < ActiveRecord::Base mount_uploader :avatar, AvatarUploader # Scopes - scope :admins, -> { where(admin: true) } + scope :admins, -> { where(admin: true) } scope :blocked, -> { with_state(:blocked) } scope :active, -> { with_state(:active) } scope :not_in_project, ->(project) { project.users.present? ? where("id not in (:ids)", ids: project.users.map(&:id) ) : all } scope :without_projects, -> { where('id NOT IN (SELECT DISTINCT(user_id) FROM members)') } + scope :with_two_factor, -> { where('otp_required_for_login IS true') } + scope :without_two_factor, -> { where('otp_required_for_login IS NOT true') } # # Class methods @@ -231,9 +233,16 @@ class User < ActiveRecord::Base def filter(filter_name) case filter_name - when "admins"; self.admins - when "blocked"; self.blocked - when "wop"; self.without_projects + when 'admins' + self.admins + when 'blocked' + self.blocked + when 'two_factor_disabled' + self.without_two_factor + when 'two_factor_enabled' + self.with_two_factor + when 'wop' + self.without_projects else self.active end diff --git a/app/views/admin/users/index.html.haml b/app/views/admin/users/index.html.haml index 45dee86b017..9c1bec7c84d 100644 --- a/app/views/admin/users/index.html.haml +++ b/app/views/admin/users/index.html.haml @@ -13,6 +13,14 @@ = link_to admin_users_path(filter: "admins") do Admins %small.pull-right= User.admins.count + %li.filter-two-factor-enabled{class: "#{'active' if params[:filter] == 'two_factor_enabled'}"} + = link_to admin_users_path(filter: 'two_factor_enabled') do + 2FA Enabled + %small.pull-right= User.with_two_factor.count + %li.filter-two-factor-disabled{class: "#{'active' if params[:filter] == 'two_factor_disabled'}"} + = link_to admin_users_path(filter: 'two_factor_disabled') do + 2FA Disabled + %small.pull-right= User.without_two_factor.count %li{class: "#{'active' if params[:filter] == "blocked"}"} = link_to admin_users_path(filter: "blocked") do Blocked diff --git a/spec/features/admin/admin_users_spec.rb b/spec/features/admin/admin_users_spec.rb index 7f5cb30cb94..86717761582 100644 --- a/spec/features/admin/admin_users_spec.rb +++ b/spec/features/admin/admin_users_spec.rb @@ -16,6 +16,46 @@ describe "Admin::Users", feature: true do expect(page).to have_content(@user.email) expect(page).to have_content(@user.name) end + + describe 'Two-factor Authentication filters' do + it 'counts users who have enabled 2FA' do + create(:user, two_factor_enabled: true) + + visit admin_users_path + + page.within('.filter-two-factor-enabled small') do + expect(page).to have_content('1') + end + end + + it 'filters by users who have enabled 2FA' do + user = create(:user, two_factor_enabled: true) + + visit admin_users_path + click_link '2FA Enabled' + + expect(page).to have_content(user.email) + end + + it 'counts users who have not enabled 2FA' do + create(:user, two_factor_enabled: false) + + visit admin_users_path + + page.within('.filter-two-factor-disabled small') do + expect(page).to have_content('2') # Including admin + end + end + + it 'filters by users who have not enabled 2FA' do + user = create(:user, two_factor_enabled: false) + + visit admin_users_path + click_link '2FA Disabled' + + expect(page).to have_content(user.email) + end + end end describe "GET /admin/users/new" do diff --git a/spec/models/user_spec.rb b/spec/models/user_spec.rb index fa7680fbbec..d86401c9fbb 100644 --- a/spec/models/user_spec.rb +++ b/spec/models/user_spec.rb @@ -308,18 +308,44 @@ describe User do end end - describe 'filter' do - before do - User.delete_all - @user = create :user - @admin = create :user, admin: true - @blocked = create :user, state: :blocked + describe '.filter' do + let(:user) { double } + + it 'filters by active users by default' do + expect(User).to receive(:active).and_return([user]) + + expect(User.filter(nil)).to include user end - it { expect(User.filter("admins")).to eq([@admin]) } - it { expect(User.filter("blocked")).to eq([@blocked]) } - it { expect(User.filter("wop")).to include(@user, @admin, @blocked) } - it { expect(User.filter(nil)).to include(@user, @admin) } + it 'filters by admins' do + expect(User).to receive(:admins).and_return([user]) + + expect(User.filter('admins')).to include user + end + + it 'filters by blocked' do + expect(User).to receive(:blocked).and_return([user]) + + expect(User.filter('blocked')).to include user + end + + it 'filters by two_factor_disabled' do + expect(User).to receive(:without_two_factor).and_return([user]) + + expect(User.filter('two_factor_disabled')).to include user + end + + it 'filters by two_factor_enabled' do + expect(User).to receive(:with_two_factor).and_return([user]) + + expect(User.filter('two_factor_enabled')).to include user + end + + it 'filters by wop' do + expect(User).to receive(:without_projects).and_return([user]) + + expect(User.filter('wop')).to include user + end end describe :not_in_project do -- GitLab