blob: fc12ada112cbf9315267f457ecd82ea81a83436e [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 Baker2170b972014-06-03 12:14:07 -0700425 fields = ['network']
426
427class ImageDeploymentsInline(PlStackTabularInline):
428 model = ImageDeployments
429 extra = 0
430 verbose_name = "Image Deployments"
431 verbose_name_plural = "Image Deployments"
432 suit_classes = 'suit-tab suit-tab-imagedeployments'
433 fields = ['deployment', 'glance_image_id']
434 readonly_fields = ['deployment', 'glance_image_id']
Scott Baker74d8e622013-07-29 16:04:22 -0700435
Tony Mack5e71a662013-05-03 23:30:41 -0400436class PlainTextWidget(forms.HiddenInput):
437 input_type = 'hidden'
438
439 def render(self, name, value, attrs=None):
440 if value is None:
441 value = ''
Tony Mack1d6b85f2013-05-07 18:49:14 -0400442 return mark_safe(str(value) + super(PlainTextWidget, self).render(name, value, attrs))
Tony Mack9bcbe4f2013-04-29 08:13:27 -0400443
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500444class PlanetStackBaseAdmin(ReadOnlyAwareAdmin):
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400445 save_on_top = False
Tony Mack332ee1d2014-02-04 15:33:45 -0500446
447 def save_model(self, request, obj, form, change):
Tony Mack3d042792014-03-17 19:18:37 -0400448 obj.caller = request.user
Tony Mack332ee1d2014-02-04 15:33:45 -0500449 # update openstack connection to use this site/tenant
450 obj.save_by_user(request.user)
451
452 def delete_model(self, request, obj):
453 obj.delete_by_user(request.user)
454
455 def save_formset(self, request, form, formset, change):
456 instances = formset.save(commit=False)
457 for instance in instances:
458 instance.save_by_user(request.user)
459 formset.save_m2m()
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400460
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400461class SliceRoleAdmin(PlanetStackBaseAdmin):
462 model = SliceRole
463 pass
464
465class SiteRoleAdmin(PlanetStackBaseAdmin):
466 model = SiteRole
467 pass
468
Siobhan Tullybf1153a2013-05-27 20:53:48 -0400469class DeploymentAdminForm(forms.ModelForm):
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400470 sites = forms.ModelMultipleChoiceField(
471 queryset=Site.objects.all(),
472 required=False,
473 widget=FilteredSelectMultiple(
474 verbose_name=('Sites'), is_stacked=False
475 )
476 )
477 class Meta:
Siobhan Tullybf1153a2013-05-27 20:53:48 -0400478 model = Deployment
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400479
Siobhan Tully320b4622014-01-17 15:11:14 -0500480 def __init__(self, *args, **kwargs):
Scott Baker5380c522014-06-06 14:49:43 -0700481 request = kwargs.pop('request', None)
Siobhan Tully320b4622014-01-17 15:11:14 -0500482 super(DeploymentAdminForm, self).__init__(*args, **kwargs)
483
Scott Baker5380c522014-06-06 14:49:43 -0700484 self.fields['accessControl'].initial = "allow site " + request.user.site.name
485
Siobhan Tully320b4622014-01-17 15:11:14 -0500486 if self.instance and self.instance.pk:
Scott Bakerc9b14f72014-05-22 13:44:20 -0700487 self.fields['sites'].initial = [x.site for x in self.instance.sitedeployments_set.all()]
Siobhan Tully320b4622014-01-17 15:11:14 -0500488
489 def save(self, commit=True):
490 deployment = super(DeploymentAdminForm, self).save(commit=False)
491
492 if commit:
493 deployment.save()
494
495 if deployment.pk:
Scott Bakerc9b14f72014-05-22 13:44:20 -0700496 # save_m2m() doesn't seem to work with 'through' relations. So we
497 # create/destroy the through models ourselves. There has to be
498 # a better way...
499
500 sites = self.cleaned_data['sites']
501
502 existing_sites = []
503 for sdp in list(deployment.sitedeployments_set.all()):
504 if sdp.site not in sites:
505 #print "deleting site", sdp.site
506 sdp.delete()
507 else:
508 existing_sites.append(sdp.site)
509
510 for site in sites:
511 if site not in existing_sites:
512 #print "adding site", site
513 sdp = SiteDeployments(site=site, deployment=deployment)
514 sdp.save()
515
Siobhan Tully320b4622014-01-17 15:11:14 -0500516 self.save_m2m()
517
518 return deployment
519
Scott Bakerff5e0f32014-05-22 14:40:27 -0700520class DeploymentAdminROForm(DeploymentAdminForm):
521 def save(self, commit=True):
522 raise PermissionDenied
523
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500524class SiteAssocInline(PlStackTabularInline):
525 model = Site.deployments.through
526 extra = 0
527 suit_classes = 'suit-tab suit-tab-sites'
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400528
Siobhan Tullybf1153a2013-05-27 20:53:48 -0400529class DeploymentAdmin(PlanetStackBaseAdmin):
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500530 model = Deployment
Scott Baker5380c522014-06-06 14:49:43 -0700531 fieldList = ['name','sites', 'accessControl']
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500532 fieldsets = [(None, {'fields': fieldList, 'classes':['suit-tab suit-tab-sites']})]
Siobhan Tully2d95e482013-09-06 10:56:06 -0400533 inlines = [DeploymentPrivilegeInline,NodeInline,TagInline]
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500534
535 user_readonly_inlines = [DeploymentPrivilegeROInline,NodeROInline,TagROInline]
536 user_readonly_fields = ['name']
537
538 suit_form_tabs =(('sites','Deployment Details'),('nodes','Nodes'),('deploymentprivileges','Privileges'),('tags','Tags'))
539
Scott Bakerff5e0f32014-05-22 14:40:27 -0700540 def get_form(self, request, obj=None, **kwargs):
541 if request.user.isReadOnlyUser():
542 kwargs["form"] = DeploymentAdminROForm
543 else:
544 kwargs["form"] = DeploymentAdminForm
Scott Baker5380c522014-06-06 14:49:43 -0700545 adminForm = super(DeploymentAdmin,self).get_form(request, obj, **kwargs)
546
547 # from stackexchange: pass the request object into the form
548
549 class AdminFormMetaClass(adminForm):
550 def __new__(cls, *args, **kwargs):
551 kwargs['request'] = request
552 return adminForm(*args, **kwargs)
553
554 return AdminFormMetaClass
555
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500556class ServiceAttrAsTabROInline(ReadOnlyTabularInline):
557 model = ServiceAttribute
558 fields = ['name','value']
559 extra = 0
560 suit_classes = 'suit-tab suit-tab-serviceattrs'
Tony Mack5cd13202013-05-01 21:48:38 -0400561
Siobhan Tullyce652d02013-10-08 21:52:35 -0400562class ServiceAttrAsTabInline(PlStackTabularInline):
563 model = ServiceAttribute
564 fields = ['name','value']
565 extra = 0
566 suit_classes = 'suit-tab suit-tab-serviceattrs'
567
Siobhan Tullyce652d02013-10-08 21:52:35 -0400568class ServiceAdmin(PlanetStackBaseAdmin):
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500569 list_display = ("name","description","versionNumber","enabled","published")
570 fieldList = ["name","description","versionNumber","enabled","published"]
571 fieldsets = [(None, {'fields': fieldList, 'classes':['suit-tab suit-tab-general']})]
572 inlines = [ServiceAttrAsTabInline,SliceInline]
573
574 user_readonly_fields = fieldList
575 user_readonly_inlines = [ServiceAttrAsTabROInline,SliceROInline]
576
577 suit_form_tabs =(('general', 'Service Details'),
578 ('slices','Slices'),
579 ('serviceattrs','Additional Attributes'),
580 )
Siobhan Tullyce652d02013-10-08 21:52:35 -0400581
Tony Mack0553f282013-06-10 22:54:50 -0400582class SiteAdmin(PlanetStackBaseAdmin):
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500583 fieldList = ['name', 'site_url', 'enabled', 'is_public', 'login_base', 'accountLink','location']
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400584 fieldsets = [
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500585 (None, {'fields': fieldList, 'classes':['suit-tab suit-tab-general']}),
Tony Macke4be32f2014-03-11 20:45:25 -0400586 #('Deployment Networks', {'fields': ['deployments'], 'classes':['suit-tab suit-tab-deployments']}),
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400587 ]
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400588 suit_form_tabs =(('general', 'Site Details'),
589 ('users','Users'),
Siobhan Tully2d95e482013-09-06 10:56:06 -0400590 ('siteprivileges','Privileges'),
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400591 ('deployments','Deployments'),
592 ('slices','Slices'),
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500593 ('nodes','Nodes'),
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400594 ('tags','Tags'),
595 )
Scott Baker545db2a2013-12-09 18:44:43 -0800596 readonly_fields = ['accountLink']
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500597
598 user_readonly_fields = ['name', 'deployments','site_url', 'enabled', 'is_public', 'login_base', 'accountLink']
Tony Macke4be32f2014-03-11 20:45:25 -0400599 user_readonly_inlines = [SliceROInline,UserROInline,TagROInline, NodeROInline, SitePrivilegeROInline,SiteDeploymentROInline]
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500600
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400601 list_display = ('name', 'login_base','site_url', 'enabled')
602 filter_horizontal = ('deployments',)
Tony Macke4be32f2014-03-11 20:45:25 -0400603 inlines = [SliceInline,UserInline,TagInline, NodeInline, SitePrivilegeInline, SiteDeploymentInline]
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400604 search_fields = ['name']
605
Tony Mack04062832013-05-10 08:22:44 -0400606 def queryset(self, request):
Tony Mack5b061472014-02-04 07:57:10 -0500607 return Site.select_by_user(request.user)
Tony Mack04062832013-05-10 08:22:44 -0400608
Tony Mack5cd13202013-05-01 21:48:38 -0400609 def get_formsets(self, request, obj=None):
610 for inline in self.get_inline_instances(request, obj):
611 # hide MyInline in the add view
612 if obj is None:
613 continue
Tony Mack2bd5b412013-06-11 21:05:06 -0400614 if isinstance(inline, SliceInline):
615 inline.model.caller = request.user
616 yield inline.get_formset(request, obj)
617
618 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
623 if isinstance(inline, SliverInline):
624 inline.model.caller = request.user
Tony Mack5cd13202013-05-01 21:48:38 -0400625 yield inline.get_formset(request, obj)
626
Scott Baker545db2a2013-12-09 18:44:43 -0800627 def accountLink(self, obj):
628 link_obj = obj.accounts.all()
629 if link_obj:
630 reverse_path = "admin:core_account_change"
631 url = reverse(reverse_path, args =(link_obj[0].id,))
632 return "<a href='%s'>%s</a>" % (url, "view billing details")
633 else:
634 return "no billing data for this site"
635 accountLink.allow_tags = True
636 accountLink.short_description = "Billing"
637
Tony Mack332ee1d2014-02-04 15:33:45 -0500638 def save_model(self, request, obj, form, change):
639 # update openstack connection to use this site/tenant
640 obj.save_by_user(request.user)
641
642 def delete_model(self, request, obj):
643 obj.delete_by_user(request.user)
644
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500645
Tony Mack9bcbe4f2013-04-29 08:13:27 -0400646class SitePrivilegeAdmin(PlanetStackBaseAdmin):
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500647 fieldList = ['user', 'site', 'role']
Tony Mack00d361f2013-04-28 10:28:42 -0400648 fieldsets = [
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500649 (None, {'fields': fieldList, 'classes':['collapse']})
Tony Mack00d361f2013-04-28 10:28:42 -0400650 ]
651 list_display = ('user', 'site', 'role')
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500652 user_readonly_fields = fieldList
653 user_readonly_inlines = []
Tony Mack00d361f2013-04-28 10:28:42 -0400654
Tony Mackc2835a92013-05-28 09:18:49 -0400655 def formfield_for_foreignkey(self, db_field, request, **kwargs):
656 if db_field.name == 'site':
657 if not request.user.is_admin:
658 # only show sites where user is an admin or pi
659 sites = set()
660 for site_privilege in SitePrivilege.objects.filer(user=request.user):
661 if site_privilege.role.role_type in ['admin', 'pi']:
662 sites.add(site_privilege.site)
663 kwargs['queryset'] = Site.objects.filter(site__in=list(sites))
664
665 if db_field.name == 'user':
666 if not request.user.is_admin:
667 # only show users from sites where caller has admin or pi role
668 roles = Role.objects.filter(role_type__in=['admin', 'pi'])
669 site_privileges = SitePrivilege.objects.filter(user=request.user).filter(role__in=roles)
670 sites = [site_privilege.site for site_privilege in site_privileges]
671 site_privileges = SitePrivilege.objects.filter(site__in=sites)
672 emails = [site_privilege.user.email for site_privilege in site_privileges]
673 users = User.objects.filter(email__in=emails)
674 kwargs['queryset'] = users
675
676 return super(SitePrivilegeAdmin, self).formfield_for_foreignkey(db_field, request, **kwargs)
677
Tony Mack04062832013-05-10 08:22:44 -0400678 def queryset(self, request):
679 # admins can see all privileges. Users can only see privileges at sites
Tony Mackc2835a92013-05-28 09:18:49 -0400680 # where they have the admin role or pi role.
Tony Mack04062832013-05-10 08:22:44 -0400681 qs = super(SitePrivilegeAdmin, self).queryset(request)
Tony Mack5b061472014-02-04 07:57:10 -0500682 #if not request.user.is_admin:
683 # roles = Role.objects.filter(role_type__in=['admin', 'pi'])
684 # site_privileges = SitePrivilege.objects.filter(user=request.user).filter(role__in=roles)
685 # login_bases = [site_privilege.site.login_base for site_privilege in site_privileges]
686 # sites = Site.objects.filter(login_base__in=login_bases)
687 # qs = qs.filter(site__in=sites)
Tony Mack04062832013-05-10 08:22:44 -0400688 return qs
689
Siobhan Tullyce652d02013-10-08 21:52:35 -0400690class SliceForm(forms.ModelForm):
691 class Meta:
692 model = Slice
693 widgets = {
694 'service': LinkedSelect
695 }
696
Tony Mack2bd5b412013-06-11 21:05:06 -0400697class SliceAdmin(PlanetStackBaseAdmin):
Siobhan Tullyce652d02013-10-08 21:52:35 -0400698 form = SliceForm
Tony Mack29bf5e82014-04-29 21:40:24 -0400699 fieldList = ['name', 'site', 'serviceClass', 'enabled','description', 'service', 'slice_url', 'max_slivers']
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500700 fieldsets = [('Slice Details', {'fields': fieldList, 'classes':['suit-tab suit-tab-general']}),]
Tony Mack29bf5e82014-04-29 21:40:24 -0400701 list_display = ('name', 'site','serviceClass', 'slice_url', 'max_slivers')
Siobhan Tully2d95e482013-09-06 10:56:06 -0400702 inlines = [SlicePrivilegeInline,SliverInline, TagInline, ReservationInline,SliceNetworkInline]
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400703
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500704 user_readonly_fields = fieldList
705 user_readonly_inlines = [SlicePrivilegeROInline,SliverROInline,TagROInline, ReservationROInline, SliceNetworkROInline]
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400706
707 suit_form_tabs =(('general', 'Slice Details'),
Siobhan Tully2d95e482013-09-06 10:56:06 -0400708 ('slicenetworks','Networks'),
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400709 ('sliceprivileges','Privileges'),
710 ('slivers','Slivers'),
711 ('tags','Tags'),
712 ('reservations','Reservations'),
713 )
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400714
Tony Mackc2835a92013-05-28 09:18:49 -0400715 def formfield_for_foreignkey(self, db_field, request, **kwargs):
716 if db_field.name == 'site':
Tony Mack5b061472014-02-04 07:57:10 -0500717 kwargs['queryset'] = Site.select_by_user(request.user)
718
Tony Mackc2835a92013-05-28 09:18:49 -0400719 return super(SliceAdmin, self).formfield_for_foreignkey(db_field, request, **kwargs)
720
Tony Mack04062832013-05-10 08:22:44 -0400721 def queryset(self, request):
722 # admins can see all keys. Users can only see slices they belong to.
Tony Mack5b061472014-02-04 07:57:10 -0500723 return Slice.select_by_user(request.user)
Tony Mack04062832013-05-10 08:22:44 -0400724
Tony Mack79748612013-05-01 14:52:03 -0400725 def get_formsets(self, request, obj=None):
726 for inline in self.get_inline_instances(request, obj):
727 # hide MyInline in the add view
728 if obj is None:
729 continue
Tony Mack2bd5b412013-06-11 21:05:06 -0400730 if isinstance(inline, SliverInline):
731 inline.model.caller = request.user
Tony Mack79748612013-05-01 14:52:03 -0400732 yield inline.get_formset(request, obj)
733
Tony Mack2bd5b412013-06-11 21:05:06 -0400734
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400735class SlicePrivilegeAdmin(PlanetStackBaseAdmin):
Tony Mack00d361f2013-04-28 10:28:42 -0400736 fieldsets = [
737 (None, {'fields': ['user', 'slice', 'role']})
738 ]
739 list_display = ('user', 'slice', 'role')
Tony Mack00d361f2013-04-28 10:28:42 -0400740
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500741 user_readonly_fields = ['user', 'slice', 'role']
742 user_readonly_inlines = []
743
Tony Mackc2835a92013-05-28 09:18:49 -0400744 def formfield_for_foreignkey(self, db_field, request, **kwargs):
745 if db_field.name == 'slice':
Tony Mack5b061472014-02-04 07:57:10 -0500746 kwargs['queryset'] = Slice.select_by_user(request.user)
Tony Mackc2835a92013-05-28 09:18:49 -0400747
748 if db_field.name == 'user':
Tony Mack5b061472014-02-04 07:57:10 -0500749 kwargs['queryset'] = User.select_by_user(request.user)
Tony Mackc2835a92013-05-28 09:18:49 -0400750
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400751 return super(SlicePrivilegeAdmin, self).formfield_for_foreignkey(db_field, request, **kwargs)
Tony Mackc2835a92013-05-28 09:18:49 -0400752
Tony Mack04062832013-05-10 08:22:44 -0400753 def queryset(self, request):
754 # admins can see all memberships. Users can only see memberships of
755 # slices where they have the admin role.
Tony Mack5b061472014-02-04 07:57:10 -0500756 return SlicePrivilege.select_by_user(request.user)
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400757
Tony Mack9bcbe4f2013-04-29 08:13:27 -0400758 def save_model(self, request, obj, form, change):
Tony Mack951dab42013-05-02 19:51:45 -0400759 # update openstack connection to use this site/tenant
760 auth = request.session.get('auth', {})
761 auth['tenant'] = obj.slice.name
762 obj.os_manager = OpenStackManager(auth=auth, caller=request.user)
Tony Mack9bcbe4f2013-04-29 08:13:27 -0400763 obj.save()
764
765 def delete_model(self, request, obj):
Tony Mack951dab42013-05-02 19:51:45 -0400766 # update openstack connection to use this site/tenant
767 auth = request.session.get('auth', {})
768 auth['tenant'] = obj.slice.name
769 obj.os_manager = OpenStackManager(auth=auth, caller=request.user)
Tony Mack9bcbe4f2013-04-29 08:13:27 -0400770 obj.delete()
771
Siobhan Tully567e3e62013-06-21 18:03:16 -0400772
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400773class ImageAdmin(PlanetStackBaseAdmin):
774
775 fieldsets = [('Image Details',
Scott Baker00b00b32014-05-07 08:47:54 -0700776 {'fields': ['name', 'disk_format', 'container_format'],
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400777 'classes': ['suit-tab suit-tab-general']})
778 ]
779
Scott Baker2170b972014-06-03 12:14:07 -0700780 suit_form_tabs =(('general','Image Details'),('slivers','Slivers'),('imagedeployments','Deployments'))
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400781
Scott Baker2170b972014-06-03 12:14:07 -0700782 inlines = [SliverInline, ImageDeploymentsInline]
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500783
Tony Mack32e1ce32014-05-07 13:29:41 -0400784 user_readonly_fields = ['name', 'disk_format', 'container_format']
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500785 user_readonly_inlines = [SliverROInline]
786
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400787class NodeForm(forms.ModelForm):
788 class Meta:
789 widgets = {
790 'site': LinkedSelect,
791 'deployment': LinkedSelect
792 }
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400793
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500794class NodeAdmin(PlanetStackBaseAdmin):
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400795 form = NodeForm
Siobhan Tullybf1153a2013-05-27 20:53:48 -0400796 list_display = ('name', 'site', 'deployment')
797 list_filter = ('deployment',)
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500798
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400799 inlines = [TagInline,SliverInline]
800 fieldsets = [('Node Details', {'fields': ['name','site','deployment'], 'classes':['suit-tab suit-tab-details']})]
801
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500802 user_readonly_fields = ['name','site','deployment']
803 user_readonly_inlines = [TagInline,SliverInline]
804
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400805 suit_form_tabs =(('details','Node Details'),('slivers','Slivers'),('tags','Tags'))
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400806
Siobhan Tully567e3e62013-06-21 18:03:16 -0400807
Tony Mackd90cdbf2013-04-16 22:48:40 -0400808class SliverForm(forms.ModelForm):
809 class Meta:
Tony Mack1d6b85f2013-05-07 18:49:14 -0400810 model = Sliver
Tony Mackd90cdbf2013-04-16 22:48:40 -0400811 ip = forms.CharField(widget=PlainTextWidget)
Tony Mack18261812013-05-02 16:39:20 -0400812 instance_name = forms.CharField(widget=PlainTextWidget)
Tony Mackd90cdbf2013-04-16 22:48:40 -0400813 widgets = {
814 'ip': PlainTextWidget(),
Tony Mack18261812013-05-02 16:39:20 -0400815 'instance_name': PlainTextWidget(),
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400816 'slice': LinkedSelect,
817 'deploymentNetwork': LinkedSelect,
818 'node': LinkedSelect,
819 'image': LinkedSelect
Siobhan Tully53437282013-04-26 19:30:27 -0400820 }
Tony Mackd90cdbf2013-04-16 22:48:40 -0400821
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500822class TagAdmin(PlanetStackBaseAdmin):
Siobhan Tullyce652d02013-10-08 21:52:35 -0400823 list_display = ['service', 'name', 'value', 'content_type', 'content_object',]
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500824 user_readonly_fields = ['service', 'name', 'value', 'content_type', 'content_object',]
825 user_readonly_inlines = []
Siobhan Tullyd3515752013-06-21 16:34:53 -0400826
Tony Mack9bcbe4f2013-04-29 08:13:27 -0400827class SliverAdmin(PlanetStackBaseAdmin):
Tony Mackd90cdbf2013-04-16 22:48:40 -0400828 form = SliverForm
Tony Mackcdec0902013-04-15 00:38:49 -0400829 fieldsets = [
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400830 ('Sliver Details', {'fields': ['slice', 'deploymentNetwork', 'node', 'ip', 'instance_name', 'numberCores', 'image', ], 'classes': ['suit-tab suit-tab-general'], })
Tony Mackcdec0902013-04-15 00:38:49 -0400831 ]
Siobhan Tully5d7dc8d2013-07-02 13:17:33 -0400832 list_display = ['ip', 'instance_name', 'slice', 'numberCores', 'image', 'node', 'deploymentNetwork']
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400833
834 suit_form_tabs =(('general', 'Sliver Details'),
835 ('tags','Tags'),
836 )
837
Siobhan Tullyde5450d2013-06-21 11:35:33 -0400838 inlines = [TagInline]
Tony Mack53106f32013-04-27 16:43:01 -0400839
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500840 user_readonly_fields = ['slice', 'deploymentNetwork', 'node', 'ip', 'instance_name', 'numberCores', 'image']
841 user_readonly_inlines = [TagROInline]
842
Tony Mackc2835a92013-05-28 09:18:49 -0400843 def formfield_for_foreignkey(self, db_field, request, **kwargs):
844 if db_field.name == 'slice':
Tony Mack5b061472014-02-04 07:57:10 -0500845 kwargs['queryset'] = Slice.select_by_user(request.user)
Tony Mackc2835a92013-05-28 09:18:49 -0400846
847 return super(SliverAdmin, self).formfield_for_foreignkey(db_field, request, **kwargs)
848
Tony Mack04062832013-05-10 08:22:44 -0400849 def queryset(self, request):
850 # admins can see all slivers. Users can only see slivers of
851 # the slices they belong to.
Tony Mack5b061472014-02-04 07:57:10 -0500852 return Sliver.select_by_user(request.user)
853
Tony Mack04062832013-05-10 08:22:44 -0400854
Tony Mack1d6b85f2013-05-07 18:49:14 -0400855 def get_formsets(self, request, obj=None):
856 # make some fields read only if we are updating an existing record
857 if obj == None:
858 #self.readonly_fields = ('ip', 'instance_name')
859 self.readonly_fields = ()
860 else:
Tony Mack1e889462013-05-10 21:34:54 -0400861 self.readonly_fields = ()
862 #self.readonly_fields = ('ip', 'instance_name', 'slice', 'image', 'key')
Tony Mack1d6b85f2013-05-07 18:49:14 -0400863
864 for inline in self.get_inline_instances(request, obj):
865 # hide MyInline in the add view
866 if obj is None:
867 continue
Scott Baker526b71e2014-05-13 13:18:01 -0700868 if isinstance(inline, SliverInline):
869 inline.model.caller = request.user
870 yield inline.get_formset(request, obj)
Tony Mack53106f32013-04-27 16:43:01 -0400871
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500872 #def save_model(self, request, obj, form, change):
873 # # update openstack connection to use this site/tenant
874 # auth = request.session.get('auth', {})
875 # auth['tenant'] = obj.slice.name
876 # obj.os_manager = OpenStackManager(auth=auth, caller=request.user)
877 # obj.creator = request.user
878 # obj.save()
Tony Mack53106f32013-04-27 16:43:01 -0400879
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500880 #def delete_model(self, request, obj):
881 # # update openstack connection to use this site/tenant
882 # auth = request.session.get('auth', {})
883 # auth['tenant'] = obj.slice.name
884 # obj.os_manager = OpenStackManager(auth=auth, caller=request.user)
885 # obj.delete()
Tony Mackcdec0902013-04-15 00:38:49 -0400886
Siobhan Tully53437282013-04-26 19:30:27 -0400887class UserCreationForm(forms.ModelForm):
888 """A form for creating new users. Includes all the required
889 fields, plus a repeated password."""
890 password1 = forms.CharField(label='Password', widget=forms.PasswordInput)
891 password2 = forms.CharField(label='Password confirmation', widget=forms.PasswordInput)
892
893 class Meta:
Siobhan Tully30fd4292013-05-10 08:59:56 -0400894 model = User
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400895 fields = ('email', 'firstname', 'lastname', 'phone', 'public_key')
Siobhan Tully53437282013-04-26 19:30:27 -0400896
897 def clean_password2(self):
898 # Check that the two password entries match
899 password1 = self.cleaned_data.get("password1")
900 password2 = self.cleaned_data.get("password2")
901 if password1 and password2 and password1 != password2:
902 raise forms.ValidationError("Passwords don't match")
903 return password2
904
905 def save(self, commit=True):
906 # Save the provided password in hashed format
907 user = super(UserCreationForm, self).save(commit=False)
Tony Mackf9f4afb2013-05-01 21:02:12 -0400908 user.password = self.cleaned_data["password1"]
909 #user.set_password(self.cleaned_data["password1"])
Siobhan Tully53437282013-04-26 19:30:27 -0400910 if commit:
911 user.save()
912 return user
913
Siobhan Tully567e3e62013-06-21 18:03:16 -0400914
Siobhan Tully53437282013-04-26 19:30:27 -0400915class UserChangeForm(forms.ModelForm):
916 """A form for updating users. Includes all the fields on
917 the user, but replaces the password field with admin's
918 password hash display field.
919 """
Siobhan Tully63b7ba42014-01-12 10:35:11 -0500920 password = ReadOnlyPasswordHashField(label='Password',
921 help_text= '<a href=\"password/\">Change Password</a>.')
Siobhan Tully53437282013-04-26 19:30:27 -0400922
923 class Meta:
Siobhan Tully30fd4292013-05-10 08:59:56 -0400924 model = User
Siobhan Tully53437282013-04-26 19:30:27 -0400925
926 def clean_password(self):
927 # Regardless of what the user provides, return the initial value.
928 # This is done here, rather than on the field, because the
929 # field does not have access to the initial value
930 return self.initial["password"]
931
Scott Baker2c3cb642014-05-19 17:55:56 -0700932class UserDashboardViewInline(PlStackTabularInline):
933 model = UserDashboardView
934 extra = 0
935 suit_classes = 'suit-tab suit-tab-dashboards'
936 fields = ['user', 'dashboardView', 'order']
937
Scott Bakered31f672014-05-21 18:14:03 -0700938class UserDashboardViewROInline(ReadOnlyTabularInline):
939 model = UserDashboardView
940 extra = 0
941 suit_classes = 'suit-tab suit-tab-dashboards'
942 fields = ['user', 'dashboardView', 'order']
943
Tony Mack2bd5b412013-06-11 21:05:06 -0400944class UserAdmin(UserAdmin):
Siobhan Tully53437282013-04-26 19:30:27 -0400945 class Meta:
946 app_label = "core"
947
948 # The forms to add and change user instances
949 form = UserChangeForm
950 add_form = UserCreationForm
951
952 # The fields to be used in displaying the User model.
953 # These override the definitions on the base UserAdmin
954 # that reference specific fields on auth.User.
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500955 list_display = ('email', 'firstname', 'lastname', 'site', 'last_login')
Siobhan Tullyce652d02013-10-08 21:52:35 -0400956 #list_display = ('email', 'username','firstname', 'lastname', 'is_admin', 'last_login')
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500957 list_filter = ('site',)
Scott Baker2c3cb642014-05-19 17:55:56 -0700958 inlines = [SlicePrivilegeInline,SitePrivilegeInline,DeploymentPrivilegeInline,UserDashboardViewInline]
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500959
960 fieldListLoginDetails = ['email','site','password','is_readonly','is_amin','public_key']
961 fieldListContactInfo = ['firstname','lastname','phone','timezone']
962
Siobhan Tully53437282013-04-26 19:30:27 -0400963 fieldsets = (
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500964 ('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 -0400965 ('Contact Information', {'fields': ('firstname','lastname','phone', 'timezone'), 'classes':['suit-tab suit-tab-contact']}),
Scott Baker2c3cb642014-05-19 17:55:56 -0700966 #('Dashboard Views', {'fields': ('dashboards',), 'classes':['suit-tab suit-tab-dashboards']}),
Siobhan Tully53437282013-04-26 19:30:27 -0400967 #('Important dates', {'fields': ('last_login',)}),
968 )
969 add_fieldsets = (
970 (None, {
971 'classes': ('wide',),
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500972 'fields': ('email', 'firstname', 'lastname', 'is_readonly', 'phone', 'public_key','password1', 'password2')}
Siobhan Tully53437282013-04-26 19:30:27 -0400973 ),
974 )
975 search_fields = ('email',)
976 ordering = ('email',)
977 filter_horizontal = ()
978
Scott Baker3ca51f62014-05-23 12:05:11 -0700979 user_readonly_fields = fieldListLoginDetails + fieldListContactInfo
Scott Bakered31f672014-05-21 18:14:03 -0700980 user_readonly_inlines = [SlicePrivilegeROInline,SitePrivilegeROInline,DeploymentPrivilegeROInline,UserDashboardViewROInline]
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500981
Scott Baker2c3cb642014-05-19 17:55:56 -0700982 suit_form_tabs =(('general','Login Details'),
983 ('contact','Contact Information'),
984 ('sliceprivileges','Slice Privileges'),
985 ('siteprivileges','Site Privileges'),
986 ('deploymentprivileges','Deployment Privileges'),
987 ('dashboards','Dashboard Views'))
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400988
Tony Mackc2835a92013-05-28 09:18:49 -0400989 def formfield_for_foreignkey(self, db_field, request, **kwargs):
990 if db_field.name == 'site':
Tony Mack5b061472014-02-04 07:57:10 -0500991 kwargs['queryset'] = Site.select_by_user(request.user)
Tony Mackc2835a92013-05-28 09:18:49 -0400992
993 return super(UserAdmin, self).formfield_for_foreignkey(db_field, request, **kwargs)
994
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500995 def has_add_permission(self, request, obj=None):
996 return (not self.__user_is_readonly(request))
997
998 def has_delete_permission(self, request, obj=None):
999 return (not self.__user_is_readonly(request))
1000
1001 def get_actions(self,request):
1002 actions = super(UserAdmin,self).get_actions(request)
1003
1004 if self.__user_is_readonly(request):
1005 if 'delete_selected' in actions:
1006 del actions['delete_selected']
1007
1008 return actions
1009
1010 def change_view(self,request,object_id, extra_context=None):
1011
1012 if self.__user_is_readonly(request):
Scott Bakerf875eba2014-05-23 12:09:15 -07001013 if not hasattr(self, "readonly_save"):
1014 # save the original readonly fields
1015 self.readonly_save = self.readonly_fields
1016 self.inlines_save = self.inlines
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001017 self.readonly_fields=self.user_readonly_fields
1018 self.inlines = self.user_readonly_inlines
Scott Bakerf875eba2014-05-23 12:09:15 -07001019 else:
1020 if hasattr(self, "readonly_save"):
1021 # restore the original readonly fields
1022 self.readonly_fields = self.readonly_save
1023 self.inlines = self.inlines_save
1024
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001025 try:
1026 return super(UserAdmin, self).change_view(request, object_id, extra_context=extra_context)
1027 except PermissionDenied:
1028 pass
1029 if request.method == 'POST':
1030 raise PermissionDenied
1031 request.readonly = True
1032 return super(UserAdmin, self).change_view(request, object_id, extra_context=extra_context)
1033
1034 def __user_is_readonly(self, request):
1035 #groups = [x.name for x in request.user.groups.all() ]
1036 #return "readonly" in groups
1037 return request.user.isReadOnlyUser()
1038
Tony Mack5b061472014-02-04 07:57:10 -05001039 def queryset(self, request):
1040 return User.select_by_user(request.user)
1041
Scott Baker2c3cb642014-05-19 17:55:56 -07001042class DashboardViewAdmin(PlanetStackBaseAdmin):
1043 fieldsets = [('Dashboard View Details',
1044 {'fields': ['name', 'url'],
1045 'classes': ['suit-tab suit-tab-general']})
1046 ]
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001047
Scott Baker2c3cb642014-05-19 17:55:56 -07001048 suit_form_tabs =(('general','Dashboard View Details'),)
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001049
1050class ServiceResourceROInline(ReadOnlyTabularInline):
1051 model = ServiceResource
1052 extra = 0
1053 fields = ['serviceClass', 'name', 'maxUnitsDeployment', 'maxUnitsNode', 'maxDuration', 'bucketInRate', 'bucketMaxSize', 'cost', 'calendarReservable']
1054
Scott Baker0165fac2014-01-13 11:49:26 -08001055class ServiceResourceInline(PlStackTabularInline):
Scott Baker3de3e372013-05-10 16:50:44 -07001056 model = ServiceResource
1057 extra = 0
1058
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001059class ServiceClassAdmin(PlanetStackBaseAdmin):
Scott Baker3de3e372013-05-10 16:50:44 -07001060 list_display = ('name', 'commitment', 'membershipFee')
1061 inlines = [ServiceResourceInline]
1062
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001063 user_readonly_fields = ['name', 'commitment', 'membershipFee']
1064 user_readonly_inlines = []
1065
1066class ReservedResourceROInline(ReadOnlyTabularInline):
1067 model = ReservedResource
1068 extra = 0
1069 fields = ['sliver', 'resource','quantity','reservationSet']
1070 suit_classes = 'suit-tab suit-tab-reservedresources'
1071
Scott Baker0165fac2014-01-13 11:49:26 -08001072class ReservedResourceInline(PlStackTabularInline):
Scott Baker133c9212013-05-17 09:09:11 -07001073 model = ReservedResource
1074 extra = 0
Siobhan Tullybfd11dc2013-09-03 12:59:24 -04001075 suit_classes = 'suit-tab suit-tab-reservedresources'
Scott Baker133c9212013-05-17 09:09:11 -07001076
1077 def formfield_for_foreignkey(self, db_field, request=None, **kwargs):
1078 field = super(ReservedResourceInline, self).formfield_for_foreignkey(db_field, request, **kwargs)
1079
1080 if db_field.name == 'resource':
1081 # restrict resources to those that the slice's service class allows
1082 if request._slice is not None:
1083 field.queryset = field.queryset.filter(serviceClass = request._slice.serviceClass, calendarReservable=True)
1084 if len(field.queryset) > 0:
1085 field.initial = field.queryset.all()[0]
1086 else:
1087 field.queryset = field.queryset.none()
1088 elif db_field.name == 'sliver':
1089 # restrict slivers to those that belong to the slice
1090 if request._slice is not None:
1091 field.queryset = field.queryset.filter(slice = request._slice)
1092 else:
1093 field.queryset = field.queryset.none()
1094
1095 return field
1096
Tony Mack5b061472014-02-04 07:57:10 -05001097 def queryset(self, request):
1098 return ReservedResource.select_by_user(request.user)
1099
Scott Baker133c9212013-05-17 09:09:11 -07001100class ReservationChangeForm(forms.ModelForm):
1101 class Meta:
1102 model = Reservation
Siobhan Tullybfd11dc2013-09-03 12:59:24 -04001103 widgets = {
1104 'slice' : LinkedSelect
1105 }
Scott Baker133c9212013-05-17 09:09:11 -07001106
1107class ReservationAddForm(forms.ModelForm):
1108 slice = forms.ModelChoiceField(queryset=Slice.objects.all(), widget=forms.Select(attrs={"onChange":"document.getElementById('id_refresh').value=1; submit()"}))
1109 refresh = forms.CharField(widget=forms.HiddenInput())
1110
1111 class Media:
1112 css = {'all': ('planetstack.css',)} # .field-refresh { display: none; }
1113
1114 def clean_slice(self):
1115 slice = self.cleaned_data.get("slice")
1116 x = ServiceResource.objects.filter(serviceClass = slice.serviceClass, calendarReservable=True)
1117 if len(x) == 0:
1118 raise forms.ValidationError("The slice you selected does not have a service class that allows reservations")
1119 return slice
1120
1121 class Meta:
1122 model = Reservation
Siobhan Tullybfd11dc2013-09-03 12:59:24 -04001123 widgets = {
1124 'slice' : LinkedSelect
1125 }
1126
Scott Baker133c9212013-05-17 09:09:11 -07001127
1128class ReservationAddRefreshForm(ReservationAddForm):
1129 """ This form is displayed when the Reservation Form receives an update
1130 from the Slice dropdown onChange handler. It doesn't validate the
1131 data and doesn't save the data. This will cause the form to be
1132 redrawn.
1133 """
1134
Scott Baker8737e5f2013-05-17 09:35:32 -07001135 """ don't validate anything other than slice """
1136 dont_validate_fields = ("startTime", "duration")
1137
Scott Baker133c9212013-05-17 09:09:11 -07001138 def full_clean(self):
1139 result = super(ReservationAddForm, self).full_clean()
Scott Baker8737e5f2013-05-17 09:35:32 -07001140
1141 for fieldname in self.dont_validate_fields:
1142 if fieldname in self._errors:
1143 del self._errors[fieldname]
1144
Scott Baker133c9212013-05-17 09:09:11 -07001145 return result
1146
1147 """ don't save anything """
1148 def is_valid(self):
1149 return False
1150
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001151class ReservationAdmin(PlanetStackBaseAdmin):
1152 fieldList = ['slice', 'startTime', 'duration']
1153 fieldsets = [('Reservation Details', {'fields': fieldList, 'classes': ['suit-tab suit-tab-general']})]
Scott Baker133c9212013-05-17 09:09:11 -07001154 list_display = ('startTime', 'duration')
Scott Baker133c9212013-05-17 09:09:11 -07001155 form = ReservationAddForm
1156
Siobhan Tullybfd11dc2013-09-03 12:59:24 -04001157 suit_form_tabs = (('general','Reservation Details'), ('reservedresources','Reserved Resources'))
1158
1159 inlines = [ReservedResourceInline]
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001160 user_readonly_inlines = [ReservedResourceROInline]
1161 user_readonly_fields = fieldList
Siobhan Tullybfd11dc2013-09-03 12:59:24 -04001162
Scott Baker133c9212013-05-17 09:09:11 -07001163 def add_view(self, request, form_url='', extra_context=None):
Scott Bakeracd45142013-05-19 16:19:16 -07001164 timezone.activate(request.user.timezone)
Scott Baker133c9212013-05-17 09:09:11 -07001165 request._refresh = False
1166 request._slice = None
1167 if request.method == 'POST':
Scott Baker8737e5f2013-05-17 09:35:32 -07001168 # "refresh" will be set to "1" if the form was submitted due to
1169 # a change in the Slice dropdown.
Scott Baker133c9212013-05-17 09:09:11 -07001170 if request.POST.get("refresh","1") == "1":
1171 request._refresh = True
1172 request.POST["refresh"] = "0"
Scott Baker8737e5f2013-05-17 09:35:32 -07001173
1174 # Keep track of the slice that was selected, so the
1175 # reservedResource inline can filter items for the slice.
Scott Baker133c9212013-05-17 09:09:11 -07001176 request._slice = request.POST.get("slice",None)
1177 if (request._slice is not None):
1178 request._slice = Slice.objects.get(id=request._slice)
1179
1180 result = super(ReservationAdmin, self).add_view(request, form_url, extra_context)
1181 return result
1182
Scott Bakeracd45142013-05-19 16:19:16 -07001183 def changelist_view(self, request, extra_context = None):
1184 timezone.activate(request.user.timezone)
1185 return super(ReservationAdmin, self).changelist_view(request, extra_context)
1186
Scott Baker133c9212013-05-17 09:09:11 -07001187 def get_form(self, request, obj=None, **kwargs):
Siobhan Tullyd3515752013-06-21 16:34:53 -04001188 request._obj_ = obj
1189 if obj is not None:
1190 # For changes, set request._slice to the slice already set in the
1191 # object.
1192 request._slice = obj.slice
1193 self.form = ReservationChangeForm
1194 else:
1195 if getattr(request, "_refresh", False):
1196 self.form = ReservationAddRefreshForm
1197 else:
1198 self.form = ReservationAddForm
1199 return super(ReservationAdmin, self).get_form(request, obj, **kwargs)
1200
Scott Baker133c9212013-05-17 09:09:11 -07001201 def get_readonly_fields(self, request, obj=None):
Siobhan Tullyd3515752013-06-21 16:34:53 -04001202 if (obj is not None):
1203 # Prevent slice from being changed after the reservation has been
1204 # created.
1205 return ['slice']
1206 else:
Scott Baker133c9212013-05-17 09:09:11 -07001207 return []
Scott Baker3de3e372013-05-10 16:50:44 -07001208
Tony Mack5b061472014-02-04 07:57:10 -05001209 def queryset(self, request):
1210 return Reservation.select_by_user(request.user)
1211
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001212class NetworkParameterTypeAdmin(PlanetStackBaseAdmin):
Scott Baker74d8e622013-07-29 16:04:22 -07001213 list_display = ("name", )
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001214 user_readonly_fields = ['name']
1215 user_readonly_inlines = []
Scott Baker74d8e622013-07-29 16:04:22 -07001216
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001217class RouterAdmin(PlanetStackBaseAdmin):
Scott Baker74d8e622013-07-29 16:04:22 -07001218 list_display = ("name", )
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001219 user_readonly_fields = ['name']
1220 user_readonly_inlines = []
1221
1222class RouterROInline(ReadOnlyTabularInline):
1223 model = Router.networks.through
1224 extra = 0
1225 verbose_name_plural = "Routers"
1226 verbose_name = "Router"
1227 suit_classes = 'suit-tab suit-tab-routers'
1228
1229 fields = ['name', 'owner', 'permittedNetworks', 'networks']
Scott Baker74d8e622013-07-29 16:04:22 -07001230
Scott Baker0165fac2014-01-13 11:49:26 -08001231class RouterInline(PlStackTabularInline):
Scott Baker74d8e622013-07-29 16:04:22 -07001232 model = Router.networks.through
1233 extra = 0
1234 verbose_name_plural = "Routers"
1235 verbose_name = "Router"
Siobhan Tully2d95e482013-09-06 10:56:06 -04001236 suit_classes = 'suit-tab suit-tab-routers'
Scott Baker74d8e622013-07-29 16:04:22 -07001237
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001238class NetworkParameterROInline(ReadOnlyTabularInline):
1239 model = NetworkParameter
1240 extra = 1
1241 verbose_name_plural = "Parameters"
1242 verbose_name = "Parameter"
1243 suit_classes = 'suit-tab suit-tab-netparams'
1244 fields = ['parameter', 'value', 'content_type', 'object_id', 'content_object']
1245
Scott Baker74d8e622013-07-29 16:04:22 -07001246class NetworkParameterInline(generic.GenericTabularInline):
Scott Baker74d8e622013-07-29 16:04:22 -07001247 model = NetworkParameter
1248 extra = 1
1249 verbose_name_plural = "Parameters"
1250 verbose_name = "Parameter"
Siobhan Tully2d95e482013-09-06 10:56:06 -04001251 suit_classes = 'suit-tab suit-tab-netparams'
Scott Baker74d8e622013-07-29 16:04:22 -07001252
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001253class NetworkSliversROInline(ReadOnlyTabularInline):
1254 fields = ['network', 'sliver', 'ip', 'port_id']
1255 model = NetworkSliver
1256 extra = 0
1257 verbose_name_plural = "Slivers"
1258 verbose_name = "Sliver"
1259 suit_classes = 'suit-tab suit-tab-networkslivers'
1260
Scott Baker0165fac2014-01-13 11:49:26 -08001261class NetworkSliversInline(PlStackTabularInline):
Scott Baker74d8e622013-07-29 16:04:22 -07001262 readonly_fields = ("ip", )
1263 model = NetworkSliver
Scott Baker874936e2014-01-13 18:15:34 -08001264 selflink_fieldname = "sliver"
Scott Baker74d8e622013-07-29 16:04:22 -07001265 extra = 0
1266 verbose_name_plural = "Slivers"
1267 verbose_name = "Sliver"
Siobhan Tully2d95e482013-09-06 10:56:06 -04001268 suit_classes = 'suit-tab suit-tab-networkslivers'
Scott Baker74d8e622013-07-29 16:04:22 -07001269
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001270class NetworkSlicesROInline(ReadOnlyTabularInline):
1271 model = NetworkSlice
1272 extra = 0
1273 verbose_name_plural = "Slices"
1274 verbose_name = "Slice"
1275 suit_classes = 'suit-tab suit-tab-networkslices'
1276 fields = ['network','slice']
1277
Scott Baker0165fac2014-01-13 11:49:26 -08001278class NetworkSlicesInline(PlStackTabularInline):
Scott Bakerd7d2a392013-08-06 08:57:30 -07001279 model = NetworkSlice
Scott Baker874936e2014-01-13 18:15:34 -08001280 selflink_fieldname = "slice"
Scott Bakerd7d2a392013-08-06 08:57:30 -07001281 extra = 0
1282 verbose_name_plural = "Slices"
1283 verbose_name = "Slice"
Siobhan Tully2d95e482013-09-06 10:56:06 -04001284 suit_classes = 'suit-tab suit-tab-networkslices'
Scott Bakerd7d2a392013-08-06 08:57:30 -07001285
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001286class NetworkAdmin(PlanetStackBaseAdmin):
Scott Baker74d8e622013-07-29 16:04:22 -07001287 list_display = ("name", "subnet", "ports", "labels")
1288 readonly_fields = ("subnet", )
Siobhan Tully2d95e482013-09-06 10:56:06 -04001289
Scott Bakerd7d2a392013-08-06 08:57:30 -07001290 inlines = [NetworkParameterInline, NetworkSliversInline, NetworkSlicesInline, RouterInline]
Scott Baker74d8e622013-07-29 16:04:22 -07001291
Siobhan Tully2d95e482013-09-06 10:56:06 -04001292 fieldsets = [
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001293 (None, {'fields': ['name','template','ports','labels','owner','guaranteedBandwidth', 'permitAllSlices','permittedSlices','network_id','router_id','subnet_id','subnet'], 'classes':['suit-tab suit-tab-general']}),]
1294
1295 user_readonly_fields = ['name','template','ports','labels','owner','guaranteedBandwidth', 'permitAllSlices','permittedSlices','network_id','router_id','subnet_id','subnet']
1296 user_readonly_inlines = [NetworkParameterROInline, NetworkSliversROInline, NetworkSlicesROInline, RouterROInline]
Siobhan Tully2d95e482013-09-06 10:56:06 -04001297
1298 suit_form_tabs =(
1299 ('general','Network Details'),
1300 ('netparams', 'Parameters'),
1301 ('networkslivers','Slivers'),
1302 ('networkslices','Slices'),
1303 ('routers','Routers'),
1304 )
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001305class NetworkTemplateAdmin(PlanetStackBaseAdmin):
Scott Baker74d8e622013-07-29 16:04:22 -07001306 list_display = ("name", "guaranteedBandwidth", "visibility")
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001307 user_readonly_fields = ["name", "guaranteedBandwidth", "visibility"]
1308 user_readonly_inlines = []
Scott Baker74d8e622013-07-29 16:04:22 -07001309
Tony Mack31c2b8f2013-04-26 20:01:42 -04001310# register a signal that caches the user's credentials when they log in
1311def cache_credentials(sender, user, request, **kwds):
1312 auth = {'username': request.POST['username'],
1313 'password': request.POST['password']}
1314 request.session['auth'] = auth
1315user_logged_in.connect(cache_credentials)
1316
Scott Baker15cddfa2013-12-09 13:45:19 -08001317def dollar_field(fieldName, short_description):
1318 def newFunc(self, obj):
1319 try:
1320 x= "$ %0.2f" % float(getattr(obj, fieldName, 0.0))
1321 except:
1322 x=getattr(obj, fieldName, 0.0)
1323 return x
1324 newFunc.short_description = short_description
1325 return newFunc
1326
1327def right_dollar_field(fieldName, short_description):
1328 def newFunc(self, obj):
1329 try:
1330 #x= '<div align=right style="width:6em">$ %0.2f</div>' % float(getattr(obj, fieldName, 0.0))
1331 x= '<div align=right>$ %0.2f</div>' % float(getattr(obj, fieldName, 0.0))
1332 except:
1333 x=getattr(obj, fieldName, 0.0)
1334 return x
1335 newFunc.short_description = short_description
1336 newFunc.allow_tags = True
1337 return newFunc
Scott Baker43105042013-12-06 23:23:36 -08001338
Scott Baker0165fac2014-01-13 11:49:26 -08001339class InvoiceChargeInline(PlStackTabularInline):
Scott Baker43105042013-12-06 23:23:36 -08001340 model = Charge
Scott Baker15cddfa2013-12-09 13:45:19 -08001341 extra = 0
Scott Baker43105042013-12-06 23:23:36 -08001342 verbose_name_plural = "Charges"
1343 verbose_name = "Charge"
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001344 exclude = ['account']
Scott Baker9cb88a22013-12-09 18:56:00 -08001345 fields = ["date", "kind", "state", "object", "coreHours", "dollar_amount", "slice"]
1346 readonly_fields = ["date", "kind", "state", "object", "coreHours", "dollar_amount", "slice"]
1347 can_delete = False
1348 max_num = 0
1349
1350 dollar_amount = right_dollar_field("amount", "Amount")
Scott Baker43105042013-12-06 23:23:36 -08001351
1352class InvoiceAdmin(admin.ModelAdmin):
1353 list_display = ("date", "account")
1354
1355 inlines = [InvoiceChargeInline]
1356
Scott Baker9cb88a22013-12-09 18:56:00 -08001357 fields = ["date", "account", "dollar_amount"]
1358 readonly_fields = ["date", "account", "dollar_amount"]
1359
1360 dollar_amount = dollar_field("amount", "Amount")
Scott Baker43105042013-12-06 23:23:36 -08001361
Scott Baker0165fac2014-01-13 11:49:26 -08001362class InvoiceInline(PlStackTabularInline):
Scott Baker15cddfa2013-12-09 13:45:19 -08001363 model = Invoice
1364 extra = 0
1365 verbose_name_plural = "Invoices"
1366 verbose_name = "Invoice"
Scott Baker0165fac2014-01-13 11:49:26 -08001367 fields = ["date", "dollar_amount"]
1368 readonly_fields = ["date", "dollar_amount"]
Scott Baker15cddfa2013-12-09 13:45:19 -08001369 suit_classes = 'suit-tab suit-tab-accountinvoice'
1370 can_delete=False
1371 max_num=0
1372
1373 dollar_amount = right_dollar_field("amount", "Amount")
1374
Scott Baker0165fac2014-01-13 11:49:26 -08001375class PendingChargeInline(PlStackTabularInline):
Scott Baker43105042013-12-06 23:23:36 -08001376 model = Charge
Scott Baker15cddfa2013-12-09 13:45:19 -08001377 extra = 0
Scott Baker43105042013-12-06 23:23:36 -08001378 verbose_name_plural = "Charges"
1379 verbose_name = "Charge"
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001380 exclude = ["invoice"]
Scott Baker15cddfa2013-12-09 13:45:19 -08001381 fields = ["date", "kind", "state", "object", "coreHours", "dollar_amount", "slice"]
1382 readonly_fields = ["date", "kind", "state", "object", "coreHours", "dollar_amount", "slice"]
Scott Baker43105042013-12-06 23:23:36 -08001383 suit_classes = 'suit-tab suit-tab-accountpendingcharges'
Scott Baker15cddfa2013-12-09 13:45:19 -08001384 can_delete=False
1385 max_num=0
Scott Baker43105042013-12-06 23:23:36 -08001386
1387 def queryset(self, request):
1388 qs = super(PendingChargeInline, self).queryset(request)
1389 qs = qs.filter(state="pending")
1390 return qs
1391
Scott Baker15cddfa2013-12-09 13:45:19 -08001392 dollar_amount = right_dollar_field("amount", "Amount")
1393
Scott Baker0165fac2014-01-13 11:49:26 -08001394class PaymentInline(PlStackTabularInline):
Scott Baker43105042013-12-06 23:23:36 -08001395 model=Payment
1396 extra = 1
1397 verbose_name_plural = "Payments"
1398 verbose_name = "Payment"
Scott Baker15cddfa2013-12-09 13:45:19 -08001399 fields = ["date", "dollar_amount"]
1400 readonly_fields = ["date", "dollar_amount"]
Scott Baker43105042013-12-06 23:23:36 -08001401 suit_classes = 'suit-tab suit-tab-accountpayments'
Scott Baker15cddfa2013-12-09 13:45:19 -08001402 can_delete=False
1403 max_num=0
1404
1405 dollar_amount = right_dollar_field("amount", "Amount")
1406
Scott Baker43105042013-12-06 23:23:36 -08001407class AccountAdmin(admin.ModelAdmin):
1408 list_display = ("site", "balance_due")
1409
1410 inlines = [InvoiceInline, PaymentInline, PendingChargeInline]
1411
1412 fieldsets = [
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001413 (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 -08001414
Scott Baker15cddfa2013-12-09 13:45:19 -08001415 readonly_fields = ['site', 'dollar_balance_due', 'dollar_total_invoices', 'dollar_total_payments']
Scott Baker43105042013-12-06 23:23:36 -08001416
1417 suit_form_tabs =(
1418 ('general','Account Details'),
1419 ('accountinvoice', 'Invoices'),
1420 ('accountpayments', 'Payments'),
1421 ('accountpendingcharges','Pending Charges'),
1422 )
1423
Scott Baker15cddfa2013-12-09 13:45:19 -08001424 dollar_balance_due = dollar_field("balance_due", "Balance Due")
1425 dollar_total_invoices = dollar_field("total_invoices", "Total Invoices")
1426 dollar_total_payments = dollar_field("total_payments", "Total Payments")
1427
Siobhan Tullyce652d02013-10-08 21:52:35 -04001428
Siobhan Tully53437282013-04-26 19:30:27 -04001429# Now register the new UserAdmin...
Siobhan Tully30fd4292013-05-10 08:59:56 -04001430admin.site.register(User, UserAdmin)
Siobhan Tully53437282013-04-26 19:30:27 -04001431# ... and, since we're not using Django's builtin permissions,
1432# unregister the Group model from admin.
Siobhan Tullyce652d02013-10-08 21:52:35 -04001433#admin.site.unregister(Group)
Siobhan Tully53437282013-04-26 19:30:27 -04001434
Siobhan Tullybf1153a2013-05-27 20:53:48 -04001435#Do not show django evolution in the admin interface
1436from django_evolution.models import Version, Evolution
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001437#admin.site.unregister(Version)
1438#admin.site.unregister(Evolution)
Siobhan Tullybf1153a2013-05-27 20:53:48 -04001439
1440
1441# When debugging it is often easier to see all the classes, but for regular use
1442# only the top-levels should be displayed
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001443showAll = False
Scott Baker43105042013-12-06 23:23:36 -08001444
Siobhan Tullybf1153a2013-05-27 20:53:48 -04001445admin.site.register(Deployment, DeploymentAdmin)
Siobhan Tully4bc09f22013-04-10 21:15:21 -04001446admin.site.register(Site, SiteAdmin)
Siobhan Tully4bc09f22013-04-10 21:15:21 -04001447admin.site.register(Slice, SliceAdmin)
Siobhan Tullyce652d02013-10-08 21:52:35 -04001448admin.site.register(Service, ServiceAdmin)
smbakera3cf70c2013-06-27 02:01:41 -07001449admin.site.register(Reservation, ReservationAdmin)
Scott Baker74d8e622013-07-29 16:04:22 -07001450admin.site.register(Network, NetworkAdmin)
1451admin.site.register(Router, RouterAdmin)
Scott Baker74d8e622013-07-29 16:04:22 -07001452admin.site.register(NetworkTemplate, NetworkTemplateAdmin)
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001453admin.site.register(Account, AccountAdmin)
1454admin.site.register(Invoice, InvoiceAdmin)
Siobhan Tullybf1153a2013-05-27 20:53:48 -04001455
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001456if True:
1457 admin.site.register(NetworkParameterType, NetworkParameterTypeAdmin)
1458 admin.site.register(ServiceClass, ServiceClassAdmin)
Siobhan Tullybfd11dc2013-09-03 12:59:24 -04001459 #admin.site.register(PlanetStack)
Siobhan Tullyd3515752013-06-21 16:34:53 -04001460 admin.site.register(Tag, TagAdmin)
Siobhan Tullyce652d02013-10-08 21:52:35 -04001461 admin.site.register(DeploymentRole)
1462 admin.site.register(SiteRole)
1463 admin.site.register(SliceRole)
1464 admin.site.register(PlanetStackRole)
Siobhan Tullybf1153a2013-05-27 20:53:48 -04001465 admin.site.register(Node, NodeAdmin)
Siobhan Tullybfd11dc2013-09-03 12:59:24 -04001466 #admin.site.register(SlicePrivilege, SlicePrivilegeAdmin)
1467 #admin.site.register(SitePrivilege, SitePrivilegeAdmin)
Siobhan Tullybf1153a2013-05-27 20:53:48 -04001468 admin.site.register(Sliver, SliverAdmin)
Siobhan Tullybf1153a2013-05-27 20:53:48 -04001469 admin.site.register(Image, ImageAdmin)
Scott Baker2c3cb642014-05-19 17:55:56 -07001470 admin.site.register(DashboardView, DashboardViewAdmin)
Tony Mack7130ac32013-03-22 21:58:00 -04001471