[MERGE] Forward-port of 8.0 up to d32d120

This commit is contained in:
Olivier Dony
2014-09-08 17:01:35 +02:00
16 changed files with 256 additions and 120 deletions
@@ -223,7 +223,7 @@ function reload_favorite_list(result) {
}
},
open_invitation_form : function(invitation){
this.$el.html(QWeb.render('invitation_view', {'invitation': JSON.parse(invitation)}));
$('.oe_application').html(QWeb.render('invitation_view', {'invitation': JSON.parse(invitation)}));
},
redirect_meeting_view : function(db, action, meeting_id, view){
var self = this;
@@ -33,7 +33,7 @@
<t t-name="invitation_view">
<div class='invitation_block well' style='width:50%; margin:auto; margin-top : 30px;'>
<div class="oe_right"><b><t t-esc="invitation['current_attendee'].cn"/> (<t t-esc="invitation['current_attendee'].email"/>)</b></div>
<div class="oe_right" style="margin-left:0px"><b><t t-esc="invitation['current_attendee'].cn"/> (<t t-esc="invitation['current_attendee'].email"/>)</b></div>
<div class="oe_left">
<img class="cal_inline cal_image" src='/web/binary/company_logo' />
</div>
@@ -97,7 +97,6 @@
<th>Description</th>
<th>Reference</th>
<th>Partner</th>
<th>Type</th>
<th>Account</th>
<th class="text-right">Amount</th>
</tr>
@@ -108,7 +107,6 @@
<td><span t-field="line.name"/></td>
<td><span t-field="line.ref"/></td>
<td><span t-field="line.partner_id"/></td>
<td><span t-field="line.type"/></td>
<td><span t-field="line.account_id"/></td>
<td class="text-right">
<span t-field="line.amount"
-1
View File
@@ -125,7 +125,6 @@ class Report(osv.Model):
user=user,
res_company=user.company_id,
website=website,
editable_no_editor=_("The preferred way to edit a report is to use the HTML Editor"),
)
return view_obj.render(cr, uid, template, values, context=context)
+2 -1
View File
@@ -260,8 +260,9 @@ class stock_move(osv.osv):
def action_done(self, cr, uid, ids, context=None):
self.product_price_update_before_done(cr, uid, ids, context=context)
super(stock_move, self).action_done(cr, uid, ids, context=context)
res = super(stock_move, self).action_done(cr, uid, ids, context=context)
self.product_price_update_after_done(cr, uid, ids, context=context)
return res
def _store_average_cost_price(self, cr, uid, move, context=None):
''' move is a browe record '''
+70 -30
View File
@@ -1,4 +1,4 @@
@charset "UTF-8";
@charset "utf-8";
@font-face {
font-family: "mnmliconsRegular";
src: url("/web/static/src/font/mnmliconsv21-webfont.eot") format("eot");
@@ -977,42 +977,82 @@
.openerp .oe_secondary_submenu .oe_secondary_submenu li {
margin-left: 20px;
}
.openerp .oe_about {
background-color: white;
background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAYAAAAGCAYAAADgzO9IAAAAKUlEQVQIHWO8e/fufwYsgAUkJigoiCIF5DMyoYggcUiXgNnBiGQKmAkARpcEQeriln4AAAAASUVORK5CYII=);
-moz-border-radius: 0 0 2px 2px;
-webkit-border-radius: 0 0 2px 2px;
border-radius: 0 0 2px 2px;
.openerp .oe_about .label {
background-color: #a24689;
}
.openerp .oe_about a {
color: #7c7bad;
color: #a24689;
}
.openerp .oe_about a:hover {
text-decoration: underline;
.openerp .oe_about .user-details {
position: relative;
padding: 0;
margin-bottom: 275px;
}
.openerp .oe_about a:focus {
outline: none;
.openerp .oe_about .user-details .user-image {
width: 100%;
text-align: center;
}
.openerp .oe_about .oe_logo {
margin-left: -6px;
.openerp .oe_about .user-details .user-info-block {
width: 100%;
position: absolute;
top: 55px;
padding-top: 35px;
}
.openerp .oe_about .oe_bottom {
text-shadow: 0 1px 1px #999999;
background-color: #8a0e0e;
background-image: -webkit-gradient(linear, left top, left bottom, from(#b41616), to(#600606));
background-image: -webkit-linear-gradient(top, #b41616, #600606);
background-image: -moz-linear-gradient(top, #b41616, #600606);
background-image: -ms-linear-gradient(top, #b41616, #600606);
background-image: -o-linear-gradient(top, #b41616, #600606);
background-image: linear-gradient(to bottom, #b41616, #600606);
color: #eeeeee;
padding: 0 16px;
-moz-border-radius: 0 0 2px 2px;
-webkit-border-radius: 0 0 2px 2px;
border-radius: 0 0 2px 2px;
.openerp .oe_about .user-details .user-info-block .user-heading {
text-align: center;
margin: 10px 0 0;
}
.openerp .oe_about .oe_bottom a {
color: #eeeeee;
.openerp .oe_about .user-details .user-info-block .navigation {
float: left;
width: auto;
padding: 0;
margin-left: 25%;
list-style: none;
border: 1px solid #a24689;
}
.openerp .oe_about .user-details .user-info-block .navigation li {
float: left;
}
.openerp .oe_about .user-details .user-info-block .navigation li a {
padding: 20px 30px;
float: left;
}
.openerp .oe_about .user-details .user-info-block .navigation li.active a {
background: #a24689;
color: white;
}
.openerp .oe_about .user-details .user-info-block .user-body {
text-align: center;
}
.openerp .oe_about .user-details .user-info-block .user-body .tab-content > div {
float: left;
width: 100%;
}
.openerp .oe_about a.oe_activate_debug_mode {
color: white !important;
font-size: 100%;
}
.openerp .oe_about #social i {
margin: 10px;
}
.openerp .oe_about #social i:hover {
-webkit-transform: scale(1.3);
-moz-transform: scale(1.3);
-ms-transform: scale(1.3);
-o-transform: scale(1.3);
transform: scale(1.3);
}
.openerp .oe_about #social .social-fb:hover {
color: #3b5998;
}
.openerp .oe_about #social .social-tw:hover {
color: #4099ff;
}
.openerp .oe_about #social .social-gp:hover {
color: #d34836;
}
.openerp .oe_about #social .social-lk:hover {
color: #007bb6;
}
.openerp a.oe_form_uri:hover {
text-decoration: underline;
+56 -18
View File
@@ -846,26 +846,64 @@ $sheet-padding: 16px
margin-left: 20px
// }}}
// About openerp {{{
$link-color-odoo: #a24689
.oe_about
background-color: white
background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAYAAAAGCAYAAADgzO9IAAAAKUlEQVQIHWO8e/fufwYsgAUkJigoiCIF5DMyoYggcUiXgNnBiGQKmAkARpcEQeriln4AAAAASUVORK5CYII=)
@include radius(0 0 2px 2px)
.label
background-color: $link-color-odoo
a
color: $link-color
&:hover
text-decoration: underline
&:focus
outline: none
.oe_logo
margin-left: -6px
.oe_bottom
text-shadow: 0 1px 1px #999999
@include vertical-gradient(#b41616, #600606)
color: #eee
padding: 0 16px
@include radius(0 0 2px 2px)
a
color: #eee
color: $link-color-odoo
.user-details
position: relative
padding: 0
margin-bottom: 275px
.user-image
width: 100%
text-align: center
.user-info-block
width: 100%
position: absolute
top: 55px
padding-top: 35px
.user-heading
text-align: center
margin: 10px 0 0
.navigation
float: left
width: auto
padding: 0
margin-left: 25%
list-style: none
border: 1px solid $link-color-odoo
li
float: left
a
padding: 20px 30px
float: left
&.active a
background: $link-color-odoo
color: #fff
.user-body
text-align: center
.tab-content > div
float: left
width: 100%
a.oe_activate_debug_mode
color: white !important
font-size: 100%
#social
i
margin: 10px
&:hover
@include transform(scale(1.3))
.social-fb:hover
color: #3B5998
.social-tw:hover
color: #4099FF
.social-gp:hover
color: #d34836
.social-lk:hover
color: #007bb6
// }}}
// ActionManager {{{
a.oe_form_uri:hover
+72 -9
View File
@@ -365,16 +365,79 @@
<t t-name="UserMenu.about">
<div class="oe_about">
<a class="oe_activate_debug_mode oe_right" href="?debug" style="background-color: white; padding:2px 6px; border-radius: 10px;">Activate the developer mode</a>
<img class="oe_logo" src="/web/static/src/img/logo2.png"/>
<h3>Version <t t-esc="version_info.server_version"/></h3>
<a class="oe_activate_debug_mode oe_right label label-primary" href="?debug" >Activate the developer mode</a>
<div class="oe_bottom">
<p>Copyright © 2004-TODAY OpenERP SA. All Rights Reserved.<br />
Odoo is a trademark of the <a target="_blank" href="https://www.odoo.com" style="text-decoration: underline;">OpenERP SA Company</a>.</p>
<p>Licenced under the terms of <a target="_blank" href="http://www.gnu.org/licenses/agpl.html" style="text-decoration: underline;">GNU Affero General Public License</a></p>
<p>For more information visit <a target="_blank" href="https://www.odoo.com" style="text-decoration: underline;">Odoo.com</a></p>
</div>
<div class="container">
<div class="">
<div class="col-sm-6 col-md-6 user-details">
<div class="user-image">
<img src="/web/static/src/img/logo2.png" alt="Odoo (Formerly OpenERP)" title="Odoo (Formerly OpenERP)" class="img-circle"/>
</div>
<div class="user-info-block">
<div class="user-heading">
<br/><span class="help-block">(Formerly OpenERP)</span>
<h3>Version <t t-esc="version_info.server_version"/></h3>
</div>
<ul class="navigation">
<li class="active">
<a data-toggle="tab" href="#settings">
<span class="glyphicon glyphicon-cog"></span>
</a>
</li>
<li>
<a data-toggle="tab" href="#email">
<span class="glyphicon glyphicon-envelope"></span>
</a>
</li>
<li>
<a data-toggle="tab" href="#events">
<span class="glyphicon glyphicon-calendar"></span>
</a>
</li>
<li>
<a data-toggle="tab" href="#social">
<span class="glyphicon glyphicon-share"></span>
</a>
</li>
</ul>
<div class="user-body">
<div class="tab-content">
<div id="settings" class="tab-pane active">
<h4>Copyright © 2004-TODAY OpenERP SA. All Rights Reserved.</h4>
<p>Odoo is a trademark of the <a target="_blank" href="https://www.odoo.com" style="text-decoration: underline;">OpenERP SA Company</a>.</p>
<p>Licenced under the terms of <a target="_blank" href="http://www.gnu.org/licenses/agpl.html" style="text-decoration: underline;">GNU Affero General Public License</a></p>
<p>For more information visit <a target="_blank" href="https://www.odoo.com" style="text-decoration: underline;">Odoo.com</a></p>
</div>
<div id="email" class="tab-pane">
<h4>OpenERP S.A.</h4>
<p>
Chaussée de Namur 40<br/>
1367 Grand-Rosière <br/>
Belgium
</p>
<!-- TODO - ALIAS contactus -->
<a class='btn btn-link' href='https://www.odoo.com/web/about/contactus'>Our website</a>
</div>
<div id="events" class="tab-pane">
<h4>Discover Events of Odoo around the world...</h4>
<a class='btn btn-link' href='https://www.odoo.com/web/about/event'> Our next Events</a>
</div>
<div id="social" class="tab-pane">
<h4>Follow Us...</h4>
<a href="https://www.odoo.com/web/about/facebook"><i class="fa fa-facebook-square fa-3x social-fb"></i></a>
<a href="https://www.odoo.com/web/about/twitter"><i class="fa fa-twitter-square fa-3x social-tw"></i></a>
<a href="https://www.odoo.com/web/about/googleplus"><i class="fa fa-google-plus-square fa-3x social-gp"></i></a>
<a href="https://www.odoo.com/web/about/linkedin"><i class="fa fa-linkedin-square fa-3x social-lk"></i></a>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</t>
+2 -2
View File
@@ -217,7 +217,7 @@
</script>
</t>
<nav id="oe_main_menu_navbar" class="navbar navbar-inverse" role="navigation">
<nav id="oe_main_menu_navbar" class="navbar navbar-inverse" role="navigation" groups="base.group_user,base.group_portal">
<div class="navbar-header">
<button type="button" class="navbar-toggle" data-toggle="collapse" data-target=".navbar-collapse">
<span class="icon-bar"></span>
@@ -233,7 +233,7 @@
<table class="oe_webclient">
<tr>
<td class="oe_leftbar" valign="top">
<div>
<div groups="base.group_user,base.group_portal">
<t t-call="web.menu_secondary"/>
</div>
</td>
+8 -4
View File
@@ -78,10 +78,14 @@ class ir_http(orm.AbstractModel):
request.session['geoip'] = record
if request.website_enabled:
if func:
self._authenticate(func.routing['auth'])
else:
self._auth_method_public()
try:
if func:
self._authenticate(func.routing['auth'])
else:
self._auth_method_public()
except Exception as e:
return self._handle_exception(e)
request.redirect = lambda url, code=302: werkzeug.utils.redirect(url_for(url), code)
request.website = request.registry['website'].get_current_website(request.cr, request.uid, context=request.context)
langs = [lg[0] for lg in request.website.get_languages()]
+1 -2
View File
@@ -54,7 +54,6 @@
<html t-att-lang="lang and lang.replace('_', '-')"
t-att-data-website-id="website.id if editable and website else None"
t-att-data-editable="'1' if editable else None"
t-att-data-editable-no-editor="editable_no_editor or None"
t-att-data-translatable="'1' if translatable else None"
t-att-data-view-xmlid="xmlid if editable else None"
t-att-data-main-object="repr(main_object) if editable else None"
@@ -95,7 +94,7 @@
m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
})(window,document,'script','//www.google-analytics.com/analytics.js','ga');
ga('create',_.str.trim('<t t-esc="website.google_analytics_key"/>'));
ga('create', _.str.trim('<t t-esc="website.google_analytics_key"/>'), 'auto');
ga('send','pageview');
</script>
</t>
+25 -12
View File
@@ -123,7 +123,7 @@ class ir_attachment(osv.osv):
else:
r = open(full_path,'rb').read().encode('base64')
except IOError:
_logger.error("_read_file reading %s",full_path)
_logger.exception("_read_file reading %s", full_path)
return r
def _file_write(self, cr, uid, value):
@@ -134,20 +134,20 @@ class ir_attachment(osv.osv):
with open(full_path, 'wb') as fp:
fp.write(bin_value)
except IOError:
_logger.error("_file_write writing %s", full_path)
_logger.exception("_file_write writing %s", full_path)
return fname
def _file_delete(self, cr, uid, fname):
count = self.search(cr, 1, [('store_fname','=',fname)], count=True)
count = self.search_count(cr, 1, [('store_fname','=',fname)])
full_path = self._full_path(cr, uid, fname)
if count <= 1 and os.path.exists(full_path):
if not count and os.path.exists(full_path):
try:
os.unlink(full_path)
except OSError:
_logger.error("_file_delete could not unlink %s",full_path)
_logger.exception("_file_delete could not unlink %s", full_path)
except IOError:
# Harmless and needed for race conditions
_logger.error("_file_delete could not unlink %s",full_path)
_logger.exception("_file_delete could not unlink %s", full_path)
def _data_get(self, cr, uid, ids, name, arg, context=None):
if context is None:
@@ -170,14 +170,18 @@ class ir_attachment(osv.osv):
location = self._storage(cr, uid, context)
file_size = len(value.decode('base64'))
attach = self.browse(cr, uid, id, context=context)
if attach.store_fname:
self._file_delete(cr, uid, attach.store_fname)
fname_to_delete = attach.store_fname
if location != 'db':
fname = self._file_write(cr, uid, value)
# SUPERUSER_ID as probably don't have write access, trigger during create
super(ir_attachment, self).write(cr, SUPERUSER_ID, [id], {'store_fname': fname, 'file_size': file_size, 'db_datas': False}, context=context)
else:
super(ir_attachment, self).write(cr, SUPERUSER_ID, [id], {'db_datas': value, 'file_size': file_size, 'store_fname': False}, context=context)
# After de-referencing the file in the database, check whether we need
# to garbage-collect it on the filesystem
if fname_to_delete:
self._file_delete(cr, uid, fname_to_delete)
return True
_name = 'ir.attachment'
@@ -315,10 +319,19 @@ class ir_attachment(osv.osv):
if isinstance(ids, (int, long)):
ids = [ids]
self.check(cr, uid, ids, 'unlink', context=context)
for attach in self.browse(cr, uid, ids, context=context):
if attach.store_fname:
self._file_delete(cr, uid, attach.store_fname)
return super(ir_attachment, self).unlink(cr, uid, ids, context)
# First delete in the database, *then* in the filesystem if the
# database allowed it. Helps avoid errors when concurrent transactions
# are deleting the same file, and some of the transactions are
# rolled back by PostgreSQL (due to concurrent updates detection).
to_delete = [a.store_fname
for a in self.browse(cr, uid, ids, context=context)
if a.store_fname]
res = super(ir_attachment, self).unlink(cr, uid, ids, context)
for file_path in to_delete:
self._file_delete(cr, uid, file_path)
return res
def create(self, cr, uid, values, context=None):
self.check(cr, uid, [], mode='write', context=context, values=values)
+6 -12
View File
@@ -63,12 +63,6 @@ class ir_http(osv.AbstractModel):
def _auth_method_user(self):
request.uid = request.session.uid
if not request.uid:
if not request.params.get('noredirect'):
query = werkzeug.urls.url_encode({
'redirect': request.httprequest.url,
})
response = werkzeug.utils.redirect('/web/login?%s' % query)
werkzeug.exceptions.abort(response)
raise http.SessionExpiredException("Session expired")
def _auth_method_none(self):
@@ -102,7 +96,10 @@ class ir_http(osv.AbstractModel):
def _handle_exception(self, exception):
# If handle_exception returns something different than None, it will be used as a response
return request._handle_exception(exception)
try:
return request._handle_exception(exception)
except openerp.exceptions.AccessDenied:
return werkzeug.exceptions.Forbidden()
def _dispatch(self):
# locate the controller method
@@ -115,11 +112,8 @@ class ir_http(osv.AbstractModel):
# check authentication level
try:
auth_method = self._authenticate(func.routing["auth"])
except Exception:
# force a Forbidden exception with the original traceback
return self._handle_exception(
convert_exception_to(
werkzeug.exceptions.Forbidden))
except Exception as e:
return self._handle_exception(e)
processing = self._postprocess_args(arguments, rule)
if processing:
+2 -8
View File
@@ -265,12 +265,6 @@ class QWeb(orm.AbstractModel):
uid = qwebcontext.get('request') and qwebcontext['request'].uid or None
can_see = self.user_has_groups(cr, uid, groups=attribute_value) if cr and uid else False
if not can_see:
if qwebcontext.get('editable') and not qwebcontext.get('editable_no_editor'):
errmsg = _("Editor disabled because some content can not be seen by a user who does not belong to the groups %s")
raise openerp.http.Retry(
_("User does not belong to groups %s") % attribute_value, {
'editable_no_editor': errmsg % attribute_value
})
return ''
attribute_value = attribute_value.encode("utf8")
@@ -313,7 +307,7 @@ class QWeb(orm.AbstractModel):
for current_node in element.iterchildren(tag=etree.Element):
try:
g_inner.append(self.render_node(current_node, qwebcontext))
except (QWebException, openerp.http.Retry):
except QWebException:
raise
except Exception:
template = qwebcontext.get('__template__')
@@ -1153,7 +1147,7 @@ class AssetsBundle(object):
content = None
domain = [('url', '=', '/web/%s/%s/%s' % (type, self.xmlid, self.version))]
bundle = self.registry['ir.attachment'].search_read(self.cr, self.uid, domain, ['datas'], context=self.context)
if bundle:
if bundle and bundle[0]['datas']:
content = bundle[0]['datas'].decode('base64')
return content
+1 -1
View File
@@ -989,7 +989,7 @@ class view(osv.osv):
:rtype: boolean
"""
return any(
(attr == 'data-oe-model' or (attr != 't-field' and attr.startswith('t-')))
(attr in ('data-oe-model', 'group') or (attr != 't-field' and attr.startswith('t-')))
for attr in node.attrib
)
+9 -16
View File
@@ -590,6 +590,12 @@ class HttpRequest(WebRequest):
be used as response."""
try:
return super(HttpRequest, self)._handle_exception(exception)
except SessionExpiredException:
if not request.params.get('noredirect'):
query = werkzeug.urls.url_encode({
'redirect': request.httprequest.url,
})
return werkzeug.utils.redirect('/web/login?%s' % query)
except werkzeug.exceptions.HTTPException, e:
return e
@@ -1096,15 +1102,6 @@ mimetypes.add_type('application/font-woff', '.woff')
mimetypes.add_type('application/vnd.ms-fontobject', '.eot')
mimetypes.add_type('application/x-font-ttf', '.ttf')
class Retry(RuntimeError):
""" Exception raised during QWeb rendering to signal that the rendering
should be retried with the provided ``render_updates`` dict merged into
the previous rendering context
"""
def __init__(self, name, render_updates=None):
super(Retry, self).__init__(name)
self.updates = render_updates or {}
class Response(werkzeug.wrappers.Response):
""" Response object passed through controller route chain.
@@ -1154,13 +1151,9 @@ class Response(werkzeug.wrappers.Response):
"""
view_obj = request.registry["ir.ui.view"]
uid = self.uid or request.uid or openerp.SUPERUSER_ID
while True:
try:
return view_obj.render(
request.cr, uid, self.template, self.qcontext,
context=request.context)
except Retry, e:
self.qcontext.update(e.updates)
return view_obj.render(
request.cr, uid, self.template, self.qcontext,
context=request.context)
def flatten(self):
""" Forces the rendering of the response's template, sets the result