From 4a0d8be8eca60abd7b541806349d67079146c5d5 Mon Sep 17 00:00:00 2001 From: souliane Date: Fri, 27 Dec 2013 13:28:26 +0100 Subject: [PATCH] core, bridge: new method paramsRegisterApp to register frontend's specific parameters --- frontends/src/bridge/DBus.py | 15 +- frontends/src/constants.py | 6 +- frontends/src/primitivus/primitivus | 6 +- frontends/src/wix/main_window.py | 4 +- frontends/src/wix/param.py | 2 + src/bridge/DBus.py | 24 ++-- src/bridge/bridge.py | 2 +- .../bridge_constructor/bridge_template.ini | 42 ++++-- src/core/sat_main.py | 1 + src/memory/memory.py | 132 +++++++++++++++--- 10 files changed, 175 insertions(+), 59 deletions(-) diff --git a/frontends/src/bridge/DBus.py b/frontends/src/bridge/DBus.py index 4b1bbcee..8f10d2f1 100644 --- a/frontends/src/bridge/DBus.py +++ b/frontends/src/bridge/DBus.py @@ -152,17 +152,17 @@ class DBusBridgeFrontend(BridgeFrontend): def getParamA(self, name, category, attribute="value", profile_key="@DEFAULT@"): return unicode(self.db_core_iface.getParamA(name, category, attribute, profile_key)) - def getParams(self, security_limit=-1, profile_key="@DEFAULT@", callback=None, errback=None): - return unicode(self.db_core_iface.getParams(security_limit, profile_key, reply_handler=callback, error_handler=lambda err:errback(err._dbus_error_name[len(const_ERROR_PREFIX)+1:]))) + def getParams(self, security_limit=-1, app='', profile_key="@DEFAULT@", callback=None, errback=None): + return unicode(self.db_core_iface.getParams(security_limit, app, profile_key, reply_handler=callback, error_handler=lambda err:errback(err._dbus_error_name[len(const_ERROR_PREFIX)+1:]))) def getParamsCategories(self, ): return self.db_core_iface.getParamsCategories() - def getParamsForCategory(self, category, security_limit=-1, profile_key="@DEFAULT@", callback=None, errback=None): - return unicode(self.db_core_iface.getParamsForCategory(category, security_limit, profile_key, reply_handler=callback, error_handler=lambda err:errback(err._dbus_error_name[len(const_ERROR_PREFIX)+1:]))) + def getParamsForCategory(self, category, security_limit=-1, app='', profile_key="@DEFAULT@", callback=None, errback=None): + return unicode(self.db_core_iface.getParamsForCategory(category, security_limit, app, profile_key, reply_handler=callback, error_handler=lambda err:errback(err._dbus_error_name[len(const_ERROR_PREFIX)+1:]))) - def getParamsUI(self, security_limit=-1, profile_key="@DEFAULT@", callback=None, errback=None): - return unicode(self.db_core_iface.getParamsUI(security_limit, profile_key, reply_handler=callback, error_handler=lambda err:errback(err._dbus_error_name[len(const_ERROR_PREFIX)+1:]))) + def getParamsUI(self, security_limit=-1, app='', profile_key="@DEFAULT@", callback=None, errback=None): + return unicode(self.db_core_iface.getParamsUI(security_limit, app, profile_key, reply_handler=callback, error_handler=lambda err:errback(err._dbus_error_name[len(const_ERROR_PREFIX)+1:]))) def getPresenceStatus(self, profile_key="@DEFAULT@"): return self.db_core_iface.getPresenceStatus(profile_key) @@ -191,6 +191,9 @@ class DBusBridgeFrontend(BridgeFrontend): def launchAction(self, callback_id, data, profile_key="@DEFAULT@", callback=None, errback=None): return self.db_core_iface.launchAction(callback_id, data, profile_key, reply_handler=callback, error_handler=lambda err:errback(err._dbus_error_name[len(const_ERROR_PREFIX)+1:])) + def paramsRegisterApp(self, xml, security_limit=-1, app=''): + return self.db_core_iface.paramsRegisterApp(xml, security_limit, app) + def registerNewAccount(self, login, password, email, host, port=5222): return unicode(self.db_core_iface.registerNewAccount(login, password, email, host, port)) diff --git a/frontends/src/constants.py b/frontends/src/constants.py index d283bf47..0c5fb072 100644 --- a/frontends/src/constants.py +++ b/frontends/src/constants.py @@ -18,7 +18,7 @@ # along with this program. If not, see . -from sat.core.i18n import _ +from sat.core.i18n import _, D_ try: from collections import OrderedDict # only available from python 2.7 @@ -56,7 +56,7 @@ class Const(object): MENU_NORMAL = "NORMAL" # from plugin_misc_text_syntaxes - _SYNTAX_XHTML = "XHTML" - _SYNTAX_CURRENT = "@CURRENT@" + SYNTAX_XHTML = "XHTML" + SYNTAX_CURRENT = "@CURRENT@" NO_SECURITY_LIMIT = -1 diff --git a/frontends/src/primitivus/primitivus b/frontends/src/primitivus/primitivus index 9ac57820..f89feb8d 100755 --- a/frontends/src/primitivus/primitivus +++ b/frontends/src/primitivus/primitivus @@ -574,11 +574,11 @@ class PrimitivusApp(QuickApp, InputHistory): def onParam(self, menu): def success(params): - self.addWindow(XMLUI(self,xml_data=params)) + self.addWindow(XMLUI(self, xml_data=params)) + def failure(error): self.showPopUp(sat_widgets.Alert(_("Error"), _("Can't get parameters"), ok_cb=self.removePopUp)) - self.bridge.getParamsUI(profile_key=self.profile, callback=success, errback=failure) - + self.bridge.getParamsUI(app=Const.APP_NAME, profile_key=self.profile, callback=success, errback=failure) def onExitRequest(self, menu): QuickApp.onExit(self) diff --git a/frontends/src/wix/main_window.py b/frontends/src/wix/main_window.py index 639ee680..dbf421d5 100644 --- a/frontends/src/wix/main_window.py +++ b/frontends/src/wix/main_window.py @@ -407,9 +407,7 @@ class MainWindow(wx.Frame, QuickApp): def onParam(self, e): debug(_("Param request")) - #xmlui = self.bridge.getParamsUI(profile_key=self.profile) - #XMLUI(self, xml_data = xmlui) - param=Param(self) + param = Param(self) def onAbout(self, e): about = wx.AboutDialogInfo() diff --git a/frontends/src/wix/param.py b/frontends/src/wix/param.py index d5c80324..99f667a4 100644 --- a/frontends/src/wix/param.py +++ b/frontends/src/wix/param.py @@ -25,6 +25,7 @@ import pdb from xml.dom import minidom from logging import debug, info, error from sat.tools.jid import JID +from sat_frontends.wix.constants import Const class Param(wx.Frame): @@ -104,6 +105,7 @@ class Param(wx.Frame): cat_dom.unlink() self.host.bridge.getParamsForCategory(category, + app=Const.APP_NAME, profile_key=self.host.profile, callback=gotParams, errback=errorGettingParams) diff --git a/src/bridge/DBus.py b/src/bridge/DBus.py index 7c9b3969..6d183c25 100755 --- a/src/bridge/DBus.py +++ b/src/bridge/DBus.py @@ -300,10 +300,10 @@ class DbusObject(dbus.service.Object): return self._callback("getParamA", unicode(name), unicode(category), unicode(attribute), unicode(profile_key)) @dbus.service.method(const_INT_PREFIX+const_CORE_SUFFIX, - in_signature='is', out_signature='s', + in_signature='iss', out_signature='s', async_callbacks=('callback', 'errback')) - def getParams(self, security_limit=-1, profile_key="@DEFAULT@", callback=None, errback=None): - return self._callback("getParams", security_limit, unicode(profile_key), callback=callback, errback=errback) + def getParams(self, security_limit=-1, app='', profile_key="@DEFAULT@", callback=None, errback=None): + return self._callback("getParams", security_limit, unicode(app), unicode(profile_key), callback=callback, errback=errback) @dbus.service.method(const_INT_PREFIX+const_CORE_SUFFIX, in_signature='', out_signature='as', @@ -312,16 +312,16 @@ class DbusObject(dbus.service.Object): return self._callback("getParamsCategories", ) @dbus.service.method(const_INT_PREFIX+const_CORE_SUFFIX, - in_signature='sis', out_signature='s', + in_signature='siss', out_signature='s', async_callbacks=('callback', 'errback')) - def getParamsForCategory(self, category, security_limit=-1, profile_key="@DEFAULT@", callback=None, errback=None): - return self._callback("getParamsForCategory", unicode(category), security_limit, unicode(profile_key), callback=callback, errback=errback) + def getParamsForCategory(self, category, security_limit=-1, app='', profile_key="@DEFAULT@", callback=None, errback=None): + return self._callback("getParamsForCategory", unicode(category), security_limit, unicode(app), unicode(profile_key), callback=callback, errback=errback) @dbus.service.method(const_INT_PREFIX+const_CORE_SUFFIX, - in_signature='is', out_signature='s', + in_signature='iss', out_signature='s', async_callbacks=('callback', 'errback')) - def getParamsUI(self, security_limit=-1, profile_key="@DEFAULT@", callback=None, errback=None): - return self._callback("getParamsUI", security_limit, unicode(profile_key), callback=callback, errback=errback) + def getParamsUI(self, security_limit=-1, app='', profile_key="@DEFAULT@", callback=None, errback=None): + return self._callback("getParamsUI", security_limit, unicode(app), unicode(profile_key), callback=callback, errback=errback) @dbus.service.method(const_INT_PREFIX+const_CORE_SUFFIX, in_signature='s', out_signature='a{sa{s(sia{ss})}}', @@ -377,6 +377,12 @@ class DbusObject(dbus.service.Object): def launchAction(self, callback_id, data, profile_key="@DEFAULT@", callback=None, errback=None): return self._callback("launchAction", unicode(callback_id), data, unicode(profile_key), callback=callback, errback=errback) + @dbus.service.method(const_INT_PREFIX+const_CORE_SUFFIX, + in_signature='sis', out_signature='', + async_callbacks=None) + def paramsRegisterApp(self, xml, security_limit=-1, app=''): + return self._callback("paramsRegisterApp", unicode(xml), security_limit, unicode(app)) + @dbus.service.method(const_INT_PREFIX+const_CORE_SUFFIX, in_signature='ssssi', out_signature='s', async_callbacks=None) diff --git a/src/bridge/bridge.py b/src/bridge/bridge.py index bc00b2f1..5330d350 100755 --- a/src/bridge/bridge.py +++ b/src/bridge/bridge.py @@ -59,7 +59,7 @@ class Bridge(object): def getParam(self, name, namespace): raise NotImplementedError - def getParams(self, security_limit, namespace): + def getParams(self, security_limit, app, namespace): raise NotImplementedError def getHistory(self, from_jid, to_jid, size): diff --git a/src/bridge/bridge_constructor/bridge_template.ini b/src/bridge/bridge_constructor/bridge_template.ini index 1bf2f9eb..5dc934eb 100644 --- a/src/bridge/bridge_constructor/bridge_template.ini +++ b/src/bridge/bridge_constructor/bridge_template.ini @@ -447,38 +447,44 @@ doc_param_4=%(doc_profile_key)s async= type=method category=core -sig_in=is +sig_in=iss sig_out=s param_0_default=-1 -param_1_default="@DEFAULT@" -doc=Return a SàT XMLUI for parameters +param_1_default='' +param_2_default="@DEFAULT@" +doc=Return a SàT XMLUI for parameters, eventually restrict the result to the parameters concerning a given frontend doc_param_0=%(doc_security_limit)s -doc_param_1=%(doc_profile_key)s +doc_param_1=app: name of the frontend requesting the parameters, or '' to get all parameters +doc_param_2=%(doc_profile_key)s [getParams] async= type=method category=core -sig_in=is +sig_in=iss sig_out=s param_0_default=-1 -param_1_default="@DEFAULT@" -doc=Return XML of parameters +param_1_default='' +param_2_default="@DEFAULT@" +doc=Return XML of parameters, eventually restrict the result to the parameters concerning a given frontend doc_param_0=%(doc_security_limit)s -doc_param_1=%(doc_profile_key)s +doc_param_1=app: name of the frontend requesting the parameters, or '' to get all parameters +doc_param_2=%(doc_profile_key)s [getParamsForCategory] async= type=method category=core -sig_in=sis +sig_in=siss sig_out=s param_1_default=-1 -param_2_default="@DEFAULT@" -doc=Return a xml of all params in a category +param_2_default='' +param_3_default="@DEFAULT@" +doc=Return a xml of all params in a category, eventually restrict the result to the parameters concerning a given frontend doc_param_0=category: Category to get doc_param_1=%(doc_security_limit)s -doc_param_2=%(doc_profile_key)s +doc_param_2=app: name of the frontend requesting the parameters, or '' to get all parameters +doc_param_3=%(doc_profile_key)s [getParamsCategories] type=method @@ -488,6 +494,18 @@ sig_out=as doc=Get all categories currently existing in parameters doc_return=list of categories +[paramsRegisterApp] +type=method +category=core +sig_in=sis +sig_out= +param_1_default=-1 +param_2_default='' +doc=Register frontend's specific parameters +doc_param_0=xml: XML definition of the parameters to be added +doc_param_1=%(doc_security_limit)s +doc_param_2=app: name of the frontend registering the parameters + [getHistory] async= type=method diff --git a/src/core/sat_main.py b/src/core/sat_main.py index ed15dd92..f5da7d27 100644 --- a/src/core/sat_main.py +++ b/src/core/sat_main.py @@ -150,6 +150,7 @@ class SAT(service.Service): self.bridge.register("getParams", self.memory.getParams) self.bridge.register("getParamsForCategory", self.memory.getParamsForCategory) self.bridge.register("getParamsCategories", self.memory.getParamsCategories) + self.bridge.register("paramsRegisterApp", self.memory.paramsRegisterApp) self.bridge.register("getHistory", self.memory.getHistory) self.bridge.register("setPresence", self.setPresence) self.bridge.register("subscription", self.subscription) diff --git a/src/memory/memory.py b/src/memory/memory.py index 87785c19..402efbdb 100644 --- a/src/memory/memory.py +++ b/src/memory/memory.py @@ -295,10 +295,40 @@ class Params(object): #the node is new return None - def updateParams(self, xml): + def updateParams(self, xml, security_limit=NO_SECURITY_LIMIT, app=''): """import xml in parameters, do nothing if the param already exist - @param xml: parameters in xml form""" - src_dom = minidom.parseString(xml.encode('utf-8')) + If security_limit is specified and greater than -1, the parameters + that have a security level lower than security_limit are skipped. + @param xml: parameters in xml form + @param security_limit: -1 means no security then the higher the most secure + @param app: name of the frontend registering the parameters or empty value + """ + src_parent = minidom.parseString(xml.encode('utf-8')).documentElement + + def pre_process_app_node(src_parent, security_limit, app): + """Parameters that are registered from a frontend must be checked""" + to_remove = [] + for type_node in src_parent.childNodes: + if type_node.nodeName != INDIVIDUAL: + to_remove.append(type_node) # accept individual parameters only + continue + for cat_node in type_node.childNodes: + if cat_node.nodeName != 'category': + to_remove.append(cat_node) + continue + to_remove_count = 0 # count the params to be removed from current category + for node in cat_node.childNodes: + if node.nodeName != "param" or not self.checkSecurityLimit(node, security_limit): + to_remove.append(node) + to_remove_count += 1 + continue + node.setAttribute('app', app) + if len(cat_node.childNodes) == to_remove_count: # remove empty category + for dummy in xrange(0, to_remove_count): + to_remove.pop() + to_remove.append(cat_node) + for node in to_remove: + node.parentNode.removeChild(node) def import_node(tgt_parent, src_parent): for child in src_parent.childNodes: @@ -315,7 +345,28 @@ class Params(object): # the node already exists, we recurse 1 more level import_node(node, child) - import_node(self.dom.documentElement, src_dom.documentElement) + if app: + pre_process_app_node(src_parent, security_limit, app) + import_node(self.dom.documentElement, src_parent) + + def paramsRegisterApp(self, xml, security_limit, app): + """Register frontend's specific parameters + If security_limit is specified and greater than -1, the parameters + that have a security level lower than security_limit are skipped. + @param xml: XML definition of the parameters to be added + @param security_limit: -1 means no security then the higher the most secure + @param app: name of the frontend registering the parameters + """ + if not app: + warning(_("Trying to register frontends parameters with no specified app: aborted")) + return + if not hasattr(self, "frontends_cache"): + self.frontends_cache = {} + if app in self.frontends_cache: + warning(_("Trying to register twice frontends parameters for %(app)s: aborted" % {"app": app})) + return + self.updateParams(xml, security_limit, app) + debug("Frontends parameters registered for %(app)s" % {'app': app}) def __default_ok(self, value, name, category): #FIXME: will not work with individual parameters @@ -471,12 +522,13 @@ class Params(object): return None return cache[(category, name)] - def __constructProfileXml(self, security_limit, profile): + def __constructProfileXml(self, security_limit, app, profile): """Construct xml for asked profile, filling values when needed /!\ as noticed in doc, don't forget to unlink the minidom.Document - @security_limit: NO_SECURITY_LIMIT (-1) to return all the params. + @param security_limit: NO_SECURITY_LIMIT (-1) to return all the params. Otherwise sole the params which have a security level defined *and* lower or equal to the specified value are returned. + @param app: name of the frontend requesting the parameters, or '' to get all parameters @param profile: profile name (not key !) @return: a deferred that fire a minidom.Document of the profile xml (cf warning above) """ @@ -518,6 +570,8 @@ class Params(object): name = param_node.getAttribute('name') if not self.checkSecurityLimit(param_node, security_limit): continue + if not self.checkApp(param_node, app): + continue if name not in dest_params: # this is reached when a previous category exists dest_params[name] = param_node.cloneNode(True) @@ -551,18 +605,31 @@ class Params(object): return d.addCallback(constructProfile, profile_cache) - def getParamsUI(self, security_limit, profile_key): - """Return a SàT XMLUI for parameters, with given profile""" + def getParamsUI(self, security_limit, app, profile_key): + """ + @param security_limit: NO_SECURITY_LIMIT (-1) to return all the params. + Otherwise sole the params which have a security level defined *and* + lower or equal to the specified value are returned. + @param app: name of the frontend requesting the parameters, or '' to get all parameters + @param profile_key: Profile key which can be either a magic (eg: @DEFAULT@) or the name of an existing profile. + @return: a SàT XMLUI for parameters + """ profile = self.getProfileName(profile_key) if not profile: error(_("Asking params for inexistant profile")) return "" - d = self.getParams(security_limit, profile) + d = self.getParams(security_limit, app, profile) return d.addCallback(lambda param_xml: paramsXml2xmlUI(param_xml)) - def getParams(self, security_limit, profile_key): - """Construct xml for asked profile - Take params xml as skeleton""" + def getParams(self, security_limit, app, profile_key): + """Construct xml for asked profile, take params xml as skeleton + @param security_limit: NO_SECURITY_LIMIT (-1) to return all the params. + Otherwise sole the params which have a security level defined *and* + lower or equal to the specified value are returned. + @param app: name of the frontend requesting the parameters, or '' to get all parameters + @param profile_key: Profile key which can be either a magic (eg: @DEFAULT@) or the name of an existing profile. + @return: XML of parameters + """ profile = self.getProfileName(profile_key) if not profile: error(_("Asking params for inexistant profile")) @@ -573,10 +640,18 @@ class Params(object): prof_xml.unlink() return '\n'.join((line for line in return_xml.split('\n') if line)) - return self.__constructProfileXml(security_limit, profile).addCallback(returnXML) + return self.__constructProfileXml(security_limit, app, profile).addCallback(returnXML) - def getParamsForCategory(self, category, security_limit, profile_key): - """Return node's xml for selected category""" + def getParamsForCategory(self, category, security_limit, app, profile_key): + """ + @param category: the desired category + @param security_limit: NO_SECURITY_LIMIT (-1) to return all the params. + Otherwise sole the params which have a security level defined *and* + lower or equal to the specified value are returned. + @param app: name of the frontend requesting the parameters, or '' to get all parameters + @param profile_key: Profile key which can be either a magic (eg: @DEFAULT@) or the name of an existing profile. + @return: node's xml for selected category + """ #TODO: manage category of general type (without existant profile) profile = self.getProfileName(profile_key) if not profile: @@ -593,7 +668,7 @@ class Params(object): prof_xml.unlink() return "" - d = self.__constructProfileXml(security_limit, profile) + d = self.__constructProfileXml(security_limit, app, profile) return d.addCallback(returnCategoryXml) def _getParamNode(self, name, category, type_="@ALL@"): # FIXME: is type_ useful ? @@ -680,6 +755,16 @@ class Params(object): return True return False + def checkApp(self, node, app): + """Check the given node against the given app. + @param node: parameter node + @param app: name of the frontend requesting the parameters, or '' to get all parameters + @return: True if this node concerns the given app. + """ + if not app or not node.hasAttribute("app"): + return True + return node.getAttribute("app") == app + class Memory(object): """This class manage all persistent informations""" @@ -1063,14 +1148,14 @@ class Memory(object): def asyncGetStringParamA(self, name, category, attr="value", security_limit=NO_SECURITY_LIMIT, profile_key='@NONE@'): return self.params.asyncGetStringParamA(name, category, attr, security_limit, profile_key) - def getParamsUI(self, security_limit=NO_SECURITY_LIMIT, profile_key='@NONE@'): - return self.params.getParamsUI(security_limit, profile_key) + def getParamsUI(self, security_limit=NO_SECURITY_LIMIT, app='', profile_key='@NONE@'): + return self.params.getParamsUI(security_limit, app, profile_key) - def getParams(self, security_limit=NO_SECURITY_LIMIT, profile_key='@NONE@'): - return self.params.getParams(security_limit, profile_key) + def getParams(self, security_limit=NO_SECURITY_LIMIT, app='', profile_key='@NONE@'): + return self.params.getParams(security_limit, app, profile_key) - def getParamsForCategory(self, category, security_limit=NO_SECURITY_LIMIT, profile_key='@NONE@'): - return self.params.getParamsForCategory(category, security_limit, profile_key) + def getParamsForCategory(self, category, security_limit=NO_SECURITY_LIMIT, app='', profile_key='@NONE@'): + return self.params.getParamsForCategory(category, security_limit, app, profile_key) def getParamsCategories(self): return self.params.getParamsCategories() @@ -1081,5 +1166,8 @@ class Memory(object): def updateParams(self, xml): return self.params.updateParams(xml) + def paramsRegisterApp(self, xml, security_limit=NO_SECURITY_LIMIT, app=''): + return self.params.paramsRegisterApp(xml, security_limit, app) + def setDefault(self, name, category, callback, errback=None): return self.params.setDefault(name, category, callback, errback)