Merge lp:~gary-wzl77/account-plugins/mcloud-plugin-lp1587282 into lp:account-plugins

Proposed by Gary.Wang
Status: Superseded
Proposed branch: lp:~gary-wzl77/account-plugins/mcloud-plugin-lp1587282
Merge into: lp:account-plugins
Diff against target: 1037 lines (+874/-2)
19 files modified
.bzrignore (+3/-0)
Makefile.am (+12/-0)
configure.ac (+25/-0)
data/providers/mcloud.provider.in.in (+29/-0)
data/providers/owncloud.provider.in.in (+13/-0)
data/providers/vk.provider.in.in (+26/-0)
debian/account-plugin-mcloud.install (+4/-0)
debian/account-plugin-owncloud.install (+3/-0)
debian/account-plugin-vk.install (+3/-0)
debian/control (+23/-0)
debian/rules (+4/-1)
qml/Makefile.am (+4/-1)
qml/mcloud/ErrorItem.qml (+48/-0)
qml/mcloud/Main.qml (+7/-0)
qml/mcloud/OAuth.qml (+283/-0)
qml/mcloud/WebView.qml (+94/-0)
qml/owncloud/Main.qml (+27/-0)
qml/owncloud/NewAccount.qml (+230/-0)
qml/vk/Main.qml (+36/-0)
To merge this branch: bzr merge lp:~gary-wzl77/account-plugins/mcloud-plugin-lp1587282
Reviewer Review Type Date Requested Status
Online Accounts Pending
Review via email: mp+296087@code.launchpad.net

This proposal has been superseded by a proposal from 2016-05-31.

Commit message

Add mcloud plugin.

Description of the change

Add mcloud plugin

Testing instructions:
1) manually install the account-plugin-mcloud package
2) download and install mcloud scope package from
   https://drive.google.com/open?id=0B2H9ECPSSfqIcGtmUEdZNHpVNVU
3) launch mcloud scope and click "Login to MCloud"

To post a comment you must log in.

Unmerged revisions

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file '.bzrignore'
2--- .bzrignore 2016-04-05 10:03:39 +0000
3+++ .bzrignore 2016-05-31 09:01:17 +0000
4@@ -28,10 +28,13 @@
5 /debian/account-plugin-google/
6 /debian/account-plugin-icons/
7 /debian/account-plugin-identica/
8+/debian/account-plugin-mcloud/
9+/debian/account-plugin-owncloud/
10 /debian/account-plugin-sina/
11 /debian/account-plugin-sohu/
12 /debian/account-plugin-tools/
13 /debian/account-plugin-twitter/
14+/debian/account-plugin-vk/
15 /debian/account-plugin-windows-live/
16 /debian/autoreconf.after
17 /debian/autoreconf.before
18
19=== modified file 'Makefile.am'
20--- Makefile.am 2016-04-05 10:46:13 +0000
21+++ Makefile.am 2016-05-31 09:01:17 +0000
22@@ -89,9 +89,12 @@
23 data/providers/identica.provider.in.in \
24 data/providers/linkedin.provider.in.in \
25 data/providers/instagram.provider.in.in \
26+ data/providers/mcloud.provider.in.in \
27+ data/providers/owncloud.provider.in.in \
28 data/providers/sina.provider.in.in \
29 data/providers/sohu.provider.in.in \
30 data/providers/twitter.provider.in.in \
31+ data/providers/vk.provider.in.in \
32 data/providers/windows-live.provider.in.in
33
34 providers_DATA = \
35@@ -132,6 +135,15 @@
36 data/webkit-options/login.live.com.conf \
37 data/webkit-options/www.linkedin.com.conf
38
39+# Temporary until these bugs are fixed:
40+# https://bugs.launchpad.net/bugs/1567908
41+# https://bugs.launchpad.net/bugs/1571587
42+iconsdir = $(datadir)/icons/hicolor/32x32/apps
43+dist_icons_DATA = \
44+ data/icons/mcloud.png \
45+ data/icons/owncloud.png \
46+ data/icons/vk.png
47+
48 dist_bin_SCRIPTS = \
49 tools/account-console
50
51
52=== modified file 'configure.ac'
53--- configure.ac 2016-04-05 10:03:39 +0000
54+++ configure.ac 2016-05-31 09:01:17 +0000
55@@ -228,6 +228,28 @@
56 AC_SUBST(SOHU_CLIENT_ID, ["$sohu_client_id"])
57 AC_SUBST(SOHU_CLIENT_SECRET, ["$sohu_client_secret"])
58
59+# Set Mcloud client id/secret
60+AC_ARG_WITH(mcloud-client-id,
61+ [AS_HELP_STRING([--with-mcloud-client-id],
62+ [Mcloud client id])],
63+ [mcloud_client_id=$withval],
64+ [mcloud_client_id="APP1ZtqoN3R0002"])
65+AC_ARG_WITH(mcloud-client-secret,
66+ [AS_HELP_STRING([--with-mcloud-client-secret],
67+ [Mcloud client secret])],
68+ [mcloud_client_secret=$withval],
69+ [mcloud_client_secret="A70EFCDC91456349E7FDECF0A33574AC"])
70+AC_SUBST(MCLOUD_CLIENT_ID, ["$mcloud_client_id"])
71+AC_SUBST(MCLOUD_CLIENT_SECRET, ["$mcloud_client_secret"])
72+
73+# Set VK client id
74+AC_ARG_WITH(vk-client-id,
75+ [AS_HELP_STRING([--with-vk-client-id],
76+ [VK client ID])],
77+ [vk_client_id=$withval],
78+ [vk_client_id="5404010"])
79+AC_SUBST(VK_CLIENT_ID, ["$vk_client_id"])
80+
81 # Set Windows Live client id
82 AC_ARG_WITH(windows-live-client-id,
83 [AS_HELP_STRING([--with-windows-live-client-id],
84@@ -244,9 +266,12 @@
85 data/providers/identica.provider.in
86 data/providers/linkedin.provider.in
87 data/providers/instagram.provider.in
88+ data/providers/mcloud.provider.in
89+ data/providers/owncloud.provider.in
90 data/providers/sina.provider.in
91 data/providers/sohu.provider.in
92 data/providers/twitter.provider.in
93+ data/providers/vk.provider.in
94 data/providers/windows-live.provider.in
95 Makefile
96 po/Makefile.in
97
98=== added directory 'data/icons'
99=== added file 'data/icons/mcloud.png'
100Binary files data/icons/mcloud.png 1970-01-01 00:00:00 +0000 and data/icons/mcloud.png 2016-05-31 09:01:17 +0000 differ
101=== added file 'data/icons/owncloud.png'
102Binary files data/icons/owncloud.png 1970-01-01 00:00:00 +0000 and data/icons/owncloud.png 2016-05-31 09:01:17 +0000 differ
103=== added file 'data/icons/vk.png'
104Binary files data/icons/vk.png 1970-01-01 00:00:00 +0000 and data/icons/vk.png 2016-05-31 09:01:17 +0000 differ
105=== added file 'data/providers/mcloud.provider.in.in'
106--- data/providers/mcloud.provider.in.in 1970-01-01 00:00:00 +0000
107+++ data/providers/mcloud.provider.in.in 2016-05-31 09:01:17 +0000
108@@ -0,0 +1,29 @@
109+<?xml version="1.0" encoding="UTF-8"?>
110+<provider id="mcloud">
111+ <name>MCloud</name>
112+ <icon>mcloud</icon>
113+ <translations>MCloud</translations>
114+ <domains>.*10086\.cn</domains>
115+ <plugin>generic-oauth</plugin>
116+ <single-account>true</single-account>
117+ <template>
118+ <group name="auth">
119+ <setting name="method">oauth2</setting>
120+ <setting name="mechanism">user_agent</setting>
121+ <group name="oauth2">
122+ <group name="user_agent">
123+ <setting name="Host">caiyun.feixin.10086.cn</setting>
124+ <setting name="AuthPath">authorize.jsp</setting>
125+ <setting name="TokenPath">access_token</setting>
126+ <setting name="RedirectUri">http://developer.ubuntu.com/en/</setting>
127+ <setting name="ResponseType">code</setting>
128+ <setting name="ClientId">@MCLOUD_CLIENT_ID@</setting>
129+ <setting type="as" name="Scope">['nd_cloud']</setting>
130+ <setting name="ForceClientAuthViaRequestBody" type="b">true</setting>
131+ <setting name="DisableStateParameter" type="b">true</setting>
132+ <setting type="as" name="AllowedSchemes">['https', 'http']</setting>
133+ </group>
134+ </group>
135+ </group>
136+ </template>
137+</provider>
138
139=== added file 'data/providers/owncloud.provider.in.in'
140--- data/providers/owncloud.provider.in.in 1970-01-01 00:00:00 +0000
141+++ data/providers/owncloud.provider.in.in 2016-05-31 09:01:17 +0000
142@@ -0,0 +1,13 @@
143+<?xml version="1.0" encoding="UTF-8"?>
144+<provider id="owncloud">
145+ <name>ownCloud</name>
146+ <icon>owncloud.png</icon>
147+ <translations>account-plugins</translations>
148+
149+ <template>
150+ <group name="auth">
151+ <setting name="method">password</setting>
152+ <setting name="mechanism">password</setting>
153+ </group>
154+ </template>
155+</provider>
156
157=== added file 'data/providers/vk.provider.in.in'
158--- data/providers/vk.provider.in.in 1970-01-01 00:00:00 +0000
159+++ data/providers/vk.provider.in.in 2016-05-31 09:01:17 +0000
160@@ -0,0 +1,26 @@
161+<?xml version="1.0" encoding="UTF-8"?>
162+<provider id="vk">
163+ <name>VKontakte</name>
164+ <icon>vk</icon>
165+ <translations>account-plugins</translations>
166+ <domains>.*vk\.com</domains>
167+
168+ <template>
169+ <group name="auth">
170+ <setting name="method">oauth2</setting>
171+ <setting name="mechanism">user_agent</setting>
172+ <group name="oauth2">
173+ <group name="user_agent">
174+ <setting name="Host">oauth.vk.com</setting>
175+ <setting name="AuthPath">authorize</setting>
176+ <setting name="TokenPath">access_token</setting>
177+ <setting name="RedirectUri">https://oauth.vk.com/blank.html</setting>
178+ <setting name="ResponseType">token</setting>
179+ <setting name="ClientId">@VK_CLIENT_ID@</setting>
180+ <setting type="as" name="Scope">['offline']</setting>
181+ <setting type="s" name="v">5.50</setting>
182+ </group>
183+ </group>
184+ </group>
185+ </template>
186+</provider>
187
188=== added file 'debian/account-plugin-mcloud.install'
189--- debian/account-plugin-mcloud.install 1970-01-01 00:00:00 +0000
190+++ debian/account-plugin-mcloud.install 2016-05-31 09:01:17 +0000
191@@ -0,0 +1,4 @@
192+usr/share/accounts/providers/mcloud.provider
193+usr/share/accounts/qml-plugins/mcloud/*.qml
194+usr/share/icons/hicolor/32x32/apps/mcloud.png
195+
196
197=== added file 'debian/account-plugin-owncloud.install'
198--- debian/account-plugin-owncloud.install 1970-01-01 00:00:00 +0000
199+++ debian/account-plugin-owncloud.install 2016-05-31 09:01:17 +0000
200@@ -0,0 +1,3 @@
201+usr/share/accounts/providers/owncloud.provider
202+usr/share/accounts/qml-plugins/owncloud/*.qml
203+usr/share/icons/hicolor/32x32/apps/owncloud.png
204
205=== added file 'debian/account-plugin-vk.install'
206--- debian/account-plugin-vk.install 1970-01-01 00:00:00 +0000
207+++ debian/account-plugin-vk.install 2016-05-31 09:01:17 +0000
208@@ -0,0 +1,3 @@
209+usr/share/accounts/providers/vk.provider
210+usr/share/accounts/qml-plugins/vk/Main.qml
211+usr/share/icons/hicolor/32x32/apps/vk.png
212
213=== modified file 'debian/control'
214--- debian/control 2016-04-05 10:52:46 +0000
215+++ debian/control 2016-05-31 09:01:17 +0000
216@@ -144,6 +144,29 @@
217 Description: GNOME Control Center account plugin for single signon - Instagram
218 GNOME Control Center account plugins for single signon
219
220+Package: account-plugin-mcloud
221+Architecture: all
222+Depends: ${misc:Depends},
223+ ubuntu-system-settings-online-accounts,
224+Description: Account plugin for online accounts - mCloud
225+ Online Accounts plugin provide the user interface to create accounts for
226+ third party services.
227+
228+Package: account-plugin-owncloud
229+Architecture: all
230+Depends: ${misc:Depends},
231+ ubuntu-system-settings-online-accounts,
232+Description: Account plugin for online accounts - ownCloud
233+ Online Accounts plugin provide the user interface to create accounts for
234+ third party services.
235+
236+Package: account-plugin-vk
237+Architecture: all
238+Depends: ${misc:Depends},
239+ libaccount-plugin-generic-oauth | ubuntu-system-settings-online-accounts,
240+Description: GNOME Control Center account plugin for single signon - VKontakte
241+ GNOME Control Center account plugins for single signon
242+
243 Package: account-plugin-tools
244 Architecture: all
245 Depends: ${misc:Depends},
246
247=== modified file 'debian/rules'
248--- debian/rules 2015-07-23 14:10:26 +0000
249+++ debian/rules 2016-05-31 09:01:17 +0000
250@@ -21,7 +21,10 @@
251 --with-linkedin-consumer-key="34gnzrg96iq5" \
252 --with-linkedin-consumer-secret="BazRki2LE8eZtcqh" \
253 --with-instagram-client-id="01c3df41a2274a14882adea8e8ebbd46" \
254- --with-instagram-client-secret="4751ccdc39c648719ea83cfb1c866c26"
255+ --with-instagram-client-secret="4751ccdc39c648719ea83cfb1c866c26" \
256+ --with-mcloud-client-id="APP1ZtqoN3R0002" \
257+ --with-mcloud-client-secret="A70EFCDC91456349E7FDECF0A33574AC" \
258+ --with-vk-client-id="5402699"
259
260 override_dh_install:
261 rm -f debian/*/usr/lib/*/*/*.la
262
263=== modified file 'qml/Makefile.am'
264--- qml/Makefile.am 2013-06-07 11:56:25 +0000
265+++ qml/Makefile.am 2016-05-31 09:01:17 +0000
266@@ -2,4 +2,7 @@
267 facebook/Main.qml \
268 flickr/Main.qml \
269 google/Main.qml \
270- twitter/Main.qml
271+ owncloud/Main.qml \
272+ owncloud/NewAccount.qml \
273+ twitter/Main.qml \
274+ vk/Main.qml
275
276=== added directory 'qml/mcloud'
277=== added file 'qml/mcloud/ErrorItem.qml'
278--- qml/mcloud/ErrorItem.qml 1970-01-01 00:00:00 +0000
279+++ qml/mcloud/ErrorItem.qml 2016-05-31 09:01:17 +0000
280@@ -0,0 +1,48 @@
281+/*
282+ * Copyright (C) 2015 Canonical Ltd.
283+ *
284+ * Contact: Alberto Mardegan <alberto.mardegan@canonical.com>
285+ *
286+ * This program is free software: you can redistribute it and/or modify it
287+ * under the terms of the GNU General Public License version 3, as published
288+ * by the Free Software Foundation.
289+ *
290+ * This program is distributed in the hope that it will be useful, but
291+ * WITHOUT ANY WARRANTY; without even the implied warranties of
292+ * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
293+ * PURPOSE. See the GNU General Public License for more details.
294+ *
295+ * You should have received a copy of the GNU General Public License along
296+ * with this program. If not, see <http://www.gnu.org/licenses/>.
297+ */
298+
299+import QtQuick 2.0
300+import Ubuntu.Components 0.1
301+import Ubuntu.Components.ListItems 0.1 as ListItem
302+
303+Item {
304+ id: root
305+
306+ signal retryRequested()
307+
308+ Column {
309+ anchors {
310+ verticalCenter: parent.verticalCenter
311+ left: parent.left; right: parent.right
312+ }
313+ spacing: units.gu(2)
314+
315+ Label {
316+ anchors { left: parent.left; right: parent.right }
317+ text: i18n.dtr("ubuntu-system-settings-online-accounts", "This service is not available right now. Try again later.")
318+ wrapMode: Text.WordWrap
319+ horizontalAlignment: Text.AlignHCenter
320+ }
321+
322+ Button {
323+ anchors.horizontalCenter: parent.horizontalCenter
324+ text: i18n.dtr("ubuntu-system-settings-online-accounts", "Try Again")
325+ onClicked: root.retryRequested()
326+ }
327+ }
328+}
329
330=== added file 'qml/mcloud/Main.qml'
331--- qml/mcloud/Main.qml 1970-01-01 00:00:00 +0000
332+++ qml/mcloud/Main.qml 2016-05-31 09:01:17 +0000
333@@ -0,0 +1,7 @@
334+import Ubuntu.OnlineAccounts.Plugin 1.0
335+import "." as Local
336+
337+OAuthMain {
338+ creationComponent: Local.OAuth {
339+ }
340+}
341
342=== added file 'qml/mcloud/OAuth.qml'
343--- qml/mcloud/OAuth.qml 1970-01-01 00:00:00 +0000
344+++ qml/mcloud/OAuth.qml 2016-05-31 09:01:17 +0000
345@@ -0,0 +1,283 @@
346+/*
347+ * Copyright (C) 2013-2016 Canonical Ltd.
348+ *
349+ * Contact: Alberto Mardegan <alberto.mardegan@canonical.com>
350+ *
351+ * This program is free software: you can redistribute it and/or modify it
352+ * under the terms of the GNU General Public License version 3, as published
353+ * by the Free Software Foundation.
354+ *
355+ * This program is distributed in the hope that it will be useful, but
356+ * WITHOUT ANY WARRANTY; without even the implied warranties of
357+ * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
358+ * PURPOSE. See the GNU General Public License for more details.
359+ *
360+ * You should have received a copy of the GNU General Public License along
361+ * with this program. If not, see <http://www.gnu.org/licenses/>.
362+ */
363+
364+import QtQuick 2.0
365+import Ubuntu.Components 1.3
366+import Ubuntu.Components.ListItems 1.3 as ListItem
367+import Ubuntu.Components.Popups 1.3
368+import Ubuntu.OnlineAccounts 0.1
369+import Ubuntu.OnlineAccounts.Plugin 1.0
370+
371+Item {
372+ id: root
373+
374+ /* To override the parameters coming from the .provider file: */
375+ property variant authenticationParameters: {}
376+ /* To override the default access control list: */
377+ property variant accessControlList: ["unconfined"]
378+
379+ property variant authReply
380+ property bool isNewAccount: false
381+ property variant __account: account
382+ property bool __isAuthenticating: false
383+ property alias globalAccountService: globalAccountSettings
384+ property bool loading: loader.status == Loader.Null || loader.status == Loader.Loading
385+
386+ signal authenticated(variant reply)
387+ signal authenticationError(variant error)
388+ signal finished
389+
390+ anchors.fill: parent
391+
392+ Component.onCompleted: {
393+ isNewAccount = (account.accountId === 0)
394+ enableAccount()
395+ authenticate()
396+ }
397+
398+ RequestHandler {
399+ id: requestHandler
400+ onRequestChanged: {
401+ if (request) {
402+ console.log("RequestHandler captured request!")
403+ loader.setSource("WebView.qml", {
404+ "signonRequest": request
405+ })
406+ } else {
407+ console.log("Request destroyed!")
408+ loader.source = ""
409+ }
410+ }
411+ }
412+
413+ Credentials {
414+ id: creds
415+ caption: account.provider.id
416+ acl: accessControlList
417+ onCredentialsIdChanged: root.credentialsStored()
418+ }
419+
420+ AccountService {
421+ id: globalAccountSettings
422+ objectHandle: account.accountServiceHandle
423+ credentials: creds
424+ autoSync: false
425+
426+ onAuthenticated: {
427+ __isAuthenticating = false
428+ authReply = reply
429+ root.authenticated(reply)
430+ }
431+ onAuthenticationError: {
432+ __isAuthenticating = false
433+ root.authenticationError(error)
434+ }
435+ }
436+
437+ AccountServiceModel {
438+ id: accountServices
439+ includeDisabled: true
440+ account: __account.objectHandle
441+ }
442+
443+ ListItem.Base {
444+ visible: loading && !errorItem.visible
445+ height: units.gu(7)
446+ showDivider: false
447+ anchors.top: parent.top
448+
449+ Item {
450+ height: units.gu(5)
451+ width: units.gu(30)
452+ anchors.horizontalCenter: parent.horizontalCenter
453+ anchors.top: parent.top
454+ anchors.margins: units.gu(1)
455+
456+ ActivityIndicator {
457+ id: loadingIndicator
458+ anchors.verticalCenter: parent.verticalCenter
459+ anchors.left: parent.left
460+ anchors.leftMargin: units.gu(5)
461+ running: loading
462+ z: 1
463+ }
464+ Label {
465+ text: i18n.dtr("ubuntu-system-settings-online-accounts", "Loading…")
466+ anchors.verticalCenter: parent.verticalCenter
467+ anchors.left: loadingIndicator.right
468+ anchors.leftMargin: units.gu(3)
469+ }
470+ }
471+ }
472+
473+ Loader {
474+ id: loader
475+ anchors {
476+ top: parent.top
477+ left: parent.left
478+ right: parent.right
479+ bottom: Qt.inputMethod.visible ? osk.top : cancelButton.top
480+ }
481+ focus: true
482+ visible: !loading
483+ }
484+
485+ ErrorItem {
486+ id: errorItem
487+ anchors { fill: parent; margins: units.gu(4) }
488+ visible: false
489+ onRetryRequested: {
490+ root.credentialsStored()
491+ visible = false
492+ }
493+ }
494+
495+ KeyboardRectangle {
496+ id: osk
497+ }
498+
499+ ListItem.SingleControl {
500+ id: cancelButton
501+ anchors.bottom: parent.bottom
502+ showDivider: false
503+ control: Button {
504+ text: i18n.dtr("ubuntu-system-settings-online-accounts", "Cancel")
505+ width: parent.width - units.gu(4)
506+ onClicked: root.cancel()
507+ }
508+ }
509+
510+ AccountServiceModel {
511+ id: possiblyDuplicateAccounts
512+ service: "global"
513+ provider: __account.provider.id
514+ }
515+
516+ function authenticate() {
517+ console.log("Authenticating...")
518+ creds.sync()
519+ }
520+
521+ function credentialsStored() {
522+ console.log("Credentials stored, id: " + creds.credentialsId)
523+ if (creds.credentialsId == 0) return
524+ var parameters = {}
525+ parameters[requestHandler.matchKey] = requestHandler.matchId
526+ parameters["providerId"] = account.provider.id
527+ for (var p in authenticationParameters) {
528+ parameters[p] = authenticationParameters[p]
529+ }
530+ __isAuthenticating = true
531+ globalAccountSettings.authenticate(parameters)
532+ }
533+
534+ function cancel() {
535+ if (__isAuthenticating) {
536+ /* This will cause the authentication to fail, and this method will
537+ * be invoked again to delete the credentials. */
538+ globalAccountSettings.cancelAuthentication()
539+ return
540+ }
541+ if (isNewAccount && creds.credentialsId != 0) {
542+ console.log("Removing credentials...")
543+ creds.remove()
544+ creds.removed.connect(finished)
545+ } else {
546+ finished()
547+ }
548+ }
549+
550+ function enableAccount() {
551+ globalAccountSettings.updateServiceEnabled(true)
552+ }
553+
554+ function getUserName(reply, callback) {
555+ /* This should work for OAuth 1.0a; for OAuth 2.0 this function needs
556+ * to be reimplemented */
557+ if ('ScreenName' in reply) return reply.ScreenName
558+ else if ('UserId' in reply) return reply.UserId
559+ return ''
560+ }
561+
562+ function accountIsDuplicate(userName) {
563+ var model = possiblyDuplicateAccounts
564+ for (var i = 0; i < model.count; i++) {
565+ if (model.get(i, "displayName") == userName)
566+ return true
567+ }
568+ return false
569+ }
570+
571+ function __gotUserName(userName, reply) {
572+ console.log("UserName: " + userName)
573+ if (userName != '') {
574+ if (accountIsDuplicate(userName)) {
575+ var dialog = PopupUtils.open(Qt.resolvedUrl("DuplicateAccount.qml"))
576+ dialog.closed.connect(cancel)
577+ return
578+ }
579+ account.updateDisplayName(userName)
580+ }
581+ beforeSaving(reply)
582+ }
583+
584+ function saveAccount() {
585+ account.synced.connect(finished)
586+ account.sync()
587+ }
588+
589+ /* reimplement this function in plugins in order to perform some actions
590+ * before quitting the plugin */
591+ function beforeSaving(reply) {
592+ saveAccount()
593+ }
594+
595+ function __getUserNameAndSave(reply) {
596+ /* If the completeCreation function is defined, run it */
597+ if (typeof(completeCreation) == "function") {
598+ console.warn("The completeCreation method is deprecated; use getUserName() or beforeSaving() instead")
599+ completeCreation(reply)
600+ return
601+ }
602+
603+ var userName = getUserName(reply, function(name) {
604+ __gotUserName(name, reply)
605+ })
606+ if (typeof(userName) == "string") {
607+ __gotUserName(userName, reply)
608+ } else if (userName === false) {
609+ cancel()
610+ return
611+ }
612+ // otherwise (userName === true), wait for the callback to be invoked
613+ }
614+
615+ onAuthenticated: __getUserNameAndSave(reply)
616+
617+ onAuthenticationError: {
618+ console.log("Authentication error, code " + error.code)
619+ if (error.code == AccountService.NetworkError) {
620+ console.log("Network error")
621+ errorItem.visible = true
622+ return
623+ }
624+ root.cancel()
625+ }
626+
627+ onFinished: loading = false
628+}
629
630=== added file 'qml/mcloud/WebView.qml'
631--- qml/mcloud/WebView.qml 1970-01-01 00:00:00 +0000
632+++ qml/mcloud/WebView.qml 2016-05-31 09:01:17 +0000
633@@ -0,0 +1,94 @@
634+import QtQuick 2.0
635+import Ubuntu.Components 1.1
636+import Ubuntu.Web 0.2
637+
638+WebView {
639+ id: root
640+
641+ property QtObject signonRequest
642+ readonly property string token_url: "https://ose.caiyun.feixin.10086.cn/oauthApp/OAuth2/getToken"
643+ readonly property string redirect_url: "http://developer.ubuntu.com/en/"
644+ readonly property string client_id: "APP1ZtqoN3R0002"
645+ readonly property string client_pass: "A70EFCDC91456349E7FDECF0A33574AC"
646+
647+ Component.onCompleted: {
648+ signonRequest.authenticated.connect(onAuthenticated)
649+ url = signonRequest.startUrl
650+ }
651+
652+ //1.WORKAROUND: we need to retrieve refresh token instead of access token.
653+ function fetchRefreshToken(code) {
654+ var http = new XMLHttpRequest()
655+ var body = "grant_type=authorization_code&code="+code+"&redirect_uri="+redirect_url
656+
657+ http.open("POST", token_url, true);
658+ http.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
659+ http.setRequestHeader("Authorization", "Basic " + Qt.btoa(client_id + ":" + client_pass));
660+ http.onreadystatechange = function() {
661+ if (http.readyState === 4 && http.status == 200) {
662+ var response = JSON.parse(http.responseText)
663+ //create a fake access_token with refresh token.
664+ var urlStr = redirect_url+"#access_token="+response.refresh_token
665+ var authUrl = Qt.resolvedUrl(urlStr);
666+ signonRequest.currentUrl = authUrl
667+ } else {
668+ console.log("error: " + http.status)
669+ }
670+ };
671+
672+ http.send(body);
673+ }
674+
675+ onLoadingStateChanged: {
676+ if (loading) {
677+ signonRequest.onLoadStarted()
678+ } else if (lastLoadSucceeded) {
679+ signonRequest.onLoadFinished(true)
680+ } else {
681+ signonRequest.onLoadFinished(false)
682+ }
683+ }
684+
685+ onUrlChanged: {
686+ //2.WORKAROUND: retrieve refresh token if code is fetched
687+ var code_pattern= new RegExp("\\?code=.*&");
688+ var urlStr = url.toString()
689+ if (code_pattern.test(urlStr)){
690+ var code = urlStr.match(/\?code=(.*)&/)[1];
691+ console.log("code::", code)
692+ fetchRefreshToken(code)
693+ } else {
694+ signonRequest.currentUrl = url
695+ }
696+ }
697+
698+ //3.WORKAROUND: Apply desktop useragent to prevent server from detecting android client,
699+ //which causes authentication failure.
700+ context: WebContext {
701+ dataPath: signonRequest ? signonRequest.rootDir : ""
702+ userAgent: "Mozilla/5.0 (Linux; Ubuntu 14.04) AppleWebKit/537.36 Chromium/35.0.1870.2 Safari/537.36"
703+ }
704+
705+ function onAuthenticated() {
706+ /* Get the cookies and set them on the request */
707+ console.log("Authenticated; getting cookies")
708+ context.cookieManager.getCookiesResponse.connect(onGotCookies)
709+ context.cookieManager.getAllCookies()
710+ visible = false
711+ }
712+
713+ function onGotCookies(requestId, cookies) {
714+ signonRequest.setCookies(cookies)
715+ }
716+
717+ /* Taken from webbrowser-app */
718+ ProgressBar {
719+ anchors.top: parent.top
720+ anchors.left: parent.left
721+ anchors.right: parent.right
722+ height: units.dp(3)
723+ showProgressPercentage: false
724+ visible: root.loading
725+ value: root.loadProgress / 100
726+ }
727+}
728
729=== added directory 'qml/owncloud'
730=== added file 'qml/owncloud/Main.qml'
731--- qml/owncloud/Main.qml 1970-01-01 00:00:00 +0000
732+++ qml/owncloud/Main.qml 2016-05-31 09:01:17 +0000
733@@ -0,0 +1,27 @@
734+import QtQuick 2.0
735+import Ubuntu.OnlineAccounts.Plugin 1.0
736+
737+Flickable {
738+ id: root
739+
740+ property int keyboardSize: Qt.inputMethod.visible ? Qt.inputMethod.keyboardRectangle.height : 0
741+ contentHeight: loader.item.height + keyboardSize
742+
743+ signal finished
744+
745+ Loader {
746+ id: loader
747+ anchors.fill: parent
748+ sourceComponent: newAccountComponent
749+
750+ Connections {
751+ target: loader.item
752+ onFinished: root.finished()
753+ }
754+ }
755+
756+ Component {
757+ id: newAccountComponent
758+ NewAccount {}
759+ }
760+}
761
762=== added file 'qml/owncloud/NewAccount.qml'
763--- qml/owncloud/NewAccount.qml 1970-01-01 00:00:00 +0000
764+++ qml/owncloud/NewAccount.qml 2016-05-31 09:01:17 +0000
765@@ -0,0 +1,230 @@
766+import QtQuick 2.0
767+import Ubuntu.Components 1.3
768+import Ubuntu.OnlineAccounts 0.1
769+
770+Item {
771+ id: root
772+
773+ signal finished
774+
775+ anchors.margins: units.gu(1)
776+ height: contents.height
777+
778+ property var __account: account
779+ property string __host: ""
780+ property bool __busy: false
781+ property string __hostError: i18n.dtr("account-plugins", "Invalid host URL")
782+
783+ Column {
784+ id: contents
785+ anchors { left: parent.left; right: parent.right }
786+ spacing: units.gu(1)
787+
788+ Label {
789+ id: errorLabel
790+ anchors { left: parent.left; right: parent.right }
791+ font.bold: true
792+ color: UbuntuColors.red
793+ wrapMode: Text.Wrap
794+ visible: !__busy && text != ""
795+ }
796+
797+ Label {
798+ anchors { left: parent.left; right: parent.right }
799+ text: i18n.dtr("account-plugins", "URL:")
800+ }
801+
802+ TextField {
803+ id: urlField
804+ anchors { left: parent.left; right: parent.right }
805+ placeholderText: i18n.dtr("account-plugins", "http://example.org")
806+ focus: true
807+ enabled: !__busy
808+
809+ inputMethodHints: Qt.ImhUrlCharactersOnly
810+ }
811+
812+ Label {
813+ anchors { left: parent.left; right: parent.right }
814+ text: i18n.dtr("account-plugins", "Username:")
815+ }
816+
817+ TextField {
818+ id: usernameField
819+ anchors { left: parent.left; right: parent.right }
820+ placeholderText: i18n.dtr("account-plugins", "Your username")
821+ enabled: !__busy
822+ inputMethodHints: Qt.ImhNoAutoUppercase + Qt.ImhNoPredictiveText + Qt.ImhPreferLowercase
823+
824+ KeyNavigation.tab: passwordField
825+ }
826+
827+ Label {
828+ anchors { left: parent.left; right: parent.right }
829+ text: i18n.dtr("account-plugins", "Password:")
830+ }
831+
832+ TextField {
833+ id: passwordField
834+ anchors { left: parent.left; right: parent.right }
835+ placeholderText: i18n.dtr("account-plugins", "Your password")
836+ echoMode: TextInput.Password
837+ enabled: !__busy
838+
839+ inputMethodHints: Qt.ImhSensitiveData
840+ Keys.onReturnPressed: login()
841+ }
842+
843+ Row {
844+ id: buttons
845+ anchors { left: parent.left; right: parent.right }
846+ height: units.gu(5)
847+ spacing: units.gu(1)
848+ Button {
849+ id: btnCancel
850+ text: i18n.dtr("account-plugins", "Cancel")
851+ height: parent.height
852+ width: (parent.width / 2) - 0.5 * parent.spacing
853+ onClicked: finished()
854+ }
855+ Button {
856+ id: btnContinue
857+ text: i18n.dtr("account-plugins", "Continue")
858+ color: UbuntuColors.green
859+ height: parent.height
860+ width: (parent.width / 2) - 0.5 * parent.spacing
861+ onClicked: login()
862+ enabled: !__busy
863+ }
864+ }
865+ }
866+
867+ ActivityIndicator {
868+ anchors.centerIn: parent
869+ running: __busy
870+ }
871+
872+ Credentials {
873+ id: creds
874+ caption: account.provider.id
875+ acl: [ "unconfined" ]
876+ storeSecret: true
877+ onCredentialsIdChanged: root.credentialsStored()
878+ }
879+
880+ AccountService {
881+ id: globalAccountSettings
882+ objectHandle: account.accountServiceHandle
883+ autoSync: false
884+ }
885+
886+ function login() {
887+ __host = cleanUrl(urlField.text)
888+ var username = usernameField.text
889+ var password = passwordField.text
890+
891+ errorLabel.text = ""
892+ __busy = true
893+ var host = __host
894+ var tryHttp = false
895+ if (__host.indexOf("http") != 0) {
896+ host = "https://" + __host
897+ tryHttp = true
898+ }
899+
900+ checkAccount(host, username, password, function cb(success) {
901+ console.log("callback called: " + success)
902+ if (success) {
903+ saveData(host, username, password)
904+ } else if (tryHttp) {
905+ host = "http://" + __host
906+ tryHttp = false
907+ checkAccount(host, username, password, cb)
908+ } else {
909+ __busy = false
910+ }
911+ })
912+ }
913+
914+ function saveData(host, username, password) {
915+ __host = host
916+ var strippedHost = __host.replace(/^https?:\/\//, '')
917+ account.updateDisplayName(username + '@' + strippedHost)
918+ creds.userName = username
919+ creds.secret = password
920+ creds.sync()
921+ }
922+
923+ function findChild(node, tagName) {
924+ if (!node) return node;
925+ var children = node.childNodes
926+ for (var i = 0; i < children.length; i++) {
927+ if (children[i].nodeName == tagName) {
928+ return children[i]
929+ }
930+ }
931+ return null
932+ }
933+
934+ function checkAccount(host, username, password, callback) {
935+ console.log("Trying host " + host + " as " + username + ':' + password)
936+ var request = new XMLHttpRequest();
937+ request.onreadystatechange = function() {
938+ if (request.readyState === XMLHttpRequest.DONE) {
939+ console.log("response: " + request.responseText)
940+ if (request.status == 200) {
941+ var root = request.responseXML ? request.responseXML.documentElement : null
942+ var metaElement = findChild(root, "meta")
943+ var statusElement = findChild(metaElement, "status")
944+ if (statusElement && statusElement.childNodes.length > 0 &&
945+ statusElement.childNodes[0].nodeValue == "ok") {
946+ callback(true)
947+ } else {
948+ var statusCodeElement = findChild(metaElement, "statuscode")
949+ var statusCode = (statusCodeElement && statusCodeElement.childNodes.length > 0) ?
950+ statusCodeElement.childNodes[0].nodeValue : "999"
951+ if (statusCode == "999") {
952+ showError(__hostError)
953+ } else {
954+ showError(i18n.dtr("account-plugins", "Invalid username or password"))
955+ }
956+ callback(false)
957+ }
958+ } else {
959+ showError(__hostError)
960+ callback(false)
961+ }
962+ }
963+ }
964+ request.open("POST", host + "/ocs/v1.php/person/check", true);
965+ request.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
966+ var body = "login=" + username + "&password=" + password
967+ request.send(body);
968+ }
969+
970+ function showError(message) {
971+ if (!errorLabel.text) errorLabel.text = message
972+ }
973+
974+ function credentialsStored() {
975+ console.log("Credentials stored, id: " + creds.credentialsId)
976+ if (creds.credentialsId == 0) return
977+
978+ globalAccountSettings.updateServiceEnabled(true)
979+ globalAccountSettings.credentials = creds
980+ globalAccountSettings.updateSettings({
981+ "host": __host
982+ })
983+ account.synced.connect(finished)
984+ account.sync()
985+ __busy = false
986+ }
987+
988+ // check host url for http
989+ function cleanUrl(url) {
990+ var host = url.trim()
991+ // if the user typed trailing '/' or "index.php", strip that
992+ return host.replace(/\/(index.php)?\/*$/, '')
993+ }
994+
995+}
996
997=== added directory 'qml/vk'
998=== added file 'qml/vk/Main.qml'
999--- qml/vk/Main.qml 1970-01-01 00:00:00 +0000
1000+++ qml/vk/Main.qml 2016-05-31 09:01:17 +0000
1001@@ -0,0 +1,36 @@
1002+import Ubuntu.OnlineAccounts.Plugin 1.0
1003+
1004+OAuthMain {
1005+ creationComponent: OAuth {
1006+ function completeCreation(reply) {
1007+ console.log("Access token: " + reply.AccessToken)
1008+ var http = new XMLHttpRequest()
1009+ var url = "https://api.vk.com/method/users.get?access_token=" + reply.AccessToken + "&fields=nickname,first_name,last_name";
1010+ http.open("GET", url, true);
1011+ http.onreadystatechange = function() {
1012+ if (http.readyState === 4){
1013+ if (http.status == 200) {
1014+ console.log("ok")
1015+ console.log("response text: " + http.responseText)
1016+ var response = JSON.parse(http.responseText)
1017+ if (response.response && response.response.length > 0) {
1018+ var data = response.response[0]
1019+ var name = data.first_name + " " + data.last_name
1020+ if (data.nickname) {
1021+ name += " (" + data.nickname + ")"
1022+ }
1023+ account.updateDisplayName(name)
1024+ }
1025+ account.synced.connect(finished)
1026+ account.sync()
1027+ } else {
1028+ console.log("error: " + http.status)
1029+ cancel()
1030+ }
1031+ }
1032+ };
1033+
1034+ http.send(null);
1035+ }
1036+ }
1037+}

Subscribers

People subscribed via source and target branches