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

0001 /* ============================================================
0002  *
0003  * This file is a part of digiKam project
0004  * https://www.digikam.org
0005  *
0006  * Date        : 2018-07-08
0007  * Description : Base class for web service talkers.
0008  *
0009  * SPDX-FileCopyrightText: 2018 by Thanh Trung Dinh <dinhthanhtrung1996 at gmail dot com>
0010  *
0011  * SPDX-License-Identifier: GPL-2.0-or-later
0012  *
0013  * ============================================================ */
0014 
0015 #ifndef DIGIKAM_WS_TALKER_H
0016 #define DIGIKAM_WS_TALKER_H
0017 
0018 // Qt includes
0019 
0020 #include <QtGlobal>
0021 #include <QList>
0022 #include <QPair>
0023 #include <QString>
0024 #include <QUrl>
0025 #include <QWidget>
0026 #include <QSettings>
0027 #include <QNetworkReply>
0028 #include <QNetworkAccessManager>
0029 #include <QMap>
0030 
0031 // Local includes
0032 
0033 #include "o0settingsstore.h"
0034 #include "wsitem.h"
0035 #include "wswizard.h"
0036 
0037 using namespace Digikam;
0038 
0039 namespace DigikamGenericUnifiedPlugin
0040 {
0041 
0042 class WSTalker : public QObject
0043 {
0044     Q_OBJECT
0045 
0046 public:
0047 
0048     enum State
0049     {
0050         DEFAULT = 0,
0051         GETUSER,
0052         LISTALBUMS,
0053         CREATEALBUM,
0054         ADDPHOTO
0055     };
0056 
0057 public:
0058 
0059     explicit WSTalker(QWidget* const parent);
0060     ~WSTalker();
0061 
0062     /*
0063      * Get ID of an existent user account saved when he logged in before,
0064      * knowing user name.
0065      */
0066     QString getUserID(const QString& userName);
0067 
0068     /*
0069      * Link user account (login).
0070      */
0071     virtual void link();
0072 
0073     /*
0074      * Unlink user account (logout).
0075      */
0076     virtual void unlink();
0077 
0078     /*
0079      * Return true if account is linked.
0080      */
0081     virtual bool linked() const;
0082 
0083     /*
0084      * This method load account that user chooses to login. If it exists and doesn't expire yet,
0085      * then obtain the saved token and pass the authentication process. Otherwise, relogin.
0086      */
0087     virtual void authenticate();
0088 
0089     /*
0090      * Force user to login on web service login page.
0091      */
0092     void reauthenticate();
0093 
0094     /*
0095      * Abort any network request realizing at the moment.
0096      */
0097     void cancel();
0098 
0099 protected:
0100 
0101     /*
0102      * Return a map of all information stored in the previous login of userName account.
0103      */
0104     QMap<QString, QVariant> getUserAccountInfo(const QString& userName);
0105 
0106     /*
0107      * Save all necessary information of user account to disk. That information will be retrieved
0108      * by getUserAccountInfo(userName) when needed.
0109      */
0110     void saveUserAccount(const QString& userName,
0111                          const QString& userID,
0112                          long long int expire,
0113                          const QString& accessToken,
0114                          const QString& refreshToken = QString());
0115 
0116     /*
0117      * Remove all information of user account that was stored by saveUserAccount(...)
0118      * TODO: this method should be called when user uninstalls digiKam.
0119      */
0120     void removeUserAccount(const QString& userName);
0121 
0122     /*
0123      * Save as removeUserAccount(userName), but for all accounts.
0124      */
0125     void removeAllAccounts();
0126 
0127     /*
0128      * A wrapper method of getUserAccountInfo(userName), but perform further verification
0129      * on account's validation and further operation in case that account is expired.
0130      */
0131     bool loadUserAccount(const QString& userName);
0132 
0133     /*
0134      * This method can be (and must be) reimplemented in derived class. Indeed, it will hard code
0135      * (at runtime) O2's settings (i.e accessToken, refreshToken, expired date and value of linked state).
0136      * It forces O2 to link to another account according to user's selection. Otherwise, O2 will
0137      * "remember" account from previous login and always link to that account, if an obligated reauthenticate
0138      * (unlink and then link) is not realized.
0139      */
0140     virtual void resetTalker(const QString& expire, const QString& accessToken, const QString& refreshToken);
0141 
0142     /*
0143      * Sort list of albums by ascending order of titles.
0144      */
0145     virtual void sortAlbumsList(QList<WSAlbum>& albumsList);
0146 
0147     /*
0148      * These methods are reimplemented in derived class and used to parse response of network requests
0149      * for user's information or APIs of web service. They will be called asynchronously when responses
0150      * for net request are received.
0151      */
0152     virtual void parseResponseGetLoggedInUser(const QByteArray& data);
0153     virtual void parseResponseListAlbums(const QByteArray& data);
0154     virtual void parseResponseCreateAlbum(const QByteArray& data);
0155     virtual void parseResponseAddPhoto(const QByteArray& data);
0156 
0157     /*
0158      * This method is called when authentication is complete. It should be reimplemented in derived class
0159      * and call saveUserAccount(...) inside. Here, we implement a minimised version so that derived class
0160      * can call it if needed.
0161      */
0162     virtual void authenticationDone(int errCode, const QString& errMsg);
0163 
0164 public:
0165 
0166     /*
0167      * These methods are reimplemented in derived class, and will be used to make network requests
0168      * for user's information or APIs of web service.
0169      */
0170     virtual void getLoggedInUser();
0171     virtual void listAlbums(long long userID = 0);
0172     virtual void createNewAlbum();
0173     virtual void addPhoto(const QString& imgPath, const QString& albumID, const QString& caption);
0174 
0175 Q_SIGNALS:
0176 
0177     void signalBusy(bool val);
0178     void signalOpenBrowser(const QUrl& url);
0179     void signalCloseBrowser();
0180     void signalAuthenticationComplete(bool);
0181     void signalCreateAlbumDone(int errCode, const QString& errMsg, const QString& newAlbumId);
0182     void signalListAlbumsDone(int errCode, const QString& errMsg, const QList <WSAlbum>& albumsList);
0183     void signalAddPhotoDone(int errCode, const QString& errMsg);
0184 
0185 protected Q_SLOTS:
0186 
0187     /*
0188      * Slots for signals from O2 authentication flow
0189      */
0190     void slotFinished(QNetworkReply* reply);
0191     void slotOpenBrowser(const QUrl& url);
0192     void slotCloseBrowser();
0193     virtual void slotLinkingFailed();
0194     virtual void slotLinkingSucceeded();
0195 
0196     /*
0197      * This is a particular slot, only used in case that digiKam will intercept O2 authentication flow,
0198      * catch all navigation from web service, and the final url whose fragment contains accessToken
0199      * and other necessary information. digiKam then parses the response to get accessToken and join back to
0200      * O2's authentication flow by calling this method.
0201      *
0202      * Facebook is a web service where this approach is used,
0203      * because the callback url is not http://127.0.0.1/            // krazy:exclude=insecurenet
0204      */
0205     virtual void slotResponseTokenReceived(const QMap<QString, QString>& rep);
0206 
0207 protected:
0208 
0209     QNetworkAccessManager*  m_netMngr;
0210     QNetworkReply*          m_reply;
0211 
0212     State                   m_state;
0213 
0214     QSettings*              m_settings;
0215     O0SettingsStore*        m_store;
0216 
0217     QString                 m_userName;
0218 
0219     WSWizard*               m_wizard;
0220 };
0221 
0222 } // namespace DigikamGenericUnifiedPlugin
0223 
0224 #endif // DIGIKAM_WS_TALKER_H