blob: 9c7cc5466eb2de1103527bdbaaa7a714f1a1fabf [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
Siobhan Tullybf1153a2013-05-27 20:53:48 -040014import django_evolution
Tony Mack7130ac32013-03-22 21:58:00 -040015
Siobhan Tully4bc09f22013-04-10 21:15:21 -040016
17class ReadonlyTabularInline(admin.TabularInline):
18 can_delete = False
19 extra = 0
20 editable_fields = []
21
22 def get_readonly_fields(self, request, obj=None):
23 fields = []
24 for field in self.model._meta.get_all_field_names():
25 if (not field == 'id'):
26 if (field not in self.editable_fields):
27 fields.append(field)
28 return fields
29
30 def has_add_permission(self, request):
31 return False
32
33class SliverInline(admin.TabularInline):
34 model = Sliver
Tony Mack3777b012013-05-07 21:38:06 -040035 fields = ['ip', 'instance_name', 'slice', 'numberCores', 'image', 'key', 'node', 'deploymentNetwork']
Siobhan Tully4bc09f22013-04-10 21:15:21 -040036 extra = 0
Tony Mack3777b012013-05-07 21:38:06 -040037 #readonly_fields = ['ip', 'instance_name', 'image']
38 readonly_fields = ['ip', 'instance_name']
Siobhan Tully4bc09f22013-04-10 21:15:21 -040039
40class SiteInline(admin.TabularInline):
41 model = Site
42 extra = 0
43
Siobhan Tully30fd4292013-05-10 08:59:56 -040044class UserInline(admin.TabularInline):
45 model = User
Siobhan Tully47ae1b52013-05-10 15:53:14 -040046 fields = ['email', 'firstname', 'lastname']
Siobhan Tully30fd4292013-05-10 08:59:56 -040047 extra = 0
48
Tony Mack00d361f2013-04-28 10:28:42 -040049class SliceInline(admin.TabularInline):
50 model = Slice
51 extra = 0
52
Tony Mack00d361f2013-04-28 10:28:42 -040053class RoleInline(admin.TabularInline):
54 model = Role
55 extra = 0
56
Siobhan Tully4bc09f22013-04-10 21:15:21 -040057class NodeInline(admin.TabularInline):
58 model = Node
59 extra = 0
60
Siobhan Tullyaa1bcd52013-05-10 12:43:09 -040061class SitePrivilegeInline(admin.TabularInline):
62 model = SitePrivilege
63 extra = 0
64
65class SliceMembershipInline(admin.TabularInline):
66 model = SliceMembership
67 extra = 0
68
Scott Baker307e06f2013-05-21 17:25:56 -070069class SliceTagInline(admin.TabularInline):
70 model = SliceTag
71 extra = 0
72
Tony Mack5e71a662013-05-03 23:30:41 -040073class PlainTextWidget(forms.HiddenInput):
74 input_type = 'hidden'
75
76 def render(self, name, value, attrs=None):
77 if value is None:
78 value = ''
Tony Mack1d6b85f2013-05-07 18:49:14 -040079 return mark_safe(str(value) + super(PlainTextWidget, self).render(name, value, attrs))
Tony Mack9bcbe4f2013-04-29 08:13:27 -040080
Siobhan Tully4bc09f22013-04-10 21:15:21 -040081class PlanetStackBaseAdmin(admin.ModelAdmin):
82 save_on_top = False
83
Tony Mackfdd4d802013-04-27 13:02:33 -040084class OSModelAdmin(PlanetStackBaseAdmin):
Tony Mackd685bfa2013-05-02 10:09:51 -040085 """Attach client connection to openstack on delete() and save()"""
Tony Mack79748612013-05-01 14:52:03 -040086
Tony Mackfdd4d802013-04-27 13:02:33 -040087 def save_model(self, request, obj, form, change):
Tony Mack38e247c2013-05-05 11:48:14 -040088 if request.user.site:
89 auth = request.session.get('auth', {})
90 auth['tenant'] = request.user.site.login_base
91 obj.os_manager = OpenStackManager(auth=auth, caller=request.user)
Tony Mackfdd4d802013-04-27 13:02:33 -040092 obj.save()
93
94 def delete_model(self, request, obj):
Tony Mack38e247c2013-05-05 11:48:14 -040095 if request.user.site:
96 auth = request.session.get('auth', {})
97 auth['tenant'] = request.user.site.login_base
98 obj.os_manager = OpenStackManager(auth=auth, caller=request.user)
Tony Mackd685bfa2013-05-02 10:09:51 -040099 obj.delete()
Tony Mack9bcbe4f2013-04-29 08:13:27 -0400100
Tony Mackd685bfa2013-05-02 10:09:51 -0400101class RoleAdmin(OSModelAdmin):
Tony Mack9bcbe4f2013-04-29 08:13:27 -0400102 fieldsets = [
103 ('Role', {'fields': ['role_type']})
104 ]
105 list_display = ('role_type',)
Tony Mackfdd4d802013-04-27 13:02:33 -0400106
Tony Mack02755d42013-05-02 00:00:10 -0400107
Siobhan Tullybf1153a2013-05-27 20:53:48 -0400108class DeploymentAdminForm(forms.ModelForm):
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400109 sites = forms.ModelMultipleChoiceField(
110 queryset=Site.objects.all(),
111 required=False,
112 widget=FilteredSelectMultiple(
113 verbose_name=('Sites'), is_stacked=False
114 )
115 )
116 class Meta:
Siobhan Tullybf1153a2013-05-27 20:53:48 -0400117 model = Deployment
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400118
119 def __init__(self, *args, **kwargs):
Siobhan Tullybf1153a2013-05-27 20:53:48 -0400120 super(DeploymentAdminForm, self).__init__(*args, **kwargs)
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400121
122 if self.instance and self.instance.pk:
123 self.fields['sites'].initial = self.instance.sites.all()
124
125 def save(self, commit=True):
Siobhan Tullybf1153a2013-05-27 20:53:48 -0400126 deploymentNetwork = super(DeploymentAdminForm, self).save(commit=False)
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400127 if commit:
128 deploymentNetwork.save()
129
130 if deploymentNetwork.pk:
131 deploymentNetwork.sites = self.cleaned_data['sites']
132 self.save_m2m()
133
134 return deploymentNetwork
135
Siobhan Tullybf1153a2013-05-27 20:53:48 -0400136class DeploymentAdmin(PlanetStackBaseAdmin):
137 form = DeploymentAdminForm
Siobhan Tullyaa1bcd52013-05-10 12:43:09 -0400138 inlines = [NodeInline,SliverInline]
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400139
Tony Mack5cd13202013-05-01 21:48:38 -0400140 def get_formsets(self, request, obj=None):
141 for inline in self.get_inline_instances(request, obj):
142 # hide MyInline in the add view
143 if obj is None:
144 continue
145 # give inline object access to driver and caller
Tony Macked163d72013-05-02 20:05:42 -0400146 auth = request.session.get('auth', {})
Siobhan Tully73291342013-05-10 10:50:08 -0400147 if request.user.site:
148 auth['tenant'] = request.user.site.login_base
Tony Macked163d72013-05-02 20:05:42 -0400149 inline.model.os_manager = OpenStackManager(auth=auth, caller=request.user)
Tony Mack5cd13202013-05-01 21:48:38 -0400150 yield inline.get_formset(request, obj)
151
Tony Mackfdd4d802013-04-27 13:02:33 -0400152class SiteAdmin(OSModelAdmin):
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400153 fieldsets = [
154 (None, {'fields': ['name', 'site_url', 'enabled', 'is_public', 'login_base']}),
155 ('Location', {'fields': ['latitude', 'longitude']}),
156 ('Deployment Networks', {'fields': ['deployments']})
157 ]
158 list_display = ('name', 'login_base','site_url', 'enabled')
159 filter_horizontal = ('deployments',)
Siobhan Tullyaa1bcd52013-05-10 12:43:09 -0400160 inlines = [NodeInline, UserInline, SitePrivilegeInline]
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400161 search_fields = ['name']
162
Tony Mack04062832013-05-10 08:22:44 -0400163 def queryset(self, request):
164 # admins can see all keys. Users can only see sites they belong to.
165 qs = super(SiteAdmin, self).queryset(request)
166 if not request.user.is_admin:
167 valid_sites = [request.user.site.login_base]
168 roles = request.user.get_roles()
169 for tenant_list in roles.values():
170 valid_sites.extend(tenant_list)
171 qs = qs.filter(login_base__in=valid_sites)
172 return qs
173
Tony Mack5cd13202013-05-01 21:48:38 -0400174 def get_formsets(self, request, obj=None):
175 for inline in self.get_inline_instances(request, obj):
176 # hide MyInline in the add view
177 if obj is None:
178 continue
179 # give inline object access to driver and caller
Tony Mack60722062013-05-02 10:57:04 -0400180 auth = request.session.get('auth', {})
Siobhan Tully30fd4292013-05-10 08:59:56 -0400181 #auth['tenant'] = request.user.site.login_base
Tony Mack60722062013-05-02 10:57:04 -0400182 inline.model.os_manager = OpenStackManager(auth=auth, caller=request.user)
Tony Mack5cd13202013-05-01 21:48:38 -0400183 yield inline.get_formset(request, obj)
184
Tony Mack9bcbe4f2013-04-29 08:13:27 -0400185class SitePrivilegeAdmin(PlanetStackBaseAdmin):
Tony Mack00d361f2013-04-28 10:28:42 -0400186 fieldsets = [
187 (None, {'fields': ['user', 'site', 'role']})
188 ]
189 list_display = ('user', 'site', 'role')
190
Tony Mack04062832013-05-10 08:22:44 -0400191 def queryset(self, request):
192 # admins can see all privileges. Users can only see privileges at sites
193 # where they have the admin role.
194 qs = super(SitePrivilegeAdmin, self).queryset(request)
195 if not request.user.is_admin:
196 roles = request.user.get_roles()
197 tenants = []
198 for (role, tenant_list) in roles:
199 if role == 'admin':
200 tenants.extend(tenant_list)
201 valid_sites = Sites.objects.filter(login_base__in=tenants)
202 qs = qs.filter(site__in=valid_sites)
203 return qs
204
Tony Mack9bcbe4f2013-04-29 08:13:27 -0400205 def save_model(self, request, obj, form, change):
206 # update openstack connection to use this site/tenant
Tony Mack93048c22013-05-02 11:20:26 -0400207 auth = request.session.get('auth', {})
Siobhan Tully30fd4292013-05-10 08:59:56 -0400208 #auth['tenant'] = obj.site.login_base
Tony Mack93048c22013-05-02 11:20:26 -0400209 obj.os_manager = OpenStackManager(auth=auth, caller=request.user)
Tony Mack9bcbe4f2013-04-29 08:13:27 -0400210 obj.save()
211
212 def delete_model(self, request, obj):
213 # update openstack connection to use this site/tenant
Tony Mack93048c22013-05-02 11:20:26 -0400214 auth = request.session.get('auth', {})
Siobhan Tully30fd4292013-05-10 08:59:56 -0400215 #auth['tenant'] = obj.site.login_base
Tony Mack93048c22013-05-02 11:20:26 -0400216 obj.os_manager = OpenStackManager(auth=auth, caller=request.user)
Tony Mack9bcbe4f2013-04-29 08:13:27 -0400217 obj.delete()
218
Tony Mackfdd4d802013-04-27 13:02:33 -0400219class KeyAdmin(OSModelAdmin):
Tony Mack759b57a2013-04-14 21:03:31 -0400220 fieldsets = [
Siobhan Tully73291342013-05-10 10:50:08 -0400221 ('Key', {'fields': ['key', 'type', 'blacklisted']})
Tony Mack759b57a2013-04-14 21:03:31 -0400222 ]
Siobhan Tully73291342013-05-10 10:50:08 -0400223 list_display = ['key', 'type', 'blacklisted']
Tony Mack8484bdb2013-04-14 20:26:03 -0400224
Siobhan Tully73291342013-05-10 10:50:08 -0400225 #def queryset(self, request):
Tony Mackc14de8f2013-05-09 21:44:17 -0400226 # admins can see all keys. Users can only see their own key.
Siobhan Tully73291342013-05-10 10:50:08 -0400227 #if request.user.is_admin:
228 # qs = super(KeyAdmin, self).queryset(request)
229 #else:
230 # qs = Key.objects.filter(user=request.user)
Scott Baker133c9212013-05-17 09:09:11 -0700231 #return qs
232
Tony Mackfdd4d802013-04-27 13:02:33 -0400233class SliceAdmin(OSModelAdmin):
Siobhan Tully30fd4292013-05-10 08:59:56 -0400234 fields = ['name', 'site', 'serviceClass', 'description', 'slice_url']
235 list_display = ('name', 'site','serviceClass', 'slice_url')
Scott Baker307e06f2013-05-21 17:25:56 -0700236 inlines = [SliverInline, SliceMembershipInline, SliceTagInline]
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400237
Tony Mack04062832013-05-10 08:22:44 -0400238 def queryset(self, request):
239 # admins can see all keys. Users can only see slices they belong to.
240 qs = super(SliceAdmin, self).queryset(request)
241 if not request.user.is_admin:
242 valid_slices = []
243 roles = request.user.get_roles()
244 for tenant_list in roles.values():
245 valid_slices.extend(tenant_list)
246 qs = qs.filter(name__in=valid_slices)
247 return qs
248
Tony Mack79748612013-05-01 14:52:03 -0400249 def get_formsets(self, request, obj=None):
250 for inline in self.get_inline_instances(request, obj):
251 # hide MyInline in the add view
252 if obj is None:
253 continue
254 # give inline object access to driver and caller
Tony Mack93048c22013-05-02 11:20:26 -0400255 auth = request.session.get('auth', {})
256 auth['tenant'] = obj.name # meed to connect using slice's tenant
257 inline.model.os_manager = OpenStackManager(auth=auth, caller=request.user)
Tony Mack79748612013-05-01 14:52:03 -0400258 yield inline.get_formset(request, obj)
259
Tony Mackfdd4d802013-04-27 13:02:33 -0400260 def get_queryset(self, request):
261 qs = super(SliceAdmin, self).get_queryset(request)
262 if request.user.is_superuser:
263 return qs
264 # users can only see slices at their site
265 return qs.filter(site=request.user.site)
266
Tony Mack9bcbe4f2013-04-29 08:13:27 -0400267class SliceMembershipAdmin(PlanetStackBaseAdmin):
Tony Mack00d361f2013-04-28 10:28:42 -0400268 fieldsets = [
269 (None, {'fields': ['user', 'slice', 'role']})
270 ]
271 list_display = ('user', 'slice', 'role')
Tony Mack00d361f2013-04-28 10:28:42 -0400272
Tony Mack04062832013-05-10 08:22:44 -0400273 def queryset(self, request):
274 # admins can see all memberships. Users can only see memberships of
275 # slices where they have the admin role.
276 qs = super(SliceMembershipAdmin, self).queryset(request)
277 if not request.user.is_admin:
278 roles = request.user.get_roles()
279 tenants = []
280 for (role, tenant_list) in roles:
281 if role == 'admin':
282 tenants.extend(tenant_list)
283 valid_slices = Slice.objects.filter(name__in=tenants)
284 qs = qs.filter(slice__in=valid_slices)
285 return qs
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400286
Tony Mack9bcbe4f2013-04-29 08:13:27 -0400287 def save_model(self, request, obj, form, change):
Tony Mack951dab42013-05-02 19:51:45 -0400288 # update openstack connection to use this site/tenant
289 auth = request.session.get('auth', {})
290 auth['tenant'] = obj.slice.name
291 obj.os_manager = OpenStackManager(auth=auth, caller=request.user)
Tony Mack9bcbe4f2013-04-29 08:13:27 -0400292 obj.save()
293
294 def delete_model(self, request, obj):
Tony Mack951dab42013-05-02 19:51:45 -0400295 # update openstack connection to use this site/tenant
296 auth = request.session.get('auth', {})
297 auth['tenant'] = obj.slice.name
298 obj.os_manager = OpenStackManager(auth=auth, caller=request.user)
Tony Mack9bcbe4f2013-04-29 08:13:27 -0400299 obj.delete()
300
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400301
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400302class ImageAdmin(admin.ModelAdmin):
303 fields = ['image_id', 'name', 'disk_format', 'container_format']
304
305class NodeAdmin(admin.ModelAdmin):
Siobhan Tullybf1153a2013-05-27 20:53:48 -0400306 list_display = ('name', 'site', 'deployment')
307 list_filter = ('deployment',)
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400308
Tony Mackd90cdbf2013-04-16 22:48:40 -0400309
310class SliverForm(forms.ModelForm):
311 class Meta:
Tony Mack1d6b85f2013-05-07 18:49:14 -0400312 model = Sliver
Tony Mackd90cdbf2013-04-16 22:48:40 -0400313 ip = forms.CharField(widget=PlainTextWidget)
Tony Mack18261812013-05-02 16:39:20 -0400314 instance_name = forms.CharField(widget=PlainTextWidget)
Tony Mackd90cdbf2013-04-16 22:48:40 -0400315 widgets = {
316 'ip': PlainTextWidget(),
Tony Mack18261812013-05-02 16:39:20 -0400317 'instance_name': PlainTextWidget(),
Siobhan Tully53437282013-04-26 19:30:27 -0400318 }
Tony Mackd90cdbf2013-04-16 22:48:40 -0400319
Tony Mack9bcbe4f2013-04-29 08:13:27 -0400320class SliverAdmin(PlanetStackBaseAdmin):
Tony Mackd90cdbf2013-04-16 22:48:40 -0400321 form = SliverForm
Tony Mackcdec0902013-04-15 00:38:49 -0400322 fieldsets = [
Tony Mack10082022013-05-06 17:15:00 -0400323 ('Sliver', {'fields': ['ip', 'instance_name', 'slice', 'numberCores', 'image', 'key', 'node', 'deploymentNetwork']})
Tony Mackcdec0902013-04-15 00:38:49 -0400324 ]
Tony Mack10082022013-05-06 17:15:00 -0400325 list_display = ['ip', 'instance_name', 'slice', 'numberCores', 'image', 'key', 'node', 'deploymentNetwork']
Tony Mack53106f32013-04-27 16:43:01 -0400326
Tony Mack04062832013-05-10 08:22:44 -0400327 def queryset(self, request):
328 # admins can see all slivers. Users can only see slivers of
329 # the slices they belong to.
330 qs = super(SliverAdmin, self).queryset(request)
331 if not request.user.is_admin:
332 tenants = []
333 roles = request.user.get_roles()
334 for tenant_list in roles.values():
335 tenants.extend(tenant_list)
336 valid_slices = Slice.objects.filter(name__in=tenants)
337 qs = qs.filter(slice__in=valid_slices)
338 return qs
339
Tony Mack1d6b85f2013-05-07 18:49:14 -0400340 def get_formsets(self, request, obj=None):
341 # make some fields read only if we are updating an existing record
342 if obj == None:
343 #self.readonly_fields = ('ip', 'instance_name')
344 self.readonly_fields = ()
345 else:
Tony Mack1e889462013-05-10 21:34:54 -0400346 self.readonly_fields = ()
347 #self.readonly_fields = ('ip', 'instance_name', 'slice', 'image', 'key')
Tony Mack1d6b85f2013-05-07 18:49:14 -0400348
349 for inline in self.get_inline_instances(request, obj):
350 # hide MyInline in the add view
351 if obj is None:
352 continue
353 # give inline object access to driver and caller
354 auth = request.session.get('auth', {})
355 auth['tenant'] = obj.name # meed to connect using slice's tenant
356 inline.model.os_manager = OpenStackManager(auth=auth, caller=request.user)
357 yield inline.get_formset(request, obj)
Tony Mack53106f32013-04-27 16:43:01 -0400358
359 def save_model(self, request, obj, form, change):
Tony Mack951dab42013-05-02 19:51:45 -0400360 # update openstack connection to use this site/tenant
361 auth = request.session.get('auth', {})
362 auth['tenant'] = obj.slice.name
363 obj.os_manager = OpenStackManager(auth=auth, caller=request.user)
Tony Mack53106f32013-04-27 16:43:01 -0400364 obj.save()
365
366 def delete_model(self, request, obj):
Tony Mack951dab42013-05-02 19:51:45 -0400367 # update openstack connection to use this site/tenant
368 auth = request.session.get('auth', {})
369 auth['tenant'] = obj.slice.name
370 obj.os_manager = OpenStackManager(auth=auth, caller=request.user)
Tony Mack53106f32013-04-27 16:43:01 -0400371 obj.delete()
Tony Mackcdec0902013-04-15 00:38:49 -0400372
Siobhan Tully53437282013-04-26 19:30:27 -0400373class UserCreationForm(forms.ModelForm):
374 """A form for creating new users. Includes all the required
375 fields, plus a repeated password."""
376 password1 = forms.CharField(label='Password', widget=forms.PasswordInput)
377 password2 = forms.CharField(label='Password confirmation', widget=forms.PasswordInput)
378
379 class Meta:
Siobhan Tully30fd4292013-05-10 08:59:56 -0400380 model = User
381 fields = ('email', 'firstname', 'lastname', 'phone', 'key', 'site')
Siobhan Tully53437282013-04-26 19:30:27 -0400382
383 def clean_password2(self):
384 # Check that the two password entries match
385 password1 = self.cleaned_data.get("password1")
386 password2 = self.cleaned_data.get("password2")
387 if password1 and password2 and password1 != password2:
388 raise forms.ValidationError("Passwords don't match")
389 return password2
390
391 def save(self, commit=True):
392 # Save the provided password in hashed format
393 user = super(UserCreationForm, self).save(commit=False)
Tony Mackf9f4afb2013-05-01 21:02:12 -0400394 user.password = self.cleaned_data["password1"]
395 #user.set_password(self.cleaned_data["password1"])
Siobhan Tully53437282013-04-26 19:30:27 -0400396 if commit:
397 user.save()
398 return user
399
400
401class UserChangeForm(forms.ModelForm):
402 """A form for updating users. Includes all the fields on
403 the user, but replaces the password field with admin's
404 password hash display field.
405 """
406 password = ReadOnlyPasswordHashField()
407
408 class Meta:
Siobhan Tully30fd4292013-05-10 08:59:56 -0400409 model = User
Siobhan Tully53437282013-04-26 19:30:27 -0400410
411 def clean_password(self):
412 # Regardless of what the user provides, return the initial value.
413 # This is done here, rather than on the field, because the
414 # field does not have access to the initial value
415 return self.initial["password"]
416
417
Siobhan Tully30fd4292013-05-10 08:59:56 -0400418class UserAdmin(UserAdmin, OSModelAdmin):
Siobhan Tully53437282013-04-26 19:30:27 -0400419 class Meta:
420 app_label = "core"
421
422 # The forms to add and change user instances
423 form = UserChangeForm
424 add_form = UserCreationForm
425
426 # The fields to be used in displaying the User model.
427 # These override the definitions on the base UserAdmin
428 # that reference specific fields on auth.User.
Tony Mack416c0f22013-05-09 16:59:09 -0400429 list_display = ('email', 'site', 'firstname', 'lastname', 'is_admin', 'last_login')
Siobhan Tully53437282013-04-26 19:30:27 -0400430 list_filter = ('site',)
Siobhan Tullyaa1bcd52013-05-10 12:43:09 -0400431 inlines = [SitePrivilegeInline, SliceMembershipInline]
Siobhan Tully53437282013-04-26 19:30:27 -0400432 fieldsets = (
Scott Baker9266e6b2013-05-19 15:54:48 -0700433 (None, {'fields': ('email', 'password', 'site', 'is_admin', 'timezone')}),
Siobhan Tullyaa1bcd52013-05-10 12:43:09 -0400434 ('Personal info', {'fields': ('firstname','lastname','phone', 'key')}),
Siobhan Tully53437282013-04-26 19:30:27 -0400435 #('Important dates', {'fields': ('last_login',)}),
436 )
437 add_fieldsets = (
438 (None, {
439 'classes': ('wide',),
Tony Mack89f70f12013-05-10 20:20:03 -0400440 'fields': ('email', 'firstname', 'lastname', 'phone', 'site', 'key','password1', 'password2', 'is_admin')}
Siobhan Tully53437282013-04-26 19:30:27 -0400441 ),
442 )
443 search_fields = ('email',)
444 ordering = ('email',)
445 filter_horizontal = ()
446
Scott Baker3de3e372013-05-10 16:50:44 -0700447class ServiceResourceInline(admin.TabularInline):
448 model = ServiceResource
449 extra = 0
450
451class ServiceClassAdmin(admin.ModelAdmin):
452 list_display = ('name', 'commitment', 'membershipFee')
453 inlines = [ServiceResourceInline]
454
Scott Baker133c9212013-05-17 09:09:11 -0700455class ReservedResourceInline(admin.TabularInline):
456 model = ReservedResource
457 extra = 0
458
459 def formfield_for_foreignkey(self, db_field, request=None, **kwargs):
460 field = super(ReservedResourceInline, self).formfield_for_foreignkey(db_field, request, **kwargs)
461
462 if db_field.name == 'resource':
463 # restrict resources to those that the slice's service class allows
464 if request._slice is not None:
465 field.queryset = field.queryset.filter(serviceClass = request._slice.serviceClass, calendarReservable=True)
466 if len(field.queryset) > 0:
467 field.initial = field.queryset.all()[0]
468 else:
469 field.queryset = field.queryset.none()
470 elif db_field.name == 'sliver':
471 # restrict slivers to those that belong to the slice
472 if request._slice is not None:
473 field.queryset = field.queryset.filter(slice = request._slice)
474 else:
475 field.queryset = field.queryset.none()
476
477 return field
478
479class ReservationChangeForm(forms.ModelForm):
480 class Meta:
481 model = Reservation
482
483class ReservationAddForm(forms.ModelForm):
484 slice = forms.ModelChoiceField(queryset=Slice.objects.all(), widget=forms.Select(attrs={"onChange":"document.getElementById('id_refresh').value=1; submit()"}))
485 refresh = forms.CharField(widget=forms.HiddenInput())
486
487 class Media:
488 css = {'all': ('planetstack.css',)} # .field-refresh { display: none; }
489
490 def clean_slice(self):
491 slice = self.cleaned_data.get("slice")
492 x = ServiceResource.objects.filter(serviceClass = slice.serviceClass, calendarReservable=True)
493 if len(x) == 0:
494 raise forms.ValidationError("The slice you selected does not have a service class that allows reservations")
495 return slice
496
497 class Meta:
498 model = Reservation
499
500class ReservationAddRefreshForm(ReservationAddForm):
501 """ This form is displayed when the Reservation Form receives an update
502 from the Slice dropdown onChange handler. It doesn't validate the
503 data and doesn't save the data. This will cause the form to be
504 redrawn.
505 """
506
Scott Baker8737e5f2013-05-17 09:35:32 -0700507 """ don't validate anything other than slice """
508 dont_validate_fields = ("startTime", "duration")
509
Scott Baker133c9212013-05-17 09:09:11 -0700510 def full_clean(self):
511 result = super(ReservationAddForm, self).full_clean()
Scott Baker8737e5f2013-05-17 09:35:32 -0700512
513 for fieldname in self.dont_validate_fields:
514 if fieldname in self._errors:
515 del self._errors[fieldname]
516
Scott Baker133c9212013-05-17 09:09:11 -0700517 return result
518
519 """ don't save anything """
520 def is_valid(self):
521 return False
522
523class ReservationAdmin(admin.ModelAdmin):
524 list_display = ('startTime', 'duration')
525 inlines = [ReservedResourceInline]
526 form = ReservationAddForm
527
528 def add_view(self, request, form_url='', extra_context=None):
Scott Bakeracd45142013-05-19 16:19:16 -0700529 timezone.activate(request.user.timezone)
Scott Baker133c9212013-05-17 09:09:11 -0700530 request._refresh = False
531 request._slice = None
532 if request.method == 'POST':
Scott Baker8737e5f2013-05-17 09:35:32 -0700533 # "refresh" will be set to "1" if the form was submitted due to
534 # a change in the Slice dropdown.
Scott Baker133c9212013-05-17 09:09:11 -0700535 if request.POST.get("refresh","1") == "1":
536 request._refresh = True
537 request.POST["refresh"] = "0"
Scott Baker8737e5f2013-05-17 09:35:32 -0700538
539 # Keep track of the slice that was selected, so the
540 # reservedResource inline can filter items for the slice.
Scott Baker133c9212013-05-17 09:09:11 -0700541 request._slice = request.POST.get("slice",None)
542 if (request._slice is not None):
543 request._slice = Slice.objects.get(id=request._slice)
544
545 result = super(ReservationAdmin, self).add_view(request, form_url, extra_context)
546 return result
547
Scott Bakeracd45142013-05-19 16:19:16 -0700548 def changelist_view(self, request, extra_context = None):
549 timezone.activate(request.user.timezone)
550 return super(ReservationAdmin, self).changelist_view(request, extra_context)
551
Scott Baker133c9212013-05-17 09:09:11 -0700552 def get_form(self, request, obj=None, **kwargs):
553 request._obj_ = obj
554 if obj is not None:
Scott Baker8737e5f2013-05-17 09:35:32 -0700555 # For changes, set request._slice to the slice already set in the
556 # object.
Scott Baker133c9212013-05-17 09:09:11 -0700557 request._slice = obj.slice
558 self.form = ReservationChangeForm
559 else:
560 if getattr(request, "_refresh", False):
561 self.form = ReservationAddRefreshForm
562 else:
563 self.form = ReservationAddForm
564 return super(ReservationAdmin, self).get_form(request, obj, **kwargs)
565
566 def get_readonly_fields(self, request, obj=None):
567 if (obj is not None):
568 # Prevent slice from being changed after the reservation has been
569 # created.
570 return ['slice']
571 else:
572 return []
Scott Baker3de3e372013-05-10 16:50:44 -0700573
Tony Mack31c2b8f2013-04-26 20:01:42 -0400574# register a signal that caches the user's credentials when they log in
575def cache_credentials(sender, user, request, **kwds):
576 auth = {'username': request.POST['username'],
577 'password': request.POST['password']}
578 request.session['auth'] = auth
579user_logged_in.connect(cache_credentials)
580
Siobhan Tully53437282013-04-26 19:30:27 -0400581# Now register the new UserAdmin...
Siobhan Tully30fd4292013-05-10 08:59:56 -0400582admin.site.register(User, UserAdmin)
Siobhan Tully53437282013-04-26 19:30:27 -0400583# ... and, since we're not using Django's builtin permissions,
584# unregister the Group model from admin.
585admin.site.unregister(Group)
586
Siobhan Tullybf1153a2013-05-27 20:53:48 -0400587#Do not show django evolution in the admin interface
588from django_evolution.models import Version, Evolution
589admin.site.unregister(Version)
590admin.site.unregister(Evolution)
591
592
593# When debugging it is often easier to see all the classes, but for regular use
594# only the top-levels should be displayed
595showAll = False
596
597admin.site.register(Deployment, DeploymentAdmin)
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400598admin.site.register(Site, SiteAdmin)
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400599admin.site.register(Slice, SliceAdmin)
Siobhan Tullyaa1bcd52013-05-10 12:43:09 -0400600#admin.site.register(Subnet)
Tony Mack759b57a2013-04-14 21:03:31 -0400601admin.site.register(Key, KeyAdmin)
Siobhan Tullybf1153a2013-05-27 20:53:48 -0400602
603
604if showAll:
605 admin.site.register(Node, NodeAdmin)
606 admin.site.register(SliceMembership, SliceMembershipAdmin)
607 admin.site.register(SitePrivilege, SitePrivilegeAdmin)
608 admin.site.register(Role, RoleAdmin)
609 admin.site.register(Sliver, SliverAdmin)
610 admin.site.register(ServiceClass, ServiceClassAdmin)
611 admin.site.register(Reservation, ReservationAdmin)
612 admin.site.register(Image, ImageAdmin)
Tony Mack7130ac32013-03-22 21:58:00 -0400613