feat: google drive initial bringup

This commit is contained in:
Himanshu Warekar 2019-08-09 22:13:39 +05:30
parent f1b3f58806
commit a23dc0a749
9 changed files with 332 additions and 3 deletions

View file

@ -76,7 +76,7 @@ def get_bootinfo():
bootinfo.calendars = sorted(frappe.get_hooks("calendars"))
bootinfo.treeviews = frappe.get_hooks("treeviews") or []
bootinfo.lang_dict = get_lang_dict()
bootinfo.gsuite_enabled = get_gsuite_status()
bootinfo.google_drive_enabled = get_google_drive_status()
bootinfo.success_action = get_success_action()
bootinfo.update(get_email_accounts(user=frappe.session.user))
bootinfo.energy_points_enabled = is_energy_point_enabled()
@ -258,8 +258,8 @@ def get_unseen_notes():
(select user from `tabNote Seen By` nsb
where nsb.parent=`tabNote`.name)''', (frappe.utils.now(), frappe.session.user), as_dict=True)
def get_gsuite_status():
return (frappe.get_value('Gsuite Settings', None, 'enable') == '1')
def get_google_drive_status():
return True if frappe.db.exists("Google Drive", {"enable": 1}) else False
def get_success_action():
return frappe.get_all("Success Action", fields=["*"])

View file

@ -0,0 +1,30 @@
// Copyright (c) 2019, Frappe Technologies and contributors
// For license information, please see license.txt
frappe.ui.form.on('Google Drive', {
refresh: function(frm) {
if (frm.is_new()) {
frm.dashboard.set_headline(__("To use Google Drive, enable <a href='#Form/Google Settings'>Google Settings</a>."));
}
},
authorize_google_drive_access: function(frm) {
let reauthorize = 0;
if(frm.doc.authorization_code) {
reauthorize = 1;
}
frappe.call({
method: "frappe.integrations.doctype.google_drive.google_drive.authorize_access",
args: {
"g_drive": frm.doc.name,
"reauthorize": reauthorize
},
callback: function(r) {
if(!r.exc) {
frm.save();
window.open(r.message.url);
}
}
});
}
});

View file

@ -0,0 +1,94 @@
{
"autoname": "format:{folder_name}-{reference_doctype}",
"creation": "2019-08-08 13:16:06.783138",
"doctype": "DocType",
"engine": "InnoDB",
"field_order": [
"enable",
"sb_00",
"user",
"folder_name",
"authorize_google_drive_access",
"authorization_code",
"refresh_token"
],
"fields": [
{
"default": "0",
"fieldname": "enable",
"fieldtype": "Check",
"label": "Enable"
},
{
"depends_on": "enable",
"fieldname": "sb_00",
"fieldtype": "Section Break",
"label": "Google Drive"
},
{
"fieldname": "user",
"fieldtype": "Link",
"in_list_view": 1,
"label": "User",
"options": "User",
"reqd": 1
},
{
"depends_on": "eval:!doc.__islocal",
"fieldname": "authorize_google_drive_access",
"fieldtype": "Button",
"label": "Authorize Google Drive Access"
},
{
"fieldname": "folder_name",
"fieldtype": "Data",
"in_list_view": 1,
"label": "Folder Name",
"reqd": 1,
"set_only_once": 1,
"unique": 1
},
{
"fieldname": "authorization_code",
"fieldtype": "Password",
"label": "Authorization Code"
},
{
"fieldname": "refresh_token",
"fieldtype": "Password",
"label": "Refresh Token"
}
],
"modified": "2019-08-09 18:20:58.169056",
"modified_by": "Administrator",
"module": "Integrations",
"name": "Google Drive",
"owner": "Administrator",
"permissions": [
{
"create": 1,
"delete": 1,
"email": 1,
"print": 1,
"read": 1,
"role": "System Manager",
"share": 1,
"write": 1
},
{
"create": 1,
"delete": 1,
"email": 1,
"export": 1,
"print": 1,
"read": 1,
"report": 1,
"role": "All",
"share": 1,
"write": 1
}
],
"sort_field": "modified",
"sort_order": "ASC",
"track_changes": 1
}

View file

@ -0,0 +1,133 @@
# -*- coding: utf-8 -*-
# Copyright (c) 2019, Frappe Technologies and contributors
# For license information, please see license.txt
from __future__ import unicode_literals
import frappe
import requests
import googleapiclient.discovery
import google.oauth2.credentials
from frappe import _
from frappe.model.document import Document
from frappe.utils import get_request_site_address
from six.moves.urllib.parse import quote
from apiclient.http import MediaFileUpload
SCOPES = "https://www.googleapis.com/auth/drive"
class GoogleDrive(Document):
def get_access_token(self):
google_settings = frappe.get_doc("Google Settings")
if not google_settings.enable:
frappe.throw(_("Google Integration is disabled."))
if not self.refresh_token:
button_label = frappe.bold(_("Allow Google Drive Access"))
raise frappe.ValidationError(_("Click on {0} to generate Refresh Token.").format(button_label))
data = {
"client_id": google_settings.client_id,
"client_secret": google_settings.get_password(fieldname="client_secret", raise_exception=False),
"refresh_token": self.get_password(fieldname="refresh_token", raise_exception=False),
"grant_type": "refresh_token",
"scope": SCOPES
}
try:
r = requests.post("https://www.googleapis.com/oauth2/v4/token", data=data).json()
except requests.exceptions.HTTPError:
button_label = frappe.bold(_("Allow Google Drive Access"))
frappe.throw(_("Something went wrong during the token generation. Click on {0} to generate a new one.").format(button_label))
return r.get("access_token")
@frappe.whitelist()
def authorize_access(g_drive, reauthorize=None):
"""
If no Authorization code get it from Google and then request for Refresh Token.
Google Contact Name is set to flags to set_value after Authorization Code is obtained.
"""
google_settings = frappe.get_doc("Google Settings")
google_drive = frappe.get_doc("Google Drive", g_drive)
redirect_uri = get_request_site_address(True) + "?cmd=frappe.integrations.doctype.google_drive.google_drive.google_callback"
if not google_drive.authorization_code or reauthorize:
frappe.cache().hset("google_drive", "google_drive", google_drive.name)
return get_authentication_url(client_id=google_settings.client_id, redirect_uri=redirect_uri)
else:
try:
data = {
"code": google_drive.authorization_code,
"client_id": google_settings.client_id,
"client_secret": google_settings.get_password(fieldname="client_secret", raise_exception=False),
"redirect_uri": redirect_uri,
"grant_type": "authorization_code"
}
r = requests.post("https://www.googleapis.com/oauth2/v4/token", data=data).json()
if "refresh_token" in r:
frappe.db.set_value("Google Drive", google_drive.name, "refresh_token", r.get("refresh_token"))
frappe.db.commit()
frappe.local.response["type"] = "redirect"
frappe.local.response["location"] = "/desk#Form/{0}/{1}".format(quote("Google Drive"), quote(google_drive.name))
frappe.msgprint(_("Google Drive has been configured."))
except Exception as e:
frappe.throw(e)
def get_authentication_url(client_id, redirect_uri):
return {
"url": "https://accounts.google.com/o/oauth2/v2/auth?access_type=offline&response_type=code&prompt=consent&client_id={}&include_granted_scopes=true&scope={}&redirect_uri={}".format(client_id, SCOPES, redirect_uri)
}
@frappe.whitelist()
def google_callback(code=None):
"""
Authorization code is sent to callback as per the API configuration
"""
google_drive = frappe.cache().hget("google_drive", "google_drive")
frappe.db.set_value("Google Drive", google_drive, "authorization_code", code)
frappe.db.commit()
authorize_access(google_drive)
def get_google_drive_object(g_drive):
"""
Returns an object of Google Drive.
"""
google_settings = frappe.get_doc("Google Settings")
account = frappe.get_doc("Google Drive", g_drive)
credentials_dict = {
"token": account.get_access_token(),
"refresh_token": account.get_password(fieldname="refresh_token", raise_exception=False),
"token_uri": "https://www.googleapis.com/oauth2/v4/token",
"client_id": google_settings.client_id,
"client_secret": google_settings.get_password(fieldname="client_secret", raise_exception=False),
"scopes": "https://www.googleapis.com/auth/drive/v3"
}
credentials = google.oauth2.credentials.Credentials(**credentials_dict)
google_drive = googleapiclient.discovery.build("drive", "v3", credentials=credentials)
return google_calendar
@frappe.whitelist()
def upload_document(doctype, docname, g_drive):
from frappe.utils.print_format import download_pdf
google_drive = get_google_drive_object(g_drive)
download_pdf(doctype=doctype, docname=docname, format="pdf")
file_metadata = {"name": frappe.local.response.filename}
media = MediaFileUpload(frappe.local.response.filename, mimetype="application/pdf")
file = google_drive.files().create(body=file_metadata, media_body=media, fields='id').execute()
# frappe.local.response.filecontent

View file

@ -0,0 +1,10 @@
# -*- coding: utf-8 -*-
# Copyright (c) 2019, Frappe Technologies and Contributors
# See license.txt
from __future__ import unicode_literals
# import frappe
import unittest
class TestGoogleDrive(unittest.TestCase):
pass

View file

@ -205,6 +205,7 @@
"public/js/frappe/ui/toolbar/toolbar.js",
"public/js/frappe/ui/toolbar/notifications.js",
"public/js/frappe/views/communication.js",
"public/js/frappe/views/google_drive_uploader.js",
"public/js/frappe/views/translation_manager.js",
"public/js/frappe/ui/sort_selector.html",

View file

@ -125,6 +125,15 @@ frappe.ui.form.Toolbar = Class.extend({
}
}
//Google Drive
if(frappe.boot.google_drive_enabled){
this.page.add_menu_item(__("Google Drive Upload"), function() {
new frappe.views.GoogleDriveUploader(me.frm);}, true);
this.print_icon = this.page.add_action_icon("fa fa-google", function() {
new frappe.views.GoogleDriveUploader(me.frm);
});
}
// email
if(frappe.model.can_email(null, me.frm) && me.frm.doc.docstatus < 2) {
this.page.add_menu_item(__("Email"), function() {

View file

@ -0,0 +1,52 @@
frappe.views.GoogleDriveUploader = Class.extend({
init: function(opts) {
$.extend(this, opts);
this.make();
},
make: function() {
let me = this;
let uploader = new frappe.ui.Dialog({
title: __("Upload File to Google Drive"),
fields: [
{
fieldtype: "Link",
fieldname: "google_drive",
options: "Google Drive",
label: __("Google Drive"),
reqd: 1,
get_query: function() {
return {
"filters": {
"owner": frappe.session.user,
}
}
}
}
],
primary_action_label: __("Submit"),
primary_action: (d) => {
frappe.show_alert({
indicator: "red",
message: __("Uploading to Google Drive.")
});
uploader.hide();
frappe.call({
method: "frappe.integrations.doctype.google_drive.google_drive.upload_document",
args: {
doctype: me.doctype,
docname: me.docname,
g_drive: d.google_drive,
},
callback: function(r) {
frappe.show_alert({
indicator: "green",
message: __("Document uploaded to Google Drive.")
});
uploader.hide();
}
})
}
});
uploader.show();
}
})