root / edumanage / models.py @ 0790d933
History | View | Annotate | Download (14.6 kB)
1 |
# -*- coding: utf-8 -*- vim:fileencoding=utf-8:
|
---|---|
2 |
# vim: tabstop=4:shiftwidth=4:softtabstop=4:expandtab
|
3 |
|
4 |
'''
|
5 |
TODO main description
|
6 |
'''
|
7 |
|
8 |
from django.db import models |
9 |
from django.utils.translation import ugettext as _ |
10 |
|
11 |
from django.contrib.contenttypes.models import ContentType |
12 |
from django.contrib.contenttypes import generic |
13 |
|
14 |
|
15 |
LANGS = ( |
16 |
('en', 'English' ), |
17 |
('el', 'Ελληνικά'), |
18 |
) |
19 |
|
20 |
|
21 |
ERTYPES = ( |
22 |
(1, 'IdP only' ), |
23 |
(2, 'SP only'), |
24 |
(3, 'IdP and SP'), |
25 |
) |
26 |
|
27 |
RADPROTOS = ( |
28 |
('radius', 'traditional RADIUS over UDP' ), |
29 |
('radius-tcp', 'RADIUS over TCP (RFC6613)'), |
30 |
('radius-tls', 'RADIUS over TLS (RFC6614)'), |
31 |
('radius-dtls', 'RADIUS over datagram TLS (RESERVED)'), |
32 |
) |
33 |
|
34 |
|
35 |
class Name_i18n(models.Model): |
36 |
'''
|
37 |
Name in a particular language
|
38 |
'''
|
39 |
|
40 |
name = models.CharField(max_length=80)
|
41 |
lang = models.CharField(max_length=5, choices=LANGS)
|
42 |
content_type = models.ForeignKey(ContentType, blank=True, null=True) |
43 |
object_id = models.PositiveIntegerField(blank=True, null=True) |
44 |
content_object = generic.GenericForeignKey('content_type', 'object_id') |
45 |
|
46 |
def __unicode__(self): |
47 |
return self.name |
48 |
|
49 |
|
50 |
class Contact(models.Model): |
51 |
'''
|
52 |
Contact
|
53 |
'''
|
54 |
|
55 |
firstname = models.CharField(max_length=80, db_column='contact_firstname') |
56 |
lastname = models.CharField(max_length=80, db_column='contact_lastname') |
57 |
email = models.CharField(max_length=80, db_column='contact_email') |
58 |
phone = models.CharField(max_length=80, db_column='contact_phone') |
59 |
|
60 |
def __unicode__(self): |
61 |
return '%s %s <%s> (%s)' % (self.firstname, self.lastname, self.email, self.phone) |
62 |
|
63 |
|
64 |
class InstitutionContactPool(models.Model): |
65 |
contact = models.OneToOneField(Contact) |
66 |
institution = models.ForeignKey("Institution")
|
67 |
|
68 |
def __unicode__(self): |
69 |
return u"%s:%s" %(self.contact, self.institution) |
70 |
|
71 |
class URL_i18n(models.Model): |
72 |
'''
|
73 |
URL of a particular type in a particular language
|
74 |
'''
|
75 |
|
76 |
URLTYPES = ( |
77 |
('info', 'Info' ), |
78 |
('policy', 'Policy'), |
79 |
) |
80 |
url = models.CharField(max_length=180, db_column='URL') |
81 |
lang = models.CharField(max_length=5, choices=LANGS)
|
82 |
urltype = models.CharField(max_length=10, choices=URLTYPES, db_column='type') |
83 |
content_type = models.ForeignKey(ContentType, blank=True, null=True) |
84 |
object_id = models.PositiveIntegerField(blank=True, null=True) |
85 |
content_object = generic.GenericForeignKey('content_type', 'object_id') |
86 |
|
87 |
def __unicode__(self): |
88 |
return self.url |
89 |
|
90 |
class InstRealm(models.Model): |
91 |
'''
|
92 |
Realm of an IdP Institution
|
93 |
'''
|
94 |
# accept if instid.ertype: 1 (idp) or 3 (idpsp)
|
95 |
realm = models.CharField(max_length=160)
|
96 |
instid = models.ForeignKey("Institution")
|
97 |
proxyto = models.ManyToManyField("InstServer")
|
98 |
|
99 |
def __unicode__(self): |
100 |
return 'Realm: %s' % self.realm |
101 |
|
102 |
|
103 |
def get_servers(self): |
104 |
return ",".join(["%s"%x for x in self.proxyto.all()]) |
105 |
|
106 |
|
107 |
class InstServer(models.Model): |
108 |
'''
|
109 |
Server of an Institution
|
110 |
'''
|
111 |
instid = models.ForeignKey("Institution")
|
112 |
ertype = models.PositiveIntegerField(max_length=1, choices=ERTYPES, db_column='type') |
113 |
# ertype:
|
114 |
# 1: accept if instid.ertype: 1 (idp) or 3 (idpsp)
|
115 |
# 2: accept if instid.ertype: 2 (sp) or 3 (idpsp)
|
116 |
# 3: accept if instid.ertype: 3 (idpsp)
|
117 |
|
118 |
# hostname/ipaddr or descriptive label of server
|
119 |
name = models.CharField(max_length=80, help_text="Descriptive label", null=True, blank=True) # ** (acts like a label) |
120 |
# hostname/ipaddr of server, overrides name
|
121 |
host = models.CharField(max_length=80, help_text="IP address of FQDN hostname") # Handling with FQDN parser or ipaddr (google lib) * !!! Add help text to render it in template (mandatory, unique) |
122 |
#TODO: Add description field or label field
|
123 |
# accept if type: 1 (idp) or 3 (idpsp) (for the folowing 4 fields)
|
124 |
port = models.PositiveIntegerField(max_length=5, null=True, blank=True) # TODO: Also ignore while exporting XML |
125 |
acct_port = models.PositiveIntegerField(max_length=5, null=True, blank=True) |
126 |
timeout = models.PositiveIntegerField(max_length=2, null=True, blank=True) |
127 |
retry = models.PositiveIntegerField(max_length=2, null=True, blank=True) |
128 |
|
129 |
status_server = models.BooleanField() |
130 |
secret = models.CharField(max_length=16)
|
131 |
proto = models.CharField(max_length=12, choices=RADPROTOS)
|
132 |
ts = models.DateTimeField(auto_now=True)
|
133 |
|
134 |
def __unicode__(self): |
135 |
return _('Server: %(servername)s, Type: %(ertype)s') % { |
136 |
# but name is many-to-many from institution
|
137 |
#'inst': self.instid,
|
138 |
'servername': self.name, |
139 |
# the human-readable name would be nice here
|
140 |
'ertype': self.ertype, |
141 |
} |
142 |
|
143 |
def get_name(self): |
144 |
if self.name: |
145 |
return self.name |
146 |
return self.host |
147 |
|
148 |
|
149 |
class InstRealmMon(models.Model): |
150 |
'''
|
151 |
Realm of an IdP Institution to be monitored
|
152 |
'''
|
153 |
|
154 |
MONTYPES = ( |
155 |
('local', 'Institution provides account for the NRO to monitor the realm' ), |
156 |
('proxyback', 'Institution proxies the realm back to the NRO'), |
157 |
) |
158 |
|
159 |
instid = models.ForeignKey("Institution")
|
160 |
realm = models.CharField(max_length=20)
|
161 |
mon_type = models.CharField(max_length=8, choices=MONTYPES)
|
162 |
|
163 |
def __unicode__(self): |
164 |
return _('Institution: %(inst)s, Monitored Realm: %(monrealm)s, Monitoring Type: %(montype)s') % { |
165 |
# but name is many-to-many from institution
|
166 |
'inst': self.instid.name, |
167 |
'monrealm': self.realm, |
168 |
'montype': self.mon_type, |
169 |
} |
170 |
|
171 |
class MonProxybackClient(models.Model): |
172 |
'''
|
173 |
Server of an Institution that will be proxying back requests for a monitored realm
|
174 |
'''
|
175 |
|
176 |
instrealmmonid = models.ForeignKey("InstRealmMon")
|
177 |
# hostname/ipaddr or descriptive label of server
|
178 |
name = models.CharField(max_length=80)
|
179 |
# hostname/ipaddr of server, overrides name
|
180 |
host = models.CharField(max_length=80)
|
181 |
status_server = models.BooleanField() |
182 |
secret = models.CharField(max_length=16)
|
183 |
proto = models.CharField(max_length=12, choices=RADPROTOS)
|
184 |
ts = models.DateTimeField(auto_now=True)
|
185 |
|
186 |
def __unicode__(self): |
187 |
return _('Institution: %(inst)s, Monitored Realm: %(monrealm)s, Proxyback Client: %(servername)s') % { |
188 |
# but name is many-to-many from institution
|
189 |
'inst': self.instid.name, |
190 |
'monrealm': self.instrealmmonid.realm, |
191 |
'servername': self.name, |
192 |
} |
193 |
|
194 |
class MonLocalEAPOLData(models.Model): |
195 |
'''
|
196 |
EAPOL data for an old-style monitored realm
|
197 |
'''
|
198 |
|
199 |
EAPTYPES = ( |
200 |
('PEAP', 'EAP-PEAP' ), |
201 |
('TTLS', 'EAP-TTLS'), |
202 |
('TLS', 'EAP-TLS'), |
203 |
) |
204 |
EAP2TYPES = ( |
205 |
('PAP', 'PAP' ), |
206 |
('CHAP', 'CHAP'), |
207 |
('MS-CHAPv2', 'MS-CHAPv2'), |
208 |
) |
209 |
MONRESPTYPES = ( |
210 |
('accept', 'Access-Accept expected' ), |
211 |
('reject', 'Access-Reject expected'), |
212 |
('both', 'RESERVED'), |
213 |
) |
214 |
|
215 |
instrealmmonid = models.ForeignKey("InstRealmMon")
|
216 |
eap_method = models.CharField(max_length=16, choices=EAPTYPES)
|
217 |
phase2 = models.CharField(max_length=16, choices=EAP2TYPES)
|
218 |
# only local-part, no realm
|
219 |
username = models.CharField(max_length=24)
|
220 |
passwp = models.CharField(max_length=24, db_column='pass') |
221 |
cert = models.CharField(max_length=32)
|
222 |
exp_response = models.CharField(max_length=6, choices=MONRESPTYPES)
|
223 |
|
224 |
def __unicode__(self): |
225 |
return _('Institution: %(inst)s, Monitored Realm: %(monrealm)s, EAP Method: %(eapmethod)s, Phase 2: %(phase2)s, Username: %(username)s') % { |
226 |
# but name is many-to-many from institution
|
227 |
'inst': self.instid.name, |
228 |
'monrealm': self.instrealmmonid.realm, |
229 |
'eapmethod': self.eap_method, |
230 |
'phase2': self.phase2, |
231 |
'username': self.username, |
232 |
} |
233 |
|
234 |
class ServiceLoc(models.Model): |
235 |
'''
|
236 |
Service Location of an SP/IdPSP Institution
|
237 |
'''
|
238 |
|
239 |
ENCTYPES = ( |
240 |
('WPA/TKIP', 'WPA-TKIP' ), |
241 |
('WPA/AES', 'WPA-AES'), |
242 |
('WPA2/TKIP', 'WPA2-TKIP'), |
243 |
('WPA2/AES', 'WPA2-AES'), |
244 |
) |
245 |
|
246 |
# accept if institutionid.ertype: 2 (sp) or 3 (idpsp)
|
247 |
institutionid = models.ForeignKey("Institution")
|
248 |
longitude = models.DecimalField(max_digits=8, decimal_places=6) |
249 |
latitude = models.DecimalField(max_digits=8, decimal_places=6) |
250 |
# TODO: multiple names can be specified [...] name in English is required
|
251 |
loc_name = generic.GenericRelation(Name_i18n) |
252 |
address_street = models.CharField(max_length=96)
|
253 |
address_city = models.CharField(max_length=64)
|
254 |
contact = models.ManyToManyField(Contact) |
255 |
SSID = models.CharField(max_length=16)
|
256 |
enc_level = models.CharField(max_length=10, choices=ENCTYPES)
|
257 |
port_restrict = models.BooleanField() |
258 |
transp_proxy = models.BooleanField() |
259 |
IPv6 = models.BooleanField() |
260 |
NAT = models.BooleanField() |
261 |
AP_no = models.PositiveIntegerField(max_length=3)
|
262 |
wired = models.BooleanField() |
263 |
# only urltype = 'info' should be accepted here
|
264 |
url = generic.GenericRelation(URL_i18n, blank=True, null=True) |
265 |
ts = models.DateTimeField(auto_now=True)
|
266 |
|
267 |
def __unicode__(self): |
268 |
return _('Institution: %(inst)s, Service Location: %(locname)s') % { |
269 |
# but name is many-to-many from institution
|
270 |
'inst': self.institutionid, |
271 |
# but locname is many-to-many
|
272 |
'locname': self.loc_name, |
273 |
} |
274 |
|
275 |
|
276 |
def get_name(self, lang=None): |
277 |
name = ', '.join([i.name for i in self.loc_name.all()]) |
278 |
if not lang: |
279 |
return name
|
280 |
else:
|
281 |
try:
|
282 |
name = self.loc_name.get(lang=lang)
|
283 |
return name
|
284 |
except Exception as e: |
285 |
return name
|
286 |
|
287 |
class Institution(models.Model): |
288 |
'''
|
289 |
Institution
|
290 |
'''
|
291 |
|
292 |
realmid = models.ForeignKey("Realm")
|
293 |
org_name = generic.GenericRelation(Name_i18n) |
294 |
ertype = models.PositiveIntegerField(max_length=1, choices=ERTYPES, db_column='type') |
295 |
|
296 |
def __unicode__(self): |
297 |
return "%s" % ', '.join([i.name for i in self.org_name.all()]) |
298 |
|
299 |
|
300 |
def get_name(self, lang=None): |
301 |
name = ', '.join([i.name for i in self.org_name.all()]) |
302 |
if not lang: |
303 |
return name
|
304 |
else:
|
305 |
try:
|
306 |
name = self.org_name.get(lang=lang)
|
307 |
return name
|
308 |
except Exception as e: |
309 |
return name
|
310 |
|
311 |
|
312 |
class InstitutionDetails(models.Model): |
313 |
'''
|
314 |
Institution Details
|
315 |
'''
|
316 |
institution = models.OneToOneField(Institution) |
317 |
# TODO: multiple names can be specified [...] name in English is required
|
318 |
address_street = models.CharField(max_length=96)
|
319 |
address_city = models.CharField(max_length=64)
|
320 |
contact = models.ManyToManyField(Contact) |
321 |
url = generic.GenericRelation(URL_i18n) |
322 |
# accept if ertype: 2 (sp) or 3 (idpsp) (Applies to the following field)
|
323 |
oper_name = models.CharField(max_length=24, null=True, blank=True) |
324 |
# accept if ertype: 1 (idp) or 3 (idpsp) (Applies to the following field)
|
325 |
number_user = models.PositiveIntegerField(max_length=6, null=True, blank=True) |
326 |
number_id = models.PositiveIntegerField(max_length=6)
|
327 |
ts = models.DateTimeField(auto_now=True)
|
328 |
|
329 |
def __unicode__(self): |
330 |
return _('Institution: %(inst)s, Type: %(ertype)s') % { |
331 |
# but name is many-to-many from institution
|
332 |
'inst': ', '.join([i.name for i in self.institution.org_name.all()]), |
333 |
'ertype': self.institution.ertype, |
334 |
} |
335 |
|
336 |
|
337 |
|
338 |
class Realm(models.Model): |
339 |
'''
|
340 |
Realm
|
341 |
'''
|
342 |
|
343 |
COUNTRIES = ( |
344 |
('gr', 'Greece' ), |
345 |
) |
346 |
|
347 |
country = models.CharField(max_length=2, choices=COUNTRIES)
|
348 |
stype = models.PositiveIntegerField(max_length=1, default=0, editable=False) |
349 |
# TODO: multiple names can be specified [...] name in English is required
|
350 |
org_name = generic.GenericRelation(Name_i18n) |
351 |
address_street = models.CharField(max_length=32)
|
352 |
address_city = models.CharField(max_length=24)
|
353 |
contact = models.ManyToManyField(Contact) |
354 |
url = generic.GenericRelation(URL_i18n) |
355 |
ts = models.DateTimeField(auto_now=True)
|
356 |
|
357 |
def __unicode__(self): |
358 |
return _('Country: %(country)s, NRO: %(orgname)s') % { |
359 |
# but name is many-to-many from institution
|
360 |
'orgname': ', '.join([i.name for i in self.org_name.all()]), |
361 |
'country': self.country, |
362 |
} |
363 |
|
364 |
|
365 |
# TODO: this represents a *database view* "realm_data", find a better way to write it
|
366 |
class RealmData(models.Model): |
367 |
'''
|
368 |
Realm statistics
|
369 |
'''
|
370 |
|
371 |
realmid = models.OneToOneField(Realm) |
372 |
# db: select count(institution.id) as number_inst from institution, realm where institution.realmid == realm.realmid
|
373 |
number_inst = models.PositiveIntegerField(max_length=5, editable=False) |
374 |
# db: select sum(institution.number_user) as number_user from institution, realm where institution.realmid == realm.realmid
|
375 |
number_user = models.PositiveIntegerField(max_length=9, editable=False) |
376 |
# db: select sum(institution.number_id) as number_id from institution, realm where institution.realmid == realm.realmid
|
377 |
number_id = models.PositiveIntegerField(max_length=9, editable=False) |
378 |
# db: select count(institution.id) as number_IdP from institution, realm where institution.realmid == realm.realmid and institution.type == 1
|
379 |
number_IdP = models.PositiveIntegerField(max_length=5, editable=False) |
380 |
# db: select count(institution.id) as number_SP from institution, realm where institution.realmid == realm.realmid and institution.type == 2
|
381 |
number_SP = models.PositiveIntegerField(max_length=5, editable=False) |
382 |
# db: select count(institution.id) as number_IdPSP from institution, realm where institution.realmid == realm.realmid and institution.type == 3
|
383 |
number_IdPSP = models.PositiveIntegerField(max_length=5, editable=False) |
384 |
# db: select greatest(max(realm.ts), max(institution.ts)) as ts from institution, realm where institution.realmid == realm.realmid
|
385 |
ts = models.DateTimeField(editable=False)
|
386 |
|
387 |
def __unicode__(self): |
388 |
return _('Country: %(country)s, NRO: %(orgname)s, Institutions: %(inst)s, IdPs: %(idp)s, SPs: %(sp)s, IdPSPs: %(idpsp)s, Users: %(numuser)s, Identities: %(numid)s') % { |
389 |
# but name is many-to-many from institution
|
390 |
'orgname': self.org_name, |
391 |
'country': self.country, |
392 |
'inst': self.number_inst, |
393 |
'idp': self.number_IdP, |
394 |
'sp': self.number_SP, |
395 |
'idpsp': self.number_IdPSP, |
396 |
'numuser': self.number_user, |
397 |
'numid': self.number_id, |
398 |
} |