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 class_key = 'login_base'
56 foreign_fields = ['abbreviated_name', 'name', 'is_public', 'latitude', 'longitude',
57 'url', 'max_slices', 'max_slivers',
59 # forget about these ones, they are read-only anyway
60 # handling them causes Cache to re-sync all over again
61 # 'last_updated', 'date_created'
64 def validate_name(self, name):
66 raise PLCInvalidArgument, "Name must be specified"
70 validate_abbreviated_name = validate_name
72 def validate_login_base(self, login_base):
73 if not len(login_base):
74 raise PLCInvalidArgument, "Login base must be specified"
76 if not set(login_base).issubset(string.lowercase + string.digits):
77 raise PLCInvalidArgument, "Login base must consist only of lowercase ASCII letters or numbers"
79 conflicts = Sites(self.api, [login_base])
80 for site in conflicts:
81 if 'site_id' not in self or self['site_id'] != site['site_id']:
82 raise PLCInvalidArgument, "login_base already in use"
86 def validate_latitude(self, latitude):
87 if not self.has_key('longitude') or \
88 self['longitude'] is None:
89 raise PLCInvalidArgument, "Longitude must also be specified"
93 def validate_longitude(self, longitude):
94 if not self.has_key('latitude') or \
95 self['latitude'] is None:
96 raise PLCInvalidArgument, "Latitude must also be specified"
100 validate_date_created = Row.validate_timestamp
101 validate_last_updated = Row.validate_timestamp
103 add_person = Row.add_object(Person, 'person_site')
104 remove_person = Row.remove_object(Person, 'person_site')
106 add_address = Row.add_object(Address, 'site_address')
107 remove_address = Row.remove_object(Address, 'site_address')
109 def update_last_updated(self, commit = True):
111 Update last_updated field with current time
114 assert 'site_id' in self
115 assert self.table_name
117 self.api.db.do("UPDATE %s SET last_updated = CURRENT_TIMESTAMP " % (self.table_name) + \
118 " where site_id = %d" % (self['site_id']) )
122 def associate_persons(self, auth, field, value):
124 Adds persons found in value list to this site (using AddPersonToSite).
125 Deletes persons not found in value list from this site (using DeletePersonFromSite).
128 assert 'person_ids' in self
129 assert 'site_id' in self
130 assert isinstance(value, list)
132 (person_ids, emails) = self.separate_types(value)[0:2]
134 # Translate emails into person_ids
136 persons = Persons(self.api, emails, ['person_id']).dict('person_id')
137 person_ids += persons.keys()
139 # Add new ids, remove stale ids
140 if self['person_ids'] != person_ids:
141 from PLC.Methods.AddPersonToSite import AddPersonToSite
142 from PLC.Methods.DeletePersonFromSite import DeletePersonFromSite
143 new_persons = set(person_ids).difference(self['person_ids'])
144 stale_persons = set(self['person_ids']).difference(person_ids)
146 for new_person in new_persons:
147 AddPersonToSite.__call__(AddPersonToSite(self.api), auth, new_person, self['site_id'])
148 for stale_person in stale_persons:
149 DeletePersonFromSite.__call__(DeletePersonFromSite(self.api), auth, stale_person, self['site_id'])
151 def associate_addresses(self, auth, field, value):
153 Deletes addresses_ids not found in value list (using DeleteAddress).
154 Adds address if slice_fields w/o address_id found in value list (using AddSiteAddress).
155 Update address if slice_fields w/ address_id found in value list (using UpdateAddress).
158 assert 'address_ids' in self
159 assert 'site_id' in self
160 assert isinstance(value, list)
162 (address_ids, blank, addresses) = self.separate_types(value)
164 for address in addresses:
165 if 'address_id' in address:
166 address_ids.append(address['address_id'])
168 # Add new ids, remove stale ids
169 if self['address_ids'] != address_ids:
170 from PLC.Methods.DeleteAddress import DeleteAddress
171 stale_addresses = set(self['address_ids']).difference(address_ids)
173 for stale_address in stale_addresses:
174 DeleteAddress.__call__(DeleteAddress(self.api), auth, stale_address)
177 from PLC.Methods.AddSiteAddress import AddSiteAddress
178 from PLC.Methods.UpdateAddress import UpdateAddress
180 updated_addresses = filter(lambda address: 'address_id' in address, addresses)
181 added_addresses = filter(lambda address: 'address_id' not in address, addresses)
183 for address in added_addresses:
184 AddSiteAddress.__call__(AddSiteAddress(self.api), auth, self['site_id'], address)
185 for address in updated_addresses:
186 address_id = address.pop('address_id')
187 UpdateAddress.__call__(UpdateAddress(self.api), auth, address_id, address)
189 def delete(self, commit = True):
191 Delete existing site.
194 assert 'site_id' in self
196 # Delete accounts of all people at the site who are not
197 # members of at least one other non-deleted site.
198 persons = Persons(self.api, self['person_ids'])
199 for person in persons:
202 person_sites = Sites(self.api, person['site_ids'])
203 for person_site in person_sites:
204 if person_site['site_id'] != self['site_id']:
209 person.delete(commit = False)
211 # Delete all site addresses
212 addresses = Addresses(self.api, self['address_ids'])
213 for address in addresses:
214 address.delete(commit = False)
216 # Delete all site slices
217 slices = Slices(self.api, self['slice_ids'])
219 slice.delete(commit = False)
221 # Delete all site PCUs
222 pcus = PCUs(self.api, self['pcu_ids'])
224 pcu.delete(commit = False)
226 # Delete all site nodes
227 nodes = Nodes(self.api, self['node_ids'])
229 node.delete(commit = False)
231 # Clean up miscellaneous join tables
232 for table in self.join_tables:
233 self.api.db.do("DELETE FROM %s WHERE site_id = %d" % \
234 (table, self['site_id']))
237 self['deleted'] = True
242 Representation of row(s) from the sites table in the
246 def __init__(self, api, site_filter = None, columns = None):
247 Table.__init__(self, api, Site, columns)
249 sql = "SELECT %s FROM view_sites WHERE deleted IS False" % \
250 ", ".join(self.columns)
252 if site_filter is not None:
253 if isinstance(site_filter, (list, tuple, set)):
254 # Separate the list into integers and strings
255 ints = filter(lambda x: isinstance(x, (int, long)), site_filter)
256 strs = filter(lambda x: isinstance(x, StringTypes), site_filter)
257 site_filter = Filter(Site.fields, {'site_id': ints, 'login_base': strs})
258 sql += " AND (%s) %s" % site_filter.sql(api, "OR")
259 elif isinstance(site_filter, dict):
260 site_filter = Filter(Site.fields, site_filter)
261 sql += " AND (%s) %s" % site_filter.sql(api, "AND")
262 elif isinstance (site_filter, StringTypes):
263 site_filter = Filter(Site.fields, {'login_base':[site_filter]})
264 sql += " AND (%s) %s" % site_filter.sql(api, "AND")
265 elif isinstance (site_filter, int):
266 site_filter = Filter(Site.fields, {'site_id':[site_filter]})
267 sql += " AND (%s) %s" % site_filter.sql(api, "AND")
269 raise PLCInvalidArgument, "Wrong site filter %r"%site_filter