Page MenuHomePhorge

power-levels-desc.cpp
No OneTemporary

Size
8 KB
Referenced Files
None
Subscribers
None

power-levels-desc.cpp

/*
* This file is part of libkazv.
* SPDX-FileCopyrightText: 2020-2023 tusooa <tusooa@kazv.moe>
* SPDX-License-Identifier: AGPL-3.0-or-later
*/
#include <libkazv-config.hpp>
#include <event.hpp>
#include "validator.hpp"
#include "power-levels-desc.hpp"
namespace Kazv
{
static std::pair<bool, json> numericValidator(const json &j)
{
if (j.is_number()) {
return {true, json(j.template get<long long>())};
} else if (j.is_string()) {
auto str = j.template get<std::string>();
try {
std::size_t pos = 0;
auto num = std::stoll(str, &pos);
if (pos != str.size()) { // not entirely a number
return {false, json()};
}
return {true, json(num)};
} catch (const std::logic_error &) {
return {false, json()};
}
} else {
return {false, json()};
}
}
static std::pair<bool, json> eventsValidator(const json &j)
{
auto [ret, val] = numericValidator(j[1]);
return {ret, json::array({j[0], std::move(val)})};
}
static std::pair<bool, json> notificationsValidator(const json &j)
{
auto ret = json::object();
auto res = cast(ret, j, "room", numericValidator);
return {res, ret};
}
static std::pair<bool, json> usersValidator(const json &j)
{
auto [ret, val] = numericValidator(j[1]);
return {ret, json::array({j[0], std::move(val)})};
}
// https://spec.matrix.org/v1.8/client-server-api/#mroompower_levels
static const auto numericFields = immer::map<std::string, long long>{
{"ban", 50},
{"events_default", 0},
{"invite", 0},
{"kick", 50},
{"redact", 50},
{"state_default", 50},
{"users_default", 0},
};
struct PowerLevelsDesc::Private
{
Private(const Event &e)
: original(e)
, normalized(normalize(e))
{}
Event normalize(const Event &e)
{
auto content = e.content().get();
auto ret = json{
{"type", "m.power_levels"},
{"state_key", ""},
{"content", json::object()},
};
// cast numeric fields
for (const auto &[key, defaultValue] : numericFields) {
ret["content"][key] = defaultValue;
cast(ret["content"], content, key, numericValidator);
}
// cast events map
ret["content"]["events"] = json::object();
castObject(ret["content"], content, "events", eventsValidator, CastObjectStrategy::IgnoreInvalid);
// cast notifications map
cast(ret["content"], content, "notifications", notificationsValidator);
// cast users map
ret["content"]["users"] = json::object();
castObject(ret["content"], content, "users", usersValidator, CastObjectStrategy::IgnoreInvalid);
return Event(ret);
}
template <class Key>
static void setInContent(json &j, Key &&k, std::optional<PowerLevel> value)
{
if (!j["content"].is_object()) {
j["content"] = json::object();
}
if (value.has_value()) {
j["content"][std::forward<Key>(k)] = value.value();
} else {
j["content"].erase(std::forward<Key>(k));
}
}
Event original;
Event normalized;
};
PowerLevelsDesc::PowerLevelsDesc(const Event &e)
: m_d(new Private(e))
{}
PowerLevelsDesc::~PowerLevelsDesc() = default;
KAZV_DEFINE_COPYABLE_UNIQUE_PTR(PowerLevelsDesc, m_d);
PowerLevel PowerLevelsDesc::powerLevelOfUser(std::string userId) const
{
const auto content = m_d->normalized.content().get();
if (content["users"].contains(userId)) {
return content["users"][userId].template get<PowerLevel>();
} else {
return content["users_default"].template get<PowerLevel>();
}
}
bool PowerLevelsDesc::canSendMessage(std::string userId, std::string eventType) const
{
auto userPowerLevels = powerLevelOfUser(userId);
const auto content = m_d->normalized.content().get();
auto powerLevelsNeeded = content["events"].contains(eventType)
? content["events"][eventType].template get<PowerLevel>()
: content["events_default"].template get<PowerLevel>();
return userPowerLevels >= powerLevelsNeeded;
}
bool PowerLevelsDesc::canSendState(std::string userId, std::string eventType) const
{
auto userPowerLevels = powerLevelOfUser(userId);
const auto content = m_d->normalized.content().get();
auto powerLevelsNeeded = content["events"].contains(eventType)
? content["events"][eventType].template get<PowerLevel>()
: content["state_default"].template get<PowerLevel>();
return userPowerLevels >= powerLevelsNeeded;
}
bool PowerLevelsDesc::canInvite(std::string userId) const
{
auto userPowerLevels = powerLevelOfUser(userId);
const auto content = m_d->normalized.content().get();
auto powerLevelsNeeded = content["invite"].template get<PowerLevel>();
return userPowerLevels >= powerLevelsNeeded;
}
bool PowerLevelsDesc::canKick(std::string userId) const
{
auto userPowerLevels = powerLevelOfUser(userId);
const auto content = m_d->normalized.content().get();
auto powerLevelsNeeded = content["kick"].template get<PowerLevel>();
return userPowerLevels >= powerLevelsNeeded;
}
bool PowerLevelsDesc::canBan(std::string userId) const
{
auto userPowerLevels = powerLevelOfUser(userId);
const auto content = m_d->normalized.content().get();
auto powerLevelsNeeded = content["ban"].template get<PowerLevel>();
return userPowerLevels >= powerLevelsNeeded;
}
bool PowerLevelsDesc::canRedact(std::string userId) const
{
auto userPowerLevels = powerLevelOfUser(userId);
const auto content = m_d->normalized.content().get();
auto powerLevelsNeeded = content["redact"].template get<PowerLevel>();
return userPowerLevels >= powerLevelsNeeded;
}
Event PowerLevelsDesc::normalizedEvent() const
{
return m_d ? m_d->normalized : Event();
}
Event PowerLevelsDesc::originalEvent() const
{
return m_d ? m_d->original : Event();
}
PowerLevelsDesc PowerLevelsDesc::setBan(std::optional<PowerLevel> powerLevel) const
{
auto e = m_d->original.originalJson().get();
m_d->setInContent(e, "ban", powerLevel);
return PowerLevelsDesc(Event(e));
}
PowerLevelsDesc PowerLevelsDesc::setKick(std::optional<PowerLevel> powerLevel) const
{
auto e = m_d->original.originalJson().get();
m_d->setInContent(e, "kick", powerLevel);
return PowerLevelsDesc(Event(e));
}
PowerLevelsDesc PowerLevelsDesc::setInvite(std::optional<PowerLevel> powerLevel) const
{
auto e = m_d->original.originalJson().get();
m_d->setInContent(e, "invite", powerLevel);
return PowerLevelsDesc(Event(e));
}
PowerLevelsDesc PowerLevelsDesc::setRedact(std::optional<PowerLevel> powerLevel) const
{
auto e = m_d->original.originalJson().get();
m_d->setInContent(e, "redact", powerLevel);
return PowerLevelsDesc(Event(e));
}
PowerLevelsDesc PowerLevelsDesc::setEventsDefault(std::optional<PowerLevel> powerLevel) const
{
auto e = m_d->original.originalJson().get();
m_d->setInContent(e, "events_default", powerLevel);
return PowerLevelsDesc(Event(e));
}
PowerLevelsDesc PowerLevelsDesc::setStateDefault(std::optional<PowerLevel> powerLevel) const
{
auto e = m_d->original.originalJson().get();
m_d->setInContent(e, "state_default", powerLevel);
return PowerLevelsDesc(Event(e));
}
PowerLevelsDesc PowerLevelsDesc::setUsersDefault(std::optional<PowerLevel> powerLevel) const
{
auto e = m_d->original.originalJson().get();
m_d->setInContent(e, "users_default", powerLevel);
return PowerLevelsDesc(Event(e));
}
PowerLevelsDesc PowerLevelsDesc::setUser(std::string userId, std::optional<PowerLevel> powerLevel) const
{
auto e = m_d->original.originalJson().get();
e.merge_patch(json{{"content", {
{"users", {
{userId, powerLevel ? json(powerLevel.value()) : json(nullptr)}
}}}}});
return PowerLevelsDesc(Event(e));
}
PowerLevelsDesc PowerLevelsDesc::setEvent(std::string eventType, std::optional<PowerLevel> powerLevel) const
{
auto e = m_d->original.originalJson().get();
e.merge_patch(json{{"content", {
{"events", {
{eventType, powerLevel ? json(powerLevel.value()) : json(nullptr)}
}}}}});
return PowerLevelsDesc(Event(e));
}
}

File Metadata

Mime Type
text/x-c++
Expires
Sun, Jan 19, 6:06 PM (1 d, 13 h)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
55367
Default Alt Text
power-levels-desc.cpp (8 KB)

Event Timeline