blob: 90f933946d574ddf8ab57609d821e472bb392b41 [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):
Siobhan Tullycf04fb62014-01-11 11:25:57 -050046 if self.__user_is_readonly(request):
Scott Bakeraf73e102014-04-22 22:40:07 -070047 if not hasattr(self, "readonly_save"):
48 # save the original readonly fields
49 self.readonly_save = self.readonly_fields
50 self.inlines_save = self.inlines
Scott Bakere8859f92014-05-23 12:42:40 -070051 if hasattr(self, "user_readonly_fields"):
52 self.readonly_fields=self.user_readonly_fields
53 if hasattr(self, "user_readonly_inlines"):
54 self.inlines = self.user_readonly_inlines
Scott Bakeraf73e102014-04-22 22:40:07 -070055 else:
56 if hasattr(self, "readonly_save"):
57 # restore the original readonly fields
58 self.readonly_fields = self.readonly_save
Scott Bakere8859f92014-05-23 12:42:40 -070059 if hasattr(self, "inlines_save"):
Scott Bakeraf73e102014-04-22 22:40:07 -070060 self.inlines = self.inlines_save
Siobhan Tullycf04fb62014-01-11 11:25:57 -050061
62 try:
63 return super(ReadOnlyAwareAdmin, self).change_view(request, object_id, extra_context=extra_context)
64 except PermissionDenied:
65 pass
66 if request.method == 'POST':
67 raise PermissionDenied
68 request.readonly = True
69 return super(ReadOnlyAwareAdmin, self).change_view(request, object_id, extra_context=extra_context)
70
Siobhan Tullycf04fb62014-01-11 11:25:57 -050071 def __user_is_readonly(self, request):
72 return request.user.isReadOnlyUser()
73
Scott Bakere8859f92014-05-23 12:42:40 -070074class SingletonAdmin (ReadOnlyAwareAdmin):
Siobhan Tullyce652d02013-10-08 21:52:35 -040075 def has_add_permission(self, request):
Scott Bakere8859f92014-05-23 12:42:40 -070076 if not super(SingletonAdmin, self).has_add_permission(request):
77 return False
78
Siobhan Tullyce652d02013-10-08 21:52:35 -040079 num_objects = self.model.objects.count()
80 if num_objects >= 1:
81 return False
82 else:
83 return True
84
85
Siobhan Tullyd3515752013-06-21 16:34:53 -040086class PlStackTabularInline(admin.TabularInline):
Scott Baker86568322014-01-12 16:53:31 -080087 def __init__(self, *args, **kwargs):
88 super(PlStackTabularInline, self).__init__(*args, **kwargs)
89
90 # InlineModelAdmin as no get_fields() method, so in order to add
91 # the selflink field, we override __init__ to modify self.fields and
92 # self.readonly_fields.
93
Scott Bakere2bbf7e2014-01-13 12:09:31 -080094 self.setup_selflink()
95
Scott Baker874936e2014-01-13 18:15:34 -080096 def get_change_url(self, model, id):
97 """ Get the URL to a change form in the admin for this model """
98 reverse_path = "admin:%s_change" % (model._meta.db_table)
Scott Bakere2bbf7e2014-01-13 12:09:31 -080099 try:
Scott Baker874936e2014-01-13 18:15:34 -0800100 url = reverse(reverse_path, args=(id,))
Scott Bakere2bbf7e2014-01-13 12:09:31 -0800101 except NoReverseMatch:
Scott Baker874936e2014-01-13 18:15:34 -0800102 return None
103
104 return url
105
106 def setup_selflink(self):
107 if hasattr(self, "selflink_fieldname"):
108 """ self.selflink_model can be defined to punch through a relation
109 to its target object. For example, in SliceNetworkInline, set
110 selflink_model = "network", and the URL will lead to the Network
111 object instead of trying to bring up a change view of the
112 SliceNetwork object.
113 """
114 self.selflink_model = getattr(self.model,self.selflink_fieldname).field.rel.to
115 else:
116 self.selflink_model = self.model
117
118 url = self.get_change_url(self.selflink_model, 0)
119
120 # We don't have an admin for this object, so don't create the
121 # selflink.
122 if (url == None):
Scott Bakere2bbf7e2014-01-13 12:09:31 -0800123 return
124
Scott Baker874936e2014-01-13 18:15:34 -0800125 # Since we need to add "selflink" to the field list, we need to create
126 # self.fields if it is None.
Scott Baker0165fac2014-01-13 11:49:26 -0800127 if (self.fields is None):
128 self.fields = []
129 for f in self.model._meta.fields:
130 if f.editable and f.name != "id":
131 self.fields.append(f.name)
Scott Baker86568322014-01-12 16:53:31 -0800132
Scott Baker874936e2014-01-13 18:15:34 -0800133 self.fields = tuple(self.fields) + ("selflink", )
Scott Baker86568322014-01-12 16:53:31 -0800134
Scott Baker874936e2014-01-13 18:15:34 -0800135 if self.readonly_fields is None:
136 self.readonly_fields = ()
Scott Baker86568322014-01-12 16:53:31 -0800137
Scott Baker874936e2014-01-13 18:15:34 -0800138 self.readonly_fields = tuple(self.readonly_fields) + ("selflink", )
Scott Baker86568322014-01-12 16:53:31 -0800139
140 def selflink(self, obj):
Scott Baker874936e2014-01-13 18:15:34 -0800141 if hasattr(self, "selflink_fieldname"):
142 obj = getattr(obj, self.selflink_fieldname)
143
Scott Baker86568322014-01-12 16:53:31 -0800144 if obj.id:
Scott Baker874936e2014-01-13 18:15:34 -0800145 url = self.get_change_url(self.selflink_model, obj.id)
146 return "<a href='%s'>Details</a>" % str(url)
Scott Baker86568322014-01-12 16:53:31 -0800147 else:
Scott Bakere2bbf7e2014-01-13 12:09:31 -0800148 return "Not present"
Scott Baker86568322014-01-12 16:53:31 -0800149
150 selflink.allow_tags = True
151 selflink.short_description = "Details"
Siobhan Tullyd3515752013-06-21 16:34:53 -0400152
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500153class ReadOnlyTabularInline(PlStackTabularInline):
154 can_delete = False
155
156 def get_readonly_fields(self, request, obj=None):
157 return self.fields
158
159 def has_add_permission(self, request):
160 return False
161
162class ReservationROInline(ReadOnlyTabularInline):
163 model = Reservation
164 extra = 0
165 suit_classes = 'suit-tab suit-tab-reservations'
166 fields = ['startTime','slice','duration']
167
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400168class ReservationInline(PlStackTabularInline):
169 model = Reservation
170 extra = 0
171 suit_classes = 'suit-tab suit-tab-reservations'
Tony Mack5b061472014-02-04 07:57:10 -0500172
173 def queryset(self, request):
174 return Reservation.select_by_user(request.user)
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400175
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500176class TagROInline(generic.GenericTabularInline):
177 model = Tag
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400178 extra = 0
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500179 suit_classes = 'suit-tab suit-tab-tags'
180 can_delete = False
181 fields = ['service', 'name', 'value']
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400182
183 def get_readonly_fields(self, request, obj=None):
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500184 return self.fields
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400185
186 def has_add_permission(self, request):
187 return False
188
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500189
Siobhan Tullyde5450d2013-06-21 11:35:33 -0400190class TagInline(generic.GenericTabularInline):
191 model = Tag
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400192 extra = 0
193 suit_classes = 'suit-tab suit-tab-tags'
Tony Mack5b061472014-02-04 07:57:10 -0500194 fields = ['service', 'name', 'value']
195
196 def queryset(self, request):
197 return Tag.select_by_user(request.user)
Siobhan Tullyde5450d2013-06-21 11:35:33 -0400198
Scott Baker74d8e622013-07-29 16:04:22 -0700199class NetworkLookerUpper:
Siobhan Tully2c780ad2013-09-06 11:22:40 -0400200 """ This is a callable that looks up a network name in a sliver and returns
201 the ip address for that network.
202 """
203
204 def __init__(self, name):
205 self.short_description = name
206 self.__name__ = name
207 self.network_name = name
208
209 def __call__(self, obj):
210 if obj is not None:
211 for nbs in obj.networksliver_set.all():
212 if (nbs.network.name == self.network_name):
213 return nbs.ip
Scott Baker74d8e622013-07-29 16:04:22 -0700214 return ""
215
216 def __str__(self):
217 return self.network_name
218
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500219class SliverROInline(ReadOnlyTabularInline):
220 model = Sliver
221 fields = ['ip', 'instance_name', 'slice', 'numberCores', 'image', 'node', 'deploymentNetwork']
222 suit_classes = 'suit-tab suit-tab-slivers'
223
Siobhan Tullyd3515752013-06-21 16:34:53 -0400224class SliverInline(PlStackTabularInline):
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400225 model = Sliver
Tony Mackb0d97422013-06-10 09:57:45 -0400226 fields = ['ip', 'instance_name', 'slice', 'numberCores', 'image', 'node', 'deploymentNetwork']
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400227 extra = 0
Tony Mack3777b012013-05-07 21:38:06 -0400228 readonly_fields = ['ip', 'instance_name']
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400229 suit_classes = 'suit-tab suit-tab-slivers'
Scott Baker74d8e622013-07-29 16:04:22 -0700230
Tony Mack5b061472014-02-04 07:57:10 -0500231 def queryset(self, request):
232 return Sliver.select_by_user(request.user)
233
Siobhan Tully2d95e482013-09-06 10:56:06 -0400234# Note this is breaking in the admin.py when trying to use an inline to add a node/image
235# def _declared_fieldsets(self):
236# # Return None so django will call get_fieldsets and we can insert our
237# # dynamic fields
238# return None
239#
240# def get_readonly_fields(self, request, obj=None):
241# readonly_fields = super(SliverInline, self).get_readonly_fields(request, obj)
242#
243# # Lookup the networks that are bound to the slivers, and add those
244# # network names to the list of readonly fields.
245#
246# for sliver in obj.slivers.all():
247# for nbs in sliver.networksliver_set.all():
248# if nbs.ip:
249# network_name = nbs.network.name
250# if network_name not in [str(x) for x in readonly_fields]:
251# readonly_fields.append(NetworkLookerUpper(network_name))
252#
253# return readonly_fields
254#
255# def get_fieldsets(self, request, obj=None):
256# form = self.get_formset(request, obj).form
257# # fields = the read/write files + the read-only fields
258# fields = self.fields
259# for fieldName in self.get_readonly_fields(request,obj):
260# if not fieldName in fields:
261# fields.append(fieldName)
262#
263# return [(None, {'fields': fields})]
Scott Baker74d8e622013-07-29 16:04:22 -0700264
Tony Mackc2835a92013-05-28 09:18:49 -0400265
Siobhan Tully567e3e62013-06-21 18:03:16 -0400266
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500267class SiteROInline(ReadOnlyTabularInline):
268 model = Site
269 extra = 0
270 fields = ['name', 'login_base', 'site_url', 'enabled']
271 suit_classes = 'suit-tab suit-tab-sites'
272
Siobhan Tullyd3515752013-06-21 16:34:53 -0400273class SiteInline(PlStackTabularInline):
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400274 model = Site
275 extra = 0
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400276 suit_classes = 'suit-tab suit-tab-sites'
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400277
Tony Mack5b061472014-02-04 07:57:10 -0500278 def queryset(self, request):
279 return Site.select_by_user(request.user)
280
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500281class UserROInline(ReadOnlyTabularInline):
282 model = User
283 fields = ['email', 'firstname', 'lastname']
284 extra = 0
285 suit_classes = 'suit-tab suit-tab-users'
286
Siobhan Tullyd3515752013-06-21 16:34:53 -0400287class UserInline(PlStackTabularInline):
Siobhan Tully30fd4292013-05-10 08:59:56 -0400288 model = User
Siobhan Tully47ae1b52013-05-10 15:53:14 -0400289 fields = ['email', 'firstname', 'lastname']
Siobhan Tully30fd4292013-05-10 08:59:56 -0400290 extra = 0
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400291 suit_classes = 'suit-tab suit-tab-users'
Siobhan Tully30fd4292013-05-10 08:59:56 -0400292
Tony Mack5b061472014-02-04 07:57:10 -0500293 def queryset(self, request):
294 return User.select_by_user(request.user)
295
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500296class SliceROInline(ReadOnlyTabularInline):
297 model = Slice
298 suit_classes = 'suit-tab suit-tab-slices'
299 fields = ['name','site', 'serviceClass', 'service']
300
Siobhan Tullyd3515752013-06-21 16:34:53 -0400301class SliceInline(PlStackTabularInline):
Tony Mack00d361f2013-04-28 10:28:42 -0400302 model = Slice
Siobhan Tullyce652d02013-10-08 21:52:35 -0400303 fields = ['name','site', 'serviceClass', 'service']
Tony Mack00d361f2013-04-28 10:28:42 -0400304 extra = 0
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400305 suit_classes = 'suit-tab suit-tab-slices'
306
Tony Mack5b061472014-02-04 07:57:10 -0500307 def queryset(self, request):
308 return Slice.select_by_user(request.user)
309
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500310class NodeROInline(ReadOnlyTabularInline):
311 model = Node
312 extra = 0
313 suit_classes = 'suit-tab suit-tab-nodes'
314 fields = ['name','deployment']
Tony Mack00d361f2013-04-28 10:28:42 -0400315
Siobhan Tullyd3515752013-06-21 16:34:53 -0400316class NodeInline(PlStackTabularInline):
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400317 model = Node
318 extra = 0
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400319 suit_classes = 'suit-tab suit-tab-nodes'
Tony Mack5b061472014-02-04 07:57:10 -0500320 fields = ['name','deployment']
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400321
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500322class DeploymentPrivilegeROInline(ReadOnlyTabularInline):
323 model = DeploymentPrivilege
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400324 extra = 0
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500325 suit_classes = 'suit-tab suit-tab-deploymentprivileges'
Scott Baker3ca51f62014-05-23 12:05:11 -0700326 fields = ['user','role','deployment']
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400327
328class DeploymentPrivilegeInline(PlStackTabularInline):
329 model = DeploymentPrivilege
330 extra = 0
331 suit_classes = 'suit-tab suit-tab-deploymentprivileges'
Scott Baker3ca51f62014-05-23 12:05:11 -0700332 fields = ['user','role','deployment']
Tony Mack5b061472014-02-04 07:57:10 -0500333
334 def queryset(self, request):
335 return DeploymentPrivilege.select_by_user(request.user)
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400336
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500337#CLEANUP DOUBLE SitePrivilegeInline
338class SitePrivilegeROInline(ReadOnlyTabularInline):
339 model = SitePrivilege
340 extra = 0
341 suit_classes = 'suit-tab suit-tab-siteprivileges'
342 fields = ['user','site', 'role']
343
Siobhan Tullyd3515752013-06-21 16:34:53 -0400344class SitePrivilegeInline(PlStackTabularInline):
Siobhan Tullyaa1bcd52013-05-10 12:43:09 -0400345 model = SitePrivilege
346 extra = 0
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400347 suit_classes = 'suit-tab suit-tab-siteprivileges'
Tony Mack5b061472014-02-04 07:57:10 -0500348 fields = ['user','site', 'role']
Siobhan Tullyaa1bcd52013-05-10 12:43:09 -0400349
Tony Mackc2835a92013-05-28 09:18:49 -0400350 def formfield_for_foreignkey(self, db_field, request, **kwargs):
351 if db_field.name == 'site':
Tony Mack5b061472014-02-04 07:57:10 -0500352 kwargs['queryset'] = Site.select_by_user(request.user)
Tony Mackc2835a92013-05-28 09:18:49 -0400353
354 if db_field.name == 'user':
Tony Mack5b061472014-02-04 07:57:10 -0500355 kwargs['queryset'] = User.select_by_user(request.user)
Tony Mackc2835a92013-05-28 09:18:49 -0400356 return super(SitePrivilegeInline, self).formfield_for_foreignkey(db_field, request, **kwargs)
357
Tony Mack5b061472014-02-04 07:57:10 -0500358 def queryset(self, request):
359 return SitePrivilege.select_by_user(request.user)
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400360
Tony Macke4be32f2014-03-11 20:45:25 -0400361class SiteDeploymentROInline(ReadOnlyTabularInline):
362 model = SiteDeployments
363 #model = Site.deployments.through
364 extra = 0
Scott Bakerf3982522014-05-23 11:58:20 -0700365 suit_classes = 'suit-tab suit-tab-deployments'
Tony Macke4be32f2014-03-11 20:45:25 -0400366 fields = ['deployment','site']
367
368class SiteDeploymentInline(PlStackTabularInline):
369 model = SiteDeployments
370 #model = Site.deployments.through
371 extra = 0
372 suit_classes = 'suit-tab suit-tab-deployments'
373 fields = ['deployment','site']
374
375 def formfield_for_foreignkey(self, db_field, request, **kwargs):
376 if db_field.name == 'site':
377 kwargs['queryset'] = Site.select_by_user(request.user)
378
379 if db_field.name == 'deployment':
380 kwargs['queryset'] = Deployment.select_by_user(request.user)
381 return super(SiteDeploymentInline, self).formfield_for_foreignkey(db_field, request, **kwargs)
382
383 def queryset(self, request):
384 return SiteDeployments.select_by_user(request.user)
385
386
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500387class SlicePrivilegeROInline(ReadOnlyTabularInline):
388 model = SlicePrivilege
389 extra = 0
390 suit_classes = 'suit-tab suit-tab-sliceprivileges'
391 fields = ['user', 'slice', 'role']
392
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400393class SlicePrivilegeInline(PlStackTabularInline):
394 model = SlicePrivilege
395 suit_classes = 'suit-tab suit-tab-sliceprivileges'
396 extra = 0
397 fields = ('user', 'slice','role')
Siobhan Tullyaa1bcd52013-05-10 12:43:09 -0400398
Tony Mackc2835a92013-05-28 09:18:49 -0400399 def formfield_for_foreignkey(self, db_field, request, **kwargs):
400 if db_field.name == 'slice':
Tony Mack5b061472014-02-04 07:57:10 -0500401 kwargs['queryset'] = Slice.select_by_user(request.user)
Tony Mackc2835a92013-05-28 09:18:49 -0400402 if db_field.name == 'user':
Tony Mack5b061472014-02-04 07:57:10 -0500403 kwargs['queryset'] = User.select_by_user(request.user)
Tony Mackc2835a92013-05-28 09:18:49 -0400404
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400405 return super(SlicePrivilegeInline, self).formfield_for_foreignkey(db_field, request, **kwargs)
Tony Mackc2835a92013-05-28 09:18:49 -0400406
Tony Mack5b061472014-02-04 07:57:10 -0500407 def queryset(self, request):
408 return SlicePrivilege.select_by_user(request.user)
409
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500410class SliceNetworkROInline(ReadOnlyTabularInline):
411 model = Network.slices.through
412 extra = 0
413 verbose_name = "Network Connection"
414 verbose_name_plural = "Network Connections"
415 suit_classes = 'suit-tab suit-tab-slicenetworks'
416 fields = ['network']
417
Scott Bakera0015eb2013-08-14 17:28:14 -0700418class SliceNetworkInline(PlStackTabularInline):
Scott Baker74d8e622013-07-29 16:04:22 -0700419 model = Network.slices.through
Scott Baker874936e2014-01-13 18:15:34 -0800420 selflink_fieldname = "network"
Scott Baker74d8e622013-07-29 16:04:22 -0700421 extra = 0
422 verbose_name = "Network Connection"
423 verbose_name_plural = "Network Connections"
Siobhan Tully2d95e482013-09-06 10:56:06 -0400424 suit_classes = 'suit-tab suit-tab-slicenetworks'
Scott Baker74d8e622013-07-29 16:04:22 -0700425
Tony Mack5e71a662013-05-03 23:30:41 -0400426class PlainTextWidget(forms.HiddenInput):
427 input_type = 'hidden'
428
429 def render(self, name, value, attrs=None):
430 if value is None:
431 value = ''
Tony Mack1d6b85f2013-05-07 18:49:14 -0400432 return mark_safe(str(value) + super(PlainTextWidget, self).render(name, value, attrs))
Tony Mack9bcbe4f2013-04-29 08:13:27 -0400433
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500434class PlanetStackBaseAdmin(ReadOnlyAwareAdmin):
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400435 save_on_top = False
Tony Mack332ee1d2014-02-04 15:33:45 -0500436
437 def save_model(self, request, obj, form, change):
Tony Mack3d042792014-03-17 19:18:37 -0400438 obj.caller = request.user
Tony Mack332ee1d2014-02-04 15:33:45 -0500439 # update openstack connection to use this site/tenant
440 obj.save_by_user(request.user)
441
442 def delete_model(self, request, obj):
443 obj.delete_by_user(request.user)
444
445 def save_formset(self, request, form, formset, change):
446 instances = formset.save(commit=False)
447 for instance in instances:
448 instance.save_by_user(request.user)
449 formset.save_m2m()
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400450
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400451class SliceRoleAdmin(PlanetStackBaseAdmin):
452 model = SliceRole
453 pass
454
455class SiteRoleAdmin(PlanetStackBaseAdmin):
456 model = SiteRole
457 pass
458
Siobhan Tullybf1153a2013-05-27 20:53:48 -0400459class DeploymentAdminForm(forms.ModelForm):
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400460 sites = forms.ModelMultipleChoiceField(
461 queryset=Site.objects.all(),
462 required=False,
463 widget=FilteredSelectMultiple(
464 verbose_name=('Sites'), is_stacked=False
465 )
466 )
467 class Meta:
Siobhan Tullybf1153a2013-05-27 20:53:48 -0400468 model = Deployment
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400469
Siobhan Tully320b4622014-01-17 15:11:14 -0500470 def __init__(self, *args, **kwargs):
471 super(DeploymentAdminForm, self).__init__(*args, **kwargs)
472
473 if self.instance and self.instance.pk:
Scott Bakerc9b14f72014-05-22 13:44:20 -0700474 self.fields['sites'].initial = [x.site for x in self.instance.sitedeployments_set.all()]
Siobhan Tully320b4622014-01-17 15:11:14 -0500475
476 def save(self, commit=True):
477 deployment = super(DeploymentAdminForm, self).save(commit=False)
478
479 if commit:
480 deployment.save()
481
482 if deployment.pk:
Scott Bakerc9b14f72014-05-22 13:44:20 -0700483 # save_m2m() doesn't seem to work with 'through' relations. So we
484 # create/destroy the through models ourselves. There has to be
485 # a better way...
486
487 sites = self.cleaned_data['sites']
488
489 existing_sites = []
490 for sdp in list(deployment.sitedeployments_set.all()):
491 if sdp.site not in sites:
492 #print "deleting site", sdp.site
493 sdp.delete()
494 else:
495 existing_sites.append(sdp.site)
496
497 for site in sites:
498 if site not in existing_sites:
499 #print "adding site", site
500 sdp = SiteDeployments(site=site, deployment=deployment)
501 sdp.save()
502
Siobhan Tully320b4622014-01-17 15:11:14 -0500503 self.save_m2m()
504
505 return deployment
506
Scott Bakerff5e0f32014-05-22 14:40:27 -0700507class DeploymentAdminROForm(DeploymentAdminForm):
508 def save(self, commit=True):
509 raise PermissionDenied
510
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500511class SiteAssocInline(PlStackTabularInline):
512 model = Site.deployments.through
513 extra = 0
514 suit_classes = 'suit-tab suit-tab-sites'
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400515
Siobhan Tullybf1153a2013-05-27 20:53:48 -0400516class DeploymentAdmin(PlanetStackBaseAdmin):
Scott Bakerff5e0f32014-05-22 14:40:27 -0700517 #form = DeploymentAdminForm
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500518 model = Deployment
519 fieldList = ['name','sites']
520 fieldsets = [(None, {'fields': fieldList, 'classes':['suit-tab suit-tab-sites']})]
Siobhan Tully2d95e482013-09-06 10:56:06 -0400521 inlines = [DeploymentPrivilegeInline,NodeInline,TagInline]
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500522
523 user_readonly_inlines = [DeploymentPrivilegeROInline,NodeROInline,TagROInline]
524 user_readonly_fields = ['name']
525
526 suit_form_tabs =(('sites','Deployment Details'),('nodes','Nodes'),('deploymentprivileges','Privileges'),('tags','Tags'))
527
Scott Bakerff5e0f32014-05-22 14:40:27 -0700528 def get_form(self, request, obj=None, **kwargs):
529 if request.user.isReadOnlyUser():
530 kwargs["form"] = DeploymentAdminROForm
531 else:
532 kwargs["form"] = DeploymentAdminForm
533 return super(DeploymentAdmin,self).get_form(request, obj, **kwargs)
534
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500535class ServiceAttrAsTabROInline(ReadOnlyTabularInline):
536 model = ServiceAttribute
537 fields = ['name','value']
538 extra = 0
539 suit_classes = 'suit-tab suit-tab-serviceattrs'
Tony Mack5cd13202013-05-01 21:48:38 -0400540
Siobhan Tullyce652d02013-10-08 21:52:35 -0400541class ServiceAttrAsTabInline(PlStackTabularInline):
542 model = ServiceAttribute
543 fields = ['name','value']
544 extra = 0
545 suit_classes = 'suit-tab suit-tab-serviceattrs'
546
Siobhan Tullyce652d02013-10-08 21:52:35 -0400547class ServiceAdmin(PlanetStackBaseAdmin):
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500548 list_display = ("name","description","versionNumber","enabled","published")
549 fieldList = ["name","description","versionNumber","enabled","published"]
550 fieldsets = [(None, {'fields': fieldList, 'classes':['suit-tab suit-tab-general']})]
551 inlines = [ServiceAttrAsTabInline,SliceInline]
552
553 user_readonly_fields = fieldList
554 user_readonly_inlines = [ServiceAttrAsTabROInline,SliceROInline]
555
556 suit_form_tabs =(('general', 'Service Details'),
557 ('slices','Slices'),
558 ('serviceattrs','Additional Attributes'),
559 )
Siobhan Tullyce652d02013-10-08 21:52:35 -0400560
Tony Mack0553f282013-06-10 22:54:50 -0400561class SiteAdmin(PlanetStackBaseAdmin):
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500562 fieldList = ['name', 'site_url', 'enabled', 'is_public', 'login_base', 'accountLink','location']
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400563 fieldsets = [
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500564 (None, {'fields': fieldList, 'classes':['suit-tab suit-tab-general']}),
Tony Macke4be32f2014-03-11 20:45:25 -0400565 #('Deployment Networks', {'fields': ['deployments'], 'classes':['suit-tab suit-tab-deployments']}),
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400566 ]
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400567 suit_form_tabs =(('general', 'Site Details'),
568 ('users','Users'),
Siobhan Tully2d95e482013-09-06 10:56:06 -0400569 ('siteprivileges','Privileges'),
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400570 ('deployments','Deployments'),
571 ('slices','Slices'),
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500572 ('nodes','Nodes'),
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400573 ('tags','Tags'),
574 )
Scott Baker545db2a2013-12-09 18:44:43 -0800575 readonly_fields = ['accountLink']
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500576
577 user_readonly_fields = ['name', 'deployments','site_url', 'enabled', 'is_public', 'login_base', 'accountLink']
Tony Macke4be32f2014-03-11 20:45:25 -0400578 user_readonly_inlines = [SliceROInline,UserROInline,TagROInline, NodeROInline, SitePrivilegeROInline,SiteDeploymentROInline]
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500579
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400580 list_display = ('name', 'login_base','site_url', 'enabled')
581 filter_horizontal = ('deployments',)
Tony Macke4be32f2014-03-11 20:45:25 -0400582 inlines = [SliceInline,UserInline,TagInline, NodeInline, SitePrivilegeInline, SiteDeploymentInline]
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400583 search_fields = ['name']
584
Tony Mack04062832013-05-10 08:22:44 -0400585 def queryset(self, request):
Tony Mack5b061472014-02-04 07:57:10 -0500586 return Site.select_by_user(request.user)
Tony Mack04062832013-05-10 08:22:44 -0400587
Tony Mack5cd13202013-05-01 21:48:38 -0400588 def get_formsets(self, request, obj=None):
589 for inline in self.get_inline_instances(request, obj):
590 # hide MyInline in the add view
591 if obj is None:
592 continue
Tony Mack2bd5b412013-06-11 21:05:06 -0400593 if isinstance(inline, SliceInline):
594 inline.model.caller = request.user
595 yield inline.get_formset(request, obj)
596
597 def get_formsets(self, request, obj=None):
598 for inline in self.get_inline_instances(request, obj):
599 # hide MyInline in the add view
600 if obj is None:
601 continue
602 if isinstance(inline, SliverInline):
603 inline.model.caller = request.user
Tony Mack5cd13202013-05-01 21:48:38 -0400604 yield inline.get_formset(request, obj)
605
Scott Baker545db2a2013-12-09 18:44:43 -0800606 def accountLink(self, obj):
607 link_obj = obj.accounts.all()
608 if link_obj:
609 reverse_path = "admin:core_account_change"
610 url = reverse(reverse_path, args =(link_obj[0].id,))
611 return "<a href='%s'>%s</a>" % (url, "view billing details")
612 else:
613 return "no billing data for this site"
614 accountLink.allow_tags = True
615 accountLink.short_description = "Billing"
616
Tony Mack332ee1d2014-02-04 15:33:45 -0500617 def save_model(self, request, obj, form, change):
618 # update openstack connection to use this site/tenant
619 obj.save_by_user(request.user)
620
621 def delete_model(self, request, obj):
622 obj.delete_by_user(request.user)
623
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500624
Tony Mack9bcbe4f2013-04-29 08:13:27 -0400625class SitePrivilegeAdmin(PlanetStackBaseAdmin):
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500626 fieldList = ['user', 'site', 'role']
Tony Mack00d361f2013-04-28 10:28:42 -0400627 fieldsets = [
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500628 (None, {'fields': fieldList, 'classes':['collapse']})
Tony Mack00d361f2013-04-28 10:28:42 -0400629 ]
630 list_display = ('user', 'site', 'role')
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500631 user_readonly_fields = fieldList
632 user_readonly_inlines = []
Tony Mack00d361f2013-04-28 10:28:42 -0400633
Tony Mackc2835a92013-05-28 09:18:49 -0400634 def formfield_for_foreignkey(self, db_field, request, **kwargs):
635 if db_field.name == 'site':
636 if not request.user.is_admin:
637 # only show sites where user is an admin or pi
638 sites = set()
639 for site_privilege in SitePrivilege.objects.filer(user=request.user):
640 if site_privilege.role.role_type in ['admin', 'pi']:
641 sites.add(site_privilege.site)
642 kwargs['queryset'] = Site.objects.filter(site__in=list(sites))
643
644 if db_field.name == 'user':
645 if not request.user.is_admin:
646 # only show users from sites where caller has admin or pi role
647 roles = Role.objects.filter(role_type__in=['admin', 'pi'])
648 site_privileges = SitePrivilege.objects.filter(user=request.user).filter(role__in=roles)
649 sites = [site_privilege.site for site_privilege in site_privileges]
650 site_privileges = SitePrivilege.objects.filter(site__in=sites)
651 emails = [site_privilege.user.email for site_privilege in site_privileges]
652 users = User.objects.filter(email__in=emails)
653 kwargs['queryset'] = users
654
655 return super(SitePrivilegeAdmin, self).formfield_for_foreignkey(db_field, request, **kwargs)
656
Tony Mack04062832013-05-10 08:22:44 -0400657 def queryset(self, request):
658 # admins can see all privileges. Users can only see privileges at sites
Tony Mackc2835a92013-05-28 09:18:49 -0400659 # where they have the admin role or pi role.
Tony Mack04062832013-05-10 08:22:44 -0400660 qs = super(SitePrivilegeAdmin, self).queryset(request)
Tony Mack5b061472014-02-04 07:57:10 -0500661 #if not request.user.is_admin:
662 # roles = Role.objects.filter(role_type__in=['admin', 'pi'])
663 # site_privileges = SitePrivilege.objects.filter(user=request.user).filter(role__in=roles)
664 # login_bases = [site_privilege.site.login_base for site_privilege in site_privileges]
665 # sites = Site.objects.filter(login_base__in=login_bases)
666 # qs = qs.filter(site__in=sites)
Tony Mack04062832013-05-10 08:22:44 -0400667 return qs
668
Siobhan Tullyce652d02013-10-08 21:52:35 -0400669class SliceForm(forms.ModelForm):
670 class Meta:
671 model = Slice
672 widgets = {
673 'service': LinkedSelect
674 }
675
Tony Mack2bd5b412013-06-11 21:05:06 -0400676class SliceAdmin(PlanetStackBaseAdmin):
Siobhan Tullyce652d02013-10-08 21:52:35 -0400677 form = SliceForm
Tony Mack29bf5e82014-04-29 21:40:24 -0400678 fieldList = ['name', 'site', 'serviceClass', 'enabled','description', 'service', 'slice_url', 'max_slivers']
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500679 fieldsets = [('Slice Details', {'fields': fieldList, 'classes':['suit-tab suit-tab-general']}),]
Tony Mack29bf5e82014-04-29 21:40:24 -0400680 list_display = ('name', 'site','serviceClass', 'slice_url', 'max_slivers')
Siobhan Tully2d95e482013-09-06 10:56:06 -0400681 inlines = [SlicePrivilegeInline,SliverInline, TagInline, ReservationInline,SliceNetworkInline]
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400682
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500683 user_readonly_fields = fieldList
684 user_readonly_inlines = [SlicePrivilegeROInline,SliverROInline,TagROInline, ReservationROInline, SliceNetworkROInline]
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400685
686 suit_form_tabs =(('general', 'Slice Details'),
Siobhan Tully2d95e482013-09-06 10:56:06 -0400687 ('slicenetworks','Networks'),
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400688 ('sliceprivileges','Privileges'),
689 ('slivers','Slivers'),
690 ('tags','Tags'),
691 ('reservations','Reservations'),
692 )
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400693
Tony Mackc2835a92013-05-28 09:18:49 -0400694 def formfield_for_foreignkey(self, db_field, request, **kwargs):
695 if db_field.name == 'site':
Tony Mack5b061472014-02-04 07:57:10 -0500696 kwargs['queryset'] = Site.select_by_user(request.user)
697
Tony Mackc2835a92013-05-28 09:18:49 -0400698 return super(SliceAdmin, self).formfield_for_foreignkey(db_field, request, **kwargs)
699
Tony Mack04062832013-05-10 08:22:44 -0400700 def queryset(self, request):
701 # admins can see all keys. Users can only see slices they belong to.
Tony Mack5b061472014-02-04 07:57:10 -0500702 return Slice.select_by_user(request.user)
Tony Mack04062832013-05-10 08:22:44 -0400703
Tony Mack79748612013-05-01 14:52:03 -0400704 def get_formsets(self, request, obj=None):
705 for inline in self.get_inline_instances(request, obj):
706 # hide MyInline in the add view
707 if obj is None:
708 continue
Tony Mack2bd5b412013-06-11 21:05:06 -0400709 if isinstance(inline, SliverInline):
710 inline.model.caller = request.user
Tony Mack79748612013-05-01 14:52:03 -0400711 yield inline.get_formset(request, obj)
712
Tony Mack2bd5b412013-06-11 21:05:06 -0400713
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400714class SlicePrivilegeAdmin(PlanetStackBaseAdmin):
Tony Mack00d361f2013-04-28 10:28:42 -0400715 fieldsets = [
716 (None, {'fields': ['user', 'slice', 'role']})
717 ]
718 list_display = ('user', 'slice', 'role')
Tony Mack00d361f2013-04-28 10:28:42 -0400719
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500720 user_readonly_fields = ['user', 'slice', 'role']
721 user_readonly_inlines = []
722
Tony Mackc2835a92013-05-28 09:18:49 -0400723 def formfield_for_foreignkey(self, db_field, request, **kwargs):
724 if db_field.name == 'slice':
Tony Mack5b061472014-02-04 07:57:10 -0500725 kwargs['queryset'] = Slice.select_by_user(request.user)
Tony Mackc2835a92013-05-28 09:18:49 -0400726
727 if db_field.name == 'user':
Tony Mack5b061472014-02-04 07:57:10 -0500728 kwargs['queryset'] = User.select_by_user(request.user)
Tony Mackc2835a92013-05-28 09:18:49 -0400729
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400730 return super(SlicePrivilegeAdmin, self).formfield_for_foreignkey(db_field, request, **kwargs)
Tony Mackc2835a92013-05-28 09:18:49 -0400731
Tony Mack04062832013-05-10 08:22:44 -0400732 def queryset(self, request):
733 # admins can see all memberships. Users can only see memberships of
734 # slices where they have the admin role.
Tony Mack5b061472014-02-04 07:57:10 -0500735 return SlicePrivilege.select_by_user(request.user)
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400736
Tony Mack9bcbe4f2013-04-29 08:13:27 -0400737 def save_model(self, request, obj, form, change):
Tony Mack951dab42013-05-02 19:51:45 -0400738 # update openstack connection to use this site/tenant
739 auth = request.session.get('auth', {})
740 auth['tenant'] = obj.slice.name
741 obj.os_manager = OpenStackManager(auth=auth, caller=request.user)
Tony Mack9bcbe4f2013-04-29 08:13:27 -0400742 obj.save()
743
744 def delete_model(self, request, obj):
Tony Mack951dab42013-05-02 19:51:45 -0400745 # update openstack connection to use this site/tenant
746 auth = request.session.get('auth', {})
747 auth['tenant'] = obj.slice.name
748 obj.os_manager = OpenStackManager(auth=auth, caller=request.user)
Tony Mack9bcbe4f2013-04-29 08:13:27 -0400749 obj.delete()
750
Siobhan Tully567e3e62013-06-21 18:03:16 -0400751
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400752class ImageAdmin(PlanetStackBaseAdmin):
753
754 fieldsets = [('Image Details',
Scott Baker00b00b32014-05-07 08:47:54 -0700755 {'fields': ['name', 'disk_format', 'container_format'],
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400756 'classes': ['suit-tab suit-tab-general']})
757 ]
758
759 suit_form_tabs =(('general','Image Details'),('slivers','Slivers'))
760
761 inlines = [SliverInline]
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500762
Tony Mack32e1ce32014-05-07 13:29:41 -0400763 user_readonly_fields = ['name', 'disk_format', 'container_format']
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500764 user_readonly_inlines = [SliverROInline]
765
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400766class NodeForm(forms.ModelForm):
767 class Meta:
768 widgets = {
769 'site': LinkedSelect,
770 'deployment': LinkedSelect
771 }
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400772
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500773class NodeAdmin(PlanetStackBaseAdmin):
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400774 form = NodeForm
Siobhan Tullybf1153a2013-05-27 20:53:48 -0400775 list_display = ('name', 'site', 'deployment')
776 list_filter = ('deployment',)
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500777
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400778 inlines = [TagInline,SliverInline]
779 fieldsets = [('Node Details', {'fields': ['name','site','deployment'], 'classes':['suit-tab suit-tab-details']})]
780
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500781 user_readonly_fields = ['name','site','deployment']
782 user_readonly_inlines = [TagInline,SliverInline]
783
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400784 suit_form_tabs =(('details','Node Details'),('slivers','Slivers'),('tags','Tags'))
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400785
Siobhan Tully567e3e62013-06-21 18:03:16 -0400786
Tony Mackd90cdbf2013-04-16 22:48:40 -0400787class SliverForm(forms.ModelForm):
788 class Meta:
Tony Mack1d6b85f2013-05-07 18:49:14 -0400789 model = Sliver
Tony Mackd90cdbf2013-04-16 22:48:40 -0400790 ip = forms.CharField(widget=PlainTextWidget)
Tony Mack18261812013-05-02 16:39:20 -0400791 instance_name = forms.CharField(widget=PlainTextWidget)
Tony Mackd90cdbf2013-04-16 22:48:40 -0400792 widgets = {
793 'ip': PlainTextWidget(),
Tony Mack18261812013-05-02 16:39:20 -0400794 'instance_name': PlainTextWidget(),
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400795 'slice': LinkedSelect,
796 'deploymentNetwork': LinkedSelect,
797 'node': LinkedSelect,
798 'image': LinkedSelect
Siobhan Tully53437282013-04-26 19:30:27 -0400799 }
Tony Mackd90cdbf2013-04-16 22:48:40 -0400800
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500801class TagAdmin(PlanetStackBaseAdmin):
Siobhan Tullyce652d02013-10-08 21:52:35 -0400802 list_display = ['service', 'name', 'value', 'content_type', 'content_object',]
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500803 user_readonly_fields = ['service', 'name', 'value', 'content_type', 'content_object',]
804 user_readonly_inlines = []
Siobhan Tullyd3515752013-06-21 16:34:53 -0400805
Tony Mack9bcbe4f2013-04-29 08:13:27 -0400806class SliverAdmin(PlanetStackBaseAdmin):
Tony Mackd90cdbf2013-04-16 22:48:40 -0400807 form = SliverForm
Tony Mackcdec0902013-04-15 00:38:49 -0400808 fieldsets = [
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400809 ('Sliver Details', {'fields': ['slice', 'deploymentNetwork', 'node', 'ip', 'instance_name', 'numberCores', 'image', ], 'classes': ['suit-tab suit-tab-general'], })
Tony Mackcdec0902013-04-15 00:38:49 -0400810 ]
Siobhan Tully5d7dc8d2013-07-02 13:17:33 -0400811 list_display = ['ip', 'instance_name', 'slice', 'numberCores', 'image', 'node', 'deploymentNetwork']
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400812
813 suit_form_tabs =(('general', 'Sliver Details'),
814 ('tags','Tags'),
815 )
816
Siobhan Tullyde5450d2013-06-21 11:35:33 -0400817 inlines = [TagInline]
Tony Mack53106f32013-04-27 16:43:01 -0400818
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500819 user_readonly_fields = ['slice', 'deploymentNetwork', 'node', 'ip', 'instance_name', 'numberCores', 'image']
820 user_readonly_inlines = [TagROInline]
821
Tony Mackc2835a92013-05-28 09:18:49 -0400822 def formfield_for_foreignkey(self, db_field, request, **kwargs):
823 if db_field.name == 'slice':
Tony Mack5b061472014-02-04 07:57:10 -0500824 kwargs['queryset'] = Slice.select_by_user(request.user)
Tony Mackc2835a92013-05-28 09:18:49 -0400825
826 return super(SliverAdmin, self).formfield_for_foreignkey(db_field, request, **kwargs)
827
Tony Mack04062832013-05-10 08:22:44 -0400828 def queryset(self, request):
829 # admins can see all slivers. Users can only see slivers of
830 # the slices they belong to.
Tony Mack5b061472014-02-04 07:57:10 -0500831 return Sliver.select_by_user(request.user)
832
Tony Mack04062832013-05-10 08:22:44 -0400833
Tony Mack1d6b85f2013-05-07 18:49:14 -0400834 def get_formsets(self, request, obj=None):
835 # make some fields read only if we are updating an existing record
836 if obj == None:
837 #self.readonly_fields = ('ip', 'instance_name')
838 self.readonly_fields = ()
839 else:
Tony Mack1e889462013-05-10 21:34:54 -0400840 self.readonly_fields = ()
841 #self.readonly_fields = ('ip', 'instance_name', 'slice', 'image', 'key')
Tony Mack1d6b85f2013-05-07 18:49:14 -0400842
843 for inline in self.get_inline_instances(request, obj):
844 # hide MyInline in the add view
845 if obj is None:
846 continue
Scott Baker526b71e2014-05-13 13:18:01 -0700847 if isinstance(inline, SliverInline):
848 inline.model.caller = request.user
849 yield inline.get_formset(request, obj)
Tony Mack53106f32013-04-27 16:43:01 -0400850
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500851 #def save_model(self, request, obj, form, change):
852 # # update openstack connection to use this site/tenant
853 # auth = request.session.get('auth', {})
854 # auth['tenant'] = obj.slice.name
855 # obj.os_manager = OpenStackManager(auth=auth, caller=request.user)
856 # obj.creator = request.user
857 # obj.save()
Tony Mack53106f32013-04-27 16:43:01 -0400858
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500859 #def delete_model(self, request, obj):
860 # # update openstack connection to use this site/tenant
861 # auth = request.session.get('auth', {})
862 # auth['tenant'] = obj.slice.name
863 # obj.os_manager = OpenStackManager(auth=auth, caller=request.user)
864 # obj.delete()
Tony Mackcdec0902013-04-15 00:38:49 -0400865
Siobhan Tully53437282013-04-26 19:30:27 -0400866class UserCreationForm(forms.ModelForm):
867 """A form for creating new users. Includes all the required
868 fields, plus a repeated password."""
869 password1 = forms.CharField(label='Password', widget=forms.PasswordInput)
870 password2 = forms.CharField(label='Password confirmation', widget=forms.PasswordInput)
871
872 class Meta:
Siobhan Tully30fd4292013-05-10 08:59:56 -0400873 model = User
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400874 fields = ('email', 'firstname', 'lastname', 'phone', 'public_key')
Siobhan Tully53437282013-04-26 19:30:27 -0400875
876 def clean_password2(self):
877 # Check that the two password entries match
878 password1 = self.cleaned_data.get("password1")
879 password2 = self.cleaned_data.get("password2")
880 if password1 and password2 and password1 != password2:
881 raise forms.ValidationError("Passwords don't match")
882 return password2
883
884 def save(self, commit=True):
885 # Save the provided password in hashed format
886 user = super(UserCreationForm, self).save(commit=False)
Tony Mackf9f4afb2013-05-01 21:02:12 -0400887 user.password = self.cleaned_data["password1"]
888 #user.set_password(self.cleaned_data["password1"])
Siobhan Tully53437282013-04-26 19:30:27 -0400889 if commit:
890 user.save()
891 return user
892
Siobhan Tully567e3e62013-06-21 18:03:16 -0400893
Siobhan Tully53437282013-04-26 19:30:27 -0400894class UserChangeForm(forms.ModelForm):
895 """A form for updating users. Includes all the fields on
896 the user, but replaces the password field with admin's
897 password hash display field.
898 """
Siobhan Tully63b7ba42014-01-12 10:35:11 -0500899 password = ReadOnlyPasswordHashField(label='Password',
900 help_text= '<a href=\"password/\">Change Password</a>.')
Siobhan Tully53437282013-04-26 19:30:27 -0400901
902 class Meta:
Siobhan Tully30fd4292013-05-10 08:59:56 -0400903 model = User
Siobhan Tully53437282013-04-26 19:30:27 -0400904
905 def clean_password(self):
906 # Regardless of what the user provides, return the initial value.
907 # This is done here, rather than on the field, because the
908 # field does not have access to the initial value
909 return self.initial["password"]
910
Scott Baker2c3cb642014-05-19 17:55:56 -0700911class UserDashboardViewInline(PlStackTabularInline):
912 model = UserDashboardView
913 extra = 0
914 suit_classes = 'suit-tab suit-tab-dashboards'
915 fields = ['user', 'dashboardView', 'order']
916
Scott Bakered31f672014-05-21 18:14:03 -0700917class UserDashboardViewROInline(ReadOnlyTabularInline):
918 model = UserDashboardView
919 extra = 0
920 suit_classes = 'suit-tab suit-tab-dashboards'
921 fields = ['user', 'dashboardView', 'order']
922
Tony Mack2bd5b412013-06-11 21:05:06 -0400923class UserAdmin(UserAdmin):
Siobhan Tully53437282013-04-26 19:30:27 -0400924 class Meta:
925 app_label = "core"
926
927 # The forms to add and change user instances
928 form = UserChangeForm
929 add_form = UserCreationForm
930
931 # The fields to be used in displaying the User model.
932 # These override the definitions on the base UserAdmin
933 # that reference specific fields on auth.User.
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500934 list_display = ('email', 'firstname', 'lastname', 'site', 'last_login')
Siobhan Tullyce652d02013-10-08 21:52:35 -0400935 #list_display = ('email', 'username','firstname', 'lastname', 'is_admin', 'last_login')
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500936 list_filter = ('site',)
Scott Baker2c3cb642014-05-19 17:55:56 -0700937 inlines = [SlicePrivilegeInline,SitePrivilegeInline,DeploymentPrivilegeInline,UserDashboardViewInline]
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500938
939 fieldListLoginDetails = ['email','site','password','is_readonly','is_amin','public_key']
940 fieldListContactInfo = ['firstname','lastname','phone','timezone']
941
Siobhan Tully53437282013-04-26 19:30:27 -0400942 fieldsets = (
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500943 ('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 -0400944 ('Contact Information', {'fields': ('firstname','lastname','phone', 'timezone'), 'classes':['suit-tab suit-tab-contact']}),
Scott Baker2c3cb642014-05-19 17:55:56 -0700945 #('Dashboard Views', {'fields': ('dashboards',), 'classes':['suit-tab suit-tab-dashboards']}),
Siobhan Tully53437282013-04-26 19:30:27 -0400946 #('Important dates', {'fields': ('last_login',)}),
947 )
948 add_fieldsets = (
949 (None, {
950 'classes': ('wide',),
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500951 'fields': ('email', 'firstname', 'lastname', 'is_readonly', 'phone', 'public_key','password1', 'password2')}
Siobhan Tully53437282013-04-26 19:30:27 -0400952 ),
953 )
954 search_fields = ('email',)
955 ordering = ('email',)
956 filter_horizontal = ()
957
Scott Baker3ca51f62014-05-23 12:05:11 -0700958 user_readonly_fields = fieldListLoginDetails + fieldListContactInfo
Scott Bakered31f672014-05-21 18:14:03 -0700959 user_readonly_inlines = [SlicePrivilegeROInline,SitePrivilegeROInline,DeploymentPrivilegeROInline,UserDashboardViewROInline]
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500960
Scott Baker2c3cb642014-05-19 17:55:56 -0700961 suit_form_tabs =(('general','Login Details'),
962 ('contact','Contact Information'),
963 ('sliceprivileges','Slice Privileges'),
964 ('siteprivileges','Site Privileges'),
965 ('deploymentprivileges','Deployment Privileges'),
966 ('dashboards','Dashboard Views'))
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400967
Tony Mackc2835a92013-05-28 09:18:49 -0400968 def formfield_for_foreignkey(self, db_field, request, **kwargs):
969 if db_field.name == 'site':
Tony Mack5b061472014-02-04 07:57:10 -0500970 kwargs['queryset'] = Site.select_by_user(request.user)
Tony Mackc2835a92013-05-28 09:18:49 -0400971
972 return super(UserAdmin, self).formfield_for_foreignkey(db_field, request, **kwargs)
973
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500974 def has_add_permission(self, request, obj=None):
975 return (not self.__user_is_readonly(request))
976
977 def has_delete_permission(self, request, obj=None):
978 return (not self.__user_is_readonly(request))
979
980 def get_actions(self,request):
981 actions = super(UserAdmin,self).get_actions(request)
982
983 if self.__user_is_readonly(request):
984 if 'delete_selected' in actions:
985 del actions['delete_selected']
986
987 return actions
988
989 def change_view(self,request,object_id, extra_context=None):
990
991 if self.__user_is_readonly(request):
Scott Bakerf875eba2014-05-23 12:09:15 -0700992 if not hasattr(self, "readonly_save"):
993 # save the original readonly fields
994 self.readonly_save = self.readonly_fields
995 self.inlines_save = self.inlines
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500996 self.readonly_fields=self.user_readonly_fields
997 self.inlines = self.user_readonly_inlines
Scott Bakerf875eba2014-05-23 12:09:15 -0700998 else:
999 if hasattr(self, "readonly_save"):
1000 # restore the original readonly fields
1001 self.readonly_fields = self.readonly_save
1002 self.inlines = self.inlines_save
1003
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001004 try:
1005 return super(UserAdmin, self).change_view(request, object_id, extra_context=extra_context)
1006 except PermissionDenied:
1007 pass
1008 if request.method == 'POST':
1009 raise PermissionDenied
1010 request.readonly = True
1011 return super(UserAdmin, self).change_view(request, object_id, extra_context=extra_context)
1012
1013 def __user_is_readonly(self, request):
1014 #groups = [x.name for x in request.user.groups.all() ]
1015 #return "readonly" in groups
1016 return request.user.isReadOnlyUser()
1017
Tony Mack5b061472014-02-04 07:57:10 -05001018 def queryset(self, request):
1019 return User.select_by_user(request.user)
1020
Scott Baker2c3cb642014-05-19 17:55:56 -07001021class DashboardViewAdmin(PlanetStackBaseAdmin):
1022 fieldsets = [('Dashboard View Details',
1023 {'fields': ['name', 'url'],
1024 'classes': ['suit-tab suit-tab-general']})
1025 ]
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001026
Scott Baker2c3cb642014-05-19 17:55:56 -07001027 suit_form_tabs =(('general','Dashboard View Details'),)
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001028
1029class ServiceResourceROInline(ReadOnlyTabularInline):
1030 model = ServiceResource
1031 extra = 0
1032 fields = ['serviceClass', 'name', 'maxUnitsDeployment', 'maxUnitsNode', 'maxDuration', 'bucketInRate', 'bucketMaxSize', 'cost', 'calendarReservable']
1033
Scott Baker0165fac2014-01-13 11:49:26 -08001034class ServiceResourceInline(PlStackTabularInline):
Scott Baker3de3e372013-05-10 16:50:44 -07001035 model = ServiceResource
1036 extra = 0
1037
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001038class ServiceClassAdmin(PlanetStackBaseAdmin):
Scott Baker3de3e372013-05-10 16:50:44 -07001039 list_display = ('name', 'commitment', 'membershipFee')
1040 inlines = [ServiceResourceInline]
1041
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001042 user_readonly_fields = ['name', 'commitment', 'membershipFee']
1043 user_readonly_inlines = []
1044
1045class ReservedResourceROInline(ReadOnlyTabularInline):
1046 model = ReservedResource
1047 extra = 0
1048 fields = ['sliver', 'resource','quantity','reservationSet']
1049 suit_classes = 'suit-tab suit-tab-reservedresources'
1050
Scott Baker0165fac2014-01-13 11:49:26 -08001051class ReservedResourceInline(PlStackTabularInline):
Scott Baker133c9212013-05-17 09:09:11 -07001052 model = ReservedResource
1053 extra = 0
Siobhan Tullybfd11dc2013-09-03 12:59:24 -04001054 suit_classes = 'suit-tab suit-tab-reservedresources'
Scott Baker133c9212013-05-17 09:09:11 -07001055
1056 def formfield_for_foreignkey(self, db_field, request=None, **kwargs):
1057 field = super(ReservedResourceInline, self).formfield_for_foreignkey(db_field, request, **kwargs)
1058
1059 if db_field.name == 'resource':
1060 # restrict resources to those that the slice's service class allows
1061 if request._slice is not None:
1062 field.queryset = field.queryset.filter(serviceClass = request._slice.serviceClass, calendarReservable=True)
1063 if len(field.queryset) > 0:
1064 field.initial = field.queryset.all()[0]
1065 else:
1066 field.queryset = field.queryset.none()
1067 elif db_field.name == 'sliver':
1068 # restrict slivers to those that belong to the slice
1069 if request._slice is not None:
1070 field.queryset = field.queryset.filter(slice = request._slice)
1071 else:
1072 field.queryset = field.queryset.none()
1073
1074 return field
1075
Tony Mack5b061472014-02-04 07:57:10 -05001076 def queryset(self, request):
1077 return ReservedResource.select_by_user(request.user)
1078
Scott Baker133c9212013-05-17 09:09:11 -07001079class ReservationChangeForm(forms.ModelForm):
1080 class Meta:
1081 model = Reservation
Siobhan Tullybfd11dc2013-09-03 12:59:24 -04001082 widgets = {
1083 'slice' : LinkedSelect
1084 }
Scott Baker133c9212013-05-17 09:09:11 -07001085
1086class ReservationAddForm(forms.ModelForm):
1087 slice = forms.ModelChoiceField(queryset=Slice.objects.all(), widget=forms.Select(attrs={"onChange":"document.getElementById('id_refresh').value=1; submit()"}))
1088 refresh = forms.CharField(widget=forms.HiddenInput())
1089
1090 class Media:
1091 css = {'all': ('planetstack.css',)} # .field-refresh { display: none; }
1092
1093 def clean_slice(self):
1094 slice = self.cleaned_data.get("slice")
1095 x = ServiceResource.objects.filter(serviceClass = slice.serviceClass, calendarReservable=True)
1096 if len(x) == 0:
1097 raise forms.ValidationError("The slice you selected does not have a service class that allows reservations")
1098 return slice
1099
1100 class Meta:
1101 model = Reservation
Siobhan Tullybfd11dc2013-09-03 12:59:24 -04001102 widgets = {
1103 'slice' : LinkedSelect
1104 }
1105
Scott Baker133c9212013-05-17 09:09:11 -07001106
1107class ReservationAddRefreshForm(ReservationAddForm):
1108 """ This form is displayed when the Reservation Form receives an update
1109 from the Slice dropdown onChange handler. It doesn't validate the
1110 data and doesn't save the data. This will cause the form to be
1111 redrawn.
1112 """
1113
Scott Baker8737e5f2013-05-17 09:35:32 -07001114 """ don't validate anything other than slice """
1115 dont_validate_fields = ("startTime", "duration")
1116
Scott Baker133c9212013-05-17 09:09:11 -07001117 def full_clean(self):
1118 result = super(ReservationAddForm, self).full_clean()
Scott Baker8737e5f2013-05-17 09:35:32 -07001119
1120 for fieldname in self.dont_validate_fields:
1121 if fieldname in self._errors:
1122 del self._errors[fieldname]
1123
Scott Baker133c9212013-05-17 09:09:11 -07001124 return result
1125
1126 """ don't save anything """
1127 def is_valid(self):
1128 return False
1129
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001130class ReservationAdmin(PlanetStackBaseAdmin):
1131 fieldList = ['slice', 'startTime', 'duration']
1132 fieldsets = [('Reservation Details', {'fields': fieldList, 'classes': ['suit-tab suit-tab-general']})]
Scott Baker133c9212013-05-17 09:09:11 -07001133 list_display = ('startTime', 'duration')
Scott Baker133c9212013-05-17 09:09:11 -07001134 form = ReservationAddForm
1135
Siobhan Tullybfd11dc2013-09-03 12:59:24 -04001136 suit_form_tabs = (('general','Reservation Details'), ('reservedresources','Reserved Resources'))
1137
1138 inlines = [ReservedResourceInline]
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001139 user_readonly_inlines = [ReservedResourceROInline]
1140 user_readonly_fields = fieldList
Siobhan Tullybfd11dc2013-09-03 12:59:24 -04001141
Scott Baker133c9212013-05-17 09:09:11 -07001142 def add_view(self, request, form_url='', extra_context=None):
Scott Bakeracd45142013-05-19 16:19:16 -07001143 timezone.activate(request.user.timezone)
Scott Baker133c9212013-05-17 09:09:11 -07001144 request._refresh = False
1145 request._slice = None
1146 if request.method == 'POST':
Scott Baker8737e5f2013-05-17 09:35:32 -07001147 # "refresh" will be set to "1" if the form was submitted due to
1148 # a change in the Slice dropdown.
Scott Baker133c9212013-05-17 09:09:11 -07001149 if request.POST.get("refresh","1") == "1":
1150 request._refresh = True
1151 request.POST["refresh"] = "0"
Scott Baker8737e5f2013-05-17 09:35:32 -07001152
1153 # Keep track of the slice that was selected, so the
1154 # reservedResource inline can filter items for the slice.
Scott Baker133c9212013-05-17 09:09:11 -07001155 request._slice = request.POST.get("slice",None)
1156 if (request._slice is not None):
1157 request._slice = Slice.objects.get(id=request._slice)
1158
1159 result = super(ReservationAdmin, self).add_view(request, form_url, extra_context)
1160 return result
1161
Scott Bakeracd45142013-05-19 16:19:16 -07001162 def changelist_view(self, request, extra_context = None):
1163 timezone.activate(request.user.timezone)
1164 return super(ReservationAdmin, self).changelist_view(request, extra_context)
1165
Scott Baker133c9212013-05-17 09:09:11 -07001166 def get_form(self, request, obj=None, **kwargs):
Siobhan Tullyd3515752013-06-21 16:34:53 -04001167 request._obj_ = obj
1168 if obj is not None:
1169 # For changes, set request._slice to the slice already set in the
1170 # object.
1171 request._slice = obj.slice
1172 self.form = ReservationChangeForm
1173 else:
1174 if getattr(request, "_refresh", False):
1175 self.form = ReservationAddRefreshForm
1176 else:
1177 self.form = ReservationAddForm
1178 return super(ReservationAdmin, self).get_form(request, obj, **kwargs)
1179
Scott Baker133c9212013-05-17 09:09:11 -07001180 def get_readonly_fields(self, request, obj=None):
Siobhan Tullyd3515752013-06-21 16:34:53 -04001181 if (obj is not None):
1182 # Prevent slice from being changed after the reservation has been
1183 # created.
1184 return ['slice']
1185 else:
Scott Baker133c9212013-05-17 09:09:11 -07001186 return []
Scott Baker3de3e372013-05-10 16:50:44 -07001187
Tony Mack5b061472014-02-04 07:57:10 -05001188 def queryset(self, request):
1189 return Reservation.select_by_user(request.user)
1190
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001191class NetworkParameterTypeAdmin(PlanetStackBaseAdmin):
Scott Baker74d8e622013-07-29 16:04:22 -07001192 list_display = ("name", )
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001193 user_readonly_fields = ['name']
1194 user_readonly_inlines = []
Scott Baker74d8e622013-07-29 16:04:22 -07001195
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001196class RouterAdmin(PlanetStackBaseAdmin):
Scott Baker74d8e622013-07-29 16:04:22 -07001197 list_display = ("name", )
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001198 user_readonly_fields = ['name']
1199 user_readonly_inlines = []
1200
1201class RouterROInline(ReadOnlyTabularInline):
1202 model = Router.networks.through
1203 extra = 0
1204 verbose_name_plural = "Routers"
1205 verbose_name = "Router"
1206 suit_classes = 'suit-tab suit-tab-routers'
1207
1208 fields = ['name', 'owner', 'permittedNetworks', 'networks']
Scott Baker74d8e622013-07-29 16:04:22 -07001209
Scott Baker0165fac2014-01-13 11:49:26 -08001210class RouterInline(PlStackTabularInline):
Scott Baker74d8e622013-07-29 16:04:22 -07001211 model = Router.networks.through
1212 extra = 0
1213 verbose_name_plural = "Routers"
1214 verbose_name = "Router"
Siobhan Tully2d95e482013-09-06 10:56:06 -04001215 suit_classes = 'suit-tab suit-tab-routers'
Scott Baker74d8e622013-07-29 16:04:22 -07001216
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001217class NetworkParameterROInline(ReadOnlyTabularInline):
1218 model = NetworkParameter
1219 extra = 1
1220 verbose_name_plural = "Parameters"
1221 verbose_name = "Parameter"
1222 suit_classes = 'suit-tab suit-tab-netparams'
1223 fields = ['parameter', 'value', 'content_type', 'object_id', 'content_object']
1224
Scott Baker74d8e622013-07-29 16:04:22 -07001225class NetworkParameterInline(generic.GenericTabularInline):
Scott Baker74d8e622013-07-29 16:04:22 -07001226 model = NetworkParameter
1227 extra = 1
1228 verbose_name_plural = "Parameters"
1229 verbose_name = "Parameter"
Siobhan Tully2d95e482013-09-06 10:56:06 -04001230 suit_classes = 'suit-tab suit-tab-netparams'
Scott Baker74d8e622013-07-29 16:04:22 -07001231
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001232class NetworkSliversROInline(ReadOnlyTabularInline):
1233 fields = ['network', 'sliver', 'ip', 'port_id']
1234 model = NetworkSliver
1235 extra = 0
1236 verbose_name_plural = "Slivers"
1237 verbose_name = "Sliver"
1238 suit_classes = 'suit-tab suit-tab-networkslivers'
1239
Scott Baker0165fac2014-01-13 11:49:26 -08001240class NetworkSliversInline(PlStackTabularInline):
Scott Baker74d8e622013-07-29 16:04:22 -07001241 readonly_fields = ("ip", )
1242 model = NetworkSliver
Scott Baker874936e2014-01-13 18:15:34 -08001243 selflink_fieldname = "sliver"
Scott Baker74d8e622013-07-29 16:04:22 -07001244 extra = 0
1245 verbose_name_plural = "Slivers"
1246 verbose_name = "Sliver"
Siobhan Tully2d95e482013-09-06 10:56:06 -04001247 suit_classes = 'suit-tab suit-tab-networkslivers'
Scott Baker74d8e622013-07-29 16:04:22 -07001248
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001249class NetworkSlicesROInline(ReadOnlyTabularInline):
1250 model = NetworkSlice
1251 extra = 0
1252 verbose_name_plural = "Slices"
1253 verbose_name = "Slice"
1254 suit_classes = 'suit-tab suit-tab-networkslices'
1255 fields = ['network','slice']
1256
Scott Baker0165fac2014-01-13 11:49:26 -08001257class NetworkSlicesInline(PlStackTabularInline):
Scott Bakerd7d2a392013-08-06 08:57:30 -07001258 model = NetworkSlice
Scott Baker874936e2014-01-13 18:15:34 -08001259 selflink_fieldname = "slice"
Scott Bakerd7d2a392013-08-06 08:57:30 -07001260 extra = 0
1261 verbose_name_plural = "Slices"
1262 verbose_name = "Slice"
Siobhan Tully2d95e482013-09-06 10:56:06 -04001263 suit_classes = 'suit-tab suit-tab-networkslices'
Scott Bakerd7d2a392013-08-06 08:57:30 -07001264
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001265class NetworkAdmin(PlanetStackBaseAdmin):
Scott Baker74d8e622013-07-29 16:04:22 -07001266 list_display = ("name", "subnet", "ports", "labels")
1267 readonly_fields = ("subnet", )
Siobhan Tully2d95e482013-09-06 10:56:06 -04001268
Scott Bakerd7d2a392013-08-06 08:57:30 -07001269 inlines = [NetworkParameterInline, NetworkSliversInline, NetworkSlicesInline, RouterInline]
Scott Baker74d8e622013-07-29 16:04:22 -07001270
Siobhan Tully2d95e482013-09-06 10:56:06 -04001271 fieldsets = [
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001272 (None, {'fields': ['name','template','ports','labels','owner','guaranteedBandwidth', 'permitAllSlices','permittedSlices','network_id','router_id','subnet_id','subnet'], 'classes':['suit-tab suit-tab-general']}),]
1273
1274 user_readonly_fields = ['name','template','ports','labels','owner','guaranteedBandwidth', 'permitAllSlices','permittedSlices','network_id','router_id','subnet_id','subnet']
1275 user_readonly_inlines = [NetworkParameterROInline, NetworkSliversROInline, NetworkSlicesROInline, RouterROInline]
Siobhan Tully2d95e482013-09-06 10:56:06 -04001276
1277 suit_form_tabs =(
1278 ('general','Network Details'),
1279 ('netparams', 'Parameters'),
1280 ('networkslivers','Slivers'),
1281 ('networkslices','Slices'),
1282 ('routers','Routers'),
1283 )
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001284class NetworkTemplateAdmin(PlanetStackBaseAdmin):
Scott Baker74d8e622013-07-29 16:04:22 -07001285 list_display = ("name", "guaranteedBandwidth", "visibility")
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001286 user_readonly_fields = ["name", "guaranteedBandwidth", "visibility"]
1287 user_readonly_inlines = []
Scott Baker74d8e622013-07-29 16:04:22 -07001288
Tony Mack31c2b8f2013-04-26 20:01:42 -04001289# register a signal that caches the user's credentials when they log in
1290def cache_credentials(sender, user, request, **kwds):
1291 auth = {'username': request.POST['username'],
1292 'password': request.POST['password']}
1293 request.session['auth'] = auth
1294user_logged_in.connect(cache_credentials)
1295
Scott Baker15cddfa2013-12-09 13:45:19 -08001296def dollar_field(fieldName, short_description):
1297 def newFunc(self, obj):
1298 try:
1299 x= "$ %0.2f" % float(getattr(obj, fieldName, 0.0))
1300 except:
1301 x=getattr(obj, fieldName, 0.0)
1302 return x
1303 newFunc.short_description = short_description
1304 return newFunc
1305
1306def right_dollar_field(fieldName, short_description):
1307 def newFunc(self, obj):
1308 try:
1309 #x= '<div align=right style="width:6em">$ %0.2f</div>' % float(getattr(obj, fieldName, 0.0))
1310 x= '<div align=right>$ %0.2f</div>' % float(getattr(obj, fieldName, 0.0))
1311 except:
1312 x=getattr(obj, fieldName, 0.0)
1313 return x
1314 newFunc.short_description = short_description
1315 newFunc.allow_tags = True
1316 return newFunc
Scott Baker43105042013-12-06 23:23:36 -08001317
Scott Baker0165fac2014-01-13 11:49:26 -08001318class InvoiceChargeInline(PlStackTabularInline):
Scott Baker43105042013-12-06 23:23:36 -08001319 model = Charge
Scott Baker15cddfa2013-12-09 13:45:19 -08001320 extra = 0
Scott Baker43105042013-12-06 23:23:36 -08001321 verbose_name_plural = "Charges"
1322 verbose_name = "Charge"
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001323 exclude = ['account']
Scott Baker9cb88a22013-12-09 18:56:00 -08001324 fields = ["date", "kind", "state", "object", "coreHours", "dollar_amount", "slice"]
1325 readonly_fields = ["date", "kind", "state", "object", "coreHours", "dollar_amount", "slice"]
1326 can_delete = False
1327 max_num = 0
1328
1329 dollar_amount = right_dollar_field("amount", "Amount")
Scott Baker43105042013-12-06 23:23:36 -08001330
1331class InvoiceAdmin(admin.ModelAdmin):
1332 list_display = ("date", "account")
1333
1334 inlines = [InvoiceChargeInline]
1335
Scott Baker9cb88a22013-12-09 18:56:00 -08001336 fields = ["date", "account", "dollar_amount"]
1337 readonly_fields = ["date", "account", "dollar_amount"]
1338
1339 dollar_amount = dollar_field("amount", "Amount")
Scott Baker43105042013-12-06 23:23:36 -08001340
Scott Baker0165fac2014-01-13 11:49:26 -08001341class InvoiceInline(PlStackTabularInline):
Scott Baker15cddfa2013-12-09 13:45:19 -08001342 model = Invoice
1343 extra = 0
1344 verbose_name_plural = "Invoices"
1345 verbose_name = "Invoice"
Scott Baker0165fac2014-01-13 11:49:26 -08001346 fields = ["date", "dollar_amount"]
1347 readonly_fields = ["date", "dollar_amount"]
Scott Baker15cddfa2013-12-09 13:45:19 -08001348 suit_classes = 'suit-tab suit-tab-accountinvoice'
1349 can_delete=False
1350 max_num=0
1351
1352 dollar_amount = right_dollar_field("amount", "Amount")
1353
Scott Baker0165fac2014-01-13 11:49:26 -08001354class PendingChargeInline(PlStackTabularInline):
Scott Baker43105042013-12-06 23:23:36 -08001355 model = Charge
Scott Baker15cddfa2013-12-09 13:45:19 -08001356 extra = 0
Scott Baker43105042013-12-06 23:23:36 -08001357 verbose_name_plural = "Charges"
1358 verbose_name = "Charge"
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001359 exclude = ["invoice"]
Scott Baker15cddfa2013-12-09 13:45:19 -08001360 fields = ["date", "kind", "state", "object", "coreHours", "dollar_amount", "slice"]
1361 readonly_fields = ["date", "kind", "state", "object", "coreHours", "dollar_amount", "slice"]
Scott Baker43105042013-12-06 23:23:36 -08001362 suit_classes = 'suit-tab suit-tab-accountpendingcharges'
Scott Baker15cddfa2013-12-09 13:45:19 -08001363 can_delete=False
1364 max_num=0
Scott Baker43105042013-12-06 23:23:36 -08001365
1366 def queryset(self, request):
1367 qs = super(PendingChargeInline, self).queryset(request)
1368 qs = qs.filter(state="pending")
1369 return qs
1370
Scott Baker15cddfa2013-12-09 13:45:19 -08001371 dollar_amount = right_dollar_field("amount", "Amount")
1372
Scott Baker0165fac2014-01-13 11:49:26 -08001373class PaymentInline(PlStackTabularInline):
Scott Baker43105042013-12-06 23:23:36 -08001374 model=Payment
1375 extra = 1
1376 verbose_name_plural = "Payments"
1377 verbose_name = "Payment"
Scott Baker15cddfa2013-12-09 13:45:19 -08001378 fields = ["date", "dollar_amount"]
1379 readonly_fields = ["date", "dollar_amount"]
Scott Baker43105042013-12-06 23:23:36 -08001380 suit_classes = 'suit-tab suit-tab-accountpayments'
Scott Baker15cddfa2013-12-09 13:45:19 -08001381 can_delete=False
1382 max_num=0
1383
1384 dollar_amount = right_dollar_field("amount", "Amount")
1385
Scott Baker43105042013-12-06 23:23:36 -08001386class AccountAdmin(admin.ModelAdmin):
1387 list_display = ("site", "balance_due")
1388
1389 inlines = [InvoiceInline, PaymentInline, PendingChargeInline]
1390
1391 fieldsets = [
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001392 (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 -08001393
Scott Baker15cddfa2013-12-09 13:45:19 -08001394 readonly_fields = ['site', 'dollar_balance_due', 'dollar_total_invoices', 'dollar_total_payments']
Scott Baker43105042013-12-06 23:23:36 -08001395
1396 suit_form_tabs =(
1397 ('general','Account Details'),
1398 ('accountinvoice', 'Invoices'),
1399 ('accountpayments', 'Payments'),
1400 ('accountpendingcharges','Pending Charges'),
1401 )
1402
Scott Baker15cddfa2013-12-09 13:45:19 -08001403 dollar_balance_due = dollar_field("balance_due", "Balance Due")
1404 dollar_total_invoices = dollar_field("total_invoices", "Total Invoices")
1405 dollar_total_payments = dollar_field("total_payments", "Total Payments")
1406
Siobhan Tullyce652d02013-10-08 21:52:35 -04001407
Siobhan Tully53437282013-04-26 19:30:27 -04001408# Now register the new UserAdmin...
Siobhan Tully30fd4292013-05-10 08:59:56 -04001409admin.site.register(User, UserAdmin)
Siobhan Tully53437282013-04-26 19:30:27 -04001410# ... and, since we're not using Django's builtin permissions,
1411# unregister the Group model from admin.
Siobhan Tullyce652d02013-10-08 21:52:35 -04001412#admin.site.unregister(Group)
Siobhan Tully53437282013-04-26 19:30:27 -04001413
Siobhan Tullybf1153a2013-05-27 20:53:48 -04001414#Do not show django evolution in the admin interface
1415from django_evolution.models import Version, Evolution
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001416#admin.site.unregister(Version)
1417#admin.site.unregister(Evolution)
Siobhan Tullybf1153a2013-05-27 20:53:48 -04001418
1419
1420# When debugging it is often easier to see all the classes, but for regular use
1421# only the top-levels should be displayed
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001422showAll = False
Scott Baker43105042013-12-06 23:23:36 -08001423
Siobhan Tullybf1153a2013-05-27 20:53:48 -04001424admin.site.register(Deployment, DeploymentAdmin)
Siobhan Tully4bc09f22013-04-10 21:15:21 -04001425admin.site.register(Site, SiteAdmin)
Siobhan Tully4bc09f22013-04-10 21:15:21 -04001426admin.site.register(Slice, SliceAdmin)
Siobhan Tullyce652d02013-10-08 21:52:35 -04001427admin.site.register(Service, ServiceAdmin)
smbakera3cf70c2013-06-27 02:01:41 -07001428admin.site.register(Reservation, ReservationAdmin)
Scott Baker74d8e622013-07-29 16:04:22 -07001429admin.site.register(Network, NetworkAdmin)
1430admin.site.register(Router, RouterAdmin)
Scott Baker74d8e622013-07-29 16:04:22 -07001431admin.site.register(NetworkTemplate, NetworkTemplateAdmin)
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001432admin.site.register(Account, AccountAdmin)
1433admin.site.register(Invoice, InvoiceAdmin)
Siobhan Tullybf1153a2013-05-27 20:53:48 -04001434
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001435if True:
1436 admin.site.register(NetworkParameterType, NetworkParameterTypeAdmin)
1437 admin.site.register(ServiceClass, ServiceClassAdmin)
Siobhan Tullybfd11dc2013-09-03 12:59:24 -04001438 #admin.site.register(PlanetStack)
Siobhan Tullyd3515752013-06-21 16:34:53 -04001439 admin.site.register(Tag, TagAdmin)
Siobhan Tullyce652d02013-10-08 21:52:35 -04001440 admin.site.register(DeploymentRole)
1441 admin.site.register(SiteRole)
1442 admin.site.register(SliceRole)
1443 admin.site.register(PlanetStackRole)
Siobhan Tullybf1153a2013-05-27 20:53:48 -04001444 admin.site.register(Node, NodeAdmin)
Siobhan Tullybfd11dc2013-09-03 12:59:24 -04001445 #admin.site.register(SlicePrivilege, SlicePrivilegeAdmin)
1446 #admin.site.register(SitePrivilege, SitePrivilegeAdmin)
Siobhan Tullybf1153a2013-05-27 20:53:48 -04001447 admin.site.register(Sliver, SliverAdmin)
Siobhan Tullybf1153a2013-05-27 20:53:48 -04001448 admin.site.register(Image, ImageAdmin)
Scott Baker2c3cb642014-05-19 17:55:56 -07001449 admin.site.register(DashboardView, DashboardViewAdmin)
Tony Mack7130ac32013-03-22 21:58:00 -04001450