1 from types import StringTypes
4 from PLC.Faults import *
5 from PLC.Parameter import Parameter
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.NodeGroups import NodeGroup, NodeGroups
13 from PLC.Addresses import Address, Addresses
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'
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 'latitude': Parameter(float, "Decimal latitude of the site", min = -90.0, max = 90.0, nullok = True),
32 'longitude': Parameter(float, "Decimal longitude of the site", min = -180.0, max = 180.0, nullok = True),
33 'url': Parameter(str, "URL of a page that describes the site", max = 254, nullok = True),
34 'date_created': Parameter(int, "Date and time when site entry was created, in seconds since UNIX epoch", ro = True),
35 'last_updated': Parameter(int, "Date and time when site entry was last updated, in seconds since UNIX epoch", ro = True),
36 'max_slices': Parameter(int, "Maximum number of slices that the site is able to create"),
37 'max_slivers': Parameter(int, "Maximum number of slivers that the site is able to create"),
38 'person_ids': Parameter([int], "List of account identifiers"),
39 'slice_ids': Parameter([int], "List of slice identifiers"),
40 'address_ids': Parameter([int], "List of address identifiers"),
41 'pcu_ids': Parameter([int], "List of PCU identifiers"),
42 'node_ids': Parameter([int], "List of site node identifiers"),
43 'peer_id': Parameter(int, "Peer at which this slice was created", nullok = True),
47 class_key = 'login_base'
48 foreign_fields = ['abbreviated_name', 'name', 'is_public', 'latitude', 'longitude',
49 'url', 'max_slices', 'max_slivers',
51 # forget about these ones, they are read-only anyway
52 # handling them causes Cache to re-sync all over again
53 # 'last_updated', 'date_created'
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.ascii_letters.lower()):
69 raise PLCInvalidArgument, "Login base must consist only of lowercase ASCII letters"
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"
93 def validate_date_created (self, timestamp):
94 return self.validate_timestamp (timestamp)
95 def validate_last_updated (self, timestamp):
96 return self.validate_timestamp (timestamp)
98 def add_person(self, person, commit = True):
100 Add person to existing site.
103 assert 'site_id' in self
104 assert isinstance(person, PLC.Persons.Person)
105 assert 'person_id' in person
107 site_id = self['site_id']
108 person_id = person['person_id']
110 if person_id not in self['person_ids']:
111 assert site_id not in person['site_ids']
113 self.api.db.do("INSERT INTO person_site (person_id, site_id)" \
114 " VALUES(%(person_id)d, %(site_id)d)",
120 self['person_ids'].append(person_id)
121 person['site_ids'].append(site_id)
123 def remove_person(self, person, commit = True):
125 Remove person from existing site.
128 assert 'site_id' in self
129 assert isinstance(person, PLC.Persons.Person)
130 assert 'person_id' in person
132 site_id = self['site_id']
133 person_id = person['person_id']
135 if person_id in self['person_ids']:
136 assert site_id in person['site_ids']
138 self.api.db.do("DELETE FROM person_site" \
139 " WHERE person_id = %(person_id)d" \
140 " AND site_id = %(site_id)d",
146 self['person_ids'].remove(person_id)
147 person['site_ids'].remove(site_id)
149 def add_address(self, address, commit = True):
151 Add address to existing site.
154 assert 'site_id' in self
155 assert isinstance(address, Address)
156 assert 'address_id' in address
158 site_id = self['site_id']
159 address_id = address['address_id']
161 if address_id not in self['address_ids']:
162 self.api.db.do("INSERT INTO site_address (address_id, site_id)" \
163 " VALUES(%(address_id)d, %(site_id)d)",
169 self['address_ids'].append(address_id)
171 def remove_address(self, address, commit = True):
173 Remove address from existing site.
176 assert 'site_id' in self
177 assert isinstance(address, Address)
178 assert 'address_id' in address
180 site_id = self['site_id']
181 address_id = address['address_id']
183 if address_id in self['address_ids']:
184 self.api.db.do("DELETE FROM site_address" \
185 " WHERE address_id = %(address_id)d" \
186 " AND site_id = %(site_id)d",
192 self['address_ids'].remove(address_id)
194 def delete(self, commit = True):
196 Delete existing site.
199 assert 'site_id' in self
201 # Delete accounts of all people at the site who are not
202 # members of at least one other non-deleted site.
203 persons = PLC.Persons.Persons(self.api, self['person_ids'])
204 for person in persons:
207 person_sites = Sites(self.api, person['site_ids'])
208 for person_site in person_sites:
209 if person_site['site_id'] != self['site_id']:
214 person.delete(commit = False)
216 # Delete all site addresses
217 addresses = Addresses(self.api, self['address_ids'])
218 for address in addresses:
219 address.delete(commit = False)
221 # Delete all site slices
222 slices = Slices(self.api, self['slice_ids'])
224 slice.delete(commit = False)
226 # Delete all site PCUs
227 pcus = PCUs(self.api, self['pcu_ids'])
229 pcu.delete(commit = False)
231 # Delete all site nodes
232 nodes = Nodes(self.api, self['node_ids'])
234 node.delete(commit = False)
236 # Clean up miscellaneous join tables
237 for table in ['person_site']:
238 self.api.db.do("DELETE FROM %s" \
239 " WHERE site_id = %d" % \
240 (table, self['site_id']), self)
243 self['deleted'] = True
248 Representation of row(s) from the sites table in the
252 def __init__(self, api, site_filter = None, columns = None):
253 Table.__init__(self, api, Site, columns)
255 sql = "SELECT %s FROM view_sites WHERE deleted IS False" % \
256 ", ".join(self.columns)
258 if site_filter is not None:
259 if isinstance(site_filter, (list, tuple, set)):
260 # Separate the list into integers and strings
261 ints = filter(lambda x: isinstance(x, (int, long)), site_filter)
262 strs = filter(lambda x: isinstance(x, StringTypes), site_filter)
263 site_filter = Filter(Site.fields, {'site_id': ints, 'login_base': strs})
264 sql += " AND (%s)" % site_filter.sql(api, "OR")
265 elif isinstance(site_filter, dict):
266 site_filter = Filter(Site.fields, site_filter)
267 sql += " AND (%s)" % site_filter.sql(api, "AND")