blob: 3a1394543bcc8fc56d940fa50b1fad664991632b [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 Tullyde5450d2013-06-21 11:35:33 -040014from django.contrib.contenttypes import generic
Siobhan Tullybfd11dc2013-09-03 12:59:24 -040015from suit.widgets import LinkedSelect
Siobhan Tullycf04fb62014-01-11 11:25:57 -050016from django.core.exceptions import PermissionDenied
Scott Bakere2bbf7e2014-01-13 12:09:31 -080017from django.core.urlresolvers import reverse, NoReverseMatch
Tony Mack7130ac32013-03-22 21:58:00 -040018
Siobhan Tullyde5450d2013-06-21 11:35:33 -040019import django_evolution
Siobhan Tully4bc09f22013-04-10 21:15:21 -040020
Siobhan Tullycf04fb62014-01-11 11:25:57 -050021class ReadOnlyAwareAdmin(admin.ModelAdmin):
22
23 def has_add_permission(self, request, obj=None):
24 return (not self.__user_is_readonly(request))
25
26 def has_delete_permission(self, request, obj=None):
27 return (not self.__user_is_readonly(request))
28
29 def save_model(self, request, obj, form, change):
30 if self.__user_is_readonly(request):
31 raise PermissionDenied
32 #pass
33 else:
34 return super(ReadOnlyAwareAdmin, self).save_model(request, obj, form, change)
35
36 def get_actions(self,request):
37 actions = super(ReadOnlyAwareAdmin,self).get_actions(request)
38
39 if self.__user_is_readonly(request):
40 if 'delete_selected' in actions:
41 del actions['delete_selected']
42
43 return actions
44
45 def change_view(self,request,object_id, extra_context=None):
46
47 if self.__user_is_readonly(request):
48 self.readonly_fields=self.user_readonly_fields
49 self.inlines = self.user_readonly_inlines
50
51 try:
52 return super(ReadOnlyAwareAdmin, self).change_view(request, object_id, extra_context=extra_context)
53 except PermissionDenied:
54 pass
55 if request.method == 'POST':
56 raise PermissionDenied
57 request.readonly = True
58 return super(ReadOnlyAwareAdmin, self).change_view(request, object_id, extra_context=extra_context)
59
60
61 def __user_is_readonly(self, request):
62 return request.user.isReadOnlyUser()
63
Siobhan Tullyce652d02013-10-08 21:52:35 -040064class SingletonAdmin (admin.ModelAdmin):
65 def has_add_permission(self, request):
66 num_objects = self.model.objects.count()
67 if num_objects >= 1:
68 return False
69 else:
70 return True
71
72
Siobhan Tullyd3515752013-06-21 16:34:53 -040073class PlStackTabularInline(admin.TabularInline):
Scott Baker86568322014-01-12 16:53:31 -080074 def __init__(self, *args, **kwargs):
75 super(PlStackTabularInline, self).__init__(*args, **kwargs)
76
77 # InlineModelAdmin as no get_fields() method, so in order to add
78 # the selflink field, we override __init__ to modify self.fields and
79 # self.readonly_fields.
80
Scott Bakere2bbf7e2014-01-13 12:09:31 -080081 self.setup_selflink()
82
83 def setup_selflink(self):
84 reverse_path = "admin:%s_change" % (self.model._meta.db_table)
85 try:
86 url = reverse(reverse_path, args=(0,))
87 except NoReverseMatch:
88 # We don't have an admin for this object, so don't create the
89 # selflink.
90 return
91
Scott Baker0165fac2014-01-13 11:49:26 -080092 if (self.fields is None):
93 self.fields = []
94 for f in self.model._meta.fields:
95 if f.editable and f.name != "id":
96 self.fields.append(f.name)
Scott Baker86568322014-01-12 16:53:31 -080097
98 if (self.fields is not None):
99 self.fields = tuple(self.fields) + ("selflink", )
100
101 if self.readonly_fields is None:
102 self.readonly_fields = ()
103
104 self.readonly_fields = tuple(self.readonly_fields) + ("selflink", )
105
106 def selflink(self, obj):
107 if obj.id:
Scott Bakere2bbf7e2014-01-13 12:09:31 -0800108 reverse_path = "admin:%s_change" % (self.model._meta.db_table)
109 url = reverse(reverse_path, args =(obj.id,))
Scott Baker86568322014-01-12 16:53:31 -0800110 return "<a href='%s'>Details</a>" % str(url)
111 else:
Scott Bakere2bbf7e2014-01-13 12:09:31 -0800112 return "Not present"
Scott Baker86568322014-01-12 16:53:31 -0800113
114 selflink.allow_tags = True
115 selflink.short_description = "Details"
Siobhan Tullyd3515752013-06-21 16:34:53 -0400116
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500117class ReadOnlyTabularInline(PlStackTabularInline):
118 can_delete = False
119
120 def get_readonly_fields(self, request, obj=None):
121 return self.fields
122
123 def has_add_permission(self, request):
124 return False
125
126class ReservationROInline(ReadOnlyTabularInline):
127 model = Reservation
128 extra = 0
129 suit_classes = 'suit-tab suit-tab-reservations'
130 fields = ['startTime','slice','duration']
131
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400132class ReservationInline(PlStackTabularInline):
133 model = Reservation
134 extra = 0
135 suit_classes = 'suit-tab suit-tab-reservations'
136
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500137class TagROInline(generic.GenericTabularInline):
138 model = Tag
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400139 extra = 0
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500140 suit_classes = 'suit-tab suit-tab-tags'
141 can_delete = False
142 fields = ['service', 'name', 'value']
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400143
144 def get_readonly_fields(self, request, obj=None):
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500145 return self.fields
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400146
147 def has_add_permission(self, request):
148 return False
149
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500150
Siobhan Tullyde5450d2013-06-21 11:35:33 -0400151class TagInline(generic.GenericTabularInline):
152 model = Tag
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400153 extra = 0
154 suit_classes = 'suit-tab suit-tab-tags'
Siobhan Tullyde5450d2013-06-21 11:35:33 -0400155
Scott Baker74d8e622013-07-29 16:04:22 -0700156class NetworkLookerUpper:
Siobhan Tully2c780ad2013-09-06 11:22:40 -0400157 """ This is a callable that looks up a network name in a sliver and returns
158 the ip address for that network.
159 """
160
161 def __init__(self, name):
162 self.short_description = name
163 self.__name__ = name
164 self.network_name = name
165
166 def __call__(self, obj):
167 if obj is not None:
168 for nbs in obj.networksliver_set.all():
169 if (nbs.network.name == self.network_name):
170 return nbs.ip
Scott Baker74d8e622013-07-29 16:04:22 -0700171 return ""
172
173 def __str__(self):
174 return self.network_name
175
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500176class SliverROInline(ReadOnlyTabularInline):
177 model = Sliver
178 fields = ['ip', 'instance_name', 'slice', 'numberCores', 'image', 'node', 'deploymentNetwork']
179 suit_classes = 'suit-tab suit-tab-slivers'
180
Siobhan Tullyd3515752013-06-21 16:34:53 -0400181class SliverInline(PlStackTabularInline):
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400182 model = Sliver
Tony Mackb0d97422013-06-10 09:57:45 -0400183 fields = ['ip', 'instance_name', 'slice', 'numberCores', 'image', 'node', 'deploymentNetwork']
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400184 extra = 0
Tony Mack3777b012013-05-07 21:38:06 -0400185 readonly_fields = ['ip', 'instance_name']
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400186 suit_classes = 'suit-tab suit-tab-slivers'
Scott Baker74d8e622013-07-29 16:04:22 -0700187
Siobhan Tully2d95e482013-09-06 10:56:06 -0400188# Note this is breaking in the admin.py when trying to use an inline to add a node/image
189# def _declared_fieldsets(self):
190# # Return None so django will call get_fieldsets and we can insert our
191# # dynamic fields
192# return None
193#
194# def get_readonly_fields(self, request, obj=None):
195# readonly_fields = super(SliverInline, self).get_readonly_fields(request, obj)
196#
197# # Lookup the networks that are bound to the slivers, and add those
198# # network names to the list of readonly fields.
199#
200# for sliver in obj.slivers.all():
201# for nbs in sliver.networksliver_set.all():
202# if nbs.ip:
203# network_name = nbs.network.name
204# if network_name not in [str(x) for x in readonly_fields]:
205# readonly_fields.append(NetworkLookerUpper(network_name))
206#
207# return readonly_fields
208#
209# def get_fieldsets(self, request, obj=None):
210# form = self.get_formset(request, obj).form
211# # fields = the read/write files + the read-only fields
212# fields = self.fields
213# for fieldName in self.get_readonly_fields(request,obj):
214# if not fieldName in fields:
215# fields.append(fieldName)
216#
217# return [(None, {'fields': fields})]
Scott Baker74d8e622013-07-29 16:04:22 -0700218
Tony Mackc2835a92013-05-28 09:18:49 -0400219
Siobhan Tully567e3e62013-06-21 18:03:16 -0400220
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500221class SiteROInline(ReadOnlyTabularInline):
222 model = Site
223 extra = 0
224 fields = ['name', 'login_base', 'site_url', 'enabled']
225 suit_classes = 'suit-tab suit-tab-sites'
226
Siobhan Tullyd3515752013-06-21 16:34:53 -0400227class SiteInline(PlStackTabularInline):
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400228 model = Site
229 extra = 0
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400230 suit_classes = 'suit-tab suit-tab-sites'
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400231
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500232class UserROInline(ReadOnlyTabularInline):
233 model = User
234 fields = ['email', 'firstname', 'lastname']
235 extra = 0
236 suit_classes = 'suit-tab suit-tab-users'
237
Siobhan Tullyd3515752013-06-21 16:34:53 -0400238class UserInline(PlStackTabularInline):
Siobhan Tully30fd4292013-05-10 08:59:56 -0400239 model = User
Siobhan Tully47ae1b52013-05-10 15:53:14 -0400240 fields = ['email', 'firstname', 'lastname']
Siobhan Tully30fd4292013-05-10 08:59:56 -0400241 extra = 0
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400242 suit_classes = 'suit-tab suit-tab-users'
Siobhan Tully30fd4292013-05-10 08:59:56 -0400243
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500244class SliceROInline(ReadOnlyTabularInline):
245 model = Slice
246 suit_classes = 'suit-tab suit-tab-slices'
247 fields = ['name','site', 'serviceClass', 'service']
248
Siobhan Tullyd3515752013-06-21 16:34:53 -0400249class SliceInline(PlStackTabularInline):
Tony Mack00d361f2013-04-28 10:28:42 -0400250 model = Slice
Siobhan Tullyce652d02013-10-08 21:52:35 -0400251 fields = ['name','site', 'serviceClass', 'service']
Tony Mack00d361f2013-04-28 10:28:42 -0400252 extra = 0
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400253 suit_classes = 'suit-tab suit-tab-slices'
254
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500255class NodeROInline(ReadOnlyTabularInline):
256 model = Node
257 extra = 0
258 suit_classes = 'suit-tab suit-tab-nodes'
259 fields = ['name','deployment']
Tony Mack00d361f2013-04-28 10:28:42 -0400260
Siobhan Tullyd3515752013-06-21 16:34:53 -0400261class NodeInline(PlStackTabularInline):
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400262 model = Node
263 extra = 0
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400264 suit_classes = 'suit-tab suit-tab-nodes'
265
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500266class DeploymentPrivilegeROInline(ReadOnlyTabularInline):
267 model = DeploymentPrivilege
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400268 extra = 0
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500269 suit_classes = 'suit-tab suit-tab-deploymentprivileges'
270 fields = ['user','role']
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400271
272class DeploymentPrivilegeInline(PlStackTabularInline):
273 model = DeploymentPrivilege
274 extra = 0
275 suit_classes = 'suit-tab suit-tab-deploymentprivileges'
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400276
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500277#CLEANUP DOUBLE SitePrivilegeInline
278class SitePrivilegeROInline(ReadOnlyTabularInline):
279 model = SitePrivilege
280 extra = 0
281 suit_classes = 'suit-tab suit-tab-siteprivileges'
282 fields = ['user','site', 'role']
283
Siobhan Tullyd3515752013-06-21 16:34:53 -0400284class SitePrivilegeInline(PlStackTabularInline):
Siobhan Tullyaa1bcd52013-05-10 12:43:09 -0400285 model = SitePrivilege
286 extra = 0
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400287 suit_classes = 'suit-tab suit-tab-siteprivileges'
Siobhan Tullyaa1bcd52013-05-10 12:43:09 -0400288
Tony Mackc2835a92013-05-28 09:18:49 -0400289 def formfield_for_foreignkey(self, db_field, request, **kwargs):
290 if db_field.name == 'site':
291 if not request.user.is_admin:
292 # only show sites where user is an admin or pi
293 roles = Role.objects.filter(role_type__in=['admin', 'pi'])
294 site_privileges = SitePrivilege.objects.filter(user=request.user).filter(role__in=roles)
295 login_bases = [site_privilege.site.login_base for site_privilege in site_privileges]
296 sites = Site.objects.filter(login_base__in=login_bases)
297 kwargs['queryset'] = sites
298
299 if db_field.name == 'user':
300 if not request.user.is_admin:
301 # only show users from sites where caller has admin or pi role
302 roles = Role.objects.filter(role_type__in=['admin', 'pi'])
303 site_privileges = SitePrivilege.objects.filter(user=request.user).filter(role__in=roles)
304 sites = [site_privilege.site for site_privilege in site_privileges]
305 site_privileges = SitePrivilege.objects.filter(site__in=sites)
306 emails = [site_privilege.user.email for site_privilege in site_privileges]
307 users = User.objects.filter(email__in=emails)
308 kwargs['queryset'] = users
309 return super(SitePrivilegeInline, self).formfield_for_foreignkey(db_field, request, **kwargs)
310
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400311class SitePrivilegeInline(PlStackTabularInline):
312 model = SitePrivilege
313 suit_classes = 'suit-tab suit-tab-siteprivileges'
Siobhan Tullyaa1bcd52013-05-10 12:43:09 -0400314 extra = 0
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400315 fields = ('user', 'site','role')
316
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500317class SlicePrivilegeROInline(ReadOnlyTabularInline):
318 model = SlicePrivilege
319 extra = 0
320 suit_classes = 'suit-tab suit-tab-sliceprivileges'
321 fields = ['user', 'slice', 'role']
322
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400323class SlicePrivilegeInline(PlStackTabularInline):
324 model = SlicePrivilege
325 suit_classes = 'suit-tab suit-tab-sliceprivileges'
326 extra = 0
327 fields = ('user', 'slice','role')
Siobhan Tullyaa1bcd52013-05-10 12:43:09 -0400328
Tony Mackc2835a92013-05-28 09:18:49 -0400329 def formfield_for_foreignkey(self, db_field, request, **kwargs):
330 if db_field.name == 'slice':
331 if not request.user.is_admin:
332 # only show slices at sites where caller has admin or pi role
333 roles = Role.objects.filter(role_type__in=['admin', 'pi'])
334 site_privileges = SitePrivilege.objects.filter(user=request.user).filter(role__in=roles)
335 sites = [site_privilege.site for site_privilege in site_privileges]
336 slices = Slice.objects.filter(site__in=sites)
337 kwargs['queryset'] = slices
338 if db_field.name == 'user':
339 if not request.user.is_admin:
340 # only show users from sites where caller has admin or pi role
341 roles = Role.objects.filter(role_type__in=['admin', 'pi'])
342 site_privileges = SitePrivilege.objects.filter(user=request.user).filter(role__in=roles)
343 sites = [site_privilege.site for site_privilege in site_privileges]
344 site_privileges = SitePrivilege.objects.filter(site__in=sites)
345 emails = [site_privilege.user.email for site_privilege in site_privileges]
346 users = User.objects.filter(email__in=emails)
347 kwargs['queryset'] = list(users)
348
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400349 return super(SlicePrivilegeInline, self).formfield_for_foreignkey(db_field, request, **kwargs)
Tony Mackc2835a92013-05-28 09:18:49 -0400350
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500351class SliceNetworkROInline(ReadOnlyTabularInline):
352 model = Network.slices.through
353 extra = 0
354 verbose_name = "Network Connection"
355 verbose_name_plural = "Network Connections"
356 suit_classes = 'suit-tab suit-tab-slicenetworks'
357 fields = ['network']
358
Scott Bakera0015eb2013-08-14 17:28:14 -0700359class SliceNetworkInline(PlStackTabularInline):
Scott Baker74d8e622013-07-29 16:04:22 -0700360 model = Network.slices.through
361 extra = 0
362 verbose_name = "Network Connection"
363 verbose_name_plural = "Network Connections"
Siobhan Tully2d95e482013-09-06 10:56:06 -0400364 suit_classes = 'suit-tab suit-tab-slicenetworks'
Scott Baker74d8e622013-07-29 16:04:22 -0700365
Tony Mack5e71a662013-05-03 23:30:41 -0400366class PlainTextWidget(forms.HiddenInput):
367 input_type = 'hidden'
368
369 def render(self, name, value, attrs=None):
370 if value is None:
371 value = ''
Tony Mack1d6b85f2013-05-07 18:49:14 -0400372 return mark_safe(str(value) + super(PlainTextWidget, self).render(name, value, attrs))
Tony Mack9bcbe4f2013-04-29 08:13:27 -0400373
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500374class PlanetStackBaseAdmin(ReadOnlyAwareAdmin):
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400375 save_on_top = False
376
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400377class SliceRoleAdmin(PlanetStackBaseAdmin):
378 model = SliceRole
379 pass
380
381class SiteRoleAdmin(PlanetStackBaseAdmin):
382 model = SiteRole
383 pass
384
Siobhan Tullybf1153a2013-05-27 20:53:48 -0400385class DeploymentAdminForm(forms.ModelForm):
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400386 sites = forms.ModelMultipleChoiceField(
387 queryset=Site.objects.all(),
388 required=False,
389 widget=FilteredSelectMultiple(
390 verbose_name=('Sites'), is_stacked=False
391 )
392 )
393 class Meta:
Siobhan Tullybf1153a2013-05-27 20:53:48 -0400394 model = Deployment
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400395
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500396class SiteAssocInline(PlStackTabularInline):
397 model = Site.deployments.through
398 extra = 0
399 suit_classes = 'suit-tab suit-tab-sites'
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400400
Siobhan Tullybf1153a2013-05-27 20:53:48 -0400401class DeploymentAdmin(PlanetStackBaseAdmin):
402 form = DeploymentAdminForm
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500403 model = Deployment
404 fieldList = ['name','sites']
405 fieldsets = [(None, {'fields': fieldList, 'classes':['suit-tab suit-tab-sites']})]
Siobhan Tully2d95e482013-09-06 10:56:06 -0400406 inlines = [DeploymentPrivilegeInline,NodeInline,TagInline]
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500407
408 user_readonly_inlines = [DeploymentPrivilegeROInline,NodeROInline,TagROInline]
409 user_readonly_fields = ['name']
410
411 suit_form_tabs =(('sites','Deployment Details'),('nodes','Nodes'),('deploymentprivileges','Privileges'),('tags','Tags'))
412
413class ServiceAttrAsTabROInline(ReadOnlyTabularInline):
414 model = ServiceAttribute
415 fields = ['name','value']
416 extra = 0
417 suit_classes = 'suit-tab suit-tab-serviceattrs'
Tony Mack5cd13202013-05-01 21:48:38 -0400418
Siobhan Tullyce652d02013-10-08 21:52:35 -0400419class ServiceAttrAsTabInline(PlStackTabularInline):
420 model = ServiceAttribute
421 fields = ['name','value']
422 extra = 0
423 suit_classes = 'suit-tab suit-tab-serviceattrs'
424
Siobhan Tullyce652d02013-10-08 21:52:35 -0400425class ServiceAdmin(PlanetStackBaseAdmin):
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500426 list_display = ("name","description","versionNumber","enabled","published")
427 fieldList = ["name","description","versionNumber","enabled","published"]
428 fieldsets = [(None, {'fields': fieldList, 'classes':['suit-tab suit-tab-general']})]
429 inlines = [ServiceAttrAsTabInline,SliceInline]
430
431 user_readonly_fields = fieldList
432 user_readonly_inlines = [ServiceAttrAsTabROInline,SliceROInline]
433
434 suit_form_tabs =(('general', 'Service Details'),
435 ('slices','Slices'),
436 ('serviceattrs','Additional Attributes'),
437 )
Siobhan Tullyce652d02013-10-08 21:52:35 -0400438
Tony Mack0553f282013-06-10 22:54:50 -0400439class SiteAdmin(PlanetStackBaseAdmin):
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500440 fieldList = ['name', 'site_url', 'enabled', 'is_public', 'login_base', 'accountLink','location']
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400441 fieldsets = [
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500442 (None, {'fields': fieldList, 'classes':['suit-tab suit-tab-general']}),
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400443 ('Deployment Networks', {'fields': ['deployments'], 'classes':['suit-tab suit-tab-deployments']}),
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400444 ]
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400445 suit_form_tabs =(('general', 'Site Details'),
446 ('users','Users'),
Siobhan Tully2d95e482013-09-06 10:56:06 -0400447 ('siteprivileges','Privileges'),
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400448 ('deployments','Deployments'),
449 ('slices','Slices'),
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500450 ('nodes','Nodes'),
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400451 ('tags','Tags'),
452 )
Scott Baker545db2a2013-12-09 18:44:43 -0800453 readonly_fields = ['accountLink']
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500454
455 user_readonly_fields = ['name', 'deployments','site_url', 'enabled', 'is_public', 'login_base', 'accountLink']
456 user_readonly_inlines = [SliceROInline,UserROInline,TagROInline, NodeROInline, SitePrivilegeROInline]
457
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400458 list_display = ('name', 'login_base','site_url', 'enabled')
459 filter_horizontal = ('deployments',)
Siobhan Tully2d95e482013-09-06 10:56:06 -0400460 inlines = [SliceInline,UserInline,TagInline, NodeInline, SitePrivilegeInline]
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400461 search_fields = ['name']
462
Tony Mack04062832013-05-10 08:22:44 -0400463 def queryset(self, request):
464 # admins can see all keys. Users can only see sites they belong to.
465 qs = super(SiteAdmin, self).queryset(request)
466 if not request.user.is_admin:
467 valid_sites = [request.user.site.login_base]
468 roles = request.user.get_roles()
469 for tenant_list in roles.values():
470 valid_sites.extend(tenant_list)
471 qs = qs.filter(login_base__in=valid_sites)
472 return qs
473
Tony Mack5cd13202013-05-01 21:48:38 -0400474 def get_formsets(self, request, obj=None):
475 for inline in self.get_inline_instances(request, obj):
476 # hide MyInline in the add view
477 if obj is None:
478 continue
Tony Mack2bd5b412013-06-11 21:05:06 -0400479 if isinstance(inline, SliceInline):
480 inline.model.caller = request.user
481 yield inline.get_formset(request, obj)
482
483 def get_formsets(self, request, obj=None):
484 for inline in self.get_inline_instances(request, obj):
485 # hide MyInline in the add view
486 if obj is None:
487 continue
488 if isinstance(inline, SliverInline):
489 inline.model.caller = request.user
Tony Mack5cd13202013-05-01 21:48:38 -0400490 yield inline.get_formset(request, obj)
491
Scott Baker545db2a2013-12-09 18:44:43 -0800492 def accountLink(self, obj):
493 link_obj = obj.accounts.all()
494 if link_obj:
495 reverse_path = "admin:core_account_change"
496 url = reverse(reverse_path, args =(link_obj[0].id,))
497 return "<a href='%s'>%s</a>" % (url, "view billing details")
498 else:
499 return "no billing data for this site"
500 accountLink.allow_tags = True
501 accountLink.short_description = "Billing"
502
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500503
Tony Mack9bcbe4f2013-04-29 08:13:27 -0400504class SitePrivilegeAdmin(PlanetStackBaseAdmin):
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500505 fieldList = ['user', 'site', 'role']
Tony Mack00d361f2013-04-28 10:28:42 -0400506 fieldsets = [
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500507 (None, {'fields': fieldList, 'classes':['collapse']})
Tony Mack00d361f2013-04-28 10:28:42 -0400508 ]
509 list_display = ('user', 'site', 'role')
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500510 user_readonly_fields = fieldList
511 user_readonly_inlines = []
Tony Mack00d361f2013-04-28 10:28:42 -0400512
Tony Mackc2835a92013-05-28 09:18:49 -0400513 def formfield_for_foreignkey(self, db_field, request, **kwargs):
514 if db_field.name == 'site':
515 if not request.user.is_admin:
516 # only show sites where user is an admin or pi
517 sites = set()
518 for site_privilege in SitePrivilege.objects.filer(user=request.user):
519 if site_privilege.role.role_type in ['admin', 'pi']:
520 sites.add(site_privilege.site)
521 kwargs['queryset'] = Site.objects.filter(site__in=list(sites))
522
523 if db_field.name == 'user':
524 if not request.user.is_admin:
525 # only show users from sites where caller has admin or pi role
526 roles = Role.objects.filter(role_type__in=['admin', 'pi'])
527 site_privileges = SitePrivilege.objects.filter(user=request.user).filter(role__in=roles)
528 sites = [site_privilege.site for site_privilege in site_privileges]
529 site_privileges = SitePrivilege.objects.filter(site__in=sites)
530 emails = [site_privilege.user.email for site_privilege in site_privileges]
531 users = User.objects.filter(email__in=emails)
532 kwargs['queryset'] = users
533
534 return super(SitePrivilegeAdmin, self).formfield_for_foreignkey(db_field, request, **kwargs)
535
Tony Mack04062832013-05-10 08:22:44 -0400536 def queryset(self, request):
537 # admins can see all privileges. Users can only see privileges at sites
Tony Mackc2835a92013-05-28 09:18:49 -0400538 # where they have the admin role or pi role.
Tony Mack04062832013-05-10 08:22:44 -0400539 qs = super(SitePrivilegeAdmin, self).queryset(request)
540 if not request.user.is_admin:
Tony Mackc2835a92013-05-28 09:18:49 -0400541 roles = Role.objects.filter(role_type__in=['admin', 'pi'])
542 site_privileges = SitePrivilege.objects.filter(user=request.user).filter(role__in=roles)
543 login_bases = [site_privilege.site.login_base for site_privilege in site_privileges]
544 sites = Site.objects.filter(login_base__in=login_bases)
545 qs = qs.filter(site__in=sites)
Tony Mack04062832013-05-10 08:22:44 -0400546 return qs
547
Siobhan Tullyce652d02013-10-08 21:52:35 -0400548class SliceForm(forms.ModelForm):
549 class Meta:
550 model = Slice
551 widgets = {
552 'service': LinkedSelect
553 }
554
Tony Mack2bd5b412013-06-11 21:05:06 -0400555class SliceAdmin(PlanetStackBaseAdmin):
Siobhan Tullyce652d02013-10-08 21:52:35 -0400556 form = SliceForm
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500557 fieldList = ['name', 'site', 'serviceClass', 'enabled','description', 'service', 'slice_url']
558 fieldsets = [('Slice Details', {'fields': fieldList, 'classes':['suit-tab suit-tab-general']}),]
Siobhan Tully30fd4292013-05-10 08:59:56 -0400559 list_display = ('name', 'site','serviceClass', 'slice_url')
Siobhan Tully2d95e482013-09-06 10:56:06 -0400560 inlines = [SlicePrivilegeInline,SliverInline, TagInline, ReservationInline,SliceNetworkInline]
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400561
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500562 user_readonly_fields = fieldList
563 user_readonly_inlines = [SlicePrivilegeROInline,SliverROInline,TagROInline, ReservationROInline, SliceNetworkROInline]
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400564
565 suit_form_tabs =(('general', 'Slice Details'),
Siobhan Tully2d95e482013-09-06 10:56:06 -0400566 ('slicenetworks','Networks'),
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400567 ('sliceprivileges','Privileges'),
568 ('slivers','Slivers'),
569 ('tags','Tags'),
570 ('reservations','Reservations'),
571 )
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400572
Tony Mackc2835a92013-05-28 09:18:49 -0400573 def formfield_for_foreignkey(self, db_field, request, **kwargs):
574 if db_field.name == 'site':
575 if not request.user.is_admin:
576 # only show sites where user is a pi or admin
577 roles = Role.objects.filter(role_type__in=['admin', 'pi'])
578 site_privileges = SitePrivilege.objects.filter(user=request.user).filter(role__in=roles)
579 login_bases = [site_privilege.site.login_base for site_privilege in site_privileges]
580 sites = Site.objects.filter(login_base__in=login_bases)
581 kwargs['queryset'] = sites
582
583 return super(SliceAdmin, self).formfield_for_foreignkey(db_field, request, **kwargs)
584
Tony Mack04062832013-05-10 08:22:44 -0400585 def queryset(self, request):
586 # admins can see all keys. Users can only see slices they belong to.
587 qs = super(SliceAdmin, self).queryset(request)
588 if not request.user.is_admin:
589 valid_slices = []
590 roles = request.user.get_roles()
591 for tenant_list in roles.values():
592 valid_slices.extend(tenant_list)
593 qs = qs.filter(name__in=valid_slices)
594 return qs
595
Tony Mack79748612013-05-01 14:52:03 -0400596 def get_formsets(self, request, obj=None):
597 for inline in self.get_inline_instances(request, obj):
598 # hide MyInline in the add view
599 if obj is None:
600 continue
Tony Mack2bd5b412013-06-11 21:05:06 -0400601 if isinstance(inline, SliverInline):
602 inline.model.caller = request.user
Tony Mack79748612013-05-01 14:52:03 -0400603 yield inline.get_formset(request, obj)
604
Tony Mackfdd4d802013-04-27 13:02:33 -0400605 def get_queryset(self, request):
606 qs = super(SliceAdmin, self).get_queryset(request)
607 if request.user.is_superuser:
608 return qs
609 # users can only see slices at their site
Tony Mack2bd5b412013-06-11 21:05:06 -0400610 return qs.filter(site=request.user.site)
611
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400612class SlicePrivilegeAdmin(PlanetStackBaseAdmin):
Tony Mack00d361f2013-04-28 10:28:42 -0400613 fieldsets = [
614 (None, {'fields': ['user', 'slice', 'role']})
615 ]
616 list_display = ('user', 'slice', 'role')
Tony Mack00d361f2013-04-28 10:28:42 -0400617
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500618 user_readonly_fields = ['user', 'slice', 'role']
619 user_readonly_inlines = []
620
Tony Mackc2835a92013-05-28 09:18:49 -0400621 def formfield_for_foreignkey(self, db_field, request, **kwargs):
622 if db_field.name == 'slice':
623 if not request.user.is_admin:
624 # only show slices at sites where caller has admin or pi role
625 roles = Role.objects.filter(role_type__in=['admin', 'pi'])
626 site_privileges = SitePrivilege.objects.filter(user=request.user).filter(role__in=roles)
627 sites = [site_privilege.site for site_privilege in site_privileges]
628 slices = Slice.objects.filter(site__in=sites)
629 kwargs['queryset'] = slices
630
631 if db_field.name == 'user':
632 if not request.user.is_admin:
633 # only show users from sites where caller has admin or pi role
634 roles = Role.objects.filter(role_type__in=['admin', 'pi'])
635 site_privileges = SitePrivilege.objects.filter(user=request.user).filter(role__in=roles)
636 sites = [site_privilege.site for site_privilege in site_privileges]
637 site_privileges = SitePrivilege.objects.filter(site__in=sites)
638 emails = [site_privilege.user.email for site_privilege in site_privileges]
639 users = User.objects.filter(email__in=emails)
640 kwargs['queryset'] = users
641
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400642 return super(SlicePrivilegeAdmin, self).formfield_for_foreignkey(db_field, request, **kwargs)
Tony Mackc2835a92013-05-28 09:18:49 -0400643
Tony Mack04062832013-05-10 08:22:44 -0400644 def queryset(self, request):
645 # admins can see all memberships. Users can only see memberships of
646 # slices where they have the admin role.
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400647 qs = super(SlicePrivilegeAdmin, self).queryset(request)
Tony Mack04062832013-05-10 08:22:44 -0400648 if not request.user.is_admin:
Tony Mackc2835a92013-05-28 09:18:49 -0400649 roles = Role.objects.filter(role_type__in=['admin', 'pi'])
650 site_privileges = SitePrivilege.objects.filter(user=request.user).filter(role__in=roles)
651 login_bases = [site_privilege.site.login_base for site_privilege in site_privileges]
652 sites = Site.objects.filter(login_base__in=login_bases)
653 slices = Slice.objects.filter(site__in=sites)
654 qs = qs.filter(slice__in=slices)
Tony Mack04062832013-05-10 08:22:44 -0400655 return qs
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400656
Tony Mack9bcbe4f2013-04-29 08:13:27 -0400657 def save_model(self, request, obj, form, change):
Tony Mack951dab42013-05-02 19:51:45 -0400658 # update openstack connection to use this site/tenant
659 auth = request.session.get('auth', {})
660 auth['tenant'] = obj.slice.name
661 obj.os_manager = OpenStackManager(auth=auth, caller=request.user)
Tony Mack9bcbe4f2013-04-29 08:13:27 -0400662 obj.save()
663
664 def delete_model(self, request, obj):
Tony Mack951dab42013-05-02 19:51:45 -0400665 # update openstack connection to use this site/tenant
666 auth = request.session.get('auth', {})
667 auth['tenant'] = obj.slice.name
668 obj.os_manager = OpenStackManager(auth=auth, caller=request.user)
Tony Mack9bcbe4f2013-04-29 08:13:27 -0400669 obj.delete()
670
Siobhan Tully567e3e62013-06-21 18:03:16 -0400671
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400672class ImageAdmin(PlanetStackBaseAdmin):
673
674 fieldsets = [('Image Details',
675 {'fields': ['image_id', 'name', 'disk_format', 'container_format'],
676 'classes': ['suit-tab suit-tab-general']})
677 ]
678
679 suit_form_tabs =(('general','Image Details'),('slivers','Slivers'))
680
681 inlines = [SliverInline]
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500682
683 user_readonly_fields = ['image_id', 'name', 'disk_format', 'container_format']
684 user_readonly_inlines = [SliverROInline]
685
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400686class NodeForm(forms.ModelForm):
687 class Meta:
688 widgets = {
689 'site': LinkedSelect,
690 'deployment': LinkedSelect
691 }
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400692
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500693class NodeAdmin(PlanetStackBaseAdmin):
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400694 form = NodeForm
Siobhan Tullybf1153a2013-05-27 20:53:48 -0400695 list_display = ('name', 'site', 'deployment')
696 list_filter = ('deployment',)
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500697
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400698 inlines = [TagInline,SliverInline]
699 fieldsets = [('Node Details', {'fields': ['name','site','deployment'], 'classes':['suit-tab suit-tab-details']})]
700
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500701 user_readonly_fields = ['name','site','deployment']
702 user_readonly_inlines = [TagInline,SliverInline]
703
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400704 suit_form_tabs =(('details','Node Details'),('slivers','Slivers'),('tags','Tags'))
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400705
Siobhan Tully567e3e62013-06-21 18:03:16 -0400706
Tony Mackd90cdbf2013-04-16 22:48:40 -0400707class SliverForm(forms.ModelForm):
708 class Meta:
Tony Mack1d6b85f2013-05-07 18:49:14 -0400709 model = Sliver
Tony Mackd90cdbf2013-04-16 22:48:40 -0400710 ip = forms.CharField(widget=PlainTextWidget)
Tony Mack18261812013-05-02 16:39:20 -0400711 instance_name = forms.CharField(widget=PlainTextWidget)
Tony Mackd90cdbf2013-04-16 22:48:40 -0400712 widgets = {
713 'ip': PlainTextWidget(),
Tony Mack18261812013-05-02 16:39:20 -0400714 'instance_name': PlainTextWidget(),
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400715 'slice': LinkedSelect,
716 'deploymentNetwork': LinkedSelect,
717 'node': LinkedSelect,
718 'image': LinkedSelect
Siobhan Tully53437282013-04-26 19:30:27 -0400719 }
Tony Mackd90cdbf2013-04-16 22:48:40 -0400720
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500721class TagAdmin(PlanetStackBaseAdmin):
Siobhan Tullyce652d02013-10-08 21:52:35 -0400722 list_display = ['service', 'name', 'value', 'content_type', 'content_object',]
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500723 user_readonly_fields = ['service', 'name', 'value', 'content_type', 'content_object',]
724 user_readonly_inlines = []
Siobhan Tullyd3515752013-06-21 16:34:53 -0400725
Tony Mack9bcbe4f2013-04-29 08:13:27 -0400726class SliverAdmin(PlanetStackBaseAdmin):
Tony Mackd90cdbf2013-04-16 22:48:40 -0400727 form = SliverForm
Tony Mackcdec0902013-04-15 00:38:49 -0400728 fieldsets = [
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400729 ('Sliver Details', {'fields': ['slice', 'deploymentNetwork', 'node', 'ip', 'instance_name', 'numberCores', 'image', ], 'classes': ['suit-tab suit-tab-general'], })
Tony Mackcdec0902013-04-15 00:38:49 -0400730 ]
Siobhan Tully5d7dc8d2013-07-02 13:17:33 -0400731 list_display = ['ip', 'instance_name', 'slice', 'numberCores', 'image', 'node', 'deploymentNetwork']
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400732
733 suit_form_tabs =(('general', 'Sliver Details'),
734 ('tags','Tags'),
735 )
736
Siobhan Tullyde5450d2013-06-21 11:35:33 -0400737 inlines = [TagInline]
Tony Mack53106f32013-04-27 16:43:01 -0400738
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500739 user_readonly_fields = ['slice', 'deploymentNetwork', 'node', 'ip', 'instance_name', 'numberCores', 'image']
740 user_readonly_inlines = [TagROInline]
741
Tony Mackc2835a92013-05-28 09:18:49 -0400742 def formfield_for_foreignkey(self, db_field, request, **kwargs):
743 if db_field.name == 'slice':
744 if not request.user.is_admin:
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400745 slices = set([sm.slice.name for sm in SlicePrivilege.objects.filter(user=request.user)])
Tony Mackc2835a92013-05-28 09:18:49 -0400746 kwargs['queryset'] = Slice.objects.filter(name__in=list(slices))
747
748 return super(SliverAdmin, self).formfield_for_foreignkey(db_field, request, **kwargs)
749
Tony Mack04062832013-05-10 08:22:44 -0400750 def queryset(self, request):
751 # admins can see all slivers. Users can only see slivers of
752 # the slices they belong to.
753 qs = super(SliverAdmin, self).queryset(request)
754 if not request.user.is_admin:
755 tenants = []
756 roles = request.user.get_roles()
757 for tenant_list in roles.values():
758 tenants.extend(tenant_list)
759 valid_slices = Slice.objects.filter(name__in=tenants)
760 qs = qs.filter(slice__in=valid_slices)
761 return qs
762
Tony Mack1d6b85f2013-05-07 18:49:14 -0400763 def get_formsets(self, request, obj=None):
764 # make some fields read only if we are updating an existing record
765 if obj == None:
766 #self.readonly_fields = ('ip', 'instance_name')
767 self.readonly_fields = ()
768 else:
Tony Mack1e889462013-05-10 21:34:54 -0400769 self.readonly_fields = ()
770 #self.readonly_fields = ('ip', 'instance_name', 'slice', 'image', 'key')
Tony Mack1d6b85f2013-05-07 18:49:14 -0400771
772 for inline in self.get_inline_instances(request, obj):
773 # hide MyInline in the add view
774 if obj is None:
775 continue
776 # give inline object access to driver and caller
777 auth = request.session.get('auth', {})
778 auth['tenant'] = obj.name # meed to connect using slice's tenant
779 inline.model.os_manager = OpenStackManager(auth=auth, caller=request.user)
780 yield inline.get_formset(request, obj)
Tony Mack53106f32013-04-27 16:43:01 -0400781
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500782 #def save_model(self, request, obj, form, change):
783 # # update openstack connection to use this site/tenant
784 # auth = request.session.get('auth', {})
785 # auth['tenant'] = obj.slice.name
786 # obj.os_manager = OpenStackManager(auth=auth, caller=request.user)
787 # obj.creator = request.user
788 # obj.save()
Tony Mack53106f32013-04-27 16:43:01 -0400789
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500790 #def delete_model(self, request, obj):
791 # # update openstack connection to use this site/tenant
792 # auth = request.session.get('auth', {})
793 # auth['tenant'] = obj.slice.name
794 # obj.os_manager = OpenStackManager(auth=auth, caller=request.user)
795 # obj.delete()
Tony Mackcdec0902013-04-15 00:38:49 -0400796
Siobhan Tully53437282013-04-26 19:30:27 -0400797class UserCreationForm(forms.ModelForm):
798 """A form for creating new users. Includes all the required
799 fields, plus a repeated password."""
800 password1 = forms.CharField(label='Password', widget=forms.PasswordInput)
801 password2 = forms.CharField(label='Password confirmation', widget=forms.PasswordInput)
802
803 class Meta:
Siobhan Tully30fd4292013-05-10 08:59:56 -0400804 model = User
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400805 fields = ('email', 'firstname', 'lastname', 'phone', 'public_key')
Siobhan Tully53437282013-04-26 19:30:27 -0400806
807 def clean_password2(self):
808 # Check that the two password entries match
809 password1 = self.cleaned_data.get("password1")
810 password2 = self.cleaned_data.get("password2")
811 if password1 and password2 and password1 != password2:
812 raise forms.ValidationError("Passwords don't match")
813 return password2
814
815 def save(self, commit=True):
816 # Save the provided password in hashed format
817 user = super(UserCreationForm, self).save(commit=False)
Tony Mackf9f4afb2013-05-01 21:02:12 -0400818 user.password = self.cleaned_data["password1"]
819 #user.set_password(self.cleaned_data["password1"])
Siobhan Tully53437282013-04-26 19:30:27 -0400820 if commit:
821 user.save()
822 return user
823
Siobhan Tully567e3e62013-06-21 18:03:16 -0400824
Siobhan Tully53437282013-04-26 19:30:27 -0400825class UserChangeForm(forms.ModelForm):
826 """A form for updating users. Includes all the fields on
827 the user, but replaces the password field with admin's
828 password hash display field.
829 """
Siobhan Tully63b7ba42014-01-12 10:35:11 -0500830 password = ReadOnlyPasswordHashField(label='Password',
831 help_text= '<a href=\"password/\">Change Password</a>.')
Siobhan Tully53437282013-04-26 19:30:27 -0400832
833 class Meta:
Siobhan Tully30fd4292013-05-10 08:59:56 -0400834 model = User
Siobhan Tully53437282013-04-26 19:30:27 -0400835
836 def clean_password(self):
837 # Regardless of what the user provides, return the initial value.
838 # This is done here, rather than on the field, because the
839 # field does not have access to the initial value
840 return self.initial["password"]
841
Tony Mack2bd5b412013-06-11 21:05:06 -0400842class UserAdmin(UserAdmin):
Siobhan Tully53437282013-04-26 19:30:27 -0400843 class Meta:
844 app_label = "core"
845
846 # The forms to add and change user instances
847 form = UserChangeForm
848 add_form = UserCreationForm
849
850 # The fields to be used in displaying the User model.
851 # These override the definitions on the base UserAdmin
852 # that reference specific fields on auth.User.
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500853 list_display = ('email', 'firstname', 'lastname', 'site', 'last_login')
Siobhan Tullyce652d02013-10-08 21:52:35 -0400854 #list_display = ('email', 'username','firstname', 'lastname', 'is_admin', 'last_login')
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500855 list_filter = ('site',)
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400856 inlines = [SlicePrivilegeInline,SitePrivilegeInline,DeploymentPrivilegeInline]
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500857
858 fieldListLoginDetails = ['email','site','password','is_readonly','is_amin','public_key']
859 fieldListContactInfo = ['firstname','lastname','phone','timezone']
860
Siobhan Tully53437282013-04-26 19:30:27 -0400861 fieldsets = (
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500862 ('Login Details', {'fields': ['email', 'site','password', 'is_readonly', 'is_admin', 'public_key'], 'classes':['suit-tab suit-tab-general']}),
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400863 ('Contact Information', {'fields': ('firstname','lastname','phone', 'timezone'), 'classes':['suit-tab suit-tab-contact']}),
Siobhan Tully53437282013-04-26 19:30:27 -0400864 #('Important dates', {'fields': ('last_login',)}),
865 )
866 add_fieldsets = (
867 (None, {
868 'classes': ('wide',),
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500869 'fields': ('email', 'firstname', 'lastname', 'is_readonly', 'phone', 'public_key','password1', 'password2')}
Siobhan Tully53437282013-04-26 19:30:27 -0400870 ),
871 )
872 search_fields = ('email',)
873 ordering = ('email',)
874 filter_horizontal = ()
875
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500876 user_readonly_fields = fieldListLoginDetails
877 user_readonly_inlines = [SlicePrivilegeROInline,SitePrivilegeROInline,DeploymentPrivilegeROInline]
878
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400879 suit_form_tabs =(('general','Login Details'),('contact','Contact Information'),('sliceprivileges','Slice Privileges'),('siteprivileges','Site Privileges'),('deploymentprivileges','Deployment Privileges'))
880
Tony Mackc2835a92013-05-28 09:18:49 -0400881 def formfield_for_foreignkey(self, db_field, request, **kwargs):
882 if db_field.name == 'site':
883 if not request.user.is_admin:
884 # show sites where caller is an admin or pi
885 sites = []
886 for site_privilege in SitePrivilege.objects.filer(user=request.user):
887 if site_privilege.role.role_type in ['admin', 'pi']:
888 sites.append(site_privilege.site.login_base)
889 kwargs['queryset'] = Site.objects.filter(login_base__in(list(sites)))
890
891 return super(UserAdmin, self).formfield_for_foreignkey(db_field, request, **kwargs)
892
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500893 def has_add_permission(self, request, obj=None):
894 return (not self.__user_is_readonly(request))
895
896 def has_delete_permission(self, request, obj=None):
897 return (not self.__user_is_readonly(request))
898
899 def get_actions(self,request):
900 actions = super(UserAdmin,self).get_actions(request)
901
902 if self.__user_is_readonly(request):
903 if 'delete_selected' in actions:
904 del actions['delete_selected']
905
906 return actions
907
908 def change_view(self,request,object_id, extra_context=None):
909
910 if self.__user_is_readonly(request):
911 self.readonly_fields=self.user_readonly_fields
912 self.inlines = self.user_readonly_inlines
913 try:
914 return super(UserAdmin, self).change_view(request, object_id, extra_context=extra_context)
915 except PermissionDenied:
916 pass
917 if request.method == 'POST':
918 raise PermissionDenied
919 request.readonly = True
920 return super(UserAdmin, self).change_view(request, object_id, extra_context=extra_context)
921
922 def __user_is_readonly(self, request):
923 #groups = [x.name for x in request.user.groups.all() ]
924 #return "readonly" in groups
925 return request.user.isReadOnlyUser()
926
927
928
929class ServiceResourceROInline(ReadOnlyTabularInline):
930 model = ServiceResource
931 extra = 0
932 fields = ['serviceClass', 'name', 'maxUnitsDeployment', 'maxUnitsNode', 'maxDuration', 'bucketInRate', 'bucketMaxSize', 'cost', 'calendarReservable']
933
Scott Baker0165fac2014-01-13 11:49:26 -0800934class ServiceResourceInline(PlStackTabularInline):
Scott Baker3de3e372013-05-10 16:50:44 -0700935 model = ServiceResource
936 extra = 0
937
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500938class ServiceClassAdmin(PlanetStackBaseAdmin):
Scott Baker3de3e372013-05-10 16:50:44 -0700939 list_display = ('name', 'commitment', 'membershipFee')
940 inlines = [ServiceResourceInline]
941
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500942 user_readonly_fields = ['name', 'commitment', 'membershipFee']
943 user_readonly_inlines = []
944
945class ReservedResourceROInline(ReadOnlyTabularInline):
946 model = ReservedResource
947 extra = 0
948 fields = ['sliver', 'resource','quantity','reservationSet']
949 suit_classes = 'suit-tab suit-tab-reservedresources'
950
Scott Baker0165fac2014-01-13 11:49:26 -0800951class ReservedResourceInline(PlStackTabularInline):
Scott Baker133c9212013-05-17 09:09:11 -0700952 model = ReservedResource
953 extra = 0
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400954 suit_classes = 'suit-tab suit-tab-reservedresources'
Scott Baker133c9212013-05-17 09:09:11 -0700955
956 def formfield_for_foreignkey(self, db_field, request=None, **kwargs):
957 field = super(ReservedResourceInline, self).formfield_for_foreignkey(db_field, request, **kwargs)
958
959 if db_field.name == 'resource':
960 # restrict resources to those that the slice's service class allows
961 if request._slice is not None:
962 field.queryset = field.queryset.filter(serviceClass = request._slice.serviceClass, calendarReservable=True)
963 if len(field.queryset) > 0:
964 field.initial = field.queryset.all()[0]
965 else:
966 field.queryset = field.queryset.none()
967 elif db_field.name == 'sliver':
968 # restrict slivers to those that belong to the slice
969 if request._slice is not None:
970 field.queryset = field.queryset.filter(slice = request._slice)
971 else:
972 field.queryset = field.queryset.none()
973
974 return field
975
976class ReservationChangeForm(forms.ModelForm):
977 class Meta:
978 model = Reservation
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400979 widgets = {
980 'slice' : LinkedSelect
981 }
Scott Baker133c9212013-05-17 09:09:11 -0700982
983class ReservationAddForm(forms.ModelForm):
984 slice = forms.ModelChoiceField(queryset=Slice.objects.all(), widget=forms.Select(attrs={"onChange":"document.getElementById('id_refresh').value=1; submit()"}))
985 refresh = forms.CharField(widget=forms.HiddenInput())
986
987 class Media:
988 css = {'all': ('planetstack.css',)} # .field-refresh { display: none; }
989
990 def clean_slice(self):
991 slice = self.cleaned_data.get("slice")
992 x = ServiceResource.objects.filter(serviceClass = slice.serviceClass, calendarReservable=True)
993 if len(x) == 0:
994 raise forms.ValidationError("The slice you selected does not have a service class that allows reservations")
995 return slice
996
997 class Meta:
998 model = Reservation
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400999 widgets = {
1000 'slice' : LinkedSelect
1001 }
1002
Scott Baker133c9212013-05-17 09:09:11 -07001003
1004class ReservationAddRefreshForm(ReservationAddForm):
1005 """ This form is displayed when the Reservation Form receives an update
1006 from the Slice dropdown onChange handler. It doesn't validate the
1007 data and doesn't save the data. This will cause the form to be
1008 redrawn.
1009 """
1010
Scott Baker8737e5f2013-05-17 09:35:32 -07001011 """ don't validate anything other than slice """
1012 dont_validate_fields = ("startTime", "duration")
1013
Scott Baker133c9212013-05-17 09:09:11 -07001014 def full_clean(self):
1015 result = super(ReservationAddForm, self).full_clean()
Scott Baker8737e5f2013-05-17 09:35:32 -07001016
1017 for fieldname in self.dont_validate_fields:
1018 if fieldname in self._errors:
1019 del self._errors[fieldname]
1020
Scott Baker133c9212013-05-17 09:09:11 -07001021 return result
1022
1023 """ don't save anything """
1024 def is_valid(self):
1025 return False
1026
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001027class ReservationAdmin(PlanetStackBaseAdmin):
1028 fieldList = ['slice', 'startTime', 'duration']
1029 fieldsets = [('Reservation Details', {'fields': fieldList, 'classes': ['suit-tab suit-tab-general']})]
Scott Baker133c9212013-05-17 09:09:11 -07001030 list_display = ('startTime', 'duration')
Scott Baker133c9212013-05-17 09:09:11 -07001031 form = ReservationAddForm
1032
Siobhan Tullybfd11dc2013-09-03 12:59:24 -04001033 suit_form_tabs = (('general','Reservation Details'), ('reservedresources','Reserved Resources'))
1034
1035 inlines = [ReservedResourceInline]
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001036 user_readonly_inlines = [ReservedResourceROInline]
1037 user_readonly_fields = fieldList
Siobhan Tullybfd11dc2013-09-03 12:59:24 -04001038
Scott Baker133c9212013-05-17 09:09:11 -07001039 def add_view(self, request, form_url='', extra_context=None):
Scott Bakeracd45142013-05-19 16:19:16 -07001040 timezone.activate(request.user.timezone)
Scott Baker133c9212013-05-17 09:09:11 -07001041 request._refresh = False
1042 request._slice = None
1043 if request.method == 'POST':
Scott Baker8737e5f2013-05-17 09:35:32 -07001044 # "refresh" will be set to "1" if the form was submitted due to
1045 # a change in the Slice dropdown.
Scott Baker133c9212013-05-17 09:09:11 -07001046 if request.POST.get("refresh","1") == "1":
1047 request._refresh = True
1048 request.POST["refresh"] = "0"
Scott Baker8737e5f2013-05-17 09:35:32 -07001049
1050 # Keep track of the slice that was selected, so the
1051 # reservedResource inline can filter items for the slice.
Scott Baker133c9212013-05-17 09:09:11 -07001052 request._slice = request.POST.get("slice",None)
1053 if (request._slice is not None):
1054 request._slice = Slice.objects.get(id=request._slice)
1055
1056 result = super(ReservationAdmin, self).add_view(request, form_url, extra_context)
1057 return result
1058
Scott Bakeracd45142013-05-19 16:19:16 -07001059 def changelist_view(self, request, extra_context = None):
1060 timezone.activate(request.user.timezone)
1061 return super(ReservationAdmin, self).changelist_view(request, extra_context)
1062
Scott Baker133c9212013-05-17 09:09:11 -07001063 def get_form(self, request, obj=None, **kwargs):
Siobhan Tullyd3515752013-06-21 16:34:53 -04001064 request._obj_ = obj
1065 if obj is not None:
1066 # For changes, set request._slice to the slice already set in the
1067 # object.
1068 request._slice = obj.slice
1069 self.form = ReservationChangeForm
1070 else:
1071 if getattr(request, "_refresh", False):
1072 self.form = ReservationAddRefreshForm
1073 else:
1074 self.form = ReservationAddForm
1075 return super(ReservationAdmin, self).get_form(request, obj, **kwargs)
1076
Scott Baker133c9212013-05-17 09:09:11 -07001077 def get_readonly_fields(self, request, obj=None):
Siobhan Tullyd3515752013-06-21 16:34:53 -04001078 if (obj is not None):
1079 # Prevent slice from being changed after the reservation has been
1080 # created.
1081 return ['slice']
1082 else:
Scott Baker133c9212013-05-17 09:09:11 -07001083 return []
Scott Baker3de3e372013-05-10 16:50:44 -07001084
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001085class NetworkParameterTypeAdmin(PlanetStackBaseAdmin):
Scott Baker74d8e622013-07-29 16:04:22 -07001086 list_display = ("name", )
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001087 user_readonly_fields = ['name']
1088 user_readonly_inlines = []
Scott Baker74d8e622013-07-29 16:04:22 -07001089
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001090class RouterAdmin(PlanetStackBaseAdmin):
Scott Baker74d8e622013-07-29 16:04:22 -07001091 list_display = ("name", )
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001092 user_readonly_fields = ['name']
1093 user_readonly_inlines = []
1094
1095class RouterROInline(ReadOnlyTabularInline):
1096 model = Router.networks.through
1097 extra = 0
1098 verbose_name_plural = "Routers"
1099 verbose_name = "Router"
1100 suit_classes = 'suit-tab suit-tab-routers'
1101
1102 fields = ['name', 'owner', 'permittedNetworks', 'networks']
Scott Baker74d8e622013-07-29 16:04:22 -07001103
Scott Baker0165fac2014-01-13 11:49:26 -08001104class RouterInline(PlStackTabularInline):
Scott Baker74d8e622013-07-29 16:04:22 -07001105 model = Router.networks.through
1106 extra = 0
1107 verbose_name_plural = "Routers"
1108 verbose_name = "Router"
Siobhan Tully2d95e482013-09-06 10:56:06 -04001109 suit_classes = 'suit-tab suit-tab-routers'
Scott Baker74d8e622013-07-29 16:04:22 -07001110
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001111class NetworkParameterROInline(ReadOnlyTabularInline):
1112 model = NetworkParameter
1113 extra = 1
1114 verbose_name_plural = "Parameters"
1115 verbose_name = "Parameter"
1116 suit_classes = 'suit-tab suit-tab-netparams'
1117 fields = ['parameter', 'value', 'content_type', 'object_id', 'content_object']
1118
Scott Baker74d8e622013-07-29 16:04:22 -07001119class NetworkParameterInline(generic.GenericTabularInline):
Scott Baker74d8e622013-07-29 16:04:22 -07001120 model = NetworkParameter
1121 extra = 1
1122 verbose_name_plural = "Parameters"
1123 verbose_name = "Parameter"
Siobhan Tully2d95e482013-09-06 10:56:06 -04001124 suit_classes = 'suit-tab suit-tab-netparams'
Scott Baker74d8e622013-07-29 16:04:22 -07001125
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001126class NetworkSliversROInline(ReadOnlyTabularInline):
1127 fields = ['network', 'sliver', 'ip', 'port_id']
1128 model = NetworkSliver
1129 extra = 0
1130 verbose_name_plural = "Slivers"
1131 verbose_name = "Sliver"
1132 suit_classes = 'suit-tab suit-tab-networkslivers'
1133
Scott Baker0165fac2014-01-13 11:49:26 -08001134class NetworkSliversInline(PlStackTabularInline):
Scott Baker74d8e622013-07-29 16:04:22 -07001135 readonly_fields = ("ip", )
1136 model = NetworkSliver
1137 extra = 0
1138 verbose_name_plural = "Slivers"
1139 verbose_name = "Sliver"
Siobhan Tully2d95e482013-09-06 10:56:06 -04001140 suit_classes = 'suit-tab suit-tab-networkslivers'
Scott Baker74d8e622013-07-29 16:04:22 -07001141
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001142class NetworkSlicesROInline(ReadOnlyTabularInline):
1143 model = NetworkSlice
1144 extra = 0
1145 verbose_name_plural = "Slices"
1146 verbose_name = "Slice"
1147 suit_classes = 'suit-tab suit-tab-networkslices'
1148 fields = ['network','slice']
1149
Scott Baker0165fac2014-01-13 11:49:26 -08001150class NetworkSlicesInline(PlStackTabularInline):
Scott Bakerd7d2a392013-08-06 08:57:30 -07001151 model = NetworkSlice
1152 extra = 0
1153 verbose_name_plural = "Slices"
1154 verbose_name = "Slice"
Siobhan Tully2d95e482013-09-06 10:56:06 -04001155 suit_classes = 'suit-tab suit-tab-networkslices'
Scott Bakerd7d2a392013-08-06 08:57:30 -07001156
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001157class NetworkAdmin(PlanetStackBaseAdmin):
Scott Baker74d8e622013-07-29 16:04:22 -07001158 list_display = ("name", "subnet", "ports", "labels")
1159 readonly_fields = ("subnet", )
Siobhan Tully2d95e482013-09-06 10:56:06 -04001160
Scott Bakerd7d2a392013-08-06 08:57:30 -07001161 inlines = [NetworkParameterInline, NetworkSliversInline, NetworkSlicesInline, RouterInline]
Scott Baker74d8e622013-07-29 16:04:22 -07001162
Siobhan Tully2d95e482013-09-06 10:56:06 -04001163 fieldsets = [
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001164 (None, {'fields': ['name','template','ports','labels','owner','guaranteedBandwidth', 'permitAllSlices','permittedSlices','network_id','router_id','subnet_id','subnet'], 'classes':['suit-tab suit-tab-general']}),]
1165
1166 user_readonly_fields = ['name','template','ports','labels','owner','guaranteedBandwidth', 'permitAllSlices','permittedSlices','network_id','router_id','subnet_id','subnet']
1167 user_readonly_inlines = [NetworkParameterROInline, NetworkSliversROInline, NetworkSlicesROInline, RouterROInline]
Siobhan Tully2d95e482013-09-06 10:56:06 -04001168
1169 suit_form_tabs =(
1170 ('general','Network Details'),
1171 ('netparams', 'Parameters'),
1172 ('networkslivers','Slivers'),
1173 ('networkslices','Slices'),
1174 ('routers','Routers'),
1175 )
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001176class NetworkTemplateAdmin(PlanetStackBaseAdmin):
Scott Baker74d8e622013-07-29 16:04:22 -07001177 list_display = ("name", "guaranteedBandwidth", "visibility")
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001178 user_readonly_fields = ["name", "guaranteedBandwidth", "visibility"]
1179 user_readonly_inlines = []
Scott Baker74d8e622013-07-29 16:04:22 -07001180
Tony Mack31c2b8f2013-04-26 20:01:42 -04001181# register a signal that caches the user's credentials when they log in
1182def cache_credentials(sender, user, request, **kwds):
1183 auth = {'username': request.POST['username'],
1184 'password': request.POST['password']}
1185 request.session['auth'] = auth
1186user_logged_in.connect(cache_credentials)
1187
Scott Baker15cddfa2013-12-09 13:45:19 -08001188def dollar_field(fieldName, short_description):
1189 def newFunc(self, obj):
1190 try:
1191 x= "$ %0.2f" % float(getattr(obj, fieldName, 0.0))
1192 except:
1193 x=getattr(obj, fieldName, 0.0)
1194 return x
1195 newFunc.short_description = short_description
1196 return newFunc
1197
1198def right_dollar_field(fieldName, short_description):
1199 def newFunc(self, obj):
1200 try:
1201 #x= '<div align=right style="width:6em">$ %0.2f</div>' % float(getattr(obj, fieldName, 0.0))
1202 x= '<div align=right>$ %0.2f</div>' % float(getattr(obj, fieldName, 0.0))
1203 except:
1204 x=getattr(obj, fieldName, 0.0)
1205 return x
1206 newFunc.short_description = short_description
1207 newFunc.allow_tags = True
1208 return newFunc
Scott Baker43105042013-12-06 23:23:36 -08001209
Scott Baker0165fac2014-01-13 11:49:26 -08001210class InvoiceChargeInline(PlStackTabularInline):
Scott Baker43105042013-12-06 23:23:36 -08001211 model = Charge
Scott Baker15cddfa2013-12-09 13:45:19 -08001212 extra = 0
Scott Baker43105042013-12-06 23:23:36 -08001213 verbose_name_plural = "Charges"
1214 verbose_name = "Charge"
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001215 exclude = ['account']
Scott Baker9cb88a22013-12-09 18:56:00 -08001216 fields = ["date", "kind", "state", "object", "coreHours", "dollar_amount", "slice"]
1217 readonly_fields = ["date", "kind", "state", "object", "coreHours", "dollar_amount", "slice"]
1218 can_delete = False
1219 max_num = 0
1220
1221 dollar_amount = right_dollar_field("amount", "Amount")
Scott Baker43105042013-12-06 23:23:36 -08001222
1223class InvoiceAdmin(admin.ModelAdmin):
1224 list_display = ("date", "account")
1225
1226 inlines = [InvoiceChargeInline]
1227
Scott Baker9cb88a22013-12-09 18:56:00 -08001228 fields = ["date", "account", "dollar_amount"]
1229 readonly_fields = ["date", "account", "dollar_amount"]
1230
1231 dollar_amount = dollar_field("amount", "Amount")
Scott Baker43105042013-12-06 23:23:36 -08001232
Scott Baker0165fac2014-01-13 11:49:26 -08001233class InvoiceInline(PlStackTabularInline):
Scott Baker15cddfa2013-12-09 13:45:19 -08001234 model = Invoice
1235 extra = 0
1236 verbose_name_plural = "Invoices"
1237 verbose_name = "Invoice"
Scott Baker0165fac2014-01-13 11:49:26 -08001238 fields = ["date", "dollar_amount"]
1239 readonly_fields = ["date", "dollar_amount"]
Scott Baker15cddfa2013-12-09 13:45:19 -08001240 suit_classes = 'suit-tab suit-tab-accountinvoice'
1241 can_delete=False
1242 max_num=0
1243
1244 dollar_amount = right_dollar_field("amount", "Amount")
1245
Scott Baker0165fac2014-01-13 11:49:26 -08001246class PendingChargeInline(PlStackTabularInline):
Scott Baker43105042013-12-06 23:23:36 -08001247 model = Charge
Scott Baker15cddfa2013-12-09 13:45:19 -08001248 extra = 0
Scott Baker43105042013-12-06 23:23:36 -08001249 verbose_name_plural = "Charges"
1250 verbose_name = "Charge"
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001251 exclude = ["invoice"]
Scott Baker15cddfa2013-12-09 13:45:19 -08001252 fields = ["date", "kind", "state", "object", "coreHours", "dollar_amount", "slice"]
1253 readonly_fields = ["date", "kind", "state", "object", "coreHours", "dollar_amount", "slice"]
Scott Baker43105042013-12-06 23:23:36 -08001254 suit_classes = 'suit-tab suit-tab-accountpendingcharges'
Scott Baker15cddfa2013-12-09 13:45:19 -08001255 can_delete=False
1256 max_num=0
Scott Baker43105042013-12-06 23:23:36 -08001257
1258 def queryset(self, request):
1259 qs = super(PendingChargeInline, self).queryset(request)
1260 qs = qs.filter(state="pending")
1261 return qs
1262
Scott Baker15cddfa2013-12-09 13:45:19 -08001263 dollar_amount = right_dollar_field("amount", "Amount")
1264
Scott Baker0165fac2014-01-13 11:49:26 -08001265class PaymentInline(PlStackTabularInline):
Scott Baker43105042013-12-06 23:23:36 -08001266 model=Payment
1267 extra = 1
1268 verbose_name_plural = "Payments"
1269 verbose_name = "Payment"
Scott Baker15cddfa2013-12-09 13:45:19 -08001270 fields = ["date", "dollar_amount"]
1271 readonly_fields = ["date", "dollar_amount"]
Scott Baker43105042013-12-06 23:23:36 -08001272 suit_classes = 'suit-tab suit-tab-accountpayments'
Scott Baker15cddfa2013-12-09 13:45:19 -08001273 can_delete=False
1274 max_num=0
1275
1276 dollar_amount = right_dollar_field("amount", "Amount")
1277
Scott Baker43105042013-12-06 23:23:36 -08001278class AccountAdmin(admin.ModelAdmin):
1279 list_display = ("site", "balance_due")
1280
1281 inlines = [InvoiceInline, PaymentInline, PendingChargeInline]
1282
1283 fieldsets = [
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001284 (None, {'fields': ['site', 'dollar_balance_due', 'dollar_total_invoices', 'dollar_total_payments'],'classes':['suit-tab suit-tab-general']}),]
Scott Baker43105042013-12-06 23:23:36 -08001285
Scott Baker15cddfa2013-12-09 13:45:19 -08001286 readonly_fields = ['site', 'dollar_balance_due', 'dollar_total_invoices', 'dollar_total_payments']
Scott Baker43105042013-12-06 23:23:36 -08001287
1288 suit_form_tabs =(
1289 ('general','Account Details'),
1290 ('accountinvoice', 'Invoices'),
1291 ('accountpayments', 'Payments'),
1292 ('accountpendingcharges','Pending Charges'),
1293 )
1294
Scott Baker15cddfa2013-12-09 13:45:19 -08001295 dollar_balance_due = dollar_field("balance_due", "Balance Due")
1296 dollar_total_invoices = dollar_field("total_invoices", "Total Invoices")
1297 dollar_total_payments = dollar_field("total_payments", "Total Payments")
1298
Siobhan Tullyce652d02013-10-08 21:52:35 -04001299
Siobhan Tully53437282013-04-26 19:30:27 -04001300# Now register the new UserAdmin...
Siobhan Tully30fd4292013-05-10 08:59:56 -04001301admin.site.register(User, UserAdmin)
Siobhan Tully53437282013-04-26 19:30:27 -04001302# ... and, since we're not using Django's builtin permissions,
1303# unregister the Group model from admin.
Siobhan Tullyce652d02013-10-08 21:52:35 -04001304#admin.site.unregister(Group)
Siobhan Tully53437282013-04-26 19:30:27 -04001305
Siobhan Tullybf1153a2013-05-27 20:53:48 -04001306#Do not show django evolution in the admin interface
1307from django_evolution.models import Version, Evolution
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001308#admin.site.unregister(Version)
1309#admin.site.unregister(Evolution)
Siobhan Tullybf1153a2013-05-27 20:53:48 -04001310
1311
1312# When debugging it is often easier to see all the classes, but for regular use
1313# only the top-levels should be displayed
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001314showAll = False
Scott Baker43105042013-12-06 23:23:36 -08001315
Siobhan Tullybf1153a2013-05-27 20:53:48 -04001316admin.site.register(Deployment, DeploymentAdmin)
Siobhan Tully4bc09f22013-04-10 21:15:21 -04001317admin.site.register(Site, SiteAdmin)
Siobhan Tully4bc09f22013-04-10 21:15:21 -04001318admin.site.register(Slice, SliceAdmin)
Siobhan Tullyce652d02013-10-08 21:52:35 -04001319admin.site.register(Service, ServiceAdmin)
smbakera3cf70c2013-06-27 02:01:41 -07001320admin.site.register(Reservation, ReservationAdmin)
Scott Baker74d8e622013-07-29 16:04:22 -07001321admin.site.register(Network, NetworkAdmin)
1322admin.site.register(Router, RouterAdmin)
Scott Baker74d8e622013-07-29 16:04:22 -07001323admin.site.register(NetworkTemplate, NetworkTemplateAdmin)
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001324admin.site.register(Account, AccountAdmin)
1325admin.site.register(Invoice, InvoiceAdmin)
Siobhan Tullybf1153a2013-05-27 20:53:48 -04001326
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001327if True:
1328 admin.site.register(NetworkParameterType, NetworkParameterTypeAdmin)
1329 admin.site.register(ServiceClass, ServiceClassAdmin)
Siobhan Tullybfd11dc2013-09-03 12:59:24 -04001330 #admin.site.register(PlanetStack)
Siobhan Tullyd3515752013-06-21 16:34:53 -04001331 admin.site.register(Tag, TagAdmin)
Siobhan Tullyce652d02013-10-08 21:52:35 -04001332 admin.site.register(DeploymentRole)
1333 admin.site.register(SiteRole)
1334 admin.site.register(SliceRole)
1335 admin.site.register(PlanetStackRole)
Siobhan Tullybf1153a2013-05-27 20:53:48 -04001336 admin.site.register(Node, NodeAdmin)
Siobhan Tullybfd11dc2013-09-03 12:59:24 -04001337 #admin.site.register(SlicePrivilege, SlicePrivilegeAdmin)
1338 #admin.site.register(SitePrivilege, SitePrivilegeAdmin)
Siobhan Tullybf1153a2013-05-27 20:53:48 -04001339 admin.site.register(Sliver, SliverAdmin)
Siobhan Tullybf1153a2013-05-27 20:53:48 -04001340 admin.site.register(Image, ImageAdmin)
Tony Mack7130ac32013-03-22 21:58:00 -04001341