Refactor v12 support to use new user_level helper from mtxclient
This commit is contained in:
parent
3184ab464c
commit
e3bc058845
18 changed files with 208 additions and 207 deletions
|
|
@ -622,7 +622,7 @@ if(USE_BUNDLED_MTXCLIENT)
|
||||||
FetchContent_Declare(
|
FetchContent_Declare(
|
||||||
MatrixClient
|
MatrixClient
|
||||||
GIT_REPOSITORY https://github.com/Nheko-Reborn/mtxclient.git
|
GIT_REPOSITORY https://github.com/Nheko-Reborn/mtxclient.git
|
||||||
GIT_TAG d6f10427d1c5e5b1a45f426274f8d2e8dd0b64be
|
GIT_TAG 873911e352a0845dfb178f77b1ddea796a5d3455
|
||||||
)
|
)
|
||||||
set(BUILD_LIB_EXAMPLES OFF CACHE INTERNAL "")
|
set(BUILD_LIB_EXAMPLES OFF CACHE INTERNAL "")
|
||||||
set(BUILD_LIB_TESTS OFF CACHE INTERNAL "")
|
set(BUILD_LIB_TESTS OFF CACHE INTERNAL "")
|
||||||
|
|
|
||||||
|
|
@ -213,8 +213,8 @@ modules:
|
||||||
- -DBUILD_SHARED_LIBS=OFF
|
- -DBUILD_SHARED_LIBS=OFF
|
||||||
buildsystem: cmake-ninja
|
buildsystem: cmake-ninja
|
||||||
sources:
|
sources:
|
||||||
- commit: 15b43844f4ec27faa5f2ec92c4ded313206763aa
|
- commit: 873911e352a0845dfb178f77b1ddea796a5d3455
|
||||||
tag: v0.10.1
|
#tag: v0.10.1
|
||||||
type: git
|
type: git
|
||||||
url: https://github.com/Nheko-Reborn/mtxclient.git
|
url: https://github.com/Nheko-Reborn/mtxclient.git
|
||||||
- name: nheko
|
- name: nheko
|
||||||
|
|
|
||||||
|
|
@ -89,7 +89,6 @@ Column {
|
||||||
anchors.left: parent.left
|
anchors.left: parent.left
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
|
|
||||||
isV12Creator: room.isV12Creator(userId)
|
|
||||||
powerlevel: userPowerlevel
|
powerlevel: userPowerlevel
|
||||||
height: fontMetrics.ascent
|
height: fontMetrics.ascent
|
||||||
width: height
|
width: height
|
||||||
|
|
@ -98,7 +97,7 @@ Column {
|
||||||
sourceSize.height: height
|
sourceSize.height: height
|
||||||
|
|
||||||
permissions: room ? room.permissions : null
|
permissions: room ? room.permissions : null
|
||||||
visible: isAdmin || isModerator || isV12Creator
|
visible: isAdmin || isModerator // implicitly includes creators as well
|
||||||
}
|
}
|
||||||
|
|
||||||
ToolTip.delay: Nheko.tooltipDelay
|
ToolTip.delay: Nheko.tooltipDelay
|
||||||
|
|
|
||||||
|
|
@ -7,10 +7,10 @@ import QtQuick.Controls
|
||||||
import im.nheko
|
import im.nheko
|
||||||
|
|
||||||
Image {
|
Image {
|
||||||
required property int powerlevel
|
required property var powerlevel
|
||||||
required property var permissions
|
required property var permissions
|
||||||
required property bool isV12Creator
|
|
||||||
|
|
||||||
|
readonly property bool isV12Creator: permissions ? permissions.creatorLevel() == powerlevel : false
|
||||||
readonly property bool isAdmin: permissions ? permissions.changeLevel(MtxEvent.PowerLevels) <= powerlevel : false
|
readonly property bool isAdmin: permissions ? permissions.changeLevel(MtxEvent.PowerLevels) <= powerlevel : false
|
||||||
readonly property bool isModerator: permissions ? permissions.redactLevel() <= powerlevel : false
|
readonly property bool isModerator: permissions ? permissions.redactLevel() <= powerlevel : false
|
||||||
readonly property bool isDefault: permissions ? permissions.defaultLevel() <= powerlevel : false
|
readonly property bool isDefault: permissions ? permissions.defaultLevel() <= powerlevel : false
|
||||||
|
|
@ -27,14 +27,15 @@ Image {
|
||||||
source: sourceUrl + (ma.hovered ? palette.highlight : palette.buttonText)
|
source: sourceUrl + (ma.hovered ? palette.highlight : palette.buttonText)
|
||||||
ToolTip.visible: ma.hovered
|
ToolTip.visible: ma.hovered
|
||||||
ToolTip.text: {
|
ToolTip.text: {
|
||||||
|
let pl = powerlevel.toLocaleString(Qt.locale(), "f", 0);
|
||||||
if (isV12Creator)
|
if (isV12Creator)
|
||||||
return qsTr("Creator");
|
return qsTr("Creator");
|
||||||
else if (isAdmin)
|
else if (isAdmin)
|
||||||
return qsTr("Administrator: %1").arg(powerlevel);
|
return qsTr("Administrator (%1)").arg(pl)
|
||||||
else if (isModerator)
|
else if (isModerator)
|
||||||
return qsTr("Moderator: %1").arg(powerlevel);
|
return qsTr("Moderator: %1").arg(pl);
|
||||||
else
|
else
|
||||||
return qsTr("User: %1").arg(powerlevel);
|
return qsTr("User: %1").arg(pl);
|
||||||
}
|
}
|
||||||
|
|
||||||
HoverHandler {
|
HoverHandler {
|
||||||
|
|
|
||||||
|
|
@ -94,14 +94,17 @@ ApplicationWindow {
|
||||||
Text {
|
Text {
|
||||||
visible: !model.isType;
|
visible: !model.isType;
|
||||||
text: {
|
text: {
|
||||||
|
let pl = model.powerlevel.toLocaleString(Qt.locale(), "f", 0);
|
||||||
|
if (editingModel.creatorLevel == model.powerlevel)
|
||||||
|
return qsTr("Creator")
|
||||||
if (editingModel.adminLevel == model.powerlevel)
|
if (editingModel.adminLevel == model.powerlevel)
|
||||||
return qsTr("Administrator (%1)").arg(model.powerlevel)
|
return qsTr("Administrator (%1)").arg(pl)
|
||||||
else if (editingModel.moderatorLevel == model.powerlevel)
|
else if (editingModel.moderatorLevel == model.powerlevel)
|
||||||
return qsTr("Moderator (%1)").arg(model.powerlevel)
|
return qsTr("Moderator (%1)").arg(pl)
|
||||||
else if (editingModel.defaultUserLevel == model.powerlevel)
|
else if (editingModel.defaultUserLevel == model.powerlevel)
|
||||||
return qsTr("User (%1)").arg(model.powerlevel)
|
return qsTr("User (%1)").arg(pl)
|
||||||
else
|
else
|
||||||
return qsTr("Custom (%1)").arg(model.powerlevel)
|
return qsTr("Custom (%1)").arg(pl)
|
||||||
}
|
}
|
||||||
color: palette.text
|
color: palette.text
|
||||||
}
|
}
|
||||||
|
|
@ -138,7 +141,7 @@ ApplicationWindow {
|
||||||
|
|
||||||
color: palette.text
|
color: palette.text
|
||||||
|
|
||||||
Keys.onPressed: {
|
Keys.onPressed: event => {
|
||||||
if (typeEntry.text.includes('.') && event.matches(StandardKey.InsertParagraphSeparator)) {
|
if (typeEntry.text.includes('.') && event.matches(StandardKey.InsertParagraphSeparator)) {
|
||||||
editingModel.types.add(typeEntry.index, typeEntry.text)
|
editingModel.types.add(typeEntry.index, typeEntry.text)
|
||||||
typeEntry.visible = false;
|
typeEntry.visible = false;
|
||||||
|
|
@ -334,12 +337,17 @@ ApplicationWindow {
|
||||||
Text {
|
Text {
|
||||||
visible: !model.isUser;
|
visible: !model.isUser;
|
||||||
text: {
|
text: {
|
||||||
|
let pl = model.powerlevel.toLocaleString(Qt.locale(), "f", 0);
|
||||||
|
if (editingModel.creatorLevel == model.powerlevel)
|
||||||
|
return qsTr("Creator")
|
||||||
if (editingModel.adminLevel == model.powerlevel)
|
if (editingModel.adminLevel == model.powerlevel)
|
||||||
return qsTr("Administrator (%1)").arg(model.powerlevel)
|
return qsTr("Administrator (%1)").arg(pl)
|
||||||
else if (editingModel.moderatorLevel == model.powerlevel)
|
else if (editingModel.moderatorLevel == model.powerlevel)
|
||||||
return qsTr("Moderator (%1)").arg(model.powerlevel)
|
return qsTr("Moderator (%1)").arg(pl)
|
||||||
|
else if (editingModel.defaultUserLevel == model.powerlevel)
|
||||||
|
return qsTr("User (%1)").arg(pl)
|
||||||
else
|
else
|
||||||
return qsTr("Custom (%1)").arg(model.powerlevel)
|
return qsTr("Custom (%1)").arg(pl)
|
||||||
}
|
}
|
||||||
color: palette.text
|
color: palette.text
|
||||||
}
|
}
|
||||||
|
|
@ -349,7 +357,7 @@ ApplicationWindow {
|
||||||
Layout.alignment: Qt.AlignRight
|
Layout.alignment: Qt.AlignRight
|
||||||
Layout.rightMargin: 2
|
Layout.rightMargin: 2
|
||||||
image: model.isUser ? ":/icons/icons/ui/dismiss.svg" : ":/icons/icons/ui/add-square-button.svg"
|
image: model.isUser ? ":/icons/icons/ui/dismiss.svg" : ":/icons/icons/ui/add-square-button.svg"
|
||||||
visible: !model.isUser || model.removeable
|
visible: (!model.isUser || model.removeable) && model.powerlevel != editingModel.creatorLevel
|
||||||
hoverEnabled: true
|
hoverEnabled: true
|
||||||
ToolTip.visible: hovered
|
ToolTip.visible: hovered
|
||||||
ToolTip.text: model.isUser ? qsTr("Remove user") : qsTr("Add user")
|
ToolTip.text: model.isUser ? qsTr("Remove user") : qsTr("Add user")
|
||||||
|
|
|
||||||
|
|
@ -168,7 +168,6 @@ ApplicationWindow {
|
||||||
sourceSize.height: height
|
sourceSize.height: height
|
||||||
powerlevel: model.powerlevel
|
powerlevel: model.powerlevel
|
||||||
permissions: room.permissions
|
permissions: room.permissions
|
||||||
isV12Creator: room.isV12Creator(model.mxid)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
EncryptionIndicator {
|
EncryptionIndicator {
|
||||||
|
|
|
||||||
|
|
@ -4621,12 +4621,14 @@ Cache::updateSpaces(lmdb::txn &txn,
|
||||||
event.state_key.at(0) == '!') {
|
event.state_key.at(0) == '!') {
|
||||||
const std::string &space = event.state_key;
|
const std::string &space = event.state_key;
|
||||||
|
|
||||||
|
auto create = getStateEvent<mtx::events::state::Create>(txn, space)
|
||||||
|
.value_or(mtx::events::StateEvent<mtx::events::state::Create>{});
|
||||||
auto pls = getStateEvent<mtx::events::state::PowerLevels>(txn, space);
|
auto pls = getStateEvent<mtx::events::state::PowerLevels>(txn, space);
|
||||||
|
|
||||||
if (!pls)
|
if (!pls)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (pls->content.user_level(event.sender) >=
|
if (pls->content.user_level(event.sender, create) >=
|
||||||
pls->content.state_level(space_event_type)) {
|
pls->content.state_level(space_event_type)) {
|
||||||
db->spacesChildren.put(txn, space, room);
|
db->spacesChildren.put(txn, space, room);
|
||||||
db->spacesParents.put(txn, room, space);
|
db->spacesParents.put(txn, room, space);
|
||||||
|
|
@ -4635,7 +4637,7 @@ Cache::updateSpaces(lmdb::txn &txn,
|
||||||
room,
|
room,
|
||||||
space,
|
space,
|
||||||
event.sender,
|
event.sender,
|
||||||
pls->content.user_level(event.sender),
|
pls->content.user_level(event.sender, create),
|
||||||
pls->content.state_level(space_event_type));
|
pls->content.state_level(space_event_type));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -4851,51 +4853,6 @@ Cache::getAccountData(lmdb::txn &txn, mtx::events::EventType type, const std::st
|
||||||
return std::nullopt;
|
return std::nullopt;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
|
||||||
Cache::isV12Creator(const std::string &room_id, const std::string &user_id)
|
|
||||||
{
|
|
||||||
auto txn = ro_txn(this->db->env_);
|
|
||||||
auto state = this->getStatesDb(txn, room_id);
|
|
||||||
|
|
||||||
return this->isV12Creator(txn, state, user_id);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool
|
|
||||||
Cache::isV12Creator(lmdb::txn &txn, lmdb::dbi &state, const std::string &user_id)
|
|
||||||
{
|
|
||||||
using namespace mtx::events;
|
|
||||||
using namespace mtx::events::state;
|
|
||||||
|
|
||||||
bool ok;
|
|
||||||
const int room_version = this->getRoomVersion(txn, state).toInt(&ok);
|
|
||||||
if (!ok || room_version < 12) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string_view create_event;
|
|
||||||
if (state.get(txn, to_string(EventType::RoomCreate), create_event)) {
|
|
||||||
try {
|
|
||||||
const StateEvent<Create> evt =
|
|
||||||
nlohmann::json::parse(create_event).get<StateEvent<Create>>();
|
|
||||||
if (evt.sender == user_id) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
const std::optional<std::vector<std::string>> &additional_creators =
|
|
||||||
evt.content.additional_creators;
|
|
||||||
if (additional_creators &&
|
|
||||||
std::find(additional_creators->begin(), additional_creators->end(), user_id) !=
|
|
||||||
additional_creators->end()) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
} catch (...) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool
|
bool
|
||||||
Cache::hasEnoughPowerLevel(const std::vector<mtx::events::EventType> &eventTypes,
|
Cache::hasEnoughPowerLevel(const std::vector<mtx::events::EventType> &eventTypes,
|
||||||
const std::string &room_id,
|
const std::string &room_id,
|
||||||
|
|
@ -4908,30 +4865,22 @@ Cache::hasEnoughPowerLevel(const std::vector<mtx::events::EventType> &eventTypes
|
||||||
try {
|
try {
|
||||||
auto db_ = getStatesDb(txn, room_id);
|
auto db_ = getStatesDb(txn, room_id);
|
||||||
|
|
||||||
if (this->isV12Creator(txn, db_, user_id)) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
int64_t min_event_level = std::numeric_limits<int64_t>::max();
|
int64_t min_event_level = std::numeric_limits<int64_t>::max();
|
||||||
int64_t user_level = std::numeric_limits<int64_t>::min();
|
int64_t user_level = std::numeric_limits<int64_t>::min();
|
||||||
|
|
||||||
std::string_view event;
|
try {
|
||||||
bool res = db_.get(txn, to_string(EventType::RoomPowerLevels), event);
|
StateEvent<Create> create = getStateEvent<mtx::events::state::Create>(txn, room_id)
|
||||||
|
.value_or(StateEvent<Create>{});
|
||||||
|
StateEvent<PowerLevels> pls =
|
||||||
|
getStateEvent<mtx::events::state::PowerLevels>(txn, room_id)
|
||||||
|
.value_or(StateEvent<PowerLevels>{});
|
||||||
|
|
||||||
if (res) {
|
user_level = pls.content.user_level(user_id, create);
|
||||||
try {
|
|
||||||
StateEvent<PowerLevels> msg =
|
|
||||||
nlohmann::json::parse(std::string_view(event.data(), event.size()))
|
|
||||||
.get<StateEvent<PowerLevels>>();
|
|
||||||
|
|
||||||
user_level = msg.content.user_level(user_id);
|
for (const auto &ty : eventTypes)
|
||||||
|
min_event_level = std::min(min_event_level, pls.content.state_level(to_string(ty)));
|
||||||
for (const auto &ty : eventTypes)
|
} catch (const nlohmann::json::exception &e) {
|
||||||
min_event_level =
|
nhlog::db()->warn("failed to parse m.room.power_levels event: {}", e.what());
|
||||||
std::min(min_event_level, msg.content.state_level(to_string(ty)));
|
|
||||||
} catch (const nlohmann::json::exception &e) {
|
|
||||||
nhlog::db()->warn("failed to parse m.room.power_levels event: {}", e.what());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return user_level >= min_event_level;
|
return user_level >= min_event_level;
|
||||||
|
|
@ -6178,13 +6127,6 @@ roomMembers(const std::string &room_id)
|
||||||
return instance_->roomMembers(room_id);
|
return instance_->roomMembers(room_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
//! Check if the given user is a room creator and that gives them an infinite PL.
|
|
||||||
bool
|
|
||||||
isV12Creator(const std::string &room_id, const std::string &user_id)
|
|
||||||
{
|
|
||||||
return instance_->isV12Creator(room_id, user_id);
|
|
||||||
}
|
|
||||||
|
|
||||||
//! Check if the given user has power level greater than
|
//! Check if the given user has power level greater than
|
||||||
//! lowest power level of the given events.
|
//! lowest power level of the given events.
|
||||||
bool
|
bool
|
||||||
|
|
@ -6466,6 +6408,7 @@ NHEKO_CACHE_GET_STATE_EVENT_DEFINITION(mtx::events::state::JoinRules)
|
||||||
NHEKO_CACHE_GET_STATE_EVENT_DEFINITION(mtx::events::state::Name)
|
NHEKO_CACHE_GET_STATE_EVENT_DEFINITION(mtx::events::state::Name)
|
||||||
NHEKO_CACHE_GET_STATE_EVENT_DEFINITION(mtx::events::state::PinnedEvents)
|
NHEKO_CACHE_GET_STATE_EVENT_DEFINITION(mtx::events::state::PinnedEvents)
|
||||||
NHEKO_CACHE_GET_STATE_EVENT_DEFINITION(mtx::events::state::PowerLevels)
|
NHEKO_CACHE_GET_STATE_EVENT_DEFINITION(mtx::events::state::PowerLevels)
|
||||||
|
NHEKO_CACHE_GET_STATE_EVENT_DEFINITION(mtx::events::state::Create)
|
||||||
NHEKO_CACHE_GET_STATE_EVENT_DEFINITION(mtx::events::state::ServerAcl)
|
NHEKO_CACHE_GET_STATE_EVENT_DEFINITION(mtx::events::state::ServerAcl)
|
||||||
NHEKO_CACHE_GET_STATE_EVENT_DEFINITION(mtx::events::state::space::Child)
|
NHEKO_CACHE_GET_STATE_EVENT_DEFINITION(mtx::events::state::space::Child)
|
||||||
NHEKO_CACHE_GET_STATE_EVENT_DEFINITION(mtx::events::state::space::Parent)
|
NHEKO_CACHE_GET_STATE_EVENT_DEFINITION(mtx::events::state::space::Parent)
|
||||||
|
|
|
||||||
|
|
@ -123,10 +123,6 @@ runMigrations();
|
||||||
std::vector<std::string>
|
std::vector<std::string>
|
||||||
roomMembers(const std::string &room_id);
|
roomMembers(const std::string &room_id);
|
||||||
|
|
||||||
//! Check if the given user is a room creator and that gives them an infinite PL.
|
|
||||||
bool
|
|
||||||
isV12Creator(const std::string &room_id, const std::string &user_id);
|
|
||||||
|
|
||||||
//! Check if the given user has power level greater than than
|
//! Check if the given user has power level greater than than
|
||||||
//! lowest power level of the given events.
|
//! lowest power level of the given events.
|
||||||
bool
|
bool
|
||||||
|
|
|
||||||
|
|
@ -145,10 +145,6 @@ public:
|
||||||
//! Retrieve all the user ids from a room.
|
//! Retrieve all the user ids from a room.
|
||||||
std::vector<std::string> roomMembers(const std::string &room_id);
|
std::vector<std::string> roomMembers(const std::string &room_id);
|
||||||
|
|
||||||
//! Check if the given user is a room creator and that gives them an infinite PL.
|
|
||||||
bool isV12Creator(const std::string &room_id, const std::string &user_id);
|
|
||||||
bool isV12Creator(lmdb::txn &txn, lmdb::dbi &state, const std::string &user_id);
|
|
||||||
|
|
||||||
//! Check if the given user has power leve greater than than
|
//! Check if the given user has power leve greater than than
|
||||||
//! lowest power level of the given events.
|
//! lowest power level of the given events.
|
||||||
bool hasEnoughPowerLevel(const std::vector<mtx::events::EventType> &eventTypes,
|
bool hasEnoughPowerLevel(const std::vector<mtx::events::EventType> &eventTypes,
|
||||||
|
|
|
||||||
|
|
@ -19,6 +19,9 @@ MemberListBackend::MemberListBackend(const QString &room_id, QObject *parent)
|
||||||
->getStateEvent<mtx::events::state::PowerLevels>(room_id_.toStdString())
|
->getStateEvent<mtx::events::state::PowerLevels>(room_id_.toStdString())
|
||||||
.value_or(mtx::events::StateEvent<mtx::events::state::PowerLevels>{})
|
.value_or(mtx::events::StateEvent<mtx::events::state::PowerLevels>{})
|
||||||
.content}
|
.content}
|
||||||
|
, create_{cache::client()
|
||||||
|
->getStateEvent<mtx::events::state::Create>(room_id_.toStdString())
|
||||||
|
.value_or(mtx::events::StateEvent<mtx::events::state::Create>{})}
|
||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
info_ = cache::singleRoomInfo(room_id_.toStdString());
|
info_ = cache::singleRoomInfo(room_id_.toStdString());
|
||||||
|
|
@ -92,7 +95,7 @@ MemberListBackend::data(const QModelIndex &index, int role) const
|
||||||
}
|
}
|
||||||
case Powerlevel:
|
case Powerlevel:
|
||||||
return static_cast<qlonglong>(
|
return static_cast<qlonglong>(
|
||||||
powerLevels_.user_level(m_memberList[index.row()].first.user_id.toStdString()));
|
powerLevels_.user_level(m_memberList[index.row()].first.user_id.toStdString(), create_));
|
||||||
default:
|
default:
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
@ -172,28 +175,4 @@ MemberList::filterAcceptsRow(int source_row, const QModelIndex &) const
|
||||||
Qt::CaseInsensitive);
|
Qt::CaseInsensitive);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
|
||||||
MemberList::lessThan(const QModelIndex &source_left, const QModelIndex &source_right) const
|
|
||||||
{
|
|
||||||
if (this->sortRole() != MemberSortRoles::Powerlevel) {
|
|
||||||
return QSortFilterProxyModel::lessThan(source_left, source_right);
|
|
||||||
}
|
|
||||||
|
|
||||||
const QString &left =
|
|
||||||
this->m_model.data(source_left, MemberListBackend::Roles::Mxid).toString();
|
|
||||||
const QString &right =
|
|
||||||
this->m_model.data(source_right, MemberListBackend::Roles::Mxid).toString();
|
|
||||||
|
|
||||||
const std::string &room_id = this->roomId().toStdString();
|
|
||||||
if (cache::isV12Creator(room_id, left.toStdString())) {
|
|
||||||
if (!cache::isV12Creator(room_id, right.toStdString())) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
// If both are creators, sort by mxid.
|
|
||||||
return left < right;
|
|
||||||
}
|
|
||||||
|
|
||||||
return QSortFilterProxyModel::lessThan(source_left, source_right);
|
|
||||||
}
|
|
||||||
|
|
||||||
#include "moc_MemberList.cpp"
|
#include "moc_MemberList.cpp"
|
||||||
|
|
|
||||||
|
|
@ -73,6 +73,7 @@ private:
|
||||||
bool loadingMoreMembers_{false};
|
bool loadingMoreMembers_{false};
|
||||||
|
|
||||||
mtx::events::state::PowerLevels powerLevels_;
|
mtx::events::state::PowerLevels powerLevels_;
|
||||||
|
mtx::events::StateEvent<mtx::events::state::Create> create_;
|
||||||
|
|
||||||
friend class MemberList;
|
friend class MemberList;
|
||||||
};
|
};
|
||||||
|
|
@ -122,7 +123,6 @@ public slots:
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
bool filterAcceptsRow(int source_row, const QModelIndex &source_parent) const override;
|
bool filterAcceptsRow(int source_row, const QModelIndex &source_parent) const override;
|
||||||
bool lessThan(const QModelIndex &source_left, const QModelIndex &source_right) const override;
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QString filterString;
|
QString filterString;
|
||||||
|
|
|
||||||
|
|
@ -17,12 +17,15 @@
|
||||||
#include "Logging.h"
|
#include "Logging.h"
|
||||||
#include "MatrixClient.h"
|
#include "MatrixClient.h"
|
||||||
|
|
||||||
PowerlevelsTypeListModel::PowerlevelsTypeListModel(const std::string &rid,
|
PowerlevelsTypeListModel::PowerlevelsTypeListModel(
|
||||||
const mtx::events::state::PowerLevels &pl,
|
const std::string &rid,
|
||||||
QObject *parent)
|
const mtx::events::state::PowerLevels &pl,
|
||||||
|
const mtx::events::StateEvent<mtx::events::state::Create> &create,
|
||||||
|
QObject *parent)
|
||||||
: QAbstractListModel(parent)
|
: QAbstractListModel(parent)
|
||||||
, room_id(rid)
|
, room_id(rid)
|
||||||
, powerLevels_(pl)
|
, powerLevels_(pl)
|
||||||
|
, create_(create)
|
||||||
{
|
{
|
||||||
std::set<mtx::events::state::power_level_t> seen_levels;
|
std::set<mtx::events::state::power_level_t> seen_levels;
|
||||||
for (const auto &[type, level] : powerLevels_.events) {
|
for (const auto &[type, level] : powerLevels_.events) {
|
||||||
|
|
@ -40,6 +43,9 @@ PowerlevelsTypeListModel::PowerlevelsTypeListModel(const std::string &rid,
|
||||||
seen_levels.insert(level);
|
seen_levels.insert(level);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (create_.content.room_version_creators_with_infinite_power()) {
|
||||||
|
seen_levels.insert(mtx::events::state::Creator);
|
||||||
|
}
|
||||||
|
|
||||||
for (const auto &level : {
|
for (const auto &level : {
|
||||||
powerLevels_.events_default,
|
powerLevels_.events_default,
|
||||||
|
|
@ -354,12 +360,15 @@ PowerlevelsTypeListModel::moveRows(const QModelIndex &,
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
PowerlevelsUserListModel::PowerlevelsUserListModel(const std::string &rid,
|
PowerlevelsUserListModel::PowerlevelsUserListModel(
|
||||||
const mtx::events::state::PowerLevels &pl,
|
const std::string &rid,
|
||||||
QObject *parent)
|
const mtx::events::state::PowerLevels &pl,
|
||||||
|
const mtx::events::StateEvent<mtx::events::state::Create> &create,
|
||||||
|
QObject *parent)
|
||||||
: QAbstractListModel(parent)
|
: QAbstractListModel(parent)
|
||||||
, room_id(rid)
|
, room_id(rid)
|
||||||
, powerLevels_(pl)
|
, powerLevels_(pl)
|
||||||
|
, create_(create)
|
||||||
{
|
{
|
||||||
std::set<mtx::events::state::power_level_t> seen_levels;
|
std::set<mtx::events::state::power_level_t> seen_levels;
|
||||||
for (const auto &[user, level] : powerLevels_.users) {
|
for (const auto &[user, level] : powerLevels_.users) {
|
||||||
|
|
@ -378,6 +387,16 @@ PowerlevelsUserListModel::PowerlevelsUserListModel(const std::string &rid,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (create_.content.room_version_creators_with_infinite_power()) {
|
||||||
|
users.push_back(Entry{"", mtx::events::state::Creator});
|
||||||
|
seen_levels.insert(mtx::events::state::Creator);
|
||||||
|
|
||||||
|
users.push_back(Entry{create_.sender, mtx::events::state::Creator});
|
||||||
|
for (const auto &user : create.content.additional_creators) {
|
||||||
|
users.push_back(Entry{user, mtx::events::state::Creator});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
for (const auto &level : {
|
for (const auto &level : {
|
||||||
powerLevels_.events_default,
|
powerLevels_.events_default,
|
||||||
powerLevels_.state_default,
|
powerLevels_.state_default,
|
||||||
|
|
@ -408,7 +427,7 @@ PowerlevelsUserListModel::toUsers() const
|
||||||
{
|
{
|
||||||
std::map<std::string, mtx::events::state::power_level_t, std::less<>> m;
|
std::map<std::string, mtx::events::state::power_level_t, std::less<>> m;
|
||||||
for (const auto &[key, pl] : std::as_const(users))
|
for (const auto &[key, pl] : std::as_const(users))
|
||||||
if (key.size() > 0 && key.at(0) == '@')
|
if (key.size() > 0 && key.at(0) == '@' && pl != mtx::events::state::Creator)
|
||||||
m[key] = pl;
|
m[key] = pl;
|
||||||
return m;
|
return m;
|
||||||
}
|
}
|
||||||
|
|
@ -459,7 +478,7 @@ PowerlevelsUserListModel::data(const QModelIndex &index, int role) const
|
||||||
case IsUser:
|
case IsUser:
|
||||||
return !user.mxid.empty();
|
return !user.mxid.empty();
|
||||||
case Moveable:
|
case Moveable:
|
||||||
return !user.mxid.empty();
|
return !user.mxid.empty() && user.pl != mtx::events::state::Creator;
|
||||||
case Removeable:
|
case Removeable:
|
||||||
return !user.mxid.empty() && user.mxid.find('.') != std::string::npos;
|
return !user.mxid.empty() && user.mxid.find('.') != std::string::npos;
|
||||||
}
|
}
|
||||||
|
|
@ -554,7 +573,15 @@ PowerlevelsUserListModel::moveRows(const QModelIndex &,
|
||||||
if (users.at(sourceRow).mxid.empty())
|
if (users.at(sourceRow).mxid.empty())
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
auto pl = users.at(destinationChild > 0 ? destinationChild - 1 : 0).pl;
|
if (users.at(sourceRow).pl == mtx::events::state::Creator)
|
||||||
|
return false;
|
||||||
|
if (users.at(destinationChild).pl == mtx::events::state::Creator)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
auto pl = users.at(destinationChild > 0 ? destinationChild - 1 : 0).pl;
|
||||||
|
if (pl == mtx::events::state::Creator)
|
||||||
|
return false;
|
||||||
|
|
||||||
auto sourceItem = users.takeAt(sourceRow);
|
auto sourceItem = users.takeAt(sourceRow);
|
||||||
sourceItem.pl = pl;
|
sourceItem.pl = pl;
|
||||||
|
|
||||||
|
|
@ -577,9 +604,12 @@ PowerlevelEditingModels::PowerlevelEditingModels(QString room_id, QObject *paren
|
||||||
->getStateEvent<mtx::events::state::PowerLevels>(room_id.toStdString())
|
->getStateEvent<mtx::events::state::PowerLevels>(room_id.toStdString())
|
||||||
.value_or(mtx::events::StateEvent<mtx::events::state::PowerLevels>{})
|
.value_or(mtx::events::StateEvent<mtx::events::state::PowerLevels>{})
|
||||||
.content)
|
.content)
|
||||||
, types_(room_id.toStdString(), powerLevels_, this)
|
, create_(cache::client()
|
||||||
, users_(room_id.toStdString(), powerLevels_, this)
|
->getStateEvent<mtx::events::state::Create>(room_id.toStdString())
|
||||||
, spaces_(room_id.toStdString(), powerLevels_, this)
|
.value_or(mtx::events::StateEvent<mtx::events::state::Create>{}))
|
||||||
|
, types_(room_id.toStdString(), powerLevels_, create_, this)
|
||||||
|
, users_(room_id.toStdString(), powerLevels_, create_, this)
|
||||||
|
, spaces_(room_id.toStdString(), powerLevels_, create_, this)
|
||||||
, room_id_(room_id.toStdString())
|
, room_id_(room_id.toStdString())
|
||||||
{
|
{
|
||||||
connect(&types_,
|
connect(&types_,
|
||||||
|
|
@ -678,16 +708,18 @@ samePl(const mtx::events::state::PowerLevels &a, const mtx::events::state::Power
|
||||||
b.redact);
|
b.redact);
|
||||||
}
|
}
|
||||||
|
|
||||||
PowerlevelsSpacesListModel::PowerlevelsSpacesListModel(const std::string &room_id_,
|
PowerlevelsSpacesListModel::PowerlevelsSpacesListModel(
|
||||||
const mtx::events::state::PowerLevels &pl,
|
const std::string &room_id_,
|
||||||
QObject *parent)
|
const mtx::events::state::PowerLevels &pl,
|
||||||
|
const mtx::events::StateEvent<mtx::events::state::Create> &create,
|
||||||
|
QObject *parent)
|
||||||
: QAbstractListModel(parent)
|
: QAbstractListModel(parent)
|
||||||
, room_id(std::move(room_id_))
|
, room_id(std::move(room_id_))
|
||||||
, oldPowerLevels_(std::move(pl))
|
, oldPowerLevels_(std::move(pl))
|
||||||
{
|
{
|
||||||
beginResetModel();
|
beginResetModel();
|
||||||
|
|
||||||
spaces.push_back(Entry{room_id, oldPowerLevels_, true});
|
spaces.push_back(Entry{room_id, oldPowerLevels_, create, true});
|
||||||
|
|
||||||
std::unordered_set<std::string> visited;
|
std::unordered_set<std::string> visited;
|
||||||
|
|
||||||
|
|
@ -703,10 +735,16 @@ PowerlevelsSpacesListModel::PowerlevelsSpacesListModel(const std::string &room_i
|
||||||
cache::client()->getStateEvent<mtx::events::state::space::Parent>(s, space);
|
cache::client()->getStateEvent<mtx::events::state::space::Parent>(s, space);
|
||||||
if (parent && parent->content.via && !parent->content.via->empty() &&
|
if (parent && parent->content.via && !parent->content.via->empty() &&
|
||||||
parent->content.canonical) {
|
parent->content.canonical) {
|
||||||
auto parentPl = cache::client()->getStateEvent<mtx::events::state::PowerLevels>(s);
|
auto childPl = cache::client()->getStateEvent<mtx::events::state::PowerLevels>(s);
|
||||||
|
auto childCreate =
|
||||||
|
cache::client()->getStateEvent<mtx::events::state::Create>(s).value_or(
|
||||||
|
mtx::events::StateEvent<mtx::events::state::Create>{});
|
||||||
|
|
||||||
spaces.push_back(Entry{
|
spaces.push_back(
|
||||||
s, parentPl ? parentPl->content : mtx::events::state::PowerLevels{}, false});
|
Entry{s,
|
||||||
|
childPl ? childPl->content : mtx::events::state::PowerLevels{},
|
||||||
|
childCreate,
|
||||||
|
false});
|
||||||
addChildren(s);
|
addChildren(s);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -813,7 +851,7 @@ PowerlevelsSpacesListModel::data(QModelIndex const &index, int role) const
|
||||||
auto entry = spaces.at(row);
|
auto entry = spaces.at(row);
|
||||||
switch (role) {
|
switch (role) {
|
||||||
case Roles::IsEditable:
|
case Roles::IsEditable:
|
||||||
return entry.pl.user_level(http::client()->user_id().to_string()) >=
|
return entry.pl.user_level(http::client()->user_id().to_string(), entry.create) >=
|
||||||
entry.pl.state_level(to_string(mtx::events::EventType::RoomPowerLevels));
|
entry.pl.state_level(to_string(mtx::events::EventType::RoomPowerLevels));
|
||||||
case Roles::IsDifferentFromBase:
|
case Roles::IsDifferentFromBase:
|
||||||
return !samePl(entry.pl, oldPowerLevels_);
|
return !samePl(entry.pl, oldPowerLevels_);
|
||||||
|
|
|
||||||
|
|
@ -29,9 +29,11 @@ public:
|
||||||
Removeable,
|
Removeable,
|
||||||
};
|
};
|
||||||
|
|
||||||
explicit PowerlevelsTypeListModel(const std::string &room_id_,
|
explicit PowerlevelsTypeListModel(
|
||||||
const mtx::events::state::PowerLevels &pl,
|
const std::string &room_id_,
|
||||||
QObject *parent = nullptr);
|
const mtx::events::state::PowerLevels &pl,
|
||||||
|
const mtx::events::StateEvent<mtx::events::state::Create> &create,
|
||||||
|
QObject *parent = nullptr);
|
||||||
|
|
||||||
QHash<int, QByteArray> roleNames() const override;
|
QHash<int, QByteArray> roleNames() const override;
|
||||||
int rowCount(const QModelIndex &) const override { return static_cast<int>(types.size()); }
|
int rowCount(const QModelIndex &) const override { return static_cast<int>(types.size()); }
|
||||||
|
|
@ -67,6 +69,7 @@ public:
|
||||||
std::string room_id;
|
std::string room_id;
|
||||||
QVector<Entry> types;
|
QVector<Entry> types;
|
||||||
mtx::events::state::PowerLevels powerLevels_;
|
mtx::events::state::PowerLevels powerLevels_;
|
||||||
|
mtx::events::StateEvent<mtx::events::state::Create> create_;
|
||||||
};
|
};
|
||||||
|
|
||||||
class PowerlevelsUserListModel final : public QAbstractListModel
|
class PowerlevelsUserListModel final : public QAbstractListModel
|
||||||
|
|
@ -88,9 +91,11 @@ public:
|
||||||
Removeable,
|
Removeable,
|
||||||
};
|
};
|
||||||
|
|
||||||
explicit PowerlevelsUserListModel(const std::string &room_id_,
|
explicit PowerlevelsUserListModel(
|
||||||
const mtx::events::state::PowerLevels &pl,
|
const std::string &room_id_,
|
||||||
QObject *parent = nullptr);
|
const mtx::events::state::PowerLevels &pl,
|
||||||
|
const mtx::events::StateEvent<mtx::events::state::Create> &create,
|
||||||
|
QObject *parent = nullptr);
|
||||||
|
|
||||||
QHash<int, QByteArray> roleNames() const override;
|
QHash<int, QByteArray> roleNames() const override;
|
||||||
int rowCount(const QModelIndex &) const override { return static_cast<int>(users.size()); }
|
int rowCount(const QModelIndex &) const override { return static_cast<int>(users.size()); }
|
||||||
|
|
@ -121,6 +126,7 @@ public:
|
||||||
std::string room_id;
|
std::string room_id;
|
||||||
QVector<Entry> users;
|
QVector<Entry> users;
|
||||||
mtx::events::state::PowerLevels powerLevels_;
|
mtx::events::state::PowerLevels powerLevels_;
|
||||||
|
mtx::events::StateEvent<mtx::events::state::Create> create_;
|
||||||
};
|
};
|
||||||
|
|
||||||
class PowerlevelsSpacesListModel final : public QAbstractListModel
|
class PowerlevelsSpacesListModel final : public QAbstractListModel
|
||||||
|
|
@ -147,9 +153,11 @@ public:
|
||||||
ApplyPermissions,
|
ApplyPermissions,
|
||||||
};
|
};
|
||||||
|
|
||||||
explicit PowerlevelsSpacesListModel(const std::string &room_id_,
|
explicit PowerlevelsSpacesListModel(
|
||||||
const mtx::events::state::PowerLevels &pl,
|
const std::string &room_id_,
|
||||||
QObject *parent = nullptr);
|
const mtx::events::state::PowerLevels &pl,
|
||||||
|
const mtx::events::StateEvent<mtx::events::state::Create> &create,
|
||||||
|
QObject *parent = nullptr);
|
||||||
|
|
||||||
QHash<int, QByteArray> roleNames() const override;
|
QHash<int, QByteArray> roleNames() const override;
|
||||||
int rowCount(const QModelIndex &) const override { return static_cast<int>(spaces.size()); }
|
int rowCount(const QModelIndex &) const override { return static_cast<int>(spaces.size()); }
|
||||||
|
|
@ -183,6 +191,7 @@ public:
|
||||||
|
|
||||||
std::string roomid;
|
std::string roomid;
|
||||||
mtx::events::state::PowerLevels pl;
|
mtx::events::state::PowerLevels pl;
|
||||||
|
mtx::events::StateEvent<mtx::events::state::Create> create;
|
||||||
bool apply = false;
|
bool apply = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -203,6 +212,7 @@ class PowerlevelEditingModels final : public QObject
|
||||||
Q_PROPERTY(PowerlevelsUserListModel *users READ users CONSTANT)
|
Q_PROPERTY(PowerlevelsUserListModel *users READ users CONSTANT)
|
||||||
Q_PROPERTY(PowerlevelsTypeListModel *types READ types CONSTANT)
|
Q_PROPERTY(PowerlevelsTypeListModel *types READ types CONSTANT)
|
||||||
Q_PROPERTY(PowerlevelsSpacesListModel *spaces READ spaces CONSTANT)
|
Q_PROPERTY(PowerlevelsSpacesListModel *spaces READ spaces CONSTANT)
|
||||||
|
Q_PROPERTY(qlonglong creatorLevel READ creatorLevel CONSTANT)
|
||||||
Q_PROPERTY(qlonglong adminLevel READ adminLevel NOTIFY adminLevelChanged)
|
Q_PROPERTY(qlonglong adminLevel READ adminLevel NOTIFY adminLevelChanged)
|
||||||
Q_PROPERTY(qlonglong moderatorLevel READ moderatorLevel NOTIFY moderatorLevelChanged)
|
Q_PROPERTY(qlonglong moderatorLevel READ moderatorLevel NOTIFY moderatorLevelChanged)
|
||||||
Q_PROPERTY(qlonglong defaultUserLevel READ defaultUserLevel NOTIFY defaultUserLevelChanged)
|
Q_PROPERTY(qlonglong defaultUserLevel READ defaultUserLevel NOTIFY defaultUserLevelChanged)
|
||||||
|
|
@ -222,6 +232,7 @@ public:
|
||||||
PowerlevelsUserListModel *users() { return &users_; }
|
PowerlevelsUserListModel *users() { return &users_; }
|
||||||
PowerlevelsTypeListModel *types() { return &types_; }
|
PowerlevelsTypeListModel *types() { return &types_; }
|
||||||
PowerlevelsSpacesListModel *spaces() { return &spaces_; }
|
PowerlevelsSpacesListModel *spaces() { return &spaces_; }
|
||||||
|
qlonglong creatorLevel() const { return mtx::events::state::Creator; }
|
||||||
qlonglong adminLevel() const
|
qlonglong adminLevel() const
|
||||||
{
|
{
|
||||||
return powerLevels_.state_level(to_string(mtx::events::EventType::RoomPowerLevels));
|
return powerLevels_.state_level(to_string(mtx::events::EventType::RoomPowerLevels));
|
||||||
|
|
@ -235,6 +246,7 @@ public:
|
||||||
Q_INVOKABLE void addRole(int pl);
|
Q_INVOKABLE void addRole(int pl);
|
||||||
|
|
||||||
mtx::events::state::PowerLevels powerLevels_;
|
mtx::events::state::PowerLevels powerLevels_;
|
||||||
|
mtx::events::StateEvent<mtx::events::state::Create> create_;
|
||||||
PowerlevelsTypeListModel types_;
|
PowerlevelsTypeListModel types_;
|
||||||
PowerlevelsUserListModel users_;
|
PowerlevelsUserListModel users_;
|
||||||
PowerlevelsSpacesListModel spaces_;
|
PowerlevelsSpacesListModel spaces_;
|
||||||
|
|
|
||||||
|
|
@ -1453,6 +1453,9 @@ utils::roomVias(const std::string &roomid)
|
||||||
auto powerlevels =
|
auto powerlevels =
|
||||||
cache::client()->getStateEvent<mtx::events::state::PowerLevels>(roomid).value_or(
|
cache::client()->getStateEvent<mtx::events::state::PowerLevels>(roomid).value_or(
|
||||||
mtx::events::StateEvent<mtx::events::state::PowerLevels>{});
|
mtx::events::StateEvent<mtx::events::state::PowerLevels>{});
|
||||||
|
auto create =
|
||||||
|
cache::client()->getStateEvent<mtx::events::state::Create>(roomid).value_or(
|
||||||
|
mtx::events::StateEvent<mtx::events::state::Create>{});
|
||||||
auto acls = cache::client()->getStateEvent<mtx::events::state::ServerAcl>(roomid);
|
auto acls = cache::client()->getStateEvent<mtx::events::state::ServerAcl>(roomid);
|
||||||
|
|
||||||
std::vector<QRegularExpression> allowedServers;
|
std::vector<QRegularExpression> allowedServers;
|
||||||
|
|
@ -1501,6 +1504,19 @@ utils::roomVias(const std::string &roomid)
|
||||||
std::set<std::string> users_with_high_pl_in_room;
|
std::set<std::string> users_with_high_pl_in_room;
|
||||||
// we should pick PL > 50, but imo that is broken, so we just pick users who have admins
|
// we should pick PL > 50, but imo that is broken, so we just pick users who have admins
|
||||||
// perm
|
// perm
|
||||||
|
if (create.content.room_version_creators_with_infinite_power()) {
|
||||||
|
{
|
||||||
|
auto user = create.sender;
|
||||||
|
auto host = mtx::identifiers::parse<mtx::identifiers::User>(user).hostname();
|
||||||
|
if (isHostAllowed(host))
|
||||||
|
users_with_high_pl.insert(user);
|
||||||
|
}
|
||||||
|
for (const auto &user : create.content.additional_creators) {
|
||||||
|
auto host = mtx::identifiers::parse<mtx::identifiers::User>(user).hostname();
|
||||||
|
if (isHostAllowed(host))
|
||||||
|
users_with_high_pl.insert(user);
|
||||||
|
}
|
||||||
|
}
|
||||||
for (const auto &user : powerlevels.content.users) {
|
for (const auto &user : powerlevels.content.users) {
|
||||||
if (user.second >= powerlevels.content.events_default &&
|
if (user.second >= powerlevels.content.events_default &&
|
||||||
user.second >= powerlevels.content.state_default) {
|
user.second >= powerlevels.content.state_default) {
|
||||||
|
|
@ -1525,12 +1541,13 @@ utils::roomVias(const std::string &roomid)
|
||||||
});
|
});
|
||||||
|
|
||||||
// add the highest powerlevel user
|
// add the highest powerlevel user
|
||||||
auto max_pl_user = std::max_element(
|
auto max_pl_user = std::max_element(users_with_high_pl_in_room.begin(),
|
||||||
users_with_high_pl_in_room.begin(),
|
users_with_high_pl_in_room.end(),
|
||||||
users_with_high_pl_in_room.end(),
|
[&pl_content = powerlevels.content, &create](
|
||||||
[&pl_content = powerlevels.content](const std::string &a, const std::string &b) {
|
const std::string &a, const std::string &b) {
|
||||||
return pl_content.user_level(a) < pl_content.user_level(b);
|
return pl_content.user_level(a, create) <
|
||||||
});
|
pl_content.user_level(b, create);
|
||||||
|
});
|
||||||
if (max_pl_user != users_with_high_pl_in_room.end()) {
|
if (max_pl_user != users_with_high_pl_in_room.end()) {
|
||||||
auto host =
|
auto host =
|
||||||
mtx::identifiers::parse<mtx::identifiers::User>(*max_pl_user).hostname();
|
mtx::identifiers::parse<mtx::identifiers::User>(*max_pl_user).hostname();
|
||||||
|
|
@ -1705,11 +1722,15 @@ utils::updateSpaceVias()
|
||||||
|
|
||||||
auto spaceid = roomid.toStdString();
|
auto spaceid = roomid.toStdString();
|
||||||
|
|
||||||
|
auto create = cache::client()->getStateEvent<mtx::events::state::Create>(spaceid).value_or(
|
||||||
|
mtx::events::StateEvent<mtx::events::state::Create>{});
|
||||||
|
|
||||||
if (auto pl = cache::client()
|
if (auto pl = cache::client()
|
||||||
->getStateEvent<mtx::events::state::PowerLevels>(spaceid)
|
->getStateEvent<mtx::events::state::PowerLevels>(spaceid)
|
||||||
.value_or(mtx::events::StateEvent<mtx::events::state::PowerLevels>{})
|
.value_or(mtx::events::StateEvent<mtx::events::state::PowerLevels>{})
|
||||||
.content;
|
.content;
|
||||||
pl.user_level(us) < pl.state_level(to_string(mtx::events::EventType::SpaceChild)))
|
pl.user_level(us, create) <
|
||||||
|
pl.state_level(to_string(mtx::events::EventType::SpaceChild)))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
auto children = cache::client()->getChildRoomIds(spaceid);
|
auto children = cache::client()->getChildRoomIds(spaceid);
|
||||||
|
|
@ -1748,12 +1769,16 @@ utils::updateSpaceVias()
|
||||||
parent->origin_server_ts < weekAgo &&
|
parent->origin_server_ts < weekAgo &&
|
||||||
// ignore unset spaces
|
// ignore unset spaces
|
||||||
(parent->content.via && !parent->content.via->empty())) {
|
(parent->content.via && !parent->content.via->empty())) {
|
||||||
|
auto childCreate =
|
||||||
|
cache::client()->getStateEvent<mtx::events::state::Create>(spaceid).value_or(
|
||||||
|
mtx::events::StateEvent<mtx::events::state::Create>{});
|
||||||
|
|
||||||
if (auto pl =
|
if (auto pl =
|
||||||
cache::client()
|
cache::client()
|
||||||
->getStateEvent<mtx::events::state::PowerLevels>(childid)
|
->getStateEvent<mtx::events::state::PowerLevels>(childid)
|
||||||
.value_or(mtx::events::StateEvent<mtx::events::state::PowerLevels>{})
|
.value_or(mtx::events::StateEvent<mtx::events::state::PowerLevels>{})
|
||||||
.content;
|
.content;
|
||||||
pl.user_level(us) <
|
pl.user_level(us, childCreate) <
|
||||||
pl.state_level(to_string(mtx::events::EventType::SpaceParent)))
|
pl.state_level(to_string(mtx::events::EventType::SpaceParent)))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
|
@ -2041,11 +2066,15 @@ utils::removeExpiredEvents()
|
||||||
if (!asus->globalExpiry && !getExpEv(roomid))
|
if (!asus->globalExpiry && !getExpEv(roomid))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
auto create = cache::client()->getStateEvent<mtx::events::state::Create>(roomid).value_or(
|
||||||
|
mtx::events::StateEvent<mtx::events::state::Create>{});
|
||||||
|
|
||||||
if (auto pl = cache::client()
|
if (auto pl = cache::client()
|
||||||
->getStateEvent<mtx::events::state::PowerLevels>(roomid)
|
->getStateEvent<mtx::events::state::PowerLevels>(roomid)
|
||||||
.value_or(mtx::events::StateEvent<mtx::events::state::PowerLevels>{})
|
.value_or(mtx::events::StateEvent<mtx::events::state::PowerLevels>{})
|
||||||
.content;
|
.content;
|
||||||
pl.user_level(us) < pl.event_level(to_string(mtx::events::EventType::RoomRedaction))) {
|
pl.user_level(us, create) <
|
||||||
|
pl.event_level(to_string(mtx::events::EventType::RoomRedaction))) {
|
||||||
nhlog::net()->warn("Can't react events in {}, not running expiration.", roomid);
|
nhlog::net()->warn("Can't react events in {}, not running expiration.", roomid);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,8 @@
|
||||||
|
|
||||||
#include "Permissions.h"
|
#include "Permissions.h"
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
|
|
||||||
#include "Cache_p.h"
|
#include "Cache_p.h"
|
||||||
#include "MatrixClient.h"
|
#include "MatrixClient.h"
|
||||||
#include "TimelineModel.h"
|
#include "TimelineModel.h"
|
||||||
|
|
@ -22,50 +24,53 @@ Permissions::invalidate()
|
||||||
->getStateEvent<mtx::events::state::PowerLevels>(roomId_.toStdString())
|
->getStateEvent<mtx::events::state::PowerLevels>(roomId_.toStdString())
|
||||||
.value_or(mtx::events::StateEvent<mtx::events::state::PowerLevels>{})
|
.value_or(mtx::events::StateEvent<mtx::events::state::PowerLevels>{})
|
||||||
.content;
|
.content;
|
||||||
|
create = cache::client()
|
||||||
|
->getStateEvent<mtx::events::state::Create>(roomId_.toStdString())
|
||||||
|
.value_or(mtx::events::StateEvent<mtx::events::state::Create>{});
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
Permissions::canInvite()
|
Permissions::canInvite()
|
||||||
{
|
{
|
||||||
const bool plCheck = pl.user_level(http::client()->user_id().to_string()) >= pl.invite;
|
const bool plCheck = pl.user_level(http::client()->user_id().to_string(), create) >= pl.invite;
|
||||||
return plCheck || this->isV12Creator();
|
return plCheck;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
Permissions::canBan()
|
Permissions::canBan()
|
||||||
{
|
{
|
||||||
const bool plCheck = pl.user_level(http::client()->user_id().to_string()) >= pl.ban;
|
const bool plCheck = pl.user_level(http::client()->user_id().to_string(), create) >= pl.ban;
|
||||||
return plCheck || this->isV12Creator();
|
return plCheck;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
Permissions::canKick()
|
Permissions::canKick()
|
||||||
{
|
{
|
||||||
const bool plCheck = pl.user_level(http::client()->user_id().to_string()) >= pl.kick;
|
const bool plCheck = pl.user_level(http::client()->user_id().to_string(), create) >= pl.kick;
|
||||||
return plCheck || this->isV12Creator();
|
return plCheck;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
Permissions::canRedact()
|
Permissions::canRedact()
|
||||||
{
|
{
|
||||||
const bool plCheck = pl.user_level(http::client()->user_id().to_string()) >= pl.redact;
|
const bool plCheck = pl.user_level(http::client()->user_id().to_string(), create) >= pl.redact;
|
||||||
return plCheck || this->isV12Creator();
|
return plCheck;
|
||||||
}
|
}
|
||||||
bool
|
bool
|
||||||
Permissions::canChange(int eventType)
|
Permissions::canChange(int eventType)
|
||||||
{
|
{
|
||||||
const bool plCheck = pl.user_level(http::client()->user_id().to_string()) >=
|
const bool plCheck = pl.user_level(http::client()->user_id().to_string(), create) >=
|
||||||
pl.state_level(to_string(qml_mtx_events::fromRoomEventType(
|
pl.state_level(to_string(qml_mtx_events::fromRoomEventType(
|
||||||
static_cast<qml_mtx_events::EventType>(eventType))));
|
static_cast<qml_mtx_events::EventType>(eventType))));
|
||||||
return plCheck || this->isV12Creator();
|
return plCheck;
|
||||||
}
|
}
|
||||||
bool
|
bool
|
||||||
Permissions::canSend(int eventType)
|
Permissions::canSend(int eventType)
|
||||||
{
|
{
|
||||||
const bool plCheck = pl.user_level(http::client()->user_id().to_string()) >=
|
const bool plCheck = pl.user_level(http::client()->user_id().to_string(), create) >=
|
||||||
pl.event_level(to_string(qml_mtx_events::fromRoomEventType(
|
pl.event_level(to_string(qml_mtx_events::fromRoomEventType(
|
||||||
static_cast<qml_mtx_events::EventType>(eventType))));
|
static_cast<qml_mtx_events::EventType>(eventType))));
|
||||||
return plCheck || this->isV12Creator();
|
return plCheck;
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
|
|
@ -94,15 +99,9 @@ Permissions::sendLevel(int eventType)
|
||||||
bool
|
bool
|
||||||
Permissions::canPingRoom()
|
Permissions::canPingRoom()
|
||||||
{
|
{
|
||||||
const bool plCheck = pl.user_level(http::client()->user_id().to_string()) >=
|
const bool plCheck = pl.user_level(http::client()->user_id().to_string(), create) >=
|
||||||
pl.notification_level(mtx::events::state::notification_keys::room);
|
pl.notification_level(mtx::events::state::notification_keys::room);
|
||||||
return plCheck || this->isV12Creator();
|
return plCheck;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
|
||||||
Permissions::isV12Creator()
|
|
||||||
{
|
|
||||||
return cache::client()->isV12Creator(this->roomId_.toStdString(),
|
|
||||||
http::client()->user_id().to_string());
|
|
||||||
}
|
|
||||||
#include "moc_Permissions.cpp"
|
#include "moc_Permissions.cpp"
|
||||||
|
|
|
||||||
|
|
@ -6,6 +6,8 @@
|
||||||
|
|
||||||
#include <QObject>
|
#include <QObject>
|
||||||
|
|
||||||
|
#include <mtx/events.hpp>
|
||||||
|
#include <mtx/events/create.hpp>
|
||||||
#include <mtx/events/power_levels.hpp>
|
#include <mtx/events/power_levels.hpp>
|
||||||
|
|
||||||
class TimelineModel;
|
class TimelineModel;
|
||||||
|
|
@ -28,16 +30,20 @@ public:
|
||||||
Q_INVOKABLE int redactLevel();
|
Q_INVOKABLE int redactLevel();
|
||||||
Q_INVOKABLE int changeLevel(int eventType);
|
Q_INVOKABLE int changeLevel(int eventType);
|
||||||
Q_INVOKABLE int sendLevel(int eventType);
|
Q_INVOKABLE int sendLevel(int eventType);
|
||||||
|
Q_INVOKABLE qint64 creatorLevel() const { return mtx::events::state::Creator; }
|
||||||
|
|
||||||
Q_INVOKABLE bool canPingRoom();
|
Q_INVOKABLE bool canPingRoom();
|
||||||
|
|
||||||
void invalidate();
|
void invalidate();
|
||||||
|
|
||||||
const mtx::events::state::PowerLevels &powerlevelEvent() const { return pl; };
|
const mtx::events::state::PowerLevels &powerlevelEvent() const { return pl; };
|
||||||
|
const mtx::events::StateEvent<mtx::events::state::Create> &createEvent() const
|
||||||
|
{
|
||||||
|
return create;
|
||||||
|
};
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool isV12Creator();
|
|
||||||
|
|
||||||
QString roomId_;
|
QString roomId_;
|
||||||
mtx::events::state::PowerLevels pl;
|
mtx::events::state::PowerLevels pl;
|
||||||
|
mtx::events::StateEvent<mtx::events::state::Create> create;
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -605,8 +605,8 @@ TimelineModel::data(const mtx::events::collections::TimelineEvents &event, int r
|
||||||
case UserName:
|
case UserName:
|
||||||
return QVariant(displayName(QString::fromStdString(acc::sender(event))));
|
return QVariant(displayName(QString::fromStdString(acc::sender(event))));
|
||||||
case UserPowerlevel: {
|
case UserPowerlevel: {
|
||||||
return static_cast<qlonglong>(
|
return static_cast<qlonglong>(permissions_.powerlevelEvent().user_level(
|
||||||
permissions_.powerlevelEvent().user_level(acc::sender(event)));
|
acc::sender(event), permissions_.createEvent()));
|
||||||
}
|
}
|
||||||
|
|
||||||
case Day: {
|
case Day: {
|
||||||
|
|
@ -1413,12 +1413,6 @@ TimelineModel::readEvent(const std::string &id)
|
||||||
!UserSettings::instance()->readReceipts());
|
!UserSettings::instance()->readReceipts());
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
|
||||||
TimelineModel::isV12Creator(const QString &id) const
|
|
||||||
{
|
|
||||||
return cache::isV12Creator(this->roomId().toStdString(), id.toStdString());
|
|
||||||
}
|
|
||||||
|
|
||||||
QString
|
QString
|
||||||
TimelineModel::displayName(const QString &id) const
|
TimelineModel::displayName(const QString &id) const
|
||||||
{
|
{
|
||||||
|
|
@ -2427,6 +2421,7 @@ QString
|
||||||
TimelineModel::formatPowerLevelEvent(
|
TimelineModel::formatPowerLevelEvent(
|
||||||
const mtx::events::StateEvent<mtx::events::state::PowerLevels> &event) const
|
const mtx::events::StateEvent<mtx::events::state::PowerLevels> &event) const
|
||||||
{
|
{
|
||||||
|
const auto create = permissions_.createEvent();
|
||||||
mtx::events::StateEvent<mtx::events::state::PowerLevels> const *prevEvent = nullptr;
|
mtx::events::StateEvent<mtx::events::state::PowerLevels> const *prevEvent = nullptr;
|
||||||
if (!event.unsigned_data.replaces_state.empty()) {
|
if (!event.unsigned_data.replaces_state.empty()) {
|
||||||
auto tempPrevEvent = events.get(event.unsigned_data.replaces_state, event.event_id);
|
auto tempPrevEvent = events.get(event.unsigned_data.replaces_state, event.event_id);
|
||||||
|
|
@ -2446,15 +2441,15 @@ TimelineModel::formatPowerLevelEvent(
|
||||||
if (!prevEvent)
|
if (!prevEvent)
|
||||||
return tr("%1 has changed the room's permissions.").arg(sender_name);
|
return tr("%1 has changed the room's permissions.").arg(sender_name);
|
||||||
|
|
||||||
auto calc_affected = [&event,
|
auto calc_affected =
|
||||||
&prevEvent](int64_t newPowerlevelSetting) -> std::pair<QStringList, int> {
|
[&event, &prevEvent, &create](int64_t newPowerlevelSetting) -> std::pair<QStringList, int> {
|
||||||
QStringList affected{};
|
QStringList affected{};
|
||||||
auto numberOfAffected = 0;
|
auto numberOfAffected = 0;
|
||||||
// We do only compare to people with explicit PL. Usually others are not going to be
|
// We do only compare to people with explicit PL. Usually others are not going to be
|
||||||
// affected either way and this is cheaper to iterate over.
|
// affected either way and this is cheaper to iterate over.
|
||||||
for (auto const &[mxid, currentPowerlevel] : event.content.users) {
|
for (auto const &[mxid, currentPowerlevel] : event.content.users) {
|
||||||
if (currentPowerlevel == newPowerlevelSetting &&
|
if (currentPowerlevel == newPowerlevelSetting &&
|
||||||
prevEvent->content.user_level(mxid) < newPowerlevelSetting) {
|
prevEvent->content.user_level(mxid, create) < newPowerlevelSetting) {
|
||||||
numberOfAffected++;
|
numberOfAffected++;
|
||||||
if (numberOfAffected <= 2) {
|
if (numberOfAffected <= 2) {
|
||||||
affected.push_back(QString::fromStdString(mxid));
|
affected.push_back(QString::fromStdString(mxid));
|
||||||
|
|
@ -2631,24 +2626,25 @@ TimelineModel::formatPowerLevelEvent(
|
||||||
// Compare if a Powerlevel of a user changed
|
// Compare if a Powerlevel of a user changed
|
||||||
for (auto const &[mxid, powerlevel] : event.content.users) {
|
for (auto const &[mxid, powerlevel] : event.content.users) {
|
||||||
auto nameOfChangedUser = utils::replaceEmoji(displayName(QString::fromStdString(mxid)));
|
auto nameOfChangedUser = utils::replaceEmoji(displayName(QString::fromStdString(mxid)));
|
||||||
if (prevEvent->content.user_level(mxid) != powerlevel) {
|
if (prevEvent->content.user_level(mxid, create) != powerlevel) {
|
||||||
if (powerlevel >= administrator_power_level) {
|
if (powerlevel >= administrator_power_level) {
|
||||||
resultingMessage.append(tr("%1 has made %2 an administrator of this room.")
|
resultingMessage.append(tr("%1 has made %2 an administrator of this room.")
|
||||||
.arg(sender_name, nameOfChangedUser));
|
.arg(sender_name, nameOfChangedUser));
|
||||||
} else if (powerlevel >= moderator_power_level &&
|
} else if (powerlevel >= moderator_power_level &&
|
||||||
powerlevel > prevEvent->content.user_level(mxid)) {
|
powerlevel > prevEvent->content.user_level(mxid, create)) {
|
||||||
resultingMessage.append(tr("%1 has made %2 a moderator of this room.")
|
resultingMessage.append(tr("%1 has made %2 a moderator of this room.")
|
||||||
.arg(sender_name, nameOfChangedUser));
|
.arg(sender_name, nameOfChangedUser));
|
||||||
} else if (powerlevel >= moderator_power_level &&
|
} else if (powerlevel >= moderator_power_level &&
|
||||||
powerlevel < prevEvent->content.user_level(mxid)) {
|
powerlevel < prevEvent->content.user_level(mxid, create)) {
|
||||||
resultingMessage.append(tr("%1 has downgraded %2 to moderator of this room.")
|
resultingMessage.append(tr("%1 has downgraded %2 to moderator of this room.")
|
||||||
.arg(sender_name, nameOfChangedUser));
|
.arg(sender_name, nameOfChangedUser));
|
||||||
} else {
|
} else {
|
||||||
resultingMessage.append(tr("%1 has changed the powerlevel of %2 from %3 to %4.")
|
resultingMessage.append(
|
||||||
.arg(sender_name,
|
tr("%1 has changed the powerlevel of %2 from %3 to %4.")
|
||||||
nameOfChangedUser,
|
.arg(sender_name,
|
||||||
QString::number(prevEvent->content.user_level(mxid)),
|
nameOfChangedUser,
|
||||||
QString::number(powerlevel)));
|
QString::number(prevEvent->content.user_level(mxid, create)),
|
||||||
|
QString::number(powerlevel)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -3379,6 +3375,7 @@ TimelineModel::pushrulesRoomContext() const
|
||||||
cache::displayName(room_id_.toStdString(), http::client()->user_id().to_string()),
|
cache::displayName(room_id_.toStdString(), http::client()->user_id().to_string()),
|
||||||
.member_count = cache::client()->memberCount(room_id_.toStdString()),
|
.member_count = cache::client()->memberCount(room_id_.toStdString()),
|
||||||
.power_levels = permissions_.powerlevelEvent(),
|
.power_levels = permissions_.powerlevelEvent(),
|
||||||
|
.create = permissions_.createEvent(),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -302,7 +302,6 @@ public:
|
||||||
static QString getBareRoomLink(const QString &);
|
static QString getBareRoomLink(const QString &);
|
||||||
static QString getRoomVias(const QString &);
|
static QString getRoomVias(const QString &);
|
||||||
|
|
||||||
Q_INVOKABLE bool isV12Creator(const QString &id) const;
|
|
||||||
Q_INVOKABLE QString displayName(const QString &id) const;
|
Q_INVOKABLE QString displayName(const QString &id) const;
|
||||||
Q_INVOKABLE QString avatarUrl(const QString &id) const;
|
Q_INVOKABLE QString avatarUrl(const QString &id) const;
|
||||||
Q_INVOKABLE QString formatDateSeparator(QDate date) const;
|
Q_INVOKABLE QString formatDateSeparator(QDate date) const;
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue