UpdatePerson: fix the part of updating the person HRN tag
[plcapi.git] / PLC / Methods / UpdatePerson.py
1 from PLC.Faults import *
2 from PLC.Method import Method
3 from PLC.Parameter import Parameter, Mixed
4 from PLC.Auth import Auth
5 from PLC.Table import Row
6 from PLC.Persons import Person, Persons
7 from PLC.sendmail import sendmail
8 from PLC.TagTypes import TagTypes
9 from PLC.PersonTags import PersonTags, PersonTag
10 from PLC.Namespace import email_to_hrn
11
12 related_fields = Person.related_fields.keys()
13 can_update = ['first_name', 'last_name', 'title', 'email',
14               'password', 'phone', 'url', 'bio', 'accepted_aup',
15               'enabled'] + related_fields
16
17 class UpdatePerson(Method):
18     """
19     Updates a person. Only the fields specified in person_fields are
20     updated, all other fields are left untouched.
21
22     Users and techs can only update themselves. PIs can only update
23     themselves and other non-PIs at their sites.
24
25     Returns 1 if successful, faults otherwise.
26     """
27
28     roles = ['admin', 'pi', 'user', 'tech']
29
30     accepted_fields = Row.accepted_fields(can_update,Person.fields)
31     # xxx check the related_fields feature
32     accepted_fields.update(Person.related_fields)
33     accepted_fields.update(Person.tags)
34
35     accepts = [
36         Auth(),
37         Mixed(Person.fields['person_id'],
38               Person.fields['email']),
39         accepted_fields
40         ]
41
42     returns = Parameter(int, '1 if successful')
43
44     def call(self, auth, person_id_or_email, person_fields):
45         # split provided fields
46         [native,related,tags,rejected] = Row.split_fields(person_fields,[Person.fields,Person.related_fields,Person.tags])
47
48         # type checking
49         native = Row.check_fields (native, self.accepted_fields)
50         if rejected:
51             raise PLCInvalidArgument, "Cannot update Person column(s) %r"%rejected
52
53         # Authenticated function
54         assert self.caller is not None
55
56         # Get account information
57         persons = Persons(self.api, [person_id_or_email])
58         if not persons:
59             raise PLCInvalidArgument, "No such account %s"%person_id_or_email
60         person = persons[0]
61
62         if person['peer_id'] is not None:
63             raise PLCInvalidArgument, "Not a local account %s"%person_id_or_email
64
65         # Check if we can update this account
66         if not self.caller.can_update(person):
67             raise PLCPermissionDenied, "Not allowed to update specified account"
68
69         # Make requested associations
70         for k,v in related.iteritems():
71             person.associate (auth, k, v)
72
73         person.update(native)
74         person.update_last_updated(False)
75         person.sync(commit=True)
76         
77         # send a mail
78         if 'enabled' in person_fields:
79             To = [("%s %s" % (person['first_name'], person['last_name']), person['email'])]
80             Cc = []
81             if person['enabled']:
82                 Subject = "%s account enabled" % (self.api.config.PLC_NAME)
83                 Body = "Your %s account has been enabled. Please visit %s to access your account." % (self.api.config.PLC_NAME, self.api.config.PLC_WWW_HOST)
84             else:
85                 Subject = "%s account disabled" % (self.api.config.PLC_NAME)
86                 Body = "Your %s account has been disabled. Please contact your PI or PlanetLab support for more information" % (self.api.config.PLC_NAME)
87             sendmail(self.api, To = To, Cc = Cc, Subject = Subject, Body = Body)
88
89         # if email was modifed make sure to update the hrn tag
90         if 'email' in native:
91             hrn_tag=PersonTags(self.api,{'tagname':'hrn','person_id':person['person_id']})
92             if hrn_tag:
93                 old_hrn = hrn_tag[0]['value']
94                 root_auth = self.api.config.PLC_HRN_ROOT
95                 login_base = old_hrn.split('.')[-2]
96                 hrn=email_to_hrn("%s.%s"%(root_auth,login_base),person['email'])
97                 tags['hrn'] = hrn
98
99         for (tagname,value) in tags.iteritems():
100             # the tagtype instance is assumed to exist, just check that
101             tag_types = TagTypes(self.api,{'tagname':tagname})
102             if not tag_types:
103                 raise PLCInvalidArgument,"No such TagType %s"%tagname
104             tag_type = tag_types[0]
105             person_tags=PersonTags(self.api,{'tagname':tagname,'person_id':person['person_id']})
106             if not person_tags:
107                 person_tag = PersonTag(self.api)
108                 person_tag['person_id'] = person['person_id']
109                 person_tag['tag_type_id'] = tag_type['tag_type_id']
110                 person_tag['tagname']  = tagname
111                 person_tag['value'] = value
112                 person_tag.sync()
113             else:
114                 person_tag = person_tags[0]
115                 person_tag['value'] = value
116                 person_tag.sync()
117
118         # Logging variables
119         self.event_objects = {'Person': [person['person_id']]}
120
121         # Redact password
122         if 'password' in person_fields:
123             person_fields['password'] = "Removed by API"
124         self.message = 'Person %d updated: %s.' % \
125                        (person['person_id'], person_fields.keys())
126         if 'enabled' in person_fields:
127             self.message += ' Person enabled'
128
129         return 1