storage_backend/storage_thumbnail/models/thumbnail_mixin.py

130 lines
4.5 KiB
Python

# Copyright 2017 Akretion (http://www.akretion.com).
# @author Sébastien BEAU <sebastien.beau@akretion.com>
# License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl).
import logging
from odoo import api, fields, models, tools
_logger = logging.getLogger(__name__)
try:
from slugify import slugify
except ImportError:
_logger.debug("Cannot `import slugify`.")
class ThumbnailMixing(models.AbstractModel):
_name = "thumbnail.mixin"
_description = "Thumbnail Mixin add the thumbnail capability"
thumbnail_ids = fields.One2many(
comodel_name="storage.thumbnail",
string="Thumbnails",
inverse_name="res_id",
domain=lambda self: [("res_model", "=", self._name)],
)
thumb_medium_id = fields.Many2one(
comodel_name="storage.thumbnail",
compute="_compute_main_thumbs",
store=True,
readonly=False,
compute_sudo=True,
)
thumb_small_id = fields.Many2one(
comodel_name="storage.thumbnail",
compute="_compute_main_thumbs",
store=True,
readonly=False,
compute_sudo=True,
)
image_medium_url = fields.Char(
string="Medium thumb URL", compute="_compute_thumb_urls", compute_sudo=True
)
image_small_url = fields.Char(
string="Small thumb URL", compute="_compute_thumb_urls", compute_sudo=True
)
_image_scale_mapping = {
"medium": (128, 128),
"small": (64, 64),
}
@api.depends("thumbnail_ids.size_x", "thumbnail_ids.size_y")
def _compute_main_thumbs(self):
for rec in self:
for scale in self._image_scale_mapping.keys():
fname = "thumb_%s_id" % scale
rec[fname] = rec._get_thumb(scale_key=scale)
@api.depends(
"thumb_medium_id", "thumb_small_id", "backend_id.backend_view_use_internal_url"
)
def _compute_thumb_urls(self):
for backend, records in tools.groupby(self, lambda x: x.backend_id):
url_fname = "url"
if backend.backend_view_use_internal_url:
url_fname = "internal_url"
for rec in records:
rec.image_medium_url = rec.thumb_medium_id[url_fname]
rec.image_small_url = rec.thumb_small_id[url_fname]
def _get_thumb(self, scale_key=None, scale=None):
"""Retrievet the first thumb matching given scale."""
assert scale_key or scale
scale = scale or self._image_scale_mapping[scale_key]
size_x, size_y = scale
for thumb in self.thumbnail_ids:
if thumb.size_x == size_x and thumb.size_y == size_y:
return thumb
def _get_medium_thumbnail(self):
return self.get_or_create_thumbnail(*self._image_scale_mapping["medium"])
def _get_small_thumbnail(self):
return self.get_or_create_thumbnail(*self._image_scale_mapping["small"])
def _get_url_key(self, url_key):
if url_key:
url_key = slugify(url_key)
return url_key
def get_existing_thumbnail(self, size_x, size_y, url_key=None):
self.ensure_one()
url_key = self._get_url_key(url_key)
thumbnail = self.env["storage.thumbnail"].browse()
for th in self.thumbnail_ids:
if th.size_x == size_x and th.size_y == size_y:
if url_key and url_key != th.url_key:
continue
thumbnail = th
break
return thumbnail
def get_or_create_thumbnail(self, size_x, size_y, url_key=None):
url_key = self._get_url_key(url_key)
thumbnail = self.get_existing_thumbnail(size_x, size_y, url_key=url_key)
if not thumbnail and self.data:
vals = self.env["storage.thumbnail"]._prepare_thumbnail(
self, size_x, size_y, url_key
)
thumbnail = self.thumbnail_ids.create(vals)
# invalidate field since a new record is created
# The actual model is a mixin, therefore the inverse into
# storage.thumbnail is not defined as a one2many to this mixin.
# As consequence, the ORM is not able to trigger the invalidation
# of thumbnail_ids on our mixin
self.thumbnail_ids.refresh()
return thumbnail
def generate_odoo_thumbnail(self):
self_sudo = self.sudo()
self_sudo._get_small_thumbnail()
self_sudo._get_medium_thumbnail()
return True
@api.model
def create(self, vals):
record = super().create(vals)
record.generate_odoo_thumbnail()
return record