Remove hardcoded user profile fields (#14079)
* Remove duplicated work display from header * Update work profile field handling * Update DUS + spec * Delegate more carefully * Update delegation guard * Adapt for removed delegation * Undo accidental schema changes * Fix seeds * Remove accidentaly change * Fix User#processed_website_url * Update guard clause * Update profile card content * Add Organization#profile * Be more conservative with profile fields * Spec fixes round 1 * Fix typo * Update spec * Limit number of header fields and update card content * Decorate correct model * Update factory * Update schema.rb * Fix validation * How bad could this possibly be? * Pretty bad, nevermind * Remove obsolete code * Reset profile fields during test runs * Move profile fields back to before(:suite) * Spec fixes * Remove accidentally re-added files * More spec fixes * Specs * Change User#tag_keywords_for_search * More spec fixes * Add comment * Undo accidental schema changes * Attempt spec fix * Remove fix attempt * Fix e2e test * Update spec * Remove guard clause * Remove hardcoded instances of education field * WIP Access display_email_on_profile via User Settings * Remove unused profile column * WIP fix issues revealed by systems specs * WIP fix issues revealed by services specs * WIP Fix failing tests * WIP Fix spec failures * wip * Move two attributes from controller to decorator * Update comment * More consistently use user.tag_line Even before the profile changes we sometimes used the user.summary attribute directly but used the user.tag_line method in other places. * Remove education * Add comment * WIP * Clean up mostly_work_with * WIP * Update work profile field handling * More work-related changes * Remove settings_only from display_area enum * Remove quickfix from _metadata partial * Remove special attributes * Remove leftover spec * Retrieve location from profile, not user * Profile.special_attributes no longer exists * Update specs * More spec fixes * Update UsersController * Update UsersController and spec * Fix e2e seeds * Minor cleanup * More e2e seed fixes * Fix profile field CSV * Fix e2e seeds * Move one more attribute in e2e seeds * Remove duplicate line * Clear inputs before typing in them Co-authored-by: Jacob Herrington <jacobherringtondeveloper@gmail.com>
This commit is contained in:
parent
9b7a0e1036
commit
1ebec4b67f
35 changed files with 157 additions and 185 deletions
|
|
@ -333,6 +333,7 @@ class StoriesController < ApplicationController
|
|||
def set_user_json_ld
|
||||
# For more info on structuring data with JSON-LD,
|
||||
# please refer to this link: https://moz.com/blog/json-ld-for-beginners
|
||||
decorated_user = @user.decorate
|
||||
@user_json_ld = {
|
||||
"@context": "http://schema.org",
|
||||
"@type": "Person",
|
||||
|
|
@ -344,9 +345,8 @@ class StoriesController < ApplicationController
|
|||
sameAs: user_same_as,
|
||||
image: Images::Profile.call(@user.profile_image_url, length: 320),
|
||||
name: @user.name,
|
||||
email: @user.setting.display_email_on_profile ? @user.email : nil,
|
||||
description: @user.profile.summary.presence || "404 bio not found",
|
||||
alumniOf: @user.education.presence
|
||||
email: decorated_user.profile_email,
|
||||
description: decorated_user.profile_summary
|
||||
}.reject { |_, v| v.blank? }
|
||||
end
|
||||
|
||||
|
|
|
|||
|
|
@ -46,9 +46,7 @@ class UsersController < ApplicationController
|
|||
set_current_tab(params["user"]["tab"])
|
||||
set_users_setting_and_notification_setting
|
||||
|
||||
@user.assign_attributes(permitted_attributes(@user))
|
||||
|
||||
if @user.save
|
||||
if @user.update(permitted_attributes(@user))
|
||||
# NOTE: [@rhymes] this queues a job to fetch the feed each time the profile is updated, regardless if the user
|
||||
# explicitly requested "Feed fetch now" or simply updated any other field
|
||||
import_articles_from_feed(@user)
|
||||
|
|
@ -170,6 +168,7 @@ class UsersController < ApplicationController
|
|||
|
||||
def onboarding_update
|
||||
authorize User
|
||||
|
||||
user_params = { saw_onboarding: true }
|
||||
|
||||
if params[:user]
|
||||
|
|
@ -181,7 +180,7 @@ class UsersController < ApplicationController
|
|||
user_params.merge!(params[:user].permit(ALLOWED_USER_PARAMS))
|
||||
end
|
||||
|
||||
update_result = Profiles::Update.call(current_user, { user: user_params, profile: profile_params })
|
||||
update_result = Profiles::Update.call(current_user, user: user_params, profile: profile_params)
|
||||
render_update_response(update_result.success?, update_result.errors_as_sentence)
|
||||
end
|
||||
|
||||
|
|
@ -381,7 +380,7 @@ class UsersController < ApplicationController
|
|||
end
|
||||
|
||||
def profile_params
|
||||
params[:profile] ? params[:profile].permit(Profile.attributes) : nil
|
||||
params[:profile] ? params[:profile].permit(Profile.static_fields + Profile.attributes) : nil
|
||||
end
|
||||
|
||||
def password_params
|
||||
|
|
|
|||
|
|
@ -18,6 +18,8 @@ class UserDecorator < ApplicationDecorator
|
|||
},
|
||||
].freeze
|
||||
|
||||
DEFAULT_PROFILE_SUMMARY = "404 bio not found".freeze
|
||||
|
||||
def cached_followed_tags
|
||||
follows_map = Rails.cache.fetch("user-#{id}-#{following_tags_count}-#{last_followed_at&.rfc3339}/followed_tags",
|
||||
expires_in: 20.hours) do
|
||||
|
|
@ -110,6 +112,19 @@ class UserDecorator < ApplicationDecorator
|
|||
created_at.after?(min_days.days.ago)
|
||||
end
|
||||
|
||||
# Returns the user's public email if it is set and the display_email_on_profile
|
||||
# settings is set to true.
|
||||
def profile_email
|
||||
return unless setting.display_email_on_profile?
|
||||
|
||||
email
|
||||
end
|
||||
|
||||
# Returns the users profile summary or a placeholder text
|
||||
def profile_summary
|
||||
profile.summary.presence || DEFAULT_PROFILE_SUMMARY
|
||||
end
|
||||
|
||||
delegate :display_sponsors, to: :setting
|
||||
|
||||
delegate :display_announcements, to: :setting
|
||||
|
|
|
|||
|
|
@ -11,15 +11,6 @@ class Profile < ApplicationRecord
|
|||
# any profile on a given Forem.
|
||||
STATIC_FIELDS = %w[summary location website_url].freeze
|
||||
|
||||
SPECIAL_DISPLAY_ATTRIBUTES = %w[summary location].freeze
|
||||
|
||||
# NOTE: @citizen428 This is a temporary mapping so we don't break DEV during
|
||||
# profile migration/generalization work.
|
||||
MAPPED_ATTRIBUTES = {
|
||||
education: :education,
|
||||
skills_languages: :mostly_work_with
|
||||
}.with_indifferent_access.freeze
|
||||
|
||||
# Generates typed accessors for all currently defined profile fields.
|
||||
def self.refresh_attributes!
|
||||
return if ENV["ENV_AVAILABLE"] == "false"
|
||||
|
|
@ -30,7 +21,7 @@ class Profile < ApplicationRecord
|
|||
# TODO: [@jacobherrington] Remove this when ProfileFields for the static
|
||||
# fields are dropped from production and the associated data is removed.
|
||||
# https://github.com/forem/forem/pull/13641#discussion_r637641185
|
||||
next if STATIC_FIELDS.any?(field.attribute_name)
|
||||
next if field.attribute_name.in?(STATIC_FIELDS)
|
||||
|
||||
store_attribute :data, field.attribute_name.to_sym, field.type
|
||||
end
|
||||
|
|
@ -45,10 +36,6 @@ class Profile < ApplicationRecord
|
|||
(stored_attributes[:data] || []).map(&:to_s)
|
||||
end
|
||||
|
||||
def self.special_attributes
|
||||
SPECIAL_DISPLAY_ATTRIBUTES
|
||||
end
|
||||
|
||||
def self.static_fields
|
||||
STATIC_FIELDS
|
||||
end
|
||||
|
|
|
|||
|
|
@ -13,8 +13,7 @@ class ProfileField < ApplicationRecord
|
|||
|
||||
enum display_area: {
|
||||
header: 0,
|
||||
left_sidebar: 1,
|
||||
settings_only: 2
|
||||
left_sidebar: 1
|
||||
}
|
||||
|
||||
belongs_to :profile_field_group, optional: true
|
||||
|
|
|
|||
|
|
@ -12,7 +12,6 @@ class User < ApplicationRecord
|
|||
bg_color_hex
|
||||
currently_hacking_on
|
||||
currently_learning
|
||||
currently_streaming_on
|
||||
dribbble_url
|
||||
education
|
||||
email_public
|
||||
|
|
@ -58,19 +57,12 @@ class User < ApplicationRecord
|
|||
after_create_commit -> { Profile.create(user: self) }, unless: :_skip_creating_profile
|
||||
|
||||
# Getters and setters for unmapped profile attributes
|
||||
(PROFILE_COLUMNS - Profile::MAPPED_ATTRIBUTES.values).each do |column|
|
||||
PROFILE_COLUMNS.each do |column|
|
||||
next if INACTIVE_PROFILE_COLUMNS.include?(column)
|
||||
next unless column.in?(Profile.attributes)
|
||||
|
||||
delegate column, "#{column}=", to: :profile, allow_nil: true
|
||||
end
|
||||
|
||||
# Getters and setters for mapped profile attributes
|
||||
Profile::MAPPED_ATTRIBUTES.each do |profile_attribute, user_attribute|
|
||||
define_method(user_attribute) { profile&.public_send(profile_attribute) }
|
||||
define_method("#{user_attribute}=") do |value|
|
||||
profile&.public_send("#{profile_attribute}=", value)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
|
@ -289,7 +281,7 @@ class User < ApplicationRecord
|
|||
end
|
||||
|
||||
def tag_line
|
||||
summary
|
||||
profile.summary
|
||||
end
|
||||
|
||||
def twitter_url
|
||||
|
|
|
|||
|
|
@ -20,7 +20,8 @@ class UserPolicy < ApplicationPolicy
|
|||
email_follower_notifications
|
||||
email_membership_newsletter
|
||||
email_mention_notifications
|
||||
email_newsletter email_public
|
||||
email_newsletter
|
||||
email_public
|
||||
email_tag_mod_newsletter
|
||||
email_unread_notifications
|
||||
employer_name
|
||||
|
|
@ -33,21 +34,17 @@ class UserPolicy < ApplicationPolicy
|
|||
feed_url
|
||||
inbox_guidelines
|
||||
inbox_type
|
||||
location
|
||||
mobile_comment_notifications
|
||||
mod_roundrobin_notifications
|
||||
welcome_notifications
|
||||
mostly_work_with
|
||||
name
|
||||
password
|
||||
password_confirmation
|
||||
payment_pointer
|
||||
permit_adjacent_sponsors
|
||||
profile_image
|
||||
summary
|
||||
text_color_hex
|
||||
username
|
||||
website_url
|
||||
].freeze
|
||||
|
||||
def edit?
|
||||
|
|
|
|||
|
|
@ -1,3 +1,5 @@
|
|||
# TODO: This should probably become `Users::Update` as we're dealing with core
|
||||
# user attributes, profile attributes and user settings.
|
||||
module Profiles
|
||||
# Deals with updates that affect fields on +Profile+ and/or +User+ in a transparent way.
|
||||
class Update
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@ module Users
|
|||
suggested_user_ids = Rails.cache.fetch(generate_cache_name, expires_in: 120.hours) do
|
||||
(reputable_user_ids + random_user_ids).uniq
|
||||
end
|
||||
User.select(:id, :name, :username, :profile_image, :summary).where(id: suggested_user_ids)
|
||||
User.select(:id, :name, :username, :profile_image).where(id: suggested_user_ids)
|
||||
end
|
||||
|
||||
private
|
||||
|
|
|
|||
|
|
@ -5,12 +5,13 @@ json.extract!(
|
|||
:id,
|
||||
:username,
|
||||
:name,
|
||||
:summary,
|
||||
:twitter_username,
|
||||
:github_username,
|
||||
:website_url,
|
||||
:location,
|
||||
)
|
||||
|
||||
Profile.static_fields.each do |attr|
|
||||
json.set! attr, user.profile.public_send(attr)
|
||||
end
|
||||
|
||||
json.joined_at user.created_at.strftime("%b %e, %Y")
|
||||
json.profile_image Images::Profile.call(user.profile_image_url, length: 320)
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ xml.rss version: "2.0" do
|
|||
xml.channel do
|
||||
xml.title user ? user.name : community_name
|
||||
xml.author user ? user.name : community_name
|
||||
xml.description user ? user.summary : Settings::Community.community_description
|
||||
xml.description user ? user.tag_line : Settings::Community.community_description
|
||||
xml.link user ? app_url(user.path) : app_url
|
||||
xml.language "en"
|
||||
if user
|
||||
|
|
|
|||
|
|
@ -53,8 +53,8 @@
|
|||
<%= inline_svg_tag("github.svg", class: "crayons-icon", aria: true, title: "GitHub logo") %>
|
||||
</a>
|
||||
<% end %>
|
||||
<% if @user.website_url.present? %>
|
||||
<a href="<%= @user.website_url %>" target="_blank" rel="noopener nofollow me" class="px-1 align-middle inline-block">
|
||||
<% if @user.profile.website_url.present? %>
|
||||
<a href="<%= @user.profile.website_url %>" target="_blank" rel="noopener nofollow me" class="px-1 align-middle inline-block">
|
||||
<%= inline_svg_tag("external.svg", class: "crayons-icon", aria: true, title: "External link icon") %>
|
||||
</a>
|
||||
<% end %>
|
||||
|
|
|
|||
|
|
@ -29,19 +29,18 @@
|
|||
</div>
|
||||
</li>
|
||||
<% end %>
|
||||
<% if actor.location.present? %>
|
||||
<% if actor.profile.location.present? %>
|
||||
<li>
|
||||
<div class="key">
|
||||
Location
|
||||
</div>
|
||||
<div class="value">
|
||||
<%= actor.location %>
|
||||
<%= actor.profile.location %>
|
||||
</div>
|
||||
</li>
|
||||
<% end %>
|
||||
<% if (header_fields = actor.profile.decorate.ui_attributes_for(area: :header)).present? %>
|
||||
<% header_fields.sort.each do |title, value| %>
|
||||
<% next if Profile.special_attributes.include?(title) %>
|
||||
<li>
|
||||
<div class="key">
|
||||
<%= title %>
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@
|
|||
<div class="ltag__user__content">
|
||||
<h2><%= link_to_if user_path.present?, user.name, user_path, class: "ltag__user__link" %><%= follow_button %></h2>
|
||||
<div class="ltag__user__summary">
|
||||
<%= link_to_if user_path.present?, user.summary, user_path, class: "ltag__user__link" %>
|
||||
<%= link_to_if user_path.present?, user.tag_line, user_path, class: "ltag__user__link" %>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -1,19 +1,18 @@
|
|||
<link rel="canonical" href="<%= user_url(@user) %>" />
|
||||
<meta name="description" content="<%= @user.profile.summary %>">
|
||||
<meta name="description" content="<%= @user.tag_line %>">
|
||||
<%= meta_keywords_default %>
|
||||
|
||||
<meta property="og:type" content="website" />
|
||||
<meta property="og:url" content="<%= user_url(@user) %>" />
|
||||
<meta property="og:title" content="<%= @user.name %> — <%= community_name %> Profile" />
|
||||
<meta property="og:image" content="<%= user_social_image_url(@user) %>">
|
||||
<meta property="og:description" content="<%= @user.profile.summary %>" />
|
||||
<meta property="og:description" content="<%= @user.tag_line %>" />
|
||||
<meta property="og:site_name" content="<%= community_name %>" />
|
||||
|
||||
<meta name="twitter:card" content="summary_large_image">
|
||||
<meta name="twitter:site" content="@<%= Settings::General.social_media_handles["twitter"] %>">
|
||||
<meta name="twitter:creator" content="@<%= @user.twitter_username %>">
|
||||
<meta name="twitter:title" content="<%= @user.name %> — <%= community_name %> Profile">
|
||||
<meta name="twitter:description" content="<%= @user.profile.summary %>">
|
||||
<meta name="twitter:description" content="<%= @user.tag_line %>">
|
||||
<meta name="twitter:image:src" content="<%= user_social_image_url(@user) %>">
|
||||
<% if @stories.any? %>
|
||||
<%= auto_discovery_link_tag(:rss, app_url("/feed/#{@user.username}"), title: "#{community_name} RSS Feed") %>
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
<% if (header_fields = @profile.ui_attributes_for(area: :header)).present? %>
|
||||
<div class="profile-header__bottom fs-base">
|
||||
<% header_fields.sort.each do |title, value| %>
|
||||
<% next if Profile.special_attributes.include?(title) %>
|
||||
<div class="crayons-definition">
|
||||
<strong class="crayons-definition__title">
|
||||
<%= sanitized_sidebar title.titleize %>
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
json.array! @users.each do |user|
|
||||
json.extract!(user, :id, :name, :username)
|
||||
|
||||
json.summary truncate(user.summary.presence || "Active #{community_name} author", length: 100)
|
||||
json.summary truncate(user.tag_line || "Active #{community_name} author", length: 100)
|
||||
json.profile_image_url Images::Profile.call(user.profile_image_url, length: 90)
|
||||
json.following false
|
||||
end
|
||||
|
|
|
|||
|
|
@ -61,13 +61,13 @@
|
|||
|
||||
<div class="profile-header__details">
|
||||
<h1 class="crayons-title fw-heavy mb-2"><%= @user.name %></h1>
|
||||
<p class="fs-base m:fs-l color-base-90 mb-4 mx-auto max-w-100 m:max-w-75"><%= @user.profile.summary.presence || ["404 bio not found"].sample %></p>
|
||||
<p class="fs-base m:fs-l color-base-90 mb-4 mx-auto max-w-100 m:max-w-75"><%= @user.tag_line.presence || ["404 bio not found"].sample %></p>
|
||||
|
||||
<div class="profile-header__meta">
|
||||
<% if @user.profile.location.present? %>
|
||||
<span class="profile-header__meta__item">
|
||||
<%= inline_svg_tag("location.svg", aria: true, class: "crayons-icon mr-2 shrink-0", title: "Location") %>
|
||||
<%= @user.location %>
|
||||
<%= @user.profile.location %>
|
||||
</span>
|
||||
<% end %>
|
||||
|
||||
|
|
@ -80,14 +80,14 @@
|
|||
<% if @user.setting.display_email_on_profile %>
|
||||
<a href="mailto:<%= @user.email %>" class="profile-header__meta__item">
|
||||
<%= inline_svg_tag("email.svg", class: "crayons-icon mr-2 shrink-0", aria: true, title: "Email address") %>
|
||||
<%= @user.email %>
|
||||
<%= @user.setting.display_email_on_profile %>
|
||||
</a>
|
||||
<% end %>
|
||||
|
||||
<% if @user.profile.website_url.present? %>
|
||||
<a href="<%= @user.website_url %>" target="_blank" rel="noopener me" class="profile-header__meta__item">
|
||||
<a href="<%= @user.profile.website_url %>" target="_blank" rel="noopener me" class="profile-header__meta__item">
|
||||
<%= inline_svg_tag("link-external.svg", class: "crayons-icon mr-2 shrink-0", aria: true, title: "Personal website") %>
|
||||
<%= @user.website_url %>
|
||||
<%= @user.profile.website_url %>
|
||||
</a>
|
||||
<% end %>
|
||||
|
||||
|
|
|
|||
|
|
@ -81,9 +81,11 @@ Rails.application.configure do
|
|||
Bullet.add_safelist(type: :unused_eager_loading, class_name: "Article", association: :top_comments)
|
||||
Bullet.add_safelist(type: :unused_eager_loading, class_name: "Comment", association: :user)
|
||||
# NOTE: @citizen428 Temporarily ignoring this while working out user - profile relationship
|
||||
Bullet.add_safelist(type: :n_plus_one_query, class_name: "User", association: :profile)
|
||||
Bullet.add_safelist(type: :n_plus_one_query, class_name: "User", association: :setting)
|
||||
Bullet.add_safelist(type: :n_plus_one_query, class_name: "User", association: :notification_setting)
|
||||
Bullet.add_whitelist(type: :n_plus_one_query, class_name: "User", association: :profile)
|
||||
Bullet.add_whitelist(type: :n_plus_one_query, class_name: "User", association: :setting)
|
||||
Bullet.add_whitelist(type: :n_plus_one_query, class_name: "User", association: :notification_setting)
|
||||
# NOTE: @citizen428 Let's ignore this for now, we have to revisit the user - profile relationship anyway
|
||||
Bullet.add_whitelist(type: :n_plus_one_query, class_name: "Profile", association: :user)
|
||||
# @mstruve: These occur during setting updates, not sure how since we are only dealing with single setting records
|
||||
Bullet.add_safelist(type: :n_plus_one_query, class_name: "Users::Setting", association: :user)
|
||||
Bullet.add_safelist(type: :n_plus_one_query, class_name: "Users::NotificationSetting", association: :user)
|
||||
|
|
|
|||
|
|
@ -13,9 +13,13 @@ describe('User Update Settings Profile', () => {
|
|||
const summary = 'This is my story...';
|
||||
const location = 'New York City';
|
||||
|
||||
cy.findByLabelText(/^Website URL$/i).type(websiteURL);
|
||||
cy.findByLabelText(/^Bio$/i).type(summary);
|
||||
cy.findByLabelText(/^Location$/i).type(location);
|
||||
cy.findByLabelText(/^Website URL$/i)
|
||||
.clear()
|
||||
.type(websiteURL);
|
||||
cy.findByLabelText(/^Bio$/i).clear().type(summary);
|
||||
cy.findByLabelText(/^Location$/i)
|
||||
.clear()
|
||||
.type(location);
|
||||
|
||||
cy.findByText(/^Save Profile Information$/i).click();
|
||||
|
||||
|
|
|
|||
|
|
@ -1,9 +0,0 @@
|
|||
module DataUpdateScripts
|
||||
class BackfillProfileSkillsLanguages
|
||||
def run
|
||||
User.where.not(mostly_work_with: [nil, ""]).find_each do |user|
|
||||
user.profile.update(skills_languages: user.mostly_work_with)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -1,28 +0,0 @@
|
|||
module DataUpdateScripts
|
||||
class SetProperDisplayAreaForProfileFields
|
||||
def run
|
||||
ProfileField.where(attribute_name: %w[brand_color1
|
||||
brand_color2
|
||||
recruiters_can_contact_me_about_job_opportunities
|
||||
display_email_on_profile
|
||||
twitter_url
|
||||
github_url
|
||||
facebook_url
|
||||
linkedin_url
|
||||
youtube_url
|
||||
instagram_url
|
||||
behance_url
|
||||
medium_url
|
||||
stackoverflow_url
|
||||
gitlab_url
|
||||
twitch_url
|
||||
mastodon_url
|
||||
website_url])
|
||||
.update_all(display_area: "settings_only")
|
||||
ProfileField.where.not(display_area: "settings_only").update_all(display_area: "header")
|
||||
ProfileField.where(attribute_name:
|
||||
%w[currently_hacking_on currently_learning mostly_work_with available_for])
|
||||
.update_all(display_area: "left_sidebar")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -14,7 +14,7 @@ RSpec.describe ApplicationHelper, type: :helper do
|
|||
expect(user.darker_color).to eq Color::CompareHex.new(described_class::USER_COLORS).brightness
|
||||
expect(user.username).to eq "[deleted user]"
|
||||
expect(user.name).to eq "[Deleted User]"
|
||||
expect(user.summary).to be_nil
|
||||
expect(user.tag_line).to be_nil
|
||||
expect(user.twitter_username).to be_nil
|
||||
expect(user.github_username).to be_nil
|
||||
end
|
||||
|
|
|
|||
|
|
@ -1,13 +0,0 @@
|
|||
require "rails_helper"
|
||||
require Rails.root.join(
|
||||
"lib/data_update_scripts/20201223013903_set_proper_display_area_for_profile_fields.rb",
|
||||
)
|
||||
|
||||
describe DataUpdateScripts::SetProperDisplayAreaForProfileFields do
|
||||
it "migrates profile fields to proper areas" do
|
||||
# Run the script
|
||||
described_class.new.run
|
||||
expect(ProfileField.find_by(attribute_name: "education").display_area).to eq("header")
|
||||
expect(ProfileField.find_by(attribute_name: "currently_learning").display_area).to eq("left_sidebar")
|
||||
end
|
||||
end
|
||||
|
|
@ -48,5 +48,17 @@ RSpec.describe ProfileField, type: :model do
|
|||
field = create(:profile_field, label: "Test? Test! 1")
|
||||
expect(field.attribute_name).to eq "test_test1"
|
||||
end
|
||||
|
||||
describe "#maximum_header_field_count" do
|
||||
it "limits the number of header fields" do
|
||||
count = [0, described_class::HEADER_FIELD_LIMIT - described_class.header.count].max
|
||||
create_list(:profile_field, count, :header)
|
||||
|
||||
expected_message = /#{Regexp.quote(ProfileField::HEADER_LIMIT_MESSAGE)}/
|
||||
|
||||
expect { create(:profile_field, :header) }
|
||||
.to raise_error(ActiveRecord::RecordInvalid, expected_message)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -413,7 +413,7 @@ RSpec.describe User, type: :model do
|
|||
user = described_class.find(create(:user, :ignore_mailchimp_subscribe_callback).id)
|
||||
|
||||
sidekiq_assert_no_enqueued_jobs(only: Users::SubscribeToMailchimpNewsletterWorker) do
|
||||
user.update(website_url: "http://example.com")
|
||||
user.update(credits_count: 100)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -827,14 +827,5 @@ RSpec.describe User, type: :model do
|
|||
expect(user.profile).to be_present
|
||||
expect(user.profile).to respond_to(:available_for)
|
||||
end
|
||||
|
||||
it "propagates changes of unmapped attributes to the profile model", :aggregate_failures do
|
||||
expect do
|
||||
user.update(available_for: "profile migrations")
|
||||
end.to change { user.profile.reload.available_for }.from(nil).to("profile migrations")
|
||||
|
||||
# Changes were also persisted in the users table
|
||||
expect(user.reload.available_for).to eq "profile migrations"
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -58,12 +58,15 @@ RSpec.describe "Api::V0::Organizations", type: :request do
|
|||
|
||||
expect(response_org_users["type_of"]).to eq("user")
|
||||
|
||||
%w[
|
||||
id username name summary twitter_username github_username website_url location
|
||||
].each do |attr|
|
||||
%w[id username name twitter_username github_username].each do |attr|
|
||||
expect(response_org_users[attr]).to eq(org_user.public_send(attr))
|
||||
end
|
||||
|
||||
org_user_profile = org_user.profile
|
||||
%w[summary location website_url].each do |attr|
|
||||
expect(response_org_users[attr]).to eq(org_user_profile.public_send(attr))
|
||||
end
|
||||
|
||||
expect(response_org_users["joined_at"]).to eq(org_user.created_at.strftime("%b %e, %Y"))
|
||||
expect(response_org_users["profile_image"]).to eq(Images::Profile.call(org_user.profile_image_url, length: 320))
|
||||
end
|
||||
|
|
@ -104,10 +107,12 @@ RSpec.describe "Api::V0::Organizations", type: :request do
|
|||
expect(response_listing["tag_list"]).to eq(listing.cached_tag_list)
|
||||
expect(response_listing["tags"]).to match_array(listing.tag_list)
|
||||
|
||||
%w[name username twitter_username github_username website_url].each do |attr|
|
||||
%w[name username twitter_username github_username].each do |attr|
|
||||
expect(response_listing["user"][attr]).to eq(org_user.public_send(attr))
|
||||
end
|
||||
|
||||
expect(response_listing["organization"]["website_url"]).to eq(org_user.profile.website_url)
|
||||
|
||||
%w[name username slug].each do |attr|
|
||||
expect(response_listing["organization"][attr]).to eq(organization.public_send(attr))
|
||||
end
|
||||
|
|
@ -149,10 +154,12 @@ RSpec.describe "Api::V0::Organizations", type: :request do
|
|||
|
||||
expect(response_article["tag_list"]).to match_array(article.tag_list)
|
||||
|
||||
%w[name username twitter_username github_username website_url].each do |attr|
|
||||
%w[name username twitter_username github_username].each do |attr|
|
||||
expect(response_article["user"][attr]).to eq(org_user.public_send(attr))
|
||||
end
|
||||
|
||||
expect(response_article["user"]["website_url"]).to eq(org_user.profile.website_url)
|
||||
|
||||
%w[name username slug].each do |attr|
|
||||
expect(response_article["organization"][attr]).to eq(organization.public_send(attr))
|
||||
end
|
||||
|
|
|
|||
|
|
@ -2,7 +2,12 @@ require "rails_helper"
|
|||
|
||||
RSpec.describe "Api::V0::Users", type: :request do
|
||||
describe "GET /api/users/:id" do
|
||||
let(:user) { create(:user, summary: "Something something", profile_image: "") }
|
||||
let!(:user) do
|
||||
create(:user,
|
||||
profile_image: "",
|
||||
_skip_creating_profile: true,
|
||||
profile: create(:profile, summary: "Something something"))
|
||||
end
|
||||
|
||||
it "returns 404 if the user id is not found" do
|
||||
get api_user_path("invalid-id")
|
||||
|
|
@ -39,12 +44,14 @@ RSpec.describe "Api::V0::Users", type: :request do
|
|||
|
||||
expect(response_user["type_of"]).to eq("user")
|
||||
|
||||
%w[
|
||||
id username name summary twitter_username github_username website_url location
|
||||
].each do |attr|
|
||||
%w[id username name twitter_username github_username].each do |attr|
|
||||
expect(response_user[attr]).to eq(user.public_send(attr))
|
||||
end
|
||||
|
||||
%w[summary website_url location].each do |attr|
|
||||
expect(response_user[attr]).to eq(user.profile.public_send(attr))
|
||||
end
|
||||
|
||||
expect(response_user["joined_at"]).to eq(user.created_at.strftime("%b %e, %Y"))
|
||||
expect(response_user["profile_image"]).to eq(Images::Profile.call(user.profile_image_url, length: 320))
|
||||
end
|
||||
|
|
@ -67,12 +74,14 @@ RSpec.describe "Api::V0::Users", type: :request do
|
|||
|
||||
expect(response_user["type_of"]).to eq("user")
|
||||
|
||||
%w[
|
||||
id username name summary twitter_username github_username website_url location
|
||||
].each do |attr|
|
||||
%w[id username name twitter_username github_username].each do |attr|
|
||||
expect(response_user[attr]).to eq(user.public_send(attr))
|
||||
end
|
||||
|
||||
%w[summary website_url location].each do |attr|
|
||||
expect(response_user[attr]).to eq(user.profile.public_send(attr))
|
||||
end
|
||||
|
||||
expect(response_user["joined_at"]).to eq(user.created_at.strftime("%b %e, %Y"))
|
||||
expect(response_user["profile_image"]).to eq(Images::Profile.call(user.profile_image_url, length: 320))
|
||||
end
|
||||
|
|
@ -85,12 +94,14 @@ RSpec.describe "Api::V0::Users", type: :request do
|
|||
|
||||
expect(response_user["type_of"]).to eq("user")
|
||||
|
||||
%w[
|
||||
id username name summary twitter_username github_username website_url location
|
||||
].each do |attr|
|
||||
%w[id username name twitter_username github_username].each do |attr|
|
||||
expect(response_user[attr]).to eq(user.public_send(attr))
|
||||
end
|
||||
|
||||
%w[summary website_url location].each do |attr|
|
||||
expect(response_user[attr]).to eq(user.profile.public_send(attr))
|
||||
end
|
||||
|
||||
expect(response_user["joined_at"]).to eq(user.created_at.strftime("%b %e, %Y"))
|
||||
expect(response_user["profile_image"]).to eq(Images::Profile.call(user.profile_image_url, length: 320))
|
||||
end
|
||||
|
|
|
|||
|
|
@ -98,19 +98,13 @@ RSpec.describe "UserProfiles", type: :request do
|
|||
expect(response.body.split("Whoaaaa").first).to include "crayons-layout__sidebar-left"
|
||||
end
|
||||
|
||||
it "does not render settings_only on page" do
|
||||
create(:profile_field, label: "whoaaaa", display_area: "settings_only")
|
||||
get "/#{user.username}"
|
||||
expect(response.body).not_to include "Whoaaaa"
|
||||
end
|
||||
|
||||
it "does not render special display header elements naively" do
|
||||
user.location = "hawaii"
|
||||
user.profile.location = "hawaii"
|
||||
user.save
|
||||
get "/#{user.username}"
|
||||
# Does not include the word, but does include the SVG
|
||||
expect(response.body).not_to include "<p>Location</p>"
|
||||
expect(response.body).to include user.location
|
||||
expect(response.body).to include user.profile.location
|
||||
expect(response.body).to include "M18.364 17.364L12 23.728l-6.364-6.364a9 9 0 1112.728 0zM12 13a2 2 0 100-4 2 2 0"
|
||||
end
|
||||
|
||||
|
|
|
|||
|
|
@ -238,14 +238,9 @@ RSpec.describe "UserSettings", type: :request do
|
|||
describe "PUT /update/:id" do
|
||||
before { sign_in user }
|
||||
|
||||
it "updates summary" do
|
||||
put "/users/#{user.id}", params: { user: { tab: "profile", summary: "Hello new summary" } }
|
||||
expect(user.summary).to eq("Hello new summary")
|
||||
end
|
||||
|
||||
it "updates profile_updated_at" do
|
||||
user.update_column(:profile_updated_at, 2.weeks.ago)
|
||||
put "/users/#{user.id}", params: { user: { tab: "profile", summary: "Hello new summary" } }
|
||||
put "/users/#{user.id}", params: { user: { tab: "profile", username: "new_username" } }
|
||||
expect(user.reload.profile_updated_at).to be > 2.minutes.ago
|
||||
end
|
||||
|
||||
|
|
|
|||
|
|
@ -38,8 +38,7 @@ RSpec.describe "UserShow", type: :request do
|
|||
"image" => Images::Profile.call(user.profile_image_url, length: 320),
|
||||
"name" => user.name,
|
||||
"email" => user.email,
|
||||
"description" => user.summary,
|
||||
"alumniOf" => user.education,
|
||||
"description" => user.tag_line,
|
||||
)
|
||||
end
|
||||
# rubocop:enable RSpec/ExampleLength
|
||||
|
|
|
|||
|
|
@ -38,7 +38,7 @@ RSpec.describe "Users", type: :request do
|
|||
"id" => suggested_user.id,
|
||||
"name" => suggested_user.name,
|
||||
"username" => suggested_user.username,
|
||||
"summary" => suggested_user.summary,
|
||||
"summary" => suggested_user.profile.summary,
|
||||
"profile_image_url" => Images::Profile.call(suggested_user.profile_image_url, length: 90),
|
||||
"following" => false,
|
||||
)
|
||||
|
|
@ -86,7 +86,7 @@ RSpec.describe "Users", type: :request do
|
|||
"id" => suggested_user.id,
|
||||
"name" => suggested_user.name,
|
||||
"username" => suggested_user.username,
|
||||
"summary" => suggested_user.summary,
|
||||
"summary" => suggested_user.profile.summary,
|
||||
"profile_image_url" => Images::Profile.call(suggested_user.profile_image_url, length: 90),
|
||||
"following" => false,
|
||||
)
|
||||
|
|
|
|||
|
|
@ -1,7 +1,12 @@
|
|||
require "rails_helper"
|
||||
|
||||
RSpec.describe "UsersOnboarding", type: :request do
|
||||
let(:user) { create(:user, saw_onboarding: false, location: "Llama Town") }
|
||||
let!(:user) do
|
||||
create(:user,
|
||||
saw_onboarding: false,
|
||||
_skip_creating_profile: true,
|
||||
profile: create(:profile, location: "Llama Town"))
|
||||
end
|
||||
|
||||
describe "PATCH /onboarding_update" do
|
||||
context "when signed in" do
|
||||
|
|
|
|||
|
|
@ -16,9 +16,8 @@ RSpec.describe Profiles::Update, type: :service do
|
|||
let(:user) { profile.user }
|
||||
|
||||
it "correctly typecasts new attributes", :aggregate_failures do
|
||||
described_class.call(user, profile: { location: 123, education: "false" })
|
||||
expect(user.location).to eq "123"
|
||||
expect(profile.education).to eq "false"
|
||||
described_class.call(user, profile: { location: 123 })
|
||||
expect(user.profile.location).to eq "123"
|
||||
end
|
||||
|
||||
it "removes old attributes from the profile" do
|
||||
|
|
@ -87,7 +86,7 @@ RSpec.describe Profiles::Update, type: :service do
|
|||
|
||||
it "enqueues resave articles job when changing summary" do
|
||||
sidekiq_assert_resave_article_worker(user) do
|
||||
described_class.call(user, profile: { summary: "#{user.summary} changed" })
|
||||
described_class.call(user, profile: { summary: "#{user.profile.summary} changed" })
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
|||
|
|
@ -32,7 +32,6 @@ seeder.create_if_doesnt_exist(User, "email", "admin@forem.local") do
|
|||
email: "admin@forem.local",
|
||||
username: "Admin_McAdmin",
|
||||
profile_image: File.open(Rails.root.join("app/assets/images/#{rand(1..40)}.png")),
|
||||
website_url: Faker::Internet.url,
|
||||
confirmed_at: Time.current,
|
||||
password: "password",
|
||||
password_confirmation: "password",
|
||||
|
|
@ -51,6 +50,7 @@ seeder.create_if_doesnt_exist(User, "email", "admin@forem.local") do
|
|||
work: "Software developer at Company",
|
||||
location: "Edinburgh",
|
||||
education: "University of Life",
|
||||
website_url: Faker::Internet.url,
|
||||
)
|
||||
|
||||
user.add_role(:super_admin)
|
||||
|
|
@ -71,7 +71,6 @@ seeder.create_if_doesnt_exist(User, "email", "trusted-user-1@forem.local") do
|
|||
email: "trusted-user-1@forem.local",
|
||||
username: "trusted_user_1",
|
||||
profile_image: File.open(Rails.root.join("app/assets/images/#{rand(1..40)}.png")),
|
||||
website_url: Faker::Internet.url,
|
||||
confirmed_at: Time.current,
|
||||
password: "password",
|
||||
password_confirmation: "password",
|
||||
|
|
@ -84,6 +83,8 @@ seeder.create_if_doesnt_exist(User, "email", "trusted-user-1@forem.local") do
|
|||
email_follower_notifications: false,
|
||||
)
|
||||
|
||||
user.profile.update(website_url: Faker::Internet.url)
|
||||
|
||||
user.add_role(:trusted)
|
||||
end
|
||||
|
||||
|
|
@ -113,9 +114,7 @@ seeder.create_if_doesnt_exist(User, "email", "change-password-user@forem.com") d
|
|||
name: "Change Password User",
|
||||
email: "change-password-user@forem.com",
|
||||
username: "changepassworduser",
|
||||
summary: Faker::Lorem.paragraph_by_chars(number: 199, supplemental: false),
|
||||
profile_image: File.open(Rails.root.join("app/assets/images/#{rand(1..40)}.png")),
|
||||
website_url: Faker::Internet.url,
|
||||
confirmed_at: Time.current,
|
||||
password: "password",
|
||||
password_confirmation: "password",
|
||||
|
|
@ -127,6 +126,10 @@ seeder.create_if_doesnt_exist(User, "email", "change-password-user@forem.com") d
|
|||
email_comment_notifications: false,
|
||||
email_follower_notifications: false,
|
||||
)
|
||||
user.profile.update(
|
||||
summary: Faker::Lorem.paragraph_by_chars(number: 199, supplemental: false),
|
||||
website_url: Faker::Internet.url,
|
||||
)
|
||||
user
|
||||
end
|
||||
|
||||
|
|
@ -137,9 +140,7 @@ seeder.create_if_doesnt_exist(User, "email", "article-editor-v1-user@forem.com")
|
|||
name: "Article Editor v1 User",
|
||||
email: "article-editor-v1-user@forem.local",
|
||||
username: "article_editor_v1_user",
|
||||
summary: Faker::Lorem.paragraph_by_chars(number: 199, supplemental: false),
|
||||
profile_image: File.open(Rails.root.join("app/assets/images/#{rand(1..40)}.png")),
|
||||
website_url: Faker::Internet.url,
|
||||
confirmed_at: Time.current,
|
||||
password: "password",
|
||||
password_confirmation: "password",
|
||||
|
|
@ -152,6 +153,10 @@ seeder.create_if_doesnt_exist(User, "email", "article-editor-v1-user@forem.com")
|
|||
email_comment_notifications: false,
|
||||
email_follower_notifications: false,
|
||||
)
|
||||
user.profile.update(
|
||||
summary: Faker::Lorem.paragraph_by_chars(number: 199, supplemental: false),
|
||||
website_url: Faker::Internet.url,
|
||||
)
|
||||
user
|
||||
end
|
||||
|
||||
|
|
@ -162,9 +167,7 @@ seeder.create_if_doesnt_exist(User, "email", "article-editor-v2-user@forem.com")
|
|||
name: "Article Editor v2 User",
|
||||
email: "article-editor-v2-user@forem.local",
|
||||
username: "article_editor_v2_user",
|
||||
summary: Faker::Lorem.paragraph_by_chars(number: 199, supplemental: false),
|
||||
profile_image: File.open(Rails.root.join("app/assets/images/#{rand(1..40)}.png")),
|
||||
website_url: Faker::Internet.url,
|
||||
confirmed_at: Time.current,
|
||||
password: "password",
|
||||
password_confirmation: "password",
|
||||
|
|
@ -176,6 +179,10 @@ seeder.create_if_doesnt_exist(User, "email", "article-editor-v2-user@forem.com")
|
|||
email_comment_notifications: false,
|
||||
email_follower_notifications: false,
|
||||
)
|
||||
user.profile.update(
|
||||
summary: Faker::Lorem.paragraph_by_chars(number: 199, supplemental: false),
|
||||
website_url: Faker::Internet.url,
|
||||
)
|
||||
user
|
||||
end
|
||||
|
||||
|
|
@ -186,9 +193,7 @@ chat_user_1 = seeder.create_if_doesnt_exist(User, "email", "chat-user-1@forem.lo
|
|||
name: "Chat user 1",
|
||||
email: "chat-user-1@forem.local",
|
||||
username: "chat_user_1",
|
||||
summary: Faker::Lorem.paragraph_by_chars(number: 199, supplemental: false),
|
||||
profile_image: File.open(Rails.root.join("app/assets/images/#{rand(1..40)}.png")),
|
||||
website_url: Faker::Internet.url,
|
||||
confirmed_at: Time.current,
|
||||
password: "password",
|
||||
password_confirmation: "password",
|
||||
|
|
@ -200,6 +205,10 @@ chat_user_1 = seeder.create_if_doesnt_exist(User, "email", "chat-user-1@forem.lo
|
|||
email_comment_notifications: false,
|
||||
email_follower_notifications: false,
|
||||
)
|
||||
user.profile.update(
|
||||
summary: Faker::Lorem.paragraph_by_chars(number: 199, supplemental: false),
|
||||
website_url: Faker::Internet.url,
|
||||
)
|
||||
user
|
||||
end
|
||||
|
||||
|
|
@ -210,9 +219,7 @@ chat_user_2 = seeder.create_if_doesnt_exist(User, "email", "chat-user-2@forem.lo
|
|||
name: "Chat user 2",
|
||||
email: "chat-user-2@forem.local",
|
||||
username: "chat_user_2",
|
||||
summary: Faker::Lorem.paragraph_by_chars(number: 199, supplemental: false),
|
||||
profile_image: File.open(Rails.root.join("app/assets/images/#{rand(1..40)}.png")),
|
||||
website_url: Faker::Internet.url,
|
||||
confirmed_at: Time.current,
|
||||
password: "password",
|
||||
password_confirmation: "password",
|
||||
|
|
@ -224,6 +231,10 @@ chat_user_2 = seeder.create_if_doesnt_exist(User, "email", "chat-user-2@forem.lo
|
|||
email_comment_notifications: false,
|
||||
email_follower_notifications: false,
|
||||
)
|
||||
user.profile.update(
|
||||
summary: Faker::Lorem.paragraph_by_chars(number: 199, supplemental: false),
|
||||
website_url: Faker::Internet.url,
|
||||
)
|
||||
user
|
||||
end
|
||||
|
||||
|
|
@ -233,9 +244,7 @@ seeder.create_if_doesnt_exist(User, "email", "notifications-user@forem.com") do
|
|||
name: "Notifications User",
|
||||
email: "notifications-user@forem.local",
|
||||
username: "notifications_user",
|
||||
summary: Faker::Lorem.paragraph_by_chars(number: 199, supplemental: false),
|
||||
profile_image: File.open(Rails.root.join("app/assets/images/#{rand(1..40)}.png")),
|
||||
website_url: Faker::Internet.url,
|
||||
confirmed_at: Time.current,
|
||||
password: "password",
|
||||
password_confirmation: "password",
|
||||
|
|
@ -247,6 +256,10 @@ seeder.create_if_doesnt_exist(User, "email", "notifications-user@forem.com") do
|
|||
email_comment_notifications: false,
|
||||
email_follower_notifications: false,
|
||||
)
|
||||
user.profile.update(
|
||||
summary: Faker::Lorem.paragraph_by_chars(number: 199, supplemental: false),
|
||||
website_url: Faker::Internet.url,
|
||||
)
|
||||
|
||||
follow = admin_user.follows.create!(followable: user)
|
||||
Notification.send_new_follower_notification_without_delay(follow)
|
||||
|
|
@ -259,9 +272,7 @@ seeder.create_if_doesnt_exist(User, "email", "liquid-tags-user@forem.com") do
|
|||
name: "Liquid tags User",
|
||||
email: "liquid-tags-user@forem.local",
|
||||
username: "liquid_tags_user",
|
||||
summary: Faker::Lorem.paragraph_by_chars(number: 199, supplemental: false),
|
||||
profile_image: File.open(Rails.root.join("app/assets/images/#{rand(1..40)}.png")),
|
||||
website_url: Faker::Internet.url,
|
||||
confirmed_at: Time.current,
|
||||
password: "password",
|
||||
password_confirmation: "password",
|
||||
|
|
@ -273,6 +284,10 @@ seeder.create_if_doesnt_exist(User, "email", "liquid-tags-user@forem.com") do
|
|||
email_comment_notifications: false,
|
||||
email_follower_notifications: false,
|
||||
)
|
||||
liquid_tags_user.profile.update(
|
||||
summary: Faker::Lorem.paragraph_by_chars(number: 199, supplemental: false),
|
||||
website_url: Faker::Internet.url,
|
||||
)
|
||||
|
||||
admin_user.follows.create!(followable: liquid_tags_user)
|
||||
end
|
||||
|
|
@ -389,9 +404,7 @@ seeder.create_if_doesnt_exist(User, "email", "series-user@forem.com") do
|
|||
name: "Series User",
|
||||
email: "series-user@forem.local",
|
||||
username: "series_user",
|
||||
summary: Faker::Lorem.paragraph_by_chars(number: 199, supplemental: false),
|
||||
profile_image: File.open(Rails.root.join("app/assets/images/#{rand(1..40)}.png")),
|
||||
website_url: Faker::Internet.url,
|
||||
confirmed_at: Time.current,
|
||||
password: "password",
|
||||
password_confirmation: "password",
|
||||
|
|
@ -404,6 +417,7 @@ seeder.create_if_doesnt_exist(User, "email", "series-user@forem.com") do
|
|||
work: "Software developer at Company",
|
||||
location: "Edinburgh",
|
||||
education: "University of Life",
|
||||
website_url: Faker::Internet.url,
|
||||
)
|
||||
series_user.notification_setting.update(
|
||||
email_comment_notifications: false,
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue