added notifications and encryption for the new roomsettings

This commit is contained in:
Jedi18 2021-02-11 19:54:09 +05:30
parent b70f37194f
commit 7401bd13b2
6 changed files with 352 additions and 6 deletions

View File

@ -2,6 +2,7 @@ import QtQuick 2.9
import QtQuick.Controls 2.3 import QtQuick.Controls 2.3
import QtQuick.Layouts 1.2 import QtQuick.Layouts 1.2
import QtQuick.Window 2.3 import QtQuick.Window 2.3
import QtQuick.Dialogs 1.2
import im.nheko 1.0 import im.nheko 1.0
ApplicationWindow { ApplicationWindow {
@ -17,7 +18,8 @@ ApplicationWindow {
palette: colors palette: colors
color: colors.window color: colors.window
title: roomSettings.roomName title: roomSettings.roomName
modality: Qt.Modal modality: Qt.WindowModal
flags: Qt.WindowStaysOnTopHint
Shortcut { Shortcut {
sequence: StandardKey.Cancel sequence: StandardKey.Cancel
@ -75,6 +77,10 @@ ApplicationWindow {
ComboBox { ComboBox {
model: [ "Muted", "Mentions only", "All messages" ] model: [ "Muted", "Mentions only", "All messages" ]
currentIndex: roomSettings.notifications
onActivated: {
roomSettings.changeNotifications(index)
}
} }
} }
@ -85,7 +91,12 @@ ApplicationWindow {
ComboBox { ComboBox {
Layout.fillWidth: true Layout.fillWidth: true
enabled: roomSettings.canChangeJoinRules
model: [ "Anyone and guests", "Anyone", "Invited users" ] model: [ "Anyone and guests", "Anyone", "Invited users" ]
currentIndex: roomSettings.accessJoinRules
onActivated: {
roomSettings.changeAccessRules(index)
}
} }
} }
@ -99,10 +110,46 @@ ApplicationWindow {
} }
Switch { Switch {
id: encryptionSwitch
checked: roomSettings.isEncryptionEnabled
onToggled: {
if(roomSettings.isEncryptionEnabled) {
checked=true;
return;
}
confirmEncryptionDialog.open();
}
}
MessageDialog {
id: confirmEncryptionDialog
title: qsTr("End-to-End Encryption")
text: qsTr("Encryption is currently experimental and things might break unexpectedly. <br>
Please take note that it can't be disabled afterwards.")
modality: Qt.WindowModal
icon: StandardIcon.Question
onAccepted: {
if(roomSettings.isEncryptionEnabled) {
return;
}
roomSettings.enableEncryption();
}
onRejected: {
encryptionSwitch.checked = false
}
standardButtons: Dialog.Ok | Dialog.Cancel
} }
} }
RowLayout { RowLayout {
visible: roomSettings.isEncryptionEnabled
MatrixText { MatrixText {
text: "Respond to key requests" text: "Respond to key requests"
} }
@ -112,6 +159,15 @@ ApplicationWindow {
} }
Switch { Switch {
ToolTip.text: qsTr("Whether or not the client should respond automatically with the session keys
upon request. Use with caution, this is a temporary measure to test the
E2E implementation until device verification is completed.")
checked: roomSettings.respondsToKeyRequests
onToggled: {
roomSettings.changeKeyRequestsPreference(checked)
}
} }
} }

View File

@ -178,7 +178,7 @@ Page {
target: TimelineManager target: TimelineManager
onOpenRoomSettingsDialog: { onOpenRoomSettingsDialog: {
var roomSettings = roomSettingsComponent.createObject(timelineRoot, { var roomSettings = roomSettingsComponent.createObject(timelineRoot, {
"roomSettings": roomSettings "roomSettings": settings
}); });
roomSettings.show(); roomSettings.show();
} }

View File

@ -126,6 +126,12 @@ TimelineViewManager::TimelineViewManager(CallManager *callManager, ChatPage *par
0, 0,
"UserProfileModel", "UserProfileModel",
"UserProfile needs to be instantiated on the C++ side"); "UserProfile needs to be instantiated on the C++ side");
qmlRegisterUncreatableType<RoomSettings>(
"im.nheko",
1,
0,
"RoomSettingsModel",
"Room Settings needs to be instantiated on the C++ side");
static auto self = this; static auto self = this;
qmlRegisterSingletonType<MainWindow>( qmlRegisterSingletonType<MainWindow>(
@ -394,8 +400,8 @@ TimelineViewManager::openRoomSettings()
{ {
MainWindow::instance()->openRoomSettings(timeline_->roomId()); MainWindow::instance()->openRoomSettings(timeline_->roomId());
RoomSettings *roomSettings = new RoomSettings(timeline_->roomId(), this); RoomSettings *settings = new RoomSettings(timeline_->roomId(), this);
emit openRoomSettingsDialog(roomSettings); emit openRoomSettingsDialog(settings);
} }
void void

View File

@ -89,7 +89,7 @@ signals:
void showRoomList(); void showRoomList();
void narrowViewChanged(); void narrowViewChanged();
void focusChanged(); void focusChanged();
void openRoomSettingsDialog(RoomSettings *roomSettings); void openRoomSettingsDialog(RoomSettings *settings);
public slots: public slots:
void updateReadReceipts(const QString &room_id, const std::vector<QString> &event_ids); void updateReadReceipts(const QString &room_id, const std::vector<QString> &event_ids);

View File

@ -5,12 +5,65 @@
#include "Cache.h" #include "Cache.h"
#include "Logging.h" #include "Logging.h"
#include "MatrixClient.h"
#include "Utils.h"
using namespace mtx::events;
RoomSettings::RoomSettings(QString roomid, QObject *parent) RoomSettings::RoomSettings(QString roomid, QObject *parent)
: roomid_{std::move(roomid)} : roomid_{std::move(roomid)}
, QObject(parent) , QObject(parent)
{ {
retrieveRoomInfo(); retrieveRoomInfo();
// get room setting notifications
http::client()->get_pushrules(
"global",
"override",
roomid_.toStdString(),
[this](const mtx::pushrules::PushRule &rule, mtx::http::RequestErr &err) {
if (err) {
if (err->status_code == boost::beast::http::status::not_found)
http::client()->get_pushrules(
"global",
"room",
roomid_.toStdString(),
[this](const mtx::pushrules::PushRule &rule,
mtx::http::RequestErr &err) {
if (err) {
notifications_ = 2; // all messages
emit notificationsChanged();
return;
}
if (rule.enabled) {
notifications_ = 1; // mentions only
emit notificationsChanged();
}
});
return;
}
if (rule.enabled) {
notifications_ = 0; // muted
emit notificationsChanged();
} else {
notifications_ = 2; // all messages
emit notificationsChanged();
}
});
// access rules
if (info_.join_rule == state::JoinRule::Public) {
if (info_.guest_access) {
accessRules_ = 0;
} else {
accessRules_ = 1;
}
} else {
accessRules_ = 2;
}
emit accessJoinRulesChanged();
} }
QString QString
@ -25,9 +78,211 @@ RoomSettings::retrieveRoomInfo()
try { try {
usesEncryption_ = cache::isRoomEncrypted(roomid_.toStdString()); usesEncryption_ = cache::isRoomEncrypted(roomid_.toStdString());
info_ = cache::singleRoomInfo(roomid_.toStdString()); info_ = cache::singleRoomInfo(roomid_.toStdString());
//setAvatar(); // setAvatar();
} catch (const lmdb::error &) { } catch (const lmdb::error &) {
nhlog::db()->warn("failed to retrieve room info from cache: {}", nhlog::db()->warn("failed to retrieve room info from cache: {}",
roomid_.toStdString()); roomid_.toStdString());
} }
}
int
RoomSettings::notifications()
{
return notifications_;
}
int
RoomSettings::accessJoinRules()
{
return accessRules_;
}
bool
RoomSettings::respondsToKeyRequests()
{
return usesEncryption_ && utils::respondsToKeyRequests(roomid_);
}
void
RoomSettings::changeKeyRequestsPreference(bool isOn)
{
utils::setKeyRequestsPreference(roomid_, isOn);
emit keyRequestsChanged();
}
void
RoomSettings::enableEncryption()
{
if (usesEncryption_)
return;
const auto room_id = roomid_.toStdString();
http::client()->enable_encryption(
room_id, [room_id, this](const mtx::responses::EventId &, mtx::http::RequestErr err) {
if (err) {
int status_code = static_cast<int>(err->status_code);
nhlog::net()->warn("failed to enable encryption in room ({}): {} {}",
room_id,
err->matrix_error.error,
status_code);
//emit enableEncryptionError(
// tr("Failed to enable encryption: %1")
// .arg(QString::fromStdString(err->matrix_error.error)));
usesEncryption_ = false;
emit encryptionChanged();
return;
}
nhlog::net()->info("enabled encryption on room ({})", room_id);
});
usesEncryption_ = true;
emit encryptionChanged();
}
bool
RoomSettings::canChangeJoinRules() const
{
try {
return cache::hasEnoughPowerLevel({EventType::RoomJoinRules},
roomid_.toStdString(),
utils::localUser().toStdString());
} catch (const lmdb::error &e) {
nhlog::db()->warn("lmdb error: {}", e.what());
}
return false;
}
bool
RoomSettings::isEncryptionEnabled() const
{
return usesEncryption_;
}
void
RoomSettings::changeNotifications(int currentIndex)
{
notifications_ = currentIndex;
std::string room_id = roomid_.toStdString();
if (notifications_ == 0) {
// mute room
// delete old rule first, then add new rule
mtx::pushrules::PushRule rule;
rule.actions = {mtx::pushrules::actions::dont_notify{}};
mtx::pushrules::PushCondition condition;
condition.kind = "event_match";
condition.key = "room_id";
condition.pattern = room_id;
rule.conditions = {condition};
http::client()->put_pushrules(
"global", "override", room_id, rule, [room_id](mtx::http::RequestErr &err) {
if (err)
nhlog::net()->error("failed to set pushrule for room {}: {} {}",
room_id,
static_cast<int>(err->status_code),
err->matrix_error.error);
http::client()->delete_pushrules(
"global", "room", room_id, [room_id](mtx::http::RequestErr &) {});
});
} else if (notifications_ == 1) {
// mentions only
// delete old rule first, then add new rule
mtx::pushrules::PushRule rule;
rule.actions = {mtx::pushrules::actions::dont_notify{}};
http::client()->put_pushrules(
"global", "room", room_id, rule, [room_id](mtx::http::RequestErr &err) {
if (err)
nhlog::net()->error("failed to set pushrule for room {}: {} {}",
room_id,
static_cast<int>(err->status_code),
err->matrix_error.error);
http::client()->delete_pushrules(
"global", "override", room_id, [room_id](mtx::http::RequestErr &) {});
});
} else {
// all messages
http::client()->delete_pushrules(
"global", "override", room_id, [room_id](mtx::http::RequestErr &) {
http::client()->delete_pushrules(
"global", "room", room_id, [room_id](mtx::http::RequestErr &) {});
});
}
}
void
RoomSettings::changeAccessRules(int index)
{
using namespace mtx::events::state;
auto guest_access = [](int index) -> state::GuestAccess {
state::GuestAccess event;
if (index == 0)
event.guest_access = state::AccessState::CanJoin;
else
event.guest_access = state::AccessState::Forbidden;
return event;
}(index);
auto join_rule = [](int index) -> state::JoinRules {
state::JoinRules event;
switch (index) {
case 0:
case 1:
event.join_rule = state::JoinRule::Public;
break;
default:
event.join_rule = state::JoinRule::Invite;
}
return event;
}(index);
updateAccessRules(roomid_.toStdString(), join_rule, guest_access);
}
void
RoomSettings::updateAccessRules(const std::string &room_id,
const mtx::events::state::JoinRules &join_rule,
const mtx::events::state::GuestAccess &guest_access)
{
// startLoadingSpinner();
// resetErrorLabel();
http::client()->send_state_event(
room_id,
join_rule,
[this, room_id, guest_access](const mtx::responses::EventId &,
mtx::http::RequestErr err) {
if (err) {
nhlog::net()->warn("failed to send m.room.join_rule: {} {}",
static_cast<int>(err->status_code),
err->matrix_error.error);
// emit showErrorMessage(QString::fromStdString(err->matrix_error.error));
return;
}
http::client()->send_state_event(
room_id,
guest_access,
[this](const mtx::responses::EventId &, mtx::http::RequestErr err) {
if (err) {
nhlog::net()->warn("failed to send m.room.guest_access: {} {}",
static_cast<int>(err->status_code),
err->matrix_error.error);
// emit showErrorMessage(
// QString::fromStdString(err->matrix_error.error));
return;
}
// emit signal that stops loading spinner and reset error label
});
});
} }

View File

@ -3,23 +3,52 @@
#include <QObject> #include <QObject>
#include <QString> #include <QString>
#include <mtx/events/guest_access.hpp>
#include "CacheStructs.h" #include "CacheStructs.h"
class RoomSettings : public QObject class RoomSettings : public QObject
{ {
Q_OBJECT Q_OBJECT
Q_PROPERTY(QString roomName READ roomName CONSTANT) Q_PROPERTY(QString roomName READ roomName CONSTANT)
Q_PROPERTY(int notifications READ notifications NOTIFY notificationsChanged)
Q_PROPERTY(int accessJoinRules READ accessJoinRules NOTIFY accessJoinRulesChanged)
Q_PROPERTY(bool canChangeJoinRules READ canChangeJoinRules CONSTANT)
Q_PROPERTY(bool isEncryptionEnabled READ isEncryptionEnabled NOTIFY encryptionChanged)
Q_PROPERTY(bool respondsToKeyRequests READ respondsToKeyRequests NOTIFY keyRequestsChanged)
public: public:
RoomSettings(QString roomid, QObject *parent = nullptr); RoomSettings(QString roomid, QObject *parent = nullptr);
QString roomName() const; QString roomName() const;
int notifications();
int accessJoinRules();
bool respondsToKeyRequests();
//! Whether the user has enough power level to send m.room.join_rules events.
bool canChangeJoinRules() const;
bool isEncryptionEnabled() const;
Q_INVOKABLE void changeNotifications(int currentIndex);
Q_INVOKABLE void changeAccessRules(int index);
Q_INVOKABLE void changeKeyRequestsPreference(bool isOn);
Q_INVOKABLE void enableEncryption();
signals:
void notificationsChanged();
void accessJoinRulesChanged();
void keyRequestsChanged();
void encryptionChanged();
private: private:
void retrieveRoomInfo(); void retrieveRoomInfo();
void updateAccessRules(const std::string &room_id,
const mtx::events::state::JoinRules &,
const mtx::events::state::GuestAccess &);
private: private:
QString roomid_; QString roomid_;
bool usesEncryption_ = false; bool usesEncryption_ = false;
RoomInfo info_; RoomInfo info_;
int notifications_ = 0;
int accessRules_ = 0;
}; };