[MERGE] server side login
bzr revid: fme@openerp.com-20140122133720-2cjcdymf6qqj213u
This commit is contained in:
@@ -12,7 +12,10 @@ This module provides the core of the OpenERP Web Client.
|
||||
'depends': ['base'],
|
||||
'auto_install': True,
|
||||
'post_load': 'wsgi_postload',
|
||||
'js' : [
|
||||
'data': [
|
||||
'views/webclient_templates.xml',
|
||||
],
|
||||
'js': [
|
||||
"static/lib/es5-shim/es5-shim.min.js",
|
||||
"static/lib/datejs/globalization/en-US.js",
|
||||
"static/lib/datejs/core.js",
|
||||
|
||||
+121
-44
@@ -6,6 +6,7 @@ import csv
|
||||
import functools
|
||||
import glob
|
||||
import itertools
|
||||
import jinja2
|
||||
import logging
|
||||
import operator
|
||||
import datetime
|
||||
@@ -16,8 +17,6 @@ import simplejson
|
||||
import time
|
||||
import urllib
|
||||
import urllib2
|
||||
import urlparse
|
||||
import xmlrpclib
|
||||
import zlib
|
||||
from xml.etree import ElementTree
|
||||
from cStringIO import StringIO
|
||||
@@ -33,13 +32,18 @@ except ImportError:
|
||||
import openerp
|
||||
import openerp.modules.registry
|
||||
from openerp.tools.translate import _
|
||||
from openerp.tools import config
|
||||
from openerp import http
|
||||
|
||||
from openerp.http import request, serialize_exception as _serialize_exception
|
||||
from openerp.http import request, serialize_exception as _serialize_exception, LazyResponse
|
||||
|
||||
_logger = logging.getLogger(__name__)
|
||||
|
||||
env = jinja2.Environment(
|
||||
loader=jinja2.PackageLoader('openerp.addons.web', "views"),
|
||||
autoescape=True
|
||||
)
|
||||
env.filters["json"] = simplejson.dumps
|
||||
|
||||
#----------------------------------------------------------
|
||||
# OpenERP Web helpers
|
||||
#----------------------------------------------------------
|
||||
@@ -108,12 +112,13 @@ def serialize_exception(f):
|
||||
return werkzeug.exceptions.InternalServerError(simplejson.dumps(error))
|
||||
return wrap
|
||||
|
||||
def redirect_with_hash(url, code=303):
|
||||
# Most IE and Safari versions decided not to preserve location.hash upon
|
||||
# redirect. And even if IE10 pretends to support it, it still fails
|
||||
# inexplicably in case of multiple redirects (and we do have some).
|
||||
# See extensive test page at http://greenbytes.de/tech/tc/httpredirects/
|
||||
return "<html><head><script>window.location = '%s' + location.hash;</script></head></html>" % url
|
||||
def redirect_with_hash(*args, **kw):
|
||||
"""
|
||||
.. deprecated:: 8.0
|
||||
|
||||
Use the ``http.redirect_with_hash()`` function instead.
|
||||
"""
|
||||
return http.redirect_with_hash(*args, **kw)
|
||||
|
||||
def module_topological_sort(modules):
|
||||
""" Return a list of module names sorted so that their dependencies of the
|
||||
@@ -512,6 +517,8 @@ def content_disposition(filename):
|
||||
# OpenERP Web web Controllers
|
||||
#----------------------------------------------------------
|
||||
|
||||
# TODO: to remove once the database manager has been migrated server side
|
||||
# and `edi` + `pos` addons has been adapted to use render_bootstrap_template()
|
||||
html_template = """<!DOCTYPE html>
|
||||
<html style="height: 100%%">
|
||||
<head>
|
||||
@@ -538,53 +545,89 @@ html_template = """<!DOCTYPE html>
|
||||
</html>
|
||||
"""
|
||||
|
||||
def render_bootstrap_template(db, template, values=None, debug=False, lazy=False, **kw):
|
||||
if request and request.debug:
|
||||
debug = True
|
||||
if values is None:
|
||||
values = {}
|
||||
values.update(kw)
|
||||
values['debug'] = debug
|
||||
|
||||
for res in ['js', 'css']:
|
||||
if res not in values:
|
||||
values[res] = manifest_list(res, db=db, debug=debug)
|
||||
|
||||
if 'modules' not in values:
|
||||
values['modules'] = module_boot(db=db)
|
||||
values['modules'] = simplejson.dumps(values['modules'])
|
||||
|
||||
def callback(template, values):
|
||||
registry = openerp.modules.registry.RegistryManager.get(db)
|
||||
with registry.cursor() as cr:
|
||||
view_obj = registry["ir.ui.view"]
|
||||
return view_obj.render(cr, openerp.SUPERUSER_ID, template, values)
|
||||
if lazy:
|
||||
return LazyResponse(callback, template=template, values=values)
|
||||
else:
|
||||
return callback(template, values)
|
||||
|
||||
class Home(http.Controller):
|
||||
|
||||
@http.route('/', type='http', auth="none")
|
||||
def index(self, s_action=None, db=None, debug=False, **kw):
|
||||
query = dict(urlparse.parse_qsl(request.httprequest.query_string, keep_blank_values=True))
|
||||
redirect = '/web' + '?' + urllib.urlencode(query)
|
||||
return redirect_with_hash(redirect)
|
||||
def index(self, s_action=None, db=None, **kw):
|
||||
return http.local_redirect('/web', query=request.params)
|
||||
|
||||
@http.route('/web', type='http', auth="none")
|
||||
def web_client(self, s_action=None, db=None, debug=False, **kw):
|
||||
debug = debug != False
|
||||
def web_client(self, s_action=None, db=None, **kw):
|
||||
# if db not provided, use the session one
|
||||
if not db:
|
||||
db = request.session.db
|
||||
|
||||
lst = http.db_list(True)
|
||||
if db not in lst:
|
||||
db = None
|
||||
guessed_db = http.db_monodb(request.httprequest)
|
||||
if guessed_db is None and len(lst) > 0:
|
||||
guessed_db = lst[0]
|
||||
# if no database provided and no database in session, use monodb
|
||||
if not db:
|
||||
db = http.db_monodb(request.httprequest)
|
||||
|
||||
def redirect(db):
|
||||
query = dict(urlparse.parse_qsl(request.httprequest.query_string, keep_blank_values=True))
|
||||
query['db'] = db
|
||||
redirect = request.httprequest.path + '?' + urllib.urlencode(query)
|
||||
return redirect_with_hash(redirect)
|
||||
# if no db can be found til here, send to the database selector
|
||||
# the database selector will redirect to database manager if needed
|
||||
if not db:
|
||||
return http.local_redirect('/web/database/selector')
|
||||
|
||||
if db is None and guessed_db is not None:
|
||||
return redirect(guessed_db)
|
||||
# always switch the session to the computed db
|
||||
if db != request.session.db:
|
||||
request.session.logout()
|
||||
request.session.db = db
|
||||
|
||||
if db is not None and db != request.session.db:
|
||||
if request.session.uid:
|
||||
html = render_bootstrap_template(db, "web.webclient_bootstrap")
|
||||
return request.make_response(html, {'Cache-Control': 'no-cache', 'Content-Type': 'text/html; charset=utf-8'})
|
||||
else:
|
||||
return http.local_redirect('/web/login', query=request.params)
|
||||
|
||||
@http.route('/web/login', type='http', auth="none")
|
||||
def web_login(self, redirect=None, db=None, **kw):
|
||||
if db and db != request.session.db:
|
||||
request.session.logout()
|
||||
request.session.db = db
|
||||
guessed_db = db
|
||||
request.params.pop('db', None)
|
||||
return http.local_redirect('/web/login', query=request.params)
|
||||
|
||||
js = "\n ".join('<script type="text/javascript" src="%s"></script>' % i for i in manifest_list('js', db=guessed_db, debug=debug))
|
||||
css = "\n ".join('<link rel="stylesheet" href="%s">' % i for i in manifest_list('css', db=guessed_db, debug=debug))
|
||||
if not request.session.db and not db:
|
||||
return http.local_redirect('/web/database/selector')
|
||||
|
||||
r = html_template % {
|
||||
'js': js,
|
||||
'css': css,
|
||||
'modules': simplejson.dumps(module_boot(db=guessed_db)),
|
||||
'init': 'var wc = new s.web.WebClient();wc.appendTo($(document.body));'
|
||||
}
|
||||
return request.make_response(r, {'Cache-Control': 'no-cache', 'Content-Type': 'text/html; charset=utf-8'})
|
||||
values = request.params.copy()
|
||||
if not redirect:
|
||||
redirect = '/web?' + request.httprequest.query_string
|
||||
values['redirect'] = redirect
|
||||
if request.httprequest.method == 'POST':
|
||||
uid = request.session.authenticate(request.session.db, request.params['login'], request.params['password'])
|
||||
if uid is not False:
|
||||
return http.redirect_with_hash(redirect)
|
||||
values['error'] = "Wrong login/password"
|
||||
return render_bootstrap_template(request.session.db, 'web.login', values, lazy=True)
|
||||
|
||||
@http.route('/login', type='http', auth="none")
|
||||
def login(self, db, login, key):
|
||||
return login_and_redirect(db, login, key)
|
||||
def login(self, db, login, key, redirect="/web", **kw):
|
||||
return login_and_redirect(db, login, key, redirect_url=redirect)
|
||||
|
||||
class WebClient(http.Controller):
|
||||
|
||||
@@ -754,6 +797,37 @@ class Proxy(http.Controller):
|
||||
|
||||
class Database(http.Controller):
|
||||
|
||||
@http.route('/web/database/selector', type='http', auth="none")
|
||||
def selector(self, **kw):
|
||||
try:
|
||||
dbs = http.db_list()
|
||||
if not dbs:
|
||||
return http.local_redirect('/web/database/manager')
|
||||
except openerp.exceptions.AccessDenied:
|
||||
dbs = False
|
||||
return env.get_template("database_selector.html").render({
|
||||
'databases': dbs,
|
||||
'debug': request.debug,
|
||||
})
|
||||
|
||||
@http.route('/web/database/manager', type='http', auth="none")
|
||||
def manager(self, **kw):
|
||||
# TODO: migrate the webclient's database manager to server side views
|
||||
request.session.logout()
|
||||
js = "\n ".join('<script type="text/javascript" src="%s"></script>' % i for i in manifest_list('js', debug=request.debug))
|
||||
css = "\n ".join('<link rel="stylesheet" href="%s">' % i for i in manifest_list('css', debug=request.debug))
|
||||
|
||||
r = html_template % {
|
||||
'js': js,
|
||||
'css': css,
|
||||
'modules': simplejson.dumps(module_boot()),
|
||||
'init': """
|
||||
var wc = new s.web.WebClient(null, { action: 'database_manager' });
|
||||
wc.appendTo($(document.body));
|
||||
"""
|
||||
}
|
||||
return r
|
||||
|
||||
@http.route('/web/database/get_list', type='json', auth="none")
|
||||
def get_list(self):
|
||||
# TODO change js to avoid calling this method if in monodb mode
|
||||
@@ -768,12 +842,15 @@ class Database(http.Controller):
|
||||
@http.route('/web/database/create', type='json', auth="none")
|
||||
def create(self, fields):
|
||||
params = dict(map(operator.itemgetter('name', 'value'), fields))
|
||||
return request.session.proxy("db").create_database(
|
||||
db_created = request.session.proxy("db").create_database(
|
||||
params['super_admin_pwd'],
|
||||
params['db_name'],
|
||||
bool(params.get('demo_data')),
|
||||
params['db_lang'],
|
||||
params['create_admin_pwd'])
|
||||
if db_created:
|
||||
request.session.authenticate(params['db_name'], 'admin', params['create_admin_pwd'])
|
||||
return db_created
|
||||
|
||||
@http.route('/web/database/duplicate', type='json', auth="none")
|
||||
def duplicate(self, fields):
|
||||
@@ -942,7 +1019,7 @@ class Session(http.Controller):
|
||||
def destroy(self):
|
||||
request.session.logout()
|
||||
|
||||
@http.route('/web/session/logout', type='http', auth="user")
|
||||
@http.route('/web/session/logout', type='http', auth="none")
|
||||
def logout(self, redirect='/web'):
|
||||
request.session.logout()
|
||||
return werkzeug.utils.redirect(redirect, 303)
|
||||
|
||||
@@ -874,153 +874,6 @@
|
||||
padding: 5px;
|
||||
width: 32px;
|
||||
}
|
||||
.openerp .oe_login {
|
||||
background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAYAAAAGCAYAAADgzO9IAAAAKUlEQVQIHWO8e/fufwYsgAUkJigoiCIF5DMyoYggcUiXgNnBiGQKmAkARpcEQeriln4AAAAASUVORK5CYII=);
|
||||
text-align: center;
|
||||
font-size: 14px;
|
||||
height: 100%;
|
||||
}
|
||||
.openerp .oe_login ul, .openerp .oe_login li {
|
||||
margin: 0;
|
||||
list-style-type: none;
|
||||
padding: 0 0 4px 0;
|
||||
}
|
||||
.openerp .oe_login button {
|
||||
cursor: pointer;
|
||||
padding: 6px 16px;
|
||||
border: 1px solid #222222;
|
||||
color: white;
|
||||
margin: 0;
|
||||
background-color: #8c1313;
|
||||
background-image: -webkit-gradient(linear, left top, left bottom, from(#b92020), to(#600606));
|
||||
background-image: -webkit-linear-gradient(top, #b92020, #600606);
|
||||
background-image: -moz-linear-gradient(top, #b92020, #600606);
|
||||
background-image: -ms-linear-gradient(top, #b92020, #600606);
|
||||
background-image: -o-linear-gradient(top, #b92020, #600606);
|
||||
background-image: linear-gradient(to bottom, #b92020, #600606);
|
||||
-moz-border-radius: 4px;
|
||||
-webkit-border-radius: 4px;
|
||||
border-radius: 4px;
|
||||
-moz-box-shadow: 0 1px 2px rgba(0, 0, 0, 0.1), 0 1px 1px rgba(155, 155, 155, 0.4) inset;
|
||||
-webkit-box-shadow: 0 1px 2px rgba(0, 0, 0, 0.1), 0 1px 1px rgba(155, 155, 155, 0.4) inset;
|
||||
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.1), 0 1px 1px rgba(155, 155, 155, 0.4) inset;
|
||||
}
|
||||
.openerp .oe_login input, .openerp .oe_login select {
|
||||
width: 252px;
|
||||
font-family: "Lucida Grande", Helvetica, Verdana, Arial;
|
||||
border: 1px solid #999999;
|
||||
background: whitesmoke;
|
||||
-moz-box-shadow: inset 0 1px 4px rgba(0, 0, 0, 0.4);
|
||||
-webkit-box-shadow: inset 0 1px 4px rgba(0, 0, 0, 0.4);
|
||||
box-shadow: inset 0 1px 4px rgba(0, 0, 0, 0.4);
|
||||
-moz-border-radius: 3px;
|
||||
-webkit-border-radius: 3px;
|
||||
border-radius: 3px;
|
||||
}
|
||||
.openerp .oe_login input {
|
||||
margin-bottom: 9px;
|
||||
padding: 5px 6px;
|
||||
}
|
||||
.openerp .oe_login select {
|
||||
padding: 1px;
|
||||
}
|
||||
.openerp .oe_login .oe_login_dbpane {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
right: 8px;
|
||||
padding: 5px 10px;
|
||||
color: #eeeeee;
|
||||
border: solid 1px #333333;
|
||||
background: #1e1e1e;
|
||||
background: rgba(30, 30, 30, 0.94);
|
||||
-moz-border-radius: 0 0 8px 8px;
|
||||
-webkit-border-radius: 0 0 8px 8px;
|
||||
border-radius: 0 0 8px 8px;
|
||||
}
|
||||
.openerp .oe_login .oe_login_dbpane input {
|
||||
padding: 2px 4px;
|
||||
margin: 4px 0;
|
||||
}
|
||||
.openerp .oe_login .oe_login_bottom {
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
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);
|
||||
}
|
||||
.openerp .oe_login .oe_login_pane {
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
margin: -160px -166px;
|
||||
border: solid 1px #333333;
|
||||
background: #1e1e1e;
|
||||
background: rgba(30, 30, 30, 0.94);
|
||||
padding: 22px 32px;
|
||||
color: #eeeeee;
|
||||
text-align: left;
|
||||
-moz-border-radius: 8px;
|
||||
-webkit-border-radius: 8px;
|
||||
border-radius: 8px;
|
||||
-moz-box-shadow: 0 0 18px rgba(0, 0, 0, 0.9);
|
||||
-webkit-box-shadow: 0 0 18px rgba(0, 0, 0, 0.9);
|
||||
box-shadow: 0 0 18px rgba(0, 0, 0, 0.9);
|
||||
}
|
||||
.openerp .oe_login .oe_login_pane h2 {
|
||||
margin-top: 0;
|
||||
font-size: 18px;
|
||||
}
|
||||
.openerp .oe_login .oe_login_logo {
|
||||
position: absolute;
|
||||
top: -70px;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
margin: 0 auto;
|
||||
text-align: center;
|
||||
}
|
||||
.openerp .oe_login .oe_login_footer {
|
||||
position: absolute;
|
||||
bottom: -40px;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
text-align: center;
|
||||
}
|
||||
.openerp .oe_login .oe_login_footer a {
|
||||
color: #eeeeee;
|
||||
margin: 0 6px;
|
||||
}
|
||||
.openerp .oe_login .oe_login_footer a:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
.openerp .oe_login .oe_login_footer span {
|
||||
font-weight: bold;
|
||||
font-size: 16px;
|
||||
}
|
||||
.openerp .oe_login .oe_login_error_message {
|
||||
display: none;
|
||||
background-color: #b41616;
|
||||
color: #eeeeee;
|
||||
padding: 14px 18px;
|
||||
margin-top: 15px;
|
||||
text-align: center;
|
||||
-moz-border-radius: 4px;
|
||||
-webkit-border-radius: 4px;
|
||||
border-radius: 4px;
|
||||
-moz-box-shadow: 0 1px 4px rgba(0, 0, 0, 0.8);
|
||||
-webkit-box-shadow: 0 1px 4px rgba(0, 0, 0, 0.8);
|
||||
box-shadow: 0 1px 4px rgba(0, 0, 0, 0.8);
|
||||
}
|
||||
.openerp .oe_login_invalid .oe_login_error_message {
|
||||
display: inline-block;
|
||||
}
|
||||
.openerp .oe_database_manager {
|
||||
background: white;
|
||||
color: black;
|
||||
@@ -1050,7 +903,7 @@
|
||||
background-image: -moz-linear-gradient(top, #fc8787, maroon);
|
||||
background-image: -ms-linear-gradient(top, #fc8787, maroon);
|
||||
background-image: -o-linear-gradient(top, #fc8787, maroon);
|
||||
background-image: linear-gradient(to bottom, #fc8787, maroon);
|
||||
background-image: linear-gradient(to bottom, #fc8787, #800000);
|
||||
}
|
||||
.openerp .navbar .oe_topbar_anonymous_login a {
|
||||
display: block;
|
||||
@@ -3385,6 +3238,33 @@ div.ui-widget-overlay {
|
||||
padding-bottom: 10px !important;
|
||||
}
|
||||
|
||||
body.oe_single_form {
|
||||
background: #eeeeee url(/web/static/src/img/form_sheetbg.png);
|
||||
height: 100%;
|
||||
}
|
||||
body.oe_single_form .oe_single_form_logo {
|
||||
padding: 10px;
|
||||
text-align: center;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
body.oe_single_form .oe_single_form_footer {
|
||||
position: absolute;
|
||||
bottom: -30px;
|
||||
right: 0px;
|
||||
width: 100%;
|
||||
text-align: center;
|
||||
}
|
||||
body.oe_single_form .oe_single_form_container {
|
||||
padding: 10px;
|
||||
position: absolute;
|
||||
left: 50%;
|
||||
top: 50%;
|
||||
width: 400px;
|
||||
/* Set margins to offset 50% of the w/h */
|
||||
margin-top: -200px;
|
||||
margin-left: -200px;
|
||||
}
|
||||
|
||||
.openerp_ie .placeholder {
|
||||
color: #afafb6 !important;
|
||||
font-style: italic !important;
|
||||
|
||||
@@ -747,108 +747,6 @@ $sheet-padding: 16px
|
||||
padding: 5px
|
||||
width: 32px
|
||||
// }}}
|
||||
// Login {{{
|
||||
.oe_login
|
||||
background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAYAAAAGCAYAAADgzO9IAAAAKUlEQVQIHWO8e/fufwYsgAUkJigoiCIF5DMyoYggcUiXgNnBiGQKmAkARpcEQeriln4AAAAASUVORK5CYII=)
|
||||
text-align: center
|
||||
font-size: 14px
|
||||
height: 100%
|
||||
ul, li
|
||||
margin: 0
|
||||
list-style-type: none
|
||||
padding: 0 0 4px 0
|
||||
button
|
||||
cursor: pointer
|
||||
padding: 6px 16px
|
||||
border: 1px solid #222
|
||||
color: white
|
||||
margin: 0
|
||||
@include vertical-gradient(#b92020, #600606)
|
||||
@include radius(4px)
|
||||
@include box-shadow((0 1px 2px rgba(0, 0, 0, 0.1), 0 1px 1px rgba(155, 155, 155, 0.4) inset))
|
||||
input, select
|
||||
width: 252px
|
||||
font-family: "Lucida Grande", Helvetica, Verdana, Arial
|
||||
border: 1px solid #999999
|
||||
background: whitesmoke
|
||||
@include box-shadow(inset 0 1px 4px rgba(0, 0, 0, 0.4))
|
||||
@include radius(3px)
|
||||
input
|
||||
margin-bottom: 9px
|
||||
padding: 5px 6px
|
||||
select
|
||||
padding: 1px
|
||||
.oe_login_dbpane
|
||||
position: fixed
|
||||
top: 0
|
||||
right: 8px
|
||||
padding: 5px 10px
|
||||
color: #eee
|
||||
border: solid 1px #333
|
||||
background: #1e1e1e
|
||||
background: rgba(30,30,30,0.94)
|
||||
@include radius(0 0 8px 8px)
|
||||
input
|
||||
padding: 2px 4px
|
||||
margin: 4px 0
|
||||
.oe_login_bottom
|
||||
position: absolute
|
||||
top: 50%
|
||||
left: 0
|
||||
right: 0
|
||||
bottom: 0
|
||||
text-shadow: 0 1px 1px #999999
|
||||
@include vertical-gradient(#b41616, #600606)
|
||||
.oe_login_pane
|
||||
position: absolute
|
||||
top: 50%
|
||||
left: 50%
|
||||
margin: -160px -166px
|
||||
border: solid 1px #333333
|
||||
background: #1e1e1e
|
||||
background: rgba(30,30,30,0.94)
|
||||
padding: 22px 32px
|
||||
color: #eee
|
||||
text-align: left
|
||||
@include radius(8px)
|
||||
@include box-shadow(0 0 18px rgba(0, 0, 0, 0.9))
|
||||
h2
|
||||
margin-top: 0
|
||||
font-size: 18px
|
||||
.oe_login_logo
|
||||
position: absolute
|
||||
top: -70px
|
||||
left: 0
|
||||
width: 100%
|
||||
margin: 0 auto
|
||||
text-align: center
|
||||
.oe_login_footer
|
||||
position: absolute
|
||||
bottom: -40px
|
||||
left: 0
|
||||
width: 100%
|
||||
text-align: center
|
||||
a
|
||||
color: #eee
|
||||
margin: 0 6px
|
||||
&:hover
|
||||
text-decoration: underline
|
||||
span
|
||||
font-weight: bold
|
||||
font-size: 16px
|
||||
.oe_login_error_message
|
||||
display: none
|
||||
background-color: #b41616
|
||||
color: #eee
|
||||
padding: 14px 18px
|
||||
margin-top: 15px
|
||||
text-align: center
|
||||
@include radius(4px)
|
||||
@include box-shadow(0 1px 4px rgba(0, 0, 0, 0.8))
|
||||
.oe_login_invalid
|
||||
.oe_login_error_message
|
||||
display: inline-block
|
||||
// }}}
|
||||
// DatabaseManager {{{
|
||||
.oe_database_manager
|
||||
background: #fff
|
||||
@@ -2698,6 +2596,38 @@ div.ui-widget-overlay
|
||||
td
|
||||
padding-bottom: 10px !important
|
||||
|
||||
// Server side single forms {{{
|
||||
@mixin single-form($width: 400px)
|
||||
padding: 10px
|
||||
position: absolute
|
||||
left: 50%
|
||||
top: 50%
|
||||
width: $width
|
||||
/* Set margins to offset 50% of the w/h */
|
||||
margin-top: -($width / 2)
|
||||
margin-left: -($width / 2)
|
||||
|
||||
body.oe_single_form
|
||||
background: #eee url(/web/static/src/img/form_sheetbg.png)
|
||||
height: 100%
|
||||
|
||||
.oe_single_form_logo
|
||||
padding: 10px
|
||||
text-align: center
|
||||
margin-bottom: 10px
|
||||
|
||||
.oe_single_form_footer
|
||||
position: absolute
|
||||
bottom: -30px
|
||||
right: 0px
|
||||
width: 100%
|
||||
text-align: center
|
||||
|
||||
.oe_single_form_container
|
||||
@include single-form(400px)
|
||||
|
||||
// }}}
|
||||
|
||||
// Internet Explorer 9+ specifics {{{
|
||||
.openerp_ie
|
||||
.placeholder
|
||||
|
||||
@@ -475,19 +475,6 @@ instance.web.DatabaseManager = instance.web.Widget.extend({
|
||||
this.$el.find('#db-create, #db-drop, #db-backup, #db-restore, #db-change-password, #back-to-login').unbind('click').end().empty();
|
||||
this._super();
|
||||
},
|
||||
/**
|
||||
* Converts a .serializeArray() result into a dict. Does not bother folding
|
||||
* multiple identical keys into an array, last key wins.
|
||||
*
|
||||
* @param {Array} array
|
||||
*/
|
||||
to_object: function (array) {
|
||||
var result = {};
|
||||
_(array).each(function (record) {
|
||||
result[record.name] = record.value;
|
||||
});
|
||||
return result;
|
||||
},
|
||||
/**
|
||||
* Blocks UI and replaces $.unblockUI by a noop to prevent third parties
|
||||
* from unblocking the UI
|
||||
@@ -525,25 +512,11 @@ instance.web.DatabaseManager = instance.web.Widget.extend({
|
||||
var self = this;
|
||||
var fields = $(form).serializeArray();
|
||||
self.rpc("/web/database/create", {'fields': fields}).done(function(result) {
|
||||
var form_obj = self.to_object(fields);
|
||||
var client_action = {
|
||||
type: 'ir.actions.client',
|
||||
tag: 'login',
|
||||
params: {
|
||||
'db': form_obj['db_name'],
|
||||
'login': 'admin',
|
||||
'password': form_obj['create_admin_pwd'],
|
||||
'login_successful': function() {
|
||||
var url = '/web?db=' + form_obj['db_name'];
|
||||
if (self.session.debug) {
|
||||
url += '&debug';
|
||||
}
|
||||
instance.web.redirect(url);
|
||||
},
|
||||
},
|
||||
_push_me: false,
|
||||
};
|
||||
self.do_action(client_action);
|
||||
if (result) {
|
||||
instance.web.redirect('/web')
|
||||
} else {
|
||||
alert("Failed to create database");
|
||||
}
|
||||
});
|
||||
},
|
||||
do_duplicate: function(form) {
|
||||
@@ -641,156 +614,20 @@ instance.web.DatabaseManager = instance.web.Widget.extend({
|
||||
},
|
||||
do_exit: function () {
|
||||
this.$el.remove();
|
||||
instance.webclient.show_login();
|
||||
instance.web.redirect('/web');
|
||||
}
|
||||
});
|
||||
instance.web.client_actions.add("database_manager", "instance.web.DatabaseManager");
|
||||
|
||||
instance.web.Login = instance.web.Widget.extend({
|
||||
template: "Login",
|
||||
remember_credentials: true,
|
||||
events: {
|
||||
'change input[name=db],select[name=db]': function(ev) {
|
||||
this.set('database_selector', $(ev.currentTarget).val());
|
||||
},
|
||||
},
|
||||
instance.web.login = function() {
|
||||
instance.web.redirect('/web/login');
|
||||
};
|
||||
instance.web.client_actions.add("login", "instance.web.login");
|
||||
|
||||
init: function(parent, action) {
|
||||
this._super(parent);
|
||||
this.has_local_storage = typeof(localStorage) != 'undefined';
|
||||
this.db_list = null;
|
||||
this.selected_db = null;
|
||||
this.selected_login = null;
|
||||
this.params = action.params || {};
|
||||
if (_.isEmpty(this.params)) {
|
||||
this.params = $.bbq.getState(true);
|
||||
}
|
||||
if (action && action.params && action.params.db) {
|
||||
this.params.db = action.params.db;
|
||||
} else if ($.deparam.querystring().db) {
|
||||
this.params.db = $.deparam.querystring().db;
|
||||
}
|
||||
if (this.params.db) {
|
||||
this.selected_db = this.params.db;
|
||||
}
|
||||
|
||||
if (this.params.login_successful) {
|
||||
this.on('login_successful', this, this.params.login_successful);
|
||||
}
|
||||
// some cleanup to remove any trace of that last login feature
|
||||
if (typeof(localStorage) != 'undefined') {
|
||||
var toRemove = [];
|
||||
_.each(_.range(localStorage.length), function(i) {
|
||||
var key = localStorage.key(i);
|
||||
if (key.match(/^.*?\|last_password$/)) {
|
||||
toRemove.push(key);
|
||||
}
|
||||
});
|
||||
_.each(toRemove, function(k) {
|
||||
localStorage.removeItem(k);
|
||||
});
|
||||
}
|
||||
},
|
||||
start: function() {
|
||||
var self = this;
|
||||
self.$el.find("form").submit(self.on_submit);
|
||||
self.$el.find('.oe_login_manage_db').click(function() {
|
||||
self.do_action("database_manager");
|
||||
});
|
||||
self.on('change:database_selector', this, function() {
|
||||
this.database_selected(this.get('database_selector'));
|
||||
});
|
||||
var d = $.when();
|
||||
if ($.param.fragment().token) {
|
||||
self.params.token = $.param.fragment().token;
|
||||
}
|
||||
// used by dbmanager.do_create via internal client action
|
||||
if (self.params.db && self.params.login && self.params.password) {
|
||||
d = self.do_login(self.params.db, self.params.login, self.params.password);
|
||||
} else {
|
||||
d = self.rpc("/web/database/get_list", {})
|
||||
.done(self.on_db_loaded)
|
||||
.fail(self.on_db_failed)
|
||||
.always(function() {
|
||||
if (self.selected_db && self.has_local_storage && self.remember_credentials) {
|
||||
self.$("[name=login]").val(localStorage.getItem(self.selected_db + '|last_login') || '');
|
||||
}
|
||||
});
|
||||
}
|
||||
return d;
|
||||
},
|
||||
database_selected: function(db) {
|
||||
var params = $.deparam.querystring();
|
||||
params.db = db;
|
||||
this.$('.oe_login_dbpane').empty().text(_t('Loading...'));
|
||||
this.$('[name=login], [name=password]').prop('readonly', true);
|
||||
instance.web.redirect('/web?' + $.param(params));
|
||||
},
|
||||
on_db_loaded: function (result) {
|
||||
var self = this;
|
||||
this.db_list = result;
|
||||
if (!this.selected_db) {
|
||||
this.selected_db = result[0];
|
||||
}
|
||||
this.$("[name=db]").replaceWith(QWeb.render('Login.dblist', { db_list: this.db_list, selected_db: this.selected_db}));
|
||||
if(this.db_list.length === 0) {
|
||||
this.do_action("database_manager");
|
||||
} else if(this.db_list.length === 1) {
|
||||
this.$('div.oe_login_dbpane').hide();
|
||||
} else {
|
||||
this.$('div.oe_login_dbpane').show();
|
||||
}
|
||||
},
|
||||
on_db_failed: function (error, event) {
|
||||
if (error.data.name === 'openerp.exceptions.AccessDenied') {
|
||||
event.preventDefault();
|
||||
}
|
||||
},
|
||||
on_submit: function(ev) {
|
||||
if(ev) {
|
||||
ev.preventDefault();
|
||||
}
|
||||
var db = this.$("form [name=db]").val();
|
||||
if (!db) {
|
||||
this.do_warn(_t("Login"), _t("No database selected !"));
|
||||
return false;
|
||||
}
|
||||
var login = this.$("form input[name=login]").val();
|
||||
var password = this.$("form input[name=password]").val();
|
||||
|
||||
this.do_login(db, login, password);
|
||||
},
|
||||
/**
|
||||
* Performs actual login operation, and UI-related stuff
|
||||
*
|
||||
* @param {String} db database to log in
|
||||
* @param {String} login user login
|
||||
* @param {String} password user password
|
||||
*/
|
||||
do_login: function (db, login, password) {
|
||||
var self = this;
|
||||
self.hide_error();
|
||||
self.$(".oe_login_pane").fadeOut("slow");
|
||||
return this.session.session_authenticate(db, login, password).then(function() {
|
||||
if (self.has_local_storage && self.remember_credentials) {
|
||||
localStorage.setItem(db + '|last_login', login);
|
||||
}
|
||||
self.trigger('login_successful');
|
||||
}, function () {
|
||||
self.$(".oe_login_pane").fadeIn("fast", function() {
|
||||
self.show_error(_t("Invalid username or password"));
|
||||
});
|
||||
});
|
||||
},
|
||||
show_error: function(message) {
|
||||
this.$el.addClass("oe_login_invalid");
|
||||
this.$(".oe_login_error_message").text(message);
|
||||
},
|
||||
hide_error: function() {
|
||||
this.$el.removeClass('oe_login_invalid');
|
||||
},
|
||||
});
|
||||
instance.web.client_actions.add("login", "instance.web.Login");
|
||||
instance.web.logout = function() {
|
||||
instance.web.redirect('/web/session/logout');
|
||||
};
|
||||
instance.web.client_actions.add("logout", "instance.web.logout");
|
||||
|
||||
|
||||
/**
|
||||
@@ -1246,6 +1083,7 @@ instance.web.FullscreenWidget = instance.web.Widget.extend({
|
||||
instance.web.Client = instance.web.Widget.extend({
|
||||
init: function(parent, origin) {
|
||||
instance.client = instance.webclient = this;
|
||||
this.client_options = {};
|
||||
this._super(parent);
|
||||
this.origin = origin;
|
||||
},
|
||||
@@ -1316,8 +1154,11 @@ instance.web.WebClient = instance.web.Client.extend({
|
||||
events: {
|
||||
'click .oe_logo_edit_admin': 'logo_edit'
|
||||
},
|
||||
init: function(parent) {
|
||||
init: function(parent, client_options) {
|
||||
this._super(parent);
|
||||
if (client_options) {
|
||||
_.extend(this.client_options, client_options);
|
||||
}
|
||||
this._current_state = null;
|
||||
this.menu_dm = new instance.web.DropMisordered();
|
||||
this.action_mutex = new $.Mutex();
|
||||
@@ -1331,11 +1172,13 @@ instance.web.WebClient = instance.web.Client.extend({
|
||||
if (jQuery.deparam !== undefined && jQuery.deparam(jQuery.param.querystring()).kitten !== undefined) {
|
||||
self.to_kitten();
|
||||
}
|
||||
if (!self.session.session_is_valid()) {
|
||||
self.show_login();
|
||||
} else {
|
||||
if (self.session.session_is_valid()) {
|
||||
self.show_application();
|
||||
}
|
||||
if (self.client_options.action) {
|
||||
self.action_manager.do_action(self.client_options.action);
|
||||
delete(self.client_options.action);
|
||||
}
|
||||
});
|
||||
},
|
||||
to_kitten: function() {
|
||||
@@ -1385,25 +1228,6 @@ instance.web.WebClient = instance.web.Client.extend({
|
||||
});
|
||||
};
|
||||
},
|
||||
show_login: function() {
|
||||
this.toggle_bars(false);
|
||||
|
||||
var state = $.bbq.getState(true);
|
||||
var action = {
|
||||
type: 'ir.actions.client',
|
||||
tag: 'login',
|
||||
_push_me: false,
|
||||
};
|
||||
|
||||
this.action_manager.do_action(action);
|
||||
this.action_manager.inner_widget.on('login_successful', this, function() {
|
||||
if ('redirect' in state) {
|
||||
openerp.web.redirect(state.redirect);
|
||||
} else {
|
||||
this.show_application(); // will load the state we just pushed
|
||||
}
|
||||
});
|
||||
},
|
||||
show_application: function() {
|
||||
var self = this;
|
||||
self.toggle_bars(true);
|
||||
@@ -1418,6 +1242,10 @@ instance.web.WebClient = instance.web.Client.extend({
|
||||
self.bind_hashchange();
|
||||
self.set_title();
|
||||
self.check_timezone();
|
||||
if (self.client_options.action_post_login) {
|
||||
self.action_manager.do_action(self.client_options.action_post_login);
|
||||
delete(self.client_options.action_post_login);
|
||||
}
|
||||
},
|
||||
update_logo: function() {
|
||||
var img = this.session.url('/web/binary/company_logo');
|
||||
@@ -1498,11 +1326,7 @@ instance.web.WebClient = instance.web.Client.extend({
|
||||
on_logout: function() {
|
||||
var self = this;
|
||||
if (!this.has_uncommitted_changes()) {
|
||||
this.session.session_logout().done(function () {
|
||||
$(window).unbind('hashchange', self.on_hashchange);
|
||||
self.do_push_state({});
|
||||
window.location.reload();
|
||||
});
|
||||
self.action_manager.do_action('logout');
|
||||
}
|
||||
},
|
||||
bind_hashchange: function() {
|
||||
@@ -1659,6 +1483,24 @@ instance.web.embed = function (origin, dbname, login, key, action, options) {
|
||||
client.insertAfter(currentScript);
|
||||
};
|
||||
|
||||
openerp.web.LoginForm = openerp.web.Widget.extend({
|
||||
init: function ($form) {
|
||||
this._super(/* no parent */);
|
||||
this.setElement($form);
|
||||
this.$el.on('submit', this.on_submit);
|
||||
this.start();
|
||||
},
|
||||
start: function () {
|
||||
if (location.hash) {
|
||||
this.$el.attr('action', this.$el.attr('action') + location.hash);
|
||||
}
|
||||
return this._super();
|
||||
},
|
||||
on_submit: function () {
|
||||
return true;
|
||||
},
|
||||
});
|
||||
|
||||
})();
|
||||
|
||||
// vim:et fdc=0 fdl=0 foldnestmax=3 fdm=syntax:
|
||||
|
||||
@@ -252,7 +252,7 @@ instance.web.Session.include( /** @lends instance.web.Session# */{
|
||||
return !!this.uid;
|
||||
},
|
||||
/**
|
||||
* The session is validated either by login or by restoration of a previous session
|
||||
* The session is validated by restoration of a previous session
|
||||
*/
|
||||
session_authenticate: function() {
|
||||
var self = this;
|
||||
|
||||
@@ -58,46 +58,6 @@
|
||||
</div>
|
||||
</t>
|
||||
|
||||
<t t-name="Login">
|
||||
<div class="oe_login">
|
||||
<div class="oe_login_bottom"> </div>
|
||||
<div class="oe_login_error_message"/>
|
||||
<div class="oe_login_pane">
|
||||
<div class="oe_login_logo"><img src='/web/static/src/img/logo2.png'/></div>
|
||||
<form action="" method="post">
|
||||
<div class="oe_login_dbpane" >
|
||||
Database:
|
||||
<input name="db" t-att-value="widget.selected_db || ''"/>
|
||||
</div>
|
||||
<ul>
|
||||
<li>Username</li>
|
||||
<li><input name="login" type="text" value="" autofocus="autofocus"/></li>
|
||||
<li>Password</li>
|
||||
<li><input name="password" type="password" value=""/></li>
|
||||
<li><button name="submit">Log in</button></li>
|
||||
</ul>
|
||||
</form>
|
||||
<div class="oe_login_footer">
|
||||
<a href="#" class="oe_login_manage_db">Manage Databases</a> |
|
||||
<a href="http://www.openerp.com" target="_blank">Powered by <span>OpenERP</span></a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</t>
|
||||
<t t-name="Login.dblist">
|
||||
<select name="db">
|
||||
<t t-foreach="db_list" t-as="db">
|
||||
<t t-if="selected_db === db">
|
||||
<option t-att-value="db" selected="true">
|
||||
<t t-esc="db"/></option>
|
||||
</t>
|
||||
<t t-if="selected_db !== db">
|
||||
<option t-att-value="db"><t t-esc="db"/></option>
|
||||
</t>
|
||||
</t>
|
||||
</select>
|
||||
</t>
|
||||
|
||||
<t t-name="DatabaseManager">
|
||||
<div class="oe_view_manager_view_form">
|
||||
<div class="oe_form">
|
||||
|
||||
@@ -0,0 +1,51 @@
|
||||
<!DOCTYPE html>
|
||||
<html style="height: 100%">
|
||||
<head>
|
||||
<meta http-equiv="content-type" content="text/html; charset=utf-8">
|
||||
<title>OpenERP</title>
|
||||
<link rel="shortcut icon" href="/web/static/src/img/favicon.ico" type="image/x-icon">
|
||||
<link rel="stylesheet" href="/web/static/src/css/full.css">
|
||||
<link rel="stylesheet" href="/web/static/lib/fontawesome/css/font-awesome.css">
|
||||
<link rel="stylesheet" href="/web/static/lib/bootstrap/css/bootstrap.css">
|
||||
<link rel="stylesheet" href="/web/static/src/css/base.css">
|
||||
<body class="oe_single_form">
|
||||
|
||||
<div class="oe_single_form_container modal-content">
|
||||
|
||||
<form class="oe_dbselector_form" role="form" action="/web" method="get">
|
||||
<div class="oe_single_form_logo">
|
||||
<img src="/web/static/src/img/logo2.png"/>
|
||||
</div>
|
||||
|
||||
<hr/>
|
||||
|
||||
<div class="form-group field-db">
|
||||
<label for="db" class="control-label">Select database</label>
|
||||
{% if databases %}
|
||||
<select name="db" id="db" class="form-control" required="required" autofocus="autofocus">
|
||||
<option></option>
|
||||
{% for db in databases %}
|
||||
<option value="{{ db }}">{{ db }}</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
{% else %}
|
||||
<input type="text" name="db" id="db" class="form-control" required="required" autofocus="autofocus"/>
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
<hr/>
|
||||
{% if debug %}
|
||||
<input type="hidden" name="debug" value=""/>
|
||||
{% endif %}
|
||||
<input type="submit" value="Continue" class="btn btn-primary pull-right"/>
|
||||
|
||||
<div class="oe_single_form_footer">
|
||||
<a class="oe_login_manage_db" href="/web/database/manager{% if debug %}?debug{% endif %}">Manage Databases</a> |
|
||||
<a href="http://www.openerp.com" target="_blank">Powered by <span>OpenERP</span></a>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
</div>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,115 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- vim:fdn=3:
|
||||
-->
|
||||
<openerp>
|
||||
<data>
|
||||
|
||||
<template id="web.layout" name="Web layout"><!DOCTYPE html>
|
||||
<html style="height: 100%">
|
||||
<head>
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1"/>
|
||||
<meta http-equiv="content-type" content="text/html; charset=utf-8" />
|
||||
<title>OpenERP</title>
|
||||
<link rel="shortcut icon" href="/web/static/src/img/favicon.ico" type="image/x-icon"/>
|
||||
<link rel="stylesheet" href="/web/static/src/css/full.css" />
|
||||
<t t-raw="head or ''"/>
|
||||
</head>
|
||||
<body t-att-class="body_classname">
|
||||
<t t-raw="0"/>
|
||||
</body>
|
||||
</html>
|
||||
</template>
|
||||
|
||||
<template id="web.webclient_bootstrap" name="Webclient Bootstrap">
|
||||
<t t-call="web.layout">
|
||||
<t t-set="head">
|
||||
<t t-foreach="css" t-as="css_file">
|
||||
<link rel="stylesheet" t-att-href="css_file"/>
|
||||
</t>
|
||||
<t t-foreach="js" t-as="js_file">
|
||||
<script type="text/javascript" t-att-src="js_file"></script>
|
||||
</t>
|
||||
<script type="text/javascript">
|
||||
$(function() {
|
||||
var s = new openerp.init(<t t-raw="modules"/>);
|
||||
<t t-if="init">
|
||||
<t t-raw="init"/>
|
||||
</t>
|
||||
<t t-if="not init">
|
||||
var wc = new s.web.WebClient();
|
||||
wc.appendTo($(document.body));
|
||||
</t>
|
||||
});
|
||||
</script>
|
||||
</t>
|
||||
</t>
|
||||
</template>
|
||||
|
||||
<template id="web.login_layout" name="Login Layout">
|
||||
<t t-call="web.layout">
|
||||
<t t-set="body_classname" t-value="'oe_single_form'"/>
|
||||
<div class="oe_single_form_container modal-content">
|
||||
<div class="oe_single_form_logo">
|
||||
<img src="/web/binary/company_logo"/>
|
||||
</div>
|
||||
<hr/>
|
||||
<t t-raw="0"/>
|
||||
</div>
|
||||
</t>
|
||||
</template>
|
||||
|
||||
<template id="web.login" name="Login">
|
||||
<t t-call="web.login_layout">
|
||||
<t t-set="head">
|
||||
<t t-foreach="css" t-as="css_file">
|
||||
<link rel="stylesheet" t-att-href="css_file"/>
|
||||
</t>
|
||||
<t t-foreach="js" t-as="js_file">
|
||||
<script type="text/javascript" t-att-src="js_file"></script>
|
||||
</t>
|
||||
<script type="text/javascript">
|
||||
$(function() {
|
||||
var s = new openerp.init(<t t-raw="modules"/>);
|
||||
var login_form = new openerp.web.LoginForm($('.oe_login_form'));
|
||||
});
|
||||
</script>
|
||||
</t>
|
||||
|
||||
<form class="oe_login_form" role="form" t-attf-action="/web/login{{ '?debug' if debug else '' }}" method="post">
|
||||
<div class="form-group field-login">
|
||||
<label for="login" class="control-label">Login</label>
|
||||
<input type="text" name="login" t-att-value="login" id="login" class="form-control" placeholder="Enter login" required="required" autofocus="autofocus"/>
|
||||
</div>
|
||||
|
||||
<div class="form-group field-password">
|
||||
<label for="password" class="control-label">Password</label>
|
||||
<input type="password" name="password" id="password" class="form-control" placeholder="Password" required="required"/>
|
||||
</div>
|
||||
|
||||
<p class="alert alert-danger" t-if="error">
|
||||
<t t-esc="error"/>
|
||||
</p>
|
||||
<p class="alert alert-success" t-if="message">
|
||||
<t t-esc="message"/>
|
||||
</p>
|
||||
|
||||
<hr/>
|
||||
<input type="hidden" name="redirect" t-att-value="redirect"/>
|
||||
<div class="clearfix oe_login_buttons">
|
||||
<button type="submit" class="btn btn-primary pull-right">Log in</button>
|
||||
</div>
|
||||
|
||||
</form>
|
||||
<div class="oe_single_form_footer" t-if="not disable_footer">
|
||||
<t t-if="not disable_database_manager">
|
||||
<a class="oe_login_manage_db" t-attf-href="/web/database/manager{{ '?debug' if debug else '' }}">Manage Databases</a>
|
||||
<span class="oe_footer_seperator"> | </span>
|
||||
</t>
|
||||
<a href="http://www.openerp.com" target="_blank">Powered by <span>OpenERP</span></a>
|
||||
</div>
|
||||
|
||||
</t>
|
||||
</template>
|
||||
|
||||
</data>
|
||||
</openerp>
|
||||
@@ -11,15 +11,6 @@ instance.web.SearchView = instance.web.SearchView.extend({
|
||||
}
|
||||
});
|
||||
|
||||
// here you may tweak globals object, if any, and play with on_* or do_* callbacks on them
|
||||
|
||||
instance.web.Login = instance.web.Login.extend({
|
||||
start: function() {
|
||||
console.log('Hello there');
|
||||
return this._super.apply(this,arguments);
|
||||
}
|
||||
});
|
||||
|
||||
};
|
||||
|
||||
// vim:et fdc=0 fdl=0:
|
||||
|
||||
Reference in New Issue
Block a user