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