portal_mixin.py 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135
  1. # -*- coding: utf-8 -*-
  2. # Part of Odoo. See LICENSE file for full copyright and licensing details.
  3. import uuid
  4. from werkzeug.urls import url_encode
  5. from odoo import api, exceptions, fields, models, _
  6. class PortalMixin(models.AbstractModel):
  7. _name = "portal.mixin"
  8. _description = 'Portal Mixin'
  9. access_url = fields.Char(
  10. 'Portal Access URL', compute='_compute_access_url',
  11. help='Customer Portal URL')
  12. access_token = fields.Char('Security Token', copy=False)
  13. # to display the warning from specific model
  14. access_warning = fields.Text("Access warning", compute="_compute_access_warning")
  15. def _compute_access_warning(self):
  16. for mixin in self:
  17. mixin.access_warning = ''
  18. def _compute_access_url(self):
  19. for record in self:
  20. record.access_url = '#'
  21. def _portal_ensure_token(self):
  22. """ Get the current record access token """
  23. if not self.access_token:
  24. # we use a `write` to force the cache clearing otherwise `return self.access_token` will return False
  25. self.sudo().write({'access_token': str(uuid.uuid4())})
  26. return self.access_token
  27. def _get_share_url(self, redirect=False, signup_partner=False, pid=None, share_token=True):
  28. """
  29. Build the url of the record that will be sent by mail and adds additional parameters such as
  30. access_token to bypass the recipient's rights,
  31. signup_partner to allows the user to create easily an account,
  32. hash token to allow the user to be authenticated in the chatter of the record portal view, if applicable
  33. :param redirect : Send the redirect url instead of the direct portal share url
  34. :param signup_partner: allows the user to create an account with pre-filled fields.
  35. :param pid: = partner_id - when given, a hash is generated to allow the user to be authenticated
  36. in the portal chatter, if any in the target page,
  37. if the user is redirected to the portal instead of the backend.
  38. :return: the url of the record with access parameters, if any.
  39. """
  40. self.ensure_one()
  41. if redirect:
  42. # model / res_id used by mail/view to check access on record
  43. params = {
  44. 'model': self._name,
  45. 'res_id': self.id,
  46. }
  47. else:
  48. params = {}
  49. if share_token and hasattr(self, 'access_token'):
  50. params['access_token'] = self._portal_ensure_token()
  51. if pid:
  52. params['pid'] = pid
  53. params['hash'] = self._sign_token(pid)
  54. if signup_partner and hasattr(self, 'partner_id') and self.partner_id:
  55. params.update(self.partner_id.signup_get_auth_param()[self.partner_id.id])
  56. return '%s?%s' % ('/mail/view' if redirect else self.access_url, url_encode(params))
  57. def _get_access_action(self, access_uid=None, force_website=False):
  58. """ Instead of the classic form view, redirect to the online document for
  59. portal users or if force_website=True. """
  60. self.ensure_one()
  61. user, record = self.env.user, self
  62. if access_uid:
  63. try:
  64. record.check_access_rights('read')
  65. record.check_access_rule("read")
  66. except exceptions.AccessError:
  67. return super(PortalMixin, self)._get_access_action(
  68. access_uid=access_uid, force_website=force_website
  69. )
  70. user = self.env['res.users'].sudo().browse(access_uid)
  71. record = self.with_user(user)
  72. if user.share or force_website:
  73. try:
  74. record.check_access_rights('read')
  75. record.check_access_rule('read')
  76. except exceptions.AccessError:
  77. if force_website:
  78. return {
  79. 'type': 'ir.actions.act_url',
  80. 'url': record.access_url,
  81. 'target': 'self',
  82. 'res_id': record.id,
  83. }
  84. else:
  85. pass
  86. else:
  87. return {
  88. 'type': 'ir.actions.act_url',
  89. 'url': record._get_share_url(),
  90. 'target': 'self',
  91. 'res_id': record.id,
  92. }
  93. return super(PortalMixin, self)._get_access_action(
  94. access_uid=access_uid, force_website=force_website
  95. )
  96. @api.model
  97. def action_share(self):
  98. action = self.env["ir.actions.actions"]._for_xml_id("portal.portal_share_action")
  99. action['context'] = {'active_id': self.env.context['active_id'],
  100. 'active_model': self.env.context['active_model']}
  101. return action
  102. def get_portal_url(self, suffix=None, report_type=None, download=None, query_string=None, anchor=None):
  103. """
  104. Get a portal url for this model, including access_token.
  105. The associated route must handle the flags for them to have any effect.
  106. - suffix: string to append to the url, before the query string
  107. - report_type: report_type query string, often one of: html, pdf, text
  108. - download: set the download query string to true
  109. - query_string: additional query string
  110. - anchor: string to append after the anchor #
  111. """
  112. self.ensure_one()
  113. url = self.access_url + '%s?access_token=%s%s%s%s%s' % (
  114. suffix if suffix else '',
  115. self._portal_ensure_token(),
  116. '&report_type=%s' % report_type if report_type else '',
  117. '&download=true' if download else '',
  118. query_string if query_string else '',
  119. '#%s' % anchor if anchor else ''
  120. )
  121. return url