2 from types import StringTypes
5 from PLC.Faults import *
6 from PLC.Parameter import Parameter, Mixed
7 from PLC.Filter import Filter
8 from PLC.Debug import profile
9 from PLC.Table import Row, Table
10 from PLC.Slices import Slice, Slices
11 from PLC.PCUs import PCU, PCUs
12 from PLC.Nodes import Node, Nodes
13 from PLC.Addresses import Address, Addresses
14 from PLC.Persons import Person, Persons
18 Representation of a row in the sites table. To use, optionally
19 instantiate with a dict of values. Update as you would a
20 dict. Commit to the database with sync().
24 primary_key = 'site_id'
25 join_tables = ['person_site', 'site_address', 'peer_site']
27 'site_id': Parameter(int, "Site identifier"),
28 'name': Parameter(str, "Full site name", max = 254),
29 'abbreviated_name': Parameter(str, "Abbreviated site name", max = 50),
30 'login_base': Parameter(str, "Site slice prefix", max = 20),
31 'is_public': Parameter(bool, "Publicly viewable site"),
32 'enabled': Parameter(bool, "Has been enabled"),
33 'latitude': Parameter(float, "Decimal latitude of the site", min = -90.0, max = 90.0, nullok = True),
34 'longitude': Parameter(float, "Decimal longitude of the site", min = -180.0, max = 180.0, nullok = True),
35 'url': Parameter(str, "URL of a page that describes the site", max = 254, nullok = True),
36 'date_created': Parameter(int, "Date and time when site entry was created, in seconds since UNIX epoch", ro = True),
37 'last_updated': Parameter(int, "Date and time when site entry was last updated, in seconds since UNIX epoch", ro = True),
38 'max_slices': Parameter(int, "Maximum number of slices that the site is able to create"),
39 'max_slivers': Parameter(int, "Maximum number of slivers that the site is able to create"),
40 'person_ids': Parameter([int], "List of account identifiers"),
41 'slice_ids': Parameter([int], "List of slice identifiers"),
42 'address_ids': Parameter([int], "List of address identifiers"),
43 'pcu_ids': Parameter([int], "List of PCU identifiers"),
44 'node_ids': Parameter([int], "List of site node identifiers"),
45 'peer_id': Parameter(int, "Peer to which this site belongs", nullok = True),
46 'peer_site_id': Parameter(int, "Foreign site identifier at peer", nullok = True),
47 'ext_consortium_id': Parameter(int, "external consortium id", nullok = True)
50 'persons': [Mixed(Parameter(int, "Person identifier"),
51 Parameter(str, "Email address"))],
52 'addresses': [Mixed(Parameter(int, "Address identifer"),
53 Filter(Address.fields))]
56 def validate_name(self, name):
58 raise PLCInvalidArgument, "Name must be specified"
62 validate_abbreviated_name = validate_name
64 def validate_login_base(self, login_base):
65 if not len(login_base):
66 raise PLCInvalidArgument, "Login base must be specified"
68 if not set(login_base).issubset(string.lowercase + string.digits):
69 raise PLCInvalidArgument, "Login base must consist only of lowercase ASCII letters or numbers"
71 conflicts = Sites(self.api, [login_base])
72 for site in conflicts:
73 if 'site_id' not in self or self['site_id'] != site['site_id']:
74 raise PLCInvalidArgument, "login_base already in use"
78 def validate_latitude(self, latitude):
79 if not self.has_key('longitude') or \
80 self['longitude'] is None:
81 raise PLCInvalidArgument, "Longitude must also be specified"
85 def validate_longitude(self, longitude):
86 if not self.has_key('latitude') or \
87 self['latitude'] is None:
88 raise PLCInvalidArgument, "Latitude must also be specified"
92 validate_date_created = Row.validate_timestamp
93 validate_last_updated = Row.validate_timestamp
95 add_person = Row.add_object(Person, 'person_site')
96 remove_person = Row.remove_object(Person, 'person_site')
98 add_address = Row.add_object(Address, 'site_address')
99 remove_address = Row.remove_object(Address, 'site_address')
101 def update_last_updated(self, commit = True):
103 Update last_updated field with current time
106 assert 'site_id' in self
107 assert self.table_name
109 self.api.db.do("UPDATE %s SET last_updated = CURRENT_TIMESTAMP " % (self.table_name) + \
110 " where site_id = %d" % (self['site_id']) )
114 def associate_persons(self, auth, field, value):
116 Adds persons found in value list to this site (using AddPersonToSite).
117 Deletes persons not found in value list from this site (using DeletePersonFromSite).
120 assert 'person_ids' in self
121 assert 'site_id' in self
122 assert isinstance(value, list)
124 (person_ids, emails) = self.separate_types(value)[0:2]
126 # Translate emails into person_ids
128 persons = Persons(self.api, emails, ['person_id']).dict('person_id')
129 person_ids += persons.keys()
131 # Add new ids, remove stale ids
132 if self['person_ids'] != person_ids:
133 from PLC.Methods.AddPersonToSite import AddPersonToSite
134 from PLC.Methods.DeletePersonFromSite import DeletePersonFromSite
135 new_persons = set(person_ids).difference(self['person_ids'])
136 stale_persons = set(self['person_ids']).difference(person_ids)
138 for new_person in new_persons:
139 AddPersonToSite.__call__(AddPersonToSite(self.api), auth, new_person, self['site_id'])
140 for stale_person in stale_persons:
141 DeletePersonFromSite.__call__(DeletePersonFromSite(self.api), auth, stale_person, self['site_id'])
143 def associate_addresses(self, auth, field, value):
145 Deletes addresses_ids not found in value list (using DeleteAddress).
146 Adds address if slice_fields w/o address_id found in value list (using AddSiteAddress).
147 Update address if slice_fields w/ address_id found in value list (using UpdateAddress).
150 assert 'address_ids' in self
151 assert 'site_id' in self
152 assert isinstance(value, list)
154 (address_ids, blank, addresses) = self.separate_types(value)
156 for address in addresses:
157 if 'address_id' in address:
158 address_ids.append(address['address_id'])
160 # Add new ids, remove stale ids
161 if self['address_ids'] != address_ids:
162 from PLC.Methods.DeleteAddress import DeleteAddress
163 stale_addresses = set(self['address_ids']).difference(address_ids)
165 for stale_address in stale_addresses:
166 DeleteAddress.__call__(DeleteAddress(self.api), auth, stale_address)
169 from PLC.Methods.AddSiteAddress import AddSiteAddress
170 from PLC.Methods.UpdateAddress import UpdateAddress
172 updated_addresses = filter(lambda address: 'address_id' in address, addresses)
173 added_addresses = filter(lambda address: 'address_id' not in address, addresses)
175 for address in added_addresses:
176 AddSiteAddress.__call__(AddSiteAddress(self.api), auth, self['site_id'], address)
177 for address in updated_addresses:
178 address_id = address.pop('address_id')
179 UpdateAddress.__call__(UpdateAddress(self.api), auth, address_id, address)
181 def delete(self, commit = True):
183 Delete existing site.
186 assert 'site_id' in self
188 # Delete accounts of all people at the site who are not
189 # members of at least one other non-deleted site.
190 persons = Persons(self.api, self['person_ids'])
191 for person in persons:
194 person_sites = Sites(self.api, person['site_ids'])
195 for person_site in person_sites:
196 if person_site['site_id'] != self['site_id']:
201 person.delete(commit = False)
203 # Delete all site addresses
204 addresses = Addresses(self.api, self['address_ids'])
205 for address in addresses:
206 address.delete(commit = False)
208 # Delete all site slices
209 slices = Slices(self.api, self['slice_ids'])
211 slice.delete(commit = False)
213 # Delete all site PCUs
214 pcus = PCUs(self.api, self['pcu_ids'])
216 pcu.delete(commit = False)
218 # Delete all site nodes
219 nodes = Nodes(self.api, self['node_ids'])
221 node.delete(commit = False)
223 # Clean up miscellaneous join tables
224 for table in self.join_tables:
225 self.api.db.do("DELETE FROM %s WHERE site_id = %d" % \
226 (table, self['site_id']))
229 self['deleted'] = True
234 Representation of row(s) from the sites table in the
238 def __init__(self, api, site_filter = None, columns = None):
239 Table.__init__(self, api, Site, columns)
241 sql = "SELECT %s FROM view_sites WHERE deleted IS False" % \
242 ", ".join(self.columns)
244 if site_filter is not None:
245 if isinstance(site_filter, (list, tuple, set)):
246 # Separate the list into integers and strings
247 ints = filter(lambda x: isinstance(x, (int, long)), site_filter)
248 strs = filter(lambda x: isinstance(x, StringTypes), site_filter)
249 site_filter = Filter(Site.fields, {'site_id': ints, 'login_base': strs})
250 sql += " AND (%s) %s" % site_filter.sql(api, "OR")
251 elif isinstance(site_filter, dict):
252 site_filter = Filter(Site.fields, site_filter)
253 sql += " AND (%s) %s" % site_filter.sql(api, "AND")
254 elif isinstance (site_filter, StringTypes):
255 site_filter = Filter(Site.fields, {'login_base':[site_filter]})
256 sql += " AND (%s) %s" % site_filter.sql(api, "AND")
257 elif isinstance (site_filter, int):
258 site_filter = Filter(Site.fields, {'site_id':[site_filter]})
259 sql += " AND (%s) %s" % site_filter.sql(api, "AND")
261 raise PLCInvalidArgument, "Wrong site filter %r"%site_filter