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
2013-03-11 13:29:29 +00:00
def copy_gdoc ( self , cr , uid , res_model , res_id , name_gdocs , name , 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 ' ,
2013-03-11 13:29:29 +00:00
' name ' : name ,
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 )
if google_doc_configs :
2013-03-11 13:29:29 +00:00
config . append ( action . name )
2013-03-08 13:30:39 +00:00
else :
2013-03-11 13:29:29 +00:00
config . append ( action . name )
2013-03-08 13:30:39 +00:00
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 "
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 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 ' )
2013-03-12 09:32:39 +00:00
config_ids = pool_gdoc_config . search ( cr , uid , [ ( ' model_id ' , ' = ' , res_model ) ] , context = context ) [ 0 ]
2013-03-08 13:30:39 +00:00
action = pool_gdoc_config . browse ( cr , uid , config_ids , context = context )
attachment = { }
2013-03-12 09:32:39 +00:00
model_fields_dic = self . pool . get ( res_model ) . read ( cr , uid , res_id , [ ] , context = context )
# check if a model is configured with a template
if config_ids :
name_gdocs = action . name_template
print ' name_gdocss ' , name_gdocs
try :
if name_gdocs . find ( ' model ' ) != - 1 :
name_gdocs = name_gdocs . replace ( ' model ' , action . model_id . name )
if name_gdocs . find ( ' filter ' ) != - 1 :
name_gdocs = name_gdocs . replace ( ' filter ' , action . filter_id . name )
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. " ) )
2013-03-11 13:29:29 +00:00
attach_ids = self . search ( cr , uid , [ ( ' res_model ' , ' = ' , res_model ) , ( ' name ' , ' = ' , action . name ) , ( ' res_id ' , ' = ' , res_id ) ] )
2013-03-08 13:30:39 +00:00
if not attach_ids :
google_template_id = action . gdocs_resource_id
2013-03-12 09:32:39 +00:00
self . copy_gdoc ( cr , uid , action . model_id . model , res_id , name_gdocs , action . name , google_template_id , context = context )
attach_ids = self . search ( cr , uid , [ ( ' res_model ' , ' = ' , res_model ) , ( ' name ' , ' = ' , action . name ) , ( ' res_id ' , ' = ' , res_id ) ] )
2013-03-08 13:30:39 +00:00
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 = {
2013-03-11 13:29:29 +00:00
' name ' : fields . char ( ' Name ' , required = True , size = 1024 ) ,
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-12 09:32:39 +00:00
def onchange_model_id ( self , cr , uid , ids , model_id ) :
res = { ' domain ' : { ' filter_id ' : [ ] } }
if model_id :
model_name = self . pool . get ( ' ir.model ' ) . read ( cr , uid , model_id , [ ' model ' ] )
if model_name :
mod_name = model_name [ ' model ' ]
res [ ' domain ' ] = { ' filter_id ' : [ ( ' model_id ' , ' = ' , mod_name ) ] }
else :
res [ ' value ' ] = { ' filter_id ' : False }
return res
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
2012-03-28 08:29:48 +00:00
config ( )