From ba2104b9cafdad1a91fb8c6d5d77e9e0f9f34b75 Mon Sep 17 00:00:00 2001 From: Raimund Hook <rhook@gitlab.com> Date: Thu, 28 Sep 2023 14:46:14 +0100 Subject: [PATCH 1/7] Add support for Mastodon as user social This change adds support for adding a link to a Mastodon social network user Signed-off-by: Raimund Hook <rhook@gitlab.com> Changelog: added --- .../stylesheets/framework/variables.scss | 1 + .../stylesheets/page_bundles/profile.scss | 4 ++++ app/controllers/admin/users_controller.rb | 3 ++- app/controllers/profiles_controller.rb | 3 ++- app/helpers/application_helper.rb | 8 +++++++ app/models/user.rb | 1 + app/models/user_detail.rb | 11 ++++++++- app/views/profiles/show.html.haml | 3 +++ app/views/users/show.html.haml | 4 ++++ ...0927124202_add_mastodon_to_user_details.rb | 23 +++++++++++++++++++ db/schema_migrations/20230927124202 | 1 + db/structure.sql | 2 ++ doc/user/profile/index.md | 1 + locale/gitlab.pot | 6 +++++ spec/controllers/profiles_controller_spec.rb | 10 ++++++++ spec/helpers/application_helper_spec.rb | 15 ++++++++++++ spec/models/user_detail_spec.rb | 23 +++++++++++++++++++ spec/models/user_spec.rb | 3 +++ 18 files changed, 119 insertions(+), 3 deletions(-) create mode 100644 db/migrate/20230927124202_add_mastodon_to_user_details.rb create mode 100644 db/schema_migrations/20230927124202 diff --git a/app/assets/stylesheets/framework/variables.scss b/app/assets/stylesheets/framework/variables.scss index a4bb39e0764d235f..31d45ad3a28559f6 100644 --- a/app/assets/stylesheets/framework/variables.scss +++ b/app/assets/stylesheets/framework/variables.scss @@ -655,6 +655,7 @@ $status-icon-size: 22px; */ $discord: #5865f2; $linkedin: #2867b2; +$mastodon: #6364ff; $skype: #0078d7; $twitter: #1d9bf0; diff --git a/app/assets/stylesheets/page_bundles/profile.scss b/app/assets/stylesheets/page_bundles/profile.scss index dbe82f583d1e898a..6b31c6678323f90d 100644 --- a/app/assets/stylesheets/page_bundles/profile.scss +++ b/app/assets/stylesheets/page_bundles/profile.scss @@ -242,6 +242,10 @@ color: $discord; } +.mastodon-icon { + color: $mastodon; +} + .key-created-at { line-height: 42px; } diff --git a/app/controllers/admin/users_controller.rb b/app/controllers/admin/users_controller.rb index 1f05e4e7b21c267a..50e0c5cc5ffedabd 100644 --- a/app/controllers/admin/users_controller.rb +++ b/app/controllers/admin/users_controller.rb @@ -342,6 +342,7 @@ def allowed_user_params :bio, :can_create_group, :color_scheme_id, + :discord, :email, :extern_uid, :external, @@ -350,6 +351,7 @@ def allowed_user_params :hide_no_ssh_key, :key_id, :linkedin, + :mastodon, :name, :password_expires_at, :projects_limit, @@ -358,7 +360,6 @@ def allowed_user_params :skype, :theme_id, :twitter, - :discord, :username, :website_url, :note, diff --git a/app/controllers/profiles_controller.rb b/app/controllers/profiles_controller.rb index da15b393e6c9bade..cb29f0f35392ca02 100644 --- a/app/controllers/profiles_controller.rb +++ b/app/controllers/profiles_controller.rb @@ -111,6 +111,7 @@ def user_params_attributes [ :avatar, :bio, + :discord, :email, :role, :gitpod_enabled, @@ -119,12 +120,12 @@ def user_params_attributes :hide_project_limit, :linkedin, :location, + :mastodon, :name, :public_email, :commit_email, :skype, :twitter, - :discord, :username, :website_url, :organization, diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb index 579373539558c01b..60c77e14a5554319 100644 --- a/app/helpers/application_helper.rb +++ b/app/helpers/application_helper.rb @@ -371,6 +371,14 @@ def discord_url(user) "https://discord.com/users/#{user.discord}" end + def mastodon_url(user) + return '' if user.mastodon.blank? + + url = user.mastodon.match %r{\A@?\b([\w\d.%+-]+)@([\w\d.-]+\.\w{2,})\b\z} + + "https://#{url[2]}/@#{url[1]}" + end + def collapsed_sidebar? cookies["sidebar_collapsed"] == "true" end diff --git a/app/models/user.rb b/app/models/user.rb index 4034677509f82500..74a09c966f725ad2 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -417,6 +417,7 @@ def update_tracked_fields!(request) delegate :pronouns, :pronouns=, to: :user_detail, allow_nil: true delegate :pronunciation, :pronunciation=, to: :user_detail, allow_nil: true delegate :registration_objective, :registration_objective=, to: :user_detail, allow_nil: true + delegate :mastodon, :mastodon=, to: :user_detail, allow_nil: true delegate :linkedin, :linkedin=, to: :user_detail, allow_nil: true delegate :twitter, :twitter=, to: :user_detail, allow_nil: true delegate :skype, :skype=, to: :user_detail, allow_nil: true diff --git a/app/models/user_detail.rb b/app/models/user_detail.rb index 9ac814eebdabd31e..fcf10adae6f67bed 100644 --- a/app/models/user_detail.rb +++ b/app/models/user_detail.rb @@ -21,6 +21,8 @@ class UserDetail < MainClusterwide::ApplicationRecord validate :discord_format validates :linkedin, length: { maximum: DEFAULT_FIELD_LENGTH }, allow_blank: true validates :location, length: { maximum: DEFAULT_FIELD_LENGTH }, allow_blank: true + validates :mastodon, length: { maximum: DEFAULT_FIELD_LENGTH }, allow_blank: true + validate :mastodon_format validates :organization, length: { maximum: DEFAULT_FIELD_LENGTH }, allow_blank: true validates :skype, length: { maximum: DEFAULT_FIELD_LENGTH }, allow_blank: true validates :twitter, length: { maximum: DEFAULT_FIELD_LENGTH }, allow_blank: true @@ -32,7 +34,7 @@ class UserDetail < MainClusterwide::ApplicationRecord enum registration_objective: REGISTRATION_OBJECTIVE_PAIRS, _suffix: true def sanitize_attrs - %i[discord linkedin skype twitter website_url].each do |attr| + %i[discord linkedin mastodon skype twitter website_url].each do |attr| value = self[attr] self[attr] = Sanitize.clean(value) if value.present? end @@ -49,6 +51,7 @@ def prevent_nil_fields self.discord = '' if discord.nil? self.linkedin = '' if linkedin.nil? self.location = '' if location.nil? + self.mastodon = '' if mastodon.nil? self.organization = '' if organization.nil? self.skype = '' if skype.nil? self.twitter = '' if twitter.nil? @@ -62,4 +65,10 @@ def discord_format errors.add(:discord, _('must contain only a discord user ID.')) end +def mastodon_format + return if mastodon.blank? || mastodon =~ %r{\A@?\b([\w\d.%+-]+)@([\w\d.-]+\.\w{2,})\b\z} + + errors.add(:mastodon, _('must contain only a mastodon username.')) +end + UserDetail.prepend_mod_with('UserDetail') diff --git a/app/views/profiles/show.html.haml b/app/views/profiles/show.html.haml index 4da48771ba341a5c..6ff7583e736d384f 100644 --- a/app/views/profiles/show.html.haml +++ b/app/views/profiles/show.html.haml @@ -122,6 +122,9 @@ allow_empty: true} %small.form-text.text-gl-muted = external_accounts_docs_link + .form-group.gl-form-group + = f.label :mastodon + = f.text_field :mastodon, class: 'gl-form-input form-control gl-md-form-input-lg', placeholder: s_("Profiles|@robin@example.com") .form-group.gl-form-group = f.label :website_url, s_('Profiles|Website url') diff --git a/app/views/users/show.html.haml b/app/views/users/show.html.haml index 0881c5bba5430a50..13c5f73d96024bd1 100644 --- a/app/views/users/show.html.haml +++ b/app/views/users/show.html.haml @@ -111,6 +111,10 @@ = render 'middle_dot_divider', breakpoint: 'sm' do = link_to discord_url(@user), class: 'gl-hover-text-decoration-none', title: "Discord", target: '_blank', rel: 'noopener noreferrer nofollow' do = sprite_icon('discord', css_class: 'discord-icon') + - if @user.mastodon.present? + = render 'middle_dot_divider', breakpoint: 'sm' do + = link_to mastodon_url(@user), class: 'gl-hover-text-decoration-none', title: "Mastodon", target: '_blank', rel: 'noopener noreferrer nofollow' do + = sprite_icon('mastodon', css_class: 'mastodon-icon') - if @user.website_url.present? = render 'middle_dot_divider', stacking: true do - if Feature.enabled?(:security_auto_fix) && @user.bot? diff --git a/db/migrate/20230927124202_add_mastodon_to_user_details.rb b/db/migrate/20230927124202_add_mastodon_to_user_details.rb new file mode 100644 index 0000000000000000..b23fd21837954be2 --- /dev/null +++ b/db/migrate/20230927124202_add_mastodon_to_user_details.rb @@ -0,0 +1,23 @@ +# frozen_string_literal: true + +class AddMastodonToUserDetails < Gitlab::Database::Migration[2.1] + disable_ddl_transaction! + + USER_DETAILS_FIELD_LIMIT = 500 + + def up + with_lock_retries do + add_column :user_details, :mastodon, :text, default: '', null: false + end + + add_text_limit :user_details, :mastodon, USER_DETAILS_FIELD_LIMIT + end + + def down + remove_text_limit :user_details, :mastodon + + with_lock_retries do + remove_column :user_details, :mastodon + end + end +end diff --git a/db/schema_migrations/20230927124202 b/db/schema_migrations/20230927124202 new file mode 100644 index 0000000000000000..a4089994e9799c7c --- /dev/null +++ b/db/schema_migrations/20230927124202 @@ -0,0 +1 @@ +652375e6b7318fe85b4b23eac3cce88618136341cee7721522adacbe52a52c66 \ No newline at end of file diff --git a/db/structure.sql b/db/structure.sql index d7d5d469d9eb12a7..6a9cdb508214152b 100644 --- a/db/structure.sql +++ b/db/structure.sql @@ -24088,6 +24088,7 @@ CREATE TABLE user_details ( enterprise_group_id bigint, enterprise_group_associated_at timestamp with time zone, email_reset_offered_at timestamp with time zone, + mastodon text DEFAULT ''::text NOT NULL, CONSTRAINT check_245664af82 CHECK ((char_length(webauthn_xid) <= 100)), CONSTRAINT check_444573ee52 CHECK ((char_length(skype) <= 500)), CONSTRAINT check_466a25be35 CHECK ((char_length(twitter) <= 500)), @@ -24099,6 +24100,7 @@ CREATE TABLE user_details ( CONSTRAINT check_8a7fcf8a60 CHECK ((char_length(location) <= 500)), CONSTRAINT check_a73b398c60 CHECK ((char_length(phone) <= 50)), CONSTRAINT check_eeeaf8d4f0 CHECK ((char_length(pronouns) <= 50)), + CONSTRAINT check_f1a8a05b9a CHECK ((char_length(mastodon) <= 500)), CONSTRAINT check_f932ed37db CHECK ((char_length(pronunciation) <= 255)) ); diff --git a/doc/user/profile/index.md b/doc/user/profile/index.md index 6536a992292e4fe0..76b454f164381d2c 100644 --- a/doc/user/profile/index.md +++ b/doc/user/profile/index.md @@ -138,6 +138,7 @@ To add links to other accounts: 1. In the **Main settings** section, add your: - Discord [user ID](https://support.discord.com/hc/en-us/articles/206346498-Where-can-I-find-my-User-Server-Message-ID-). - LinkedIn profile name. + - Mastodon username. - Skype username. - Twitter @username. diff --git a/locale/gitlab.pot b/locale/gitlab.pot index f4e362f05d15f8a2..ca11ea53c0668c86 100644 --- a/locale/gitlab.pot +++ b/locale/gitlab.pot @@ -36207,6 +36207,9 @@ msgstr "" msgid "Profiles|%{provider} Active" msgstr "" +msgid "Profiles|@robin@example.com" +msgstr "" + msgid "Profiles|@username" msgstr "" @@ -57148,6 +57151,9 @@ msgstr "" msgid "must contain only a discord user ID." msgstr "" +msgid "must contain only a mastodon username." +msgstr "" + msgid "must have a repository" msgstr "" diff --git a/spec/controllers/profiles_controller_spec.rb b/spec/controllers/profiles_controller_spec.rb index 2bcb47f97ab00a25..4f350ddf1ef4da4a 100644 --- a/spec/controllers/profiles_controller_spec.rb +++ b/spec/controllers/profiles_controller_spec.rb @@ -128,6 +128,16 @@ expect(user.reload.discord).to eq(discord_user_id) expect(response).to have_gitlab_http_status(:found) end + + it 'allows updating user specified mastodon username', :aggregate_failures do + mastodon_username = '@robin@example.com' + sign_in(user) + + put :update, params: { user: { mastodon: mastodon_username } } + + expect(user.reload.mastodon).to eq(mastodon_username) + expect(response).to have_gitlab_http_status(:found) + end end describe 'GET audit_log' do diff --git a/spec/helpers/application_helper_spec.rb b/spec/helpers/application_helper_spec.rb index 7cf64c6e049befd7..3e95cb25b1208f9c 100644 --- a/spec/helpers/application_helper_spec.rb +++ b/spec/helpers/application_helper_spec.rb @@ -637,6 +637,21 @@ def stub_controller_method(method_name, value) expect(discord).to eq('https://discord.com/users/1234567890123456789') end end + + context 'when mastodon is set' do + let_it_be(:user) { build(:user) } + let(:mastodon) { mastodon_url(user) } + + it 'returns an empty string if mastodon username is not set' do + expect(mastodon).to eq('') + end + + it 'returns mastodon url when mastodon username is set' do + user.mastodon = '@robin@example.com' + + expect(mastodon).to eq('https://example.com/@robin') + end + end end describe '#gitlab_ui_form_for' do diff --git a/spec/models/user_detail_spec.rb b/spec/models/user_detail_spec.rb index 428fd5470c3127e3..58f4322f21f1dc24 100644 --- a/spec/models/user_detail_spec.rb +++ b/spec/models/user_detail_spec.rb @@ -59,6 +59,27 @@ end end + describe '#mastodon' do + it { is_expected.to validate_length_of(:mastodon).is_at_most(500) } + + context 'when discord is set' do + let_it_be(:user_detail) { create(:user_detail) } + + it 'accepts a valid mastodon username' do + user_detail.mastodon = '@robin@example.com' + + expect(user_detail).to be_valid + end + + it 'throws an error when mastodon username format is wrong' do + user_detail.mastodon = '@robin' + + expect(user_detail).not_to be_valid + expect(user_detail.errors.full_messages).to match_array([_('Mastodon must contain only a mastodon username.')]) + end + end + end + describe '#location' do it { is_expected.to validate_length_of(:location).is_at_most(500) } end @@ -97,6 +118,7 @@ discord: '1234567890123456789', linkedin: 'linkedin', location: 'location', + mastodon: '@robin@example.com', organization: 'organization', skype: 'skype', twitter: 'twitter', @@ -117,6 +139,7 @@ it_behaves_like 'prevents `nil` value', :discord it_behaves_like 'prevents `nil` value', :linkedin it_behaves_like 'prevents `nil` value', :location + it_behaves_like 'prevents `nil` value', :mastodon it_behaves_like 'prevents `nil` value', :organization it_behaves_like 'prevents `nil` value', :skype it_behaves_like 'prevents `nil` value', :twitter diff --git a/spec/models/user_spec.rb b/spec/models/user_spec.rb index 947d83badf636531..c9da1a31c8686e51 100644 --- a/spec/models/user_spec.rb +++ b/spec/models/user_spec.rb @@ -113,6 +113,9 @@ it { is_expected.to delegate_method(:linkedin).to(:user_detail).allow_nil } it { is_expected.to delegate_method(:linkedin=).to(:user_detail).with_arguments(:args).allow_nil } + it { is_expected.to delegate_method(:mastodon).to(:user_detail).allow_nil } + it { is_expected.to delegate_method(:mastodon=).to(:user_detail).with_arguments(:args).allow_nil } + it { is_expected.to delegate_method(:twitter).to(:user_detail).allow_nil } it { is_expected.to delegate_method(:twitter=).to(:user_detail).with_arguments(:args).allow_nil } -- GitLab From 2fac622ff3567e815f9d5b27372f5d9fcfe96f33 Mon Sep 17 00:00:00 2001 From: Raimund Hook <rhook@gitlab.com> Date: Wed, 11 Oct 2023 16:40:06 +0100 Subject: [PATCH 2/7] Updates from review Signed-off-by: Raimund Hook <rhook@gitlab.com> --- app/views/profiles/show.html.haml | 2 +- app/views/users/show.html.haml | 3 ++- db/migrate/20230927124202_add_mastodon_to_user_details.rb | 4 +--- locale/gitlab.pot | 3 --- 4 files changed, 4 insertions(+), 8 deletions(-) diff --git a/app/views/profiles/show.html.haml b/app/views/profiles/show.html.haml index 6ff7583e736d384f..b50a454df72baf51 100644 --- a/app/views/profiles/show.html.haml +++ b/app/views/profiles/show.html.haml @@ -124,7 +124,7 @@ = external_accounts_docs_link .form-group.gl-form-group = f.label :mastodon - = f.text_field :mastodon, class: 'gl-form-input form-control gl-md-form-input-lg', placeholder: s_("Profiles|@robin@example.com") + = f.text_field :mastodon, class: 'gl-form-input form-control gl-md-form-input-lg', placeholder: "@robin@example.com" .form-group.gl-form-group = f.label :website_url, s_('Profiles|Website url') diff --git a/app/views/users/show.html.haml b/app/views/users/show.html.haml index 13c5f73d96024bd1..ddde0f17d16729e5 100644 --- a/app/views/users/show.html.haml +++ b/app/views/users/show.html.haml @@ -113,8 +113,9 @@ = sprite_icon('discord', css_class: 'discord-icon') - if @user.mastodon.present? = render 'middle_dot_divider', breakpoint: 'sm' do + = sprite_icon('mastodon', css_class: 'mastodon-icon') = link_to mastodon_url(@user), class: 'gl-hover-text-decoration-none', title: "Mastodon", target: '_blank', rel: 'noopener noreferrer nofollow' do - = sprite_icon('mastodon', css_class: 'mastodon-icon') + = mastodon_url(@user).gsub('https://', '') - if @user.website_url.present? = render 'middle_dot_divider', stacking: true do - if Feature.enabled?(:security_auto_fix) && @user.bot? diff --git a/db/migrate/20230927124202_add_mastodon_to_user_details.rb b/db/migrate/20230927124202_add_mastodon_to_user_details.rb index b23fd21837954be2..a1aa099087b98c51 100644 --- a/db/migrate/20230927124202_add_mastodon_to_user_details.rb +++ b/db/migrate/20230927124202_add_mastodon_to_user_details.rb @@ -7,15 +7,13 @@ class AddMastodonToUserDetails < Gitlab::Database::Migration[2.1] def up with_lock_retries do - add_column :user_details, :mastodon, :text, default: '', null: false + add_column :user_details, :mastodon, :text, default: '', null: false, if_not_exists: true end add_text_limit :user_details, :mastodon, USER_DETAILS_FIELD_LIMIT end def down - remove_text_limit :user_details, :mastodon - with_lock_retries do remove_column :user_details, :mastodon end diff --git a/locale/gitlab.pot b/locale/gitlab.pot index ca11ea53c0668c86..9c223a5381cceaa2 100644 --- a/locale/gitlab.pot +++ b/locale/gitlab.pot @@ -36207,9 +36207,6 @@ msgstr "" msgid "Profiles|%{provider} Active" msgstr "" -msgid "Profiles|@robin@example.com" -msgstr "" - msgid "Profiles|@username" msgstr "" -- GitLab From cf34663fc8d7f34b5b316906084c28d44583ac27 Mon Sep 17 00:00:00 2001 From: Raimund Hook <rhook@gitlab.com> Date: Fri, 13 Oct 2023 15:56:47 +0100 Subject: [PATCH 3/7] Added FF for UI elements with user actor Signed-off-by: Raimund Hook <rhook@gitlab.com> --- app/views/profiles/show.html.haml | 7 ++++--- app/views/users/show.html.haml | 5 ++--- config/feature_flags/development/mastodon_social_ui.yml | 8 ++++++++ 3 files changed, 14 insertions(+), 6 deletions(-) create mode 100644 config/feature_flags/development/mastodon_social_ui.yml diff --git a/app/views/profiles/show.html.haml b/app/views/profiles/show.html.haml index b50a454df72baf51..002953b165831c64 100644 --- a/app/views/profiles/show.html.haml +++ b/app/views/profiles/show.html.haml @@ -122,9 +122,10 @@ allow_empty: true} %small.form-text.text-gl-muted = external_accounts_docs_link - .form-group.gl-form-group - = f.label :mastodon - = f.text_field :mastodon, class: 'gl-form-input form-control gl-md-form-input-lg', placeholder: "@robin@example.com" + - if Feature.enabled?(:mastodon_social_ui, @user) + .form-group.gl-form-group + = f.label :mastodon + = f.text_field :mastodon, class: 'gl-form-input form-control gl-md-form-input-lg', placeholder: "@robin@example.com" .form-group.gl-form-group = f.label :website_url, s_('Profiles|Website url') diff --git a/app/views/users/show.html.haml b/app/views/users/show.html.haml index ddde0f17d16729e5..29360dc7c9484d21 100644 --- a/app/views/users/show.html.haml +++ b/app/views/users/show.html.haml @@ -111,11 +111,10 @@ = render 'middle_dot_divider', breakpoint: 'sm' do = link_to discord_url(@user), class: 'gl-hover-text-decoration-none', title: "Discord", target: '_blank', rel: 'noopener noreferrer nofollow' do = sprite_icon('discord', css_class: 'discord-icon') - - if @user.mastodon.present? + - if Feature.enabled?(:mastodon_social_ui, @user) && @user.mastodon.present? = render 'middle_dot_divider', breakpoint: 'sm' do - = sprite_icon('mastodon', css_class: 'mastodon-icon') = link_to mastodon_url(@user), class: 'gl-hover-text-decoration-none', title: "Mastodon", target: '_blank', rel: 'noopener noreferrer nofollow' do - = mastodon_url(@user).gsub('https://', '') + = sprite_icon('mastodon', css_class: 'mastodon-icon') - if @user.website_url.present? = render 'middle_dot_divider', stacking: true do - if Feature.enabled?(:security_auto_fix) && @user.bot? diff --git a/config/feature_flags/development/mastodon_social_ui.yml b/config/feature_flags/development/mastodon_social_ui.yml new file mode 100644 index 0000000000000000..5e04d8176e4924d1 --- /dev/null +++ b/config/feature_flags/development/mastodon_social_ui.yml @@ -0,0 +1,8 @@ +--- +name: mastodon_social_ui +introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/132892 +rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/428163 +milestone: '16.5' +type: development +group: group::tenant scale +default_enabled: false -- GitLab From f97d421bb0c8ecda1386df7af6e42d246e17aa40 Mon Sep 17 00:00:00 2001 From: Raimund Hook <rhook@gitlab.com> Date: Fri, 13 Oct 2023 16:06:55 +0100 Subject: [PATCH 4/7] Update doc message with an 'introduced' blurb Signed-off-by: Raimund Hook <rhook@gitlab.com> --- doc/user/profile/index.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/doc/user/profile/index.md b/doc/user/profile/index.md index 76b454f164381d2c..183a1bc599d89aac 100644 --- a/doc/user/profile/index.md +++ b/doc/user/profile/index.md @@ -128,6 +128,8 @@ to match your username. ## Add external accounts to your user profile page +> Mastodon user account [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/132892) as a beta feature in 16.5 [with a flag](../feature_flags.md) named `mastodon_social_ui`. Disabled by default. + You can add links to certain other external accounts you might have, like Skype and Twitter. They can help other users connect with you on other platforms. -- GitLab From 97fcf10989aa0031cff57c3b4847ac11519e6136 Mon Sep 17 00:00:00 2001 From: Niklas <mc.taucher2003@gmail.com> Date: Tue, 17 Oct 2023 09:23:35 +0000 Subject: [PATCH 5/7] Apply 1 suggestion(s) to 1 file(s) --- spec/models/user_detail_spec.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/models/user_detail_spec.rb b/spec/models/user_detail_spec.rb index 58f4322f21f1dc24..b443988cde9aa200 100644 --- a/spec/models/user_detail_spec.rb +++ b/spec/models/user_detail_spec.rb @@ -62,7 +62,7 @@ describe '#mastodon' do it { is_expected.to validate_length_of(:mastodon).is_at_most(500) } - context 'when discord is set' do + context 'when mastodon is set' do let_it_be(:user_detail) { create(:user_detail) } it 'accepts a valid mastodon username' do -- GitLab From 5050e772b91c7b9599a7d286363cf554bda4ba67 Mon Sep 17 00:00:00 2001 From: Jon Glassman <jglassman@gitlab.com> Date: Tue, 17 Oct 2023 11:50:06 +0000 Subject: [PATCH 6/7] Apply 1 suggestion(s) to 1 file(s) --- doc/user/profile/index.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/user/profile/index.md b/doc/user/profile/index.md index 183a1bc599d89aac..fea9bc491cf9a4b7 100644 --- a/doc/user/profile/index.md +++ b/doc/user/profile/index.md @@ -128,7 +128,7 @@ to match your username. ## Add external accounts to your user profile page -> Mastodon user account [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/132892) as a beta feature in 16.5 [with a flag](../feature_flags.md) named `mastodon_social_ui`. Disabled by default. +> Mastodon user account [introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/132892) as a beta feature in 16.5 [with a flag](../feature_flags.md) named `mastodon_social_ui`. Disabled by default. You can add links to certain other external accounts you might have, like Skype and Twitter. They can help other users connect with you on other platforms. -- GitLab From fb2df5c629879dbbe2d6ab9209b352cf6b2da706 Mon Sep 17 00:00:00 2001 From: Raimund Hook <rhook@gitlab.com> Date: Wed, 18 Oct 2023 18:52:11 +0100 Subject: [PATCH 7/7] Extract regex into constant Signed-off-by: Raimund Hook <rhook@gitlab.com> --- app/helpers/application_helper.rb | 2 +- app/models/user_detail.rb | 14 +++++++++++++- 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb index 60c77e14a5554319..541a71d3302f80af 100644 --- a/app/helpers/application_helper.rb +++ b/app/helpers/application_helper.rb @@ -374,7 +374,7 @@ def discord_url(user) def mastodon_url(user) return '' if user.mastodon.blank? - url = user.mastodon.match %r{\A@?\b([\w\d.%+-]+)@([\w\d.-]+\.\w{2,})\b\z} + url = user.mastodon.match UserDetail::MASTODON_VALIDATION_REGEX "https://#{url[2]}/@#{url[1]}" end diff --git a/app/models/user_detail.rb b/app/models/user_detail.rb index fcf10adae6f67bed..bbb08ed577430c04 100644 --- a/app/models/user_detail.rb +++ b/app/models/user_detail.rb @@ -17,6 +17,18 @@ class UserDetail < MainClusterwide::ApplicationRecord DEFAULT_FIELD_LENGTH = 500 + MASTODON_VALIDATION_REGEX = / + \A # beginning of string + @?\b # optional leading at + ([\w\d.%+-]+) # character group to pick up words in user portion of username + @ # separator between user and host + ( # beginning of charagter group for host portion + [\w\d.-]+ # character group to pick up words in host portion of username + \.\w{2,} # pick up tld of host domain, 2 chars or more + )\b # end of character group to pick up words in host portion of username + \z # end of string + /x + validates :discord, length: { maximum: DEFAULT_FIELD_LENGTH }, allow_blank: true validate :discord_format validates :linkedin, length: { maximum: DEFAULT_FIELD_LENGTH }, allow_blank: true @@ -66,7 +78,7 @@ def discord_format end def mastodon_format - return if mastodon.blank? || mastodon =~ %r{\A@?\b([\w\d.%+-]+)@([\w\d.-]+\.\w{2,})\b\z} + return if mastodon.blank? || mastodon =~ UserDetail::MASTODON_VALIDATION_REGEX errors.add(:mastodon, _('must contain only a mastodon username.')) end -- GitLab