[MERGE] Merged trunk-website-al

bzr revid: psa@tinyerp.com-20130816054140-g1m26dkuk1t9n6oz
This commit is contained in:
Paramjit Singh Sahota
2013-08-16 11:11:40 +05:30
13 changed files with 211 additions and 95 deletions
-8
View File
@@ -15,13 +15,5 @@ OpenERP Website CMS
'views/views.xml',
'views/res_config.xml',
'website_data.xml',
],
'js': [
'static/lib/bootstrap/js/bootstrap.js',
'static/src/js/website.js',
],
'css': [
'static/src/css/editor.css',
],
'qweb': ['static/src/xml/*.xml'],
}
+43
View File
@@ -12,6 +12,8 @@ from openerp.addons.web.http import request
import werkzeug
import werkzeug.exceptions
import werkzeug.wrappers
import hashlib
import os
logger = logging.getLogger(__name__)
@@ -154,6 +156,47 @@ class Website(openerp.addons.web.controllers.main.Home):
return response
@http.route('/website/image', type='http', auth="public")
def image(self, model, id, field, **kw):
last_update = '__last_update'
Model = request.registry[model]
headers = [('Content-Type', 'image/png')]
etag = request.httprequest.headers.get('If-None-Match')
hashed_session = hashlib.md5(request.session_id).hexdigest()
retag = hashed_session
try:
if etag:
date = Model.read(request.cr, request.uid, [id], [last_update], request.context)[0].get(last_update)
if hashlib.md5(date).hexdigest() == etag:
return werkzeug.wrappers.Response(status=304)
res = Model.read(request.cr, request.uid, [id], [last_update, field], request.context)[0]
retag = hashlib.md5(res.get(last_update)).hexdigest()
image_base64 = res.get(field)
if kw.get('resize'):
resize = kw.get('resize').split(',')
if len(resize) == 2 and int(resize[0]) and int(resize[1]):
width = int(resize[0])
height = int(resize[1])
# resize maximum 500*500
if width > 500: width = 500
if height > 500: height = 500
image_base64 = openerp.tools.image_resize_image(base64_source=image_base64, size=(width, height), encoding='base64', filetype='PNG')
image_data = base64.b64decode(image_base64)
except Exception:
image_data = open(os.path.join(http.addons_manifest['web']['addons_path'], 'web', 'static', 'src', 'img', 'placeholder.png'), 'rb').read()
headers.append(('ETag', retag))
headers.append(('Content-Length', len(image_data)))
try:
ncache = int(kw.get('cache'))
headers.append(('Cache-Control', 'no-cache' if ncache == 0 else 'max-age=%s' % (ncache)))
except:
pass
return request.make_response(image_data, headers)
@http.route(['/website/publish/'], type='http', auth="public")
def publish(self, **post):
_id = int(post['id'])
+52 -26
View File
@@ -1,20 +1,36 @@
openerp.website = function(instance) {
// Ugly. I'll clean this monday
$(function () { if ($('html').attr('data-editable') !== '1') return;
instance.web.ActionManager.include({
// Temporary fix until un-webclientization of the editorbar
ir_actions_client: function (action) {
if (instance.web.client_actions.get_object(action.tag)) {
return this._super.apply(this, arguments);
} else {
console.warn("Action '%s' not found in registry", action.tag);
return $.when();
}
}
});
// TODO fme: put everything in openerp.website scope and load templates on
// next tick or document ready
// Also check with xmo if jquery.keypress.js is still needed.
var _lt = instance.web._lt;
var QWeb = instance.web.qweb;
instance.website.EditorBar = instance.web.Widget.extend({
var doc_ready = $.Deferred();
$(doc_ready.resolve);
var templates = [
'/website/static/src/xml/website.xml'
];
function loadTemplates(templates) {
var def = $.Deferred();
var count = templates.length;
templates.forEach(function(t) {
openerp.qweb.add_template(t, function(err) {
if (err) {
def.reject();
} else {
count--;
if (count < 1) {
def.resolve();
}
}
});
});
return def;
}
var EditorBar = openerp.Widget.extend({
template: 'Website.EditorBar',
events: {
'click button[data-action=edit]': 'edit',
@@ -23,17 +39,13 @@ instance.website.EditorBar = instance.web.Widget.extend({
'click button[data-action=snippet]': 'snippet',
},
container: 'body',
init: function () {
this._super.apply(this, arguments);
this.saving_mutex = new $.Mutex();
},
customize_setup: function() {
var self = this;
var view_name = $('html').data('view-xmlid');
var menu = $('#customize-menu');
this.$('#customize-menu-button').click(function(event) {
menu.empty();
self.rpc('/website/customize_template_get', { 'xml_id': view_name }).then(
openerp.jsonRpc('/website/customize_template_get', 'call', { 'xml_id': view_name }).then(
function(result) {
_.each(result, function (item) {
if (item.header) {
@@ -48,7 +60,7 @@ instance.website.EditorBar = instance.web.Widget.extend({
});
menu.on('click', 'a', function (event) {
var view_id = $(event.target).data('view-id');
self.rpc('/website/customize_template_toggle', {
openerp.jsonRpc('/website/customize_template_toggle', 'call', {
'view_id': view_id
}).then( function(result) {
window.location.reload();
@@ -58,6 +70,8 @@ instance.website.EditorBar = instance.web.Widget.extend({
start: function() {
var self = this;
this.saving_mutex = new openerp.Mutex();
this.$('#website-top-edit').hide();
this.$('#website-top-view').show();
@@ -73,7 +87,7 @@ instance.website.EditorBar = instance.web.Widget.extend({
self.snippet_start();
this.rte = new instance.website.RTE(this);
this.rte = new RTE(this);
this.rte.on('change', this, this.proxy('rte_changed'));
return $.when(
@@ -156,7 +170,11 @@ instance.website.EditorBar = instance.web.Widget.extend({
.prop('contentEditable', false);
html = $w.wrap('<div>').parent().html();
}
return (new instance.web.DataSet(this, 'ir.ui.view')).call('save', [data.oeModel, data.oeId, data.oeField, html, xpath]);
return openerp.jsonRpc('/web/dataset/call', 'call', {
model: 'ir.ui.view',
method: 'save',
args: [data.oeModel, data.oeId, data.oeField, html, xpath]
});
},
cancel: function () {
window.location.reload();
@@ -194,7 +212,7 @@ instance.website.EditorBar = instance.web.Widget.extend({
},
});
instance.website.RTE = instance.web.Widget.extend({
var RTE = openerp.Widget.extend({
tagName: 'li',
id: 'oe_rte_toolbar',
className: 'oe_right oe_rte_toolbar',
@@ -297,7 +315,12 @@ instance.website.RTE = instance.web.Widget.extend({
}
});
$(function(){
$.when(doc_ready, loadTemplates(templates)).then(function() {
var editor = new EditorBar();
editor.prependTo($('body'));
$('body').css('padding-top', '50px'); // Not working properly: editor.$el.outerHeight());
// TODO: Create an openerp.Widget out of this
function make_static(){
$('.oe_snippet_demo').removeClass('oe_new');
@@ -382,6 +405,10 @@ $(function(){
}
});
});
// }()); I'll clean this monday
$(function () {
$(document).on('click', '.js_publish, .js_unpublish', function (e) {
e.preventDefault();
@@ -401,4 +428,3 @@ $(function () {
});
});
};
@@ -1,19 +0,0 @@
$(function() {
// Init headless webclient
// TODO: Webclient research : use iframe embedding mode
// Meanwhile, let's HACK !!!
var s = new openerp.init(['web', 'website']);
s.web.WebClient.bind_hashchange = s.web.WebClient.show_common = s.web.blockUI = s.web.unblockUI = function() {};
s.web.WebClient.include({ do_push_state: function() {} });
var wc = new s.web.WebClient();
wc.start();
var instance = openerp.instances[wc.session.name];
// Another hack since we have no callback when webclient has loaded modules.
instance.web.qweb.add_template('/website/static/src/xml/website.xml');
$(function() {
var editor = new instance.website.EditorBar(instance.webclient);
editor.prependTo($('body'));
$('body').css('padding-top', '50px'); // Not working properly: editor.$el.outerHeight());
});
});
+44 -5
View File
@@ -20,10 +20,13 @@
<template id="layout">
&lt;!DOCTYPE html&gt;
<html t-att-data-view-xmlid="__stack__[0]">
<html t-att-data-view-xmlid="__stack__[0]" t-att-data-editable="'1' if editable else '0'">
<head>
<title><t t-esc="title or res_company.name"/></title>
<script type="text/javascript" src="/web/static/lib/underscore/underscore.js"></script>
<script type="text/javascript" src="/web/static/lib/underscore.string/lib/underscore.string.js"></script>
<script type="text/javascript" src="/web/static/lib/jquery/jquery.js"></script>
<script type="text/javascript" src="/website/static/lib/bootstrap/js/bootstrap.js"></script>
<script type="text/javascript" src="//cdnjs.cloudflare.com/ajax/libs/ckeditor/4.2/ckeditor.js"></script>
<script type="text/javascript" src="/website/static/lib/ckeditor.sharedspace/plugin.js"></script>
<script type="text/javascript">
@@ -34,11 +37,15 @@
</script>
<t t-if="editable">
<t t-raw="css"/>
<t t-raw="script"/>
<link rel='stylesheet' href='/website/static/src/css/snippets.css'/>
<script type="text/javascript" src="/website/static/src/js/website_bootstrap.js"></script>
<link rel='stylesheet' href='/website/static/src/css/editor.css'/>
<script type="text/javascript" src="/web/static/lib/jquery.ui/js/jquery-ui-1.9.1.custom.js"></script>
<script type="text/javascript" src="/web/static/lib/qweb/qweb2.js"></script>
<script type="text/javascript" src="/web/static/src/js/openerpframework.js"></script>
</t>
<script type="text/javascript" src="/website/static/src/js/website.js"></script>
<t t-raw="head or ''"/>
<t t-call="website.theme"/>
@@ -382,6 +389,36 @@
</t>
</template>
<template id="500">
<t t-call="website.layout">
<div class="container">
<h1 class="mt32">500: Internal Server Error!</h1>
<pre t-esc="traceback"/>
</div>
</t>
</template>
<template id="401">
<t t-call="website.layout">
<div class="container">
<h1 class="mt32">401: Unauthorized Access!</h1>
<p>
The page you were looking for could not be
authorized.
</p><p>
Maybe you were looking for one of these
popular pages ?
</p>
<pre class="hidden" t-esc="error"/>
<ul>
<li><a href="/">Homepage</a></li>
<li><a href="/">Contact Us</a></li>
</ul>
</div>
</t>
</template>
<template id="contactus" name="Contact us">
<t t-call="website.layout">
<t t-set="title">Contact us - <t t-raw="res_company.name"/></t>
@@ -408,7 +445,9 @@
<span>&amp;#x2706; <span t-field="res_company.phone"></span></span><br/>
<i class="icon-envelope"></i> <span t-field="res_company.email"></span>
</address>
<img class="thumbnail" t-att-src="google_map_url"/>
<a t-att-href="res_company.partner_id.google_map_link()" target="_BLANK">
<img class="thumbnail" t-att-src="res_company.partner_id.google_map_img()"/>
</a>
</div>
</div>
</div>
+28 -9
View File
@@ -2,12 +2,16 @@
import simplejson
import openerp
from openerp.osv import osv
from openerp.osv import osv, orm
from openerp.addons.web import http
from openerp.addons.web.controllers import main
from openerp.addons.web.http import request
import urllib
import math
import traceback
import logging
logger = logging.getLogger(__name__)
def auth_method_public():
@@ -24,7 +28,7 @@ def urlplus(url, params):
return url
url += "?"
for k,v in params.items():
url += "%s=%s&" % (k, urllib.quote_plus(v))
url += "%s=%s&" % (k, urllib.quote_plus(str(v)))
return url
@@ -42,11 +46,16 @@ class website(osv.osv):
def get_rendering_context(self, additional_values=None):
debug = 'debug' in request.params
is_logged = True
try:
request.session.check_security()
except: # TODO fme: check correct exception
is_logged = False
is_public_user = request.uid == self.get_public_user().id
values = {
'debug': debug,
'is_public_user': is_public_user,
'editable': not is_public_user,
'editable': is_logged and not is_public_user,
'request': request,
'registry': request.registry,
'cr': request.cr,
@@ -55,11 +64,6 @@ class website(osv.osv):
'res_company': request.registry['res.company'].browse(request.cr, openerp.SUPERUSER_ID, 1),
'json': simplejson,
}
if values['editable']:
values.update({
'script': "\n".join(['<script type="text/javascript" src="%s"></script>' % i for i in main.manifest_list('js', db=request.db, debug=debug)]),
'css': "\n".join('<link rel="stylesheet" href="%s">' % i for i in main.manifest_list('css', db=request.db, debug=debug))
})
if additional_values:
values.update(additional_values)
return values
@@ -68,7 +72,22 @@ class website(osv.osv):
context = {
'inherit_branding': values.get('editable', False),
}
return request.registry.get("ir.ui.view").render(request.cr, request.uid, template, values, context=context)
try:
return request.registry.get("ir.ui.view").render(request.cr, request.uid, template, values, context=context)
except (osv.except_osv, orm.except_orm), err:
logger.error(err)
values['error'] = err[1]
return self.render('website.401', values)
except ValueError:
logger.error("Website Rendering Error.\n\n%s" % (traceback.format_exc()))
return self.render('website.404', values)
except Exception:
logger.error("Website Rendering Error.\n\n%s" % (traceback.format_exc()))
if values['editable']:
values['traceback'] = traceback.format_exc()
return self.render('website.500', values)
else:
return self.render('website.404', values)
def pager(self, url, total, page=1, step=30, scope=5, url_args=None):
# Compute Pager
-1
View File
@@ -103,7 +103,6 @@ class website_event(http.Controller):
event = request.registry['event.event'].browse(request.cr, request.uid, event_id, {'show_address': 1})
values = website.get_rendering_context({
'event_id': event,
'google_map_url': "http://maps.googleapis.com/maps/api/staticmap?center=%s&sensor=false&zoom=12&size=298x298" % urllib.quote_plus('%s, %s %s, %s' % (event.street, event.city, event.zip, event.country_id and event.country_id.name_get()[0][1] or ''))
})
return website.render("website_event.detail", values)
+14
View File
@@ -1,6 +1,7 @@
# -*- coding: utf-8 -*-
from openerp.osv import osv, fields
from openerp import SUPERUSER_ID
# defined for access rules
class product(osv.osv):
@@ -9,3 +10,16 @@ class product(osv.osv):
'event_ticket_ids': fields.one2many('event.event.ticket', 'product_id', 'Event Tickets'),
}
class event_event(osv.osv):
_inherit = "event.event"
def google_map_img(self, cr, uid, ids, zoom=8, width=298, height=298, context=None):
partner = self.browse(cr, uid, ids[0], context=context)
if partner.address_id:
return self.browse(cr, SUPERUSER_ID, ids[0], context=context).address_id.google_map_img()
def google_map_link(self, cr, uid, ids, zoom=8, context=None):
partner = self.browse(cr, uid, ids[0], context=context)
if partner.address_id:
return self.browse(cr, SUPERUSER_ID, ids[0], context=context).address_id.google_map_link()
+5 -2
View File
@@ -44,6 +44,7 @@
<div class="span8">
<ul class="media-list">
<li t-foreach="event_ids" t-as="event_id" class="media thumbnail">
<t t-esc="event_id"/>
<div class="media-body">
<span t-if="not event_id.event_ticket_ids" class="label pull-right">No tickets needed.</span>
<t t-if="event_id.event_ticket_ids">
@@ -112,14 +113,16 @@
<t t-call="website.layout">
<t t-set="head">
<script type="text/javascript" src="/website_event/static/src/js/website_event.js"></script>
<t t-raw="head"/>
<t t-raw="head or ''"/>
</t>
<t t-set="title">Events</t>
<div class="container mt48">
<div class="row">
<div class="span4 css_noprint">
<h4>When &amp; Where</h4>
<img t-att-src="google_map_url"/>
<a t-att-href="event_id.google_map_link()" target="_BLANK">
<img class="thumbnail" t-att-src="event_id.google_map_img()"/>
</a>
<address>
<pre t-field="event_id.address_id"/>
<i class="icon-time"></i> <span t-field="event_id.date_begin"> </span><br/>
+2
View File
@@ -9,3 +9,5 @@ class hr(osv.osv):
'website_published': fields.boolean('Available in the website'),
}
def img(self, cr, uid, ids, field='image_small', context=None):
return "/website/image?model=%s&field=%s&id=%s" % (self._name, field, ids[0])
+1 -1
View File
@@ -32,7 +32,7 @@
<div t-foreach="employee_ids" t-as="employee_id" class="span4 mt16">
<div class="media thumbnail">
<a class="pull-left" href="#">
<img class="media-object" t-att-src="'data:image/png;base64,%%s' %% employee_id.image_small"/>
<img class="media-object" t-att-src="employee_id.img('image_small')"/>
</a>
<div class="media-body">
<t t-call="website.publish"><t t-set="object" t-value="employee_id"/></t>
+20 -24
View File
@@ -49,7 +49,6 @@
<t t-call="website.layout">
<t t-set="head">
<script type="text/javascript" src="/website_sale/static/src/js/website_sale.js"></script>
<link rel='stylesheet' href='/website_sale/static/src/css/website_sale.css'/>
<t t-raw="head or ''"/>
</t>
<t t-set="title">Shop - <t t-raw="title">Categories</t></t>
@@ -66,7 +65,7 @@
<xpath expr="//div[@id='shop_content']" position="before">
<div class="span4">
<ul class="nav nav-list">
<li t-att-class=" '' if current_category else 'active' " class='active'><a href='/shop/'>All Products</a></li>
<li t-att-class=" '' if current_category else 'active' " class='active'><a href="/shop/">All Products</a></li>
<t t-foreach="categories" t-as="category">
<t t-call="website_sale.categories_recursive"/>
</t>
@@ -82,7 +81,7 @@
<template id="categories_recursive">
<li t-att-class="category.id == current_category and 'active' or ''">
<a t-att-href="'/shop/category/%%s/' %% category.id" t-field="category.name"></a>
<a t-attf-href="/shop/category/#{ category.id }/" t-field="category.name"></a>
<ul t-if="category.child_id" class="nav nav-list">
<t t-foreach="category.child_id" t-as="category">
<t t-call="website_sale.categories_recursive"/>
@@ -108,18 +107,18 @@
</div>
</div>
<div class='row grid grid-align-top'>
<div t-foreach="products" t-as="product" class="oe_product span2 mb16 thumbnail text-center">
<a t-att-href="'/shop/product/%%s/' %% product.id">
<div t-foreach="products" t-as="product" class="span2 mb16 thumbnail text-center">
<a t-attf-href="/shop/product/#{ product.id }/ ">
<h5 t-field="product.name"> </h5>
</a>
<a t-att-href="'/shop/product/%%s/' %% product.id">
<img class="img-rounded" t-att-src="'data:image/png;base64,' + product.image"/>
<a t-attf-href="/shop/product/#{ product.id }/">
<img class="img-rounded" t-att-src="product.img('image_small')"/>
</a>
<div>
<div t-field="product.description_sale"></div>
<div><span t-field="product.list_price"></span>€</div>
<div class="mb8 mt8">
<a t-att-href="'./add_cart/%s/' % product.id" class="btn btn-small btn-success">Add to cart</a>
<a t-attf-href="./add_cart/#{ product.id }/" class="btn btn-small btn-success">Add to cart</a>
</div>
</div>
</div>
@@ -137,16 +136,13 @@
<t t-call="website_sale.layout">
<t t-set="title">Product</t>
<t t-set="shop_content">
<div class="oe_product_detail" id="product_detail">
<div id="product_detail">
<t t-call="website.publish"><t t-set="object" t-value="product"/></t>
<h2 t-field="product.name"></h2>
<div class="oe_button_cart">
<a t-att-href="'./add_cart/%s/' % product.id" class="btn btn-small btn-success">Add to cart</a>
</div>
<img class="media-object" t-att-src="'data:image/png;base64,' + product.image"/>
<a t-attf-href="./add_cart/#{ product.id }/" class="btn btn-small btn-success pull-right">Add to cart</a>
<img class="media-object" t-att-src="product.img('image')"/>
<div t-field="product.description_website"></div>
<div class="oe_website_sale_price"><t t-field="product.list_price" />€</div>
<div><t t-field="product.list_price" />€</div>
</div>
</t>
</t>
@@ -158,9 +154,9 @@
<div class='row mt16'>
<t t-foreach="product.recommended_products()" t-as="product">
<div class='span2 thumbnail'>
<a t-att-href="'/shop/product/%%s/' %% product.id">
<a t-attf-href="/shop/product/#{ product.id }/">
<div class='mt16 text-center'>
<img t-att-src="'data:image/png;base64,' + product.image"/>
<img t-att-src="product.img('image_small')"/>
<h5 t-field='product.name'></h5>
</div>
</a>
@@ -195,10 +191,10 @@
<t t-foreach="order.order_line" t-as="line">
<tr>
<td>
<a t-att-href="'/shop/product/%%s/' %% line.product_id"><img class="img-rounded" t-att-src="'data:image/png;base64,' + line.product_id.image"/></a>
<a t-attf-href="/shop/product/#{ line.product_id.id }/"><img class="img-rounded" t-att-src="line.product_id.img('image_small')"/></a>
</td>
<td>
<a t-att-href="'/shop/product/%%s/' %% line.product_id"><span t-field="line.product_id.name"/></a><br/>
<a t-attf-href="/shop/product/#{ line.product_id.id }/"><span t-field="line.product_id.name"/></a><br/>
<small t-field="line.product_id.description_sale"/>
</td>
<td>
@@ -241,7 +237,7 @@
<t t-set="title">Shop - Checkout</t>
<div class="container mt48 oe_website_sale">
<div class="row">
<div class="span4 oe_total">
<div class="span4">
<table class="table table-condensed">
<thead>
<tr>
@@ -255,7 +251,7 @@
<tr>
<td><t t-esc="line.name"/></td>
<td><t t-esc="line.product_uom_qty"/></td>
<td class="css_alignright"><t t-esc="line.product_id.list_price"/>€</td>
<td><t t-esc="line.product_id.list_price"/>€</td>
</tr>
</t>
</tbody>
@@ -423,7 +419,7 @@
<t t-set="title">Shop - Payment</t>
<div class="container mt48 oe_website_sale">
<div class="row">
<div class="span4 oe_total">
<div class="span4">
<table class="table table-condensed">
<thead>
<tr>
@@ -437,7 +433,7 @@
<tr>
<td><t t-esc="line.name"/></td>
<td><t t-esc="line.product_uom_qty"/></td>
<td class="css_alignright"><t t-esc="line.product_id.list_price"/>€</td>
<td><t t-esc="line.product_id.list_price"/>€</td>
</tr>
</t>
</tbody>
@@ -449,7 +445,7 @@
</table>
</div>
<div class="span8">
<div class="js_payments row">
<div class="row">
<h3 class="span8">Click on your payment method</h3>
<t t-foreach="payments or []" t-as="payment">
<div t-att-title="payment.name">
+2
View File
@@ -57,6 +57,8 @@ class product_product(osv.osv):
product_ids = self.search(cr, uid, [("id", "in", product_ids)])
return self.browse(cr, uid, product_ids)
def img(self, cr, uid, ids, field='image_small', context=None):
return "/website/image?model=%s&field=%s&id=%s" % (self._name, field, ids[0])
class sale_order(osv.osv):
_inherit = "sale.order"