mirror of
https://github.com/discourse/discourse.git
synced 2025-05-22 05:01:14 +08:00
DEV: Stop injecting a service result object in the caller object
Currently, when calling a service with its block form, a `#result` method is automatically created on the caller object. Even if it never clashed so far, this could happen. This patch removes that method, and instead use a more classical way of doing things: the result object is now provided as an argument to the main block. This means if we need to access the result object in an outcome block, it will be done like this from now on: ```ruby MyService.call(params) do |result| on_success do # do something with the result object do_something(result) end end ``` In the same vein, this patch introduces the ability to match keys from the result object in the outcome blocks, like we already do with step definitions in a service. For example: ```ruby on_success do |model:, contract:| do_something(model, contract) end ``` Instead of ```ruby on_success do do_something(result.model, result.contract) end ```
This commit is contained in:

committed by
Loïc Guitaut

parent
07ff21d045
commit
f79dd5c8b5
@ -27,9 +27,9 @@ class Admin::Config::FlagsController < Admin::AdminController
|
|||||||
|
|
||||||
def create
|
def create
|
||||||
Flags::CreateFlag.call(service_params) do
|
Flags::CreateFlag.call(service_params) do
|
||||||
on_success do
|
on_success do |flag:|
|
||||||
Discourse.request_refresh!
|
Discourse.request_refresh!
|
||||||
render json: result.flag, serializer: FlagSerializer, used_flag_ids: Flag.used_flag_ids
|
render json: flag, serializer: FlagSerializer, used_flag_ids: Flag.used_flag_ids
|
||||||
end
|
end
|
||||||
on_failure { render(json: failed_json, status: 422) }
|
on_failure { render(json: failed_json, status: 422) }
|
||||||
on_failed_policy(:invalid_access) { raise Discourse::InvalidAccess }
|
on_failed_policy(:invalid_access) { raise Discourse::InvalidAccess }
|
||||||
@ -42,9 +42,9 @@ class Admin::Config::FlagsController < Admin::AdminController
|
|||||||
|
|
||||||
def update
|
def update
|
||||||
Flags::UpdateFlag.call(service_params) do
|
Flags::UpdateFlag.call(service_params) do
|
||||||
on_success do
|
on_success do |flag:|
|
||||||
Discourse.request_refresh!
|
Discourse.request_refresh!
|
||||||
render json: result.flag, serializer: FlagSerializer, used_flag_ids: Flag.used_flag_ids
|
render json: flag, serializer: FlagSerializer, used_flag_ids: Flag.used_flag_ids
|
||||||
end
|
end
|
||||||
on_failure { render(json: failed_json, status: 422) }
|
on_failure { render(json: failed_json, status: 422) }
|
||||||
on_model_not_found(:message) { raise Discourse::NotFound }
|
on_model_not_found(:message) { raise Discourse::NotFound }
|
||||||
|
@ -40,9 +40,9 @@ class Admin::SiteSettingsController < Admin::AdminController
|
|||||||
previous_value = value_or_default(SiteSetting.get(id)) if update_existing_users
|
previous_value = value_or_default(SiteSetting.get(id)) if update_existing_users
|
||||||
|
|
||||||
SiteSetting::Update.call(service_params.merge(setting_name: id, new_value: value)) do
|
SiteSetting::Update.call(service_params.merge(setting_name: id, new_value: value)) do
|
||||||
on_success do
|
on_success do |contract:|
|
||||||
if update_existing_users
|
if update_existing_users
|
||||||
SiteSettingUpdateExistingUsers.call(id, result.contract.new_value, previous_value)
|
SiteSettingUpdateExistingUsers.call(id, contract.new_value, previous_value)
|
||||||
end
|
end
|
||||||
render body: nil
|
render body: nil
|
||||||
end
|
end
|
||||||
|
@ -121,13 +121,13 @@ class Admin::UsersController < Admin::StaffController
|
|||||||
|
|
||||||
def suspend
|
def suspend
|
||||||
User::Suspend.call(service_params) do
|
User::Suspend.call(service_params) do
|
||||||
on_success do
|
on_success do |contract:, user:, full_reason:|
|
||||||
render_json_dump(
|
render_json_dump(
|
||||||
suspension: {
|
suspension: {
|
||||||
suspend_reason: result.contract.reason,
|
suspend_reason: contract.reason,
|
||||||
full_suspend_reason: result.full_reason,
|
full_suspend_reason: full_reason,
|
||||||
suspended_till: result.user.suspended_till,
|
suspended_till: user.suspended_till,
|
||||||
suspended_at: result.user.suspended_at,
|
suspended_at: user.suspended_at,
|
||||||
suspended_by: BasicUserSerializer.new(current_user, root: false).as_json,
|
suspended_by: BasicUserSerializer.new(current_user, root: false).as_json,
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
@ -316,13 +316,13 @@ class Admin::UsersController < Admin::StaffController
|
|||||||
|
|
||||||
def silence
|
def silence
|
||||||
User::Silence.call(service_params) do
|
User::Silence.call(service_params) do
|
||||||
on_success do
|
on_success do |full_reason:, user:|
|
||||||
render_json_dump(
|
render_json_dump(
|
||||||
silence: {
|
silence: {
|
||||||
silenced: true,
|
silenced: true,
|
||||||
silence_reason: result.full_reason,
|
silence_reason: full_reason,
|
||||||
silenced_till: result.user.silenced_till,
|
silenced_till: user.silenced_till,
|
||||||
silenced_at: result.user.silenced_at,
|
silenced_at: user.silenced_at,
|
||||||
silenced_by: BasicUserSerializer.new(current_user, root: false).as_json,
|
silenced_by: BasicUserSerializer.new(current_user, root: false).as_json,
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
@ -4,14 +4,11 @@ class Experiments::Toggle
|
|||||||
include Service::Base
|
include Service::Base
|
||||||
|
|
||||||
policy :current_user_is_admin
|
policy :current_user_is_admin
|
||||||
|
|
||||||
contract do
|
contract do
|
||||||
attribute :setting_name, :string
|
attribute :setting_name, :string
|
||||||
validates :setting_name, presence: true
|
validates :setting_name, presence: true
|
||||||
end
|
end
|
||||||
|
|
||||||
policy :setting_is_available
|
policy :setting_is_available
|
||||||
|
|
||||||
transaction { step :toggle }
|
transaction { step :toggle }
|
||||||
|
|
||||||
private
|
private
|
||||||
|
@ -97,8 +97,6 @@ class Service::Runner
|
|||||||
# @!visibility private
|
# @!visibility private
|
||||||
attr_reader :service, :object, :dependencies
|
attr_reader :service, :object, :dependencies
|
||||||
|
|
||||||
delegate :result, to: :object
|
|
||||||
|
|
||||||
# @!visibility private
|
# @!visibility private
|
||||||
def initialize(service, object, dependencies)
|
def initialize(service, object, dependencies)
|
||||||
@service = service
|
@service = service
|
||||||
@ -117,8 +115,7 @@ class Service::Runner
|
|||||||
|
|
||||||
# @!visibility private
|
# @!visibility private
|
||||||
def call(&block)
|
def call(&block)
|
||||||
instance_eval(&block)
|
instance_exec(result, &block)
|
||||||
setup_and_run_service
|
|
||||||
# Always have `on_failure` as the last action
|
# Always have `on_failure` as the last action
|
||||||
(
|
(
|
||||||
actions
|
actions
|
||||||
@ -132,12 +129,8 @@ class Service::Runner
|
|||||||
|
|
||||||
attr_reader :actions
|
attr_reader :actions
|
||||||
|
|
||||||
def setup_and_run_service
|
def result
|
||||||
runner = self
|
@result ||= service.call(dependencies)
|
||||||
object.instance_eval do
|
|
||||||
def result = @_result
|
|
||||||
@_result = runner.service.call(runner.dependencies)
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def failure_for?(key)
|
def failure_for?(key)
|
||||||
@ -151,6 +144,7 @@ class Service::Runner
|
|||||||
-> do
|
-> do
|
||||||
object.instance_exec(
|
object.instance_exec(
|
||||||
result[[*action[:key], args.first || action[:default_name]].join(".")],
|
result[[*action[:key], args.first || action[:default_name]].join(".")],
|
||||||
|
**result.slice(*block.parameters.filter_map { _1.last if _1.first == :keyreq }),
|
||||||
&block
|
&block
|
||||||
)
|
)
|
||||||
end,
|
end,
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
class Chat::Api::ChannelMessagesController < Chat::ApiController
|
class Chat::Api::ChannelMessagesController < Chat::ApiController
|
||||||
def index
|
def index
|
||||||
::Chat::ListChannelMessages.call(service_params) do
|
::Chat::ListChannelMessages.call(service_params) do |result|
|
||||||
on_success { render_serialized(result, ::Chat::MessagesSerializer, root: false) }
|
on_success { render_serialized(result, ::Chat::MessagesSerializer, root: false) }
|
||||||
on_failure { render(json: failed_json, status: 422) }
|
on_failure { render(json: failed_json, status: 422) }
|
||||||
on_failed_policy(:can_view_channel) { raise Discourse::InvalidAccess }
|
on_failed_policy(:can_view_channel) { raise Discourse::InvalidAccess }
|
||||||
@ -52,7 +52,7 @@ class Chat::Api::ChannelMessagesController < Chat::ApiController
|
|||||||
|
|
||||||
def update
|
def update
|
||||||
Chat::UpdateMessage.call(service_params) do
|
Chat::UpdateMessage.call(service_params) do
|
||||||
on_success { render json: success_json.merge(message_id: result[:message].id) }
|
on_success { |message:| render json: success_json.merge(message_id: message.id) }
|
||||||
on_failure { render(json: failed_json, status: 422) }
|
on_failure { render(json: failed_json, status: 422) }
|
||||||
on_model_not_found(:message) { raise Discourse::NotFound }
|
on_model_not_found(:message) { raise Discourse::NotFound }
|
||||||
on_model_errors(:message) do |model|
|
on_model_errors(:message) do |model|
|
||||||
@ -69,7 +69,9 @@ class Chat::Api::ChannelMessagesController < Chat::ApiController
|
|||||||
|
|
||||||
# users can't force a thread through JSON API
|
# users can't force a thread through JSON API
|
||||||
Chat::CreateMessage.call(service_params.merge(force_thread: false)) do
|
Chat::CreateMessage.call(service_params.merge(force_thread: false)) do
|
||||||
on_success { render json: success_json.merge(message_id: result[:message_instance].id) }
|
on_success do |message_instance:|
|
||||||
|
render json: success_json.merge(message_id: message_instance.id)
|
||||||
|
end
|
||||||
on_failure { render(json: failed_json, status: 422) }
|
on_failure { render(json: failed_json, status: 422) }
|
||||||
on_failed_policy(:no_silenced_user) { raise Discourse::InvalidAccess }
|
on_failed_policy(:no_silenced_user) { raise Discourse::InvalidAccess }
|
||||||
on_model_not_found(:channel) { raise Discourse::NotFound }
|
on_model_not_found(:channel) { raise Discourse::NotFound }
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
class Chat::Api::ChannelThreadMessagesController < Chat::ApiController
|
class Chat::Api::ChannelThreadMessagesController < Chat::ApiController
|
||||||
def index
|
def index
|
||||||
::Chat::ListChannelThreadMessages.call(service_params) do
|
::Chat::ListChannelThreadMessages.call(service_params) do |result|
|
||||||
on_success do
|
on_success do
|
||||||
render_serialized(
|
render_serialized(
|
||||||
result,
|
result,
|
||||||
|
@ -3,16 +3,16 @@
|
|||||||
class Chat::Api::ChannelThreadsController < Chat::ApiController
|
class Chat::Api::ChannelThreadsController < Chat::ApiController
|
||||||
def index
|
def index
|
||||||
::Chat::LookupChannelThreads.call(service_params) do
|
::Chat::LookupChannelThreads.call(service_params) do
|
||||||
on_success do
|
on_success do |threads:, channel:, tracking:, memberships:, load_more_url:, participants:|
|
||||||
render_serialized(
|
render_serialized(
|
||||||
::Chat::ThreadsView.new(
|
::Chat::ThreadsView.new(
|
||||||
user: guardian.user,
|
user: guardian.user,
|
||||||
threads: result.threads,
|
threads_participants: participants,
|
||||||
channel: result.channel,
|
threads:,
|
||||||
tracking: result.tracking,
|
channel:,
|
||||||
memberships: result.memberships,
|
tracking:,
|
||||||
load_more_url: result.load_more_url,
|
memberships:,
|
||||||
threads_participants: result.participants,
|
load_more_url:,
|
||||||
),
|
),
|
||||||
::Chat::ThreadListSerializer,
|
::Chat::ThreadListSerializer,
|
||||||
root: false,
|
root: false,
|
||||||
@ -31,15 +31,15 @@ class Chat::Api::ChannelThreadsController < Chat::ApiController
|
|||||||
|
|
||||||
def show
|
def show
|
||||||
::Chat::LookupThread.call(service_params) do
|
::Chat::LookupThread.call(service_params) do
|
||||||
on_success do
|
on_success do |thread:, membership:, participants:|
|
||||||
render_serialized(
|
render_serialized(
|
||||||
result.thread,
|
thread,
|
||||||
::Chat::ThreadSerializer,
|
::Chat::ThreadSerializer,
|
||||||
root: "thread",
|
root: "thread",
|
||||||
membership: result.membership,
|
|
||||||
include_thread_preview: true,
|
include_thread_preview: true,
|
||||||
include_thread_original_message: true,
|
include_thread_original_message: true,
|
||||||
participants: result.participants,
|
membership:,
|
||||||
|
participants:,
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
on_failed_policy(:invalid_access) { raise Discourse::InvalidAccess }
|
on_failed_policy(:invalid_access) { raise Discourse::InvalidAccess }
|
||||||
@ -58,8 +58,8 @@ class Chat::Api::ChannelThreadsController < Chat::ApiController
|
|||||||
on_failed_policy(:can_view_channel) { raise Discourse::InvalidAccess }
|
on_failed_policy(:can_view_channel) { raise Discourse::InvalidAccess }
|
||||||
on_failed_policy(:can_edit_thread) { raise Discourse::InvalidAccess }
|
on_failed_policy(:can_edit_thread) { raise Discourse::InvalidAccess }
|
||||||
on_model_not_found(:thread) { raise Discourse::NotFound }
|
on_model_not_found(:thread) { raise Discourse::NotFound }
|
||||||
on_failed_step(:update) do
|
on_failed_step(:update) do |step|
|
||||||
render json: failed_json.merge(errors: [result["result.step.update"].error]), status: 422
|
render json: failed_json.merge(errors: [step.error]), status: 422
|
||||||
end
|
end
|
||||||
on_success { render(json: success_json) }
|
on_success { render(json: success_json) }
|
||||||
on_failure { render(json: failed_json, status: 422) }
|
on_failure { render(json: failed_json, status: 422) }
|
||||||
@ -71,20 +71,19 @@ class Chat::Api::ChannelThreadsController < Chat::ApiController
|
|||||||
|
|
||||||
def create
|
def create
|
||||||
::Chat::CreateThread.call(service_params) do
|
::Chat::CreateThread.call(service_params) do
|
||||||
on_success do
|
on_success do |thread:, membership:|
|
||||||
render_serialized(
|
render_serialized(
|
||||||
result.thread,
|
thread,
|
||||||
::Chat::ThreadSerializer,
|
::Chat::ThreadSerializer,
|
||||||
root: false,
|
root: false,
|
||||||
membership: result.membership,
|
|
||||||
include_thread_original_message: true,
|
include_thread_original_message: true,
|
||||||
|
membership:,
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
on_failed_policy(:threading_enabled_for_channel) { raise Discourse::NotFound }
|
on_failed_policy(:threading_enabled_for_channel) { raise Discourse::NotFound }
|
||||||
on_failed_policy(:can_view_channel) { raise Discourse::InvalidAccess }
|
on_failed_policy(:can_view_channel) { raise Discourse::InvalidAccess }
|
||||||
on_failed_step(:create_thread) do
|
on_failed_step(:create_thread) do |step|
|
||||||
render json: failed_json.merge(errors: [result["result.step.create_thread"].error]),
|
render json: failed_json.merge(errors: [step.error]), status: 422
|
||||||
status: 422
|
|
||||||
end
|
end
|
||||||
on_failure { render(json: failed_json, status: 422) }
|
on_failure { render(json: failed_json, status: 422) }
|
||||||
on_failed_contract do |contract|
|
on_failed_contract do |contract|
|
||||||
|
@ -3,17 +3,13 @@
|
|||||||
class Chat::Api::ChannelThreadsCurrentUserNotificationsSettingsController < Chat::ApiController
|
class Chat::Api::ChannelThreadsCurrentUserNotificationsSettingsController < Chat::ApiController
|
||||||
def update
|
def update
|
||||||
Chat::UpdateThreadNotificationSettings.call(service_params) do
|
Chat::UpdateThreadNotificationSettings.call(service_params) do
|
||||||
|
on_success do |membership:|
|
||||||
|
render_serialized(membership, Chat::BaseThreadMembershipSerializer, root: "membership")
|
||||||
|
end
|
||||||
|
on_failure { render(json: failed_json, status: 422) }
|
||||||
on_failed_policy(:threading_enabled_for_channel) { raise Discourse::NotFound }
|
on_failed_policy(:threading_enabled_for_channel) { raise Discourse::NotFound }
|
||||||
on_failed_policy(:can_view_channel) { raise Discourse::InvalidAccess }
|
on_failed_policy(:can_view_channel) { raise Discourse::InvalidAccess }
|
||||||
on_model_not_found(:thread) { raise Discourse::NotFound }
|
on_model_not_found(:thread) { raise Discourse::NotFound }
|
||||||
on_success do
|
|
||||||
render_serialized(
|
|
||||||
result.membership,
|
|
||||||
Chat::BaseThreadMembershipSerializer,
|
|
||||||
root: "membership",
|
|
||||||
)
|
|
||||||
end
|
|
||||||
on_failure { render(json: failed_json, status: 422) }
|
|
||||||
on_failed_contract do |contract|
|
on_failed_contract do |contract|
|
||||||
render(json: failed_json.merge(errors: contract.errors.full_messages), status: 400)
|
render(json: failed_json.merge(errors: contract.errors.full_messages), status: 400)
|
||||||
end
|
end
|
||||||
|
@ -3,17 +3,13 @@
|
|||||||
class Chat::Api::ChannelThreadsCurrentUserTitlePromptSeenController < Chat::ApiController
|
class Chat::Api::ChannelThreadsCurrentUserTitlePromptSeenController < Chat::ApiController
|
||||||
def update
|
def update
|
||||||
Chat::MarkThreadTitlePromptSeen.call(service_params) do
|
Chat::MarkThreadTitlePromptSeen.call(service_params) do
|
||||||
|
on_success do |membership:|
|
||||||
|
render_serialized(membership, Chat::BaseThreadMembershipSerializer, root: "membership")
|
||||||
|
end
|
||||||
|
on_failure { render(json: failed_json, status: 422) }
|
||||||
on_failed_policy(:threading_enabled_for_channel) { raise Discourse::NotFound }
|
on_failed_policy(:threading_enabled_for_channel) { raise Discourse::NotFound }
|
||||||
on_failed_policy(:can_view_channel) { raise Discourse::InvalidAccess }
|
on_failed_policy(:can_view_channel) { raise Discourse::InvalidAccess }
|
||||||
on_model_not_found(:thread) { raise Discourse::NotFound }
|
on_model_not_found(:thread) { raise Discourse::NotFound }
|
||||||
on_success do
|
|
||||||
render_serialized(
|
|
||||||
result.membership,
|
|
||||||
Chat::BaseThreadMembershipSerializer,
|
|
||||||
root: "membership",
|
|
||||||
)
|
|
||||||
end
|
|
||||||
on_failure { render(json: failed_json, status: 422) }
|
|
||||||
on_failed_contract do |contract|
|
on_failed_contract do |contract|
|
||||||
render(json: failed_json.merge(errors: contract.errors.full_messages), status: 400)
|
render(json: failed_json.merge(errors: contract.errors.full_messages), status: 400)
|
||||||
end
|
end
|
||||||
|
@ -57,24 +57,19 @@ class Chat::Api::ChannelsController < Chat::ApiController
|
|||||||
Chat::CreateCategoryChannel.call(
|
Chat::CreateCategoryChannel.call(
|
||||||
service_params.merge(channel_params.merge(category_id: channel_params[:chatable_id])),
|
service_params.merge(channel_params.merge(category_id: channel_params[:chatable_id])),
|
||||||
) do
|
) do
|
||||||
on_success do
|
on_success do |channel:, membership:|
|
||||||
render_serialized(
|
render_serialized(channel, Chat::ChannelSerializer, root: "channel", membership:)
|
||||||
result.channel,
|
|
||||||
Chat::ChannelSerializer,
|
|
||||||
root: "channel",
|
|
||||||
membership: result.membership,
|
|
||||||
)
|
|
||||||
end
|
end
|
||||||
on_model_not_found(:category) { raise ActiveRecord::RecordNotFound }
|
on_model_not_found(:category) { raise ActiveRecord::RecordNotFound }
|
||||||
on_failed_policy(:can_create_channel) { raise Discourse::InvalidAccess }
|
on_failed_policy(:can_create_channel) { raise Discourse::InvalidAccess }
|
||||||
on_failed_policy(:category_channel_does_not_exist) do
|
on_failed_policy(:category_channel_does_not_exist) do
|
||||||
raise Discourse::InvalidParameters.new(I18n.t("chat.errors.channel_exists_for_category"))
|
raise Discourse::InvalidParameters.new(I18n.t("chat.errors.channel_exists_for_category"))
|
||||||
end
|
end
|
||||||
on_model_errors(:channel) do
|
on_model_errors(:channel) do |model|
|
||||||
render_json_error(result.channel, type: :record_invalid, status: 422)
|
render_json_error(model, type: :record_invalid, status: 422)
|
||||||
end
|
end
|
||||||
on_model_errors(:membership) do
|
on_model_errors(:membership) do |model|
|
||||||
render_json_error(result.membership, type: :record_invalid, status: 422)
|
render_json_error(model, type: :record_invalid, status: 422)
|
||||||
end
|
end
|
||||||
on_failure { render(json: failed_json, status: 422) }
|
on_failure { render(json: failed_json, status: 422) }
|
||||||
on_failed_contract do |contract|
|
on_failed_contract do |contract|
|
||||||
@ -101,12 +96,12 @@ class Chat::Api::ChannelsController < Chat::ApiController
|
|||||||
end
|
end
|
||||||
|
|
||||||
Chat::UpdateChannel.call(service_params.merge(params_to_edit)) do
|
Chat::UpdateChannel.call(service_params.merge(params_to_edit)) do
|
||||||
on_success do
|
on_success do |channel:|
|
||||||
render_serialized(
|
render_serialized(
|
||||||
result.channel,
|
channel,
|
||||||
Chat::ChannelSerializer,
|
Chat::ChannelSerializer,
|
||||||
root: "channel",
|
root: "channel",
|
||||||
membership: result.channel.membership_for(current_user),
|
membership: channel.membership_for(current_user),
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
on_model_not_found(:channel) { raise ActiveRecord::RecordNotFound }
|
on_model_not_found(:channel) { raise ActiveRecord::RecordNotFound }
|
||||||
|
@ -3,18 +3,14 @@
|
|||||||
class Chat::Api::ChannelsCurrentUserMembershipFollowsController < Chat::Api::ChannelsController
|
class Chat::Api::ChannelsCurrentUserMembershipFollowsController < Chat::Api::ChannelsController
|
||||||
def destroy
|
def destroy
|
||||||
Chat::UnfollowChannel.call(service_params) do
|
Chat::UnfollowChannel.call(service_params) do
|
||||||
on_success do
|
on_success do |membership:|
|
||||||
render_serialized(
|
render_serialized(membership, Chat::UserChannelMembershipSerializer, root: "membership")
|
||||||
result.membership,
|
|
||||||
Chat::UserChannelMembershipSerializer,
|
|
||||||
root: "membership",
|
|
||||||
)
|
|
||||||
end
|
end
|
||||||
on_model_not_found(:channel) { raise Discourse::NotFound }
|
|
||||||
on_failure { render(json: failed_json, status: 422) }
|
|
||||||
on_failed_contract do |contract|
|
on_failed_contract do |contract|
|
||||||
render(json: failed_json.merge(errors: contract.errors.full_messages), status: 400)
|
render(json: failed_json.merge(errors: contract.errors.full_messages), status: 400)
|
||||||
end
|
end
|
||||||
|
on_model_not_found(:channel) { raise Discourse::NotFound }
|
||||||
|
on_failure { render(json: failed_json, status: 422) }
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -20,9 +20,7 @@ class Chat::Api::ChannelsReadController < Chat::ApiController
|
|||||||
|
|
||||||
def update_all
|
def update_all
|
||||||
Chat::MarkAllUserChannelsRead.call(service_params) do
|
Chat::MarkAllUserChannelsRead.call(service_params) do
|
||||||
on_success do
|
on_success { |updated_memberships:| render(json: success_json.merge(updated_memberships:)) }
|
||||||
render(json: success_json.merge(updated_memberships: result.updated_memberships))
|
|
||||||
end
|
|
||||||
on_failure { render(json: failed_json, status: 422) }
|
on_failure { render(json: failed_json, status: 422) }
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
class Chat::Api::ChannelsStatusController < Chat::Api::ChannelsController
|
class Chat::Api::ChannelsStatusController < Chat::Api::ChannelsController
|
||||||
def update
|
def update
|
||||||
Chat::UpdateChannelStatus.call(service_params) do
|
Chat::UpdateChannelStatus.call(service_params) do
|
||||||
on_success { render_serialized(result.channel, Chat::ChannelSerializer, root: "channel") }
|
on_success { |channel:| render_serialized(channel, Chat::ChannelSerializer, root: "channel") }
|
||||||
on_model_not_found(:channel) { raise ActiveRecord::RecordNotFound }
|
on_model_not_found(:channel) { raise ActiveRecord::RecordNotFound }
|
||||||
on_failed_policy(:check_channel_permission) { raise Discourse::InvalidAccess }
|
on_failed_policy(:check_channel_permission) { raise Discourse::InvalidAccess }
|
||||||
on_failure { render(json: failed_json, status: 422) }
|
on_failure { render(json: failed_json, status: 422) }
|
||||||
|
@ -4,7 +4,7 @@ class Chat::Api::ChatablesController < Chat::ApiController
|
|||||||
before_action :ensure_logged_in
|
before_action :ensure_logged_in
|
||||||
|
|
||||||
def index
|
def index
|
||||||
::Chat::SearchChatable.call(service_params) do
|
::Chat::SearchChatable.call(service_params) do |result|
|
||||||
on_success { render_serialized(result, ::Chat::ChatablesSerializer, root: false) }
|
on_success { render_serialized(result, ::Chat::ChatablesSerializer, root: false) }
|
||||||
on_failure { render(json: failed_json, status: 422) }
|
on_failure { render(json: failed_json, status: 422) }
|
||||||
on_failed_contract do |contract|
|
on_failed_contract do |contract|
|
||||||
|
@ -3,12 +3,12 @@
|
|||||||
class Chat::Api::CurrentUserChannelsController < Chat::ApiController
|
class Chat::Api::CurrentUserChannelsController < Chat::ApiController
|
||||||
def index
|
def index
|
||||||
Chat::ListUserChannels.call(service_params) do
|
Chat::ListUserChannels.call(service_params) do
|
||||||
on_success do
|
on_success do |structured:, post_allowed_category_ids:|
|
||||||
render_serialized(
|
render_serialized(
|
||||||
result.structured,
|
structured,
|
||||||
Chat::ChannelIndexSerializer,
|
Chat::ChannelIndexSerializer,
|
||||||
root: false,
|
root: false,
|
||||||
post_allowed_category_ids: result.post_allowed_category_ids,
|
post_allowed_category_ids: post_allowed_category_ids,
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
on_failure { render(json: failed_json, status: 422) }
|
on_failure { render(json: failed_json, status: 422) }
|
||||||
|
@ -3,26 +3,26 @@
|
|||||||
class Chat::Api::CurrentUserThreadsController < Chat::ApiController
|
class Chat::Api::CurrentUserThreadsController < Chat::ApiController
|
||||||
def index
|
def index
|
||||||
::Chat::LookupUserThreads.call(service_params) do
|
::Chat::LookupUserThreads.call(service_params) do
|
||||||
on_success do
|
on_success do |threads:, tracking:, memberships:, load_more_url:, participants:|
|
||||||
render_serialized(
|
render_serialized(
|
||||||
::Chat::ThreadsView.new(
|
::Chat::ThreadsView.new(
|
||||||
user: guardian.user,
|
user: guardian.user,
|
||||||
threads: result.threads,
|
threads_participants: participants,
|
||||||
channel: result.channel,
|
channel: nil,
|
||||||
tracking: result.tracking,
|
threads:,
|
||||||
memberships: result.memberships,
|
tracking:,
|
||||||
load_more_url: result.load_more_url,
|
memberships:,
|
||||||
threads_participants: result.participants,
|
load_more_url:,
|
||||||
),
|
),
|
||||||
::Chat::ThreadListSerializer,
|
::Chat::ThreadListSerializer,
|
||||||
root: false,
|
root: false,
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
on_model_not_found(:threads) { render json: success_json.merge(threads: []) }
|
|
||||||
on_failure { render(json: failed_json, status: 422) }
|
|
||||||
on_failed_contract do |contract|
|
on_failed_contract do |contract|
|
||||||
render(json: failed_json.merge(errors: contract.errors.full_messages), status: 400)
|
render(json: failed_json.merge(errors: contract.errors.full_messages), status: 400)
|
||||||
end
|
end
|
||||||
|
on_model_not_found(:threads) { render json: success_json.merge(threads: []) }
|
||||||
|
on_failure { render(json: failed_json, status: 422) }
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -3,14 +3,7 @@
|
|||||||
class Chat::Api::DirectMessagesController < Chat::ApiController
|
class Chat::Api::DirectMessagesController < Chat::ApiController
|
||||||
def create
|
def create
|
||||||
Chat::CreateDirectMessageChannel.call(service_params) do
|
Chat::CreateDirectMessageChannel.call(service_params) do
|
||||||
on_success do
|
on_success { |channel:| render_serialized(channel, Chat::ChannelSerializer, root: "channel") }
|
||||||
render_serialized(
|
|
||||||
result.channel,
|
|
||||||
Chat::ChannelSerializer,
|
|
||||||
root: "channel",
|
|
||||||
membership: result.membership,
|
|
||||||
)
|
|
||||||
end
|
|
||||||
on_model_not_found(:target_users) { raise ActiveRecord::RecordNotFound }
|
on_model_not_found(:target_users) { raise ActiveRecord::RecordNotFound }
|
||||||
on_failed_policy(:satisfies_dms_max_users_limit) do |policy|
|
on_failed_policy(:satisfies_dms_max_users_limit) do |policy|
|
||||||
render_json_dump({ error: policy.reason }, status: 400)
|
render_json_dump({ error: policy.reason }, status: 400)
|
||||||
|
@ -9,8 +9,8 @@ module Jobs
|
|||||||
on_failed_contract do |contract|
|
on_failed_contract do |contract|
|
||||||
Rails.logger.error(contract.errors.full_messages.join(", "))
|
Rails.logger.error(contract.errors.full_messages.join(", "))
|
||||||
end
|
end
|
||||||
on_model_not_found(:channel) do
|
on_model_not_found(:channel) do |contract:|
|
||||||
Rails.logger.error("Channel not found (id=#{result.contract.channel_id})")
|
Rails.logger.error("Channel not found (id=#{contract.channel_id})")
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -17,7 +17,7 @@ module ChatSDK
|
|||||||
|
|
||||||
def messages(channel_id:, guardian:, **params)
|
def messages(channel_id:, guardian:, **params)
|
||||||
Chat::ListChannelMessages.call(channel_id:, guardian:, **params, direction: "future") do
|
Chat::ListChannelMessages.call(channel_id:, guardian:, **params, direction: "future") do
|
||||||
on_success { result.messages }
|
on_success { |messages:| messages }
|
||||||
on_failure { raise "Unexpected error" }
|
on_failure { raise "Unexpected error" }
|
||||||
on_failed_policy(:can_view_channel) { raise "Guardian can't view channel" }
|
on_failed_policy(:can_view_channel) { raise "Guardian can't view channel" }
|
||||||
on_failed_policy(:target_message_exists) { raise "Target message doesn't exist" }
|
on_failed_policy(:target_message_exists) { raise "Target message doesn't exist" }
|
||||||
|
@ -90,7 +90,7 @@ module ChatSDK
|
|||||||
|
|
||||||
def stop_stream(message_id:, guardian:)
|
def stop_stream(message_id:, guardian:)
|
||||||
Chat::StopMessageStreaming.call(message_id:, guardian:) do
|
Chat::StopMessageStreaming.call(message_id:, guardian:) do
|
||||||
on_success { result.message }
|
on_success { |message:| message }
|
||||||
on_model_not_found(:message) { raise "Couldn't find message with id: `#{message_id}`" }
|
on_model_not_found(:message) { raise "Couldn't find message with id: `#{message_id}`" }
|
||||||
on_model_not_found(:membership) do
|
on_model_not_found(:membership) do
|
||||||
raise "Couldn't find membership for user with id: `#{guardian.user.id}`"
|
raise "Couldn't find membership for user with id: `#{guardian.user.id}`"
|
||||||
@ -145,7 +145,7 @@ module ChatSDK
|
|||||||
raise "User with id: `#{guardian.user.id}` can't join this channel"
|
raise "User with id: `#{guardian.user.id}` can't join this channel"
|
||||||
end
|
end
|
||||||
on_failed_contract { |contract| raise contract.errors.full_messages.join(", ") }
|
on_failed_contract { |contract| raise contract.errors.full_messages.join(", ") }
|
||||||
on_success { result.message_instance }
|
on_success { |message_instance:| message_instance }
|
||||||
on_failure { raise "Unexpected error" }
|
on_failure { raise "Unexpected error" }
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -75,7 +75,7 @@ module ChatSDK
|
|||||||
|
|
||||||
def messages(thread_id:, guardian:, direction: "future", **params)
|
def messages(thread_id:, guardian:, direction: "future", **params)
|
||||||
Chat::ListChannelThreadMessages.call(thread_id:, guardian:, direction:, **params) do
|
Chat::ListChannelThreadMessages.call(thread_id:, guardian:, direction:, **params) do
|
||||||
on_success { result.messages }
|
on_success { |messages:| messages }
|
||||||
on_failed_policy(:can_view_thread) { raise "Guardian can't view thread" }
|
on_failed_policy(:can_view_thread) { raise "Guardian can't view thread" }
|
||||||
on_failed_policy(:target_message_exists) { raise "Target message doesn't exist" }
|
on_failed_policy(:target_message_exists) { raise "Target message doesn't exist" }
|
||||||
on_failure { raise "Unexpected error" }
|
on_failure { raise "Unexpected error" }
|
||||||
@ -96,7 +96,7 @@ module ChatSDK
|
|||||||
raise "Threading is not enabled for this channel"
|
raise "Threading is not enabled for this channel"
|
||||||
end
|
end
|
||||||
on_failed_contract { |contract| raise contract.errors.full_messages.join(", ") }
|
on_failed_contract { |contract| raise contract.errors.full_messages.join(", ") }
|
||||||
on_success { result.thread_instance }
|
on_success { |thread:| thread }
|
||||||
on_failure { raise "Unexpected error" }
|
on_failure { raise "Unexpected error" }
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -67,49 +67,49 @@ module ChatSpecHelpers
|
|||||||
end
|
end
|
||||||
|
|
||||||
def update_message!(message, text: nil, user: Discourse.system_user, upload_ids: nil)
|
def update_message!(message, text: nil, user: Discourse.system_user, upload_ids: nil)
|
||||||
result =
|
Chat::UpdateMessage.call(
|
||||||
Chat::UpdateMessage.call(
|
guardian: user.guardian,
|
||||||
guardian: user.guardian,
|
message_id: message.id,
|
||||||
message_id: message.id,
|
upload_ids: upload_ids,
|
||||||
upload_ids: upload_ids,
|
message: text,
|
||||||
message: text,
|
process_inline: true,
|
||||||
process_inline: true,
|
) do |result|
|
||||||
)
|
on_success { result.message_instance }
|
||||||
service_failed!(result) if result.failure?
|
on_failure { service_failed!(result) }
|
||||||
result.message_instance
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def trash_message!(message, user: Discourse.system_user)
|
def trash_message!(message, user: Discourse.system_user)
|
||||||
result =
|
Chat::TrashMessage.call(
|
||||||
Chat::TrashMessage.call(
|
message_id: message.id,
|
||||||
message_id: message.id,
|
channel_id: message.chat_channel_id,
|
||||||
channel_id: message.chat_channel_id,
|
guardian: user.guardian,
|
||||||
guardian: user.guardian,
|
) do |result|
|
||||||
)
|
on_success { result }
|
||||||
service_failed!(result) if result.failure?
|
on_failure { service_failed!(result) }
|
||||||
result
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def restore_message!(message, user: Discourse.system_user)
|
def restore_message!(message, user: Discourse.system_user)
|
||||||
result =
|
Chat::RestoreMessage.call(
|
||||||
Chat::RestoreMessage.call(
|
message_id: message.id,
|
||||||
message_id: message.id,
|
channel_id: message.chat_channel_id,
|
||||||
channel_id: message.chat_channel_id,
|
guardian: user.guardian,
|
||||||
guardian: user.guardian,
|
) do |result|
|
||||||
)
|
on_success { result }
|
||||||
service_failed!(result) if result.failure?
|
on_failure { service_failed!(result) }
|
||||||
result
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def add_users_to_channel(users, channel, user: Discourse.system_user)
|
def add_users_to_channel(users, channel, user: Discourse.system_user)
|
||||||
result =
|
::Chat::AddUsersToChannel.call(
|
||||||
::Chat::AddUsersToChannel.call(
|
guardian: user.guardian,
|
||||||
guardian: user.guardian,
|
channel_id: channel.id,
|
||||||
channel_id: channel.id,
|
usernames: Array(users).map(&:username),
|
||||||
usernames: Array(users).map(&:username),
|
) do |result|
|
||||||
)
|
on_success { result }
|
||||||
service_failed!(result) if result.failure?
|
on_failure { service_failed!(result) }
|
||||||
result
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def create_draft(channel, thread: nil, user: Discourse.system_user, data: { message: "draft" })
|
def create_draft(channel, thread: nil, user: Discourse.system_user, data: { message: "draft" })
|
||||||
@ -119,15 +119,15 @@ module ChatSpecHelpers
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
result =
|
::Chat::UpsertDraft.call(
|
||||||
::Chat::UpsertDraft.call(
|
guardian: user.guardian,
|
||||||
guardian: user.guardian,
|
channel_id: channel.id,
|
||||||
channel_id: channel.id,
|
thread_id: thread&.id,
|
||||||
thread_id: thread&.id,
|
data: data.to_json,
|
||||||
data: data.to_json,
|
) do |result|
|
||||||
)
|
on_success { result }
|
||||||
service_failed!(result) if result.failure?
|
on_failure { service_failed!(result) }
|
||||||
result
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -11,10 +11,20 @@ describe Chat::Api::CurrentUserThreadsController do
|
|||||||
|
|
||||||
describe "#index" do
|
describe "#index" do
|
||||||
describe "success" do
|
describe "success" do
|
||||||
|
let!(:thread) do
|
||||||
|
Fabricate(
|
||||||
|
:chat_thread,
|
||||||
|
original_message_user: current_user,
|
||||||
|
with_replies: 2,
|
||||||
|
use_service: true,
|
||||||
|
)
|
||||||
|
end
|
||||||
|
|
||||||
it "works" do
|
it "works" do
|
||||||
get "/chat/api/me/threads"
|
get "/chat/api/me/threads"
|
||||||
|
|
||||||
expect(response.status).to eq(200)
|
expect(response).to have_http_status :ok
|
||||||
|
expect(response.parsed_body[:threads]).not_to be_empty
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -150,10 +150,13 @@ RSpec.describe Service::Runner do
|
|||||||
describe ".call" do
|
describe ".call" do
|
||||||
subject(:runner) { described_class.call(service, &actions_block) }
|
subject(:runner) { described_class.call(service, &actions_block) }
|
||||||
|
|
||||||
let(:result) { object.result }
|
|
||||||
let(:actions_block) { object.instance_eval(actions) }
|
let(:actions_block) { object.instance_eval(actions) }
|
||||||
let(:service) { SuccessService }
|
let(:service) { SuccessWithModelService }
|
||||||
let(:actions) { "proc {}" }
|
let(:actions) { <<-BLOCK }
|
||||||
|
proc do |result|
|
||||||
|
on_success { |fake_model:| [result, fake_model] }
|
||||||
|
end
|
||||||
|
BLOCK
|
||||||
let(:object) do
|
let(:object) do
|
||||||
Class
|
Class
|
||||||
.new(ApplicationController) do
|
.new(ApplicationController) do
|
||||||
@ -171,10 +174,12 @@ RSpec.describe Service::Runner do
|
|||||||
.new
|
.new
|
||||||
end
|
end
|
||||||
|
|
||||||
it "runs the provided service in the context of a controller" do
|
it "allows access to the result object" do
|
||||||
runner
|
expect(runner.first).to be_a Service::Base::Context
|
||||||
expect(result).to be_a Service::Base::Context
|
end
|
||||||
expect(result).to be_a_success
|
|
||||||
|
it "allows using keyword args in blocks" do
|
||||||
|
expect(runner.last).to eq :model_found
|
||||||
end
|
end
|
||||||
|
|
||||||
context "when using the on_success action" do
|
context "when using the on_success action" do
|
||||||
@ -241,7 +246,7 @@ RSpec.describe Service::Runner do
|
|||||||
|
|
||||||
context "when using the block argument" do
|
context "when using the block argument" do
|
||||||
let(:actions) { <<-BLOCK }
|
let(:actions) { <<-BLOCK }
|
||||||
proc do
|
proc do |result|
|
||||||
on_failed_policy(:test) { |policy| policy == result["result.policy.test"] }
|
on_failed_policy(:test) { |policy| policy == result["result.policy.test"] }
|
||||||
end
|
end
|
||||||
BLOCK
|
BLOCK
|
||||||
@ -279,7 +284,7 @@ RSpec.describe Service::Runner do
|
|||||||
|
|
||||||
context "when using the block argument" do
|
context "when using the block argument" do
|
||||||
let(:actions) { <<-BLOCK }
|
let(:actions) { <<-BLOCK }
|
||||||
proc do
|
proc do |result|
|
||||||
on_failed_contract { |contract| contract == result["result.contract.default"] }
|
on_failed_contract { |contract| contract == result["result.contract.default"] }
|
||||||
end
|
end
|
||||||
BLOCK
|
BLOCK
|
||||||
@ -301,8 +306,9 @@ RSpec.describe Service::Runner do
|
|||||||
|
|
||||||
context "when using the on_model_not_found action" do
|
context "when using the on_model_not_found action" do
|
||||||
let(:actions) { <<-BLOCK }
|
let(:actions) { <<-BLOCK }
|
||||||
proc do
|
proc do |result|
|
||||||
on_model_not_found(:fake_model) { :no_model }
|
on_success { [result] }
|
||||||
|
on_model_not_found(:fake_model) { [:no_model, result] }
|
||||||
end
|
end
|
||||||
BLOCK
|
BLOCK
|
||||||
|
|
||||||
@ -311,7 +317,7 @@ RSpec.describe Service::Runner do
|
|||||||
let(:service) { FailureWithOptionalModelService }
|
let(:service) { FailureWithOptionalModelService }
|
||||||
|
|
||||||
it "does not run the provided block" do
|
it "does not run the provided block" do
|
||||||
expect(runner).not_to eq :no_model
|
expect(runner).not_to include :no_model
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -320,13 +326,13 @@ RSpec.describe Service::Runner do
|
|||||||
|
|
||||||
context "when not using the block argument" do
|
context "when not using the block argument" do
|
||||||
it "runs the provided block" do
|
it "runs the provided block" do
|
||||||
expect(runner).to eq :no_model
|
expect(runner).to include :no_model
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
context "when using the block argument" do
|
context "when using the block argument" do
|
||||||
let(:actions) { <<-BLOCK }
|
let(:actions) { <<-BLOCK }
|
||||||
proc do
|
proc do |result|
|
||||||
on_model_not_found(:fake_model) { |model| model == result["result.model.fake_model"] }
|
on_model_not_found(:fake_model) { |model| model == result["result.model.fake_model"] }
|
||||||
end
|
end
|
||||||
BLOCK
|
BLOCK
|
||||||
@ -341,7 +347,7 @@ RSpec.describe Service::Runner do
|
|||||||
let(:service) { SuccessWithModelService }
|
let(:service) { SuccessWithModelService }
|
||||||
|
|
||||||
it "does not run the provided block" do
|
it "does not run the provided block" do
|
||||||
expect(runner).not_to eq :no_model
|
expect(runner).not_to include :no_model
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@ -351,7 +357,7 @@ RSpec.describe Service::Runner do
|
|||||||
let(:service) { FailureWithCollectionModelService }
|
let(:service) { FailureWithCollectionModelService }
|
||||||
|
|
||||||
it "runs the provided block" do
|
it "runs the provided block" do
|
||||||
expect(runner).to eq :no_model
|
expect(runner).to include :no_model
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -359,7 +365,7 @@ RSpec.describe Service::Runner do
|
|||||||
let(:service) { SuccessWithCollectionModelService }
|
let(:service) { SuccessWithCollectionModelService }
|
||||||
|
|
||||||
it "does not run the provided block" do
|
it "does not run the provided block" do
|
||||||
expect(runner).not_to eq :no_model
|
expect(runner).not_to include :no_model
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@ -371,23 +377,21 @@ RSpec.describe Service::Runner do
|
|||||||
before { Fabricate(:user) }
|
before { Fabricate(:user) }
|
||||||
|
|
||||||
it "does not run the provided block" do
|
it "does not run the provided block" do
|
||||||
expect(runner).not_to eq :no_model
|
expect(runner).not_to include :no_model
|
||||||
end
|
end
|
||||||
|
|
||||||
it "does not fetch records from the relation" do
|
it "does not fetch records from the relation" do
|
||||||
runner
|
expect(runner.last[:fake_model]).not_to be_loaded
|
||||||
expect(result[:fake_model]).not_to be_loaded
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
context "when the service fails" do
|
context "when the service fails" do
|
||||||
it "runs the provided block" do
|
it "runs the provided block" do
|
||||||
expect(runner).to eq :no_model
|
expect(runner).to include :no_model
|
||||||
end
|
end
|
||||||
|
|
||||||
it "does not fetch records from the relation" do
|
it "does not fetch records from the relation" do
|
||||||
runner
|
expect(runner.last[:fake_model]).not_to be_loaded
|
||||||
expect(result[:fake_model]).not_to be_loaded
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
Reference in New Issue
Block a user