Implemented custom login and created functional tests for it custom_login
authorlampehe-local <henri.lampela@ixonos.com>
Mon, 10 May 2010 10:34:33 +0000 (13:34 +0300)
committerlampehe-local <henri.lampela@ixonos.com>
Mon, 10 May 2010 10:34:33 +0000 (13:34 +0300)
Reviewed by: Kaj Wallin

doc/test_cases/functionality-tests.doc
src/engine/engine.cpp
src/engine/engine.h
src/facebookservice/facebookauthentication.cpp
src/facebookservice/facebookauthentication.h
src/facebookservice/facebookcommon.h
src/situareservice/situareservice.cpp
src/src.pro
src/ui/logindialog.cpp [new file with mode: 0644]
src/ui/logindialog.h [new file with mode: 0644]

index 5fb98f4..cf43137 100644 (file)
Binary files a/doc/test_cases/functionality-tests.doc and b/doc/test_cases/functionality-tests.doc differ
index 605bc33..b125837 100644 (file)
@@ -38,18 +38,28 @@ SituareEngine::SituareEngine(QMainWindow *parent)
             m_situareService, SLOT(credentialsReady(FacebookCredentials)));
     connect(m_facebookAuthenticator, SIGNAL(credentialsReady(FacebookCredentials)),
             this, SLOT(loginOk()));
-
-    connect(m_ui, SIGNAL(requestReverseGeo()), this, SLOT(requestAddress()));
-    connect(m_situareService, SIGNAL(reverseGeoReady(QString)), m_ui, SIGNAL(reverseGeoReady(QString)));
-    connect(m_ui, SIGNAL(statusUpdate(QString,bool)), this, SLOT(requestUpdateLocation(QString,bool)));
+    connect(m_facebookAuthenticator, SIGNAL(quitSituare()),
+            this, SLOT(quitApplication()));
+
+    connect(m_ui, SIGNAL(requestReverseGeo()),
+            this, SLOT(requestAddress()));
+    connect(m_situareService, SIGNAL(reverseGeoReady(QString)),
+            m_ui, SIGNAL(reverseGeoReady(QString)));
+    connect(m_ui, SIGNAL(statusUpdate(QString,bool)),
+            this, SLOT(requestUpdateLocation(QString,bool)));
     connect(m_situareService, SIGNAL(userDataChanged(User*,QList<User*>&)),
             this, SLOT(userDataChanged(User*,QList<User*>&)));
-    connect(this, SIGNAL(userLocationReady(User*)), m_ui, SIGNAL(userLocationReady(User*)));
-    connect(this, SIGNAL(friendsLocationsReady(QList<User*>&)), m_ui, SIGNAL(friendsLocationsReady(QList<User*>&)));
-       connect(m_situareService, SIGNAL(error(QString)), this, SLOT(error(QString)));
-    connect(m_situareService, SIGNAL(updateWasSuccessful()), this, SLOT(updateWasSuccessful()));
-
-    connect(m_ui, SIGNAL(refreshUserData()), this, SLOT(refreshUserData()));
+    connect(this, SIGNAL(userLocationReady(User*)),
+            m_ui, SIGNAL(userLocationReady(User*)));
+    connect(this, SIGNAL(friendsLocationsReady(QList<User*>&)),
+            m_ui, SIGNAL(friendsLocationsReady(QList<User*>&)));
+    connect(m_situareService, SIGNAL(error(QString)),
+            this, SLOT(error(QString)));
+    connect(m_situareService, SIGNAL(updateWasSuccessful()),
+            this, SLOT(updateWasSuccessful()));
+
+    connect(m_ui, SIGNAL(refreshUserData()),
+            this, SLOT(refreshUserData()));
 
     m_facebookAuthenticator->start();
 }
@@ -58,7 +68,14 @@ SituareEngine::~SituareEngine()
 {
     qDebug() << __PRETTY_FUNCTION__;
     delete m_ui;
-    delete m_facebookAuthenticator;
+}
+
+void SituareEngine::quitApplication()
+{
+    qDebug() << __PRETTY_FUNCTION__;
+
+    m_facebookAuthenticator->setAttribute(Qt::WA_DeleteOnClose);
+    m_facebookAuthenticator->close();
 }
 
 void SituareEngine::error(const QString &error)
@@ -71,7 +88,9 @@ void SituareEngine::error(const QString &error)
 void SituareEngine::loginOk()
 {
     qDebug() << __PRETTY_FUNCTION__;
-    m_facebookAuthenticator->hide();
+
+    m_facebookAuthenticator->setAttribute(Qt::WA_DeleteOnClose);
+    m_facebookAuthenticator->close();
     m_ui->show();
     m_situareService->fetchLocations(); // request user locations
 }
index d1d2103..cb8c40b 100644 (file)
@@ -106,6 +106,12 @@ public slots:
     */
     void userDataChanged(User *user, QList<User *> &friendsList);
 
+    /**
+    * @brief Slot to intercept signal when user has cancelled login process
+    *
+    */
+    void quitApplication();
+
 /*******************************************************************************
  * SIGNALS
  ******************************************************************************/
index 55d75ba..a6aa7c8 100644 (file)
@@ -4,6 +4,7 @@
 
        Ville Tiensuu - ville.tiensuu@ixonos.com
        Kaj Wallin - kaj.wallin@ixonos.com
+       Henri Lampela - henri.lampela@ixonos.com
 
    Situare is free software; you can redistribute it and/or
    modify it under the terms of the GNU General Public License
 #include <QtGui>
 #include <QtDebug>
 #include <QDateTime>
+
+#ifdef Q_WS_MAEMO_5
+#include <QMaemo5InformationBox>
+#endif // Q_WS_MAEMO_5
+
 #include "facebookauthentication.h"
 #include "facebookcommon.h"
 
@@ -31,6 +37,13 @@ FacebookAuthentication::FacebookAuthentication(QWidget *parent)
 {
     qDebug() << __PRETTY_FUNCTION__;
 
+    m_refresh = false;
+    m_email.clear();
+    m_password.clear();
+    m_loginAttempts = 0;
+
+    m_loginDialog = new LoginDialog(this);
+
     m_webView = new QWebView;
     m_mainlayout = new QHBoxLayout;
 
@@ -40,6 +53,14 @@ FacebookAuthentication::FacebookAuthentication(QWidget *parent)
 
     connect(m_webView, SIGNAL(urlChanged(const QUrl &)),
             this, SLOT(updateCredentials(const QUrl &)));
+    connect(m_webView, SIGNAL(loadFinished(bool)),
+            this, SLOT(loadDone(bool)));
+
+    connect(m_loginDialog, SIGNAL(loginDialogDone(QString,QString)),
+            this, SLOT(loginDialogDone(QString,QString)));
+
+    connect(this, SIGNAL(loginFailure()),
+            this, SLOT(loginFailed()));
 
     readCredentials(m_loginCredentials);
 }
@@ -47,23 +68,130 @@ FacebookAuthentication::FacebookAuthentication(QWidget *parent)
 FacebookAuthentication::~FacebookAuthentication()
 {
     qDebug() << __PRETTY_FUNCTION__;
-    delete m_webView;
-    delete m_mainlayout;
+
+    if(m_webView) {
+        delete m_webView;
+        m_webView = 0;
+    }
+    if(m_mainlayout) {
+        delete m_mainlayout;
+        m_mainlayout = 0;
+    }
+    if(m_loginDialog) {
+        delete m_loginDialog;
+        m_loginDialog = 0;
+    }
+}
+
+void FacebookAuthentication::loginDialogDone(const QString &email, const QString &password)
+{
+    qDebug() << __PRETTY_FUNCTION__;
+
+    m_email.append(email);
+    m_password.append(password);
 }
 
 void FacebookAuthentication::start()
 {
     qDebug() << __PRETTY_FUNCTION__;    
     if (!verifyCredentials(m_loginCredentials)){
+        if(m_loginDialog->exec() != QDialog::Accepted) {
+            // if login dialog was canceled we need to stop processing webview            
+            // stop and disconnect m_webView;
+            m_webView->stop();
+            disconnect(m_webView, SIGNAL(loadFinished(bool)),
+                       this, SLOT(loadDone(bool)));
+            disconnect(m_webView, SIGNAL(urlChanged(const QUrl &)),
+                       this, SLOT(updateCredentials(const QUrl &)));
+
+            emit quitSituare();
+        }
         m_webView->setZoomFactor(FACEBOOK_LOGINPAGE_FONT_SIZE);
         m_webView->load(m_facebookLoginPage);
+        this->toggleProgressIndicator(true);
+        m_refresh = true;
         setCentralWidget(m_webView);
+        m_webView->hide();
         this->show();
     }
     else
         emit credentialsReady(m_loginCredentials);
 }
 
+void FacebookAuthentication::loadDone(bool done)
+{
+    qDebug() << __PRETTY_FUNCTION__;
+
+    // for the first time the login page is opened, we need to refresh it to get cookies working
+    if(m_refresh) {
+        m_webView->load(m_facebookLoginPage);
+        m_refresh = false;
+    }
+
+    if (done)
+    {
+        this->toggleProgressIndicator(false);
+        QWebFrame* frame = m_webView->page()->currentFrame();
+        if (frame!=NULL)
+        {
+            // set email box
+            QWebElementCollection emailCollection = frame->findAllElements("input[name=email]");
+
+            foreach (QWebElement element, emailCollection) {
+                element.setAttribute("value", m_email.toAscii());
+            }
+            // set password box
+            QWebElementCollection passwordCollection = frame->findAllElements("input[name=pass]");
+            foreach (QWebElement element, passwordCollection) {
+                element.setAttribute("value", m_password.toAscii());
+            }
+            // find connect button
+            QWebElementCollection buttonCollection = frame->findAllElements("input[name=login]");
+            foreach (QWebElement element, buttonCollection)
+            {
+                QPoint pos(element.geometry().center());
+
+                // send a mouse click event to the web page
+                QMouseEvent event0(QEvent::MouseButtonPress, pos, Qt::LeftButton, Qt::LeftButton, Qt::NoModifier);
+                QApplication::sendEvent(m_webView->page(), &event0);
+                QMouseEvent event1(QEvent::MouseButtonRelease, pos, Qt::LeftButton, Qt::LeftButton, Qt::NoModifier);
+                QApplication::sendEvent(m_webView->page(), &event1);
+            }
+        }
+    }
+}
+
+void FacebookAuthentication::loginFailed()
+{
+    qDebug() << __PRETTY_FUNCTION__;
+
+    m_email.clear();
+    m_password.clear();
+
+#ifdef Q_WS_MAEMO_5
+    QMaemo5InformationBox::information(this, tr("Invalid E-mail address or password"),
+                                       QMaemo5InformationBox::NoTimeout);
+
+#endif // Q_WS_MAEMO_5
+
+    if(m_loginDialog->exec() != QDialog::Accepted) {
+        // if login dialog was canceled we need to stop processing webview        
+        // stop and disconnect m_webView;
+        m_webView->stop();
+        disconnect(m_webView, SIGNAL(loadFinished(bool)),
+                   this, SLOT(loadDone(bool)));
+        disconnect(m_webView, SIGNAL(urlChanged(const QUrl &)),
+                   this, SLOT(updateCredentials(const QUrl &)));
+
+        emit quitSituare();
+    }
+    else {
+        // re-load login page for webview
+        this->toggleProgressIndicator(true);
+        m_webView->setZoomFactor(FACEBOOK_LOGINPAGE_FONT_SIZE);
+        m_webView->load(m_facebookLoginPage);
+    }
+}
 
 bool FacebookAuthentication::updateCredentials(const QUrl &url)
 {    
@@ -85,6 +213,11 @@ bool FacebookAuthentication::updateCredentials(const QUrl &url)
         if ( callbackUrl.indexOf(LOGIN_SUCCESS_REPLY) == 0 ){
             qDebug() << "login success" << endl;
 
+            disconnect(m_webView, SIGNAL(loadFinished(bool)),
+                       this, SLOT(loadDone(bool)));
+            disconnect(m_webView, SIGNAL(urlChanged(const QUrl &)),
+                       this, SLOT(updateCredentials(const QUrl &)));
+
             // let's find out session key            
             int indexOfCredential = callbackUrl.indexOf(SESSION_KEY);
 
@@ -174,7 +307,14 @@ bool FacebookAuthentication::updateCredentials(const QUrl &url)
 
         else if ( callbackUrl.indexOf(LOGIN_FAILURE_REPLY) == 0){
             qWarning() << "login failure" << endl;
-            emit loginFailure();
+            qDebug() << callbackUrl;
+            ++m_loginAttempts;
+            /* emit loginFailure for every second login attemps, since webview loads login
+               error page (loadingDone() signal is emitted) and we need to avoid that because
+               at this point we don't have new login parameters */
+            if(m_loginAttempts % 2) {
+                emit loginFailure();
+            }
         }
 
         else if ( callbackUrl.indexOf(LOGIN_PAGE) == 0){
@@ -183,18 +323,18 @@ bool FacebookAuthentication::updateCredentials(const QUrl &url)
 
         else {
             qDebug() << "totally wrong webPage";
+            // we should not get a wrong page at this point
             emit loginFailure();
-            start();
         }
     }
 
     else {
         qDebug() << " Loading of page failed invalid URL" << endl;
+        // we should not get a wrong page at this point
         emit loginFailure();
         return FALSE;
     }
 
-
     return (foundSessionKey && foundUserID && foundExpires && foundSessionSecret && foundSig);
 }
 
@@ -270,3 +410,13 @@ void FacebookAuthentication::readCredentials(FacebookCredentials &credentialsFro
 
      return loginPage;
  }
+
+ void FacebookAuthentication::toggleProgressIndicator(bool value)
+ {
+     qDebug() << __PRETTY_FUNCTION__;
+ #ifdef Q_WS_MAEMO_5
+     setAttribute(Qt::WA_Maemo5ShowProgressIndicator, value);
+ #else
+     Q_UNUSED(value);
+ #endif // Q_WS_MAEMO_5
+ }
index 785d909..c7d1a10 100644 (file)
@@ -4,6 +4,7 @@
 
        Ville Tiensuu - ville.tiensuu@ixonos.com
        Kaj Wallin - kaj.wallin@ixonos.com
+       Henri Lampela - henri.lampela@ixonos.com
 
    Situare is free software; you can redistribute it and/or
    modify it under the terms of the GNU General Public License
@@ -27,7 +28,9 @@
 #include <QtWebKit>
 #include <QString>
 #include <QLayout>
+
 #include "facebookcredentials.h"
+#include "ui/logindialog.h"
 
 /**
 * @brief FacebookAuthentication class takes care of transmitting username and password to facebook.
@@ -70,6 +73,7 @@ public:
     FacebookCredentials loginCredentials() const;
 
 public slots:
+
     /**
     * @brief Shows the m_webView and loads page that is specified in the m_facebookLoginPage
     *        variable. Specifies font size for the page.
@@ -77,6 +81,21 @@ public slots:
     */
     void start();
 
+    /**
+    * @brief Slot to intercept signal when user has pressed connect button from loginDialog
+    *
+    * @param email E-mail
+    * @param password Password
+    */
+    void loginDialogDone(const QString &email, const QString &password);
+
+    /**
+    * @brief Toggle progress indicator.
+    *
+    * @param state true if progress indicator should be shown, false otherwise
+    */
+    void toggleProgressIndicator(bool state);
+
 private: 
 
     /**
@@ -130,6 +149,19 @@ private slots:
     */
     bool updateCredentials(const QUrl & url);
 
+    /**
+    * @brief Slot to intercept signal when webview has finished loading webpage
+    *
+    * @param done Status of the loading
+    */
+    void loadDone(bool done);
+
+    /**
+    * @brief Slot to intercept signal when login has failed (loginFailure signal)
+    *
+    */
+    void loginFailed();
+
 signals:
 
     /**
@@ -147,14 +179,13 @@ signals:
     */
     void loginFailure();
 
-private:
-
     /**
-    * @brief String that contantains URL of facebook loginpage.
+    * @brief Signal that indicates when user has cancelled login process
     *
-    * @var m_facebookLoginPage
     */
-    QString m_facebookLoginPage;
+    void quitSituare();
+
+private:
 
     /**
     * @brief Dataclass that contains authorization to use facebook. Dataclass is composed of five
@@ -164,19 +195,14 @@ private:
     */
     FacebookCredentials m_loginCredentials;
 
-    /**
-    * @brief Lays out m_webView in window.
-    *
-    * @var m_mainlayout
-    */
-    QHBoxLayout *m_mainlayout;
-
-    /**
-    * @brief Shows facebook login page.
-    *
-    * @var m_webView
-    */
-    QWebView *m_webView;
+    QString m_email; ///< Placeholder for email
+    QString m_facebookLoginPage; ///< String that contantains URL of facebook loginpage.
+    int m_loginAttempts; ///< Indicates login attempts
+    LoginDialog *m_loginDialog; ///< Login dialog
+    QHBoxLayout *m_mainlayout; ///< Lays out m_webView in window.
+    QString m_password; ///< Placeholder for password
+    bool m_refresh; ///< Indicates when webpage is refreshed
+    QWebView *m_webView; ///< Shows facebook login page.
 };
 
 #endif // FACEBOOKAUTHENTICATION_H
index 601e85d..d638fb0 100644 (file)
@@ -52,10 +52,4 @@ const QString LOGIN_PAGE = "http://www.facebook.com/login.php?api_key=";
 const QString DIRECTORY_NAME = "Ixonos";
 const QString FILE_NAME = "Situare";
 
-
-
-
-
-
-
 #endif // FACEBOOKCOMMON_H
index fdd9714..f57b43f 100644 (file)
@@ -220,8 +220,12 @@ void SituareService::requestFinished(QNetworkReply *reply)
             parseUserData(replyArray);
         }
         else if(replyArray == "") {
-            qDebug() << "No error, update was successful";
-            emit updateWasSuccessful();
+            if(url.toString().contains(UPDATE_LOCATION.toAscii())) {
+                emit updateWasSuccessful();
+            }
+            else {
+                // server error!
+            }
         }
         else {
             // Street address ready
index 10c60d8..b817190 100644 (file)
@@ -35,6 +35,7 @@ SOURCES += main.cpp \
     ui/situareuser.cpp \
     engine/engine.cpp \
     ui/settingsdialog.cpp \
+    ui/logindialog.cpp \
     map/maptilerequest.cpp \
     ui/imagebutton.cpp
 HEADERS += ui/mainwindow.h \
@@ -68,18 +69,20 @@ HEADERS += ui/mainwindow.h \
     ui/situareuser.h \
     engine/engine.h \
     ui/settingsdialog.h \
+    ui/logindialog.h \
     map/maptilerequest.h \
     ui/imagebutton.h
 QT += network \
     webkit
-#DEFINES += QT_NO_DEBUG_OUTPUT
 
+#DEFINES += QT_NO_DEBUG_OUTPUT
 !maemo5 { 
     message(QJson built in)
     message(Make sure you have QJson development headers installed)
     message(install headers with: sudo apt-get install libqjson-dev)
 }
 maemo5 {
+    QT += maemo5
     message(QJson built in)
     message(Make sure you have QJson development headers installed)
     message(add: deb http://repository.maemo.org/extras-devel fremantle free non-free)
diff --git a/src/ui/logindialog.cpp b/src/ui/logindialog.cpp
new file mode 100644 (file)
index 0000000..6870c7c
--- /dev/null
@@ -0,0 +1,66 @@
+/*
+   Situare - A location system for Facebook
+   Copyright (C) 2010  Ixonos Plc. Authors:
+
+      Henri Lampela - henri.lampela@ixonos.com
+
+   Situare is free software; you can redistribute it and/or
+   modify it under the terms of the GNU General Public License
+   version 2 as published by the Free Software Foundation.
+
+   Situare 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.
+
+   You should have received a copy of the GNU General Public License
+   along with Situare; if not, write to the Free Software
+   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301,
+   USA.
+*/
+
+#include <QtGui>
+#include <QDebug>
+#include <QFormLayout>
+#include "logindialog.h"
+
+LoginDialog::LoginDialog(QWidget *parent)
+    : QDialog(parent)
+{
+    qDebug() << __PRETTY_FUNCTION__;
+
+    setWindowTitle(tr("Login to Situare with Facebook account"));
+
+    m_emailEdit = new QLineEdit();
+    m_passwordEdit = new QLineEdit();
+    m_passwordEdit->setEchoMode(QLineEdit::Password);
+
+    QGridLayout *gridLayout = new QGridLayout(this);
+    QDialogButtonBox *buttonBox = new QDialogButtonBox(Qt::Vertical);
+    QPushButton *connectButton = buttonBox->addButton(QDialogButtonBox::Ok);
+    QPushButton *cancelButton = buttonBox->addButton(QDialogButtonBox::Cancel);
+    connectButton->setText(tr("Connect"));
+
+    QFormLayout *form = new QFormLayout();
+    form->addRow(new QLabel(tr("E-mail:")), m_emailEdit);
+    form->addRow(new QLabel(tr("Password:")), m_passwordEdit);
+
+    gridLayout->addLayout(form, 0, 0, 2, 1);
+    gridLayout->addWidget(buttonBox, 0, 1, 1, 1);
+
+    connect(connectButton, SIGNAL(clicked()),
+            this, SLOT(connectPressed()));
+    connect(cancelButton, SIGNAL(clicked()),
+            this, SLOT(reject()));
+
+    setLayout(gridLayout);
+}
+
+void LoginDialog::connectPressed()
+{
+    qDebug() << __PRETTY_FUNCTION__;
+
+    emit loginDialogDone(m_emailEdit->text(), m_passwordEdit->text());
+
+    accept();
+}
diff --git a/src/ui/logindialog.h b/src/ui/logindialog.h
new file mode 100644 (file)
index 0000000..6d180e6
--- /dev/null
@@ -0,0 +1,86 @@
+/*
+   Situare - A location system for Facebook
+   Copyright (C) 2010  Ixonos Plc. Authors:
+
+      Henri Lampela - henri.lampela@ixonos.com
+
+   Situare is free software; you can redistribute it and/or
+   modify it under the terms of the GNU General Public License
+   version 2 as published by the Free Software Foundation.
+
+   Situare 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.
+
+   You should have received a copy of the GNU General Public License
+   along with Situare; if not, write to the Free Software
+   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301,
+   USA.
+*/
+
+#ifndef LOGINDIALOG_H
+#define LOGINDIALOG_H
+
+#include <QDialog>
+
+class QDialogButtonBox;
+class QLabel;
+class QLineEdit;
+class QPushButton;
+
+/**
+* @brief Custom login dialog. Email and password inserted into dialog will be forwarded to webview
+*        Email and password will not be saved.
+*
+* @author Henri Lampela
+*/
+class LoginDialog : public QDialog
+{
+    Q_OBJECT
+
+public:
+
+    /**
+    * @brief Default constructor
+    *
+    * @param parent Instance of parent widget
+    */
+    LoginDialog(QWidget *parent = 0);
+
+/*******************************************************************************
+ * MEMBER FUNCTIONS AND SLOTS
+ ******************************************************************************/
+
+private slots:
+
+    /**
+    * @brief Private slot for connect button
+    *
+    */
+    void connectPressed();
+
+signals:
+
+    /**
+    * @brief Signal for sending email and password to facebookauthentication class
+    *
+    * @param email E-mail
+    * @param password Password
+    */
+    void loginDialogDone(const QString &email, const QString &password);
+
+/*******************************************************************************
+ * DATA MEMBERS
+ ******************************************************************************/
+
+private:
+
+    QLineEdit *m_emailEdit; ///< Pointer to email line edit
+    QLineEdit *m_passwordEdit; ///< Pointer to password line edit
+
+};
+
+
+
+#endif // LOGINDIALOG_H