File indexing completed on 2025-01-05 03:53:41

0001 /* ============================================================
0002  *
0003  * This file is a part of digiKam project
0004  * https://www.digikam.org
0005  *
0006  * Date        : 2011-04-12
0007  * Description : A tool to export items to Rajce web service
0008  *
0009  * SPDX-FileCopyrightText: 2011      by Lukas Krejci <krejci.l at centrum dot cz>
0010  * SPDX-FileCopyrightText: 2011-2024 by Gilles Caulier <caulier dot gilles at gmail dot com>
0011  *
0012  * SPDX-License-Identifier: GPL-2.0-or-later
0013  *
0014  * ============================================================ */
0015 
0016 #include "rajcetalker.h"
0017 
0018 // Qt includes
0019 
0020 #include <QWidget>
0021 #include <QQueue>
0022 #include <QNetworkReply>
0023 #include <QCryptographicHash>
0024 #include <QXmlResultItems>
0025 #include <QXmlQuery>
0026 #include <QRecursiveMutex>
0027 #include <QFileInfo>
0028 #include <QUrl>
0029 
0030 // Local includes
0031 
0032 #include "digikam_debug.h"
0033 #include "rajcempform.h"
0034 #include "rajcecommand.h"
0035 #include "digikam_version.h"
0036 #include "dmetadata.h"
0037 #include "wstoolutils.h"
0038 #include "networkmanager.h"
0039 #include "previewloadthread.h"
0040 
0041 using namespace Digikam;
0042 
0043 namespace DigikamGenericRajcePlugin
0044 {
0045 
0046 const QUrl RAJCE_URL(QLatin1String("https://www.rajce.idnes.cz/liveAPI/index.php"));
0047 
0048 class Q_DECL_HIDDEN RajceTalker::Private
0049 {
0050 public:
0051 
0052     explicit Private()
0053       : netMngr    (nullptr),
0054         reply      (nullptr)
0055     {
0056     }
0057 
0058     QQueue<QSharedPointer<RajceCommand> > commandQueue;
0059 
0060     QRecursiveMutex                       queueAccess;
0061 
0062     QString                               tmpDir;
0063 
0064     QNetworkAccessManager*                netMngr;
0065     QNetworkReply*                        reply;
0066 
0067     RajceSession                          session;
0068 };
0069 
0070 RajceTalker::RajceTalker(QWidget* const parent)
0071     : QObject(parent),
0072       d      (new Private)
0073 {
0074     d->tmpDir  = WSToolUtils::makeTemporaryDir("rajce").absolutePath() + QLatin1Char('/');
0075     d->netMngr = NetworkManager::instance()->getNetworkManager(this);
0076 
0077     connect(d->netMngr, SIGNAL(finished(QNetworkReply*)),
0078             this, SLOT(slotFinished(QNetworkReply*)));
0079 }
0080 
0081 RajceTalker::~RajceTalker()
0082 {
0083     WSToolUtils::removeTemporaryDir("rajce");
0084 
0085     delete d;
0086 }
0087 
0088 const RajceSession& RajceTalker::session() const
0089 {
0090     return d->session;
0091 }
0092 
0093 void RajceTalker::startCommand(const QSharedPointer<RajceCommand>& command)
0094 {
0095     qCDebug(DIGIKAM_WEBSERVICES_LOG) << "Sending command:\n" << command->getXml();
0096 
0097     QByteArray data = command.data()->encode();
0098 
0099     QNetworkRequest netRequest(RAJCE_URL);
0100     netRequest.setHeader(QNetworkRequest::ContentTypeHeader, command.data()->contentType());
0101 
0102     d->reply = d->netMngr->post(netRequest, data);
0103 
0104     connect(d->reply, SIGNAL(uploadProgress(qint64,qint64)),
0105             SLOT(slotUploadProgress(qint64,qint64)));
0106 
0107     Q_EMIT signalBusyStarted(command.data()->commandType());
0108 }
0109 
0110 void RajceTalker::login(const QString& username, const QString& password)
0111 {
0112     QSharedPointer<RajceCommand> command = QSharedPointer<LoginCommand>(new LoginCommand(username, password));
0113     enqueueCommand(command);
0114 }
0115 
0116 void RajceTalker::loadAlbums()
0117 {
0118     QSharedPointer<RajceCommand> command = QSharedPointer<AlbumListCommand>(new AlbumListCommand(d->session));
0119     enqueueCommand(command);
0120 }
0121 
0122 void RajceTalker::createAlbum(const QString& name, const QString& description, bool visible)
0123 {
0124     QSharedPointer<RajceCommand> command = QSharedPointer<CreateAlbumCommand>(new CreateAlbumCommand(name, description, visible, d->session));
0125     enqueueCommand(command);
0126 }
0127 
0128 void RajceTalker::slotFinished(QNetworkReply* reply)
0129 {
0130     if (reply != d->reply)
0131     {
0132         return;
0133     }
0134 
0135     QString response      = QString::fromUtf8(reply->readAll());
0136 
0137     qCDebug(DIGIKAM_WEBSERVICES_LOG) << response;
0138 
0139     d->queueAccess.lock();
0140 
0141     QSharedPointer<RajceCommand> command = d->commandQueue.head();
0142     d->reply                             = nullptr;
0143 
0144     command->processResponse(response, d->session);
0145 
0146     RajceCommandType type = command.data()->commandType();
0147 
0148     qCDebug(DIGIKAM_WEBSERVICES_LOG) << "State after command: " << d->session;
0149 
0150     // Let the users react on the command before we
0151     // let the next queued command in.
0152     // This enables the connected slots to read in
0153     // reliable values from the state and/or
0154     // clear the error state once it's handled.
0155     Q_EMIT signalBusyFinished(type);
0156 
0157     reply->deleteLater();
0158 
0159     // Only dequeue the command after the above signal has been
0160     // emitted so that the users can queue other commands
0161     // without them being started straight away in the enqueue
0162     // method which would happen if the command was dequeued
0163     // before the signal and the signal was emitted in the same
0164     // thread (which is the case (always?)).
0165     d->commandQueue.dequeue();
0166 
0167     // see if there's something to continue with
0168     if (d->commandQueue.size() > 0)
0169     {
0170         startCommand(d->commandQueue.head());
0171     }
0172 
0173     d->queueAccess.unlock();
0174 }
0175 
0176 void RajceTalker::logout()
0177 {
0178     //TODO
0179 }
0180 
0181 void RajceTalker::openAlbum(const RajceAlbum& album)
0182 {
0183     QSharedPointer<RajceCommand> command = QSharedPointer<OpenAlbumCommand>(new OpenAlbumCommand(album.id, d->session));
0184     enqueueCommand(command);
0185 }
0186 
0187 void RajceTalker::closeAlbum()
0188 {
0189     if (!d->session.openAlbumToken().isEmpty())
0190     {
0191         QSharedPointer<RajceCommand> command = QSharedPointer<CloseAlbumCommand>(new CloseAlbumCommand(d->session));
0192         enqueueCommand(command);
0193     }
0194     else
0195     {
0196         Q_EMIT signalBusyFinished(CloseAlbum);
0197     }
0198 }
0199 
0200 void RajceTalker::uploadPhoto(const QString& path, unsigned dimension, int jpgQuality)
0201 {
0202     QSharedPointer<RajceCommand> command = QSharedPointer<AddPhotoCommand>(new AddPhotoCommand(d->tmpDir, path, dimension, jpgQuality, d->session));
0203     enqueueCommand(command);
0204 }
0205 
0206 void RajceTalker::clearLastError()
0207 {
0208     d->session.lastErrorCode()    = 0;
0209     d->session.lastErrorMessage() = QLatin1String("");
0210 }
0211 
0212 void RajceTalker::slotUploadProgress(qint64 bytesSent, qint64 bytesTotal)
0213 {
0214     if (bytesTotal <= 0)
0215     {
0216         return;
0217     }
0218 
0219     unsigned percent = (unsigned)((float)bytesSent / bytesTotal * 100);
0220 
0221     qCDebug(DIGIKAM_WEBSERVICES_LOG) << "Percent signalled: " << percent;
0222 
0223     QSharedPointer<RajceCommand> command = d->commandQueue.head();
0224     Q_EMIT signalBusyProgress(command.data()->commandType(), percent);
0225 }
0226 
0227 void RajceTalker::enqueueCommand(const QSharedPointer<RajceCommand>& command)
0228 {
0229     if (d->session.lastErrorCode() != 0)
0230     {
0231         return;
0232     }
0233 
0234     d->queueAccess.lock();
0235     d->commandQueue.enqueue(command);
0236 
0237     if (d->commandQueue.size() == 1)
0238     {
0239         startCommand(command);
0240     }
0241 
0242     d->queueAccess.unlock();
0243 }
0244 
0245 void RajceTalker::cancelCurrentCommand()
0246 {
0247     if (d->reply != nullptr)
0248     {
0249         slotFinished(d->reply);
0250         d->reply->abort();
0251         d->reply = nullptr;
0252     }
0253 }
0254 
0255 void RajceTalker::init(const RajceSession& initialState)
0256 {
0257     d->session = initialState;
0258 }
0259 
0260 } // namespace DigikamGenericRajcePlugin
0261 
0262 #include "moc_rajcetalker.cpp"