[REF]google_docs to google_drive, using oauth authentication
bzr revid: dle@openerp.com-20130627160715-ok7q82cyivirzri1
This commit is contained in:
commit
53358465b3
|
@ -36,6 +36,8 @@ class base_config_settings(osv.osv_memory):
|
|||
help="""Enable the public part of openerp, openerp becomes a public website."""),
|
||||
'module_auth_oauth': fields.boolean('Use external authentication providers, sign in with google, facebook, ...'),
|
||||
'module_base_import': fields.boolean("Allow users to import data from CSV files"),
|
||||
'module_google_drive': fields.boolean('Attach Google documents to any record',
|
||||
help="""This installs the module google_docs."""),
|
||||
}
|
||||
|
||||
def open_company(self, cr, uid, ids, context=None):
|
||||
|
|
|
@ -81,6 +81,15 @@
|
|||
</div>
|
||||
</div>
|
||||
</group>
|
||||
<group>
|
||||
<label for="id" string="Google Drive"/>
|
||||
<div name="google_drive">
|
||||
<div name="module_google_drive">
|
||||
<field name="module_google_drive" class="oe_inline"/>
|
||||
<label for="module_google_drive"/>
|
||||
</div>
|
||||
</div>
|
||||
</group>
|
||||
</form>
|
||||
</field>
|
||||
</record>
|
||||
|
|
|
@ -709,5 +709,6 @@ Andrew</field>
|
|||
eval="[ ref('msg_case18_1'), ref('msg_case18_2')], True, {}"
|
||||
/>
|
||||
|
||||
|
||||
</data>
|
||||
</openerp>
|
||||
|
|
|
@ -20,7 +20,6 @@
|
|||
##############################################################################
|
||||
|
||||
import google_base_account
|
||||
import wizard
|
||||
|
||||
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
|
||||
|
||||
|
|
|
@ -30,10 +30,9 @@ The module adds google user in res user.
|
|||
""",
|
||||
'author': 'OpenERP SA',
|
||||
'website': 'http://www.openerp.com',
|
||||
'depends': ['base'],
|
||||
'depends': ['base_setup'],
|
||||
'data': [
|
||||
'google_base_account_view.xml',
|
||||
'wizard/google_login_view.xml',
|
||||
'google_base_account_data.xml',
|
||||
],
|
||||
'demo': [],
|
||||
'installable': True,
|
||||
|
|
|
@ -19,14 +19,48 @@
|
|||
#
|
||||
##############################################################################
|
||||
|
||||
from openerp.osv import fields,osv
|
||||
|
||||
class res_users(osv.osv):
|
||||
_inherit = "res.users"
|
||||
_columns = {
|
||||
'gmail_user': fields.char('Username', size=64,),
|
||||
'gmail_password': fields.char('Password', size=64),
|
||||
}
|
||||
from openerp.osv import osv
|
||||
from openerp import SUPERUSER_ID
|
||||
from openerp.tools.translate import _
|
||||
|
||||
import urllib
|
||||
import urllib2
|
||||
import simplejson
|
||||
|
||||
|
||||
class google_service(osv.osv):
|
||||
_name = 'google.service'
|
||||
|
||||
def generate_refresh_token(self, cr, uid, service, authorization_code, context=None):
|
||||
if authorization_code:
|
||||
ir_config = self.pool['ir.config_parameter']
|
||||
client_id = ir_config.get_param(cr, SUPERUSER_ID, 'google_%s_client_id' % service)
|
||||
client_secret = ir_config.get_param(cr, SUPERUSER_ID, 'google_%s_client_secret' % service)
|
||||
redirect_uri = ir_config.get_param(cr, SUPERUSER_ID, 'google_redirect_uri')
|
||||
|
||||
#Get the Refresh Token From Google And store it in ir.config_parameter
|
||||
headers = {"Content-type": "application/x-www-form-urlencoded"}
|
||||
data = dict(code=authorization_code, client_id=client_id, client_secret=client_secret, redirect_uri=redirect_uri, grant_type="authorization_code")
|
||||
data = urllib.urlencode(data)
|
||||
try:
|
||||
req = urllib2.Request("https://accounts.google.com/o/oauth2/token", data, headers)
|
||||
content = urllib2.urlopen(req).read()
|
||||
except urllib2.HTTPError:
|
||||
raise self.pool.get('res.config.settings').get_config_warning(cr, _("Something went wrong during your token generation. Maybe your Authorization Code is invalid or already expired"), context=context)
|
||||
|
||||
content = simplejson.loads(content)
|
||||
return content.get('refresh_token')
|
||||
|
||||
def _get_google_token_uri(self, cr, uid, service, context=None):
|
||||
ir_config = self.pool['ir.config_parameter']
|
||||
params = {
|
||||
'scope': 'https://www.googleapis.com/auth/drive',
|
||||
'redirect_uri': ir_config.get_param(cr, SUPERUSER_ID, 'google_redirect_uri'),
|
||||
'client_id': ir_config.get_param(cr, SUPERUSER_ID, 'google_%s_client_id' % service),
|
||||
'response_type': 'code',
|
||||
'client_id': ir_config.get_param(cr, SUPERUSER_ID, 'google_%s_client_id' % service),
|
||||
}
|
||||
uri = 'https://accounts.google.com/o/oauth2/auth?%s' % urllib.urlencode(params)
|
||||
return uri
|
||||
|
||||
# vim:expandtab:smartindent:toabstop=4:softtabstop=4:shiftwidth=4:
|
||||
|
||||
|
|
|
@ -0,0 +1,9 @@
|
|||
<?xml version="1.0"?>
|
||||
<openerp>
|
||||
<data noupdate="1">
|
||||
<record id="config_google_redirect_uri" model="ir.config_parameter">
|
||||
<field name="key">google_redirect_uri</field>
|
||||
<field name="value">urn:ietf:wg:oauth:2.0:oob</field>
|
||||
</record>
|
||||
</data>
|
||||
</openerp>
|
|
@ -1,20 +0,0 @@
|
|||
<?xml version="1.0"?>
|
||||
<openerp>
|
||||
<data>
|
||||
<record id="view_users_gogole_form" model="ir.ui.view">
|
||||
<field name="name">res.users.google.form1</field>
|
||||
<field name="model">res.users</field>
|
||||
<field name="inherit_id" ref="base.view_users_form"/>
|
||||
<field name="arch" type="xml">
|
||||
<xpath expr="//notebook" position="inside">
|
||||
<page string="Synchronization">
|
||||
<group string="Google Account" colspan="4">
|
||||
<field name="gmail_user"/>
|
||||
<field name="gmail_password" password="True"/>
|
||||
</group>
|
||||
</page>
|
||||
</xpath>
|
||||
</field>
|
||||
</record>
|
||||
</data>
|
||||
</openerp>
|
|
@ -1,25 +0,0 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
##############################################################################
|
||||
#
|
||||
# OpenERP, Open Source Management Solution
|
||||
# Copyright (C) 2004-2010 Tiny SPRL (<http://tiny.be>).
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Affero General Public License as
|
||||
# published by the Free Software Foundation, either version 3 of the
|
||||
# License, or (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU Affero General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Affero General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
##############################################################################
|
||||
|
||||
import google_login
|
||||
|
||||
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
|
||||
|
|
@ -1,85 +0,0 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
##############################################################################
|
||||
#
|
||||
# OpenERP, Open Source Management Solution
|
||||
# Copyright (C) 2004-2010 Tiny SPRL (<http://tiny.be>).
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Affero General Public License as
|
||||
# published by the Free Software Foundation, either version 3 of the
|
||||
# License, or (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU Affero General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Affero General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
##############################################################################
|
||||
|
||||
from openerp.osv import fields,osv
|
||||
from openerp.tools.translate import _
|
||||
try:
|
||||
import gdata.contacts.service
|
||||
import gdata.contacts.client
|
||||
import gdata.calendar.service
|
||||
except ImportError:
|
||||
raise osv.except_osv(_('Google Contacts Import Error!'), _('Please install gdata-python-client from http://code.google.com/p/gdata-python-client/downloads/list'))
|
||||
|
||||
class google_login(osv.osv_memory):
|
||||
_description ='Google Contact'
|
||||
_name = 'google.login'
|
||||
_columns = {
|
||||
'user': fields.char('Google Username', size=64, required=True),
|
||||
'password': fields.char('Google Password', size=64),
|
||||
}
|
||||
|
||||
def google_login(self, user, password, type='', context=None):
|
||||
if type == 'group':
|
||||
gd_client = gdata.contacts.service.ContactsService()
|
||||
elif type == 'contact':
|
||||
gd_client = gdata.contacts.service.ContactsService()
|
||||
elif type == 'calendar':
|
||||
gd_client = gdata.calendar.service.CalendarService()
|
||||
elif type =='docs_client':
|
||||
gd_client = gdata.docs.client.DocsClient()
|
||||
else:
|
||||
gd_client = gdata.contacts.service.ContactsService()
|
||||
try:
|
||||
gd_client.ClientLogin(user, password, gd_client.source)
|
||||
except Exception:
|
||||
return False
|
||||
return gd_client
|
||||
|
||||
|
||||
def default_get(self, cr, uid, fields, context=None):
|
||||
res = super(google_login, self).default_get(cr, uid, fields, context=context)
|
||||
user_obj = self.pool.get('res.users').browse(cr, uid, uid)
|
||||
if 'user' in fields:
|
||||
res.update({'user': user_obj.gmail_user})
|
||||
if 'password' in fields:
|
||||
res.update({'password': user_obj.gmail_password})
|
||||
return res
|
||||
|
||||
def login(self, cr, uid, ids, context=None):
|
||||
data = self.read(cr, uid, ids)[0]
|
||||
user = data['user']
|
||||
password = data['password']
|
||||
if self.google_login(user, password):
|
||||
res = {
|
||||
'gmail_user': user,
|
||||
'gmail_password': password
|
||||
}
|
||||
self.pool.get('res.users').write(cr, uid, uid, res, context=context)
|
||||
else:
|
||||
raise osv.except_osv(_('Error!'), _("Authentication failed. Check the user and password."))
|
||||
|
||||
return self._get_next_action(cr, uid, context=context)
|
||||
|
||||
def _get_next_action(self, cr, uid, context=None):
|
||||
return {'type': 'ir.actions.act_window_close'}
|
||||
|
||||
|
||||
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
|
|
@ -1,35 +0,0 @@
|
|||
<?xml version="1.0"?>
|
||||
<openerp>
|
||||
<data>
|
||||
<record model="ir.ui.view" id="view_google_login_form">
|
||||
<field name="name">google.login.form</field>
|
||||
<field name="model">google.login</field>
|
||||
<field name="arch" type="xml">
|
||||
<form string="Google login" version="7.0">
|
||||
<group>
|
||||
<field name="user" placeholder="e.g. user@gmail.com"/>
|
||||
<field name="password" password="True"/>
|
||||
</group>
|
||||
<footer>
|
||||
<button name="login" string="_Login" type="object" class="oe_highlight"/>
|
||||
or
|
||||
<button string="Cancel" class="oe_link" special="cancel" />
|
||||
</footer>
|
||||
</form>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<!--
|
||||
Login Action
|
||||
-->
|
||||
<record model="ir.actions.act_window" id="act_google_login_form">
|
||||
<field name="name">Google Login</field>
|
||||
<field name="type">ir.actions.act_window</field>
|
||||
<field name="res_model">google.login</field>
|
||||
<field name="view_type">form</field>
|
||||
<field name="view_mode">form</field>
|
||||
<field name="target">new</field>
|
||||
<field name="view_id" ref="view_google_login_form" />
|
||||
</record>
|
||||
</data>
|
||||
</openerp>
|
|
@ -1 +0,0 @@
|
|||
import google_docs
|
|
@ -1,193 +0,0 @@
|
|||
##############################################################################
|
||||
#
|
||||
# OpenERP, Open Source Management Solution
|
||||
# Copyright (C) 2004-2012 OpenERP SA (<http://www.openerp.com>).
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Affero General Public License as
|
||||
# published by the Free Software Foundation, either version 3 of the
|
||||
# License, or (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU Affero General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Affero General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
##############################################################################
|
||||
import logging
|
||||
from datetime import datetime
|
||||
|
||||
from openerp.tools import DEFAULT_SERVER_DATETIME_FORMAT
|
||||
from openerp.osv import fields, osv
|
||||
from openerp.tools.translate import _
|
||||
|
||||
_logger = logging.getLogger(__name__)
|
||||
|
||||
try:
|
||||
import gdata.docs.data
|
||||
import gdata.docs.client
|
||||
|
||||
# API breakage madness in the gdata API - those guys are insane.
|
||||
try:
|
||||
# gdata 2.0.15+
|
||||
gdata.docs.client.DocsClient.copy_resource
|
||||
except AttributeError:
|
||||
# gdata 2.0.14- : copy_resource() was copy()
|
||||
gdata.docs.client.DocsClient.copy_resource = gdata.docs.client.DocsClient.copy
|
||||
|
||||
try:
|
||||
# gdata 2.0.16+
|
||||
gdata.docs.client.DocsClient.get_resource_by_id
|
||||
except AttributeError:
|
||||
try:
|
||||
# gdata 2.0.15+
|
||||
gdata.docs.client.DocsClient.get_resource_by_self_link
|
||||
def get_resource_by_id_2_0_16(self, resource_id, **kwargs):
|
||||
return self.GetResourceBySelfLink(
|
||||
gdata.docs.client.RESOURCE_FEED_URI + ('/%s' % resource_id), **kwargs)
|
||||
gdata.docs.client.DocsClient.get_resource_by_id = get_resource_by_id_2_0_16
|
||||
except AttributeError:
|
||||
# gdata 2.0.14- : alias get_resource_by_id()
|
||||
gdata.docs.client.DocsClient.get_resource_by_id = gdata.docs.client.DocsClient.get_doc
|
||||
|
||||
try:
|
||||
import atom.http_interface
|
||||
_logger.info('GData lib version `%s` detected' % atom.http_interface.USER_AGENT)
|
||||
except (ImportError, AttributeError):
|
||||
_logger.debug('GData lib version could not be detected', exc_info=True)
|
||||
|
||||
except ImportError:
|
||||
_logger.warning("Please install latest gdata-python-client from http://code.google.com/p/gdata-python-client/downloads/list")
|
||||
|
||||
|
||||
class google_docs_ir_attachment(osv.osv):
|
||||
_inherit = 'ir.attachment'
|
||||
|
||||
def _auth(self, cr, uid, context=None):
|
||||
'''
|
||||
Connexion with google base account
|
||||
@return client object for connexion
|
||||
'''
|
||||
#pool the google.login in google_base_account
|
||||
google_pool = self.pool.get('google.login')
|
||||
#get gmail password and login. We use default_get() instead of a create() followed by a read() on the
|
||||
# google.login object, because it is easier. The keys 'user' and 'password' ahve to be passed in the dict
|
||||
# but the values will be replaced by the user gmail password and login.
|
||||
user_config = google_pool.default_get(cr, uid, {'user' : '' , 'password' : ''}, context=context)
|
||||
#login gmail account
|
||||
client = google_pool.google_login(user_config['user'], user_config['password'], type='docs_client', context=context)
|
||||
if not client:
|
||||
raise osv.except_osv(_('Google Docs Error!'), _("Check your google configuration in Users/Users/Synchronization tab."))
|
||||
_logger.info('Logged into google docs as %s', user_config['user'])
|
||||
return client
|
||||
|
||||
def create_empty_google_doc(self, cr, uid, res_model, res_id, context=None):
|
||||
'''Create a new google document, empty and with a default type (txt)
|
||||
:param res_model: the object for which the google doc is created
|
||||
:param res_id: the Id of the object for which the google doc is created
|
||||
:return: the ID of the google document object created
|
||||
'''
|
||||
#login with the base account google module
|
||||
client = self._auth(cr, uid, context=context)
|
||||
# create the document in google docs
|
||||
title = "%s %s" % (context.get("name","Untitled Document."), datetime.today().strftime(DEFAULT_SERVER_DATETIME_FORMAT))
|
||||
local_resource = gdata.docs.data.Resource(gdata.docs.data.DOCUMENT_LABEL,title=title)
|
||||
#create a new doc in Google Docs
|
||||
gdocs_resource = client.post(entry=local_resource, uri='https://docs.google.com/feeds/default/private/full/')
|
||||
# create an ir.attachment into the db
|
||||
self.create(cr, uid, {
|
||||
'res_model': res_model,
|
||||
'res_id': res_id,
|
||||
'type': 'url',
|
||||
'name': title,
|
||||
'url': gdocs_resource.get_alternate_link().href,
|
||||
}, context=context)
|
||||
return {'resource_id': gdocs_resource.resource_id.text,
|
||||
'title': title,
|
||||
'url': gdocs_resource.get_alternate_link().href}
|
||||
|
||||
def copy_gdoc(self, cr, uid, res_model, res_id, name_gdocs, gdoc_template_id, context=None):
|
||||
'''
|
||||
copy an existing document in google docs
|
||||
:param res_model: the object for which the google doc is created
|
||||
:param res_id: the Id of the object for which the google doc is created
|
||||
:param name_gdocs: the name of the future ir.attachment that will be created. Based on the google doc template foun.
|
||||
:param gdoc_template_id: the id of the google doc document to copy
|
||||
:return: the ID of the google document object created
|
||||
'''
|
||||
#login with the base account google module
|
||||
client = self._auth(cr, uid)
|
||||
# fetch and copy the original document
|
||||
try:
|
||||
doc = client.get_resource_by_id(gdoc_template_id)
|
||||
#copy the document you choose in the configuration
|
||||
copy_resource = client.copy_resource(doc, name_gdocs)
|
||||
except:
|
||||
raise osv.except_osv(_('Google Docs Error!'), _("Your resource id is not correct. You can find the id in the google docs URL."))
|
||||
# create an ir.attachment
|
||||
self.create(cr, uid, {
|
||||
'res_model': res_model,
|
||||
'res_id': res_id,
|
||||
'type': 'url',
|
||||
'name': name_gdocs,
|
||||
'url': copy_resource.get_alternate_link().href
|
||||
}, context=context)
|
||||
return copy_resource.resource_id.text
|
||||
|
||||
def google_doc_get(self, cr, uid, res_model, ids, context=None):
|
||||
'''
|
||||
Function called by the js, when no google doc are yet associated with a record, with the aim to create one. It
|
||||
will first seek for a google.docs.config associated with the model `res_model` to find out what's the template
|
||||
of google doc to copy (this is usefull if you want to start with a non-empty document, a type or a name
|
||||
different than the default values). If no config is associated with the `res_model`, then a blank text document
|
||||
with a default name is created.
|
||||
:param res_model: the object for which the google doc is created
|
||||
:param ids: the list of ids of the objects for which the google doc is created. This list is supposed to have
|
||||
a length of 1 element only (batch processing is not supported in the code, though nothing really prevent it)
|
||||
:return: the google document object created
|
||||
'''
|
||||
if len(ids) != 1:
|
||||
raise osv.except_osv(_('Google Docs Error!'), _("Creating google docs may only be done by one at a time."))
|
||||
res_id = ids[0]
|
||||
pool_ir_attachment = self.pool.get('ir.attachment')
|
||||
pool_gdoc_config = self.pool.get('google.docs.config')
|
||||
name_gdocs = ''
|
||||
model_fields_dic = self.pool[res_model].read(cr, uid, res_id, [], context=context)
|
||||
|
||||
# check if a model is configured with a template
|
||||
google_docs_config = pool_gdoc_config.search(cr, uid, [('model_id', '=', res_model)], context=context)
|
||||
if google_docs_config:
|
||||
name_gdocs = pool_gdoc_config.browse(cr, uid, google_docs_config, context=context)[0].name_template
|
||||
try:
|
||||
name_gdocs = name_gdocs % model_fields_dic
|
||||
except:
|
||||
raise osv.except_osv(_('Key Error!'), _("Your Google Doc Name Pattern's key does not found in object."))
|
||||
google_template_id = pool_gdoc_config.browse(cr, uid, google_docs_config[0], context=context).gdocs_resource_id
|
||||
google_document = pool_ir_attachment.copy_gdoc(cr, uid, res_model, res_id, name_gdocs, google_template_id, context=context)
|
||||
else:
|
||||
google_document = pool_ir_attachment.create_empty_google_doc(cr, uid, res_model, res_id, context=context)
|
||||
return google_document
|
||||
|
||||
class config(osv.osv):
|
||||
_name = 'google.docs.config'
|
||||
_description = "Google Docs templates config"
|
||||
|
||||
_columns = {
|
||||
'model_id': fields.many2one('ir.model', 'Model', required=True),
|
||||
'gdocs_resource_id': fields.char('Google Resource ID to Use as Template', size=64, help='''
|
||||
This is the id of the template document, on google side. You can find it thanks to its URL:
|
||||
*for a text document with url like `https://docs.google.com/a/openerp.com/document/d/123456789/edit`, the ID is `document:123456789`
|
||||
*for a spreadsheet document with url like `https://docs.google.com/a/openerp.com/spreadsheet/ccc?key=123456789#gid=0`, the ID is `spreadsheet:123456789`
|
||||
*for a presentation (slide show) document with url like `https://docs.google.com/a/openerp.com/presentation/d/123456789/edit#slide=id.p`, the ID is `presentation:123456789`
|
||||
*for a drawing document with url like `https://docs.google.com/a/openerp.com/drawings/d/123456789/edit`, the ID is `drawings:123456789`
|
||||
...
|
||||
''', required=True),
|
||||
'name_template': fields.char('Google Doc Name Pattern', size=64, help='Choose how the new google docs will be named, on google side. Eg. gdoc_%(field_name)s', required=True),
|
||||
}
|
||||
|
||||
_defaults = {
|
||||
'name_template': 'gdoc_%(name)s',
|
||||
}
|
|
@ -1,159 +0,0 @@
|
|||
# Translation of OpenERP Server.
|
||||
# This file contains the translation of the following modules:
|
||||
# * google_docs
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: OpenERP Server 7.0alpha\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2012-12-21 17:05+0000\n"
|
||||
"PO-Revision-Date: 2012-12-21 17:05+0000\n"
|
||||
"Last-Translator: <>\n"
|
||||
"Language-Team: \n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: \n"
|
||||
"Plural-Forms: \n"
|
||||
|
||||
#. module: google_docs
|
||||
#: code:addons/google_docs/google_docs.py:139
|
||||
#, python-format
|
||||
msgid "Key Error!"
|
||||
msgstr ""
|
||||
|
||||
#. module: google_docs
|
||||
#: view:google.docs.config:0
|
||||
msgid "for a presentation (slide show) document with url like `https://docs.google.com/a/openerp.com/presentation/d/123456789/edit#slide=id.p`, the ID is `presentation:123456789`"
|
||||
msgstr ""
|
||||
|
||||
#. module: google_docs
|
||||
#: view:google.docs.config:0
|
||||
msgid "for a text document with url like `https://docs.google.com/a/openerp.com/document/d/123456789/edit`, the ID is `document:123456789`"
|
||||
msgstr ""
|
||||
|
||||
#. module: google_docs
|
||||
#: field:google.docs.config,gdocs_resource_id:0
|
||||
msgid "Google Resource ID to Use as Template"
|
||||
msgstr ""
|
||||
|
||||
#. module: google_docs
|
||||
#: view:google.docs.config:0
|
||||
msgid "for a drawing document with url like `https://docs.google.com/a/openerp.com/drawings/d/123456789/edit`, the ID is `drawings:123456789`"
|
||||
msgstr ""
|
||||
|
||||
#. module: google_docs
|
||||
#. openerp-web
|
||||
#: code:addons/google_docs/static/src/xml/gdocs.xml:6
|
||||
#, python-format
|
||||
msgid "Add Google Doc..."
|
||||
msgstr ""
|
||||
|
||||
#. module: google_docs
|
||||
#: view:google.docs.config:0
|
||||
msgid "This is the id of the template document, on google side. You can find it thanks to its URL:"
|
||||
msgstr ""
|
||||
|
||||
#. module: google_docs
|
||||
#: model:ir.model,name:google_docs.model_google_docs_config
|
||||
msgid "Google Docs templates config"
|
||||
msgstr ""
|
||||
|
||||
#. module: google_docs
|
||||
#. openerp-web
|
||||
#: code:addons/google_docs/static/src/js/gdocs.js:25
|
||||
#, python-format
|
||||
msgid "The user google credentials are not set yet. Contact your administrator for help."
|
||||
msgstr ""
|
||||
|
||||
#. module: google_docs
|
||||
#: view:google.docs.config:0
|
||||
msgid "for a spreadsheet document with url like `https://docs.google.com/a/openerp.com/spreadsheet/ccc?key=123456789#gid=0`, the ID is `spreadsheet:123456789`"
|
||||
msgstr ""
|
||||
|
||||
#. module: google_docs
|
||||
#: code:addons/google_docs/google_docs.py:101
|
||||
#, python-format
|
||||
msgid "Your resource id is not correct. You can find the id in the google docs URL."
|
||||
msgstr ""
|
||||
|
||||
#. module: google_docs
|
||||
#: code:addons/google_docs/google_docs.py:125
|
||||
#, python-format
|
||||
msgid "Creating google docs may only be done by one at a time."
|
||||
msgstr ""
|
||||
|
||||
#. module: google_docs
|
||||
#: code:addons/google_docs/google_docs.py:56
|
||||
#: code:addons/google_docs/google_docs.py:101
|
||||
#: code:addons/google_docs/google_docs.py:125
|
||||
#, python-format
|
||||
msgid "Google Docs Error!"
|
||||
msgstr ""
|
||||
|
||||
#. module: google_docs
|
||||
#: code:addons/google_docs/google_docs.py:56
|
||||
#, python-format
|
||||
msgid "Check your google configuration in Users/Users/Synchronization tab."
|
||||
msgstr ""
|
||||
|
||||
#. module: google_docs
|
||||
#: model:ir.ui.menu,name:google_docs.menu_gdocs_config
|
||||
msgid "Google Docs configuration"
|
||||
msgstr ""
|
||||
|
||||
#. module: google_docs
|
||||
#: model:ir.actions.act_window,name:google_docs.action_google_docs_users_config
|
||||
#: model:ir.ui.menu,name:google_docs.menu_gdocs_model_config
|
||||
msgid "Models configuration"
|
||||
msgstr ""
|
||||
|
||||
#. module: google_docs
|
||||
#: field:google.docs.config,model_id:0
|
||||
msgid "Model"
|
||||
msgstr ""
|
||||
|
||||
#. module: google_docs
|
||||
#. openerp-web
|
||||
#: code:addons/google_docs/static/src/js/gdocs.js:28
|
||||
#, python-format
|
||||
msgid "User Google credentials are not yet set."
|
||||
msgstr ""
|
||||
|
||||
#. module: google_docs
|
||||
#: code:addons/google_docs/google_docs.py:139
|
||||
#, python-format
|
||||
msgid "Your Google Doc Name Pattern's key does not found in object."
|
||||
msgstr ""
|
||||
|
||||
#. module: google_docs
|
||||
#: help:google.docs.config,name_template:0
|
||||
msgid "Choose how the new google docs will be named, on google side. Eg. gdoc_%(field_name)s"
|
||||
msgstr ""
|
||||
|
||||
#. module: google_docs
|
||||
#: view:google.docs.config:0
|
||||
msgid "Google Docs Configuration"
|
||||
msgstr ""
|
||||
|
||||
#. module: google_docs
|
||||
#: help:google.docs.config,gdocs_resource_id:0
|
||||
msgid "\n"
|
||||
"This is the id of the template document, on google side. You can find it thanks to its URL: \n"
|
||||
"*for a text document with url like `https://docs.google.com/a/openerp.com/document/d/123456789/edit`, the ID is `document:123456789`\n"
|
||||
"*for a spreadsheet document with url like `https://docs.google.com/a/openerp.com/spreadsheet/ccc?key=123456789#gid=0`, the ID is `spreadsheet:123456789`\n"
|
||||
"*for a presentation (slide show) document with url like `https://docs.google.com/a/openerp.com/presentation/d/123456789/edit#slide=id.p`, the ID is `presentation:123456789`\n"
|
||||
"*for a drawing document with url like `https://docs.google.com/a/openerp.com/drawings/d/123456789/edit`, the ID is `drawings:123456789`\n"
|
||||
"...\n"
|
||||
""
|
||||
msgstr ""
|
||||
|
||||
#. module: google_docs
|
||||
#: model:ir.model,name:google_docs.model_ir_attachment
|
||||
msgid "ir.attachment"
|
||||
msgstr ""
|
||||
|
||||
#. module: google_docs
|
||||
#: field:google.docs.config,name_template:0
|
||||
msgid "Google Doc Name Pattern"
|
||||
msgstr ""
|
||||
|
|
@ -1,54 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<openerp>
|
||||
<data>
|
||||
|
||||
<!-- add google docs config field in user form -->
|
||||
|
||||
<record model="ir.ui.view" id="view_google_docs_config_tree">
|
||||
<field name="name">google_docs.config.tree</field>
|
||||
<field name="model">google.docs.config</field>
|
||||
<field name="arch" type="xml">
|
||||
<tree string="Google Docs Configuration">
|
||||
<field name="model_id"/>
|
||||
<field name="name_template"/>
|
||||
</tree>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record model="ir.ui.view" id="view_google_docs_config_form">
|
||||
<field name="name">google_docs.config.form</field>
|
||||
<field name="model">google.docs.config</field>
|
||||
<field name="arch" type="xml">
|
||||
<form string="Google Docs Configuration" version="7.0">
|
||||
<group>
|
||||
<field name="model_id"/>
|
||||
<label for='gdocs_resource_id'/>
|
||||
<div>
|
||||
<field name='gdocs_resource_id'/>
|
||||
<p class="oe_grey">
|
||||
This is the id of the template document, on google side. You can find it thanks to its URL:
|
||||
<ul>
|
||||
<li>for a text document with url like `https://docs.google.com/a/openerp.com/document/d/123456789/edit`, the ID is `document:123456789`</li>
|
||||
<li>for a spreadsheet document with url like `https://docs.google.com/a/openerp.com/spreadsheet/ccc?key=123456789#gid=0`, the ID is `spreadsheet:123456789`</li>
|
||||
<li>for a presentation (slide show) document with url like `https://docs.google.com/a/openerp.com/presentation/d/123456789/edit#slide=id.p`, the ID is `presentation:123456789`</li>
|
||||
<li>for a drawing document with url like `https://docs.google.com/a/openerp.com/drawings/d/123456789/edit`, the ID is `drawings:123456789`</li>
|
||||
</ul>
|
||||
</p>
|
||||
</div>
|
||||
<field name='name_template'/>
|
||||
</group>
|
||||
</form>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record model='ir.actions.act_window' id='action_google_docs_users_config'>
|
||||
<field name='name'>Models configuration</field>
|
||||
<field name='res_model'>google.docs.config</field>
|
||||
<field name='type'>ir.actions.act_window</field>
|
||||
<field name='view_type'>form</field>
|
||||
<field name='view_id' ref='view_google_docs_config_tree'/>
|
||||
</record>
|
||||
<menuitem name='Google Docs configuration' id='menu_gdocs_config' parent='base.menu_administration'/>
|
||||
<menuitem name='Models configuration' id='menu_gdocs_model_config' parent='menu_gdocs_config' action='action_google_docs_users_config'/>
|
||||
</data>
|
||||
</openerp>
|
|
@ -1,3 +0,0 @@
|
|||
id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
|
||||
access_google_docs,google.docs.config,model_google_docs_config,,1,0,0,0
|
||||
access_google_docs,google.docs.config,model_google_docs_config,base.group_system,1,1,1,1
|
|
|
@ -1,40 +0,0 @@
|
|||
openerp.google_docs = function(instance, m) {
|
||||
var _t = instance.web._t,
|
||||
QWeb = instance.web.qweb;
|
||||
|
||||
instance.web.Sidebar.include({
|
||||
redraw: function() {
|
||||
var self = this;
|
||||
this._super.apply(this, arguments);
|
||||
self.$el.find('.oe_sidebar_add_attachment').after(QWeb.render('AddGoogleDocumentItem', {widget: self}))
|
||||
self.$el.find('.oe_sidebar_add_google_doc').on('click', function (e) {
|
||||
self.on_google_doc();
|
||||
});
|
||||
},
|
||||
on_google_doc: function() {
|
||||
var self = this;
|
||||
var view = self.getParent();
|
||||
var ids = ( view.fields_view.type != "form" )? view.groups.get_selection().ids : [ view.datarecord.id ];
|
||||
if( !_.isEmpty(ids) ){
|
||||
view.sidebar_eval_context().done(function (context) {
|
||||
var ds = new instance.web.DataSet(this, 'ir.attachment', context);
|
||||
ds.call('google_doc_get', [view.dataset.model, ids, context]).done(function(r) {
|
||||
if (r == 'False') {
|
||||
var params = {
|
||||
error: response,
|
||||
message: _t("The user google credentials are not set yet. Contact your administrator for help.")
|
||||
}
|
||||
$(openerp.web.qweb.render("DialogWarning", params)).dialog({
|
||||
title: _t("User Google credentials are not yet set."),
|
||||
modal: true,
|
||||
});
|
||||
}
|
||||
}).done(function(r){
|
||||
window.open(r.url,"_blank");
|
||||
view.reload();
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
};
|
|
@ -0,0 +1 @@
|
|||
import google_drive
|
|
@ -20,22 +20,31 @@
|
|||
##############################################################################
|
||||
|
||||
{
|
||||
'name': 'Google Docs integration',
|
||||
'name': 'Google Drive™ integration',
|
||||
'version': '0.2',
|
||||
'author': 'OpenERP SA',
|
||||
'website': 'http://openerp.com',
|
||||
'category': 'Tools',
|
||||
'installable': True,
|
||||
'auto_install': False,
|
||||
'js': ['static/src/js/gdocs.js'],
|
||||
'qweb': ['static/src/xml/gdocs.xml'],
|
||||
'js': [
|
||||
'static/lib/gapi/client.js',
|
||||
'static/src/js/gdrive.js',
|
||||
],
|
||||
'data': [
|
||||
'security/ir.model.access.csv',
|
||||
'res_config_user_view.xml'
|
||||
'res_config_user_view.xml',
|
||||
'google_drive_data.xml'
|
||||
],
|
||||
'depends': ['google_base_account','document'],
|
||||
'demo': [
|
||||
'google_drive_demo.xml'
|
||||
],
|
||||
'depends': ['base_setup', 'google_base_account'],
|
||||
'description': """
|
||||
Module to attach a google document to any model.
|
||||
================================================
|
||||
Integrate google document to OpenERP record.
|
||||
============================================
|
||||
|
||||
This module allows you to integrate google documents to any of your OpenERP record quickly and easily using OAuth 2.0 for Installed Applications,
|
||||
You can configure your google Authorization Code from Settings > Configuration > General Settings by clicking on "Generate Google Authorization Code"
|
||||
"""
|
||||
}
|
|
@ -0,0 +1,211 @@
|
|||
##############################################################################
|
||||
#
|
||||
# OpenERP, Open Source Management Solution
|
||||
# Copyright (C) 2004-2012 OpenERP SA (<http://www.openerp.com>).
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Affero General Public License as
|
||||
# published by the Free Software Foundation, either version 3 of the
|
||||
# License, or (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU Affero General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Affero General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
##############################################################################
|
||||
import logging
|
||||
|
||||
from openerp import SUPERUSER_ID
|
||||
from openerp.osv import fields, osv
|
||||
from openerp.tools.translate import _
|
||||
|
||||
import urllib
|
||||
import urllib2
|
||||
import json
|
||||
import re
|
||||
|
||||
_logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class config(osv.osv):
|
||||
_name = 'google.drive.config'
|
||||
_description = "Google Drive templates config"
|
||||
|
||||
def get_google_drive_url(self, cr, uid, config_id, res_id, template_id, context=None):
|
||||
config = self.browse(cr, SUPERUSER_ID, config_id, context=context)
|
||||
model = config.model_id
|
||||
filter_name = config.filter_id and config.filter_id.name or False
|
||||
record = self.pool.get(model.model).read(cr, uid, res_id, [], context=context)
|
||||
record.update({'model': model.name, 'filter': filter_name})
|
||||
name_gdocs = config.name_template
|
||||
try:
|
||||
name_gdocs = name_gdocs % record
|
||||
except:
|
||||
raise osv.except_osv(_('Key Error!'), _("At least one key cannot be found in your Google Drive name pattern"))
|
||||
|
||||
attach_pool = self.pool.get("ir.attachment")
|
||||
attach_ids = attach_pool.search(cr, uid, [('res_model', '=', model.model), ('name', '=', name_gdocs), ('res_id', '=', res_id)])
|
||||
url = False
|
||||
if attach_ids:
|
||||
attachment = attach_pool.browse(cr, uid, attach_ids[0], context)
|
||||
url = attachment.url
|
||||
else:
|
||||
url = self.copy_doc(cr, uid, res_id, template_id, name_gdocs, model.model, context)
|
||||
return url
|
||||
|
||||
def copy_doc(self, cr, uid, res_id, template_id, name_gdocs, res_model, context=None):
|
||||
ir_config = self.pool['ir.config_parameter']
|
||||
google_drive_refresh_token = ir_config.get_param(cr, SUPERUSER_ID, 'google_drive_refresh_token')
|
||||
if not google_drive_refresh_token:
|
||||
raise self.pool.get('res.config.settings').get_config_warning(cr, _("You haven't configured 'Authorization Code' generated from google, Please generate and configure it in %(menu:base_setup.menu_general_configuration)s."), context=context)
|
||||
google_drive_client_id = ir_config.get_param(cr, SUPERUSER_ID, 'google_drive_client_id')
|
||||
google_drive_client_secret = ir_config.get_param(cr, SUPERUSER_ID, 'google_drive_client_secret')
|
||||
google_web_base_url = ir_config.get_param(cr, SUPERUSER_ID, 'web.base.url')
|
||||
|
||||
#For Getting New Access Token With help of old Refresh Token
|
||||
headers = {"Content-type": "application/x-www-form-urlencoded", "Accept-Encoding": "gzip, deflate"}
|
||||
data = dict(client_id=google_drive_client_id,
|
||||
refresh_token=google_drive_refresh_token,
|
||||
client_secret=google_drive_client_secret,
|
||||
grant_type="refresh_token")
|
||||
|
||||
data = urllib.urlencode(data)
|
||||
try:
|
||||
req = urllib2.Request('https://accounts.google.com/o/oauth2/token', data, headers)
|
||||
content = urllib2.urlopen(req).read()
|
||||
except urllib2.HTTPError:
|
||||
raise self.pool.get('res.config.settings').get_config_warning(cr, _("Something went wrong during the token generation. Please request again an authorization code in %(menu:base_setup.menu_general_configuration)s."), context=context)
|
||||
content = json.loads(content)
|
||||
|
||||
# Copy template in to drive with help of new access token
|
||||
if 'access_token' in content:
|
||||
request_url = "https://www.googleapis.com/drive/v2/files/%s?fields=parents/id&access_token=%s" % (template_id, content['access_token'])
|
||||
try:
|
||||
req = urllib2.Request(request_url, None, headers)
|
||||
parents = urllib2.urlopen(req).read()
|
||||
except urllib2.HTTPError:
|
||||
raise self.pool.get('res.config.settings').get_config_warning(cr, _("The Google Template cannot be found. Maybe it has been deleted."), context=context)
|
||||
parents_dict = json.loads(parents)
|
||||
|
||||
record_url = "Click on link to open Record in OpenERP\n %s/?db=%s#id=%s&model=%s" % (google_web_base_url, cr.dbname, res_id, res_model)
|
||||
data = {"title": name_gdocs, "description": record_url, "parents": parents_dict['parents']}
|
||||
request_url = "https://www.googleapis.com/drive/v2/files/%s/copy?access_token=%s" % (template_id, content['access_token'])
|
||||
headers = {'Content-type': 'application/json', 'Accept': 'text/plain'}
|
||||
data_json = json.dumps(data)
|
||||
# resp, content = Http().request(request_url, "POST", data_json, headers)
|
||||
req = urllib2.Request(request_url, data_json, headers)
|
||||
content = urllib2.urlopen(req).read()
|
||||
content = json.loads(content)
|
||||
res = False
|
||||
if 'alternateLink' in content.keys():
|
||||
attach_pool = self.pool.get("ir.attachment")
|
||||
attach_vals = {'res_model': res_model, 'name': name_gdocs, 'res_id': res_id, 'type': 'url', 'url': content['alternateLink']}
|
||||
attach_pool.create(cr, uid, attach_vals)
|
||||
res = content['alternateLink']
|
||||
return res
|
||||
|
||||
def get_google_drive_config(self, cr, uid, res_model, res_id, context=None):
|
||||
'''
|
||||
Function called by the js, when no google doc are yet associated with a record, with the aim to create one. It
|
||||
will first seek for a google.docs.config associated with the model `res_model` to find out what's the template
|
||||
of google doc to copy (this is usefull if you want to start with a non-empty document, a type or a name
|
||||
different than the default values). If no config is associated with the `res_model`, then a blank text document
|
||||
with a default name is created.
|
||||
:param res_model: the object for which the google doc is created
|
||||
:param ids: the list of ids of the objects for which the google doc is created. This list is supposed to have
|
||||
a length of 1 element only (batch processing is not supported in the code, though nothing really prevent it)
|
||||
:return: the config id and config name
|
||||
'''
|
||||
if not res_id:
|
||||
raise osv.except_osv(_('Google Drive Error!'), _("Creating google drive may only be done by one at a time."))
|
||||
# check if a model is configured with a template
|
||||
config_ids = self.search(cr, uid, [('model_id', '=', res_model)], context=context)
|
||||
configs = []
|
||||
for config in self.browse(cr, uid, config_ids, context=context):
|
||||
if config.filter_id:
|
||||
if (config.filter_id.user_id and config.filter_id.user_id.id != uid):
|
||||
#Private
|
||||
continue
|
||||
domain = [('id', 'in', [res_id])] + eval(config.filter_id.domain)
|
||||
local_context = context and context.copy() or {}
|
||||
local_context.update(eval(config.filter_id.context))
|
||||
google_doc_configs = self.pool.get(config.filter_id.model_id).search(cr, uid, domain, context=local_context)
|
||||
if google_doc_configs:
|
||||
configs.append({'id': config.id, 'name': config.name})
|
||||
else:
|
||||
configs.append({'id': config.id, 'name': config.name})
|
||||
return configs
|
||||
|
||||
def _resource_get(self, cr, uid, ids, name, arg, context=None):
|
||||
result = {}
|
||||
for data in self.browse(cr, uid, ids, context):
|
||||
mo = re.search("(key=|/d/)([A-Za-z0-9-_]+)", data.google_drive_template_url)
|
||||
if mo:
|
||||
result[data.id] = mo.group(2)
|
||||
else:
|
||||
raise osv.except_osv(_('Incorrect URL!'), _("Please enter a valid Google Document URL."))
|
||||
return result
|
||||
|
||||
def _client_id_get(self, cr, uid, ids, name, arg, context=None):
|
||||
result = {}
|
||||
client_id = self.pool['ir.config_parameter'].get_param(cr, SUPERUSER_ID, 'google_drive_client_id')
|
||||
for config_id in ids:
|
||||
result[config_id] = client_id
|
||||
return result
|
||||
|
||||
_columns = {
|
||||
'name': fields.char('Template Name', required=True, size=1024),
|
||||
'model_id': fields.many2one('ir.model', 'Model', ondelete='set null', required=True),
|
||||
'model': fields.related('model_id', 'model', type='char', string='Model', readonly=True),
|
||||
'filter_id': fields.many2one('ir.filters', 'Filter', domain="[('model_id', '=', model)]"),
|
||||
'google_drive_template_url': fields.char('Template URL', required=True, size=1024),
|
||||
'google_drive_resource_id': fields.function(_resource_get, type="char", string='Resource Id'),
|
||||
'google_drive_client_id': fields.function(_client_id_get, type="char", string='Google Client '),
|
||||
'name_template': fields.char('Google Drive Name Pattern', size=64, help='Choose how the new google drive will be named, on google side. Eg. gdoc_%(field_name)s', required=True),
|
||||
}
|
||||
|
||||
def onchange_model_id(self, cr, uid, ids, model_id, context=None):
|
||||
res = {}
|
||||
if model_id:
|
||||
model = self.pool['ir.model'].browse(cr, uid, model_id, context=context)
|
||||
res['value'] = {'model': model.model}
|
||||
else:
|
||||
res['value'] = {'filter_id': False, 'model': False}
|
||||
return res
|
||||
|
||||
_defaults = {
|
||||
'name_template': 'Document %(name)s',
|
||||
}
|
||||
|
||||
def _check_model_id(self, cr, uid, ids, context=None):
|
||||
config_id = self.browse(cr, uid, ids[0], context=context)
|
||||
if config_id.filter_id and config_id.model_id.model != config_id.filter_id.model_id:
|
||||
return False
|
||||
return True
|
||||
|
||||
_constraints = [
|
||||
(_check_model_id, 'Model of selected filter is not matching with model of current template.', ['model_id', 'filter_id']),
|
||||
]
|
||||
|
||||
config()
|
||||
|
||||
|
||||
class base_config_settings(osv.osv):
|
||||
_inherit = "base.config.settings"
|
||||
|
||||
_columns = {
|
||||
'google_drive_authorization_code': fields.char('Authorization Code', size=124),
|
||||
'google_drive_uri': fields.char('URI', readonly=True, help="The URL to generate the authorization code from Google"),
|
||||
}
|
||||
_defaults = {
|
||||
'google_drive_uri': lambda s, cr, uid, c: s.pool['google.service']._get_google_token_uri(cr, uid, 'drive', context=c),
|
||||
}
|
||||
|
||||
def set_google_authorization_code(self, cr, uid, ids, context=None):
|
||||
config = self.browse(cr, uid, ids[0], context)
|
||||
refresh_token = self.pool['google.service'].generate_refresh_token(cr, uid, 'drive', config.google_drive_authorization_code, context=context)
|
||||
self.pool['ir.config_parameter'].set_param(cr, uid, 'google_drive_refresh_token', refresh_token)
|
|
@ -0,0 +1,16 @@
|
|||
<?xml version="1.0"?>
|
||||
<openerp>
|
||||
<data noupdate="1">
|
||||
|
||||
<record id="config_google_drive_client_id" model="ir.config_parameter">
|
||||
<field name="key">google_drive_client_id</field>
|
||||
<field name="value">39623646228-eg3ggo3mk6o40m7rguobi3rkl9frh4tb.apps.googleusercontent.com</field>
|
||||
</record>
|
||||
|
||||
<record id="config_google_drive_client_secret" model="ir.config_parameter">
|
||||
<field name="key">google_drive_client_secret</field>
|
||||
<field name="value">Ul-PtmnSWs3euWs20fdono0e</field>
|
||||
</record>
|
||||
|
||||
</data>
|
||||
</openerp>
|
|
@ -0,0 +1,24 @@
|
|||
<?xml version="1.0"?>
|
||||
<openerp>
|
||||
<data noupdate="1">
|
||||
|
||||
<!-- filter demo -->
|
||||
<record id="filter_partner" model="ir.filters">
|
||||
<field name="name">Customer</field>
|
||||
<field name="model_id">res.partner</field>
|
||||
<field name="domain">[['customer', '=', 1]]</field>
|
||||
<field name="user_id" eval="False" />
|
||||
</record>
|
||||
|
||||
<!-- template demo -->
|
||||
<record id="template_partner" model="google.drive.config">
|
||||
<field name="name">Partner Review</field>
|
||||
<field name="model_id" ref="base.model_res_partner"/>
|
||||
<field name="filter_id" ref="filter_partner"/>
|
||||
<field name="google_drive_template_url">https://docs.google.com/spreadsheet/ccc?key=0Ah2qnrLAoZmUdGRvdVdmS1VoSDctWk1kd18taGZ4ckE#gid=0</field>
|
||||
<field name="name_template">Partner Review %(name)s</field>
|
||||
</record>
|
||||
|
||||
</data>
|
||||
</openerp>
|
||||
|
|
@ -0,0 +1,227 @@
|
|||
# Translation of OpenERP Server.
|
||||
# This file contains the translation of the following modules:
|
||||
# * google_drive
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: OpenERP Server 8.0alpha1\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2013-06-27 16:03+0000\n"
|
||||
"PO-Revision-Date: 2013-06-27 16:03+0000\n"
|
||||
"Last-Translator: <>\n"
|
||||
"Language-Team: \n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: \n"
|
||||
"Plural-Forms: \n"
|
||||
|
||||
#. module: google_drive
|
||||
#: model:ir.ui.menu,name:google_drive.menu_google_drive_config
|
||||
msgid "Google Drive configuration"
|
||||
msgstr ""
|
||||
|
||||
#. module: google_drive
|
||||
#: code:addons/google_drive/google_drive.py:48
|
||||
#, python-format
|
||||
msgid "Key Error!"
|
||||
msgstr ""
|
||||
|
||||
#. module: google_drive
|
||||
#: view:google.drive.config:0
|
||||
msgid "The name of the attached document can use fixed or variable data. To distinguish between documents in\n"
|
||||
" Google Drive, use fixed words and fields. For instance, in the example above, if you wrote Agrolait_%(name)s_Sales\n"
|
||||
" in the Google Drive name field, the document in your Google Drive and in OpenERP attachment will be named\n"
|
||||
" 'Agrolait_SO0001_Sales'."
|
||||
msgstr ""
|
||||
|
||||
#. module: google_drive
|
||||
#: view:google.drive.config:0
|
||||
msgid "- If filter is not specified, link of google document will appear in \"More\" option for all users for all opportunities."
|
||||
msgstr ""
|
||||
|
||||
#. module: google_drive
|
||||
#: view:google.drive.config:0
|
||||
msgid "To create a new filter:"
|
||||
msgstr ""
|
||||
|
||||
#. module: google_drive
|
||||
#: model:ir.model,name:google_drive.model_base_config_settings
|
||||
msgid "base.config.settings"
|
||||
msgstr ""
|
||||
|
||||
#. module: google_drive
|
||||
#: model:ir.actions.act_window,help:google_drive.action_google_drive_users_config
|
||||
msgid "<p class=\"oe_view_nocontent_create\">\n"
|
||||
" Click to add a new template.\n"
|
||||
" </p>\n"
|
||||
" <p>\n"
|
||||
" Link your own google drive templates to any record of OpenERP. If you have really specific documents you want your collaborator fill in, e.g. Use a spreadsheet to control the quality of your product or review the delivery checklist for each order in a foreign country, ... Its very easy to manage them, link them to OpenERP and use them to collaborate with your employees.\n"
|
||||
" </p>\n"
|
||||
" "
|
||||
msgstr ""
|
||||
|
||||
#. module: google_drive
|
||||
#: code:addons/google_drive/google_drive.py:150
|
||||
#, python-format
|
||||
msgid "Incorrect URL!"
|
||||
msgstr ""
|
||||
|
||||
#. module: google_drive
|
||||
#: view:base.config.settings:0
|
||||
msgid "Configure your templates"
|
||||
msgstr ""
|
||||
|
||||
#. module: google_drive
|
||||
#: help:google.drive.config,name_template:0
|
||||
msgid "Choose how the new google drive will be named, on google side. Eg. gdoc_%(field_name)s"
|
||||
msgstr ""
|
||||
|
||||
#. module: google_drive
|
||||
#: view:google.drive.config:0
|
||||
msgid "- Go to the OpenERP document you want to filter. For instance, go to Opportunities and search on Sales Department."
|
||||
msgstr ""
|
||||
|
||||
#. module: google_drive
|
||||
#: view:google.drive.config:0
|
||||
msgid "- In this \"Search\" view, select the option \"Save Current Filter\", enter the name (Ex: Sales Department)"
|
||||
msgstr ""
|
||||
|
||||
#. module: google_drive
|
||||
#: view:google.drive.config:0
|
||||
msgid "- If you select \"Share with all users\", link of google document in \"More\" options will appear for all users in opportunities of Sales Department."
|
||||
msgstr ""
|
||||
|
||||
#. module: google_drive
|
||||
#: view:google.drive.config:0
|
||||
msgid "- If you don't select \"Share with all users\", link of google document in \"More\" options will not appear for other users in opportunities of Sales Department."
|
||||
msgstr ""
|
||||
|
||||
#. module: google_drive
|
||||
#: code:addons/google_drive/google_drive.py:48
|
||||
#, python-format
|
||||
msgid "At least one key cannot be found in your Google Drive name pattern"
|
||||
msgstr ""
|
||||
|
||||
#. module: google_drive
|
||||
#: code:addons/google_drive/google_drive.py:150
|
||||
#, python-format
|
||||
msgid "Please enter a valid Google Document URL."
|
||||
msgstr ""
|
||||
|
||||
#. module: google_drive
|
||||
#: field:google.drive.config,google_drive_client_id:0
|
||||
msgid "Google Client "
|
||||
msgstr ""
|
||||
|
||||
#. module: google_drive
|
||||
#: view:google.drive.config:0
|
||||
msgid "https://docs.google.com/document/d/1vOtpJK9scIQz6taD9tJRIETWbEw3fSiaQHArsJYcua4/edit"
|
||||
msgstr ""
|
||||
|
||||
#. module: google_drive
|
||||
#: field:google.drive.config,filter_id:0
|
||||
msgid "Filter"
|
||||
msgstr ""
|
||||
|
||||
#. module: google_drive
|
||||
#: field:google.drive.config,name_template:0
|
||||
msgid "Google Drive Name Pattern"
|
||||
msgstr ""
|
||||
|
||||
#. module: google_drive
|
||||
#: help:base.config.settings,google_drive_uri:0
|
||||
msgid "The URL to generate the authorization code from Google"
|
||||
msgstr ""
|
||||
|
||||
#. module: google_drive
|
||||
#: model:ir.filters,name:google_drive.filter_partner
|
||||
msgid "Customer"
|
||||
msgstr ""
|
||||
|
||||
#. module: google_drive
|
||||
#: field:google.drive.config,google_drive_resource_id:0
|
||||
msgid "Resource Id"
|
||||
msgstr ""
|
||||
|
||||
#. module: google_drive
|
||||
#: code:addons/google_drive/google_drive.py:91
|
||||
#, python-format
|
||||
msgid "The Google Template cannot be found. Maybe it has been deleted."
|
||||
msgstr ""
|
||||
|
||||
#. module: google_drive
|
||||
#: model:ir.actions.act_window,name:google_drive.action_google_drive_users_config
|
||||
#: model:ir.ui.menu,name:google_drive.menu_google_drive_model_config
|
||||
msgid "Google Drive Templates"
|
||||
msgstr ""
|
||||
|
||||
#. module: google_drive
|
||||
#: code:addons/google_drive/google_drive.py:81
|
||||
#, python-format
|
||||
msgid "Something went wrong during the token generation. Please request again an authorization code in %(menu:base_setup.menu_general_configuration)s."
|
||||
msgstr ""
|
||||
|
||||
#. module: google_drive
|
||||
#: code:addons/google_drive/google_drive.py:124
|
||||
#, python-format
|
||||
msgid "Google Drive Error!"
|
||||
msgstr ""
|
||||
|
||||
#. module: google_drive
|
||||
#: field:base.config.settings,google_drive_uri:0
|
||||
msgid "URI"
|
||||
msgstr ""
|
||||
|
||||
#. module: google_drive
|
||||
#: code:addons/google_drive/google_drive.py:124
|
||||
#, python-format
|
||||
msgid "Creating google drive may only be done by one at a time."
|
||||
msgstr ""
|
||||
|
||||
#. module: google_drive
|
||||
#: field:google.drive.config,model:0
|
||||
#: field:google.drive.config,model_id:0
|
||||
msgid "Model"
|
||||
msgstr ""
|
||||
|
||||
#. module: google_drive
|
||||
#: view:google.drive.config:0
|
||||
msgid "Google Drive Configuration"
|
||||
msgstr ""
|
||||
|
||||
#. module: google_drive
|
||||
#: field:google.drive.config,name:0
|
||||
msgid "Template Name"
|
||||
msgstr ""
|
||||
|
||||
#. module: google_drive
|
||||
#: constraint:google.drive.config:0
|
||||
msgid "Model of selected filter is not matching with model of current template."
|
||||
msgstr ""
|
||||
|
||||
#. module: google_drive
|
||||
#: field:google.drive.config,google_drive_template_url:0
|
||||
msgid "Template URL"
|
||||
msgstr ""
|
||||
|
||||
#. module: google_drive
|
||||
#: view:base.config.settings:0
|
||||
msgid "and paste it here"
|
||||
msgstr ""
|
||||
|
||||
#. module: google_drive
|
||||
#: field:base.config.settings,google_drive_authorization_code:0
|
||||
msgid "Authorization Code"
|
||||
msgstr ""
|
||||
|
||||
#. module: google_drive
|
||||
#: model:ir.model,name:google_drive.model_google_drive_config
|
||||
msgid "Google Drive templates config"
|
||||
msgstr ""
|
||||
|
||||
#. module: google_drive
|
||||
#: code:addons/google_drive/google_drive.py:64
|
||||
#, python-format
|
||||
msgid "You haven't configured 'Authorization Code' generated from google, Please generate and configure it in %(menu:base_setup.menu_general_configuration)s."
|
||||
msgstr ""
|
||||
|
|
@ -0,0 +1,93 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<openerp>
|
||||
<data>
|
||||
|
||||
<!-- add google drive config field in user form -->
|
||||
|
||||
<record model="ir.ui.view" id="view_google_drive_config_tree">
|
||||
<field name="name">google_drive.config.tree</field>
|
||||
<field name="model">google.drive.config</field>
|
||||
<field name="arch" type="xml">
|
||||
<tree string="Google Drive Configuration">
|
||||
<field name="name" />
|
||||
<field name="model_id" />
|
||||
</tree>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record model="ir.ui.view" id="view_google_drive_config_form">
|
||||
<field name="name">google_drive.config.form</field>
|
||||
<field name="model">google.drive.config</field>
|
||||
<field name="arch" type="xml">
|
||||
<form string="Google Drive Configuration" version="7.0">
|
||||
<field name="model" invisible="1" />
|
||||
<group>
|
||||
<field name="name" />
|
||||
<field name="model_id" on_change="onchange_model_id(model_id)" />
|
||||
<label for='filter_id' />
|
||||
<div>
|
||||
<field name='filter_id' />
|
||||
<p class="oe_grey">
|
||||
<b>To create a new filter:</b><br/>
|
||||
- Go to the OpenERP document you want to filter. For instance, go to Opportunities and search on Sales Department.<br/>
|
||||
- In this "Search" view, select the option "Save Current Filter", enter the name (Ex: Sales Department)<br/>
|
||||
- If you select "Share with all users", link of google document in "More" options will appear for all users in opportunities of Sales Department.<br/>
|
||||
- If you don't select "Share with all users", link of google document in "More" options will not appear for other users in opportunities of Sales Department.<br/>
|
||||
- If filter is not specified, link of google document will appear in "More" option for all users for all opportunities.
|
||||
</p>
|
||||
</div>
|
||||
<field name='google_drive_template_url' placeholder="https://docs.google.com/document/d/1vOtpJK9scIQz6taD9tJRIETWbEw3fSiaQHArsJYcua4/edit" required="1" />
|
||||
<field name='google_drive_resource_id' invisible="1" />
|
||||
<label for='name_template' />
|
||||
<div>
|
||||
<field name='name_template' />
|
||||
<p class="oe_grey">
|
||||
The name of the attached document can use fixed or variable data. To distinguish between documents in
|
||||
Google Drive, use fixed words and fields. For instance, in the example above, if you wrote Agrolait_%%(name)s_Sales
|
||||
in the Google Drive name field, the document in your Google Drive and in OpenERP attachment will be named
|
||||
'Agrolait_SO0001_Sales'.
|
||||
</p>
|
||||
</div>
|
||||
</group>
|
||||
</form>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record model='ir.actions.act_window' id='action_google_drive_users_config'>
|
||||
<field name='name'>Google Drive Templates</field>
|
||||
<field name='res_model'>google.drive.config</field>
|
||||
<field name='type'>ir.actions.act_window</field>
|
||||
<field name='view_type'>form</field>
|
||||
<field name='view_id' ref='view_google_drive_config_tree' />
|
||||
<field name="help" type="html">
|
||||
<p class="oe_view_nocontent_create">
|
||||
Click to add a new template.
|
||||
</p>
|
||||
<p>
|
||||
Link your own google drive templates to any record of OpenERP. If you have really specific documents you want your collaborator fill in, e.g. Use a spreadsheet to control the quality of your product or review the delivery checklist for each order in a foreign country, ... Its very easy to manage them, link them to OpenERP and use them to collaborate with your employees.
|
||||
</p>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="inherited_google_view_general_configuration" model="ir.ui.view">
|
||||
<field name="name">General Settings</field>
|
||||
<field name="model">base.config.settings</field>
|
||||
<field name="inherit_id" ref="base_setup.view_general_configuration" />
|
||||
<field name="arch" type="xml">
|
||||
<xpath expr="//div[@name='module_google_drive']" position="after">
|
||||
<div attrs="{'invisible': [('module_google_drive','=',False)]}">
|
||||
<div class="oe_inline">
|
||||
<field name="google_drive_uri" widget="url" text="Generate Google Authorization Code" class="oe_inline oe_bold"/>
|
||||
and paste it here
|
||||
<field name="google_drive_authorization_code" class="oe_inline" />
|
||||
</div>
|
||||
<button type="action" name="%(google_drive.action_google_drive_users_config)d" string="Configure your templates" class="oe_link" />
|
||||
</div>
|
||||
</xpath>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<menuitem name='Google Drive configuration' id='menu_google_drive_config' parent='base.menu_administration' />
|
||||
<menuitem id='menu_google_drive_model_config' parent='menu_google_drive_config' action='action_google_drive_users_config' />
|
||||
</data>
|
||||
</openerp>
|
|
@ -0,0 +1,3 @@
|
|||
id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
|
||||
access_google_drive_all,google.drive.config,model_google_drive_config,,1,0,0,0
|
||||
access_google_drive,google.drive.config,model_google_drive_config,base.group_system,1,1,1,1
|
|
|
@ -0,0 +1,7 @@
|
|||
var gapi=window.gapi=window.gapi||{};gapi._bs=new Date().getTime();(function(){var f=null,g=encodeURIComponent,k=window,m=decodeURIComponent,n="push",r="test",t="shift",u="replace",y="length",B="split",C="join";var D=k,E=document,aa=D.location,ba=function(){},ca=/\[native code\]/,G=function(a,b,c){return a[b]=a[b]||c},da=function(a){for(var b=0;b<this[y];b++)if(this[b]===a)return b;return-1},ea=function(a){a=a.sort();for(var b=[],c=void 0,d=0;d<a[y];d++){var e=a[d];e!=c&&b[n](e);c=e}return b},H=function(){var a;if((a=Object.create)&&ca[r](a))a=a(f);else{a={};for(var b in a)a[b]=void 0}return a},I=G(D,"gapi",{});var J;J=G(D,"___jsl",H());G(J,"I",0);G(J,"hel",10);var K=function(){var a=aa.href,b;if(J.dpo)b=J.h;else{b=J.h;var c=RegExp("([#].*&|[#])jsh=([^&#]*)","g"),d=RegExp("([?#].*&|[?#])jsh=([^&#]*)","g");if(a=a&&(c.exec(a)||d.exec(a)))try{b=m(a[2])}catch(e){}}return b},fa=function(a){var b=G(J,"PQ",[]);J.PQ=[];var c=b[y];if(0===c)a();else for(var d=0,e=function(){++d===c&&a()},h=0;h<c;h++)b[h](e)},L=function(a){return G(G(J,"H",H()),a,H())};var M=G(J,"perf",H()),N=G(M,"g",H()),ga=G(M,"i",H());G(M,"r",[]);H();H();var O=function(a,b,c){var d=M.r;"function"===typeof d?d(a,b,c):d[n]([a,b,c])},Q=function(a,b,c){b&&0<b[y]&&(b=P(b),c&&0<c[y]&&(b+="___"+P(c)),28<b[y]&&(b=b.substr(0,28)+(b[y]-28)),c=b,b=G(ga,"_p",H()),G(b,c,H())[a]=(new Date).getTime(),O(a,"_p",c))},P=function(a){return a[C]("__")[u](/\./g,"_")[u](/\-/g,"_")[u](/\,/g,"_")};var S=H(),T=[],U=function(a){throw Error("Bad hint"+(a?": "+a:""));};T[n](["jsl",function(a){for(var b in a)if(Object.prototype.hasOwnProperty.call(a,b)){var c=a[b];"object"==typeof c?J[b]=G(J,b,[]).concat(c):G(J,b,c)}if(b=a.u)a=G(J,"us",[]),a[n](b),(b=/^https:(.*)$/.exec(b))&&a[n]("http:"+b[1])}]);var ha=/^(\/[a-zA-Z0-9_\-]+)+$/,ia=/^[a-zA-Z0-9\-_\.!]+$/,ja=/^gapi\.loaded_[0-9]+$/,ka=/^[a-zA-Z0-9,._-]+$/,oa=function(a,b,c,d){var e=a[B](";"),h=S[e[t]()],l=f;h&&(l=h(e,b,c,d));if(!(b=!l))b=l,c=b.match(la),d=b.match(ma),b=!(d&&1===d[y]&&na[r](b)&&c&&1===c[y]);b&&U(a);return l},qa=function(a,b,c,d){a=pa(a);ja[r](c)||U("invalid_callback");b=V(b);d=d&&d[y]?V(d):f;var e=function(a){return g(a)[u](/%2C/g,",")};return[g(a.d)[u](/%2C/g,",")[u](/%2F/g,"/"),"/k=",e(a.version),"/m=",e(b),d?"/exm="+e(d):
|
||||
"","/rt=j/sv=1/d=1/ed=1",a.a?"/am="+e(a.a):"",a.b?"/rs="+e(a.b):"","/cb=",e(c)][C]("")},pa=function(a){"/"!==a.charAt(0)&&U("relative path");for(var b=a.substring(1)[B]("/"),c=[];b[y];){a=b[t]();if(!a[y]||0==a.indexOf("."))U("empty/relative directory");else if(0<a.indexOf("=")){b.unshift(a);break}c[n](a)}a={};for(var d=0,e=b[y];d<e;++d){var h=b[d][B]("="),l=m(h[0]),p=m(h[1]);2!=h[y]||(!l||!p)||(a[l]=a[l]||p)}b="/"+c[C]("/");ha[r](b)||U("invalid_prefix");c=W(a,"k",!0);d=W(a,"am");a=W(a,"rs");return{d:b,
|
||||
version:c,a:d,b:a}},V=function(a){for(var b=[],c=0,d=a[y];c<d;++c){var e=a[c][u](/\./g,"_")[u](/-/g,"_");ka[r](e)&&b[n](e)}return b[C](",")},W=function(a,b,c){a=a[b];!a&&c&&U("missing: "+b);if(a){if(ia[r](a))return a;U("invalid: "+b)}return f},na=/^https?:\/\/[a-z0-9_.-]+\.google\.com(:\d+)?\/[a-zA-Z0-9_.,!=\-\/]+$/,ma=/\/cb=/g,la=/\/\//g,ra=function(){var a=K();if(!a)throw Error("Bad hint");return a};S.m=function(a,b,c,d){(a=a[0])||U("missing_hint");return"https://apis.google.com"+qa(a,b,c,d)};var X=decodeURI("%73cript"),Y=function(a,b){for(var c=[],d=0;d<a[y];++d){var e=a[d];e&&0>da.call(b,e)&&c[n](e)}return c},sa=function(a){"loading"!=E.readyState?Z(a):E.write("<"+X+' src="'+encodeURI(a)+'"></'+X+">")},Z=function(a){var b=E.createElement(X);b.setAttribute("src",a);b.async="true";(a=E.getElementsByTagName(X)[0])?a.parentNode.insertBefore(b,a):(E.head||E.body||E.documentElement).appendChild(b)},ta=function(a,b){var c=b&&b._c;if(c)for(var d=0;d<T[y];d++){var e=T[d][0],h=T[d][1];h&&Object.prototype.hasOwnProperty.call(c,
|
||||
e)&&h(c[e],a,b)}},ua=function(a,b){$(function(){var c;c=b===K()?G(I,"_",H()):H();c=G(L(b),"_",c);a(c)})},wa=function(a,b){var c=b||{};"function"==typeof b&&(c={},c.callback=b);ta(a,c);var d=a?a[B](":"):[],e=c.h||ra(),h=G(J,"ah",H());if(!h["::"]||!d[y])va(d||[],c,e);else{for(var l=[],p=f;p=d[t]();){var v=p[B]("."),v=h[p]||h[v[1]&&"ns:"+v[0]||""]||e,s=l[y]&&l[l[y]-1]||f,z=s;if(!s||s.hint!=v)z={hint:v,c:[]},l[n](z);z.c[n](p)}var A=l[y];if(1<A){var F=c.callback;F&&(c.callback=function(){0==--A&&F()})}for(;d=
|
||||
l[t]();)va(d.c,c,d.hint)}},va=function(a,b,c){a=ea(a)||[];var d=b.callback,e=b.config,h=b.timeout,l=b.ontimeout,p=f,v=!1;if(h&&!l||!h&&l)throw"Timeout requires both the timeout parameter and ontimeout parameter to be set";var s=G(L(c),"r",[]).sort(),z=G(L(c),"L",[]).sort(),A=[].concat(s),F=function(a,b){if(v)return 0;D.clearTimeout(p);z[n].apply(z,q);var d=((I||{}).config||{}).update;d?d(e):e&&G(J,"cu",[])[n](e);if(b){Q("me0",a,A);try{ua(b,c)}finally{Q("me1",a,A)}}return 1};0<h&&(p=D.setTimeout(function(){v=
|
||||
!0;l()},h));var q=Y(a,z);if(q[y]){var q=Y(a,s),w=G(J,"CP",[]),x=w[y];w[x]=function(a){if(!a)return 0;Q("ml1",q,A);var b=function(b){w[x]=f;F(q,a)&&fa(function(){d&&d();b()})},c=function(){var a=w[x+1];a&&a()};0<x&&w[x-1]?w[x]=function(){b(c)}:b(c)};if(q[y]){var R="loaded_"+J.I++;I[R]=function(a){w[x](a);I[R]=f};a=oa(c,q,"gapi."+R,s);s[n].apply(s,q);Q("ml0",q,A);b.sync||D.___gapisync?sa(a):Z(a)}else w[x](ba)}else F(q)&&d&&d()};var $=function(a){if(J.hee&&0<J.hel)try{return a()}catch(b){J.hel--,wa("debug_error",function(){k.___jsl.hefn(b)})}else return a()};I.load=function(a,b){return $(function(){return wa(a,b)})};N.bs0=k.gapi._bs||(new Date).getTime();O("bs0");N.bs1=(new Date).getTime();O("bs1");delete k.gapi._bs;})();
|
||||
gapi.load("client",{callback:window["gapi_onload"],_c:{"jsl":{"ci":{"services":{},"deviceType":"desktop","lexps":[102,103,100,71,98,96,110,108,79,106,45,17,86,81,112,61,30],"inline":{"css":1},"report":{},"oauth-flow":{"disableOpt":true,"authUrl":"https://accounts.google.com/o/oauth2/auth","proxyUrl":"https://accounts.google.com/o/oauth2/postmessageRelay","persist":true},"isLoggedIn":true,"isPlusUser":true,"iframes":{"additnow":{"methods":["launchurl"],"url":"https://apis.google.com/additnow/additnow.html?bsv"},"shortlists":{"url":"?bsv"},"plus":{"methods":["onauth"],"url":":socialhost:/u/:session_index:/_/pages/badge?bsv"},":socialhost:":"https://plusone.google.com","recobox":{"params":{"url":""},"url":":socialhost:/:session_prefix:_/widget/render/recobox?bsv"},"plus_followers":{"params":{"url":""},"url":":socialhost:/_/im/_/widget/render/plus/followers?bsv"},"autocomplete":{"params":{"url":""},"url":":socialhost:/:session_prefix:_/widget/render/autocomplete?bsv"},"plus_share":{"params":{"url":""},"url":":socialhost:/:session_prefix:_/+1/sharebutton?plusShare\u003dtrue\u0026bsv"},"savetowallet":{"url":"https://clients5.google.com/s2w/o/savetowallet?bsv"},"panoembed":{"url":"https://ssl.gstatic.com/pano/embed/?bsv"},"signin":{"methods":["onauth"],"params":{"url":""},"url":":socialhost:/:session_prefix:_/widget/render/signin?bsv"},"appcirclepicker":{"url":":socialhost:/:session_prefix:_/widget/render/appcirclepicker?bsv"},"commentcount":{"url":":socialhost:/:session_prefix:_/widget/render/commentcount?bsv"},"hangout":{"url":"https://talkgadget.google.com/:session_prefix:talkgadget/_/widget?bsv"},"plus_circle":{"params":{"url":""},"url":":socialhost:/:session_prefix:_/widget/plus/circle?bsv"},"savetodrive":{"methods":["save"],"url":"https://drive.google.com/savetodrivebutton?usegapi\u003d1\u0026bsv"},"card":{"url":":socialhost:/:session_prefix:_/hovercard/card?bsv"},"evwidget":{"params":{"url":""},"url":":socialhost:/:session_prefix:_/events/widget?bsv"},"zoomableimage":{"url":"https://ssl.gstatic.com/microscope/embed/?bsv"},":signuphost:":"https://plus.google.com","plusone":{"preloadUrl":["https://ssl.gstatic.com/s2/oz/images/stars/po/Publisher/sprite4-a67f741843ffc4220554c34bd01bb0bb.png"],"params":{"count":"","size":"","url":""},"url":":socialhost:/:session_prefix:_/+1/fastbutton?bsv"},"comments":{"methods":["scroll","openwindow"],"params":{"location":["search","hash"]},"url":":socialhost:/:session_prefix:_/widget/render/comments?bsv"}},"debug":{"host":"https://plusone.google.com","reportExceptionRate":0.05,"rethrowException":true},"csi":{"rate":0.01},"googleapis.config":{"mobilesignupurl":"https://m.google.com/app/plus/oob?"}},"h":"m;/_/scs/apps-static/_/js/k\u003doz.gapi.en.02N985CHyyc.O/m\u003d__features__/am\u003dIQ/rt\u003dj/d\u003d1/rs\u003dAItRSTPZZ0JVQCv9Qljsu0NQlsb1ZzD2zQ","u":"https://apis.google.com/js/client.js","hee":true,"fp":"e2aa6cd0095417dbec61deca3abed1394160dab3","dpo":false},"fp":"e2aa6cd0095417dbec61deca3abed1394160dab3","annotation":["autocomplete","profile","interactivepost"],"bimodal":["signin"]}});
|
Binary file not shown.
After Width: | Height: | Size: 2.1 KiB |
Binary file not shown.
After Width: | Height: | Size: 479 B |
Binary file not shown.
After Width: | Height: | Size: 19 KiB |
|
@ -0,0 +1,71 @@
|
|||
openerp.google_drive = function (instance, m) {
|
||||
var _t = instance.web._t,
|
||||
QWeb = instance.web.qweb;
|
||||
|
||||
instance.web.Sidebar.include({
|
||||
start: function () {
|
||||
var self = this;
|
||||
var ids
|
||||
this._super.apply(this, arguments);
|
||||
var view = self.getParent();
|
||||
var result;
|
||||
if (view.fields_view.type == "form") {
|
||||
ids = []
|
||||
view.on("load_record", self, function (r) {
|
||||
ids = [r.id]
|
||||
self.add_gdoc_items(view, r.id)
|
||||
});
|
||||
}
|
||||
},
|
||||
add_gdoc_items: function (view, res_id) {
|
||||
var self = this;
|
||||
var gdoc_item = _.indexOf(_.pluck(self.items.other, 'classname'), 'oe_share_gdoc');
|
||||
if (gdoc_item !== -1) {
|
||||
self.items.other.splice(gdoc_item, 1);
|
||||
}
|
||||
if (res_id) {
|
||||
view.sidebar_eval_context().done(function (context) {
|
||||
var ds = new instance.web.DataSet(this, 'google.drive.config', context);
|
||||
ds.call('get_google_drive_config', [view.dataset.model, res_id, context]).done(function (r) {
|
||||
if (!_.isEmpty(r)) {
|
||||
_.each(r, function (res) {
|
||||
var g_item = _.indexOf(_.pluck(self.items.other, 'label'), res.name);
|
||||
if (g_item !== -1) {
|
||||
self.items.other.splice(g_item, 1);
|
||||
}
|
||||
self.add_items('other', [{
|
||||
label: res.name+ '<img style="position:absolute;right:5px;height:20px;width:20px;" title="Google Drive" src="google_drive/static/src/img/drive_icon.png"/>',
|
||||
config_id: res.id,
|
||||
res_id: res_id,
|
||||
res_model: view.dataset.model,
|
||||
callback: self.on_google_doc,
|
||||
classname: 'oe_share_gdoc'
|
||||
},
|
||||
]);
|
||||
})
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
fetch: function (model, fields, domain, ctx) {
|
||||
return new instance.web.Model(model).query(fields).filter(domain).context(ctx).all()
|
||||
},
|
||||
|
||||
on_google_doc: function (doc_item) {
|
||||
var self = this;
|
||||
self.config = doc_item;
|
||||
var loaded = self.fetch('google.drive.config', ['google_drive_resource_id', 'google_drive_client_id'], [['id', '=', doc_item.config_id]])
|
||||
.then(function (configs) {
|
||||
var ds = new instance.web.DataSet(self, 'google.drive.config');
|
||||
ds.call('get_google_drive_url', [doc_item.config_id, doc_item.res_id,configs[0].google_drive_resource_id]).done(function (url) {
|
||||
if (url){
|
||||
window.open(url, '_blank');
|
||||
}
|
||||
});
|
||||
});
|
||||
},
|
||||
|
||||
});
|
||||
};
|
Loading…
Reference in New Issue