summaryrefslogtreecommitdiff
path: root/addons/web/controllers/main.py
diff options
context:
space:
mode:
authorXavier Morel <xmo@openerp.com>2012-03-22 15:33:31 +0100
committerXavier Morel <xmo@openerp.com>2012-03-22 15:33:31 +0100
commit7353e02e2ef4a403d4b79c1b157f2ca00b77d2fc (patch)
treea319552e3664ea272fdfb8abf31c961bcd5e1e6e /addons/web/controllers/main.py
parent514c63288c7d5d88d764b44696c5e3a5fc148dfb (diff)
parent1da49a44a57aa413e5eb96afe9c6d294e09848fd (diff)
[MERGE] from trunk
bzr revid: xmo@openerp.com-20120322143331-iajlifomw1hohbht
Diffstat (limited to 'addons/web/controllers/main.py')
-rw-r--r--addons/web/controllers/main.py181
1 files changed, 141 insertions, 40 deletions
diff --git a/addons/web/controllers/main.py b/addons/web/controllers/main.py
index 6a143d58231..e074445187c 100644
--- a/addons/web/controllers/main.py
+++ b/addons/web/controllers/main.py
@@ -98,19 +98,72 @@ html_template = """<!DOCTYPE html>
<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" />
%(css)s
%(js)s
<script type="text/javascript">
$(function() {
var s = new openerp.init(%(modules)s);
- %(init)s
+ var wc = new s.web.WebClient();
+ wc.appendTo($(document.body));
});
</script>
</head>
- <body class="openerp" id="oe"></body>
+ <body></body>
</html>
"""
+def sass2scss(src):
+ # Validated by diff -u of sass2scss against:
+ # sass-convert -F sass -T scss openerp.sass openerp.scss
+ block = []
+ sass = ('', block)
+ reComment = re.compile(r'//.*$')
+ reIndent = re.compile(r'^\s+')
+ reIgnore = re.compile(r'^\s*(//.*)?$')
+ reFixes = { re.compile(r'\(\((.*)\)\)') : r'(\1)', }
+ lastLevel = 0
+ prevBlocks = {}
+ for l in src.split('\n'):
+ l = l.rstrip()
+ if reIgnore.search(l): continue
+ l = reComment.sub('', l)
+ l = l.rstrip()
+ indent = reIndent.match(l)
+ level = indent.end() if indent else 0
+ l = l[level:]
+ if level>lastLevel:
+ prevBlocks[lastLevel] = block
+ newBlock = []
+ block[-1] = (block[-1], newBlock)
+ block = newBlock
+ elif level<lastLevel:
+ block = prevBlocks[level]
+ lastLevel = level
+ if not l: continue
+ # Fixes
+ for ereg, repl in reFixes.items():
+ l = ereg.sub(repl if type(repl)==str else repl(), l)
+ block.append(l)
+
+ def write(sass, level=-1):
+ out = ""
+ indent = ' '*level
+ if type(sass)==tuple:
+ if level>=0:
+ out += indent+sass[0]+" {\n"
+ for e in sass[1]:
+ out += write(e, level+1)
+ if level>=0:
+ out = out.rstrip(" \n")
+ out += ' }\n'
+ if level==0:
+ out += "\n"
+ else:
+ out += indent+sass+";\n"
+ return out
+ return write(sass)
+
class WebClient(openerpweb.Controller):
_cp_path = "/web/webclient"
@@ -270,7 +323,6 @@ class WebClient(openerpweb.Controller):
'js': js,
'css': css,
'modules': simplejson.dumps(self.server_wide_modules(req)),
- 'init': 'new s.web.WebClient().start();',
}
return r
@@ -351,19 +403,14 @@ class Database(openerpweb.Controller):
def get_list(self, req):
proxy = req.session.proxy("db")
dbs = proxy.list()
- h = req.httprequest.headers['Host'].split(':')[0]
+ h = req.httprequest.environ['HTTP_HOST'].split(':')[0]
d = h.split('.')[0]
r = req.config.dbfilter.replace('%h', h).replace('%d', d)
dbs = [i for i in dbs if re.match(r, i)]
return {"db_list": dbs}
@openerpweb.jsonrequest
- def progress(self, req, password, id):
- return req.session.proxy('db').get_progress(password, id)
-
- @openerpweb.jsonrequest
def create(self, req, fields):
-
params = dict(map(operator.itemgetter('name', 'value'), fields))
create_attrs = (
params['super_admin_pwd'],
@@ -373,17 +420,7 @@ class Database(openerpweb.Controller):
params['create_admin_pwd']
)
- try:
- return req.session.proxy("db").create(*create_attrs)
- except xmlrpclib.Fault, e:
- if e.faultCode and isinstance(e.faultCode, str)\
- and e.faultCode.split(':')[0] == 'AccessDenied':
- return {'error': e.faultCode, 'title': 'Database creation error'}
- return {
- 'error': "Could not create database '%s': %s" % (
- params['db_name'], e.faultString),
- 'title': 'Database creation error'
- }
+ return req.session.proxy("db").create_database(*create_attrs)
@openerpweb.jsonrequest
def drop(self, req, fields):
@@ -435,6 +472,50 @@ class Database(openerpweb.Controller):
return {'error': e.faultCode, 'title': 'Change Password'}
return {'error': 'Error, password not changed !', 'title': 'Change Password'}
+def topological_sort(modules):
+ """ Return a list of module names sorted so that their dependencies of the
+ modules are listed before the module itself
+
+ modules is a dict of {module_name: dependencies}
+
+ :param modules: modules to sort
+ :type modules: dict
+ :returns: list(str)
+ """
+
+ dependencies = set(itertools.chain.from_iterable(modules.itervalues()))
+ # incoming edge: dependency on other module (if a depends on b, a has an
+ # incoming edge from b, aka there's an edge from b to a)
+ # outgoing edge: other module depending on this one
+
+ # [Tarjan 1976], http://en.wikipedia.org/wiki/Topological_sorting#Algorithms
+ #L ← Empty list that will contain the sorted nodes
+ L = []
+ #S ← Set of all nodes with no outgoing edges (modules on which no other
+ # module depends)
+ S = set(module for module in modules if module not in dependencies)
+
+ visited = set()
+ #function visit(node n)
+ def visit(n):
+ #if n has not been visited yet then
+ if n not in visited:
+ #mark n as visited
+ visited.add(n)
+ #change: n not web module, can not be resolved, ignore
+ if n not in modules: return
+ #for each node m with an edge from m to n do (dependencies of n)
+ for m in modules[n]:
+ #visit(m)
+ visit(m)
+ #add n to L
+ L.append(n)
+ #for each node n in S do
+ for n in S:
+ #visit(n)
+ visit(n)
+ return L
+
class Session(openerpweb.Controller):
_cp_path = "/web/session"
@@ -502,20 +583,32 @@ class Session(openerpweb.Controller):
def modules(self, req):
# Compute available candidates module
loadable = openerpweb.addons_manifest
- loaded = req.config.server_wide_modules
+ loaded = set(req.config.server_wide_modules)
candidates = [mod for mod in loadable if mod not in loaded]
- # Compute active true modules that might be on the web side only
- active = set(name for name in candidates
- if openerpweb.addons_manifest[name].get('active'))
+ # already installed modules have no dependencies
+ modules = dict.fromkeys(loaded, [])
+
+ # Compute auto_install modules that might be on the web side only
+ modules.update((name, openerpweb.addons_manifest[name].get('depends', []))
+ for name in candidates
+ if openerpweb.addons_manifest[name].get('auto_install'))
# Retrieve database installed modules
Modules = req.session.model('ir.module.module')
- installed = set(module['name'] for module in Modules.search_read(
- [('state','=','installed'), ('name','in', candidates)], ['name']))
-
- # Merge both
- return list(active | installed)
+ for module in Modules.search_read(
+ [('state','=','installed'), ('name','in', candidates)],
+ ['name', 'dependencies_id']):
+ deps = module.get('dependencies_id')
+ if deps:
+ dependencies = map(
+ operator.itemgetter('name'),
+ req.session.model('ir.module.module.dependency').read(deps, ['name']))
+ modules[module['name']] = list(
+ set(modules.get(module['name'], []) + dependencies))
+
+ sorted_modules = topological_sort(modules)
+ return [module for module in sorted_modules if module not in loaded]
@openerpweb.jsonrequest
def eval_domain_and_context(self, req, contexts, domains,
@@ -762,11 +855,13 @@ class Menu(openerpweb.Controller):
Menus = s.model('ir.ui.menu')
# If a menu action is defined use its domain to get the root menu items
user_menu_id = s.model('res.users').read([s._uid], ['menu_id'], context)[0]['menu_id']
+
+ menu_domain = [('parent_id', '=', False)]
if user_menu_id:
- menu_domain = s.model('ir.actions.act_window').read([user_menu_id[0]], ['domain'], context)[0]['domain']
- menu_domain = ast.literal_eval(menu_domain)
- else:
- menu_domain = [('parent_id', '=', False)]
+ domain_string = s.model('ir.actions.act_window').read([user_menu_id[0]], ['domain'], context)[0]['domain']
+ if domain_string:
+ menu_domain = ast.literal_eval(domain_string)
+
return Menus.search(menu_domain, 0, False, False, context)
def do_load(self, req):
@@ -780,13 +875,13 @@ class Menu(openerpweb.Controller):
context = req.session.eval_context(req.context)
Menus = req.session.model('ir.ui.menu')
- menu_roots = Menus.read(self.do_get_user_roots(req), ['name', 'sequence', 'parent_id'], context)
+ menu_roots = Menus.read(self.do_get_user_roots(req), ['name', 'sequence', 'parent_id', 'action'], context)
menu_root = {'id': False, 'name': 'root', 'parent_id': [-1, ''], 'children' : menu_roots}
# menus are loaded fully unlike a regular tree view, cause there are a
# limited number of items (752 when all 6.1 addons are installed)
menu_ids = Menus.search([], 0, False, False, context)
- menu_items = Menus.read(menu_ids, ['name', 'sequence', 'parent_id'], context)
+ menu_items = Menus.read(menu_ids, ['name', 'sequence', 'parent_id', 'action'], context)
# adds roots at the end of the sequence, so that they will overwrite
# equivalent menu items from full menu read when put into id:item
# mapping, resulting in children being correctly set on the roots.
@@ -1179,10 +1274,15 @@ class SearchView(View):
filters = Model.get_filters(model)
for filter in filters:
try:
- filter["context"] = req.session.eval_context(
- parse_context(filter["context"], req.session))
- filter["domain"] = req.session.eval_domain(
- parse_domain(filter["domain"], req.session))
+ parsed_context = parse_context(filter["context"], req.session)
+ filter["context"] = (parsed_context
+ if not isinstance(parsed_context, common.nonliterals.BaseContext)
+ else req.session.eval_context(parsed_context))
+
+ parsed_domain = parse_domain(filter["domain"], req.session)
+ filter["domain"] = (parsed_domain
+ if not isinstance(parsed_domain, common.nonliterals.BaseDomain)
+ else req.session.eval_domain(parsed_domain))
except Exception:
logger.exception("Failed to parse custom filter %s in %s",
filter['name'], model)
@@ -1215,6 +1315,7 @@ class SearchView(View):
ctx = common.nonliterals.CompoundContext(context_to_save)
ctx.session = req.session
ctx = ctx.evaluate()
+ ctx['dashboard_merge_domains_contexts'] = False # TODO: replace this 6.1 workaround by attribute on <action/>
domain = common.nonliterals.CompoundDomain(domain)
domain.session = req.session
domain = domain.evaluate()
@@ -1230,7 +1331,7 @@ class SearchView(View):
if board and 'arch' in board:
xml = ElementTree.fromstring(board['arch'])
column = xml.find('./board/column')
- if column:
+ if column is not None:
new_action = ElementTree.Element('action', {
'name' : str(action_id),
'string' : name,