From c57f0a6d257620cde5d6ff543f6f3bf15ee81d6c Mon Sep 17 00:00:00 2001 From: Ethan Urie Date: Wed, 6 Sep 2023 15:25:21 -0400 Subject: [PATCH 1/8] Adding ability to view Trusted user in User admin panel Also adding the ability to trust/untrust a user from the admin panel. Renamed vue component to comply with eslint rules (cherry picked from commit 66b5d4e55c8b12598733bbcb40088a79f90f621f) Pulling in the trust/untrust services Add trust specs for UserActionsHelper (cherry picked from commit a57b001b7e99275bbe33dea1c69643b93b48bfec) Add request specs (cherry picked from commit 87ff28cf5ee4501c347ef5c3656ba04c0e4139e5) Fix trust/untrust spec in model (cherry picked from commit edca4ae268af599e85c2e5249a52930e9a83ade3) Fix trust/untrust spec in model (cherry picked from commit edca4ae268af599e85c2e5249a52930e9a83ade3) (cherry picked from commit 5a680330755696bc2244d0b41897ab984867d1f2) Updated locale file and json files Refactor to simplify the setting of the custom attribute Use `let_it_be_with_reload` for the `user` to fix issues with setting the custom attribute. Utilize the `trusted_with_spam_attribute` association Remove unnecessary files The action components for the users admin panel weren't meant to be part of this MR. Moving them out to the appropriate MR. Remove unneeded changes for controller and helpers Filter reason options if user selects `Trust user` Renamed vue component to comply with eslint rules (cherry picked from commit 66b5d4e55c8b12598733bbcb40088a79f90f621f) (cherry picked from commit a57b001b7e99275bbe33dea1c69643b93b48bfec) (cherry picked from commit 87ff28cf5ee4501c347ef5c3656ba04c0e4139e5) (cherry picked from commit edca4ae268af599e85c2e5249a52930e9a83ade3) (cherry picked from commit edca4ae268af599e85c2e5249a52930e9a83ade3) (cherry picked from commit 5a680330755696bc2244d0b41897ab984867d1f2) Changelog: added --- .../admin/abuse_report/constants.js | 1 + app/controllers/admin/users_controller.rb | 22 +------ config/routes/admin.rb | 2 - locale/gitlab.pot | 24 +++++++ .../admin_users_data_attributes_paths.json | 62 ++++++++++++++----- spec/frontend/admin/users/constants.js | 4 ++ .../helpers/admin/user_actions_helper_spec.rb | 59 +++++++++++++++--- 7 files changed, 130 insertions(+), 44 deletions(-) diff --git a/app/assets/javascripts/admin/abuse_report/constants.js b/app/assets/javascripts/admin/abuse_report/constants.js index f028408bed7287..cef9ff0a6a2625 100644 --- a/app/assets/javascripts/admin/abuse_report/constants.js +++ b/app/assets/javascripts/admin/abuse_report/constants.js @@ -51,6 +51,7 @@ export const REASON_OPTIONS = [ text: s__('AbuseReport|Confirmed violation of a copyright or a trademark'), }, { value: 'malware', text: s__('AbuseReport|Confirmed posting of malware') }, + { value: 'trusted', text: s__(`AbuseReport|Confirmed trusted user`) }, { value: 'other', text: s__('AbuseReport|Something else') }, { value: 'unconfirmed', text: s__('AbuseReport|Abuse unconfirmed') }, ]; diff --git a/app/controllers/admin/users_controller.rb b/app/controllers/admin/users_controller.rb index 9634257209daf4..8bb582b7cfe3b6 100644 --- a/app/controllers/admin/users_controller.rb +++ b/app/controllers/admin/users_controller.rb @@ -164,26 +164,6 @@ def unlock end end - def trust - result = Users::TrustService.new(current_user).execute(user) - - if result[:status] == :success - redirect_back_or_admin_user(notice: _("Successfully trusted")) - else - redirect_back_or_admin_user(alert: _("Error occurred. User was not updated")) - end - end - - def untrust - result = Users::UntrustService.new(current_user).execute(user) - - if result[:status] == :success - redirect_back_or_admin_user(notice: _("Successfully untrusted")) - else - redirect_back_or_admin_user(alert: _("Error occurred. User was not updated")) - end - end - def confirm if update_user(&:force_confirm) redirect_back_or_admin_user(notice: _("Successfully confirmed")) @@ -310,7 +290,7 @@ def paginate_without_count? end def users_with_included_associations(users) - users.includes(:authorized_projects) # rubocop: disable CodeReuse/ActiveRecord + users.includes(:authorized_projects, :trusted_with_spam_attribute) # rubocop: disable CodeReuse/ActiveRecord end def admin_making_changes_for_another_user? diff --git a/config/routes/admin.rb b/config/routes/admin.rb index e8ad19624e9823..5513ac1813a0a5 100644 --- a/config/routes/admin.rb +++ b/config/routes/admin.rb @@ -22,8 +22,6 @@ put :unlock put :confirm put :approve - put :trust - put :untrust delete :reject post :impersonate patch :disable_two_factor diff --git a/locale/gitlab.pot b/locale/gitlab.pot index 4ba49ace5c768d..d179b6b1c2a162 100644 --- a/locale/gitlab.pot +++ b/locale/gitlab.pot @@ -3879,6 +3879,9 @@ msgstr "" msgid "AdminUsers|Admins" msgstr "" +msgid "AdminUsers|Allow user %{username} to create possible spam?" +msgstr "" + msgid "AdminUsers|An error occurred while fetching this user's contributions, and the request cannot return the number of issues, merge requests, groups, and projects linked to this user. If you proceed with deleting the user, all their contributions will still be deleted." msgstr "" @@ -3981,6 +3984,9 @@ msgstr "" msgid "AdminUsers|Delete user and contributions" msgstr "" +msgid "AdminUsers|Disallow user %{username} to create possible spam?" +msgstr "" + msgid "AdminUsers|Export permissions as CSV (max 100,000 users)" msgstr "" @@ -4095,6 +4101,9 @@ msgstr "" msgid "AdminUsers|The maximum compute minutes that jobs in this namespace can use on shared runners each month. Set 0 for unlimited. Set empty to inherit the global setting of %{minutes}" msgstr "" +msgid "AdminUsers|The user can create issues, notes, snippets, and merge requests without being blocked." +msgstr "" + msgid "AdminUsers|The user can't access git repositories." msgstr "" @@ -4125,6 +4134,9 @@ msgstr "" msgid "AdminUsers|To confirm, type %{username}." msgstr "" +msgid "AdminUsers|Trust user" +msgstr "" + msgid "AdminUsers|Unban user" msgstr "" @@ -4140,6 +4152,9 @@ msgstr "" msgid "AdminUsers|Unlock user %{username}?" msgstr "" +msgid "AdminUsers|Untrust user" +msgstr "" + msgid "AdminUsers|User administration" msgstr "" @@ -4170,6 +4185,9 @@ msgstr "" msgid "AdminUsers|What does this mean?" msgstr "" +msgid "AdminUsers|When allowed to create possible spam:" +msgstr "" + msgid "AdminUsers|When banned:" msgstr "" @@ -4188,6 +4206,9 @@ msgstr "" msgid "AdminUsers|You are about to permanently delete the user %{username}. This will delete all issues, merge requests, groups, and projects linked to them. To avoid data loss, consider using the %{strongStart}Block user%{strongEnd} feature instead. After you %{strongStart}Delete user%{strongEnd}, you cannot undo this action or recover the data." msgstr "" +msgid "AdminUsers|You can allow possible spam in the future if necessary." +msgstr "" + msgid "AdminUsers|You can always block their account again if needed." msgstr "" @@ -4203,6 +4224,9 @@ msgstr "" msgid "AdminUsers|You can ban their account in the future if necessary." msgstr "" +msgid "AdminUsers|You can disallow creating possible spam in the future." +msgstr "" + msgid "AdminUsers|You can unban their account in the future. Their data remains intact." msgstr "" diff --git a/spec/fixtures/api/schemas/entities/admin_users_data_attributes_paths.json b/spec/fixtures/api/schemas/entities/admin_users_data_attributes_paths.json index 44d8e48a972c48..61472b273e1342 100644 --- a/spec/fixtures/api/schemas/entities/admin_users_data_attributes_paths.json +++ b/spec/fixtures/api/schemas/entities/admin_users_data_attributes_paths.json @@ -1,19 +1,51 @@ { "type": "object", "properties": { - "edit": { "type": "string" }, - "approve": { "type": "string" }, - "reject": { "type": "string" }, - "unblock": { "type": "string" }, - "block": { "type": "string" }, - "deactivate": { "type": "string" }, - "activate": { "type": "string" }, - "unlock": { "type": "string" }, - "delete": { "type": "string" }, - "delete_with_contributions": { "type": "string" }, - "admin_user": { "type": "string" }, - "ban": { "type": "string" }, - "unban": { "type": "string" } + "edit": { + "type": "string" + }, + "approve": { + "type": "string" + }, + "reject": { + "type": "string" + }, + "unblock": { + "type": "string" + }, + "block": { + "type": "string" + }, + "deactivate": { + "type": "string" + }, + "activate": { + "type": "string" + }, + "unlock": { + "type": "string" + }, + "delete": { + "type": "string" + }, + "delete_with_contributions": { + "type": "string" + }, + "admin_user": { + "type": "string" + }, + "ban": { + "type": "string" + }, + "unban": { + "type": "string" + }, + "trust": { + "type": "string" + }, + "untrust": { + "type": "string" + } }, "required": [ "edit", @@ -28,7 +60,9 @@ "delete_with_contributions", "admin_user", "ban", - "unban" + "unban", + "trust", + "untrust" ], "additionalProperties": false } diff --git a/spec/frontend/admin/users/constants.js b/spec/frontend/admin/users/constants.js index d341eb03b1b33c..39e8e51f43ca0b 100644 --- a/spec/frontend/admin/users/constants.js +++ b/spec/frontend/admin/users/constants.js @@ -9,6 +9,8 @@ const REJECT = 'reject'; const APPROVE = 'approve'; const BAN = 'ban'; const UNBAN = 'unban'; +const TRUST = 'trust'; +const UNTRUST = 'untrust'; export const EDIT = 'edit'; @@ -24,6 +26,8 @@ export const CONFIRMATION_ACTIONS = [ UNBAN, APPROVE, REJECT, + TRUST, + UNTRUST, ]; export const DELETE_ACTIONS = [DELETE, DELETE_WITH_CONTRIBUTIONS]; diff --git a/spec/helpers/admin/user_actions_helper_spec.rb b/spec/helpers/admin/user_actions_helper_spec.rb index 87d2308690c617..abfdabf3413df9 100644 --- a/spec/helpers/admin/user_actions_helper_spec.rb +++ b/spec/helpers/admin/user_actions_helper_spec.rb @@ -2,7 +2,7 @@ require "spec_helper" -RSpec.describe Admin::UserActionsHelper do +RSpec.describe Admin::UserActionsHelper, feature_category: :user_management do describe '#admin_actions' do let_it_be(:current_user) { build(:user) } @@ -29,13 +29,33 @@ context 'the user is a standard user' do let_it_be(:user) { create(:user) } - it { is_expected.to contain_exactly("edit", "block", "ban", "deactivate", "delete", "delete_with_contributions") } + it do + is_expected.to contain_exactly( + "edit", + "block", + "ban", + "deactivate", + "delete", + "delete_with_contributions", + "trust" + ) + end end context 'the user is an admin user' do let_it_be(:user) { create(:user, :admin) } - it { is_expected.to contain_exactly("edit", "block", "ban", "deactivate", "delete", "delete_with_contributions") } + it do + is_expected.to contain_exactly( + "edit", + "block", + "ban", + "deactivate", + "delete", + "delete_with_contributions", + "trust" + ) + end end context 'the user is blocked by LDAP' do @@ -59,7 +79,16 @@ context 'the user is deactivated' do let_it_be(:user) { create(:user, :deactivated) } - it { is_expected.to contain_exactly("edit", "block", "ban", "activate", "delete", "delete_with_contributions") } + it do + is_expected.to contain_exactly( + "edit", + "block", + "ban", + "activate", + "delete", + "delete_with_contributions" + ) + end end context 'the user is locked' do @@ -77,7 +106,8 @@ "deactivate", "unlock", "delete", - "delete_with_contributions" + "delete_with_contributions", + "trust" ) } end @@ -88,6 +118,21 @@ it { is_expected.to contain_exactly("edit", "unban", "delete", "delete_with_contributions") } end + context 'the user is trusted' do + let_it_be(:user) { create(:user, :trusted) } + + it do + is_expected.to contain_exactly("edit", + "block", + "deactivate", + "ban", + "delete", + "delete_with_contributions", + "untrust" + ) + end + end + context 'the current_user does not have permission to delete the user' do let_it_be(:user) { build(:user) } @@ -95,7 +140,7 @@ allow(helper).to receive(:can?).with(current_user, :destroy_user, user).and_return(false) end - it { is_expected.to contain_exactly("edit", "block", "ban", "deactivate") } + it { is_expected.to contain_exactly("edit", "block", "ban", "deactivate", "trust") } end context 'the user is a sole owner of a group' do @@ -106,7 +151,7 @@ group.add_owner(user) end - it { is_expected.to contain_exactly("edit", "block", "ban", "deactivate", "delete_with_contributions") } + it { is_expected.to contain_exactly("edit", "block", "ban", "deactivate", "delete_with_contributions", "trust") } end context 'the user is a bot' do -- GitLab From 4665858ad6388bb75e2cc1c448c4a15fae33432a Mon Sep 17 00:00:00 2001 From: Ethan Urie Date: Wed, 6 Sep 2023 15:29:42 -0400 Subject: [PATCH 2/8] Updated locale file Remove unneeded changes for controller and helpers Filter reason options if user selects `Trust user` --- .../admin/abuse_report/constants.js | 1 - app/controllers/admin/users_controller.rb | 2 +- config/routes/admin.rb | 2 + locale/gitlab.pot | 33 ---------- .../admin_users_data_attributes_paths.json | 62 +++++-------------- .../master/gl-common-scanning-report.json | 8 +-- spec/frontend/admin/users/constants.js | 4 -- .../helpers/admin/user_actions_helper_spec.rb | 59 +++--------------- 8 files changed, 26 insertions(+), 145 deletions(-) diff --git a/app/assets/javascripts/admin/abuse_report/constants.js b/app/assets/javascripts/admin/abuse_report/constants.js index cef9ff0a6a2625..f028408bed7287 100644 --- a/app/assets/javascripts/admin/abuse_report/constants.js +++ b/app/assets/javascripts/admin/abuse_report/constants.js @@ -51,7 +51,6 @@ export const REASON_OPTIONS = [ text: s__('AbuseReport|Confirmed violation of a copyright or a trademark'), }, { value: 'malware', text: s__('AbuseReport|Confirmed posting of malware') }, - { value: 'trusted', text: s__(`AbuseReport|Confirmed trusted user`) }, { value: 'other', text: s__('AbuseReport|Something else') }, { value: 'unconfirmed', text: s__('AbuseReport|Abuse unconfirmed') }, ]; diff --git a/app/controllers/admin/users_controller.rb b/app/controllers/admin/users_controller.rb index 8bb582b7cfe3b6..50e0c5cc5ffeda 100644 --- a/app/controllers/admin/users_controller.rb +++ b/app/controllers/admin/users_controller.rb @@ -290,7 +290,7 @@ def paginate_without_count? end def users_with_included_associations(users) - users.includes(:authorized_projects, :trusted_with_spam_attribute) # rubocop: disable CodeReuse/ActiveRecord + users.includes(:authorized_projects) # rubocop: disable CodeReuse/ActiveRecord end def admin_making_changes_for_another_user? diff --git a/config/routes/admin.rb b/config/routes/admin.rb index 5513ac1813a0a5..e8ad19624e9823 100644 --- a/config/routes/admin.rb +++ b/config/routes/admin.rb @@ -22,6 +22,8 @@ put :unlock put :confirm put :approve + put :trust + put :untrust delete :reject post :impersonate patch :disable_two_factor diff --git a/locale/gitlab.pot b/locale/gitlab.pot index d179b6b1c2a162..dd093b5d33a9dd 100644 --- a/locale/gitlab.pot +++ b/locale/gitlab.pot @@ -3879,9 +3879,6 @@ msgstr "" msgid "AdminUsers|Admins" msgstr "" -msgid "AdminUsers|Allow user %{username} to create possible spam?" -msgstr "" - msgid "AdminUsers|An error occurred while fetching this user's contributions, and the request cannot return the number of issues, merge requests, groups, and projects linked to this user. If you proceed with deleting the user, all their contributions will still be deleted." msgstr "" @@ -3984,9 +3981,6 @@ msgstr "" msgid "AdminUsers|Delete user and contributions" msgstr "" -msgid "AdminUsers|Disallow user %{username} to create possible spam?" -msgstr "" - msgid "AdminUsers|Export permissions as CSV (max 100,000 users)" msgstr "" @@ -4101,9 +4095,6 @@ msgstr "" msgid "AdminUsers|The maximum compute minutes that jobs in this namespace can use on shared runners each month. Set 0 for unlimited. Set empty to inherit the global setting of %{minutes}" msgstr "" -msgid "AdminUsers|The user can create issues, notes, snippets, and merge requests without being blocked." -msgstr "" - msgid "AdminUsers|The user can't access git repositories." msgstr "" @@ -4134,9 +4125,6 @@ msgstr "" msgid "AdminUsers|To confirm, type %{username}." msgstr "" -msgid "AdminUsers|Trust user" -msgstr "" - msgid "AdminUsers|Unban user" msgstr "" @@ -4152,9 +4140,6 @@ msgstr "" msgid "AdminUsers|Unlock user %{username}?" msgstr "" -msgid "AdminUsers|Untrust user" -msgstr "" - msgid "AdminUsers|User administration" msgstr "" @@ -4185,9 +4170,6 @@ msgstr "" msgid "AdminUsers|What does this mean?" msgstr "" -msgid "AdminUsers|When allowed to create possible spam:" -msgstr "" - msgid "AdminUsers|When banned:" msgstr "" @@ -4206,9 +4188,6 @@ msgstr "" msgid "AdminUsers|You are about to permanently delete the user %{username}. This will delete all issues, merge requests, groups, and projects linked to them. To avoid data loss, consider using the %{strongStart}Block user%{strongEnd} feature instead. After you %{strongStart}Delete user%{strongEnd}, you cannot undo this action or recover the data." msgstr "" -msgid "AdminUsers|You can allow possible spam in the future if necessary." -msgstr "" - msgid "AdminUsers|You can always block their account again if needed." msgstr "" @@ -4224,9 +4203,6 @@ msgstr "" msgid "AdminUsers|You can ban their account in the future if necessary." msgstr "" -msgid "AdminUsers|You can disallow creating possible spam in the future." -msgstr "" - msgid "AdminUsers|You can unban their account in the future. Their data remains intact." msgstr "" @@ -19081,9 +19057,6 @@ msgstr "" msgid "Error occurred. User was not unlocked" msgstr "" -msgid "Error occurred. User was not updated" -msgstr "" - msgid "Error parsing CSV file. Please make sure it has" msgstr "" @@ -46282,9 +46255,6 @@ msgstr "" msgid "Successfully synced %{synced_timeago}." msgstr "" -msgid "Successfully trusted" -msgstr "" - msgid "Successfully unbanned" msgstr "" @@ -46297,9 +46267,6 @@ msgstr "" msgid "Successfully unlocked" msgstr "" -msgid "Successfully untrusted" -msgstr "" - msgid "Successfully updated %{last_updated_timeago}." msgstr "" diff --git a/spec/fixtures/api/schemas/entities/admin_users_data_attributes_paths.json b/spec/fixtures/api/schemas/entities/admin_users_data_attributes_paths.json index 61472b273e1342..44d8e48a972c48 100644 --- a/spec/fixtures/api/schemas/entities/admin_users_data_attributes_paths.json +++ b/spec/fixtures/api/schemas/entities/admin_users_data_attributes_paths.json @@ -1,51 +1,19 @@ { "type": "object", "properties": { - "edit": { - "type": "string" - }, - "approve": { - "type": "string" - }, - "reject": { - "type": "string" - }, - "unblock": { - "type": "string" - }, - "block": { - "type": "string" - }, - "deactivate": { - "type": "string" - }, - "activate": { - "type": "string" - }, - "unlock": { - "type": "string" - }, - "delete": { - "type": "string" - }, - "delete_with_contributions": { - "type": "string" - }, - "admin_user": { - "type": "string" - }, - "ban": { - "type": "string" - }, - "unban": { - "type": "string" - }, - "trust": { - "type": "string" - }, - "untrust": { - "type": "string" - } + "edit": { "type": "string" }, + "approve": { "type": "string" }, + "reject": { "type": "string" }, + "unblock": { "type": "string" }, + "block": { "type": "string" }, + "deactivate": { "type": "string" }, + "activate": { "type": "string" }, + "unlock": { "type": "string" }, + "delete": { "type": "string" }, + "delete_with_contributions": { "type": "string" }, + "admin_user": { "type": "string" }, + "ban": { "type": "string" }, + "unban": { "type": "string" } }, "required": [ "edit", @@ -60,9 +28,7 @@ "delete_with_contributions", "admin_user", "ban", - "unban", - "trust", - "untrust" + "unban" ], "additionalProperties": false } diff --git a/spec/fixtures/security_reports/master/gl-common-scanning-report.json b/spec/fixtures/security_reports/master/gl-common-scanning-report.json index 47e2a503b02bc7..cd17da5a7aec80 100644 --- a/spec/fixtures/security_reports/master/gl-common-scanning-report.json +++ b/spec/fixtures/security_reports/master/gl-common-scanning-report.json @@ -420,9 +420,7 @@ "value": "foo" } ], - "links": [ - - ] + "links": [] } ], "remediations": [ @@ -484,9 +482,7 @@ "diff": "dG90YWxseSBsZWdpdGltYXRlIGRpZmYsIDEwLzEwIHdvdWxkIGFwcGx5" } ], - "dependency_files": [ - - ], + "dependency_files": [], "scan": { "analyzer": { "id": "common-analyzer", diff --git a/spec/frontend/admin/users/constants.js b/spec/frontend/admin/users/constants.js index 39e8e51f43ca0b..d341eb03b1b33c 100644 --- a/spec/frontend/admin/users/constants.js +++ b/spec/frontend/admin/users/constants.js @@ -9,8 +9,6 @@ const REJECT = 'reject'; const APPROVE = 'approve'; const BAN = 'ban'; const UNBAN = 'unban'; -const TRUST = 'trust'; -const UNTRUST = 'untrust'; export const EDIT = 'edit'; @@ -26,8 +24,6 @@ export const CONFIRMATION_ACTIONS = [ UNBAN, APPROVE, REJECT, - TRUST, - UNTRUST, ]; export const DELETE_ACTIONS = [DELETE, DELETE_WITH_CONTRIBUTIONS]; diff --git a/spec/helpers/admin/user_actions_helper_spec.rb b/spec/helpers/admin/user_actions_helper_spec.rb index abfdabf3413df9..87d2308690c617 100644 --- a/spec/helpers/admin/user_actions_helper_spec.rb +++ b/spec/helpers/admin/user_actions_helper_spec.rb @@ -2,7 +2,7 @@ require "spec_helper" -RSpec.describe Admin::UserActionsHelper, feature_category: :user_management do +RSpec.describe Admin::UserActionsHelper do describe '#admin_actions' do let_it_be(:current_user) { build(:user) } @@ -29,33 +29,13 @@ context 'the user is a standard user' do let_it_be(:user) { create(:user) } - it do - is_expected.to contain_exactly( - "edit", - "block", - "ban", - "deactivate", - "delete", - "delete_with_contributions", - "trust" - ) - end + it { is_expected.to contain_exactly("edit", "block", "ban", "deactivate", "delete", "delete_with_contributions") } end context 'the user is an admin user' do let_it_be(:user) { create(:user, :admin) } - it do - is_expected.to contain_exactly( - "edit", - "block", - "ban", - "deactivate", - "delete", - "delete_with_contributions", - "trust" - ) - end + it { is_expected.to contain_exactly("edit", "block", "ban", "deactivate", "delete", "delete_with_contributions") } end context 'the user is blocked by LDAP' do @@ -79,16 +59,7 @@ context 'the user is deactivated' do let_it_be(:user) { create(:user, :deactivated) } - it do - is_expected.to contain_exactly( - "edit", - "block", - "ban", - "activate", - "delete", - "delete_with_contributions" - ) - end + it { is_expected.to contain_exactly("edit", "block", "ban", "activate", "delete", "delete_with_contributions") } end context 'the user is locked' do @@ -106,8 +77,7 @@ "deactivate", "unlock", "delete", - "delete_with_contributions", - "trust" + "delete_with_contributions" ) } end @@ -118,21 +88,6 @@ it { is_expected.to contain_exactly("edit", "unban", "delete", "delete_with_contributions") } end - context 'the user is trusted' do - let_it_be(:user) { create(:user, :trusted) } - - it do - is_expected.to contain_exactly("edit", - "block", - "deactivate", - "ban", - "delete", - "delete_with_contributions", - "untrust" - ) - end - end - context 'the current_user does not have permission to delete the user' do let_it_be(:user) { build(:user) } @@ -140,7 +95,7 @@ allow(helper).to receive(:can?).with(current_user, :destroy_user, user).and_return(false) end - it { is_expected.to contain_exactly("edit", "block", "ban", "deactivate", "trust") } + it { is_expected.to contain_exactly("edit", "block", "ban", "deactivate") } end context 'the user is a sole owner of a group' do @@ -151,7 +106,7 @@ group.add_owner(user) end - it { is_expected.to contain_exactly("edit", "block", "ban", "deactivate", "delete_with_contributions", "trust") } + it { is_expected.to contain_exactly("edit", "block", "ban", "deactivate", "delete_with_contributions") } end context 'the user is a bot' do -- GitLab From e277fcf1fc81bacdb17603dec80f29b2412222ac Mon Sep 17 00:00:00 2001 From: Ethan Urie Date: Fri, 13 Oct 2023 09:37:01 -0400 Subject: [PATCH 3/8] Combination of many cherry picks from original branch (cherry picked from commit 66b5d4e55c8b12598733bbcb40088a79f90f621f) (cherry picked from commit a57b001b7e99275bbe33dea1c69643b93b48bfec) (cherry picked from commit 87ff28cf5ee4501c347ef5c3656ba04c0e4139e5) (cherry picked from commit edca4ae268af599e85c2e5249a52930e9a83ade3) (cherry picked from commit edca4ae268af599e85c2e5249a52930e9a83ade3) (cherry picked from commit 5a680330755696bc2244d0b41897ab984867d1f2) (cherry picked from commit 66b5d4e55c8b12598733bbcb40088a79f90f621f) (cherry picked from commit a57b001b7e99275bbe33dea1c69643b93b48bfec) (cherry picked from commit 87ff28cf5ee4501c347ef5c3656ba04c0e4139e5) (cherry picked from commit edca4ae268af599e85c2e5249a52930e9a83ade3) (cherry picked from commit edca4ae268af599e85c2e5249a52930e9a83ade3) (cherry picked from commit 5a680330755696bc2244d0b41897ab984867d1f2) (cherry picked from commit 66b5d4e55c8b12598733bbcb40088a79f90f621f) (cherry picked from commit a57b001b7e99275bbe33dea1c69643b93b48bfec) (cherry picked from commit 87ff28cf5ee4501c347ef5c3656ba04c0e4139e5) (cherry picked from commit edca4ae268af599e85c2e5249a52930e9a83ade3) (cherry picked from commit edca4ae268af599e85c2e5249a52930e9a83ade3) (cherry picked from commit 5a680330755696bc2244d0b41897ab984867d1f2) (cherry picked from commit 66b5d4e55c8b12598733bbcb40088a79f90f621f) (cherry picked from commit a57b001b7e99275bbe33dea1c69643b93b48bfec) (cherry picked from commit 87ff28cf5ee4501c347ef5c3656ba04c0e4139e5) (cherry picked from commit edca4ae268af599e85c2e5249a52930e9a83ade3) (cherry picked from commit edca4ae268af599e85c2e5249a52930e9a83ade3) (cherry picked from commit 5a680330755696bc2244d0b41897ab984867d1f2) (cherry picked from commit 66b5d4e55c8b12598733bbcb40088a79f90f621f) (cherry picked from commit a57b001b7e99275bbe33dea1c69643b93b48bfec) (cherry picked from commit 87ff28cf5ee4501c347ef5c3656ba04c0e4139e5) (cherry picked from commit edca4ae268af599e85c2e5249a52930e9a83ade3) (cherry picked from commit edca4ae268af599e85c2e5249a52930e9a83ade3) (cherry picked from commit 5a680330755696bc2244d0b41897ab984867d1f2) Update documentation and add constants --- .../admin/users/components/actions/index.js | 4 ++ .../users/components/actions/trust_user.vue | 62 +++++++++++++++++++ .../users/components/actions/untrust_user.vue | 56 +++++++++++++++++ .../javascripts/admin/users/constants.js | 2 + app/controllers/admin/users_controller.rb | 22 ++++++- app/helpers/admin/user_actions_helper.rb | 15 +++++ app/helpers/users_helper.rb | 4 +- app/models/user.rb | 8 +++ app/views/admin/users/_users.html.haml | 3 + doc/administration/moderate_users.md | 27 ++++++++ doc/administration/review_spam_logs.md | 12 ---- locale/gitlab.pot | 36 +++++++++++ spec/features/admin/admin_users_spec.rb | 8 +++ .../admin_users_data_attributes_paths.json | 62 ++++++++++++++----- .../master/gl-common-scanning-report.json | 8 ++- spec/frontend/admin/users/constants.js | 4 ++ .../helpers/admin/user_actions_helper_spec.rb | 59 +++++++++++++++--- 17 files changed, 355 insertions(+), 37 deletions(-) create mode 100644 app/assets/javascripts/admin/users/components/actions/trust_user.vue create mode 100644 app/assets/javascripts/admin/users/components/actions/untrust_user.vue diff --git a/app/assets/javascripts/admin/users/components/actions/index.js b/app/assets/javascripts/admin/users/components/actions/index.js index 4e63a85df891f2..633bc4d8b15c32 100644 --- a/app/assets/javascripts/admin/users/components/actions/index.js +++ b/app/assets/javascripts/admin/users/components/actions/index.js @@ -9,6 +9,8 @@ import Reject from './reject.vue'; import Unban from './unban.vue'; import Unblock from './unblock.vue'; import Unlock from './unlock.vue'; +import Trust from './trust_user.vue'; +import Untrust from './untrust_user.vue'; export default { Activate, @@ -22,4 +24,6 @@ export default { Unblock, Unlock, Reject, + Trust, + Untrust, }; diff --git a/app/assets/javascripts/admin/users/components/actions/trust_user.vue b/app/assets/javascripts/admin/users/components/actions/trust_user.vue new file mode 100644 index 00000000000000..ce94c1cd8ccae9 --- /dev/null +++ b/app/assets/javascripts/admin/users/components/actions/trust_user.vue @@ -0,0 +1,62 @@ + + + diff --git a/app/assets/javascripts/admin/users/components/actions/untrust_user.vue b/app/assets/javascripts/admin/users/components/actions/untrust_user.vue new file mode 100644 index 00000000000000..ba2904a9f40d77 --- /dev/null +++ b/app/assets/javascripts/admin/users/components/actions/untrust_user.vue @@ -0,0 +1,56 @@ + + + diff --git a/app/assets/javascripts/admin/users/constants.js b/app/assets/javascripts/admin/users/constants.js index 9cd61d6b1dbcc6..43c9a8749cde76 100644 --- a/app/assets/javascripts/admin/users/constants.js +++ b/app/assets/javascripts/admin/users/constants.js @@ -19,4 +19,6 @@ export const I18N_USER_ACTIONS = { deleteWithContributions: s__('AdminUsers|Delete user and contributions'), ban: s__('AdminUsers|Ban user'), unban: s__('AdminUsers|Unban user'), + trust: s__('AdminUsers|Trust user'), + untrust: s__('AdminUsers|Untrust user'), }; diff --git a/app/controllers/admin/users_controller.rb b/app/controllers/admin/users_controller.rb index 50e0c5cc5ffeda..ee78d5a8c35f46 100644 --- a/app/controllers/admin/users_controller.rb +++ b/app/controllers/admin/users_controller.rb @@ -164,6 +164,26 @@ def unlock end end + def trust + result = Users::TrustService.new(current_user).execute(user) + + if result[:status] == :success + redirect_back_or_admin_user(notice: _("Successfully trusted")) + else + redirect_back_or_admin_user(alert: _("Error occurred. User was not updated")) + end + end + + def untrust + result = Users::UntrustService.new(current_user).execute(user) + + if result[:status] == :success + redirect_back_or_admin_user(notice: _("Successfully untrusted")) + else + redirect_back_or_admin_user(alert: _("Error occurred. User was not updated")) + end + end + def confirm if update_user(&:force_confirm) redirect_back_or_admin_user(notice: _("Successfully confirmed")) @@ -290,7 +310,7 @@ def paginate_without_count? end def users_with_included_associations(users) - users.includes(:authorized_projects) # rubocop: disable CodeReuse/ActiveRecord + users.includes(:authorized_projects, :trusted_with_spam_attribute) # rubocop: disable CodeReuse/ActiveRecord end def admin_making_changes_for_another_user? diff --git a/app/helpers/admin/user_actions_helper.rb b/app/helpers/admin/user_actions_helper.rb index 969c5d5a0b5b14..ba40b3c8a8df5a 100644 --- a/app/helpers/admin/user_actions_helper.rb +++ b/app/helpers/admin/user_actions_helper.rb @@ -16,6 +16,7 @@ def admin_actions(user) unlock_actions delete_actions ban_actions + trust_actions @actions end @@ -66,5 +67,19 @@ def ban_actions @actions << 'ban' end end + + def trust_actions + return if @user.internal? || + @user.blocked_pending_approval? || + @user.banned? || + @user.blocked? || + @user.deactivated? + + @actions << if @user.trusted? + 'untrust' + else + 'trust' + end + end end end diff --git a/app/helpers/users_helper.rb b/app/helpers/users_helper.rb index a892b6e6ac6f7c..81c41aee142a70 100644 --- a/app/helpers/users_helper.rb +++ b/app/helpers/users_helper.rb @@ -262,7 +262,9 @@ def admin_users_paths delete_with_contributions: admin_user_path(:id, hard_delete: true), admin_user: admin_user_path(:id), ban: ban_admin_user_path(:id), - unban: unban_admin_user_path(:id) + unban: unban_admin_user_path(:id), + trust: trust_admin_user_path(:id), + untrust: untrust_admin_user_path(:id) } end diff --git a/app/models/user.rb b/app/models/user.rb index fdc0b531521bc1..bc256ef0f310fe 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -601,6 +601,12 @@ def blocked? scope :by_provider_and_extern_uid, ->(provider, extern_uid) { joins(:identities).merge(Identity.with_extern_uid(provider, extern_uid)) } scope :by_ids_or_usernames, -> (ids, usernames) { where(username: usernames).or(where(id: ids)) } scope :without_forbidden_states, -> { where.not(state: FORBIDDEN_SEARCH_STATES) } + scope :trusted, -> do + where('EXISTS (?)', ::UserCustomAttribute + .select(1) + .where('user_id = users.id') + .trusted_with_spam) + end strip_attributes! :name @@ -769,6 +775,8 @@ def filter_items(filter_name) external when 'deactivated' deactivated + when "trusted" + trusted else active_without_ghosts end diff --git a/app/views/admin/users/_users.html.haml b/app/views/admin/users/_users.html.haml index d4a9009a0cf1b7..bbb068c3680e21 100644 --- a/app/views/admin/users/_users.html.haml +++ b/app/views/admin/users/_users.html.haml @@ -44,6 +44,9 @@ = gl_tab_link_to admin_users_path(filter: "wop"), { item_active: active_when(params[:filter] == 'wop'), class: 'gl-border-0!' } do = s_('AdminUsers|Without projects') = gl_tab_counter_badge(limited_counter_with_delimiter(User.without_projects)) + = gl_tab_link_to admin_users_path(filter: "trusted"), { item_active: active_when(params[:filter] == 'trusted'), class: 'gl-border-0!' } do + = s_('AdminUsers|Trusted') + = gl_tab_counter_badge(limited_counter_with_delimiter(User.trusted)) .nav-controls = render_if_exists 'admin/users/admin_email_users' = render_if_exists 'admin/users/admin_export_user_permissions' diff --git a/doc/administration/moderate_users.md b/doc/administration/moderate_users.md index b30294c5fe0bd5..7131a99290cfab 100644 --- a/doc/administration/moderate_users.md +++ b/doc/administration/moderate_users.md @@ -287,6 +287,33 @@ You can also delete a user and their contributions, such as merge requests, issu NOTE: Before 15.1, additionally groups of which deleted user were the only owner among direct members were deleted. +## Trust and untrust a user + +> **Trust user** [introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/132402) in GitLab 16.5. + +GitLab administrators can trust and untrust users. Users are untrusted by default and will be blocked from creating issues, notes, or snippets that are considered to be spam. Trusted users are allowed to create issues, notes, snippets, and merge requests without being blocked for spamming. + +### Trust a user + +1. On the left sidebar, select **Search or go to**. +1. Select **Admin Area**. +1. Select **Overview > Users**. +1. Select a user. +1. Select the **{settings}** **User administration** dropdown list. +1. Select **Trust user**. +1. Select **Trust user**. + +### Untrust a user + +1. On the left sidebar, select **Search or go to**. +1. Select **Admin Area**. +1. Select **Overview > Users**. +1. Select the **Trusted** tab. +1. Select a user. +1. Select the **{settings}** **User administration** dropdown list. +1. Select **Untrust user**. +1. Select **Untrust user**. + ## Troubleshooting When moderating users, you may need to perform bulk actions on them based on certain conditions. The following rails console scripts show some examples of this. You may [start a rails console session](../administration/operations/rails_console.md#starting-a-rails-console-session) and use scripts similar to the following: diff --git a/doc/administration/review_spam_logs.md b/doc/administration/review_spam_logs.md index 35cc78a9bf36d3..e3b96cdae95059 100644 --- a/doc/administration/review_spam_logs.md +++ b/doc/administration/review_spam_logs.md @@ -38,15 +38,3 @@ You can resolve a spam log with one of the following effects: NOTE: Users can be [blocked](../api/users.md#block-user) and [unblocked](../api/users.md#unblock-user) using the GitLab API. - - diff --git a/locale/gitlab.pot b/locale/gitlab.pot index dd093b5d33a9dd..bc2ddc7aa80b7f 100644 --- a/locale/gitlab.pot +++ b/locale/gitlab.pot @@ -3879,6 +3879,9 @@ msgstr "" msgid "AdminUsers|Admins" msgstr "" +msgid "AdminUsers|Allow user %{username} to create possible spam?" +msgstr "" + msgid "AdminUsers|An error occurred while fetching this user's contributions, and the request cannot return the number of issues, merge requests, groups, and projects linked to this user. If you proceed with deleting the user, all their contributions will still be deleted." msgstr "" @@ -3981,6 +3984,9 @@ msgstr "" msgid "AdminUsers|Delete user and contributions" msgstr "" +msgid "AdminUsers|Disallow user %{username} to create possible spam?" +msgstr "" + msgid "AdminUsers|Export permissions as CSV (max 100,000 users)" msgstr "" @@ -4095,6 +4101,9 @@ msgstr "" msgid "AdminUsers|The maximum compute minutes that jobs in this namespace can use on shared runners each month. Set 0 for unlimited. Set empty to inherit the global setting of %{minutes}" msgstr "" +msgid "AdminUsers|The user can create issues, notes, snippets, and merge requests without being blocked." +msgstr "" + msgid "AdminUsers|The user can't access git repositories." msgstr "" @@ -4125,6 +4134,12 @@ msgstr "" msgid "AdminUsers|To confirm, type %{username}." msgstr "" +msgid "AdminUsers|Trust user" +msgstr "" + +msgid "AdminUsers|Trusted" +msgstr "" + msgid "AdminUsers|Unban user" msgstr "" @@ -4140,6 +4155,9 @@ msgstr "" msgid "AdminUsers|Unlock user %{username}?" msgstr "" +msgid "AdminUsers|Untrust user" +msgstr "" + msgid "AdminUsers|User administration" msgstr "" @@ -4170,6 +4188,9 @@ msgstr "" msgid "AdminUsers|What does this mean?" msgstr "" +msgid "AdminUsers|When allowed to create possible spam:" +msgstr "" + msgid "AdminUsers|When banned:" msgstr "" @@ -4188,6 +4209,9 @@ msgstr "" msgid "AdminUsers|You are about to permanently delete the user %{username}. This will delete all issues, merge requests, groups, and projects linked to them. To avoid data loss, consider using the %{strongStart}Block user%{strongEnd} feature instead. After you %{strongStart}Delete user%{strongEnd}, you cannot undo this action or recover the data." msgstr "" +msgid "AdminUsers|You can allow possible spam in the future if necessary." +msgstr "" + msgid "AdminUsers|You can always block their account again if needed." msgstr "" @@ -4203,6 +4227,9 @@ msgstr "" msgid "AdminUsers|You can ban their account in the future if necessary." msgstr "" +msgid "AdminUsers|You can disallow creating possible spam in the future." +msgstr "" + msgid "AdminUsers|You can unban their account in the future. Their data remains intact." msgstr "" @@ -19057,6 +19084,9 @@ msgstr "" msgid "Error occurred. User was not unlocked" msgstr "" +msgid "Error occurred. User was not updated" +msgstr "" + msgid "Error parsing CSV file. Please make sure it has" msgstr "" @@ -46255,6 +46285,9 @@ msgstr "" msgid "Successfully synced %{synced_timeago}." msgstr "" +msgid "Successfully trusted" +msgstr "" + msgid "Successfully unbanned" msgstr "" @@ -46267,6 +46300,9 @@ msgstr "" msgid "Successfully unlocked" msgstr "" +msgid "Successfully untrusted" +msgstr "" + msgid "Successfully updated %{last_updated_timeago}." msgstr "" diff --git a/spec/features/admin/admin_users_spec.rb b/spec/features/admin/admin_users_spec.rb index ca08bc9e577da3..9ab5b1fd3bb875 100644 --- a/spec/features/admin/admin_users_spec.rb +++ b/spec/features/admin/admin_users_spec.rb @@ -82,4 +82,12 @@ end end end + + it 'does not perform N+1 queries' do + control_queries = ActiveRecord::QueryRecorder.new { visit admin_users_path } + + expect { create(:user) }.to change { User.count }.by(1) + + expect { visit admin_users_path }.not_to exceed_query_limit(control_queries) + end end diff --git a/spec/fixtures/api/schemas/entities/admin_users_data_attributes_paths.json b/spec/fixtures/api/schemas/entities/admin_users_data_attributes_paths.json index 44d8e48a972c48..61472b273e1342 100644 --- a/spec/fixtures/api/schemas/entities/admin_users_data_attributes_paths.json +++ b/spec/fixtures/api/schemas/entities/admin_users_data_attributes_paths.json @@ -1,19 +1,51 @@ { "type": "object", "properties": { - "edit": { "type": "string" }, - "approve": { "type": "string" }, - "reject": { "type": "string" }, - "unblock": { "type": "string" }, - "block": { "type": "string" }, - "deactivate": { "type": "string" }, - "activate": { "type": "string" }, - "unlock": { "type": "string" }, - "delete": { "type": "string" }, - "delete_with_contributions": { "type": "string" }, - "admin_user": { "type": "string" }, - "ban": { "type": "string" }, - "unban": { "type": "string" } + "edit": { + "type": "string" + }, + "approve": { + "type": "string" + }, + "reject": { + "type": "string" + }, + "unblock": { + "type": "string" + }, + "block": { + "type": "string" + }, + "deactivate": { + "type": "string" + }, + "activate": { + "type": "string" + }, + "unlock": { + "type": "string" + }, + "delete": { + "type": "string" + }, + "delete_with_contributions": { + "type": "string" + }, + "admin_user": { + "type": "string" + }, + "ban": { + "type": "string" + }, + "unban": { + "type": "string" + }, + "trust": { + "type": "string" + }, + "untrust": { + "type": "string" + } }, "required": [ "edit", @@ -28,7 +60,9 @@ "delete_with_contributions", "admin_user", "ban", - "unban" + "unban", + "trust", + "untrust" ], "additionalProperties": false } diff --git a/spec/fixtures/security_reports/master/gl-common-scanning-report.json b/spec/fixtures/security_reports/master/gl-common-scanning-report.json index cd17da5a7aec80..47e2a503b02bc7 100644 --- a/spec/fixtures/security_reports/master/gl-common-scanning-report.json +++ b/spec/fixtures/security_reports/master/gl-common-scanning-report.json @@ -420,7 +420,9 @@ "value": "foo" } ], - "links": [] + "links": [ + + ] } ], "remediations": [ @@ -482,7 +484,9 @@ "diff": "dG90YWxseSBsZWdpdGltYXRlIGRpZmYsIDEwLzEwIHdvdWxkIGFwcGx5" } ], - "dependency_files": [], + "dependency_files": [ + + ], "scan": { "analyzer": { "id": "common-analyzer", diff --git a/spec/frontend/admin/users/constants.js b/spec/frontend/admin/users/constants.js index d341eb03b1b33c..39e8e51f43ca0b 100644 --- a/spec/frontend/admin/users/constants.js +++ b/spec/frontend/admin/users/constants.js @@ -9,6 +9,8 @@ const REJECT = 'reject'; const APPROVE = 'approve'; const BAN = 'ban'; const UNBAN = 'unban'; +const TRUST = 'trust'; +const UNTRUST = 'untrust'; export const EDIT = 'edit'; @@ -24,6 +26,8 @@ export const CONFIRMATION_ACTIONS = [ UNBAN, APPROVE, REJECT, + TRUST, + UNTRUST, ]; export const DELETE_ACTIONS = [DELETE, DELETE_WITH_CONTRIBUTIONS]; diff --git a/spec/helpers/admin/user_actions_helper_spec.rb b/spec/helpers/admin/user_actions_helper_spec.rb index 87d2308690c617..abfdabf3413df9 100644 --- a/spec/helpers/admin/user_actions_helper_spec.rb +++ b/spec/helpers/admin/user_actions_helper_spec.rb @@ -2,7 +2,7 @@ require "spec_helper" -RSpec.describe Admin::UserActionsHelper do +RSpec.describe Admin::UserActionsHelper, feature_category: :user_management do describe '#admin_actions' do let_it_be(:current_user) { build(:user) } @@ -29,13 +29,33 @@ context 'the user is a standard user' do let_it_be(:user) { create(:user) } - it { is_expected.to contain_exactly("edit", "block", "ban", "deactivate", "delete", "delete_with_contributions") } + it do + is_expected.to contain_exactly( + "edit", + "block", + "ban", + "deactivate", + "delete", + "delete_with_contributions", + "trust" + ) + end end context 'the user is an admin user' do let_it_be(:user) { create(:user, :admin) } - it { is_expected.to contain_exactly("edit", "block", "ban", "deactivate", "delete", "delete_with_contributions") } + it do + is_expected.to contain_exactly( + "edit", + "block", + "ban", + "deactivate", + "delete", + "delete_with_contributions", + "trust" + ) + end end context 'the user is blocked by LDAP' do @@ -59,7 +79,16 @@ context 'the user is deactivated' do let_it_be(:user) { create(:user, :deactivated) } - it { is_expected.to contain_exactly("edit", "block", "ban", "activate", "delete", "delete_with_contributions") } + it do + is_expected.to contain_exactly( + "edit", + "block", + "ban", + "activate", + "delete", + "delete_with_contributions" + ) + end end context 'the user is locked' do @@ -77,7 +106,8 @@ "deactivate", "unlock", "delete", - "delete_with_contributions" + "delete_with_contributions", + "trust" ) } end @@ -88,6 +118,21 @@ it { is_expected.to contain_exactly("edit", "unban", "delete", "delete_with_contributions") } end + context 'the user is trusted' do + let_it_be(:user) { create(:user, :trusted) } + + it do + is_expected.to contain_exactly("edit", + "block", + "deactivate", + "ban", + "delete", + "delete_with_contributions", + "untrust" + ) + end + end + context 'the current_user does not have permission to delete the user' do let_it_be(:user) { build(:user) } @@ -95,7 +140,7 @@ allow(helper).to receive(:can?).with(current_user, :destroy_user, user).and_return(false) end - it { is_expected.to contain_exactly("edit", "block", "ban", "deactivate") } + it { is_expected.to contain_exactly("edit", "block", "ban", "deactivate", "trust") } end context 'the user is a sole owner of a group' do @@ -106,7 +151,7 @@ group.add_owner(user) end - it { is_expected.to contain_exactly("edit", "block", "ban", "deactivate", "delete_with_contributions") } + it { is_expected.to contain_exactly("edit", "block", "ban", "deactivate", "delete_with_contributions", "trust") } end context 'the user is a bot' do -- GitLab From a84538168375df4252d9810de159254738d5c564 Mon Sep 17 00:00:00 2001 From: Ethan Urie Date: Mon, 23 Oct 2023 14:56:15 -0400 Subject: [PATCH 4/8] Reword confirmation dialog --- .../users/components/actions/trust_user.vue | 8 +++--- .../users/components/actions/untrust_user.vue | 4 +-- locale/gitlab.pot | 26 +++++++++---------- 3 files changed, 19 insertions(+), 19 deletions(-) diff --git a/app/assets/javascripts/admin/users/components/actions/trust_user.vue b/app/assets/javascripts/admin/users/components/actions/trust_user.vue index ce94c1cd8ccae9..41ff8d4120de27 100644 --- a/app/assets/javascripts/admin/users/components/actions/trust_user.vue +++ b/app/assets/javascripts/admin/users/components/actions/trust_user.vue @@ -6,13 +6,13 @@ import { I18N_USER_ACTIONS } from '../../constants'; // TODO: To be replaced with