diff --git a/app/models/person.rb b/app/models/person.rb index 819e930da4c..f32055834b7 100644 --- a/app/models/person.rb +++ b/app/models/person.rb @@ -278,6 +278,14 @@ def self.fields_edit_requestable methods: ["url", "country_iso2"], }.freeze + USER_COMMON_SERIALIZE_OPTIONS = { + only: ["name", "gender"], + methods: ["country_iso2"], + # grrr… some tests (and apparently also API endpoints) rely on serializing this data _through_ person. + # Not a good code design decision, but very cumbersome to properly refactor. Signed GB 2025-01-09 + include: User::DEFAULT_SERIALIZE_OPTIONS[:include], + }.freeze + def personal_records [self.ranksAverage, self.ranksSingle].compact.flatten end @@ -306,8 +314,17 @@ def serializable_hash(options = nil) json[:incorrect_wca_id_claim_count] = incorrect_wca_id_claim_count end + # Passing down options from Person to User (which are completely different models in the DB!) + # is a horrible idea. Unfortunately, our external APIs have come to rely on it, + # so we need to hack around it. + # - `merge_union` makes sure that only values specified in USER_COMMON_SERIALIZE_OPTIONS kick in + # - `filter` makes sure that when the result of `merge_union` are empty, the defaults from + # User::DEFAULT_SERIALIZE_OPTIONS can override. + user_override_options = USER_COMMON_SERIALIZE_OPTIONS.merge_union(options&.stringify_keys) + .filter { |_, v| v.present? } + # If there's a user for this Person, merge in all their data, # the Person's data takes priority, though. - (user || User.new).serializable_hash(options).merge(json) + (user || User.new).serializable_hash(user_override_options).merge(json) end end diff --git a/config/initializers/monkey_patches.rb b/config/initializers/monkey_patches.rb index b0ec1cd5b41..003ccbe9aba 100644 --- a/config/initializers/monkey_patches.rb +++ b/config/initializers/monkey_patches.rb @@ -51,6 +51,14 @@ def xss_aware_join(delimiter = '') end end + Hash.class_eval do + def merge_union(other = nil) + self.to_h do |key, value| + [key, value & (other&.fetch(key.to_s, []) || [])] + end + end + end + ActiveSupport::Duration.class_eval do def in_seconds self.to_i