blob: 5281bb1f56e1dbe459d7e559badea6587b2bd11d [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
Scott Baker874936e2014-01-13 18:15:34 -080083 def get_change_url(self, model, id):
84 """ Get the URL to a change form in the admin for this model """
85 reverse_path = "admin:%s_change" % (model._meta.db_table)
Scott Bakere2bbf7e2014-01-13 12:09:31 -080086 try:
Scott Baker874936e2014-01-13 18:15:34 -080087 url = reverse(reverse_path, args=(id,))
Scott Bakere2bbf7e2014-01-13 12:09:31 -080088 except NoReverseMatch:
Scott Baker874936e2014-01-13 18:15:34 -080089 return None
90
91 return url
92
93 def setup_selflink(self):
94 if hasattr(self, "selflink_fieldname"):
95 """ self.selflink_model can be defined to punch through a relation
96 to its target object. For example, in SliceNetworkInline, set
97 selflink_model = "network", and the URL will lead to the Network
98 object instead of trying to bring up a change view of the
99 SliceNetwork object.
100 """
101 self.selflink_model = getattr(self.model,self.selflink_fieldname).field.rel.to
102 else:
103 self.selflink_model = self.model
104
105 url = self.get_change_url(self.selflink_model, 0)
106
107 # We don't have an admin for this object, so don't create the
108 # selflink.
109 if (url == None):
Scott Bakere2bbf7e2014-01-13 12:09:31 -0800110 return
111
Scott Baker874936e2014-01-13 18:15:34 -0800112 # Since we need to add "selflink" to the field list, we need to create
113 # self.fields if it is None.
Scott Baker0165fac2014-01-13 11:49:26 -0800114 if (self.fields is None):
115 self.fields = []
116 for f in self.model._meta.fields:
117 if f.editable and f.name != "id":
118 self.fields.append(f.name)
Scott Baker86568322014-01-12 16:53:31 -0800119
Scott Baker874936e2014-01-13 18:15:34 -0800120 self.fields = tuple(self.fields) + ("selflink", )
Scott Baker86568322014-01-12 16:53:31 -0800121
Scott Baker874936e2014-01-13 18:15:34 -0800122 if self.readonly_fields is None:
123 self.readonly_fields = ()
Scott Baker86568322014-01-12 16:53:31 -0800124
Scott Baker874936e2014-01-13 18:15:34 -0800125 self.readonly_fields = tuple(self.readonly_fields) + ("selflink", )
Scott Baker86568322014-01-12 16:53:31 -0800126
127 def selflink(self, obj):
Scott Baker874936e2014-01-13 18:15:34 -0800128 if hasattr(self, "selflink_fieldname"):
129 obj = getattr(obj, self.selflink_fieldname)
130
Scott Baker86568322014-01-12 16:53:31 -0800131 if obj.id:
Scott Baker874936e2014-01-13 18:15:34 -0800132 url = self.get_change_url(self.selflink_model, obj.id)
133 return "<a href='%s'>Details</a>" % str(url)
Scott Baker86568322014-01-12 16:53:31 -0800134 else:
Scott Bakere2bbf7e2014-01-13 12:09:31 -0800135 return "Not present"
Scott Baker86568322014-01-12 16:53:31 -0800136
137 selflink.allow_tags = True
138 selflink.short_description = "Details"
Siobhan Tullyd3515752013-06-21 16:34:53 -0400139
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500140class ReadOnlyTabularInline(PlStackTabularInline):
141 can_delete = False
142
143 def get_readonly_fields(self, request, obj=None):
144 return self.fields
145
146 def has_add_permission(self, request):
147 return False
148
149class ReservationROInline(ReadOnlyTabularInline):
150 model = Reservation
151 extra = 0
152 suit_classes = 'suit-tab suit-tab-reservations'
153 fields = ['startTime','slice','duration']
154
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400155class ReservationInline(PlStackTabularInline):
156 model = Reservation
157 extra = 0
158 suit_classes = 'suit-tab suit-tab-reservations'
159
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500160class TagROInline(generic.GenericTabularInline):
161 model = Tag
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400162 extra = 0
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500163 suit_classes = 'suit-tab suit-tab-tags'
164 can_delete = False
165 fields = ['service', 'name', 'value']
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400166
167 def get_readonly_fields(self, request, obj=None):
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500168 return self.fields
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400169
170 def has_add_permission(self, request):
171 return False
172
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500173
Siobhan Tullyde5450d2013-06-21 11:35:33 -0400174class TagInline(generic.GenericTabularInline):
175 model = Tag
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400176 extra = 0
177 suit_classes = 'suit-tab suit-tab-tags'
Siobhan Tullyde5450d2013-06-21 11:35:33 -0400178
Scott Baker74d8e622013-07-29 16:04:22 -0700179class NetworkLookerUpper:
Siobhan Tully2c780ad2013-09-06 11:22:40 -0400180 """ This is a callable that looks up a network name in a sliver and returns
181 the ip address for that network.
182 """
183
184 def __init__(self, name):
185 self.short_description = name
186 self.__name__ = name
187 self.network_name = name
188
189 def __call__(self, obj):
190 if obj is not None:
191 for nbs in obj.networksliver_set.all():
192 if (nbs.network.name == self.network_name):
193 return nbs.ip
Scott Baker74d8e622013-07-29 16:04:22 -0700194 return ""
195
196 def __str__(self):
197 return self.network_name
198
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500199class SliverROInline(ReadOnlyTabularInline):
200 model = Sliver
201 fields = ['ip', 'instance_name', 'slice', 'numberCores', 'image', 'node', 'deploymentNetwork']
202 suit_classes = 'suit-tab suit-tab-slivers'
203
Siobhan Tullyd3515752013-06-21 16:34:53 -0400204class SliverInline(PlStackTabularInline):
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400205 model = Sliver
Tony Mackb0d97422013-06-10 09:57:45 -0400206 fields = ['ip', 'instance_name', 'slice', 'numberCores', 'image', 'node', 'deploymentNetwork']
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400207 extra = 0
Tony Mack3777b012013-05-07 21:38:06 -0400208 readonly_fields = ['ip', 'instance_name']
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400209 suit_classes = 'suit-tab suit-tab-slivers'
Scott Baker74d8e622013-07-29 16:04:22 -0700210
Siobhan Tully2d95e482013-09-06 10:56:06 -0400211# Note this is breaking in the admin.py when trying to use an inline to add a node/image
212# def _declared_fieldsets(self):
213# # Return None so django will call get_fieldsets and we can insert our
214# # dynamic fields
215# return None
216#
217# def get_readonly_fields(self, request, obj=None):
218# readonly_fields = super(SliverInline, self).get_readonly_fields(request, obj)
219#
220# # Lookup the networks that are bound to the slivers, and add those
221# # network names to the list of readonly fields.
222#
223# for sliver in obj.slivers.all():
224# for nbs in sliver.networksliver_set.all():
225# if nbs.ip:
226# network_name = nbs.network.name
227# if network_name not in [str(x) for x in readonly_fields]:
228# readonly_fields.append(NetworkLookerUpper(network_name))
229#
230# return readonly_fields
231#
232# def get_fieldsets(self, request, obj=None):
233# form = self.get_formset(request, obj).form
234# # fields = the read/write files + the read-only fields
235# fields = self.fields
236# for fieldName in self.get_readonly_fields(request,obj):
237# if not fieldName in fields:
238# fields.append(fieldName)
239#
240# return [(None, {'fields': fields})]
Scott Baker74d8e622013-07-29 16:04:22 -0700241
Tony Mackc2835a92013-05-28 09:18:49 -0400242
Siobhan Tully567e3e62013-06-21 18:03:16 -0400243
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500244class SiteROInline(ReadOnlyTabularInline):
245 model = Site
246 extra = 0
247 fields = ['name', 'login_base', 'site_url', 'enabled']
248 suit_classes = 'suit-tab suit-tab-sites'
249
Siobhan Tullyd3515752013-06-21 16:34:53 -0400250class SiteInline(PlStackTabularInline):
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400251 model = Site
252 extra = 0
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400253 suit_classes = 'suit-tab suit-tab-sites'
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400254
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500255class UserROInline(ReadOnlyTabularInline):
256 model = User
257 fields = ['email', 'firstname', 'lastname']
258 extra = 0
259 suit_classes = 'suit-tab suit-tab-users'
260
Siobhan Tullyd3515752013-06-21 16:34:53 -0400261class UserInline(PlStackTabularInline):
Siobhan Tully30fd4292013-05-10 08:59:56 -0400262 model = User
Siobhan Tully47ae1b52013-05-10 15:53:14 -0400263 fields = ['email', 'firstname', 'lastname']
Siobhan Tully30fd4292013-05-10 08:59:56 -0400264 extra = 0
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400265 suit_classes = 'suit-tab suit-tab-users'
Siobhan Tully30fd4292013-05-10 08:59:56 -0400266
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500267class SliceROInline(ReadOnlyTabularInline):
268 model = Slice
269 suit_classes = 'suit-tab suit-tab-slices'
270 fields = ['name','site', 'serviceClass', 'service']
271
Siobhan Tullyd3515752013-06-21 16:34:53 -0400272class SliceInline(PlStackTabularInline):
Tony Mack00d361f2013-04-28 10:28:42 -0400273 model = Slice
Siobhan Tullyce652d02013-10-08 21:52:35 -0400274 fields = ['name','site', 'serviceClass', 'service']
Tony Mack00d361f2013-04-28 10:28:42 -0400275 extra = 0
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400276 suit_classes = 'suit-tab suit-tab-slices'
277
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500278class NodeROInline(ReadOnlyTabularInline):
279 model = Node
280 extra = 0
281 suit_classes = 'suit-tab suit-tab-nodes'
282 fields = ['name','deployment']
Tony Mack00d361f2013-04-28 10:28:42 -0400283
Siobhan Tullyd3515752013-06-21 16:34:53 -0400284class NodeInline(PlStackTabularInline):
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400285 model = Node
286 extra = 0
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400287 suit_classes = 'suit-tab suit-tab-nodes'
288
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500289class DeploymentPrivilegeROInline(ReadOnlyTabularInline):
290 model = DeploymentPrivilege
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400291 extra = 0
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500292 suit_classes = 'suit-tab suit-tab-deploymentprivileges'
293 fields = ['user','role']
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400294
295class DeploymentPrivilegeInline(PlStackTabularInline):
296 model = DeploymentPrivilege
297 extra = 0
298 suit_classes = 'suit-tab suit-tab-deploymentprivileges'
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400299
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500300#CLEANUP DOUBLE SitePrivilegeInline
301class SitePrivilegeROInline(ReadOnlyTabularInline):
302 model = SitePrivilege
303 extra = 0
304 suit_classes = 'suit-tab suit-tab-siteprivileges'
305 fields = ['user','site', 'role']
306
Siobhan Tullyd3515752013-06-21 16:34:53 -0400307class SitePrivilegeInline(PlStackTabularInline):
Siobhan Tullyaa1bcd52013-05-10 12:43:09 -0400308 model = SitePrivilege
309 extra = 0
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400310 suit_classes = 'suit-tab suit-tab-siteprivileges'
Siobhan Tullyaa1bcd52013-05-10 12:43:09 -0400311
Tony Mackc2835a92013-05-28 09:18:49 -0400312 def formfield_for_foreignkey(self, db_field, request, **kwargs):
313 if db_field.name == 'site':
314 if not request.user.is_admin:
315 # only show sites where user is an admin or pi
316 roles = Role.objects.filter(role_type__in=['admin', 'pi'])
317 site_privileges = SitePrivilege.objects.filter(user=request.user).filter(role__in=roles)
318 login_bases = [site_privilege.site.login_base for site_privilege in site_privileges]
319 sites = Site.objects.filter(login_base__in=login_bases)
320 kwargs['queryset'] = sites
321
322 if db_field.name == 'user':
323 if not request.user.is_admin:
324 # only show users from sites where caller has admin or pi role
325 roles = Role.objects.filter(role_type__in=['admin', 'pi'])
326 site_privileges = SitePrivilege.objects.filter(user=request.user).filter(role__in=roles)
327 sites = [site_privilege.site for site_privilege in site_privileges]
328 site_privileges = SitePrivilege.objects.filter(site__in=sites)
329 emails = [site_privilege.user.email for site_privilege in site_privileges]
330 users = User.objects.filter(email__in=emails)
331 kwargs['queryset'] = users
332 return super(SitePrivilegeInline, self).formfield_for_foreignkey(db_field, request, **kwargs)
333
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400334class SitePrivilegeInline(PlStackTabularInline):
335 model = SitePrivilege
336 suit_classes = 'suit-tab suit-tab-siteprivileges'
Siobhan Tullyaa1bcd52013-05-10 12:43:09 -0400337 extra = 0
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400338 fields = ('user', 'site','role')
339
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500340class SlicePrivilegeROInline(ReadOnlyTabularInline):
341 model = SlicePrivilege
342 extra = 0
343 suit_classes = 'suit-tab suit-tab-sliceprivileges'
344 fields = ['user', 'slice', 'role']
345
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400346class SlicePrivilegeInline(PlStackTabularInline):
347 model = SlicePrivilege
348 suit_classes = 'suit-tab suit-tab-sliceprivileges'
349 extra = 0
350 fields = ('user', 'slice','role')
Siobhan Tullyaa1bcd52013-05-10 12:43:09 -0400351
Tony Mackc2835a92013-05-28 09:18:49 -0400352 def formfield_for_foreignkey(self, db_field, request, **kwargs):
353 if db_field.name == 'slice':
354 if not request.user.is_admin:
355 # only show slices at sites where caller has admin or pi role
356 roles = Role.objects.filter(role_type__in=['admin', 'pi'])
357 site_privileges = SitePrivilege.objects.filter(user=request.user).filter(role__in=roles)
358 sites = [site_privilege.site for site_privilege in site_privileges]
359 slices = Slice.objects.filter(site__in=sites)
360 kwargs['queryset'] = slices
361 if db_field.name == 'user':
362 if not request.user.is_admin:
363 # only show users from sites where caller has admin or pi role
364 roles = Role.objects.filter(role_type__in=['admin', 'pi'])
365 site_privileges = SitePrivilege.objects.filter(user=request.user).filter(role__in=roles)
366 sites = [site_privilege.site for site_privilege in site_privileges]
367 site_privileges = SitePrivilege.objects.filter(site__in=sites)
368 emails = [site_privilege.user.email for site_privilege in site_privileges]
369 users = User.objects.filter(email__in=emails)
370 kwargs['queryset'] = list(users)
371
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400372 return super(SlicePrivilegeInline, self).formfield_for_foreignkey(db_field, request, **kwargs)
Tony Mackc2835a92013-05-28 09:18:49 -0400373
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500374class SliceNetworkROInline(ReadOnlyTabularInline):
375 model = Network.slices.through
376 extra = 0
377 verbose_name = "Network Connection"
378 verbose_name_plural = "Network Connections"
379 suit_classes = 'suit-tab suit-tab-slicenetworks'
380 fields = ['network']
381
Scott Bakera0015eb2013-08-14 17:28:14 -0700382class SliceNetworkInline(PlStackTabularInline):
Scott Baker74d8e622013-07-29 16:04:22 -0700383 model = Network.slices.through
Scott Baker874936e2014-01-13 18:15:34 -0800384 selflink_fieldname = "network"
Scott Baker74d8e622013-07-29 16:04:22 -0700385 extra = 0
386 verbose_name = "Network Connection"
387 verbose_name_plural = "Network Connections"
Siobhan Tully2d95e482013-09-06 10:56:06 -0400388 suit_classes = 'suit-tab suit-tab-slicenetworks'
Scott Baker74d8e622013-07-29 16:04:22 -0700389
Tony Mack5e71a662013-05-03 23:30:41 -0400390class PlainTextWidget(forms.HiddenInput):
391 input_type = 'hidden'
392
393 def render(self, name, value, attrs=None):
394 if value is None:
395 value = ''
Tony Mack1d6b85f2013-05-07 18:49:14 -0400396 return mark_safe(str(value) + super(PlainTextWidget, self).render(name, value, attrs))
Tony Mack9bcbe4f2013-04-29 08:13:27 -0400397
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500398class PlanetStackBaseAdmin(ReadOnlyAwareAdmin):
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400399 save_on_top = False
400
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400401class SliceRoleAdmin(PlanetStackBaseAdmin):
402 model = SliceRole
403 pass
404
405class SiteRoleAdmin(PlanetStackBaseAdmin):
406 model = SiteRole
407 pass
408
Siobhan Tullybf1153a2013-05-27 20:53:48 -0400409class DeploymentAdminForm(forms.ModelForm):
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400410 sites = forms.ModelMultipleChoiceField(
411 queryset=Site.objects.all(),
412 required=False,
413 widget=FilteredSelectMultiple(
414 verbose_name=('Sites'), is_stacked=False
415 )
416 )
417 class Meta:
Siobhan Tullybf1153a2013-05-27 20:53:48 -0400418 model = Deployment
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400419
Siobhan Tully320b4622014-01-17 15:11:14 -0500420 def __init__(self, *args, **kwargs):
421 super(DeploymentAdminForm, self).__init__(*args, **kwargs)
422
423 if self.instance and self.instance.pk:
424 self.fields['sites'].initial = self.instance.sites.all()
425
426 def save(self, commit=True):
427 deployment = super(DeploymentAdminForm, self).save(commit=False)
428
429 if commit:
430 deployment.save()
431
432 if deployment.pk:
433 deployment.sites = self.cleaned_data['sites']
434 self.save_m2m()
435
436 return deployment
437
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500438class SiteAssocInline(PlStackTabularInline):
439 model = Site.deployments.through
440 extra = 0
441 suit_classes = 'suit-tab suit-tab-sites'
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400442
Siobhan Tullybf1153a2013-05-27 20:53:48 -0400443class DeploymentAdmin(PlanetStackBaseAdmin):
444 form = DeploymentAdminForm
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500445 model = Deployment
446 fieldList = ['name','sites']
447 fieldsets = [(None, {'fields': fieldList, 'classes':['suit-tab suit-tab-sites']})]
Siobhan Tully2d95e482013-09-06 10:56:06 -0400448 inlines = [DeploymentPrivilegeInline,NodeInline,TagInline]
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500449
450 user_readonly_inlines = [DeploymentPrivilegeROInline,NodeROInline,TagROInline]
451 user_readonly_fields = ['name']
452
453 suit_form_tabs =(('sites','Deployment Details'),('nodes','Nodes'),('deploymentprivileges','Privileges'),('tags','Tags'))
454
455class ServiceAttrAsTabROInline(ReadOnlyTabularInline):
456 model = ServiceAttribute
457 fields = ['name','value']
458 extra = 0
459 suit_classes = 'suit-tab suit-tab-serviceattrs'
Tony Mack5cd13202013-05-01 21:48:38 -0400460
Siobhan Tullyce652d02013-10-08 21:52:35 -0400461class ServiceAttrAsTabInline(PlStackTabularInline):
462 model = ServiceAttribute
463 fields = ['name','value']
464 extra = 0
465 suit_classes = 'suit-tab suit-tab-serviceattrs'
466
Siobhan Tullyce652d02013-10-08 21:52:35 -0400467class ServiceAdmin(PlanetStackBaseAdmin):
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500468 list_display = ("name","description","versionNumber","enabled","published")
469 fieldList = ["name","description","versionNumber","enabled","published"]
470 fieldsets = [(None, {'fields': fieldList, 'classes':['suit-tab suit-tab-general']})]
471 inlines = [ServiceAttrAsTabInline,SliceInline]
472
473 user_readonly_fields = fieldList
474 user_readonly_inlines = [ServiceAttrAsTabROInline,SliceROInline]
475
476 suit_form_tabs =(('general', 'Service Details'),
477 ('slices','Slices'),
478 ('serviceattrs','Additional Attributes'),
479 )
Siobhan Tullyce652d02013-10-08 21:52:35 -0400480
Tony Mack0553f282013-06-10 22:54:50 -0400481class SiteAdmin(PlanetStackBaseAdmin):
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500482 fieldList = ['name', 'site_url', 'enabled', 'is_public', 'login_base', 'accountLink','location']
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400483 fieldsets = [
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500484 (None, {'fields': fieldList, 'classes':['suit-tab suit-tab-general']}),
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400485 ('Deployment Networks', {'fields': ['deployments'], 'classes':['suit-tab suit-tab-deployments']}),
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400486 ]
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400487 suit_form_tabs =(('general', 'Site Details'),
488 ('users','Users'),
Siobhan Tully2d95e482013-09-06 10:56:06 -0400489 ('siteprivileges','Privileges'),
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400490 ('deployments','Deployments'),
491 ('slices','Slices'),
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500492 ('nodes','Nodes'),
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400493 ('tags','Tags'),
494 )
Scott Baker545db2a2013-12-09 18:44:43 -0800495 readonly_fields = ['accountLink']
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500496
497 user_readonly_fields = ['name', 'deployments','site_url', 'enabled', 'is_public', 'login_base', 'accountLink']
498 user_readonly_inlines = [SliceROInline,UserROInline,TagROInline, NodeROInline, SitePrivilegeROInline]
499
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400500 list_display = ('name', 'login_base','site_url', 'enabled')
501 filter_horizontal = ('deployments',)
Siobhan Tully2d95e482013-09-06 10:56:06 -0400502 inlines = [SliceInline,UserInline,TagInline, NodeInline, SitePrivilegeInline]
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400503 search_fields = ['name']
504
Tony Mack04062832013-05-10 08:22:44 -0400505 def queryset(self, request):
506 # admins can see all keys. Users can only see sites they belong to.
507 qs = super(SiteAdmin, self).queryset(request)
508 if not request.user.is_admin:
509 valid_sites = [request.user.site.login_base]
510 roles = request.user.get_roles()
511 for tenant_list in roles.values():
512 valid_sites.extend(tenant_list)
513 qs = qs.filter(login_base__in=valid_sites)
514 return qs
515
Tony Mack5cd13202013-05-01 21:48:38 -0400516 def get_formsets(self, request, obj=None):
517 for inline in self.get_inline_instances(request, obj):
518 # hide MyInline in the add view
519 if obj is None:
520 continue
Tony Mack2bd5b412013-06-11 21:05:06 -0400521 if isinstance(inline, SliceInline):
522 inline.model.caller = request.user
523 yield inline.get_formset(request, obj)
524
525 def get_formsets(self, request, obj=None):
526 for inline in self.get_inline_instances(request, obj):
527 # hide MyInline in the add view
528 if obj is None:
529 continue
530 if isinstance(inline, SliverInline):
531 inline.model.caller = request.user
Tony Mack5cd13202013-05-01 21:48:38 -0400532 yield inline.get_formset(request, obj)
533
Scott Baker545db2a2013-12-09 18:44:43 -0800534 def accountLink(self, obj):
535 link_obj = obj.accounts.all()
536 if link_obj:
537 reverse_path = "admin:core_account_change"
538 url = reverse(reverse_path, args =(link_obj[0].id,))
539 return "<a href='%s'>%s</a>" % (url, "view billing details")
540 else:
541 return "no billing data for this site"
542 accountLink.allow_tags = True
543 accountLink.short_description = "Billing"
544
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500545
Tony Mack9bcbe4f2013-04-29 08:13:27 -0400546class SitePrivilegeAdmin(PlanetStackBaseAdmin):
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500547 fieldList = ['user', 'site', 'role']
Tony Mack00d361f2013-04-28 10:28:42 -0400548 fieldsets = [
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500549 (None, {'fields': fieldList, 'classes':['collapse']})
Tony Mack00d361f2013-04-28 10:28:42 -0400550 ]
551 list_display = ('user', 'site', 'role')
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500552 user_readonly_fields = fieldList
553 user_readonly_inlines = []
Tony Mack00d361f2013-04-28 10:28:42 -0400554
Tony Mackc2835a92013-05-28 09:18:49 -0400555 def formfield_for_foreignkey(self, db_field, request, **kwargs):
556 if db_field.name == 'site':
557 if not request.user.is_admin:
558 # only show sites where user is an admin or pi
559 sites = set()
560 for site_privilege in SitePrivilege.objects.filer(user=request.user):
561 if site_privilege.role.role_type in ['admin', 'pi']:
562 sites.add(site_privilege.site)
563 kwargs['queryset'] = Site.objects.filter(site__in=list(sites))
564
565 if db_field.name == 'user':
566 if not request.user.is_admin:
567 # only show users from sites where caller has admin or pi role
568 roles = Role.objects.filter(role_type__in=['admin', 'pi'])
569 site_privileges = SitePrivilege.objects.filter(user=request.user).filter(role__in=roles)
570 sites = [site_privilege.site for site_privilege in site_privileges]
571 site_privileges = SitePrivilege.objects.filter(site__in=sites)
572 emails = [site_privilege.user.email for site_privilege in site_privileges]
573 users = User.objects.filter(email__in=emails)
574 kwargs['queryset'] = users
575
576 return super(SitePrivilegeAdmin, self).formfield_for_foreignkey(db_field, request, **kwargs)
577
Tony Mack04062832013-05-10 08:22:44 -0400578 def queryset(self, request):
579 # admins can see all privileges. Users can only see privileges at sites
Tony Mackc2835a92013-05-28 09:18:49 -0400580 # where they have the admin role or pi role.
Tony Mack04062832013-05-10 08:22:44 -0400581 qs = super(SitePrivilegeAdmin, self).queryset(request)
582 if not request.user.is_admin:
Tony Mackc2835a92013-05-28 09:18:49 -0400583 roles = Role.objects.filter(role_type__in=['admin', 'pi'])
584 site_privileges = SitePrivilege.objects.filter(user=request.user).filter(role__in=roles)
585 login_bases = [site_privilege.site.login_base for site_privilege in site_privileges]
586 sites = Site.objects.filter(login_base__in=login_bases)
587 qs = qs.filter(site__in=sites)
Tony Mack04062832013-05-10 08:22:44 -0400588 return qs
589
Siobhan Tullyce652d02013-10-08 21:52:35 -0400590class SliceForm(forms.ModelForm):
591 class Meta:
592 model = Slice
593 widgets = {
594 'service': LinkedSelect
595 }
596
Tony Mack2bd5b412013-06-11 21:05:06 -0400597class SliceAdmin(PlanetStackBaseAdmin):
Siobhan Tullyce652d02013-10-08 21:52:35 -0400598 form = SliceForm
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500599 fieldList = ['name', 'site', 'serviceClass', 'enabled','description', 'service', 'slice_url']
600 fieldsets = [('Slice Details', {'fields': fieldList, 'classes':['suit-tab suit-tab-general']}),]
Siobhan Tully30fd4292013-05-10 08:59:56 -0400601 list_display = ('name', 'site','serviceClass', 'slice_url')
Siobhan Tully2d95e482013-09-06 10:56:06 -0400602 inlines = [SlicePrivilegeInline,SliverInline, TagInline, ReservationInline,SliceNetworkInline]
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400603
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500604 user_readonly_fields = fieldList
605 user_readonly_inlines = [SlicePrivilegeROInline,SliverROInline,TagROInline, ReservationROInline, SliceNetworkROInline]
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400606
607 suit_form_tabs =(('general', 'Slice Details'),
Siobhan Tully2d95e482013-09-06 10:56:06 -0400608 ('slicenetworks','Networks'),
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400609 ('sliceprivileges','Privileges'),
610 ('slivers','Slivers'),
611 ('tags','Tags'),
612 ('reservations','Reservations'),
613 )
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400614
Tony Mackc2835a92013-05-28 09:18:49 -0400615 def formfield_for_foreignkey(self, db_field, request, **kwargs):
616 if db_field.name == 'site':
617 if not request.user.is_admin:
618 # only show sites where user is a pi or admin
619 roles = Role.objects.filter(role_type__in=['admin', 'pi'])
620 site_privileges = SitePrivilege.objects.filter(user=request.user).filter(role__in=roles)
621 login_bases = [site_privilege.site.login_base for site_privilege in site_privileges]
622 sites = Site.objects.filter(login_base__in=login_bases)
623 kwargs['queryset'] = sites
624
625 return super(SliceAdmin, self).formfield_for_foreignkey(db_field, request, **kwargs)
626
Tony Mack04062832013-05-10 08:22:44 -0400627 def queryset(self, request):
628 # admins can see all keys. Users can only see slices they belong to.
629 qs = super(SliceAdmin, self).queryset(request)
630 if not request.user.is_admin:
631 valid_slices = []
632 roles = request.user.get_roles()
633 for tenant_list in roles.values():
634 valid_slices.extend(tenant_list)
635 qs = qs.filter(name__in=valid_slices)
636 return qs
637
Tony Mack79748612013-05-01 14:52:03 -0400638 def get_formsets(self, request, obj=None):
639 for inline in self.get_inline_instances(request, obj):
640 # hide MyInline in the add view
641 if obj is None:
642 continue
Tony Mack2bd5b412013-06-11 21:05:06 -0400643 if isinstance(inline, SliverInline):
644 inline.model.caller = request.user
Tony Mack79748612013-05-01 14:52:03 -0400645 yield inline.get_formset(request, obj)
646
Tony Mackfdd4d802013-04-27 13:02:33 -0400647 def get_queryset(self, request):
648 qs = super(SliceAdmin, self).get_queryset(request)
649 if request.user.is_superuser:
650 return qs
651 # users can only see slices at their site
Tony Mack2bd5b412013-06-11 21:05:06 -0400652 return qs.filter(site=request.user.site)
653
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400654class SlicePrivilegeAdmin(PlanetStackBaseAdmin):
Tony Mack00d361f2013-04-28 10:28:42 -0400655 fieldsets = [
656 (None, {'fields': ['user', 'slice', 'role']})
657 ]
658 list_display = ('user', 'slice', 'role')
Tony Mack00d361f2013-04-28 10:28:42 -0400659
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500660 user_readonly_fields = ['user', 'slice', 'role']
661 user_readonly_inlines = []
662
Tony Mackc2835a92013-05-28 09:18:49 -0400663 def formfield_for_foreignkey(self, db_field, request, **kwargs):
664 if db_field.name == 'slice':
665 if not request.user.is_admin:
666 # only show slices at sites where caller has admin or pi role
667 roles = Role.objects.filter(role_type__in=['admin', 'pi'])
668 site_privileges = SitePrivilege.objects.filter(user=request.user).filter(role__in=roles)
669 sites = [site_privilege.site for site_privilege in site_privileges]
670 slices = Slice.objects.filter(site__in=sites)
671 kwargs['queryset'] = slices
672
673 if db_field.name == 'user':
674 if not request.user.is_admin:
675 # only show users from sites where caller has admin or pi role
676 roles = Role.objects.filter(role_type__in=['admin', 'pi'])
677 site_privileges = SitePrivilege.objects.filter(user=request.user).filter(role__in=roles)
678 sites = [site_privilege.site for site_privilege in site_privileges]
679 site_privileges = SitePrivilege.objects.filter(site__in=sites)
680 emails = [site_privilege.user.email for site_privilege in site_privileges]
681 users = User.objects.filter(email__in=emails)
682 kwargs['queryset'] = users
683
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400684 return super(SlicePrivilegeAdmin, self).formfield_for_foreignkey(db_field, request, **kwargs)
Tony Mackc2835a92013-05-28 09:18:49 -0400685
Tony Mack04062832013-05-10 08:22:44 -0400686 def queryset(self, request):
687 # admins can see all memberships. Users can only see memberships of
688 # slices where they have the admin role.
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400689 qs = super(SlicePrivilegeAdmin, self).queryset(request)
Tony Mack04062832013-05-10 08:22:44 -0400690 if not request.user.is_admin:
Tony Mackc2835a92013-05-28 09:18:49 -0400691 roles = Role.objects.filter(role_type__in=['admin', 'pi'])
692 site_privileges = SitePrivilege.objects.filter(user=request.user).filter(role__in=roles)
693 login_bases = [site_privilege.site.login_base for site_privilege in site_privileges]
694 sites = Site.objects.filter(login_base__in=login_bases)
695 slices = Slice.objects.filter(site__in=sites)
696 qs = qs.filter(slice__in=slices)
Tony Mack04062832013-05-10 08:22:44 -0400697 return qs
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400698
Tony Mack9bcbe4f2013-04-29 08:13:27 -0400699 def save_model(self, request, obj, form, change):
Tony Mack951dab42013-05-02 19:51:45 -0400700 # update openstack connection to use this site/tenant
701 auth = request.session.get('auth', {})
702 auth['tenant'] = obj.slice.name
703 obj.os_manager = OpenStackManager(auth=auth, caller=request.user)
Tony Mack9bcbe4f2013-04-29 08:13:27 -0400704 obj.save()
705
706 def delete_model(self, request, obj):
Tony Mack951dab42013-05-02 19:51:45 -0400707 # update openstack connection to use this site/tenant
708 auth = request.session.get('auth', {})
709 auth['tenant'] = obj.slice.name
710 obj.os_manager = OpenStackManager(auth=auth, caller=request.user)
Tony Mack9bcbe4f2013-04-29 08:13:27 -0400711 obj.delete()
712
Siobhan Tully567e3e62013-06-21 18:03:16 -0400713
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400714class ImageAdmin(PlanetStackBaseAdmin):
715
716 fieldsets = [('Image Details',
717 {'fields': ['image_id', 'name', 'disk_format', 'container_format'],
718 'classes': ['suit-tab suit-tab-general']})
719 ]
720
721 suit_form_tabs =(('general','Image Details'),('slivers','Slivers'))
722
723 inlines = [SliverInline]
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500724
725 user_readonly_fields = ['image_id', 'name', 'disk_format', 'container_format']
726 user_readonly_inlines = [SliverROInline]
727
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400728class NodeForm(forms.ModelForm):
729 class Meta:
730 widgets = {
731 'site': LinkedSelect,
732 'deployment': LinkedSelect
733 }
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400734
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500735class NodeAdmin(PlanetStackBaseAdmin):
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400736 form = NodeForm
Siobhan Tullybf1153a2013-05-27 20:53:48 -0400737 list_display = ('name', 'site', 'deployment')
738 list_filter = ('deployment',)
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500739
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400740 inlines = [TagInline,SliverInline]
741 fieldsets = [('Node Details', {'fields': ['name','site','deployment'], 'classes':['suit-tab suit-tab-details']})]
742
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500743 user_readonly_fields = ['name','site','deployment']
744 user_readonly_inlines = [TagInline,SliverInline]
745
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400746 suit_form_tabs =(('details','Node Details'),('slivers','Slivers'),('tags','Tags'))
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400747
Siobhan Tully567e3e62013-06-21 18:03:16 -0400748
Tony Mackd90cdbf2013-04-16 22:48:40 -0400749class SliverForm(forms.ModelForm):
750 class Meta:
Tony Mack1d6b85f2013-05-07 18:49:14 -0400751 model = Sliver
Tony Mackd90cdbf2013-04-16 22:48:40 -0400752 ip = forms.CharField(widget=PlainTextWidget)
Tony Mack18261812013-05-02 16:39:20 -0400753 instance_name = forms.CharField(widget=PlainTextWidget)
Tony Mackd90cdbf2013-04-16 22:48:40 -0400754 widgets = {
755 'ip': PlainTextWidget(),
Tony Mack18261812013-05-02 16:39:20 -0400756 'instance_name': PlainTextWidget(),
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400757 'slice': LinkedSelect,
758 'deploymentNetwork': LinkedSelect,
759 'node': LinkedSelect,
760 'image': LinkedSelect
Siobhan Tully53437282013-04-26 19:30:27 -0400761 }
Tony Mackd90cdbf2013-04-16 22:48:40 -0400762
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500763class TagAdmin(PlanetStackBaseAdmin):
Siobhan Tullyce652d02013-10-08 21:52:35 -0400764 list_display = ['service', 'name', 'value', 'content_type', 'content_object',]
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500765 user_readonly_fields = ['service', 'name', 'value', 'content_type', 'content_object',]
766 user_readonly_inlines = []
Siobhan Tullyd3515752013-06-21 16:34:53 -0400767
Tony Mack9bcbe4f2013-04-29 08:13:27 -0400768class SliverAdmin(PlanetStackBaseAdmin):
Tony Mackd90cdbf2013-04-16 22:48:40 -0400769 form = SliverForm
Tony Mackcdec0902013-04-15 00:38:49 -0400770 fieldsets = [
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400771 ('Sliver Details', {'fields': ['slice', 'deploymentNetwork', 'node', 'ip', 'instance_name', 'numberCores', 'image', ], 'classes': ['suit-tab suit-tab-general'], })
Tony Mackcdec0902013-04-15 00:38:49 -0400772 ]
Siobhan Tully5d7dc8d2013-07-02 13:17:33 -0400773 list_display = ['ip', 'instance_name', 'slice', 'numberCores', 'image', 'node', 'deploymentNetwork']
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400774
775 suit_form_tabs =(('general', 'Sliver Details'),
776 ('tags','Tags'),
777 )
778
Siobhan Tullyde5450d2013-06-21 11:35:33 -0400779 inlines = [TagInline]
Tony Mack53106f32013-04-27 16:43:01 -0400780
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500781 user_readonly_fields = ['slice', 'deploymentNetwork', 'node', 'ip', 'instance_name', 'numberCores', 'image']
782 user_readonly_inlines = [TagROInline]
783
Tony Mackc2835a92013-05-28 09:18:49 -0400784 def formfield_for_foreignkey(self, db_field, request, **kwargs):
785 if db_field.name == 'slice':
786 if not request.user.is_admin:
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400787 slices = set([sm.slice.name for sm in SlicePrivilege.objects.filter(user=request.user)])
Tony Mackc2835a92013-05-28 09:18:49 -0400788 kwargs['queryset'] = Slice.objects.filter(name__in=list(slices))
789
790 return super(SliverAdmin, self).formfield_for_foreignkey(db_field, request, **kwargs)
791
Tony Mack04062832013-05-10 08:22:44 -0400792 def queryset(self, request):
793 # admins can see all slivers. Users can only see slivers of
794 # the slices they belong to.
795 qs = super(SliverAdmin, self).queryset(request)
796 if not request.user.is_admin:
797 tenants = []
798 roles = request.user.get_roles()
799 for tenant_list in roles.values():
800 tenants.extend(tenant_list)
801 valid_slices = Slice.objects.filter(name__in=tenants)
802 qs = qs.filter(slice__in=valid_slices)
803 return qs
804
Tony Mack1d6b85f2013-05-07 18:49:14 -0400805 def get_formsets(self, request, obj=None):
806 # make some fields read only if we are updating an existing record
807 if obj == None:
808 #self.readonly_fields = ('ip', 'instance_name')
809 self.readonly_fields = ()
810 else:
Tony Mack1e889462013-05-10 21:34:54 -0400811 self.readonly_fields = ()
812 #self.readonly_fields = ('ip', 'instance_name', 'slice', 'image', 'key')
Tony Mack1d6b85f2013-05-07 18:49:14 -0400813
814 for inline in self.get_inline_instances(request, obj):
815 # hide MyInline in the add view
816 if obj is None:
817 continue
818 # give inline object access to driver and caller
819 auth = request.session.get('auth', {})
820 auth['tenant'] = obj.name # meed to connect using slice's tenant
821 inline.model.os_manager = OpenStackManager(auth=auth, caller=request.user)
822 yield inline.get_formset(request, obj)
Tony Mack53106f32013-04-27 16:43:01 -0400823
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500824 #def save_model(self, request, obj, form, change):
825 # # update openstack connection to use this site/tenant
826 # auth = request.session.get('auth', {})
827 # auth['tenant'] = obj.slice.name
828 # obj.os_manager = OpenStackManager(auth=auth, caller=request.user)
829 # obj.creator = request.user
830 # obj.save()
Tony Mack53106f32013-04-27 16:43:01 -0400831
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500832 #def delete_model(self, request, obj):
833 # # update openstack connection to use this site/tenant
834 # auth = request.session.get('auth', {})
835 # auth['tenant'] = obj.slice.name
836 # obj.os_manager = OpenStackManager(auth=auth, caller=request.user)
837 # obj.delete()
Tony Mackcdec0902013-04-15 00:38:49 -0400838
Siobhan Tully53437282013-04-26 19:30:27 -0400839class UserCreationForm(forms.ModelForm):
840 """A form for creating new users. Includes all the required
841 fields, plus a repeated password."""
842 password1 = forms.CharField(label='Password', widget=forms.PasswordInput)
843 password2 = forms.CharField(label='Password confirmation', widget=forms.PasswordInput)
844
845 class Meta:
Siobhan Tully30fd4292013-05-10 08:59:56 -0400846 model = User
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400847 fields = ('email', 'firstname', 'lastname', 'phone', 'public_key')
Siobhan Tully53437282013-04-26 19:30:27 -0400848
849 def clean_password2(self):
850 # Check that the two password entries match
851 password1 = self.cleaned_data.get("password1")
852 password2 = self.cleaned_data.get("password2")
853 if password1 and password2 and password1 != password2:
854 raise forms.ValidationError("Passwords don't match")
855 return password2
856
857 def save(self, commit=True):
858 # Save the provided password in hashed format
859 user = super(UserCreationForm, self).save(commit=False)
Tony Mackf9f4afb2013-05-01 21:02:12 -0400860 user.password = self.cleaned_data["password1"]
861 #user.set_password(self.cleaned_data["password1"])
Siobhan Tully53437282013-04-26 19:30:27 -0400862 if commit:
863 user.save()
864 return user
865
Siobhan Tully567e3e62013-06-21 18:03:16 -0400866
Siobhan Tully53437282013-04-26 19:30:27 -0400867class UserChangeForm(forms.ModelForm):
868 """A form for updating users. Includes all the fields on
869 the user, but replaces the password field with admin's
870 password hash display field.
871 """
Siobhan Tully63b7ba42014-01-12 10:35:11 -0500872 password = ReadOnlyPasswordHashField(label='Password',
873 help_text= '<a href=\"password/\">Change Password</a>.')
Siobhan Tully53437282013-04-26 19:30:27 -0400874
875 class Meta:
Siobhan Tully30fd4292013-05-10 08:59:56 -0400876 model = User
Siobhan Tully53437282013-04-26 19:30:27 -0400877
878 def clean_password(self):
879 # Regardless of what the user provides, return the initial value.
880 # This is done here, rather than on the field, because the
881 # field does not have access to the initial value
882 return self.initial["password"]
883
Tony Mack2bd5b412013-06-11 21:05:06 -0400884class UserAdmin(UserAdmin):
Siobhan Tully53437282013-04-26 19:30:27 -0400885 class Meta:
886 app_label = "core"
887
888 # The forms to add and change user instances
889 form = UserChangeForm
890 add_form = UserCreationForm
891
892 # The fields to be used in displaying the User model.
893 # These override the definitions on the base UserAdmin
894 # that reference specific fields on auth.User.
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500895 list_display = ('email', 'firstname', 'lastname', 'site', 'last_login')
Siobhan Tullyce652d02013-10-08 21:52:35 -0400896 #list_display = ('email', 'username','firstname', 'lastname', 'is_admin', 'last_login')
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500897 list_filter = ('site',)
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400898 inlines = [SlicePrivilegeInline,SitePrivilegeInline,DeploymentPrivilegeInline]
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500899
900 fieldListLoginDetails = ['email','site','password','is_readonly','is_amin','public_key']
901 fieldListContactInfo = ['firstname','lastname','phone','timezone']
902
Siobhan Tully53437282013-04-26 19:30:27 -0400903 fieldsets = (
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500904 ('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 -0400905 ('Contact Information', {'fields': ('firstname','lastname','phone', 'timezone'), 'classes':['suit-tab suit-tab-contact']}),
Siobhan Tully53437282013-04-26 19:30:27 -0400906 #('Important dates', {'fields': ('last_login',)}),
907 )
908 add_fieldsets = (
909 (None, {
910 'classes': ('wide',),
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500911 'fields': ('email', 'firstname', 'lastname', 'is_readonly', 'phone', 'public_key','password1', 'password2')}
Siobhan Tully53437282013-04-26 19:30:27 -0400912 ),
913 )
914 search_fields = ('email',)
915 ordering = ('email',)
916 filter_horizontal = ()
917
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500918 user_readonly_fields = fieldListLoginDetails
919 user_readonly_inlines = [SlicePrivilegeROInline,SitePrivilegeROInline,DeploymentPrivilegeROInline]
920
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400921 suit_form_tabs =(('general','Login Details'),('contact','Contact Information'),('sliceprivileges','Slice Privileges'),('siteprivileges','Site Privileges'),('deploymentprivileges','Deployment Privileges'))
922
Tony Mackc2835a92013-05-28 09:18:49 -0400923 def formfield_for_foreignkey(self, db_field, request, **kwargs):
924 if db_field.name == 'site':
925 if not request.user.is_admin:
926 # show sites where caller is an admin or pi
927 sites = []
928 for site_privilege in SitePrivilege.objects.filer(user=request.user):
929 if site_privilege.role.role_type in ['admin', 'pi']:
930 sites.append(site_privilege.site.login_base)
931 kwargs['queryset'] = Site.objects.filter(login_base__in(list(sites)))
932
933 return super(UserAdmin, self).formfield_for_foreignkey(db_field, request, **kwargs)
934
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500935 def has_add_permission(self, request, obj=None):
936 return (not self.__user_is_readonly(request))
937
938 def has_delete_permission(self, request, obj=None):
939 return (not self.__user_is_readonly(request))
940
941 def get_actions(self,request):
942 actions = super(UserAdmin,self).get_actions(request)
943
944 if self.__user_is_readonly(request):
945 if 'delete_selected' in actions:
946 del actions['delete_selected']
947
948 return actions
949
950 def change_view(self,request,object_id, extra_context=None):
951
952 if self.__user_is_readonly(request):
953 self.readonly_fields=self.user_readonly_fields
954 self.inlines = self.user_readonly_inlines
955 try:
956 return super(UserAdmin, self).change_view(request, object_id, extra_context=extra_context)
957 except PermissionDenied:
958 pass
959 if request.method == 'POST':
960 raise PermissionDenied
961 request.readonly = True
962 return super(UserAdmin, self).change_view(request, object_id, extra_context=extra_context)
963
964 def __user_is_readonly(self, request):
965 #groups = [x.name for x in request.user.groups.all() ]
966 #return "readonly" in groups
967 return request.user.isReadOnlyUser()
968
969
970
971class ServiceResourceROInline(ReadOnlyTabularInline):
972 model = ServiceResource
973 extra = 0
974 fields = ['serviceClass', 'name', 'maxUnitsDeployment', 'maxUnitsNode', 'maxDuration', 'bucketInRate', 'bucketMaxSize', 'cost', 'calendarReservable']
975
Scott Baker0165fac2014-01-13 11:49:26 -0800976class ServiceResourceInline(PlStackTabularInline):
Scott Baker3de3e372013-05-10 16:50:44 -0700977 model = ServiceResource
978 extra = 0
979
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500980class ServiceClassAdmin(PlanetStackBaseAdmin):
Scott Baker3de3e372013-05-10 16:50:44 -0700981 list_display = ('name', 'commitment', 'membershipFee')
982 inlines = [ServiceResourceInline]
983
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500984 user_readonly_fields = ['name', 'commitment', 'membershipFee']
985 user_readonly_inlines = []
986
987class ReservedResourceROInline(ReadOnlyTabularInline):
988 model = ReservedResource
989 extra = 0
990 fields = ['sliver', 'resource','quantity','reservationSet']
991 suit_classes = 'suit-tab suit-tab-reservedresources'
992
Scott Baker0165fac2014-01-13 11:49:26 -0800993class ReservedResourceInline(PlStackTabularInline):
Scott Baker133c9212013-05-17 09:09:11 -0700994 model = ReservedResource
995 extra = 0
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400996 suit_classes = 'suit-tab suit-tab-reservedresources'
Scott Baker133c9212013-05-17 09:09:11 -0700997
998 def formfield_for_foreignkey(self, db_field, request=None, **kwargs):
999 field = super(ReservedResourceInline, self).formfield_for_foreignkey(db_field, request, **kwargs)
1000
1001 if db_field.name == 'resource':
1002 # restrict resources to those that the slice's service class allows
1003 if request._slice is not None:
1004 field.queryset = field.queryset.filter(serviceClass = request._slice.serviceClass, calendarReservable=True)
1005 if len(field.queryset) > 0:
1006 field.initial = field.queryset.all()[0]
1007 else:
1008 field.queryset = field.queryset.none()
1009 elif db_field.name == 'sliver':
1010 # restrict slivers to those that belong to the slice
1011 if request._slice is not None:
1012 field.queryset = field.queryset.filter(slice = request._slice)
1013 else:
1014 field.queryset = field.queryset.none()
1015
1016 return field
1017
1018class ReservationChangeForm(forms.ModelForm):
1019 class Meta:
1020 model = Reservation
Siobhan Tullybfd11dc2013-09-03 12:59:24 -04001021 widgets = {
1022 'slice' : LinkedSelect
1023 }
Scott Baker133c9212013-05-17 09:09:11 -07001024
1025class ReservationAddForm(forms.ModelForm):
1026 slice = forms.ModelChoiceField(queryset=Slice.objects.all(), widget=forms.Select(attrs={"onChange":"document.getElementById('id_refresh').value=1; submit()"}))
1027 refresh = forms.CharField(widget=forms.HiddenInput())
1028
1029 class Media:
1030 css = {'all': ('planetstack.css',)} # .field-refresh { display: none; }
1031
1032 def clean_slice(self):
1033 slice = self.cleaned_data.get("slice")
1034 x = ServiceResource.objects.filter(serviceClass = slice.serviceClass, calendarReservable=True)
1035 if len(x) == 0:
1036 raise forms.ValidationError("The slice you selected does not have a service class that allows reservations")
1037 return slice
1038
1039 class Meta:
1040 model = Reservation
Siobhan Tullybfd11dc2013-09-03 12:59:24 -04001041 widgets = {
1042 'slice' : LinkedSelect
1043 }
1044
Scott Baker133c9212013-05-17 09:09:11 -07001045
1046class ReservationAddRefreshForm(ReservationAddForm):
1047 """ This form is displayed when the Reservation Form receives an update
1048 from the Slice dropdown onChange handler. It doesn't validate the
1049 data and doesn't save the data. This will cause the form to be
1050 redrawn.
1051 """
1052
Scott Baker8737e5f2013-05-17 09:35:32 -07001053 """ don't validate anything other than slice """
1054 dont_validate_fields = ("startTime", "duration")
1055
Scott Baker133c9212013-05-17 09:09:11 -07001056 def full_clean(self):
1057 result = super(ReservationAddForm, self).full_clean()
Scott Baker8737e5f2013-05-17 09:35:32 -07001058
1059 for fieldname in self.dont_validate_fields:
1060 if fieldname in self._errors:
1061 del self._errors[fieldname]
1062
Scott Baker133c9212013-05-17 09:09:11 -07001063 return result
1064
1065 """ don't save anything """
1066 def is_valid(self):
1067 return False
1068
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001069class ReservationAdmin(PlanetStackBaseAdmin):
1070 fieldList = ['slice', 'startTime', 'duration']
1071 fieldsets = [('Reservation Details', {'fields': fieldList, 'classes': ['suit-tab suit-tab-general']})]
Scott Baker133c9212013-05-17 09:09:11 -07001072 list_display = ('startTime', 'duration')
Scott Baker133c9212013-05-17 09:09:11 -07001073 form = ReservationAddForm
1074
Siobhan Tullybfd11dc2013-09-03 12:59:24 -04001075 suit_form_tabs = (('general','Reservation Details'), ('reservedresources','Reserved Resources'))
1076
1077 inlines = [ReservedResourceInline]
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001078 user_readonly_inlines = [ReservedResourceROInline]
1079 user_readonly_fields = fieldList
Siobhan Tullybfd11dc2013-09-03 12:59:24 -04001080
Scott Baker133c9212013-05-17 09:09:11 -07001081 def add_view(self, request, form_url='', extra_context=None):
Scott Bakeracd45142013-05-19 16:19:16 -07001082 timezone.activate(request.user.timezone)
Scott Baker133c9212013-05-17 09:09:11 -07001083 request._refresh = False
1084 request._slice = None
1085 if request.method == 'POST':
Scott Baker8737e5f2013-05-17 09:35:32 -07001086 # "refresh" will be set to "1" if the form was submitted due to
1087 # a change in the Slice dropdown.
Scott Baker133c9212013-05-17 09:09:11 -07001088 if request.POST.get("refresh","1") == "1":
1089 request._refresh = True
1090 request.POST["refresh"] = "0"
Scott Baker8737e5f2013-05-17 09:35:32 -07001091
1092 # Keep track of the slice that was selected, so the
1093 # reservedResource inline can filter items for the slice.
Scott Baker133c9212013-05-17 09:09:11 -07001094 request._slice = request.POST.get("slice",None)
1095 if (request._slice is not None):
1096 request._slice = Slice.objects.get(id=request._slice)
1097
1098 result = super(ReservationAdmin, self).add_view(request, form_url, extra_context)
1099 return result
1100
Scott Bakeracd45142013-05-19 16:19:16 -07001101 def changelist_view(self, request, extra_context = None):
1102 timezone.activate(request.user.timezone)
1103 return super(ReservationAdmin, self).changelist_view(request, extra_context)
1104
Scott Baker133c9212013-05-17 09:09:11 -07001105 def get_form(self, request, obj=None, **kwargs):
Siobhan Tullyd3515752013-06-21 16:34:53 -04001106 request._obj_ = obj
1107 if obj is not None:
1108 # For changes, set request._slice to the slice already set in the
1109 # object.
1110 request._slice = obj.slice
1111 self.form = ReservationChangeForm
1112 else:
1113 if getattr(request, "_refresh", False):
1114 self.form = ReservationAddRefreshForm
1115 else:
1116 self.form = ReservationAddForm
1117 return super(ReservationAdmin, self).get_form(request, obj, **kwargs)
1118
Scott Baker133c9212013-05-17 09:09:11 -07001119 def get_readonly_fields(self, request, obj=None):
Siobhan Tullyd3515752013-06-21 16:34:53 -04001120 if (obj is not None):
1121 # Prevent slice from being changed after the reservation has been
1122 # created.
1123 return ['slice']
1124 else:
Scott Baker133c9212013-05-17 09:09:11 -07001125 return []
Scott Baker3de3e372013-05-10 16:50:44 -07001126
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001127class NetworkParameterTypeAdmin(PlanetStackBaseAdmin):
Scott Baker74d8e622013-07-29 16:04:22 -07001128 list_display = ("name", )
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001129 user_readonly_fields = ['name']
1130 user_readonly_inlines = []
Scott Baker74d8e622013-07-29 16:04:22 -07001131
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001132class RouterAdmin(PlanetStackBaseAdmin):
Scott Baker74d8e622013-07-29 16:04:22 -07001133 list_display = ("name", )
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001134 user_readonly_fields = ['name']
1135 user_readonly_inlines = []
1136
1137class RouterROInline(ReadOnlyTabularInline):
1138 model = Router.networks.through
1139 extra = 0
1140 verbose_name_plural = "Routers"
1141 verbose_name = "Router"
1142 suit_classes = 'suit-tab suit-tab-routers'
1143
1144 fields = ['name', 'owner', 'permittedNetworks', 'networks']
Scott Baker74d8e622013-07-29 16:04:22 -07001145
Scott Baker0165fac2014-01-13 11:49:26 -08001146class RouterInline(PlStackTabularInline):
Scott Baker74d8e622013-07-29 16:04:22 -07001147 model = Router.networks.through
1148 extra = 0
1149 verbose_name_plural = "Routers"
1150 verbose_name = "Router"
Siobhan Tully2d95e482013-09-06 10:56:06 -04001151 suit_classes = 'suit-tab suit-tab-routers'
Scott Baker74d8e622013-07-29 16:04:22 -07001152
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001153class NetworkParameterROInline(ReadOnlyTabularInline):
1154 model = NetworkParameter
1155 extra = 1
1156 verbose_name_plural = "Parameters"
1157 verbose_name = "Parameter"
1158 suit_classes = 'suit-tab suit-tab-netparams'
1159 fields = ['parameter', 'value', 'content_type', 'object_id', 'content_object']
1160
Scott Baker74d8e622013-07-29 16:04:22 -07001161class NetworkParameterInline(generic.GenericTabularInline):
Scott Baker74d8e622013-07-29 16:04:22 -07001162 model = NetworkParameter
1163 extra = 1
1164 verbose_name_plural = "Parameters"
1165 verbose_name = "Parameter"
Siobhan Tully2d95e482013-09-06 10:56:06 -04001166 suit_classes = 'suit-tab suit-tab-netparams'
Scott Baker74d8e622013-07-29 16:04:22 -07001167
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001168class NetworkSliversROInline(ReadOnlyTabularInline):
1169 fields = ['network', 'sliver', 'ip', 'port_id']
1170 model = NetworkSliver
1171 extra = 0
1172 verbose_name_plural = "Slivers"
1173 verbose_name = "Sliver"
1174 suit_classes = 'suit-tab suit-tab-networkslivers'
1175
Scott Baker0165fac2014-01-13 11:49:26 -08001176class NetworkSliversInline(PlStackTabularInline):
Scott Baker74d8e622013-07-29 16:04:22 -07001177 readonly_fields = ("ip", )
1178 model = NetworkSliver
Scott Baker874936e2014-01-13 18:15:34 -08001179 selflink_fieldname = "sliver"
Scott Baker74d8e622013-07-29 16:04:22 -07001180 extra = 0
1181 verbose_name_plural = "Slivers"
1182 verbose_name = "Sliver"
Siobhan Tully2d95e482013-09-06 10:56:06 -04001183 suit_classes = 'suit-tab suit-tab-networkslivers'
Scott Baker74d8e622013-07-29 16:04:22 -07001184
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001185class NetworkSlicesROInline(ReadOnlyTabularInline):
1186 model = NetworkSlice
1187 extra = 0
1188 verbose_name_plural = "Slices"
1189 verbose_name = "Slice"
1190 suit_classes = 'suit-tab suit-tab-networkslices'
1191 fields = ['network','slice']
1192
Scott Baker0165fac2014-01-13 11:49:26 -08001193class NetworkSlicesInline(PlStackTabularInline):
Scott Bakerd7d2a392013-08-06 08:57:30 -07001194 model = NetworkSlice
Scott Baker874936e2014-01-13 18:15:34 -08001195 selflink_fieldname = "slice"
Scott Bakerd7d2a392013-08-06 08:57:30 -07001196 extra = 0
1197 verbose_name_plural = "Slices"
1198 verbose_name = "Slice"
Siobhan Tully2d95e482013-09-06 10:56:06 -04001199 suit_classes = 'suit-tab suit-tab-networkslices'
Scott Bakerd7d2a392013-08-06 08:57:30 -07001200
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001201class NetworkAdmin(PlanetStackBaseAdmin):
Scott Baker74d8e622013-07-29 16:04:22 -07001202 list_display = ("name", "subnet", "ports", "labels")
1203 readonly_fields = ("subnet", )
Siobhan Tully2d95e482013-09-06 10:56:06 -04001204
Scott Bakerd7d2a392013-08-06 08:57:30 -07001205 inlines = [NetworkParameterInline, NetworkSliversInline, NetworkSlicesInline, RouterInline]
Scott Baker74d8e622013-07-29 16:04:22 -07001206
Siobhan Tully2d95e482013-09-06 10:56:06 -04001207 fieldsets = [
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001208 (None, {'fields': ['name','template','ports','labels','owner','guaranteedBandwidth', 'permitAllSlices','permittedSlices','network_id','router_id','subnet_id','subnet'], 'classes':['suit-tab suit-tab-general']}),]
1209
1210 user_readonly_fields = ['name','template','ports','labels','owner','guaranteedBandwidth', 'permitAllSlices','permittedSlices','network_id','router_id','subnet_id','subnet']
1211 user_readonly_inlines = [NetworkParameterROInline, NetworkSliversROInline, NetworkSlicesROInline, RouterROInline]
Siobhan Tully2d95e482013-09-06 10:56:06 -04001212
1213 suit_form_tabs =(
1214 ('general','Network Details'),
1215 ('netparams', 'Parameters'),
1216 ('networkslivers','Slivers'),
1217 ('networkslices','Slices'),
1218 ('routers','Routers'),
1219 )
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001220class NetworkTemplateAdmin(PlanetStackBaseAdmin):
Scott Baker74d8e622013-07-29 16:04:22 -07001221 list_display = ("name", "guaranteedBandwidth", "visibility")
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001222 user_readonly_fields = ["name", "guaranteedBandwidth", "visibility"]
1223 user_readonly_inlines = []
Scott Baker74d8e622013-07-29 16:04:22 -07001224
Tony Mack31c2b8f2013-04-26 20:01:42 -04001225# register a signal that caches the user's credentials when they log in
1226def cache_credentials(sender, user, request, **kwds):
1227 auth = {'username': request.POST['username'],
1228 'password': request.POST['password']}
1229 request.session['auth'] = auth
1230user_logged_in.connect(cache_credentials)
1231
Scott Baker15cddfa2013-12-09 13:45:19 -08001232def dollar_field(fieldName, short_description):
1233 def newFunc(self, obj):
1234 try:
1235 x= "$ %0.2f" % float(getattr(obj, fieldName, 0.0))
1236 except:
1237 x=getattr(obj, fieldName, 0.0)
1238 return x
1239 newFunc.short_description = short_description
1240 return newFunc
1241
1242def right_dollar_field(fieldName, short_description):
1243 def newFunc(self, obj):
1244 try:
1245 #x= '<div align=right style="width:6em">$ %0.2f</div>' % float(getattr(obj, fieldName, 0.0))
1246 x= '<div align=right>$ %0.2f</div>' % float(getattr(obj, fieldName, 0.0))
1247 except:
1248 x=getattr(obj, fieldName, 0.0)
1249 return x
1250 newFunc.short_description = short_description
1251 newFunc.allow_tags = True
1252 return newFunc
Scott Baker43105042013-12-06 23:23:36 -08001253
Scott Baker0165fac2014-01-13 11:49:26 -08001254class InvoiceChargeInline(PlStackTabularInline):
Scott Baker43105042013-12-06 23:23:36 -08001255 model = Charge
Scott Baker15cddfa2013-12-09 13:45:19 -08001256 extra = 0
Scott Baker43105042013-12-06 23:23:36 -08001257 verbose_name_plural = "Charges"
1258 verbose_name = "Charge"
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001259 exclude = ['account']
Scott Baker9cb88a22013-12-09 18:56:00 -08001260 fields = ["date", "kind", "state", "object", "coreHours", "dollar_amount", "slice"]
1261 readonly_fields = ["date", "kind", "state", "object", "coreHours", "dollar_amount", "slice"]
1262 can_delete = False
1263 max_num = 0
1264
1265 dollar_amount = right_dollar_field("amount", "Amount")
Scott Baker43105042013-12-06 23:23:36 -08001266
1267class InvoiceAdmin(admin.ModelAdmin):
1268 list_display = ("date", "account")
1269
1270 inlines = [InvoiceChargeInline]
1271
Scott Baker9cb88a22013-12-09 18:56:00 -08001272 fields = ["date", "account", "dollar_amount"]
1273 readonly_fields = ["date", "account", "dollar_amount"]
1274
1275 dollar_amount = dollar_field("amount", "Amount")
Scott Baker43105042013-12-06 23:23:36 -08001276
Scott Baker0165fac2014-01-13 11:49:26 -08001277class InvoiceInline(PlStackTabularInline):
Scott Baker15cddfa2013-12-09 13:45:19 -08001278 model = Invoice
1279 extra = 0
1280 verbose_name_plural = "Invoices"
1281 verbose_name = "Invoice"
Scott Baker0165fac2014-01-13 11:49:26 -08001282 fields = ["date", "dollar_amount"]
1283 readonly_fields = ["date", "dollar_amount"]
Scott Baker15cddfa2013-12-09 13:45:19 -08001284 suit_classes = 'suit-tab suit-tab-accountinvoice'
1285 can_delete=False
1286 max_num=0
1287
1288 dollar_amount = right_dollar_field("amount", "Amount")
1289
Scott Baker0165fac2014-01-13 11:49:26 -08001290class PendingChargeInline(PlStackTabularInline):
Scott Baker43105042013-12-06 23:23:36 -08001291 model = Charge
Scott Baker15cddfa2013-12-09 13:45:19 -08001292 extra = 0
Scott Baker43105042013-12-06 23:23:36 -08001293 verbose_name_plural = "Charges"
1294 verbose_name = "Charge"
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001295 exclude = ["invoice"]
Scott Baker15cddfa2013-12-09 13:45:19 -08001296 fields = ["date", "kind", "state", "object", "coreHours", "dollar_amount", "slice"]
1297 readonly_fields = ["date", "kind", "state", "object", "coreHours", "dollar_amount", "slice"]
Scott Baker43105042013-12-06 23:23:36 -08001298 suit_classes = 'suit-tab suit-tab-accountpendingcharges'
Scott Baker15cddfa2013-12-09 13:45:19 -08001299 can_delete=False
1300 max_num=0
Scott Baker43105042013-12-06 23:23:36 -08001301
1302 def queryset(self, request):
1303 qs = super(PendingChargeInline, self).queryset(request)
1304 qs = qs.filter(state="pending")
1305 return qs
1306
Scott Baker15cddfa2013-12-09 13:45:19 -08001307 dollar_amount = right_dollar_field("amount", "Amount")
1308
Scott Baker0165fac2014-01-13 11:49:26 -08001309class PaymentInline(PlStackTabularInline):
Scott Baker43105042013-12-06 23:23:36 -08001310 model=Payment
1311 extra = 1
1312 verbose_name_plural = "Payments"
1313 verbose_name = "Payment"
Scott Baker15cddfa2013-12-09 13:45:19 -08001314 fields = ["date", "dollar_amount"]
1315 readonly_fields = ["date", "dollar_amount"]
Scott Baker43105042013-12-06 23:23:36 -08001316 suit_classes = 'suit-tab suit-tab-accountpayments'
Scott Baker15cddfa2013-12-09 13:45:19 -08001317 can_delete=False
1318 max_num=0
1319
1320 dollar_amount = right_dollar_field("amount", "Amount")
1321
Scott Baker43105042013-12-06 23:23:36 -08001322class AccountAdmin(admin.ModelAdmin):
1323 list_display = ("site", "balance_due")
1324
1325 inlines = [InvoiceInline, PaymentInline, PendingChargeInline]
1326
1327 fieldsets = [
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001328 (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 -08001329
Scott Baker15cddfa2013-12-09 13:45:19 -08001330 readonly_fields = ['site', 'dollar_balance_due', 'dollar_total_invoices', 'dollar_total_payments']
Scott Baker43105042013-12-06 23:23:36 -08001331
1332 suit_form_tabs =(
1333 ('general','Account Details'),
1334 ('accountinvoice', 'Invoices'),
1335 ('accountpayments', 'Payments'),
1336 ('accountpendingcharges','Pending Charges'),
1337 )
1338
Scott Baker15cddfa2013-12-09 13:45:19 -08001339 dollar_balance_due = dollar_field("balance_due", "Balance Due")
1340 dollar_total_invoices = dollar_field("total_invoices", "Total Invoices")
1341 dollar_total_payments = dollar_field("total_payments", "Total Payments")
1342
Siobhan Tullyce652d02013-10-08 21:52:35 -04001343
Siobhan Tully53437282013-04-26 19:30:27 -04001344# Now register the new UserAdmin...
Siobhan Tully30fd4292013-05-10 08:59:56 -04001345admin.site.register(User, UserAdmin)
Siobhan Tully53437282013-04-26 19:30:27 -04001346# ... and, since we're not using Django's builtin permissions,
1347# unregister the Group model from admin.
Siobhan Tullyce652d02013-10-08 21:52:35 -04001348#admin.site.unregister(Group)
Siobhan Tully53437282013-04-26 19:30:27 -04001349
Siobhan Tullybf1153a2013-05-27 20:53:48 -04001350#Do not show django evolution in the admin interface
1351from django_evolution.models import Version, Evolution
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001352#admin.site.unregister(Version)
1353#admin.site.unregister(Evolution)
Siobhan Tullybf1153a2013-05-27 20:53:48 -04001354
1355
1356# When debugging it is often easier to see all the classes, but for regular use
1357# only the top-levels should be displayed
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001358showAll = False
Scott Baker43105042013-12-06 23:23:36 -08001359
Siobhan Tullybf1153a2013-05-27 20:53:48 -04001360admin.site.register(Deployment, DeploymentAdmin)
Siobhan Tully4bc09f22013-04-10 21:15:21 -04001361admin.site.register(Site, SiteAdmin)
Siobhan Tully4bc09f22013-04-10 21:15:21 -04001362admin.site.register(Slice, SliceAdmin)
Siobhan Tullyce652d02013-10-08 21:52:35 -04001363admin.site.register(Service, ServiceAdmin)
smbakera3cf70c2013-06-27 02:01:41 -07001364admin.site.register(Reservation, ReservationAdmin)
Scott Baker74d8e622013-07-29 16:04:22 -07001365admin.site.register(Network, NetworkAdmin)
1366admin.site.register(Router, RouterAdmin)
Scott Baker74d8e622013-07-29 16:04:22 -07001367admin.site.register(NetworkTemplate, NetworkTemplateAdmin)
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001368admin.site.register(Account, AccountAdmin)
1369admin.site.register(Invoice, InvoiceAdmin)
Siobhan Tullybf1153a2013-05-27 20:53:48 -04001370
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001371if True:
1372 admin.site.register(NetworkParameterType, NetworkParameterTypeAdmin)
1373 admin.site.register(ServiceClass, ServiceClassAdmin)
Siobhan Tullybfd11dc2013-09-03 12:59:24 -04001374 #admin.site.register(PlanetStack)
Siobhan Tullyd3515752013-06-21 16:34:53 -04001375 admin.site.register(Tag, TagAdmin)
Siobhan Tullyce652d02013-10-08 21:52:35 -04001376 admin.site.register(DeploymentRole)
1377 admin.site.register(SiteRole)
1378 admin.site.register(SliceRole)
1379 admin.site.register(PlanetStackRole)
Siobhan Tullybf1153a2013-05-27 20:53:48 -04001380 admin.site.register(Node, NodeAdmin)
Siobhan Tullybfd11dc2013-09-03 12:59:24 -04001381 #admin.site.register(SlicePrivilege, SlicePrivilegeAdmin)
1382 #admin.site.register(SitePrivilege, SitePrivilegeAdmin)
Siobhan Tullybf1153a2013-05-27 20:53:48 -04001383 admin.site.register(Sliver, SliverAdmin)
Siobhan Tullybf1153a2013-05-27 20:53:48 -04001384 admin.site.register(Image, ImageAdmin)
Tony Mack7130ac32013-03-22 21:58:00 -04001385