[ADD] ir.attachment: add token field for external access
Introduce a new attachment field (access_token) to allow external unauthenticated access. This will be an opaque unique number (typically a UUID) that should be provided via an appropriate controller, for unauthenticated display. The field is intended to be NULL unless unauthenticated access has been allowed, in which case a value will be set for the access_token. This could be used e.g. for allowing access to images within mailings, even when the recipient is not logged in (which is sometimes entirely impossible, when email providers use restricted proxy servers to load images) Note 1: this is still a work-in-progress, but serves to freeze the API. The implementation of the access check and provisioning of the new field will be added later. Note 2: namimg collisions with the file download token prevent the use of a shorter 'token' parameter for download routes. Apologies for the late (and incomplete) addition in saas-18 :-/
This commit is contained in:
@@ -417,10 +417,13 @@ def xml2json_from_elementtree(el, preserve_whitespaces=False):
|
||||
res["children"] = kids
|
||||
return res
|
||||
|
||||
def binary_content(xmlid=None, model='ir.attachment', id=None, field='datas', unique=False, filename=None, filename_field='datas_fname', download=False, mimetype=None, default_mimetype='application/octet-stream', env=None):
|
||||
def binary_content(xmlid=None, model='ir.attachment', id=None, field='datas', unique=False,
|
||||
filename=None, filename_field='datas_fname', download=False, mimetype=None,
|
||||
default_mimetype='application/octet-stream', access_token=None, env=None):
|
||||
return request.registry['ir.http'].binary_content(
|
||||
xmlid=xmlid, model=model, id=id, field=field, unique=unique, filename=filename, filename_field=filename_field,
|
||||
download=download, mimetype=mimetype, default_mimetype=default_mimetype, env=env)
|
||||
xmlid=xmlid, model=model, id=id, field=field, unique=unique, filename=filename,
|
||||
filename_field=filename_field, download=download, mimetype=mimetype,
|
||||
default_mimetype=default_mimetype, access_token=access_token, env=env)
|
||||
|
||||
#----------------------------------------------------------
|
||||
# Odoo Web web Controllers
|
||||
@@ -971,8 +974,13 @@ class Binary(http.Controller):
|
||||
'/web/content/<int:id>-<string:unique>/<string:filename>',
|
||||
'/web/content/<string:model>/<int:id>/<string:field>',
|
||||
'/web/content/<string:model>/<int:id>/<string:field>/<string:filename>'], type='http', auth="public")
|
||||
def content_common(self, xmlid=None, model='ir.attachment', id=None, field='datas', filename=None, filename_field='datas_fname', unique=None, mimetype=None, download=None, data=None, token=None):
|
||||
status, headers, content = binary_content(xmlid=xmlid, model=model, id=id, field=field, unique=unique, filename=filename, filename_field=filename_field, download=download, mimetype=mimetype)
|
||||
def content_common(self, xmlid=None, model='ir.attachment', id=None, field='datas',
|
||||
filename=None, filename_field='datas_fname', unique=None, mimetype=None,
|
||||
download=None, data=None, token=None, access_token=None):
|
||||
status, headers, content = binary_content(
|
||||
xmlid=xmlid, model=model, id=id, field=field, unique=unique, filename=filename,
|
||||
filename_field=filename_field, download=download, mimetype=mimetype,
|
||||
access_token=access_token)
|
||||
if status == 304:
|
||||
response = werkzeug.wrappers.Response(status=status, headers=headers)
|
||||
elif status == 301:
|
||||
@@ -1004,8 +1012,13 @@ class Binary(http.Controller):
|
||||
'/web/image/<int:id>-<string:unique>/<string:filename>',
|
||||
'/web/image/<int:id>-<string:unique>/<int:width>x<int:height>',
|
||||
'/web/image/<int:id>-<string:unique>/<int:width>x<int:height>/<string:filename>'], type='http', auth="public")
|
||||
def content_image(self, xmlid=None, model='ir.attachment', id=None, field='datas', filename_field='datas_fname', unique=None, filename=None, mimetype=None, download=None, width=0, height=0, crop=False):
|
||||
status, headers, content = binary_content(xmlid=xmlid, model=model, id=id, field=field, unique=unique, filename=filename, filename_field=filename_field, download=download, mimetype=mimetype, default_mimetype='image/png')
|
||||
def content_image(self, xmlid=None, model='ir.attachment', id=None, field='datas',
|
||||
filename_field='datas_fname', unique=None, filename=None, mimetype=None,
|
||||
download=None, width=0, height=0, crop=False, access_token=None):
|
||||
status, headers, content = binary_content(
|
||||
xmlid=xmlid, model=model, id=id, field=field, unique=unique, filename=filename,
|
||||
filename_field=filename_field, download=download, mimetype=mimetype,
|
||||
default_mimetype='image/png', access_token=access_token)
|
||||
if status == 304:
|
||||
return werkzeug.wrappers.Response(status=304, headers=headers)
|
||||
elif status == 301:
|
||||
|
||||
@@ -202,7 +202,10 @@ class Http(models.AbstractModel):
|
||||
return werkzeug.wrappers.Response(html, status=code, content_type='text/html;charset=utf-8')
|
||||
|
||||
@classmethod
|
||||
def binary_content(cls, xmlid=None, model='ir.attachment', id=None, field='datas', unique=False, filename=None, filename_field='datas_fname', download=False, mimetype=None, default_mimetype='application/octet-stream', env=None):
|
||||
def binary_content(cls, xmlid=None, model='ir.attachment', id=None, field='datas',
|
||||
unique=False, filename=None, filename_field='datas_fname', download=False,
|
||||
mimetype=None, default_mimetype='application/octet-stream',
|
||||
access_token=None, env=None):
|
||||
env = env or request.env
|
||||
obj = None
|
||||
if xmlid:
|
||||
@@ -212,7 +215,10 @@ class Http(models.AbstractModel):
|
||||
if obj and 'website_published' in obj._fields:
|
||||
if env[obj._name].sudo().search([('id', '=', obj.id), ('website_published', '=', True)]):
|
||||
env = env(user=SUPERUSER_ID)
|
||||
return super(Http, cls).binary_content(xmlid=xmlid, model=model, id=id, field=field, unique=unique, filename=filename, filename_field=filename_field, download=download, mimetype=mimetype, default_mimetype=default_mimetype, env=env)
|
||||
return super(Http, cls).binary_content(
|
||||
xmlid=xmlid, model=model, id=id, field=field, unique=unique, filename=filename,
|
||||
filename_field=filename_field, download=download, mimetype=mimetype,
|
||||
default_mimetype=default_mimetype, access_token=access_token, env=env)
|
||||
|
||||
|
||||
class ModelConverter(ModelConverter):
|
||||
|
||||
@@ -279,6 +279,9 @@ class IrAttachment(models.Model):
|
||||
url = fields.Char('Url', index=True, size=1024)
|
||||
public = fields.Boolean('Is public document')
|
||||
|
||||
# for external access
|
||||
access_token = fields.Char('Access Token')
|
||||
|
||||
# the field 'datas' is computed and may use the other fields below
|
||||
datas = fields.Binary(string='File Content', compute='_compute_datas', inverse='_inverse_datas')
|
||||
db_datas = fields.Binary('Database Data')
|
||||
|
||||
@@ -248,7 +248,10 @@ class IrHttp(models.AbstractModel):
|
||||
return content_disposition(filename)
|
||||
|
||||
@classmethod
|
||||
def binary_content(cls, xmlid=None, model='ir.attachment', id=None, field='datas', unique=False, filename=None, filename_field='datas_fname', download=False, mimetype=None, default_mimetype='application/octet-stream', env=None):
|
||||
def binary_content(cls, xmlid=None, model='ir.attachment', id=None, field='datas',
|
||||
unique=False, filename=None, filename_field='datas_fname', download=False,
|
||||
mimetype=None, default_mimetype='application/octet-stream',
|
||||
access_token=None, env=None):
|
||||
""" Get file, attachment or downloadable content
|
||||
|
||||
If the ``xmlid`` and ``id`` parameter is omitted, fetches the default value for the
|
||||
@@ -265,6 +268,7 @@ class IrHttp(models.AbstractModel):
|
||||
:param bool download: apply headers to download the file
|
||||
:param str mimetype: mintype of the field (for headers)
|
||||
:param str default_mimetype: default mintype if no mintype found
|
||||
:param str access_token: optional token for unauthenticated access
|
||||
:param Environment env: by default use request.env
|
||||
:returns: (status, headers, content)
|
||||
"""
|
||||
|
||||
Reference in New Issue
Block a user