mirror of
https://github.com/discourse/discourse.git
synced 2025-06-04 20:44:40 +08:00
DEV: Make service contracts immutable
We decided to make contracts immutable once their validations have run. Indeed, it doesn’t make a lot of sense to modify a contract value outside the contract itself. If processing is needed, then it should happen inside the contract itself.
This commit is contained in:

committed by
Loïc Guitaut

parent
6d918c6307
commit
c78211cf8d
@ -202,13 +202,18 @@ module Service
|
|||||||
attributes = class_name.attribute_names.map(&:to_sym)
|
attributes = class_name.attribute_names.map(&:to_sym)
|
||||||
default_values = {}
|
default_values = {}
|
||||||
default_values = context[default_values_from].slice(*attributes) if default_values_from
|
default_values = context[default_values_from].slice(*attributes) if default_values_from
|
||||||
contract = class_name.new(default_values.merge(context[:params].slice(*attributes)))
|
contract =
|
||||||
|
class_name.new(
|
||||||
|
**default_values.merge(context[:params].slice(*attributes)),
|
||||||
|
options: context[:options],
|
||||||
|
)
|
||||||
context[contract_name] = contract
|
context[contract_name] = contract
|
||||||
context[result_key] = Context.build
|
context[result_key] = Context.build
|
||||||
if contract.invalid?
|
if contract.invalid?
|
||||||
context[result_key].fail(errors: contract.errors, parameters: contract.raw_attributes)
|
context[result_key].fail(errors: contract.errors, parameters: contract.raw_attributes)
|
||||||
context.fail!
|
context.fail!
|
||||||
end
|
end
|
||||||
|
contract.freeze
|
||||||
end
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
|
@ -8,12 +8,17 @@ class Service::ContractBase
|
|||||||
|
|
||||||
delegate :slice, :merge, to: :to_hash
|
delegate :slice, :merge, to: :to_hash
|
||||||
|
|
||||||
def [](key)
|
def initialize(*args, options: nil, **kwargs)
|
||||||
public_send(key)
|
@__options__ = options
|
||||||
|
super(*args, **kwargs)
|
||||||
end
|
end
|
||||||
|
|
||||||
def []=(key, value)
|
def options
|
||||||
public_send("#{key}=", value)
|
@__options__
|
||||||
|
end
|
||||||
|
|
||||||
|
def [](key)
|
||||||
|
public_send(key)
|
||||||
end
|
end
|
||||||
|
|
||||||
def to_hash
|
def to_hash
|
||||||
|
@ -46,6 +46,16 @@ module Chat
|
|||||||
|
|
||||||
validates :chat_channel_id, presence: true
|
validates :chat_channel_id, presence: true
|
||||||
validates :message, presence: true, if: -> { upload_ids.blank? }
|
validates :message, presence: true, if: -> { upload_ids.blank? }
|
||||||
|
|
||||||
|
after_validation do
|
||||||
|
next if message.blank?
|
||||||
|
self.message =
|
||||||
|
TextCleaner.clean(
|
||||||
|
message,
|
||||||
|
strip_whitespaces: options.strip_whitespaces,
|
||||||
|
strip_zero_width_spaces: true,
|
||||||
|
)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
model :channel
|
model :channel
|
||||||
step :enforce_membership
|
step :enforce_membership
|
||||||
@ -57,7 +67,6 @@ module Chat
|
|||||||
policy :ensure_valid_thread_for_channel
|
policy :ensure_valid_thread_for_channel
|
||||||
policy :ensure_thread_matches_parent
|
policy :ensure_thread_matches_parent
|
||||||
model :uploads, optional: true
|
model :uploads, optional: true
|
||||||
step :clean_message
|
|
||||||
model :message_instance, :instantiate_message
|
model :message_instance, :instantiate_message
|
||||||
transaction do
|
transaction do
|
||||||
step :create_excerpt
|
step :create_excerpt
|
||||||
@ -134,14 +143,6 @@ module Chat
|
|||||||
guardian.user.uploads.where(id: params[:upload_ids])
|
guardian.user.uploads.where(id: params[:upload_ids])
|
||||||
end
|
end
|
||||||
|
|
||||||
def clean_message(params:, options:)
|
|
||||||
params[:message] = TextCleaner.clean(
|
|
||||||
params[:message],
|
|
||||||
strip_whitespaces: options.strip_whitespaces,
|
|
||||||
strip_zero_width_spaces: true,
|
|
||||||
)
|
|
||||||
end
|
|
||||||
|
|
||||||
def instantiate_message(channel:, guardian:, params:, uploads:, thread:, reply:, options:)
|
def instantiate_message(channel:, guardian:, params:, uploads:, thread:, reply:, options:)
|
||||||
channel.chat_messages.new(
|
channel.chat_messages.new(
|
||||||
user: guardian.user,
|
user: guardian.user,
|
||||||
|
@ -24,8 +24,9 @@ module Chat
|
|||||||
attribute :include_category_channels, :boolean, default: true
|
attribute :include_category_channels, :boolean, default: true
|
||||||
attribute :include_direct_message_channels, :boolean, default: true
|
attribute :include_direct_message_channels, :boolean, default: true
|
||||||
attribute :excluded_memberships_channel_id, :integer
|
attribute :excluded_memberships_channel_id, :integer
|
||||||
|
|
||||||
|
after_validation { self.term = term&.downcase&.strip&.gsub(/^[@#]+/, "") }
|
||||||
end
|
end
|
||||||
step :clean_term
|
|
||||||
model :memberships, optional: true
|
model :memberships, optional: true
|
||||||
model :users, optional: true
|
model :users, optional: true
|
||||||
model :groups, optional: true
|
model :groups, optional: true
|
||||||
@ -34,10 +35,6 @@ module Chat
|
|||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
def clean_term(params:)
|
|
||||||
params[:term] = params[:term]&.downcase&.strip&.gsub(/^[@#]+/, "")
|
|
||||||
end
|
|
||||||
|
|
||||||
def fetch_memberships(guardian:)
|
def fetch_memberships(guardian:)
|
||||||
::Chat::ChannelMembershipManager.all_for_user(guardian.user)
|
::Chat::ChannelMembershipManager.all_for_user(guardian.user)
|
||||||
end
|
end
|
||||||
|
@ -33,6 +33,16 @@ module Chat
|
|||||||
|
|
||||||
validates :message_id, presence: true
|
validates :message_id, presence: true
|
||||||
validates :message, presence: true, if: -> { upload_ids.blank? }
|
validates :message, presence: true, if: -> { upload_ids.blank? }
|
||||||
|
|
||||||
|
after_validation do
|
||||||
|
next if message.blank?
|
||||||
|
self.message =
|
||||||
|
TextCleaner.clean(
|
||||||
|
message,
|
||||||
|
strip_whitespaces: options.strip_whitespaces,
|
||||||
|
strip_zero_width_spaces: true,
|
||||||
|
)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
model :message
|
model :message
|
||||||
model :uploads, optional: true
|
model :uploads, optional: true
|
||||||
@ -40,7 +50,6 @@ module Chat
|
|||||||
model :membership
|
model :membership
|
||||||
policy :can_modify_channel_message
|
policy :can_modify_channel_message
|
||||||
policy :can_modify_message
|
policy :can_modify_message
|
||||||
step :clean_message
|
|
||||||
transaction do
|
transaction do
|
||||||
step :modify_message
|
step :modify_message
|
||||||
step :update_excerpt
|
step :update_excerpt
|
||||||
@ -90,14 +99,6 @@ module Chat
|
|||||||
guardian.can_edit_chat?(message)
|
guardian.can_edit_chat?(message)
|
||||||
end
|
end
|
||||||
|
|
||||||
def clean_message(params:, options:)
|
|
||||||
params[:message] = TextCleaner.clean(
|
|
||||||
params[:message],
|
|
||||||
strip_zero_width_spaces: true,
|
|
||||||
strip_whitespaces: options.strip_whitespaces,
|
|
||||||
)
|
|
||||||
end
|
|
||||||
|
|
||||||
def modify_message(params:, message:, guardian:, uploads:)
|
def modify_message(params:, message:, guardian:, uploads:)
|
||||||
message.message = params[:message]
|
message.message = params[:message]
|
||||||
message.last_editor_id = guardian.user.id
|
message.last_editor_id = guardian.user.id
|
||||||
|
Reference in New Issue
Block a user