forked from OCA/server-tools
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
0 parents
commit f8bb336
Showing
14 changed files
with
929 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,91 @@ | ||
.. image:: https://img.shields.io/badge/licence-AGPL--3-blue.svg | ||
:target: http://www.gnu.org/licenses/agpl-3.0-standalone.html | ||
:alt: License: AGPL-3 | ||
|
||
==================== | ||
Multiple Images Base | ||
==================== | ||
|
||
This module extends the functionality of any model to support multiple images | ||
(a gallery) attached to it and allow you to manage them. | ||
|
||
Installation | ||
============ | ||
|
||
This module adds abstract models to work on. Its sole purpose is to serve as | ||
base for other modules that implement galleries, so if you install this one | ||
manually you will notice no change. You should install any other module based | ||
on this one and this will get installed automatically. | ||
|
||
Usage | ||
===== | ||
|
||
To manage all stored images, you need to: | ||
|
||
* Go to *Settings > Configuration > Multi images*. | ||
|
||
... but you probably prefer to manage them from the forms supplied by | ||
submodules that inherit this behavior. | ||
|
||
Development | ||
=========== | ||
|
||
To develop a module based on this one: | ||
|
||
* See module ``product_multi_image`` as an example. | ||
* You have to inherit model ``base_multi_image.owner`` to the model that needs | ||
the gallery:: | ||
|
||
class MyOwner(models.Model): | ||
_name = "mymodule.name" | ||
_inherit = "base_multi_image.owner" | ||
|
||
# If you need this, you will need ``post_init_hook_for_submodules`` | ||
old_image_field = fields.Binary(related="image_main", store=False) | ||
|
||
.. image:: https://odoo-community.org/website/image/ir.attachment/5784_f2813bd/datas | ||
:alt: Try me on Runbot | ||
:target: https://runbot.odoo-community.org/runbot/149/8.0 | ||
|
||
Bug Tracker | ||
=========== | ||
|
||
Bugs are tracked on `GitHub Issues | ||
<https://github.com/OCA/server-tools/issues>`_. In case of trouble, please | ||
check there if your issue has already been reported. If you spotted it first, | ||
help us smashing it by providing a detailed and welcomed `feedback | ||
<https://github.com/OCA/ | ||
server-tools/issues/new?body=module:%20 | ||
base_multi_image%0Aversion:%20 | ||
8.0%0A%0A**Steps%20to%20reproduce**%0A-%20...%0A%0A**Current%20behavior**%0A%0A**Expected%20behavior**>`_. | ||
|
||
Credits | ||
======= | ||
|
||
Original implementation | ||
----------------------- | ||
This module is inspired in previous module *product_images* from OpenLabs | ||
and Akretion. | ||
|
||
Contributors | ||
------------ | ||
|
||
* Sharoon Thomas | ||
* Pedro M. Baeza <[email protected]> | ||
* Rafael Blasco <[email protected]> | ||
* Jairo Llopis <[email protected]> | ||
|
||
Maintainer | ||
---------- | ||
|
||
.. image:: https://odoo-community.org/logo.png | ||
:alt: Odoo Community Association | ||
:target: https://odoo-community.org | ||
|
||
This module is maintained by the OCA. | ||
|
||
OCA, or the Odoo Community Association, is a nonprofit organization whose | ||
mission is to support the collaborative development of Odoo features and | ||
promote its widespread use. | ||
|
||
To contribute to this module, please visit http://odoo-community.org. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
# -*- coding: utf-8 -*- | ||
# © 2014 Serv. Tecnol. Avanzados (http://www.serviciosbaeza.com) | ||
# Pedro M. Baeza <[email protected]> | ||
# © 2015 Antiun Ingeniería S.L. - Jairo Llopis | ||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). | ||
|
||
from . import models |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
# -*- coding: utf-8 -*- | ||
# © 2014 Serv. Tecnol. Avanzados (http://www.serviciosbaeza.com) | ||
# Pedro M. Baeza <[email protected]> | ||
# © 2015 Antiun Ingeniería S.L. - Jairo Llopis | ||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). | ||
|
||
{ | ||
"name": "Multiple images base", | ||
"summary": "Allow multiple images for database objects", | ||
"version": "8.0.1.0.0", | ||
"author": "Serv. Tecnol. Avanzados - Pedro M. Baeza, " | ||
"Antiun Ingeniería, S.L., " | ||
"Odoo Community Association (OCA)", | ||
"license": "AGPL-3", | ||
"website": "http://www.antiun.com", | ||
"category": "Tools", | ||
"depends": ['base'], | ||
'installable': True, | ||
"data": [ | ||
"security/ir.model.access.csv", | ||
"views/image_view.xml", | ||
], | ||
"images": [ | ||
"images/form.png", | ||
"images/kanban.png", | ||
], | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
# -*- coding: utf-8 -*- | ||
# © 2016 Antiun Ingeniería S.L. - Jairo Llopis | ||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). | ||
|
||
from openerp import SUPERUSER_ID | ||
import logging | ||
|
||
_logger = logging.getLogger(__name__) | ||
|
||
|
||
def post_init_hook_for_submodules(cr, registry, model, field): | ||
"""Moves images from single to multi mode. | ||
Feel free to use this as a ``post_init_hook`` for submodules. | ||
:param str model: | ||
Model name, like ``product.template``. | ||
:param str field: | ||
Binary field that had the images in that :param:`model`, like | ||
``image``. | ||
""" | ||
with cr.savepoint(): | ||
records = registry[model].search( | ||
cr, | ||
SUPERUSER_ID, | ||
[(field, "!=", False)], | ||
context=dict()) | ||
|
||
_logger.info("Moving images from %s to multi image mode.", model) | ||
for r in registry[model].browse(cr, SUPERUSER_ID, records): | ||
_logger.debug("Setting up multi image for record %d.", r.id) | ||
r.image_main = r[field] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
# Translation of OpenERP Server. | ||
# This file contains the translation of the following modules: | ||
# * product_images_olbs | ||
# | ||
msgid "" | ||
msgstr "" | ||
"Project-Id-Version: OpenERP Server 5.0.14\n" | ||
"Report-Msgid-Bugs-To: [email protected]\n" | ||
"POT-Creation-Date: 2010-11-22 10:19:32+0000\n" | ||
"PO-Revision-Date: 2010-11-22 10:19:32+0000\n" | ||
"Last-Translator: <>\n" | ||
"Language-Team: \n" | ||
"MIME-Version: 1.0\n" | ||
"Content-Type: text/plain; charset=UTF-8\n" | ||
"Content-Transfer-Encoding: \n" | ||
"Plural-Forms: \n" | ||
|
||
#. module: product_images_olbs | ||
#: model:ir.module.module,shortdesc:product_images_olbs.module_meta_information | ||
msgid "Product Image Gallery" | ||
msgstr "Product Image Gallery" | ||
|
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
# -*- coding: utf-8 -*- | ||
# © 2009 Sharoon Thomas Open Labs Business Solutions | ||
# © 2015 Antiun Ingeniería S.L. - Jairo Llopis | ||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). | ||
|
||
from . import image, owner |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,181 @@ | ||
# -*- coding: utf-8 -*- | ||
# © 2014 Serv. Tecnol. Avanzados (http://www.serviciosbaeza.com) | ||
# Pedro M. Baeza <[email protected]> | ||
# © 2015 Antiun Ingeniería S.L. - Jairo Llopis | ||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). | ||
|
||
import base64 | ||
import urllib | ||
import os | ||
import logging | ||
from openerp import models, fields, api, exceptions, _ | ||
from openerp import tools | ||
|
||
_logger = logging.getLogger(__name__) | ||
|
||
|
||
class ImageABC(models.Model): | ||
_name = "base_multi_image.image" | ||
_sql_constraints = [ | ||
('uniq_name_owner', 'UNIQUE(owner_id, owner_model, name)', | ||
_('A document can have only one image with the same name.')), | ||
] | ||
|
||
owner_id = fields.Integer( | ||
"Owner", | ||
required=True) | ||
owner_model = fields.Char( | ||
required=True) | ||
storage = fields.Selection( | ||
[('url', 'URL'), ('file', 'OS file'), ('db', 'Database')], | ||
required=True, | ||
default='db') | ||
name = fields.Char( | ||
'Image title', | ||
required=True, | ||
translate=True) | ||
filename = fields.Char() | ||
extension = fields.Char( | ||
'File extension', | ||
readonly=True) | ||
file_db_store = fields.Binary( | ||
'Image stored in database', | ||
filters='*.png,*.jpg,*.gif') | ||
path = fields.Char( | ||
"Image path", | ||
help="Image path") | ||
url = fields.Char( | ||
'Image remote URL') | ||
image_main = fields.Binary( | ||
"Full-sized image", | ||
compute="_get_image") | ||
image_medium = fields.Binary( | ||
"Medium-sized image", | ||
compute="_get_image_sizes", | ||
help="Medium-sized image. It is automatically resized as a " | ||
"128 x 128 px image, with aspect ratio preserved, only when the " | ||
"image exceeds one of those sizes. Use this field in form views " | ||
"or kanban views.") | ||
image_small = fields.Binary( | ||
"Small-sized image", | ||
compute="_get_image_sizes", | ||
help="Small-sized image. It is automatically resized as a 64 x 64 px " | ||
"image, with aspect ratio preserved. Use this field anywhere a " | ||
"small image is required.") | ||
comments = fields.Text( | ||
'Comments', | ||
translate=True) | ||
show_technical = fields.Boolean( | ||
compute="_show_technical") | ||
|
||
@api.multi | ||
@api.depends('storage', 'path', 'file_db_store', 'url') | ||
def _get_image(self): | ||
"""Get image data from the right storage type.""" | ||
for s in self: | ||
s.image_main = getattr(s, "_get_image_from_%s" % s.storage)() | ||
|
||
@api.multi | ||
@api.depends("owner_id", "owner_model") | ||
def _show_technical(self): | ||
"""Know if you need to show the technical fields.""" | ||
self.show_technical = all( | ||
"default_owner_%s" % f not in self.env.context | ||
for f in ("id", "model")) | ||
|
||
@api.multi | ||
def _get_image_from_db(self): | ||
return self.file_db_store | ||
|
||
@api.multi | ||
def _get_image_from_file(self): | ||
if self.path and os.path.exists(self.path): | ||
try: | ||
with open(self.path, 'rb') as f: | ||
return base64.b64encode(f.read()) | ||
except Exception as e: | ||
_logger.error("Can not open the image %s, error : %s", | ||
self.path, e, exc_info=True) | ||
else: | ||
_logger.error("The image %s doesn't exist ", self.path) | ||
|
||
return False | ||
|
||
@api.multi | ||
def _get_image_from_url(self): | ||
if self.url: | ||
try: | ||
(filename, header) = urllib.urlretrieve(self.url) | ||
with open(filename, 'rb') as f: | ||
return base64.b64encode(f.read()) | ||
except: | ||
_logger.error("URL %s cannot be fetched", self.url, | ||
exc_info=True) | ||
|
||
return False | ||
|
||
@api.multi | ||
@api.depends('image_main') | ||
def _get_image_sizes(self): | ||
for s in self: | ||
try: | ||
vals = tools.image_get_resized_images( | ||
s.with_context(bin_size=False).image_main) | ||
except: | ||
vals = {"image_medium": False, | ||
"image_small": False} | ||
s.update(vals) | ||
|
||
@api.multi | ||
def _check_filestore(self): | ||
"""check if the filestore is created, and do it otherwise.""" | ||
for s in self: | ||
dir_path = os.path.dirname(s.path) | ||
try: | ||
if not os.path.exists(dir_path): | ||
os.makedirs(dir_path) | ||
except OSError as e: | ||
raise exceptions.Warning( | ||
_('The image filestore cannot be created, %s') % e) | ||
|
||
@api.model | ||
def _make_pretty(self, name): | ||
return name.replace('_', ' ').capitalize() | ||
|
||
@api.onchange('url') | ||
def _onchange_url(self): | ||
if self.url: | ||
filename = self.url.split('/')[-1] | ||
self.name, self.extension = os.path.splitext(filename) | ||
self.name = self._make_pretty(self.name) | ||
|
||
@api.onchange('path') | ||
def _onchange_path(self): | ||
if self.path: | ||
self.name, self.extension = os.path.splitext(os.path.basename( | ||
self.path)) | ||
self.name = self._make_pretty(self.name) | ||
|
||
@api.onchange('filename') | ||
def _onchange_filename(self): | ||
if self.filename: | ||
self.name, self.extension = os.path.splitext(self.filename) | ||
self.name = self._make_pretty(self.name) | ||
|
||
@api.constrains('storage', 'url') | ||
def _check_url(self): | ||
if self.storage == 'url' and not self.url: | ||
raise exceptions.ValidationError( | ||
'You must provide an URL for the image.') | ||
|
||
@api.constrains('storage', 'path') | ||
def _check_path(self): | ||
if self.storage == 'file' and not self.path: | ||
raise exceptions.ValidationError( | ||
'You must provide a file path for the image.') | ||
|
||
@api.constrains('storage', 'file_db_store') | ||
def _check_store(self): | ||
if self.storage == 'db' and not self.file_db_store: | ||
raise exceptions.ValidationError( | ||
'You must provide an attached file for the image.') |
Oops, something went wrong.