You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

181 lines
6.0 KiB

  1. # -*- coding: utf-8 -*-
  2. # © 2014 Serv. Tecnol. Avanzados (http://www.serviciosbaeza.com)
  3. # Pedro M. Baeza <pedro.baeza@serviciosbaeza.com>
  4. # © 2015 Antiun Ingeniería S.L. - Jairo Llopis
  5. # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
  6. import base64
  7. import urllib
  8. import os
  9. import logging
  10. from openerp import models, fields, api, exceptions, _
  11. from openerp import tools
  12. _logger = logging.getLogger(__name__)
  13. class ImageABC(models.Model):
  14. _name = "base_multi_image.image"
  15. _sql_constraints = [
  16. ('uniq_name_owner', 'UNIQUE(owner_id, owner_model, name)',
  17. _('A document can have only one image with the same name.')),
  18. ]
  19. owner_id = fields.Integer(
  20. "Owner",
  21. required=True)
  22. owner_model = fields.Char(
  23. required=True)
  24. storage = fields.Selection(
  25. [('url', 'URL'), ('file', 'OS file'), ('db', 'Database')],
  26. required=True,
  27. default='db')
  28. name = fields.Char(
  29. 'Image title',
  30. required=True,
  31. translate=True)
  32. filename = fields.Char()
  33. extension = fields.Char(
  34. 'File extension',
  35. readonly=True)
  36. file_db_store = fields.Binary(
  37. 'Image stored in database',
  38. filters='*.png,*.jpg,*.gif')
  39. path = fields.Char(
  40. "Image path",
  41. help="Image path")
  42. url = fields.Char(
  43. 'Image remote URL')
  44. image_main = fields.Binary(
  45. "Full-sized image",
  46. compute="_get_image")
  47. image_medium = fields.Binary(
  48. "Medium-sized image",
  49. compute="_get_image_sizes",
  50. help="Medium-sized image. It is automatically resized as a "
  51. "128 x 128 px image, with aspect ratio preserved, only when the "
  52. "image exceeds one of those sizes. Use this field in form views "
  53. "or kanban views.")
  54. image_small = fields.Binary(
  55. "Small-sized image",
  56. compute="_get_image_sizes",
  57. help="Small-sized image. It is automatically resized as a 64 x 64 px "
  58. "image, with aspect ratio preserved. Use this field anywhere a "
  59. "small image is required.")
  60. comments = fields.Text(
  61. 'Comments',
  62. translate=True)
  63. show_technical = fields.Boolean(
  64. compute="_show_technical")
  65. @api.multi
  66. @api.depends('storage', 'path', 'file_db_store', 'url')
  67. def _get_image(self):
  68. """Get image data from the right storage type."""
  69. for s in self:
  70. s.image_main = getattr(s, "_get_image_from_%s" % s.storage)()
  71. @api.multi
  72. @api.depends("owner_id", "owner_model")
  73. def _show_technical(self):
  74. """Know if you need to show the technical fields."""
  75. self.show_technical = all(
  76. "default_owner_%s" % f not in self.env.context
  77. for f in ("id", "model"))
  78. @api.multi
  79. def _get_image_from_db(self):
  80. return self.file_db_store
  81. @api.multi
  82. def _get_image_from_file(self):
  83. if self.path and os.path.exists(self.path):
  84. try:
  85. with open(self.path, 'rb') as f:
  86. return base64.b64encode(f.read())
  87. except Exception as e:
  88. _logger.error("Can not open the image %s, error : %s",
  89. self.path, e, exc_info=True)
  90. else:
  91. _logger.error("The image %s doesn't exist ", self.path)
  92. return False
  93. @api.multi
  94. def _get_image_from_url(self):
  95. if self.url:
  96. try:
  97. (filename, header) = urllib.urlretrieve(self.url)
  98. with open(filename, 'rb') as f:
  99. return base64.b64encode(f.read())
  100. except:
  101. _logger.error("URL %s cannot be fetched", self.url,
  102. exc_info=True)
  103. return False
  104. @api.multi
  105. @api.depends('image_main')
  106. def _get_image_sizes(self):
  107. for s in self:
  108. try:
  109. vals = tools.image_get_resized_images(
  110. s.with_context(bin_size=False).image_main)
  111. except:
  112. vals = {"image_medium": False,
  113. "image_small": False}
  114. s.update(vals)
  115. @api.multi
  116. def _check_filestore(self):
  117. """check if the filestore is created, and do it otherwise."""
  118. for s in self:
  119. dir_path = os.path.dirname(s.path)
  120. try:
  121. if not os.path.exists(dir_path):
  122. os.makedirs(dir_path)
  123. except OSError as e:
  124. raise exceptions.Warning(
  125. _('The image filestore cannot be created, %s') % e)
  126. @api.model
  127. def _make_pretty(self, name):
  128. return name.replace('_', ' ').capitalize()
  129. @api.onchange('url')
  130. def _onchange_url(self):
  131. if self.url:
  132. filename = self.url.split('/')[-1]
  133. self.name, self.extension = os.path.splitext(filename)
  134. self.name = self._make_pretty(self.name)
  135. @api.onchange('path')
  136. def _onchange_path(self):
  137. if self.path:
  138. self.name, self.extension = os.path.splitext(os.path.basename(
  139. self.path))
  140. self.name = self._make_pretty(self.name)
  141. @api.onchange('filename')
  142. def _onchange_filename(self):
  143. if self.filename:
  144. self.name, self.extension = os.path.splitext(self.filename)
  145. self.name = self._make_pretty(self.name)
  146. @api.constrains('storage', 'url')
  147. def _check_url(self):
  148. if self.storage == 'url' and not self.url:
  149. raise exceptions.ValidationError(
  150. 'You must provide an URL for the image.')
  151. @api.constrains('storage', 'path')
  152. def _check_path(self):
  153. if self.storage == 'file' and not self.path:
  154. raise exceptions.ValidationError(
  155. 'You must provide a file path for the image.')
  156. @api.constrains('storage', 'file_db_store')
  157. def _check_store(self):
  158. if self.storage == 'db' and not self.file_db_store:
  159. raise exceptions.ValidationError(
  160. 'You must provide an attached file for the image.')