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.

174 lines
5.4 KiB

  1. # Copyright 2019 Therp BV <https://therp.nl>
  2. # Copyright 2019-2020 initOS GmbH <https://initos.com>
  3. # License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html).
  4. import datetime
  5. from odoo import api, fields, models, tools
  6. from odoo.tools.safe_eval import safe_eval
  7. import dateutil
  8. import vobject
  9. from dateutil import tz
  10. class DavCollectionFieldMapping(models.Model):
  11. _name = "dav.collection.field_mapping"
  12. _description = "A field mapping for a WebDAV collection"
  13. collection_id = fields.Many2one(
  14. "dav.collection",
  15. required=True,
  16. ondelete="cascade",
  17. )
  18. name = fields.Char(
  19. required=True,
  20. help="Attribute name in the vobject",
  21. )
  22. mapping_type = fields.Selection(
  23. [
  24. ("simple", "Simple"),
  25. ("code", "Code"),
  26. ],
  27. default="simple",
  28. required=True,
  29. )
  30. field_id = fields.Many2one(
  31. "ir.model.fields",
  32. required=True,
  33. ondelete="cascade",
  34. help="Field of the model the values are mapped to",
  35. )
  36. model_id = fields.Many2one(
  37. "ir.model",
  38. related="collection_id.model_id",
  39. )
  40. import_code = fields.Text(
  41. help="Code to import the value from a vobject. Use the variable "
  42. "result for the output of the value and item as input"
  43. )
  44. export_code = fields.Text(
  45. help="Code to export the value to a vobject. Use the variable "
  46. "result for the output of the value and record as input"
  47. )
  48. def from_vobject(self, child):
  49. self.ensure_one()
  50. if self.mapping_type == "code":
  51. return self._from_vobject_code(child)
  52. return self._from_vobject_simple(child)
  53. def _from_vobject_code(self, child):
  54. self.ensure_one()
  55. context = {
  56. "datetime": datetime,
  57. "dateutil": dateutil,
  58. "item": child,
  59. "result": None,
  60. "tools": tools,
  61. "tz": tz,
  62. "vobject": vobject,
  63. }
  64. safe_eval(self.import_code, context, mode="exec", nocopy=True)
  65. return context.get("result", {})
  66. def _from_vobject_simple(self, child):
  67. self.ensure_one()
  68. name = self.name.lower()
  69. conversion_funcs = [
  70. "_from_vobject_%s_%s" % (self.field_id.ttype, name),
  71. "_from_vobject_%s" % self.field_id.ttype,
  72. ]
  73. for conversion_func in conversion_funcs:
  74. if hasattr(self, conversion_func):
  75. value = getattr(self, conversion_func)(child)
  76. if value:
  77. return value
  78. return child.value
  79. @api.model
  80. def _from_vobject_datetime(self, item):
  81. if isinstance(item.value, datetime.datetime):
  82. value = item.value.astimezone(dateutil.tz.UTC)
  83. return value.strftime(tools.DEFAULT_SERVER_DATETIME_FORMAT)
  84. elif isinstance(item.value, datetime.date):
  85. return item.value.strftime(tools.DEFAULT_SERVER_DATETIME_FORMAT)
  86. return None
  87. @api.model
  88. def _from_vobject_date(self, item):
  89. if isinstance(item.value, datetime.datetime):
  90. value = item.value.astimezone(dateutil.tz.UTC)
  91. return value.strftime(tools.DEFAULT_SERVER_DATE_FORMAT)
  92. elif isinstance(item.value, datetime.date):
  93. return item.value.strftime(tools.DEFAULT_SERVER_DATE_FORMAT)
  94. return None
  95. @api.model
  96. def _from_vobject_binary(self, item):
  97. return item.value.encode("ascii")
  98. @api.model
  99. def _from_vobject_char_n(self, item):
  100. return item.family
  101. def to_vobject(self, record):
  102. self.ensure_one()
  103. if self.mapping_type == "code":
  104. result = self._to_vobject_code(record)
  105. else:
  106. result = self._to_vobject_simple(record)
  107. if isinstance(result, datetime.datetime) and not result.tzinfo:
  108. return result.replace(tzinfo=tz.UTC)
  109. return result
  110. def _to_vobject_code(self, record):
  111. self.ensure_one()
  112. context = {
  113. "datetime": datetime,
  114. "dateutil": dateutil,
  115. "record": record,
  116. "result": None,
  117. "tools": tools,
  118. "tz": tz,
  119. "vobject": vobject,
  120. }
  121. safe_eval(self.export_code, context, mode="exec", nocopy=True)
  122. return context.get("result", None)
  123. def _to_vobject_simple(self, record):
  124. self.ensure_one()
  125. conversion_funcs = [
  126. "_to_vobject_%s_%s" % (self.field_id.ttype, self.name.lower()),
  127. "_to_vobject_%s" % self.field_id.ttype,
  128. ]
  129. value = record[self.field_id.name]
  130. for conversion_func in conversion_funcs:
  131. if hasattr(self, conversion_func):
  132. return getattr(self, conversion_func)(value)
  133. return value
  134. @api.model
  135. def _to_vobject_datetime(self, value):
  136. result = fields.Datetime.from_string(value)
  137. return result.replace(tzinfo=tz.UTC)
  138. @api.model
  139. def _to_vobject_datetime_rev(self, value):
  140. return value and value.replace("-", "").replace(" ", "T").replace(":", "") + "Z"
  141. @api.model
  142. def _to_vobject_date(self, value):
  143. return fields.Date.from_string(value)
  144. @api.model
  145. def _to_vobject_binary(self, value):
  146. return value and value.decode("ascii")
  147. @api.model
  148. def _to_vobject_char_n(self, value):
  149. # TODO: how are we going to handle compound types like this?
  150. return vobject.vcard.Name(family=value)