2019-05-02 18:17:27 -04:00
|
|
|
# frozen_string_literal: true
|
|
|
|
|
2014-05-27 13:54:04 -04:00
|
|
|
class UserProfile < ActiveRecord::Base
|
2022-06-14 12:27:01 -04:00
|
|
|
BAKED_VERSION = 1
|
|
|
|
|
2014-06-10 01:19:08 -04:00
|
|
|
belongs_to :user, inverse_of: :user_profile
|
2019-04-28 23:58:52 -04:00
|
|
|
belongs_to :card_background_upload, class_name: "Upload"
|
|
|
|
belongs_to :profile_background_upload, class_name: "Upload"
|
2019-11-08 00:34:24 -05:00
|
|
|
belongs_to :granted_title_badge, class_name: "Badge"
|
2019-12-09 14:15:47 -05:00
|
|
|
belongs_to :featured_topic, class_name: 'Topic'
|
2022-06-14 12:27:01 -04:00
|
|
|
|
2022-06-08 19:24:30 -04:00
|
|
|
has_many :upload_references, as: :target, dependent: :destroy
|
2022-06-14 12:27:01 -04:00
|
|
|
has_many :user_profile_views, dependent: :destroy
|
2014-06-10 01:19:08 -04:00
|
|
|
|
2022-04-28 05:00:02 -04:00
|
|
|
validates :bio_raw, length: { maximum: 3000 }, watched_words: true
|
2022-09-20 22:07:06 -04:00
|
|
|
validates :website, url: true, length: { maximum: 3000 }, allow_blank: true, if: :validate_website?
|
|
|
|
validates :location, length: { maximum: 3000 }, watched_words: true
|
2014-06-10 01:19:08 -04:00
|
|
|
validates :user, presence: true
|
2022-04-28 05:00:02 -04:00
|
|
|
|
2022-06-14 12:27:01 -04:00
|
|
|
validate :website_domain_validator, if: :validate_website?
|
|
|
|
|
2014-06-10 01:19:08 -04:00
|
|
|
before_save :cook
|
2022-06-14 12:27:01 -04:00
|
|
|
before_save :apply_watched_words, if: :location?
|
|
|
|
|
2014-07-22 21:42:24 -04:00
|
|
|
after_save :trigger_badges
|
2021-10-29 10:58:05 -04:00
|
|
|
after_save :pull_hotlinked_image
|
2014-06-10 01:19:08 -04:00
|
|
|
|
2022-06-08 19:24:30 -04:00
|
|
|
after_save do
|
|
|
|
if saved_change_to_profile_background_upload_id? || saved_change_to_card_background_upload_id? || saved_change_to_bio_raw?
|
|
|
|
upload_ids = [self.profile_background_upload_id, self.card_background_upload_id] + Upload.extract_upload_ids(self.bio_raw)
|
|
|
|
UploadReference.ensure_exist!(upload_ids: upload_ids, target: self)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2021-10-29 10:58:05 -04:00
|
|
|
attr_accessor :skip_pull_hotlinked_image
|
|
|
|
|
2014-12-07 18:23:53 -05:00
|
|
|
def bio_excerpt(length = 350, opts = {})
|
2019-05-29 11:05:52 -04:00
|
|
|
return nil if bio_cooked.blank?
|
2017-05-18 16:39:48 -04:00
|
|
|
excerpt = PrettyText.excerpt(bio_cooked, length, opts).sub(/<br>$/, '')
|
2014-11-25 16:14:21 -05:00
|
|
|
return excerpt if excerpt.blank? || (user.has_trust_level?(TrustLevel[1]) && !user.suspended?)
|
2014-06-10 01:19:08 -04:00
|
|
|
PrettyText.strip_links(excerpt)
|
|
|
|
end
|
|
|
|
|
|
|
|
def bio_processed
|
2014-11-25 16:14:21 -05:00
|
|
|
return bio_cooked if bio_cooked.blank? || (user.has_trust_level?(TrustLevel[1]) && !user.suspended?)
|
2014-06-10 01:19:08 -04:00
|
|
|
PrettyText.strip_links(bio_cooked)
|
|
|
|
end
|
|
|
|
|
|
|
|
def bio_summary
|
2014-12-07 18:23:53 -05:00
|
|
|
bio_excerpt(500, strip_links: true, text_entities: true)
|
2014-06-10 01:19:08 -04:00
|
|
|
end
|
|
|
|
|
|
|
|
def recook_bio
|
|
|
|
self.bio_raw_will_change!
|
|
|
|
cook
|
|
|
|
end
|
|
|
|
|
2014-10-20 12:11:36 -04:00
|
|
|
def upload_card_background(upload)
|
2019-04-28 23:58:52 -04:00
|
|
|
self.update!(card_background_upload: upload)
|
2014-10-16 15:05:36 -04:00
|
|
|
end
|
|
|
|
|
2014-10-20 12:11:36 -04:00
|
|
|
def clear_card_background
|
2019-04-28 23:58:52 -04:00
|
|
|
self.update!(card_background_upload: nil)
|
2014-10-16 15:05:36 -04:00
|
|
|
end
|
|
|
|
|
2014-06-11 21:52:50 -04:00
|
|
|
def upload_profile_background(upload)
|
2019-04-28 23:58:52 -04:00
|
|
|
self.update!(profile_background_upload: upload)
|
2014-06-11 21:52:50 -04:00
|
|
|
end
|
|
|
|
|
|
|
|
def clear_profile_background
|
2019-04-28 23:58:52 -04:00
|
|
|
self.update!(profile_background_upload: nil)
|
2014-06-11 21:52:50 -04:00
|
|
|
end
|
|
|
|
|
2014-08-05 02:37:56 -04:00
|
|
|
def self.rebake_old(limit)
|
|
|
|
problems = []
|
|
|
|
UserProfile.where('bio_cooked_version IS NULL OR bio_cooked_version < ?', BAKED_VERSION)
|
|
|
|
.limit(limit).each do |p|
|
|
|
|
begin
|
|
|
|
p.rebake!
|
|
|
|
rescue => e
|
|
|
|
problems << { profile: p, ex: e }
|
|
|
|
end
|
|
|
|
end
|
|
|
|
problems
|
|
|
|
end
|
|
|
|
|
|
|
|
def rebake!
|
|
|
|
update_columns(bio_cooked: cooked, bio_cooked_version: BAKED_VERSION)
|
|
|
|
end
|
|
|
|
|
2018-05-07 04:03:26 -04:00
|
|
|
def self.import_url_for_user(background_url, user, options = nil)
|
2021-06-04 08:13:58 -04:00
|
|
|
if SiteSetting.verbose_upload_logging
|
|
|
|
Rails.logger.warn("Verbose Upload Logging: Downloading profile background from #{background_url}")
|
|
|
|
end
|
|
|
|
|
2018-05-07 04:03:26 -04:00
|
|
|
tempfile = FileHelper.download(
|
|
|
|
background_url,
|
|
|
|
max_file_size: SiteSetting.max_image_size_kb.kilobytes,
|
|
|
|
tmp_file_name: "sso-profile-background",
|
|
|
|
follow_redirect: true
|
|
|
|
)
|
|
|
|
|
|
|
|
return unless tempfile
|
|
|
|
|
|
|
|
ext = FastImage.type(tempfile).to_s
|
|
|
|
tempfile.rewind
|
|
|
|
|
|
|
|
is_card_background = !options || options[:is_card_background]
|
|
|
|
type = is_card_background ? "card_background" : "profile_background"
|
|
|
|
|
|
|
|
upload = UploadCreator.new(tempfile, "external-profile-background." + ext, origin: background_url, type: type).create_for(user.id)
|
|
|
|
|
|
|
|
if (is_card_background)
|
|
|
|
user.user_profile.upload_card_background(upload)
|
|
|
|
else
|
|
|
|
user.user_profile.upload_profile_background(upload)
|
|
|
|
end
|
|
|
|
|
|
|
|
rescue Net::ReadTimeout, OpenURI::HTTPError
|
|
|
|
# skip saving, we are not connected to the net
|
|
|
|
ensure
|
|
|
|
tempfile.close! if tempfile && tempfile.respond_to?(:close!)
|
|
|
|
end
|
|
|
|
|
2014-07-03 03:29:44 -04:00
|
|
|
protected
|
|
|
|
|
2014-07-22 21:42:24 -04:00
|
|
|
def trigger_badges
|
|
|
|
BadgeGranter.queue_badge_grant(Badge::Trigger::UserChange, user: self)
|
2014-07-03 03:29:44 -04:00
|
|
|
end
|
|
|
|
|
2021-10-29 10:58:05 -04:00
|
|
|
def pull_hotlinked_image
|
|
|
|
if !skip_pull_hotlinked_image && saved_change_to_bio_raw?
|
|
|
|
Jobs.enqueue_in(
|
|
|
|
SiteSetting.editing_grace_period,
|
|
|
|
:pull_user_profile_hotlinked_images,
|
|
|
|
user_id: self.user_id
|
|
|
|
)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2014-06-10 01:19:08 -04:00
|
|
|
private
|
|
|
|
|
2022-06-14 12:27:01 -04:00
|
|
|
def self.remove_featured_topic_from_all_profiles(topic)
|
|
|
|
where(featured_topic_id: topic.id).update_all(featured_topic_id: nil)
|
|
|
|
end
|
|
|
|
|
2014-08-05 02:37:56 -04:00
|
|
|
def cooked
|
|
|
|
if self.bio_raw.present?
|
2014-09-05 01:20:39 -04:00
|
|
|
PrettyText.cook(self.bio_raw, omit_nofollow: user.has_trust_level?(TrustLevel[3]) && !SiteSetting.tl3_links_no_follow)
|
2014-08-05 02:37:56 -04:00
|
|
|
else
|
|
|
|
nil
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2014-06-10 01:19:08 -04:00
|
|
|
def cook
|
|
|
|
if self.bio_raw.present?
|
2014-08-05 02:37:56 -04:00
|
|
|
if bio_raw_changed?
|
|
|
|
self.bio_cooked = cooked
|
|
|
|
self.bio_cooked_version = BAKED_VERSION
|
|
|
|
end
|
2014-06-10 01:19:08 -04:00
|
|
|
else
|
|
|
|
self.bio_cooked = nil
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2022-06-14 12:27:01 -04:00
|
|
|
def apply_watched_words
|
2022-07-26 11:15:42 -04:00
|
|
|
self.location = WordWatcher.apply_to_text(location)
|
2022-06-14 12:27:01 -04:00
|
|
|
end
|
|
|
|
|
2016-12-26 10:24:54 -05:00
|
|
|
def website_domain_validator
|
2020-07-26 20:23:54 -04:00
|
|
|
allowed_domains = SiteSetting.allowed_user_website_domains
|
2017-04-18 03:48:51 -04:00
|
|
|
return if (allowed_domains.blank? || self.website.blank?)
|
2016-12-26 10:24:54 -05:00
|
|
|
|
2018-05-17 03:51:24 -04:00
|
|
|
domain = begin
|
|
|
|
URI.parse(self.website).host
|
2018-08-14 06:23:32 -04:00
|
|
|
rescue URI::Error
|
2018-05-17 03:51:24 -04:00
|
|
|
end
|
2017-04-18 03:48:51 -04:00
|
|
|
self.errors.add :base, (I18n.t('user.website.domain_not_allowed', domains: allowed_domains.split('|').join(", "))) unless allowed_domains.split('|').include?(domain)
|
2016-12-26 10:24:54 -05:00
|
|
|
end
|
|
|
|
|
2022-06-14 12:27:01 -04:00
|
|
|
def validate_website?
|
|
|
|
new_record? || website_changed?
|
2019-12-09 14:15:47 -05:00
|
|
|
end
|
2014-05-27 13:54:04 -04:00
|
|
|
end
|
2014-05-29 00:59:14 -04:00
|
|
|
|
|
|
|
# == Schema Information
|
|
|
|
#
|
|
|
|
# Table name: user_profiles
|
|
|
|
#
|
2019-04-28 23:58:52 -04:00
|
|
|
# user_id :integer not null, primary key
|
2022-09-20 22:07:06 -04:00
|
|
|
# location :string(3000)
|
|
|
|
# website :string(3000)
|
2019-04-28 23:58:52 -04:00
|
|
|
# bio_raw :text
|
|
|
|
# bio_cooked :text
|
|
|
|
# dismissed_banner_key :integer
|
|
|
|
# bio_cooked_version :integer
|
|
|
|
# badge_granted_title :boolean default(FALSE)
|
|
|
|
# views :integer default(0), not null
|
|
|
|
# profile_background_upload_id :integer
|
|
|
|
# card_background_upload_id :integer
|
2019-11-19 05:20:14 -05:00
|
|
|
# granted_title_badge_id :bigint
|
2019-12-30 01:13:27 -05:00
|
|
|
# featured_topic_id :integer
|
2014-08-06 23:33:11 -04:00
|
|
|
#
|
|
|
|
# Indexes
|
|
|
|
#
|
2020-01-09 11:08:55 -05:00
|
|
|
# index_user_profiles_on_bio_cooked_version (bio_cooked_version)
|
|
|
|
# index_user_profiles_on_card_background_upload_id (card_background_upload_id)
|
|
|
|
# index_user_profiles_on_granted_title_badge_id (granted_title_badge_id)
|
|
|
|
# index_user_profiles_on_profile_background_upload_id (profile_background_upload_id)
|
2014-05-29 00:59:14 -04:00
|
|
|
#
|
2019-05-13 10:53:42 -04:00
|
|
|
# Foreign Keys
|
|
|
|
#
|
|
|
|
# fk_rails_... (card_background_upload_id => uploads.id)
|
2019-11-08 00:34:24 -05:00
|
|
|
# fk_rails_... (granted_title_badge_id => badges.id)
|
2019-11-19 05:20:14 -05:00
|
|
|
# fk_rails_... (profile_background_upload_id => uploads.id)
|
2019-05-13 10:53:42 -04:00
|
|
|
#
|