File indexing completed on 2024-05-12 05:04:10
0001 // SPDX-FileCopyrightText: 2023 Rishi Kumar <rsi.dev17@gmail.com> 0002 // SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL 0003 0004 #include "accounttoolmodel.h" 0005 0006 #include "accountmanager.h" 0007 0008 #include <KLocalizedString> 0009 0010 using namespace Qt::Literals::StringLiterals; 0011 0012 AccountsToolModel::AccountsToolModel(QObject *parent) 0013 : QAbstractListModel(parent) 0014 { 0015 fillTimeline(); 0016 fetchSelectedAccountPosition(); 0017 } 0018 0019 bool AccountsToolModel::loading() const 0020 { 0021 return m_loading; 0022 } 0023 0024 void AccountsToolModel::setLoading(bool loading) 0025 { 0026 if (m_loading == loading) { 0027 return; 0028 } 0029 m_loading = loading; 0030 Q_EMIT loadingChanged(); 0031 } 0032 0033 QUrlQuery AccountsToolModel::buildQuery() const 0034 { 0035 QUrlQuery query; 0036 query.addQueryItem(QStringLiteral("origin"), m_location); 0037 query.addQueryItem(QStringLiteral("status"), m_moderationStatus); 0038 query.addQueryItem(QStringLiteral("role_ids"), m_role); 0039 query.addQueryItem(QStringLiteral("username"), m_username); 0040 query.addQueryItem(QStringLiteral("display_name"), m_displayName); 0041 query.addQueryItem(QStringLiteral("email"), m_email); 0042 query.addQueryItem(QStringLiteral("ip"), m_ip); 0043 return query; 0044 } 0045 0046 QVariant AccountsToolModel::data(const QModelIndex &index, int role) const 0047 { 0048 Q_ASSERT(checkIndex(index, QAbstractItemModel::CheckIndexOption::IndexIsValid)); 0049 0050 const auto identity = m_accounts[index.row()].get(); 0051 switch (role) { 0052 case CustomRoles::IdentityRole: 0053 return QVariant::fromValue<AdminAccountInfo *>(identity); 0054 default: 0055 return {}; 0056 } 0057 } 0058 0059 int AccountsToolModel::rowCount(const QModelIndex &) const 0060 { 0061 return m_accounts.count(); 0062 } 0063 0064 QHash<int, QByteArray> AccountsToolModel::roleNames() const 0065 { 0066 return { 0067 {CustomRoles::IdentityRole, "identity"}, 0068 }; 0069 } 0070 0071 QString AccountsToolModel::location() const 0072 { 0073 return m_location; 0074 } 0075 0076 void AccountsToolModel::setLocation(const QString &location) 0077 { 0078 if (location == m_location) { 0079 return; 0080 } 0081 m_location = location; 0082 Q_EMIT locationChanged(); 0083 // resetting everything before populating 0084 m_pagination = false; 0085 clear(); 0086 fillTimeline(); 0087 } 0088 0089 QString AccountsToolModel::moderationStatus() const 0090 { 0091 return m_location; 0092 } 0093 0094 void AccountsToolModel::setModerationStatus(const QString &moderationStatus) 0095 { 0096 if (moderationStatus == m_moderationStatus) { 0097 return; 0098 } 0099 m_moderationStatus = moderationStatus; 0100 Q_EMIT moderationStatusChanged(); 0101 // resetting everything before populating 0102 m_pagination = false; 0103 clear(); 0104 fillTimeline(); 0105 } 0106 0107 QString AccountsToolModel::role() const 0108 { 0109 return m_role; 0110 } 0111 0112 void AccountsToolModel::setRole(const QString &role) 0113 { 0114 if (role == m_role) { 0115 return; 0116 } 0117 m_role = role; 0118 Q_EMIT roleChanged(); 0119 // resetting everything before populating 0120 m_pagination = false; 0121 clear(); 0122 fillTimeline(); 0123 } 0124 0125 QString AccountsToolModel::username() const 0126 { 0127 return m_username; 0128 } 0129 0130 void AccountsToolModel::setUsername(const QString &username) 0131 { 0132 if (username == m_username) { 0133 return; 0134 } 0135 m_username = username; 0136 Q_EMIT usernameChanged(); 0137 // resetting everything before populating 0138 m_pagination = false; 0139 clear(); 0140 fillTimeline(); 0141 } 0142 0143 QString AccountsToolModel::displayName() const 0144 { 0145 return m_displayName; 0146 } 0147 0148 void AccountsToolModel::setDisplayName(const QString &displayName) 0149 { 0150 if (displayName == m_displayName) { 0151 return; 0152 } 0153 m_displayName = displayName; 0154 Q_EMIT displayNameChanged(); 0155 // resetting everything before populating 0156 m_pagination = false; 0157 clear(); 0158 fillTimeline(); 0159 } 0160 0161 QString AccountsToolModel::email() const 0162 { 0163 return m_email; 0164 } 0165 0166 void AccountsToolModel::setEmail(const QString &email) 0167 { 0168 if (email == m_email) { 0169 return; 0170 } 0171 m_email = email; 0172 Q_EMIT emailChanged(); 0173 // resetting everything before populating 0174 m_pagination = false; 0175 clear(); 0176 fillTimeline(); 0177 } 0178 0179 QString AccountsToolModel::ip() const 0180 { 0181 return m_ip; 0182 } 0183 0184 void AccountsToolModel::setIp(const QString &ip) 0185 { 0186 if (ip == m_ip) { 0187 return; 0188 } 0189 m_ip = ip; 0190 Q_EMIT ipChanged(); 0191 // resetting everything before populating 0192 m_pagination = false; 0193 clear(); 0194 fillTimeline(); 0195 } 0196 0197 int AccountsToolModel::selectedAccountPosition() const 0198 { 0199 return m_selectedAccountPosition; 0200 } 0201 0202 void AccountsToolModel::clear() 0203 { 0204 beginResetModel(); 0205 m_accounts.clear(); 0206 endResetModel(); 0207 setLoading(false); 0208 } 0209 0210 void AccountsToolModel::approveAccount(const int row) 0211 { 0212 executeAdminAction(row, AdminAccountAction::ApproveAccount); 0213 } 0214 0215 void AccountsToolModel::rejectAccount(const int row) 0216 { 0217 executeAdminAction(row, AdminAccountAction::RejectAccount); 0218 } 0219 0220 void AccountsToolModel::enableAccount(const int row) 0221 { 0222 executeAdminAction(row, AdminAccountAction::EnableDisabledAccount); 0223 } 0224 0225 void AccountsToolModel::unsilenceAccount(const int row) 0226 { 0227 executeAdminAction(row, AdminAccountAction::UnsilenceAccount); 0228 } 0229 0230 void AccountsToolModel::unsuspendAccount(const int row) 0231 { 0232 executeAdminAction(row, AdminAccountAction::UnsuspendAccount); 0233 } 0234 void AccountsToolModel::unsensitiveAccount(const int row) 0235 { 0236 executeAdminAction(row, AdminAccountAction::UnmarkSensitiveAccount); 0237 } 0238 0239 void AccountsToolModel::actionAgainstAccount(const int row, const QString &type, const bool &emailWarning, const QString ¬e) 0240 { 0241 executeAdminAction(row, 0242 AdminAccountAction::ActionAgainstAccount, 0243 {{QStringLiteral("type"), type}, {QStringLiteral("send_email_notification"), emailWarning}, {QStringLiteral("text"), note}}); 0244 } 0245 0246 bool AccountsToolModel::canFetchMore(const QModelIndex &parent) const 0247 { 0248 Q_UNUSED(parent); 0249 return !m_next.isEmpty() && m_pagination; 0250 } 0251 0252 void AccountsToolModel::deleteAccountData(const int row) 0253 { 0254 auto account = AccountManager::instance().selectedAccount(); 0255 auto identity = m_accounts[row]; 0256 const auto accountId = identity->userLevelIdentity()->id(); 0257 0258 account->deleteResource(account->apiUrl(QStringLiteral("/api/v1/admin/accounts/%1").arg(accountId)), true, this, [=](QNetworkReply *reply) { 0259 const auto doc = QJsonDocument::fromJson(reply->readAll()).object(); 0260 qDebug() << "DELETED: " << doc; 0261 }); 0262 } 0263 0264 void AccountsToolModel::executeAdminAction(const int row, AdminAccountAction adminAccountAction, const QJsonObject &extraArguments) 0265 { 0266 auto identity = m_accounts[row]; 0267 const QHash<AdminAccountAction, QString> accountActionMap = { 0268 {AdminAccountAction::ApproveAccount, QStringLiteral("/approve")}, 0269 {AdminAccountAction::RejectAccount, QStringLiteral("/reject")}, 0270 {AdminAccountAction::ActionAgainstAccount, QStringLiteral("/action")}, 0271 {AdminAccountAction::EnableDisabledAccount, QStringLiteral("/enable")}, 0272 {AdminAccountAction::UnsilenceAccount, QStringLiteral("/unsilence")}, 0273 {AdminAccountAction::UnsuspendAccount, QStringLiteral("/unsuspend")}, 0274 {AdminAccountAction::UnmarkSensitiveAccount, QStringLiteral("/unsensitive")}, 0275 }; 0276 0277 const auto apiCall = accountActionMap[adminAccountAction]; 0278 0279 const auto accountId = identity->userLevelIdentity()->id(); 0280 0281 const QString accountApiUrl = QStringLiteral("/api/v1/admin/accounts/") + accountId + apiCall; 0282 0283 const QJsonDocument doc(extraArguments); 0284 // to be used when receiving parameter from actionAgainstAccount 0285 const auto type = doc["type"_L1].toString(); 0286 0287 auto account = AccountManager::instance().selectedAccount(); 0288 QUrl url = account->apiUrl(accountApiUrl); 0289 0290 account->post(url, doc, true, this, [=](QNetworkReply *reply) { 0291 auto doc = QJsonDocument::fromJson(reply->readAll()); 0292 auto jsonObj = doc.object(); 0293 0294 if (!jsonObj.value("error"_L1).isUndefined()) { 0295 const QHash<AdminAccountAction, QString> accountActionMap = { 0296 {AdminAccountAction::ApproveAccount, i18n("Could not accept account")}, 0297 {AdminAccountAction::RejectAccount, i18n("Could not reject account")}, 0298 {AdminAccountAction::ActionAgainstAccount, i18n("Could not take action against the account")}, 0299 {AdminAccountAction::EnableDisabledAccount, i18n("Could not enable the disabled account")}, 0300 {AdminAccountAction::UnsilenceAccount, i18n("Could not unsilence the account")}, 0301 {AdminAccountAction::UnsuspendAccount, i18n("Could not unsuspend the account")}, 0302 {AdminAccountAction::UnmarkSensitiveAccount, i18n("Could not mark the account as not sensitive")}, 0303 }; 0304 const auto errorMessage = accountActionMap[adminAccountAction]; 0305 Q_EMIT account->errorOccured(errorMessage); 0306 return; 0307 } 0308 0309 switch (adminAccountAction) { 0310 case AdminAccountAction::ApproveAccount: 0311 identity->setApproved(true); 0312 break; 0313 case AdminAccountAction::RejectAccount: 0314 identity->setApproved(false); 0315 break; 0316 case AdminAccountAction::ActionAgainstAccount: 0317 if (type == QStringLiteral("disable")) { 0318 identity->setDisabled(true); 0319 } else if (type == QStringLiteral("sensitive")) { 0320 identity->setSensitized(true); 0321 } else if (type == QStringLiteral("silence")) { 0322 identity->setSilence(true); 0323 } else if (type == QStringLiteral("suspend")) { 0324 identity->setSuspended(true); 0325 } 0326 break; 0327 case AdminAccountAction::EnableDisabledAccount: 0328 identity->setDisabled(false); 0329 break; 0330 case AdminAccountAction::UnsilenceAccount: 0331 identity->setSilence(false); 0332 break; 0333 case AdminAccountAction::UnsuspendAccount: 0334 identity->setSuspended(false); 0335 break; 0336 case AdminAccountAction::UnmarkSensitiveAccount: 0337 identity->setSensitized(false); 0338 break; 0339 } 0340 Q_EMIT dataChanged(index(row, 0), index(row, 0)); 0341 }); 0342 } 0343 0344 void AccountsToolModel::fetchMore(const QModelIndex &parent) 0345 { 0346 Q_UNUSED(parent); 0347 0348 fillTimeline(); 0349 } 0350 0351 void AccountsToolModel::fetchSelectedAccountPosition() 0352 { 0353 auto account = AccountManager::instance().selectedAccount(); 0354 0355 const auto id = account->identity()->id(); 0356 0357 QUrl url = account->apiUrl(QStringLiteral("/api/v1/admin/accounts/%1").arg(id)); 0358 0359 account->get(url, true, this, [this](QNetworkReply *reply) { 0360 const auto doc = QJsonDocument::fromJson(reply->readAll()); 0361 m_selectedAccountPosition = doc["role"_L1]["position"_L1].toInt(); 0362 }); 0363 } 0364 0365 void AccountsToolModel::fillTimeline() 0366 { 0367 // selecting the current logged in account 0368 auto account = AccountManager::instance().selectedAccount(); 0369 0370 // loading logic here 0371 m_pagination = true; 0372 if (m_loading) { 0373 return; 0374 } 0375 setLoading(true); 0376 0377 QUrl url; 0378 if (m_next.isEmpty()) { 0379 url = account->apiUrl(QStringLiteral("/api/v2/admin/accounts")); 0380 } else { 0381 url = m_next; 0382 } 0383 // To be removed when the pagination api response is fixed 0384 if (url.toString().contains("v1"_L1)) { 0385 url = QUrl(url.toString().replace("/v1/"_L1, "/v2/"_L1)); 0386 } 0387 0388 url.setQuery(buildQuery()); 0389 0390 account->get(url, true, this, [this, account](QNetworkReply *reply) { 0391 const auto doc = QJsonDocument::fromJson(reply->readAll()); 0392 const auto accounts = doc.array(); 0393 0394 if (!accounts.isEmpty()) { 0395 static QRegularExpression re(QStringLiteral("<(.*)>; rel=\"next\"")); 0396 const auto next = reply->rawHeader(QByteArrayLiteral("Link")); 0397 const auto match = re.match(QString::fromUtf8(next)); 0398 if (re.isValid()) { 0399 m_next = QUrl::fromUserInput(match.captured(1)); 0400 } 0401 QList<std::shared_ptr<AdminAccountInfo>> fetchedAccounts; 0402 0403 std::transform( 0404 accounts.cbegin(), 0405 accounts.cend(), 0406 std::back_inserter(fetchedAccounts), 0407 [account](const QJsonValue &value) -> auto{ 0408 const auto identityJson = value.toObject(); 0409 return account->adminIdentityLookup(identityJson["id"_L1].toString(), identityJson); 0410 }); 0411 beginInsertRows({}, m_accounts.size(), m_accounts.size() + fetchedAccounts.size() - 1); 0412 m_accounts += fetchedAccounts; 0413 endInsertRows(); 0414 } 0415 0416 setLoading(false); 0417 }); 0418 } 0419 0420 #include "moc_accounttoolmodel.cpp"