1 from types import StringTypes
4 from PLC.Faults import *
5 from PLC.Parameter import Parameter, Mixed
6 from PLC.Filter import Filter
7 from PLC.Debug import profile
8 from PLC.Table import Row, Table
9 from PLC.Slices import Slice, Slices
10 from PLC.PCUs import PCU, PCUs
11 from PLC.Nodes import Node, Nodes
12 from PLC.Addresses import Address, Addresses
13 from PLC.Persons import Person, Persons
17 Representation of a row in the sites table. To use, optionally
18 instantiate with a dict of values. Update as you would a
19 dict. Commit to the database with sync().
23 primary_key = 'site_id'
24 join_tables = ['person_site', 'site_address', 'peer_site']
26 'site_id': Parameter(int, "Site identifier"),
27 'name': Parameter(str, "Full site name", max = 254),
28 'abbreviated_name': Parameter(str, "Abbreviated site name", max = 50),
29 'login_base': Parameter(str, "Site slice prefix", max = 20),
30 'is_public': Parameter(bool, "Publicly viewable site"),
31 'enabled': Parameter(bool, "Has been enabled"),
32 'latitude': Parameter(float, "Decimal latitude of the site", min = -90.0, max = 90.0, nullok = True),
33 'longitude': Parameter(float, "Decimal longitude of the site", min = -180.0, max = 180.0, nullok = True),
34 'url': Parameter(str, "URL of a page that describes the site", max = 254, nullok = True),
35 'date_created': Parameter(int, "Date and time when site entry was created, in seconds since UNIX epoch", ro = True),
36 'last_updated': Parameter(int, "Date and time when site entry was last updated, in seconds since UNIX epoch", ro = True),
37 'max_slices': Parameter(int, "Maximum number of slices that the site is able to create"),
38 'max_slivers': Parameter(int, "Maximum number of slivers that the site is able to create"),
39 'person_ids': Parameter([int], "List of account identifiers"),
40 'slice_ids': Parameter([int], "List of slice identifiers"),
41 'address_ids': Parameter([int], "List of address identifiers"),
42 'pcu_ids': Parameter([int], "List of PCU identifiers"),
43 'node_ids': Parameter([int], "List of site node identifiers"),
44 'peer_id': Parameter(int, "Peer to which this site belongs", nullok = True),
45 'peer_site_id': Parameter(int, "Foreign site identifier at peer", nullok = True),
46 'ext_consortium_id': Parameter(int, "external consortium id", nullok = True)
49 'persons': [Mixed(Parameter(int, "Person identifier"),
50 Parameter(str, "Email address"))],
51 'addresses': [Mixed(Parameter(int, "Address identifer"),
52 Filter(Address.fields))]
55 def validate_name(self, name):
57 raise PLCInvalidArgument, "Name must be specified"
61 validate_abbreviated_name = validate_name
63 def validate_login_base(self, login_base):
64 if not len(login_base):
65 raise PLCInvalidArgument, "Login base must be specified"
67 if not set(login_base).issubset(string.lowercase + string.digits):
68 raise PLCInvalidArgument, "Login base must consist only of lowercase ASCII letters or numbers"
70 conflicts = Sites(self.api, [login_base])
71 for site in conflicts:
72 if 'site_id' not in self or self['site_id'] != site['site_id']:
73 raise PLCInvalidArgument, "login_base already in use"
77 def validate_latitude(self, latitude):
78 if not self.has_key('longitude') or \
79 self['longitude'] is None:
80 raise PLCInvalidArgument, "Longitude must also be specified"
84 def validate_longitude(self, longitude):
85 if not self.has_key('latitude') or \
86 self['latitude'] is None:
87 raise PLCInvalidArgument, "Latitude must also be specified"
91 validate_date_created = Row.validate_timestamp
92 validate_last_updated = Row.validate_timestamp
94 add_person = Row.add_object(Person, 'person_site')
95 remove_person = Row.remove_object(Person, 'person_site')
97 add_address = Row.add_object(Address, 'site_address')
98 remove_address = Row.remove_object(Address, 'site_address')
100 def update_last_updated(self, commit = True):
102 Update last_updated field with current time
105 assert 'site_id' in self
106 assert self.table_name
108 self.api.db.do("UPDATE %s SET last_updated = CURRENT_TIMESTAMP " % (self.table_name) + \
109 " where site_id = %d" % (self['site_id']) )
113 def associate_persons(self, auth, field, value):
115 Adds persons found in value list to this site (using AddPersonToSite).
116 Deletes persons not found in value list from this site (using DeletePersonFromSite).
119 assert 'person_ids' in self
120 assert 'site_id' in self
121 assert isinstance(value, list)
123 (person_ids, emails) = self.separate_types(value)[0:2]
125 # Translate emails into person_ids
127 persons = Persons(self.api, emails, ['person_id']).dict('person_id')
128 person_ids += persons.keys()
130 # Add new ids, remove stale ids
131 if self['person_ids'] != person_ids:
132 from PLC.Methods.AddPersonToSite import AddPersonToSite
133 from PLC.Methods.DeletePersonFromSite import DeletePersonFromSite
134 new_persons = set(person_ids).difference(self['person_ids'])
135 stale_persons = set(self['person_ids']).difference(person_ids)
137 for new_person in new_persons:
138 AddPersonToSite.__call__(AddPersonToSite(self.api), auth, new_person, self['site_id'])
139 for stale_person in stale_persons:
140 DeletePersonFromSite.__call__(DeletePersonFromSite(self.api), auth, stale_person, self['site_id'])
142 def associate_addresses(self, auth, field, value):
144 Deletes addresses_ids not found in value list (using DeleteAddress).
145 Adds address if slice_fields w/o address_id found in value list (using AddSiteAddress).
146 Update address if slice_fields w/ address_id found in value list (using UpdateAddress).
149 assert 'address_ids' in self
150 assert 'site_id' in self
151 assert isinstance(value, list)
153 (address_ids, blank, addresses) = self.separate_types(value)
155 for address in addresses:
156 if 'address_id' in address:
157 address_ids.append(address['address_id'])
159 # Add new ids, remove stale ids
160 if self['address_ids'] != address_ids:
161 from PLC.Methods.DeleteAddress import DeleteAddress
162 stale_addresses = set(self['address_ids']).difference(address_ids)
164 for stale_address in stale_addresses:
165 DeleteAddress.__call__(DeleteAddress(self.api), auth, stale_address)
168 from PLC.Methods.AddSiteAddress import AddSiteAddress
169 from PLC.Methods.UpdateAddress import UpdateAddress
171 updated_addresses = filter(lambda address: 'address_id' in address, addresses)
172 added_addresses = filter(lambda address: 'address_id' not in address, addresses)
174 for address in added_addresses:
175 AddSiteAddress.__call__(AddSiteAddress(self.api), auth, self['site_id'], address)
176 for address in updated_addresses:
177 address_id = address.pop('address_id')
178 UpdateAddress.__call__(UpdateAddress(self.api), auth, address_id, address)
180 def delete(self, commit = True):
182 Delete existing site.
185 assert 'site_id' in self
187 # Delete accounts of all people at the site who are not
188 # members of at least one other non-deleted site.
189 persons = Persons(self.api, self['person_ids'])
190 for person in persons:
193 person_sites = Sites(self.api, person['site_ids'])
194 for person_site in person_sites:
195 if person_site['site_id'] != self['site_id']:
200 person.delete(commit = False)
202 # Delete all site addresses
203 addresses = Addresses(self.api, self['address_ids'])
204 for address in addresses:
205 address.delete(commit = False)
207 # Delete all site slices
208 slices = Slices(self.api, self['slice_ids'])
210 slice.delete(commit = False)
212 # Delete all site PCUs
213 pcus = PCUs(self.api, self['pcu_ids'])
215 pcu.delete(commit = False)
217 # Delete all site nodes
218 nodes = Nodes(self.api, self['node_ids'])
220 node.delete(commit = False)
222 # Clean up miscellaneous join tables
223 for table in self.join_tables:
224 self.api.db.do("DELETE FROM %s WHERE site_id = %d" % \
225 (table, self['site_id']))
228 self['deleted'] = True
233 Representation of row(s) from the sites table in the
237 def __init__(self, api, site_filter = None, columns = None):
238 Table.__init__(self, api, Site, columns)
240 sql = "SELECT %s FROM view_sites WHERE deleted IS False" % \
241 ", ".join(self.columns)
243 if site_filter is not None:
244 if isinstance(site_filter, (list, tuple, set)):
245 # Separate the list into integers and strings
246 ints = filter(lambda x: isinstance(x, (int, long)), site_filter)
247 strs = filter(lambda x: isinstance(x, StringTypes), site_filter)
248 site_filter = Filter(Site.fields, {'site_id': ints, 'login_base': strs})
249 sql += " AND (%s) %s" % site_filter.sql(api, "OR")
250 elif isinstance(site_filter, dict):
251 site_filter = Filter(Site.fields, site_filter)
252 sql += " AND (%s) %s" % site_filter.sql(api, "AND")
253 elif isinstance (site_filter, StringTypes):
254 site_filter = Filter(Site.fields, {'login_base':[site_filter]})
255 sql += " AND (%s) %s" % site_filter.sql(api, "AND")
256 elif isinstance (site_filter, int):
257 site_filter = Filter(Site.fields, {'site_id':[site_filter]})
258 sql += " AND (%s) %s" % site_filter.sql(api, "AND")
260 raise PLCInvalidArgument, "Wrong site filter %r"%site_filter