From: Stephen Soltesz Date: Tue, 1 Dec 2009 17:08:37 +0000 (+0000) Subject: Add PersonTags as well. Performed a simple test but not extensive regression X-Git-Tag: PLCAPI-4.3-31~7 X-Git-Url: http://git.onelab.eu/?p=plcapi.git;a=commitdiff_plain;h=5d2859509faf449daf088d98ae5e737c6c096d69 Add PersonTags as well. Performed a simple test but not extensive regression tests (i.e. by non-admin users, etc) --- diff --git a/PLC/Methods/AddPersonTag.py b/PLC/Methods/AddPersonTag.py new file mode 100644 index 0000000..6824657 --- /dev/null +++ b/PLC/Methods/AddPersonTag.py @@ -0,0 +1,86 @@ +# $Id: AddPersonTag.py 14587 2009-07-19 13:18:50Z thierry $ +# $URL: http://svn.planet-lab.org/svn/PLCAPI/tags/PLCAPI-4.3-27/PLC/Methods/AddPersonTag.py $ +# +# Thierry Parmentelat - INRIA +# +# $Revision: 14587 $ +# +from PLC.Faults import * +from PLC.Method import Method +from PLC.Parameter import Parameter, Mixed +from PLC.Auth import Auth + +from PLC.TagTypes import TagType, TagTypes +from PLC.PersonTags import PersonTag, PersonTags +from PLC.Persons import Person, Persons + +from PLC.Nodes import Nodes + +class AddPersonTag(Method): + """ + Sets the specified setting for the specified person + to the specified value. + + In general only tech(s), PI(s) and of course admin(s) are allowed to + do the change, but this is defined in the tag type object. + + Returns the new person_tag_id (> 0) if successful, faults + otherwise. + """ + + roles = ['admin', 'pi', 'tech', 'user'] + + accepts = [ + Auth(), + # no other way to refer to a person + PersonTag.fields['person_id'], + Mixed(TagType.fields['tag_type_id'], + TagType.fields['tagname']), + PersonTag.fields['value'], + ] + + returns = Parameter(int, 'New person_tag_id (> 0) if successful') + + object_type = 'Person' + + + def call(self, auth, person_id, tag_type_id_or_name, value): + persons = Persons(self.api, [person_id]) + if not persons: + raise PLCInvalidArgument, "No such person %r"%person_id + person = persons[0] + + tag_types = TagTypes(self.api, [tag_type_id_or_name]) + if not tag_types: + raise PLCInvalidArgument, "No such tag type %r"%tag_type_id_or_name + tag_type = tag_types[0] + + # checks for existence - does not allow several different settings + conflicts = PersonTags(self.api, + {'person_id':person['person_id'], + 'tag_type_id':tag_type['tag_type_id']}) + + if len(conflicts) : + raise PLCInvalidArgument, "Person %d already has setting %d"%(person['person_id'], + tag_type['tag_type_id']) + + # check permission : it not admin, is the user affiliated with the same site as this person + if 'admin' not in self.caller['roles']: + # check caller is affiliated with at least one of Person's sites + if len(set(person['site_ids']) & set(self.caller['site_ids'])) == 0: + raise PLCPermissionDenied, "Not a member of the person's sites: %s"%person['site_ids'] + + required_min_role = tag_type ['min_role_id'] + if required_min_role is not None and \ + min(self.caller['role_ids']) > required_min_role: + raise PLCPermissionDenied, "Not allowed to modify the specified person setting, requires role %d",required_min_role + + person_tag = PersonTag(self.api) + person_tag['person_id'] = person['person_id'] + person_tag['tag_type_id'] = tag_type['tag_type_id'] + person_tag['value'] = value + + person_tag.sync() + self.object_ids = [person_tag['person_tag_id']] + + return person_tag['person_tag_id'] diff --git a/PLC/Methods/DeletePersonTag.py b/PLC/Methods/DeletePersonTag.py new file mode 100644 index 0000000..51a1432 --- /dev/null +++ b/PLC/Methods/DeletePersonTag.py @@ -0,0 +1,71 @@ +# $Id: DeletePersonTag.py 14587 2009-07-19 13:18:50Z thierry $ +# $URL: http://svn.planet-lab.org/svn/PLCAPI/tags/PLCAPI-4.3-27/PLC/Methods/DeletePersonTag.py $ +# +# Thierry Parmentelat - INRIA +# +# $Revision: 14587 $ +# + +from PLC.Faults import * +from PLC.Method import Method +from PLC.Parameter import Parameter, Mixed +from PLC.Auth import Auth + +from PLC.PersonTags import PersonTag, PersonTags +from PLC.Persons import Person, Persons + +from PLC.Nodes import Node, Nodes +from PLC.Persons import Person, Persons + +class DeletePersonTag(Method): + """ + Deletes the specified person setting + + Attributes may require the caller to have a particular role in order + to be deleted, depending on the related tag type. + Admins may delete attributes of any slice or sliver. + + Returns 1 if successful, faults otherwise. + """ + + roles = ['admin', 'pi', 'user'] + + accepts = [ + Auth(), + PersonTag.fields['person_tag_id'] + ] + + returns = Parameter(int, '1 if successful') + + object_type = 'Person' + + + def call(self, auth, person_tag_id): + person_tags = PersonTags(self.api, [person_tag_id]) + if not person_tags: + raise PLCInvalidArgument, "No such person tag %r"%person_tag_id + person_tag = person_tags[0] + + ### reproducing a check from UpdateSliceTag, looks dumb though + persons = Persons(self.api, [person_tag['person_id']]) + if not persons: + raise PLCInvalidArgument, "No such person %r"%person_tag['person_id'] + person = persons[0] + + assert person_tag['person_tag_id'] in person['person_tag_ids'] + + # check permission : it not admin, is the user affiliated with the right person + if 'admin' not in self.caller['roles']: + # check caller is affiliated with this person's site + if len(set(person['site_ids']) & set(self.caller['site_ids'])) == 0: + raise PLCPermissionDenied, "Not a member of the person's sites: %s"%person['site_ids'] + + required_min_role = tag_type ['min_role_id'] + if required_min_role is not None and \ + min(self.caller['role_ids']) > required_min_role: + raise PLCPermissionDenied, "Not allowed to modify the specified person setting, requires role %d",required_min_role + + person_tag.delete() + self.object_ids = [person_tag['person_tag_id']] + + return 1 diff --git a/PLC/Methods/GetPersonTags.py b/PLC/Methods/GetPersonTags.py new file mode 100644 index 0000000..516638f --- /dev/null +++ b/PLC/Methods/GetPersonTags.py @@ -0,0 +1,44 @@ +# $Id: GetPersonTags.py 14587 2009-07-19 13:18:50Z thierry $ +# $URL: http://svn.planet-lab.org/svn/PLCAPI/tags/PLCAPI-4.3-27/PLC/Methods/GetPersonTags.py $ +# +# Thierry Parmentelat - INRIA +# +# $Revision: 14587 $ +# +from PLC.Faults import * +from PLC.Method import Method +from PLC.Parameter import Parameter, Mixed +from PLC.Filter import Filter +from PLC.Auth import Auth + +from PLC.PersonTags import PersonTag, PersonTags + +class GetPersonTags(Method): + """ + Returns an array of structs containing details about + persons and related settings. + + If person_tag_filter is specified and is an array of + person setting identifiers, only person settings matching + the filter will be returned. If return_fields is specified, only + the specified details will be returned. + """ + + roles = ['admin', 'pi', 'user', 'node'] + + accepts = [ + Auth(), + Mixed([PersonTag.fields['person_tag_id']], + Parameter(int,"Person setting id"), + Filter(PersonTag.fields)), + Parameter([str], "List of fields to return", nullok = True) + ] + + returns = [PersonTag.fields] + + + def call(self, auth, person_tag_filter = None, return_fields = None): + + person_tags = PersonTags(self.api, person_tag_filter, return_fields) + + return person_tags diff --git a/PLC/Methods/UpdatePersonTag.py b/PLC/Methods/UpdatePersonTag.py new file mode 100644 index 0000000..928b54f --- /dev/null +++ b/PLC/Methods/UpdatePersonTag.py @@ -0,0 +1,68 @@ +# $Id: UpdatePersonTag.py 14587 2009-07-19 13:18:50Z thierry $ +# $URL: http://svn.planet-lab.org/svn/PLCAPI/tags/PLCAPI-4.3-27/PLC/Methods/UpdatePersonTag.py $ +# +# $Revision: 14587 $ +# + +from PLC.Faults import * +from PLC.Method import Method +from PLC.Parameter import Parameter, Mixed +from PLC.Auth import Auth + +from PLC.PersonTags import PersonTag, PersonTags +from PLC.Persons import Person, Persons + +from PLC.Nodes import Nodes +from PLC.Persons import Persons + +class UpdatePersonTag(Method): + """ + Updates the value of an existing person setting + + Access rights depend on the tag type. + + Returns 1 if successful, faults otherwise. + """ + + roles = ['admin', 'pi', 'tech', 'user'] + + accepts = [ + Auth(), + PersonTag.fields['person_tag_id'], + PersonTag.fields['value'] + ] + + returns = Parameter(int, '1 if successful') + + object_type = 'Person' + + def call(self, auth, person_tag_id, value): + person_tags = PersonTags(self.api, [person_tag_id]) + if not person_tags: + raise PLCInvalidArgument, "No such person setting %r"%person_tag_id + person_tag = person_tags[0] + + ### reproducing a check from UpdateSliceTag, looks dumb though + persons = Persons(self.api, [person_tag['person_id']]) + if not persons: + raise PLCInvalidArgument, "No such person %r"%person_tag['person_id'] + person = persons[0] + + assert person_tag['person_tag_id'] in person['person_tag_ids'] + + # check permission : it not admin, is the user affiliated with the right person + if 'admin' not in self.caller['roles']: + # check caller is affiliated with this person's person + if len(set(person['person_ids']) & set(self.caller['person_ids'])) == 0: + raise PLCPermissionDenied, "Not a member of the person's persons: %s"%person['person_ids'] + + required_min_role = tag_type ['min_role_id'] + if required_min_role is not None and \ + min(self.caller['role_ids']) > required_min_role: + raise PLCPermissionDenied, "Not allowed to modify the specified person setting, requires role %d",required_min_role + + person_tag['value'] = value + person_tag.sync() + + self.object_ids = [person_tag['person_tag_id']] + return 1 diff --git a/PLC/Methods/__init__.py b/PLC/Methods/__init__.py index 50c1dea..52fb070 100644 --- a/PLC/Methods/__init__.py +++ b/PLC/Methods/__init__.py @@ -25,6 +25,7 @@ AddPCUType AddPeer AddPerson AddPersonKey +AddPersonTag AddPersonToSite AddPersonToSlice AddRole @@ -75,6 +76,7 @@ DeletePeer DeletePerson DeletePersonFromSite DeletePersonFromSlice +DeletePersonTag DeleteRole DeleteRoleFromPerson DeleteSession @@ -113,6 +115,7 @@ GetPCUs GetPeerData GetPeerName GetPeers +GetPersonTags GetPersons GetPlcRelease GetRoles @@ -172,6 +175,7 @@ UpdatePCUProtocolType UpdatePCUType UpdatePeer UpdatePerson +UpdatePersonTag UpdateSite UpdateSiteTag UpdateSlice diff --git a/PLC/PersonTags.py b/PLC/PersonTags.py new file mode 100644 index 0000000..1809470 --- /dev/null +++ b/PLC/PersonTags.py @@ -0,0 +1,61 @@ +# $Id: PersonTags.py 14587 2009-07-19 13:18:50Z thierry $ +# $URL: http://svn.planet-lab.org/svn/PLCAPI/tags/PLCAPI-4.3-27/PLC/PersonTags.py $ +# +# Thierry Parmentelat - INRIA +# +# $Revision: 14587 $ +# +from PLC.Faults import * +from PLC.Parameter import Parameter +from PLC.Filter import Filter +from PLC.Table import Row, Table +from PLC.TagTypes import TagType, TagTypes +from PLC.Persons import Person + +class PersonTag(Row): + """ + Representation of a row in the person_tag. + To use, instantiate with a dict of values. + """ + + table_name = 'person_tag' + primary_key = 'person_tag_id' + fields = { + 'person_tag_id': Parameter(int, "Person setting identifier"), + 'person_id': Person.fields['person_id'], + 'email': Person.fields['email'], + 'tag_type_id': TagType.fields['tag_type_id'], + 'tagname': TagType.fields['tagname'], + 'description': TagType.fields['description'], + 'category': TagType.fields['category'], + 'min_role_id': TagType.fields['min_role_id'], + 'value': Parameter(str, "Person setting value"), + ### relations + + } + +class PersonTags(Table): + """ + Representation of row(s) from the person_tag table in the + database. + """ + + def __init__(self, api, person_tag_filter = None, columns = None): + Table.__init__(self, api, PersonTag, columns) + + sql = "SELECT %s FROM view_person_tags WHERE True" % \ + ", ".join(self.columns) + + if person_tag_filter is not None: + if isinstance(person_tag_filter, (list, tuple, set)): + person_tag_filter = Filter(PersonTag.fields, {'person_tag_id': person_tag_filter}) + elif isinstance(person_tag_filter, dict): + person_tag_filter = Filter(PersonTag.fields, person_tag_filter) + elif isinstance(person_tag_filter, int): + person_tag_filter = Filter(PersonTag.fields, {'person_tag_id': [person_tag_filter]}) + else: + raise PLCInvalidArgument, "Wrong person setting filter %r"%person_tag_filter + sql += " AND (%s) %s" % person_tag_filter.sql(api) + + + self.selectall(sql) diff --git a/PLC/Persons.py b/PLC/Persons.py index 862d6ba..678697d 100644 --- a/PLC/Persons.py +++ b/PLC/Persons.py @@ -57,6 +57,7 @@ class Person(Row): 'slice_ids': Parameter([int], "List of slice identifiers"), 'peer_id': Parameter(int, "Peer to which this user belongs", nullok = True), 'peer_person_id': Parameter(int, "Foreign user identifier at peer", nullok = True), + 'person_tag_ids' : Parameter ([int], "List of tags attached to this person"), } related_fields = { 'roles': [Mixed(Parameter(int, "Role identifier"), @@ -68,6 +69,10 @@ class Person(Row): 'slices': [Mixed(Parameter(int, "Slice identifier"), Parameter(str, "Slice name"))] } + view_tags_name = "view_person_tags" + # tags are used by the Add/Get/Update methods to expose tags + # this is initialized here and updated by the accessors factory + tags = { } def validate_email(self, email): """ @@ -380,8 +385,13 @@ class Persons(Table): def __init__(self, api, person_filter = None, columns = None): Table.__init__(self, api, Person, columns) - sql = "SELECT %s FROM view_persons WHERE deleted IS False" % \ - ", ".join(self.columns) + view = "view_persons" + for tagname in self.tag_columns: + view= "%s left join %s using (%s)"%(view,Person.tagvalue_view_name(tagname), + Person.primary_key) + + sql = "SELECT %s FROM %s WHERE deleted IS False" % \ + (", ".join(self.columns.keys()+self.tag_columns.keys()),view) if person_filter is not None: if isinstance(person_filter, (list, tuple, set)): diff --git a/PLC/TagTypes.py b/PLC/TagTypes.py index 39306f5..1f4835c 100644 --- a/PLC/TagTypes.py +++ b/PLC/TagTypes.py @@ -23,7 +23,7 @@ class TagType (Row): table_name = 'tag_types' primary_key = 'tag_type_id' - join_tables = ['node_tag', 'interface_tag', 'slice_tag', 'site_tag' ] + join_tables = ['node_tag', 'interface_tag', 'slice_tag', 'site_tag', 'person_tag' ] fields = { 'tag_type_id': Parameter(int, "Node tag type identifier"), 'tagname': Parameter(str, "Node tag type name", max = 100), diff --git a/PLC/__init__.py b/PLC/__init__.py index 5ee17c4..0be5ac4 100644 --- a/PLC/__init__.py +++ b/PLC/__init__.py @@ -34,6 +34,7 @@ PCUs POD Parameter Peers +PersonTags Persons PostgreSQL PyCurl