# HG changeset patch # User Goffi # Date 1367791904 -7200 # Node ID 6fe7da6b4b32142a278a1694dbe37afe5889b601 # Parent e5b83fbb02194bdcda1b2ee2fa441f7496be73c4 node "roster" access model management diff -r e5b83fbb0219 -r 6fe7da6b4b32 sat_pubsub/backend.py --- a/sat_pubsub/backend.py Sun Apr 28 19:29:58 2013 +0200 +++ b/sat_pubsub/backend.py Mon May 06 00:11:44 2013 +0200 @@ -116,6 +116,19 @@ "never": "Never", "on_sub": "When a new subscription is processed"} }, + const.OPT_ACCESS_MODEL: + {"type": "list-single", + "label": "Who can subscribe to this node", + "options": { + const.VAL_AMODEL_OPEN: "Public node", + const.VAL_AMODEL_ROSTER: "Node restricted to some roster groups", + const.VAL_AMODEL_JID: "Node restricted to some jids", + } + }, + const.OPT_ROSTER_GROUPS_ALLOWED: + {"type": "list-multi", + "label": "Groups of the roster allowed to access the node", + }, } subscriptionOptions = { @@ -199,7 +212,7 @@ @param item: """ item_config = None - access_model = const.VAL_DEFAULT + access_model = const.VAL_AMODEL_DEFAULT for i in range(len(item.children)): elt = item.children[i] if not (elt.uri,elt.name)==(data_form.NS_X_DATA,'x'): @@ -211,7 +224,7 @@ break if item_config: - access_model = item_config.get(const.OPT_ACCESS_MODEL, const.VAL_DEFAULT) + access_model = item_config.get(const.OPT_ACCESS_MODEL, const.VAL_AMODEL_DEFAULT) return (access_model, item_config) @@ -381,10 +394,13 @@ return True - def createNode(self, nodeIdentifier, requestor): + def createNode(self, nodeIdentifier, requestor, options = None): if not nodeIdentifier: nodeIdentifier = 'generic/%s' % uuid.uuid4() + if not options: + options = {} + if self.supportsCreatorCheck(): groupblog = nodeIdentifier.startswith(const.NS_GROUPBLOG_PREFIX) try: @@ -402,6 +418,7 @@ nodeType = 'leaf' config = self.storage.getDefaultConfiguration(nodeType) config['pubsub#node_type'] = nodeType + config.update(options) d = self.storage.createNode(nodeIdentifier, requestor, config) d.addCallback(lambda _: nodeIdentifier) @@ -454,20 +471,20 @@ return d def checkGroup(self, roster_groups, entity): - """Check that requester is in roster + """Check that entity is authorized and in roster @param roster_group: tuple which 2 items: - roster: mapping of jid to RosterItem as given by self.roster.getRoster - groups: list of authorized groups @param entity: entity which must be in group - @return: True if requestor is in roster""" + @return: (True, roster) if entity is in roster and authorized + (False, roster) if entity is in roster but not authorized + @raise: error.NotInRoster if entity is not in roster""" roster, authorized_groups = roster_groups _entity = entity.userhostJID() if not _entity in roster: raise error.NotInRoster - if roster[_entity].groups.intersection(authorized_groups): - return (True, roster) - raise error.NotInRoster + return (roster[_entity].groups.intersection(authorized_groups), roster) def _getNodeGroups(self, roster, nodeIdentifier): d = self.storage.getNodeGroups(nodeIdentifier) @@ -481,16 +498,16 @@ ret = [] for data in items_data: item, access_model, access_list = data - if access_model == const.VAL_OPEN: + if access_model == const.VAL_AMODEL_OPEN: pass - elif access_model == const.VAL_ROSTER: + elif access_model == const.VAL_AMODEL_ROSTER: form = data_form.Form('submit', formNamespace=const.NS_ITEM_CONFIG) - access = data_form.Field(None, const.OPT_ACCESS_MODEL, value=const.VAL_ROSTER) + access = data_form.Field(None, const.OPT_ACCESS_MODEL, value=const.VAL_AMODEL_ROSTER) allowed = data_form.Field(None, const.OPT_ROSTER_GROUPS_ALLOWED, values=access_list) form.addField(access) form.addField(allowed) item.addChild(form.toElement()) - elif access_model == const.VAL_JID: + elif access_model == const.VAL_AMODEL_JID: #FIXME: manage jid raise NotImplementedError else: @@ -528,7 +545,7 @@ d.addCallback(self.roster.getRoster) if access_model == 'open' or affiliation == 'owner': - d.addCallback(lambda roster: (True,roster)) + d.addCallback(lambda roster: (True, roster)) d.addCallback(access_checked) elif access_model == 'roster': d.addCallback(self._getNodeGroups,node.nodeIdentifier) @@ -919,7 +936,7 @@ def create(self, request): d = self.backend.createNode(request.nodeIdentifier, - request.sender) + request.sender, request.options) return d.addErrback(self._mapErrors) diff -r e5b83fbb0219 -r 6fe7da6b4b32 sat_pubsub/const.py --- a/sat_pubsub/const.py Sun Apr 28 19:29:58 2013 +0200 +++ b/sat_pubsub/const.py Mon May 06 00:11:44 2013 +0200 @@ -57,7 +57,7 @@ NS_ITEM_CONFIG = "http://jabber.org/protocol/pubsub#item-config" OPT_ACCESS_MODEL = 'pubsub#access_model' OPT_ROSTER_GROUPS_ALLOWED = 'pubsub#roster_groups_allowed' -VAL_OPEN = 'open' -VAL_ROSTER = 'roster' -VAL_JID = 'jid' -VAL_DEFAULT = VAL_OPEN +VAL_AMODEL_OPEN = 'open' +VAL_AMODEL_ROSTER = 'roster' +VAL_AMODEL_JID = 'jid' +VAL_AMODEL_DEFAULT = VAL_AMODEL_OPEN diff -r e5b83fbb0219 -r 6fe7da6b4b32 sat_pubsub/pgsql_storage.py --- a/sat_pubsub/pgsql_storage.py Sun Apr 28 19:29:58 2013 +0200 +++ b/sat_pubsub/pgsql_storage.py Mon May 06 00:11:44 2013 +0200 @@ -73,12 +73,12 @@ "pubsub#persist_items": True, "pubsub#deliver_payloads": True, "pubsub#send_last_published_item": 'on_sub', - "pubsub#access_model": 'open', + const.OPT_ACCESS_MODEL: const.VAL_AMODEL_DEFAULT, }, 'collection': { "pubsub#deliver_payloads": True, "pubsub#send_last_published_item": 'on_sub', - "pubsub#access_model": 'open', + const.OPT_ACCESS_MODEL: const.VAL_AMODEL_DEFAULT, } } @@ -95,7 +95,7 @@ persist_items, deliver_payloads, send_last_published_item, - access_model + access_model, FROM nodes WHERE node=%s""", (nodeIdentifier,)) @@ -108,18 +108,18 @@ configuration = { 'pubsub#persist_items': row[1], 'pubsub#deliver_payloads': row[2], - 'pubsub#send_last_published_item': - row[3], - 'pubsub#access_model':row[4]} + 'pubsub#send_last_published_item': row[3], + const.OPT_ACCESS_MODEL:row[4], + } node = LeafNode(nodeIdentifier, configuration) node.dbpool = self.dbpool return node elif row[0] == 'collection': configuration = { 'pubsub#deliver_payloads': row[2], - 'pubsub#send_last_published_item': - row[3], - 'pubsub#access_model':row[4]} + 'pubsub#send_last_published_item': row[3], + const.OPT_ACCESS_MODEL: row[4], + } node = CollectionNode(nodeIdentifier, configuration) node.dbpool = self.dbpool return node @@ -152,11 +152,15 @@ config['pubsub#persist_items'], config['pubsub#deliver_payloads'], config['pubsub#send_last_published_item'], - config['pubsub#access_model']) + config[const.OPT_ACCESS_MODEL], + ) ) except cursor._pool.dbapi.IntegrityError: raise error.NodeExists() + cursor.execute("""SELECT node_id FROM nodes WHERE node=%s""", (nodeIdentifier,)); + node_id = cursor.fetchone()[0] + cursor.execute("""SELECT 1 from entities where jid=%s""", (owner,)) @@ -166,12 +170,21 @@ cursor.execute("""INSERT INTO affiliations (node_id, entity_id, affiliation) - SELECT node_id, entity_id, 'owner' FROM - (SELECT node_id FROM nodes WHERE node=%s) as n - CROSS JOIN + SELECT %s, entity_id, 'owner' FROM (SELECT entity_id FROM entities WHERE jid=%s) as e""", - (nodeIdentifier, owner)) + (node_id, owner)) + + #TODO: manage JID access + if config[const.OPT_ACCESS_MODEL] == const.VAL_AMODEL_ROSTER: + if const.OPT_ROSTER_GROUPS_ALLOWED in config: + allowed_groups = config[const.OPT_ROSTER_GROUPS_ALLOWED] + else: + allowed_groups = [] + for group in allowed_groups: + #TODO: check that group are actually in roster + cursor.execute("""INSERT INTO node_groups_authorized (node_id, groupname) + VALUES (%s,%s)""" , (node_id, group)) def deleteNode(self, nodeIdentifier): @@ -534,7 +547,7 @@ access_model, self.nodeIdentifier)) - if access_model == const.VAL_ROSTER: + if access_model == const.VAL_AMODEL_ROSTER: item_id = cursor.fetchone()[0]; if const.OPT_ROSTER_GROUPS_ALLOWED in item_config: item_config.fields[const.OPT_ROSTER_GROUPS_ALLOWED].fieldType='list-multi' #XXX: needed to force list if there is only one value