3 from types import StringTypes
6 from PLC.Faults import *
7 from PLC.Parameter import Parameter, Mixed
8 from PLC.Filter import Filter
9 from PLC.Debug import profile
10 from PLC.Table import Row, Table
11 from PLC.Slices import Slice, Slices
12 from PLC.PCUs import PCU, PCUs
13 from PLC.Nodes import Node, Nodes
14 from PLC.Addresses import Address, Addresses
15 from PLC.Persons import Person, Persons
19 Representation of a row in the sites table. To use, optionally
20 instantiate with a dict of values. Update as you would a
21 dict. Commit to the database with sync().
25 primary_key = 'site_id'
26 join_tables = ['person_site', 'site_address', 'peer_site']
28 'site_id': Parameter(int, "Site identifier"),
29 'name': Parameter(str, "Full site name", max = 254),
30 'abbreviated_name': Parameter(str, "Abbreviated site name", max = 50),
31 'login_base': Parameter(str, "Site slice prefix", max = 20),
32 'is_public': Parameter(bool, "Publicly viewable site"),
33 'enabled': Parameter(bool, "Has been enabled"),
34 'latitude': Parameter(float, "Decimal latitude of the site", min = -90.0, max = 90.0, nullok = True),
35 'longitude': Parameter(float, "Decimal longitude of the site", min = -180.0, max = 180.0, nullok = True),
36 'url': Parameter(str, "URL of a page that describes the site", max = 254, nullok = True),
37 'date_created': Parameter(int, "Date and time when site entry was created, in seconds since UNIX epoch", ro = True),
38 'last_updated': Parameter(int, "Date and time when site entry was last updated, in seconds since UNIX epoch", ro = True),
39 'max_slices': Parameter(int, "Maximum number of slices that the site is able to create"),
40 'max_slivers': Parameter(int, "Maximum number of slivers that the site is able to create"),
41 'person_ids': Parameter([int], "List of account identifiers"),
42 'slice_ids': Parameter([int], "List of slice identifiers"),
43 'address_ids': Parameter([int], "List of address identifiers"),
44 'pcu_ids': Parameter([int], "List of PCU identifiers"),
45 'node_ids': Parameter([int], "List of site node identifiers"),
46 'peer_id': Parameter(int, "Peer to which this site belongs", nullok = True),
47 'peer_site_id': Parameter(int, "Foreign site identifier at peer", nullok = True),
48 'ext_consortium_id': Parameter(int, "external consortium id", nullok = True)
51 'persons': [Mixed(Parameter(int, "Person identifier"),
52 Parameter(str, "Email address"))],
53 'addresses': [Mixed(Parameter(int, "Address identifer"),
54 Filter(Address.fields))]
57 def validate_name(self, name):
59 raise PLCInvalidArgument, "Name must be specified"
63 validate_abbreviated_name = validate_name
65 def validate_login_base(self, login_base):
66 if not len(login_base):
67 raise PLCInvalidArgument, "Login base must be specified"
69 if not set(login_base).issubset(string.lowercase + string.digits):
70 raise PLCInvalidArgument, "Login base must consist only of lowercase ASCII letters or numbers"
72 conflicts = Sites(self.api, [login_base])
73 for site in conflicts:
74 if 'site_id' not in self or self['site_id'] != site['site_id']:
75 raise PLCInvalidArgument, "login_base already in use"
79 def validate_latitude(self, latitude):
80 if not self.has_key('longitude') or \
81 self['longitude'] is None:
82 raise PLCInvalidArgument, "Longitude must also be specified"
86 def validate_longitude(self, longitude):
87 if not self.has_key('latitude') or \
88 self['latitude'] is None:
89 raise PLCInvalidArgument, "Latitude must also be specified"
93 validate_date_created = Row.validate_timestamp
94 validate_last_updated = Row.validate_timestamp
96 add_person = Row.add_object(Person, 'person_site')
97 remove_person = Row.remove_object(Person, 'person_site')
99 add_address = Row.add_object(Address, 'site_address')
100 remove_address = Row.remove_object(Address, 'site_address')
102 def update_last_updated(self, commit = True):
104 Update last_updated field with current time
107 assert 'site_id' in self
108 assert self.table_name
110 self.api.db.do("UPDATE %s SET last_updated = CURRENT_TIMESTAMP " % (self.table_name) + \
111 " where site_id = %d" % (self['site_id']) )
115 def associate_persons(self, auth, field, value):
117 Adds persons found in value list to this site (using AddPersonToSite).
118 Deletes persons not found in value list from this site (using DeletePersonFromSite).
121 assert 'person_ids' in self
122 assert 'site_id' in self
123 assert isinstance(value, list)
125 (person_ids, emails) = self.separate_types(value)[0:2]
127 # Translate emails into person_ids
129 persons = Persons(self.api, emails, ['person_id']).dict('person_id')
130 person_ids += persons.keys()
132 # Add new ids, remove stale ids
133 if self['person_ids'] != person_ids:
134 from PLC.Methods.AddPersonToSite import AddPersonToSite
135 from PLC.Methods.DeletePersonFromSite import DeletePersonFromSite
136 new_persons = set(person_ids).difference(self['person_ids'])
137 stale_persons = set(self['person_ids']).difference(person_ids)
139 for new_person in new_persons:
140 AddPersonToSite.__call__(AddPersonToSite(self.api), auth, new_person, self['site_id'])
141 for stale_person in stale_persons:
142 DeletePersonFromSite.__call__(DeletePersonFromSite(self.api), auth, stale_person, self['site_id'])
144 def associate_addresses(self, auth, field, value):
146 Deletes addresses_ids not found in value list (using DeleteAddress).
147 Adds address if slice_fields w/o address_id found in value list (using AddSiteAddress).
148 Update address if slice_fields w/ address_id found in value list (using UpdateAddress).
151 assert 'address_ids' in self
152 assert 'site_id' in self
153 assert isinstance(value, list)
155 (address_ids, blank, addresses) = self.separate_types(value)
157 for address in addresses:
158 if 'address_id' in address:
159 address_ids.append(address['address_id'])
161 # Add new ids, remove stale ids
162 if self['address_ids'] != address_ids:
163 from PLC.Methods.DeleteAddress import DeleteAddress
164 stale_addresses = set(self['address_ids']).difference(address_ids)
166 for stale_address in stale_addresses:
167 DeleteAddress.__call__(DeleteAddress(self.api), auth, stale_address)
170 from PLC.Methods.AddSiteAddress import AddSiteAddress
171 from PLC.Methods.UpdateAddress import UpdateAddress
173 updated_addresses = filter(lambda address: 'address_id' in address, addresses)
174 added_addresses = filter(lambda address: 'address_id' not in address, addresses)
176 for address in added_addresses:
177 AddSiteAddress.__call__(AddSiteAddress(self.api), auth, self['site_id'], address)
178 for address in updated_addresses:
179 address_id = address.pop('address_id')
180 UpdateAddress.__call__(UpdateAddress(self.api), auth, address_id, address)
182 def delete(self, commit = True):
184 Delete existing site.
187 assert 'site_id' in self
189 # Delete accounts of all people at the site who are not
190 # members of at least one other non-deleted site.
191 persons = Persons(self.api, self['person_ids'])
192 for person in persons:
195 person_sites = Sites(self.api, person['site_ids'])
196 for person_site in person_sites:
197 if person_site['site_id'] != self['site_id']:
202 person.delete(commit = False)
204 # Delete all site addresses
205 addresses = Addresses(self.api, self['address_ids'])
206 for address in addresses:
207 address.delete(commit = False)
209 # Delete all site slices
210 slices = Slices(self.api, self['slice_ids'])
212 slice.delete(commit = False)
214 # Delete all site PCUs
215 pcus = PCUs(self.api, self['pcu_ids'])
217 pcu.delete(commit = False)
219 # Delete all site nodes
220 nodes = Nodes(self.api, self['node_ids'])
222 node.delete(commit = False)
224 # Clean up miscellaneous join tables
225 for table in self.join_tables:
226 self.api.db.do("DELETE FROM %s WHERE site_id = %d" % \
227 (table, self['site_id']))
230 self['deleted'] = True
235 Representation of row(s) from the sites table in the
239 def __init__(self, api, site_filter = None, columns = None):
240 Table.__init__(self, api, Site, columns)
242 sql = "SELECT %s FROM view_sites WHERE deleted IS False" % \
243 ", ".join(self.columns)
245 if site_filter is not None:
246 if isinstance(site_filter, (list, tuple, set)):
247 # Separate the list into integers and strings
248 ints = filter(lambda x: isinstance(x, (int, long)), site_filter)
249 strs = filter(lambda x: isinstance(x, StringTypes), site_filter)
250 site_filter = Filter(Site.fields, {'site_id': ints, 'login_base': strs})
251 sql += " AND (%s) %s" % site_filter.sql(api, "OR")
252 elif isinstance(site_filter, dict):
253 site_filter = Filter(Site.fields, site_filter)
254 sql += " AND (%s) %s" % site_filter.sql(api, "AND")
255 elif isinstance (site_filter, StringTypes):
256 site_filter = Filter(Site.fields, {'login_base':[site_filter]})
257 sql += " AND (%s) %s" % site_filter.sql(api, "AND")
258 elif isinstance (site_filter, int):
259 site_filter = Filter(Site.fields, {'site_id':[site_filter]})
260 sql += " AND (%s) %s" % site_filter.sql(api, "AND")
262 raise PLCInvalidArgument, "Wrong site filter %r"%site_filter