File indexing completed on 2024-12-08 07:33:44

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 "jobs/neochatdeletedevicejob.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 (m_connection) {
0027         auto job = m_connection->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         if (!m_connection->isKnownE2eeCapableDevice(m_connection->userId(), device.deviceId)) {
0069             return Unencrypted;
0070         }
0071         if (m_connection->isVerifiedDevice(m_connection->userId(), device.deviceId)) {
0072             return Verified;
0073         } else {
0074             return Unverified;
0075         }
0076     }
0077     return {};
0078 }
0079 
0080 int DevicesModel::rowCount(const QModelIndex &parent) const
0081 {
0082     Q_UNUSED(parent);
0083     return m_devices.size();
0084 }
0085 
0086 QHash<int, QByteArray> DevicesModel::roleNames() const
0087 {
0088     return {
0089         {Id, "id"},
0090         {DisplayName, "displayName"},
0091         {LastIp, "lastIp"},
0092         {LastTimestamp, "lastTimestamp"},
0093         {TimestampString, "timestamp"},
0094         {Type, "type"},
0095     };
0096 }
0097 
0098 void DevicesModel::logout(const QString &deviceId, const QString &password)
0099 {
0100     int index;
0101     for (index = 0; m_devices[index].deviceId != deviceId; index++)
0102         ;
0103 
0104     auto job = m_connection->callApi<NeochatDeleteDeviceJob>(m_devices[index].deviceId);
0105 
0106     connect(job, &BaseJob::result, this, [this, job, password, index] {
0107         auto onSuccess = [this, index]() {
0108             beginRemoveRows(QModelIndex(), index, index);
0109             m_devices.remove(index);
0110             endRemoveRows();
0111             Q_EMIT countChanged();
0112         };
0113         if (job->error() != BaseJob::Success) {
0114             QJsonObject replyData = job->jsonData();
0115             QJsonObject authData;
0116             authData["session"_ls] = replyData["session"_ls];
0117             authData["password"_ls] = password;
0118             authData["type"_ls] = "m.login.password"_ls;
0119             QJsonObject identifier = {{"type"_ls, "m.id.user"_ls}, {"user"_ls, m_connection->user()->id()}};
0120             authData["identifier"_ls] = identifier;
0121             auto *innerJob = m_connection->callApi<NeochatDeleteDeviceJob>(m_devices[index].deviceId, authData);
0122             connect(innerJob, &BaseJob::success, this, onSuccess);
0123         } else {
0124             onSuccess();
0125         }
0126     });
0127 }
0128 
0129 void DevicesModel::setName(const QString &deviceId, const QString &name)
0130 {
0131     int index;
0132     for (index = 0; m_devices[index].deviceId != deviceId; index++);
0133 
0134     auto job = m_connection->callApi<UpdateDeviceJob>(m_devices[index].deviceId, name);
0135     QString oldName = m_devices[index].displayName;
0136     beginResetModel();
0137     m_devices[index].displayName = name;
0138     endResetModel();
0139     connect(job, &BaseJob::failure, this, [this, index, oldName]() {
0140         beginResetModel();
0141         m_devices[index].displayName = oldName;
0142         endResetModel();
0143     });
0144 }
0145 
0146 Connection *DevicesModel::connection() const
0147 {
0148     return m_connection;
0149 }
0150 
0151 void DevicesModel::setConnection(Connection *connection)
0152 {
0153     if (m_connection) {
0154         disconnect(m_connection, nullptr, this, nullptr);
0155     }
0156     m_connection = connection;
0157     Q_EMIT connectionChanged();
0158     fetchDevices();
0159 
0160     connect(m_connection, &Connection::sessionVerified, this, [this](const QString &userId, const QString &deviceId) {
0161         Q_UNUSED(deviceId);
0162         if (userId == m_connection->userId()) {
0163             fetchDevices();
0164         }
0165     });
0166     connect(m_connection, &Connection::finishedQueryingKeys, this, [this]() {
0167         fetchDevices();
0168     });
0169 }
0170 
0171 #include "moc_devicesmodel.cpp"