[REF] base, mail: splits the documents feature from ir attachment
Moved the field 'active', 'res_model_name' and 'thumbnail' from ir.attachment to enterprise's documents.document. Moved the pdf split feature to enterprise's Documents module. task: #1908896
This commit is contained in:
@@ -13,7 +13,6 @@ var DocumentViewer = Widget.extend({
|
||||
template: "DocumentViewer",
|
||||
events: {
|
||||
'click .o_download_btn': '_onDownload',
|
||||
'click .o_split_btn': '_onSplitPDF',
|
||||
'click .o_viewer_img': '_onImageClicked',
|
||||
'click .o_viewer_video': '_onVideoClicked',
|
||||
'click .move_next': '_onNext',
|
||||
@@ -44,7 +43,7 @@ var DocumentViewer = Widget.extend({
|
||||
init: function (parent, attachments, activeAttachmentID) {
|
||||
this._super.apply(this, arguments);
|
||||
this.attachment = _.filter(attachments, function (attachment) {
|
||||
var match = attachment.type == 'url' ? attachment.url.match("(youtu|.png|.jpg|.gif)") : attachment.mimetype.match("(image|video|application/pdf|text)");
|
||||
var match = attachment.type === 'url' ? attachment.url.match("(youtu|.png|.jpg|.gif)") : attachment.mimetype.match("(image|video|application/pdf|text)");
|
||||
|
||||
if (match) {
|
||||
attachment.type = match[1];
|
||||
@@ -67,6 +66,7 @@ var DocumentViewer = Widget.extend({
|
||||
}
|
||||
});
|
||||
this.activeAttachment = _.findWhere(attachments, {id: activeAttachmentID});
|
||||
this.modelName = 'ir.attachment';
|
||||
this._reset();
|
||||
},
|
||||
/**
|
||||
@@ -325,24 +325,6 @@ var DocumentViewer = Widget.extend({
|
||||
this._zoom(scale);
|
||||
}
|
||||
},
|
||||
/**
|
||||
* @private
|
||||
* @param {MouseEvent} e
|
||||
*/
|
||||
_onSplitPDF: function (e) {
|
||||
e.stopPropagation();
|
||||
var self = this;
|
||||
var indices = $("input[name=Indices]").val();
|
||||
var remainder = $("input[type=checkbox][name=remainder]").is(":checked");
|
||||
this._rpc({
|
||||
model: 'ir.attachment',
|
||||
method: 'split_pdf',
|
||||
args: [this.activeAttachment.id, indices, remainder],
|
||||
}).always(function () {
|
||||
self.trigger_up('document_viewer_attachment_changed');
|
||||
self.destroy();
|
||||
});
|
||||
},
|
||||
/**
|
||||
* @private
|
||||
* @param {MouseEvent} e
|
||||
|
||||
@@ -485,27 +485,6 @@ $o-mail-attachment-margin: 5px;
|
||||
.o_image_caption {
|
||||
bottom: 20%;
|
||||
position: absolute;
|
||||
|
||||
.o_split_pdf_area {
|
||||
background-color: #3a3a3a;
|
||||
margin: 5px;
|
||||
padding: 6px;
|
||||
margin-left: 50px;
|
||||
|
||||
.o_split_btn {
|
||||
vertical-align: baseline;
|
||||
}
|
||||
|
||||
.o_page_number_input {
|
||||
width: 13%;
|
||||
color: black;
|
||||
display: inline;
|
||||
}
|
||||
|
||||
.o_remainder_input {
|
||||
vertical-align: middle;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -35,6 +35,7 @@
|
||||
-->
|
||||
<t t-name="DocumentViewer.Content">
|
||||
<div class="o_viewer_content">
|
||||
<t t-set="model" t-value="widget.modelName"/>
|
||||
<div class="o_viewer-header">
|
||||
<span class="o_image_caption">
|
||||
<i class="fa fa-picture-o mr8" t-if="widget.activeAttachment.type == 'image'" role="img" aria-label="Image" title="Image"/>
|
||||
@@ -42,11 +43,6 @@
|
||||
<i class="fa fa-video-camera mr8" t-if="widget.activeAttachment.type == 'video'" role="img" aria-label="Video" title="Video"/>
|
||||
<t t-esc="widget.activeAttachment.name"/>
|
||||
<a role="button" href="#" class="o_download_btn ml8 small" data-toggle="tooltip" data-placement="right" title="Download"><i class="fa fa-fw fa-download" role="img" aria-label="Download"/></a>
|
||||
<span t-if="widget.activeAttachment.type == 'application/pdf'" class="o_split_pdf_area">
|
||||
<label for="Indices">Extract pages:&nbsp;</label><input class="o_page_number_input" name="Indices" placeholder="e.g. 1-5, 7, 8-9"/>
|
||||
<label for="remainder">All pages:&nbsp;</label><input class="o_remainder_input" type="checkbox" name="remainder" value="remainder"/>
|
||||
<button class="btn btn-sm btn-primary o_split_btn" data-toggle="tooltip" title="Split">Split</button>
|
||||
</span>
|
||||
</span>
|
||||
<a role="button" class="o_close_btn float-right" href="#" aria-label="Close" title="Close">×</a>
|
||||
</div>
|
||||
@@ -55,12 +51,12 @@
|
||||
<div t-if="widget.activeAttachment.type == 'image'" class="o_loading_img text-center">
|
||||
<i class="fa fa-circle-o-notch fa-spin text-gray-light fa-3x fa-fw" role="img" aria-label="Loading" title="Loading"/>
|
||||
</div>
|
||||
<img t-if="widget.activeAttachment.type == 'image'" class="o_viewer_img" t-attf-src="/web/image/#{widget.activeAttachment.id}?unique=1&signature=#{widget.activeAttachment.checksum}" alt="Viewer"/>
|
||||
<iframe class="mt32 o_viewer_pdf" t-if="widget.activeAttachment.type == 'application/pdf'" t-attf-src="/web/static/lib/pdfjs/web/viewer.html?file=/web/content/#{widget.activeAttachment.id}" />
|
||||
<iframe class="mt32 o_viewer_text" t-if="(widget.activeAttachment.type || '').indexOf('text') !== -1" t-attf-src="/web/content/#{widget.activeAttachment.id}" />
|
||||
<iframe class="mt32 o_viewer_text" t-if="widget.activeAttachment.type == 'youtu'" allow="autoplay; encrypted-media" width="560" height="315" t-attf-src="https://www.youtube.com/embed/#{widget.activeAttachment.youtube}"/>
|
||||
<img t-if="widget.activeAttachment.type === 'image'" class="o_viewer_img" t-attf-src="/web/image/#{widget.activeAttachment.id}?unique=1&signature=#{widget.activeAttachment.checksum}&model=#{model}" alt="Viewer"/>
|
||||
<iframe t-if="widget.activeAttachment.type == 'application/pdf'" class="mt32 o_viewer_pdf" t-attf-src="/web/static/lib/pdfjs/web/viewer.html?file=/web/content/#{widget.activeAttachment.id}?model%3D#{model}" />
|
||||
<iframe t-if="(widget.activeAttachment.type || '').indexOf('text') !== -1" class="mt32 o_viewer_text" t-attf-src="/web/content/#{widget.activeAttachment.id}?model%3D#{model}" />
|
||||
<iframe t-if="widget.activeAttachment.type == 'youtu'" class="mt32 o_viewer_text" allow="autoplay; encrypted-media" width="560" height="315" t-attf-src="https://www.youtube.com/embed/#{widget.activeAttachment.youtube}"/>
|
||||
<video t-if="widget.activeAttachment.type == 'video'" class="o_viewer_video" controls="controls">
|
||||
<source t-attf-src="/web/image/#{widget.activeAttachment.id}" t-att-data-type="widget.activeAttachment.mimetype"/>
|
||||
<source t-attf-src="/web/image/#{widget.activeAttachment.id}?model=#{model}" t-att-data-type="widget.activeAttachment.mimetype"/>
|
||||
</video>
|
||||
</div>
|
||||
</div>
|
||||
@@ -86,7 +82,7 @@
|
||||
-->
|
||||
<t t-name="DocumentViewer">
|
||||
<div class="modal o_modal_fullscreen" tabindex="-1" data-keyboard="false" role="dialog">
|
||||
<t t-call="DocumentViewer.Content"/>
|
||||
<t class="o_document_viewer_content_call" t-call="DocumentViewer.Content"/>
|
||||
|
||||
<t t-if="widget.attachment.length !== 1">
|
||||
<a class="arrow arrow-left move_previous" href="#">
|
||||
|
||||
@@ -1445,11 +1445,11 @@ QUnit.test('chatter: Attachment viewer', function (assert) {
|
||||
"image caption should have correct download link");
|
||||
// click on first image attachement
|
||||
testUtils.dom.click(form.$('.o_thread_message .o_attachment .o_image_box .o_image_overlay').first());
|
||||
assert.strictEqual($('.o_modal_fullscreen img.o_viewer_img[data-src="/web/image/1?unique=1&signature=999"]').length, 1,
|
||||
assert.strictEqual($('.o_modal_fullscreen img.o_viewer_img[data-src="/web/image/1?unique=1&signature=999&model=ir.attachment"]').length, 1,
|
||||
"Modal popup should open with first image src");
|
||||
// click on next button
|
||||
testUtils.dom.click($('.modal .arrow.arrow-right.move_next span'));
|
||||
assert.strictEqual($('.o_modal_fullscreen img.o_viewer_img[data-src="/web/image/2?unique=1&signature=999"]').length, 1,
|
||||
assert.strictEqual($('.o_modal_fullscreen img.o_viewer_img[data-src="/web/image/2?unique=1&signature=999&model=ir.attachment"]').length, 1,
|
||||
"Modal popup should have now second image src");
|
||||
assert.strictEqual($('.o_modal_fullscreen .o_viewer_toolbar .o_download_btn').length, 1,
|
||||
"Modal popup should have download button");
|
||||
|
||||
@@ -19,16 +19,16 @@ var createViewer = function (params) {
|
||||
var viewer = new DocumentViewer(parent, params.attachments, params.attachmentID);
|
||||
|
||||
var mockRPC = function (route) {
|
||||
if (route === '/web/static/lib/pdfjs/web/viewer.html?file=/web/content/1') {
|
||||
if (route === '/web/static/lib/pdfjs/web/viewer.html?file=/web/content/1?model%3Dir.attachment') {
|
||||
return $.when();
|
||||
}
|
||||
if (route === 'https://www.youtube.com/embed/FYqW0Gdwbzk') {
|
||||
return $.when();
|
||||
}
|
||||
if (route === '/web/content/4') {
|
||||
if (route === '/web/content/4?model%3Dir.attachment') {
|
||||
return $.when();
|
||||
}
|
||||
if (route === '/web/image/6?unique=1&signature=999') {
|
||||
if (route === '/web/image/6?unique=1&signature=999&model=ir.attachment') {
|
||||
return $.when();
|
||||
}
|
||||
};
|
||||
@@ -100,38 +100,6 @@ QUnit.module('DocumentViewer', {
|
||||
viewer.destroy();
|
||||
});
|
||||
|
||||
QUnit.test('Document Viewer PDF', function (assert) {
|
||||
assert.expect(6);
|
||||
|
||||
var viewer = createViewer({
|
||||
attachmentID: 1,
|
||||
attachments: this.attachments,
|
||||
mockRPC: function (route, args) {
|
||||
if (args.method === 'split_pdf') {
|
||||
assert.deepEqual(args.args, [1, "", false], "should have the right arguments");
|
||||
return $.when();
|
||||
}
|
||||
return this._super.apply(this, arguments);
|
||||
},
|
||||
intercepts: {
|
||||
document_viewer_attachment_changed: function () {
|
||||
assert.ok(true, "should trigger document_viewer_attachment_changed event");
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
assert.containsOnce(viewer, '.o_page_number_input',
|
||||
"pdf should have a page input");
|
||||
assert.containsOnce(viewer, '.o_remainder_input',
|
||||
"pdf should have a remainder checkbox");
|
||||
assert.containsOnce(viewer, '.o_split_btn',
|
||||
"pdf should have a split button");
|
||||
|
||||
testUtils.dom.click(viewer.$('.o_split_btn'));
|
||||
|
||||
assert.ok(viewer.isDestroyed(), 'viewer should be destroyed');
|
||||
});
|
||||
|
||||
QUnit.test('Document Viewer Youtube', function (assert) {
|
||||
assert.expect(3);
|
||||
|
||||
@@ -165,7 +133,7 @@ QUnit.module('DocumentViewer', {
|
||||
|
||||
assert.strictEqual(viewer.$(".o_image_caption:contains('text.html')").length, 1,
|
||||
"the viewer be on the right attachment");
|
||||
assert.containsOnce(viewer, 'iframe[data-src="/web/content/4"]',
|
||||
assert.containsOnce(viewer, 'iframe[data-src="/web/content/4?model%3Dir.attachment"]',
|
||||
"there should be an iframe with the right src");
|
||||
|
||||
viewer.destroy();
|
||||
@@ -197,7 +165,7 @@ QUnit.module('DocumentViewer', {
|
||||
|
||||
assert.strictEqual(viewer.$(".o_image_caption:contains('image.jpg')").length, 1,
|
||||
"the viewer be on the right attachment");
|
||||
assert.containsOnce(viewer, 'img[data-src="/web/image/6?unique=1&signature=999"]',
|
||||
assert.containsOnce(viewer, 'img[data-src="/web/image/6?unique=1&signature=999&model=ir.attachment"]',
|
||||
"there should be a video player");
|
||||
|
||||
viewer.destroy();
|
||||
|
||||
@@ -144,9 +144,7 @@
|
||||
<field name="url"/>
|
||||
<field name="type"/>
|
||||
<field name="create_date"/>
|
||||
<field name="active"/>
|
||||
<field name="name"/>
|
||||
<field name="res_model_name"/>
|
||||
<field name="res_name"/>
|
||||
<templates>
|
||||
<t t-name="kanban-box">
|
||||
@@ -155,7 +153,7 @@
|
||||
<div class="o_kanban_image_wrapper">
|
||||
<t t-set="webimage" t-value="new RegExp('image.*(gif|jpeg|jpg|png)').test(record.mimetype.value)"/>
|
||||
<div t-if="record.type.raw_value == 'url'" class="o_url_image fa fa-link fa-3x text-muted"/>
|
||||
<img t-elif="webimage" t-attf-src="/web/image/#{record.id.raw_value}?field=thumbnail" width="100" height="100" alt="Document" class="o_attachment_image"/>
|
||||
<img t-elif="webimage" t-attf-src="/web/image/#{record.id.raw_value}" width="100" height="100" alt="Document" class="o_attachment_image"/>
|
||||
<div t-else="!webimage" class="o_image o_image_thumbnail" t-att-data-mimetype="record.mimetype.value"/>
|
||||
</div>
|
||||
</div>
|
||||
@@ -170,13 +168,7 @@
|
||||
</t>
|
||||
</div>
|
||||
<div class="o_kanban_record_body">
|
||||
<t t-if="record.res_model_name.raw_value">
|
||||
<strong><field name="res_model_name"/></strong>
|
||||
<t t-if="record.res_name.raw_value">
|
||||
<span t-att-title="record.res_name.raw_value">: <field name="res_name"/></span>
|
||||
</t>
|
||||
</t>
|
||||
<t t-elif="record.type.raw_value == 'url'">
|
||||
<t t-if="record.type.raw_value == 'url'">
|
||||
<span class="o_document_url"><i class="fa fa-globe"/> <field name="url" widget="url"/></span>
|
||||
</t>
|
||||
<samp t-else="" class="text-muted"> </samp>
|
||||
|
||||
@@ -6,17 +6,14 @@ import itertools
|
||||
import logging
|
||||
import mimetypes
|
||||
import os
|
||||
import io
|
||||
import re
|
||||
from collections import defaultdict
|
||||
import uuid
|
||||
|
||||
from odoo import api, fields, models, tools, SUPERUSER_ID, exceptions, _
|
||||
from odoo import api, fields, models, tools, SUPERUSER_ID, _
|
||||
from odoo.exceptions import AccessError, ValidationError
|
||||
from odoo.tools import config, human_size, ustr, html_escape
|
||||
from odoo.tools.mimetypes import guess_mimetype
|
||||
from odoo.tools import crop_image, image_resize_image
|
||||
from PyPDF2 import PdfFileWriter, PdfFileReader
|
||||
|
||||
_logger = logging.getLogger(__name__)
|
||||
|
||||
@@ -46,14 +43,6 @@ class IrAttachment(models.Model):
|
||||
record = self.env[attachment.res_model].browse(attachment.res_id)
|
||||
attachment.res_name = record.display_name
|
||||
|
||||
@api.depends('res_model')
|
||||
def _compute_res_model_name(self):
|
||||
for record in self:
|
||||
if record.res_model:
|
||||
model = self.env['ir.model'].search([('model', '=', record.res_model)], limit=1)
|
||||
if model:
|
||||
record.res_model_name = model[0].name
|
||||
|
||||
@api.model
|
||||
def _storage(self):
|
||||
return self.env['ir.config_parameter'].sudo().get_param('ir_attachment.location', 'file')
|
||||
@@ -290,7 +279,6 @@ class IrAttachment(models.Model):
|
||||
description = fields.Text('Description')
|
||||
res_name = fields.Char('Resource Name', compute='_compute_res_name', store=True)
|
||||
res_model = fields.Char('Resource Model', readonly=True, help="The database object this attachment will be attached to.")
|
||||
res_model_name = fields.Char(compute='_compute_res_model_name', store=True, index=True)
|
||||
res_field = fields.Char('Resource Field', readonly=True)
|
||||
res_id = fields.Integer('Resource ID', readonly=True, help="The record id this is attached to.")
|
||||
company_id = fields.Many2one('res.company', string='Company', change_default=True,
|
||||
@@ -312,8 +300,6 @@ class IrAttachment(models.Model):
|
||||
checksum = fields.Char("Checksum/SHA1", size=40, index=True, readonly=True)
|
||||
mimetype = fields.Char('Mime Type', readonly=True)
|
||||
index_content = fields.Text('Indexed Content', readonly=True, prefetch=False)
|
||||
active = fields.Boolean(default=True, string="Active", oldname='archived')
|
||||
thumbnail = fields.Binary(readonly=1, attachment=True)
|
||||
|
||||
@api.model_cr_context
|
||||
def _auto_init(self):
|
||||
@@ -449,18 +435,6 @@ class IrAttachment(models.Model):
|
||||
self.check('read')
|
||||
return super(IrAttachment, self).read(fields, load=load)
|
||||
|
||||
def _make_thumbnail(self, vals):
|
||||
if vals.get('datas') and not vals.get('res_field'):
|
||||
vals['thumbnail'] = False
|
||||
if vals.get('mimetype') and re.match('image.*(gif|jpeg|jpg|png)', vals['mimetype']):
|
||||
try:
|
||||
temp_image = crop_image(vals['datas'], type='center', size=(80, 80), ratio=(1, 1))
|
||||
vals['thumbnail'] = image_resize_image(base64_source=temp_image, size=(80, 80),
|
||||
encoding='base64')
|
||||
except Exception:
|
||||
pass
|
||||
return vals
|
||||
|
||||
@api.multi
|
||||
def write(self, vals):
|
||||
self.check('write', values=vals)
|
||||
@@ -469,8 +443,6 @@ class IrAttachment(models.Model):
|
||||
vals.pop(field, False)
|
||||
if 'mimetype' in vals or 'datas' in vals:
|
||||
vals = self._check_contents(vals)
|
||||
if all([not attachment.res_field for attachment in self]):
|
||||
vals = self._make_thumbnail(vals)
|
||||
return super(IrAttachment, self).write(vals)
|
||||
|
||||
@api.multi
|
||||
@@ -502,7 +474,6 @@ class IrAttachment(models.Model):
|
||||
for field in ('file_size', 'checksum'):
|
||||
values.pop(field, False)
|
||||
values = self._check_contents(values)
|
||||
values = self._make_thumbnail(values)
|
||||
self.browse().check('write', values=values)
|
||||
return super(IrAttachment, self).create(vals_list)
|
||||
|
||||
@@ -518,87 +489,6 @@ class IrAttachment(models.Model):
|
||||
def action_get(self):
|
||||
return self.env['ir.actions.act_window'].for_xml_id('base', 'action_attachment')
|
||||
|
||||
def _make_pdf(self, output, name_ext):
|
||||
"""
|
||||
:param output: PdfFileWriter object.
|
||||
:param name_ext: the additional name of the new attachment (page count).
|
||||
:return: the id of the attachment.
|
||||
"""
|
||||
self.ensure_one()
|
||||
try:
|
||||
stream = io.BytesIO()
|
||||
output.write(stream)
|
||||
return self.copy({
|
||||
'name': self.name+'-'+name_ext,
|
||||
'datas_fname': os.path.splitext(self.datas_fname or self.name)[0]+'-'+name_ext+".pdf",
|
||||
'datas': base64.b64encode(stream.getvalue()),
|
||||
})
|
||||
except Exception:
|
||||
raise Exception
|
||||
|
||||
def _split_pdf_groups(self, pdf_groups=None, remainder=False):
|
||||
"""
|
||||
calls _make_pdf to create the a new attachment for each page section.
|
||||
:param pdf_groups: a list of lists representing the pages to split: pages = [[1,1], [4,5], [7,7]]
|
||||
:returns the list of the ID's of the new PDF attachments.
|
||||
|
||||
"""
|
||||
self.ensure_one()
|
||||
with io.BytesIO(base64.b64decode(self.datas)) as stream:
|
||||
try:
|
||||
input_pdf = PdfFileReader(stream)
|
||||
except Exception:
|
||||
raise exceptions.ValidationError(_("ERROR: Invalid PDF file!"))
|
||||
max_page = input_pdf.getNumPages()
|
||||
remainder_set = set(range(0, max_page))
|
||||
new_pdf_ids = []
|
||||
if not pdf_groups:
|
||||
pdf_groups = []
|
||||
for pages in pdf_groups:
|
||||
pages[1] = min(max_page, pages[1])
|
||||
pages[0] = min(max_page, pages[0])
|
||||
if pages[0] == pages[1]:
|
||||
name_ext = "%s" % (pages[0],)
|
||||
else:
|
||||
name_ext = "%s-%s" % (pages[0], pages[1])
|
||||
output = PdfFileWriter()
|
||||
for i in range(pages[0]-1, pages[1]):
|
||||
output.addPage(input_pdf.getPage(i))
|
||||
new_pdf_id = self._make_pdf(output, name_ext)
|
||||
new_pdf_ids.append(new_pdf_id)
|
||||
remainder_set = remainder_set.difference(set(range(pages[0] - 1, pages[1])))
|
||||
if remainder:
|
||||
for i in remainder_set:
|
||||
output_page = PdfFileWriter()
|
||||
name_ext = "%s" % (i + 1,)
|
||||
output_page.addPage(input_pdf.getPage(i))
|
||||
new_pdf_id = self._make_pdf(output_page, name_ext)
|
||||
new_pdf_ids.append(new_pdf_id)
|
||||
self.write({'active': False})
|
||||
elif not len(remainder_set):
|
||||
self.write({'active': False})
|
||||
return new_pdf_ids
|
||||
|
||||
def split_pdf(self, indices=None, remainder=False):
|
||||
"""
|
||||
called by the Document Viewer's Split PDF button.
|
||||
evaluates the input string and turns it into a list of lists to be processed by _split_pdf_groups
|
||||
|
||||
:param indices: the formatted string of pdf split (e.g. 1,5-10, 8-22, 29-34) o_page_number_input
|
||||
:param remainder: bool, if true splits the non specified pages, one by one. form checkbox o_remainder_input
|
||||
:returns the list of the ID's of the newly created pdf attachments.
|
||||
"""
|
||||
self.ensure_one()
|
||||
if 'pdf' not in self.mimetype:
|
||||
raise exceptions.ValidationError(_("ERROR: the file must be a PDF"))
|
||||
if indices:
|
||||
try:
|
||||
pages = [[int(x) for x in x.split('-')] for x in indices.split(',')]
|
||||
except ValueError:
|
||||
raise exceptions.ValidationError(_("ERROR: Invalid list of pages to split. Example: 1,5-9,10"))
|
||||
return self._split_pdf_groups(pdf_groups=[[min(x), max(x)] for x in pages], remainder=remainder)
|
||||
return self._split_pdf_groups(remainder=remainder)
|
||||
|
||||
@api.model
|
||||
def get_serve_attachment(self, url, extra_domain=None, extra_fields=None, order=None):
|
||||
domain = [('type', '=', 'binary'), ('url', '=', url)] + (extra_domain or [])
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
# ir_http modular http routing
|
||||
#----------------------------------------------------------
|
||||
import base64
|
||||
import datetime
|
||||
import hashlib
|
||||
import logging
|
||||
import mimetypes
|
||||
@@ -23,7 +22,6 @@ from odoo.exceptions import AccessDenied, AccessError
|
||||
from odoo.http import request, STATIC_CACHE, content_disposition
|
||||
from odoo.tools import pycompat, consteq
|
||||
from odoo.tools.mimetypes import guess_mimetype
|
||||
from ast import literal_eval
|
||||
from odoo.modules.module import get_resource_path, get_module_path
|
||||
|
||||
_logger = logging.getLogger(__name__)
|
||||
@@ -260,6 +258,13 @@ class IrHttp(models.AbstractModel):
|
||||
"""
|
||||
return False
|
||||
|
||||
@classmethod
|
||||
def _get_special_models(cls):
|
||||
"""
|
||||
:return: the set of models that have to pass through several specific fields checks:
|
||||
used for the 'url' and the 'access_token' fields.
|
||||
"""
|
||||
return {'ir.attachment'}
|
||||
|
||||
@classmethod
|
||||
def binary_content(cls, xmlid=None, model='ir.attachment', id=None, field='datas',
|
||||
@@ -290,6 +295,7 @@ class IrHttp(models.AbstractModel):
|
||||
:returns: (status, headers, content)
|
||||
"""
|
||||
env = env or request.env
|
||||
attachment_models = cls._get_special_models()
|
||||
# get object and content
|
||||
obj = None
|
||||
if xmlid:
|
||||
@@ -301,7 +307,7 @@ class IrHttp(models.AbstractModel):
|
||||
return (404, [], None)
|
||||
|
||||
# access token grant access
|
||||
if model == 'ir.attachment' and access_token:
|
||||
if model in attachment_models and access_token:
|
||||
obj = obj.sudo()
|
||||
if access_mode:
|
||||
if not cls._check_access_mode(env, id, access_mode, model, access_token=access_token,
|
||||
@@ -320,7 +326,7 @@ class IrHttp(models.AbstractModel):
|
||||
|
||||
# attachment by url check
|
||||
module_resource_path = None
|
||||
if model == 'ir.attachment' and obj.type == 'url' and obj.url:
|
||||
if model in attachment_models and obj.type == 'url' and obj.url:
|
||||
url_match = re.match("^/(\w+)/(.+)$", obj.url)
|
||||
if url_match:
|
||||
module = url_match.group(1)
|
||||
|
||||
Reference in New Issue
Block a user