Lifts both per-property and per-property-set RBAC tables from fewo-webapp into oatpp-authkit. Combined into one commit because they share a DbClient and the cross-table effective-permission resolver — the resolver itself stays in fewo since it joins property_set_members (a fewo-side concept). New files (all in oatpp-authkit): - dto/UserPermissionDto.hpp — UserPropertyPermissionDto + UserGroupPermissionDto, both registered as temporal. EffectivePermissionDto stays in fewo (it's the result shape of fewo's property_set_members JOIN). - db/UserPermissionDb.hpp — DbClient with CRUD for both tables. Each table also has a *Schema struct exposing kSchema for SchemaBuilder composition. Natural-key UNIQUE indexes carried explicitly: ux_..._user_property_until, ux_..._user_set_until. - repo/ConcreteUserPermissionRepository.hpp — two concrete repos + makeUserPropertyPermissionRepository / makeUserGroupPermissionRepository factories that wrap each in TemporalRepository. - test/test_user_permission_schema.cpp — verifies both schemas compose with TemporalRepository to produce the expected 5 DDL statements each (entity table + 3 schema indexes + 1 temporal composite index). 12 of 12 tests pass. Bumped 0.10.0 → 0.11.0. Per-row natural-key UNIQUE prevents duplicate live grants for the same (user_id, property_id) or (user_id, set_id) pair while still allowing historical rows for the same key (their valid_until differs). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
141 lines
5 KiB
C++
141 lines
5 KiB
C++
#ifndef OATPP_AUTHKIT_REPO_CONCRETE_USER_PERMISSION_REPOSITORY_HPP
|
|
#define OATPP_AUTHKIT_REPO_CONCRETE_USER_PERMISSION_REPOSITORY_HPP
|
|
|
|
// Concrete inner adapters of Repository<UserPropertyPermissionDto> and
|
|
// Repository<UserGroupPermissionDto> (authkit#14 PRs 2 & 3). Stack each
|
|
// under TemporalRepository for versioning + soft-delete via valid_until.
|
|
|
|
#include "oatpp-authkit/db/UserPermissionDb.hpp"
|
|
#include "oatpp-authkit/dto/UserPermissionDto.hpp"
|
|
#include "oatpp-authkit/repo/Repository.hpp"
|
|
#include "oatpp-authkit/repo/SchemaContract.hpp"
|
|
#include "oatpp-authkit/repo/TemporalRepository.hpp"
|
|
|
|
#include "oatpp/core/Types.hpp"
|
|
|
|
#include <memory>
|
|
|
|
namespace oatpp_authkit::repo {
|
|
|
|
/**
|
|
* @brief Inner adapter for `Repository<UserPropertyPermissionDto>`,
|
|
* delegating to `db::UserPermissionDb`.
|
|
*
|
|
* Schema lives in `db::UserPropertyPermissionSchema` — this repo
|
|
* contributes nothing to the schema, only adapts queries.
|
|
*/
|
|
class ConcreteUserPropertyPermissionRepository
|
|
: public Repository<dto::UserPropertyPermissionDto>
|
|
{
|
|
public:
|
|
inline static constexpr DecoratorSchema kSchema = {
|
|
"ConcreteUserPropertyPermissionRepository",
|
|
nullptr, 0, nullptr, 0, nullptr, 0,
|
|
};
|
|
|
|
explicit ConcreteUserPropertyPermissionRepository(
|
|
std::shared_ptr<db::UserPermissionDb> updb)
|
|
: m_db(std::move(updb)) {}
|
|
|
|
oatpp::Object<dto::UserPropertyPermissionDto>
|
|
findByEntityId(const oatpp::String& entityId) override
|
|
{
|
|
auto res = m_db->getPropertyPermissionByEntityId(entityId);
|
|
if (!res || !res->isSuccess()) return nullptr;
|
|
auto rows = res->template fetch<
|
|
oatpp::Vector<oatpp::Object<dto::UserPropertyPermissionDto>>>();
|
|
if (!rows || rows->empty()) return nullptr;
|
|
return (*rows)[0];
|
|
}
|
|
|
|
oatpp::Vector<oatpp::Object<dto::UserPropertyPermissionDto>> list() override {
|
|
auto res = m_db->getAllPropertyPermissionsRaw();
|
|
auto out = oatpp::Vector<oatpp::Object<dto::UserPropertyPermissionDto>>::createShared();
|
|
if (!res || !res->isSuccess()) return out;
|
|
auto fetched = res->template fetch<
|
|
oatpp::Vector<oatpp::Object<dto::UserPropertyPermissionDto>>>();
|
|
if (!fetched) return out;
|
|
for (auto& row : *fetched) if (row) out->push_back(row);
|
|
return out;
|
|
}
|
|
|
|
void save(const oatpp::Object<dto::UserPropertyPermissionDto>& d) override {
|
|
m_db->upsertPropertyPermissionById(d);
|
|
}
|
|
|
|
void softDelete(const oatpp::String& entityId) override {
|
|
m_db->softDeletePropertyPermission(entityId);
|
|
}
|
|
|
|
private:
|
|
std::shared_ptr<db::UserPermissionDb> m_db;
|
|
};
|
|
|
|
/**
|
|
* @brief Inner adapter for `Repository<UserGroupPermissionDto>`,
|
|
* delegating to `db::UserPermissionDb`.
|
|
*/
|
|
class ConcreteUserGroupPermissionRepository
|
|
: public Repository<dto::UserGroupPermissionDto>
|
|
{
|
|
public:
|
|
inline static constexpr DecoratorSchema kSchema = {
|
|
"ConcreteUserGroupPermissionRepository",
|
|
nullptr, 0, nullptr, 0, nullptr, 0,
|
|
};
|
|
|
|
explicit ConcreteUserGroupPermissionRepository(
|
|
std::shared_ptr<db::UserPermissionDb> updb)
|
|
: m_db(std::move(updb)) {}
|
|
|
|
oatpp::Object<dto::UserGroupPermissionDto>
|
|
findByEntityId(const oatpp::String& entityId) override
|
|
{
|
|
auto res = m_db->getGroupPermissionByEntityId(entityId);
|
|
if (!res || !res->isSuccess()) return nullptr;
|
|
auto rows = res->template fetch<
|
|
oatpp::Vector<oatpp::Object<dto::UserGroupPermissionDto>>>();
|
|
if (!rows || rows->empty()) return nullptr;
|
|
return (*rows)[0];
|
|
}
|
|
|
|
oatpp::Vector<oatpp::Object<dto::UserGroupPermissionDto>> list() override {
|
|
auto res = m_db->getAllGroupPermissionsRaw();
|
|
auto out = oatpp::Vector<oatpp::Object<dto::UserGroupPermissionDto>>::createShared();
|
|
if (!res || !res->isSuccess()) return out;
|
|
auto fetched = res->template fetch<
|
|
oatpp::Vector<oatpp::Object<dto::UserGroupPermissionDto>>>();
|
|
if (!fetched) return out;
|
|
for (auto& row : *fetched) if (row) out->push_back(row);
|
|
return out;
|
|
}
|
|
|
|
void save(const oatpp::Object<dto::UserGroupPermissionDto>& d) override {
|
|
m_db->upsertGroupPermissionById(d);
|
|
}
|
|
|
|
void softDelete(const oatpp::String& entityId) override {
|
|
m_db->softDeleteGroupPermission(entityId);
|
|
}
|
|
|
|
private:
|
|
std::shared_ptr<db::UserPermissionDb> m_db;
|
|
};
|
|
|
|
inline std::shared_ptr<Repository<dto::UserPropertyPermissionDto>>
|
|
makeUserPropertyPermissionRepository(std::shared_ptr<db::UserPermissionDb> updb)
|
|
{
|
|
auto concrete = std::make_shared<ConcreteUserPropertyPermissionRepository>(std::move(updb));
|
|
return std::make_shared<TemporalRepository<dto::UserPropertyPermissionDto>>(concrete);
|
|
}
|
|
|
|
inline std::shared_ptr<Repository<dto::UserGroupPermissionDto>>
|
|
makeUserGroupPermissionRepository(std::shared_ptr<db::UserPermissionDb> updb)
|
|
{
|
|
auto concrete = std::make_shared<ConcreteUserGroupPermissionRepository>(std::move(updb));
|
|
return std::make_shared<TemporalRepository<dto::UserGroupPermissionDto>>(concrete);
|
|
}
|
|
|
|
} // namespace oatpp_authkit::repo
|
|
|
|
#endif
|