[MIG] google_drive : migrate to new api

This commit is contained in:
vbh-odoo
2016-05-31 09:09:22 +02:00
committed by Jérome Maes
parent b581e2004f
commit 3174d2f56e
7 changed files with 170 additions and 172 deletions
+1 -1
View File
@@ -10,9 +10,9 @@
'data': [
'security/ir.model.access.csv',
'data/google_drive_data.xml',
'views/res_config_views.xml',
'views/google_drive_views.xml',
'views/google_drive_templates.xml',
'views/res_config_views.xml',
],
'demo': [
'data/google_drive_demo.xml'
@@ -1,13 +1,13 @@
<?xml version="1.0"?>
<openerp>
<odoo>
<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">598905559630.apps.googleusercontent.com</field>
<field name="group_ids" eval="[(4, ref('base.group_system'))]" />
</record>
<record id="config_google_drive_client_secret" model="ir.config_parameter">
<field name="key">google_drive_client_secret</field>
<field name="value">vTmou73c-njP-1qCxm7qx7QE</field>
@@ -15,4 +15,4 @@
</record>
</data>
</openerp>
</odoo>
@@ -1,5 +1,5 @@
<?xml version="1.0"?>
<openerp>
<odoo>
<data noupdate="1">
<!-- filter demo -->
@@ -18,7 +18,6 @@
<field name="google_drive_template_url">https://docs.google.com/spreadsheet/ccc?key=1eIM-q7PX9wp1vEUUdUvrmAe8V3Do60vXDETulNmI9mA#gid=0</field>
<field name="name_template">Partner Review %(name)s</field>
</record>
</data>
</openerp>
</data>
</odoo>
+117 -112
View File
@@ -1,85 +1,92 @@
# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
import logging
from openerp import SUPERUSER_ID
from openerp.addons.google_account import TIMEOUT
from openerp.osv import fields, osv
from openerp.tools.translate import _
from openerp.tools.safe_eval import safe_eval as eval
from openerp.exceptions import UserError
import werkzeug.urls
import urllib2
import json
import re
import openerp
import urllib2
import werkzeug.urls
from odoo import api, fields, models
from odoo.exceptions import RedirectWarning, UserError
from odoo.tools.safe_eval import safe_eval as eval
from odoo.tools.translate import _
from odoo.addons.google_account import TIMEOUT
_logger = logging.getLogger(__name__)
class config(osv.Model):
class GoogleDrive(models.Model):
_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)[0]
record.update({'model': model.name, 'filter': filter_name})
name_gdocs = config.name_template
@api.multi
def get_google_drive_url(self, res_id, template_id):
self.ensure_one()
self = self.sudo()
model = self.model_id
filter_name = self.filter_id.name if self.filter_id else False
record = self.env[model.model].browse(res_id).read()[0]
record.update({
'model': model.name,
'filter': filter_name
})
name_gdocs = self.name_template
try:
name_gdocs = name_gdocs % record
except:
raise UserError(_("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)])
attachments = self.env["ir.attachment"].search([('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
if attachments:
url = attachments[0].url
else:
url = self.copy_doc(cr, uid, res_id, template_id, name_gdocs, model.model, context).get('url')
url = self.copy_doc(res_id, template_id, name_gdocs, model.model).get('url')
return url
def get_access_token(self, cr, uid, scope=None, context=None):
ir_config = self.pool['ir.config_parameter']
google_drive_refresh_token = ir_config.get_param(cr, SUPERUSER_ID, 'google_drive_refresh_token')
@api.model
def get_access_token(self, scope=None):
Config = self.env['ir.config_parameter']
google_drive_refresh_token = Config.sudo().get_param('google_drive_refresh_token')
user_is_admin = self.env['res.users'].browse(self.env.user.id)._is_admin()
if not google_drive_refresh_token:
if self.pool['res.users']._is_admin(cr, uid, [uid]):
model, action_id = self.pool['ir.model.data'].get_object_reference(cr, uid, 'base_setup', 'action_general_configuration')
if user_is_admin:
dummy, action_id = self.env['ir.model.data'].get_object_reference('base_setup', 'action_general_configuration')
msg = _("You haven't configured 'Authorization Code' generated from google, Please generate and configure it .")
raise openerp.exceptions.RedirectWarning(msg, action_id, _('Go to the configuration panel'))
raise RedirectWarning(msg, action_id, _('Go to the configuration panel'))
else:
raise UserError(_("Google Drive is not yet configured. Please contact your administrator."))
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_drive_client_id = Config.sudo().get_param('google_drive_client_id')
google_drive_client_secret = Config.sudo().get_param('google_drive_client_secret')
#For Getting New Access Token With help of old Refresh Token
data = werkzeug.url_encode(dict(client_id=google_drive_client_id,
refresh_token=google_drive_refresh_token,
client_secret=google_drive_client_secret,
grant_type="refresh_token",
scope=scope or 'https://www.googleapis.com/auth/drive'))
data = werkzeug.url_encode({
'client_id': google_drive_client_id,
'refresh_token': google_drive_refresh_token,
'client_secret': google_drive_client_secret,
'grant_type': "refresh_token",
'scope': scope or 'https://www.googleapis.com/auth/drive'
})
headers = {"Content-type": "application/x-www-form-urlencoded"}
try:
req = urllib2.Request('https://accounts.google.com/o/oauth2/token', data, headers)
content = urllib2.urlopen(req, timeout=TIMEOUT).read()
except urllib2.HTTPError:
if user_is_admin:
model, action_id = self.pool['ir.model.data'].get_object_reference(cr, uid, 'base_setup', 'action_general_configuration')
dummy, action_id = self.env['ir.model.data'].get_object_reference('base_setup', 'action_general_configuration')
msg = _("Something went wrong during the token generation. Please request again an authorization code .")
raise openerp.exceptions.RedirectWarning(msg, action_id, _('Go to the configuration panel'))
raise RedirectWarning(msg, action_id, _('Go to the configuration panel'))
else:
raise UserError(_("Google Drive is not yet configured. Please contact your administrator."))
content = json.loads(content)
return content.get('access_token')
def copy_doc(self, cr, uid, res_id, template_id, name_gdocs, res_model, context=None):
ir_config = self.pool['ir.config_parameter']
google_web_base_url = ir_config.get_param(cr, SUPERUSER_ID, 'web.base.url')
access_token = self.get_access_token(cr, uid, context=context)
@api.model
def copy_doc(self, res_id, template_id, name_gdocs, res_model):
google_web_base_url = self.env['ir.config_parameter'].sudo().get_param('web.base.url')
access_token = self.get_access_token()
# Copy template in to drive with help of new access token
request_url = "https://www.googleapis.com/drive/v2/files/%s?fields=parents/id&access_token=%s" % (template_id, access_token)
headers = {"Content-type": "application/x-www-form-urlencoded"}
@@ -90,10 +97,17 @@ class config(osv.Model):
raise UserError(_("The Google Template cannot be found. Maybe it has been deleted."))
parents_dict = json.loads(parents)
record_url = "Click on link to open Record in Odoo\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']}
record_url = "Click on link to open Record in Odoo\n %s/?db=%s#id=%s&model=%s" % (google_web_base_url, self._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, access_token)
headers = {'Content-type': 'application/json', 'Accept': 'text/plain'}
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)
@@ -101,11 +115,15 @@ class config(osv.Model):
content = json.loads(content)
res = {}
if content.get('alternateLink'):
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']}
res['id'] = attach_pool.create(cr, uid, attach_vals)
res['id'] = self.env["ir.attachment"].create({
'res_model': res_model,
'name': name_gdocs,
'res_id': res_id,
'type': 'url',
'url': content['alternateLink']
}).id
# Commit in order to attach the document to the current object instance, even if the permissions has not been written.
cr.commit()
self._cr.commit()
res['url'] = content['alternateLink']
key = self._get_key_from_url(res['url'])
request_url = "https://www.googleapis.com/drive/v2/files/%s/permissions?emailMessage=This+is+a+drive+file+created+by+Odoo&sendNotificationEmails=false&access_token=%s" % (key, access_token)
@@ -114,10 +132,9 @@ class config(osv.Model):
req = urllib2.Request(request_url, json.dumps(data), headers)
urllib2.urlopen(req, timeout=TIMEOUT)
except urllib2.HTTPError:
raise self.pool.get('res.config.settings').get_config_warning(cr, _("The permission 'reader' for 'anyone with the link' has not been written on the document"), context=context)
user = self.pool['res.users'].browse(cr, uid, uid, context=context)
if user.email:
data = {'role': 'writer', 'type': 'user', 'value': user.email}
raise self.env['res.config.settings'].get_config_warning(_("The permission 'reader' for 'anyone with the link' has not been written on the document"))
if self.env.user.email:
data = {'role': 'writer', 'type': 'user', 'value': self.env.user.email}
try:
req = urllib2.Request(request_url, json.dumps(data), headers)
urllib2.urlopen(req, timeout=TIMEOUT)
@@ -125,7 +142,8 @@ class config(osv.Model):
pass
return res
def get_google_drive_config(self, cr, uid, res_model, res_id, context=None):
@api.model
def get_google_drive_config(self, res_model, res_id):
'''
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
@@ -140,81 +158,68 @@ class config(osv.Model):
if not res_id:
raise UserError(_("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):
configs = self.search([('model_id', '=', res_model)])
config_values = []
for config in configs:
if config.filter_id:
if (config.filter_id.user_id and config.filter_id.user_id.id != uid):
if config.filter_id.user_id and config.filter_id.user_id.id != self.env.user.id:
#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)
additionnal_context = eval(config.filter_id.context)
google_doc_configs = self.env[config.filter_id.model_id].with_context(**additionnal_context).search(domain)
if google_doc_configs:
configs.append({'id': config.id, 'name': config.name})
config_values.append({'id': config.id, 'name': config.name})
else:
configs.append({'id': config.id, 'name': config.name})
return configs
config_values.append({'id': config.id, 'name': config.name})
return config_values
name = fields.Char('Template Name', required=True)
model_id = fields.Many2one('ir.model', 'Model', ondelete='set null', required=True)
model = fields.Char('Model', related='model_id.model', readonly=True)
filter_id = fields.Many2one('ir.filters', 'Filter', domain="[('model_id', '=', model)]")
google_drive_template_url = fields.Char('Template URL', required=True)
google_drive_resource_id = fields.Char('Resource Id', compute='_compute_ressource_id')
google_drive_client_id = fields.Char('Google Client', compute='_compute_client_id')
name_template = fields.Char('Google Drive Name Pattern', default='Document %(name)s', help='Choose how the new google drive will be named, on google side. Eg. gdoc_%(field_name)s', required=True)
active = fields.Boolean('Active', default=True)
def _get_key_from_url(self, url):
mo = re.search("(key=|/d/)([A-Za-z0-9-_]+)", url)
if mo:
return mo.group(2)
word = re.search("(key=|/d/)([A-Za-z0-9-_]+)", url)
if word:
return word.group(2)
return None
def _resource_get(self, cr, uid, ids, name, arg, context=None):
@api.multi
def _compute_ressource_id(self):
result = {}
for data in self.browse(cr, uid, ids, context):
mo = self._get_key_from_url(data.google_drive_template_url)
if mo:
result[data.id] = mo
for record in self:
word = self._get_key_from_url(record.google_drive_template_url)
if word:
record.google_drive_resource_id = word
else:
raise UserError(_("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
@api.multi
def _compute_client_id(self):
google_drive_client_id = self.env['ir.config_parameter'].sudo().get_param('google_drive_client_id')
for record in self:
record.google_drive_client_id = google_drive_client_id
_columns = {
'name': fields.char('Template Name', required=True),
'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', help='Choose how the new google drive will be named, on google side. Eg. gdoc_%(field_name)s', required=True),
'active': fields.boolean('Active'),
}
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}
@api.onchange('model_id')
def _onchange_model_id(self):
if self.model_id:
self.model = self.model_id.model
else:
res['value'] = {'filter_id': False, 'model': False}
return res
self.filter_id = False
self.model = False
_defaults = {
'name_template': 'Document %(name)s',
'active': True,
}
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:
@api.constrains('model_id', 'filter_id')
def _check_model_id(self):
if self.filter_id and self.model_id.model != self.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']),
]
def get_google_scope(self):
return 'https://www.googleapis.com/auth/drive https://www.googleapis.com/auth/drive.file'
+20 -33
View File
@@ -1,43 +1,30 @@
# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
from openerp import SUPERUSER_ID
from openerp.osv import fields, osv
from odoo import api, fields, models
class base_config_settings(osv.TransientModel):
class BaseConfigSettings(models.TransientModel):
_inherit = "base.config.settings"
def _get_drive_uri(self, cr, uid, ids, field_name, arg, context=None):
return {
wizard_id: self.default_get(cr, uid, ['google_drive_uri']).get('google_drive_uri')
for wizard_id in ids
}
@api.model
def _default_google_drive_authorization_code(self):
return self.env['ir.config_parameter'].sudo().get_param('google_drive_authorization_code')
def _get_wizard_ids(self, cr, uid, ids, context=None):
result = []
if any(rec.key in ['google_drive_client_id', 'google_redirect_uri'] for rec in self.browse(cr, uid, ids, context=context)):
result.extend(self.pool['base.config.settings'].search(cr, uid, [], context=context))
return result
google_drive_authorization_code = fields.Char(string='Authorization Code', default=_default_google_drive_authorization_code)
google_drive_uri = fields.Char(compute='_compute_drive_uri', string='URI', help="The URL to generate the authorization code from Google")
_columns = {
'google_drive_authorization_code': fields.char('Authorization Code'),
'google_drive_uri': fields.function(_get_drive_uri, string='URI', help="The URL to generate the authorization code from Google", type="char", store={
'ir.config_parameter': (_get_wizard_ids, None, 20),
}), # TODO: 1. in master, remove the store, there is no reason for this field to be stored. It's just a dynamic link.
# TODO: 2. when converted to the new API, the code to get the default value can be moved to the compute method directly, and the default value can be removed
# the only reason the default value is defined is because function fields are not computed in draft mode in the old API.
}
_defaults = {
'google_drive_uri': lambda s, cr, uid, c: s.pool['google.service']._get_google_token_uri(cr, uid, 'drive', scope=s.pool['google.drive.config'].get_google_scope(), context=c),
'google_drive_authorization_code': lambda s, cr, uid, c: s.pool['ir.config_parameter'].get_param(cr, SUPERUSER_ID, 'google_drive_authorization_code', context=c),
}
@api.depends('google_drive_authorization_code')
def _compute_drive_uri(self):
google_drive_uri = self.env['google.service']._get_google_token_uri('drive', scope=self.env['google.drive.config'].get_google_scope())
for config in self:
config.google_drive_uri = google_drive_uri
def set_google_authorization_code(self, cr, uid, ids, context=None):
ir_config_param = self.pool['ir.config_parameter']
config = self.browse(cr, uid, ids[0], context)
auth_code = config.google_drive_authorization_code
if auth_code and auth_code != ir_config_param.get_param(cr, uid, 'google_drive_authorization_code', context=context):
refresh_token = self.pool['google.service'].generate_refresh_token(cr, uid, 'drive', config.google_drive_authorization_code, context=context)
ir_config_param.set_param(cr, uid, 'google_drive_authorization_code', auth_code, groups=['base.group_system'])
ir_config_param.set_param(cr, uid, 'google_drive_refresh_token', refresh_token, groups=['base.group_system'])
@api.multi
def set_google_authorization_code(self):
self.ensure_one()
ICP = self.env['ir.config_parameter']
if self.google_drive_authorization_code and self.google_drive_authorization_code != ICP.get_param('google_drive_authorization_code'):
refresh_token = self.env['google.service'].generate_refresh_token('drive', self.google_drive_authorization_code)
ICP.set_param('google_drive_authorization_code', self.google_drive_authorization_code, groups=['base.group_system'])
ICP.set_param('google_drive_refresh_token', refresh_token, groups=['base.group_system'])
@@ -1,10 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<openerp>
<data>
<template id="assets_backend" name="google_drive assets" inherit_id="web.assets_backend">
<xpath expr="." position="inside">
<script type="text/javascript" src="/google_drive/static/src/js/gdrive.js"></script>
</xpath>
</template>
</data>
</openerp>
<odoo>
<template id="assets_backend" name="google_drive assets" inherit_id="web.assets_backend">
<xpath expr="." position="inside">
<script type="text/javascript" src="/google_drive/static/src/js/gdrive.js"></script>
</xpath>
</template>
</odoo>
@@ -1,8 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<openerp>
<data>
<odoo>
<!-- add google drive config field in user form -->
<record model="ir.ui.view" id="view_google_drive_config_tree">
<record id="view_google_drive_config_tree" model="ir.ui.view">
<field name="name">google_drive.config.tree</field>
<field name="model">google.drive.config</field>
<field name="arch" type="xml">
@@ -13,7 +13,7 @@
</field>
</record>
<record model="ir.ui.view" id="view_google_drive_config_form">
<record id="view_google_drive_config_form" model="ir.ui.view">
<field name="name">google_drive.config.form</field>
<field name="model">google.drive.config</field>
<field name="arch" type="xml">
@@ -52,7 +52,7 @@
</field>
</record>
<record model='ir.actions.act_window' id='action_google_drive_users_config'>
<record id='action_google_drive_users_config' model='ir.actions.act_window'>
<field name='name'>Templates</field>
<field name='res_model'>google.drive.config</field>
<field name='type'>ir.actions.act_window</field>
@@ -68,7 +68,14 @@
</field>
</record>
<menuitem name='Google Drive' 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>
<menuitem
id='menu_google_drive_config'
name='Google Drive'
parent='base.menu_administration' />
<menuitem
id='menu_google_drive_model_config'
parent='menu_google_drive_config'
action='action_google_drive_users_config' />
</odoo>