File indexing completed on 2024-05-12 05:04:11
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 "reporttoolmodel.h" 0005 0006 #include "abstractaccount.h" 0007 #include "accountmanager.h" 0008 0009 #include <KLocalizedString> 0010 0011 using namespace Qt::StringLiterals; 0012 0013 ReportToolModel::ReportToolModel(QObject *parent) 0014 : QAbstractListModel(parent) 0015 { 0016 fillTimeline(); 0017 fetchSelectedAccountDetails(); 0018 } 0019 0020 bool ReportToolModel::loading() const 0021 { 0022 return m_loading; 0023 } 0024 0025 void ReportToolModel::setLoading(bool loading) 0026 { 0027 if (m_loading == loading) { 0028 return; 0029 } 0030 m_loading = loading; 0031 Q_EMIT loadingChanged(); 0032 } 0033 0034 QUrlQuery ReportToolModel::buildQuery() const 0035 { 0036 QUrlQuery query; 0037 if (m_moderationStatus == QStringLiteral("resolved")) { 0038 query.addQueryItem(QStringLiteral("resolved"), QStringLiteral("true")); 0039 } 0040 if (!m_accountId.isEmpty()) { 0041 query.addQueryItem(QStringLiteral("account_id"), m_accountId); 0042 } 0043 if (!m_targetAccountId.isEmpty()) { 0044 query.addQueryItem(QStringLiteral("target_account_id"), m_targetAccountId); 0045 } 0046 return query; 0047 } 0048 0049 QVariant ReportToolModel::data(const QModelIndex &index, int role) const 0050 { 0051 Q_ASSERT(checkIndex(index, QAbstractItemModel::CheckIndexOption::IndexIsValid)); 0052 0053 const auto identity = m_reports[index.row()].get(); 0054 switch (role) { 0055 case CustomRoles::ReportRole: 0056 return QVariant::fromValue<ReportInfo *>(identity); 0057 default: 0058 return {}; 0059 } 0060 } 0061 0062 int ReportToolModel::rowCount(const QModelIndex &) const 0063 { 0064 return m_reports.count(); 0065 } 0066 0067 QHash<int, QByteArray> ReportToolModel::roleNames() const 0068 { 0069 return { 0070 {CustomRoles::ReportRole, "reportInfo"}, 0071 }; 0072 } 0073 0074 QString ReportToolModel::moderationStatus() const 0075 { 0076 return m_moderationStatus; 0077 } 0078 0079 void ReportToolModel::setModerationStatus(const QString &moderationStatus) 0080 { 0081 if (moderationStatus == m_moderationStatus) { 0082 return; 0083 } 0084 m_moderationStatus = moderationStatus; 0085 Q_EMIT moderationStatusChanged(); 0086 m_pagination = false; 0087 clear(); 0088 fillTimeline(); 0089 } 0090 0091 QString ReportToolModel::origin() const 0092 { 0093 return m_origin; 0094 } 0095 0096 void ReportToolModel::setOrigin(const QString &origin) 0097 { 0098 if (origin == m_origin) { 0099 return; 0100 } 0101 m_origin = origin; 0102 Q_EMIT moderationStatusChanged(); 0103 m_pagination = false; 0104 clear(); 0105 fillTimeline(); 0106 } 0107 0108 void ReportToolModel::clear() 0109 { 0110 beginResetModel(); 0111 m_reports.clear(); 0112 endResetModel(); 0113 setLoading(false); 0114 } 0115 0116 void ReportToolModel::resolveReport(const int row) 0117 { 0118 executeReportAction(row, ReportAction::ResolveReport); 0119 } 0120 0121 void ReportToolModel::unresolveReport(const int row) 0122 { 0123 executeReportAction(row, ReportAction::UnresolveReport); 0124 } 0125 0126 void ReportToolModel::assignReport(const int row) 0127 { 0128 executeReportAction(row, ReportAction::AssignReport); 0129 } 0130 0131 void ReportToolModel::unassignReport(const int row) 0132 { 0133 executeReportAction(row, ReportAction::UnassignReport); 0134 } 0135 0136 void ReportToolModel::updateReport(const int row, const QString &type, const QList<int> &ruleIds) 0137 { 0138 QJsonArray ruleIdArray; 0139 for (const int ruleId : ruleIds) { 0140 ruleIdArray.append(ruleId); 0141 } 0142 QJsonObject obj{{"category"_L1, type}, {"rule_ids"_L1, ruleIdArray}}; 0143 const auto doc = QJsonDocument(obj); 0144 const auto account = AccountManager::instance().selectedAccount(); 0145 const auto report = m_reports[row]; 0146 const auto reportId = report->reportId(); 0147 QUrl url = account->apiUrl(QStringLiteral("/api/v1/admin/reports/%1").arg(reportId)); 0148 account->put(url, doc, true, this, [=](QNetworkReply *) {}); 0149 Q_EMIT dataChanged(index(row, 0), index(row, 0)); 0150 } 0151 0152 void ReportToolModel::fetchSelectedAccountDetails() 0153 { 0154 auto account = AccountManager::instance().selectedAccount(); 0155 0156 const auto id = account->identity()->id(); 0157 0158 QUrl url = account->apiUrl(QStringLiteral("/api/v1/admin/accounts/%1").arg(id)); 0159 0160 account->get(url, true, this, [this, account, id](QNetworkReply *reply) { 0161 const auto doc = QJsonDocument::fromJson(reply->readAll()); 0162 m_selectedAccount = account->adminIdentityLookup(id, doc.object()); 0163 }); 0164 Q_EMIT moderationStatusChanged(); 0165 } 0166 0167 void ReportToolModel::executeReportAction(const int row, ReportAction reportAction, const QJsonObject &extraArguments) 0168 { 0169 auto report = m_reports[row]; 0170 const QHash<ReportAction, QString> reportActionMap = { 0171 {ReportAction::ResolveReport, QStringLiteral("/resolve")}, 0172 {ReportAction::UnresolveReport, QStringLiteral("/reopen")}, 0173 {ReportAction::AssignReport, QStringLiteral("/assign_to_self")}, 0174 {ReportAction::UnassignReport, QStringLiteral("/unassign")}, 0175 }; 0176 0177 const auto apiCall = reportActionMap[reportAction]; 0178 0179 const auto reportId = report->reportId(); 0180 0181 const QString reportApiUrl = QStringLiteral("/api/v1/admin/reports/%1/%2").arg(reportId, apiCall); 0182 0183 const QJsonDocument doc(extraArguments); 0184 0185 auto account = AccountManager::instance().selectedAccount(); 0186 QUrl url = account->apiUrl(reportApiUrl); 0187 0188 account->post(url, doc, true, this, [=](QNetworkReply *reply) { 0189 auto doc = QJsonDocument::fromJson(reply->readAll()); 0190 auto jsonObj = doc.object(); 0191 0192 if (!jsonObj.value("error"_L1).isUndefined()) { 0193 const QHash<ReportAction, QString> accountActionMap = { 0194 {ReportAction::ResolveReport, i18n("Could not resolve report")}, 0195 {ReportAction::UnresolveReport, i18n("Could not unresolve report")}, 0196 {ReportAction::AssignReport, i18n("Could not assign report")}, 0197 {ReportAction::UnassignReport, i18n("Could not unassign report")}, 0198 }; 0199 const auto errorMessage = accountActionMap[reportAction]; 0200 Q_EMIT account->errorOccured(errorMessage); 0201 return; 0202 } 0203 0204 switch (reportAction) { 0205 case ReportAction::ResolveReport: 0206 report->setActionTaken(true); 0207 break; 0208 case ReportAction::UnresolveReport: 0209 report->setActionTaken(false); 0210 break; 0211 case ReportAction::AssignReport: 0212 report->setAssignedModerator(true); 0213 report->setAssignedAccount(m_selectedAccount.get()); 0214 break; 0215 case ReportAction::UnassignReport: 0216 report->setAssignedModerator(false); 0217 report->setAssignedAccount({}); 0218 break; 0219 } 0220 Q_EMIT dataChanged(index(row, 0), index(row, 0)); 0221 }); 0222 } 0223 0224 bool ReportToolModel::canFetchMore(const QModelIndex &parent) const 0225 { 0226 Q_UNUSED(parent); 0227 return !m_next.isEmpty() && m_pagination; 0228 } 0229 0230 void ReportToolModel::fetchMore(const QModelIndex &parent) 0231 { 0232 Q_UNUSED(parent); 0233 0234 fillTimeline(); 0235 } 0236 0237 void ReportToolModel::fillTimeline() 0238 { 0239 auto account = AccountManager::instance().selectedAccount(); 0240 m_pagination = true; 0241 0242 if (m_loading) { 0243 return; 0244 } 0245 setLoading(true); 0246 0247 QUrl url; 0248 if (m_next.isEmpty()) { 0249 url = account->apiUrl(QStringLiteral("/api/v1/admin/reports")); 0250 } else { 0251 url = m_next; 0252 } 0253 url.setQuery(buildQuery()); 0254 0255 account->get(url, true, this, [this, account](QNetworkReply *reply) { 0256 const auto doc = QJsonDocument::fromJson(reply->readAll()); 0257 const auto reportsArray = doc.array(); 0258 0259 if (!reportsArray.isEmpty()) { 0260 static QRegularExpression re(QStringLiteral("<(.*)>; rel=\"next\"")); 0261 const auto next = reply->rawHeader(QByteArrayLiteral("Link")); 0262 const auto match = re.match(QString::fromUtf8(next)); 0263 if (re.isValid()) { 0264 m_next = QUrl::fromUserInput(match.captured(1)); 0265 } 0266 QList<std::shared_ptr<ReportInfo>> fetchedReports; 0267 0268 std::transform( 0269 reportsArray.cbegin(), 0270 reportsArray.cend(), 0271 std::back_inserter(fetchedReports), 0272 [ account, this ](const QJsonValue &value) -> auto{ 0273 const auto reportInfoJson = value.toObject(); 0274 const auto accountPopulate = account->reportInfoLookup(reportInfoJson["id"_L1].toString(), reportInfoJson); 0275 // hack to determine the report's origin to be removed when we have the specific query for it 0276 if (m_origin == QStringLiteral("local") && accountPopulate->targetAccount()->isLocal()) { 0277 return accountPopulate; 0278 } else if (m_origin == QStringLiteral("remote") && !accountPopulate->targetAccount()->isLocal()) { 0279 return accountPopulate; 0280 } else if (m_origin.isEmpty()) { 0281 return accountPopulate; 0282 } 0283 return std::shared_ptr<ReportInfo>(); 0284 }); 0285 beginInsertRows({}, m_reports.size(), m_reports.size() + fetchedReports.size() - 1); 0286 m_reports += fetchedReports; 0287 endInsertRows(); 0288 } 0289 setLoading(false); 0290 }); 0291 } 0292 0293 #include "moc_reporttoolmodel.cpp"