diff options
| author | Christophe Matthieu <chm@odoo.com> | 2015-08-10 16:39:09 +0200 |
|---|---|---|
| committer | Christophe Simonis <chs@odoo.com> | 2015-09-03 19:31:00 +0200 |
| commit | 522fcacb21febf96393d3132b5c3f32c69b9a82a (patch) | |
| tree | f1f5b35dce7eeb611180bfa480c0efb3ea0c8725 | |
| parent | 952b03e32dc8ef6bae383debec8d78e40e22599f (diff) | |
[IMP] base: assets now directly use /web/content url
| -rw-r--r-- | addons/im_livechat/controllers/main.py | 12 | ||||
| -rw-r--r-- | addons/im_livechat/views/im_livechat_channel_templates.xml | 4 | ||||
| -rw-r--r-- | addons/mail/views/mail_message_views.xml | 9 | ||||
| -rw-r--r-- | addons/web/controllers/main.py | 43 | ||||
| -rw-r--r-- | addons/website/views/website_templates.xml | 2 | ||||
| -rw-r--r-- | openerp/addons/base/ir/ir_attachment.py | 8 | ||||
| -rw-r--r-- | openerp/addons/base/ir/ir_qweb.py | 139 |
7 files changed, 91 insertions, 126 deletions
diff --git a/addons/im_livechat/controllers/main.py b/addons/im_livechat/controllers/main.py index 152e1374fb5..ce4096b0b23 100644 --- a/addons/im_livechat/controllers/main.py +++ b/addons/im_livechat/controllers/main.py @@ -1,10 +1,22 @@ # -*- coding: utf-8 -*- from openerp import http, _ from openerp.http import request +from openerp.addons.base.ir.ir_qweb import AssetsBundle +from openerp.addons.web.controllers.main import binary_content +import base64 class LivechatController(http.Controller): + @http.route('/im_livechat/external_lib.<any(css,js):ext>', type='http', auth='none') + def livechat_lib(self, xmlid, ext, **kwargs): + asset = AssetsBundle("im_livechat.external_lib") + # can't use /web/content directly because we don't have attachment ids (attachments must be created) + status, headers, content = binary_content(id=getattr(asset, ext)().id, unique=asset.checksum) + content_base64 = base64.b64decode(content) + headers.append(('Content-Length', len(content_base64))) + return request.make_response(content_base64, headers) + @http.route('/im_livechat/support/<int:channel_id>', type='http', auth='public') def support_page(self, channel_id, **kwargs): channel = request.env['im_livechat.channel'].sudo().browse(channel_id) diff --git a/addons/im_livechat/views/im_livechat_channel_templates.xml b/addons/im_livechat/views/im_livechat_channel_templates.xml index 3079f6f97f1..ddd92458417 100644 --- a/addons/im_livechat/views/im_livechat_channel_templates.xml +++ b/addons/im_livechat/views/im_livechat_channel_templates.xml @@ -87,9 +87,9 @@ --> <template id="external_loader" name="Livechat : external_script field of livechat channel"> <!-- css style --> - <link t-att-href="'%s/web/css/im_livechat.external_lib' % (url)" rel="stylesheet"/> + <link t-att-href="'%s/im_livechat/external_lib.css' % (url)" rel="stylesheet"/> <!-- js of all the required lib (internal and external) --> - <script t-att-src="'%s/web/js/im_livechat.external_lib' % (url)" type="text/javascript"/> + <script t-att-src="'%s/im_livechat/external_lib.js' % (url)" type="text/javascript" /> <!-- the loader --> <script t-att-src="'%s/im_livechat/loader/%i' % (url, channel_id)" type="text/javascript"/> </template> diff --git a/addons/mail/views/mail_message_views.xml b/addons/mail/views/mail_message_views.xml index 3103ab7faf1..621b43e3382 100644 --- a/addons/mail/views/mail_message_views.xml +++ b/addons/mail/views/mail_message_views.xml @@ -121,11 +121,10 @@ <div class="oe_kanban_global_click"> <div class="oe_kanban_vignette"> <div class="oe_attachment"> - <div t-if="!record.url.value"> - <div class="o_image" t-att-data-mimetype="record.mimetype.value" t-attf-data-src="/web/image/#{record.id}/100x80"/> - </div> - <div t-if="record.url.value"> - <img t-att-src="record.url.value"/> + <div> + <t t-set="webimage" t-value="new RegExp('image.*(gif|jpe|jpg|png)').test(record.mimetype.value)"/> + <div t-if="!webimage" class="o_image" t-att-data-mimetype="record.mimetype.value"/> + <img t-if="webimage" t-att-src="record.url.value"/> </div> <div class="oe_name"> <field name="name"/> diff --git a/addons/web/controllers/main.py b/addons/web/controllers/main.py index e956b0dc3c4..7d5d68f9788 100644 --- a/addons/web/controllers/main.py +++ b/addons/web/controllers/main.py @@ -480,7 +480,7 @@ def binary_content(xmlid=None, model='ir.attachment', id=None, field='datas', un # mimetype if not mimetype: - if 'mimetype' in obj and obj.mimetype: + if 'mimetype' in obj and obj.mimetype and obj.mimetype != 'application/octet-stream': mimetype = obj.mimetype elif filename: mimetype = mimetypes.guess_type(filename)[0] @@ -570,33 +570,6 @@ class Home(http.Controller): return werkzeug.utils.redirect('/', 303) return login_and_redirect(db, login, key, redirect_url=redirect) - @http.route([ - '/web/js/<xmlid>', - '/web/js/<xmlid>/<version>', - ], type='http', auth='public') - def js_bundle(self, xmlid, version=None, **kw): - try: - bundle = AssetsBundle(xmlid) - except QWebTemplateNotFound: - return request.not_found() - - response = request.make_response(bundle.js(), [('Content-Type', 'application/javascript')]) - return make_conditional(response, bundle.last_modified, max_age=BUNDLE_MAXAGE) - - @http.route([ - '/web/css/<xmlid>', - '/web/css/<xmlid>/<version>', - '/web/css.<int:page>/<xmlid>/<version>', - ], type='http', auth='public') - def css_bundle(self, xmlid, version=None, page=None, **kw): - try: - bundle = AssetsBundle(xmlid) - except QWebTemplateNotFound: - return request.not_found() - - response = request.make_response(bundle.css(page), [('Content-Type', 'text/css')]) - return make_conditional(response, bundle.last_modified, max_age=BUNDLE_MAXAGE) - class WebClient(http.Controller): @http.route('/web/webclient/csslist', type='json', auth="none") @@ -1064,6 +1037,8 @@ class Binary(http.Controller): '/web/content/<string:xmlid>/<string:filename>', '/web/content/<int:id>', '/web/content/<int:id>/<string:filename>', + '/web/content/<int:id>-<string:unique>', + '/web/content/<int:id>-<string:unique>/<string:filename>', '/web/content/<string:model>/<int:id>/<string:field>', '/web/content/<string:model>/<int:id>/<string:field>/<string:filename>'], type='http', auth="public") def content_common(self, xmlid=None, model='ir.attachment', id=None, field='datas', filename=None, filename_field='datas_fname', unique=None, mimetype=None, download=None, data=None, token=None): @@ -1085,14 +1060,18 @@ class Binary(http.Controller): '/web/image/<string:xmlid>/<string:filename>', '/web/image/<string:xmlid>/<int:width>x<int:height>', '/web/image/<string:xmlid>/<int:width>x<int:height>/<string:filename>', - '/web/image/<int:id>', - '/web/image/<int:id>/<string:filename>', '/web/image/<string:model>/<int:id>/<string:field>', '/web/image/<string:model>/<int:id>/<string:field>/<string:filename>', + '/web/image/<string:model>/<int:id>/<string:field>/<int:width>x<int:height>', + '/web/image/<string:model>/<int:id>/<string:field>/<int:width>x<int:height>/<string:filename>', + '/web/image/<int:id>', + '/web/image/<int:id>/<string:filename>', '/web/image/<int:id>/<int:width>x<int:height>', '/web/image/<int:id>/<int:width>x<int:height>/<string:filename>', - '/web/image/<string:model>/<int:id>/<string:field>/<int:width>x<int:height>', - '/web/image/<string:model>/<int:id>/<string:field>/<int:width>x<int:height>/<string:filename>'], type='http', auth="public") + '/web/image/<int:id>-<string:unique>', + '/web/image/<int:id>-<string:unique>/<string:filename>', + '/web/image/<int:id>-<string:unique>/<int:width>x<int:height>', + '/web/image/<int:id>-<string:unique>/<int:width>x<int:height>/<string:filename>'], type='http', auth="public") def content_image(self, xmlid=None, model='ir.attachment', id=None, field='datas', filename_field='datas_fname', unique=None, filename=None, mimetype=None, download=None, width=0, height=0): status, headers, content = binary_content(xmlid=xmlid, model=model, id=id, field=field, unique=unique, filename=filename, filename_field=filename_field, download=download, mimetype=mimetype, default_mimetype='image/png') if status == 304: diff --git a/addons/website/views/website_templates.xml b/addons/website/views/website_templates.xml index 8d102c592a1..2ebc132a395 100644 --- a/addons/website/views/website_templates.xml +++ b/addons/website/views/website_templates.xml @@ -476,7 +476,7 @@ 'data-disable' (optional) to unchecked one or more HTML ids, or list separate by comma 'data-reload="/"' (optional) force the reloading of the page if the url match with the string ( = regexp). - Otherwise, only the '/web/css/website.assets_frontend' is reloaded + Otherwise, only the '/web/content/website.assets_frontend' is reloaded For the sets (data-enable and/or data-disable without data-xmlid), the set is automatically checked if: diff --git a/openerp/addons/base/ir/ir_attachment.py b/openerp/addons/base/ir/ir_attachment.py index e21efbbc354..c3922392899 100644 --- a/openerp/addons/base/ir/ir_attachment.py +++ b/openerp/addons/base/ir/ir_attachment.py @@ -451,11 +451,3 @@ class ir_attachment(osv.osv): def action_get(self, cr, uid, context=None): return self.pool.get('ir.actions.act_window').for_xml_id( cr, uid, 'base', 'action_attachment', context=context) - - def invalidate_bundle(self, cr, uid, type='%', xmlid=None, context=None): - assert type in ('%', 'css', 'js'), "Unhandled bundle type" - xmlid = '%' if xmlid is None else xmlid + '%' - domain = [('url', '=like', '/web/%s/%s/%%' % (type, xmlid))] - ids = self.search(cr, uid, domain, context=context) - if ids: - self.unlink(cr, uid, ids, context=context) diff --git a/openerp/addons/base/ir/ir_qweb.py b/openerp/addons/base/ir/ir_qweb.py index 4d73eab6898..dd825aea032 100644 --- a/openerp/addons/base/ir/ir_qweb.py +++ b/openerp/addons/base/ir/ir_qweb.py @@ -1166,7 +1166,7 @@ class AssetsBundle(object): raise NotImplementedError def can_aggregate(self, url): - return not urlparse(url).netloc and not url.startswith(('/web/css', '/web/js')) + return not urlparse(url).netloc and not url.startswith('/web/content') def to_html(self, sep=None, css=True, js=True, debug=False, async=False): if sep is None: @@ -1186,16 +1186,10 @@ class AssetsBundle(object): else: url_for = self.context.get('url_for', lambda url: url) if css and self.stylesheets: - suffix = '' - if request: - ua = request.httprequest.user_agent - if ua.browser == "msie" and int((ua.version or '0').split('.')[0]) < 10: - suffix = '.0' - href = '/web/css%s/%s/%s' % (suffix, self.xmlid, self.version) - response.append('<link href="%s" rel="stylesheet"/>' % url_for(href)) - if js: - src = '/web/js/%s/%s' % (self.xmlid, self.version) - response.append('<script %s type="text/javascript" src="%s"></script>' % (async and 'async="async"' or '', url_for(src))) + for attachment in self.css(): + response.append('<link href="%s" rel="stylesheet"/>' % url_for(attachment.url)) + if js and self.javascripts: + response.append('<script %s type="text/javascript" src="%s"></script>' % (async and 'async="async"' or '', url_for(self.js().url))) response.extend(self.remains) return sep + sep.join(response) @@ -1220,53 +1214,69 @@ class AssetsBundle(object): check = self.html + str(self.last_modified) return hashlib.sha1(check).hexdigest() - def js(self): - content = self.get_cache('js') - if content is None: - content = ';\n'.join(asset.minify() for asset in self.javascripts) - self.set_cache('js', content) - return content + def clean_attachments(self, type): + ira = self.registry['ir.attachment'] + domain = ['&', '!', ('url', '=like', '/web/content/%%-%s/%%' % self.version), ('url', '=like', '/web/content/%%-%%/%s%%.%s' % (self.xmlid, type))] + attachment_ids = ira.search(self.cr, openerp.SUPERUSER_ID, domain, context=self.context) + return ira.unlink(self.cr, openerp.SUPERUSER_ID, attachment_ids, context=self.context) - def css(self, page_number=None): - """Generate css content from given bundle""" - if page_number is not None: - return self.css_page(page_number) + def get_attachments(self, type, inc=None): + ira = self.registry['ir.attachment'] + domain = [('url', '=like', '/web/content/%%-%s/%s%s.%s' % (self.version, self.xmlid, ('%%' if inc is None else '.%s' % inc), type))] + attachment_ids = ira.search(self.cr, openerp.SUPERUSER_ID, domain, context=self.context) + return ira.browse(self.cr, openerp.SUPERUSER_ID, attachment_ids, context=self.context) - content = self.get_cache('css') - if content is None: - content = self.preprocess_css() + def save_attachment(self, type, content, inc=None): + ira = self.registry['ir.attachment'] + self.clean_attachments(type) + attachments = self.get_attachments(type, inc) + values = {} + + if not attachments: + values["name"] = "/web/content/%s" % type + values["datas_fname"] = '%s%s.%s' % (self.xmlid, ('' if inc is None else '.%s' % inc), type) + values["res_model"] = 'ir.ui.view' + values["type"] = 'binary' + attachment_id = ira.create(self.cr, openerp.SUPERUSER_ID, values, context=self.context) + url = '/web/content/%s-%s/%s' % (attachment_id, self.version, values["datas_fname"]) + values["name"] = url + values["url"] = url + else: + attachment_id = attachments[0].id + + values["datas"] = content.encode('utf8').encode('base64') + ira.write(self.cr, openerp.SUPERUSER_ID, attachment_id, values, context=self.context) + + return ira.browse(self.cr, openerp.SUPERUSER_ID, attachment_id, context=self.context) + + def js(self): + attachments = self.get_attachments(type) + if not attachments or attachments[0].__last_update < max([asset.last_modified for asset in self.javascripts]): + content = ';\n'.join(asset.minify() for asset in self.javascripts) + return self.save_attachment('js', content) + return attachments[0] + def css(self): + ira = self.registry['ir.attachment'] + attachments = self.get_attachments('css') + if not attachments: + # get css content + css = self.preprocess_css() if self.css_errors: msg = '\n'.join(self.css_errors) - content += self.css_message(msg) + css += self.css_message(msg) # move up all @import rules to the top matches = [] - def push(matchobj): - matches.append(matchobj.group(0)) - return '' - - content = re.sub(self.rx_css_import, push, content) + css = re.sub(self.rx_css_import, lambda matchobj: matches.append(matchobj.group(0)) and '', css) + matches.append(css) + css = u'\n'.join(matches) - matches.append(content) - content = u'\n'.join(matches) - if not self.css_errors: - self.set_cache('css', content) - content = content.encode('utf-8') - - return content - - def css_page(self, page_number): - content = self.get_cache('css.%d' % (page_number,)) - if page_number: - return content - if content is None: - css = self.css().decode('utf-8') + # split for browser max file size and browser max expression re_rules = '([^{]+\{(?:[^{}]|\{[^{}]*\})*\})' re_selectors = '()(?:\s*@media\s*[^{]*\{)?(?:\s*(?:[^,{]*(?:,|\{(?:[^}]*\}))))' - css_url = '@import url(\'/web/css.%%d/%s/%s\');' % (self.xmlid, self.version) - pages = [[]] - page = pages[0] + page = [] + pages = [page] page_selectors = 0 for rule in re.findall(re_rules, css): selectors = len(re.findall(re_selectors, rule)) @@ -1277,38 +1287,11 @@ class AssetsBundle(object): pages.append([rule]) page = pages[-1] page_selectors = selectors - if len(pages) == 1: - pages = [] for idx, page in enumerate(pages): - self.set_cache("css.%d" % (idx+1), ''.join(page)) - content = '\n'.join(css_url % i for i in range(1,len(pages)+1)) - self.set_cache("css.0", content) - if not content: - return self.css() - return content - - def get_cache(self, type): - content = None - domain = [('url', '=', '/web/%s/%s/%s' % (type, self.xmlid, self.version))] - bundle = self.registry['ir.attachment'].search_read(self.cr, openerp.SUPERUSER_ID, domain, ['datas'], context=self.context) - if bundle and bundle[0]['datas']: - content = bundle[0]['datas'].decode('base64') - return content - - def set_cache(self, type, content): - ira = self.registry['ir.attachment'] - url = '/web/%s/%s/%s' % (type, self.xmlid, self.version) - try: - with self.cr.savepoint(): - ira.invalidate_bundle(self.cr, openerp.SUPERUSER_ID, type=type, xmlid=self.xmlid) - ira.create(self.cr, openerp.SUPERUSER_ID, dict( - datas=content.encode('utf8').encode('base64'), - type='binary', - name=url, - url=url, - ), context=self.context) - except psycopg2.Error: - pass + attachments |= self.save_attachment("css", ' '.join(page), inc=idx) + elif len(attachments) > 1: + attachments = attachments[1:] + return attachments def css_message(self, message): # '\A' == css content carriage return |
