20#ifndef ORES_SERVICE_MESSAGING_HANDLER_HELPERS_HPP
21#define ORES_SERVICE_MESSAGING_HANDLER_HELPERS_HPP
26#include <boost/uuid/uuid.hpp>
27#include <rfl/json.hpp>
28#include "ores.nats/domain/message.hpp"
29#include "ores.nats/service/client.hpp"
30#include "ores.database/domain/context.hpp"
31#include "ores.utility/rfl/reflectors.hpp"
32#include "ores.service/error_code.hpp"
34namespace ores::service::messaging {
39namespace change_reasons {
40 inline constexpr std::string_view new_record =
"system.new_record";
41 inline constexpr std::string_view update =
"system.update";
67 std::string_view change_reason = change_reasons::new_record) {
70 if constexpr (
requires { obj.tenant_id; }) {
71 if constexpr (std::is_assignable_v<
decltype(obj.tenant_id)&, std::string>)
73 else if constexpr (std::is_assignable_v<
decltype(obj.tenant_id)&,
79 const auto& actor = ctx.
actor();
81 if constexpr (
requires { obj.modified_by; }) {
83 obj.modified_by = actor;
84 else if (!svc.empty())
85 obj.modified_by = svc;
88 if constexpr (
requires { obj.performed_by; })
89 obj.performed_by = svc;
91 if constexpr (
requires { obj.change_reason_code; }) {
92 if (obj.change_reason_code.empty())
93 obj.change_reason_code = std::string(change_reason);
99template<
typename Resp>
104 const auto json = rfl::json::write(resp);
105 const auto* p =
reinterpret_cast<const std::byte*
>(json.data());
129 std::string_view required_permission) {
130 const auto& perms = ctx.
roles();
132 if (perms.empty())
return true;
134 for (
const auto& p : perms) {
135 if (p ==
"*" || p == required_permission)
return true;
137 if (p.size() >= 2 && p.ends_with(
"::*")) {
138 const auto prefix = std::string_view(p).substr(0, p.size() - 1);
139 if (required_permission.starts_with(prefix))
return true;
151 std::string_view error_str;
155 default: error_str =
"unauthorized";
break;
158 {{
"X-Error", std::string(error_str)}});
163template<
typename Req>
165 const std::string_view sv(
166 reinterpret_cast<const char*
>(msg.
data.data()), msg.
data.size());
167 auto r = rfl::json::read<Req>(sv);
168 if (!r)
return std::nullopt;
error_code
Error codes returned by service-layer request helpers.
Definition error_code.hpp:28
@ forbidden
The caller is authenticated but lacks the required permission.
@ token_expired
The JWT token has expired.
Context for the operations on a postgres database.
Definition context.hpp:47
const std::string & service_account() const
Gets the service account for this context.
Definition context.hpp:127
const std::vector< std::string > & roles() const
Gets the permission codes carried in this context.
Definition context.hpp:142
const std::string & actor() const
Gets the current actor (end-user) for this context.
Definition context.hpp:118
const utility::uuid::tenant_id & tenant_id() const
Gets the tenant ID for this context.
Definition context.hpp:94
A received NATS message.
Definition message.hpp:40
std::string reply_subject
The reply-to subject, empty for one-way publishes.
Definition message.hpp:51
std::vector< std::byte > data
The message payload bytes.
Definition message.hpp:58
NATS client: connection, pub/sub, request/reply, and JetStream.
Definition client.hpp:73
void publish(std::string_view subject, std::span< const std::byte > data, std::unordered_map< std::string, std::string > headers={})
Publish a message to a subject.
Definition client.cpp:298
const boost::uuids::uuid & to_uuid() const noexcept
Returns the underlying boost UUID.
Definition tenant_id.cpp:77
std::string to_string() const
Converts the tenant_id to its string representation.
Definition tenant_id.cpp:81