Take the 2-minute tour ×
Ask Ubuntu is a question and answer site for Ubuntu users and developers. It's 100% free, no registration required.

I'm writing an Ubuntu Touch application in QML. I'd like to integrate with Trello. There are two ways to log into Trello in the API, one of which is OAuth, which I plan on using. What is the best way to do this from QML? I'd prefer not to use a C++ backend, but I am willing to do so if that is the only way.

share|improve this question
    
So I know your app now integrates with Trello. Care to answer your own question? –  andrewsomething Mar 2 at 16:08
    
@andrewsomething There are two ways, one is to use OAuth and the other involves opening an external URL and having the user copy back a token. I'm using the second option, without using OAuth. If you'd find a detailed explanation useful even though I'm not using OAuth, I can do a full answer. –  iBelieve Mar 2 at 18:59

2 Answers 2

You could create an account plugin for Trello, so that a Trello account could be created from the "Online Account" panel in the System Settings. The you could use the Ubuntu.OnlineAccounts QML module to login, like this:

import QtQuick 2.0
import Ubuntu.OnlineAccounts 0.1

Rectangle {
    width: 400
    height: 300

    AccountServiceModel {
        id: accounts
        service: "trello-board"
    }
    ListView {
        id: listView
        anchors.fill: parent
        model: accounts
        delegate: Item {
            width: parent.width
            height: 60
            AccountService { 
                id: accts
                objectHandle: accountServiceHandle
                onAuthenticated: { console.log("Access token is " + reply.AccessToken) }
                onAuthenticationError: { console.log("Authentication failed, code " + error.code) }
            }    
            Text {
                anchors.fill: parent
                text: providerName + ": " + displayName
                MouseArea {
                    anchors.fill: parent
                    onClicked: accts.authenticate(null)
                }
            }
        }
    }
}

This code will get you the OAuth token. In order to create the account in the first place, you need to create the following files:

  • /usr/share/accounts/providers/trello.provider
  • /usr/share/accounts/services/trello-board.service
  • /usr/share/accounts/qml-plugins/trello/Main.qml

Given that Trello uses OAuth 1.0 like Flickr and twitter, just create the above files using the twitter or flickr version as a template, and modify them as needed (for the .service file, you could use flickr-sharing.service); in trello.provider you'll need to change the API endpoints as following:

<setting name="RequestEndpoint">https://trello.com/1/OAuthGetRequestToken</setting>
<setting name="TokenEndpoint">https://trello.com/1/OAuthGetAccessToken</setting>
<setting name="AuthorizationEndpoint">https://trello.com/1/OAuthAuthorizeToken</setting>

And of course, change the other fields (callback URL, client ID and secret) to match those you set when you registered your app with Trello. If all goes well, you'll be able to create a Trello account from the "Online Accounts" panel in the System Settings.

share|improve this answer
    
I followed your method, and it showed up in Online Accounts, but when I try to add my Trello account, I'm told that "Your browser is not supported" –  iBelieve Aug 26 '13 at 16:03
    
This also won't work in the click package world as an app won't be able to install anything outside of their namespace (e.g. /usr/share/accounts/). –  andrewsomething Aug 31 '13 at 0:19
    
This is a great start, but it doesn't really explain then how to use it. Especially for an api that requires signed requests –  Chris Wayne Sep 1 '13 at 2:54

Since the approach that mardy uses isn't actually available to apps under confinement on Ubuntu Touch, it is necessary to do the OAuth dance your self. Essentially, you need to load the login page in a WebView and then intercept the response using the onUrlChanged signal to extract the auth token. Below is an example using StackExchange's own OAuth implementation.

In OAuth.qml:

import QtQuick 2.0
import QtWebKit 3.0
import "OAuth.js" as OAuth

Rectangle {
    height: 750
    width: 500

    Text {
        id: nextState
        visible: false
        anchors.centerIn: parent
        text: "Log in successful!"
    }

    Item {
        id: stackOAuth
        property string nextState: "AuthDone"
        anchors.fill: parent
        Component.onCompleted: OAuth.checkToken()
        property string token: ""
        WebView {
            id: loginView
            visible: false
            anchors.fill: parent
            onUrlChanged: OAuth.urlChanged(url)
        }
        Rectangle {
            height: 50
            width: parent.width
            anchors.left: parent.left
            anchors.right: parent.right
            anchors.bottom: parent.bottom
            Text {
                text: loginView.url
            }
        }

        states: [
            State {
                name: "Login"
                PropertyChanges {
                    target: loginView
                    visible: true
                    url: "https://stackexchange.com/oauth/dialog"+
                         "?redirect_uri=https://stackexchange.com/oauth/login_success"+
                         "&client_id=YOUR_CLIENT_ID&scope=read_inbox"
                }
            },
            State {
                name: "AuthDone"
                PropertyChanges {
                    target: loginView
                    visible: false
                    opacity: 0
                }
                PropertyChanges {
                    target: nextState
                    visible: true
                }
            }
        ]
    }
}

Then in OAuth.js you have code to extract the token from the url and handel storing/checking it from your database:

.import QtQuick.LocalStorage 2.0 as Sql

function urlChanged(url) {
    var authorized = false;
    var mUrl = url.toString();
    var token = "";
    if (mUrl.indexOf("https://stackexchange.com") > -1) {
        var query = mUrl.substring(mUrl.indexOf('#') + 1);
        var vars = query.split("&");
        for (var i=0;i<vars.length;i++) {
            var pair = vars[i].split("=");
            if (pair[0] == "access_token") {
                authorized = true;
                token = pair[1];
                console.log("Found token: " + token)
                saveToken(token);
            }
        }
    }
    if (authorized) {
        stackOAuth.token = token;
        stackOAuth.state = "AuthDone";
    }
}

function saveToken(token) {
    console.log("Saving...")
    var db = Sql.LocalStorage.openDatabaseSync("Token", "1.0", "the token", 1);
    var dataStr = "INSERT INTO Token VALUES(?)";
    var data = [token];
    db.transaction(function(tx) {
        tx.executeSql('CREATE TABLE IF NOT EXISTS Token(token TEXT)');
        tx.executeSql(dataStr, data);
    });
}

function checkToken() {
    var db = Sql.LocalStorage.openDatabaseSync("Token", "1.0", "the token", 1);
    var dataStr = "SELECT * FROM Token";
    db.transaction(function(tx) {
        tx.executeSql('CREATE TABLE IF NOT EXISTS Token(token TEXT)');
        var rs = tx.executeSql(dataStr);
        if (rs.rows.item(0)) {
            stackOAuth.token = rs.rows.item(0).token
            stackOAuth.state = "AuthDone"
            console.log("Auth done...")
        } else {
            stackOAuth.state = "Login"
            console.log("Logging in....")
        }
    });
}

This example is (more or less) a port of the old QtQuick 1.0 example from Nokia to QtQuick 2.0.

share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.