Allow editing aliases
This commit is contained in:
parent
42b53817e0
commit
931855441a
13 changed files with 643 additions and 9 deletions
336
src/AliasEditModel.cpp
Normal file
336
src/AliasEditModel.cpp
Normal file
|
|
@ -0,0 +1,336 @@
|
|||
// SPDX-FileCopyrightText: 2022 Nheko Contributors
|
||||
//
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
#include "AliasEditModel.h"
|
||||
|
||||
#include <QSharedPointer>
|
||||
|
||||
#include <set>
|
||||
|
||||
#include <mtx/responses/common.hpp>
|
||||
|
||||
#include "Cache.h"
|
||||
#include "Cache_p.h"
|
||||
#include "ChatPage.h"
|
||||
#include "Logging.h"
|
||||
#include "MatrixClient.h"
|
||||
#include "timeline/Permissions.h"
|
||||
#include "timeline/TimelineModel.h"
|
||||
|
||||
AliasEditingModel::AliasEditingModel(const std::string &rid, QObject *parent)
|
||||
: QAbstractListModel(parent)
|
||||
, room_id(rid)
|
||||
, aliasEvent(cache::client()
|
||||
->getStateEvent<mtx::events::state::CanonicalAlias>(room_id)
|
||||
.value_or(mtx::events::StateEvent<mtx::events::state::CanonicalAlias>{})
|
||||
.content)
|
||||
, canSendStateEvent(
|
||||
Permissions(QString::fromStdString(rid)).canChange(qml_mtx_events::CanonicalAlias))
|
||||
{
|
||||
std::set<std::string> seen_aliases;
|
||||
|
||||
if (!aliasEvent.alias.empty()) {
|
||||
aliases.push_back(Entry{aliasEvent.alias, true, true, false});
|
||||
seen_aliases.insert(aliasEvent.alias);
|
||||
}
|
||||
|
||||
for (const auto &alias : aliasEvent.alt_aliases) {
|
||||
if (!seen_aliases.count(alias)) {
|
||||
aliases.push_back(Entry{aliasEvent.alias, false, true, false});
|
||||
seen_aliases.insert(aliasEvent.alias);
|
||||
}
|
||||
}
|
||||
|
||||
for (const auto &alias : aliases) {
|
||||
fetchAliasesStatus(alias.alias);
|
||||
}
|
||||
fetchPublishedAliases();
|
||||
}
|
||||
|
||||
void
|
||||
AliasEditingModel::fetchPublishedAliases()
|
||||
{
|
||||
auto job = QSharedPointer<FetchPublishedAliasesJob>::create();
|
||||
connect(job.data(),
|
||||
&FetchPublishedAliasesJob::advertizedAliasesFetched,
|
||||
this,
|
||||
&AliasEditingModel::updatePublishedAliases);
|
||||
http::client()->list_room_aliases(
|
||||
room_id, [job](const mtx::responses::Aliases &aliasesFetched, mtx::http::RequestErr) {
|
||||
emit job->advertizedAliasesFetched(std::move(aliasesFetched.aliases));
|
||||
});
|
||||
}
|
||||
|
||||
void
|
||||
AliasEditingModel::fetchAliasesStatus(const std::string &alias)
|
||||
{
|
||||
auto job = QSharedPointer<FetchPublishedAliasesJob>::create();
|
||||
connect(
|
||||
job.data(), &FetchPublishedAliasesJob::aliasFetched, this, &AliasEditingModel::updateAlias);
|
||||
http::client()->resolve_room_alias(
|
||||
alias, [job, alias](const mtx::responses::RoomId &roomIdFetched, mtx::http::RequestErr e) {
|
||||
if (!e)
|
||||
emit job->aliasFetched(alias, std::move(roomIdFetched.room_id));
|
||||
});
|
||||
}
|
||||
|
||||
QHash<int, QByteArray>
|
||||
AliasEditingModel::roleNames() const
|
||||
{
|
||||
return {
|
||||
{Name, "name"},
|
||||
{IsPublished, "isPublished"},
|
||||
{IsCanonical, "isCanonical"},
|
||||
{IsAdvertized, "isAdvertized"},
|
||||
};
|
||||
}
|
||||
|
||||
QVariant
|
||||
AliasEditingModel::data(const QModelIndex &index, int role) const
|
||||
{
|
||||
if (!index.isValid() || index.row() >= aliases.size())
|
||||
return {};
|
||||
|
||||
const auto &entry = aliases.at(index.row());
|
||||
|
||||
switch (role) {
|
||||
case Name:
|
||||
return QString::fromStdString(entry.alias);
|
||||
case IsPublished:
|
||||
return entry.published;
|
||||
case IsCanonical:
|
||||
return entry.canonical;
|
||||
case IsAdvertized:
|
||||
return entry.advertized;
|
||||
}
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
bool
|
||||
AliasEditingModel::deleteAlias(int row)
|
||||
{
|
||||
if (row < 0 || row >= aliases.size() || aliases.at(row).alias.empty())
|
||||
return false;
|
||||
|
||||
auto alias = aliases.at(row);
|
||||
|
||||
beginRemoveRows(QModelIndex(), row, row);
|
||||
aliases.remove(row);
|
||||
endRemoveRows();
|
||||
|
||||
if (alias.published)
|
||||
http::client()->delete_room_alias(alias.alias, [alias](mtx::http::RequestErr e) {
|
||||
if (e) {
|
||||
nhlog::net()->error("Failed to delete {}: {}", alias.alias, *e);
|
||||
ChatPage::instance()->showNotification(
|
||||
tr("Failed to unpublish alias %1: %2")
|
||||
.arg(QString::fromStdString(alias.alias),
|
||||
QString::fromStdString(e->matrix_error.error)));
|
||||
}
|
||||
});
|
||||
|
||||
if (aliasEvent.alias == alias.alias)
|
||||
aliasEvent.alias.clear();
|
||||
|
||||
for (size_t i = 0; i < aliasEvent.alt_aliases.size(); i++) {
|
||||
if (aliasEvent.alt_aliases[i] == alias.alias) {
|
||||
aliasEvent.alt_aliases.erase(aliasEvent.alt_aliases.begin() + i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
AliasEditingModel::addAlias(QString newAlias)
|
||||
{
|
||||
const auto aliasStr = newAlias.toStdString();
|
||||
for (const auto &e : aliases) {
|
||||
if (e.alias == aliasStr) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
beginInsertRows(QModelIndex(), aliases.length(), aliases.length());
|
||||
if (aliasEvent.alias.empty())
|
||||
aliasEvent.alias = aliasStr;
|
||||
else
|
||||
aliasEvent.alt_aliases.push_back(aliasStr);
|
||||
aliases.push_back(
|
||||
Entry{aliasStr, aliasEvent.alias.empty() && canSendStateEvent, canSendStateEvent, false});
|
||||
endInsertRows();
|
||||
|
||||
auto job = QSharedPointer<FetchPublishedAliasesJob>::create();
|
||||
connect(
|
||||
job.data(), &FetchPublishedAliasesJob::aliasFetched, this, &AliasEditingModel::updateAlias);
|
||||
auto room = room_id;
|
||||
http::client()->add_room_alias(
|
||||
aliasStr, room_id, [job, aliasStr, room](mtx::http::RequestErr e) {
|
||||
if (e) {
|
||||
nhlog::net()->error("Failed to publish {}: {}", aliasStr, *e);
|
||||
ChatPage::instance()->showNotification(
|
||||
tr("Failed to unpublish alias %1: %2")
|
||||
.arg(QString::fromStdString(aliasStr),
|
||||
QString::fromStdString(e->matrix_error.error)));
|
||||
emit job->aliasFetched(aliasStr, "");
|
||||
} else {
|
||||
emit job->aliasFetched(aliasStr, room);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void
|
||||
AliasEditingModel::makeCanonical(int row)
|
||||
{
|
||||
if (!canSendStateEvent || row < 0 || row >= aliases.size() || aliases.at(row).alias.empty())
|
||||
return;
|
||||
|
||||
auto moveAlias = aliases.at(row).alias;
|
||||
|
||||
if (!aliasEvent.alias.empty()) {
|
||||
for (qsizetype i = 0; i < aliases.size(); i++) {
|
||||
if (moveAlias == aliases[i].alias) {
|
||||
if (aliases[i].canonical) {
|
||||
aliases[i].canonical = false;
|
||||
aliasEvent.alt_aliases.push_back(aliasEvent.alias);
|
||||
emit dataChanged(index(i), index(i), {IsCanonical});
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
aliasEvent.alias = moveAlias;
|
||||
for (auto i = aliasEvent.alt_aliases.begin(); i != aliasEvent.alt_aliases.end(); ++i) {
|
||||
if (*i == moveAlias) {
|
||||
aliasEvent.alt_aliases.erase(i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
aliases[row].canonical = true;
|
||||
aliases[row].advertized = true;
|
||||
emit dataChanged(index(row), index(row), {IsCanonical, IsAdvertized});
|
||||
}
|
||||
|
||||
void
|
||||
AliasEditingModel::togglePublish(int row)
|
||||
{
|
||||
if (row < 0 || row >= aliases.size() || aliases.at(row).alias.empty())
|
||||
return;
|
||||
auto aliasStr = aliases[row].alias;
|
||||
|
||||
auto job = QSharedPointer<FetchPublishedAliasesJob>::create();
|
||||
connect(
|
||||
job.data(), &FetchPublishedAliasesJob::aliasFetched, this, &AliasEditingModel::updateAlias);
|
||||
auto room = room_id;
|
||||
if (!aliases[row].published)
|
||||
http::client()->add_room_alias(
|
||||
aliasStr, room_id, [job, aliasStr, room](mtx::http::RequestErr e) {
|
||||
if (e) {
|
||||
nhlog::net()->error("Failed to publish {}: {}", aliasStr, *e);
|
||||
ChatPage::instance()->showNotification(
|
||||
tr("Failed to unpublish alias %1: %2")
|
||||
.arg(QString::fromStdString(aliasStr),
|
||||
QString::fromStdString(e->matrix_error.error)));
|
||||
emit job->aliasFetched(aliasStr, "");
|
||||
} else {
|
||||
emit job->aliasFetched(aliasStr, room);
|
||||
}
|
||||
});
|
||||
else
|
||||
http::client()->delete_room_alias(aliasStr, [job, aliasStr, room](mtx::http::RequestErr e) {
|
||||
if (e) {
|
||||
nhlog::net()->error("Failed to unpublish {}: {}", aliasStr, *e);
|
||||
ChatPage::instance()->showNotification(
|
||||
tr("Failed to unpublish alias %1: %2")
|
||||
.arg(QString::fromStdString(aliasStr),
|
||||
QString::fromStdString(e->matrix_error.error)));
|
||||
emit job->aliasFetched(aliasStr, room);
|
||||
} else {
|
||||
emit job->aliasFetched(aliasStr, "");
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void
|
||||
AliasEditingModel::toggleAdvertize(int row)
|
||||
{
|
||||
if (!canSendStateEvent || row < 0 || row >= aliases.size() || aliases.at(row).alias.empty())
|
||||
return;
|
||||
|
||||
auto &moveAlias = aliases[row];
|
||||
if (aliasEvent.alias == moveAlias.alias) {
|
||||
moveAlias.canonical = false;
|
||||
moveAlias.advertized = false;
|
||||
aliasEvent.alias.clear();
|
||||
emit dataChanged(index(row), index(row), {IsAdvertized, IsCanonical});
|
||||
} else if (moveAlias.advertized) {
|
||||
for (auto i = aliasEvent.alt_aliases.begin(); i != aliasEvent.alt_aliases.end(); ++i) {
|
||||
if (*i == moveAlias.alias) {
|
||||
aliasEvent.alt_aliases.erase(i);
|
||||
moveAlias.advertized = false;
|
||||
emit dataChanged(index(row), index(row), {IsAdvertized});
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
aliasEvent.alt_aliases.push_back(moveAlias.alias);
|
||||
moveAlias.advertized = true;
|
||||
emit dataChanged(index(row), index(row), {IsAdvertized});
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
AliasEditingModel::updateAlias(std::string alias, std::string target)
|
||||
{
|
||||
for (qsizetype i = 0; i < aliases.size(); i++) {
|
||||
auto &e = aliases[i];
|
||||
if (e.alias == alias) {
|
||||
e.published = (target == room_id);
|
||||
emit dataChanged(index(i), index(i), {IsPublished});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
AliasEditingModel::updatePublishedAliases(std::vector<std::string> advAliases)
|
||||
{
|
||||
for (const auto &advAlias : advAliases) {
|
||||
bool found = false;
|
||||
for (qsizetype i = 0; i < aliases.size(); i++) {
|
||||
auto &alias = aliases[i];
|
||||
if (alias.alias == advAlias) {
|
||||
alias.published = true;
|
||||
emit dataChanged(index(i), index(i), {IsPublished});
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
|
||||
if (!found) {
|
||||
beginInsertRows(QModelIndex(), aliases.size(), aliases.size());
|
||||
aliases.push_back(Entry{advAlias, false, false, true});
|
||||
endInsertRows();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
AliasEditingModel::commit()
|
||||
{
|
||||
if (!canSendStateEvent)
|
||||
return;
|
||||
|
||||
http::client()->send_state_event(
|
||||
room_id, aliasEvent, [](const mtx::responses::EventId &, mtx::http::RequestErr e) {
|
||||
if (e) {
|
||||
nhlog::net()->error("Failed to send Alias event: {}", *e);
|
||||
ChatPage::instance()->showNotification(
|
||||
tr("Failed to update aliases: %1")
|
||||
.arg(QString::fromStdString(e->matrix_error.error)));
|
||||
}
|
||||
});
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue