blob: 0e38d43a1434bf7fa8675c8787295185fb8419aa [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
Scott Bakerb24cc932014-06-09 10:51:16 -0700221 fields = ['ip', 'instance_name', 'slice', 'numberCores', 'deploymentNetwork', 'image', 'node']
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500222 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
Scott Bakerb24cc932014-06-09 10:51:16 -0700226 fields = ['ip', 'instance_name', 'slice', 'numberCores', 'deploymentNetwork', 'image', 'node']
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
Scott Bakerb24cc932014-06-09 10:51:16 -0700234 def formfield_for_foreignkey(self, db_field, request=None, **kwargs):
Scott Bakerb24cc932014-06-09 10:51:16 -0700235 if db_field.name == 'deploymentNetwork':
Scott Baker3b678742014-06-09 13:11:54 -0700236 kwargs['queryset'] = Deployment.select_by_acl(request.user)
237
238 field = super(SliverInline, self).formfield_for_foreignkey(db_field, request, **kwargs)
Scott Bakerb24cc932014-06-09 10:51:16 -0700239
240 return field
241
Siobhan Tully2d95e482013-09-06 10:56:06 -0400242# Note this is breaking in the admin.py when trying to use an inline to add a node/image
243# def _declared_fieldsets(self):
244# # Return None so django will call get_fieldsets and we can insert our
245# # dynamic fields
246# return None
247#
248# def get_readonly_fields(self, request, obj=None):
249# readonly_fields = super(SliverInline, self).get_readonly_fields(request, obj)
250#
251# # Lookup the networks that are bound to the slivers, and add those
252# # network names to the list of readonly fields.
253#
254# for sliver in obj.slivers.all():
255# for nbs in sliver.networksliver_set.all():
256# if nbs.ip:
257# network_name = nbs.network.name
258# if network_name not in [str(x) for x in readonly_fields]:
259# readonly_fields.append(NetworkLookerUpper(network_name))
260#
261# return readonly_fields
262#
263# def get_fieldsets(self, request, obj=None):
264# form = self.get_formset(request, obj).form
265# # fields = the read/write files + the read-only fields
266# fields = self.fields
267# for fieldName in self.get_readonly_fields(request,obj):
268# if not fieldName in fields:
269# fields.append(fieldName)
270#
271# return [(None, {'fields': fields})]
Scott Baker74d8e622013-07-29 16:04:22 -0700272
Tony Mackc2835a92013-05-28 09:18:49 -0400273
Siobhan Tully567e3e62013-06-21 18:03:16 -0400274
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500275class SiteROInline(ReadOnlyTabularInline):
276 model = Site
277 extra = 0
278 fields = ['name', 'login_base', 'site_url', 'enabled']
279 suit_classes = 'suit-tab suit-tab-sites'
280
Siobhan Tullyd3515752013-06-21 16:34:53 -0400281class SiteInline(PlStackTabularInline):
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400282 model = Site
283 extra = 0
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400284 suit_classes = 'suit-tab suit-tab-sites'
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400285
Tony Mack5b061472014-02-04 07:57:10 -0500286 def queryset(self, request):
287 return Site.select_by_user(request.user)
288
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500289class UserROInline(ReadOnlyTabularInline):
290 model = User
291 fields = ['email', 'firstname', 'lastname']
292 extra = 0
293 suit_classes = 'suit-tab suit-tab-users'
294
Siobhan Tullyd3515752013-06-21 16:34:53 -0400295class UserInline(PlStackTabularInline):
Siobhan Tully30fd4292013-05-10 08:59:56 -0400296 model = User
Siobhan Tully47ae1b52013-05-10 15:53:14 -0400297 fields = ['email', 'firstname', 'lastname']
Siobhan Tully30fd4292013-05-10 08:59:56 -0400298 extra = 0
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400299 suit_classes = 'suit-tab suit-tab-users'
Siobhan Tully30fd4292013-05-10 08:59:56 -0400300
Tony Mack5b061472014-02-04 07:57:10 -0500301 def queryset(self, request):
302 return User.select_by_user(request.user)
303
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500304class SliceROInline(ReadOnlyTabularInline):
305 model = Slice
306 suit_classes = 'suit-tab suit-tab-slices'
307 fields = ['name','site', 'serviceClass', 'service']
308
Siobhan Tullyd3515752013-06-21 16:34:53 -0400309class SliceInline(PlStackTabularInline):
Tony Mack00d361f2013-04-28 10:28:42 -0400310 model = Slice
Siobhan Tullyce652d02013-10-08 21:52:35 -0400311 fields = ['name','site', 'serviceClass', 'service']
Tony Mack00d361f2013-04-28 10:28:42 -0400312 extra = 0
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400313 suit_classes = 'suit-tab suit-tab-slices'
314
Tony Mack5b061472014-02-04 07:57:10 -0500315 def queryset(self, request):
316 return Slice.select_by_user(request.user)
317
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500318class NodeROInline(ReadOnlyTabularInline):
319 model = Node
320 extra = 0
321 suit_classes = 'suit-tab suit-tab-nodes'
Scott Baker838d7df2014-06-09 11:01:16 -0700322 fields = ['name','deployment','site']
Tony Mack00d361f2013-04-28 10:28:42 -0400323
Siobhan Tullyd3515752013-06-21 16:34:53 -0400324class NodeInline(PlStackTabularInline):
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400325 model = Node
326 extra = 0
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400327 suit_classes = 'suit-tab suit-tab-nodes'
Scott Baker838d7df2014-06-09 11:01:16 -0700328 fields = ['name','deployment','site']
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400329
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500330class DeploymentPrivilegeROInline(ReadOnlyTabularInline):
331 model = DeploymentPrivilege
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400332 extra = 0
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500333 suit_classes = 'suit-tab suit-tab-deploymentprivileges'
Scott Baker3ca51f62014-05-23 12:05:11 -0700334 fields = ['user','role','deployment']
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400335
336class DeploymentPrivilegeInline(PlStackTabularInline):
337 model = DeploymentPrivilege
338 extra = 0
339 suit_classes = 'suit-tab suit-tab-deploymentprivileges'
Scott Baker3ca51f62014-05-23 12:05:11 -0700340 fields = ['user','role','deployment']
Tony Mack5b061472014-02-04 07:57:10 -0500341
342 def queryset(self, request):
343 return DeploymentPrivilege.select_by_user(request.user)
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400344
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500345#CLEANUP DOUBLE SitePrivilegeInline
346class SitePrivilegeROInline(ReadOnlyTabularInline):
347 model = SitePrivilege
348 extra = 0
349 suit_classes = 'suit-tab suit-tab-siteprivileges'
350 fields = ['user','site', 'role']
351
Siobhan Tullyd3515752013-06-21 16:34:53 -0400352class SitePrivilegeInline(PlStackTabularInline):
Siobhan Tullyaa1bcd52013-05-10 12:43:09 -0400353 model = SitePrivilege
354 extra = 0
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400355 suit_classes = 'suit-tab suit-tab-siteprivileges'
Tony Mack5b061472014-02-04 07:57:10 -0500356 fields = ['user','site', 'role']
Siobhan Tullyaa1bcd52013-05-10 12:43:09 -0400357
Tony Mackc2835a92013-05-28 09:18:49 -0400358 def formfield_for_foreignkey(self, db_field, request, **kwargs):
359 if db_field.name == 'site':
Tony Mack5b061472014-02-04 07:57:10 -0500360 kwargs['queryset'] = Site.select_by_user(request.user)
Tony Mackc2835a92013-05-28 09:18:49 -0400361
362 if db_field.name == 'user':
Tony Mack5b061472014-02-04 07:57:10 -0500363 kwargs['queryset'] = User.select_by_user(request.user)
Tony Mackc2835a92013-05-28 09:18:49 -0400364 return super(SitePrivilegeInline, self).formfield_for_foreignkey(db_field, request, **kwargs)
365
Tony Mack5b061472014-02-04 07:57:10 -0500366 def queryset(self, request):
367 return SitePrivilege.select_by_user(request.user)
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400368
Tony Macke4be32f2014-03-11 20:45:25 -0400369class SiteDeploymentROInline(ReadOnlyTabularInline):
370 model = SiteDeployments
371 #model = Site.deployments.through
372 extra = 0
Scott Bakerf3982522014-05-23 11:58:20 -0700373 suit_classes = 'suit-tab suit-tab-deployments'
Tony Macke4be32f2014-03-11 20:45:25 -0400374 fields = ['deployment','site']
375
376class SiteDeploymentInline(PlStackTabularInline):
377 model = SiteDeployments
378 #model = Site.deployments.through
379 extra = 0
380 suit_classes = 'suit-tab suit-tab-deployments'
381 fields = ['deployment','site']
382
383 def formfield_for_foreignkey(self, db_field, request, **kwargs):
384 if db_field.name == 'site':
385 kwargs['queryset'] = Site.select_by_user(request.user)
386
387 if db_field.name == 'deployment':
388 kwargs['queryset'] = Deployment.select_by_user(request.user)
389 return super(SiteDeploymentInline, self).formfield_for_foreignkey(db_field, request, **kwargs)
390
391 def queryset(self, request):
392 return SiteDeployments.select_by_user(request.user)
393
394
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500395class SlicePrivilegeROInline(ReadOnlyTabularInline):
396 model = SlicePrivilege
397 extra = 0
398 suit_classes = 'suit-tab suit-tab-sliceprivileges'
399 fields = ['user', 'slice', 'role']
400
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400401class SlicePrivilegeInline(PlStackTabularInline):
402 model = SlicePrivilege
403 suit_classes = 'suit-tab suit-tab-sliceprivileges'
404 extra = 0
405 fields = ('user', 'slice','role')
Siobhan Tullyaa1bcd52013-05-10 12:43:09 -0400406
Tony Mackc2835a92013-05-28 09:18:49 -0400407 def formfield_for_foreignkey(self, db_field, request, **kwargs):
408 if db_field.name == 'slice':
Tony Mack5b061472014-02-04 07:57:10 -0500409 kwargs['queryset'] = Slice.select_by_user(request.user)
Tony Mackc2835a92013-05-28 09:18:49 -0400410 if db_field.name == 'user':
Tony Mack5b061472014-02-04 07:57:10 -0500411 kwargs['queryset'] = User.select_by_user(request.user)
Tony Mackc2835a92013-05-28 09:18:49 -0400412
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400413 return super(SlicePrivilegeInline, self).formfield_for_foreignkey(db_field, request, **kwargs)
Tony Mackc2835a92013-05-28 09:18:49 -0400414
Tony Mack5b061472014-02-04 07:57:10 -0500415 def queryset(self, request):
416 return SlicePrivilege.select_by_user(request.user)
417
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500418class SliceNetworkROInline(ReadOnlyTabularInline):
419 model = Network.slices.through
420 extra = 0
421 verbose_name = "Network Connection"
422 verbose_name_plural = "Network Connections"
423 suit_classes = 'suit-tab suit-tab-slicenetworks'
424 fields = ['network']
425
Scott Bakera0015eb2013-08-14 17:28:14 -0700426class SliceNetworkInline(PlStackTabularInline):
Scott Baker74d8e622013-07-29 16:04:22 -0700427 model = Network.slices.through
Scott Baker874936e2014-01-13 18:15:34 -0800428 selflink_fieldname = "network"
Scott Baker74d8e622013-07-29 16:04:22 -0700429 extra = 0
430 verbose_name = "Network Connection"
431 verbose_name_plural = "Network Connections"
Siobhan Tully2d95e482013-09-06 10:56:06 -0400432 suit_classes = 'suit-tab suit-tab-slicenetworks'
Scott Baker2170b972014-06-03 12:14:07 -0700433 fields = ['network']
434
435class ImageDeploymentsInline(PlStackTabularInline):
436 model = ImageDeployments
437 extra = 0
438 verbose_name = "Image Deployments"
439 verbose_name_plural = "Image Deployments"
440 suit_classes = 'suit-tab suit-tab-imagedeployments'
441 fields = ['deployment', 'glance_image_id']
442 readonly_fields = ['deployment', 'glance_image_id']
Scott Baker74d8e622013-07-29 16:04:22 -0700443
Tony Mack5e71a662013-05-03 23:30:41 -0400444class PlainTextWidget(forms.HiddenInput):
445 input_type = 'hidden'
446
447 def render(self, name, value, attrs=None):
448 if value is None:
449 value = ''
Tony Mack1d6b85f2013-05-07 18:49:14 -0400450 return mark_safe(str(value) + super(PlainTextWidget, self).render(name, value, attrs))
Tony Mack9bcbe4f2013-04-29 08:13:27 -0400451
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500452class PlanetStackBaseAdmin(ReadOnlyAwareAdmin):
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400453 save_on_top = False
Tony Mack332ee1d2014-02-04 15:33:45 -0500454
455 def save_model(self, request, obj, form, change):
Tony Mack3d042792014-03-17 19:18:37 -0400456 obj.caller = request.user
Tony Mack332ee1d2014-02-04 15:33:45 -0500457 # update openstack connection to use this site/tenant
458 obj.save_by_user(request.user)
459
460 def delete_model(self, request, obj):
461 obj.delete_by_user(request.user)
462
463 def save_formset(self, request, form, formset, change):
464 instances = formset.save(commit=False)
465 for instance in instances:
466 instance.save_by_user(request.user)
467 formset.save_m2m()
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400468
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400469class SliceRoleAdmin(PlanetStackBaseAdmin):
470 model = SliceRole
471 pass
472
473class SiteRoleAdmin(PlanetStackBaseAdmin):
474 model = SiteRole
475 pass
476
Siobhan Tullybf1153a2013-05-27 20:53:48 -0400477class DeploymentAdminForm(forms.ModelForm):
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400478 sites = forms.ModelMultipleChoiceField(
479 queryset=Site.objects.all(),
480 required=False,
Scott Baker70983182014-06-09 22:10:00 -0700481 help_text="Select which sites are allowed to host nodes in this deployment",
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400482 widget=FilteredSelectMultiple(
483 verbose_name=('Sites'), is_stacked=False
484 )
485 )
486 class Meta:
Siobhan Tullybf1153a2013-05-27 20:53:48 -0400487 model = Deployment
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400488
Siobhan Tully320b4622014-01-17 15:11:14 -0500489 def __init__(self, *args, **kwargs):
Scott Baker5380c522014-06-06 14:49:43 -0700490 request = kwargs.pop('request', None)
Siobhan Tully320b4622014-01-17 15:11:14 -0500491 super(DeploymentAdminForm, self).__init__(*args, **kwargs)
492
Scott Baker5380c522014-06-06 14:49:43 -0700493 self.fields['accessControl'].initial = "allow site " + request.user.site.name
494
Siobhan Tully320b4622014-01-17 15:11:14 -0500495 if self.instance and self.instance.pk:
Scott Bakerc9b14f72014-05-22 13:44:20 -0700496 self.fields['sites'].initial = [x.site for x in self.instance.sitedeployments_set.all()]
Siobhan Tully320b4622014-01-17 15:11:14 -0500497
498 def save(self, commit=True):
499 deployment = super(DeploymentAdminForm, self).save(commit=False)
500
501 if commit:
502 deployment.save()
503
504 if deployment.pk:
Scott Bakerc9b14f72014-05-22 13:44:20 -0700505 # save_m2m() doesn't seem to work with 'through' relations. So we
506 # create/destroy the through models ourselves. There has to be
507 # a better way...
508
509 sites = self.cleaned_data['sites']
510
511 existing_sites = []
512 for sdp in list(deployment.sitedeployments_set.all()):
513 if sdp.site not in sites:
514 #print "deleting site", sdp.site
515 sdp.delete()
516 else:
517 existing_sites.append(sdp.site)
518
519 for site in sites:
520 if site not in existing_sites:
521 #print "adding site", site
522 sdp = SiteDeployments(site=site, deployment=deployment)
523 sdp.save()
524
Siobhan Tully320b4622014-01-17 15:11:14 -0500525 self.save_m2m()
526
527 return deployment
528
Scott Bakerff5e0f32014-05-22 14:40:27 -0700529class DeploymentAdminROForm(DeploymentAdminForm):
530 def save(self, commit=True):
531 raise PermissionDenied
532
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500533class SiteAssocInline(PlStackTabularInline):
534 model = Site.deployments.through
535 extra = 0
536 suit_classes = 'suit-tab suit-tab-sites'
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400537
Siobhan Tullybf1153a2013-05-27 20:53:48 -0400538class DeploymentAdmin(PlanetStackBaseAdmin):
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500539 model = Deployment
Scott Baker5380c522014-06-06 14:49:43 -0700540 fieldList = ['name','sites', 'accessControl']
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500541 fieldsets = [(None, {'fields': fieldList, 'classes':['suit-tab suit-tab-sites']})]
Siobhan Tully2d95e482013-09-06 10:56:06 -0400542 inlines = [DeploymentPrivilegeInline,NodeInline,TagInline]
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500543
544 user_readonly_inlines = [DeploymentPrivilegeROInline,NodeROInline,TagROInline]
545 user_readonly_fields = ['name']
546
547 suit_form_tabs =(('sites','Deployment Details'),('nodes','Nodes'),('deploymentprivileges','Privileges'),('tags','Tags'))
548
Scott Bakerff5e0f32014-05-22 14:40:27 -0700549 def get_form(self, request, obj=None, **kwargs):
550 if request.user.isReadOnlyUser():
551 kwargs["form"] = DeploymentAdminROForm
552 else:
553 kwargs["form"] = DeploymentAdminForm
Scott Baker5380c522014-06-06 14:49:43 -0700554 adminForm = super(DeploymentAdmin,self).get_form(request, obj, **kwargs)
555
556 # from stackexchange: pass the request object into the form
557
558 class AdminFormMetaClass(adminForm):
559 def __new__(cls, *args, **kwargs):
560 kwargs['request'] = request
561 return adminForm(*args, **kwargs)
562
563 return AdminFormMetaClass
564
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500565class ServiceAttrAsTabROInline(ReadOnlyTabularInline):
566 model = ServiceAttribute
567 fields = ['name','value']
568 extra = 0
569 suit_classes = 'suit-tab suit-tab-serviceattrs'
Tony Mack5cd13202013-05-01 21:48:38 -0400570
Siobhan Tullyce652d02013-10-08 21:52:35 -0400571class ServiceAttrAsTabInline(PlStackTabularInline):
572 model = ServiceAttribute
573 fields = ['name','value']
574 extra = 0
575 suit_classes = 'suit-tab suit-tab-serviceattrs'
576
Siobhan Tullyce652d02013-10-08 21:52:35 -0400577class ServiceAdmin(PlanetStackBaseAdmin):
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500578 list_display = ("name","description","versionNumber","enabled","published")
579 fieldList = ["name","description","versionNumber","enabled","published"]
580 fieldsets = [(None, {'fields': fieldList, 'classes':['suit-tab suit-tab-general']})]
581 inlines = [ServiceAttrAsTabInline,SliceInline]
582
583 user_readonly_fields = fieldList
584 user_readonly_inlines = [ServiceAttrAsTabROInline,SliceROInline]
585
586 suit_form_tabs =(('general', 'Service Details'),
587 ('slices','Slices'),
588 ('serviceattrs','Additional Attributes'),
589 )
Siobhan Tullyce652d02013-10-08 21:52:35 -0400590
Tony Mack0553f282013-06-10 22:54:50 -0400591class SiteAdmin(PlanetStackBaseAdmin):
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500592 fieldList = ['name', 'site_url', 'enabled', 'is_public', 'login_base', 'accountLink','location']
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400593 fieldsets = [
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500594 (None, {'fields': fieldList, 'classes':['suit-tab suit-tab-general']}),
Tony Macke4be32f2014-03-11 20:45:25 -0400595 #('Deployment Networks', {'fields': ['deployments'], 'classes':['suit-tab suit-tab-deployments']}),
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400596 ]
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400597 suit_form_tabs =(('general', 'Site Details'),
598 ('users','Users'),
Siobhan Tully2d95e482013-09-06 10:56:06 -0400599 ('siteprivileges','Privileges'),
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400600 ('deployments','Deployments'),
601 ('slices','Slices'),
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500602 ('nodes','Nodes'),
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400603 ('tags','Tags'),
604 )
Scott Baker545db2a2013-12-09 18:44:43 -0800605 readonly_fields = ['accountLink']
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500606
607 user_readonly_fields = ['name', 'deployments','site_url', 'enabled', 'is_public', 'login_base', 'accountLink']
Tony Macke4be32f2014-03-11 20:45:25 -0400608 user_readonly_inlines = [SliceROInline,UserROInline,TagROInline, NodeROInline, SitePrivilegeROInline,SiteDeploymentROInline]
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500609
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400610 list_display = ('name', 'login_base','site_url', 'enabled')
611 filter_horizontal = ('deployments',)
Tony Macke4be32f2014-03-11 20:45:25 -0400612 inlines = [SliceInline,UserInline,TagInline, NodeInline, SitePrivilegeInline, SiteDeploymentInline]
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400613 search_fields = ['name']
614
Tony Mack04062832013-05-10 08:22:44 -0400615 def queryset(self, request):
Tony Mack5b061472014-02-04 07:57:10 -0500616 return Site.select_by_user(request.user)
Tony Mack04062832013-05-10 08:22:44 -0400617
Tony Mack5cd13202013-05-01 21:48:38 -0400618 def get_formsets(self, request, obj=None):
619 for inline in self.get_inline_instances(request, obj):
620 # hide MyInline in the add view
621 if obj is None:
622 continue
Tony Mack2bd5b412013-06-11 21:05:06 -0400623 if isinstance(inline, SliceInline):
624 inline.model.caller = request.user
625 yield inline.get_formset(request, obj)
626
627 def get_formsets(self, request, obj=None):
628 for inline in self.get_inline_instances(request, obj):
629 # hide MyInline in the add view
630 if obj is None:
631 continue
632 if isinstance(inline, SliverInline):
633 inline.model.caller = request.user
Tony Mack5cd13202013-05-01 21:48:38 -0400634 yield inline.get_formset(request, obj)
635
Scott Baker545db2a2013-12-09 18:44:43 -0800636 def accountLink(self, obj):
637 link_obj = obj.accounts.all()
638 if link_obj:
639 reverse_path = "admin:core_account_change"
640 url = reverse(reverse_path, args =(link_obj[0].id,))
641 return "<a href='%s'>%s</a>" % (url, "view billing details")
642 else:
643 return "no billing data for this site"
644 accountLink.allow_tags = True
645 accountLink.short_description = "Billing"
646
Tony Mack332ee1d2014-02-04 15:33:45 -0500647 def save_model(self, request, obj, form, change):
648 # update openstack connection to use this site/tenant
649 obj.save_by_user(request.user)
650
651 def delete_model(self, request, obj):
652 obj.delete_by_user(request.user)
653
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500654
Tony Mack9bcbe4f2013-04-29 08:13:27 -0400655class SitePrivilegeAdmin(PlanetStackBaseAdmin):
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500656 fieldList = ['user', 'site', 'role']
Tony Mack00d361f2013-04-28 10:28:42 -0400657 fieldsets = [
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500658 (None, {'fields': fieldList, 'classes':['collapse']})
Tony Mack00d361f2013-04-28 10:28:42 -0400659 ]
660 list_display = ('user', 'site', 'role')
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500661 user_readonly_fields = fieldList
662 user_readonly_inlines = []
Tony Mack00d361f2013-04-28 10:28:42 -0400663
Tony Mackc2835a92013-05-28 09:18:49 -0400664 def formfield_for_foreignkey(self, db_field, request, **kwargs):
665 if db_field.name == 'site':
666 if not request.user.is_admin:
667 # only show sites where user is an admin or pi
668 sites = set()
669 for site_privilege in SitePrivilege.objects.filer(user=request.user):
670 if site_privilege.role.role_type in ['admin', 'pi']:
671 sites.add(site_privilege.site)
672 kwargs['queryset'] = Site.objects.filter(site__in=list(sites))
673
674 if db_field.name == 'user':
675 if not request.user.is_admin:
676 # only show users from sites where caller has admin or pi role
677 roles = Role.objects.filter(role_type__in=['admin', 'pi'])
678 site_privileges = SitePrivilege.objects.filter(user=request.user).filter(role__in=roles)
679 sites = [site_privilege.site for site_privilege in site_privileges]
680 site_privileges = SitePrivilege.objects.filter(site__in=sites)
681 emails = [site_privilege.user.email for site_privilege in site_privileges]
682 users = User.objects.filter(email__in=emails)
683 kwargs['queryset'] = users
684
685 return super(SitePrivilegeAdmin, self).formfield_for_foreignkey(db_field, request, **kwargs)
686
Tony Mack04062832013-05-10 08:22:44 -0400687 def queryset(self, request):
688 # admins can see all privileges. Users can only see privileges at sites
Tony Mackc2835a92013-05-28 09:18:49 -0400689 # where they have the admin role or pi role.
Tony Mack04062832013-05-10 08:22:44 -0400690 qs = super(SitePrivilegeAdmin, self).queryset(request)
Tony Mack5b061472014-02-04 07:57:10 -0500691 #if not request.user.is_admin:
692 # roles = Role.objects.filter(role_type__in=['admin', 'pi'])
693 # site_privileges = SitePrivilege.objects.filter(user=request.user).filter(role__in=roles)
694 # login_bases = [site_privilege.site.login_base for site_privilege in site_privileges]
695 # sites = Site.objects.filter(login_base__in=login_bases)
696 # qs = qs.filter(site__in=sites)
Tony Mack04062832013-05-10 08:22:44 -0400697 return qs
698
Siobhan Tullyce652d02013-10-08 21:52:35 -0400699class SliceForm(forms.ModelForm):
700 class Meta:
701 model = Slice
702 widgets = {
703 'service': LinkedSelect
704 }
705
Tony Mack2bd5b412013-06-11 21:05:06 -0400706class SliceAdmin(PlanetStackBaseAdmin):
Siobhan Tullyce652d02013-10-08 21:52:35 -0400707 form = SliceForm
Tony Mack29bf5e82014-04-29 21:40:24 -0400708 fieldList = ['name', 'site', 'serviceClass', 'enabled','description', 'service', 'slice_url', 'max_slivers']
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500709 fieldsets = [('Slice Details', {'fields': fieldList, 'classes':['suit-tab suit-tab-general']}),]
Tony Mack29bf5e82014-04-29 21:40:24 -0400710 list_display = ('name', 'site','serviceClass', 'slice_url', 'max_slivers')
Siobhan Tully2d95e482013-09-06 10:56:06 -0400711 inlines = [SlicePrivilegeInline,SliverInline, TagInline, ReservationInline,SliceNetworkInline]
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400712
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500713 user_readonly_fields = fieldList
714 user_readonly_inlines = [SlicePrivilegeROInline,SliverROInline,TagROInline, ReservationROInline, SliceNetworkROInline]
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400715
716 suit_form_tabs =(('general', 'Slice Details'),
Siobhan Tully2d95e482013-09-06 10:56:06 -0400717 ('slicenetworks','Networks'),
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400718 ('sliceprivileges','Privileges'),
719 ('slivers','Slivers'),
720 ('tags','Tags'),
721 ('reservations','Reservations'),
722 )
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400723
Tony Mackc2835a92013-05-28 09:18:49 -0400724 def formfield_for_foreignkey(self, db_field, request, **kwargs):
725 if db_field.name == 'site':
Tony Mack5b061472014-02-04 07:57:10 -0500726 kwargs['queryset'] = Site.select_by_user(request.user)
727
Tony Mackc2835a92013-05-28 09:18:49 -0400728 return super(SliceAdmin, self).formfield_for_foreignkey(db_field, request, **kwargs)
729
Tony Mack04062832013-05-10 08:22:44 -0400730 def queryset(self, request):
731 # admins can see all keys. Users can only see slices they belong to.
Tony Mack5b061472014-02-04 07:57:10 -0500732 return Slice.select_by_user(request.user)
Tony Mack04062832013-05-10 08:22:44 -0400733
Tony Mack79748612013-05-01 14:52:03 -0400734 def get_formsets(self, request, obj=None):
735 for inline in self.get_inline_instances(request, obj):
736 # hide MyInline in the add view
737 if obj is None:
738 continue
Tony Mack2bd5b412013-06-11 21:05:06 -0400739 if isinstance(inline, SliverInline):
740 inline.model.caller = request.user
Tony Mack79748612013-05-01 14:52:03 -0400741 yield inline.get_formset(request, obj)
742
Tony Mack2bd5b412013-06-11 21:05:06 -0400743
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400744class SlicePrivilegeAdmin(PlanetStackBaseAdmin):
Tony Mack00d361f2013-04-28 10:28:42 -0400745 fieldsets = [
746 (None, {'fields': ['user', 'slice', 'role']})
747 ]
748 list_display = ('user', 'slice', 'role')
Tony Mack00d361f2013-04-28 10:28:42 -0400749
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500750 user_readonly_fields = ['user', 'slice', 'role']
751 user_readonly_inlines = []
752
Tony Mackc2835a92013-05-28 09:18:49 -0400753 def formfield_for_foreignkey(self, db_field, request, **kwargs):
754 if db_field.name == 'slice':
Tony Mack5b061472014-02-04 07:57:10 -0500755 kwargs['queryset'] = Slice.select_by_user(request.user)
Tony Mackc2835a92013-05-28 09:18:49 -0400756
757 if db_field.name == 'user':
Tony Mack5b061472014-02-04 07:57:10 -0500758 kwargs['queryset'] = User.select_by_user(request.user)
Tony Mackc2835a92013-05-28 09:18:49 -0400759
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400760 return super(SlicePrivilegeAdmin, self).formfield_for_foreignkey(db_field, request, **kwargs)
Tony Mackc2835a92013-05-28 09:18:49 -0400761
Tony Mack04062832013-05-10 08:22:44 -0400762 def queryset(self, request):
763 # admins can see all memberships. Users can only see memberships of
764 # slices where they have the admin role.
Tony Mack5b061472014-02-04 07:57:10 -0500765 return SlicePrivilege.select_by_user(request.user)
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400766
Tony Mack9bcbe4f2013-04-29 08:13:27 -0400767 def save_model(self, request, obj, form, change):
Tony Mack951dab42013-05-02 19:51:45 -0400768 # update openstack connection to use this site/tenant
769 auth = request.session.get('auth', {})
770 auth['tenant'] = obj.slice.name
771 obj.os_manager = OpenStackManager(auth=auth, caller=request.user)
Tony Mack9bcbe4f2013-04-29 08:13:27 -0400772 obj.save()
773
774 def delete_model(self, request, obj):
Tony Mack951dab42013-05-02 19:51:45 -0400775 # update openstack connection to use this site/tenant
776 auth = request.session.get('auth', {})
777 auth['tenant'] = obj.slice.name
778 obj.os_manager = OpenStackManager(auth=auth, caller=request.user)
Tony Mack9bcbe4f2013-04-29 08:13:27 -0400779 obj.delete()
780
Siobhan Tully567e3e62013-06-21 18:03:16 -0400781
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400782class ImageAdmin(PlanetStackBaseAdmin):
783
784 fieldsets = [('Image Details',
Scott Baker00b00b32014-05-07 08:47:54 -0700785 {'fields': ['name', 'disk_format', 'container_format'],
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400786 'classes': ['suit-tab suit-tab-general']})
787 ]
788
Scott Baker2170b972014-06-03 12:14:07 -0700789 suit_form_tabs =(('general','Image Details'),('slivers','Slivers'),('imagedeployments','Deployments'))
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400790
Scott Baker2170b972014-06-03 12:14:07 -0700791 inlines = [SliverInline, ImageDeploymentsInline]
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500792
Tony Mack32e1ce32014-05-07 13:29:41 -0400793 user_readonly_fields = ['name', 'disk_format', 'container_format']
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500794 user_readonly_inlines = [SliverROInline]
795
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400796class NodeForm(forms.ModelForm):
797 class Meta:
798 widgets = {
799 'site': LinkedSelect,
800 'deployment': LinkedSelect
801 }
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400802
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500803class NodeAdmin(PlanetStackBaseAdmin):
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400804 form = NodeForm
Siobhan Tullybf1153a2013-05-27 20:53:48 -0400805 list_display = ('name', 'site', 'deployment')
806 list_filter = ('deployment',)
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500807
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400808 inlines = [TagInline,SliverInline]
809 fieldsets = [('Node Details', {'fields': ['name','site','deployment'], 'classes':['suit-tab suit-tab-details']})]
810
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500811 user_readonly_fields = ['name','site','deployment']
812 user_readonly_inlines = [TagInline,SliverInline]
813
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400814 suit_form_tabs =(('details','Node Details'),('slivers','Slivers'),('tags','Tags'))
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400815
Siobhan Tully567e3e62013-06-21 18:03:16 -0400816
Tony Mackd90cdbf2013-04-16 22:48:40 -0400817class SliverForm(forms.ModelForm):
818 class Meta:
Tony Mack1d6b85f2013-05-07 18:49:14 -0400819 model = Sliver
Tony Mackd90cdbf2013-04-16 22:48:40 -0400820 ip = forms.CharField(widget=PlainTextWidget)
Tony Mack18261812013-05-02 16:39:20 -0400821 instance_name = forms.CharField(widget=PlainTextWidget)
Tony Mackd90cdbf2013-04-16 22:48:40 -0400822 widgets = {
823 'ip': PlainTextWidget(),
Tony Mack18261812013-05-02 16:39:20 -0400824 'instance_name': PlainTextWidget(),
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400825 'slice': LinkedSelect,
826 'deploymentNetwork': LinkedSelect,
827 'node': LinkedSelect,
828 'image': LinkedSelect
Siobhan Tully53437282013-04-26 19:30:27 -0400829 }
Tony Mackd90cdbf2013-04-16 22:48:40 -0400830
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500831class TagAdmin(PlanetStackBaseAdmin):
Siobhan Tullyce652d02013-10-08 21:52:35 -0400832 list_display = ['service', 'name', 'value', 'content_type', 'content_object',]
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500833 user_readonly_fields = ['service', 'name', 'value', 'content_type', 'content_object',]
834 user_readonly_inlines = []
Siobhan Tullyd3515752013-06-21 16:34:53 -0400835
Tony Mack9bcbe4f2013-04-29 08:13:27 -0400836class SliverAdmin(PlanetStackBaseAdmin):
Tony Mackd90cdbf2013-04-16 22:48:40 -0400837 form = SliverForm
Tony Mackcdec0902013-04-15 00:38:49 -0400838 fieldsets = [
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400839 ('Sliver Details', {'fields': ['slice', 'deploymentNetwork', 'node', 'ip', 'instance_name', 'numberCores', 'image', ], 'classes': ['suit-tab suit-tab-general'], })
Tony Mackcdec0902013-04-15 00:38:49 -0400840 ]
Siobhan Tully5d7dc8d2013-07-02 13:17:33 -0400841 list_display = ['ip', 'instance_name', 'slice', 'numberCores', 'image', 'node', 'deploymentNetwork']
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400842
843 suit_form_tabs =(('general', 'Sliver Details'),
844 ('tags','Tags'),
845 )
846
Siobhan Tullyde5450d2013-06-21 11:35:33 -0400847 inlines = [TagInline]
Tony Mack53106f32013-04-27 16:43:01 -0400848
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500849 user_readonly_fields = ['slice', 'deploymentNetwork', 'node', 'ip', 'instance_name', 'numberCores', 'image']
850 user_readonly_inlines = [TagROInline]
851
Tony Mackc2835a92013-05-28 09:18:49 -0400852 def formfield_for_foreignkey(self, db_field, request, **kwargs):
853 if db_field.name == 'slice':
Tony Mack5b061472014-02-04 07:57:10 -0500854 kwargs['queryset'] = Slice.select_by_user(request.user)
Tony Mackc2835a92013-05-28 09:18:49 -0400855
856 return super(SliverAdmin, self).formfield_for_foreignkey(db_field, request, **kwargs)
857
Tony Mack04062832013-05-10 08:22:44 -0400858 def queryset(self, request):
859 # admins can see all slivers. Users can only see slivers of
860 # the slices they belong to.
Tony Mack5b061472014-02-04 07:57:10 -0500861 return Sliver.select_by_user(request.user)
862
Tony Mack04062832013-05-10 08:22:44 -0400863
Tony Mack1d6b85f2013-05-07 18:49:14 -0400864 def get_formsets(self, request, obj=None):
865 # make some fields read only if we are updating an existing record
866 if obj == None:
867 #self.readonly_fields = ('ip', 'instance_name')
868 self.readonly_fields = ()
869 else:
Tony Mack1e889462013-05-10 21:34:54 -0400870 self.readonly_fields = ()
871 #self.readonly_fields = ('ip', 'instance_name', 'slice', 'image', 'key')
Tony Mack1d6b85f2013-05-07 18:49:14 -0400872
873 for inline in self.get_inline_instances(request, obj):
874 # hide MyInline in the add view
875 if obj is None:
876 continue
Scott Baker526b71e2014-05-13 13:18:01 -0700877 if isinstance(inline, SliverInline):
878 inline.model.caller = request.user
879 yield inline.get_formset(request, obj)
Tony Mack53106f32013-04-27 16:43:01 -0400880
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500881 #def save_model(self, request, obj, form, change):
882 # # update openstack connection to use this site/tenant
883 # auth = request.session.get('auth', {})
884 # auth['tenant'] = obj.slice.name
885 # obj.os_manager = OpenStackManager(auth=auth, caller=request.user)
886 # obj.creator = request.user
887 # obj.save()
Tony Mack53106f32013-04-27 16:43:01 -0400888
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500889 #def delete_model(self, request, obj):
890 # # update openstack connection to use this site/tenant
891 # auth = request.session.get('auth', {})
892 # auth['tenant'] = obj.slice.name
893 # obj.os_manager = OpenStackManager(auth=auth, caller=request.user)
894 # obj.delete()
Tony Mackcdec0902013-04-15 00:38:49 -0400895
Siobhan Tully53437282013-04-26 19:30:27 -0400896class UserCreationForm(forms.ModelForm):
897 """A form for creating new users. Includes all the required
898 fields, plus a repeated password."""
899 password1 = forms.CharField(label='Password', widget=forms.PasswordInput)
900 password2 = forms.CharField(label='Password confirmation', widget=forms.PasswordInput)
901
902 class Meta:
Siobhan Tully30fd4292013-05-10 08:59:56 -0400903 model = User
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400904 fields = ('email', 'firstname', 'lastname', 'phone', 'public_key')
Siobhan Tully53437282013-04-26 19:30:27 -0400905
906 def clean_password2(self):
907 # Check that the two password entries match
908 password1 = self.cleaned_data.get("password1")
909 password2 = self.cleaned_data.get("password2")
910 if password1 and password2 and password1 != password2:
911 raise forms.ValidationError("Passwords don't match")
912 return password2
913
914 def save(self, commit=True):
915 # Save the provided password in hashed format
916 user = super(UserCreationForm, self).save(commit=False)
Tony Mackf9f4afb2013-05-01 21:02:12 -0400917 user.password = self.cleaned_data["password1"]
918 #user.set_password(self.cleaned_data["password1"])
Siobhan Tully53437282013-04-26 19:30:27 -0400919 if commit:
920 user.save()
921 return user
922
Siobhan Tully567e3e62013-06-21 18:03:16 -0400923
Siobhan Tully53437282013-04-26 19:30:27 -0400924class UserChangeForm(forms.ModelForm):
925 """A form for updating users. Includes all the fields on
926 the user, but replaces the password field with admin's
927 password hash display field.
928 """
Siobhan Tully63b7ba42014-01-12 10:35:11 -0500929 password = ReadOnlyPasswordHashField(label='Password',
930 help_text= '<a href=\"password/\">Change Password</a>.')
Siobhan Tully53437282013-04-26 19:30:27 -0400931
932 class Meta:
Siobhan Tully30fd4292013-05-10 08:59:56 -0400933 model = User
Siobhan Tully53437282013-04-26 19:30:27 -0400934
935 def clean_password(self):
936 # Regardless of what the user provides, return the initial value.
937 # This is done here, rather than on the field, because the
938 # field does not have access to the initial value
939 return self.initial["password"]
940
Scott Baker2c3cb642014-05-19 17:55:56 -0700941class UserDashboardViewInline(PlStackTabularInline):
942 model = UserDashboardView
943 extra = 0
944 suit_classes = 'suit-tab suit-tab-dashboards'
945 fields = ['user', 'dashboardView', 'order']
946
Scott Bakered31f672014-05-21 18:14:03 -0700947class UserDashboardViewROInline(ReadOnlyTabularInline):
948 model = UserDashboardView
949 extra = 0
950 suit_classes = 'suit-tab suit-tab-dashboards'
951 fields = ['user', 'dashboardView', 'order']
952
Tony Mack2bd5b412013-06-11 21:05:06 -0400953class UserAdmin(UserAdmin):
Siobhan Tully53437282013-04-26 19:30:27 -0400954 class Meta:
955 app_label = "core"
956
957 # The forms to add and change user instances
958 form = UserChangeForm
959 add_form = UserCreationForm
960
961 # The fields to be used in displaying the User model.
962 # These override the definitions on the base UserAdmin
963 # that reference specific fields on auth.User.
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500964 list_display = ('email', 'firstname', 'lastname', 'site', 'last_login')
Siobhan Tullyce652d02013-10-08 21:52:35 -0400965 #list_display = ('email', 'username','firstname', 'lastname', 'is_admin', 'last_login')
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500966 list_filter = ('site',)
Scott Baker2c3cb642014-05-19 17:55:56 -0700967 inlines = [SlicePrivilegeInline,SitePrivilegeInline,DeploymentPrivilegeInline,UserDashboardViewInline]
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500968
969 fieldListLoginDetails = ['email','site','password','is_readonly','is_amin','public_key']
970 fieldListContactInfo = ['firstname','lastname','phone','timezone']
971
Siobhan Tully53437282013-04-26 19:30:27 -0400972 fieldsets = (
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500973 ('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 -0400974 ('Contact Information', {'fields': ('firstname','lastname','phone', 'timezone'), 'classes':['suit-tab suit-tab-contact']}),
Scott Baker2c3cb642014-05-19 17:55:56 -0700975 #('Dashboard Views', {'fields': ('dashboards',), 'classes':['suit-tab suit-tab-dashboards']}),
Siobhan Tully53437282013-04-26 19:30:27 -0400976 #('Important dates', {'fields': ('last_login',)}),
977 )
978 add_fieldsets = (
979 (None, {
980 'classes': ('wide',),
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500981 'fields': ('email', 'firstname', 'lastname', 'is_readonly', 'phone', 'public_key','password1', 'password2')}
Siobhan Tully53437282013-04-26 19:30:27 -0400982 ),
983 )
984 search_fields = ('email',)
985 ordering = ('email',)
986 filter_horizontal = ()
987
Scott Baker3ca51f62014-05-23 12:05:11 -0700988 user_readonly_fields = fieldListLoginDetails + fieldListContactInfo
Scott Bakered31f672014-05-21 18:14:03 -0700989 user_readonly_inlines = [SlicePrivilegeROInline,SitePrivilegeROInline,DeploymentPrivilegeROInline,UserDashboardViewROInline]
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500990
Scott Baker2c3cb642014-05-19 17:55:56 -0700991 suit_form_tabs =(('general','Login Details'),
992 ('contact','Contact Information'),
993 ('sliceprivileges','Slice Privileges'),
994 ('siteprivileges','Site Privileges'),
995 ('deploymentprivileges','Deployment Privileges'),
996 ('dashboards','Dashboard Views'))
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400997
Tony Mackc2835a92013-05-28 09:18:49 -0400998 def formfield_for_foreignkey(self, db_field, request, **kwargs):
999 if db_field.name == 'site':
Tony Mack5b061472014-02-04 07:57:10 -05001000 kwargs['queryset'] = Site.select_by_user(request.user)
Tony Mackc2835a92013-05-28 09:18:49 -04001001
1002 return super(UserAdmin, self).formfield_for_foreignkey(db_field, request, **kwargs)
1003
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001004 def has_add_permission(self, request, obj=None):
1005 return (not self.__user_is_readonly(request))
1006
1007 def has_delete_permission(self, request, obj=None):
1008 return (not self.__user_is_readonly(request))
1009
1010 def get_actions(self,request):
1011 actions = super(UserAdmin,self).get_actions(request)
1012
1013 if self.__user_is_readonly(request):
1014 if 'delete_selected' in actions:
1015 del actions['delete_selected']
1016
1017 return actions
1018
1019 def change_view(self,request,object_id, extra_context=None):
1020
1021 if self.__user_is_readonly(request):
Scott Bakerf875eba2014-05-23 12:09:15 -07001022 if not hasattr(self, "readonly_save"):
1023 # save the original readonly fields
1024 self.readonly_save = self.readonly_fields
1025 self.inlines_save = self.inlines
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001026 self.readonly_fields=self.user_readonly_fields
1027 self.inlines = self.user_readonly_inlines
Scott Bakerf875eba2014-05-23 12:09:15 -07001028 else:
1029 if hasattr(self, "readonly_save"):
1030 # restore the original readonly fields
1031 self.readonly_fields = self.readonly_save
1032 self.inlines = self.inlines_save
1033
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001034 try:
1035 return super(UserAdmin, self).change_view(request, object_id, extra_context=extra_context)
1036 except PermissionDenied:
1037 pass
1038 if request.method == 'POST':
1039 raise PermissionDenied
1040 request.readonly = True
1041 return super(UserAdmin, self).change_view(request, object_id, extra_context=extra_context)
1042
1043 def __user_is_readonly(self, request):
1044 #groups = [x.name for x in request.user.groups.all() ]
1045 #return "readonly" in groups
1046 return request.user.isReadOnlyUser()
1047
Tony Mack5b061472014-02-04 07:57:10 -05001048 def queryset(self, request):
1049 return User.select_by_user(request.user)
1050
Scott Baker2c3cb642014-05-19 17:55:56 -07001051class DashboardViewAdmin(PlanetStackBaseAdmin):
1052 fieldsets = [('Dashboard View Details',
1053 {'fields': ['name', 'url'],
1054 'classes': ['suit-tab suit-tab-general']})
1055 ]
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001056
Scott Baker2c3cb642014-05-19 17:55:56 -07001057 suit_form_tabs =(('general','Dashboard View Details'),)
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001058
1059class ServiceResourceROInline(ReadOnlyTabularInline):
1060 model = ServiceResource
1061 extra = 0
1062 fields = ['serviceClass', 'name', 'maxUnitsDeployment', 'maxUnitsNode', 'maxDuration', 'bucketInRate', 'bucketMaxSize', 'cost', 'calendarReservable']
1063
Scott Baker0165fac2014-01-13 11:49:26 -08001064class ServiceResourceInline(PlStackTabularInline):
Scott Baker3de3e372013-05-10 16:50:44 -07001065 model = ServiceResource
1066 extra = 0
1067
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001068class ServiceClassAdmin(PlanetStackBaseAdmin):
Scott Baker3de3e372013-05-10 16:50:44 -07001069 list_display = ('name', 'commitment', 'membershipFee')
1070 inlines = [ServiceResourceInline]
1071
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001072 user_readonly_fields = ['name', 'commitment', 'membershipFee']
1073 user_readonly_inlines = []
1074
1075class ReservedResourceROInline(ReadOnlyTabularInline):
1076 model = ReservedResource
1077 extra = 0
1078 fields = ['sliver', 'resource','quantity','reservationSet']
1079 suit_classes = 'suit-tab suit-tab-reservedresources'
1080
Scott Baker0165fac2014-01-13 11:49:26 -08001081class ReservedResourceInline(PlStackTabularInline):
Scott Baker133c9212013-05-17 09:09:11 -07001082 model = ReservedResource
1083 extra = 0
Siobhan Tullybfd11dc2013-09-03 12:59:24 -04001084 suit_classes = 'suit-tab suit-tab-reservedresources'
Scott Baker133c9212013-05-17 09:09:11 -07001085
1086 def formfield_for_foreignkey(self, db_field, request=None, **kwargs):
1087 field = super(ReservedResourceInline, self).formfield_for_foreignkey(db_field, request, **kwargs)
1088
1089 if db_field.name == 'resource':
1090 # restrict resources to those that the slice's service class allows
1091 if request._slice is not None:
1092 field.queryset = field.queryset.filter(serviceClass = request._slice.serviceClass, calendarReservable=True)
1093 if len(field.queryset) > 0:
1094 field.initial = field.queryset.all()[0]
1095 else:
1096 field.queryset = field.queryset.none()
1097 elif db_field.name == 'sliver':
1098 # restrict slivers to those that belong to the slice
1099 if request._slice is not None:
1100 field.queryset = field.queryset.filter(slice = request._slice)
1101 else:
1102 field.queryset = field.queryset.none()
1103
1104 return field
1105
Tony Mack5b061472014-02-04 07:57:10 -05001106 def queryset(self, request):
1107 return ReservedResource.select_by_user(request.user)
1108
Scott Baker133c9212013-05-17 09:09:11 -07001109class ReservationChangeForm(forms.ModelForm):
1110 class Meta:
1111 model = Reservation
Siobhan Tullybfd11dc2013-09-03 12:59:24 -04001112 widgets = {
1113 'slice' : LinkedSelect
1114 }
Scott Baker133c9212013-05-17 09:09:11 -07001115
1116class ReservationAddForm(forms.ModelForm):
1117 slice = forms.ModelChoiceField(queryset=Slice.objects.all(), widget=forms.Select(attrs={"onChange":"document.getElementById('id_refresh').value=1; submit()"}))
1118 refresh = forms.CharField(widget=forms.HiddenInput())
1119
1120 class Media:
1121 css = {'all': ('planetstack.css',)} # .field-refresh { display: none; }
1122
1123 def clean_slice(self):
1124 slice = self.cleaned_data.get("slice")
1125 x = ServiceResource.objects.filter(serviceClass = slice.serviceClass, calendarReservable=True)
1126 if len(x) == 0:
1127 raise forms.ValidationError("The slice you selected does not have a service class that allows reservations")
1128 return slice
1129
1130 class Meta:
1131 model = Reservation
Siobhan Tullybfd11dc2013-09-03 12:59:24 -04001132 widgets = {
1133 'slice' : LinkedSelect
1134 }
1135
Scott Baker133c9212013-05-17 09:09:11 -07001136
1137class ReservationAddRefreshForm(ReservationAddForm):
1138 """ This form is displayed when the Reservation Form receives an update
1139 from the Slice dropdown onChange handler. It doesn't validate the
1140 data and doesn't save the data. This will cause the form to be
1141 redrawn.
1142 """
1143
Scott Baker8737e5f2013-05-17 09:35:32 -07001144 """ don't validate anything other than slice """
1145 dont_validate_fields = ("startTime", "duration")
1146
Scott Baker133c9212013-05-17 09:09:11 -07001147 def full_clean(self):
1148 result = super(ReservationAddForm, self).full_clean()
Scott Baker8737e5f2013-05-17 09:35:32 -07001149
1150 for fieldname in self.dont_validate_fields:
1151 if fieldname in self._errors:
1152 del self._errors[fieldname]
1153
Scott Baker133c9212013-05-17 09:09:11 -07001154 return result
1155
1156 """ don't save anything """
1157 def is_valid(self):
1158 return False
1159
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001160class ReservationAdmin(PlanetStackBaseAdmin):
1161 fieldList = ['slice', 'startTime', 'duration']
1162 fieldsets = [('Reservation Details', {'fields': fieldList, 'classes': ['suit-tab suit-tab-general']})]
Scott Baker133c9212013-05-17 09:09:11 -07001163 list_display = ('startTime', 'duration')
Scott Baker133c9212013-05-17 09:09:11 -07001164 form = ReservationAddForm
1165
Siobhan Tullybfd11dc2013-09-03 12:59:24 -04001166 suit_form_tabs = (('general','Reservation Details'), ('reservedresources','Reserved Resources'))
1167
1168 inlines = [ReservedResourceInline]
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001169 user_readonly_inlines = [ReservedResourceROInline]
1170 user_readonly_fields = fieldList
Siobhan Tullybfd11dc2013-09-03 12:59:24 -04001171
Scott Baker133c9212013-05-17 09:09:11 -07001172 def add_view(self, request, form_url='', extra_context=None):
Scott Bakeracd45142013-05-19 16:19:16 -07001173 timezone.activate(request.user.timezone)
Scott Baker133c9212013-05-17 09:09:11 -07001174 request._refresh = False
1175 request._slice = None
1176 if request.method == 'POST':
Scott Baker8737e5f2013-05-17 09:35:32 -07001177 # "refresh" will be set to "1" if the form was submitted due to
1178 # a change in the Slice dropdown.
Scott Baker133c9212013-05-17 09:09:11 -07001179 if request.POST.get("refresh","1") == "1":
1180 request._refresh = True
1181 request.POST["refresh"] = "0"
Scott Baker8737e5f2013-05-17 09:35:32 -07001182
1183 # Keep track of the slice that was selected, so the
1184 # reservedResource inline can filter items for the slice.
Scott Baker133c9212013-05-17 09:09:11 -07001185 request._slice = request.POST.get("slice",None)
1186 if (request._slice is not None):
1187 request._slice = Slice.objects.get(id=request._slice)
1188
1189 result = super(ReservationAdmin, self).add_view(request, form_url, extra_context)
1190 return result
1191
Scott Bakeracd45142013-05-19 16:19:16 -07001192 def changelist_view(self, request, extra_context = None):
1193 timezone.activate(request.user.timezone)
1194 return super(ReservationAdmin, self).changelist_view(request, extra_context)
1195
Scott Baker133c9212013-05-17 09:09:11 -07001196 def get_form(self, request, obj=None, **kwargs):
Siobhan Tullyd3515752013-06-21 16:34:53 -04001197 request._obj_ = obj
1198 if obj is not None:
1199 # For changes, set request._slice to the slice already set in the
1200 # object.
1201 request._slice = obj.slice
1202 self.form = ReservationChangeForm
1203 else:
1204 if getattr(request, "_refresh", False):
1205 self.form = ReservationAddRefreshForm
1206 else:
1207 self.form = ReservationAddForm
1208 return super(ReservationAdmin, self).get_form(request, obj, **kwargs)
1209
Scott Baker133c9212013-05-17 09:09:11 -07001210 def get_readonly_fields(self, request, obj=None):
Siobhan Tullyd3515752013-06-21 16:34:53 -04001211 if (obj is not None):
1212 # Prevent slice from being changed after the reservation has been
1213 # created.
1214 return ['slice']
1215 else:
Scott Baker133c9212013-05-17 09:09:11 -07001216 return []
Scott Baker3de3e372013-05-10 16:50:44 -07001217
Tony Mack5b061472014-02-04 07:57:10 -05001218 def queryset(self, request):
1219 return Reservation.select_by_user(request.user)
1220
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001221class NetworkParameterTypeAdmin(PlanetStackBaseAdmin):
Scott Baker74d8e622013-07-29 16:04:22 -07001222 list_display = ("name", )
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001223 user_readonly_fields = ['name']
1224 user_readonly_inlines = []
Scott Baker74d8e622013-07-29 16:04:22 -07001225
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001226class RouterAdmin(PlanetStackBaseAdmin):
Scott Baker74d8e622013-07-29 16:04:22 -07001227 list_display = ("name", )
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001228 user_readonly_fields = ['name']
1229 user_readonly_inlines = []
1230
1231class RouterROInline(ReadOnlyTabularInline):
1232 model = Router.networks.through
1233 extra = 0
1234 verbose_name_plural = "Routers"
1235 verbose_name = "Router"
1236 suit_classes = 'suit-tab suit-tab-routers'
1237
1238 fields = ['name', 'owner', 'permittedNetworks', 'networks']
Scott Baker74d8e622013-07-29 16:04:22 -07001239
Scott Baker0165fac2014-01-13 11:49:26 -08001240class RouterInline(PlStackTabularInline):
Scott Baker74d8e622013-07-29 16:04:22 -07001241 model = Router.networks.through
1242 extra = 0
1243 verbose_name_plural = "Routers"
1244 verbose_name = "Router"
Siobhan Tully2d95e482013-09-06 10:56:06 -04001245 suit_classes = 'suit-tab suit-tab-routers'
Scott Baker74d8e622013-07-29 16:04:22 -07001246
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001247class NetworkParameterROInline(ReadOnlyTabularInline):
1248 model = NetworkParameter
1249 extra = 1
1250 verbose_name_plural = "Parameters"
1251 verbose_name = "Parameter"
1252 suit_classes = 'suit-tab suit-tab-netparams'
1253 fields = ['parameter', 'value', 'content_type', 'object_id', 'content_object']
1254
Scott Baker74d8e622013-07-29 16:04:22 -07001255class NetworkParameterInline(generic.GenericTabularInline):
Scott Baker74d8e622013-07-29 16:04:22 -07001256 model = NetworkParameter
1257 extra = 1
1258 verbose_name_plural = "Parameters"
1259 verbose_name = "Parameter"
Siobhan Tully2d95e482013-09-06 10:56:06 -04001260 suit_classes = 'suit-tab suit-tab-netparams'
Scott Baker74d8e622013-07-29 16:04:22 -07001261
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001262class NetworkSliversROInline(ReadOnlyTabularInline):
1263 fields = ['network', 'sliver', 'ip', 'port_id']
1264 model = NetworkSliver
1265 extra = 0
1266 verbose_name_plural = "Slivers"
1267 verbose_name = "Sliver"
1268 suit_classes = 'suit-tab suit-tab-networkslivers'
1269
Scott Baker0165fac2014-01-13 11:49:26 -08001270class NetworkSliversInline(PlStackTabularInline):
Scott Baker74d8e622013-07-29 16:04:22 -07001271 readonly_fields = ("ip", )
1272 model = NetworkSliver
Scott Baker874936e2014-01-13 18:15:34 -08001273 selflink_fieldname = "sliver"
Scott Baker74d8e622013-07-29 16:04:22 -07001274 extra = 0
1275 verbose_name_plural = "Slivers"
1276 verbose_name = "Sliver"
Siobhan Tully2d95e482013-09-06 10:56:06 -04001277 suit_classes = 'suit-tab suit-tab-networkslivers'
Scott Baker74d8e622013-07-29 16:04:22 -07001278
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001279class NetworkSlicesROInline(ReadOnlyTabularInline):
1280 model = NetworkSlice
1281 extra = 0
1282 verbose_name_plural = "Slices"
1283 verbose_name = "Slice"
1284 suit_classes = 'suit-tab suit-tab-networkslices'
1285 fields = ['network','slice']
1286
Scott Baker0165fac2014-01-13 11:49:26 -08001287class NetworkSlicesInline(PlStackTabularInline):
Scott Bakerd7d2a392013-08-06 08:57:30 -07001288 model = NetworkSlice
Scott Baker874936e2014-01-13 18:15:34 -08001289 selflink_fieldname = "slice"
Scott Bakerd7d2a392013-08-06 08:57:30 -07001290 extra = 0
1291 verbose_name_plural = "Slices"
1292 verbose_name = "Slice"
Siobhan Tully2d95e482013-09-06 10:56:06 -04001293 suit_classes = 'suit-tab suit-tab-networkslices'
Scott Bakerd7d2a392013-08-06 08:57:30 -07001294
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001295class NetworkAdmin(PlanetStackBaseAdmin):
Scott Baker74d8e622013-07-29 16:04:22 -07001296 list_display = ("name", "subnet", "ports", "labels")
1297 readonly_fields = ("subnet", )
Siobhan Tully2d95e482013-09-06 10:56:06 -04001298
Scott Bakerd7d2a392013-08-06 08:57:30 -07001299 inlines = [NetworkParameterInline, NetworkSliversInline, NetworkSlicesInline, RouterInline]
Scott Baker74d8e622013-07-29 16:04:22 -07001300
Siobhan Tully2d95e482013-09-06 10:56:06 -04001301 fieldsets = [
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001302 (None, {'fields': ['name','template','ports','labels','owner','guaranteedBandwidth', 'permitAllSlices','permittedSlices','network_id','router_id','subnet_id','subnet'], 'classes':['suit-tab suit-tab-general']}),]
1303
1304 user_readonly_fields = ['name','template','ports','labels','owner','guaranteedBandwidth', 'permitAllSlices','permittedSlices','network_id','router_id','subnet_id','subnet']
1305 user_readonly_inlines = [NetworkParameterROInline, NetworkSliversROInline, NetworkSlicesROInline, RouterROInline]
Siobhan Tully2d95e482013-09-06 10:56:06 -04001306
1307 suit_form_tabs =(
1308 ('general','Network Details'),
1309 ('netparams', 'Parameters'),
1310 ('networkslivers','Slivers'),
1311 ('networkslices','Slices'),
1312 ('routers','Routers'),
1313 )
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001314class NetworkTemplateAdmin(PlanetStackBaseAdmin):
Scott Baker74d8e622013-07-29 16:04:22 -07001315 list_display = ("name", "guaranteedBandwidth", "visibility")
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001316 user_readonly_fields = ["name", "guaranteedBandwidth", "visibility"]
1317 user_readonly_inlines = []
Scott Baker74d8e622013-07-29 16:04:22 -07001318
Tony Mack31c2b8f2013-04-26 20:01:42 -04001319# register a signal that caches the user's credentials when they log in
1320def cache_credentials(sender, user, request, **kwds):
1321 auth = {'username': request.POST['username'],
1322 'password': request.POST['password']}
1323 request.session['auth'] = auth
1324user_logged_in.connect(cache_credentials)
1325
Scott Baker15cddfa2013-12-09 13:45:19 -08001326def dollar_field(fieldName, short_description):
1327 def newFunc(self, obj):
1328 try:
1329 x= "$ %0.2f" % float(getattr(obj, fieldName, 0.0))
1330 except:
1331 x=getattr(obj, fieldName, 0.0)
1332 return x
1333 newFunc.short_description = short_description
1334 return newFunc
1335
1336def right_dollar_field(fieldName, short_description):
1337 def newFunc(self, obj):
1338 try:
1339 #x= '<div align=right style="width:6em">$ %0.2f</div>' % float(getattr(obj, fieldName, 0.0))
1340 x= '<div align=right>$ %0.2f</div>' % float(getattr(obj, fieldName, 0.0))
1341 except:
1342 x=getattr(obj, fieldName, 0.0)
1343 return x
1344 newFunc.short_description = short_description
1345 newFunc.allow_tags = True
1346 return newFunc
Scott Baker43105042013-12-06 23:23:36 -08001347
Scott Baker0165fac2014-01-13 11:49:26 -08001348class InvoiceChargeInline(PlStackTabularInline):
Scott Baker43105042013-12-06 23:23:36 -08001349 model = Charge
Scott Baker15cddfa2013-12-09 13:45:19 -08001350 extra = 0
Scott Baker43105042013-12-06 23:23:36 -08001351 verbose_name_plural = "Charges"
1352 verbose_name = "Charge"
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001353 exclude = ['account']
Scott Baker9cb88a22013-12-09 18:56:00 -08001354 fields = ["date", "kind", "state", "object", "coreHours", "dollar_amount", "slice"]
1355 readonly_fields = ["date", "kind", "state", "object", "coreHours", "dollar_amount", "slice"]
1356 can_delete = False
1357 max_num = 0
1358
1359 dollar_amount = right_dollar_field("amount", "Amount")
Scott Baker43105042013-12-06 23:23:36 -08001360
1361class InvoiceAdmin(admin.ModelAdmin):
1362 list_display = ("date", "account")
1363
1364 inlines = [InvoiceChargeInline]
1365
Scott Baker9cb88a22013-12-09 18:56:00 -08001366 fields = ["date", "account", "dollar_amount"]
1367 readonly_fields = ["date", "account", "dollar_amount"]
1368
1369 dollar_amount = dollar_field("amount", "Amount")
Scott Baker43105042013-12-06 23:23:36 -08001370
Scott Baker0165fac2014-01-13 11:49:26 -08001371class InvoiceInline(PlStackTabularInline):
Scott Baker15cddfa2013-12-09 13:45:19 -08001372 model = Invoice
1373 extra = 0
1374 verbose_name_plural = "Invoices"
1375 verbose_name = "Invoice"
Scott Baker0165fac2014-01-13 11:49:26 -08001376 fields = ["date", "dollar_amount"]
1377 readonly_fields = ["date", "dollar_amount"]
Scott Baker15cddfa2013-12-09 13:45:19 -08001378 suit_classes = 'suit-tab suit-tab-accountinvoice'
1379 can_delete=False
1380 max_num=0
1381
1382 dollar_amount = right_dollar_field("amount", "Amount")
1383
Scott Baker0165fac2014-01-13 11:49:26 -08001384class PendingChargeInline(PlStackTabularInline):
Scott Baker43105042013-12-06 23:23:36 -08001385 model = Charge
Scott Baker15cddfa2013-12-09 13:45:19 -08001386 extra = 0
Scott Baker43105042013-12-06 23:23:36 -08001387 verbose_name_plural = "Charges"
1388 verbose_name = "Charge"
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001389 exclude = ["invoice"]
Scott Baker15cddfa2013-12-09 13:45:19 -08001390 fields = ["date", "kind", "state", "object", "coreHours", "dollar_amount", "slice"]
1391 readonly_fields = ["date", "kind", "state", "object", "coreHours", "dollar_amount", "slice"]
Scott Baker43105042013-12-06 23:23:36 -08001392 suit_classes = 'suit-tab suit-tab-accountpendingcharges'
Scott Baker15cddfa2013-12-09 13:45:19 -08001393 can_delete=False
1394 max_num=0
Scott Baker43105042013-12-06 23:23:36 -08001395
1396 def queryset(self, request):
1397 qs = super(PendingChargeInline, self).queryset(request)
1398 qs = qs.filter(state="pending")
1399 return qs
1400
Scott Baker15cddfa2013-12-09 13:45:19 -08001401 dollar_amount = right_dollar_field("amount", "Amount")
1402
Scott Baker0165fac2014-01-13 11:49:26 -08001403class PaymentInline(PlStackTabularInline):
Scott Baker43105042013-12-06 23:23:36 -08001404 model=Payment
1405 extra = 1
1406 verbose_name_plural = "Payments"
1407 verbose_name = "Payment"
Scott Baker15cddfa2013-12-09 13:45:19 -08001408 fields = ["date", "dollar_amount"]
1409 readonly_fields = ["date", "dollar_amount"]
Scott Baker43105042013-12-06 23:23:36 -08001410 suit_classes = 'suit-tab suit-tab-accountpayments'
Scott Baker15cddfa2013-12-09 13:45:19 -08001411 can_delete=False
1412 max_num=0
1413
1414 dollar_amount = right_dollar_field("amount", "Amount")
1415
Scott Baker43105042013-12-06 23:23:36 -08001416class AccountAdmin(admin.ModelAdmin):
1417 list_display = ("site", "balance_due")
1418
1419 inlines = [InvoiceInline, PaymentInline, PendingChargeInline]
1420
1421 fieldsets = [
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001422 (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 -08001423
Scott Baker15cddfa2013-12-09 13:45:19 -08001424 readonly_fields = ['site', 'dollar_balance_due', 'dollar_total_invoices', 'dollar_total_payments']
Scott Baker43105042013-12-06 23:23:36 -08001425
1426 suit_form_tabs =(
1427 ('general','Account Details'),
1428 ('accountinvoice', 'Invoices'),
1429 ('accountpayments', 'Payments'),
1430 ('accountpendingcharges','Pending Charges'),
1431 )
1432
Scott Baker15cddfa2013-12-09 13:45:19 -08001433 dollar_balance_due = dollar_field("balance_due", "Balance Due")
1434 dollar_total_invoices = dollar_field("total_invoices", "Total Invoices")
1435 dollar_total_payments = dollar_field("total_payments", "Total Payments")
1436
Siobhan Tullyce652d02013-10-08 21:52:35 -04001437
Siobhan Tully53437282013-04-26 19:30:27 -04001438# Now register the new UserAdmin...
Siobhan Tully30fd4292013-05-10 08:59:56 -04001439admin.site.register(User, UserAdmin)
Siobhan Tully53437282013-04-26 19:30:27 -04001440# ... and, since we're not using Django's builtin permissions,
1441# unregister the Group model from admin.
Siobhan Tullyce652d02013-10-08 21:52:35 -04001442#admin.site.unregister(Group)
Siobhan Tully53437282013-04-26 19:30:27 -04001443
Siobhan Tullybf1153a2013-05-27 20:53:48 -04001444#Do not show django evolution in the admin interface
1445from django_evolution.models import Version, Evolution
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001446#admin.site.unregister(Version)
1447#admin.site.unregister(Evolution)
Siobhan Tullybf1153a2013-05-27 20:53:48 -04001448
1449
1450# When debugging it is often easier to see all the classes, but for regular use
1451# only the top-levels should be displayed
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001452showAll = False
Scott Baker43105042013-12-06 23:23:36 -08001453
Siobhan Tullybf1153a2013-05-27 20:53:48 -04001454admin.site.register(Deployment, DeploymentAdmin)
Siobhan Tully4bc09f22013-04-10 21:15:21 -04001455admin.site.register(Site, SiteAdmin)
Siobhan Tully4bc09f22013-04-10 21:15:21 -04001456admin.site.register(Slice, SliceAdmin)
Siobhan Tullyce652d02013-10-08 21:52:35 -04001457admin.site.register(Service, ServiceAdmin)
smbakera3cf70c2013-06-27 02:01:41 -07001458admin.site.register(Reservation, ReservationAdmin)
Scott Baker74d8e622013-07-29 16:04:22 -07001459admin.site.register(Network, NetworkAdmin)
1460admin.site.register(Router, RouterAdmin)
Scott Baker74d8e622013-07-29 16:04:22 -07001461admin.site.register(NetworkTemplate, NetworkTemplateAdmin)
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001462admin.site.register(Account, AccountAdmin)
1463admin.site.register(Invoice, InvoiceAdmin)
Siobhan Tullybf1153a2013-05-27 20:53:48 -04001464
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001465if True:
1466 admin.site.register(NetworkParameterType, NetworkParameterTypeAdmin)
1467 admin.site.register(ServiceClass, ServiceClassAdmin)
Siobhan Tullybfd11dc2013-09-03 12:59:24 -04001468 #admin.site.register(PlanetStack)
Siobhan Tullyd3515752013-06-21 16:34:53 -04001469 admin.site.register(Tag, TagAdmin)
Siobhan Tullyce652d02013-10-08 21:52:35 -04001470 admin.site.register(DeploymentRole)
1471 admin.site.register(SiteRole)
1472 admin.site.register(SliceRole)
1473 admin.site.register(PlanetStackRole)
Siobhan Tullybf1153a2013-05-27 20:53:48 -04001474 admin.site.register(Node, NodeAdmin)
Siobhan Tullybfd11dc2013-09-03 12:59:24 -04001475 #admin.site.register(SlicePrivilege, SlicePrivilegeAdmin)
1476 #admin.site.register(SitePrivilege, SitePrivilegeAdmin)
Siobhan Tullybf1153a2013-05-27 20:53:48 -04001477 admin.site.register(Sliver, SliverAdmin)
Siobhan Tullybf1153a2013-05-27 20:53:48 -04001478 admin.site.register(Image, ImageAdmin)
Scott Baker2c3cb642014-05-19 17:55:56 -07001479 admin.site.register(DashboardView, DashboardViewAdmin)
Tony Mack7130ac32013-03-22 21:58:00 -04001480