20#ifndef ORES_IAM_MESSAGING_ACCOUNT_PARTY_HANDLER_HPP
21#define ORES_IAM_MESSAGING_ACCOUNT_PARTY_HANDLER_HPP
24#include <boost/uuid/string_generator.hpp>
25#include "ores.logging/make_logger.hpp"
26#include "ores.nats/domain/message.hpp"
27#include "ores.nats/service/client.hpp"
28#include "ores.database/domain/context.hpp"
29#include "ores.database/service/tenant_context.hpp"
30#include "ores.security/jwt/jwt_authenticator.hpp"
31#include "ores.service/messaging/handler_helpers.hpp"
32#include "ores.service/messaging/workflow_helpers.hpp"
33#include "ores.service/service/request_context.hpp"
34#include "ores.iam.api/messaging/account_party_protocol.hpp"
35#include "ores.iam.core/service/account_party_service.hpp"
37namespace ores::iam::messaging {
41inline auto& account_party_handler_lg() {
42 static auto instance = ores::logging::make_logger(
43 "ores.iam.messaging.account_party_handler");
49using ores::service::messaging::reply;
50using ores::service::messaging::decode;
51using ores::service::messaging::stamp;
52using ores::service::messaging::error_reply;
53using ores::service::messaging::has_permission;
54using ores::service::messaging::log_handler_entry;
57class account_party_handler {
62 : nats_(nats), ctx_(
std::move(ctx)), signer_(
std::move(signer)) {}
65 [[maybe_unused]]
const auto correlation_id =
66 log_handler_entry(account_party_handler_lg(), msg);
68 service::account_party_service svc(ctx_);
69 auto aps = svc.list_account_parties();
70 get_account_parties_response resp;
71 resp.total_available_count =
72 static_cast<int>(aps.size());
73 resp.account_parties = std::move(aps);
74 BOOST_LOG_SEV(account_party_handler_lg(), debug)
76 reply(nats_, msg, resp);
77 }
catch (
const std::exception& e) {
78 BOOST_LOG_SEV(account_party_handler_lg(), error)
79 << msg.
subject <<
" failed: " << e.what();
80 reply(nats_, msg, get_account_parties_response{});
85 [[maybe_unused]]
const auto correlation_id =
86 log_handler_entry(account_party_handler_lg(), msg);
87 auto req = decode<get_account_parties_by_account_request>(msg);
89 BOOST_LOG_SEV(account_party_handler_lg(), warn)
90 <<
"Failed to decode: " << msg.
subject;
94 service::account_party_service svc(ctx_);
95 boost::uuids::string_generator sg;
96 auto aps = svc.list_account_parties_by_account(
98 get_account_parties_by_account_response resp;
99 resp.account_parties = std::move(aps);
100 BOOST_LOG_SEV(account_party_handler_lg(), debug)
101 <<
"Completed " << msg.
subject;
102 reply(nats_, msg, resp);
103 }
catch (
const std::exception& e) {
104 BOOST_LOG_SEV(account_party_handler_lg(), error)
105 << msg.
subject <<
" failed: " << e.what();
107 get_account_parties_by_account_response{});
112 using ores::service::messaging::is_workflow_command;
113 using ores::service::messaging::extract_workflow_header;
114 using ores::service::messaging::publish_step_completion;
115 using ores::service::messaging::workflow_step_id_header;
116 using ores::service::messaging::workflow_instance_id_header;
117 using ores::service::messaging::workflow_tenant_id_header;
120 if (is_workflow_command(msg)) {
121 const auto step_id = extract_workflow_header(msg, workflow_step_id_header);
122 const auto inst_id = extract_workflow_header(msg, workflow_instance_id_header);
123 const auto tenant_id = extract_workflow_header(msg, workflow_tenant_id_header);
125 auto req = decode<save_account_party_request>(msg);
127 publish_step_completion(nats_, step_id, inst_id,
false,
"",
128 "Failed to decode save_account_party_request");
133 auto wf_ctx = tenant_context::with_tenant(ctx_, tenant_id);
134 service::account_party_service svc(wf_ctx);
135 for (
auto ap : req->account_parties) {
137 svc.save_account_party(ap);
139 BOOST_LOG_SEV(account_party_handler_lg(), debug)
140 <<
"Workflow step completed: " << msg.
subject;
141 publish_step_completion(nats_, step_id, inst_id,
true,
142 rfl::json::write(save_account_party_response{.success =
true}),
"");
143 }
catch (
const std::exception& e) {
144 BOOST_LOG_SEV(account_party_handler_lg(), error)
145 <<
"Workflow step failed: " << msg.
subject
146 <<
" — " << e.what();
147 publish_step_completion(nats_, step_id, inst_id,
false,
"", e.what());
152 [[maybe_unused]]
const auto correlation_id =
153 log_handler_entry(account_party_handler_lg(), msg);
154 auto req = decode<save_account_party_request>(msg);
156 BOOST_LOG_SEV(account_party_handler_lg(), warn)
157 <<
"Failed to decode: " << msg.
subject;
161 auto ctx_expected = ores::service::service::make_request_context(
162 ctx_, msg, std::optional<ores::security::jwt::jwt_authenticator>{signer_});
164 error_reply(nats_, msg, ctx_expected.error());
167 const auto& ctx = *ctx_expected;
168 if (!has_permission(ctx,
"iam::accounts:update")) {
172 service::account_party_service svc(ctx);
173 for (
auto ap : req->account_parties) {
175 svc.save_account_party(ap);
177 BOOST_LOG_SEV(account_party_handler_lg(), debug)
178 <<
"Completed " << msg.
subject;
180 save_account_party_response{.success =
true});
181 }
catch (
const std::exception& e) {
182 BOOST_LOG_SEV(account_party_handler_lg(), error)
183 << msg.
subject <<
" failed: " << e.what();
184 reply(nats_, msg, save_account_party_response{
185 .success =
false, .message = e.what()});
190 [[maybe_unused]]
const auto correlation_id =
191 log_handler_entry(account_party_handler_lg(), msg);
192 auto req = decode<delete_account_party_request>(msg);
194 BOOST_LOG_SEV(account_party_handler_lg(), warn)
195 <<
"Failed to decode: " << msg.
subject;
198 auto ctx_expected = ores::service::service::make_request_context(
199 ctx_, msg, std::optional<ores::security::jwt::jwt_authenticator>{signer_});
201 error_reply(nats_, msg, ctx_expected.error());
204 const auto& ctx = *ctx_expected;
205 if (!has_permission(ctx,
"iam::accounts:update")) {
210 service::account_party_service svc(ctx);
211 boost::uuids::string_generator sg;
212 for (
const auto& key : req->keys)
213 svc.remove_account_party(
214 sg(key.account_id), sg(key.party_id));
215 BOOST_LOG_SEV(account_party_handler_lg(), debug)
216 <<
"Completed " << msg.
subject;
218 delete_account_party_response{.success =
true});
219 }
catch (
const std::exception& e) {
220 BOOST_LOG_SEV(account_party_handler_lg(), error)
221 << msg.
subject <<
" failed: " << e.what();
222 reply(nats_, msg, delete_account_party_response{
223 .success =
false, .message = e.what()});
Implements logging infrastructure for ORE Studio.
Definition boost_severity.hpp:28
@ forbidden
The caller is authenticated but lacks the required permission.
Context for the operations on a postgres database.
Definition context.hpp:47
Manages tenant context for multi-tenant database operations.
Definition tenant_context.hpp:37
A received NATS message.
Definition message.hpp:40
std::string subject
The subject the message was published to.
Definition message.hpp:44
NATS client: connection, pub/sub, request/reply, and JetStream.
Definition client.hpp:73
JWT authentication primitive.
Definition jwt_authenticator.hpp:45