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.

132 lines
5.0 KiB

  1. ###################################################################################
  2. #
  3. # Copyright (C) 2017 MuK IT GmbH
  4. #
  5. # This program is free software: you can redistribute it and/or modify
  6. # it under the terms of the GNU Affero General Public License as
  7. # published by the Free Software Foundation, either version 3 of the
  8. # License, or (at your option) any later version.
  9. #
  10. # This program is distributed in the hope that it will be useful,
  11. # but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. # GNU Affero General Public License for more details.
  14. #
  15. # You should have received a copy of the GNU Affero General Public License
  16. # along with this program. If not, see <http://www.gnu.org/licenses/>.
  17. #
  18. ###################################################################################
  19. import re
  20. import uuid
  21. import base64
  22. from odoo import api, fields, models
  23. XML_ID = "muk_web_theme._assets_primary_variables"
  24. SCSS_URL = "/muk_web_theme/static/src/scss/colors.scss"
  25. TEMPLATE = """
  26. $o-brand-odoo: {0};
  27. $o-brand-primary: {1};
  28. $mk-brand-gradient-start: lighten($o-brand-odoo, 10%);
  29. $mk-brand-gradient-end: lighten($o-brand-odoo, 20%);
  30. """
  31. class ResConfigSettings(models.TransientModel):
  32. _inherit = 'res.config.settings'
  33. theme_background_image = fields.Binary(
  34. related="company_id.background_image",
  35. readonly=False,
  36. required=True)
  37. theme_color_brand = fields.Char(
  38. string="Brand Color")
  39. theme_color_primary = fields.Char(
  40. string="Primary Color")
  41. @api.multi
  42. def set_values(self):
  43. res = super(ResConfigSettings, self).set_values()
  44. self._save_scss_values()
  45. return res
  46. @api.model
  47. def get_values(self):
  48. res = super(ResConfigSettings, self).get_values()
  49. res.update(self._get_scss_values())
  50. return res
  51. def _get_custom_scss_url(self, url, xmlid):
  52. return self._build_custom_scss_url(url.rsplit(".", 1), xmlid)
  53. def _build_custom_scss_url(self, url_parts, xmlid):
  54. return "%s.custom.%s.%s" % (url_parts[0], xmlid, url_parts[1])
  55. def _get_custom_attachment(self, url):
  56. return self.env["ir.attachment"].search([("url", '=', url)])
  57. def _get_scss_values(self):
  58. custom_url = self._get_custom_scss_url(SCSS_URL, XML_ID)
  59. custom_attachment = self._get_custom_attachment(custom_url)
  60. if custom_attachment.exists():
  61. content = str(base64.b64decode(custom_attachment.datas))
  62. brand = re.search( r'o-brand-odoo\:?\s(.*?);', content)
  63. primary = re.search( r'o-brand-primary\:?\s(.*?);', content)
  64. return {
  65. 'theme_color_brand': brand and brand.group(1) or "#243742",
  66. 'theme_color_primary': primary and primary.group(1) or "#5D8DA8",
  67. }
  68. else:
  69. return {
  70. 'theme_color_brand': "#243742",
  71. 'theme_color_primary': "#5D8DA8",
  72. }
  73. def _build_custom_scss_template(self):
  74. return TEMPLATE.format(
  75. self.theme_color_brand or "#243742",
  76. self.theme_color_primary or "#5D8DA8"
  77. )
  78. def _save_scss_values(self):
  79. custom_url = self._get_custom_scss_url(SCSS_URL, XML_ID)
  80. custom_attachment = self._get_custom_attachment(custom_url)
  81. custom_content = self._build_custom_scss_template()
  82. datas = base64.b64encode((custom_content).encode("utf-8"))
  83. if custom_attachment:
  84. custom_attachment.write({"datas": datas})
  85. else:
  86. self.env["ir.attachment"].create({
  87. 'name': custom_url,
  88. 'type': "binary",
  89. 'mimetype': "text/scss",
  90. 'datas': datas,
  91. 'datas_fname': SCSS_URL.split("/")[-1],
  92. 'url': custom_url,
  93. })
  94. view_to_xpath = self.env["ir.ui.view"].get_related_views(
  95. XML_ID, bundles=True
  96. ).filtered(lambda v: v.arch.find(url) >= 0)
  97. self.env["ir.ui.view"].create({
  98. 'name': custom_url,
  99. 'key': 'web_editor.scss_%s' % str(uuid.uuid4())[:6],
  100. 'mode': "extension",
  101. 'inherit_id': view_to_xpath.id,
  102. 'arch': """
  103. <data inherit_id="%(inherit_xml_id)s" name="%(name)s">
  104. <xpath expr="//link[@href='%(url_to_replace)s']" position="attributes">
  105. <attribute name="href">%(new_url)s</attribute>
  106. </xpath>
  107. </data>
  108. """ % {
  109. 'inherit_xml_id': view_to_xpath.xml_id,
  110. 'name': custom_url,
  111. 'url_to_replace': url,
  112. 'new_url': custom_url,
  113. }
  114. })
  115. self.env["ir.qweb"].clear_caches()