Improved v12 support

This commit is contained in:
Sofia/Nep 2025-09-22 14:04:35 -03:00
parent 5b025fa2b0
commit 4a85031516
No known key found for this signature in database
GPG key ID: C83ACF9DBED618E1
13 changed files with 132 additions and 16 deletions

View file

@ -618,7 +618,7 @@ if(USE_BUNDLED_MTXCLIENT)
FetchContent_Declare(
MatrixClient
GIT_REPOSITORY https://github.com/Nheko-Reborn/mtxclient.git
GIT_TAG v0.10.1
GIT_TAG d6f10427d1c5e5b1a45f426274f8d2e8dd0b64be
)
set(BUILD_LIB_EXAMPLES OFF CACHE INTERNAL "")
set(BUILD_LIB_TESTS OFF CACHE INTERNAL "")

View file

@ -89,6 +89,7 @@ Column {
anchors.left: parent.left
anchors.verticalCenter: parent.verticalCenter
isV12Creator: room.isV12Creator(userId)
powerlevel: userPowerlevel
height: fontMetrics.ascent
width: height
@ -97,7 +98,7 @@ Column {
sourceSize.height: height
permissions: room ? room.permissions : null
visible: isAdmin || isModerator
visible: isAdmin || isModerator || isV12Creator
}
ToolTip.delay: Nheko.tooltipDelay

View file

@ -9,13 +9,14 @@ import im.nheko
Image {
required property int powerlevel
required property var permissions
required property bool isV12Creator
readonly property bool isAdmin: permissions ? permissions.changeLevel(MtxEvent.PowerLevels) <= powerlevel : false
readonly property bool isModerator: permissions ? permissions.redactLevel() <= powerlevel : false
readonly property bool isDefault: permissions ? permissions.defaultLevel() <= powerlevel : false
readonly property string sourceUrl: {
if (isAdmin)
if (isAdmin || isV12Creator)
return "image://colorimage/:/icons/icons/ui/ribbon_star.svg?";
else if (isModerator)
return "image://colorimage/:/icons/icons/ui/ribbon.svg?";
@ -26,7 +27,9 @@ Image {
source: sourceUrl + (ma.hovered ? palette.highlight : palette.buttonText)
ToolTip.visible: ma.hovered
ToolTip.text: {
if (isAdmin)
if (isV12Creator)
return qsTr("Creator");
else if (isAdmin)
return qsTr("Administrator: %1").arg(powerlevel);
else if (isModerator)
return qsTr("Moderator: %1").arg(powerlevel);

View file

@ -168,6 +168,7 @@ ApplicationWindow {
sourceSize.height: height
powerlevel: model.powerlevel
permissions: room.permissions
isV12Creator: room.isV12Creator(model.mxid)
}
EncryptionIndicator {

View file

@ -4851,6 +4851,51 @@ Cache::getAccountData(lmdb::txn &txn, mtx::events::EventType type, const std::st
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
Cache::hasEnoughPowerLevel(const std::vector<mtx::events::EventType> &eventTypes,
const std::string &room_id,
@ -4863,6 +4908,10 @@ Cache::hasEnoughPowerLevel(const std::vector<mtx::events::EventType> &eventTypes
try {
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 user_level = std::numeric_limits<int64_t>::min();
@ -6129,6 +6178,13 @@ roomMembers(const std::string &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
//! lowest power level of the given events.
bool

View file

@ -123,6 +123,10 @@ runMigrations();
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);
//! Check if the given user has power level greater than than
//! lowest power level of the given events.
bool

View file

@ -145,6 +145,10 @@ public:
//! Retrieve all the user ids from a room.
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
//! lowest power level of the given events.
bool hasEnoughPowerLevel(const std::vector<mtx::events::EventType> &eventTypes,

View file

@ -172,4 +172,28 @@ MemberList::filterAcceptsRow(int source_row, const QModelIndex &) const
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"

View file

@ -122,6 +122,7 @@ public slots:
protected:
bool filterAcceptsRow(int source_row, const QModelIndex &source_parent) const override;
bool lessThan(const QModelIndex &source_left, const QModelIndex &source_right) const override;
private:
QString filterString;

View file

@ -27,39 +27,45 @@ Permissions::invalidate()
bool
Permissions::canInvite()
{
return pl.user_level(http::client()->user_id().to_string()) >= pl.invite;
const bool plCheck = pl.user_level(http::client()->user_id().to_string()) >= pl.invite;
return plCheck || this->isV12Creator();
}
bool
Permissions::canBan()
{
return pl.user_level(http::client()->user_id().to_string()) >= pl.ban;
const bool plCheck = pl.user_level(http::client()->user_id().to_string()) >= pl.ban;
return plCheck || this->isV12Creator();
}
bool
Permissions::canKick()
{
return pl.user_level(http::client()->user_id().to_string()) >= pl.kick;
const bool plCheck = pl.user_level(http::client()->user_id().to_string()) >= pl.kick;
return plCheck || this->isV12Creator();
}
bool
Permissions::canRedact()
{
return pl.user_level(http::client()->user_id().to_string()) >= pl.redact;
const bool plCheck = pl.user_level(http::client()->user_id().to_string()) >= pl.redact;
return plCheck || this->isV12Creator();
}
bool
Permissions::canChange(int eventType)
{
return pl.user_level(http::client()->user_id().to_string()) >=
pl.state_level(to_string(
qml_mtx_events::fromRoomEventType(static_cast<qml_mtx_events::EventType>(eventType))));
const bool plCheck = pl.user_level(http::client()->user_id().to_string()) >=
pl.state_level(to_string(qml_mtx_events::fromRoomEventType(
static_cast<qml_mtx_events::EventType>(eventType))));
return plCheck || this->isV12Creator();
}
bool
Permissions::canSend(int eventType)
{
return pl.user_level(http::client()->user_id().to_string()) >=
pl.event_level(to_string(
qml_mtx_events::fromRoomEventType(static_cast<qml_mtx_events::EventType>(eventType))));
const bool plCheck = pl.user_level(http::client()->user_id().to_string()) >=
pl.event_level(to_string(qml_mtx_events::fromRoomEventType(
static_cast<qml_mtx_events::EventType>(eventType))));
return plCheck || this->isV12Creator();
}
int
@ -88,8 +94,15 @@ Permissions::sendLevel(int eventType)
bool
Permissions::canPingRoom()
{
return pl.user_level(http::client()->user_id().to_string()) >=
pl.notification_level(mtx::events::state::notification_keys::room);
const bool plCheck = pl.user_level(http::client()->user_id().to_string()) >=
pl.notification_level(mtx::events::state::notification_keys::room);
return plCheck || this->isV12Creator();
}
bool
Permissions::isV12Creator()
{
return cache::client()->isV12Creator(this->roomId_.toStdString(),
http::client()->user_id().to_string());
}
#include "moc_Permissions.cpp"

View file

@ -36,6 +36,8 @@ public:
const mtx::events::state::PowerLevels &powerlevelEvent() const { return pl; };
private:
bool isV12Creator();
QString roomId_;
mtx::events::state::PowerLevels pl;
};

View file

@ -1414,6 +1414,12 @@ TimelineModel::readEvent(const std::string &id)
!UserSettings::instance()->readReceipts());
}
bool
TimelineModel::isV12Creator(const QString &id) const
{
return cache::isV12Creator(this->roomId().toStdString(), id.toStdString());
}
QString
TimelineModel::displayName(const QString &id) const
{

View file

@ -302,6 +302,7 @@ public:
static QString getBareRoomLink(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 avatarUrl(const QString &id) const;
Q_INVOKABLE QString formatDateSeparator(QDate date) const;