summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChristophe Matthieu <chm@odoo.com>2015-08-10 16:39:09 +0200
committerChristophe Simonis <chs@odoo.com>2015-09-03 19:31:00 +0200
commit522fcacb21febf96393d3132b5c3f32c69b9a82a (patch)
treef1f5b35dce7eeb611180bfa480c0efb3ea0c8725
parent952b03e32dc8ef6bae383debec8d78e40e22599f (diff)
[IMP] base: assets now directly use /web/content url
-rw-r--r--addons/im_livechat/controllers/main.py12
-rw-r--r--addons/im_livechat/views/im_livechat_channel_templates.xml4
-rw-r--r--addons/mail/views/mail_message_views.xml9
-rw-r--r--addons/web/controllers/main.py43
-rw-r--r--addons/website/views/website_templates.xml2
-rw-r--r--openerp/addons/base/ir/ir_attachment.py8
-rw-r--r--openerp/addons/base/ir/ir_qweb.py139
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