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