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.
2 Answers
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.
- 498
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.
- 37,702