docbrown/app/services/users/update.rb
Michael Kohl 08d82e7256
Profile generalization: cleanup (#12947)
* Remove hardcoded instances of education field

* WIP Access display_email_on_profile via User Settings

* Remove unused profile column

* WIP Fix reference to bg_color_hex and text_color_hex

* 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

* Match user settings changes

* 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 delegation, rename inline concern

* Drop profile columns from users table

* 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

* Fix formatting issues

* Profiles::Update -> Users::Update

* Remove RegistrationsController#resolve_profile_field_issues

* Fix schema.rb

* More cleanup

* Fix specs

* Fix remaining spec

Co-authored-by: Jacob Herrington <jacobherringtondeveloper@gmail.com>
2021-08-20 16:36:02 +02:00

122 lines
3.5 KiB
Ruby

module Users
# Deals with updates that affect fields on +Profile+ and/or +User+ in a transparent way.
class Update
using HashAnyKey
include ImageUploads
CORE_PROFILE_FIELDS = %i[summary].freeze
CORE_USER_FIELDS = %i[name username profile_image].freeze
CORE_SETTINGS_FIELDS = %i[brand_color1 brand_color2].freeze
# @param user [User] the user whose profile we are updating
# @param updated_attributes [Hash<Symbol, Hash<Symbol, Object>>] the profile
# and/or user attributes to update. The corresponding has keys are +:user+ and
# +:profile+ respectively.
# @example
# Users::Update.call(
# current_user,
# profile: { website_url: "https://example.com" },
# )
# @return [Users::Update] a class instance that can be used for success checks
def self.call(user, updated_attributes = {})
new(user, updated_attributes).call
end
def initialize(user, updated_attributes)
@user = user
@profile = user.profile
@users_setting = user.setting
@updated_profile_attributes = updated_attributes[:profile] || {}
@updated_user_attributes = updated_attributes[:user].to_h || {}
@updated_users_setting_attributes = updated_attributes[:users_setting].to_h || {}
@errors = []
@success = false
end
def call
if update_successful?
@success = true
@user.touch(:profile_updated_at)
conditionally_resave_articles
else
errors.concat(@profile.errors.full_messages)
errors.concat(@user.errors.full_messages)
errors.concat(@users_setting.errors.full_messages)
Honeycomb.add_field("error", errors_as_sentence)
Honeycomb.add_field("errored", true)
end
self
end
def success?
@success
end
def errors_as_sentence
errors.to_sentence
end
private
attr_reader :errors
def update_successful?
return false unless verify_profile_image
Profile.transaction do
update_profile
@user.update!(@updated_user_attributes)
@users_setting.update!(@updated_users_setting_attributes)
end
true
rescue ActiveRecord::RecordInvalid
false
end
def verify_profile_image
image = @updated_user_attributes[:profile_image]
return true unless image
return true if valid_image_file?(image) && valid_filename?(image)
false
end
def valid_image_file?(image)
return true if file?(image)
errors.append(IS_NOT_FILE_MESSAGE)
false
end
def valid_filename?(image)
return true unless long_filename?(image)
errors.append(FILENAME_TOO_LONG_MESSAGE)
false
end
def update_profile
# We don't update `data` directly. This uses the defined store_attributes
# so we can make use of their typecasting.
@profile.assign_attributes(@updated_profile_attributes)
# Before saving, filter out obsolete profile fields
@profile.data.slice!(*Profile.attributes)
@profile.save!
end
def conditionally_resave_articles
return unless resave_articles? && !@user.suspended?
Users::ResaveArticlesWorker.perform_async(@user.id)
end
def resave_articles?
user_fields = CORE_USER_FIELDS + Authentication::Providers.username_fields
@updated_user_attributes.any_key?(user_fields) ||
@updated_profile_attributes.any_key?(CORE_PROFILE_FIELDS) ||
@updated_users_setting_attributes.any_key?(CORE_SETTINGS_FIELDS)
end
end
end