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.

179 lines
5.9 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 Image(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. name = fields.Char(
  28. 'Image title',
  29. translate=True)
  30. filename = fields.Char()
  31. extension = fields.Char(
  32. 'File extension',
  33. readonly=True)
  34. file_db_store = fields.Binary(
  35. 'Image stored in database',
  36. filters='*.png,*.jpg,*.gif')
  37. path = fields.Char(
  38. "Image path",
  39. help="Image path")
  40. url = fields.Char(
  41. 'Image remote URL')
  42. image_main = fields.Binary(
  43. "Full-sized image",
  44. compute="_get_image")
  45. image_medium = fields.Binary(
  46. "Medium-sized image",
  47. compute="_get_image_sizes",
  48. help="Medium-sized image. It is automatically resized as a "
  49. "128 x 128 px image, with aspect ratio preserved, only when the "
  50. "image exceeds one of those sizes. Use this field in form views "
  51. "or kanban views.")
  52. image_small = fields.Binary(
  53. "Small-sized image",
  54. compute="_get_image_sizes",
  55. help="Small-sized image. It is automatically resized as a 64 x 64 px "
  56. "image, with aspect ratio preserved. Use this field anywhere a "
  57. "small image is required.")
  58. comments = fields.Text(
  59. 'Comments',
  60. translate=True)
  61. show_technical = fields.Boolean(
  62. compute="_show_technical")
  63. @api.multi
  64. @api.depends('storage', 'path', 'file_db_store', 'url')
  65. def _get_image(self):
  66. """Get image data from the right storage type."""
  67. for s in self:
  68. s.image_main = getattr(s, "_get_image_from_%s" % s.storage)()
  69. @api.multi
  70. @api.depends("owner_id", "owner_model")
  71. def _show_technical(self):
  72. """Know if you need to show the technical fields."""
  73. self.show_technical = all(
  74. "default_owner_%s" % f not in self.env.context
  75. for f in ("id", "model"))
  76. @api.multi
  77. def _get_image_from_db(self):
  78. return self.file_db_store
  79. @api.multi
  80. def _get_image_from_file(self):
  81. if self.path and os.path.exists(self.path):
  82. try:
  83. with open(self.path, 'rb') as f:
  84. return base64.b64encode(f.read())
  85. except Exception as e:
  86. _logger.error("Can not open the image %s, error : %s",
  87. self.path, e, exc_info=True)
  88. else:
  89. _logger.error("The image %s doesn't exist ", self.path)
  90. return False
  91. @api.multi
  92. def _get_image_from_url(self):
  93. if self.url:
  94. try:
  95. (filename, header) = urllib.urlretrieve(self.url)
  96. with open(filename, 'rb') as f:
  97. return base64.b64encode(f.read())
  98. except:
  99. _logger.error("URL %s cannot be fetched", self.url,
  100. exc_info=True)
  101. return False
  102. @api.multi
  103. @api.depends('image_main')
  104. def _get_image_sizes(self):
  105. for s in self:
  106. try:
  107. vals = tools.image_get_resized_images(
  108. s.with_context(bin_size=False).image_main)
  109. except:
  110. vals = {"image_medium": False,
  111. "image_small": False}
  112. s.update(vals)
  113. @api.multi
  114. def _check_filestore(self):
  115. """check if the filestore is created, and do it otherwise."""
  116. for s in self:
  117. dir_path = os.path.dirname(s.path)
  118. try:
  119. if not os.path.exists(dir_path):
  120. os.makedirs(dir_path)
  121. except OSError as e:
  122. raise exceptions.Warning(
  123. _('The image filestore cannot be created, %s') % e)
  124. @api.model
  125. def _make_name_pretty(self, name):
  126. return name.replace('_', ' ').capitalize()
  127. @api.onchange('url')
  128. def _onchange_url(self):
  129. if self.url:
  130. filename = self.url.split('/')[-1]
  131. self.name, self.extension = os.path.splitext(filename)
  132. self.name = self._make_name_pretty(self.name)
  133. @api.onchange('path')
  134. def _onchange_path(self):
  135. if self.path:
  136. self.name, self.extension = os.path.splitext(os.path.basename(
  137. self.path))
  138. self.name = self._make_name_pretty(self.name)
  139. @api.onchange('filename')
  140. def _onchange_filename(self):
  141. if self.filename:
  142. self.name, self.extension = os.path.splitext(self.filename)
  143. self.name = self._make_name_pretty(self.name)
  144. @api.constrains('storage', 'url')
  145. def _check_url(self):
  146. if self.storage == 'url' and not self.url:
  147. raise exceptions.ValidationError(
  148. 'You must provide an URL for the image.')
  149. @api.constrains('storage', 'path')
  150. def _check_path(self):
  151. if self.storage == 'file' and not self.path:
  152. raise exceptions.ValidationError(
  153. 'You must provide a file path for the image.')
  154. @api.constrains('storage', 'file_db_store')
  155. def _check_store(self):
  156. if self.storage == 'db' and not self.file_db_store:
  157. raise exceptions.ValidationError(
  158. 'You must provide an attached file for the image.')