ae937d38e049dd811a777e241fcbdce51011ce8c
[plstackapi.git] / planetstack / core / admin.py
1 from core.models import Site
2 from core.models import *
3 from openstack.manager import OpenStackManager
4
5 from django.contrib import admin
6 from django.contrib.auth.models import Group
7 from django import forms
8 from django.utils.safestring import mark_safe
9 from django.contrib.auth.admin import UserAdmin
10 from django.contrib.admin.widgets import FilteredSelectMultiple
11 from django.contrib.auth.forms import ReadOnlyPasswordHashField
12 from django.contrib.auth.signals import user_logged_in
13 from django.utils import timezone
14 from django.contrib.contenttypes import generic
15
16 import django_evolution 
17
18 class PlStackTabularInline(admin.TabularInline):
19     exclude = ['enacted']
20
21 class ReadonlyTabularInline(PlStackTabularInline):
22     can_delete = False
23     extra = 0
24     editable_fields = []
25
26     def get_readonly_fields(self, request, obj=None):
27         fields = []
28         for field in self.model._meta.get_all_field_names():
29             if (not field == 'id'):
30                 if (field not in self.editable_fields):
31                     fields.append(field)
32         return fields
33
34     def has_add_permission(self, request):
35         return False
36
37 class TagInline(generic.GenericTabularInline):
38     model = Tag
39     exclude = ['enacted']
40     extra = 1
41
42 class NetworkLookerUpper:
43     """ This is a callable that looks up a network name in a sliver and returns\r
44         the ip address for that network.\r
45     """\r
46 \r
47     def __init__(self, name):\r
48         self.short_description = name\r
49         self.__name__ = name\r
50         self.network_name = name\r
51 \r
52     def __call__(self, obj):\r
53         if obj is not None:\r
54             for nbs in obj.networksliver_set.all():\r
55                 if (nbs.network.name == self.network_name):\r
56                     return nbs.ip\r
57         return ""
58
59     def __str__(self):
60         return self.network_name
61
62 class SliverInline(PlStackTabularInline):
63     model = Sliver
64     fields = ['ip', 'instance_name', 'slice', 'numberCores', 'image', 'node', 'deploymentNetwork']
65     extra = 0
66     readonly_fields = ['ip', 'instance_name']
67
68
69     def _declared_fieldsets(self):
70         # Return None so django will call get_fieldsets and we can insert our
71         # dynamic fields
72         return None
73
74     def get_readonly_fields(self, request, obj=None):
75         readonly_fields = super(SliverInline, self).get_readonly_fields(request, obj)
76
77         # Lookup the networks that are bound to the slivers, and add those
78         # network names to the list of readonly fields.
79
80         for sliver in obj.slivers.all():
81             for nbs in sliver.networksliver_set.all():
82                 if nbs.ip is not None:
83                     network_name = nbs.network.name
84                     if network_name not in [str(x) for x in readonly_fields]:
85                         readonly_fields.append(NetworkLookerUpper(network_name))
86
87         return readonly_fields
88
89     def get_fieldsets(self, request, obj=None):
90         form = self.get_formset(request, obj).form
91         # fields = the read/write files + the read-only fields
92         fields = self.fields
93         for fieldName in self.get_readonly_fields(request,obj):
94             if not fieldName in fields:
95                 fields.append(fieldName)
96
97         return [(None, {'fields': fields})]
98     
99
100 class SiteInline(PlStackTabularInline):
101     model = Site
102     extra = 0
103
104 class UserInline(PlStackTabularInline):
105     model = User
106     fields = ['email', 'firstname', 'lastname']
107     extra = 0
108
109 class SliceInline(PlStackTabularInline):
110     model = Slice
111     extra = 0
112
113 class RoleInline(PlStackTabularInline):
114     model = Role
115     extra = 0 
116
117 class NodeInline(PlStackTabularInline):
118     model = Node
119     extra = 0
120
121 class SitePrivilegeInline(PlStackTabularInline):
122     model = SitePrivilege
123     extra = 0
124
125     def formfield_for_foreignkey(self, db_field, request, **kwargs):
126         if db_field.name == 'site':
127             if not request.user.is_admin:
128                 # only show sites where user is an admin or pi
129                 roles = Role.objects.filter(role_type__in=['admin', 'pi'])
130                 site_privileges = SitePrivilege.objects.filter(user=request.user).filter(role__in=roles)
131                 login_bases = [site_privilege.site.login_base for site_privilege in site_privileges]
132                 sites = Site.objects.filter(login_base__in=login_bases)
133                 kwargs['queryset'] = sites
134
135         if db_field.name == 'user':
136             if not request.user.is_admin:
137                 # only show users from sites where caller has admin or pi role
138                 roles = Role.objects.filter(role_type__in=['admin', 'pi'])
139                 site_privileges = SitePrivilege.objects.filter(user=request.user).filter(role__in=roles)
140                 sites = [site_privilege.site for site_privilege in site_privileges]
141                 site_privileges = SitePrivilege.objects.filter(site__in=sites)
142                 emails = [site_privilege.user.email for site_privilege in site_privileges]
143                 users = User.objects.filter(email__in=emails)
144                 kwargs['queryset'] = users
145         return super(SitePrivilegeInline, self).formfield_for_foreignkey(db_field, request, **kwargs)
146
147 class SliceMembershipInline(PlStackTabularInline):
148     model = SliceMembership
149     extra = 0
150     fields = ('user', 'role')
151
152     def formfield_for_foreignkey(self, db_field, request, **kwargs):
153         if db_field.name == 'slice':
154             if not request.user.is_admin:
155                 # only show slices at sites where caller has admin or pi role
156                 roles = Role.objects.filter(role_type__in=['admin', 'pi'])
157                 site_privileges = SitePrivilege.objects.filter(user=request.user).filter(role__in=roles)
158                 sites = [site_privilege.site for site_privilege in site_privileges]
159                 slices = Slice.objects.filter(site__in=sites)
160                 kwargs['queryset'] = slices 
161         if db_field.name == 'user':
162             if not request.user.is_admin:
163                 # only show users from sites where caller has admin or pi role
164                 roles = Role.objects.filter(role_type__in=['admin', 'pi'])
165                 site_privileges = SitePrivilege.objects.filter(user=request.user).filter(role__in=roles)
166                 sites = [site_privilege.site for site_privilege in site_privileges]
167                 site_privileges = SitePrivilege.objects.filter(site__in=sites)
168                 emails = [site_privilege.user.email for site_privilege in site_privileges]   
169                 users = User.objects.filter(email__in=emails) 
170                 kwargs['queryset'] = list(users)
171
172         return super(SliceMembershipInline, self).formfield_for_foreignkey(db_field, request, **kwargs)
173
174 class SliceNetworkInline(PlStackTabularInline):
175     model = Network.slices.through
176     extra = 0
177     verbose_name = "Network Connection"
178     verbose_name_plural = "Network Connections"
179
180 class SliceTagInline(PlStackTabularInline):
181     model = SliceTag
182     extra = 0
183
184 class PlainTextWidget(forms.HiddenInput):
185     input_type = 'hidden'
186
187     def render(self, name, value, attrs=None):
188         if value is None:
189             value = ''
190         return mark_safe(str(value) + super(PlainTextWidget, self).render(name, value, attrs))
191
192 class PlanetStackBaseAdmin(admin.ModelAdmin):
193     save_on_top = False
194     exclude = ['enacted']
195
196 class RoleAdmin(PlanetStackBaseAdmin):
197     fieldsets = [
198         ('Role', {'fields': ['role_type']})
199     ]
200     list_display = ('role_type',)
201
202
203 class DeploymentAdminForm(forms.ModelForm):
204     sites = forms.ModelMultipleChoiceField(
205         queryset=Site.objects.all(),
206         required=False,
207         widget=FilteredSelectMultiple(
208             verbose_name=('Sites'), is_stacked=False
209         )
210     )
211     class Meta:
212         model = Deployment
213
214     def __init__(self, *args, **kwargs):
215         super(DeploymentAdminForm, self).__init__(*args, **kwargs)
216
217         if self.instance and self.instance.pk:
218             self.fields['sites'].initial = self.instance.sites.all()
219
220     def save(self, commit=True):
221         deploymentNetwork = super(DeploymentAdminForm, self).save(commit=False)
222         if commit:
223             deploymentNetwork.save()
224
225         if deploymentNetwork.pk:
226             deploymentNetwork.sites = self.cleaned_data['sites']
227             self.save_m2m()
228
229         return deploymentNetwork
230
231 class DeploymentAdmin(PlanetStackBaseAdmin):
232     form = DeploymentAdminForm
233     inlines = [NodeInline,SliverInline]
234
235     def get_formsets(self, request, obj=None):
236         for inline in self.get_inline_instances(request, obj):
237             # hide MyInline in the add view
238             if obj is None:
239                 continue
240             # give inline object access to driver and caller
241             auth = request.session.get('auth', {})
242             if request.user.site:
243                 auth['tenant'] = request.user.site.login_base
244             inline.model.os_manager = OpenStackManager(auth=auth, caller=request.user)
245             yield inline.get_formset(request, obj)
246
247 class SiteAdmin(PlanetStackBaseAdmin):
248     fieldsets = [
249         (None, {'fields': ['name', 'site_url', 'enabled', 'is_public', 'login_base', 'location']}),
250         ('Deployment Networks', {'fields': ['deployments']})
251     ]
252     list_display = ('name', 'login_base','site_url', 'enabled')
253     filter_horizontal = ('deployments',)
254     inlines = [TagInline, NodeInline, UserInline, SitePrivilegeInline]
255     search_fields = ['name']
256
257     def queryset(self, request):
258         # admins can see all keys. Users can only see sites they belong to.
259         qs = super(SiteAdmin, self).queryset(request)
260         if not request.user.is_admin:
261             valid_sites = [request.user.site.login_base]
262             roles = request.user.get_roles()
263             for tenant_list in roles.values():
264                 valid_sites.extend(tenant_list)
265             qs = qs.filter(login_base__in=valid_sites)
266         return qs
267
268     def get_formsets(self, request, obj=None):
269         for inline in self.get_inline_instances(request, obj):
270             # hide MyInline in the add view
271             if obj is None:
272                 continue
273             if isinstance(inline, SliceInline):
274                 inline.model.caller = request.user
275             yield inline.get_formset(request, obj)
276
277     def get_formsets(self, request, obj=None):
278         for inline in self.get_inline_instances(request, obj):
279             # hide MyInline in the add view
280             if obj is None:
281                 continue
282             if isinstance(inline, SliverInline):
283                 inline.model.caller = request.user
284             yield inline.get_formset(request, obj)
285
286 class SitePrivilegeAdmin(PlanetStackBaseAdmin):
287     fieldsets = [
288         (None, {'fields': ['user', 'site', 'role']})
289     ]
290     list_display = ('user', 'site', 'role')
291
292     def formfield_for_foreignkey(self, db_field, request, **kwargs):
293         if db_field.name == 'site':
294             if not request.user.is_admin:
295                 # only show sites where user is an admin or pi
296                 sites = set()
297                 for site_privilege in SitePrivilege.objects.filer(user=request.user):
298                     if site_privilege.role.role_type in ['admin', 'pi']:
299                         sites.add(site_privilege.site)
300                 kwargs['queryset'] = Site.objects.filter(site__in=list(sites))
301
302         if db_field.name == 'user':
303             if not request.user.is_admin:
304                 # only show users from sites where caller has admin or pi role
305                 roles = Role.objects.filter(role_type__in=['admin', 'pi'])
306                 site_privileges = SitePrivilege.objects.filter(user=request.user).filter(role__in=roles)
307                 sites = [site_privilege.site for site_privilege in site_privileges]
308                 site_privileges = SitePrivilege.objects.filter(site__in=sites)
309                 emails = [site_privilege.user.email for site_privilege in site_privileges]
310                 users = User.objects.filter(email__in=emails)
311                 kwargs['queryset'] = users
312
313         return super(SitePrivilegeAdmin, self).formfield_for_foreignkey(db_field, request, **kwargs)
314
315     def queryset(self, request):
316         # admins can see all privileges. Users can only see privileges at sites
317         # where they have the admin role or pi role.
318         qs = super(SitePrivilegeAdmin, self).queryset(request)
319         if not request.user.is_admin:
320             roles = Role.objects.filter(role_type__in=['admin', 'pi'])
321             site_privileges = SitePrivilege.objects.filter(user=request.user).filter(role__in=roles)
322             login_bases = [site_privilege.site.login_base for site_privilege in site_privileges]
323             sites = Site.objects.filter(login_base__in=login_bases)
324             qs = qs.filter(site__in=sites)
325         return qs
326
327 class SliceAdmin(PlanetStackBaseAdmin):
328     fields = ['name', 'site', 'serviceClass', 'description', 'slice_url']
329     list_display = ('name', 'site','serviceClass', 'slice_url')
330     inlines = [SliverInline, SliceMembershipInline, TagInline, SliceTagInline, SliceNetworkInline]
331
332     def formfield_for_foreignkey(self, db_field, request, **kwargs):
333         if db_field.name == 'site':
334             if not request.user.is_admin:
335                 # only show sites where user is a pi or admin 
336                 roles = Role.objects.filter(role_type__in=['admin', 'pi'])
337                 site_privileges = SitePrivilege.objects.filter(user=request.user).filter(role__in=roles)
338                 login_bases = [site_privilege.site.login_base for site_privilege in site_privileges]
339                 sites = Site.objects.filter(login_base__in=login_bases)
340                 kwargs['queryset'] = sites
341
342         return super(SliceAdmin, self).formfield_for_foreignkey(db_field, request, **kwargs)
343
344     def queryset(self, request):
345         # admins can see all keys. Users can only see slices they belong to.
346         qs = super(SliceAdmin, self).queryset(request)
347         if not request.user.is_admin:
348             valid_slices = []
349             roles = request.user.get_roles()
350             for tenant_list in roles.values():
351                 valid_slices.extend(tenant_list)
352             qs = qs.filter(name__in=valid_slices)
353         return qs
354
355     def get_formsets(self, request, obj=None):
356         for inline in self.get_inline_instances(request, obj):
357             # hide MyInline in the add view
358             if obj is None:
359                 continue
360             if isinstance(inline, SliverInline):
361                 inline.model.caller = request.user
362             yield inline.get_formset(request, obj)
363
364     def get_queryset(self, request):
365         qs = super(SliceAdmin, self).get_queryset(request)
366         if request.user.is_superuser:
367             return qs
368         # users can only see slices at their site
369         return qs.filter(site=request.user.site)
370
371     def save_model(self, request, obj, form, change):
372         # update openstack connection to use this site/tenant
373         obj.caller = request.user
374         obj.save() 
375
376 class SliceMembershipAdmin(PlanetStackBaseAdmin):
377     fieldsets = [
378         (None, {'fields': ['user', 'slice', 'role']})
379     ]
380     list_display = ('user', 'slice', 'role')
381
382     def formfield_for_foreignkey(self, db_field, request, **kwargs):
383         if db_field.name == 'slice':
384             if not request.user.is_admin:
385                 # only show slices at sites where caller has admin or pi role
386                 roles = Role.objects.filter(role_type__in=['admin', 'pi'])
387                 site_privileges = SitePrivilege.objects.filter(user=request.user).filter(role__in=roles)
388                 sites = [site_privilege.site for site_privilege in site_privileges]
389                 slices = Slice.objects.filter(site__in=sites)
390                 kwargs['queryset'] = slices
391         
392         if db_field.name == 'user':
393             if not request.user.is_admin:
394                 # only show users from sites where caller has admin or pi role
395                 roles = Role.objects.filter(role_type__in=['admin', 'pi'])
396                 site_privileges = SitePrivilege.objects.filter(user=request.user).filter(role__in=roles)
397                 sites = [site_privilege.site for site_privilege in site_privileges]
398                 site_privileges = SitePrivilege.objects.filter(site__in=sites)
399                 emails = [site_privilege.user.email for site_privilege in site_privileges]
400                 users = User.objects.filter(email__in=emails)
401                 kwargs['queryset'] = users
402
403         return super(SliceMembershipAdmin, self).formfield_for_foreignkey(db_field, request, **kwargs)
404
405     def queryset(self, request):
406         # admins can see all memberships. Users can only see memberships of
407         # slices where they have the admin role.
408         qs = super(SliceMembershipAdmin, self).queryset(request)
409         if not request.user.is_admin:
410             roles = Role.objects.filter(role_type__in=['admin', 'pi'])
411             site_privileges = SitePrivilege.objects.filter(user=request.user).filter(role__in=roles)
412             login_bases = [site_privilege.site.login_base for site_privilege in site_privileges]
413             sites = Site.objects.filter(login_base__in=login_bases)
414             slices = Slice.objects.filter(site__in=sites)
415             qs = qs.filter(slice__in=slices)
416         return qs
417
418     def save_model(self, request, obj, form, change):
419         # update openstack connection to use this site/tenant
420         auth = request.session.get('auth', {})
421         auth['tenant'] = obj.slice.name
422         obj.os_manager = OpenStackManager(auth=auth, caller=request.user)
423         obj.save()
424
425     def delete_model(self, request, obj):
426         # update openstack connection to use this site/tenant
427         auth = request.session.get('auth', {})
428         auth['tenant'] = obj.slice.name
429         obj.os_manager = OpenStackManager(auth=auth, caller=request.user)
430         obj.delete()
431
432
433 class ImageAdmin(admin.ModelAdmin):
434     fields = ['image_id', 'name', 'disk_format', 'container_format']
435
436 class NodeAdmin(admin.ModelAdmin):
437     list_display = ('name', 'site', 'deployment')
438     list_filter = ('deployment',)
439     inlines = [TagInline]
440
441
442 class SliverForm(forms.ModelForm):
443     class Meta:
444         model = Sliver
445         ip = forms.CharField(widget=PlainTextWidget)
446         instance_name = forms.CharField(widget=PlainTextWidget)
447         widgets = {
448             'ip': PlainTextWidget(),
449             'instance_name': PlainTextWidget(),
450         }
451
452 class ProjectAdmin(admin.ModelAdmin):
453     exclude = ['enacted']
454
455 class TagAdmin(admin.ModelAdmin):
456     exclude = ['enacted']
457
458 class SliverAdmin(PlanetStackBaseAdmin):
459     form = SliverForm
460     fieldsets = [
461         ('Sliver', {'fields': ['ip', 'instance_name', 'slice', 'numberCores', 'image', 'node', 'deploymentNetwork']})
462     ]
463     list_display = ['ip', 'instance_name', 'slice', 'numberCores', 'image', 'node', 'deploymentNetwork']
464     inlines = [TagInline]
465
466     def formfield_for_foreignkey(self, db_field, request, **kwargs):
467         if db_field.name == 'slice':
468             if not request.user.is_admin:
469                 slices = set([sm.slice.name for sm in SliceMembership.objects.filter(user=request.user)]) 
470                 kwargs['queryset'] = Slice.objects.filter(name__in=list(slices))
471
472         return super(SliverAdmin, self).formfield_for_foreignkey(db_field, request, **kwargs)
473
474     def queryset(self, request):
475         # admins can see all slivers. Users can only see slivers of 
476         # the slices they belong to.
477         qs = super(SliverAdmin, self).queryset(request)
478         if not request.user.is_admin:
479             tenants = []
480             roles = request.user.get_roles()
481             for tenant_list in roles.values():
482                 tenants.extend(tenant_list)
483             valid_slices = Slice.objects.filter(name__in=tenants)
484             qs = qs.filter(slice__in=valid_slices)
485         return qs
486
487     def get_formsets(self, request, obj=None):
488         # make some fields read only if we are updating an existing record
489         if obj == None:
490             #self.readonly_fields = ('ip', 'instance_name') 
491             self.readonly_fields = () 
492         else:
493             self.readonly_fields = () 
494             #self.readonly_fields = ('ip', 'instance_name', 'slice', 'image', 'key') 
495
496         for inline in self.get_inline_instances(request, obj):
497             # hide MyInline in the add view
498             if obj is None:
499                 continue
500             # give inline object access to driver and caller
501             auth = request.session.get('auth', {})
502             auth['tenant'] = obj.name       # meed to connect using slice's tenant
503             inline.model.os_manager = OpenStackManager(auth=auth, caller=request.user)
504             yield inline.get_formset(request, obj)
505
506     def save_model(self, request, obj, form, change):
507         # update openstack connection to use this site/tenant
508         auth = request.session.get('auth', {})
509         auth['tenant'] = obj.slice.name
510         obj.os_manager = OpenStackManager(auth=auth, caller=request.user)
511         obj.creator = request.user
512         obj.save()
513
514     def delete_model(self, request, obj):
515         # update openstack connection to use this site/tenant
516         auth = request.session.get('auth', {})
517         auth['tenant'] = obj.slice.name
518         obj.os_manager = OpenStackManager(auth=auth, caller=request.user)
519         obj.delete()
520
521 class UserCreationForm(forms.ModelForm):
522     """A form for creating new users. Includes all the required
523     fields, plus a repeated password."""
524     password1 = forms.CharField(label='Password', widget=forms.PasswordInput)
525     password2 = forms.CharField(label='Password confirmation', widget=forms.PasswordInput)
526
527     class Meta:
528         model = User
529         fields = ('email', 'firstname', 'lastname', 'phone', 'public_key', 'site')
530
531     def clean_password2(self):
532         # Check that the two password entries match
533         password1 = self.cleaned_data.get("password1")
534         password2 = self.cleaned_data.get("password2")
535         if password1 and password2 and password1 != password2:
536             raise forms.ValidationError("Passwords don't match")
537         return password2
538
539     def save(self, commit=True):
540         # Save the provided password in hashed format
541         user = super(UserCreationForm, self).save(commit=False)
542         user.password = self.cleaned_data["password1"]
543         #user.set_password(self.cleaned_data["password1"])
544         if commit:
545             user.save()
546         return user
547
548
549 class UserChangeForm(forms.ModelForm):
550     """A form for updating users. Includes all the fields on
551     the user, but replaces the password field with admin's
552     password hash display field.
553     """
554     password = ReadOnlyPasswordHashField()
555
556     class Meta:
557         model = User
558
559     def clean_password(self):
560         # Regardless of what the user provides, return the initial value.
561         # This is done here, rather than on the field, because the
562         # field does not have access to the initial value
563         return self.initial["password"]
564
565
566 class UserAdmin(UserAdmin):
567     class Meta:
568         app_label = "core"
569
570     # The forms to add and change user instances
571     form = UserChangeForm
572     add_form = UserCreationForm
573
574     # The fields to be used in displaying the User model.
575     # These override the definitions on the base UserAdmin
576     # that reference specific fields on auth.User.
577     list_display = ('email', 'site', 'firstname', 'lastname', 'is_admin', 'last_login')
578     list_filter = ('site',)
579     inlines = [SitePrivilegeInline, SliceMembershipInline]
580     fieldsets = (
581         (None, {'fields': ('email', 'password', 'site', 'is_admin', 'timezone')}),
582         ('Personal info', {'fields': ('firstname','lastname','phone', 'public_key')}),
583         #('Important dates', {'fields': ('last_login',)}),
584     )
585     add_fieldsets = (
586         (None, {
587             'classes': ('wide',),
588             'fields': ('email', 'firstname', 'lastname', 'phone', 'site', 'public_key','password1', 'password2', 'is_admin')}
589         ),
590     )
591     search_fields = ('email',)
592     ordering = ('email',)
593     filter_horizontal = ()
594
595     def formfield_for_foreignkey(self, db_field, request, **kwargs):
596         if db_field.name == 'site':
597             if not request.user.is_admin:
598                 # show sites where caller is an admin or pi 
599                 sites = []
600                 for site_privilege in SitePrivilege.objects.filer(user=request.user):
601                     if site_privilege.role.role_type in ['admin', 'pi']:
602                         sites.append(site_privilege.site.login_base)  
603                 kwargs['queryset'] = Site.objects.filter(login_base__in(list(sites)))
604
605         return super(UserAdmin, self).formfield_for_foreignkey(db_field, request, **kwargs)
606
607 class ServiceResourceInline(admin.TabularInline):
608     exclude = ['enacted']
609     model = ServiceResource
610     extra = 0
611
612 class ServiceClassAdmin(admin.ModelAdmin):
613     exclude = ['enacted']
614     list_display = ('name', 'commitment', 'membershipFee')
615     inlines = [ServiceResourceInline]
616
617 class ReservedResourceInline(admin.TabularInline):
618     exclude = ['enacted']
619     model = ReservedResource
620     extra = 0
621
622     def formfield_for_foreignkey(self, db_field, request=None, **kwargs):
623         field = super(ReservedResourceInline, self).formfield_for_foreignkey(db_field, request, **kwargs)
624
625         if db_field.name == 'resource':
626             # restrict resources to those that the slice's service class allows
627             if request._slice is not None:
628                 field.queryset = field.queryset.filter(serviceClass = request._slice.serviceClass, calendarReservable=True)
629                 if len(field.queryset) > 0:
630                     field.initial = field.queryset.all()[0]
631             else:\r
632                 field.queryset = field.queryset.none()\r
633         elif db_field.name == 'sliver':\r
634             # restrict slivers to those that belong to the slice\r
635             if request._slice is not None:\r
636                 field.queryset = field.queryset.filter(slice = request._slice)
637             else:
638                 field.queryset = field.queryset.none()\r
639 \r
640         return field
641
642 class ReservationChangeForm(forms.ModelForm):
643     class Meta:
644         model = Reservation
645
646 class ReservationAddForm(forms.ModelForm):
647     slice = forms.ModelChoiceField(queryset=Slice.objects.all(), widget=forms.Select(attrs={"onChange":"document.getElementById('id_refresh').value=1; submit()"}))
648     refresh = forms.CharField(widget=forms.HiddenInput())
649
650     class Media:
651        css = {'all': ('planetstack.css',)}   # .field-refresh { display: none; }
652
653     def clean_slice(self):
654         slice = self.cleaned_data.get("slice")
655         x = ServiceResource.objects.filter(serviceClass = slice.serviceClass, calendarReservable=True)
656         if len(x) == 0:
657             raise forms.ValidationError("The slice you selected does not have a service class that allows reservations")
658         return slice
659
660     class Meta:
661         model = Reservation
662
663 class ReservationAddRefreshForm(ReservationAddForm):
664     """ This form is displayed when the Reservation Form receives an update
665         from the Slice dropdown onChange handler. It doesn't validate the
666         data and doesn't save the data. This will cause the form to be
667         redrawn.
668     """
669
670     """ don't validate anything other than slice """
671     dont_validate_fields = ("startTime", "duration")
672
673     def full_clean(self):
674         result = super(ReservationAddForm, self).full_clean()
675
676         for fieldname in self.dont_validate_fields:
677             if fieldname in self._errors:
678                 del self._errors[fieldname]
679
680         return result
681
682     """ don't save anything """
683     def is_valid(self):
684         return False
685
686 class ReservationAdmin(admin.ModelAdmin):
687     exclude = ['enacted']
688     list_display = ('startTime', 'duration')
689     inlines = [ReservedResourceInline]
690     form = ReservationAddForm
691
692     def add_view(self, request, form_url='', extra_context=None):
693         timezone.activate(request.user.timezone)
694         request._refresh = False
695         request._slice = None
696         if request.method == 'POST':
697             # "refresh" will be set to "1" if the form was submitted due to
698             # a change in the Slice dropdown.
699             if request.POST.get("refresh","1") == "1":
700                 request._refresh = True
701                 request.POST["refresh"] = "0"
702
703             # Keep track of the slice that was selected, so the
704             # reservedResource inline can filter items for the slice.
705             request._slice = request.POST.get("slice",None)
706             if (request._slice is not None):
707                 request._slice = Slice.objects.get(id=request._slice)
708
709         result =  super(ReservationAdmin, self).add_view(request, form_url, extra_context)
710         return result
711
712     def changelist_view(self, request, extra_context = None):
713         timezone.activate(request.user.timezone)
714         return super(ReservationAdmin, self).changelist_view(request, extra_context)
715
716     def get_form(self, request, obj=None, **kwargs):
717         request._obj_ = obj
718         if obj is not None:
719             # For changes, set request._slice to the slice already set in the
720             # object.
721             request._slice = obj.slice
722             self.form = ReservationChangeForm
723         else:
724             if getattr(request, "_refresh", False):
725                 self.form = ReservationAddRefreshForm
726             else:
727                 self.form = ReservationAddForm
728         return super(ReservationAdmin, self).get_form(request, obj, **kwargs)
729
730     def get_readonly_fields(self, request, obj=None):
731         if (obj is not None):
732             # Prevent slice from being changed after the reservation has been
733             # created.
734             return ['slice']
735         else:
736             return []
737
738 class NetworkParameterTypeAdmin(admin.ModelAdmin):
739     exclude = ['enacted']
740     list_display = ("name", )
741
742 class RouterAdmin(admin.ModelAdmin):
743     exclude = ['enacted']
744     list_display = ("name", )
745
746 class RouterInline(admin.TabularInline):
747     # exclude = ['enacted']
748     model = Router.networks.through
749     extra = 0
750     verbose_name_plural = "Routers"
751     verbose_name = "Router"
752
753 class NetworkParameterInline(generic.GenericTabularInline):
754     exclude = ['enacted']
755     model = NetworkParameter
756     extra = 1
757     verbose_name_plural = "Parameters"
758     verbose_name = "Parameter"
759
760 class NetworkSliversInline(admin.TabularInline):
761     exclude = ['enacted']
762     readonly_fields = ("ip", )
763     model = NetworkSliver
764     extra = 0
765     verbose_name_plural = "Slivers"
766     verbose_name = "Sliver"
767
768 class NetworkSlicesInline(admin.TabularInline):
769     exclude = ['enacted']
770     model = NetworkSlice
771     extra = 0
772     verbose_name_plural = "Slices"
773     verbose_name = "Slice"
774
775 class NetworkAdmin(admin.ModelAdmin):
776     exclude = ['enacted']
777     list_display = ("name", "subnet", "ports", "labels")
778     readonly_fields = ("subnet", )
779     inlines = [NetworkParameterInline, NetworkSliversInline, NetworkSlicesInline, RouterInline]
780
781 class NetworkTemplateAdmin(admin.ModelAdmin):
782     exclude = ['enacted']
783     list_display = ("name", "guaranteedBandwidth", "visibility")
784
785 # register a signal that caches the user's credentials when they log in
786 def cache_credentials(sender, user, request, **kwds):
787     auth = {'username': request.POST['username'],
788             'password': request.POST['password']}
789     request.session['auth'] = auth
790 user_logged_in.connect(cache_credentials)
791
792 # Now register the new UserAdmin...
793 admin.site.register(User, UserAdmin)
794 # ... and, since we're not using Django's builtin permissions,
795 # unregister the Group model from admin.
796 admin.site.unregister(Group)
797
798 #Do not show django evolution in the admin interface
799 from django_evolution.models import Version, Evolution
800 admin.site.unregister(Version)
801 admin.site.unregister(Evolution)
802
803
804 # When debugging it is often easier to see all the classes, but for regular use 
805 # only the top-levels should be displayed
806 showAll = False
807
808 admin.site.register(Deployment, DeploymentAdmin)
809 admin.site.register(Site, SiteAdmin)
810 admin.site.register(Slice, SliceAdmin)
811 admin.site.register(Project, ProjectAdmin)
812 admin.site.register(ServiceClass, ServiceClassAdmin)
813 admin.site.register(Reservation, ReservationAdmin)
814 admin.site.register(Network, NetworkAdmin)
815 admin.site.register(Router, RouterAdmin)
816 admin.site.register(NetworkParameterType, NetworkParameterTypeAdmin)
817 admin.site.register(NetworkTemplate, NetworkTemplateAdmin)
818
819 if showAll:
820     admin.site.register(Tag, TagAdmin)
821     admin.site.register(Node, NodeAdmin)
822     admin.site.register(SliceMembership, SliceMembershipAdmin)
823     admin.site.register(SitePrivilege, SitePrivilegeAdmin)
824     admin.site.register(Role, RoleAdmin)
825     admin.site.register(Sliver, SliverAdmin)
826     admin.site.register(Image, ImageAdmin)
827