blob: bc49b8a8deeebfdb2198c6c371041d86e36ae066 [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
Scott Bakeracd45142013-05-19 16:19:16 -070012from django.contrib.auth.signals import user_logged_in
13from django.utils import timezone
Tony Mack7130ac32013-03-22 21:58:00 -040014
Siobhan Tully4bc09f22013-04-10 21:15:21 -040015
16class ReadonlyTabularInline(admin.TabularInline):
17 can_delete = False
18 extra = 0
19 editable_fields = []
20
21 def get_readonly_fields(self, request, obj=None):
22 fields = []
23 for field in self.model._meta.get_all_field_names():
24 if (not field == 'id'):
25 if (field not in self.editable_fields):
26 fields.append(field)
27 return fields
28
29 def has_add_permission(self, request):
30 return False
31
32class SliverInline(admin.TabularInline):
33 model = Sliver
Tony Mack3777b012013-05-07 21:38:06 -040034 fields = ['ip', 'instance_name', 'slice', 'numberCores', 'image', 'key', 'node', 'deploymentNetwork']
Siobhan Tully4bc09f22013-04-10 21:15:21 -040035 extra = 0
Tony Mack3777b012013-05-07 21:38:06 -040036 #readonly_fields = ['ip', 'instance_name', 'image']
37 readonly_fields = ['ip', 'instance_name']
Siobhan Tully4bc09f22013-04-10 21:15:21 -040038
39class SiteInline(admin.TabularInline):
40 model = Site
41 extra = 0
42
Siobhan Tully30fd4292013-05-10 08:59:56 -040043class UserInline(admin.TabularInline):
44 model = User
Siobhan Tully47ae1b52013-05-10 15:53:14 -040045 fields = ['email', 'firstname', 'lastname']
Siobhan Tully30fd4292013-05-10 08:59:56 -040046 extra = 0
47
Tony Mack00d361f2013-04-28 10:28:42 -040048class SliceInline(admin.TabularInline):
49 model = Slice
50 extra = 0
51
Tony Mack00d361f2013-04-28 10:28:42 -040052class RoleInline(admin.TabularInline):
53 model = Role
54 extra = 0
55
Siobhan Tully4bc09f22013-04-10 21:15:21 -040056class NodeInline(admin.TabularInline):
57 model = Node
58 extra = 0
59
Siobhan Tullyaa1bcd52013-05-10 12:43:09 -040060class SitePrivilegeInline(admin.TabularInline):
61 model = SitePrivilege
62 extra = 0
63
64class SliceMembershipInline(admin.TabularInline):
65 model = SliceMembership
66 extra = 0
67
Tony Mack5e71a662013-05-03 23:30:41 -040068class PlainTextWidget(forms.HiddenInput):
69 input_type = 'hidden'
70
71 def render(self, name, value, attrs=None):
72 if value is None:
73 value = ''
Tony Mack1d6b85f2013-05-07 18:49:14 -040074 return mark_safe(str(value) + super(PlainTextWidget, self).render(name, value, attrs))
Tony Mack9bcbe4f2013-04-29 08:13:27 -040075
Siobhan Tully4bc09f22013-04-10 21:15:21 -040076class PlanetStackBaseAdmin(admin.ModelAdmin):
77 save_on_top = False
78
Tony Mackfdd4d802013-04-27 13:02:33 -040079class OSModelAdmin(PlanetStackBaseAdmin):
Tony Mackd685bfa2013-05-02 10:09:51 -040080 """Attach client connection to openstack on delete() and save()"""
Tony Mack79748612013-05-01 14:52:03 -040081
Tony Mackfdd4d802013-04-27 13:02:33 -040082 def save_model(self, request, obj, form, change):
Tony Mack38e247c2013-05-05 11:48:14 -040083 if request.user.site:
84 auth = request.session.get('auth', {})
85 auth['tenant'] = request.user.site.login_base
86 obj.os_manager = OpenStackManager(auth=auth, caller=request.user)
Tony Mackfdd4d802013-04-27 13:02:33 -040087 obj.save()
88
89 def delete_model(self, request, obj):
Tony Mack38e247c2013-05-05 11:48:14 -040090 if request.user.site:
91 auth = request.session.get('auth', {})
92 auth['tenant'] = request.user.site.login_base
93 obj.os_manager = OpenStackManager(auth=auth, caller=request.user)
Tony Mackd685bfa2013-05-02 10:09:51 -040094 obj.delete()
Tony Mack9bcbe4f2013-04-29 08:13:27 -040095
Tony Mackd685bfa2013-05-02 10:09:51 -040096class RoleAdmin(OSModelAdmin):
Tony Mack9bcbe4f2013-04-29 08:13:27 -040097 fieldsets = [
98 ('Role', {'fields': ['role_type']})
99 ]
100 list_display = ('role_type',)
Tony Mackfdd4d802013-04-27 13:02:33 -0400101
Tony Mack02755d42013-05-02 00:00:10 -0400102
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400103class DeploymentNetworkAdminForm(forms.ModelForm):
104 sites = forms.ModelMultipleChoiceField(
105 queryset=Site.objects.all(),
106 required=False,
107 widget=FilteredSelectMultiple(
108 verbose_name=('Sites'), is_stacked=False
109 )
110 )
111 class Meta:
112 model = DeploymentNetwork
113
114 def __init__(self, *args, **kwargs):
115 super(DeploymentNetworkAdminForm, self).__init__(*args, **kwargs)
116
117 if self.instance and self.instance.pk:
118 self.fields['sites'].initial = self.instance.sites.all()
119
120 def save(self, commit=True):
121 deploymentNetwork = super(DeploymentNetworkAdminForm, self).save(commit=False)
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400122 if commit:
123 deploymentNetwork.save()
124
125 if deploymentNetwork.pk:
126 deploymentNetwork.sites = self.cleaned_data['sites']
127 self.save_m2m()
128
129 return deploymentNetwork
130
131class DeploymentNetworkAdmin(PlanetStackBaseAdmin):
132 form = DeploymentNetworkAdminForm
Siobhan Tullyaa1bcd52013-05-10 12:43:09 -0400133 inlines = [NodeInline,SliverInline]
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400134
Tony Mack5cd13202013-05-01 21:48:38 -0400135 def get_formsets(self, request, obj=None):
136 for inline in self.get_inline_instances(request, obj):
137 # hide MyInline in the add view
138 if obj is None:
139 continue
140 # give inline object access to driver and caller
Tony Macked163d72013-05-02 20:05:42 -0400141 auth = request.session.get('auth', {})
Siobhan Tully73291342013-05-10 10:50:08 -0400142 if request.user.site:
143 auth['tenant'] = request.user.site.login_base
Tony Macked163d72013-05-02 20:05:42 -0400144 inline.model.os_manager = OpenStackManager(auth=auth, caller=request.user)
Tony Mack5cd13202013-05-01 21:48:38 -0400145 yield inline.get_formset(request, obj)
146
Tony Mackfdd4d802013-04-27 13:02:33 -0400147class SiteAdmin(OSModelAdmin):
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400148 fieldsets = [
149 (None, {'fields': ['name', 'site_url', 'enabled', 'is_public', 'login_base']}),
150 ('Location', {'fields': ['latitude', 'longitude']}),
151 ('Deployment Networks', {'fields': ['deployments']})
152 ]
153 list_display = ('name', 'login_base','site_url', 'enabled')
154 filter_horizontal = ('deployments',)
Siobhan Tullyaa1bcd52013-05-10 12:43:09 -0400155 inlines = [NodeInline, UserInline, SitePrivilegeInline]
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400156 search_fields = ['name']
157
Tony Mack04062832013-05-10 08:22:44 -0400158 def queryset(self, request):
159 # admins can see all keys. Users can only see sites they belong to.
160 qs = super(SiteAdmin, self).queryset(request)
161 if not request.user.is_admin:
162 valid_sites = [request.user.site.login_base]
163 roles = request.user.get_roles()
164 for tenant_list in roles.values():
165 valid_sites.extend(tenant_list)
166 qs = qs.filter(login_base__in=valid_sites)
167 return qs
168
Tony Mack5cd13202013-05-01 21:48:38 -0400169 def get_formsets(self, request, obj=None):
170 for inline in self.get_inline_instances(request, obj):
171 # hide MyInline in the add view
172 if obj is None:
173 continue
174 # give inline object access to driver and caller
Tony Mack60722062013-05-02 10:57:04 -0400175 auth = request.session.get('auth', {})
Siobhan Tully30fd4292013-05-10 08:59:56 -0400176 #auth['tenant'] = request.user.site.login_base
Tony Mack60722062013-05-02 10:57:04 -0400177 inline.model.os_manager = OpenStackManager(auth=auth, caller=request.user)
Tony Mack5cd13202013-05-01 21:48:38 -0400178 yield inline.get_formset(request, obj)
179
Tony Mack9bcbe4f2013-04-29 08:13:27 -0400180class SitePrivilegeAdmin(PlanetStackBaseAdmin):
Tony Mack00d361f2013-04-28 10:28:42 -0400181 fieldsets = [
182 (None, {'fields': ['user', 'site', 'role']})
183 ]
184 list_display = ('user', 'site', 'role')
185
Tony Mack04062832013-05-10 08:22:44 -0400186 def queryset(self, request):
187 # admins can see all privileges. Users can only see privileges at sites
188 # where they have the admin role.
189 qs = super(SitePrivilegeAdmin, self).queryset(request)
190 if not request.user.is_admin:
191 roles = request.user.get_roles()
192 tenants = []
193 for (role, tenant_list) in roles:
194 if role == 'admin':
195 tenants.extend(tenant_list)
196 valid_sites = Sites.objects.filter(login_base__in=tenants)
197 qs = qs.filter(site__in=valid_sites)
198 return qs
199
Tony Mack9bcbe4f2013-04-29 08:13:27 -0400200 def save_model(self, request, obj, form, change):
201 # update openstack connection to use this site/tenant
Tony Mack93048c22013-05-02 11:20:26 -0400202 auth = request.session.get('auth', {})
Siobhan Tully30fd4292013-05-10 08:59:56 -0400203 #auth['tenant'] = obj.site.login_base
Tony Mack93048c22013-05-02 11:20:26 -0400204 obj.os_manager = OpenStackManager(auth=auth, caller=request.user)
Tony Mack9bcbe4f2013-04-29 08:13:27 -0400205 obj.save()
206
207 def delete_model(self, request, obj):
208 # update openstack connection to use this site/tenant
Tony Mack93048c22013-05-02 11:20:26 -0400209 auth = request.session.get('auth', {})
Siobhan Tully30fd4292013-05-10 08:59:56 -0400210 #auth['tenant'] = obj.site.login_base
Tony Mack93048c22013-05-02 11:20:26 -0400211 obj.os_manager = OpenStackManager(auth=auth, caller=request.user)
Tony Mack9bcbe4f2013-04-29 08:13:27 -0400212 obj.delete()
213
Tony Mackfdd4d802013-04-27 13:02:33 -0400214class KeyAdmin(OSModelAdmin):
Tony Mack759b57a2013-04-14 21:03:31 -0400215 fieldsets = [
Siobhan Tully73291342013-05-10 10:50:08 -0400216 ('Key', {'fields': ['key', 'type', 'blacklisted']})
Tony Mack759b57a2013-04-14 21:03:31 -0400217 ]
Siobhan Tully73291342013-05-10 10:50:08 -0400218 list_display = ['key', 'type', 'blacklisted']
Tony Mack8484bdb2013-04-14 20:26:03 -0400219
Siobhan Tully73291342013-05-10 10:50:08 -0400220 #def queryset(self, request):
Tony Mackc14de8f2013-05-09 21:44:17 -0400221 # admins can see all keys. Users can only see their own key.
Siobhan Tully73291342013-05-10 10:50:08 -0400222 #if request.user.is_admin:
223 # qs = super(KeyAdmin, self).queryset(request)
224 #else:
225 # qs = Key.objects.filter(user=request.user)
Scott Baker133c9212013-05-17 09:09:11 -0700226 #return qs
227
Tony Mackfdd4d802013-04-27 13:02:33 -0400228class SliceAdmin(OSModelAdmin):
Siobhan Tully30fd4292013-05-10 08:59:56 -0400229 fields = ['name', 'site', 'serviceClass', 'description', 'slice_url']
230 list_display = ('name', 'site','serviceClass', 'slice_url')
Siobhan Tully47ae1b52013-05-10 15:53:14 -0400231 inlines = [SliverInline, SliceMembershipInline]
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400232
Tony Mack04062832013-05-10 08:22:44 -0400233 def queryset(self, request):
234 # admins can see all keys. Users can only see slices they belong to.
235 qs = super(SliceAdmin, self).queryset(request)
236 if not request.user.is_admin:
237 valid_slices = []
238 roles = request.user.get_roles()
239 for tenant_list in roles.values():
240 valid_slices.extend(tenant_list)
241 qs = qs.filter(name__in=valid_slices)
242 return qs
243
Tony Mack79748612013-05-01 14:52:03 -0400244 def get_formsets(self, request, obj=None):
245 for inline in self.get_inline_instances(request, obj):
246 # hide MyInline in the add view
247 if obj is None:
248 continue
249 # give inline object access to driver and caller
Tony Mack93048c22013-05-02 11:20:26 -0400250 auth = request.session.get('auth', {})
251 auth['tenant'] = obj.name # meed to connect using slice's tenant
252 inline.model.os_manager = OpenStackManager(auth=auth, caller=request.user)
Tony Mack79748612013-05-01 14:52:03 -0400253 yield inline.get_formset(request, obj)
254
Tony Mackfdd4d802013-04-27 13:02:33 -0400255 def get_queryset(self, request):
256 qs = super(SliceAdmin, self).get_queryset(request)
257 if request.user.is_superuser:
258 return qs
259 # users can only see slices at their site
260 return qs.filter(site=request.user.site)
261
Tony Mack9bcbe4f2013-04-29 08:13:27 -0400262class SliceMembershipAdmin(PlanetStackBaseAdmin):
Tony Mack00d361f2013-04-28 10:28:42 -0400263 fieldsets = [
264 (None, {'fields': ['user', 'slice', 'role']})
265 ]
266 list_display = ('user', 'slice', 'role')
Tony Mack00d361f2013-04-28 10:28:42 -0400267
Tony Mack04062832013-05-10 08:22:44 -0400268 def queryset(self, request):
269 # admins can see all memberships. Users can only see memberships of
270 # slices where they have the admin role.
271 qs = super(SliceMembershipAdmin, self).queryset(request)
272 if not request.user.is_admin:
273 roles = request.user.get_roles()
274 tenants = []
275 for (role, tenant_list) in roles:
276 if role == 'admin':
277 tenants.extend(tenant_list)
278 valid_slices = Slice.objects.filter(name__in=tenants)
279 qs = qs.filter(slice__in=valid_slices)
280 return qs
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400281
Tony Mack9bcbe4f2013-04-29 08:13:27 -0400282 def save_model(self, request, obj, form, change):
Tony Mack951dab42013-05-02 19:51:45 -0400283 # update openstack connection to use this site/tenant
284 auth = request.session.get('auth', {})
285 auth['tenant'] = obj.slice.name
286 obj.os_manager = OpenStackManager(auth=auth, caller=request.user)
Tony Mack9bcbe4f2013-04-29 08:13:27 -0400287 obj.save()
288
289 def delete_model(self, request, obj):
Tony Mack951dab42013-05-02 19:51:45 -0400290 # update openstack connection to use this site/tenant
291 auth = request.session.get('auth', {})
292 auth['tenant'] = obj.slice.name
293 obj.os_manager = OpenStackManager(auth=auth, caller=request.user)
Tony Mack9bcbe4f2013-04-29 08:13:27 -0400294 obj.delete()
295
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400296
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400297class ImageAdmin(admin.ModelAdmin):
298 fields = ['image_id', 'name', 'disk_format', 'container_format']
299
300class NodeAdmin(admin.ModelAdmin):
301 list_display = ('name', 'site', 'deploymentNetwork')
302 list_filter = ('deploymentNetwork',)
303
Tony Mackd90cdbf2013-04-16 22:48:40 -0400304
305class SliverForm(forms.ModelForm):
306 class Meta:
Tony Mack1d6b85f2013-05-07 18:49:14 -0400307 model = Sliver
Tony Mackd90cdbf2013-04-16 22:48:40 -0400308 ip = forms.CharField(widget=PlainTextWidget)
Tony Mack18261812013-05-02 16:39:20 -0400309 instance_name = forms.CharField(widget=PlainTextWidget)
Tony Mackd90cdbf2013-04-16 22:48:40 -0400310 widgets = {
311 'ip': PlainTextWidget(),
Tony Mack18261812013-05-02 16:39:20 -0400312 'instance_name': PlainTextWidget(),
Siobhan Tully53437282013-04-26 19:30:27 -0400313 }
Tony Mackd90cdbf2013-04-16 22:48:40 -0400314
Tony Mack9bcbe4f2013-04-29 08:13:27 -0400315class SliverAdmin(PlanetStackBaseAdmin):
Tony Mackd90cdbf2013-04-16 22:48:40 -0400316 form = SliverForm
Tony Mackcdec0902013-04-15 00:38:49 -0400317 fieldsets = [
Tony Mack10082022013-05-06 17:15:00 -0400318 ('Sliver', {'fields': ['ip', 'instance_name', 'slice', 'numberCores', 'image', 'key', 'node', 'deploymentNetwork']})
Tony Mackcdec0902013-04-15 00:38:49 -0400319 ]
Tony Mack10082022013-05-06 17:15:00 -0400320 list_display = ['ip', 'instance_name', 'slice', 'numberCores', 'image', 'key', 'node', 'deploymentNetwork']
Tony Mack53106f32013-04-27 16:43:01 -0400321
Tony Mack04062832013-05-10 08:22:44 -0400322 def queryset(self, request):
323 # admins can see all slivers. Users can only see slivers of
324 # the slices they belong to.
325 qs = super(SliverAdmin, self).queryset(request)
326 if not request.user.is_admin:
327 tenants = []
328 roles = request.user.get_roles()
329 for tenant_list in roles.values():
330 tenants.extend(tenant_list)
331 valid_slices = Slice.objects.filter(name__in=tenants)
332 qs = qs.filter(slice__in=valid_slices)
333 return qs
334
Tony Mack1d6b85f2013-05-07 18:49:14 -0400335 def get_formsets(self, request, obj=None):
336 # make some fields read only if we are updating an existing record
337 if obj == None:
338 #self.readonly_fields = ('ip', 'instance_name')
339 self.readonly_fields = ()
340 else:
Tony Mack1e889462013-05-10 21:34:54 -0400341 self.readonly_fields = ()
342 #self.readonly_fields = ('ip', 'instance_name', 'slice', 'image', 'key')
Tony Mack1d6b85f2013-05-07 18:49:14 -0400343
344 for inline in self.get_inline_instances(request, obj):
345 # hide MyInline in the add view
346 if obj is None:
347 continue
348 # give inline object access to driver and caller
349 auth = request.session.get('auth', {})
350 auth['tenant'] = obj.name # meed to connect using slice's tenant
351 inline.model.os_manager = OpenStackManager(auth=auth, caller=request.user)
352 yield inline.get_formset(request, obj)
Tony Mack53106f32013-04-27 16:43:01 -0400353
354 def save_model(self, request, obj, form, change):
Tony Mack951dab42013-05-02 19:51:45 -0400355 # update openstack connection to use this site/tenant
356 auth = request.session.get('auth', {})
357 auth['tenant'] = obj.slice.name
358 obj.os_manager = OpenStackManager(auth=auth, caller=request.user)
Tony Mack53106f32013-04-27 16:43:01 -0400359 obj.save()
360
361 def delete_model(self, request, obj):
Tony Mack951dab42013-05-02 19:51:45 -0400362 # update openstack connection to use this site/tenant
363 auth = request.session.get('auth', {})
364 auth['tenant'] = obj.slice.name
365 obj.os_manager = OpenStackManager(auth=auth, caller=request.user)
Tony Mack53106f32013-04-27 16:43:01 -0400366 obj.delete()
Tony Mackcdec0902013-04-15 00:38:49 -0400367
Siobhan Tully53437282013-04-26 19:30:27 -0400368class UserCreationForm(forms.ModelForm):
369 """A form for creating new users. Includes all the required
370 fields, plus a repeated password."""
371 password1 = forms.CharField(label='Password', widget=forms.PasswordInput)
372 password2 = forms.CharField(label='Password confirmation', widget=forms.PasswordInput)
373
374 class Meta:
Siobhan Tully30fd4292013-05-10 08:59:56 -0400375 model = User
376 fields = ('email', 'firstname', 'lastname', 'phone', 'key', 'site')
Siobhan Tully53437282013-04-26 19:30:27 -0400377
378 def clean_password2(self):
379 # Check that the two password entries match
380 password1 = self.cleaned_data.get("password1")
381 password2 = self.cleaned_data.get("password2")
382 if password1 and password2 and password1 != password2:
383 raise forms.ValidationError("Passwords don't match")
384 return password2
385
386 def save(self, commit=True):
387 # Save the provided password in hashed format
388 user = super(UserCreationForm, self).save(commit=False)
Tony Mackf9f4afb2013-05-01 21:02:12 -0400389 user.password = self.cleaned_data["password1"]
390 #user.set_password(self.cleaned_data["password1"])
Siobhan Tully53437282013-04-26 19:30:27 -0400391 if commit:
392 user.save()
393 return user
394
395
396class UserChangeForm(forms.ModelForm):
397 """A form for updating users. Includes all the fields on
398 the user, but replaces the password field with admin's
399 password hash display field.
400 """
401 password = ReadOnlyPasswordHashField()
402
403 class Meta:
Siobhan Tully30fd4292013-05-10 08:59:56 -0400404 model = User
Siobhan Tully53437282013-04-26 19:30:27 -0400405
406 def clean_password(self):
407 # Regardless of what the user provides, return the initial value.
408 # This is done here, rather than on the field, because the
409 # field does not have access to the initial value
410 return self.initial["password"]
411
412
Siobhan Tully30fd4292013-05-10 08:59:56 -0400413class UserAdmin(UserAdmin, OSModelAdmin):
Siobhan Tully53437282013-04-26 19:30:27 -0400414 class Meta:
415 app_label = "core"
416
417 # The forms to add and change user instances
418 form = UserChangeForm
419 add_form = UserCreationForm
420
421 # The fields to be used in displaying the User model.
422 # These override the definitions on the base UserAdmin
423 # that reference specific fields on auth.User.
Tony Mack416c0f22013-05-09 16:59:09 -0400424 list_display = ('email', 'site', 'firstname', 'lastname', 'is_admin', 'last_login')
Siobhan Tully53437282013-04-26 19:30:27 -0400425 list_filter = ('site',)
Siobhan Tullyaa1bcd52013-05-10 12:43:09 -0400426 inlines = [SitePrivilegeInline, SliceMembershipInline]
Siobhan Tully53437282013-04-26 19:30:27 -0400427 fieldsets = (
Scott Baker9266e6b2013-05-19 15:54:48 -0700428 (None, {'fields': ('email', 'password', 'site', 'is_admin', 'timezone')}),
Siobhan Tullyaa1bcd52013-05-10 12:43:09 -0400429 ('Personal info', {'fields': ('firstname','lastname','phone', 'key')}),
Siobhan Tully53437282013-04-26 19:30:27 -0400430 #('Important dates', {'fields': ('last_login',)}),
431 )
432 add_fieldsets = (
433 (None, {
434 'classes': ('wide',),
Tony Mack89f70f12013-05-10 20:20:03 -0400435 'fields': ('email', 'firstname', 'lastname', 'phone', 'site', 'key','password1', 'password2', 'is_admin')}
Siobhan Tully53437282013-04-26 19:30:27 -0400436 ),
437 )
438 search_fields = ('email',)
439 ordering = ('email',)
440 filter_horizontal = ()
441
Scott Baker3de3e372013-05-10 16:50:44 -0700442class ServiceResourceInline(admin.TabularInline):
443 model = ServiceResource
444 extra = 0
445
446class ServiceClassAdmin(admin.ModelAdmin):
447 list_display = ('name', 'commitment', 'membershipFee')
448 inlines = [ServiceResourceInline]
449
Scott Baker133c9212013-05-17 09:09:11 -0700450class ReservedResourceInline(admin.TabularInline):
451 model = ReservedResource
452 extra = 0
453
454 def formfield_for_foreignkey(self, db_field, request=None, **kwargs):
455 field = super(ReservedResourceInline, self).formfield_for_foreignkey(db_field, request, **kwargs)
456
457 if db_field.name == 'resource':
458 # restrict resources to those that the slice's service class allows
459 if request._slice is not None:
460 field.queryset = field.queryset.filter(serviceClass = request._slice.serviceClass, calendarReservable=True)
461 if len(field.queryset) > 0:
462 field.initial = field.queryset.all()[0]
463 else:
464 field.queryset = field.queryset.none()
465 elif db_field.name == 'sliver':
466 # restrict slivers to those that belong to the slice
467 if request._slice is not None:
468 field.queryset = field.queryset.filter(slice = request._slice)
469 else:
470 field.queryset = field.queryset.none()
471
472 return field
473
474class ReservationChangeForm(forms.ModelForm):
475 class Meta:
476 model = Reservation
477
478class ReservationAddForm(forms.ModelForm):
479 slice = forms.ModelChoiceField(queryset=Slice.objects.all(), widget=forms.Select(attrs={"onChange":"document.getElementById('id_refresh').value=1; submit()"}))
480 refresh = forms.CharField(widget=forms.HiddenInput())
481
482 class Media:
483 css = {'all': ('planetstack.css',)} # .field-refresh { display: none; }
484
485 def clean_slice(self):
486 slice = self.cleaned_data.get("slice")
487 x = ServiceResource.objects.filter(serviceClass = slice.serviceClass, calendarReservable=True)
488 if len(x) == 0:
489 raise forms.ValidationError("The slice you selected does not have a service class that allows reservations")
490 return slice
491
492 class Meta:
493 model = Reservation
494
495class ReservationAddRefreshForm(ReservationAddForm):
496 """ This form is displayed when the Reservation Form receives an update
497 from the Slice dropdown onChange handler. It doesn't validate the
498 data and doesn't save the data. This will cause the form to be
499 redrawn.
500 """
501
Scott Baker8737e5f2013-05-17 09:35:32 -0700502 """ don't validate anything other than slice """
503 dont_validate_fields = ("startTime", "duration")
504
Scott Baker133c9212013-05-17 09:09:11 -0700505 def full_clean(self):
506 result = super(ReservationAddForm, self).full_clean()
Scott Baker8737e5f2013-05-17 09:35:32 -0700507
508 for fieldname in self.dont_validate_fields:
509 if fieldname in self._errors:
510 del self._errors[fieldname]
511
Scott Baker133c9212013-05-17 09:09:11 -0700512 return result
513
514 """ don't save anything """
515 def is_valid(self):
516 return False
517
518class ReservationAdmin(admin.ModelAdmin):
519 list_display = ('startTime', 'duration')
520 inlines = [ReservedResourceInline]
521 form = ReservationAddForm
522
523 def add_view(self, request, form_url='', extra_context=None):
Scott Bakeracd45142013-05-19 16:19:16 -0700524 timezone.activate(request.user.timezone)
Scott Baker133c9212013-05-17 09:09:11 -0700525 request._refresh = False
526 request._slice = None
527 if request.method == 'POST':
Scott Baker8737e5f2013-05-17 09:35:32 -0700528 # "refresh" will be set to "1" if the form was submitted due to
529 # a change in the Slice dropdown.
Scott Baker133c9212013-05-17 09:09:11 -0700530 if request.POST.get("refresh","1") == "1":
531 request._refresh = True
532 request.POST["refresh"] = "0"
Scott Baker8737e5f2013-05-17 09:35:32 -0700533
534 # Keep track of the slice that was selected, so the
535 # reservedResource inline can filter items for the slice.
Scott Baker133c9212013-05-17 09:09:11 -0700536 request._slice = request.POST.get("slice",None)
537 if (request._slice is not None):
538 request._slice = Slice.objects.get(id=request._slice)
539
540 result = super(ReservationAdmin, self).add_view(request, form_url, extra_context)
541 return result
542
Scott Bakeracd45142013-05-19 16:19:16 -0700543 def changelist_view(self, request, extra_context = None):
544 timezone.activate(request.user.timezone)
545 return super(ReservationAdmin, self).changelist_view(request, extra_context)
546
Scott Baker133c9212013-05-17 09:09:11 -0700547 def get_form(self, request, obj=None, **kwargs):
548 request._obj_ = obj
549 if obj is not None:
Scott Baker8737e5f2013-05-17 09:35:32 -0700550 # For changes, set request._slice to the slice already set in the
551 # object.
Scott Baker133c9212013-05-17 09:09:11 -0700552 request._slice = obj.slice
553 self.form = ReservationChangeForm
554 else:
555 if getattr(request, "_refresh", False):
556 self.form = ReservationAddRefreshForm
557 else:
558 self.form = ReservationAddForm
559 return super(ReservationAdmin, self).get_form(request, obj, **kwargs)
560
561 def get_readonly_fields(self, request, obj=None):
562 if (obj is not None):
563 # Prevent slice from being changed after the reservation has been
564 # created.
565 return ['slice']
566 else:
567 return []
Scott Baker3de3e372013-05-10 16:50:44 -0700568
Tony Mack31c2b8f2013-04-26 20:01:42 -0400569# register a signal that caches the user's credentials when they log in
570def cache_credentials(sender, user, request, **kwds):
571 auth = {'username': request.POST['username'],
572 'password': request.POST['password']}
573 request.session['auth'] = auth
574user_logged_in.connect(cache_credentials)
575
Siobhan Tully53437282013-04-26 19:30:27 -0400576# Now register the new UserAdmin...
Siobhan Tully30fd4292013-05-10 08:59:56 -0400577admin.site.register(User, UserAdmin)
Siobhan Tully53437282013-04-26 19:30:27 -0400578# ... and, since we're not using Django's builtin permissions,
579# unregister the Group model from admin.
580admin.site.unregister(Group)
581
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400582admin.site.register(Site, SiteAdmin)
Siobhan Tullyaa1bcd52013-05-10 12:43:09 -0400583admin.site.register(SitePrivilege, SitePrivilegeAdmin)
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400584admin.site.register(Slice, SliceAdmin)
Siobhan Tullyaa1bcd52013-05-10 12:43:09 -0400585admin.site.register(SliceMembership, SliceMembershipAdmin)
586#admin.site.register(Subnet)
Siobhan Tully73291342013-05-10 10:50:08 -0400587admin.site.register(Image, ImageAdmin)
Siobhan Tullyaa1bcd52013-05-10 12:43:09 -0400588admin.site.register(Node, NodeAdmin)
Tony Mackcdec0902013-04-15 00:38:49 -0400589admin.site.register(Sliver, SliverAdmin)
Tony Mack759b57a2013-04-14 21:03:31 -0400590admin.site.register(Key, KeyAdmin)
Siobhan Tullyaa1bcd52013-05-10 12:43:09 -0400591admin.site.register(Role, RoleAdmin)
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400592admin.site.register(DeploymentNetwork, DeploymentNetworkAdmin)
Scott Baker3de3e372013-05-10 16:50:44 -0700593admin.site.register(ServiceClass, ServiceClassAdmin)
Scott Baker133c9212013-05-17 09:09:11 -0700594admin.site.register(Reservation, ReservationAdmin)
Tony Mack7130ac32013-03-22 21:58:00 -0400595