[IMP] base: assets now directly use /web/content url

This commit is contained in:
Christophe Matthieu
2015-09-03 19:31:00 +02:00
committed by Christophe Simonis
parent 952b03e32d
commit 522fcacb21
7 changed files with 91 additions and 126 deletions
+12
View File
@@ -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)
@@ -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>
+4 -5
View File
@@ -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"/>
+11 -32
View File
@@ -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:
+1 -1
View File
@@ -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:
-8
View File
@@ -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)
+61 -78
View File
@@ -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 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 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)
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):
content = self.get_cache('js')
if content is None:
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)
self.set_cache('js', content)
return content
def css(self, page_number=None):
"""Generate css content from given bundle"""
if page_number is not None:
return self.css_page(page_number)
content = self.get_cache('css')
if content is None:
content = self.preprocess_css()
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 ''
css = re.sub(self.rx_css_import, lambda matchobj: matches.append(matchobj.group(0)) and '', css)
matches.append(css)
css = u'\n'.join(matches)
content = re.sub(self.rx_css_import, push, content)
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