blob: d11c8947fedcb58d7d1c65c53d2fbf82ab11db80 [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 Tullycf04fb62014-01-11 11:25:57 -0500420class SiteAssocInline(PlStackTabularInline):
421 model = Site.deployments.through
422 extra = 0
423 suit_classes = 'suit-tab suit-tab-sites'
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400424
Siobhan Tullybf1153a2013-05-27 20:53:48 -0400425class DeploymentAdmin(PlanetStackBaseAdmin):
426 form = DeploymentAdminForm
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500427 model = Deployment
428 fieldList = ['name','sites']
429 fieldsets = [(None, {'fields': fieldList, 'classes':['suit-tab suit-tab-sites']})]
Siobhan Tully2d95e482013-09-06 10:56:06 -0400430 inlines = [DeploymentPrivilegeInline,NodeInline,TagInline]
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500431
432 user_readonly_inlines = [DeploymentPrivilegeROInline,NodeROInline,TagROInline]
433 user_readonly_fields = ['name']
434
435 suit_form_tabs =(('sites','Deployment Details'),('nodes','Nodes'),('deploymentprivileges','Privileges'),('tags','Tags'))
436
437class ServiceAttrAsTabROInline(ReadOnlyTabularInline):
438 model = ServiceAttribute
439 fields = ['name','value']
440 extra = 0
441 suit_classes = 'suit-tab suit-tab-serviceattrs'
Tony Mack5cd13202013-05-01 21:48:38 -0400442
Siobhan Tullyce652d02013-10-08 21:52:35 -0400443class ServiceAttrAsTabInline(PlStackTabularInline):
444 model = ServiceAttribute
445 fields = ['name','value']
446 extra = 0
447 suit_classes = 'suit-tab suit-tab-serviceattrs'
448
Siobhan Tullyce652d02013-10-08 21:52:35 -0400449class ServiceAdmin(PlanetStackBaseAdmin):
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500450 list_display = ("name","description","versionNumber","enabled","published")
451 fieldList = ["name","description","versionNumber","enabled","published"]
452 fieldsets = [(None, {'fields': fieldList, 'classes':['suit-tab suit-tab-general']})]
453 inlines = [ServiceAttrAsTabInline,SliceInline]
454
455 user_readonly_fields = fieldList
456 user_readonly_inlines = [ServiceAttrAsTabROInline,SliceROInline]
457
458 suit_form_tabs =(('general', 'Service Details'),
459 ('slices','Slices'),
460 ('serviceattrs','Additional Attributes'),
461 )
Siobhan Tullyce652d02013-10-08 21:52:35 -0400462
Tony Mack0553f282013-06-10 22:54:50 -0400463class SiteAdmin(PlanetStackBaseAdmin):
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500464 fieldList = ['name', 'site_url', 'enabled', 'is_public', 'login_base', 'accountLink','location']
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400465 fieldsets = [
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500466 (None, {'fields': fieldList, 'classes':['suit-tab suit-tab-general']}),
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400467 ('Deployment Networks', {'fields': ['deployments'], 'classes':['suit-tab suit-tab-deployments']}),
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400468 ]
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400469 suit_form_tabs =(('general', 'Site Details'),
470 ('users','Users'),
Siobhan Tully2d95e482013-09-06 10:56:06 -0400471 ('siteprivileges','Privileges'),
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400472 ('deployments','Deployments'),
473 ('slices','Slices'),
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500474 ('nodes','Nodes'),
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400475 ('tags','Tags'),
476 )
Scott Baker545db2a2013-12-09 18:44:43 -0800477 readonly_fields = ['accountLink']
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500478
479 user_readonly_fields = ['name', 'deployments','site_url', 'enabled', 'is_public', 'login_base', 'accountLink']
480 user_readonly_inlines = [SliceROInline,UserROInline,TagROInline, NodeROInline, SitePrivilegeROInline]
481
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400482 list_display = ('name', 'login_base','site_url', 'enabled')
483 filter_horizontal = ('deployments',)
Siobhan Tully2d95e482013-09-06 10:56:06 -0400484 inlines = [SliceInline,UserInline,TagInline, NodeInline, SitePrivilegeInline]
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400485 search_fields = ['name']
486
Tony Mack04062832013-05-10 08:22:44 -0400487 def queryset(self, request):
488 # admins can see all keys. Users can only see sites they belong to.
489 qs = super(SiteAdmin, self).queryset(request)
490 if not request.user.is_admin:
491 valid_sites = [request.user.site.login_base]
492 roles = request.user.get_roles()
493 for tenant_list in roles.values():
494 valid_sites.extend(tenant_list)
495 qs = qs.filter(login_base__in=valid_sites)
496 return qs
497
Tony Mack5cd13202013-05-01 21:48:38 -0400498 def get_formsets(self, request, obj=None):
499 for inline in self.get_inline_instances(request, obj):
500 # hide MyInline in the add view
501 if obj is None:
502 continue
Tony Mack2bd5b412013-06-11 21:05:06 -0400503 if isinstance(inline, SliceInline):
504 inline.model.caller = request.user
505 yield inline.get_formset(request, obj)
506
507 def get_formsets(self, request, obj=None):
508 for inline in self.get_inline_instances(request, obj):
509 # hide MyInline in the add view
510 if obj is None:
511 continue
512 if isinstance(inline, SliverInline):
513 inline.model.caller = request.user
Tony Mack5cd13202013-05-01 21:48:38 -0400514 yield inline.get_formset(request, obj)
515
Scott Baker545db2a2013-12-09 18:44:43 -0800516 def accountLink(self, obj):
517 link_obj = obj.accounts.all()
518 if link_obj:
519 reverse_path = "admin:core_account_change"
520 url = reverse(reverse_path, args =(link_obj[0].id,))
521 return "<a href='%s'>%s</a>" % (url, "view billing details")
522 else:
523 return "no billing data for this site"
524 accountLink.allow_tags = True
525 accountLink.short_description = "Billing"
526
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500527
Tony Mack9bcbe4f2013-04-29 08:13:27 -0400528class SitePrivilegeAdmin(PlanetStackBaseAdmin):
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500529 fieldList = ['user', 'site', 'role']
Tony Mack00d361f2013-04-28 10:28:42 -0400530 fieldsets = [
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500531 (None, {'fields': fieldList, 'classes':['collapse']})
Tony Mack00d361f2013-04-28 10:28:42 -0400532 ]
533 list_display = ('user', 'site', 'role')
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500534 user_readonly_fields = fieldList
535 user_readonly_inlines = []
Tony Mack00d361f2013-04-28 10:28:42 -0400536
Tony Mackc2835a92013-05-28 09:18:49 -0400537 def formfield_for_foreignkey(self, db_field, request, **kwargs):
538 if db_field.name == 'site':
539 if not request.user.is_admin:
540 # only show sites where user is an admin or pi
541 sites = set()
542 for site_privilege in SitePrivilege.objects.filer(user=request.user):
543 if site_privilege.role.role_type in ['admin', 'pi']:
544 sites.add(site_privilege.site)
545 kwargs['queryset'] = Site.objects.filter(site__in=list(sites))
546
547 if db_field.name == 'user':
548 if not request.user.is_admin:
549 # only show users from sites where caller has admin or pi role
550 roles = Role.objects.filter(role_type__in=['admin', 'pi'])
551 site_privileges = SitePrivilege.objects.filter(user=request.user).filter(role__in=roles)
552 sites = [site_privilege.site for site_privilege in site_privileges]
553 site_privileges = SitePrivilege.objects.filter(site__in=sites)
554 emails = [site_privilege.user.email for site_privilege in site_privileges]
555 users = User.objects.filter(email__in=emails)
556 kwargs['queryset'] = users
557
558 return super(SitePrivilegeAdmin, self).formfield_for_foreignkey(db_field, request, **kwargs)
559
Tony Mack04062832013-05-10 08:22:44 -0400560 def queryset(self, request):
561 # admins can see all privileges. Users can only see privileges at sites
Tony Mackc2835a92013-05-28 09:18:49 -0400562 # where they have the admin role or pi role.
Tony Mack04062832013-05-10 08:22:44 -0400563 qs = super(SitePrivilegeAdmin, self).queryset(request)
564 if not request.user.is_admin:
Tony Mackc2835a92013-05-28 09:18:49 -0400565 roles = Role.objects.filter(role_type__in=['admin', 'pi'])
566 site_privileges = SitePrivilege.objects.filter(user=request.user).filter(role__in=roles)
567 login_bases = [site_privilege.site.login_base for site_privilege in site_privileges]
568 sites = Site.objects.filter(login_base__in=login_bases)
569 qs = qs.filter(site__in=sites)
Tony Mack04062832013-05-10 08:22:44 -0400570 return qs
571
Siobhan Tullyce652d02013-10-08 21:52:35 -0400572class SliceForm(forms.ModelForm):
573 class Meta:
574 model = Slice
575 widgets = {
576 'service': LinkedSelect
577 }
578
Tony Mack2bd5b412013-06-11 21:05:06 -0400579class SliceAdmin(PlanetStackBaseAdmin):
Siobhan Tullyce652d02013-10-08 21:52:35 -0400580 form = SliceForm
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500581 fieldList = ['name', 'site', 'serviceClass', 'enabled','description', 'service', 'slice_url']
582 fieldsets = [('Slice Details', {'fields': fieldList, 'classes':['suit-tab suit-tab-general']}),]
Siobhan Tully30fd4292013-05-10 08:59:56 -0400583 list_display = ('name', 'site','serviceClass', 'slice_url')
Siobhan Tully2d95e482013-09-06 10:56:06 -0400584 inlines = [SlicePrivilegeInline,SliverInline, TagInline, ReservationInline,SliceNetworkInline]
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400585
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500586 user_readonly_fields = fieldList
587 user_readonly_inlines = [SlicePrivilegeROInline,SliverROInline,TagROInline, ReservationROInline, SliceNetworkROInline]
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400588
589 suit_form_tabs =(('general', 'Slice Details'),
Siobhan Tully2d95e482013-09-06 10:56:06 -0400590 ('slicenetworks','Networks'),
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400591 ('sliceprivileges','Privileges'),
592 ('slivers','Slivers'),
593 ('tags','Tags'),
594 ('reservations','Reservations'),
595 )
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400596
Tony Mackc2835a92013-05-28 09:18:49 -0400597 def formfield_for_foreignkey(self, db_field, request, **kwargs):
598 if db_field.name == 'site':
599 if not request.user.is_admin:
600 # only show sites where user is a pi or admin
601 roles = Role.objects.filter(role_type__in=['admin', 'pi'])
602 site_privileges = SitePrivilege.objects.filter(user=request.user).filter(role__in=roles)
603 login_bases = [site_privilege.site.login_base for site_privilege in site_privileges]
604 sites = Site.objects.filter(login_base__in=login_bases)
605 kwargs['queryset'] = sites
606
607 return super(SliceAdmin, self).formfield_for_foreignkey(db_field, request, **kwargs)
608
Tony Mack04062832013-05-10 08:22:44 -0400609 def queryset(self, request):
610 # admins can see all keys. Users can only see slices they belong to.
611 qs = super(SliceAdmin, self).queryset(request)
612 if not request.user.is_admin:
613 valid_slices = []
614 roles = request.user.get_roles()
615 for tenant_list in roles.values():
616 valid_slices.extend(tenant_list)
617 qs = qs.filter(name__in=valid_slices)
618 return qs
619
Tony Mack79748612013-05-01 14:52:03 -0400620 def get_formsets(self, request, obj=None):
621 for inline in self.get_inline_instances(request, obj):
622 # hide MyInline in the add view
623 if obj is None:
624 continue
Tony Mack2bd5b412013-06-11 21:05:06 -0400625 if isinstance(inline, SliverInline):
626 inline.model.caller = request.user
Tony Mack79748612013-05-01 14:52:03 -0400627 yield inline.get_formset(request, obj)
628
Tony Mackfdd4d802013-04-27 13:02:33 -0400629 def get_queryset(self, request):
630 qs = super(SliceAdmin, self).get_queryset(request)
631 if request.user.is_superuser:
632 return qs
633 # users can only see slices at their site
Tony Mack2bd5b412013-06-11 21:05:06 -0400634 return qs.filter(site=request.user.site)
635
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400636class SlicePrivilegeAdmin(PlanetStackBaseAdmin):
Tony Mack00d361f2013-04-28 10:28:42 -0400637 fieldsets = [
638 (None, {'fields': ['user', 'slice', 'role']})
639 ]
640 list_display = ('user', 'slice', 'role')
Tony Mack00d361f2013-04-28 10:28:42 -0400641
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500642 user_readonly_fields = ['user', 'slice', 'role']
643 user_readonly_inlines = []
644
Tony Mackc2835a92013-05-28 09:18:49 -0400645 def formfield_for_foreignkey(self, db_field, request, **kwargs):
646 if db_field.name == 'slice':
647 if not request.user.is_admin:
648 # only show slices at sites where caller has admin or pi role
649 roles = Role.objects.filter(role_type__in=['admin', 'pi'])
650 site_privileges = SitePrivilege.objects.filter(user=request.user).filter(role__in=roles)
651 sites = [site_privilege.site for site_privilege in site_privileges]
652 slices = Slice.objects.filter(site__in=sites)
653 kwargs['queryset'] = slices
654
655 if db_field.name == 'user':
656 if not request.user.is_admin:
657 # only show users from sites where caller has admin or pi role
658 roles = Role.objects.filter(role_type__in=['admin', 'pi'])
659 site_privileges = SitePrivilege.objects.filter(user=request.user).filter(role__in=roles)
660 sites = [site_privilege.site for site_privilege in site_privileges]
661 site_privileges = SitePrivilege.objects.filter(site__in=sites)
662 emails = [site_privilege.user.email for site_privilege in site_privileges]
663 users = User.objects.filter(email__in=emails)
664 kwargs['queryset'] = users
665
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400666 return super(SlicePrivilegeAdmin, self).formfield_for_foreignkey(db_field, request, **kwargs)
Tony Mackc2835a92013-05-28 09:18:49 -0400667
Tony Mack04062832013-05-10 08:22:44 -0400668 def queryset(self, request):
669 # admins can see all memberships. Users can only see memberships of
670 # slices where they have the admin role.
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400671 qs = super(SlicePrivilegeAdmin, self).queryset(request)
Tony Mack04062832013-05-10 08:22:44 -0400672 if not request.user.is_admin:
Tony Mackc2835a92013-05-28 09:18:49 -0400673 roles = Role.objects.filter(role_type__in=['admin', 'pi'])
674 site_privileges = SitePrivilege.objects.filter(user=request.user).filter(role__in=roles)
675 login_bases = [site_privilege.site.login_base for site_privilege in site_privileges]
676 sites = Site.objects.filter(login_base__in=login_bases)
677 slices = Slice.objects.filter(site__in=sites)
678 qs = qs.filter(slice__in=slices)
Tony Mack04062832013-05-10 08:22:44 -0400679 return qs
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400680
Tony Mack9bcbe4f2013-04-29 08:13:27 -0400681 def save_model(self, request, obj, form, change):
Tony Mack951dab42013-05-02 19:51:45 -0400682 # update openstack connection to use this site/tenant
683 auth = request.session.get('auth', {})
684 auth['tenant'] = obj.slice.name
685 obj.os_manager = OpenStackManager(auth=auth, caller=request.user)
Tony Mack9bcbe4f2013-04-29 08:13:27 -0400686 obj.save()
687
688 def delete_model(self, request, obj):
Tony Mack951dab42013-05-02 19:51:45 -0400689 # update openstack connection to use this site/tenant
690 auth = request.session.get('auth', {})
691 auth['tenant'] = obj.slice.name
692 obj.os_manager = OpenStackManager(auth=auth, caller=request.user)
Tony Mack9bcbe4f2013-04-29 08:13:27 -0400693 obj.delete()
694
Siobhan Tully567e3e62013-06-21 18:03:16 -0400695
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400696class ImageAdmin(PlanetStackBaseAdmin):
697
698 fieldsets = [('Image Details',
699 {'fields': ['image_id', 'name', 'disk_format', 'container_format'],
700 'classes': ['suit-tab suit-tab-general']})
701 ]
702
703 suit_form_tabs =(('general','Image Details'),('slivers','Slivers'))
704
705 inlines = [SliverInline]
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500706
707 user_readonly_fields = ['image_id', 'name', 'disk_format', 'container_format']
708 user_readonly_inlines = [SliverROInline]
709
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400710class NodeForm(forms.ModelForm):
711 class Meta:
712 widgets = {
713 'site': LinkedSelect,
714 'deployment': LinkedSelect
715 }
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400716
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500717class NodeAdmin(PlanetStackBaseAdmin):
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400718 form = NodeForm
Siobhan Tullybf1153a2013-05-27 20:53:48 -0400719 list_display = ('name', 'site', 'deployment')
720 list_filter = ('deployment',)
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500721
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400722 inlines = [TagInline,SliverInline]
723 fieldsets = [('Node Details', {'fields': ['name','site','deployment'], 'classes':['suit-tab suit-tab-details']})]
724
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500725 user_readonly_fields = ['name','site','deployment']
726 user_readonly_inlines = [TagInline,SliverInline]
727
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400728 suit_form_tabs =(('details','Node Details'),('slivers','Slivers'),('tags','Tags'))
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400729
Siobhan Tully567e3e62013-06-21 18:03:16 -0400730
Tony Mackd90cdbf2013-04-16 22:48:40 -0400731class SliverForm(forms.ModelForm):
732 class Meta:
Tony Mack1d6b85f2013-05-07 18:49:14 -0400733 model = Sliver
Tony Mackd90cdbf2013-04-16 22:48:40 -0400734 ip = forms.CharField(widget=PlainTextWidget)
Tony Mack18261812013-05-02 16:39:20 -0400735 instance_name = forms.CharField(widget=PlainTextWidget)
Tony Mackd90cdbf2013-04-16 22:48:40 -0400736 widgets = {
737 'ip': PlainTextWidget(),
Tony Mack18261812013-05-02 16:39:20 -0400738 'instance_name': PlainTextWidget(),
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400739 'slice': LinkedSelect,
740 'deploymentNetwork': LinkedSelect,
741 'node': LinkedSelect,
742 'image': LinkedSelect
Siobhan Tully53437282013-04-26 19:30:27 -0400743 }
Tony Mackd90cdbf2013-04-16 22:48:40 -0400744
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500745class TagAdmin(PlanetStackBaseAdmin):
Siobhan Tullyce652d02013-10-08 21:52:35 -0400746 list_display = ['service', 'name', 'value', 'content_type', 'content_object',]
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500747 user_readonly_fields = ['service', 'name', 'value', 'content_type', 'content_object',]
748 user_readonly_inlines = []
Siobhan Tullyd3515752013-06-21 16:34:53 -0400749
Tony Mack9bcbe4f2013-04-29 08:13:27 -0400750class SliverAdmin(PlanetStackBaseAdmin):
Tony Mackd90cdbf2013-04-16 22:48:40 -0400751 form = SliverForm
Tony Mackcdec0902013-04-15 00:38:49 -0400752 fieldsets = [
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400753 ('Sliver Details', {'fields': ['slice', 'deploymentNetwork', 'node', 'ip', 'instance_name', 'numberCores', 'image', ], 'classes': ['suit-tab suit-tab-general'], })
Tony Mackcdec0902013-04-15 00:38:49 -0400754 ]
Siobhan Tully5d7dc8d2013-07-02 13:17:33 -0400755 list_display = ['ip', 'instance_name', 'slice', 'numberCores', 'image', 'node', 'deploymentNetwork']
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400756
757 suit_form_tabs =(('general', 'Sliver Details'),
758 ('tags','Tags'),
759 )
760
Siobhan Tullyde5450d2013-06-21 11:35:33 -0400761 inlines = [TagInline]
Tony Mack53106f32013-04-27 16:43:01 -0400762
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500763 user_readonly_fields = ['slice', 'deploymentNetwork', 'node', 'ip', 'instance_name', 'numberCores', 'image']
764 user_readonly_inlines = [TagROInline]
765
Tony Mackc2835a92013-05-28 09:18:49 -0400766 def formfield_for_foreignkey(self, db_field, request, **kwargs):
767 if db_field.name == 'slice':
768 if not request.user.is_admin:
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400769 slices = set([sm.slice.name for sm in SlicePrivilege.objects.filter(user=request.user)])
Tony Mackc2835a92013-05-28 09:18:49 -0400770 kwargs['queryset'] = Slice.objects.filter(name__in=list(slices))
771
772 return super(SliverAdmin, self).formfield_for_foreignkey(db_field, request, **kwargs)
773
Tony Mack04062832013-05-10 08:22:44 -0400774 def queryset(self, request):
775 # admins can see all slivers. Users can only see slivers of
776 # the slices they belong to.
777 qs = super(SliverAdmin, self).queryset(request)
778 if not request.user.is_admin:
779 tenants = []
780 roles = request.user.get_roles()
781 for tenant_list in roles.values():
782 tenants.extend(tenant_list)
783 valid_slices = Slice.objects.filter(name__in=tenants)
784 qs = qs.filter(slice__in=valid_slices)
785 return qs
786
Tony Mack1d6b85f2013-05-07 18:49:14 -0400787 def get_formsets(self, request, obj=None):
788 # make some fields read only if we are updating an existing record
789 if obj == None:
790 #self.readonly_fields = ('ip', 'instance_name')
791 self.readonly_fields = ()
792 else:
Tony Mack1e889462013-05-10 21:34:54 -0400793 self.readonly_fields = ()
794 #self.readonly_fields = ('ip', 'instance_name', 'slice', 'image', 'key')
Tony Mack1d6b85f2013-05-07 18:49:14 -0400795
796 for inline in self.get_inline_instances(request, obj):
797 # hide MyInline in the add view
798 if obj is None:
799 continue
800 # give inline object access to driver and caller
801 auth = request.session.get('auth', {})
802 auth['tenant'] = obj.name # meed to connect using slice's tenant
803 inline.model.os_manager = OpenStackManager(auth=auth, caller=request.user)
804 yield inline.get_formset(request, obj)
Tony Mack53106f32013-04-27 16:43:01 -0400805
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500806 #def save_model(self, request, obj, form, change):
807 # # update openstack connection to use this site/tenant
808 # auth = request.session.get('auth', {})
809 # auth['tenant'] = obj.slice.name
810 # obj.os_manager = OpenStackManager(auth=auth, caller=request.user)
811 # obj.creator = request.user
812 # obj.save()
Tony Mack53106f32013-04-27 16:43:01 -0400813
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500814 #def delete_model(self, request, obj):
815 # # update openstack connection to use this site/tenant
816 # auth = request.session.get('auth', {})
817 # auth['tenant'] = obj.slice.name
818 # obj.os_manager = OpenStackManager(auth=auth, caller=request.user)
819 # obj.delete()
Tony Mackcdec0902013-04-15 00:38:49 -0400820
Siobhan Tully53437282013-04-26 19:30:27 -0400821class UserCreationForm(forms.ModelForm):
822 """A form for creating new users. Includes all the required
823 fields, plus a repeated password."""
824 password1 = forms.CharField(label='Password', widget=forms.PasswordInput)
825 password2 = forms.CharField(label='Password confirmation', widget=forms.PasswordInput)
826
827 class Meta:
Siobhan Tully30fd4292013-05-10 08:59:56 -0400828 model = User
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400829 fields = ('email', 'firstname', 'lastname', 'phone', 'public_key')
Siobhan Tully53437282013-04-26 19:30:27 -0400830
831 def clean_password2(self):
832 # Check that the two password entries match
833 password1 = self.cleaned_data.get("password1")
834 password2 = self.cleaned_data.get("password2")
835 if password1 and password2 and password1 != password2:
836 raise forms.ValidationError("Passwords don't match")
837 return password2
838
839 def save(self, commit=True):
840 # Save the provided password in hashed format
841 user = super(UserCreationForm, self).save(commit=False)
Tony Mackf9f4afb2013-05-01 21:02:12 -0400842 user.password = self.cleaned_data["password1"]
843 #user.set_password(self.cleaned_data["password1"])
Siobhan Tully53437282013-04-26 19:30:27 -0400844 if commit:
845 user.save()
846 return user
847
Siobhan Tully567e3e62013-06-21 18:03:16 -0400848
Siobhan Tully53437282013-04-26 19:30:27 -0400849class UserChangeForm(forms.ModelForm):
850 """A form for updating users. Includes all the fields on
851 the user, but replaces the password field with admin's
852 password hash display field.
853 """
Siobhan Tully63b7ba42014-01-12 10:35:11 -0500854 password = ReadOnlyPasswordHashField(label='Password',
855 help_text= '<a href=\"password/\">Change Password</a>.')
Siobhan Tully53437282013-04-26 19:30:27 -0400856
857 class Meta:
Siobhan Tully30fd4292013-05-10 08:59:56 -0400858 model = User
Siobhan Tully53437282013-04-26 19:30:27 -0400859
860 def clean_password(self):
861 # Regardless of what the user provides, return the initial value.
862 # This is done here, rather than on the field, because the
863 # field does not have access to the initial value
864 return self.initial["password"]
865
Tony Mack2bd5b412013-06-11 21:05:06 -0400866class UserAdmin(UserAdmin):
Siobhan Tully53437282013-04-26 19:30:27 -0400867 class Meta:
868 app_label = "core"
869
870 # The forms to add and change user instances
871 form = UserChangeForm
872 add_form = UserCreationForm
873
874 # The fields to be used in displaying the User model.
875 # These override the definitions on the base UserAdmin
876 # that reference specific fields on auth.User.
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500877 list_display = ('email', 'firstname', 'lastname', 'site', 'last_login')
Siobhan Tullyce652d02013-10-08 21:52:35 -0400878 #list_display = ('email', 'username','firstname', 'lastname', 'is_admin', 'last_login')
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500879 list_filter = ('site',)
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400880 inlines = [SlicePrivilegeInline,SitePrivilegeInline,DeploymentPrivilegeInline]
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500881
882 fieldListLoginDetails = ['email','site','password','is_readonly','is_amin','public_key']
883 fieldListContactInfo = ['firstname','lastname','phone','timezone']
884
Siobhan Tully53437282013-04-26 19:30:27 -0400885 fieldsets = (
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500886 ('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 -0400887 ('Contact Information', {'fields': ('firstname','lastname','phone', 'timezone'), 'classes':['suit-tab suit-tab-contact']}),
Siobhan Tully53437282013-04-26 19:30:27 -0400888 #('Important dates', {'fields': ('last_login',)}),
889 )
890 add_fieldsets = (
891 (None, {
892 'classes': ('wide',),
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500893 'fields': ('email', 'firstname', 'lastname', 'is_readonly', 'phone', 'public_key','password1', 'password2')}
Siobhan Tully53437282013-04-26 19:30:27 -0400894 ),
895 )
896 search_fields = ('email',)
897 ordering = ('email',)
898 filter_horizontal = ()
899
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500900 user_readonly_fields = fieldListLoginDetails
901 user_readonly_inlines = [SlicePrivilegeROInline,SitePrivilegeROInline,DeploymentPrivilegeROInline]
902
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400903 suit_form_tabs =(('general','Login Details'),('contact','Contact Information'),('sliceprivileges','Slice Privileges'),('siteprivileges','Site Privileges'),('deploymentprivileges','Deployment Privileges'))
904
Tony Mackc2835a92013-05-28 09:18:49 -0400905 def formfield_for_foreignkey(self, db_field, request, **kwargs):
906 if db_field.name == 'site':
907 if not request.user.is_admin:
908 # show sites where caller is an admin or pi
909 sites = []
910 for site_privilege in SitePrivilege.objects.filer(user=request.user):
911 if site_privilege.role.role_type in ['admin', 'pi']:
912 sites.append(site_privilege.site.login_base)
913 kwargs['queryset'] = Site.objects.filter(login_base__in(list(sites)))
914
915 return super(UserAdmin, self).formfield_for_foreignkey(db_field, request, **kwargs)
916
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500917 def has_add_permission(self, request, obj=None):
918 return (not self.__user_is_readonly(request))
919
920 def has_delete_permission(self, request, obj=None):
921 return (not self.__user_is_readonly(request))
922
923 def get_actions(self,request):
924 actions = super(UserAdmin,self).get_actions(request)
925
926 if self.__user_is_readonly(request):
927 if 'delete_selected' in actions:
928 del actions['delete_selected']
929
930 return actions
931
932 def change_view(self,request,object_id, extra_context=None):
933
934 if self.__user_is_readonly(request):
935 self.readonly_fields=self.user_readonly_fields
936 self.inlines = self.user_readonly_inlines
937 try:
938 return super(UserAdmin, self).change_view(request, object_id, extra_context=extra_context)
939 except PermissionDenied:
940 pass
941 if request.method == 'POST':
942 raise PermissionDenied
943 request.readonly = True
944 return super(UserAdmin, self).change_view(request, object_id, extra_context=extra_context)
945
946 def __user_is_readonly(self, request):
947 #groups = [x.name for x in request.user.groups.all() ]
948 #return "readonly" in groups
949 return request.user.isReadOnlyUser()
950
951
952
953class ServiceResourceROInline(ReadOnlyTabularInline):
954 model = ServiceResource
955 extra = 0
956 fields = ['serviceClass', 'name', 'maxUnitsDeployment', 'maxUnitsNode', 'maxDuration', 'bucketInRate', 'bucketMaxSize', 'cost', 'calendarReservable']
957
Scott Baker0165fac2014-01-13 11:49:26 -0800958class ServiceResourceInline(PlStackTabularInline):
Scott Baker3de3e372013-05-10 16:50:44 -0700959 model = ServiceResource
960 extra = 0
961
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500962class ServiceClassAdmin(PlanetStackBaseAdmin):
Scott Baker3de3e372013-05-10 16:50:44 -0700963 list_display = ('name', 'commitment', 'membershipFee')
964 inlines = [ServiceResourceInline]
965
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500966 user_readonly_fields = ['name', 'commitment', 'membershipFee']
967 user_readonly_inlines = []
968
969class ReservedResourceROInline(ReadOnlyTabularInline):
970 model = ReservedResource
971 extra = 0
972 fields = ['sliver', 'resource','quantity','reservationSet']
973 suit_classes = 'suit-tab suit-tab-reservedresources'
974
Scott Baker0165fac2014-01-13 11:49:26 -0800975class ReservedResourceInline(PlStackTabularInline):
Scott Baker133c9212013-05-17 09:09:11 -0700976 model = ReservedResource
977 extra = 0
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400978 suit_classes = 'suit-tab suit-tab-reservedresources'
Scott Baker133c9212013-05-17 09:09:11 -0700979
980 def formfield_for_foreignkey(self, db_field, request=None, **kwargs):
981 field = super(ReservedResourceInline, self).formfield_for_foreignkey(db_field, request, **kwargs)
982
983 if db_field.name == 'resource':
984 # restrict resources to those that the slice's service class allows
985 if request._slice is not None:
986 field.queryset = field.queryset.filter(serviceClass = request._slice.serviceClass, calendarReservable=True)
987 if len(field.queryset) > 0:
988 field.initial = field.queryset.all()[0]
989 else:
990 field.queryset = field.queryset.none()
991 elif db_field.name == 'sliver':
992 # restrict slivers to those that belong to the slice
993 if request._slice is not None:
994 field.queryset = field.queryset.filter(slice = request._slice)
995 else:
996 field.queryset = field.queryset.none()
997
998 return field
999
1000class ReservationChangeForm(forms.ModelForm):
1001 class Meta:
1002 model = Reservation
Siobhan Tullybfd11dc2013-09-03 12:59:24 -04001003 widgets = {
1004 'slice' : LinkedSelect
1005 }
Scott Baker133c9212013-05-17 09:09:11 -07001006
1007class ReservationAddForm(forms.ModelForm):
1008 slice = forms.ModelChoiceField(queryset=Slice.objects.all(), widget=forms.Select(attrs={"onChange":"document.getElementById('id_refresh').value=1; submit()"}))
1009 refresh = forms.CharField(widget=forms.HiddenInput())
1010
1011 class Media:
1012 css = {'all': ('planetstack.css',)} # .field-refresh { display: none; }
1013
1014 def clean_slice(self):
1015 slice = self.cleaned_data.get("slice")
1016 x = ServiceResource.objects.filter(serviceClass = slice.serviceClass, calendarReservable=True)
1017 if len(x) == 0:
1018 raise forms.ValidationError("The slice you selected does not have a service class that allows reservations")
1019 return slice
1020
1021 class Meta:
1022 model = Reservation
Siobhan Tullybfd11dc2013-09-03 12:59:24 -04001023 widgets = {
1024 'slice' : LinkedSelect
1025 }
1026
Scott Baker133c9212013-05-17 09:09:11 -07001027
1028class ReservationAddRefreshForm(ReservationAddForm):
1029 """ This form is displayed when the Reservation Form receives an update
1030 from the Slice dropdown onChange handler. It doesn't validate the
1031 data and doesn't save the data. This will cause the form to be
1032 redrawn.
1033 """
1034
Scott Baker8737e5f2013-05-17 09:35:32 -07001035 """ don't validate anything other than slice """
1036 dont_validate_fields = ("startTime", "duration")
1037
Scott Baker133c9212013-05-17 09:09:11 -07001038 def full_clean(self):
1039 result = super(ReservationAddForm, self).full_clean()
Scott Baker8737e5f2013-05-17 09:35:32 -07001040
1041 for fieldname in self.dont_validate_fields:
1042 if fieldname in self._errors:
1043 del self._errors[fieldname]
1044
Scott Baker133c9212013-05-17 09:09:11 -07001045 return result
1046
1047 """ don't save anything """
1048 def is_valid(self):
1049 return False
1050
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001051class ReservationAdmin(PlanetStackBaseAdmin):
1052 fieldList = ['slice', 'startTime', 'duration']
1053 fieldsets = [('Reservation Details', {'fields': fieldList, 'classes': ['suit-tab suit-tab-general']})]
Scott Baker133c9212013-05-17 09:09:11 -07001054 list_display = ('startTime', 'duration')
Scott Baker133c9212013-05-17 09:09:11 -07001055 form = ReservationAddForm
1056
Siobhan Tullybfd11dc2013-09-03 12:59:24 -04001057 suit_form_tabs = (('general','Reservation Details'), ('reservedresources','Reserved Resources'))
1058
1059 inlines = [ReservedResourceInline]
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001060 user_readonly_inlines = [ReservedResourceROInline]
1061 user_readonly_fields = fieldList
Siobhan Tullybfd11dc2013-09-03 12:59:24 -04001062
Scott Baker133c9212013-05-17 09:09:11 -07001063 def add_view(self, request, form_url='', extra_context=None):
Scott Bakeracd45142013-05-19 16:19:16 -07001064 timezone.activate(request.user.timezone)
Scott Baker133c9212013-05-17 09:09:11 -07001065 request._refresh = False
1066 request._slice = None
1067 if request.method == 'POST':
Scott Baker8737e5f2013-05-17 09:35:32 -07001068 # "refresh" will be set to "1" if the form was submitted due to
1069 # a change in the Slice dropdown.
Scott Baker133c9212013-05-17 09:09:11 -07001070 if request.POST.get("refresh","1") == "1":
1071 request._refresh = True
1072 request.POST["refresh"] = "0"
Scott Baker8737e5f2013-05-17 09:35:32 -07001073
1074 # Keep track of the slice that was selected, so the
1075 # reservedResource inline can filter items for the slice.
Scott Baker133c9212013-05-17 09:09:11 -07001076 request._slice = request.POST.get("slice",None)
1077 if (request._slice is not None):
1078 request._slice = Slice.objects.get(id=request._slice)
1079
1080 result = super(ReservationAdmin, self).add_view(request, form_url, extra_context)
1081 return result
1082
Scott Bakeracd45142013-05-19 16:19:16 -07001083 def changelist_view(self, request, extra_context = None):
1084 timezone.activate(request.user.timezone)
1085 return super(ReservationAdmin, self).changelist_view(request, extra_context)
1086
Scott Baker133c9212013-05-17 09:09:11 -07001087 def get_form(self, request, obj=None, **kwargs):
Siobhan Tullyd3515752013-06-21 16:34:53 -04001088 request._obj_ = obj
1089 if obj is not None:
1090 # For changes, set request._slice to the slice already set in the
1091 # object.
1092 request._slice = obj.slice
1093 self.form = ReservationChangeForm
1094 else:
1095 if getattr(request, "_refresh", False):
1096 self.form = ReservationAddRefreshForm
1097 else:
1098 self.form = ReservationAddForm
1099 return super(ReservationAdmin, self).get_form(request, obj, **kwargs)
1100
Scott Baker133c9212013-05-17 09:09:11 -07001101 def get_readonly_fields(self, request, obj=None):
Siobhan Tullyd3515752013-06-21 16:34:53 -04001102 if (obj is not None):
1103 # Prevent slice from being changed after the reservation has been
1104 # created.
1105 return ['slice']
1106 else:
Scott Baker133c9212013-05-17 09:09:11 -07001107 return []
Scott Baker3de3e372013-05-10 16:50:44 -07001108
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001109class NetworkParameterTypeAdmin(PlanetStackBaseAdmin):
Scott Baker74d8e622013-07-29 16:04:22 -07001110 list_display = ("name", )
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001111 user_readonly_fields = ['name']
1112 user_readonly_inlines = []
Scott Baker74d8e622013-07-29 16:04:22 -07001113
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001114class RouterAdmin(PlanetStackBaseAdmin):
Scott Baker74d8e622013-07-29 16:04:22 -07001115 list_display = ("name", )
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001116 user_readonly_fields = ['name']
1117 user_readonly_inlines = []
1118
1119class RouterROInline(ReadOnlyTabularInline):
1120 model = Router.networks.through
1121 extra = 0
1122 verbose_name_plural = "Routers"
1123 verbose_name = "Router"
1124 suit_classes = 'suit-tab suit-tab-routers'
1125
1126 fields = ['name', 'owner', 'permittedNetworks', 'networks']
Scott Baker74d8e622013-07-29 16:04:22 -07001127
Scott Baker0165fac2014-01-13 11:49:26 -08001128class RouterInline(PlStackTabularInline):
Scott Baker74d8e622013-07-29 16:04:22 -07001129 model = Router.networks.through
1130 extra = 0
1131 verbose_name_plural = "Routers"
1132 verbose_name = "Router"
Siobhan Tully2d95e482013-09-06 10:56:06 -04001133 suit_classes = 'suit-tab suit-tab-routers'
Scott Baker74d8e622013-07-29 16:04:22 -07001134
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001135class NetworkParameterROInline(ReadOnlyTabularInline):
1136 model = NetworkParameter
1137 extra = 1
1138 verbose_name_plural = "Parameters"
1139 verbose_name = "Parameter"
1140 suit_classes = 'suit-tab suit-tab-netparams'
1141 fields = ['parameter', 'value', 'content_type', 'object_id', 'content_object']
1142
Scott Baker74d8e622013-07-29 16:04:22 -07001143class NetworkParameterInline(generic.GenericTabularInline):
Scott Baker74d8e622013-07-29 16:04:22 -07001144 model = NetworkParameter
1145 extra = 1
1146 verbose_name_plural = "Parameters"
1147 verbose_name = "Parameter"
Siobhan Tully2d95e482013-09-06 10:56:06 -04001148 suit_classes = 'suit-tab suit-tab-netparams'
Scott Baker74d8e622013-07-29 16:04:22 -07001149
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001150class NetworkSliversROInline(ReadOnlyTabularInline):
1151 fields = ['network', 'sliver', 'ip', 'port_id']
1152 model = NetworkSliver
1153 extra = 0
1154 verbose_name_plural = "Slivers"
1155 verbose_name = "Sliver"
1156 suit_classes = 'suit-tab suit-tab-networkslivers'
1157
Scott Baker0165fac2014-01-13 11:49:26 -08001158class NetworkSliversInline(PlStackTabularInline):
Scott Baker74d8e622013-07-29 16:04:22 -07001159 readonly_fields = ("ip", )
1160 model = NetworkSliver
Scott Baker874936e2014-01-13 18:15:34 -08001161 selflink_fieldname = "sliver"
Scott Baker74d8e622013-07-29 16:04:22 -07001162 extra = 0
1163 verbose_name_plural = "Slivers"
1164 verbose_name = "Sliver"
Siobhan Tully2d95e482013-09-06 10:56:06 -04001165 suit_classes = 'suit-tab suit-tab-networkslivers'
Scott Baker74d8e622013-07-29 16:04:22 -07001166
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001167class NetworkSlicesROInline(ReadOnlyTabularInline):
1168 model = NetworkSlice
1169 extra = 0
1170 verbose_name_plural = "Slices"
1171 verbose_name = "Slice"
1172 suit_classes = 'suit-tab suit-tab-networkslices'
1173 fields = ['network','slice']
1174
Scott Baker0165fac2014-01-13 11:49:26 -08001175class NetworkSlicesInline(PlStackTabularInline):
Scott Bakerd7d2a392013-08-06 08:57:30 -07001176 model = NetworkSlice
Scott Baker874936e2014-01-13 18:15:34 -08001177 selflink_fieldname = "slice"
Scott Bakerd7d2a392013-08-06 08:57:30 -07001178 extra = 0
1179 verbose_name_plural = "Slices"
1180 verbose_name = "Slice"
Siobhan Tully2d95e482013-09-06 10:56:06 -04001181 suit_classes = 'suit-tab suit-tab-networkslices'
Scott Bakerd7d2a392013-08-06 08:57:30 -07001182
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001183class NetworkAdmin(PlanetStackBaseAdmin):
Scott Baker74d8e622013-07-29 16:04:22 -07001184 list_display = ("name", "subnet", "ports", "labels")
1185 readonly_fields = ("subnet", )
Siobhan Tully2d95e482013-09-06 10:56:06 -04001186
Scott Bakerd7d2a392013-08-06 08:57:30 -07001187 inlines = [NetworkParameterInline, NetworkSliversInline, NetworkSlicesInline, RouterInline]
Scott Baker74d8e622013-07-29 16:04:22 -07001188
Siobhan Tully2d95e482013-09-06 10:56:06 -04001189 fieldsets = [
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001190 (None, {'fields': ['name','template','ports','labels','owner','guaranteedBandwidth', 'permitAllSlices','permittedSlices','network_id','router_id','subnet_id','subnet'], 'classes':['suit-tab suit-tab-general']}),]
1191
1192 user_readonly_fields = ['name','template','ports','labels','owner','guaranteedBandwidth', 'permitAllSlices','permittedSlices','network_id','router_id','subnet_id','subnet']
1193 user_readonly_inlines = [NetworkParameterROInline, NetworkSliversROInline, NetworkSlicesROInline, RouterROInline]
Siobhan Tully2d95e482013-09-06 10:56:06 -04001194
1195 suit_form_tabs =(
1196 ('general','Network Details'),
1197 ('netparams', 'Parameters'),
1198 ('networkslivers','Slivers'),
1199 ('networkslices','Slices'),
1200 ('routers','Routers'),
1201 )
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001202class NetworkTemplateAdmin(PlanetStackBaseAdmin):
Scott Baker74d8e622013-07-29 16:04:22 -07001203 list_display = ("name", "guaranteedBandwidth", "visibility")
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001204 user_readonly_fields = ["name", "guaranteedBandwidth", "visibility"]
1205 user_readonly_inlines = []
Scott Baker74d8e622013-07-29 16:04:22 -07001206
Tony Mack31c2b8f2013-04-26 20:01:42 -04001207# register a signal that caches the user's credentials when they log in
1208def cache_credentials(sender, user, request, **kwds):
1209 auth = {'username': request.POST['username'],
1210 'password': request.POST['password']}
1211 request.session['auth'] = auth
1212user_logged_in.connect(cache_credentials)
1213
Scott Baker15cddfa2013-12-09 13:45:19 -08001214def dollar_field(fieldName, short_description):
1215 def newFunc(self, obj):
1216 try:
1217 x= "$ %0.2f" % float(getattr(obj, fieldName, 0.0))
1218 except:
1219 x=getattr(obj, fieldName, 0.0)
1220 return x
1221 newFunc.short_description = short_description
1222 return newFunc
1223
1224def right_dollar_field(fieldName, short_description):
1225 def newFunc(self, obj):
1226 try:
1227 #x= '<div align=right style="width:6em">$ %0.2f</div>' % float(getattr(obj, fieldName, 0.0))
1228 x= '<div align=right>$ %0.2f</div>' % float(getattr(obj, fieldName, 0.0))
1229 except:
1230 x=getattr(obj, fieldName, 0.0)
1231 return x
1232 newFunc.short_description = short_description
1233 newFunc.allow_tags = True
1234 return newFunc
Scott Baker43105042013-12-06 23:23:36 -08001235
Scott Baker0165fac2014-01-13 11:49:26 -08001236class InvoiceChargeInline(PlStackTabularInline):
Scott Baker43105042013-12-06 23:23:36 -08001237 model = Charge
Scott Baker15cddfa2013-12-09 13:45:19 -08001238 extra = 0
Scott Baker43105042013-12-06 23:23:36 -08001239 verbose_name_plural = "Charges"
1240 verbose_name = "Charge"
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001241 exclude = ['account']
Scott Baker9cb88a22013-12-09 18:56:00 -08001242 fields = ["date", "kind", "state", "object", "coreHours", "dollar_amount", "slice"]
1243 readonly_fields = ["date", "kind", "state", "object", "coreHours", "dollar_amount", "slice"]
1244 can_delete = False
1245 max_num = 0
1246
1247 dollar_amount = right_dollar_field("amount", "Amount")
Scott Baker43105042013-12-06 23:23:36 -08001248
1249class InvoiceAdmin(admin.ModelAdmin):
1250 list_display = ("date", "account")
1251
1252 inlines = [InvoiceChargeInline]
1253
Scott Baker9cb88a22013-12-09 18:56:00 -08001254 fields = ["date", "account", "dollar_amount"]
1255 readonly_fields = ["date", "account", "dollar_amount"]
1256
1257 dollar_amount = dollar_field("amount", "Amount")
Scott Baker43105042013-12-06 23:23:36 -08001258
Scott Baker0165fac2014-01-13 11:49:26 -08001259class InvoiceInline(PlStackTabularInline):
Scott Baker15cddfa2013-12-09 13:45:19 -08001260 model = Invoice
1261 extra = 0
1262 verbose_name_plural = "Invoices"
1263 verbose_name = "Invoice"
Scott Baker0165fac2014-01-13 11:49:26 -08001264 fields = ["date", "dollar_amount"]
1265 readonly_fields = ["date", "dollar_amount"]
Scott Baker15cddfa2013-12-09 13:45:19 -08001266 suit_classes = 'suit-tab suit-tab-accountinvoice'
1267 can_delete=False
1268 max_num=0
1269
1270 dollar_amount = right_dollar_field("amount", "Amount")
1271
Scott Baker0165fac2014-01-13 11:49:26 -08001272class PendingChargeInline(PlStackTabularInline):
Scott Baker43105042013-12-06 23:23:36 -08001273 model = Charge
Scott Baker15cddfa2013-12-09 13:45:19 -08001274 extra = 0
Scott Baker43105042013-12-06 23:23:36 -08001275 verbose_name_plural = "Charges"
1276 verbose_name = "Charge"
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001277 exclude = ["invoice"]
Scott Baker15cddfa2013-12-09 13:45:19 -08001278 fields = ["date", "kind", "state", "object", "coreHours", "dollar_amount", "slice"]
1279 readonly_fields = ["date", "kind", "state", "object", "coreHours", "dollar_amount", "slice"]
Scott Baker43105042013-12-06 23:23:36 -08001280 suit_classes = 'suit-tab suit-tab-accountpendingcharges'
Scott Baker15cddfa2013-12-09 13:45:19 -08001281 can_delete=False
1282 max_num=0
Scott Baker43105042013-12-06 23:23:36 -08001283
1284 def queryset(self, request):
1285 qs = super(PendingChargeInline, self).queryset(request)
1286 qs = qs.filter(state="pending")
1287 return qs
1288
Scott Baker15cddfa2013-12-09 13:45:19 -08001289 dollar_amount = right_dollar_field("amount", "Amount")
1290
Scott Baker0165fac2014-01-13 11:49:26 -08001291class PaymentInline(PlStackTabularInline):
Scott Baker43105042013-12-06 23:23:36 -08001292 model=Payment
1293 extra = 1
1294 verbose_name_plural = "Payments"
1295 verbose_name = "Payment"
Scott Baker15cddfa2013-12-09 13:45:19 -08001296 fields = ["date", "dollar_amount"]
1297 readonly_fields = ["date", "dollar_amount"]
Scott Baker43105042013-12-06 23:23:36 -08001298 suit_classes = 'suit-tab suit-tab-accountpayments'
Scott Baker15cddfa2013-12-09 13:45:19 -08001299 can_delete=False
1300 max_num=0
1301
1302 dollar_amount = right_dollar_field("amount", "Amount")
1303
Scott Baker43105042013-12-06 23:23:36 -08001304class AccountAdmin(admin.ModelAdmin):
1305 list_display = ("site", "balance_due")
1306
1307 inlines = [InvoiceInline, PaymentInline, PendingChargeInline]
1308
1309 fieldsets = [
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001310 (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 -08001311
Scott Baker15cddfa2013-12-09 13:45:19 -08001312 readonly_fields = ['site', 'dollar_balance_due', 'dollar_total_invoices', 'dollar_total_payments']
Scott Baker43105042013-12-06 23:23:36 -08001313
1314 suit_form_tabs =(
1315 ('general','Account Details'),
1316 ('accountinvoice', 'Invoices'),
1317 ('accountpayments', 'Payments'),
1318 ('accountpendingcharges','Pending Charges'),
1319 )
1320
Scott Baker15cddfa2013-12-09 13:45:19 -08001321 dollar_balance_due = dollar_field("balance_due", "Balance Due")
1322 dollar_total_invoices = dollar_field("total_invoices", "Total Invoices")
1323 dollar_total_payments = dollar_field("total_payments", "Total Payments")
1324
Siobhan Tullyce652d02013-10-08 21:52:35 -04001325
Siobhan Tully53437282013-04-26 19:30:27 -04001326# Now register the new UserAdmin...
Siobhan Tully30fd4292013-05-10 08:59:56 -04001327admin.site.register(User, UserAdmin)
Siobhan Tully53437282013-04-26 19:30:27 -04001328# ... and, since we're not using Django's builtin permissions,
1329# unregister the Group model from admin.
Siobhan Tullyce652d02013-10-08 21:52:35 -04001330#admin.site.unregister(Group)
Siobhan Tully53437282013-04-26 19:30:27 -04001331
Siobhan Tullybf1153a2013-05-27 20:53:48 -04001332#Do not show django evolution in the admin interface
1333from django_evolution.models import Version, Evolution
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001334#admin.site.unregister(Version)
1335#admin.site.unregister(Evolution)
Siobhan Tullybf1153a2013-05-27 20:53:48 -04001336
1337
1338# When debugging it is often easier to see all the classes, but for regular use
1339# only the top-levels should be displayed
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001340showAll = False
Scott Baker43105042013-12-06 23:23:36 -08001341
Siobhan Tullybf1153a2013-05-27 20:53:48 -04001342admin.site.register(Deployment, DeploymentAdmin)
Siobhan Tully4bc09f22013-04-10 21:15:21 -04001343admin.site.register(Site, SiteAdmin)
Siobhan Tully4bc09f22013-04-10 21:15:21 -04001344admin.site.register(Slice, SliceAdmin)
Siobhan Tullyce652d02013-10-08 21:52:35 -04001345admin.site.register(Service, ServiceAdmin)
smbakera3cf70c2013-06-27 02:01:41 -07001346admin.site.register(Reservation, ReservationAdmin)
Scott Baker74d8e622013-07-29 16:04:22 -07001347admin.site.register(Network, NetworkAdmin)
1348admin.site.register(Router, RouterAdmin)
Scott Baker74d8e622013-07-29 16:04:22 -07001349admin.site.register(NetworkTemplate, NetworkTemplateAdmin)
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001350admin.site.register(Account, AccountAdmin)
1351admin.site.register(Invoice, InvoiceAdmin)
Siobhan Tullybf1153a2013-05-27 20:53:48 -04001352
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001353if True:
1354 admin.site.register(NetworkParameterType, NetworkParameterTypeAdmin)
1355 admin.site.register(ServiceClass, ServiceClassAdmin)
Siobhan Tullybfd11dc2013-09-03 12:59:24 -04001356 #admin.site.register(PlanetStack)
Siobhan Tullyd3515752013-06-21 16:34:53 -04001357 admin.site.register(Tag, TagAdmin)
Siobhan Tullyce652d02013-10-08 21:52:35 -04001358 admin.site.register(DeploymentRole)
1359 admin.site.register(SiteRole)
1360 admin.site.register(SliceRole)
1361 admin.site.register(PlanetStackRole)
Siobhan Tullybf1153a2013-05-27 20:53:48 -04001362 admin.site.register(Node, NodeAdmin)
Siobhan Tullybfd11dc2013-09-03 12:59:24 -04001363 #admin.site.register(SlicePrivilege, SlicePrivilegeAdmin)
1364 #admin.site.register(SitePrivilege, SitePrivilegeAdmin)
Siobhan Tullybf1153a2013-05-27 20:53:48 -04001365 admin.site.register(Sliver, SliverAdmin)
Siobhan Tullybf1153a2013-05-27 20:53:48 -04001366 admin.site.register(Image, ImageAdmin)
Tony Mack7130ac32013-03-22 21:58:00 -04001367