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"