File indexing completed on 2025-01-05 03:53:37
0001 /* ============================================================ 0002 * 0003 * This file is a part of digiKam project 0004 * https://www.digikam.org 0005 * 0006 * Date : 2011-03-22 0007 * Description : a Iface C++ interface 0008 * 0009 * SPDX-FileCopyrightText: 2011-2024 by Gilles Caulier <caulier dot gilles at gmail dot com> 0010 * SPDX-FileCopyrightText: 2011 by Hormiere Guillaume <hormiere dot guillaume at gmail dot com> 0011 * SPDX-FileCopyrightText: 2011 by Manuel Campomanes <campomanes dot manuel at gmail dot com> 0012 * 0013 * SPDX-License-Identifier: GPL-2.0-or-later 0014 * 0015 * ============================================================ */ 0016 0017 #include "mediawiki_queryrevision.h" 0018 0019 // Qt includes 0020 0021 #include <QTimer> 0022 #include <QUrl> 0023 #include <QUrlQuery> 0024 #include <QXmlStreamReader> 0025 #include <QNetworkAccessManager> 0026 #include <QNetworkReply> 0027 #include <QNetworkRequest> 0028 0029 // Local includes 0030 0031 #include "mediawiki_iface.h" 0032 #include "mediawiki_job_p.h" 0033 0034 namespace MediaWiki 0035 { 0036 0037 class Q_DECL_HIDDEN QueryRevisionPrivate : public JobPrivate 0038 { 0039 public: 0040 0041 explicit QueryRevisionPrivate(Iface& MediaWiki) 0042 : JobPrivate(MediaWiki) 0043 { 0044 } 0045 0046 QMap<QString, QString> requestParameter; 0047 }; 0048 0049 QueryRevision::QueryRevision(Iface& MediaWiki, QObject* const parent) 0050 : Job(*new QueryRevisionPrivate(MediaWiki), parent) 0051 { 0052 } 0053 0054 QueryRevision::~QueryRevision() 0055 { 0056 } 0057 0058 void QueryRevision::start() 0059 { 0060 QTimer::singleShot(0, this, SLOT(doWorkSendRequest())); 0061 } 0062 0063 void QueryRevision::setPageName(const QString& pageName) 0064 { 0065 Q_D(QueryRevision); 0066 d->requestParameter[QStringLiteral("titles")] = pageName; 0067 } 0068 0069 void QueryRevision::setProperties(Properties properties) 0070 { 0071 Q_D(QueryRevision); 0072 QString buff; 0073 0074 if (properties & QueryRevision::Ids) 0075 { 0076 buff.append(QStringLiteral("ids")); 0077 } 0078 0079 if (properties & QueryRevision::Flags) 0080 { 0081 if (buff.length()) 0082 { 0083 buff.append(QStringLiteral("|")); 0084 } 0085 0086 buff.append(QStringLiteral("flags")); 0087 } 0088 0089 if (properties & QueryRevision::Timestamp) 0090 { 0091 if (buff.length()) 0092 { 0093 buff.append(QStringLiteral("|")); 0094 } 0095 0096 buff.append(QStringLiteral("timestamp")); 0097 } 0098 0099 if (properties & QueryRevision::User) 0100 { 0101 if (buff.length()) 0102 { 0103 buff.append(QStringLiteral("|")); 0104 } 0105 0106 buff.append(QStringLiteral("user")); 0107 } 0108 0109 if (properties & QueryRevision::Comment) 0110 { 0111 if (buff.length()) 0112 { 0113 buff.append(QStringLiteral("|")); 0114 } 0115 0116 buff.append(QStringLiteral("comment")); 0117 } 0118 0119 if (properties & QueryRevision::Size) 0120 { 0121 if (buff.length()) 0122 { 0123 buff.append(QStringLiteral("|")); 0124 } 0125 0126 buff.append(QStringLiteral("size")); 0127 } 0128 0129 if (properties & QueryRevision::Content) 0130 { 0131 if (buff.length()) 0132 { 0133 buff.append(QStringLiteral("|")); 0134 } 0135 0136 buff.append(QStringLiteral("content")); 0137 } 0138 0139 d->requestParameter[QStringLiteral("rvprop")] = buff; 0140 } 0141 0142 void QueryRevision::setPageId(unsigned int pageId) 0143 { 0144 Q_D(QueryRevision); 0145 d->requestParameter[QStringLiteral("pageids")] = QString::number(pageId); 0146 } 0147 0148 void QueryRevision::setRevisionId(unsigned int revisionId) 0149 { 0150 Q_D(QueryRevision); 0151 d->requestParameter[QStringLiteral("revids")] = QString::number(revisionId); 0152 } 0153 0154 void QueryRevision::setLimit(int limit) 0155 { 0156 Q_D(QueryRevision); 0157 d->requestParameter[QStringLiteral("rvlimit")] = QString::number(limit); 0158 } 0159 0160 void QueryRevision::setStartId(int startId) 0161 { 0162 Q_D(QueryRevision); 0163 d->requestParameter[QStringLiteral("rvstartid")] = QString::number(startId); 0164 } 0165 0166 void QueryRevision::setEndId(int endId) 0167 { 0168 Q_D(QueryRevision); 0169 d->requestParameter[QStringLiteral("rvendid")] = QString::number(endId); 0170 } 0171 0172 void QueryRevision::setStartTimestamp(const QDateTime& start) 0173 { 0174 Q_D(QueryRevision); 0175 d->requestParameter[QStringLiteral("rvstart")] = start.toString(QStringLiteral("yyyy-MM-ddThh:mm:ssZ")); 0176 } 0177 0178 void QueryRevision::setEndTimestamp(const QDateTime& end) 0179 { 0180 Q_D(QueryRevision); 0181 d->requestParameter[QStringLiteral("rvend")] = end.toString(QStringLiteral("yyyy-MM-ddThh:mm:ssZ")); 0182 } 0183 0184 void QueryRevision::setUser(const QString& user) 0185 { 0186 Q_D(QueryRevision); 0187 d->requestParameter[QStringLiteral("rvuser")] = user; 0188 } 0189 0190 void QueryRevision::setExcludeUser(const QString& excludeUser) 0191 { 0192 Q_D(QueryRevision); 0193 d->requestParameter[QStringLiteral("rvexcludeuser")] = excludeUser; 0194 } 0195 0196 void QueryRevision::setDirection(QueryRevision::Direction direction) 0197 { 0198 Q_D(QueryRevision); 0199 0200 if (direction == QueryRevision::Older) 0201 { 0202 d->requestParameter[QStringLiteral("rvdir")] = QStringLiteral("older"); 0203 } 0204 else if (direction == QueryRevision::Newer) 0205 { 0206 d->requestParameter[QStringLiteral("rvdir")] = QStringLiteral("newer"); 0207 } 0208 } 0209 0210 void QueryRevision::setGenerateXML(bool generateXML) 0211 { 0212 Q_D(QueryRevision); 0213 0214 if (generateXML) 0215 { 0216 d->requestParameter[QStringLiteral("rvgeneratexml")] = QStringLiteral("on"); 0217 } 0218 } 0219 0220 void QueryRevision::setSection(int section) 0221 { 0222 Q_D(QueryRevision); 0223 d->requestParameter[QStringLiteral("rvsection")] = QString::number(section); 0224 } 0225 0226 void QueryRevision::setToken(QueryRevision::Token token) 0227 { 0228 Q_D(QueryRevision); 0229 0230 if (QueryRevision::Rollback == token) 0231 { 0232 d->requestParameter[QStringLiteral("rvtoken")] = QStringLiteral("rollback"); 0233 } 0234 } 0235 0236 void QueryRevision::setExpandTemplates(bool expandTemplates) 0237 { 0238 Q_D(QueryRevision); 0239 0240 if (expandTemplates) 0241 { 0242 d->requestParameter[QStringLiteral("rvexpandtemplates")] = QStringLiteral("on"); 0243 } 0244 } 0245 void QueryRevision::doWorkSendRequest() 0246 { 0247 Q_D(QueryRevision); 0248 0249 // Set the url 0250 0251 QUrl url = d->MediaWiki.url(); 0252 QUrlQuery query; 0253 query.addQueryItem(QStringLiteral("format"), QStringLiteral("xml")); 0254 query.addQueryItem(QStringLiteral("action"), QStringLiteral("query")); 0255 query.addQueryItem(QStringLiteral("prop"), QStringLiteral("revisions")); 0256 0257 QMapIterator<QString, QString> i(d->requestParameter); 0258 0259 while (i.hasNext()) 0260 { 0261 i.next(); 0262 query.addQueryItem(i.key(), i.value()); 0263 } 0264 0265 url.setQuery(query); 0266 0267 // Set the request 0268 0269 QNetworkRequest request(url); 0270 request.setRawHeader("User-Agent", d->MediaWiki.userAgent().toUtf8()); 0271 0272 setPercent(25); // Request ready. 0273 0274 // Send the request 0275 0276 d->reply = d->manager->get(request); 0277 connectReply(); 0278 0279 connect(d->reply, SIGNAL(finished()), 0280 this, SLOT(doWorkProcessReply())); 0281 0282 setPercent(50); // Request sent. 0283 } 0284 0285 void QueryRevision::doWorkProcessReply() 0286 { 0287 Q_D(QueryRevision); 0288 0289 disconnect(d->reply, SIGNAL(finished()), 0290 this, SLOT(doWorkProcessReply())); 0291 0292 setPercent(75); // Response received. 0293 0294 if (d->reply->error() == QNetworkReply::NoError) 0295 { 0296 QList<Revision> results; 0297 Revision tempR; 0298 QString replytmp = QString::fromUtf8(d->reply->readAll()); 0299 0300 if (d->requestParameter.contains(QStringLiteral("rvgeneratexml"))) 0301 { 0302 for (int i = replytmp.indexOf(QStringLiteral("parsetree")) ; 0303 i != -1 ; 0304 i = replytmp.indexOf(QStringLiteral("parsetree"), i+1)) 0305 { 0306 int count = 0; 0307 0308 while (count < 2) 0309 { 0310 if ((replytmp[i] == QLatin1Char('"')) && 0311 (replytmp[i-1] != QLatin1Char('\\'))) 0312 { 0313 count++; 0314 } 0315 0316 if (replytmp[i] == QLatin1Char('<')) 0317 { 0318 replytmp[i] = QChar(255); 0319 } 0320 0321 if (replytmp[i] == QLatin1Char('>')) 0322 { 0323 replytmp[i] = QChar(254); 0324 } 0325 0326 ++i; 0327 } 0328 } 0329 } 0330 0331 QXmlStreamReader reader(replytmp); 0332 0333 while (!reader.atEnd() && !reader.hasError()) 0334 { 0335 QXmlStreamReader::TokenType token = reader.readNext(); 0336 0337 if (token == QXmlStreamReader::StartElement) 0338 { 0339 if ((reader.name() == QLatin1String("page")) && d->requestParameter.contains(QStringLiteral("rvtoken"))) 0340 { 0341 tempR.setRollback(reader.attributes().value(QStringLiteral("rollbacktoken")).toString()); 0342 } 0343 0344 if (reader.name() == QLatin1String("rev")) 0345 { 0346 if (d->requestParameter.contains(QStringLiteral("rvprop"))) 0347 { 0348 QString rvprop = d->requestParameter[QStringLiteral("rvprop")]; 0349 0350 if (rvprop.contains(QStringLiteral("ids"))) 0351 { 0352 tempR.setRevisionId(reader.attributes().value(QStringLiteral("revid")).toString().toInt()); 0353 tempR.setParentId(reader.attributes().value(QStringLiteral("parentid")).toString().toInt());} 0354 0355 if (rvprop.contains(QStringLiteral("size"))) 0356 { 0357 tempR.setSize(reader.attributes().value(QStringLiteral("size")).toString().toInt()); 0358 } 0359 0360 if (rvprop.contains(QStringLiteral("minor"))) 0361 { 0362 tempR.setMinorRevision(true); 0363 } 0364 0365 if (rvprop.contains(QStringLiteral("user"))) 0366 { 0367 tempR.setUser(reader.attributes().value(QStringLiteral("user")).toString()); 0368 } 0369 0370 if (rvprop.contains(QStringLiteral("timestamp"))) 0371 { 0372 tempR.setTimestamp(QDateTime::fromString(reader.attributes().value(QStringLiteral("timestamp")).toString(),QStringLiteral("yyyy-MM-ddThh:mm:ssZ"))); 0373 } 0374 0375 if (rvprop.contains(QStringLiteral("comment"))) 0376 { 0377 tempR.setComment(reader.attributes().value(QStringLiteral("comment")).toString()); 0378 } 0379 0380 if (d->requestParameter.contains(QStringLiteral("rvgeneratexml"))) 0381 { 0382 tempR.setParseTree(reader.attributes().value(QStringLiteral("parsetree")).toString()); 0383 } 0384 0385 if (rvprop.contains(QStringLiteral("content"))) 0386 { 0387 tempR.setContent(reader.readElementText()); 0388 } 0389 } 0390 0391 results << tempR; 0392 } 0393 else if (reader.name() == QLatin1String("error")) 0394 { 0395 if (reader.attributes().value(QStringLiteral("code")).toString() == QLatin1String("rvrevids")) 0396 { 0397 this->setError(this->WrongRevisionId); 0398 } 0399 else if (reader.attributes().value(QStringLiteral("code")).toString() == QLatin1String("rvmultpages")) 0400 { 0401 this->setError(this->MultiPagesNotAllowed); 0402 } 0403 else if (reader.attributes().value(QStringLiteral("code")).toString() == QLatin1String("rvaccessdenied")) 0404 { 0405 this->setError(this->TitleAccessDenied); 0406 } 0407 else if (reader.attributes().value(QStringLiteral("code")).toString() == QLatin1String("rvbadparams")) 0408 { 0409 this->setError(this->TooManyParams); 0410 } 0411 else if (reader.attributes().value(QStringLiteral("code")).toString() == QLatin1String("rvnosuchsection")) 0412 { 0413 this->setError(this->SectionNotFound); 0414 } 0415 0416 d->reply->close(); 0417 d->reply->deleteLater(); 0418 //Q_EMIT revision(QList<Revision>()); 0419 emitResult(); 0420 return; 0421 } 0422 } 0423 } 0424 if (!reader.hasError()) 0425 { 0426 setError(KJob::NoError); 0427 0428 for (int i = 0 ; i < results.length() ; ++i) 0429 { 0430 results[i].setParseTree(results[i].parseTree().replace(QChar(254), QStringLiteral(">"))); 0431 results[i].setParseTree(results[i].parseTree().replace(QChar(255), QStringLiteral("<"))); 0432 } 0433 0434 Q_EMIT revision(results); 0435 setPercent(100); // Response parsed successfully. 0436 } 0437 else 0438 { 0439 setError(XmlError); 0440 d->reply->close(); 0441 d->reply->deleteLater(); 0442 0443 //Q_EMIT revision(QList<Revision>()); 0444 } 0445 } 0446 else 0447 { 0448 setError(NetworkError); 0449 d->reply->close(); 0450 d->reply->deleteLater(); 0451 0452 //Q_EMIT revision(QList<Revision>()); 0453 } 0454 0455 emitResult(); 0456 } 0457 0458 } // namespace MediaWiki 0459 0460 #include "moc_mediawiki_queryrevision.cpp"