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', 'date_created', 'last_updated', 'max_slices', 'max_slivers',
53 def validate_name(self, name):
55 raise PLCInvalidArgument, "Name must be specified"
59 validate_abbreviated_name = validate_name
61 def validate_login_base(self, login_base):
62 if not len(login_base):
63 raise PLCInvalidArgument, "Login base must be specified"
65 if not set(login_base).issubset(string.ascii_letters.lower()):
66 raise PLCInvalidArgument, "Login base must consist only of lowercase ASCII letters"
68 conflicts = Sites(self.api, [login_base])
69 for site in conflicts:
70 if 'site_id' not in self or self['site_id'] != site['site_id']:
71 raise PLCInvalidArgument, "login_base already in use"
75 def validate_latitude(self, latitude):
76 if not self.has_key('longitude') or \
77 self['longitude'] is None:
78 raise PLCInvalidArgument, "Longitude must also be specified"
82 def validate_longitude(self, longitude):
83 if not self.has_key('latitude') or \
84 self['latitude'] is None:
85 raise PLCInvalidArgument, "Latitude must also be specified"
89 def add_person(self, person, commit = True):
91 Add person to existing site.
94 assert 'site_id' in self
95 assert isinstance(person, PLC.Persons.Person)
96 assert 'person_id' in person
98 site_id = self['site_id']
99 person_id = person['person_id']
101 if person_id not in self['person_ids']:
102 assert site_id not in person['site_ids']
104 self.api.db.do("INSERT INTO person_site (person_id, site_id)" \
105 " VALUES(%(person_id)d, %(site_id)d)",
111 self['person_ids'].append(person_id)
112 person['site_ids'].append(site_id)
114 def remove_person(self, person, commit = True):
116 Remove person from existing site.
119 assert 'site_id' in self
120 assert isinstance(person, PLC.Persons.Person)
121 assert 'person_id' in person
123 site_id = self['site_id']
124 person_id = person['person_id']
126 if person_id in self['person_ids']:
127 assert site_id in person['site_ids']
129 self.api.db.do("DELETE FROM person_site" \
130 " WHERE person_id = %(person_id)d" \
131 " AND site_id = %(site_id)d",
137 self['person_ids'].remove(person_id)
138 person['site_ids'].remove(site_id)
140 def add_address(self, address, commit = True):
142 Add address to existing site.
145 assert 'site_id' in self
146 assert isinstance(address, Address)
147 assert 'address_id' in address
149 site_id = self['site_id']
150 address_id = address['address_id']
152 if address_id not in self['address_ids']:
153 self.api.db.do("INSERT INTO site_address (address_id, site_id)" \
154 " VALUES(%(address_id)d, %(site_id)d)",
160 self['address_ids'].append(address_id)
162 def remove_address(self, address, commit = True):
164 Remove address from existing site.
167 assert 'site_id' in self
168 assert isinstance(address, Address)
169 assert 'address_id' in address
171 site_id = self['site_id']
172 address_id = address['address_id']
174 if address_id in self['address_ids']:
175 self.api.db.do("DELETE FROM site_address" \
176 " WHERE address_id = %(address_id)d" \
177 " AND site_id = %(site_id)d",
183 self['address_ids'].remove(address_id)
185 def delete(self, commit = True):
187 Delete existing site.
190 assert 'site_id' in self
192 # Delete accounts of all people at the site who are not
193 # members of at least one other non-deleted site.
194 persons = PLC.Persons.Persons(self.api, self['person_ids'])
195 for person in persons:
198 person_sites = Sites(self.api, person['site_ids'])
199 for person_site in person_sites:
200 if person_site['site_id'] != self['site_id']:
205 person.delete(commit = False)
207 # Delete all site addresses
208 addresses = Addresses(self.api, self['address_ids'])
209 for address in addresses:
210 address.delete(commit = False)
212 # Delete all site slices
213 slices = Slices(self.api, self['slice_ids'])
215 slice.delete(commit = False)
217 # Delete all site PCUs
218 pcus = PCUs(self.api, self['pcu_ids'])
220 pcu.delete(commit = False)
222 # Delete all site nodes
223 nodes = Nodes(self.api, self['node_ids'])
225 node.delete(commit = False)
227 # Clean up miscellaneous join tables
228 for table in ['person_site']:
229 self.api.db.do("DELETE FROM %s" \
230 " WHERE site_id = %d" % \
231 (table, self['site_id']), self)
234 self['deleted'] = True
239 Representation of row(s) from the sites table in the
243 def __init__(self, api, site_filter = None, columns = None):
244 Table.__init__(self, api, Site, columns)
246 sql = "SELECT %s FROM view_sites WHERE deleted IS False" % \
247 ", ".join(self.columns)
249 if site_filter is not None:
250 if isinstance(site_filter, (list, tuple, set)):
251 # Separate the list into integers and strings
252 ints = filter(lambda x: isinstance(x, (int, long)), site_filter)
253 strs = filter(lambda x: isinstance(x, StringTypes), site_filter)
254 site_filter = Filter(Site.fields, {'site_id': ints, 'login_base': strs})
255 sql += " AND (%s)" % site_filter.sql(api, "OR")
256 elif isinstance(site_filter, dict):
257 site_filter = Filter(Site.fields, site_filter)
258 sql += " AND (%s)" % site_filter.sql(api, "AND")