From 89f20d2c297d99d4eb0ded8be78fbf86b8ec45d3 Mon Sep 17 00:00:00 2001
From: ThanhDodeurOdoo <tso@odoo.com>
Date: Wed, 7 Nov 2018 14:52:33 +0000
Subject: [PATCH] [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
---
 addons/mail/static/src/js/document_viewer.js  |  22 +---
 addons/mail/static/src/scss/composer.scss     |  21 ----
 addons/mail/static/src/xml/thread.xml         |  18 ++-
 addons/mail/static/tests/chatter_tests.js     |   4 +-
 .../static/tests/document_viewer_tests.js     |  42 +------
 addons/mail/views/mail_message_views.xml      |  12 +-
 odoo/addons/base/models/ir_attachment.py      | 112 +-----------------
 odoo/addons/base/models/ir_http.py            |  14 ++-
 8 files changed, 29 insertions(+), 216 deletions(-)

diff --git a/addons/mail/static/src/js/document_viewer.js b/addons/mail/static/src/js/document_viewer.js
index e2c03e24d6a8..9affc3f41cf1 100644
--- a/addons/mail/static/src/js/document_viewer.js
+++ b/addons/mail/static/src/js/document_viewer.js
@@ -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
diff --git a/addons/mail/static/src/scss/composer.scss b/addons/mail/static/src/scss/composer.scss
index bd9307bdd2fb..aa5131b0de5b 100644
--- a/addons/mail/static/src/scss/composer.scss
+++ b/addons/mail/static/src/scss/composer.scss
@@ -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;
-                    }
-                }
             }
         }
 
diff --git a/addons/mail/static/src/xml/thread.xml b/addons/mail/static/src/xml/thread.xml
index fcfe8ba7de2c..914168306b83 100644
--- a/addons/mail/static/src/xml/thread.xml
+++ b/addons/mail/static/src/xml/thread.xml
@@ -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:&amp;nbsp;</label><input class="o_page_number_input" name="Indices" placeholder="e.g. 1-5, 7, 8-9"/>
-                        <label for="remainder">All pages:&amp;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&amp;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&amp;signature=#{widget.activeAttachment.checksum}&amp;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="#">
diff --git a/addons/mail/static/tests/chatter_tests.js b/addons/mail/static/tests/chatter_tests.js
index 470b6045797b..ac9f715be5dd 100644
--- a/addons/mail/static/tests/chatter_tests.js
+++ b/addons/mail/static/tests/chatter_tests.js
@@ -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");
diff --git a/addons/mail/static/tests/document_viewer_tests.js b/addons/mail/static/tests/document_viewer_tests.js
index ef825f84e2a1..87fa2dbed942 100644
--- a/addons/mail/static/tests/document_viewer_tests.js
+++ b/addons/mail/static/tests/document_viewer_tests.js
@@ -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();
diff --git a/addons/mail/views/mail_message_views.xml b/addons/mail/views/mail_message_views.xml
index d224fb2ccc04..df7643f7f36f 100644
--- a/addons/mail/views/mail_message_views.xml
+++ b/addons/mail/views/mail_message_views.xml
@@ -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>
diff --git a/odoo/addons/base/models/ir_attachment.py b/odoo/addons/base/models/ir_attachment.py
index 535605d9fe78..967f93a33e20 100644
--- a/odoo/addons/base/models/ir_attachment.py
+++ b/odoo/addons/base/models/ir_attachment.py
@@ -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 [])
diff --git a/odoo/addons/base/models/ir_http.py b/odoo/addons/base/models/ir_http.py
index 63d12137d7a3..5d6e84a59b3c 100644
--- a/odoo/addons/base/models/ir_http.py
+++ b/odoo/addons/base/models/ir_http.py
@@ -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)
-- 
GitLab