diff --git a/app/assets/javascripts/pipelines/components/pipelines_list/tokens/pipeline_trigger_author_token.vue b/app/assets/javascripts/pipelines/components/pipelines_list/tokens/pipeline_trigger_author_token.vue
index dfa6d8c13a5..ae5758233bc 100644
--- a/app/assets/javascripts/pipelines/components/pipelines_list/tokens/pipeline_trigger_author_token.vue
+++ b/app/assets/javascripts/pipelines/components/pipelines_list/tokens/pipeline_trigger_author_token.vue
@@ -3,7 +3,7 @@ import {
GlFilteredSearchToken,
GlAvatar,
GlFilteredSearchSuggestion,
- GlDeprecatedDropdownDivider,
+ GlDropdownDivider,
GlLoadingIcon,
} from '@gitlab/ui';
import { debounce } from 'lodash';
@@ -21,7 +21,7 @@ export default {
GlFilteredSearchToken,
GlAvatar,
GlFilteredSearchSuggestion,
- GlDeprecatedDropdownDivider,
+ GlDropdownDivider,
GlLoadingIcon,
},
props: {
@@ -94,7 +94,7 @@ export default {
{{
$options.anyTriggerAuthor
}}
-
+
diff --git a/app/assets/stylesheets/framework/mixins.scss b/app/assets/stylesheets/framework/mixins.scss
index 61e8c0d4718..63be2bdef8e 100644
--- a/app/assets/stylesheets/framework/mixins.scss
+++ b/app/assets/stylesheets/framework/mixins.scss
@@ -215,7 +215,7 @@
}
&.build-trace-rounded {
- border-radius: $border-radius-base;
+ border-radius: $gl-border-radius-base;
}
}
diff --git a/app/assets/stylesheets/page_bundles/pipeline.scss b/app/assets/stylesheets/page_bundles/pipeline.scss
index cbabfd1fa50..8e7be629481 100644
--- a/app/assets/stylesheets/page_bundles/pipeline.scss
+++ b/app/assets/stylesheets/page_bundles/pipeline.scss
@@ -476,3 +476,9 @@
height: auto !important;
}
}
+
+.test-reports-table {
+ .build-trace {
+ @include build-trace();
+ }
+}
diff --git a/app/assets/stylesheets/pages/pipelines.scss b/app/assets/stylesheets/pages/pipelines.scss
index 5e7222b52eb..0e8f29e793e 100644
--- a/app/assets/stylesheets/pages/pipelines.scss
+++ b/app/assets/stylesheets/pages/pipelines.scss
@@ -130,12 +130,6 @@
float: none;
}
-.test-reports-table {
- .build-trace {
- @include build-trace();
- }
-}
-
.progress-bar.bg-primary {
background-color: $blue-500 !important;
}
diff --git a/app/controllers/admin/users_controller.rb b/app/controllers/admin/users_controller.rb
index 9afad86185d..8c8df153412 100644
--- a/app/controllers/admin/users_controller.rb
+++ b/app/controllers/admin/users_controller.rb
@@ -72,6 +72,7 @@ class Admin::UsersController < Admin::ApplicationController
def deactivate
return redirect_back_or_admin_user(notice: _("Error occurred. A blocked user cannot be deactivated")) if user.blocked?
return redirect_back_or_admin_user(notice: _("Successfully deactivated")) if user.deactivated?
+ return redirect_back_or_admin_user(notice: _("Internal users cannot be deactivated")) if user.internal?
return redirect_back_or_admin_user(notice: _("The user you are trying to deactivate has been active in the past %{minimum_inactive_days} days and cannot be deactivated") % { minimum_inactive_days: ::User::MINIMUM_INACTIVE_DAYS }) unless user.can_be_deactivated?
user.deactivate
diff --git a/app/models/user.rb b/app/models/user.rb
index 5ef1498bd85..6aea0fd77e3 100644
--- a/app/models/user.rb
+++ b/app/models/user.rb
@@ -1711,7 +1711,7 @@ class User < ApplicationRecord
end
def can_be_deactivated?
- active? && no_recent_activity?
+ active? && no_recent_activity? && !internal?
end
def last_active_at
diff --git a/app/services/personal_access_tokens/revoke_service.rb b/app/services/personal_access_tokens/revoke_service.rb
index 16ba42bd317..17405002d8d 100644
--- a/app/services/personal_access_tokens/revoke_service.rb
+++ b/app/services/personal_access_tokens/revoke_service.rb
@@ -2,11 +2,12 @@
module PersonalAccessTokens
class RevokeService
- attr_reader :token, :current_user
+ attr_reader :token, :current_user, :group
- def initialize(current_user = nil, params = { token: nil })
+ def initialize(current_user = nil, params = { token: nil, group: nil })
@current_user = current_user
@token = params[:token]
+ @group = params[:group]
end
def execute
@@ -34,3 +35,5 @@ module PersonalAccessTokens
end
end
end
+
+PersonalAccessTokens::RevokeService.prepend_if_ee('EE::PersonalAccessTokens::RevokeService')
diff --git a/app/views/admin/users/show.html.haml b/app/views/admin/users/show.html.haml
index e0edf83b04c..0ae4d987aab 100644
--- a/app/views/admin/users/show.html.haml
+++ b/app/views/admin/users/show.html.haml
@@ -150,26 +150,27 @@
= render 'admin/users/user_detail_note'
- - if @user.deactivated?
- .card.border-info
- .card-header.bg-info.text-white
- Reactivate this user
- .card-body
- = render partial: 'admin/users/user_activation_effects'
- %br
- = link_to 'Activate user', activate_admin_user_path(@user), method: :put, class: "btn gl-button btn-info", data: { confirm: 'Are you sure?' }
- - elsif @user.can_be_deactivated?
- .card.border-warning
- .card-header.bg-warning.text-white
- Deactivate this user
- .card-body
- = render partial: 'admin/users/user_deactivation_effects'
- %br
- %button.btn.gl-button.btn-warning{ data: { 'gl-modal-action': 'deactivate',
- content: 'You can always re-activate their account, their data will remain intact.',
- url: deactivate_admin_user_path(@user),
- username: sanitize_name(@user.name) } }
- = s_('AdminUsers|Deactivate user')
+ - unless @user.internal?
+ - if @user.deactivated?
+ .card.border-info
+ .card-header.bg-info.text-white
+ Reactivate this user
+ .card-body
+ = render partial: 'admin/users/user_activation_effects'
+ %br
+ = link_to 'Activate user', activate_admin_user_path(@user), method: :put, class: "btn gl-button btn-info", data: { confirm: 'Are you sure?' }
+ - elsif @user.can_be_deactivated?
+ .card.border-warning
+ .card-header.bg-warning.text-white
+ Deactivate this user
+ .card-body
+ = render partial: 'admin/users/user_deactivation_effects'
+ %br
+ %button.btn.gl-button.btn-warning{ data: { 'gl-modal-action': 'deactivate',
+ content: 'You can always re-activate their account, their data will remain intact.',
+ url: deactivate_admin_user_path(@user),
+ username: sanitize_name(@user.name) } }
+ = s_('AdminUsers|Deactivate user')
- if @user.blocked?
.card.border-info
diff --git a/changelogs/unreleased/Replace-GlDeprecatedDropdown-with-GlDropdown-in-app-assets-javascripts-pi.yml b/changelogs/unreleased/Replace-GlDeprecatedDropdown-with-GlDropdown-in-app-assets-javascripts-pi.yml
new file mode 100644
index 00000000000..21834cbdf35
--- /dev/null
+++ b/changelogs/unreleased/Replace-GlDeprecatedDropdown-with-GlDropdown-in-app-assets-javascripts-pi.yml
@@ -0,0 +1,5 @@
+---
+title: Replace-GlDeprecatedDropdown-with-GlDropdown-in-app/assets/javascripts/pipelines/components/pipelines_list/tokens/pipeline_trigger_author_token.vue
+merge_request: 41424
+author: nuwe1
+type: other
diff --git a/changelogs/unreleased/sk-250679-fix-deactivate-user-api.yml b/changelogs/unreleased/sk-250679-fix-deactivate-user-api.yml
new file mode 100644
index 00000000000..6ecd19d877c
--- /dev/null
+++ b/changelogs/unreleased/sk-250679-fix-deactivate-user-api.yml
@@ -0,0 +1,5 @@
+---
+title: Fix incorrect HTTP response in deactivate user API for internal user
+merge_request: 43356
+author: Sashi Kumar
+type: fixed
diff --git a/doc/api/users.md b/doc/api/users.md
index 5a53695b362..a70f6e3008f 100644
--- a/doc/api/users.md
+++ b/doc/api/users.md
@@ -1250,6 +1250,7 @@ Returns:
- `403 Forbidden` when trying to deactivate a user:
- Blocked by admin or by LDAP synchronization.
- That has any activity in past 180 days. These users cannot be deactivated.
+ - That is internal.
## Activate user
diff --git a/doc/development/product_analytics/snowplow.md b/doc/development/product_analytics/snowplow.md
index 6179c976bba..21d92566ffd 100644
--- a/doc/development/product_analytics/snowplow.md
+++ b/doc/development/product_analytics/snowplow.md
@@ -372,10 +372,10 @@ Snowplow Micro is a Docker-based solution for testing frontend and backend event
docker run --mount type=bind,source=$(pwd)/example,destination=/config -p 9090:9090 snowplow/snowplow-micro:latest --collector-config /config/micro.conf --iglu /config/iglu.json
```
-1. Install snowplow micro by cloning the settings in [this project](https://gitlab.com/a_akgun/snowplow-micro):
+1. Install Snowplow Micro by cloning the settings in [this project](https://gitlab.com/gitlab-org/snowplow-micro-configuration):
```shell
- git clone git@gitlab.com:a_akgun/snowplow-micro.git
+ git clone git@gitlab.com:gitlab-org/snowplow-micro-configuration.git
./snowplow-micro.sh
```
diff --git a/lib/api/users.rb b/lib/api/users.rb
index b13be9c114e..68869cc3781 100644
--- a/lib/api/users.rb
+++ b/lib/api/users.rb
@@ -547,10 +547,15 @@ module API
unless user.can_be_deactivated?
forbidden!('A blocked user cannot be deactivated by the API') if user.blocked?
+ forbidden!('An internal user cannot be deactivated by the API') if user.internal?
forbidden!("The user you are trying to deactivate has been active in the past #{::User::MINIMUM_INACTIVE_DAYS} days and cannot be deactivated")
end
- user.deactivate
+ if user.deactivate
+ true
+ else
+ render_api_error!(user.errors.full_messages, 400)
+ end
end
# rubocop: enable CodeReuse/ActiveRecord
diff --git a/lib/gitlab/usage_data.rb b/lib/gitlab/usage_data.rb
index aba453ff780..69131501803 100644
--- a/lib/gitlab/usage_data.rb
+++ b/lib/gitlab/usage_data.rb
@@ -12,6 +12,19 @@
# redis_usage_data { ::Gitlab::UsageCounters::PodLogs.usage_totals[:total] }
module Gitlab
class UsageData
+ CE_MEMOIZED_VALUES = %i(
+ issue_minimum_id
+ issue_maximum_id
+ project_minimum_id
+ project_maximum_id
+ user_minimum_id
+ user_maximum_id
+ unique_visit_service
+ deployment_minimum_id
+ deployment_maximum_id
+ auth_providers
+ ).freeze
+
class << self
include Gitlab::Utils::UsageData
include Gitlab::Utils::StrongMemoize
@@ -810,16 +823,7 @@ module Gitlab
end
def clear_memoized
- clear_memoization(:issue_minimum_id)
- clear_memoization(:issue_maximum_id)
- clear_memoization(:user_minimum_id)
- clear_memoization(:user_maximum_id)
- clear_memoization(:unique_visit_service)
- clear_memoization(:deployment_minimum_id)
- clear_memoization(:deployment_maximum_id)
- clear_memoization(:project_minimum_id)
- clear_memoization(:project_maximum_id)
- clear_memoization(:auth_providers)
+ CE_MEMOIZED_VALUES.each { |v| clear_memoization(v) } # rubocop:disable UsageData/LargeTable
end
# rubocop: disable CodeReuse/ActiveRecord
diff --git a/locale/gitlab.pot b/locale/gitlab.pot
index 3e7ff0e5ee7..a1006b2c199 100644
--- a/locale/gitlab.pot
+++ b/locale/gitlab.pot
@@ -14096,6 +14096,9 @@ msgstr ""
msgid "Internal users"
msgstr ""
+msgid "Internal users cannot be deactivated"
+msgstr ""
+
msgid "Interval Pattern"
msgstr ""
diff --git a/scripts/lint-doc.sh b/scripts/lint-doc.sh
index 0ce989738df..87256269de2 100755
--- a/scripts/lint-doc.sh
+++ b/scripts/lint-doc.sh
@@ -77,7 +77,7 @@ function run_locally_or_in_docker() {
$cmd $args
elif hash docker 2>/dev/null
then
- docker run -t -v ${PWD}:/gitlab -w /gitlab --rm registry.gitlab.com/gitlab-org/gitlab-docs:lint ${cmd} ${args}
+ docker run -t -v ${PWD}:/gitlab -w /gitlab --rm registry.gitlab.com/gitlab-org/gitlab-docs/lint:latest ${cmd} ${args}
else
echo
echo " ✖ ERROR: '${cmd}' not found. Install '${cmd}' or Docker to proceed." >&2
diff --git a/spec/controllers/admin/users_controller_spec.rb b/spec/controllers/admin/users_controller_spec.rb
index 17702b00754..29064218e64 100644
--- a/spec/controllers/admin/users_controller_spec.rb
+++ b/spec/controllers/admin/users_controller_spec.rb
@@ -190,6 +190,17 @@ RSpec.describe Admin::UsersController do
expect(flash[:notice]).to eq('Error occurred. A blocked user cannot be deactivated')
end
end
+
+ context 'for an internal user' do
+ it 'does not deactivate the user' do
+ internal_user = User.alert_bot
+
+ put :deactivate, params: { id: internal_user.username }
+
+ expect(internal_user.reload.deactivated?).to be_falsey
+ expect(flash[:notice]).to eq('Internal users cannot be deactivated')
+ end
+ end
end
describe 'PUT block/:id' do
diff --git a/spec/lib/gitlab/usage_data_spec.rb b/spec/lib/gitlab/usage_data_spec.rb
index f66d0a2ea98..f269c156676 100644
--- a/spec/lib/gitlab/usage_data_spec.rb
+++ b/spec/lib/gitlab/usage_data_spec.rb
@@ -8,6 +8,7 @@ RSpec.describe Gitlab::UsageData, :aggregate_failures do
before do
stub_usage_data_connections
stub_object_store_settings
+ clear_memoized_values(described_class::CE_MEMOIZED_VALUES)
end
describe '.uncached_data' do
@@ -24,25 +25,13 @@ RSpec.describe Gitlab::UsageData, :aggregate_failures do
end
it 'clears memoized values' do
- values = %i(issue_minimum_id issue_maximum_id
- project_minimum_id project_maximum_id
- user_minimum_id user_maximum_id unique_visit_service
- deployment_minimum_id deployment_maximum_id
- auth_providers)
-
- if Gitlab.ee?
- values << %i(approval_merge_request_rule_minimum_id
- approval_merge_request_rule_maximum_id
- merge_request_minimum_id
- merge_request_maximum_id)
- values.flatten!
- end
-
- values.each do |key|
- expect(described_class).to receive(:clear_memoization).with(key)
- end
+ allow(described_class).to receive(:clear_memoization)
subject
+
+ described_class::CE_MEMOIZED_VALUES.each do |key|
+ expect(described_class).to have_received(:clear_memoization).with(key)
+ end
end
it 'merge_requests_users is included only in montly counters' do
@@ -175,8 +164,6 @@ RSpec.describe Gitlab::UsageData, :aggregate_failures do
describe 'usage_activity_by_stage_manage' do
it 'includes accurate usage_activity_by_stage data' do
- described_class.clear_memoization(:auth_providers)
-
stub_config(
omniauth:
{ providers: omniauth_providers }
@@ -1142,8 +1129,6 @@ RSpec.describe Gitlab::UsageData, :aggregate_failures do
subject { described_class.compliance_unique_visits_data }
before do
- described_class.clear_memoization(:unique_visit_service)
-
allow_next_instance_of(::Gitlab::Analytics::UniqueVisits) do |instance|
::Gitlab::Analytics::UniqueVisits.compliance_events.each do |target|
allow(instance).to receive(:unique_visits_for).with(targets: target).and_return(123)
@@ -1174,7 +1159,6 @@ RSpec.describe Gitlab::UsageData, :aggregate_failures do
subject { described_class.search_unique_visits_data }
before do
- described_class.clear_memoization(:unique_visit_service)
events = ::Gitlab::UsageDataCounters::HLLRedisCounter.events_for_category('search')
events.each do |event|
allow(::Gitlab::UsageDataCounters::HLLRedisCounter).to receive(:unique_events).with(event_names: event, start_date: 7.days.ago.to_date, end_date: Date.current).and_return(123)
diff --git a/spec/models/user_spec.rb b/spec/models/user_spec.rb
index 0dd9349b750..225aab9d4c6 100644
--- a/spec/models/user_spec.rb
+++ b/spec/models/user_spec.rb
@@ -2781,6 +2781,14 @@ RSpec.describe User do
it_behaves_like 'eligible for deactivation'
end
+
+ context 'a user who is internal' do
+ it 'returns false' do
+ internal_user = create(:user, :bot)
+
+ expect(internal_user.can_be_deactivated?).to be_falsey
+ end
+ end
end
describe "#contributed_projects" do
diff --git a/spec/requests/api/users_spec.rb b/spec/requests/api/users_spec.rb
index 1ba6b818afa..60843f368c1 100644
--- a/spec/requests/api/users_spec.rb
+++ b/spec/requests/api/users_spec.rb
@@ -2482,6 +2482,17 @@ RSpec.describe API::Users, :do_not_mock_admin_mode do
end
end
+ context 'for an internal user' do
+ it 'returns 403' do
+ internal_user = User.alert_bot
+
+ post api("/users/#{internal_user.id}/deactivate", admin)
+
+ expect(response).to have_gitlab_http_status(:forbidden)
+ expect(json_response['message']).to eq('403 Forbidden - An internal user cannot be deactivated by the API')
+ end
+ end
+
context 'for a user that does not exist' do
before do
post api("/users/0/deactivate", admin)
diff --git a/spec/support/helpers/usage_data_helpers.rb b/spec/support/helpers/usage_data_helpers.rb
index 17e806d21d9..8bb0b46f2c3 100644
--- a/spec/support/helpers/usage_data_helpers.rb
+++ b/spec/support/helpers/usage_data_helpers.rb
@@ -173,6 +173,10 @@ module UsageDataHelpers
allow(Gitlab::Prometheus::Internal).to receive(:prometheus_enabled?).and_return(false)
end
+ def clear_memoized_values(values)
+ values.each { |v| described_class.clear_memoization(v) }
+ end
+
def stub_object_store_settings
allow(Settings).to receive(:[]).with('artifacts')
.and_return(