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 'uuid': Parameter(str, "Universal Unique Identifier"),
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 class_key = 'login_base'
57 foreign_fields = ['abbreviated_name', 'name', 'is_public', 'latitude', 'longitude',
58 'url', 'max_slices', 'max_slivers', 'uuid',
60 # forget about these ones, they are read-only anyway
61 # handling them causes Cache to re-sync all over again
62 # 'last_updated', 'date_created'
65 def validate_name(self, name):
67 raise PLCInvalidArgument, "Name must be specified"
71 validate_abbreviated_name = validate_name
73 def validate_login_base(self, login_base):
74 if not len(login_base):
75 raise PLCInvalidArgument, "Login base must be specified"
77 if not set(login_base).issubset(string.lowercase + string.digits):
78 raise PLCInvalidArgument, "Login base must consist only of lowercase ASCII letters or numbers"
80 conflicts = Sites(self.api, [login_base])
81 for site in conflicts:
82 if 'site_id' not in self or self['site_id'] != site['site_id']:
83 raise PLCInvalidArgument, "login_base already in use"
87 def validate_latitude(self, latitude):
88 if not self.has_key('longitude') or \
89 self['longitude'] is None:
90 raise PLCInvalidArgument, "Longitude must also be specified"
94 def validate_longitude(self, longitude):
95 if not self.has_key('latitude') or \
96 self['latitude'] is None:
97 raise PLCInvalidArgument, "Latitude must also be specified"
101 validate_date_created = Row.validate_timestamp
102 validate_last_updated = Row.validate_timestamp
104 add_person = Row.add_object(Person, 'person_site')
105 remove_person = Row.remove_object(Person, 'person_site')
107 add_address = Row.add_object(Address, 'site_address')
108 remove_address = Row.remove_object(Address, 'site_address')
110 def update_last_updated(self, commit = True):
112 Update last_updated field with current time
115 assert 'site_id' in self
116 assert self.table_name
118 self.api.db.do("UPDATE %s SET last_updated = CURRENT_TIMESTAMP " % (self.table_name) + \
119 " where site_id = %d" % (self['site_id']) )
123 def associate_persons(self, auth, field, value):
125 Adds persons found in value list to this site (using AddPersonToSite).
126 Deletes persons not found in value list from this site (using DeletePersonFromSite).
129 assert 'person_ids' in self
130 assert 'site_id' in self
131 assert isinstance(value, list)
133 (person_ids, emails) = self.separate_types(value)[0:2]
135 # Translate emails into person_ids
137 persons = Persons(self.api, emails, ['person_id']).dict('person_id')
138 person_ids += persons.keys()
140 # Add new ids, remove stale ids
141 if self['person_ids'] != person_ids:
142 from PLC.Methods.AddPersonToSite import AddPersonToSite
143 from PLC.Methods.DeletePersonFromSite import DeletePersonFromSite
144 new_persons = set(person_ids).difference(self['person_ids'])
145 stale_persons = set(self['person_ids']).difference(person_ids)
147 for new_person in new_persons:
148 AddPersonToSite.__call__(AddPersonToSite(self.api), auth, new_person, self['site_id'])
149 for stale_person in stale_persons:
150 DeletePersonFromSite.__call__(DeletePersonFromSite(self.api), auth, stale_person, self['site_id'])
152 def associate_addresses(self, auth, field, value):
154 Deletes addresses_ids not found in value list (using DeleteAddress).
155 Adds address if slice_fields w/o address_id found in value list (using AddSiteAddress).
156 Update address if slice_fields w/ address_id found in value list (using UpdateAddress).
159 assert 'address_ids' in self
160 assert 'site_id' in self
161 assert isinstance(value, list)
163 (address_ids, blank, addresses) = self.separate_types(value)
165 for address in addresses:
166 if 'address_id' in address:
167 address_ids.append(address['address_id'])
169 # Add new ids, remove stale ids
170 if self['address_ids'] != address_ids:
171 from PLC.Methods.DeleteAddress import DeleteAddress
172 stale_addresses = set(self['address_ids']).difference(address_ids)
174 for stale_address in stale_addresses:
175 DeleteAddress.__call__(DeleteAddress(self.api), auth, stale_address)
178 from PLC.Methods.AddSiteAddress import AddSiteAddress
179 from PLC.Methods.UpdateAddress import UpdateAddress
181 updated_addresses = filter(lambda address: 'address_id' in address, addresses)
182 added_addresses = filter(lambda address: 'address_id' not in address, addresses)
184 for address in added_addresses:
185 AddSiteAddress.__call__(AddSiteAddress(self.api), auth, self['site_id'], address)
186 for address in updated_addresses:
187 address_id = address.pop('address_id')
188 UpdateAddress.__call__(UpdateAddress(self.api), auth, address_id, address)
190 def delete(self, commit = True):
192 Delete existing site.
195 assert 'site_id' in self
197 # Delete accounts of all people at the site who are not
198 # members of at least one other non-deleted site.
199 persons = Persons(self.api, self['person_ids'])
200 for person in persons:
203 person_sites = Sites(self.api, person['site_ids'])
204 for person_site in person_sites:
205 if person_site['site_id'] != self['site_id']:
210 person.delete(commit = False)
212 # Delete all site addresses
213 addresses = Addresses(self.api, self['address_ids'])
214 for address in addresses:
215 address.delete(commit = False)
217 # Delete all site slices
218 slices = Slices(self.api, self['slice_ids'])
220 slice.delete(commit = False)
222 # Delete all site PCUs
223 pcus = PCUs(self.api, self['pcu_ids'])
225 pcu.delete(commit = False)
227 # Delete all site nodes
228 nodes = Nodes(self.api, self['node_ids'])
230 node.delete(commit = False)
232 # Clean up miscellaneous join tables
233 for table in self.join_tables:
234 self.api.db.do("DELETE FROM %s WHERE site_id = %d" % \
235 (table, self['site_id']))
238 self['deleted'] = True
243 Representation of row(s) from the sites table in the
247 def __init__(self, api, site_filter = None, columns = None):
248 Table.__init__(self, api, Site, columns)
250 sql = "SELECT %s FROM view_sites WHERE deleted IS False" % \
251 ", ".join(self.columns)
253 if site_filter is not None:
254 if isinstance(site_filter, (list, tuple, set)):
255 # Separate the list into integers and strings
256 ints = filter(lambda x: isinstance(x, (int, long)), site_filter)
257 strs = filter(lambda x: isinstance(x, StringTypes), site_filter)
258 site_filter = Filter(Site.fields, {'site_id': ints, 'login_base': strs})
259 sql += " AND (%s) %s" % site_filter.sql(api, "OR")
260 elif isinstance(site_filter, dict):
261 site_filter = Filter(Site.fields, site_filter)
262 sql += " AND (%s) %s" % site_filter.sql(api, "AND")
263 elif isinstance (site_filter, StringTypes):
264 site_filter = Filter(Site.fields, {'login_base':[site_filter]})
265 sql += " AND (%s) %s" % site_filter.sql(api, "AND")
266 elif isinstance (site_filter, int):
267 site_filter = Filter(Site.fields, {'site_id':[site_filter]})
268 sql += " AND (%s) %s" % site_filter.sql(api, "AND")
270 raise PLCInvalidArgument, "Wrong site filter %r"%site_filter