diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2023-04-25 03:09:02 +0000 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2023-04-25 03:09:02 +0000 |
commit | 26891eec2cea8ca5e75a96a50d8785da6042cc5a (patch) | |
tree | b732a7a69a0a4cf44afa24bf9d6eddfa5c3805fd /app | |
parent | 15e5a05bcd3525dd6c046dca2682b04532ba9bd1 (diff) | |
download | gitlab-ce-26891eec2cea8ca5e75a96a50d8785da6042cc5a.tar.gz |
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'app')
-rw-r--r-- | app/assets/javascripts/profile/preferences/components/profile_preferences.vue | 4 | ||||
-rw-r--r-- | app/controllers/concerns/product_analytics_tracking.rb | 20 | ||||
-rw-r--r-- | app/controllers/concerns/redis_tracking.rb | 49 | ||||
-rw-r--r-- | app/controllers/concerns/snippets_actions.rb | 4 | ||||
-rw-r--r-- | app/controllers/concerns/wiki_actions.rb | 4 | ||||
-rw-r--r-- | app/controllers/profiles/preferences_controller.rb | 4 | ||||
-rw-r--r-- | app/controllers/projects/pipelines_controller.rb | 12 | ||||
-rw-r--r-- | app/controllers/search_controller.rb | 2 | ||||
-rw-r--r-- | app/controllers/users_controller.rb | 7 | ||||
-rw-r--r-- | app/models/user.rb | 61 | ||||
-rw-r--r-- | app/services/users/update_service.rb | 29 | ||||
-rw-r--r-- | app/views/profiles/preferences/show.html.haml | 16 | ||||
-rw-r--r-- | app/views/users/show.html.haml | 2 |
13 files changed, 123 insertions, 91 deletions
diff --git a/app/assets/javascripts/profile/preferences/components/profile_preferences.vue b/app/assets/javascripts/profile/preferences/components/profile_preferences.vue index d0d947ddd6e..164ec46cdb9 100644 --- a/app/assets/javascripts/profile/preferences/components/profile_preferences.vue +++ b/app/assets/javascripts/profile/preferences/components/profile_preferences.vue @@ -131,6 +131,10 @@ export default { :message-url="view.message_url" :config="$options.integrationViewConfigs[view.name]" /> + </div> + + <div class="col-lg-4"></div> + <div class="col-lg-8"> <hr /> </div> <div class="col-sm-12 js-hide-when-nothing-matches-search"> diff --git a/app/controllers/concerns/product_analytics_tracking.rb b/app/controllers/concerns/product_analytics_tracking.rb index fc33770b4d8..5424354b92c 100644 --- a/app/controllers/concerns/product_analytics_tracking.rb +++ b/app/controllers/concerns/product_analytics_tracking.rb @@ -2,7 +2,6 @@ module ProductAnalyticsTracking include Gitlab::Tracking::Helpers - include RedisTracking extend ActiveSupport::Concern class_methods do @@ -39,4 +38,23 @@ module ProductAnalyticsTracking **optional_arguments ) end + + def track_unique_redis_hll_event(event_name, &block) + custom_id = block ? yield(self) : nil + + unique_id = custom_id || visitor_id + + return unless unique_id + + Gitlab::UsageDataCounters::HLLRedisCounter.track_event(event_name, values: unique_id) + end + + def visitor_id + return cookies[:visitor_id] if cookies[:visitor_id].present? + return unless current_user + + uuid = SecureRandom.uuid + cookies[:visitor_id] = { value: uuid, expires: 24.months } + uuid + end end diff --git a/app/controllers/concerns/redis_tracking.rb b/app/controllers/concerns/redis_tracking.rb deleted file mode 100644 index 445e72b8266..00000000000 --- a/app/controllers/concerns/redis_tracking.rb +++ /dev/null @@ -1,49 +0,0 @@ -# frozen_string_literal: true - -# Example: -# -# # In controller include module -# # Track event for index action -# -# include RedisTracking -# -# track_redis_hll_event :index, :show, name: 'i_analytics_dev_ops_score' -# -# You can also pass custom conditions using `if:`, using the same format as with Rails callbacks. -# You can also pass an optional block that calculates and returns a custom id to track. -module RedisTracking - include Gitlab::Tracking::Helpers - extend ActiveSupport::Concern - - class_methods do - def track_redis_hll_event(*controller_actions, name:, if: nil, &block) - custom_conditions = Array.wrap(binding.local_variable_get('if')) - conditions = [:trackable_html_request?, *custom_conditions] - - after_action only: controller_actions, if: conditions do - track_unique_redis_hll_event(name, &block) - end - end - end - - private - - def track_unique_redis_hll_event(event_name, &block) - custom_id = block ? yield(self) : nil - - unique_id = custom_id || visitor_id - - return unless unique_id - - Gitlab::UsageDataCounters::HLLRedisCounter.track_event(event_name, values: unique_id) - end - - def visitor_id - return cookies[:visitor_id] if cookies[:visitor_id].present? - return unless current_user - - uuid = SecureRandom.uuid - cookies[:visitor_id] = { value: uuid, expires: 24.months } - uuid - end -end diff --git a/app/controllers/concerns/snippets_actions.rb b/app/controllers/concerns/snippets_actions.rb index 1bb81a46e50..62c5aee16e4 100644 --- a/app/controllers/concerns/snippets_actions.rb +++ b/app/controllers/concerns/snippets_actions.rb @@ -9,13 +9,13 @@ module SnippetsActions include Gitlab::NoteableMetadata include Snippets::SendBlob include SnippetsSort - include RedisTracking + include ProductAnalyticsTracking included do skip_before_action :verify_authenticity_token, if: -> { action_name == 'show' && js_request? } - track_redis_hll_event :show, name: 'i_snippets_show' + track_event :show, name: 'i_snippets_show' respond_to :html end diff --git a/app/controllers/concerns/wiki_actions.rb b/app/controllers/concerns/wiki_actions.rb index a007abacacc..265cf2a7698 100644 --- a/app/controllers/concerns/wiki_actions.rb +++ b/app/controllers/concerns/wiki_actions.rb @@ -5,7 +5,7 @@ module WikiActions include PreviewMarkdown include SendsBlob include Gitlab::Utils::StrongMemoize - include RedisTracking + include ProductAnalyticsTracking extend ActiveSupport::Concern RESCUE_GIT_TIMEOUTS_IN = %w[show edit history diff pages].freeze @@ -46,7 +46,7 @@ module WikiActions end end - track_redis_hll_event :show, name: 'wiki_action' + track_event :show, name: 'wiki_action' helper_method :view_file_button, :diff_file_html_data diff --git a/app/controllers/profiles/preferences_controller.rb b/app/controllers/profiles/preferences_controller.rb index 7786bad4251..b7e8432c039 100644 --- a/app/controllers/profiles/preferences_controller.rb +++ b/app/controllers/profiles/preferences_controller.rb @@ -37,7 +37,7 @@ class Profiles::PreferencesController < Profiles::ApplicationController end def preferences_param_names - [ + preferences_param_names = [ :color_scheme_id, :diffs_deletion_color, :diffs_addition_color, @@ -60,6 +60,8 @@ class Profiles::PreferencesController < Profiles::ApplicationController :use_legacy_web_ide, :use_new_navigation ] + preferences_param_names << :enabled_following if ::Feature.enabled?(:disable_follow_users, user) + preferences_param_names end end diff --git a/app/controllers/projects/pipelines_controller.rb b/app/controllers/projects/pipelines_controller.rb index a8107a46b4f..30f582f90a5 100644 --- a/app/controllers/projects/pipelines_controller.rb +++ b/app/controllers/projects/pipelines_controller.rb @@ -2,7 +2,7 @@ class Projects::PipelinesController < Projects::ApplicationController include ::Gitlab::Utils::StrongMemoize - include RedisTracking + include ProductAnalyticsTracking include ProductAnalyticsTracking include ProjectStatsRefreshConflictsGuard @@ -34,11 +34,11 @@ class Projects::PipelinesController < Projects::ApplicationController label: 'redis_hll_counters.analytics.analytics_total_unique_counts_monthly', destinations: %i[redis_hll snowplow] - track_redis_hll_event :charts, name: 'p_analytics_ci_cd_pipelines', if: -> { should_track_ci_cd_pipelines? } - track_redis_hll_event :charts, name: 'p_analytics_ci_cd_deployment_frequency', if: -> { should_track_ci_cd_deployment_frequency? } - track_redis_hll_event :charts, name: 'p_analytics_ci_cd_lead_time', if: -> { should_track_ci_cd_lead_time? } - track_redis_hll_event :charts, name: 'p_analytics_ci_cd_time_to_restore_service', if: -> { should_track_ci_cd_time_to_restore_service? } - track_redis_hll_event :charts, name: 'p_analytics_ci_cd_change_failure_rate', if: -> { should_track_ci_cd_change_failure_rate? } + track_event :charts, name: 'p_analytics_ci_cd_pipelines', conditions: -> { should_track_ci_cd_pipelines? } + track_event :charts, name: 'p_analytics_ci_cd_deployment_frequency', conditions: -> { should_track_ci_cd_deployment_frequency? } + track_event :charts, name: 'p_analytics_ci_cd_lead_time', conditions: -> { should_track_ci_cd_lead_time? } + track_event :charts, name: 'p_analytics_ci_cd_time_to_restore_service', conditions: -> { should_track_ci_cd_time_to_restore_service? } + track_event :charts, name: 'p_analytics_ci_cd_change_failure_rate', conditions: -> { should_track_ci_cd_change_failure_rate? } wrap_parameters Ci::Pipeline diff --git a/app/controllers/search_controller.rb b/app/controllers/search_controller.rb index 688c56e56e0..a3c6499bc54 100644 --- a/app/controllers/search_controller.rb +++ b/app/controllers/search_controller.rb @@ -3,7 +3,7 @@ class SearchController < ApplicationController include ControllerWithCrossProjectAccessCheck include SearchHelper - include RedisTracking + include ProductAnalyticsTracking include ProductAnalyticsTracking include SearchRateLimitable diff --git a/app/controllers/users_controller.rb b/app/controllers/users_controller.rb index e4354eaa452..02b29d42313 100644 --- a/app/controllers/users_controller.rb +++ b/app/controllers/users_controller.rb @@ -191,7 +191,12 @@ class UsersController < ApplicationController def follow followee = current_user.follow(user) - flash[:alert] = followee.errors.full_messages.join(', ') if followee&.errors&.any? + if followee + flash[:alert] = followee.errors.full_messages.join(', ') if followee&.errors&.any? + else + flash[:alert] = s_('Action not allowed.') + end + redirect_path = referer_path(request) || @user redirect_to redirect_path diff --git a/app/models/user.rb b/app/models/user.rb index 0aa509e58d7..cb1fbd97a00 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -349,29 +349,30 @@ class User < ApplicationRecord # User's role enum role: { software_developer: 0, development_team_lead: 1, devops_engineer: 2, systems_administrator: 3, security_analyst: 4, data_analyst: 5, product_manager: 6, product_designer: 7, other: 8 }, _suffix: true - delegate :notes_filter_for, - :set_notes_filter, - :first_day_of_week, :first_day_of_week=, - :timezone, :timezone=, - :time_display_relative, :time_display_relative=, - :time_format_in_24h, :time_format_in_24h=, - :show_whitespace_in_diffs, :show_whitespace_in_diffs=, - :view_diffs_file_by_file, :view_diffs_file_by_file=, - :pass_user_identities_to_ci_jwt, :pass_user_identities_to_ci_jwt=, - :tab_width, :tab_width=, - :sourcegraph_enabled, :sourcegraph_enabled=, - :gitpod_enabled, :gitpod_enabled=, - :setup_for_company, :setup_for_company=, - :render_whitespace_in_code, :render_whitespace_in_code=, - :markdown_surround_selection, :markdown_surround_selection=, - :markdown_automatic_lists, :markdown_automatic_lists=, - :diffs_deletion_color, :diffs_deletion_color=, - :diffs_addition_color, :diffs_addition_color=, - :use_legacy_web_ide, :use_legacy_web_ide=, - :use_new_navigation, :use_new_navigation=, - :pinned_nav_items, :pinned_nav_items=, - :achievements_enabled, :achievements_enabled=, - to: :user_preference + delegate :notes_filter_for, + :set_notes_filter, + :first_day_of_week, :first_day_of_week=, + :timezone, :timezone=, + :time_display_relative, :time_display_relative=, + :time_format_in_24h, :time_format_in_24h=, + :show_whitespace_in_diffs, :show_whitespace_in_diffs=, + :view_diffs_file_by_file, :view_diffs_file_by_file=, + :pass_user_identities_to_ci_jwt, :pass_user_identities_to_ci_jwt=, + :tab_width, :tab_width=, + :sourcegraph_enabled, :sourcegraph_enabled=, + :gitpod_enabled, :gitpod_enabled=, + :setup_for_company, :setup_for_company=, + :render_whitespace_in_code, :render_whitespace_in_code=, + :markdown_surround_selection, :markdown_surround_selection=, + :markdown_automatic_lists, :markdown_automatic_lists=, + :diffs_deletion_color, :diffs_deletion_color=, + :diffs_addition_color, :diffs_addition_color=, + :use_legacy_web_ide, :use_legacy_web_ide=, + :use_new_navigation, :use_new_navigation=, + :pinned_nav_items, :pinned_nav_items=, + :achievements_enabled, :achievements_enabled=, + :enabled_following, :enabled_following=, + to: :user_preference delegate :path, to: :namespace, allow_nil: true, prefix: true delegate :job_title, :job_title=, to: :user_detail, allow_nil: true @@ -1694,7 +1695,7 @@ class User < ApplicationRecord end def follow(user) - return false if self.id == user.id + return false unless following_users_allowed?(user) begin followee = Users::UserFollowUser.create(follower_id: self.id, followee_id: user.id) @@ -1713,6 +1714,18 @@ class User < ApplicationRecord end end + def following_users_allowed?(user) + return false if self.id == user.id + + following_users_enabled? && user.following_users_enabled? + end + + def following_users_enabled? + return true unless ::Feature.enabled?(:disable_follow_users, self) + + enabled_following + end + def forkable_namespaces strong_memoize(:forkable_namespaces) do personal_namespace = Namespace.where(id: namespace_id) diff --git a/app/services/users/update_service.rb b/app/services/users/update_service.rb index 96018db5974..36c41c03303 100644 --- a/app/services/users/update_service.rb +++ b/app/services/users/update_service.rb @@ -6,6 +6,7 @@ module Users attr_reader :user, :identity_params ATTRS_REQUIRING_PASSWORD_CHECK = %w[email].freeze + BATCH_SIZE = 100 def initialize(current_user, params = {}) @current_user = current_user @@ -34,7 +35,7 @@ module Users reset_unconfirmed_email if @user.save(validate: validate) && update_status - notify_success(user_exists) + after_update(user_exists) else messages = @user.errors.full_messages + Array(@user.status&.errors&.full_messages) error(messages.uniq.join('. ')) @@ -80,8 +81,6 @@ module Users def notify_success(user_exists) notify_new_user(@user, nil) unless user_exists - - success end def discard_read_only_attributes @@ -118,6 +117,30 @@ module Users def provider_params identity_params.slice(*provider_attributes) end + + def after_update(user_exists) + notify_success(user_exists) + remove_followers_and_followee! if ::Feature.enabled?(:disable_follow_users, user) + + success + end + + def remove_followers_and_followee! + return false unless user.user_preference.enabled_following_previously_changed?(from: true, to: false) + + # rubocop: disable CodeReuse/ActiveRecord + loop do + inner_query = Users::UserFollowUser + .where(follower_id: user.id).or(Users::UserFollowUser.where(followee_id: user.id)) + .select(:follower_id, :followee_id) + .limit(BATCH_SIZE) + + deleted_records = Users::UserFollowUser.where('(follower_id, followee_id) IN (?)', inner_query).delete_all + + break if deleted_records == 0 + end + # rubocop: enable CodeReuse/ActiveRecord + end end end diff --git a/app/views/profiles/preferences/show.html.haml b/app/views/profiles/preferences/show.html.haml index c16469bbf79..8fb66cb3cd9 100644 --- a/app/views/profiles/preferences/show.html.haml +++ b/app/views/profiles/preferences/show.html.haml @@ -170,5 +170,21 @@ - if Feature.enabled?(:user_time_settings) .form-group = f.gitlab_ui_checkbox_component :time_format_in_24h, s_('Preferences|Display time in 24-hour format') + - if Feature.enabled?(:disable_follow_users, @user) + .row.js-preferences-form.js-search-settings-section + .col-sm-12 + %hr + .col-lg-4.profile-settings-sidebar#disabled_following + %h4.gl-mt-0 + = s_('Preferences|Disable follow users feature') + %p + = s_('Preferences|Turns off the ability to follow or be followed by other users.') + = succeed '.' do + = link_to _('Learn more'), help_page_path('user/profile/index', anchor: 'follow-users'), target: '_blank', rel: 'noopener noreferrer' + .col-lg-8 + .form-group + = f.gitlab_ui_checkbox_component :enabled_following, + s_('Preferences|Disable follow users') + #js-profile-preferences-app{ data: data_attributes } diff --git a/app/views/users/show.html.haml b/app/views/users/show.html.haml index 70dccc4821b..e26b4de7b20 100644 --- a/app/views/users/show.html.haml +++ b/app/views/users/show.html.haml @@ -36,7 +36,7 @@ = render Pajamas::ButtonComponent.new(href: [:admin, @user], icon: 'user', button_options: { class: 'gl-flex-grow-1 gl-mx-1 has-tooltip', title: s_('UserProfile|View user in admin area'), data: {toggle: 'tooltip', placement: 'bottom', container: 'body'}}) - - if current_user && current_user.id != @user.id + - if current_user && current_user.following_users_allowed?(@user) - if current_user.following?(@user) = form_tag user_unfollow_path(@user, :json), class: link_classes + 'gl-display-inline-block' do = render Pajamas::ButtonComponent.new(type: :submit, button_options: { class: 'gl-w-full', data: { track_action: 'click_button', track_label: 'unfollow_from_profile' } }) do |