diff --git a/addons/web_editor/controllers/main.py b/addons/web_editor/controllers/main.py index d4ff41de09d..83320fef24f 100644 --- a/addons/web_editor/controllers/main.py +++ b/addons/web_editor/controllers/main.py @@ -4,20 +4,18 @@ import base64 import io import json import logging -import os import re import time -import uuid import werkzeug.wrappers from PIL import Image, ImageFont, ImageDraw -from lxml import etree, html +from lxml import etree from odoo.http import request from odoo import http, tools -from odoo.modules.module import get_resource_path, get_module_path logger = logging.getLogger(__name__) + class Web_Editor(http.Controller): #------------------------------------------------------ # convert font into picture @@ -296,40 +294,57 @@ class Web_Editor(http.Controller): result['originalSrc'] = record.url return result - def _get_view_fields_to_read(self): - return ['name', 'id', 'key', 'xml_id', 'arch', 'active', 'inherit_id'] - - ## The get_assets_editor_resources route is in charge of transmitting the resources the assets - ## editor needs to work. - ## @param key - the xml_id or id of the view the resources are related to - ## @param get_views - True if the views must be fetched (default to True) - ## @param get_scss - True if the style must be fetched (default to True) - ## @param get_js - True if the javascript must be fetched (default to True) - ## @param bundles - True if the bundles views must be fetched (default to False) - ## @param bundles_restriction - Names of the bundle in which to look for scss files (if empty, search in all of them) - ## @param only_user_custom_files - True if only user custom files are needed (default to True) - ## @returns a dictionary with views info in the views key and style info in the scss key @http.route("/web_editor/get_assets_editor_resources", type="json", auth="user", website=True) def get_assets_editor_resources(self, key, get_views=True, get_scss=True, get_js=True, bundles=False, bundles_restriction=[], only_user_custom_files=True): + """ + Transmit the resources the assets editor needs to work. + + Params: + key (str): the key of the view the resources are related to + + get_views (bool, default=True): + True if the views must be fetched + + get_scss (bool, default=True): + True if the style must be fetched + + get_js (bool, default=True): + True if the javascript must be fetched + + bundles (bool, default=False): + True if the bundles views must be fetched + + bundles_restriction (list, default=[]): + Names of the bundles in which to look for scss files + (if empty, search in all of them) + + only_user_custom_files (bool, default=True): + True if only user custom files must be fetched + + Returns: + dict: views, scss, js + """ # Related views must be fetched if the user wants the views and/or the style views = request.env["ir.ui.view"].get_related_views(key, bundles=bundles) - views = views.read(self._get_view_fields_to_read()) + views = views.read(request.env['web_editor.assets'].get_view_fields_to_read()) - js_files_data_by_bundle = [] scss_files_data_by_bundle = [] + js_files_data_by_bundle = [] - if get_js: - js_files_data_by_bundle = self.load_resources('js', views, bundles_restriction, only_user_custom_files) if get_scss: - scss_files_data_by_bundle = self.load_resources('scss', views, bundles_restriction, only_user_custom_files) + scss_files_data_by_bundle = self._load_resources('scss', views, bundles_restriction, only_user_custom_files) + if get_js: + js_files_data_by_bundle = self._load_resources('js', views, bundles_restriction, only_user_custom_files) - return dict( - views=get_views and views or [], - scss=get_scss and scss_files_data_by_bundle or [], - js=get_js and js_files_data_by_bundle or [], - ) + return { + 'views': get_views and views or [], + 'scss': get_scss and scss_files_data_by_bundle or [], + 'js': get_js and js_files_data_by_bundle or [], + } + + def _load_resources(self, file_type, views, bundles_restriction, only_user_custom_files): + AssetsUtils = request.env['web_editor.assets'] - def load_resources(self, file_type, views, bundles_restriction, only_user_custom_files): files_data_by_bundle = [] resources_type_info = {'t_call_assets_attribute': 't-js', 'mimetype': 'text/javascript'} if file_type == 'scss': @@ -339,10 +354,6 @@ class Web_Editor(http.Controller): # This will used to exclude library scss files from the result excluded_url_matcher = re.compile("^(.+/lib/.+)|(.+import_bootstrap.+\.scss)$") - # Load already customized files attachments - custom_url = self._make_custom_scss_or_js_file_url("%%.%%", "%%") - custom_attachments = self.get_custom_attachment(custom_url, op='=like') - # First check the t-call-assets used in the related views url_infos = dict() for v in views: @@ -363,7 +374,7 @@ class Web_Editor(http.Controller): continue # Check if the file is customized and get bundle/path info - file_data = self._match_scss_or_js_file_url(url) + file_data = AssetsUtils.get_asset_info(url) if not file_data: continue @@ -375,13 +386,19 @@ class Web_Editor(http.Controller): or file_type == 'scss' and not only_user_custom_files: files_data.append(url) - # File data is returned sorted by bundle, with the bundles names and xmlids + # scss data is returned sorted by bundle, with the bundles + # names and xmlids if len(files_data): - files_data_by_bundle.append([dict(xmlid=asset_name, name=request.env.ref(asset_name).name), files_data]) + files_data_by_bundle.append([ + {'xmlid': asset_name, 'name': request.env.ref(asset_name).name}, + files_data + ]) # Filter bundles/files: - # - A file which appears in multiple bundles only appears in the first one (the first in the DOM) - # - Only keep bundles with files which appears in the asked bundles and only keep those files + # - A file which appears in multiple bundles only appears in the + # first one (the first in the DOM) + # - Only keep bundles with files which appears in the asked bundles + # and only keep those files for i in range(0, len(files_data_by_bundle)): bundle_1 = files_data_by_bundle[i] for j in range(0, len(files_data_by_bundle)): @@ -393,7 +410,8 @@ class Web_Editor(http.Controller): bundle_1 = files_data_by_bundle[i] for j in range(i + 1, len(files_data_by_bundle)): bundle_2 = files_data_by_bundle[j] - # In every bundle, keep only the files which were not found in previous bundles + # In every bundle, keep only the files which were not found + # in previous bundles bundle_2[1] = [item_2 for item_2 in bundle_2[1] if item_2 not in bundle_1[1]] # Only keep bundles which still have files and that were requested @@ -403,146 +421,57 @@ class Web_Editor(http.Controller): ] # Fetch the arch of each kept file, in each bundle + urls = [] + for bundle_data in files_data_by_bundle: + urls += bundle_data[1] + custom_attachments = AssetsUtils.get_all_custom_attachments(urls) + for bundle_data in files_data_by_bundle: for i in range(0, len(bundle_data[1])): url = bundle_data[1][i] url_info = url_infos[url] - content = None - if url_info["customized"]: - # If the file is already customized, the content is found in the corresponding attachment - content = base64.b64decode(custom_attachments.filtered(lambda a: a.url == url).datas) - else: - # If the file is not yet customized, the content is found by reading the local scss file - module = url_info["module"] - module_path = get_module_path(module) - module_resource_path = get_resource_path(module, url_info["resource_path"]) - if module_path and module_resource_path: - module_path = os.path.join(os.path.normpath(module_path), '') # join ensures the path ends with '/' - module_resource_path = os.path.normpath(module_resource_path) - if module_resource_path.startswith(module_path): - with open(module_resource_path, "rb") as f: - content = f.read() + content = AssetsUtils.get_asset_content(url, url_info, custom_attachments) + + bundle_data[1][i] = { + 'url': "/%s/%s" % (url_info["module"], url_info["resource_path"]), + 'arch': content, + 'customized': url_info["customized"], + } - bundle_data[1][i] = dict( - url="/%s/%s" % (url_info["module"], url_info["resource_path"]), - arch=content, - customized=url_info["customized"], - ) return files_data_by_bundle - def save_scss_or_js_view_hook(self): - return {} + @http.route("/web_editor/save_asset", type="json", auth="user", website=True) + def save_asset(self, url, bundle_xmlid, content, file_type): + """ + Save a given modification of a scss/js file. - def save_scss_or_js_attachment_hook(self): - return {} + Params: + url (str): + the original url of the scss/js file which has to be modified - ## The save_scss_or_js route is in charge of saving a given modification of a scss/js file. - ## @param url - the original url of the scss/js file which has to be modified - ## @param bundle_xmlid - the xmlid of the bundle in which the scss/js file addition can be found - ## @param content - the new content of the scss/js file - ## @param file_type - scss or js - @http.route("/web_editor/save_scss_or_js", type="json", auth="user", website=True) - def save_scss_or_js(self, url, bundle_xmlid, content, file_type): - IrAttachment = request.env["ir.attachment"] + bundle_xmlid (str): + the xmlid of the bundle in which the scss/js file addition can + be found - custom_url = self._make_custom_scss_or_js_file_url(url, bundle_xmlid) + content (str): the new content of the scss/js file - # Check if the file to save had already been modified - custom_attachment = self.get_custom_attachment(custom_url) - datas = base64.b64encode((content or "\n").encode("utf-8")) - if custom_attachment: - # If it was already modified, simply override the corresponding attachment content - custom_attachment.write({"datas": datas}) - else: - # If not, create a new attachment to copy the original scss/js file content, with its modifications - new_attach = { - 'name': custom_url, - 'type': "binary", - 'mimetype': (file_type == 'js' and 'text/javascript' or 'text/scss'), - 'datas': datas, - 'datas_fname': url.split("/")[-1], - 'url': custom_url, - } - new_attach.update(self.save_scss_or_js_attachment_hook()) - IrAttachment.create(new_attach) + file_type (str): 'scss' or 'js' + """ + request.env['web_editor.assets'].save_asset(url, bundle_xmlid, content, file_type) - # Create a view to extend the template which adds the original file to link the new modified version instead - IrUiView = request.env["ir.ui.view"] - file_type_info = { - 'tag': 'link' if file_type == 'scss' else 'script', - 'attribute': 'href' if file_type == 'scss' else 'src', - } + @http.route("/web_editor/reset_asset", type="json", auth="user", website=True) + def reset_asset(self, url, bundle_xmlid): + """ + The reset_asset route is in charge of reverting all the changes that + were done to a scss/js file. - def views_linking_url(view): - """ - Returns whether the view arch has some html link tag linked to the url. + Params: + url (str): + the original URL of the scss/js file to reset - (note: searching for the URL string is not enough as it could appear in a comment or an xpath expression.) - """ - tree = etree.XML(view.arch) - return bool(tree.xpath("//%%(tag)s[@%%(attribute)s='%(url)s']" % { - 'url': url, - } % file_type_info)) - - view_to_xpath = IrUiView.get_related_views(bundle_xmlid, bundles=True).filtered(views_linking_url) - - new_view = { - 'name': custom_url, - 'key': 'web_editor.%s_%s' % (file_type, str(uuid.uuid4())[:6]), - 'mode': "extension", - 'inherit_id': view_to_xpath.id, - 'arch': """ - - - %(new_url)s - - - """ % { - 'inherit_xml_id': view_to_xpath.xml_id, - 'name': custom_url, - 'url_to_replace': url, - 'new_url': custom_url, - } % file_type_info - } - new_view.update(self.save_scss_or_js_view_hook()) - IrUiView.create(new_view) - - request.env["ir.qweb"].clear_caches() - - ## The reset_scss_or_js route is in charge of reverting all the changes that were done to a scss/js file. - ## @param url - the original URL of the scss file to reset - ## @param bundle_xmlid - the xmlid of the bundle in which the scss file addition can be found - @http.route("/web_editor/reset_scss_or_js", type="json", auth="user", website=True) - def reset_scss_or_js(self, url, bundle_xmlid): - custom_url = self._make_custom_scss_or_js_file_url(url, bundle_xmlid) - - # Simply delete the attachement which contains the modified scss/js file and the xpath view which links it - self.get_custom_attachment(custom_url).unlink() - self.get_custom_view(custom_url).unlink() - - def get_custom_attachment(self, custom_url, op='='): - assert op in ('=like', '='), 'Invalid operator' - IrAttachment = request.env["ir.attachment"] - return IrAttachment.search([("url", op, custom_url)]) - - def get_custom_view(self, custom_url, op='='): - assert op in ('=like', '='), 'Invalid operator' - IrUiView = request.env["ir.ui.view"] - return IrUiView.search([("name", op, custom_url)]) - - def _make_custom_scss_or_js_file_url(self, url, bundle): - parts = url.rsplit(".", 1) - return "%s.custom.%s.%s" % (parts[0], bundle, parts[1]) - - _match_file_url_regex = re.compile("^/(\w+)/(.+?)(\.custom\.(.+))?\.(\w+)$") - def _match_scss_or_js_file_url(self, url): - m = self._match_file_url_regex.match(url) - if not m: - return False - return { - 'module': m.group(1), - 'resource_path': "%s.%s" % (m.group(2), m.group(5)), - 'customized': bool(m.group(3)), - 'bundle': m.group(4) or False - } + bundle_xmlid (str): + the xmlid of the bundle in which the scss/js file addition can + be found + """ + request.env['web_editor.assets'].reset_asset(url, bundle_xmlid) diff --git a/addons/web_editor/models/__init__.py b/addons/web_editor/models/__init__.py index b895b36ca54..e9a790f7e61 100644 --- a/addons/web_editor/models/__init__.py +++ b/addons/web_editor/models/__init__.py @@ -7,4 +7,6 @@ from . import ir_ui_view from . import ir_http from . import ir_translation +from . import assets + from . import test_models diff --git a/addons/web_editor/models/assets.py b/addons/web_editor/models/assets.py new file mode 100644 index 00000000000..9406fc495b2 --- /dev/null +++ b/addons/web_editor/models/assets.py @@ -0,0 +1,279 @@ +# -*- coding: utf-8 -*- +# Part of Odoo. See LICENSE file for full copyright and licensing details. + +import base64 +import os +import re +import uuid + +from lxml import etree + +from odoo import models +from odoo.modules.module import get_resource_path, get_module_path + +_match_asset_file_url_regex = re.compile("^/(\w+)/(.+?)(\.custom\.(.+))?\.(\w+)$") + + +class Assets(models.AbstractModel): + _name = 'web_editor.assets' + _description = 'Assets Utils' + + def get_view_fields_to_read(self): + return ['name', 'id', 'key', 'xml_id', 'arch', 'active', 'inherit_id'] + + def get_all_custom_attachments(self, urls): + """ + Fetch all the ir.attachment records related to given URLs. + + Params: + urls (str[]): list of urls + + Returns: + ir.attachment(): attachment records related to the given URLs. + """ + return self._get_custom_attachment(urls, op='in') + + def get_asset_content(self, url, url_info=None, custom_attachments=None): + """ + Fetch the content of an asset (scss / js) file. That content is either + the one of the related file on the disk or the one of the corresponding + custom ir.attachment record. + + Params: + url (str): the URL of the asset (scss / js) file/ir.attachment + + url_info (dict, optional): + the related url info (see get_asset_info) (allows to optimize + some code which already have the info and do not want this + function to re-get it) + + custom_attachments (ir.attachment(), optional): + the related custom ir.attachment records the function might need + to search into (allows to optimize some code which already have + that info and do not want this function to re-get it) + + Returns: + utf-8 encoded content of the asset (scss / js) + """ + if url_info is None: + url_info = self.get_asset_info(url) + + if url_info["customized"]: + # If the file is already customized, the content is found in the + # corresponding attachment + attachment = None + if custom_attachments is None: + attachment = self._get_custom_attachment(url) + else: + attachment = custom_attachments.filtered(lambda r: r.url == url) + return attachment and base64.b64decode(attachment.datas) or False + + # If the file is not yet customized, the content is found by reading + # the local scss file + module = url_info["module"] + module_path = get_module_path(module) + module_resource_path = get_resource_path(module, url_info["resource_path"]) + if module_path and module_resource_path: + module_path = os.path.join(os.path.normpath(module_path), '') # join ensures the path ends with '/' + module_resource_path = os.path.normpath(module_resource_path) + if module_resource_path.startswith(module_path): + with open(module_resource_path, "rb") as f: + return f.read() + + def get_asset_info(self, url): + """ + Return information about an asset (scss / js) file/ir.attachment just by + looking at its URL. + + Params: + url (str): the url of the asset (scss / js) file/ir.attachment + + Returns: + dict: + module (str): the original asset's related app + + resource_path (str): + the relative path to the original asset from the related app + + customized (bool): whether the asset is a customized one or not + + bundle (str): + the name of the bundle the asset customizes (False if this + is not a customized asset) + """ + m = _match_asset_file_url_regex.match(url) + if not m: + return False + return { + 'module': m.group(1), + 'resource_path': "%s.%s" % (m.group(2), m.group(5)), + 'customized': bool(m.group(3)), + 'bundle': m.group(4) or False + } + + def make_custom_asset_file_url(self, url, bundle_xmlid): + """ + Return the customized version of an asset URL, that is the URL the asset + would have if it was customized. + + Params: + url (str): the original asset's url + bundle_xmlid (str): the name of the bundle the asset would customize + + Returns: + str: the URL the given asset would have if it was customized in the + given bundle + """ + parts = url.rsplit(".", 1) + return "%s.custom.%s.%s" % (parts[0], bundle_xmlid, parts[1]) + + def reset_asset(self, url, bundle_xmlid): + """ + Delete the potential customizations made to a given (original) asset. + + Params: + url (str): the URL of the original asset (scss / js) file + + bundle_xmlid (str): + the name of the bundle in which the customizations to delete + were made + """ + custom_url = self.make_custom_asset_file_url(url, bundle_xmlid) + + # Simply delete the attachement which contains the modified scss/js file + # and the xpath view which links it + self._get_custom_attachment(custom_url).unlink() + self._get_custom_view(custom_url).unlink() + + def save_asset(self, url, bundle_xmlid, content, file_type): + """ + Customize the content of a given asset (scss / js). + + Params: + url (src): + the URL of the original asset to customize (whether or not the + asset was already customized) + + bundle_xmlid (src): + the name of the bundle in which the customizations will take + effect + + content (src): the new content of the asset (scss / js) + + file_type (src): + either 'scss' or 'js' according to the file being customized + """ + custom_url = self.make_custom_asset_file_url(url, bundle_xmlid) + datas = base64.b64encode((content or "\n").encode("utf-8")) + + # Check if the file to save had already been modified + custom_attachment = self._get_custom_attachment(custom_url) + if custom_attachment: + # If it was already modified, simply override the corresponding + # attachment content + custom_attachment.write({"datas": datas}) + else: + # If not, create a new attachment to copy the original scss/js file + # content, with its modifications + new_attach = { + 'name': custom_url, + 'type': "binary", + 'mimetype': (file_type == 'js' and 'text/javascript' or 'text/scss'), + 'datas': datas, + 'datas_fname': url.split("/")[-1], + 'url': custom_url, + } + new_attach.update(self._save_asset_attachment_hook()) + self.env["ir.attachment"].create(new_attach) + + # Create a view to extend the template which adds the original file + # to link the new modified version instead + file_type_info = { + 'tag': 'link' if file_type == 'scss' else 'script', + 'attribute': 'href' if file_type == 'scss' else 'src', + } + + def views_linking_url(view): + """ + Returns whether the view arch has some html tag linked to + the url. (note: searching for the URL string is not enough as it + could appear in a comment or an xpath expression.) + """ + tree = etree.XML(view.arch) + return bool(tree.xpath("//%%(tag)s[@%%(attribute)s='%(url)s']" % { + 'url': url, + } % file_type_info)) + + IrUiView = self.env["ir.ui.view"] + view_to_xpath = IrUiView.get_related_views(bundle_xmlid, bundles=True).filtered(views_linking_url) + new_view = { + 'name': custom_url, + 'key': 'web_editor.%s_%s' % (file_type, str(uuid.uuid4())[:6]), + 'mode': "extension", + 'inherit_id': view_to_xpath.id, + 'arch': """ + + + %(new_url)s + + + """ % { + 'inherit_xml_id': view_to_xpath.xml_id, + 'name': custom_url, + 'url_to_replace': url, + 'new_url': custom_url, + } % file_type_info + } + new_view.update(self._save_asset_view_hook()) + IrUiView.create(new_view) + + self.env["ir.qweb"].clear_caches() + + def _get_custom_attachment(self, custom_url, op='='): + """ + Fetch the ir.attachment record related to the given customized asset. + + Params: + custom_url (str): the URL of the customized asset + op (str, default: '='): the operator to use to search the records + + Returns: + ir.attachment() + """ + assert op in ('in', '='), 'Invalid operator' + return self.env["ir.attachment"].search([("url", op, custom_url)]) + + def _get_custom_view(self, custom_url, op='='): + """ + Fetch the ir.ui.view record related to the given customized asset (the + inheriting view which replace the original asset by the customized one). + + Params: + custom_url (str): the URL of the customized asset + op (str, default: '='): the operator to use to search the records + + Returns: + ir.ui.view() + """ + assert op in ('='), 'Invalid operator' + return self.env["ir.ui.view"].search([("name", op, custom_url)]) + + def _save_asset_attachment_hook(self): + """ + Returns the additional values to use to write the DB on customized + attachment creation. + + Returns: + dict + """ + return {} + + def _save_asset_view_hook(self): + """ + Returns the additional values to use to write the DB on customized + asset's related view creation. + + Returns: + dict + """ + return {} diff --git a/addons/web_editor/static/src/js/common/ace.js b/addons/web_editor/static/src/js/common/ace.js index f231bb0aac6..f242129c4a8 100644 --- a/addons/web_editor/static/src/js/common/ace.js +++ b/addons/web_editor/static/src/js/common/ace.js @@ -535,7 +535,7 @@ var ViewEditor = Widget.extend({ } else { var resource = type === 'scss' ? this.scss[resID] : this.js[resID]; return this._rpc({ - route: '/web_editor/reset_scss_or_js', + route: '/web_editor/reset_asset', params: { url: resID, bundle_xmlid: resource.bundle_xmlid, @@ -560,7 +560,7 @@ var ViewEditor = Widget.extend({ var bundleXmlID = sessionIdEndsWithJS ? this.js[session.id].bundle_xmlid : this.scss[session.id].bundle_xmlid; var fileType = sessionIdEndsWithJS ? 'js' : 'scss'; self._rpc({ - route: '/web_editor/save_scss_or_js', + route: '/web_editor/save_asset', params: { url: session.id, bundle_xmlid: bundleXmlID, diff --git a/addons/website/controllers/main.py b/addons/website/controllers/main.py index 6ba749bc3c2..a2d1d332f80 100644 --- a/addons/website/controllers/main.py +++ b/addons/website/controllers/main.py @@ -4,6 +4,7 @@ import base64 import datetime import json import os +import re import logging import requests import werkzeug.utils @@ -368,6 +369,42 @@ class Website(Home): self.theme_customize(enable and enable.split(",") or [], disable and disable.split(",") or []) return request.redirect(href + ("&theme=true" if "#" in href else "#theme=true") + ("&tab=" + tab)) + @http.route(['/website/make_scss_custo'], type='json', auth='user', website=True) + def make_scss_custo(self, url, values): + """ + Makes a scss customization of the given file. That file must + contain a scss map including a line comment containing the word 'hook', + to indicate the location where to write the new key,value pairs. + + Params: + url (str): + the URL of the scss file to customize (supposed to be a variable + file which will appear in the assets_common bundle) + + values (dict): + key,value mapping to integrate in the file's map (containing the + word hook). If a key is already in the file's map, its value is + overridden. + """ + AssetsUtils = request.env['web_editor.assets'] + + custom_url = AssetsUtils.make_custom_asset_file_url(url, 'web.assets_common') + updatedFileContent = AssetsUtils.get_asset_content(custom_url) or AssetsUtils.get_asset_content(url) + updatedFileContent = updatedFileContent.decode('utf-8') + for name, value in values.items(): + pattern = "'%s': %%s,\n" % name + regex = re.compile(pattern % ".+") + replacement = pattern % value + if regex.search(updatedFileContent): + updatedFileContent = re.sub(regex, replacement, updatedFileContent) + else: + updatedFileContent = re.sub(r'( *)(.*hook.*)', r'\1%s\1\2' % replacement, updatedFileContent) + + # Bundle is 'assets_common' as this route is only meant to update + # variables scss files + AssetsUtils.save_asset(url, 'web.assets_common', updatedFileContent, 'scss') + return True + @http.route(['/website/multi_render'], type='json', auth="public", website=True) def multi_render(self, ids_or_xml_ids, values=None): View = request.env['ir.ui.view'] diff --git a/addons/website/models/assets.py b/addons/website/models/assets.py index 92aa9bb1d8a..0d2be3d2b91 100644 --- a/addons/website/models/assets.py +++ b/addons/website/models/assets.py @@ -1,38 +1,55 @@ # -*- coding: utf-8 -*- # Part of Odoo. See LICENSE file for full copyright and licensing details. -from odoo.addons.web_editor.controllers.main import Web_Editor -from odoo.http import request + +from odoo import models -class Web_Editor(Web_Editor): +class Assets(models.AbstractModel): + _inherit = 'web_editor.assets' - def _get_view_fields_to_read(self): - res = super(Web_Editor, self)._get_view_fields_to_read() + def get_view_fields_to_read(self): + res = super(Assets, self).get_view_fields_to_read() res.append('website_id') return res - def save_scss_or_js_view_hook(self): - res = super(Web_Editor, self).save_scss_or_js_view_hook() - - website = request.env['website'].get_current_website() - if website: - res['website_id'] = website.id - return res - - def save_scss_or_js_attachment_hook(self): - res = super(Web_Editor, self).save_scss_or_js_attachment_hook() - - website = request.env['website'].get_current_website() - if website: - res['website_id'] = website.id - return res - - def get_custom_attachment(self, custom_url, op='='): - website = request.env['website'].get_current_website() - res = super(Web_Editor, self).get_custom_attachment(custom_url, op=op) + def _get_custom_attachment(self, custom_url, op='='): + """ + See web_editor.Assets._get_custom_attachment + Extend to only return the attachments related to the current website. + """ + website = self.env['website'].get_current_website() + res = super(Assets, self)._get_custom_attachment(custom_url, op=op) return res.with_context(website_id=website.id).filtered(lambda x: not x.website_id or x.website_id == website) - def get_custom_view(self, custom_url, op='='): - website = request.env['website'].get_current_website() - res = super(Web_Editor, self).get_custom_view(custom_url, op=op) + def _get_custom_view(self, custom_url, op='='): + """ + See web_editor.Assets._get_custom_view + Extend to only return the views related to the current website. + """ + website = self.env['website'].get_current_website() + res = super(Assets, self)._get_custom_view(custom_url, op=op) return res.with_context(website_id=website.id).filter_duplicate() + + def _save_asset_attachment_hook(self): + """ + See web_editor.Assets._save_asset_attachment_hook + Extend to add website ID at attachment creation. + """ + res = super(Assets, self)._save_asset_attachment_hook() + + website = self.env['website'].get_current_website() + if website: + res['website_id'] = website.id + return res + + def _save_asset_view_hook(self): + """ + See web_editor.Assets._save_asset_view_hook + Extend to add website ID at view creation. + """ + res = super(Assets, self)._save_asset_view_hook() + + website = self.env['website'].get_current_website() + if website: + res['website_id'] = website.id + return res diff --git a/addons/website/static/src/js/widgets/theme.js b/addons/website/static/src/js/widgets/theme.js index 89bab6bb058..cc054b2fc00 100644 --- a/addons/website/static/src/js/widgets/theme.js +++ b/addons/website/static/src/js/widgets/theme.js @@ -416,46 +416,12 @@ var ThemeCustomizeDialog = Dialog.extend({ * @private */ _makeSCSSCusto: function (url, values) { - var self = this; - return this._rpc({ // TODO improve to be more efficient - route: '/web_editor/get_assets_editor_resources', + return this._rpc({ + route: '/website/make_scss_custo', params: { - 'key': 'website.layout', - 'get_views': false, - 'get_scss': true, - 'get_js': false, - 'bundles': false, - 'bundles_restriction': [], - 'only_user_custom_files': false, + 'url': url, + 'values': values, }, - }).then(function (data) { - var file = _.find(data.scss[0][1], function (file) { - return file.url === url; - }); - - var updatedFileContent = file.arch; - _.each(values, function (value, name) { - var pattern = _.str.sprintf("'%s': %%s,\n", name); - var regex = new RegExp(_.str.sprintf(pattern, ".+")); - var replacement = _.str.sprintf(pattern, value); - if (regex.test(updatedFileContent)) { - updatedFileContent = updatedFileContent - .replace(regex, replacement); - } else { - updatedFileContent = updatedFileContent - .replace(/( *)(.*hook.*)/, _.str.sprintf('$1%s$1$2', replacement)); - } - }); - - return self._rpc({ - route: '/web_editor/save_scss_or_js', - params: { - 'url': file.url, - 'bundle_xmlid': 'web.assets_common', - 'content': updatedFileContent, - 'file_type': 'scss', - }, - }); }); }, /**