Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion app/avo/resources/user.rb
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ def fields # rubocop:disable Metrics
field :email_reset, as: :boolean
field :handle, as: :text
field :public_email, as: :boolean
field :twitter_username, as: :text, as_html: true, format_using: -> { link_to value, "https://twitter.com/#{value}", target: :_blank, rel: :noopener if value.present? }
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you rename to social_link (and follow the same for helpers ...) and remove the forma_using here (swap with validation on model side to be valid link)?

field :social_link, as: :text, as_html: true
field :unconfirmed_email, as: :text

field :mail_fails, as: :number
Expand Down
2 changes: 1 addition & 1 deletion app/controllers/profiles_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ def params_user
end
end

PERMITTED_PROFILE_PARAMS = %i[handle twitter_username unconfirmed_email public_email full_name].freeze
PERMITTED_PROFILE_PARAMS = %i[handle social_link unconfirmed_email public_email full_name].freeze

def verify_password
password = params.expect(user: :password)[:password]
Expand Down
2 changes: 1 addition & 1 deletion app/controllers/users_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ def create
location
password
website
twitter_username
social_link
full_name
].freeze

Expand Down
8 changes: 2 additions & 6 deletions app/helpers/users_helper.rb
Original file line number Diff line number Diff line change
@@ -1,10 +1,6 @@
module UsersHelper
def twitter_username(user)
"@#{user.twitter_username}" if user.twitter_username.present?
end

def twitter_url(user)
"https://twitter.com/#{user.twitter_username}"
def social_link(user)
user.social_link.presence
end

def show_policies_acknowledge_banner?(user)
Expand Down
8 changes: 3 additions & 5 deletions app/models/user.rb
Original file line number Diff line number Diff line change
Expand Up @@ -73,10 +73,7 @@ class User < ApplicationRecord
validates :handle, format: { with: Patterns::HANDLE_PATTERN }, length: { within: 2..40 }, allow_nil: true
validate :unique_with_org_handle

validates :twitter_username, format: {
with: /\A[a-zA-Z0-9_]*\z/,
message: "can only contain letters, numbers, and underscores"
}, allow_nil: true, length: { within: 0..20 }
validates :social_link, length: { maximum: Gemcutter::MAX_FIELD_LENGTH }, format: { with: Patterns::URL_VALIDATION_REGEXP }, allow_blank: true

validates :password,
length: { minimum: 10 },
Expand Down Expand Up @@ -344,7 +341,8 @@ def clear_personal_attributes
handle: nil, email_confirmed: false,
unconfirmed_email: nil, blocked_email: nil,
api_key: nil, confirmation_token: nil, remember_token: nil,
twitter_username: nil, webauthn_id: nil, full_name: nil,
twitter_username: nil, social_link: nil,
webauthn_id: nil, full_name: nil,
totp_seed: nil, mfa_hashed_recovery_codes: nil,
mfa_level: :disabled,
password: SecureRandom.hex(20).encode("UTF-8")
Expand Down
8 changes: 2 additions & 6 deletions app/views/dashboards/_subject.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -21,14 +21,10 @@
</div>
<% end %>

<% if user.twitter_username.present? %>
<% if user.social_link.present? %>
<div class="flex items-center mb-4 text-b3 lg:text-b2">
<%= icon_tag("x-twitter", color: :primary, class: "w-6 text-orange mr-3") %>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

remove the icon here and just use the link in link_to as is in social_link field (if present)

<p class="text-neutral-800 dark:text-white"><%=
link_to(
twitter_username(user),
twitter_url(user)
)
link_to(social_link(user))
%></p>
</div>
<% end %>
Expand Down
13 changes: 4 additions & 9 deletions app/views/profiles/edit.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -21,21 +21,16 @@
</div>

<div class="text_field">
<%= form.label :twitter_username, class: 'form__label form__label__icon-container' do %>
<%=
image_tag("/images/x_icon.png", alt: 'X icon', class: 'form__label__icon')
%>

<span class='form__label__text'><%= t('.twitter_username') %></span>
<%= form.label :social_link, class: 'form__label form__label__icon-container' do %>
<span class='form__label__text'><%= t('.social_link') %></span>
<% end %>

<p class='form__field__instructions'>
<%= t('.optional_twitter_username') %>
<%= t('.optional_social_link') %>
</p>

<div class="form__input__addon-container form__input__addon-left">
<span class="form__input__addon">@</span>
<%= form.text_field(:twitter_username, class: 'form__input') %>
<%= form.text_field(:social_link, class: 'form__input') %>
</div>
</div>

Expand Down
13 changes: 2 additions & 11 deletions app/views/profiles/show.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -65,19 +65,10 @@
</p>
<% end %>

<% if @user.twitter_username.present? %>
<%=
image_tag(
"/images/x_icon.png",
alt: "X icon",
class: "profile__header__icon"
)
%>

<% if @user.social_link.present? %>
<%=
link_to(
twitter_username(@user),
twitter_url(@user),
social_link(@user),
class: "profile__header__attribute t-link--black"
)
%>
Expand Down
4 changes: 2 additions & 2 deletions config/locales/de.yml
Original file line number Diff line number Diff line change
Expand Up @@ -763,8 +763,8 @@ de:
email_awaiting_confirmation:
enter_password:
optional_full_name:
optional_twitter_username:
twitter_username: Benutzername
optional_social_link:
social_link:
title: Bearbeite Profil
delete:
delete:
Expand Down
4 changes: 2 additions & 2 deletions config/locales/en.yml
Original file line number Diff line number Diff line change
Expand Up @@ -684,8 +684,8 @@ en:
email_awaiting_confirmation: Please confirm your new email address %{unconfirmed_email}
enter_password: Please enter your account's password
optional_full_name: Optional. Will be displayed publicly
optional_twitter_username: Optional X username. Will be displayed publicly
twitter_username: Username
optional_social_link: Optional social link. Will be displayed publicly
social_link: Social Link
title: Edit profile
delete:
delete: Delete
Expand Down
5 changes: 2 additions & 3 deletions config/locales/es.yml
Original file line number Diff line number Diff line change
Expand Up @@ -767,9 +767,8 @@ es:
%{unconfirmed_email}
enter_password: Por favor introduce tu contraseña
optional_full_name: Opcional. Será mostrado en tu perfil público
optional_twitter_username: Usuario de X opcional. Será mostrado en tu perfil
público
twitter_username: Usuario
optional_social_link:
social_link:
title: Editar perfil
delete:
delete: Eliminar
Expand Down
4 changes: 2 additions & 2 deletions config/locales/fr.yml
Original file line number Diff line number Diff line change
Expand Up @@ -696,8 +696,8 @@ fr:
%{unconfirmed_email}
enter_password: Veuillez entrer le mot de passe de votre compte
optional_full_name:
optional_twitter_username: Nom d'utilisateur X optionnel. Sera affiché publiquement
twitter_username: Pseudonyme
optional_social_link:
social_link:
title: Modification de profil
delete:
delete: Supprimer
Expand Down
4 changes: 2 additions & 2 deletions config/locales/ja.yml
Original file line number Diff line number Diff line change
Expand Up @@ -686,8 +686,8 @@ ja:
email_awaiting_confirmation: 新しいEメールアドレス%{unconfirmed_email}を確認してください。
enter_password: アカウントのパスワードを入力してください。
optional_full_name: 省略可能です。公開されます。
optional_twitter_username: Xのユーザー名。省略可能です。公開されます。
twitter_username: ユーザー名
optional_social_link:
social_link:
title: プロフィールを編集
delete:
delete: 削除
Expand Down
4 changes: 2 additions & 2 deletions config/locales/nl.yml
Original file line number Diff line number Diff line change
Expand Up @@ -675,8 +675,8 @@ nl:
email_awaiting_confirmation:
enter_password:
optional_full_name:
optional_twitter_username:
twitter_username: Gebruikersnaam
optional_social_link:
social_link:
title: Wijzig profiel
delete:
delete:
Expand Down
4 changes: 2 additions & 2 deletions config/locales/pt-BR.yml
Original file line number Diff line number Diff line change
Expand Up @@ -687,8 +687,8 @@ pt-BR:
email_awaiting_confirmation:
enter_password:
optional_full_name:
optional_twitter_username:
twitter_username: Usuário
optional_social_link:
social_link:
title: Editar Perfil
delete:
delete:
Expand Down
4 changes: 2 additions & 2 deletions config/locales/zh-CN.yml
Original file line number Diff line number Diff line change
Expand Up @@ -684,8 +684,8 @@ zh-CN:
email_awaiting_confirmation: 请确认您新的邮箱地址 %{unconfirmed_email}
enter_password: 请输入您账户的密码
optional_full_name: 将公开显示(可选)
optional_twitter_username: 可选 X 用户名。这将会被公开显示
twitter_username: 用户名
optional_social_link:
social_link:
title: 修改个人资料
delete:
delete: 删除
Expand Down
4 changes: 2 additions & 2 deletions config/locales/zh-TW.yml
Original file line number Diff line number Diff line change
Expand Up @@ -676,8 +676,8 @@ zh-TW:
email_awaiting_confirmation: 請確認您的新電子郵件地址 %{unconfirmed_email}
enter_password: 輸入密碼
optional_full_name: 選填。將公開顯示
optional_twitter_username: X 帳號(可選)
twitter_username: 帳號
optional_social_link:
social_link:
title: 編輯個人檔案
delete:
delete: 刪除
Expand Down
5 changes: 5 additions & 0 deletions db/migrate/20250715222503_add_social_link_to_users.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
class AddSocialLinkToUsers < ActiveRecord::Migration[8.0]
def change
add_column :users, :social_link, :string
end
end
3 changes: 2 additions & 1 deletion db/schema.rb
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
#
# It's strongly recommended that you check this file into your version control system.

ActiveRecord::Schema[8.0].define(version: 2025_07_02_195347) do
ActiveRecord::Schema[8.0].define(version: 2025_07_15_222503) do
# These are extensions that must be enabled in order to support this database
enable_extension "hstore"
enable_extension "pg_catalog.plpgsql"
Expand Down Expand Up @@ -603,6 +603,7 @@
t.boolean "public_email", default: false, null: false
t.datetime "deleted_at"
t.datetime "policies_acknowledged_at"
t.string "social_link"
t.index "lower((email)::text) varchar_pattern_ops", name: "index_users_on_lower_email"
t.index ["email"], name: "index_users_on_email"
t.index ["handle"], name: "index_users_on_handle"
Expand Down
28 changes: 20 additions & 8 deletions test/models/user_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -162,14 +162,26 @@ class UserTest < ActiveSupport::TestCase
end
end

context "twitter_username" do
should validate_length_of(:twitter_username).is_at_most(20)
should allow_value("user123_32").for(:twitter_username)
should_not allow_value("@user").for(:twitter_username)
should_not allow_value("user 1").for(:twitter_username)
should_not allow_value("user-1").for(:twitter_username)
should allow_value("01234567890123456789").for(:twitter_username)
should_not allow_value("012345678901234567890").for(:twitter_username)
context "social_link" do
should "be less than 255 characters" do
user = build(:user, social_link: format("%s.example.com", "a" * 256))

refute_predicate user, :valid?
assert_contains user.errors[:social_link], "is too long (maximum is 255 characters)"
end

should "be valid when it matches a valid URI regex" do
user = build(:user, social_link: "https://example.com/someone")

assert_predicate user, :valid?
end

should "be invalid when it doesn't match a valid URI regex" do
user = build(:user, social_link: ">\"<script>alert(document.cookie)</script>.gmail.com")

refute_predicate user, :valid?
assert_contains user.errors[:social_link], "is invalid"
end
end

context "password" do
Expand Down
21 changes: 11 additions & 10 deletions test/system/profile_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -107,42 +107,43 @@ class ProfileTest < ApplicationSystemTestCase
assert page.has_content?("Email Me")
end

test "adding X(formerly Twitter) username" do
test "adding social link" do
social_link = "https://example.com/nick1"
sign_in
visit profile_path("nick1")

click_link "Edit Profile"
fill_in "user_twitter_username", with: "nick1"
fill_in "user_social_link", with: social_link
fill_in "Password", with: PasswordHelpers::SECURE_TEST_PASSWORD
click_button "Update"

sign_out
visit profile_path("nick1")

assert page.has_link?("@nick1", href: "https://twitter.com/nick1")
assert page.has_link?(social_link)
end

test "adding X(formerly Twitter) username without filling in your password" do
twitter_username = "nick1twitter"
test "adding social link without filling in your password" do
social_link = "https://example.com/nick1"

sign_in
visit profile_path("nick1")

click_link "Edit Profile"
fill_in "user_twitter_username", with: twitter_username
fill_in "user_social_link", with: social_link

assert_equal twitter_username, page.find_by_id("user_twitter_username").value
assert_equal social_link, page.find_by_id("user_social_link").value

click_button "Update"

# Verify that the newly added Twitter username is still on the form so that the user does not need to re-enter it
assert_equal twitter_username, page.find_by_id("user_twitter_username").value
# Verify that the newly added social link is still on the form so that the user does not need to re-enter it
assert_equal social_link, page.find_by_id("user_social_link").value

fill_in "Password", with: PasswordHelpers::SECURE_TEST_PASSWORD
click_button "Update"

assert page.has_content? "Your profile was updated."
assert_equal twitter_username, page.find_by_id("user_twitter_username").value
assert_equal social_link, page.find_by_id("user_social_link").value
end

test "deleting profile" do
Expand Down