blob: 0329cd6bd85807e4c4fef13270c591c29b38384c [file] [log] [blame]
Siobhan Tully30fd4292013-05-10 08:59:56 -04001from core.models import Site
2from core.models import *
3from openstack.manager import OpenStackManager
Tony Macke59a7c82013-04-27 11:08:10 -04004
Tony Mack7130ac32013-03-22 21:58:00 -04005from django.contrib import admin
Siobhan Tully53437282013-04-26 19:30:27 -04006from django.contrib.auth.models import Group
Siobhan Tully4bc09f22013-04-10 21:15:21 -04007from django import forms
Tony Mackd90cdbf2013-04-16 22:48:40 -04008from django.utils.safestring import mark_safe
Tony Mack7130ac32013-03-22 21:58:00 -04009from django.contrib.auth.admin import UserAdmin
Siobhan Tully4bc09f22013-04-10 21:15:21 -040010from django.contrib.admin.widgets import FilteredSelectMultiple
Siobhan Tully53437282013-04-26 19:30:27 -040011from django.contrib.auth.forms import ReadOnlyPasswordHashField
Tony Mack31c2b8f2013-04-26 20:01:42 -040012from django.contrib.auth.signals import user_logged_in
Tony Mack7130ac32013-03-22 21:58:00 -040013
Siobhan Tully4bc09f22013-04-10 21:15:21 -040014
15class ReadonlyTabularInline(admin.TabularInline):
16 can_delete = False
17 extra = 0
18 editable_fields = []
19
20 def get_readonly_fields(self, request, obj=None):
21 fields = []
22 for field in self.model._meta.get_all_field_names():
23 if (not field == 'id'):
24 if (field not in self.editable_fields):
25 fields.append(field)
26 return fields
27
28 def has_add_permission(self, request):
29 return False
30
31class SliverInline(admin.TabularInline):
32 model = Sliver
Tony Mack3777b012013-05-07 21:38:06 -040033 fields = ['ip', 'instance_name', 'slice', 'numberCores', 'image', 'key', 'node', 'deploymentNetwork']
Siobhan Tully4bc09f22013-04-10 21:15:21 -040034 extra = 0
Tony Mack3777b012013-05-07 21:38:06 -040035 #readonly_fields = ['ip', 'instance_name', 'image']
36 readonly_fields = ['ip', 'instance_name']
Siobhan Tully4bc09f22013-04-10 21:15:21 -040037
38class SiteInline(admin.TabularInline):
39 model = Site
40 extra = 0
41
Siobhan Tully30fd4292013-05-10 08:59:56 -040042class UserInline(admin.TabularInline):
43 model = User
Siobhan Tully47ae1b52013-05-10 15:53:14 -040044 fields = ['email', 'firstname', 'lastname']
Siobhan Tully30fd4292013-05-10 08:59:56 -040045 extra = 0
46
Tony Mack00d361f2013-04-28 10:28:42 -040047class SliceInline(admin.TabularInline):
48 model = Slice
49 extra = 0
50
Tony Mack00d361f2013-04-28 10:28:42 -040051class RoleInline(admin.TabularInline):
52 model = Role
53 extra = 0
54
Siobhan Tully4bc09f22013-04-10 21:15:21 -040055class NodeInline(admin.TabularInline):
56 model = Node
57 extra = 0
58
Siobhan Tullyaa1bcd52013-05-10 12:43:09 -040059class SitePrivilegeInline(admin.TabularInline):
60 model = SitePrivilege
61 extra = 0
62
63class SliceMembershipInline(admin.TabularInline):
64 model = SliceMembership
65 extra = 0
66
Tony Mack5e71a662013-05-03 23:30:41 -040067class PlainTextWidget(forms.HiddenInput):
68 input_type = 'hidden'
69
70 def render(self, name, value, attrs=None):
71 if value is None:
72 value = ''
Tony Mack1d6b85f2013-05-07 18:49:14 -040073 return mark_safe(str(value) + super(PlainTextWidget, self).render(name, value, attrs))
Tony Mack9bcbe4f2013-04-29 08:13:27 -040074
Siobhan Tully4bc09f22013-04-10 21:15:21 -040075class PlanetStackBaseAdmin(admin.ModelAdmin):
76 save_on_top = False
77
Tony Mackfdd4d802013-04-27 13:02:33 -040078class OSModelAdmin(PlanetStackBaseAdmin):
Tony Mackd685bfa2013-05-02 10:09:51 -040079 """Attach client connection to openstack on delete() and save()"""
Tony Mack79748612013-05-01 14:52:03 -040080
Tony Mackfdd4d802013-04-27 13:02:33 -040081 def save_model(self, request, obj, form, change):
Tony Mack38e247c2013-05-05 11:48:14 -040082 if request.user.site:
83 auth = request.session.get('auth', {})
84 auth['tenant'] = request.user.site.login_base
85 obj.os_manager = OpenStackManager(auth=auth, caller=request.user)
Tony Mackfdd4d802013-04-27 13:02:33 -040086 obj.save()
87
88 def delete_model(self, request, obj):
Tony Mack38e247c2013-05-05 11:48:14 -040089 if request.user.site:
90 auth = request.session.get('auth', {})
91 auth['tenant'] = request.user.site.login_base
92 obj.os_manager = OpenStackManager(auth=auth, caller=request.user)
Tony Mackd685bfa2013-05-02 10:09:51 -040093 obj.delete()
Tony Mack9bcbe4f2013-04-29 08:13:27 -040094
Tony Mackd685bfa2013-05-02 10:09:51 -040095class RoleAdmin(OSModelAdmin):
Tony Mack9bcbe4f2013-04-29 08:13:27 -040096 fieldsets = [
97 ('Role', {'fields': ['role_type']})
98 ]
99 list_display = ('role_type',)
Tony Mackfdd4d802013-04-27 13:02:33 -0400100
Tony Mack02755d42013-05-02 00:00:10 -0400101
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400102class DeploymentNetworkAdminForm(forms.ModelForm):
103 sites = forms.ModelMultipleChoiceField(
104 queryset=Site.objects.all(),
105 required=False,
106 widget=FilteredSelectMultiple(
107 verbose_name=('Sites'), is_stacked=False
108 )
109 )
110 class Meta:
111 model = DeploymentNetwork
112
113 def __init__(self, *args, **kwargs):
114 super(DeploymentNetworkAdminForm, self).__init__(*args, **kwargs)
115
116 if self.instance and self.instance.pk:
117 self.fields['sites'].initial = self.instance.sites.all()
118
119 def save(self, commit=True):
120 deploymentNetwork = super(DeploymentNetworkAdminForm, self).save(commit=False)
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400121 if commit:
122 deploymentNetwork.save()
123
124 if deploymentNetwork.pk:
125 deploymentNetwork.sites = self.cleaned_data['sites']
126 self.save_m2m()
127
128 return deploymentNetwork
129
130class DeploymentNetworkAdmin(PlanetStackBaseAdmin):
131 form = DeploymentNetworkAdminForm
Siobhan Tullyaa1bcd52013-05-10 12:43:09 -0400132 inlines = [NodeInline,SliverInline]
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400133
Tony Mack5cd13202013-05-01 21:48:38 -0400134 def get_formsets(self, request, obj=None):
135 for inline in self.get_inline_instances(request, obj):
136 # hide MyInline in the add view
137 if obj is None:
138 continue
139 # give inline object access to driver and caller
Tony Macked163d72013-05-02 20:05:42 -0400140 auth = request.session.get('auth', {})
Siobhan Tully73291342013-05-10 10:50:08 -0400141 if request.user.site:
142 auth['tenant'] = request.user.site.login_base
Tony Macked163d72013-05-02 20:05:42 -0400143 inline.model.os_manager = OpenStackManager(auth=auth, caller=request.user)
Tony Mack5cd13202013-05-01 21:48:38 -0400144 yield inline.get_formset(request, obj)
145
Tony Mackfdd4d802013-04-27 13:02:33 -0400146class SiteAdmin(OSModelAdmin):
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400147 fieldsets = [
148 (None, {'fields': ['name', 'site_url', 'enabled', 'is_public', 'login_base']}),
149 ('Location', {'fields': ['latitude', 'longitude']}),
150 ('Deployment Networks', {'fields': ['deployments']})
151 ]
152 list_display = ('name', 'login_base','site_url', 'enabled')
153 filter_horizontal = ('deployments',)
Siobhan Tullyaa1bcd52013-05-10 12:43:09 -0400154 inlines = [NodeInline, UserInline, SitePrivilegeInline]
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400155 search_fields = ['name']
156
Tony Mack04062832013-05-10 08:22:44 -0400157 def queryset(self, request):
158 # admins can see all keys. Users can only see sites they belong to.
159 qs = super(SiteAdmin, self).queryset(request)
160 if not request.user.is_admin:
161 valid_sites = [request.user.site.login_base]
162 roles = request.user.get_roles()
163 for tenant_list in roles.values():
164 valid_sites.extend(tenant_list)
165 qs = qs.filter(login_base__in=valid_sites)
166 return qs
167
Tony Mack5cd13202013-05-01 21:48:38 -0400168 def get_formsets(self, request, obj=None):
169 for inline in self.get_inline_instances(request, obj):
170 # hide MyInline in the add view
171 if obj is None:
172 continue
173 # give inline object access to driver and caller
Tony Mack60722062013-05-02 10:57:04 -0400174 auth = request.session.get('auth', {})
Siobhan Tully30fd4292013-05-10 08:59:56 -0400175 #auth['tenant'] = request.user.site.login_base
Tony Mack60722062013-05-02 10:57:04 -0400176 inline.model.os_manager = OpenStackManager(auth=auth, caller=request.user)
Tony Mack5cd13202013-05-01 21:48:38 -0400177 yield inline.get_formset(request, obj)
178
Tony Mack9bcbe4f2013-04-29 08:13:27 -0400179class SitePrivilegeAdmin(PlanetStackBaseAdmin):
Tony Mack00d361f2013-04-28 10:28:42 -0400180 fieldsets = [
181 (None, {'fields': ['user', 'site', 'role']})
182 ]
183 list_display = ('user', 'site', 'role')
184
Tony Mack04062832013-05-10 08:22:44 -0400185 def queryset(self, request):
186 # admins can see all privileges. Users can only see privileges at sites
187 # where they have the admin role.
188 qs = super(SitePrivilegeAdmin, self).queryset(request)
189 if not request.user.is_admin:
190 roles = request.user.get_roles()
191 tenants = []
192 for (role, tenant_list) in roles:
193 if role == 'admin':
194 tenants.extend(tenant_list)
195 valid_sites = Sites.objects.filter(login_base__in=tenants)
196 qs = qs.filter(site__in=valid_sites)
197 return qs
198
Tony Mack9bcbe4f2013-04-29 08:13:27 -0400199 def save_model(self, request, obj, form, change):
200 # update openstack connection to use this site/tenant
Tony Mack93048c22013-05-02 11:20:26 -0400201 auth = request.session.get('auth', {})
Siobhan Tully30fd4292013-05-10 08:59:56 -0400202 #auth['tenant'] = obj.site.login_base
Tony Mack93048c22013-05-02 11:20:26 -0400203 obj.os_manager = OpenStackManager(auth=auth, caller=request.user)
Tony Mack9bcbe4f2013-04-29 08:13:27 -0400204 obj.save()
205
206 def delete_model(self, request, obj):
207 # update openstack connection to use this site/tenant
Tony Mack93048c22013-05-02 11:20:26 -0400208 auth = request.session.get('auth', {})
Siobhan Tully30fd4292013-05-10 08:59:56 -0400209 #auth['tenant'] = obj.site.login_base
Tony Mack93048c22013-05-02 11:20:26 -0400210 obj.os_manager = OpenStackManager(auth=auth, caller=request.user)
Tony Mack9bcbe4f2013-04-29 08:13:27 -0400211 obj.delete()
212
Tony Mackfdd4d802013-04-27 13:02:33 -0400213class KeyAdmin(OSModelAdmin):
Tony Mack759b57a2013-04-14 21:03:31 -0400214 fieldsets = [
Siobhan Tully73291342013-05-10 10:50:08 -0400215 ('Key', {'fields': ['key', 'type', 'blacklisted']})
Tony Mack759b57a2013-04-14 21:03:31 -0400216 ]
Siobhan Tully73291342013-05-10 10:50:08 -0400217 list_display = ['key', 'type', 'blacklisted']
Tony Mack8484bdb2013-04-14 20:26:03 -0400218
Siobhan Tully73291342013-05-10 10:50:08 -0400219 #def queryset(self, request):
Tony Mackc14de8f2013-05-09 21:44:17 -0400220 # admins can see all keys. Users can only see their own key.
Siobhan Tully73291342013-05-10 10:50:08 -0400221 #if request.user.is_admin:
222 # qs = super(KeyAdmin, self).queryset(request)
223 #else:
224 # qs = Key.objects.filter(user=request.user)
Scott Baker133c9212013-05-17 09:09:11 -0700225 #return qs
226
Tony Mackfdd4d802013-04-27 13:02:33 -0400227class SliceAdmin(OSModelAdmin):
Siobhan Tully30fd4292013-05-10 08:59:56 -0400228 fields = ['name', 'site', 'serviceClass', 'description', 'slice_url']
229 list_display = ('name', 'site','serviceClass', 'slice_url')
Siobhan Tully47ae1b52013-05-10 15:53:14 -0400230 inlines = [SliverInline, SliceMembershipInline]
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400231
Tony Mack04062832013-05-10 08:22:44 -0400232 def queryset(self, request):
233 # admins can see all keys. Users can only see slices they belong to.
234 qs = super(SliceAdmin, self).queryset(request)
235 if not request.user.is_admin:
236 valid_slices = []
237 roles = request.user.get_roles()
238 for tenant_list in roles.values():
239 valid_slices.extend(tenant_list)
240 qs = qs.filter(name__in=valid_slices)
241 return qs
242
Tony Mack79748612013-05-01 14:52:03 -0400243 def get_formsets(self, request, obj=None):
244 for inline in self.get_inline_instances(request, obj):
245 # hide MyInline in the add view
246 if obj is None:
247 continue
248 # give inline object access to driver and caller
Tony Mack93048c22013-05-02 11:20:26 -0400249 auth = request.session.get('auth', {})
250 auth['tenant'] = obj.name # meed to connect using slice's tenant
251 inline.model.os_manager = OpenStackManager(auth=auth, caller=request.user)
Tony Mack79748612013-05-01 14:52:03 -0400252 yield inline.get_formset(request, obj)
253
Tony Mackfdd4d802013-04-27 13:02:33 -0400254 def get_queryset(self, request):
255 qs = super(SliceAdmin, self).get_queryset(request)
256 if request.user.is_superuser:
257 return qs
258 # users can only see slices at their site
259 return qs.filter(site=request.user.site)
260
Tony Mack9bcbe4f2013-04-29 08:13:27 -0400261class SliceMembershipAdmin(PlanetStackBaseAdmin):
Tony Mack00d361f2013-04-28 10:28:42 -0400262 fieldsets = [
263 (None, {'fields': ['user', 'slice', 'role']})
264 ]
265 list_display = ('user', 'slice', 'role')
Tony Mack00d361f2013-04-28 10:28:42 -0400266
Tony Mack04062832013-05-10 08:22:44 -0400267 def queryset(self, request):
268 # admins can see all memberships. Users can only see memberships of
269 # slices where they have the admin role.
270 qs = super(SliceMembershipAdmin, self).queryset(request)
271 if not request.user.is_admin:
272 roles = request.user.get_roles()
273 tenants = []
274 for (role, tenant_list) in roles:
275 if role == 'admin':
276 tenants.extend(tenant_list)
277 valid_slices = Slice.objects.filter(name__in=tenants)
278 qs = qs.filter(slice__in=valid_slices)
279 return qs
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400280
Tony Mack9bcbe4f2013-04-29 08:13:27 -0400281 def save_model(self, request, obj, form, change):
Tony Mack951dab42013-05-02 19:51:45 -0400282 # update openstack connection to use this site/tenant
283 auth = request.session.get('auth', {})
284 auth['tenant'] = obj.slice.name
285 obj.os_manager = OpenStackManager(auth=auth, caller=request.user)
Tony Mack9bcbe4f2013-04-29 08:13:27 -0400286 obj.save()
287
288 def delete_model(self, request, obj):
Tony Mack951dab42013-05-02 19:51:45 -0400289 # update openstack connection to use this site/tenant
290 auth = request.session.get('auth', {})
291 auth['tenant'] = obj.slice.name
292 obj.os_manager = OpenStackManager(auth=auth, caller=request.user)
Tony Mack9bcbe4f2013-04-29 08:13:27 -0400293 obj.delete()
294
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400295
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400296class ImageAdmin(admin.ModelAdmin):
297 fields = ['image_id', 'name', 'disk_format', 'container_format']
298
299class NodeAdmin(admin.ModelAdmin):
300 list_display = ('name', 'site', 'deploymentNetwork')
301 list_filter = ('deploymentNetwork',)
302
Tony Mackd90cdbf2013-04-16 22:48:40 -0400303
304class SliverForm(forms.ModelForm):
305 class Meta:
Tony Mack1d6b85f2013-05-07 18:49:14 -0400306 model = Sliver
Tony Mackd90cdbf2013-04-16 22:48:40 -0400307 ip = forms.CharField(widget=PlainTextWidget)
Tony Mack18261812013-05-02 16:39:20 -0400308 instance_name = forms.CharField(widget=PlainTextWidget)
Tony Mackd90cdbf2013-04-16 22:48:40 -0400309 widgets = {
310 'ip': PlainTextWidget(),
Tony Mack18261812013-05-02 16:39:20 -0400311 'instance_name': PlainTextWidget(),
Siobhan Tully53437282013-04-26 19:30:27 -0400312 }
Tony Mackd90cdbf2013-04-16 22:48:40 -0400313
Tony Mack9bcbe4f2013-04-29 08:13:27 -0400314class SliverAdmin(PlanetStackBaseAdmin):
Tony Mackd90cdbf2013-04-16 22:48:40 -0400315 form = SliverForm
Tony Mackcdec0902013-04-15 00:38:49 -0400316 fieldsets = [
Tony Mack10082022013-05-06 17:15:00 -0400317 ('Sliver', {'fields': ['ip', 'instance_name', 'slice', 'numberCores', 'image', 'key', 'node', 'deploymentNetwork']})
Tony Mackcdec0902013-04-15 00:38:49 -0400318 ]
Tony Mack10082022013-05-06 17:15:00 -0400319 list_display = ['ip', 'instance_name', 'slice', 'numberCores', 'image', 'key', 'node', 'deploymentNetwork']
Tony Mack53106f32013-04-27 16:43:01 -0400320
Tony Mack04062832013-05-10 08:22:44 -0400321 def queryset(self, request):
322 # admins can see all slivers. Users can only see slivers of
323 # the slices they belong to.
324 qs = super(SliverAdmin, self).queryset(request)
325 if not request.user.is_admin:
326 tenants = []
327 roles = request.user.get_roles()
328 for tenant_list in roles.values():
329 tenants.extend(tenant_list)
330 valid_slices = Slice.objects.filter(name__in=tenants)
331 qs = qs.filter(slice__in=valid_slices)
332 return qs
333
Tony Mack1d6b85f2013-05-07 18:49:14 -0400334 def get_formsets(self, request, obj=None):
335 # make some fields read only if we are updating an existing record
336 if obj == None:
337 #self.readonly_fields = ('ip', 'instance_name')
338 self.readonly_fields = ()
339 else:
Tony Mack1e889462013-05-10 21:34:54 -0400340 self.readonly_fields = ()
341 #self.readonly_fields = ('ip', 'instance_name', 'slice', 'image', 'key')
Tony Mack1d6b85f2013-05-07 18:49:14 -0400342
343 for inline in self.get_inline_instances(request, obj):
344 # hide MyInline in the add view
345 if obj is None:
346 continue
347 # give inline object access to driver and caller
348 auth = request.session.get('auth', {})
349 auth['tenant'] = obj.name # meed to connect using slice's tenant
350 inline.model.os_manager = OpenStackManager(auth=auth, caller=request.user)
351 yield inline.get_formset(request, obj)
Tony Mack53106f32013-04-27 16:43:01 -0400352
353 def save_model(self, request, obj, form, change):
Tony Mack951dab42013-05-02 19:51:45 -0400354 # update openstack connection to use this site/tenant
355 auth = request.session.get('auth', {})
356 auth['tenant'] = obj.slice.name
357 obj.os_manager = OpenStackManager(auth=auth, caller=request.user)
Tony Mack53106f32013-04-27 16:43:01 -0400358 obj.save()
359
360 def delete_model(self, request, obj):
Tony Mack951dab42013-05-02 19:51:45 -0400361 # update openstack connection to use this site/tenant
362 auth = request.session.get('auth', {})
363 auth['tenant'] = obj.slice.name
364 obj.os_manager = OpenStackManager(auth=auth, caller=request.user)
Tony Mack53106f32013-04-27 16:43:01 -0400365 obj.delete()
Tony Mackcdec0902013-04-15 00:38:49 -0400366
Siobhan Tully53437282013-04-26 19:30:27 -0400367class UserCreationForm(forms.ModelForm):
368 """A form for creating new users. Includes all the required
369 fields, plus a repeated password."""
370 password1 = forms.CharField(label='Password', widget=forms.PasswordInput)
371 password2 = forms.CharField(label='Password confirmation', widget=forms.PasswordInput)
372
373 class Meta:
Siobhan Tully30fd4292013-05-10 08:59:56 -0400374 model = User
375 fields = ('email', 'firstname', 'lastname', 'phone', 'key', 'site')
Siobhan Tully53437282013-04-26 19:30:27 -0400376
377 def clean_password2(self):
378 # Check that the two password entries match
379 password1 = self.cleaned_data.get("password1")
380 password2 = self.cleaned_data.get("password2")
381 if password1 and password2 and password1 != password2:
382 raise forms.ValidationError("Passwords don't match")
383 return password2
384
385 def save(self, commit=True):
386 # Save the provided password in hashed format
387 user = super(UserCreationForm, self).save(commit=False)
Tony Mackf9f4afb2013-05-01 21:02:12 -0400388 user.password = self.cleaned_data["password1"]
389 #user.set_password(self.cleaned_data["password1"])
Siobhan Tully53437282013-04-26 19:30:27 -0400390 if commit:
391 user.save()
392 return user
393
394
395class UserChangeForm(forms.ModelForm):
396 """A form for updating users. Includes all the fields on
397 the user, but replaces the password field with admin's
398 password hash display field.
399 """
400 password = ReadOnlyPasswordHashField()
401
402 class Meta:
Siobhan Tully30fd4292013-05-10 08:59:56 -0400403 model = User
Siobhan Tully53437282013-04-26 19:30:27 -0400404
405 def clean_password(self):
406 # Regardless of what the user provides, return the initial value.
407 # This is done here, rather than on the field, because the
408 # field does not have access to the initial value
409 return self.initial["password"]
410
411
Siobhan Tully30fd4292013-05-10 08:59:56 -0400412class UserAdmin(UserAdmin, OSModelAdmin):
Siobhan Tully53437282013-04-26 19:30:27 -0400413 class Meta:
414 app_label = "core"
415
416 # The forms to add and change user instances
417 form = UserChangeForm
418 add_form = UserCreationForm
419
420 # The fields to be used in displaying the User model.
421 # These override the definitions on the base UserAdmin
422 # that reference specific fields on auth.User.
Tony Mack416c0f22013-05-09 16:59:09 -0400423 list_display = ('email', 'site', 'firstname', 'lastname', 'is_admin', 'last_login')
Siobhan Tully53437282013-04-26 19:30:27 -0400424 list_filter = ('site',)
Siobhan Tullyaa1bcd52013-05-10 12:43:09 -0400425 inlines = [SitePrivilegeInline, SliceMembershipInline]
Siobhan Tully53437282013-04-26 19:30:27 -0400426 fieldsets = (
Tony Mack89f70f12013-05-10 20:20:03 -0400427 (None, {'fields': ('email', 'password', 'site', 'is_admin')}),
Siobhan Tullyaa1bcd52013-05-10 12:43:09 -0400428 ('Personal info', {'fields': ('firstname','lastname','phone', 'key')}),
Siobhan Tully53437282013-04-26 19:30:27 -0400429 #('Important dates', {'fields': ('last_login',)}),
430 )
431 add_fieldsets = (
432 (None, {
433 'classes': ('wide',),
Tony Mack89f70f12013-05-10 20:20:03 -0400434 'fields': ('email', 'firstname', 'lastname', 'phone', 'site', 'key','password1', 'password2', 'is_admin')}
Siobhan Tully53437282013-04-26 19:30:27 -0400435 ),
436 )
437 search_fields = ('email',)
438 ordering = ('email',)
439 filter_horizontal = ()
440
Scott Baker3de3e372013-05-10 16:50:44 -0700441class ServiceResourceInline(admin.TabularInline):
442 model = ServiceResource
443 extra = 0
444
445class ServiceClassAdmin(admin.ModelAdmin):
446 list_display = ('name', 'commitment', 'membershipFee')
447 inlines = [ServiceResourceInline]
448
Scott Baker133c9212013-05-17 09:09:11 -0700449class ReservedResourceInline(admin.TabularInline):
450 model = ReservedResource
451 extra = 0
452
453 def formfield_for_foreignkey(self, db_field, request=None, **kwargs):
454 field = super(ReservedResourceInline, self).formfield_for_foreignkey(db_field, request, **kwargs)
455
456 if db_field.name == 'resource':
457 # restrict resources to those that the slice's service class allows
458 if request._slice is not None:
459 field.queryset = field.queryset.filter(serviceClass = request._slice.serviceClass, calendarReservable=True)
460 if len(field.queryset) > 0:
461 field.initial = field.queryset.all()[0]
462 else:
463 field.queryset = field.queryset.none()
464 elif db_field.name == 'sliver':
465 # restrict slivers to those that belong to the slice
466 if request._slice is not None:
467 field.queryset = field.queryset.filter(slice = request._slice)
468 else:
469 field.queryset = field.queryset.none()
470
471 return field
472
473class ReservationChangeForm(forms.ModelForm):
474 class Meta:
475 model = Reservation
476
477class ReservationAddForm(forms.ModelForm):
478 slice = forms.ModelChoiceField(queryset=Slice.objects.all(), widget=forms.Select(attrs={"onChange":"document.getElementById('id_refresh').value=1; submit()"}))
479 refresh = forms.CharField(widget=forms.HiddenInput())
480
481 class Media:
482 css = {'all': ('planetstack.css',)} # .field-refresh { display: none; }
483
484 def clean_slice(self):
485 slice = self.cleaned_data.get("slice")
486 x = ServiceResource.objects.filter(serviceClass = slice.serviceClass, calendarReservable=True)
487 if len(x) == 0:
488 raise forms.ValidationError("The slice you selected does not have a service class that allows reservations")
489 return slice
490
491 class Meta:
492 model = Reservation
493
494class ReservationAddRefreshForm(ReservationAddForm):
495 """ This form is displayed when the Reservation Form receives an update
496 from the Slice dropdown onChange handler. It doesn't validate the
497 data and doesn't save the data. This will cause the form to be
498 redrawn.
499 """
500
Scott Baker8737e5f2013-05-17 09:35:32 -0700501 """ don't validate anything other than slice """
502 dont_validate_fields = ("startTime", "duration")
503
Scott Baker133c9212013-05-17 09:09:11 -0700504 def full_clean(self):
505 result = super(ReservationAddForm, self).full_clean()
Scott Baker8737e5f2013-05-17 09:35:32 -0700506
507 for fieldname in self.dont_validate_fields:
508 if fieldname in self._errors:
509 del self._errors[fieldname]
510
Scott Baker133c9212013-05-17 09:09:11 -0700511 return result
512
513 """ don't save anything """
514 def is_valid(self):
515 return False
516
517class ReservationAdmin(admin.ModelAdmin):
518 list_display = ('startTime', 'duration')
519 inlines = [ReservedResourceInline]
520 form = ReservationAddForm
521
522 def add_view(self, request, form_url='', extra_context=None):
523 request._refresh = False
524 request._slice = None
525 if request.method == 'POST':
Scott Baker8737e5f2013-05-17 09:35:32 -0700526 # "refresh" will be set to "1" if the form was submitted due to
527 # a change in the Slice dropdown.
Scott Baker133c9212013-05-17 09:09:11 -0700528 if request.POST.get("refresh","1") == "1":
529 request._refresh = True
530 request.POST["refresh"] = "0"
Scott Baker8737e5f2013-05-17 09:35:32 -0700531
532 # Keep track of the slice that was selected, so the
533 # reservedResource inline can filter items for the slice.
Scott Baker133c9212013-05-17 09:09:11 -0700534 request._slice = request.POST.get("slice",None)
535 if (request._slice is not None):
536 request._slice = Slice.objects.get(id=request._slice)
537
538 result = super(ReservationAdmin, self).add_view(request, form_url, extra_context)
539 return result
540
541 def get_form(self, request, obj=None, **kwargs):
542 request._obj_ = obj
543 if obj is not None:
Scott Baker8737e5f2013-05-17 09:35:32 -0700544 # For changes, set request._slice to the slice already set in the
545 # object.
Scott Baker133c9212013-05-17 09:09:11 -0700546 request._slice = obj.slice
547 self.form = ReservationChangeForm
548 else:
549 if getattr(request, "_refresh", False):
550 self.form = ReservationAddRefreshForm
551 else:
552 self.form = ReservationAddForm
553 return super(ReservationAdmin, self).get_form(request, obj, **kwargs)
554
555 def get_readonly_fields(self, request, obj=None):
556 if (obj is not None):
557 # Prevent slice from being changed after the reservation has been
558 # created.
559 return ['slice']
560 else:
561 return []
Scott Baker3de3e372013-05-10 16:50:44 -0700562
Tony Mack31c2b8f2013-04-26 20:01:42 -0400563# register a signal that caches the user's credentials when they log in
564def cache_credentials(sender, user, request, **kwds):
565 auth = {'username': request.POST['username'],
566 'password': request.POST['password']}
567 request.session['auth'] = auth
568user_logged_in.connect(cache_credentials)
569
Siobhan Tully53437282013-04-26 19:30:27 -0400570# Now register the new UserAdmin...
Siobhan Tully30fd4292013-05-10 08:59:56 -0400571admin.site.register(User, UserAdmin)
Siobhan Tully53437282013-04-26 19:30:27 -0400572# ... and, since we're not using Django's builtin permissions,
573# unregister the Group model from admin.
574admin.site.unregister(Group)
575
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400576admin.site.register(Site, SiteAdmin)
Siobhan Tullyaa1bcd52013-05-10 12:43:09 -0400577admin.site.register(SitePrivilege, SitePrivilegeAdmin)
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400578admin.site.register(Slice, SliceAdmin)
Siobhan Tullyaa1bcd52013-05-10 12:43:09 -0400579admin.site.register(SliceMembership, SliceMembershipAdmin)
580#admin.site.register(Subnet)
Siobhan Tully73291342013-05-10 10:50:08 -0400581admin.site.register(Image, ImageAdmin)
Siobhan Tullyaa1bcd52013-05-10 12:43:09 -0400582admin.site.register(Node, NodeAdmin)
Tony Mackcdec0902013-04-15 00:38:49 -0400583admin.site.register(Sliver, SliverAdmin)
Tony Mack759b57a2013-04-14 21:03:31 -0400584admin.site.register(Key, KeyAdmin)
Siobhan Tullyaa1bcd52013-05-10 12:43:09 -0400585admin.site.register(Role, RoleAdmin)
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400586admin.site.register(DeploymentNetwork, DeploymentNetworkAdmin)
Scott Baker3de3e372013-05-10 16:50:44 -0700587admin.site.register(ServiceClass, ServiceClassAdmin)
Scott Baker133c9212013-05-17 09:09:11 -0700588admin.site.register(Reservation, ReservationAdmin)
Tony Mack7130ac32013-03-22 21:58:00 -0400589