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"