106 lines
4.2 KiB
C++
106 lines
4.2 KiB
C++
#pragma once
|
|
#include "adminive/amis.hpp"
|
|
#include <functional>
|
|
#include <mutex>
|
|
#include <string>
|
|
#include <utility>
|
|
namespace adminive {
|
|
template <Json_Type Json>
|
|
struct Http_Response {
|
|
int status{200};
|
|
Json body{};
|
|
};
|
|
template <Json_Type Json, class Data>
|
|
Json make_http_result(int status, std::string message, Data&& data) {
|
|
Json result = json_object<Json>();
|
|
json_set(result, "status", status);
|
|
json_set(result, "msg", std::move(message));
|
|
json_set(result, "data", std::forward<Data>(data));
|
|
return result;
|
|
}
|
|
template <Json_Type Json>
|
|
Http_Response<Json> make_http_success(Json data, std::string message = {}) {
|
|
return Http_Response<Json>{200, make_http_result<Json>(0, std::move(message), std::move(data))};
|
|
}
|
|
template <Json_Type Json>
|
|
Http_Response<Json> make_http_error(int status, const Update_Result& update) {
|
|
Json result = make_http_result<Json>(status, update.message, json_object<Json>());
|
|
Json errors = json_object<Json>();
|
|
Json field_errors = json_object<Json>();
|
|
for(const auto& [name, message] : update.field_errors) {
|
|
json_set(errors, name, message);
|
|
json_set(field_errors, name, message);
|
|
}
|
|
json_set(result, "errors", std::move(errors));
|
|
json_set(result, "field_errors", std::move(field_errors));
|
|
return Http_Response<Json>{status, std::move(result)};
|
|
}
|
|
template <Json_Type Json>
|
|
Http_Response<Json> make_http_error(int status, std::string message) {
|
|
return Http_Response<Json>{status, make_http_result<Json>(status, std::move(message), json_object<Json>())};
|
|
}
|
|
template <class T, Json_Type Json>
|
|
requires Writable_Adapted_Object<T>
|
|
class Resource_Service {
|
|
public:
|
|
using Object = std::remove_cvref_t<T>;
|
|
using Model = Object_Model_Type<Object>;
|
|
using Transaction_Function = std::function<void(Object&, Model)>;
|
|
Resource_Service(T& value, std::string path, Transaction_Function transaction = {}, std::mutex* shared_mutex = nullptr) : value_(value), path_(std::move(path)), transaction_(std::move(transaction)), shared_mutex_(shared_mutex) {}
|
|
const std::string& path() const noexcept {
|
|
return path_;
|
|
}
|
|
Json amis_schema() const {
|
|
std::scoped_lock lock(resource_mutex());
|
|
return to_amis_form_schema<Json>(value_, path_ + "/data", describe<Model>().list_options().confirm_label);
|
|
}
|
|
Http_Response<Json> descriptor_response() const {
|
|
return make_http_success<Json>(to_descriptor_json<Json, Object>());
|
|
}
|
|
Http_Response<Json> data_response() const {
|
|
std::scoped_lock lock(resource_mutex());
|
|
return make_http_success<Json>(to_frontend_json<Json>(value_));
|
|
}
|
|
Http_Response<Json> amis_response() const {
|
|
return make_http_success<Json>(amis_schema());
|
|
}
|
|
Http_Response<Json> update_response(std::string_view body) {
|
|
Json patch;
|
|
try {
|
|
patch = parse_json<Json>(body);
|
|
} catch(const std::exception& error) {
|
|
return make_http_error<Json>(400, error.what());
|
|
}
|
|
std::scoped_lock lock(resource_mutex());
|
|
auto candidate = Object_Adapter<Object>::snapshot(value_);
|
|
auto result = apply_model_json<Json>(candidate, patch, Write_Mode::update, false);
|
|
if(!result.success) {
|
|
return make_http_error<Json>(422, result);
|
|
}
|
|
try {
|
|
if(transaction_) {
|
|
transaction_(value_, std::move(candidate));
|
|
} else {
|
|
Object_Adapter<Object>::commit(value_, std::move(candidate));
|
|
}
|
|
} catch(const Json_Assignment_Error& error) {
|
|
return make_http_error<Json>(422, error.result());
|
|
} catch(const Field_Validation_Error& error) {
|
|
return make_http_error<Json>(422, object_commit_error<Object>(error));
|
|
} catch(const std::exception& error) {
|
|
return make_http_error<Json>(500, error.what());
|
|
}
|
|
return make_http_success<Json>(to_frontend_json<Json>(value_), result.message);
|
|
}
|
|
private:
|
|
std::mutex& resource_mutex() const noexcept {
|
|
return shared_mutex_ ? *shared_mutex_ : mutex_;
|
|
}
|
|
T& value_;
|
|
std::string path_;
|
|
Transaction_Function transaction_;
|
|
std::mutex* shared_mutex_{};
|
|
mutable std::mutex mutex_;
|
|
};
|
|
}
|