xlwt = None
import openerp
+import openerp.modules.registry
+from openerp.tools.translate import _
from .. import http
openerpweb = http
loadable = openerpweb.addons_manifest.keys()
modules = {}
try:
- import openerp.modules.registry
registry = openerp.modules.registry.RegistryManager.get(dbname)
with registry.cursor() as cr:
m = registry.get('ir.module.module')
return response.make_conditional(req.httprequest)
def login_and_redirect(req, db, login, key, redirect_url='/'):
- req.session.authenticate(db, login, key, {})
+ wsgienv = req.httprequest.environ
+ env = dict(
+ base_location=req.httprequest.url_root.rstrip('/'),
+ HTTP_HOST=wsgienv['HTTP_HOST'],
+ REMOTE_ADDR=wsgienv['REMOTE_ADDR'],
+ )
+ req.session.authenticate(db, login, key, env)
return set_cookie_and_redirect(req, redirect_url)
def set_cookie_and_redirect(req, redirect_url):
<body>
<!--[if lte IE 8]>
<script src="http://ajax.googleapis.com/ajax/libs/chrome-frame/1/CFInstall.min.js"></script>
- <script>
- var test = function() {
- CFInstall.check({
- mode: "overlay"
- });
- };
- if (window.localStorage && false) {
- if (! localStorage.getItem("hasShownGFramePopup")) {
- test();
- localStorage.setItem("hasShownGFramePopup", true);
- }
- } else {
- test();
- }
- </script>
+ <script>CFInstall.check({mode: "overlay"});</script>
<![endif]-->
</body>
</html>
def login(self, req, db, login, key):
return login_and_redirect(req, db, login, key)
+ @openerpweb.jsonrequest
+ def jsonrpc(self, req, service, method, args):
+ """ Method used by client APIs to contact OpenERP. """
+ return getattr(req.session.proxy(service), method)(*args)
+
class WebClient(openerpweb.Controller):
_cp_path = "/web/webclient"
messages = ir_translation.search_read([('module','in',mods),('lang','=',lang),
('comments','like','openerp-web'),('value','!=',False),
('value','!=','')],
- ['module','src','value','lang'], order='module')
+ ['module','src','value','lang'], order='module')
for mod, msg_group in itertools.groupby(messages, key=operator.itemgetter('module')):
translations_per_module.setdefault(mod,{'messages':[]})
translations_per_module[mod]['messages'].extend({'id': m['src'],
@openerpweb.jsonrequest
def version_info(self, req):
- return {
- "version": openerp.release.version
- }
+ return openerp.service.web_services.RPC_VERSION_1
class Proxy(openerpweb.Controller):
_cp_path = '/web/proxy'
except xmlrpclib.Fault, e:
if e.faultCode and e.faultCode.split(':')[0] == 'AccessDenied':
return {'error': e.faultCode, 'title': 'Drop Database'}
- return {'error': 'Could not drop database !', 'title': 'Drop Database'}
+ return {'error': _('Could not drop database !'), 'title': _('Drop Database')}
@openerpweb.httprequest
def backup(self, req, backup_db, backup_pwd, token):
{'fileToken': int(token)}
)
except xmlrpclib.Fault, e:
- return simplejson.dumps([[],[{'error': e.faultCode, 'title': 'backup Database'}]])
+ return simplejson.dumps([[],[{'error': e.faultCode, 'title': _('Backup Database')}]])
@openerpweb.httprequest
def restore(self, req, db_file, restore_pwd, new_db):
return req.session.proxy("db").change_admin_password(old_password, new_password)
except xmlrpclib.Fault, e:
if e.faultCode and e.faultCode.split(':')[0] == 'AccessDenied':
- return {'error': e.faultCode, 'title': 'Change Password'}
- return {'error': 'Error, password not changed !', 'title': 'Change Password'}
+ return {'error': e.faultCode, 'title': _('Change Password')}
+ return {'error': _('Error, password not changed !'), 'title': _('Change Password')}
class Session(openerpweb.Controller):
_cp_path = "/web/session"
return {
"session_id": req.session_id,
"uid": req.session._uid,
- "context": req.session.get_context() if req.session._uid else {},
+ "user_context": req.session.get_context() if req.session._uid else {},
"db": req.session._db,
- "login": req.session._login,
+ "username": req.session._login,
}
@openerpweb.jsonrequest
old_password, new_password,confirm_password = operator.itemgetter('old_pwd', 'new_password','confirm_pwd')(
dict(map(operator.itemgetter('name', 'value'), fields)))
if not (old_password.strip() and new_password.strip() and confirm_password.strip()):
- return {'error':'All passwords have to be filled.','title': 'Change Password'}
+ return {'error':_('You cannot leave any password empty.'),'title': _('Change Password')}
if new_password != confirm_password:
- return {'error': 'The new password and its confirmation must be identical.','title': 'Change Password'}
+ return {'error': _('The new password and its confirmation must be identical.'),'title': _('Change Password')}
try:
if req.session.model('res.users').change_password(
old_password, new_password):
return {'new_password':new_password}
except Exception:
- return {'error': 'Original password incorrect, your password was not changed.', 'title': 'Change Password'}
- return {'error': 'Error, password not changed !', 'title': 'Change Password'}
+ return {'error': _('The old password you provided is incorrect, your password was not changed.'), 'title': _('Change Password')}
+ return {'error': _('Error, password not changed !'), 'title': _('Change Password')}
@openerpweb.jsonrequest
def sc_list(self, req):
try:
return req.session.proxy("db").list_lang() or []
except Exception, e:
- return {"error": e, "title": "Languages"}
+ return {"error": e, "title": _("Languages")}
@openerpweb.jsonrequest
def modules(self, req):
_cp_path = "/web/menu"
@openerpweb.jsonrequest
- def load(self, req):
- return {'data': self.do_load(req)}
-
- @openerpweb.jsonrequest
def get_user_roots(self, req):
- return self.do_get_user_roots(req)
-
- def do_get_user_roots(self, req):
""" Return all root menu ids visible for the session user.
:param req: A request object, with an OpenERP session attribute
return Menus.search(menu_domain, 0, False, False, req.context)
- def do_load(self, req):
+ @openerpweb.jsonrequest
+ def load(self, req):
""" Loads all menu items (all applications and their sub-menus).
:param req: A request object, with an OpenERP session attribute
"""
Menus = req.session.model('ir.ui.menu')
- fields = ['name', 'sequence', 'parent_id', 'action',
- 'needaction_enabled', 'needaction_counter']
- menu_roots = Menus.read(self.do_get_user_roots(req), fields, req.context)
+ fields = ['name', 'sequence', 'parent_id', 'action']
+ menu_root_ids = self.get_user_roots(req)
+ menu_roots = Menus.read(menu_root_ids, fields, req.context) if menu_root_ids else []
menu_root = {
'id': False,
'name': 'root',
'parent_id': [-1, ''],
- 'children': menu_roots
+ 'children': menu_roots,
+ 'all_menu_ids': menu_root_ids,
}
+ if not menu_roots:
+ return menu_root
# 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, req.context)
+ menu_ids = Menus.search([('id', 'child_of', menu_root_ids)], 0, False, False, req.context)
menu_items = Menus.read(menu_ids, fields, req.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.
menu_items.extend(menu_roots)
+ menu_root['all_menu_ids'] = menu_ids # includes menu_root_ids!
# make a tree using parent_id
menu_items_map = dict(
return menu_root
@openerpweb.jsonrequest
+ def load_needaction(self, req, menu_ids):
+ """ Loads needaction counters for specific menu ids.
+
+ :return: needaction data
+ :rtype: dict(menu_id: {'needaction_enabled': boolean, 'needaction_counter': int})
+ """
+ return req.session.model('ir.ui.menu').get_needaction_data(menu_ids, req.context)
+
+ @openerpweb.jsonrequest
def action(self, req, menu_id):
+ # still used by web_shortcut
actions = load_actions_from_ir_values(req,'action', 'tree_but_open',
[('ir.ui.menu', menu_id)], False)
return {"action": actions}
def _call_kw(self, req, model, method, args, kwargs):
# Temporary implements future display_name special field for model#read()
- if method == 'read' and kwargs.get('context') and kwargs['context'].get('future_display_name'):
+ if method == 'read' and kwargs.get('context', {}).get('future_display_name'):
if 'display_name' in args[1]:
- names = req.session.model(model).name_get(args[0], **kwargs)
+ names = dict(req.session.model(model).name_get(args[0], **kwargs))
args[1].remove('display_name')
- r = getattr(req.session.model(model), method)(*args, **kwargs)
- for i in range(len(r)):
- r[i]['display_name'] = names[i][1] or "%s#%d" % (model, names[i][0])
- return r
+ records = req.session.model(model).read(*args, **kwargs)
+ for record in records:
+ record['display_name'] = \
+ names.get(record['id']) or "%s#%d" % (model, (record['id']))
+ return records
return getattr(req.session.model(model), method)(*args, **kwargs)
@openerpweb.jsonrequest
- def onchange(self, req, model, method, args, context_id=None):
- """ Support method for handling onchange calls: behaves much like call
- with the following differences:
-
- * Does not take a domain_id
- * Is aware of the return value's structure, and will parse the domains
- if needed in order to return either parsed literal domains (in JSON)
- or non-literal domain instances, allowing those domains to be used
- from JS
-
- :param req:
- :type req: web.common.http.JsonRequest
- :param str model: object type on which to call the method
- :param str method: name of the onchange handler method
- :param list args: arguments to call the onchange handler with
- :param int context_id: index of the context object in the list of
- arguments
- :return: result of the onchange call with all domains parsed
- """
- return self._call_kw(req, model, method, args, {})
-
- @openerpweb.jsonrequest
def call(self, req, model, method, args, domain_id=None, context_id=None):
return self._call_kw(req, model, method, args, {})
-
+
@openerpweb.jsonrequest
def call_kw(self, req, model, method, args, kwargs):
return self._call_kw(req, model, method, args, kwargs)
class View(openerpweb.Controller):
_cp_path = "/web/view"
- def fields_view_get(self, req, model, view_id, view_type,
- transform=True, toolbar=False, submenu=False):
- Model = req.session.model(model)
- fvg = Model.fields_view_get(view_id, view_type, req.context, toolbar, submenu)
- # todo fme?: check that we should pass the evaluated context here
- self.process_view(req.session, fvg, req.context, transform, (view_type == 'kanban'))
- return fvg
-
- def process_view(self, session, fvg, context, transform, preserve_whitespaces=False):
- # depending on how it feels, xmlrpclib.ServerProxy can translate
- # XML-RPC strings to ``str`` or ``unicode``. ElementTree does not
- # enjoy unicode strings which can not be trivially converted to
- # strings, and it blows up during parsing.
-
- # So ensure we fix this retardation by converting view xml back to
- # bit strings.
- if isinstance(fvg['arch'], unicode):
- arch = fvg['arch'].encode('utf-8')
- else:
- arch = fvg['arch']
- fvg['arch_string'] = arch
-
- fvg['arch'] = xml2json_from_elementtree(
- ElementTree.fromstring(arch), preserve_whitespaces)
-
- if 'id' in fvg['fields']:
- # Special case for id's
- id_field = fvg['fields']['id']
- id_field['original_type'] = id_field['type']
- id_field['type'] = 'id'
-
- for field in fvg['fields'].itervalues():
- for view in field.get("views", {}).itervalues():
- self.process_view(session, view, None, transform)
-
@openerpweb.jsonrequest
def add_custom(self, req, view_id, arch):
CustomView = req.session.model('ir.ui.view.custom')
return {'result': True}
return {'result': False}
- @openerpweb.jsonrequest
- def load(self, req, model, view_id, view_type, toolbar=False):
- return self.fields_view_get(req, model, view_id, view_type, toolbar=toolbar)
-
class TreeView(View):
_cp_path = "/web/treeview"
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 (TypeError, xmlrpclib.Fault):
except:
pass
return req.make_response(image_data, headers)
- def placeholder(self, req):
+
+ def placeholder(self, req, image='placeholder.png'):
addons_path = openerpweb.addons_manifest['web']['addons_path']
- return open(os.path.join(addons_path, 'web', 'static', 'src', 'img', 'placeholder.png'), 'rb').read()
+ return open(os.path.join(addons_path, 'web', 'static', 'src', 'img', image), 'rb').read()
@openerpweb.httprequest
def saveas(self, req, model, field, id=None, filename_field=None, **kw):
jdata = simplejson.loads(data)
model = jdata['model']
field = jdata['field']
+ data = jdata['data']
id = jdata.get('id', None)
filename_field = jdata.get('filename_field', None)
context = jdata.get('context', {})
fields = [field]
if filename_field:
fields.append(filename_field)
- if id:
+ if data:
+ res = { field: data }
+ elif id:
res = Model.read([int(id)], fields, context)[0]
else:
res = Model.default_get(fields, context)
filecontent = base64.b64decode(res.get(field, ''))
if not filecontent:
- raise ValueError("No content found for field '%s' on '%s:%s'" %
+ raise ValueError(_("No content found for field '%s' on '%s:%s'") %
(field, model, id))
else:
filename = '%s_%s' % (model.replace('.', '_'), id)
@openerpweb.httprequest
def upload(self, req, callback, ufile):
# TODO: might be useful to have a configuration flag for max-length file uploads
+ out = """<script language="javascript" type="text/javascript">
+ var win = window.top.window;
+ win.jQuery(win).trigger(%s, %s);
+ </script>"""
try:
- out = """<script language="javascript" type="text/javascript">
- var win = window.top.window;
- win.jQuery(win).trigger(%s, %s);
- </script>"""
data = ufile.read()
args = [len(data), ufile.filename,
ufile.content_type, base64.b64encode(data)]
@openerpweb.httprequest
def upload_attachment(self, req, callback, model, id, ufile):
Model = req.session.model('ir.attachment')
+ out = """<script language="javascript" type="text/javascript">
+ var win = window.top.window;
+ win.jQuery(win).trigger(%s, %s);
+ </script>"""
try:
- out = """<script language="javascript" type="text/javascript">
- var win = window.top.window;
- win.jQuery(win).trigger(%s, %s);
- </script>"""
attachment_id = Model.create({
'name': ufile.filename,
'datas': base64.encodestring(ufile.read()),
'filename': ufile.filename,
'id': attachment_id
}
- except Exception, e:
- args = { 'error': e.message }
+ except xmlrpclib.Fault, e:
+ args = {'error':e.faultCode }
return out % (simplejson.dumps(callback), simplejson.dumps(args))
+ @openerpweb.httprequest
+ def company_logo(self, req, dbname=None):
+ # TODO add etag, refactor to use /image code for etag
+ uid = None
+ if req.session._db:
+ dbname = req.session._db
+ uid = req.session._uid
+ elif dbname is None:
+ dbname = db_monodb(req)
+
+ if uid is None:
+ uid = openerp.SUPERUSER_ID
+
+ if not dbname:
+ image_data = self.placeholder(req, 'logo.png')
+ else:
+ registry = openerp.modules.registry.RegistryManager.get(dbname)
+ with registry.cursor() as cr:
+ user = registry.get('res.users').browse(cr, uid, uid)
+ if user.company_id.logo_web:
+ image_data = user.company_id.logo_web.decode('base64')
+ else:
+ image_data = self.placeholder(req, 'nologo.png')
+ headers = [
+ ('Content-Type', 'image/png'),
+ ('Content-Length', len(image_data)),
+ ]
+ return req.make_response(image_data, headers)
+
class Action(openerpweb.Controller):
_cp_path = "/web/action"
def fields_info(self, req, model, export_fields):
info = {}
fields = self.fields_get(req, model)
+ if ".id" in export_fields:
+ fields['.id'] = fields.pop('id', {'string': 'ID'})
# To make fields retrieval more efficient, fetch all sub-fields of a
# given field at the same time. Because the order in the export list is