Statistics
| Branch: | Tag: | Revision:

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
            }