diff --git a/core/utilities/assistants/webservices/facebook/fbtalker.cpp b/core/utilities/assistants/webservices/facebook/fbtalker.cpp index 12d0831ade..683d33429d 100644 --- a/core/utilities/assistants/webservices/facebook/fbtalker.cpp +++ b/core/utilities/assistants/webservices/facebook/fbtalker.cpp @@ -1,854 +1,866 @@ /* ============================================================ * * This file is a part of digiKam project * http://www.digikam.org * * Date : 2008-12-26 * Description : a tool to export items to Facebook web service * * Copyright (C) 2008-2010 by Luka Renko * Copyright (c) 2011 by Dirk Tilger * Copyright (C) 2008-2018 by Gilles Caulier * Copyright (C) 2018 by Thanh Trung Dinh * * This program is free software; you can redistribute it * and/or modify it under the terms of the GNU General * Public License as published by the Free Software Foundation; * either version 2, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * ============================================================ */ #include "fbtalker.h" // Qt includes #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include // Local includes #include "digikam_debug.h" #include "digikam_config.h" #include "digikam_version.h" #include "fbmpform.h" #include "wstoolutils.h" #ifdef HAVE_QWEBENGINE # include "webwidget_qwebengine.h" #else # include "webwidget.h" #endif namespace Digikam { bool operator< (const FbUser& first, const FbUser& second) { return first.name < second.name; } bool operator< (const FbAlbum& first, const FbAlbum& second) { return first.title < second.title; } // ----------------------------------------------------------------------------- class Q_DECL_HIDDEN FbTalker::Private { public: enum State { FB_GETLOGGEDINUSER = 0, + FB_LOGOUTUSER, FB_LISTALBUMS, FB_CREATEALBUM, FB_ADDPHOTO }; public: explicit Private() { apiURL = QLatin1String("https://graph.facebook.com/%1/%2"); authUrl = QLatin1String("https://www.facebook.com/dialog/oauth"); tokenUrl = QLatin1String("https://graph.facebook.com/oauth/access_token"); redirectUrl = QLatin1String("https://www.facebook.com/connect/login_success.html"); scope = QLatin1String("user_photos,publish_pages,manage_pages"); //publish_to_groups,user_friends not necessary? apikey = QLatin1String("400589753481372"); clientSecret = QLatin1String("5b0b5cd096e110cd4f4c72f517e2c544"); serviceName = QLatin1String("Facebook"); serviceDate = QLatin1String("token_date"); serviceKey = QLatin1String("access_token"); dialog = 0; parent = 0; settings = 0; netMngr = 0; reply = 0; view = 0; state = FB_GETLOGGEDINUSER; } QString apiURL; QString authUrl; QString tokenUrl; QString redirectUrl; QString scope; QString apikey; QString clientSecret; QString accessToken; QString serviceName; QString serviceDate; QString serviceKey; QDialog* dialog; QWidget* parent; QSettings* settings; QNetworkAccessManager* netMngr; QNetworkReply* reply; WebWidget* view; State state; QMap urlParametersMap; FbUser user; }; // ----------------------------------------------------------------------------- FbTalker::FbTalker(QWidget* const parent) : d(new Private()) { d->parent = parent; d->netMngr = new QNetworkAccessManager(this); d->view = new WebWidget(d->parent); d->view->resize(800, 600); d->settings = WSToolUtils::getOauthSettings(this); connect(this, SIGNAL(linkingFailed()), this, SLOT(slotLinkingFailed())); connect(this, SIGNAL(linkingSucceeded()), this, SLOT(slotLinkingSucceeded())); connect(d->netMngr, SIGNAL(finished(QNetworkReply*)), this, SLOT(slotFinished(QNetworkReply*))); connect(d->view, SIGNAL(urlChanged(QUrl)), this, SLOT(slotCatchUrl(QUrl))); connect(d->view, SIGNAL(closeView(bool)), this, SIGNAL(signalBusy(bool))); } FbTalker::~FbTalker() { if (d->reply) { d->reply->abort(); } delete d; } // ---------------------------------------------------------------------------------------------- void FbTalker::link() { emit signalBusy(true); QUrl url(d->authUrl); QUrlQuery query(url); query.addQueryItem(QLatin1String("client_id"), d->apikey); query.addQueryItem(QLatin1String("scope"), d->scope); query.addQueryItem(QLatin1String("redirect_uri"), d->redirectUrl); query.addQueryItem(QLatin1String("response_type"), "token"); url.setQuery(query); d->view->setWindowFlags(Qt::Dialog); d->view->load(url); d->view->show(); } void FbTalker::unlink() { d->accessToken = QString(); + d->user = FbUser(); d->settings->beginGroup(d->serviceName); d->settings->remove(QString()); d->settings->endGroup(); #ifdef HAVE_QWEBENGINE d->view->page()->profile()->cookieStore()->deleteAllCookies(); #else d->view->page()->networkAccessManager()->setCookieJar(new QNetworkCookieJar()); #endif emit linkingSucceeded(); } void FbTalker::cancel() { if (d->reply) { d->reply->abort(); d->reply = 0; } emit signalBusy(false); } void FbTalker::slotLinkingFailed() { qCDebug(DIGIKAM_WEBSERVICES_LOG) << "LINK to Facebook fail"; emit signalBusy(false); } void FbTalker::slotLinkingSucceeded() { if (d->accessToken.isEmpty()) { qCDebug(DIGIKAM_WEBSERVICES_LOG) << "UNLINK to Facebook ok"; emit signalBusy(false); return; } qCDebug(DIGIKAM_WEBSERVICES_LOG) << "LINK to Facebook ok"; d->view->close(); writeSettings(); getLoggedInUser(); } void FbTalker::slotCatchUrl(const QUrl& url) { d->urlParametersMap = parseUrlParameters(url.toString()); - d->accessToken = d->urlParametersMap.value("access_token"); + QString accessToken = d->urlParametersMap.value("access_token"); + qCDebug(DIGIKAM_WEBSERVICES_LOG) << "Received URL from webview in link function:" << url ; - if (!d->accessToken.isEmpty()) + if (!accessToken.isEmpty()) { qDebug(DIGIKAM_WEBSERVICES_LOG) << "Access Token Received"; + d->accessToken = accessToken; emit linkingSucceeded(); } else { emit linkingFailed(); } } QMap FbTalker::parseUrlParameters(const QString& url) { QMap urlParameters; if (url.indexOf(QLatin1Char('#')) == -1) { return urlParameters; } QString tmp = url.right(url.length() - url.indexOf(QLatin1Char('#')) - 1); tmp = tmp.right(tmp.length() - tmp.indexOf(QLatin1Char('#')) - 1); QStringList paramlist = tmp.split(QLatin1Char('&')); for (int i = 0 ; i < paramlist.count() ; ++i) { QStringList paramarg = paramlist.at(i).split(QLatin1Char('=')); if (paramarg.count() == 2) { urlParameters.insert(paramarg.at(0), paramarg.at(1)); } } return urlParameters; } FbUser FbTalker::getUser() const { return d->user; } bool FbTalker::linked() { return (!d->accessToken.isEmpty()); } void FbTalker::getLoggedInUser() { qCDebug(DIGIKAM_WEBSERVICES_LOG) << "getLoggedInUser called "; if (d->reply) { d->reply->abort(); d->reply = 0; } emit signalBusy(true); emit signalLoginProgress(3); QUrl url(d->apiURL.arg("me").arg("")); QUrlQuery q; q.addQueryItem(QLatin1String("access_token"), d->accessToken.toUtf8()); url.setQuery(q); QNetworkRequest netRequest(url); netRequest.setHeader(QNetworkRequest::ContentTypeHeader, QLatin1String("application/x-www-form-urlencoded")); qCDebug(DIGIKAM_WEBSERVICES_LOG) << "url = " << netRequest.url(); d->reply = d->netMngr->get(netRequest); d->state = Private::FB_GETLOGGEDINUSER; } // ---------------------------------------------------------------------------------------------- void FbTalker::logout() { if (d->reply) { d->reply->abort(); d->reply = 0; } - QMap args; - args[QLatin1String("next")] = QLatin1String("https://www.digikam.org"); - args[QLatin1String("access_token")] = d->accessToken.toUtf8(); + emit signalBusy(true); QUrl url(QLatin1String("https://www.facebook.com/logout.php")); QUrlQuery q; - q.addQueryItem(QLatin1String("next"), QLatin1String("https://www.digikam.org")); q.addQueryItem(QLatin1String("access_token"), d->accessToken.toUtf8()); url.setQuery(q); - qCDebug(DIGIKAM_WEBSERVICES_LOG) << "Logout URL: " << url; - d->view->setWindowFlags(Qt::Dialog); - d->view->load(url); - d->view->show(); + QNetworkRequest netRequest(url); + netRequest.setHeader(QNetworkRequest::ContentTypeHeader, + QLatin1String("application/x-www-form-urlencoded")); - emit signalBusy(false); + qCDebug(DIGIKAM_WEBSERVICES_LOG) << "url = " << netRequest.url(); + d->reply = d->netMngr->get(netRequest); + + d->state = Private::FB_LOGOUTUSER; } //---------------------------------------------------------------------------------------------------- void FbTalker::listAlbums(long long userID) { qCDebug(DIGIKAM_WEBSERVICES_LOG) << "Requesting albums for user " << userID; if (d->reply) { d->reply->abort(); d->reply = 0; } emit signalBusy(true); QUrl url; /* * If userID is specified, load albums of that user, * else load albums of current user */ if (!userID) { url = QUrl(d->apiURL.arg(d->user.id) .arg("albums")); } else { url = QUrl(d->apiURL.arg(userID) .arg("albums")); } QUrlQuery q; q.addQueryItem(QLatin1String("fields"), QLatin1String("id,name,description,privacy,link,location")); q.addQueryItem(QLatin1String("access_token"), d->accessToken.toUtf8()); url.setQuery(q); QNetworkRequest netRequest(url); netRequest.setHeader(QNetworkRequest::ContentTypeHeader, QLatin1String("application/x-www-form-urlencoded")); d->reply = d->netMngr->get(netRequest); d->state = Private::FB_LISTALBUMS; } void FbTalker::createAlbum(const FbAlbum& album) { if (d->reply) { d->reply->abort(); d->reply = 0; } emit signalBusy(true); QUrlQuery params; params.addQueryItem("access_token", d->accessToken.toUtf8()); params.addQueryItem("name", album.title); if (!album.location.isEmpty()) params.addQueryItem("location", album.location); /* * description is deprecated and now a param of message */ if (!album.description.isEmpty()) params.addQueryItem("message", album.description); // TODO (Dirk): Wasn't that a requested feature in Bugzilla? switch (album.privacy) { case FB_ME: params.addQueryItem("privacy","{'value':'SELF'}"); break; case FB_FRIENDS: params.addQueryItem("privacy","{'value':'ALL_FRIENDS'}"); break; case FB_FRIENDS_OF_FRIENDS: params.addQueryItem("privacy","{'value':'FRIENDS_OF_FRIENDS'}"); break; case FB_EVERYONE: params.addQueryItem("privacy","{'value':'EVERYONE'}"); break; case FB_CUSTOM: //TODO params.addQueryItem("privacy","{'value':'CUSTOM'}"); break; } QUrl url(QUrl(d->apiURL.arg(d->user.id) .arg("albums"))); url.setQuery(params); QNetworkRequest netRequest(url); netRequest.setHeader(QNetworkRequest::ContentTypeHeader, QLatin1String("application/x-www-form-urlencoded")); qCDebug(DIGIKAM_WEBSERVICES_LOG) << "url to create new album " << netRequest.url() << params.query(); d->reply = d->netMngr->post(netRequest, params.query().toUtf8()); d->state = Private::FB_CREATEALBUM; } void FbTalker::addPhoto(const QString& imgPath, const QString& albumID, const QString& caption) { qCDebug(DIGIKAM_WEBSERVICES_LOG) << "Adding photo " << imgPath << " to album with id " << albumID << " using caption '" << caption << "'"; if (d->reply) { d->reply->abort(); d->reply = 0; } emit signalBusy(true); QMap args; args[QLatin1String("access_token")] = d->accessToken.toUtf8(); if (!caption.isEmpty()) args[QLatin1String("message")] = caption; FbMPForm form; for (QMap::const_iterator it = args.constBegin() ; it != args.constEnd() ; ++it) { form.addPair(it.key(), it.value()); } qCDebug(DIGIKAM_WEBSERVICES_LOG) << "FORM: " << endl << form.formData(); if (!form.addFile(QUrl::fromLocalFile(imgPath).fileName(), imgPath)) { emit signalAddPhotoDone(666, i18n("Cannot open file")); emit signalBusy(false); return; } form.finish(); QVariant arg_1; if (albumID.isEmpty()) { arg_1 = d->user.id; } else { arg_1 = albumID; } QNetworkRequest netRequest(QUrl(d->apiURL.arg(arg_1.toString()).arg("photos"))); netRequest.setHeader(QNetworkRequest::ContentTypeHeader, form.contentType()); d->reply = d->netMngr->post(netRequest, form.formData()); d->state = Private::FB_ADDPHOTO; } //---------------------------------------------------------------------------------------------------- QString FbTalker::errorToText(int errCode, const QString &errMsg) { QString transError; qCDebug(DIGIKAM_WEBSERVICES_LOG) << "errorToText: " << errCode << ": " << errMsg; switch (errCode) { case 0: transError = QLatin1String(""); break; case 2: transError = i18n("The service is not available at this time."); break; case 4: transError = i18n("The application has reached the maximum number of requests allowed."); break; case 102: transError = i18n("Invalid session key or session expired. Try to log in again."); break; case 120: transError = i18n("Invalid album ID."); break; case 321: transError = i18n("Album is full."); break; case 324: transError = i18n("Missing or invalid file."); break; case 325: transError = i18n("Too many unapproved photos pending."); break; default: transError = errMsg; break; } return transError; } void FbTalker::slotFinished(QNetworkReply* reply) { if (reply != d->reply) { return; } d->reply = 0; if (reply->error() != QNetworkReply::NoError) { if (d->state == Private::FB_ADDPHOTO) { emit signalBusy(false); emit signalAddPhotoDone(reply->error(), reply->errorString()); } else { emit signalBusy(false); QMessageBox::critical(QApplication::activeWindow(), i18n("Error"), reply->errorString()); } qCDebug(DIGIKAM_WEBSERVICES_LOG) << reply->error() << " text :"<< QString(reply->readAll()); reply->deleteLater(); return; } QByteArray buffer = reply->readAll(); switch(d->state) { case (Private::FB_GETLOGGEDINUSER): parseResponseGetLoggedInUser(buffer); break; + case (Private::FB_LOGOUTUSER): + parseResponseLogoutUser(buffer); + break; case (Private::FB_LISTALBUMS): parseResponseListAlbums(buffer); break; case (Private::FB_CREATEALBUM): parseResponseCreateAlbum(buffer); break; case (Private::FB_ADDPHOTO): parseResponseAddPhoto(buffer); break; } reply->deleteLater(); } int FbTalker::parseErrorResponse(const QDomElement& e, QString& errMsg) { int errCode = -1; for (QDomNode node = e.firstChild() ; !node.isNull() ; node = node.nextSibling()) { if (!node.isElement()) continue; if (node.nodeName() == QLatin1String("error_code")) { errCode = node.toElement().text().toInt(); qCDebug(DIGIKAM_WEBSERVICES_LOG) << "Error Code:" << errCode; } else if (node.nodeName() == QLatin1String("error_msg")) { errMsg = node.toElement().text(); qCDebug(DIGIKAM_WEBSERVICES_LOG) << "Error Text:" << errMsg; } } return errCode; } void FbTalker::parseResponseGetLoggedInUser(const QByteArray& data) { QString errMsg; QJsonParseError err; QJsonDocument doc = QJsonDocument::fromJson(data, &err); qCDebug(DIGIKAM_WEBSERVICES_LOG) << "Logged in data " << doc; if (err.error != QJsonParseError::NoError) { emit signalBusy(false); return; } QJsonObject jsonObject = doc.object(); d->user.id = jsonObject[QLatin1String("id")].toString(); if (!(QString::compare(jsonObject[QLatin1String("id")].toString(), QLatin1String(""), Qt::CaseInsensitive) == 0)) { qCDebug(DIGIKAM_WEBSERVICES_LOG) << "ID found in response of GetLoggedInUser"; } d->user.name = jsonObject[QLatin1String("name")].toString(); d->user.profileURL = jsonObject[QLatin1String("link")].toString(); emit signalLoginDone(0, QString()); } +void FbTalker::parseResponseLogoutUser(const QByteArray& /*data*/) +{ + unlink(); + emit signalLoginDone(-1, QString()); +} + void FbTalker::parseResponseAddPhoto(const QByteArray& data) { qCDebug(DIGIKAM_WEBSERVICES_LOG) <<"Parse Add Photo data is "< albumsList; QJsonDocument doc = QJsonDocument::fromJson(data, &err); if (err.error != QJsonParseError::NoError) { emit signalBusy(false); return; } QJsonObject jsonObject = doc.object(); if (jsonObject.contains(QLatin1String("data"))) { QJsonArray jsonArray = jsonObject[QLatin1String("data")].toArray(); foreach (const QJsonValue& value, jsonArray) { QJsonObject obj = value.toObject(); FbAlbum album; album.id = obj[QLatin1String("id")].toString(); album.title = obj[QLatin1String("name")].toString(); album.location = obj[QLatin1String("location")].toString(); album.url = obj[QLatin1String("link")].toString(); album.description = obj[QLatin1String("description")].toString(); album.uploadable = obj[QLatin1String("can_upload")].toBool(); qCDebug(DIGIKAM_WEBSERVICES_LOG) << "can_upload " << album.uploadable; if (QString::compare(obj[QLatin1String("privacy")].toString(), QLatin1String("ALL_FRIENDS"), Qt::CaseInsensitive) == 0) { album.privacy = FB_FRIENDS; } else if (QString::compare(obj[QLatin1String("privacy")].toString(), QLatin1String("FRIENDS_OF_FRIENDS"), Qt::CaseInsensitive) == 0) { album.privacy = FB_FRIENDS; } else if (QString::compare(obj[QLatin1String("privacy")].toString(), QLatin1String("EVERYONE"), Qt::CaseInsensitive) == 0) { album.privacy = FB_EVERYONE; } else if (QString::compare(obj[QLatin1String("privacy")].toString(), QLatin1String("CUSTOM"), Qt::CaseInsensitive) == 0) { album.privacy = FB_CUSTOM; } else if (QString::compare(obj[QLatin1String("privacy")].toString(), QLatin1String("SELF"), Qt::CaseInsensitive) == 0) { album.privacy = FB_ME; } albumsList.append(album); } errCode = 0; } if (jsonObject.contains(QLatin1String("error"))) { QJsonObject obj = jsonObject[QLatin1String("error")].toObject(); errCode = obj[QLatin1String("code")].toInt(); errMsg = obj[QLatin1String("message")].toString(); } std::sort(albumsList.begin(), albumsList.end()); emit signalBusy(false); emit signalListAlbumsDone(errCode, errorToText(errCode, errMsg), albumsList); } void FbTalker::writeSettings() { d->settings->beginGroup(d->serviceName); d->settings->setValue(d->serviceDate, QDateTime::currentDateTime()); d->settings->setValue(d->serviceKey, d->accessToken); d->settings->endGroup(); } void FbTalker::readSettings() { d->settings->beginGroup(d->serviceName); QDateTime dateTime = d->settings->value(d->serviceDate).toDateTime(); d->accessToken = d->settings->value(d->serviceKey).toString(); d->settings->endGroup(); if (d->accessToken.isEmpty()) { qCDebug(DIGIKAM_WEBSERVICES_LOG) << "Linking..."; link(); } else if (dateTime.secsTo(QDateTime::currentDateTime()) > 3600) { qCDebug(DIGIKAM_WEBSERVICES_LOG) << "Access token has expired"; qCDebug(DIGIKAM_WEBSERVICES_LOG) << "Linking..."; d->accessToken = QString(); link(); } else { qCDebug(DIGIKAM_WEBSERVICES_LOG) << "Already Linked"; emit linkingSucceeded(); } } } // namespace Digikam diff --git a/core/utilities/assistants/webservices/facebook/fbtalker.h b/core/utilities/assistants/webservices/facebook/fbtalker.h index b7e9671865..88972c5614 100644 --- a/core/utilities/assistants/webservices/facebook/fbtalker.h +++ b/core/utilities/assistants/webservices/facebook/fbtalker.h @@ -1,114 +1,115 @@ /* ============================================================ * * This file is a part of digiKam project * http://www.digikam.org * * Date : 2008-12-26 * Description : a tool to export items to Facebook web service * * Copyright (C) 2008-2009 by Luka Renko * Copyright (C) 2008-2018 by Gilles Caulier * Copyright (C) 2018 by Thanh Trung Dinh * * This program is free software; you can redistribute it * and/or modify it under the terms of the GNU General * Public License as published by the Free Software Foundation; * either version 2, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * ============================================================ */ #ifndef DIGIKAM_FB_TALKER_H #define DIGIKAM_FB_TALKER_H // Qt includes #include #include #include #include #include #include #include // Local includes #include "fbitem.h" class QDomElement; namespace Digikam { class FbTalker : public QObject { Q_OBJECT public: explicit FbTalker(QWidget* const parent); ~FbTalker(); void link(); void unlink(); bool linked(); void cancel(); FbUser getUser() const; void logout(); void listAlbums(long long userID = 0); void createAlbum(const FbAlbum& album); void addPhoto(const QString& imgPath, const QString& albumID, const QString& caption); void readSettings(); void writeSettings(); Q_SIGNALS: void signalBusy(bool val); void signalListAlbumsDone(int errCode, const QString& errMsg, const QList & albumsList); void signalCreateAlbumDone(int errCode, const QString& errMsg, const QString& newAlbumId); void signalAddPhotoDone(int errCode, const QString& errMsg); void signalLoginProgress(int step, int maxStep = 0, const QString& label = QString()); void signalLoginDone(int errCode, const QString& errMsg); void linkingSucceeded(); void linkingFailed(); private: void getLoggedInUser(); QString errorToText(int errCode, const QString& errMsg); int parseErrorResponse(const QDomElement& e, QString& errMsg); void parseResponseGetLoggedInUser(const QByteArray& data); + void parseResponseLogoutUser(const QByteArray& data); void parseResponseAddPhoto(const QByteArray& data); void parseResponseCreateAlbum(const QByteArray& data); void parseResponseListAlbums(const QByteArray& data); QMap parseUrlParameters(const QString& url); private Q_SLOTS: void slotLinkingFailed(); void slotLinkingSucceeded(); void slotCatchUrl(const QUrl& url); void slotFinished(QNetworkReply* reply); private: class Private; Private* const d; }; } // namespace Digikam #endif // DIGIKAM_FB_TALKER_H diff --git a/core/utilities/assistants/webservices/facebook/fbwindow.cpp b/core/utilities/assistants/webservices/facebook/fbwindow.cpp index d60022c605..b66021fbee 100644 --- a/core/utilities/assistants/webservices/facebook/fbwindow.cpp +++ b/core/utilities/assistants/webservices/facebook/fbwindow.cpp @@ -1,663 +1,658 @@ /* ============================================================ * * This file is a part of digiKam project * http://www.digikam.org * * Date : 2005-17-26 * Description : a tool to export items to Facebook web service * * Copyright (C) 2005-2008 by Vardhman Jain * Copyright (C) 2008-2018 by Gilles Caulier * Copyright (C) 2008-2009 by Luka Renko * Copyright (C) 2018 by Thanh Trung Dinh * * This program is free software; you can redistribute it * and/or modify it under the terms of the GNU General * Public License as published by the Free Software Foundation; * either version 2, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * ============================================================ */ #include "fbwindow.h" // Qt includes #include #include #include #include #include #include #include #include #include // KDE includes #include #include #include // Local includes #include "digikam_debug.h" #include "dmetadata.h" #include "ditemslist.h" #include "digikam_version.h" #include "dprogresswdg.h" #include "wstoolutils.h" #include "fbitem.h" #include "fbtalker.h" #include "fbwidget.h" #include "fbnewalbumdlg.h" #include "previewloadthread.h" namespace Digikam { class Q_DECL_HIDDEN FbWindow::Private { public: explicit Private(QWidget* const parent, DInfoInterface* const interface) { iface = interface; widget = new FbWidget(parent, iface, QLatin1String("Facebook")); imgList = widget->imagesList(); progressBar = widget->progressBar(); changeUserBtn = widget->getChangeUserBtn(); albumsCoB = widget->getAlbumsCoB(); newAlbumBtn = widget->getNewAlbmBtn(); reloadAlbumsBtn = widget->getReloadBtn(); resizeChB = widget->getResizeCheckBox(); dimensionSpB = widget->getDimensionSpB(); imageQualitySpB = widget->getImgQualitySpB(); imagesCount = 0; imagesTotal = 0; talker = 0; albumDlg = 0; } FbWidget* widget; DItemsList* imgList; QPushButton* changeUserBtn; QComboBox* albumsCoB; QPushButton* newAlbumBtn; QPushButton* reloadAlbumsBtn; QCheckBox* resizeChB; QSpinBox* dimensionSpB; QSpinBox* imageQualitySpB; DProgressWdg* progressBar; unsigned int imagesCount; unsigned int imagesTotal; QString tmpDir; QString tmpPath; QString profileAID; QString currentAlbumID; QList transferQueue; FbTalker* talker; FbNewAlbumDlg* albumDlg; DInfoInterface* iface; }; FbWindow::FbWindow(DInfoInterface* const iface, QWidget* const /*parent*/) : WSToolDialog(0), d(new Private(this, iface)) { d->tmpPath.clear(); d->tmpDir = WSToolUtils::makeTemporaryDir("facebook").absolutePath() + QLatin1Char('/'); setMainWidget(d->widget); setModal(false); setWindowTitle(i18n("Export to Facebook Web Service")); startButton()->setText(i18n("Start Upload")); startButton()->setToolTip(i18n("Start upload to Facebook web service")); d->widget->setMinimumSize(700, 500); - d->changeUserBtn->setText(i18n("Continue with Facebook")); + d->changeUserBtn->setStyleSheet(QLatin1String("QPushButton {background-color: " + "#3b5998; color: #ffffff;}")); d->changeUserBtn->setIcon(QIcon::fromTheme(QLatin1String("facebook"))); + d->changeUserBtn->setText(i18n("Continue with Facebook")); // ------------------------------------------------------------------------ connect(d->imgList, SIGNAL(signalImageListChanged()), this, SLOT(slotImageListChanged())); connect(d->changeUserBtn, SIGNAL(clicked()), this, SLOT(slotUserChangeRequest())); connect(d->newAlbumBtn, SIGNAL(clicked()), this, SLOT(slotNewAlbumRequest())); connect(d->widget, SIGNAL(reloadAlbums(long long)), this, SLOT(slotReloadAlbumsRequest(long long))); connect(startButton(), SIGNAL(clicked()), this, SLOT(slotStartTransfer())); connect(this, SIGNAL(finished(int)), this, SLOT(slotFinished())); connect(this, SIGNAL(cancelClicked()), this, SLOT(slotCancelClicked())); d->albumDlg = new FbNewAlbumDlg(this, QLatin1String("Facebook")); // ------------------------------------------------------------------------ d->talker = new FbTalker(this); connect(d->talker, SIGNAL(signalBusy(bool)), this, SLOT(slotBusy(bool))); connect(d->talker, SIGNAL(signalLoginProgress(int,int,QString)), this, SLOT(slotLoginProgress(int,int,QString))); connect(d->talker, SIGNAL(signalLoginDone(int,QString)), this, SLOT(slotLoginDone(int,QString))); connect(d->talker, SIGNAL(signalAddPhotoDone(int,QString)), this, SLOT(slotAddPhotoDone(int,QString))); connect(d->talker, SIGNAL(signalCreateAlbumDone(int,QString,QString)), this, SLOT(slotCreateAlbumDone(int,QString,QString))); connect(d->talker, SIGNAL(signalListAlbumsDone(int,QString,QList)), this, SLOT(slotListAlbumsDone(int,QString,QList))); connect(d->progressBar, SIGNAL(signalProgressCanceled()), this, SLOT(slotStopAndCloseProgressBar())); // ------------------------------------------------------------------------ readSettings(); buttonStateChange(false); authenticate(); } FbWindow::~FbWindow() { WSToolUtils::removeTemporaryDir("facebook"); delete d->albumDlg; delete d->talker; delete d; } void FbWindow::slotStopAndCloseProgressBar() { // Cancel the operation slotCancelClicked(); // Write settings and tidy up slotFinished(); // Close the dialog reject(); } void FbWindow::slotFinished() { writeSettings(); d->imgList->listView()->clear(); d->progressBar->progressCompleted(); } void FbWindow::slotCancelClicked() { setRejectButtonMode(QDialogButtonBox::Close); d->talker->cancel(); d->transferQueue.clear(); d->imgList->cancelProcess(); d->progressBar->hide(); d->progressBar->progressCompleted(); } void FbWindow::closeEvent(QCloseEvent* e) { if (!e) { return; } slotFinished(); e->accept(); } void FbWindow::readSettings() { KConfig config; KConfigGroup grp = config.group("Facebook Settings"); if (grp.readEntry("Resize", false)) { d->resizeChB->setChecked(true); d->dimensionSpB->setEnabled(true); } else { d->resizeChB->setChecked(false); d->dimensionSpB->setEnabled(false); } d->currentAlbumID = grp.readEntry("Current Album", QString()); d->dimensionSpB->setValue(grp.readEntry("Maximum Width", 1600)); d->imageQualitySpB->setValue(grp.readEntry("Image Quality", 85)); winId(); KConfigGroup dialogGroup = config.group("Facebook Export Dialog"); KWindowConfig::restoreWindowSize(windowHandle(), dialogGroup); resize(windowHandle()->size()); } void FbWindow::writeSettings() { KConfig config; KConfigGroup grp = config.group("Facebook Settings"); grp.writeEntry("Current Album", d->currentAlbumID); grp.writeEntry("Resize", d->resizeChB->isChecked()); grp.writeEntry("Maximum Width", d->dimensionSpB->value()); grp.writeEntry("Image Quality", d->imageQualitySpB->value()); KConfigGroup dialogGroup = config.group("Facebook Export Dialog"); KWindowConfig::saveWindowSize(windowHandle(), dialogGroup); config.sync(); } void FbWindow::authenticate() { - setRejectButtonMode(QDialogButtonBox::Cancel); d->progressBar->show(); d->progressBar->setFormat(QLatin1String("")); + setRejectButtonMode(QDialogButtonBox::Cancel); qCDebug(DIGIKAM_WEBSERVICES_LOG) << "Calling Login method "; d->talker->readSettings(); } void FbWindow::slotLoginProgress(int step, int maxStep, const QString& label) { DProgressWdg* const progressBar = d->progressBar; if (!label.isEmpty()) { progressBar->setFormat(label); } if (maxStep > 0) { progressBar->setMaximum(maxStep); } progressBar->setValue(step); } void FbWindow::slotLoginDone(int errCode, const QString& errMsg) { setRejectButtonMode(QDialogButtonBox::Close); d->progressBar->hide(); buttonStateChange(d->talker->linked()); if (d->talker->linked()) { d->changeUserBtn->setText(i18n("Logout from Facebook")); } else { d->changeUserBtn->setText(i18n("Continue with Facebook")); } FbUser user = d->talker->getUser(); setProfileAID(user.id.toLongLong()); d->widget->updateLabels(user.name, user.profileURL); d->albumsCoB->clear(); - d->albumsCoB->addItem(i18n(""), QString()); - if (errCode == 0 && d->talker->linked()) { + d->albumsCoB->addItem(i18n(""), QString()); d->talker->listAlbums(); // get albums to fill combo box } - else + else if (errCode > 0) { QMessageBox::critical(this, QString(), i18n("Facebook Call Failed: %1\n", errMsg)); } } void FbWindow::slotListAlbumsDone(int errCode, const QString& errMsg, const QList& albumsList) { QString albumDebug = QLatin1String(""); foreach (const FbAlbum& album, albumsList) { albumDebug.append(QString::fromLatin1("%1: %2\n").arg(album.id).arg(album.title)); } qCDebug(DIGIKAM_WEBSERVICES_LOG) << "Received albums (errCode = " << errCode << ", errMsg = " << errMsg << "): " << albumDebug; if (errCode != 0) { QMessageBox::critical(this, QString(), i18n("Facebook Call Failed: %1\n", errMsg)); return; } d->albumsCoB->clear(); d->albumsCoB->addItem(i18n(""), QString()); for (int i = 0 ; i < albumsList.size() ; ++i) { QString albumIcon; switch (albumsList.at(i).privacy) { case FB_ME: albumIcon = QLatin1String("secure-card"); break; case FB_FRIENDS: albumIcon = QLatin1String("user-identity"); break; case FB_FRIENDS_OF_FRIENDS: albumIcon = QLatin1String("system-users"); break; case FB_EVERYONE: albumIcon = QLatin1String("folder-html"); break; case FB_CUSTOM: albumIcon = QLatin1String("configure"); break; } d->albumsCoB->addItem(QIcon::fromTheme(albumIcon), albumsList.at(i).title, albumsList.at(i).id); if (d->currentAlbumID == albumsList.at(i).id) { d->albumsCoB->setCurrentIndex(i + 1); } } } void FbWindow::buttonStateChange(bool state) { d->newAlbumBtn->setEnabled(state); d->reloadAlbumsBtn->setEnabled(state); startButton()->setEnabled(state); } void FbWindow::slotBusy(bool val) { if (val) { setCursor(Qt::WaitCursor); d->changeUserBtn->setEnabled(false); buttonStateChange(false); } else { setCursor(Qt::ArrowCursor); d->changeUserBtn->setEnabled(true); buttonStateChange(d->talker->linked()); } } -void FbWindow::slotUserLogout() +void FbWindow::slotUserChangeRequest() { + qCDebug(DIGIKAM_WEBSERVICES_LOG) << "Slot Change User Request"; + if (d->talker->linked()) { qCDebug(DIGIKAM_WEBSERVICES_LOG) << "Slot User Logout"; - // Logout and wait until it's done d->talker->logout(); - d->talker->unlink(); } else { authenticate(); } } -void FbWindow::slotUserChangeRequest() -{ - qCDebug(DIGIKAM_WEBSERVICES_LOG) << "Slot Change User Request"; - slotUserLogout(); -} - void FbWindow::slotReloadAlbumsRequest(long long userID) { qCDebug(DIGIKAM_WEBSERVICES_LOG) << "Reload Albums Request for UID:" << userID; if (userID == 0) { FbUser user = d->talker->getUser(); setProfileAID(user.id.toLongLong()); d->talker->listAlbums(); // re-get albums from current user } else { setProfileAID(userID); d->talker->listAlbums(userID); // re-get albums for friend } } void FbWindow::slotNewAlbumRequest() { qCDebug(DIGIKAM_WEBSERVICES_LOG) << "Slot New Album Request"; if (d->albumDlg->exec() == QDialog::Accepted) { qCDebug(DIGIKAM_WEBSERVICES_LOG) << "Calling New Album method"; FbAlbum newAlbum; d->albumDlg->getAlbumProperties(newAlbum); d->talker->createAlbum(newAlbum); } } void FbWindow::slotStartTransfer() { qCDebug(DIGIKAM_WEBSERVICES_LOG) << "slotStartTransfer invoked"; d->imgList->clearProcessedStatus(); d->transferQueue = d->imgList->imageUrls(); if (d->transferQueue.isEmpty()) { return; } d->currentAlbumID = d->albumsCoB->itemData(d->albumsCoB->currentIndex()).toString(); qCDebug(DIGIKAM_WEBSERVICES_LOG) << "upload request got album id from widget: " << d->currentAlbumID; d->imagesTotal = d->transferQueue.count(); d->imagesCount = 0; setRejectButtonMode(QDialogButtonBox::Cancel); d->progressBar->setFormat(i18n("%v / %m")); d->progressBar->setMaximum(d->imagesTotal); d->progressBar->setValue(0); d->progressBar->show(); d->progressBar->progressScheduled(i18n("Facebook export"), true, true); d->progressBar->progressThumbnailChanged(QIcon::fromTheme(QLatin1String("facebook")).pixmap(22, 22)); uploadNextPhoto(); } void FbWindow::setProfileAID(long long userID) { // store AID of Profile Photos album // http://wiki.developers.facebook.com/index.php/Profile_archive_album d->profileAID = QString::number((userID << 32) + (-3 & 0xFFFFFFFF)); } QString FbWindow::getImageCaption(const QString& fileName) { DItemInfo info(d->iface->itemInfo(QUrl::fromLocalFile(fileName))); // Facebook doesn't support image titles. Include it in descriptions if needed. QStringList descriptions = QStringList() << info.title() << info.comment(); descriptions.removeAll(QLatin1String("")); return descriptions.join(QLatin1String("\n\n")); } bool FbWindow::prepareImageForUpload(const QString& imgPath, QString& caption) { QImage image = PreviewLoadThread::loadHighQualitySynchronously(imgPath).copyQImage(); if (image.isNull()) { image.load(imgPath); } if (image.isNull()) { return false; } // get temporary file name d->tmpPath = d->tmpDir + QFileInfo(imgPath).baseName().trimmed() + QLatin1String(".jpg"); // rescale image if requested int maxDim = d->dimensionSpB->value(); if (d->resizeChB->isChecked() && (image.width() > maxDim || image.height() > maxDim)) { qCDebug(DIGIKAM_WEBSERVICES_LOG) << "Resizing to " << maxDim; image = image.scaled(maxDim, maxDim, Qt::KeepAspectRatio, Qt::SmoothTransformation); } qCDebug(DIGIKAM_WEBSERVICES_LOG) << "Saving to temp file: " << d->tmpPath; image.save(d->tmpPath, "JPEG", d->imageQualitySpB->value()); // copy meta data to temporary image DMetadata meta; if (meta.load(imgPath)) { caption = getImageCaption(imgPath); meta.setItemDimensions(image.size()); meta.setItemOrientation(MetaEngine::ORIENTATION_NORMAL); meta.setMetadataWritingMode((int)DMetadata::WRITE_TO_FILE_ONLY); meta.save(d->tmpPath, true); } else { caption.clear(); } return true; } void FbWindow::uploadNextPhoto() { if (d->transferQueue.isEmpty()) { setRejectButtonMode(QDialogButtonBox::Close); d->progressBar->hide(); d->progressBar->progressCompleted(); return; } d->imgList->processing(d->transferQueue.first()); QString imgPath = d->transferQueue.first().toLocalFile(); d->progressBar->setMaximum(d->imagesTotal); d->progressBar->setValue(d->imagesCount); QString caption; if (d->resizeChB->isChecked()) { if (!prepareImageForUpload(imgPath, caption)) { slotAddPhotoDone(666, i18n("Cannot open file")); return; } d->talker->addPhoto(d->tmpPath, d->currentAlbumID, caption); } else { caption = getImageCaption(imgPath); d->tmpPath.clear(); d->talker->addPhoto(imgPath, d->currentAlbumID, caption); } } void FbWindow::slotAddPhotoDone(int errCode, const QString& errMsg) { // Remove temporary file if it was used if (!d->tmpPath.isEmpty()) { QFile::remove(d->tmpPath); d->tmpPath.clear(); } d->imgList->processed(d->transferQueue.first(), (errCode == 0)); if (errCode == 0) { d->transferQueue.removeFirst(); d->imagesCount++; } else { if (QMessageBox::question(this, i18n("Uploading Failed"), i18n("Failed to upload photo into Facebook: %1\n" "Do you want to continue?", errMsg)) != QMessageBox::Yes) { setRejectButtonMode(QDialogButtonBox::Close); d->progressBar->hide(); d->progressBar->progressCompleted(); d->transferQueue.clear(); return; } } uploadNextPhoto(); } void FbWindow::slotCreateAlbumDone(int errCode, const QString& errMsg, const QString& newAlbumID) { if (errCode != 0) { QMessageBox::critical(this, QString(), i18n("Facebook Call Failed: %1", errMsg)); return; } // reload album list and automatically select new album d->currentAlbumID = newAlbumID; d->talker->listAlbums(); } void FbWindow::slotImageListChanged() { startButton()->setEnabled(!(d->imgList->imageUrls().isEmpty())); } } // namespace Digikam diff --git a/core/utilities/assistants/webservices/facebook/fbwindow.h b/core/utilities/assistants/webservices/facebook/fbwindow.h index 7b31f53c07..45b3977ab0 100644 --- a/core/utilities/assistants/webservices/facebook/fbwindow.h +++ b/core/utilities/assistants/webservices/facebook/fbwindow.h @@ -1,102 +1,101 @@ /* ============================================================ * * This file is a part of digiKam project * http://www.digikam.org * * Date : 2008-12-26 * Description : a tool to export items to Facebook web service * * Copyright (C) 2005-2008 by Vardhman Jain * Copyright (C) 2008-2018 by Gilles Caulier * Copyright (C) 2008-2009 by Luka Renko * * This program is free software; you can redistribute it * and/or modify it under the terms of the GNU General * Public License as published by the Free Software Foundation; * either version 2, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * ============================================================ */ #ifndef DIGIKAM_FB_WINDOW_H #define DIGIKAM_FB_WINDOW_H // Qt includes #include // Local includes #include "digikam_export.h" #include "dinfointerface.h" #include "wstooldialog.h" class QCloseEvent; class QUrl; namespace Digikam { class FbAlbum; class DIGIKAM_EXPORT FbWindow : public WSToolDialog { Q_OBJECT public: explicit FbWindow(DInfoInterface* const iface, QWidget* const parent); ~FbWindow(); private Q_SLOTS: void slotBusy(bool val); void slotLoginProgress(int step, int maxStep, const QString& label); void slotLoginDone(int errCode, const QString& errMsg); void slotAddPhotoDone(int errCode, const QString& errMsg); void slotCreateAlbumDone(int errCode, const QString& errMsg, const QString &newAlbumID); void slotListAlbumsDone(int errCode, const QString& errMsg, const QList& albumsList); - void slotUserLogout(); void slotUserChangeRequest(); void slotReloadAlbumsRequest(long long userID); void slotNewAlbumRequest(); void slotStartTransfer(); void slotImageListChanged(); void slotStopAndCloseProgressBar(); void slotFinished(); void slotCancelClicked(); private: void setProfileAID(long long userID); QString getImageCaption(const QString& fileName); bool prepareImageForUpload(const QString& imgPath, QString& caption); void uploadNextPhoto(); void readSettings(); void writeSettings(); void authenticate(); void buttonStateChange(bool state); void closeEvent(QCloseEvent*); private: class Private; Private* const d; }; } // namespace Digikam #endif // DIGIKAM_FB_WINDOW_H