From 0f5326a4cda82fcf2ff3fcc26b0fb45919d6a98f Mon Sep 17 00:00:00 2001 From: Mangesh-Khairnar Date: Wed, 29 Jan 2020 18:21:34 +0530 Subject: [PATCH] feat: api indexing --- .../doctype/google_indexing/__init__.py | 0 .../google_indexing/google_indexing.js | 31 +++++ .../google_indexing/google_indexing.json | 59 +++++++++ .../google_indexing/google_indexing.py | 120 ++++++++++++++++++ .../google_indexing/test_google_indexing.py | 10 ++ 5 files changed, 220 insertions(+) create mode 100644 frappe/integrations/doctype/google_indexing/__init__.py create mode 100644 frappe/integrations/doctype/google_indexing/google_indexing.js create mode 100644 frappe/integrations/doctype/google_indexing/google_indexing.json create mode 100644 frappe/integrations/doctype/google_indexing/google_indexing.py create mode 100644 frappe/integrations/doctype/google_indexing/test_google_indexing.py diff --git a/frappe/integrations/doctype/google_indexing/__init__.py b/frappe/integrations/doctype/google_indexing/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/frappe/integrations/doctype/google_indexing/google_indexing.js b/frappe/integrations/doctype/google_indexing/google_indexing.js new file mode 100644 index 0000000000..d742effd05 --- /dev/null +++ b/frappe/integrations/doctype/google_indexing/google_indexing.js @@ -0,0 +1,31 @@ +// Copyright (c) 2020, Frappe Technologies and contributors +// For license information, please see license.txt + +frappe.ui.form.on('Google Indexing', { + refresh: function(frm) { + if (!frm.doc.enable) { + frm.dashboard.set_headline(__("To use Google API Indexing, enable {0}.", [`${__('Google Settings')}`])); + } + }, + + authorize_api_indexing_access: function(frm) { + let reauthorize = 0; + if(frm.doc.authorization_code) { + reauthorize = 1; + } + + frappe.call({ + method: "frappe.integrations.doctype.google_indexing.google_indexing.authorize_access", + args: { + "g_contact": frm.doc.name, + "reauthorize": reauthorize + }, + callback: function(r) { + if(!r.exc) { + frm.save(); + window.open(r.message.url); + } + } + }); + } +}); \ No newline at end of file diff --git a/frappe/integrations/doctype/google_indexing/google_indexing.json b/frappe/integrations/doctype/google_indexing/google_indexing.json new file mode 100644 index 0000000000..669c46b5f1 --- /dev/null +++ b/frappe/integrations/doctype/google_indexing/google_indexing.json @@ -0,0 +1,59 @@ +{ + "actions": [], + "creation": "2020-02-03 09:24:27.503449", + "doctype": "DocType", + "editable_grid": 1, + "engine": "InnoDB", + "field_order": [ + "enable_indexing", + "authorize_api_indexing_access", + "refresh_token", + "access_token" + ], + "fields": [ + { + "default": "0", + "fieldname": "enable_indexing", + "fieldtype": "Check", + "label": "Enable Indexing" + }, + { + "fieldname": "authorize_api_indexing_access", + "fieldtype": "Button", + "label": "Authorize API Indexing Access" + }, + { + "fieldname": "refresh_token", + "fieldtype": "Password", + "label": "Refresh Token" + }, + { + "fieldname": "access_token", + "fieldtype": "Password", + "label": "Access Token" + } + ], + "issingle": 1, + "links": [], + "modified": "2020-02-03 09:24:51.894310", + "modified_by": "Administrator", + "module": "Integrations", + "name": "Google Indexing", + "owner": "Administrator", + "permissions": [ + { + "create": 1, + "delete": 1, + "email": 1, + "print": 1, + "read": 1, + "role": "System Manager", + "share": 1, + "write": 1 + } + ], + "quick_entry": 1, + "sort_field": "modified", + "sort_order": "DESC", + "track_changes": 1 +} \ No newline at end of file diff --git a/frappe/integrations/doctype/google_indexing/google_indexing.py b/frappe/integrations/doctype/google_indexing/google_indexing.py new file mode 100644 index 0000000000..f9b62ce5c8 --- /dev/null +++ b/frappe/integrations/doctype/google_indexing/google_indexing.py @@ -0,0 +1,120 @@ +# -*- coding: utf-8 -*- +# Copyright (c) 2020, 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 +import os + +from frappe import _ +from googleapiclient.errors import HttpError +from frappe.model.document import Document +from frappe.integrations.doctype.google_settings.google_settings import get_auth_url + +SCOPES = "https://www.googleapis.com/auth/indexing" + +class GoogleIndexing(Document): + def validate(self): + if not frappe.db.get_single_value("Google Settings", "enable"): + frappe.throw(_("Enable Google API in Google Settings.")) + + 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 API Indexing 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(get_auth_url(), 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(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_indexing = frappe.get_doc("Google Indexing") + + redirect_uri = get_request_site_address(True) + "?cmd=frappe.integrations.doctype.google_indexing.google_indexing.google_callback" + + if not google_drive.authorization_code or reauthorize: + return get_authentication_url(client_id=google_settings.client_id, redirect_uri=redirect_uri) + else: + try: + data = { + "code": google_indexing.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(get_auth_url(), data=data).json() + + if "refresh_token" in r: + frappe.db.set_value("Google Indexing", google_indexing.name, "refresh_token", r.get("refresh_token")) + frappe.db.commit() + + frappe.local.response["type"] = "redirect" + frappe.local.response["location"] = "/desk#Form/{0}".format(quote("Google Indexing")) + + frappe.msgprint(_("Google Indexing 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 + """ + frappe.db.set_value("Google Indexing", None, "authorization_code", code) + frappe.db.commit() + + authorize_access() + +def get_google_indexing_object(): + """ + Returns an object of Google Indexing Service + """ + google_settings = frappe.get_doc("Google Settings") + account = frappe.get_doc("Google Indexing") + + credentials_dict = { + "token": account.get_access_token(), + "refresh_token": account.get_password(fieldname="refresh_token", raise_exception=False), + "token_uri": get_auth_url(), + "client_id": google_settings.client_id, + "client_secret": google_settings.get_password(fieldname="client_secret", raise_exception=False), + "scopes": "https://www.googleapis.com/auth/indexing" + } + + credentials = google.oauth2.credentials.Credentials(**credentials_dict) + google_indexing = googleapiclient.discovery.build("indexing", "v3", credentials=credentials) + + return google_indexing, account \ No newline at end of file diff --git a/frappe/integrations/doctype/google_indexing/test_google_indexing.py b/frappe/integrations/doctype/google_indexing/test_google_indexing.py new file mode 100644 index 0000000000..6bf7dc9d3e --- /dev/null +++ b/frappe/integrations/doctype/google_indexing/test_google_indexing.py @@ -0,0 +1,10 @@ +# -*- coding: utf-8 -*- +# Copyright (c) 2020, Frappe Technologies and Contributors +# See license.txt +from __future__ import unicode_literals + +# import frappe +import unittest + +class TestGoogleIndexing(unittest.TestCase): + pass