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