blob: 6e7bbb65d2ef5cfdd4e5b3b8520a2f79803d1a3a [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
Scott Baker307e06f2013-05-21 17:25:56 -070068class SliceTagInline(admin.TabularInline):
69 model = SliceTag
70 extra = 0
71
Tony Mack5e71a662013-05-03 23:30:41 -040072class PlainTextWidget(forms.HiddenInput):
73 input_type = 'hidden'
74
75 def render(self, name, value, attrs=None):
76 if value is None:
77 value = ''
Tony Mack1d6b85f2013-05-07 18:49:14 -040078 return mark_safe(str(value) + super(PlainTextWidget, self).render(name, value, attrs))
Tony Mack9bcbe4f2013-04-29 08:13:27 -040079
Siobhan Tully4bc09f22013-04-10 21:15:21 -040080class PlanetStackBaseAdmin(admin.ModelAdmin):
81 save_on_top = False
82
Tony Mackfdd4d802013-04-27 13:02:33 -040083class OSModelAdmin(PlanetStackBaseAdmin):
Tony Mackd685bfa2013-05-02 10:09:51 -040084 """Attach client connection to openstack on delete() and save()"""
Tony Mack79748612013-05-01 14:52:03 -040085
Tony Mackfdd4d802013-04-27 13:02:33 -040086 def save_model(self, request, obj, form, change):
Tony Mack38e247c2013-05-05 11:48:14 -040087 if request.user.site:
88 auth = request.session.get('auth', {})
89 auth['tenant'] = request.user.site.login_base
90 obj.os_manager = OpenStackManager(auth=auth, caller=request.user)
Tony Mackfdd4d802013-04-27 13:02:33 -040091 obj.save()
92
93 def delete_model(self, request, obj):
Tony Mack38e247c2013-05-05 11:48:14 -040094 if request.user.site:
95 auth = request.session.get('auth', {})
96 auth['tenant'] = request.user.site.login_base
97 obj.os_manager = OpenStackManager(auth=auth, caller=request.user)
Tony Mackd685bfa2013-05-02 10:09:51 -040098 obj.delete()
Tony Mack9bcbe4f2013-04-29 08:13:27 -040099
Tony Mackd685bfa2013-05-02 10:09:51 -0400100class RoleAdmin(OSModelAdmin):
Tony Mack9bcbe4f2013-04-29 08:13:27 -0400101 fieldsets = [
102 ('Role', {'fields': ['role_type']})
103 ]
104 list_display = ('role_type',)
Tony Mackfdd4d802013-04-27 13:02:33 -0400105
Tony Mack02755d42013-05-02 00:00:10 -0400106
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400107class DeploymentNetworkAdminForm(forms.ModelForm):
108 sites = forms.ModelMultipleChoiceField(
109 queryset=Site.objects.all(),
110 required=False,
111 widget=FilteredSelectMultiple(
112 verbose_name=('Sites'), is_stacked=False
113 )
114 )
115 class Meta:
116 model = DeploymentNetwork
117
118 def __init__(self, *args, **kwargs):
119 super(DeploymentNetworkAdminForm, self).__init__(*args, **kwargs)
120
121 if self.instance and self.instance.pk:
122 self.fields['sites'].initial = self.instance.sites.all()
123
124 def save(self, commit=True):
125 deploymentNetwork = super(DeploymentNetworkAdminForm, self).save(commit=False)
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400126 if commit:
127 deploymentNetwork.save()
128
129 if deploymentNetwork.pk:
130 deploymentNetwork.sites = self.cleaned_data['sites']
131 self.save_m2m()
132
133 return deploymentNetwork
134
135class DeploymentNetworkAdmin(PlanetStackBaseAdmin):
136 form = DeploymentNetworkAdminForm
Siobhan Tullyaa1bcd52013-05-10 12:43:09 -0400137 inlines = [NodeInline,SliverInline]
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400138
Tony Mack5cd13202013-05-01 21:48:38 -0400139 def get_formsets(self, request, obj=None):
140 for inline in self.get_inline_instances(request, obj):
141 # hide MyInline in the add view
142 if obj is None:
143 continue
144 # give inline object access to driver and caller
Tony Macked163d72013-05-02 20:05:42 -0400145 auth = request.session.get('auth', {})
Siobhan Tully73291342013-05-10 10:50:08 -0400146 if request.user.site:
147 auth['tenant'] = request.user.site.login_base
Tony Macked163d72013-05-02 20:05:42 -0400148 inline.model.os_manager = OpenStackManager(auth=auth, caller=request.user)
Tony Mack5cd13202013-05-01 21:48:38 -0400149 yield inline.get_formset(request, obj)
150
Tony Mackfdd4d802013-04-27 13:02:33 -0400151class SiteAdmin(OSModelAdmin):
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400152 fieldsets = [
153 (None, {'fields': ['name', 'site_url', 'enabled', 'is_public', 'login_base']}),
154 ('Location', {'fields': ['latitude', 'longitude']}),
155 ('Deployment Networks', {'fields': ['deployments']})
156 ]
157 list_display = ('name', 'login_base','site_url', 'enabled')
158 filter_horizontal = ('deployments',)
Siobhan Tullyaa1bcd52013-05-10 12:43:09 -0400159 inlines = [NodeInline, UserInline, SitePrivilegeInline]
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400160 search_fields = ['name']
161
Tony Mack04062832013-05-10 08:22:44 -0400162 def queryset(self, request):
163 # admins can see all keys. Users can only see sites they belong to.
164 qs = super(SiteAdmin, self).queryset(request)
165 if not request.user.is_admin:
166 valid_sites = [request.user.site.login_base]
167 roles = request.user.get_roles()
168 for tenant_list in roles.values():
169 valid_sites.extend(tenant_list)
170 qs = qs.filter(login_base__in=valid_sites)
171 return qs
172
Tony Mack5cd13202013-05-01 21:48:38 -0400173 def get_formsets(self, request, obj=None):
174 for inline in self.get_inline_instances(request, obj):
175 # hide MyInline in the add view
176 if obj is None:
177 continue
178 # give inline object access to driver and caller
Tony Mack60722062013-05-02 10:57:04 -0400179 auth = request.session.get('auth', {})
Siobhan Tully30fd4292013-05-10 08:59:56 -0400180 #auth['tenant'] = request.user.site.login_base
Tony Mack60722062013-05-02 10:57:04 -0400181 inline.model.os_manager = OpenStackManager(auth=auth, caller=request.user)
Tony Mack5cd13202013-05-01 21:48:38 -0400182 yield inline.get_formset(request, obj)
183
Tony Mack9bcbe4f2013-04-29 08:13:27 -0400184class SitePrivilegeAdmin(PlanetStackBaseAdmin):
Tony Mack00d361f2013-04-28 10:28:42 -0400185 fieldsets = [
186 (None, {'fields': ['user', 'site', 'role']})
187 ]
188 list_display = ('user', 'site', 'role')
189
Tony Mack04062832013-05-10 08:22:44 -0400190 def queryset(self, request):
191 # admins can see all privileges. Users can only see privileges at sites
192 # where they have the admin role.
193 qs = super(SitePrivilegeAdmin, self).queryset(request)
194 if not request.user.is_admin:
195 roles = request.user.get_roles()
196 tenants = []
197 for (role, tenant_list) in roles:
198 if role == 'admin':
199 tenants.extend(tenant_list)
200 valid_sites = Sites.objects.filter(login_base__in=tenants)
201 qs = qs.filter(site__in=valid_sites)
202 return qs
203
Tony Mack9bcbe4f2013-04-29 08:13:27 -0400204 def save_model(self, request, obj, form, change):
205 # update openstack connection to use this site/tenant
Tony Mack93048c22013-05-02 11:20:26 -0400206 auth = request.session.get('auth', {})
Siobhan Tully30fd4292013-05-10 08:59:56 -0400207 #auth['tenant'] = obj.site.login_base
Tony Mack93048c22013-05-02 11:20:26 -0400208 obj.os_manager = OpenStackManager(auth=auth, caller=request.user)
Tony Mack9bcbe4f2013-04-29 08:13:27 -0400209 obj.save()
210
211 def delete_model(self, request, obj):
212 # update openstack connection to use this site/tenant
Tony Mack93048c22013-05-02 11:20:26 -0400213 auth = request.session.get('auth', {})
Siobhan Tully30fd4292013-05-10 08:59:56 -0400214 #auth['tenant'] = obj.site.login_base
Tony Mack93048c22013-05-02 11:20:26 -0400215 obj.os_manager = OpenStackManager(auth=auth, caller=request.user)
Tony Mack9bcbe4f2013-04-29 08:13:27 -0400216 obj.delete()
217
Tony Mackfdd4d802013-04-27 13:02:33 -0400218class KeyAdmin(OSModelAdmin):
Tony Mack759b57a2013-04-14 21:03:31 -0400219 fieldsets = [
Siobhan Tully73291342013-05-10 10:50:08 -0400220 ('Key', {'fields': ['key', 'type', 'blacklisted']})
Tony Mack759b57a2013-04-14 21:03:31 -0400221 ]
Siobhan Tully73291342013-05-10 10:50:08 -0400222 list_display = ['key', 'type', 'blacklisted']
Tony Mack8484bdb2013-04-14 20:26:03 -0400223
Siobhan Tully73291342013-05-10 10:50:08 -0400224 #def queryset(self, request):
Tony Mackc14de8f2013-05-09 21:44:17 -0400225 # admins can see all keys. Users can only see their own key.
Siobhan Tully73291342013-05-10 10:50:08 -0400226 #if request.user.is_admin:
227 # qs = super(KeyAdmin, self).queryset(request)
228 #else:
229 # qs = Key.objects.filter(user=request.user)
Scott Baker133c9212013-05-17 09:09:11 -0700230 #return qs
231
Tony Mackfdd4d802013-04-27 13:02:33 -0400232class SliceAdmin(OSModelAdmin):
Siobhan Tully30fd4292013-05-10 08:59:56 -0400233 fields = ['name', 'site', 'serviceClass', 'description', 'slice_url']
234 list_display = ('name', 'site','serviceClass', 'slice_url')
Scott Baker307e06f2013-05-21 17:25:56 -0700235 inlines = [SliverInline, SliceMembershipInline, SliceTagInline]
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400236
Tony Mack04062832013-05-10 08:22:44 -0400237 def queryset(self, request):
238 # admins can see all keys. Users can only see slices they belong to.
239 qs = super(SliceAdmin, self).queryset(request)
240 if not request.user.is_admin:
241 valid_slices = []
242 roles = request.user.get_roles()
243 for tenant_list in roles.values():
244 valid_slices.extend(tenant_list)
245 qs = qs.filter(name__in=valid_slices)
246 return qs
247
Tony Mack79748612013-05-01 14:52:03 -0400248 def get_formsets(self, request, obj=None):
249 for inline in self.get_inline_instances(request, obj):
250 # hide MyInline in the add view
251 if obj is None:
252 continue
253 # give inline object access to driver and caller
Tony Mack93048c22013-05-02 11:20:26 -0400254 auth = request.session.get('auth', {})
255 auth['tenant'] = obj.name # meed to connect using slice's tenant
256 inline.model.os_manager = OpenStackManager(auth=auth, caller=request.user)
Tony Mack79748612013-05-01 14:52:03 -0400257 yield inline.get_formset(request, obj)
258
Tony Mackfdd4d802013-04-27 13:02:33 -0400259 def get_queryset(self, request):
260 qs = super(SliceAdmin, self).get_queryset(request)
261 if request.user.is_superuser:
262 return qs
263 # users can only see slices at their site
264 return qs.filter(site=request.user.site)
265
Tony Mack9bcbe4f2013-04-29 08:13:27 -0400266class SliceMembershipAdmin(PlanetStackBaseAdmin):
Tony Mack00d361f2013-04-28 10:28:42 -0400267 fieldsets = [
268 (None, {'fields': ['user', 'slice', 'role']})
269 ]
270 list_display = ('user', 'slice', 'role')
Tony Mack00d361f2013-04-28 10:28:42 -0400271
Tony Mack04062832013-05-10 08:22:44 -0400272 def queryset(self, request):
273 # admins can see all memberships. Users can only see memberships of
274 # slices where they have the admin role.
275 qs = super(SliceMembershipAdmin, self).queryset(request)
276 if not request.user.is_admin:
277 roles = request.user.get_roles()
278 tenants = []
279 for (role, tenant_list) in roles:
280 if role == 'admin':
281 tenants.extend(tenant_list)
282 valid_slices = Slice.objects.filter(name__in=tenants)
283 qs = qs.filter(slice__in=valid_slices)
284 return qs
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400285
Tony Mack9bcbe4f2013-04-29 08:13:27 -0400286 def save_model(self, request, obj, form, change):
Tony Mack951dab42013-05-02 19:51:45 -0400287 # update openstack connection to use this site/tenant
288 auth = request.session.get('auth', {})
289 auth['tenant'] = obj.slice.name
290 obj.os_manager = OpenStackManager(auth=auth, caller=request.user)
Tony Mack9bcbe4f2013-04-29 08:13:27 -0400291 obj.save()
292
293 def delete_model(self, request, obj):
Tony Mack951dab42013-05-02 19:51:45 -0400294 # update openstack connection to use this site/tenant
295 auth = request.session.get('auth', {})
296 auth['tenant'] = obj.slice.name
297 obj.os_manager = OpenStackManager(auth=auth, caller=request.user)
Tony Mack9bcbe4f2013-04-29 08:13:27 -0400298 obj.delete()
299
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400300
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400301class ImageAdmin(admin.ModelAdmin):
302 fields = ['image_id', 'name', 'disk_format', 'container_format']
303
304class NodeAdmin(admin.ModelAdmin):
305 list_display = ('name', 'site', 'deploymentNetwork')
306 list_filter = ('deploymentNetwork',)
307
Tony Mackd90cdbf2013-04-16 22:48:40 -0400308
309class SliverForm(forms.ModelForm):
310 class Meta:
Tony Mack1d6b85f2013-05-07 18:49:14 -0400311 model = Sliver
Tony Mackd90cdbf2013-04-16 22:48:40 -0400312 ip = forms.CharField(widget=PlainTextWidget)
Tony Mack18261812013-05-02 16:39:20 -0400313 instance_name = forms.CharField(widget=PlainTextWidget)
Tony Mackd90cdbf2013-04-16 22:48:40 -0400314 widgets = {
315 'ip': PlainTextWidget(),
Tony Mack18261812013-05-02 16:39:20 -0400316 'instance_name': PlainTextWidget(),
Siobhan Tully53437282013-04-26 19:30:27 -0400317 }
Tony Mackd90cdbf2013-04-16 22:48:40 -0400318
Tony Mack9bcbe4f2013-04-29 08:13:27 -0400319class SliverAdmin(PlanetStackBaseAdmin):
Tony Mackd90cdbf2013-04-16 22:48:40 -0400320 form = SliverForm
Tony Mackcdec0902013-04-15 00:38:49 -0400321 fieldsets = [
Tony Mack10082022013-05-06 17:15:00 -0400322 ('Sliver', {'fields': ['ip', 'instance_name', 'slice', 'numberCores', 'image', 'key', 'node', 'deploymentNetwork']})
Tony Mackcdec0902013-04-15 00:38:49 -0400323 ]
Tony Mack10082022013-05-06 17:15:00 -0400324 list_display = ['ip', 'instance_name', 'slice', 'numberCores', 'image', 'key', 'node', 'deploymentNetwork']
Tony Mack53106f32013-04-27 16:43:01 -0400325
Tony Mack04062832013-05-10 08:22:44 -0400326 def queryset(self, request):
327 # admins can see all slivers. Users can only see slivers of
328 # the slices they belong to.
329 qs = super(SliverAdmin, self).queryset(request)
330 if not request.user.is_admin:
331 tenants = []
332 roles = request.user.get_roles()
333 for tenant_list in roles.values():
334 tenants.extend(tenant_list)
335 valid_slices = Slice.objects.filter(name__in=tenants)
336 qs = qs.filter(slice__in=valid_slices)
337 return qs
338
Tony Mack1d6b85f2013-05-07 18:49:14 -0400339 def get_formsets(self, request, obj=None):
340 # make some fields read only if we are updating an existing record
341 if obj == None:
342 #self.readonly_fields = ('ip', 'instance_name')
343 self.readonly_fields = ()
344 else:
Tony Mack1e889462013-05-10 21:34:54 -0400345 self.readonly_fields = ()
346 #self.readonly_fields = ('ip', 'instance_name', 'slice', 'image', 'key')
Tony Mack1d6b85f2013-05-07 18:49:14 -0400347
348 for inline in self.get_inline_instances(request, obj):
349 # hide MyInline in the add view
350 if obj is None:
351 continue
352 # give inline object access to driver and caller
353 auth = request.session.get('auth', {})
354 auth['tenant'] = obj.name # meed to connect using slice's tenant
355 inline.model.os_manager = OpenStackManager(auth=auth, caller=request.user)
356 yield inline.get_formset(request, obj)
Tony Mack53106f32013-04-27 16:43:01 -0400357
358 def save_model(self, request, obj, form, change):
Tony Mack951dab42013-05-02 19:51:45 -0400359 # update openstack connection to use this site/tenant
360 auth = request.session.get('auth', {})
361 auth['tenant'] = obj.slice.name
362 obj.os_manager = OpenStackManager(auth=auth, caller=request.user)
Tony Mack53106f32013-04-27 16:43:01 -0400363 obj.save()
364
365 def delete_model(self, request, obj):
Tony Mack951dab42013-05-02 19:51:45 -0400366 # update openstack connection to use this site/tenant
367 auth = request.session.get('auth', {})
368 auth['tenant'] = obj.slice.name
369 obj.os_manager = OpenStackManager(auth=auth, caller=request.user)
Tony Mack53106f32013-04-27 16:43:01 -0400370 obj.delete()
Tony Mackcdec0902013-04-15 00:38:49 -0400371
Siobhan Tully53437282013-04-26 19:30:27 -0400372class UserCreationForm(forms.ModelForm):
373 """A form for creating new users. Includes all the required
374 fields, plus a repeated password."""
375 password1 = forms.CharField(label='Password', widget=forms.PasswordInput)
376 password2 = forms.CharField(label='Password confirmation', widget=forms.PasswordInput)
377
378 class Meta:
Siobhan Tully30fd4292013-05-10 08:59:56 -0400379 model = User
380 fields = ('email', 'firstname', 'lastname', 'phone', 'key', 'site')
Siobhan Tully53437282013-04-26 19:30:27 -0400381
382 def clean_password2(self):
383 # Check that the two password entries match
384 password1 = self.cleaned_data.get("password1")
385 password2 = self.cleaned_data.get("password2")
386 if password1 and password2 and password1 != password2:
387 raise forms.ValidationError("Passwords don't match")
388 return password2
389
390 def save(self, commit=True):
391 # Save the provided password in hashed format
392 user = super(UserCreationForm, self).save(commit=False)
Tony Mackf9f4afb2013-05-01 21:02:12 -0400393 user.password = self.cleaned_data["password1"]
394 #user.set_password(self.cleaned_data["password1"])
Siobhan Tully53437282013-04-26 19:30:27 -0400395 if commit:
396 user.save()
397 return user
398
399
400class UserChangeForm(forms.ModelForm):
401 """A form for updating users. Includes all the fields on
402 the user, but replaces the password field with admin's
403 password hash display field.
404 """
405 password = ReadOnlyPasswordHashField()
406
407 class Meta:
Siobhan Tully30fd4292013-05-10 08:59:56 -0400408 model = User
Siobhan Tully53437282013-04-26 19:30:27 -0400409
410 def clean_password(self):
411 # Regardless of what the user provides, return the initial value.
412 # This is done here, rather than on the field, because the
413 # field does not have access to the initial value
414 return self.initial["password"]
415
416
Siobhan Tully30fd4292013-05-10 08:59:56 -0400417class UserAdmin(UserAdmin, OSModelAdmin):
Siobhan Tully53437282013-04-26 19:30:27 -0400418 class Meta:
419 app_label = "core"
420
421 # The forms to add and change user instances
422 form = UserChangeForm
423 add_form = UserCreationForm
424
425 # The fields to be used in displaying the User model.
426 # These override the definitions on the base UserAdmin
427 # that reference specific fields on auth.User.
Tony Mack416c0f22013-05-09 16:59:09 -0400428 list_display = ('email', 'site', 'firstname', 'lastname', 'is_admin', 'last_login')
Siobhan Tully53437282013-04-26 19:30:27 -0400429 list_filter = ('site',)
Siobhan Tullyaa1bcd52013-05-10 12:43:09 -0400430 inlines = [SitePrivilegeInline, SliceMembershipInline]
Siobhan Tully53437282013-04-26 19:30:27 -0400431 fieldsets = (
Scott Baker9266e6b2013-05-19 15:54:48 -0700432 (None, {'fields': ('email', 'password', 'site', 'is_admin', 'timezone')}),
Siobhan Tullyaa1bcd52013-05-10 12:43:09 -0400433 ('Personal info', {'fields': ('firstname','lastname','phone', 'key')}),
Siobhan Tully53437282013-04-26 19:30:27 -0400434 #('Important dates', {'fields': ('last_login',)}),
435 )
436 add_fieldsets = (
437 (None, {
438 'classes': ('wide',),
Tony Mack89f70f12013-05-10 20:20:03 -0400439 'fields': ('email', 'firstname', 'lastname', 'phone', 'site', 'key','password1', 'password2', 'is_admin')}
Siobhan Tully53437282013-04-26 19:30:27 -0400440 ),
441 )
442 search_fields = ('email',)
443 ordering = ('email',)
444 filter_horizontal = ()
445
Scott Baker3de3e372013-05-10 16:50:44 -0700446class ServiceResourceInline(admin.TabularInline):
447 model = ServiceResource
448 extra = 0
449
450class ServiceClassAdmin(admin.ModelAdmin):
451 list_display = ('name', 'commitment', 'membershipFee')
452 inlines = [ServiceResourceInline]
453
Scott Baker133c9212013-05-17 09:09:11 -0700454class ReservedResourceInline(admin.TabularInline):
455 model = ReservedResource
456 extra = 0
457
458 def formfield_for_foreignkey(self, db_field, request=None, **kwargs):
459 field = super(ReservedResourceInline, self).formfield_for_foreignkey(db_field, request, **kwargs)
460
461 if db_field.name == 'resource':
462 # restrict resources to those that the slice's service class allows
463 if request._slice is not None:
464 field.queryset = field.queryset.filter(serviceClass = request._slice.serviceClass, calendarReservable=True)
465 if len(field.queryset) > 0:
466 field.initial = field.queryset.all()[0]
467 else:
468 field.queryset = field.queryset.none()
469 elif db_field.name == 'sliver':
470 # restrict slivers to those that belong to the slice
471 if request._slice is not None:
472 field.queryset = field.queryset.filter(slice = request._slice)
473 else:
474 field.queryset = field.queryset.none()
475
476 return field
477
478class ReservationChangeForm(forms.ModelForm):
479 class Meta:
480 model = Reservation
481
482class ReservationAddForm(forms.ModelForm):
483 slice = forms.ModelChoiceField(queryset=Slice.objects.all(), widget=forms.Select(attrs={"onChange":"document.getElementById('id_refresh').value=1; submit()"}))
484 refresh = forms.CharField(widget=forms.HiddenInput())
485
486 class Media:
487 css = {'all': ('planetstack.css',)} # .field-refresh { display: none; }
488
489 def clean_slice(self):
490 slice = self.cleaned_data.get("slice")
491 x = ServiceResource.objects.filter(serviceClass = slice.serviceClass, calendarReservable=True)
492 if len(x) == 0:
493 raise forms.ValidationError("The slice you selected does not have a service class that allows reservations")
494 return slice
495
496 class Meta:
497 model = Reservation
498
499class ReservationAddRefreshForm(ReservationAddForm):
500 """ This form is displayed when the Reservation Form receives an update
501 from the Slice dropdown onChange handler. It doesn't validate the
502 data and doesn't save the data. This will cause the form to be
503 redrawn.
504 """
505
Scott Baker8737e5f2013-05-17 09:35:32 -0700506 """ don't validate anything other than slice """
507 dont_validate_fields = ("startTime", "duration")
508
Scott Baker133c9212013-05-17 09:09:11 -0700509 def full_clean(self):
510 result = super(ReservationAddForm, self).full_clean()
Scott Baker8737e5f2013-05-17 09:35:32 -0700511
512 for fieldname in self.dont_validate_fields:
513 if fieldname in self._errors:
514 del self._errors[fieldname]
515
Scott Baker133c9212013-05-17 09:09:11 -0700516 return result
517
518 """ don't save anything """
519 def is_valid(self):
520 return False
521
522class ReservationAdmin(admin.ModelAdmin):
523 list_display = ('startTime', 'duration')
524 inlines = [ReservedResourceInline]
525 form = ReservationAddForm
526
527 def add_view(self, request, form_url='', extra_context=None):
Scott Bakeracd45142013-05-19 16:19:16 -0700528 timezone.activate(request.user.timezone)
Scott Baker133c9212013-05-17 09:09:11 -0700529 request._refresh = False
530 request._slice = None
531 if request.method == 'POST':
Scott Baker8737e5f2013-05-17 09:35:32 -0700532 # "refresh" will be set to "1" if the form was submitted due to
533 # a change in the Slice dropdown.
Scott Baker133c9212013-05-17 09:09:11 -0700534 if request.POST.get("refresh","1") == "1":
535 request._refresh = True
536 request.POST["refresh"] = "0"
Scott Baker8737e5f2013-05-17 09:35:32 -0700537
538 # Keep track of the slice that was selected, so the
539 # reservedResource inline can filter items for the slice.
Scott Baker133c9212013-05-17 09:09:11 -0700540 request._slice = request.POST.get("slice",None)
541 if (request._slice is not None):
542 request._slice = Slice.objects.get(id=request._slice)
543
544 result = super(ReservationAdmin, self).add_view(request, form_url, extra_context)
545 return result
546
Scott Bakeracd45142013-05-19 16:19:16 -0700547 def changelist_view(self, request, extra_context = None):
548 timezone.activate(request.user.timezone)
549 return super(ReservationAdmin, self).changelist_view(request, extra_context)
550
Scott Baker133c9212013-05-17 09:09:11 -0700551 def get_form(self, request, obj=None, **kwargs):
552 request._obj_ = obj
553 if obj is not None:
Scott Baker8737e5f2013-05-17 09:35:32 -0700554 # For changes, set request._slice to the slice already set in the
555 # object.
Scott Baker133c9212013-05-17 09:09:11 -0700556 request._slice = obj.slice
557 self.form = ReservationChangeForm
558 else:
559 if getattr(request, "_refresh", False):
560 self.form = ReservationAddRefreshForm
561 else:
562 self.form = ReservationAddForm
563 return super(ReservationAdmin, self).get_form(request, obj, **kwargs)
564
565 def get_readonly_fields(self, request, obj=None):
566 if (obj is not None):
567 # Prevent slice from being changed after the reservation has been
568 # created.
569 return ['slice']
570 else:
571 return []
Scott Baker3de3e372013-05-10 16:50:44 -0700572
Tony Mack31c2b8f2013-04-26 20:01:42 -0400573# register a signal that caches the user's credentials when they log in
574def cache_credentials(sender, user, request, **kwds):
575 auth = {'username': request.POST['username'],
576 'password': request.POST['password']}
577 request.session['auth'] = auth
578user_logged_in.connect(cache_credentials)
579
Siobhan Tully53437282013-04-26 19:30:27 -0400580# Now register the new UserAdmin...
Siobhan Tully30fd4292013-05-10 08:59:56 -0400581admin.site.register(User, UserAdmin)
Siobhan Tully53437282013-04-26 19:30:27 -0400582# ... and, since we're not using Django's builtin permissions,
583# unregister the Group model from admin.
584admin.site.unregister(Group)
585
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400586admin.site.register(Site, SiteAdmin)
Siobhan Tullyaa1bcd52013-05-10 12:43:09 -0400587admin.site.register(SitePrivilege, SitePrivilegeAdmin)
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400588admin.site.register(Slice, SliceAdmin)
Siobhan Tullyaa1bcd52013-05-10 12:43:09 -0400589admin.site.register(SliceMembership, SliceMembershipAdmin)
590#admin.site.register(Subnet)
Siobhan Tully73291342013-05-10 10:50:08 -0400591admin.site.register(Image, ImageAdmin)
Siobhan Tullyaa1bcd52013-05-10 12:43:09 -0400592admin.site.register(Node, NodeAdmin)
Tony Mackcdec0902013-04-15 00:38:49 -0400593admin.site.register(Sliver, SliverAdmin)
Tony Mack759b57a2013-04-14 21:03:31 -0400594admin.site.register(Key, KeyAdmin)
Siobhan Tullyaa1bcd52013-05-10 12:43:09 -0400595admin.site.register(Role, RoleAdmin)
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400596admin.site.register(DeploymentNetwork, DeploymentNetworkAdmin)
Scott Baker3de3e372013-05-10 16:50:44 -0700597admin.site.register(ServiceClass, ServiceClassAdmin)
Scott Baker133c9212013-05-17 09:09:11 -0700598admin.site.register(Reservation, ReservationAdmin)
Tony Mack7130ac32013-03-22 21:58:00 -0400599