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"