2012-03-02 10:35:05 +00:00
##############################################################################
#
# 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/>.
#
##############################################################################
2012-12-09 18:22:37 +00:00
import logging
2012-11-01 07:18:46 +00:00
from datetime import datetime
2012-12-09 18:22:37 +00:00
2012-12-06 14:56:32 +00:00
from openerp . tools import DEFAULT_SERVER_DATETIME_FORMAT
2013-03-05 13:17:57 +00:00
from openerp import SUPERUSER_ID
2012-12-06 14:56:32 +00:00
from openerp . osv import fields , osv
from openerp . tools . translate import _
2013-03-05 13:17:57 +00:00
from urlparse import urlparse
2012-12-09 18:22:37 +00:00
_logger = logging . getLogger ( __name__ )
2012-03-02 10:35:05 +00:00
try :
import gdata . docs . data
import gdata . docs . client
2013-02-01 11:51:53 +00:00
# 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 )
2012-03-02 10:35:05 +00:00
except ImportError :
2012-10-10 20:47:33 +00:00
_logger . warning ( " Please install latest gdata-python-client from http://code.google.com/p/gdata-python-client/downloads/list " )
2012-02-24 10:52:15 +00:00
2013-02-01 11:51:53 +00:00
2012-02-29 18:45:20 +00:00
class google_docs_ir_attachment ( osv . osv ) :
2012-02-29 12:29:40 +00:00
_inherit = ' ir.attachment '
2012-02-24 10:52:15 +00:00
2012-05-23 09:51:36 +00:00
def _auth ( self , cr , uid , context = None ) :
2012-03-28 08:29:48 +00:00
'''
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 ' )
2012-05-23 09:51:36 +00:00
#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.
2013-02-01 11:51:53 +00:00
user_config = google_pool . default_get ( cr , uid , { ' user ' : ' ' , ' password ' : ' ' } , context = context )
2012-03-28 08:29:48 +00:00
#login gmail account
2013-02-01 11:51:53 +00:00
client = google_pool . google_login ( user_config [ ' user ' ] , user_config [ ' password ' ] , type = ' docs_client ' , context = context )
2012-03-28 09:47:18 +00:00
if not client :
2013-02-01 11:51:53 +00:00
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 ' ] )
2012-02-29 18:45:20 +00:00
return client
2012-02-24 10:52:15 +00:00
2013-03-08 13:30:39 +00:00
# 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.SPREADSHEET_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}
2012-02-24 10:52:15 +00:00
2012-05-23 09:51:36 +00:00
def copy_gdoc ( self , cr , uid , res_model , res_id , name_gdocs , gdoc_template_id , context = None ) :
2012-03-28 11:41:13 +00:00
'''
copy an existing document in google docs
2012-05-23 09:51:36 +00:00
: 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
2012-03-28 11:41:13 +00:00
'''
2012-05-23 09:51:36 +00:00
#login with the base account google module
2012-03-28 08:29:48 +00:00
client = self . _auth ( cr , uid )
2012-02-29 18:45:20 +00:00
# fetch and copy the original document
2012-03-28 11:41:13 +00:00
try :
2013-02-01 11:51:53 +00:00
doc = client . get_resource_by_id ( gdoc_template_id )
2012-03-28 11:41:13 +00:00
#copy the document you choose in the configuration
2013-02-01 11:51:53 +00:00
copy_resource = client . copy_resource ( doc , name_gdocs )
2012-03-28 11:41:13 +00:00
except :
2013-02-25 09:16:39 +00:00
raise osv . except_osv ( _ ( ' Google Drive Error! ' ) , _ ( " Your resource id is not correct. You can find the id in the google docs URL. " ) )
2012-05-23 09:51:36 +00:00
# create an ir.attachment
2012-03-01 14:45:07 +00:00
self . create ( cr , uid , {
2012-05-23 09:51:36 +00:00
' res_model ' : res_model ,
' res_id ' : res_id ,
2012-03-01 14:45:07 +00:00
' type ' : ' url ' ,
2012-03-30 14:51:49 +00:00
' name ' : name_gdocs ,
2012-03-01 14:45:07 +00:00
' url ' : copy_resource . get_alternate_link ( ) . href
2012-05-23 09:51:36 +00:00
} , context = context )
return copy_resource . resource_id . text
2012-02-29 18:45:20 +00:00
2012-05-23 09:51:36 +00:00
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
'''
2012-10-19 10:40:20 +00:00
if len ( ids ) != 1 :
2013-02-25 09:16:39 +00:00
raise osv . except_osv ( _ ( ' Google Drive Error! ' ) , _ ( " Creating google drive may only be done by one at a time. " ) )
2012-05-23 09:51:36 +00:00
res_id = ids [ 0 ]
2012-03-30 14:51:49 +00:00
pool_gdoc_config = self . pool . get ( ' google.docs.config ' )
2012-05-23 09:51:36 +00:00
2013-03-08 13:30:39 +00:00
config_ids = pool_gdoc_config . search ( cr , uid , [ ( ' model_id ' , ' = ' , res_model ) ] , context = context )
config = [ ]
for config_id in config_ids :
action = pool_gdoc_config . browse ( cr , uid , config_id , context = context )
if action . filter_id :
google_doc_configs = self . _filt ( cr , uid , action , action . filter_id , res_id , context = context )
print google_doc_configs , ' rrrrrrrrrrr ' , res_id
if google_doc_configs :
config . append ( action . name_template )
else :
config . append ( action . name_template )
return config
def _filt ( self , cr , uid , action , action_filter , record_ids , context = None ) :
""" filter the list record_ids that satisfy the action filter """
records = { }
if record_ids and action_filter :
assert action . model_id . model == action_filter . model_id , " Filter model different from action rule model "
print ' aaction_filter ' , action_filter . model_id
model = self . pool . get ( action_filter . model_id )
domain = [ ( ' id ' , ' in ' , [ record_ids ] ) ] + eval ( action_filter . domain )
ctx = dict ( context or { } )
ctx . update ( eval ( action_filter . context ) )
print ' domain--------- ' , domain
record_ids = model . search ( cr , uid , domain , context = ctx )
return record_ids
def get_attachment ( self , cr , uid , res_model , rec_name , ids , context = None ) :
res_id = ids [ 0 ]
pool_gdoc_config = self . pool . get ( ' google.docs.config ' )
action_dom = [ ( ' model_id ' , ' = ' , res_model ) ]
config_ids = pool_gdoc_config . search ( cr , uid , action_dom , context = context ) [ 0 ]
action = pool_gdoc_config . browse ( cr , uid , config_ids , context = context )
attachment = { }
attach_ids = self . search ( cr , uid , [ ( ' res_model ' , ' = ' , res_model ) , ( ' name ' , ' = ' , action . name_template ) , ( ' res_id ' , ' = ' , res_id ) ] )
if not attach_ids :
google_template_id = action . gdocs_resource_id
self . copy_gdoc ( cr , uid , action . model_id . model , ids [ 0 ] , action . name_template , google_template_id , context = context )
attach_ids = self . search ( cr , uid , [ ( ' res_model ' , ' = ' , res_model ) , ( ' name ' , ' = ' , action . name_template ) ] )
attachments = self . browse ( cr , uid , attach_ids , context ) [ 0 ]
attachment [ ' url ' ] = attachments . url
return attachment
2012-03-05 16:11:15 +00:00
2012-03-12 14:41:31 +00:00
class config ( osv . osv ) :
_name = ' google.docs.config '
2013-02-25 09:16:39 +00:00
_description = " Google Drive templates config "
2013-03-05 13:17:57 +00:00
def _resource_get ( self , cr , uid , ids , name , arg , context = None ) :
result = { }
for data in self . browse ( cr , uid , ids , context ) :
template_url = data . gdocs_template_url
url = urlparse ( template_url )
res = url . path . split ( ' / ' )
resource = res [ 1 ]
if res [ 1 ] == " spreadsheet " :
key = url . query . split ( ' = ' ) [ 1 ]
else :
key = res [ 3 ]
res_id = resource + " : " + key
result [ data . id ] = str ( res_id )
return result
2012-02-29 18:45:20 +00:00
_columns = {
2012-09-26 14:08:02 +00:00
' model_id ' : fields . many2one ( ' ir.model ' , ' Model ' , required = True ) ,
2013-02-28 07:28:22 +00:00
' filter_id ' : fields . many2one ( ' ir.filters ' , ' Filter ' ) ,
2013-03-05 13:17:57 +00:00
' gdocs_template_url ' : fields . char ( ' Template Url ' , required = True , size = 1024 ) ,
' gdocs_resource_id ' : fields . function ( _resource_get , type = " char " , string = ' Resource Id ' , store = True ) ,
2013-02-25 09:16:39 +00:00
' 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 ) ,
2012-02-29 18:45:20 +00:00
}
2013-03-08 13:30:39 +00:00
def onchange_model_id ( self , cr , uid , ids , model_id , name_template ) :
2013-03-04 05:20:58 +00:00
res = { ' domain ' : { ' filter_id ' : [ ] } }
if model_id :
2013-03-08 13:30:39 +00:00
model_name = self . pool . get ( ' ir.model ' ) . read ( cr , uid , model_id , [ ' model ' , ' name ' ] )
mod_model = model_name [ ' model ' ]
mod_name = model_name [ ' name ' ]
res [ ' domain ' ] = { ' filter_id ' : [ ( ' model_id ' , ' = ' , mod_model ) ] }
mod_name = model_name [ ' name ' ]
name = name_template . replace ( ' model ' , mod_name )
res [ ' value ' ] = { ' filter_id ' : False , ' name_template ' : name or False }
return res
def onchange_filter_id ( self , cr , uid , ids , model_id , filter_id , name_template ) :
res = { }
if filter_id :
filter_name = self . pool . get ( ' ir.filters ' ) . browse ( cr , uid , filter_id )
name = name_template . replace ( ' filter ' , filter_name . name )
res [ ' value ' ] = { ' name_template ' : name or False }
2013-03-04 05:20:58 +00:00
return res
2013-03-08 13:30:39 +00:00
2013-03-04 05:20:58 +00:00
2012-02-29 18:45:20 +00:00
_defaults = {
2013-03-05 13:17:57 +00:00
' name_template ' : ' %(name)s _model_filter_gdoc ' ,
2012-02-29 18:45:20 +00:00
}
2013-03-05 13:17:57 +00:00
2013-03-08 13:30:39 +00:00
# def _wrap_create(self, old_create, model):
# """ Return a wrapper around `old_create` calling both `old_create` and
# `_process`, in that order.
# """
# def wrapper(cr, uid, vals, context=None):
# # avoid loops or cascading actions
#
# if context and context.get('action'):
# return old_create(cr, uid, vals, context=context)
#
# context = dict(context or {}, action=True)
# new_id = old_create(cr, uid, vals, context=context)
#
# # as it is a new record, we do not consider the actions that have a prefilter
# action_dom = [('model_id', '=', model)]
# config_ids = self.search(cr, uid, action_dom, context=context)
## # check postconditions, and execute actions on the records that satisfy them
# for action in self.browse(cr, uid, config_ids, context=context):
# if self._filter(cr, uid, action, action.filter_id, [new_id], context=context):
# self._process(cr, uid, action, [new_id], context=context)
# return new_id
#
# return wrapper
#
# def _filter(self, cr, uid, action, action_filter, record_ids, context=None):
# """ filter the list record_ids that satisfy the action filter """
# if record_ids and action_filter:
# assert action.model_id.model == action_filter.model_id, "Filter model different from action rule model"
# model = self.pool.get(action_filter.model_id)
# domain = [('id', 'in', record_ids)] + eval(action_filter.domain)
# ctx = dict(context or {})
# ctx.update(eval(action_filter.context))
# record_ids = model.search(cr, uid, domain, context=ctx)
# return record_ids
#
# def _process(self, cr, uid, action, record_ids, context=None):
# """ process the given action on the records """
# # execute server actions
# model = self.pool.get(action.model_id.model)
# template_url = action.gdocs_template_url
# attach_obj = self.pool.get('ir.attachment')
# for record_id in record_ids:
# record_id = int(record_id)
# model_fields_dic = self.pool.get(action.model_id.model).read(cr, uid, record_id, [], context=context)
# name_gdocs = action.name_template
# name_gdocs = name_gdocs.replace('model',action.model_id.name)
# if action.filter_id:
# name_gdocs = name_gdocs.replace('filter',action.filter_id.name)
# try:
# name_gdocs = name_gdocs % model_fields_dic
# except:
# raise osv.except_osv(_('Key Error!'), _("Your Google Drive Name Pattern's key does not found in object."))
# attachments = attach_obj.search(cr, uid, [('res_id','=',record_id),('name','=',name_gdocs)])
# if not attachments:
# google_template_id = action.gdocs_resource_id
# attach_obj.copy_gdoc(cr, uid, action.model_id.model, record_id, name_gdocs, google_template_id, context=context)
# return True
#
# def _wrap_write(self, old_write, model):
# """ Return a wrapper around `old_write` calling both `old_write` and
# `_process`, in that order.
# """
# def wrapper(cr, uid, ids, vals, context=None):
# # avoid loops or cascading actions
# if context and context.get('action'):
# return old_write(cr, uid, ids, vals, context=context)
#
# context = dict(context or {}, action=True)
# ids = [ids] if isinstance(ids, (int, long, str)) else ids
#
# # retrieve the action rules to possibly execute
# action_dom = [('model_id', '=', model)]
# config_ids = self.search(cr, uid, action_dom, context=context)
# gconfigs = self.browse(cr, uid, config_ids, context=context)
#
# # check preconditions
# pre_ids = {}
# for gconfig in gconfigs:
# pre_ids[gconfig] = self._filter(cr, uid, gconfig, gconfig.filter_id, ids, context=context)
#
# # execute write
# old_write(cr, uid, ids, vals, context=context)
#
2013-03-05 13:17:57 +00:00
# # check postconditions, and execute actions on the records that satisfy them
2013-03-08 13:30:39 +00:00
# for gconfig in gconfigs:
# post_ids = self._filter(cr, uid, gconfig, gconfig.filter_id, pre_ids[gconfig], context=context)
# print 'post_idsss',post_ids
# if post_ids:
# print 'post_idsss',post_ids
# self._process(cr, uid, gconfig, post_ids, context=context)
# return True
#
# return wrapper
#
# def _register_hook(self, cr, ids=None):
# """ Wrap the methods `create` and `write` of the models specified by
# the rules given by `ids` (or all existing rules if `ids` is `None`.)
# """
# if ids is None:
# ids = self.search(cr, SUPERUSER_ID, [])
# for config in self.browse(cr, SUPERUSER_ID, ids):
# model = config.model_id.model
# model_obj = self.pool.get(model)
# model_obj.create = self._wrap_create(model_obj.create, model)
# model_obj.write = self._wrap_write(model_obj.write, model)
# return True
#
# def create(self, cr, uid, vals, context=None):
# res_id = super(config, self).create(cr, uid, vals, context=context)
# self._register_hook(cr, [res_id])
# return res_id
#
# def write(self, cr, uid, ids, vals, context=None):
# if isinstance(ids, (int, long)):
# ids = [ids]
# super(config, self).write(cr, uid, ids, vals, context=context)
# self._register_hook(cr, ids)
# return True
2013-03-05 13:17:57 +00:00
2012-03-28 08:29:48 +00:00
config ( )