PlainTextWidget no longer wipes out the form field value
[plstackapi.git] / plstackapi / core / admin.py
1 from plstackapi.core.models import Site
2 from plstackapi.core.models import *
3 from plstackapi.openstack.manager import OpenStackManager
4
5 from django.contrib import admin
6 from django.contrib.auth.models import Group
7 from django import forms
8 from django.utils.safestring import mark_safe
9 from django.contrib.auth.admin import UserAdmin
10 from django.contrib.admin.widgets import FilteredSelectMultiple
11 from django.contrib.auth.forms import ReadOnlyPasswordHashField
12 from django.contrib.auth.signals import user_logged_in 
13
14
15 class 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
31 class SliverInline(admin.TabularInline):
32     model = Sliver
33     fields = ['ip', 'name', 'slice', 'numberCores', 'image', 'key', 'node', 'deploymentNetwork']
34     extra = 0
35
36 class SiteInline(admin.TabularInline):
37     model = Site
38     extra = 0
39
40 class SliceInline(admin.TabularInline):
41     model = Slice
42     extra = 0
43
44 class UserInline(admin.TabularInline):
45     model = PLUser
46     extra = 0
47
48 class RoleInline(admin.TabularInline):
49     model = Role
50     extra = 0 
51
52 class NodeInline(admin.TabularInline):
53     model = Node
54     extra = 0
55
56 class PlainTextWidget(forms.HiddenInput):
57     input_type = 'hidden'
58
59     def render(self, name, value, attrs=None):
60         if value is None:
61             value = ''
62         return mark_safe(value + super(PlainTextWidget, self).render(name, value, attrs))
63
64 class PlanetStackBaseAdmin(admin.ModelAdmin):
65     save_on_top = False
66
67 class OSModelAdmin(PlanetStackBaseAdmin):
68     """Attach client connection to openstack on delete() and save()"""
69
70     def save_model(self, request, obj, form, change):
71         auth = request.session.get('auth', {})
72         auth['tenant'] = request.user.site.login_base
73         obj.os_manager = OpenStackManager(auth=auth, caller=request.user)
74         obj.save()
75
76     def delete_model(self, request, obj):
77         auth = request.session.get('auth', {})
78         auth['tenant'] = request.user.site.login_base
79         obj.os_manager = OpenStackManager(auth=auth, caller=request.user)
80         obj.delete() 
81
82 class RoleAdmin(OSModelAdmin):
83     fieldsets = [
84         ('Role', {'fields': ['role_type']})
85     ]
86     list_display = ('role_type',)
87
88
89 class DeploymentNetworkAdminForm(forms.ModelForm):
90     sites = forms.ModelMultipleChoiceField(
91         queryset=Site.objects.all(),
92         required=False,
93         widget=FilteredSelectMultiple(
94             verbose_name=('Sites'), is_stacked=False
95         )
96     )
97     class Meta:
98         model = DeploymentNetwork
99
100     def __init__(self, *args, **kwargs):
101         super(DeploymentNetworkAdminForm, self).__init__(*args, **kwargs)
102
103         if self.instance and self.instance.pk:
104             self.fields['sites'].initial = self.instance.sites.all()
105
106     def save(self, commit=True):
107         deploymentNetwork = super(DeploymentNetworkAdminForm, self).save(commit=False)
108         if commit:
109             deploymentNetwork.save()
110
111         if deploymentNetwork.pk:
112             deploymentNetwork.sites = self.cleaned_data['sites']
113             self.save_m2m()
114
115         return deploymentNetwork
116
117 class DeploymentNetworkAdmin(PlanetStackBaseAdmin):
118     form = DeploymentNetworkAdminForm
119     inlines = [NodeInline,]
120
121     def get_formsets(self, request, obj=None):
122         for inline in self.get_inline_instances(request, obj):
123             # hide MyInline in the add view
124             if obj is None:
125                 continue
126             # give inline object access to driver and caller
127             auth = request.session.get('auth', {})
128             auth['tenant'] = request.user.site.login_base
129             inline.model.os_manager = OpenStackManager(auth=auth, caller=request.user)
130             yield inline.get_formset(request, obj)
131
132 class SiteAdmin(OSModelAdmin):
133     fieldsets = [
134         (None, {'fields': ['name', 'site_url', 'enabled', 'is_public', 'login_base']}),
135         ('Location', {'fields': ['latitude', 'longitude']}),
136         ('Deployment Networks', {'fields': ['deployments']})
137     ]
138     list_display = ('name', 'login_base','site_url', 'enabled')
139     filter_horizontal = ('deployments',)
140     inlines = [NodeInline,]
141     search_fields = ['name']
142
143     def get_formsets(self, request, obj=None):
144         for inline in self.get_inline_instances(request, obj):
145             # hide MyInline in the add view
146             if obj is None:
147                 continue
148             # give inline object access to driver and caller
149             auth = request.session.get('auth', {})
150             auth['tenant'] = request.user.site.login_base
151             inline.model.os_manager = OpenStackManager(auth=auth, caller=request.user)
152             yield inline.get_formset(request, obj)
153
154 class SitePrivilegeAdmin(PlanetStackBaseAdmin):
155     fieldsets = [
156         (None, {'fields': ['user', 'site', 'role']})
157     ]
158     list_display = ('user', 'site', 'role')
159
160     def save_model(self, request, obj, form, change):
161         # update openstack connection to use this site/tenant   
162         auth = request.session.get('auth', {})
163         auth['tenant'] = obj.site.login_base
164         obj.os_manager = OpenStackManager(auth=auth, caller=request.user)
165         obj.save()
166
167     def delete_model(self, request, obj):
168         # update openstack connection to use this site/tenant   
169         auth = request.session.get('auth', {})
170         auth['tenant'] = obj.site.login_base
171         obj.os_manager = OpenStackManager(auth=auth, caller=request.user)
172         obj.delete()
173
174 class KeyAdmin(OSModelAdmin):
175     fieldsets = [
176         ('Key', {'fields': ['name', 'key', 'type', 'blacklisted', 'user']})
177     ]
178     list_display = ['name', 'key', 'type', 'blacklisted', 'user']
179
180     def get_queryset(self, request):
181         # get keys user is allowed to see
182         qs = super(KeyAdmin, self).get_queryset(request)
183         if request.user.is_superuser:
184             return qs
185         # users can only see their own keys
186         return qs.filter(user=request.user)  
187         
188
189 class SliceAdmin(OSModelAdmin):
190     fields = ['name', 'site', 'serviceClass', 'instantiation', 'description', 'slice_url']
191     list_display = ('name', 'site','serviceClass', 'slice_url', 'instantiation')
192     inlines = [SliverInline]
193
194     def get_formsets(self, request, obj=None):
195         for inline in self.get_inline_instances(request, obj):
196             # hide MyInline in the add view
197             if obj is None:
198                 continue
199             # give inline object access to driver and caller
200             auth = request.session.get('auth', {})
201             auth['tenant'] = obj.name       # meed to connect using slice's tenant
202             inline.model.os_manager = OpenStackManager(auth=auth, caller=request.user)
203             yield inline.get_formset(request, obj)
204
205     def get_queryset(self, request):
206         qs = super(SliceAdmin, self).get_queryset(request)
207         if request.user.is_superuser:
208             return qs
209         # users can only see slices at their site
210         return qs.filter(site=request.user.site) 
211
212 class SliceMembershipAdmin(PlanetStackBaseAdmin):
213     fieldsets = [
214         (None, {'fields': ['user', 'slice', 'role']})
215     ]
216     list_display = ('user', 'slice', 'role')
217
218     def save_model(self, request, obj, form, change):
219         # update openstack connection to use this site/tenant
220         auth = request.session.get('auth', {})
221         auth['tenant'] = obj.slice.name
222         obj.os_manager = OpenStackManager(auth=auth, caller=request.user)
223         obj.save()
224
225     def delete_model(self, request, obj):
226         # update openstack connection to use this site/tenant
227         auth = request.session.get('auth', {})
228         auth['tenant'] = obj.slice.name
229         obj.os_manager = OpenStackManager(auth=auth, caller=request.user)
230         obj.delete()
231
232
233 class SubnetAdmin(PlanetStackBaseAdmin):
234     fields = ['cidr', 'ip_version', 'start', 'end', 'slice']
235     list_display = ('slice','cidr', 'start', 'end', 'ip_version')
236
237     def save_model(self, request, obj, form, change):
238         # update openstack connection to use this site/tenant
239         auth = request.session.get('auth', {})
240         auth['tenant'] = obj.slice.name
241         obj.os_manager = OpenStackManager(auth=auth, caller=request.user)
242         obj.save()
243
244     def delete_model(self, request, obj):
245         # update openstack connection to use this site/tenant
246         auth = request.session.get('auth', {})
247         auth['tenant'] = obj.slice.name
248         obj.os_manager = OpenStackManager(auth=auth, caller=request.user)
249         obj.delete()
250
251 class ImageAdmin(admin.ModelAdmin):
252     fields = ['image_id', 'name', 'disk_format', 'container_format']
253
254 class NodeAdmin(admin.ModelAdmin):
255     list_display = ('name', 'site', 'deploymentNetwork')
256     list_filter = ('deploymentNetwork',)
257
258
259 class SliverForm(forms.ModelForm):
260     class Meta:
261         ip = forms.CharField(widget=PlainTextWidget)
262         instance_name = forms.CharField(widget=PlainTextWidget)
263         model = Sliver
264         widgets = {
265             'ip': PlainTextWidget(),
266             'instance_name': PlainTextWidget(),
267         }
268
269 class SliverAdmin(PlanetStackBaseAdmin):
270     form = SliverForm
271     fieldsets = [
272         ('Sliver', {'fields': ['ip', 'instance_name', 'name', 'slice', 'numberCores', 'image', 'key', 'node', 'deploymentNetwork']})
273     ]
274     list_display = ['ip', 'instance_name', 'name', 'slice', 'numberCores', 'image', 'key', 'node', 'deploymentNetwork']
275
276     def save_model(self, request, obj, form, change):
277         # update openstack connection to use this site/tenant
278         auth = request.session.get('auth', {})
279         auth['tenant'] = obj.slice.name
280         obj.os_manager = OpenStackManager(auth=auth, caller=request.user)
281         obj.save()
282
283     def delete_model(self, request, obj):
284         # update openstack connection to use this site/tenant
285         auth = request.session.get('auth', {})
286         auth['tenant'] = obj.slice.name
287         obj.os_manager = OpenStackManager(auth=auth, caller=request.user)
288         obj.delete()
289
290 class UserCreationForm(forms.ModelForm):
291     """A form for creating new users. Includes all the required
292     fields, plus a repeated password."""
293     password1 = forms.CharField(label='Password', widget=forms.PasswordInput)
294     password2 = forms.CharField(label='Password confirmation', widget=forms.PasswordInput)
295
296     class Meta:
297         model = PLUser
298         fields = ('email', 'firstname', 'lastname', 'phone', 'site')
299
300     def clean_password2(self):
301         # Check that the two password entries match
302         password1 = self.cleaned_data.get("password1")
303         password2 = self.cleaned_data.get("password2")
304         if password1 and password2 and password1 != password2:
305             raise forms.ValidationError("Passwords don't match")
306         return password2
307
308     def save(self, commit=True):
309         # Save the provided password in hashed format
310         user = super(UserCreationForm, self).save(commit=False)
311         user.password = self.cleaned_data["password1"]
312         #user.set_password(self.cleaned_data["password1"])
313         if commit:
314             user.save()
315         return user
316
317
318 class UserChangeForm(forms.ModelForm):
319     """A form for updating users. Includes all the fields on
320     the user, but replaces the password field with admin's
321     password hash display field.
322     """
323     password = ReadOnlyPasswordHashField()
324
325     class Meta:
326         model = PLUser
327
328     def clean_password(self):
329         # Regardless of what the user provides, return the initial value.
330         # This is done here, rather than on the field, because the
331         # field does not have access to the initial value
332         return self.initial["password"]
333
334
335 class PLUserAdmin(UserAdmin, OSModelAdmin):
336     class Meta:
337         app_label = "core"
338
339     # The forms to add and change user instances
340     form = UserChangeForm
341     add_form = UserCreationForm
342
343     # The fields to be used in displaying the User model.
344     # These override the definitions on the base UserAdmin
345     # that reference specific fields on auth.User.
346     list_display = ('email', 'site', 'firstname', 'lastname', 'last_login')
347     list_filter = ('site',)
348     fieldsets = (
349         (None, {'fields': ('email', 'password')}),
350         ('Personal info', {'fields': ('firstname','lastname','phone','site')}),
351         #('Important dates', {'fields': ('last_login',)}),
352     )
353     add_fieldsets = (
354         (None, {
355             'classes': ('wide',),
356             'fields': ('email', 'firstname', 'lastname', 'phone', 'site', 'password1', 'password2')}
357         ),
358     )
359     search_fields = ('email',)
360     ordering = ('email',)
361     filter_horizontal = ()
362
363 # register a signal that caches the user's credentials when they log in
364 def cache_credentials(sender, user, request, **kwds):
365     auth = {'username': request.POST['username'],
366             'password': request.POST['password']}
367     request.session['auth'] = auth
368 user_logged_in.connect(cache_credentials)
369
370 # Now register the new UserAdmin...
371 admin.site.register(PLUser, PLUserAdmin)
372 # ... and, since we're not using Django's builtin permissions,
373 # unregister the Group model from admin.
374 admin.site.unregister(Group)
375
376 admin.site.register(Site, SiteAdmin)
377 admin.site.register(SitePrivilege, SitePrivilegeAdmin)
378 admin.site.register(Slice, SliceAdmin)
379 admin.site.register(SliceMembership, SliceMembershipAdmin)
380 admin.site.register(Subnet, SubnetAdmin)
381 admin.site.register(Image, ImageAdmin)
382 admin.site.register(Node, NodeAdmin)
383 admin.site.register(Sliver, SliverAdmin)
384 admin.site.register(Key, KeyAdmin)
385 admin.site.register(Role, RoleAdmin)
386 admin.site.register(DeploymentNetwork, DeploymentNetworkAdmin)
387