From 25a4eb07575094766111c5cca9b46f79dd1ed59f Mon Sep 17 00:00:00 2001
From: barredterra <14891507+barredterra@users.noreply.github.com>
Date: Mon, 29 Mar 2021 19:25:41 +0200
Subject: [PATCH 01/28] feat: google drive picker
---
.../google_settings/google_settings.json | 12 ++-
.../google_settings/test_google_settings.py | 10 +++
frappe/public/icons/social/google_drive.svg | 1 +
.../js/frappe/file_uploader/FileUploader.vue | 46 ++++++++++-
frappe/public/js/integrations/google_drive.js | 81 +++++++++++++++++++
5 files changed, 145 insertions(+), 5 deletions(-)
create mode 100644 frappe/integrations/doctype/google_settings/test_google_settings.py
create mode 100644 frappe/public/icons/social/google_drive.svg
create mode 100644 frappe/public/js/integrations/google_drive.js
diff --git a/frappe/integrations/doctype/google_settings/google_settings.json b/frappe/integrations/doctype/google_settings/google_settings.json
index 086c56c020..6a4f181f2d 100644
--- a/frappe/integrations/doctype/google_settings/google_settings.json
+++ b/frappe/integrations/doctype/google_settings/google_settings.json
@@ -1,4 +1,5 @@
{
+ "actions": [],
"creation": "2019-06-14 00:08:37.255003",
"doctype": "DocType",
"engine": "InnoDB",
@@ -8,7 +9,8 @@
"client_id",
"client_secret",
"sb_01",
- "api_key"
+ "api_key",
+ "app_id"
],
"fields": [
{
@@ -46,10 +48,16 @@
"fieldname": "sb_01",
"fieldtype": "Section Break",
"label": "API Key"
+ },
+ {
+ "fieldname": "app_id",
+ "fieldtype": "Data",
+ "label": "App ID"
}
],
"issingle": 1,
- "modified": "2019-08-06 22:37:41.699703",
+ "links": [],
+ "modified": "2021-03-28 22:24:05.963403",
"modified_by": "Administrator",
"module": "Integrations",
"name": "Google Settings",
diff --git a/frappe/integrations/doctype/google_settings/test_google_settings.py b/frappe/integrations/doctype/google_settings/test_google_settings.py
new file mode 100644
index 0000000000..476e772b58
--- /dev/null
+++ b/frappe/integrations/doctype/google_settings/test_google_settings.py
@@ -0,0 +1,10 @@
+# -*- coding: utf-8 -*-
+# Copyright (c) 2021, Frappe Technologies and Contributors
+# See license.txt
+from __future__ import unicode_literals
+
+# import frappe
+import unittest
+
+class TestGoogleSettings(unittest.TestCase):
+ pass
diff --git a/frappe/public/icons/social/google_drive.svg b/frappe/public/icons/social/google_drive.svg
new file mode 100644
index 0000000000..d43b4d3dbd
--- /dev/null
+++ b/frappe/public/icons/social/google_drive.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/frappe/public/js/frappe/file_uploader/FileUploader.vue b/frappe/public/js/frappe/file_uploader/FileUploader.vue
index d0b09c7593..61b87606a5 100644
--- a/frappe/public/js/frappe/file_uploader/FileUploader.vue
+++ b/frappe/public/js/frappe/file_uploader/FileUploader.vue
@@ -63,6 +63,12 @@
{{ upload_notes }}
@@ -116,6 +122,7 @@
import FilePreview from './FilePreview.vue';
import FileBrowser from './FileBrowser.vue';
import WebLink from './WebLink.vue';
+import GoogleDrive from '../../integrations/google_drive';
export default {
name: 'FileUploader',
@@ -173,8 +180,16 @@ export default {
currently_uploading: -1,
show_file_browser: false,
show_web_link: false,
+ allow_take_photo: false,
+ allow_google_drive: false
}
},
+ created() {
+ this.allow_take_photo = window.navigator.mediaDevices;
+ frappe.db.get_single_value("Google Settings", "enable").then(resp => {
+ this.allow_google_drive = Boolean(resp);
+ });
+ },
watch: {
files(newvalue, oldvalue) {
if (!this.allow_multiple && newvalue.length > 1) {
@@ -187,9 +202,6 @@ export default {
return this.files.length > 0
&& this.files.every(
file => file.total !== 0 && file.progress === file.total);
- },
- allow_take_photo() {
- return window.navigator.mediaDevices;
}
},
methods: {
@@ -408,6 +420,10 @@ export default {
form_data.append('file_url', file.file_url);
}
+ if (file.file_name) {
+ form_data.append('file_name', file.file_name);
+ }
+
if (this.doctype && this.docname) {
form_data.append('doctype', this.doctype);
form_data.append('docname', this.docname);
@@ -437,6 +453,30 @@ export default {
);
});
},
+ show_google_drive_picker() {
+ frappe.db.get_value("Google Settings", "Google Settings", ["client_id", "api_key", "app_id"]).then(resp => {
+ let dialog = cur_dialog;
+ dialog.hide();
+ let google_drive = new GoogleDrive({
+ pickerCallback: data => this.google_drive_callback(data, dialog),
+ developerKey: resp.message.api_key,
+ clientId: resp.message.client_id,
+ appId: resp.message.app_id
+ });
+ google_drive.loadPicker();
+ });
+ },
+ google_drive_callback(data, dialog) {
+ if (data.action == google.picker.Action.PICKED) {
+ // debugger;
+ this.upload_file({
+ file_url: data.docs[0].url,
+ file_name: data.docs[0].name
+ });
+ } else if (data.action == google.picker.Action.CANCEL) {
+ dialog.show();
+ }
+ },
url_to_file(url, filename, mime_type) {
return fetch(url)
.then(res => res.arrayBuffer())
diff --git a/frappe/public/js/integrations/google_drive.js b/frappe/public/js/integrations/google_drive.js
new file mode 100644
index 0000000000..9c6aea5375
--- /dev/null
+++ b/frappe/public/js/integrations/google_drive.js
@@ -0,0 +1,81 @@
+export default class GoogleDrive {
+ constructor({
+ pickerCallback,
+ developerKey,
+ clientId,
+ appId
+ } = {}) {
+ console.log('GoogleDrive constructor');
+ this.pickerCallback = pickerCallback;
+ this.pickerApiLoaded = false;
+ this.scope = ['https://www.googleapis.com/auth/drive.file'];
+ this.developerKey = developerKey;
+ this.clientId = clientId;
+ this.appId = appId;
+ }
+
+ loadPicker() {
+ // load the google API library
+ $.ajax({
+ method: "GET",
+ url: "https://apis.google.com/js/api.js",
+ dataType: "script",
+ cache: true,
+ context: this
+ }).done(function() {
+ this.loadGapi();
+ }.bind(this));
+ }
+
+ loadGapi() {
+ // load auth and picker libraries
+ if (!frappe.boot.user.google_drive_token) {
+ gapi.load('auth', function() {
+ console.log('gapi.load("auth") callback');
+ this.onAuthApiLoad();
+ }.bind(this));
+ }
+
+ gapi.load('picker', function() {
+ console.log('gapi.load("picker") callback');
+ this.onPickerApiLoad();
+ }.bind(this));
+ }
+
+ onAuthApiLoad() {
+ gapi.auth.authorize({
+ 'client_id': this.clientId,
+ 'scope': this.scope,
+ 'immediate': false
+ }, function(authResult) {
+ this.handleAuthResult(authResult);
+ }.bind(this));
+ }
+
+ handleAuthResult(authResult) {
+ if (authResult && !authResult.error) {
+ frappe.boot.user.google_drive_token = authResult.access_token;
+ this.createPicker();
+ }
+ }
+
+ onPickerApiLoad() {
+ this.pickerApiLoaded = true;
+ this.createPicker();
+ }
+
+ createPicker() {
+ // Create and render a Picker object for searching images.
+ if (this.pickerApiLoaded && frappe.boot.user.google_drive_token) {
+ var view = new google.picker.View(google.picker.ViewId.DOCS);
+ var picker = new google.picker.PickerBuilder()
+ .setAppId(this.appId)
+ .setOAuthToken(frappe.boot.user.google_drive_token)
+ .addView(view)
+ .setDeveloperKey(this.developerKey)
+ .setCallback(this.pickerCallback)
+ .build();
+ picker.setVisible(true);
+ }
+ }
+}
From 7d333dbf703001c50dc80aa0a28477b741e9b51f Mon Sep 17 00:00:00 2001
From: barredterra <14891507+barredterra@users.noreply.github.com>
Date: Mon, 29 Mar 2021 21:09:06 +0200
Subject: [PATCH 02/28] fix: scope for google picker
---
frappe/public/js/integrations/google_drive.js | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/frappe/public/js/integrations/google_drive.js b/frappe/public/js/integrations/google_drive.js
index 9c6aea5375..1c7e4dda21 100644
--- a/frappe/public/js/integrations/google_drive.js
+++ b/frappe/public/js/integrations/google_drive.js
@@ -8,7 +8,7 @@ export default class GoogleDrive {
console.log('GoogleDrive constructor');
this.pickerCallback = pickerCallback;
this.pickerApiLoaded = false;
- this.scope = ['https://www.googleapis.com/auth/drive.file'];
+ this.scope = ['https://www.googleapis.com/auth/drive.readonly'];
this.developerKey = developerKey;
this.clientId = clientId;
this.appId = appId;
From c44cecae5db1ef7231b742ca84ade406224e17d6 Mon Sep 17 00:00:00 2001
From: barredterra <14891507+barredterra@users.noreply.github.com>
Date: Mon, 29 Mar 2021 21:11:26 +0200
Subject: [PATCH 03/28] fix: remove log statements
---
frappe/public/js/integrations/google_drive.js | 3 ---
1 file changed, 3 deletions(-)
diff --git a/frappe/public/js/integrations/google_drive.js b/frappe/public/js/integrations/google_drive.js
index 1c7e4dda21..e7093fb29a 100644
--- a/frappe/public/js/integrations/google_drive.js
+++ b/frappe/public/js/integrations/google_drive.js
@@ -5,7 +5,6 @@ export default class GoogleDrive {
clientId,
appId
} = {}) {
- console.log('GoogleDrive constructor');
this.pickerCallback = pickerCallback;
this.pickerApiLoaded = false;
this.scope = ['https://www.googleapis.com/auth/drive.readonly'];
@@ -31,13 +30,11 @@ export default class GoogleDrive {
// load auth and picker libraries
if (!frappe.boot.user.google_drive_token) {
gapi.load('auth', function() {
- console.log('gapi.load("auth") callback');
this.onAuthApiLoad();
}.bind(this));
}
gapi.load('picker', function() {
- console.log('gapi.load("picker") callback');
this.onPickerApiLoad();
}.bind(this));
}
From f9dbbf69e0e89e3f36ac821994cfccb6a576f32d Mon Sep 17 00:00:00 2001
From: barredterra <14891507+barredterra@users.noreply.github.com>
Date: Mon, 29 Mar 2021 21:22:13 +0200
Subject: [PATCH 04/28] feat: better home view for google drive picker
---
frappe/public/js/integrations/google_drive.js | 5 ++++-
1 file changed, 4 insertions(+), 1 deletion(-)
diff --git a/frappe/public/js/integrations/google_drive.js b/frappe/public/js/integrations/google_drive.js
index e7093fb29a..6b9ee9d0ff 100644
--- a/frappe/public/js/integrations/google_drive.js
+++ b/frappe/public/js/integrations/google_drive.js
@@ -64,7 +64,10 @@ export default class GoogleDrive {
createPicker() {
// Create and render a Picker object for searching images.
if (this.pickerApiLoaded && frappe.boot.user.google_drive_token) {
- var view = new google.picker.View(google.picker.ViewId.DOCS);
+ var view = new google.picker.DocsView(google.picker.ViewId.DOCS)
+ .setParent('root') // show the root folder by default
+ .setIncludeFolders(true); // also show folders, not just files
+
var picker = new google.picker.PickerBuilder()
.setAppId(this.appId)
.setOAuthToken(frappe.boot.user.google_drive_token)
From 11f4edf051bf9842e58228faae2d2a349d2e763d Mon Sep 17 00:00:00 2001
From: barredterra <14891507+barredterra@users.noreply.github.com>
Date: Mon, 29 Mar 2021 21:22:37 +0200
Subject: [PATCH 05/28] feat: localize google drive picker
---
frappe/public/js/integrations/google_drive.js | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/frappe/public/js/integrations/google_drive.js b/frappe/public/js/integrations/google_drive.js
index 6b9ee9d0ff..076178046e 100644
--- a/frappe/public/js/integrations/google_drive.js
+++ b/frappe/public/js/integrations/google_drive.js
@@ -70,11 +70,13 @@ export default class GoogleDrive {
var picker = new google.picker.PickerBuilder()
.setAppId(this.appId)
+ .setDeveloperKey(this.developerKey)
.setOAuthToken(frappe.boot.user.google_drive_token)
.addView(view)
- .setDeveloperKey(this.developerKey)
+ .setLocale(frappe.boot.lang)
.setCallback(this.pickerCallback)
.build();
+
picker.setVisible(true);
}
}
From 741011085b6ba3cccc86ba3514d9deff4eb82b54 Mon Sep 17 00:00:00 2001
From: barredterra <14891507+barredterra@users.noreply.github.com>
Date: Tue, 30 Mar 2021 00:49:02 +0200
Subject: [PATCH 06/28] refactor: bind this
---
frappe/public/js/integrations/google_drive.js | 23 ++++++-------------
1 file changed, 7 insertions(+), 16 deletions(-)
diff --git a/frappe/public/js/integrations/google_drive.js b/frappe/public/js/integrations/google_drive.js
index 076178046e..06d9cbbe54 100644
--- a/frappe/public/js/integrations/google_drive.js
+++ b/frappe/public/js/integrations/google_drive.js
@@ -5,9 +5,9 @@ export default class GoogleDrive {
clientId,
appId
} = {}) {
- this.pickerCallback = pickerCallback;
- this.pickerApiLoaded = false;
this.scope = ['https://www.googleapis.com/auth/drive.readonly'];
+ this.pickerApiLoaded = false;
+ this.pickerCallback = pickerCallback;
this.developerKey = developerKey;
this.clientId = clientId;
this.appId = appId;
@@ -19,24 +19,17 @@ export default class GoogleDrive {
method: "GET",
url: "https://apis.google.com/js/api.js",
dataType: "script",
- cache: true,
- context: this
- }).done(function() {
- this.loadGapi();
- }.bind(this));
+ cache: true
+ }).done(this.loadGapi.bind(this));
}
loadGapi() {
// load auth and picker libraries
if (!frappe.boot.user.google_drive_token) {
- gapi.load('auth', function() {
- this.onAuthApiLoad();
- }.bind(this));
+ gapi.load('auth', this.onAuthApiLoad.bind(this));
}
- gapi.load('picker', function() {
- this.onPickerApiLoad();
- }.bind(this));
+ gapi.load('picker', this.onPickerApiLoad.bind(this));
}
onAuthApiLoad() {
@@ -44,9 +37,7 @@ export default class GoogleDrive {
'client_id': this.clientId,
'scope': this.scope,
'immediate': false
- }, function(authResult) {
- this.handleAuthResult(authResult);
- }.bind(this));
+ }, this.handleAuthResult.bind(this));
}
handleAuthResult(authResult) {
From a018e7b4458c028ebed29d8e889ae72f086d0479 Mon Sep 17 00:00:00 2001
From: barredterra <14891507+barredterra@users.noreply.github.com>
Date: Tue, 30 Mar 2021 01:28:12 +0200
Subject: [PATCH 07/28] refactor: rename GoogleDrive -> GoogleDrivePicker
---
frappe/public/js/frappe/file_uploader/FileUploader.vue | 4 ++--
.../integrations/{google_drive.js => google_drive_picker.js} | 2 +-
2 files changed, 3 insertions(+), 3 deletions(-)
rename frappe/public/js/integrations/{google_drive.js => google_drive_picker.js} (98%)
diff --git a/frappe/public/js/frappe/file_uploader/FileUploader.vue b/frappe/public/js/frappe/file_uploader/FileUploader.vue
index 61b87606a5..154d4e0ea1 100644
--- a/frappe/public/js/frappe/file_uploader/FileUploader.vue
+++ b/frappe/public/js/frappe/file_uploader/FileUploader.vue
@@ -122,7 +122,7 @@
import FilePreview from './FilePreview.vue';
import FileBrowser from './FileBrowser.vue';
import WebLink from './WebLink.vue';
-import GoogleDrive from '../../integrations/google_drive';
+import GoogleDrivePicker from '../../integrations/google_drive_picker';
export default {
name: 'FileUploader',
@@ -457,7 +457,7 @@ export default {
frappe.db.get_value("Google Settings", "Google Settings", ["client_id", "api_key", "app_id"]).then(resp => {
let dialog = cur_dialog;
dialog.hide();
- let google_drive = new GoogleDrive({
+ let google_drive = new GoogleDrivePicker({
pickerCallback: data => this.google_drive_callback(data, dialog),
developerKey: resp.message.api_key,
clientId: resp.message.client_id,
diff --git a/frappe/public/js/integrations/google_drive.js b/frappe/public/js/integrations/google_drive_picker.js
similarity index 98%
rename from frappe/public/js/integrations/google_drive.js
rename to frappe/public/js/integrations/google_drive_picker.js
index 06d9cbbe54..7ce9810f72 100644
--- a/frappe/public/js/integrations/google_drive.js
+++ b/frappe/public/js/integrations/google_drive_picker.js
@@ -1,4 +1,4 @@
-export default class GoogleDrive {
+export default class GoogleDrivePicker {
constructor({
pickerCallback,
developerKey,
From 144608241e9825af20c88b122a70f29d22aa5a41 Mon Sep 17 00:00:00 2001
From: barredterra <14891507+barredterra@users.noreply.github.com>
Date: Tue, 30 Mar 2021 02:20:11 +0200
Subject: [PATCH 08/28] refactor: save one API call
---
.../google_settings/google_settings.py | 22 +++++++++++++--
.../js/frappe/file_uploader/FileUploader.vue | 28 +++++++++----------
.../js/integrations/google_drive_picker.js | 8 ++++--
3 files changed, 38 insertions(+), 20 deletions(-)
diff --git a/frappe/integrations/doctype/google_settings/google_settings.py b/frappe/integrations/doctype/google_settings/google_settings.py
index ecc975235a..bd0e845977 100644
--- a/frappe/integrations/doctype/google_settings/google_settings.py
+++ b/frappe/integrations/doctype/google_settings/google_settings.py
@@ -3,11 +3,29 @@
# For license information, please see license.txt
from __future__ import unicode_literals
-# import frappe
+import frappe
from frappe.model.document import Document
class GoogleSettings(Document):
pass
def get_auth_url():
- return "https://www.googleapis.com/oauth2/v4/token"
\ No newline at end of file
+ return "https://www.googleapis.com/oauth2/v4/token"
+
+
+@frappe.whitelist(allow_guest=True)
+def get_file_picker_settings():
+ """Return all the data FileUploader needs to start the Google Drive Picker."""
+ if frappe.session.user == 'Guest':
+ return {'enabled': False}
+
+ google_settings = frappe.get_single("Google Settings")
+ if not google_settings.enable:
+ return {'enabled': False}
+
+ return {
+ 'enabled': True,
+ 'appId': google_settings.app_id,
+ 'developerKey': google_settings.api_key,
+ 'clientId': google_settings.client_id
+ }
diff --git a/frappe/public/js/frappe/file_uploader/FileUploader.vue b/frappe/public/js/frappe/file_uploader/FileUploader.vue
index 154d4e0ea1..64365cfc11 100644
--- a/frappe/public/js/frappe/file_uploader/FileUploader.vue
+++ b/frappe/public/js/frappe/file_uploader/FileUploader.vue
@@ -63,7 +63,7 @@
{{ __('Camera') }}
-