File indexing completed on 2024-05-12 16:25:04
0001 // SPDX-FileCopyrightText: Tobias Fella <tobias.fella@kde.org> 0002 // SPDX-License-Identifier: GPL-2.0-or-later 0003 0004 #include "devicesmodel.h" 0005 0006 #include "controller.h" 0007 0008 #include <QDateTime> 0009 #include <QLocale> 0010 0011 #include <KLocalizedString> 0012 0013 #include <Quotient/csapi/device_management.h> 0014 #include <Quotient/connection.h> 0015 #include <Quotient/user.h> 0016 0017 using namespace Quotient; 0018 0019 DevicesModel::DevicesModel(QObject *parent) 0020 : QAbstractListModel(parent) 0021 { 0022 } 0023 0024 void DevicesModel::fetchDevices() 0025 { 0026 if (Controller::instance().activeConnection()) { 0027 auto job = Controller::instance().activeConnection()->callApi<GetDevicesJob>(); 0028 connect(job, &BaseJob::success, this, [this, job]() { 0029 beginResetModel(); 0030 m_devices = job->devices(); 0031 endResetModel(); 0032 Q_EMIT countChanged(); 0033 }); 0034 } 0035 } 0036 0037 QVariant DevicesModel::data(const QModelIndex &index, int role) const 0038 { 0039 if (index.row() < 0 || index.row() >= rowCount(QModelIndex())) { 0040 return {}; 0041 } 0042 0043 const auto &device = m_devices[index.row()]; 0044 0045 switch (role) { 0046 case Id: 0047 return device.deviceId; 0048 case DisplayName: 0049 return device.displayName; 0050 case LastIp: 0051 return device.lastSeenIp; 0052 case LastTimestamp: 0053 if (device.lastSeenTs) { 0054 return *device.lastSeenTs; 0055 } else { 0056 return false; 0057 } 0058 case TimestampString: 0059 if (device.lastSeenTs) { 0060 return QDateTime::fromMSecsSinceEpoch(*device.lastSeenTs).toString(QLocale().dateTimeFormat(QLocale::ShortFormat)); 0061 } else { 0062 return false; 0063 } 0064 case Type: 0065 if (device.deviceId == m_connection->deviceId()) { 0066 return This; 0067 } 0068 #ifdef Quotient_E2EE_ENABLED 0069 if (!m_connection->isKnownE2eeCapableDevice(m_connection->userId(), device.deviceId)) { 0070 return Unencrypted; 0071 } 0072 if (m_connection->isVerifiedDevice(m_connection->userId(), device.deviceId)) { 0073 return Verified; 0074 } else { 0075 return Unverified; 0076 } 0077 #else 0078 return Unverified; 0079 #endif 0080 } 0081 return {}; 0082 } 0083 0084 int DevicesModel::rowCount(const QModelIndex &parent) const 0085 { 0086 Q_UNUSED(parent); 0087 return m_devices.size(); 0088 } 0089 0090 QHash<int, QByteArray> DevicesModel::roleNames() const 0091 { 0092 return { 0093 {Id, "id"}, 0094 {DisplayName, "displayName"}, 0095 {LastIp, "lastIp"}, 0096 {LastTimestamp, "lastTimestamp"}, 0097 {TimestampString, "timestamp"}, 0098 {Type, "type"}, 0099 }; 0100 } 0101 0102 void DevicesModel::logout(const QString &deviceId, const QString &password) 0103 { 0104 int index; 0105 for (index = 0; m_devices[index].deviceId != deviceId; index++) 0106 ; 0107 0108 auto job = Controller::instance().activeConnection()->callApi<NeochatDeleteDeviceJob>(m_devices[index].deviceId); 0109 0110 connect(job, &BaseJob::result, this, [this, job, password, index] { 0111 auto onSuccess = [this, index]() { 0112 beginRemoveRows(QModelIndex(), index, index); 0113 m_devices.remove(index); 0114 endRemoveRows(); 0115 Q_EMIT countChanged(); 0116 }; 0117 if (job->error() != BaseJob::Success) { 0118 QJsonObject replyData = job->jsonData(); 0119 QJsonObject authData; 0120 authData["session"] = replyData["session"]; 0121 authData["password"] = password; 0122 authData["type"] = "m.login.password"; 0123 QJsonObject identifier = {{"type", "m.id.user"}, {"user", Controller::instance().activeConnection()->user()->id()}}; 0124 authData["identifier"] = identifier; 0125 auto *innerJob = Controller::instance().activeConnection()->callApi<NeochatDeleteDeviceJob>(m_devices[index].deviceId, authData); 0126 connect(innerJob, &BaseJob::success, this, onSuccess); 0127 } else { 0128 onSuccess(); 0129 } 0130 }); 0131 } 0132 0133 void DevicesModel::setName(const QString &deviceId, const QString &name) 0134 { 0135 int index; 0136 for (index = 0; m_devices[index].deviceId != deviceId; index++); 0137 0138 auto job = Controller::instance().activeConnection()->callApi<UpdateDeviceJob>(m_devices[index].deviceId, name); 0139 QString oldName = m_devices[index].displayName; 0140 beginResetModel(); 0141 m_devices[index].displayName = name; 0142 endResetModel(); 0143 connect(job, &BaseJob::failure, this, [this, index, oldName]() { 0144 beginResetModel(); 0145 m_devices[index].displayName = oldName; 0146 endResetModel(); 0147 }); 0148 } 0149 0150 Connection *DevicesModel::connection() const 0151 { 0152 return m_connection; 0153 } 0154 0155 void DevicesModel::setConnection(Connection *connection) 0156 { 0157 if (m_connection) { 0158 disconnect(m_connection, nullptr, this, nullptr); 0159 } 0160 m_connection = connection; 0161 Q_EMIT connectionChanged(); 0162 fetchDevices(); 0163 0164 #ifdef Quotient_E2EE_ENABLED 0165 connect(m_connection, &Connection::sessionVerified, this, [this](const QString &userId, const QString &deviceId) { 0166 Q_UNUSED(deviceId); 0167 if (userId == Controller::instance().activeConnection()->userId()) { 0168 fetchDevices(); 0169 } 0170 }); 0171 connect(m_connection, &Connection::finishedQueryingKeys, this, [this]() { 0172 fetchDevices(); 0173 }); 0174 #endif 0175 } 0176 0177 #include "moc_devicesmodel.cpp"