diff --git a/pingen/pingen.py b/pingen/pingen.py index 0d84856..da1378a 100644 --- a/pingen/pingen.py +++ b/pingen/pingen.py @@ -56,7 +56,8 @@ class Pingen(object): def __init__(self, token, staging=True): self._token = token - self.staging = True + self.staging = staging + self._session = None super(Pingen, self).__init__() @property @@ -65,6 +66,32 @@ class Pingen(object): return 'https://stage-api.pingen.com' return 'https://api.pingen.com' + @property + def session(self): + """ Build a requests session """ + if self._session is not None: + return self._session + self._session = requests.Session( + params={'token': self._token}, + # with safe_mode, requests catch errors and + # returns a blank response with an error + config={'safe_mode': True}, + # verify = False required for staging environment + # because the SSL certificate is wrong + verify=not self.staging) + return self._session + + def __enter__(self): + return self + + def __exit__(self, *args): + self.close() + + def close(self): + """Dispose of any internal state. """ + if self._session: + self._session.close() + def _send(self, method, endpoint, **kwargs): """ Send a request to the pingen API using requests @@ -77,23 +104,6 @@ class Pingen(object): """ complete_url = urlparse.urljoin(self.url, endpoint) - auth_param = {'token': self._token} - if 'params' in kwargs: - kwargs['params'].update(auth_param) - else: - kwargs['params'] = auth_param - - # with safe_mode, requests catch errors and - # returns a blank response with an error - config = {'safe_mode': True} - if 'config' in kwargs: - kwargs['config'].update(config) - else: - kwargs['config'] = config - - # verify = False required for staging environment - # because the SSL certificate is wrong - kwargs['verify'] = not self.staging response = method(complete_url, **kwargs) if not response.ok: @@ -140,7 +150,7 @@ class Pingen(object): multipart, content_type = encode_multipart_formdata(formdata) response = self._send( - requests.post, + self.session.post, 'document/upload', headers={'Content-Type': content_type}, data=multipart) @@ -169,7 +179,7 @@ class Pingen(object): 'color': color, } response = self._send( - requests.post, + self.session.post, 'document/send', params={'id': document_id}, data={'data': json.dumps(data)}) @@ -183,7 +193,7 @@ class Pingen(object): :return: dict of infos of the post """ response = self._send( - requests.get, + self.session.get, 'post/get', params={'id': post_id}) diff --git a/pingen/pingen_document.py b/pingen/pingen_document.py index 1ef9f39..6a2a80d 100644 --- a/pingen/pingen_document.py +++ b/pingen/pingen_document.py @@ -25,7 +25,6 @@ from cStringIO import StringIO from contextlib import closing from openerp.osv import osv, orm, fields -from openerp import tools from openerp.tools.translate import _ from openerp import pooler from .pingen import APIError, ConnectionError, POST_SENDING_STATUS @@ -91,16 +90,24 @@ class pingen_document(orm.Model): 'Only one Pingen document is allowed per attachment.'), ] - def _push_to_pingen(self, cr, uid, document, context=None): - """ Push a document to pingen.com """ + def _get_pingen_session(self, cr, uid, context=None): + """ Returns a pingen session for a user""" + company = self.pool.get('res.users').browse( + cr, uid, uid, context=context).company_id + return self.pool.get('res.company')._pingen(cr, uid, company, context=context) + + def _push_to_pingen(self, cr, uid, document, pingen=None, context=None): + """ Push a document to pingen.com + + :param Pingen pingen: optional pingen object to, reuse session + """ attachment_obj = self.pool.get('ir.attachment') decoded_document = attachment_obj._decoded_content( cr, uid, document.attachment_id, context=context) - company = self.pool.get('res.users').browse( - cr, uid, uid, context=context).company_id - pingen = self.pool.get('res.company')._pingen(cr, uid, company, context=context) + if pingen is None: + pingen = self._get_pingen_session(cr, uid, context=context) try: doc_id, post_id, infos = pingen.push_document( document.datas_fname, @@ -145,27 +152,29 @@ class pingen_document(orm.Model): Wrapper method for multiple ids (when triggered from button for instance) for public interface. """ - for document in self.browse(cr, uid, ids, context=context): - try: - self._push_to_pingen(cr, uid, document, context=context) - except ConnectionError as e: - raise osv.except_osv( - _('Pingen Connection Error'), - _('Connection Error when asking for sending the document %s to Pingen') % document.name) + with self._get_pingen_session(cr, uid, context=context) as session: + for document in self.browse(cr, uid, ids, context=context): + try: + self._push_to_pingen( + cr, uid, document, pingen=session, context=context) + except ConnectionError as e: + raise osv.except_osv( + _('Pingen Connection Error'), + _('Connection Error when asking for sending the document %s to Pingen') % document.name) - except APIError as e: - raise osv.except_osv( - _('Pingen Error'), - _('Error when asking Pingen to send the document %s: ' - '\n%s') % (document.name, e)) + except APIError as e: + raise osv.except_osv( + _('Pingen Error'), + _('Error when asking Pingen to send the document %s: ' + '\n%s') % (document.name, e)) - except: - _logger.exception( - 'Unexcepted Error when updating the status of pingen.document %s: ' % - document.id) - raise osv.except_osv( - _('Error'), - _('Unexcepted Error when updating the status of Document %s') % document.name) + except: + _logger.exception( + 'Unexcepted Error when updating the status of pingen.document %s: ' % + document.id) + raise osv.except_osv( + _('Error'), + _('Unexcepted Error when updating the status of Document %s') % document.name) return True def _push_and_send_to_pingen_cron(self, cr, uid, ids, context=None): @@ -186,28 +195,35 @@ class pingen_document(orm.Model): context=context) with closing(pooler.get_db(cr.dbname).cursor()) as loc_cr: - for document in self.browse(loc_cr, uid, ids, context=context): + with self._get_pingen_session(cr, uid, context=context) as session: + for document in self.browse(loc_cr, uid, ids, context=context): - if document.state == 'error': - self._resolve_error(loc_cr, uid, document, context=context) - document.refresh() + if document.state == 'error': + self._resolve_error(loc_cr, uid, document, context=context) + document.refresh() - try: - if document.state == 'pending': - self._push_to_pingen(loc_cr, uid, document, context=context) + try: + if document.state == 'pending': + self._push_to_pingen( + loc_cr, uid, document, pingen=session, context=context) - elif document.state == 'pushed': - self._ask_pingen_send(loc_cr, uid, document, context=context) - except ConnectionError as e: - document.write({'last_error_message': e, 'state': 'error'}, context=context) - except APIError as e: - document.write({'last_error_message': e, 'state': 'pingen_error'}, context=context) - except: - _logger.error('Unexcepted error in pingen cron') - loc_cr.rollback() - raise + elif document.state == 'pushed': + self._ask_pingen_send( + loc_cr, uid, document, pingen=session, context=context) + except ConnectionError as e: + document.write({'last_error_message': e, + 'state': 'error'}, + context=context) + except APIError as e: + document.write({'last_error_message': e, + 'state': 'pingen_error'}, + context=context) + except: + _logger.error('Unexcepted error in pingen cron') + loc_cr.rollback() + raise - loc_cr.commit() + loc_cr.commit() return True @@ -227,17 +243,16 @@ class pingen_document(orm.Model): self._resolve_error(cr, uid, document, context=context) return True - def _ask_pingen_send(self, cr, uid, document, context=None): + def _ask_pingen_send(self, cr, uid, document, pingen, context=None): """ For a document already pushed to pingen, ask to send it. + + :param Pingen pingen: pingen object to reuse """ # sending has been explicitely asked so we change the option # for consistency if not document.pingen_send: document.write({'pingen_send': True}, context=context) - company = self.pool.get('res.users').browse( - cr, uid, uid, context=context).company_id - pingen = self.pool.get('res.company')._pingen(cr, uid, company, context=context) try: post_id = pingen.send_document( document.pingen_id, @@ -267,39 +282,39 @@ class pingen_document(orm.Model): Wrapper method for multiple ids (when triggered from button for instance) for public interface. """ - for document in self.browse(cr, uid, ids, context=context): - try: - self._ask_pingen_send(cr, uid, document, context=context) - except ConnectionError as e: - raise osv.except_osv( - _('Pingen Connection Error'), - _('Connection Error when asking for ' - 'sending the document %s to Pingen') % document.name) + with self._get_pingen_session(cr, uid, context=context) as session: + for document in self.browse(cr, uid, ids, context=context): + try: + self._ask_pingen_send(cr, uid, document, pingen=session, context=context) + except ConnectionError as e: + raise osv.except_osv( + _('Pingen Connection Error'), + _('Connection Error when asking for ' + 'sending the document %s to Pingen') % document.name) - except APIError as e: - raise osv.except_osv( - _('Pingen Error'), - _('Error when asking Pingen to send the document %s: ' - '\n%s') % (document.name, e)) + except APIError as e: + raise osv.except_osv( + _('Pingen Error'), + _('Error when asking Pingen to send the document %s: ' + '\n%s') % (document.name, e)) - except: - _logger.exception( - 'Unexcepted Error when updating the status of pingen.document %s: ' % - document.id) - raise osv.except_osv( - _('Error'), - _('Unexcepted Error when updating the status of Document %s') % document.name) + except: + _logger.exception( + 'Unexcepted Error when updating the status of pingen.document %s: ' % + document.id) + raise osv.except_osv( + _('Error'), + _('Unexcepted Error when updating the status of Document %s') % document.name) return True - def _update_post_infos(self, cr, uid, document, context=None): + def _update_post_infos(self, cr, uid, document, pingen, context=None): """ Update the informations from pingen of a document in the Sendcenter + + :param Pingen pingen: pingen object to reuse """ if not document.post_id: return - company = self.pool.get('res.users').browse( - cr, uid, uid, context=context).company_id - pingen = self.pool.get('res.company')._pingen(cr, uid, company, context=context) try: post_infos = pingen.post_infos(document.post_id) except ConnectionError as e: @@ -350,19 +365,21 @@ class pingen_document(orm.Model): context=context) with closing(pooler.get_db(cr.dbname).cursor()) as loc_cr: - for document in self.browse(loc_cr, uid, ids, context=context): - try: - self._update_post_infos(loc_cr, uid, document, context=context) - except (ConnectionError, APIError): - # will be retried the next time - # In any case, the error has been logged by _update_post_infos - loc_cr.rollback() - except: - _logger.error('Unexcepted error in pingen cron') - loc_cr.rollback() - raise + with self._get_pingen_session(cr, uid, context=context) as session: + for document in self.browse(loc_cr, uid, ids, context=context): + try: + self._update_post_infos( + loc_cr, uid, document, pingen=session, context=context) + except (ConnectionError, APIError): + # will be retried the next time + # In any case, the error has been logged by _update_post_infos + loc_cr.rollback() + except: + _logger.error('Unexcepted error in pingen cron') + loc_cr.rollback() + raise - loc_cr.commit() + loc_cr.commit() return True def update_post_infos(self, cr, uid, ids, context=None): @@ -371,27 +388,29 @@ class pingen_document(orm.Model): Wrapper method for multiple ids (when triggered from button for instance) for public interface. """ - for document in self.browse(cr, uid, ids, context=context): - try: - self._update_post_infos(cr, uid, document, context=context) - except ConnectionError as e: - raise osv.except_osv( - _('Pingen Connection Error'), - _('Connection Error when updating the status of Document %s' - ' from Pingen') % document.name) + with self._get_pingen_session(cr, uid, context=context) as session: + for document in self.browse(cr, uid, ids, context=context): + try: + self._update_post_infos( + cr, uid, document, pingen=session, context=context) + except ConnectionError as e: + raise osv.except_osv( + _('Pingen Connection Error'), + _('Connection Error when updating the status of Document %s' + ' from Pingen') % document.name) - except APIError as e: - raise osv.except_osv( - _('Pingen Error'), - _('Error when updating the status of Document %s from Pingen: ' - '\n%s') % (document.name, e)) + except APIError as e: + raise osv.except_osv( + _('Pingen Error'), + _('Error when updating the status of Document %s from Pingen: ' + '\n%s') % (document.name, e)) - except: - _logger.exception( - 'Unexcepted Error when updating the status of pingen.document %s: ' % - document.id) - raise osv.except_osv( - _('Error'), - _('Unexcepted Error when updating the status of Document %s') % document.name) + except: + _logger.exception( + 'Unexcepted Error when updating the status of pingen.document %s: ' % + document.id) + raise osv.except_osv( + _('Error'), + _('Unexcepted Error when updating the status of Document %s') % document.name) return True