Merge remote-tracking branch 'odoo/master' into master-wmsstagingmig-jco
[odoo/odoo.git] / addons / google_account / google_account.py
1 # -*- coding: utf-8 -*-
2
3 import openerp
4 from openerp.http import request
5 from openerp.osv import osv
6 from openerp import SUPERUSER_ID
7 from openerp.tools.translate import _
8 from datetime import datetime
9 from openerp.tools import DEFAULT_SERVER_DATETIME_FORMAT
10
11 import werkzeug.urls
12 import urllib2
13 import simplejson
14
15 import logging
16 _logger = logging.getLogger(__name__)
17
18
19 class google_service(osv.osv_memory):
20     _name = 'google.service'
21
22     def generate_refresh_token(self, cr, uid, service, authorization_code, context=None):
23         ir_config = self.pool['ir.config_parameter']
24         client_id = ir_config.get_param(cr, SUPERUSER_ID, 'google_%s_client_id' % service)
25         client_secret = ir_config.get_param(cr, SUPERUSER_ID, 'google_%s_client_secret' % service)
26         redirect_uri = ir_config.get_param(cr, SUPERUSER_ID, 'google_redirect_uri')
27
28         #Get the Refresh Token From Google And store it in ir.config_parameter
29         headers = {"Content-type": "application/x-www-form-urlencoded"}
30         data = dict(code=authorization_code, client_id=client_id, client_secret=client_secret, redirect_uri=redirect_uri, grant_type="authorization_code")
31         data = werkzeug.url_encode(data)
32         try:
33             req = urllib2.Request("https://accounts.google.com/o/oauth2/token", data, headers)
34             content = urllib2.urlopen(req).read()
35         except urllib2.HTTPError:
36             error_msg = "Something went wrong during your token generation. Maybe your Authorization Code is invalid or already expired"
37             raise self.pool.get('res.config.settings').get_config_warning(cr, _(error_msg), context=context)
38
39         content = simplejson.loads(content)
40         return content.get('refresh_token')
41
42     def _get_google_token_uri(self, cr, uid, service, scope, context=None):
43         ir_config = self.pool['ir.config_parameter']
44         params = {
45             'scope': scope,
46             'redirect_uri': ir_config.get_param(cr, SUPERUSER_ID, 'google_redirect_uri'),
47             'client_id': ir_config.get_param(cr, SUPERUSER_ID, 'google_%s_client_id' % service),
48             'response_type': 'code',
49             'client_id': ir_config.get_param(cr, SUPERUSER_ID, 'google_%s_client_id' % service),
50         }
51         uri = 'https://accounts.google.com/o/oauth2/auth?%s' % werkzeug.url_encode(params)
52         return uri
53
54     # If no scope is passed, we use service by default to get a default scope
55     def _get_authorize_uri(self, cr, uid, from_url, service, scope=False, context=None):
56         """ This method return the url needed to allow this instance of OpenErp to access to the scope of gmail specified as parameters """
57         state_obj = dict(d=cr.dbname, s=service, f=from_url)
58
59         base_url = self.get_base_url(cr, uid, context)
60         client_id = self.get_client_id(cr, uid, service, context)
61
62         params = {
63             'response_type': 'code',
64             'client_id': client_id,
65             'state': simplejson.dumps(state_obj),
66             'scope': scope or 'https://www.googleapis.com/auth/%s' % (service,),
67             'redirect_uri': base_url + '/google_account/authentication',
68             'approval_prompt': 'force',
69             'access_type': 'offline'
70         }
71
72         uri = self.get_uri_oauth(a='auth') + "?%s" % werkzeug.url_encode(params)
73         return uri
74
75     def _get_google_token_json(self, cr, uid, authorize_code, service, context=None):
76         res = False
77         base_url = self.get_base_url(cr, uid, context)
78         client_id = self.get_client_id(cr, uid, service, context)
79         client_secret = self.get_client_secret(cr, uid, service, context)
80
81         params = {
82             'code': authorize_code,
83             'client_id': client_id,
84             'client_secret': client_secret,
85             'grant_type': 'authorization_code',
86             'redirect_uri': base_url + '/google_account/authentication'
87         }
88
89         headers = {"content-type": "application/x-www-form-urlencoded"}
90
91         try:
92             uri = self.get_uri_oauth(a='token')
93             data = werkzeug.url_encode(params)
94
95             st, res = self._do_request(cr, uid, uri, params=data, headers=headers, type='POST', preuri='', context=context)
96         except urllib2.HTTPError:
97             error_msg = "Something went wrong during your token generation. Maybe your Authorization Code is invalid"
98             raise self.pool.get('res.config.settings').get_config_warning(cr, _(error_msg), context=context)
99         return res
100
101     def _refresh_google_token_json(self, cr, uid, refresh_token, service, context=None):  # exchange_AUTHORIZATION vs Token (service = calendar)
102         res = False
103         client_id = self.get_client_id(cr, uid, service, context)
104         client_secret = self.get_client_secret(cr, uid, service, context)
105
106         params = {
107             'refresh_token': refresh_token,
108             'client_id': client_id,
109             'client_secret': client_secret,
110             'grant_type': 'refresh_token',
111         }
112
113         headers = {"content-type": "application/x-www-form-urlencoded"}
114
115         try:
116             uri = self.get_uri_oauth(a='token')
117
118             data = werkzeug.url_encode(params)
119             st, res = self._do_request(cr, uid, uri, params=data, headers=headers, type='POST', preuri='', context=context)
120         except urllib2.HTTPError, e:
121             if e.code == 400:  # invalid grant
122                 registry = openerp.modules.registry.RegistryManager.get(request.session.db)
123                 with registry.cursor() as cur:
124                     self.pool['res.users'].write(cur, uid, [uid], {'google_%s_rtoken' % service: False}, context=context)
125             error_key = simplejson.loads(e.read()).get("error", "nc")
126             _logger.exception("Bad google request : %s !" % error_key)
127             error_msg = "Something went wrong during your token generation. Maybe your Authorization Code is invalid or already expired [%s]" % error_key
128             raise self.pool.get('res.config.settings').get_config_warning(cr, _(error_msg), context=context)
129         return res
130
131     def _do_request(self, cr, uid, uri, params={}, headers={}, type='POST', preuri="https://www.googleapis.com", context=None):
132         if context is None:
133             context = {}
134
135         """ Return a tuple ('HTTP_CODE', 'HTTP_RESPONSE') """
136         _logger.debug("Uri: %s - Type : %s - Headers: %s - Params : %s !" % (uri, type, headers, werkzeug.url_encode(params) if type == 'GET' else params))
137
138         status = 418
139         response = ""
140         try:
141             if type.upper() == 'GET' or type.upper() == 'DELETE':
142                 data = werkzeug.url_encode(params)
143                 req = urllib2.Request(preuri + uri + "?" + data)
144             elif type.upper() == 'POST' or type.upper() == 'PATCH' or type.upper() == 'PUT':
145                 req = urllib2.Request(preuri + uri, params, headers)
146             else:
147                 raise ('Method not supported [%s] not in [GET, POST, PUT, PATCH or DELETE]!' % (type))
148             req.get_method = lambda: type.upper()
149
150             request = urllib2.urlopen(req)
151             status = request.getcode()
152
153             if int(status) in (204, 404):  # Page not found, no response
154                 response = False
155             else:
156                 content = request.read()
157                 response = simplejson.loads(content)
158
159             if context.get('ask_time'):
160                 try:
161                     date = datetime.strptime(request.headers.get('date'), "%a, %d %b %Y %H:%M:%S %Z")
162                 except:
163                     date = datetime.now().strftime(DEFAULT_SERVER_DATETIME_FORMAT)
164                 context['ask_time'] = date
165         except urllib2.HTTPError, e:
166             if e.code in (400, 401, 410):
167                 raise e
168
169             _logger.exception("Bad google request : %s !" % e.read())
170             raise self.pool.get('res.config.settings').get_config_warning(cr, _("Something went wrong with your request to google"), context=context)
171         return (status, response)
172
173     def get_base_url(self, cr, uid, context=None):
174         return self.pool.get('ir.config_parameter').get_param(cr, uid, 'web.base.url', default='http://www.openerp.com?NoBaseUrl', context=context)
175
176     def get_client_id(self, cr, uid, service, context=None):
177         return self.pool.get('ir.config_parameter').get_param(cr, uid, 'google_%s_client_id' % (service,), default=False, context=context)
178
179     def get_client_secret(self, cr, uid, service, context=None):
180         return self.pool.get('ir.config_parameter').get_param(cr, uid, 'google_%s_client_secret' % (service,), default=False, context=context)
181
182     def get_uri_oauth(self, a=''):  # a = optional action
183         return "https://accounts.google.com/o/oauth2/%s" % (a,)
184
185     def get_uri_api(self):
186         return 'https://www.googleapis.com'