blob: 8bf797650cad5a5acec9d790ff1ab5b3c237458d [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,
481 widget=FilteredSelectMultiple(
482 verbose_name=('Sites'), is_stacked=False
483 )
484 )
485 class Meta:
Siobhan Tullybf1153a2013-05-27 20:53:48 -0400486 model = Deployment
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400487
Siobhan Tully320b4622014-01-17 15:11:14 -0500488 def __init__(self, *args, **kwargs):
Scott Baker5380c522014-06-06 14:49:43 -0700489 request = kwargs.pop('request', None)
Siobhan Tully320b4622014-01-17 15:11:14 -0500490 super(DeploymentAdminForm, self).__init__(*args, **kwargs)
491
Scott Baker5380c522014-06-06 14:49:43 -0700492 self.fields['accessControl'].initial = "allow site " + request.user.site.name
493
Siobhan Tully320b4622014-01-17 15:11:14 -0500494 if self.instance and self.instance.pk:
Scott Bakerc9b14f72014-05-22 13:44:20 -0700495 self.fields['sites'].initial = [x.site for x in self.instance.sitedeployments_set.all()]
Siobhan Tully320b4622014-01-17 15:11:14 -0500496
497 def save(self, commit=True):
498 deployment = super(DeploymentAdminForm, self).save(commit=False)
499
500 if commit:
501 deployment.save()
502
503 if deployment.pk:
Scott Bakerc9b14f72014-05-22 13:44:20 -0700504 # save_m2m() doesn't seem to work with 'through' relations. So we
505 # create/destroy the through models ourselves. There has to be
506 # a better way...
507
508 sites = self.cleaned_data['sites']
509
510 existing_sites = []
511 for sdp in list(deployment.sitedeployments_set.all()):
512 if sdp.site not in sites:
513 #print "deleting site", sdp.site
514 sdp.delete()
515 else:
516 existing_sites.append(sdp.site)
517
518 for site in sites:
519 if site not in existing_sites:
520 #print "adding site", site
521 sdp = SiteDeployments(site=site, deployment=deployment)
522 sdp.save()
523
Siobhan Tully320b4622014-01-17 15:11:14 -0500524 self.save_m2m()
525
526 return deployment
527
Scott Bakerff5e0f32014-05-22 14:40:27 -0700528class DeploymentAdminROForm(DeploymentAdminForm):
529 def save(self, commit=True):
530 raise PermissionDenied
531
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500532class SiteAssocInline(PlStackTabularInline):
533 model = Site.deployments.through
534 extra = 0
535 suit_classes = 'suit-tab suit-tab-sites'
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400536
Siobhan Tullybf1153a2013-05-27 20:53:48 -0400537class DeploymentAdmin(PlanetStackBaseAdmin):
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500538 model = Deployment
Scott Baker5380c522014-06-06 14:49:43 -0700539 fieldList = ['name','sites', 'accessControl']
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500540 fieldsets = [(None, {'fields': fieldList, 'classes':['suit-tab suit-tab-sites']})]
Siobhan Tully2d95e482013-09-06 10:56:06 -0400541 inlines = [DeploymentPrivilegeInline,NodeInline,TagInline]
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500542
543 user_readonly_inlines = [DeploymentPrivilegeROInline,NodeROInline,TagROInline]
544 user_readonly_fields = ['name']
545
546 suit_form_tabs =(('sites','Deployment Details'),('nodes','Nodes'),('deploymentprivileges','Privileges'),('tags','Tags'))
547
Scott Bakerff5e0f32014-05-22 14:40:27 -0700548 def get_form(self, request, obj=None, **kwargs):
549 if request.user.isReadOnlyUser():
550 kwargs["form"] = DeploymentAdminROForm
551 else:
552 kwargs["form"] = DeploymentAdminForm
Scott Baker5380c522014-06-06 14:49:43 -0700553 adminForm = super(DeploymentAdmin,self).get_form(request, obj, **kwargs)
554
555 # from stackexchange: pass the request object into the form
556
557 class AdminFormMetaClass(adminForm):
558 def __new__(cls, *args, **kwargs):
559 kwargs['request'] = request
560 return adminForm(*args, **kwargs)
561
562 return AdminFormMetaClass
563
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500564class ServiceAttrAsTabROInline(ReadOnlyTabularInline):
565 model = ServiceAttribute
566 fields = ['name','value']
567 extra = 0
568 suit_classes = 'suit-tab suit-tab-serviceattrs'
Tony Mack5cd13202013-05-01 21:48:38 -0400569
Siobhan Tullyce652d02013-10-08 21:52:35 -0400570class ServiceAttrAsTabInline(PlStackTabularInline):
571 model = ServiceAttribute
572 fields = ['name','value']
573 extra = 0
574 suit_classes = 'suit-tab suit-tab-serviceattrs'
575
Siobhan Tullyce652d02013-10-08 21:52:35 -0400576class ServiceAdmin(PlanetStackBaseAdmin):
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500577 list_display = ("name","description","versionNumber","enabled","published")
578 fieldList = ["name","description","versionNumber","enabled","published"]
579 fieldsets = [(None, {'fields': fieldList, 'classes':['suit-tab suit-tab-general']})]
580 inlines = [ServiceAttrAsTabInline,SliceInline]
581
582 user_readonly_fields = fieldList
583 user_readonly_inlines = [ServiceAttrAsTabROInline,SliceROInline]
584
585 suit_form_tabs =(('general', 'Service Details'),
586 ('slices','Slices'),
587 ('serviceattrs','Additional Attributes'),
588 )
Siobhan Tullyce652d02013-10-08 21:52:35 -0400589
Tony Mack0553f282013-06-10 22:54:50 -0400590class SiteAdmin(PlanetStackBaseAdmin):
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500591 fieldList = ['name', 'site_url', 'enabled', 'is_public', 'login_base', 'accountLink','location']
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400592 fieldsets = [
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500593 (None, {'fields': fieldList, 'classes':['suit-tab suit-tab-general']}),
Tony Macke4be32f2014-03-11 20:45:25 -0400594 #('Deployment Networks', {'fields': ['deployments'], 'classes':['suit-tab suit-tab-deployments']}),
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400595 ]
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400596 suit_form_tabs =(('general', 'Site Details'),
597 ('users','Users'),
Siobhan Tully2d95e482013-09-06 10:56:06 -0400598 ('siteprivileges','Privileges'),
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400599 ('deployments','Deployments'),
600 ('slices','Slices'),
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500601 ('nodes','Nodes'),
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400602 ('tags','Tags'),
603 )
Scott Baker545db2a2013-12-09 18:44:43 -0800604 readonly_fields = ['accountLink']
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500605
606 user_readonly_fields = ['name', 'deployments','site_url', 'enabled', 'is_public', 'login_base', 'accountLink']
Tony Macke4be32f2014-03-11 20:45:25 -0400607 user_readonly_inlines = [SliceROInline,UserROInline,TagROInline, NodeROInline, SitePrivilegeROInline,SiteDeploymentROInline]
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500608
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400609 list_display = ('name', 'login_base','site_url', 'enabled')
610 filter_horizontal = ('deployments',)
Tony Macke4be32f2014-03-11 20:45:25 -0400611 inlines = [SliceInline,UserInline,TagInline, NodeInline, SitePrivilegeInline, SiteDeploymentInline]
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400612 search_fields = ['name']
613
Tony Mack04062832013-05-10 08:22:44 -0400614 def queryset(self, request):
Tony Mack5b061472014-02-04 07:57:10 -0500615 return Site.select_by_user(request.user)
Tony Mack04062832013-05-10 08:22:44 -0400616
Tony Mack5cd13202013-05-01 21:48:38 -0400617 def get_formsets(self, request, obj=None):
618 for inline in self.get_inline_instances(request, obj):
619 # hide MyInline in the add view
620 if obj is None:
621 continue
Tony Mack2bd5b412013-06-11 21:05:06 -0400622 if isinstance(inline, SliceInline):
623 inline.model.caller = request.user
624 yield inline.get_formset(request, obj)
625
626 def get_formsets(self, request, obj=None):
627 for inline in self.get_inline_instances(request, obj):
628 # hide MyInline in the add view
629 if obj is None:
630 continue
631 if isinstance(inline, SliverInline):
632 inline.model.caller = request.user
Tony Mack5cd13202013-05-01 21:48:38 -0400633 yield inline.get_formset(request, obj)
634
Scott Baker545db2a2013-12-09 18:44:43 -0800635 def accountLink(self, obj):
636 link_obj = obj.accounts.all()
637 if link_obj:
638 reverse_path = "admin:core_account_change"
639 url = reverse(reverse_path, args =(link_obj[0].id,))
640 return "<a href='%s'>%s</a>" % (url, "view billing details")
641 else:
642 return "no billing data for this site"
643 accountLink.allow_tags = True
644 accountLink.short_description = "Billing"
645
Tony Mack332ee1d2014-02-04 15:33:45 -0500646 def save_model(self, request, obj, form, change):
647 # update openstack connection to use this site/tenant
648 obj.save_by_user(request.user)
649
650 def delete_model(self, request, obj):
651 obj.delete_by_user(request.user)
652
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500653
Tony Mack9bcbe4f2013-04-29 08:13:27 -0400654class SitePrivilegeAdmin(PlanetStackBaseAdmin):
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500655 fieldList = ['user', 'site', 'role']
Tony Mack00d361f2013-04-28 10:28:42 -0400656 fieldsets = [
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500657 (None, {'fields': fieldList, 'classes':['collapse']})
Tony Mack00d361f2013-04-28 10:28:42 -0400658 ]
659 list_display = ('user', 'site', 'role')
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500660 user_readonly_fields = fieldList
661 user_readonly_inlines = []
Tony Mack00d361f2013-04-28 10:28:42 -0400662
Tony Mackc2835a92013-05-28 09:18:49 -0400663 def formfield_for_foreignkey(self, db_field, request, **kwargs):
664 if db_field.name == 'site':
665 if not request.user.is_admin:
666 # only show sites where user is an admin or pi
667 sites = set()
668 for site_privilege in SitePrivilege.objects.filer(user=request.user):
669 if site_privilege.role.role_type in ['admin', 'pi']:
670 sites.add(site_privilege.site)
671 kwargs['queryset'] = Site.objects.filter(site__in=list(sites))
672
673 if db_field.name == 'user':
674 if not request.user.is_admin:
675 # only show users from sites where caller has admin or pi role
676 roles = Role.objects.filter(role_type__in=['admin', 'pi'])
677 site_privileges = SitePrivilege.objects.filter(user=request.user).filter(role__in=roles)
678 sites = [site_privilege.site for site_privilege in site_privileges]
679 site_privileges = SitePrivilege.objects.filter(site__in=sites)
680 emails = [site_privilege.user.email for site_privilege in site_privileges]
681 users = User.objects.filter(email__in=emails)
682 kwargs['queryset'] = users
683
684 return super(SitePrivilegeAdmin, self).formfield_for_foreignkey(db_field, request, **kwargs)
685
Tony Mack04062832013-05-10 08:22:44 -0400686 def queryset(self, request):
687 # admins can see all privileges. Users can only see privileges at sites
Tony Mackc2835a92013-05-28 09:18:49 -0400688 # where they have the admin role or pi role.
Tony Mack04062832013-05-10 08:22:44 -0400689 qs = super(SitePrivilegeAdmin, self).queryset(request)
Tony Mack5b061472014-02-04 07:57:10 -0500690 #if not request.user.is_admin:
691 # roles = Role.objects.filter(role_type__in=['admin', 'pi'])
692 # site_privileges = SitePrivilege.objects.filter(user=request.user).filter(role__in=roles)
693 # login_bases = [site_privilege.site.login_base for site_privilege in site_privileges]
694 # sites = Site.objects.filter(login_base__in=login_bases)
695 # qs = qs.filter(site__in=sites)
Tony Mack04062832013-05-10 08:22:44 -0400696 return qs
697
Siobhan Tullyce652d02013-10-08 21:52:35 -0400698class SliceForm(forms.ModelForm):
699 class Meta:
700 model = Slice
701 widgets = {
702 'service': LinkedSelect
703 }
704
Tony Mack2bd5b412013-06-11 21:05:06 -0400705class SliceAdmin(PlanetStackBaseAdmin):
Siobhan Tullyce652d02013-10-08 21:52:35 -0400706 form = SliceForm
Tony Mack29bf5e82014-04-29 21:40:24 -0400707 fieldList = ['name', 'site', 'serviceClass', 'enabled','description', 'service', 'slice_url', 'max_slivers']
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500708 fieldsets = [('Slice Details', {'fields': fieldList, 'classes':['suit-tab suit-tab-general']}),]
Tony Mack29bf5e82014-04-29 21:40:24 -0400709 list_display = ('name', 'site','serviceClass', 'slice_url', 'max_slivers')
Siobhan Tully2d95e482013-09-06 10:56:06 -0400710 inlines = [SlicePrivilegeInline,SliverInline, TagInline, ReservationInline,SliceNetworkInline]
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400711
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500712 user_readonly_fields = fieldList
713 user_readonly_inlines = [SlicePrivilegeROInline,SliverROInline,TagROInline, ReservationROInline, SliceNetworkROInline]
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400714
715 suit_form_tabs =(('general', 'Slice Details'),
Siobhan Tully2d95e482013-09-06 10:56:06 -0400716 ('slicenetworks','Networks'),
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400717 ('sliceprivileges','Privileges'),
718 ('slivers','Slivers'),
719 ('tags','Tags'),
720 ('reservations','Reservations'),
721 )
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400722
Tony Mackc2835a92013-05-28 09:18:49 -0400723 def formfield_for_foreignkey(self, db_field, request, **kwargs):
724 if db_field.name == 'site':
Tony Mack5b061472014-02-04 07:57:10 -0500725 kwargs['queryset'] = Site.select_by_user(request.user)
726
Tony Mackc2835a92013-05-28 09:18:49 -0400727 return super(SliceAdmin, self).formfield_for_foreignkey(db_field, request, **kwargs)
728
Tony Mack04062832013-05-10 08:22:44 -0400729 def queryset(self, request):
730 # admins can see all keys. Users can only see slices they belong to.
Tony Mack5b061472014-02-04 07:57:10 -0500731 return Slice.select_by_user(request.user)
Tony Mack04062832013-05-10 08:22:44 -0400732
Tony Mack79748612013-05-01 14:52:03 -0400733 def get_formsets(self, request, obj=None):
734 for inline in self.get_inline_instances(request, obj):
735 # hide MyInline in the add view
736 if obj is None:
737 continue
Tony Mack2bd5b412013-06-11 21:05:06 -0400738 if isinstance(inline, SliverInline):
739 inline.model.caller = request.user
Tony Mack79748612013-05-01 14:52:03 -0400740 yield inline.get_formset(request, obj)
741
Tony Mack2bd5b412013-06-11 21:05:06 -0400742
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400743class SlicePrivilegeAdmin(PlanetStackBaseAdmin):
Tony Mack00d361f2013-04-28 10:28:42 -0400744 fieldsets = [
745 (None, {'fields': ['user', 'slice', 'role']})
746 ]
747 list_display = ('user', 'slice', 'role')
Tony Mack00d361f2013-04-28 10:28:42 -0400748
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500749 user_readonly_fields = ['user', 'slice', 'role']
750 user_readonly_inlines = []
751
Tony Mackc2835a92013-05-28 09:18:49 -0400752 def formfield_for_foreignkey(self, db_field, request, **kwargs):
753 if db_field.name == 'slice':
Tony Mack5b061472014-02-04 07:57:10 -0500754 kwargs['queryset'] = Slice.select_by_user(request.user)
Tony Mackc2835a92013-05-28 09:18:49 -0400755
756 if db_field.name == 'user':
Tony Mack5b061472014-02-04 07:57:10 -0500757 kwargs['queryset'] = User.select_by_user(request.user)
Tony Mackc2835a92013-05-28 09:18:49 -0400758
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400759 return super(SlicePrivilegeAdmin, self).formfield_for_foreignkey(db_field, request, **kwargs)
Tony Mackc2835a92013-05-28 09:18:49 -0400760
Tony Mack04062832013-05-10 08:22:44 -0400761 def queryset(self, request):
762 # admins can see all memberships. Users can only see memberships of
763 # slices where they have the admin role.
Tony Mack5b061472014-02-04 07:57:10 -0500764 return SlicePrivilege.select_by_user(request.user)
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400765
Tony Mack9bcbe4f2013-04-29 08:13:27 -0400766 def save_model(self, request, obj, form, change):
Tony Mack951dab42013-05-02 19:51:45 -0400767 # update openstack connection to use this site/tenant
768 auth = request.session.get('auth', {})
769 auth['tenant'] = obj.slice.name
770 obj.os_manager = OpenStackManager(auth=auth, caller=request.user)
Tony Mack9bcbe4f2013-04-29 08:13:27 -0400771 obj.save()
772
773 def delete_model(self, request, obj):
Tony Mack951dab42013-05-02 19:51:45 -0400774 # update openstack connection to use this site/tenant
775 auth = request.session.get('auth', {})
776 auth['tenant'] = obj.slice.name
777 obj.os_manager = OpenStackManager(auth=auth, caller=request.user)
Tony Mack9bcbe4f2013-04-29 08:13:27 -0400778 obj.delete()
779
Siobhan Tully567e3e62013-06-21 18:03:16 -0400780
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400781class ImageAdmin(PlanetStackBaseAdmin):
782
783 fieldsets = [('Image Details',
Scott Baker00b00b32014-05-07 08:47:54 -0700784 {'fields': ['name', 'disk_format', 'container_format'],
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400785 'classes': ['suit-tab suit-tab-general']})
786 ]
787
Scott Baker2170b972014-06-03 12:14:07 -0700788 suit_form_tabs =(('general','Image Details'),('slivers','Slivers'),('imagedeployments','Deployments'))
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400789
Scott Baker2170b972014-06-03 12:14:07 -0700790 inlines = [SliverInline, ImageDeploymentsInline]
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500791
Tony Mack32e1ce32014-05-07 13:29:41 -0400792 user_readonly_fields = ['name', 'disk_format', 'container_format']
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500793 user_readonly_inlines = [SliverROInline]
794
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400795class NodeForm(forms.ModelForm):
796 class Meta:
797 widgets = {
798 'site': LinkedSelect,
799 'deployment': LinkedSelect
800 }
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400801
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500802class NodeAdmin(PlanetStackBaseAdmin):
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400803 form = NodeForm
Siobhan Tullybf1153a2013-05-27 20:53:48 -0400804 list_display = ('name', 'site', 'deployment')
805 list_filter = ('deployment',)
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500806
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400807 inlines = [TagInline,SliverInline]
808 fieldsets = [('Node Details', {'fields': ['name','site','deployment'], 'classes':['suit-tab suit-tab-details']})]
809
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500810 user_readonly_fields = ['name','site','deployment']
811 user_readonly_inlines = [TagInline,SliverInline]
812
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400813 suit_form_tabs =(('details','Node Details'),('slivers','Slivers'),('tags','Tags'))
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400814
Siobhan Tully567e3e62013-06-21 18:03:16 -0400815
Tony Mackd90cdbf2013-04-16 22:48:40 -0400816class SliverForm(forms.ModelForm):
817 class Meta:
Tony Mack1d6b85f2013-05-07 18:49:14 -0400818 model = Sliver
Tony Mackd90cdbf2013-04-16 22:48:40 -0400819 ip = forms.CharField(widget=PlainTextWidget)
Tony Mack18261812013-05-02 16:39:20 -0400820 instance_name = forms.CharField(widget=PlainTextWidget)
Tony Mackd90cdbf2013-04-16 22:48:40 -0400821 widgets = {
822 'ip': PlainTextWidget(),
Tony Mack18261812013-05-02 16:39:20 -0400823 'instance_name': PlainTextWidget(),
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400824 'slice': LinkedSelect,
825 'deploymentNetwork': LinkedSelect,
826 'node': LinkedSelect,
827 'image': LinkedSelect
Siobhan Tully53437282013-04-26 19:30:27 -0400828 }
Tony Mackd90cdbf2013-04-16 22:48:40 -0400829
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500830class TagAdmin(PlanetStackBaseAdmin):
Siobhan Tullyce652d02013-10-08 21:52:35 -0400831 list_display = ['service', 'name', 'value', 'content_type', 'content_object',]
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500832 user_readonly_fields = ['service', 'name', 'value', 'content_type', 'content_object',]
833 user_readonly_inlines = []
Siobhan Tullyd3515752013-06-21 16:34:53 -0400834
Tony Mack9bcbe4f2013-04-29 08:13:27 -0400835class SliverAdmin(PlanetStackBaseAdmin):
Tony Mackd90cdbf2013-04-16 22:48:40 -0400836 form = SliverForm
Tony Mackcdec0902013-04-15 00:38:49 -0400837 fieldsets = [
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400838 ('Sliver Details', {'fields': ['slice', 'deploymentNetwork', 'node', 'ip', 'instance_name', 'numberCores', 'image', ], 'classes': ['suit-tab suit-tab-general'], })
Tony Mackcdec0902013-04-15 00:38:49 -0400839 ]
Siobhan Tully5d7dc8d2013-07-02 13:17:33 -0400840 list_display = ['ip', 'instance_name', 'slice', 'numberCores', 'image', 'node', 'deploymentNetwork']
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400841
842 suit_form_tabs =(('general', 'Sliver Details'),
843 ('tags','Tags'),
844 )
845
Siobhan Tullyde5450d2013-06-21 11:35:33 -0400846 inlines = [TagInline]
Tony Mack53106f32013-04-27 16:43:01 -0400847
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500848 user_readonly_fields = ['slice', 'deploymentNetwork', 'node', 'ip', 'instance_name', 'numberCores', 'image']
849 user_readonly_inlines = [TagROInline]
850
Tony Mackc2835a92013-05-28 09:18:49 -0400851 def formfield_for_foreignkey(self, db_field, request, **kwargs):
852 if db_field.name == 'slice':
Tony Mack5b061472014-02-04 07:57:10 -0500853 kwargs['queryset'] = Slice.select_by_user(request.user)
Tony Mackc2835a92013-05-28 09:18:49 -0400854
855 return super(SliverAdmin, self).formfield_for_foreignkey(db_field, request, **kwargs)
856
Tony Mack04062832013-05-10 08:22:44 -0400857 def queryset(self, request):
858 # admins can see all slivers. Users can only see slivers of
859 # the slices they belong to.
Tony Mack5b061472014-02-04 07:57:10 -0500860 return Sliver.select_by_user(request.user)
861
Tony Mack04062832013-05-10 08:22:44 -0400862
Tony Mack1d6b85f2013-05-07 18:49:14 -0400863 def get_formsets(self, request, obj=None):
864 # make some fields read only if we are updating an existing record
865 if obj == None:
866 #self.readonly_fields = ('ip', 'instance_name')
867 self.readonly_fields = ()
868 else:
Tony Mack1e889462013-05-10 21:34:54 -0400869 self.readonly_fields = ()
870 #self.readonly_fields = ('ip', 'instance_name', 'slice', 'image', 'key')
Tony Mack1d6b85f2013-05-07 18:49:14 -0400871
872 for inline in self.get_inline_instances(request, obj):
873 # hide MyInline in the add view
874 if obj is None:
875 continue
Scott Baker526b71e2014-05-13 13:18:01 -0700876 if isinstance(inline, SliverInline):
877 inline.model.caller = request.user
878 yield inline.get_formset(request, obj)
Tony Mack53106f32013-04-27 16:43:01 -0400879
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500880 #def save_model(self, request, obj, form, change):
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.creator = request.user
886 # obj.save()
Tony Mack53106f32013-04-27 16:43:01 -0400887
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500888 #def delete_model(self, request, obj):
889 # # update openstack connection to use this site/tenant
890 # auth = request.session.get('auth', {})
891 # auth['tenant'] = obj.slice.name
892 # obj.os_manager = OpenStackManager(auth=auth, caller=request.user)
893 # obj.delete()
Tony Mackcdec0902013-04-15 00:38:49 -0400894
Siobhan Tully53437282013-04-26 19:30:27 -0400895class UserCreationForm(forms.ModelForm):
896 """A form for creating new users. Includes all the required
897 fields, plus a repeated password."""
898 password1 = forms.CharField(label='Password', widget=forms.PasswordInput)
899 password2 = forms.CharField(label='Password confirmation', widget=forms.PasswordInput)
900
901 class Meta:
Siobhan Tully30fd4292013-05-10 08:59:56 -0400902 model = User
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400903 fields = ('email', 'firstname', 'lastname', 'phone', 'public_key')
Siobhan Tully53437282013-04-26 19:30:27 -0400904
905 def clean_password2(self):
906 # Check that the two password entries match
907 password1 = self.cleaned_data.get("password1")
908 password2 = self.cleaned_data.get("password2")
909 if password1 and password2 and password1 != password2:
910 raise forms.ValidationError("Passwords don't match")
911 return password2
912
913 def save(self, commit=True):
914 # Save the provided password in hashed format
915 user = super(UserCreationForm, self).save(commit=False)
Tony Mackf9f4afb2013-05-01 21:02:12 -0400916 user.password = self.cleaned_data["password1"]
917 #user.set_password(self.cleaned_data["password1"])
Siobhan Tully53437282013-04-26 19:30:27 -0400918 if commit:
919 user.save()
920 return user
921
Siobhan Tully567e3e62013-06-21 18:03:16 -0400922
Siobhan Tully53437282013-04-26 19:30:27 -0400923class UserChangeForm(forms.ModelForm):
924 """A form for updating users. Includes all the fields on
925 the user, but replaces the password field with admin's
926 password hash display field.
927 """
Siobhan Tully63b7ba42014-01-12 10:35:11 -0500928 password = ReadOnlyPasswordHashField(label='Password',
929 help_text= '<a href=\"password/\">Change Password</a>.')
Siobhan Tully53437282013-04-26 19:30:27 -0400930
931 class Meta:
Siobhan Tully30fd4292013-05-10 08:59:56 -0400932 model = User
Siobhan Tully53437282013-04-26 19:30:27 -0400933
934 def clean_password(self):
935 # Regardless of what the user provides, return the initial value.
936 # This is done here, rather than on the field, because the
937 # field does not have access to the initial value
938 return self.initial["password"]
939
Scott Baker2c3cb642014-05-19 17:55:56 -0700940class UserDashboardViewInline(PlStackTabularInline):
941 model = UserDashboardView
942 extra = 0
943 suit_classes = 'suit-tab suit-tab-dashboards'
944 fields = ['user', 'dashboardView', 'order']
945
Scott Bakered31f672014-05-21 18:14:03 -0700946class UserDashboardViewROInline(ReadOnlyTabularInline):
947 model = UserDashboardView
948 extra = 0
949 suit_classes = 'suit-tab suit-tab-dashboards'
950 fields = ['user', 'dashboardView', 'order']
951
Tony Mack2bd5b412013-06-11 21:05:06 -0400952class UserAdmin(UserAdmin):
Siobhan Tully53437282013-04-26 19:30:27 -0400953 class Meta:
954 app_label = "core"
955
956 # The forms to add and change user instances
957 form = UserChangeForm
958 add_form = UserCreationForm
959
960 # The fields to be used in displaying the User model.
961 # These override the definitions on the base UserAdmin
962 # that reference specific fields on auth.User.
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500963 list_display = ('email', 'firstname', 'lastname', 'site', 'last_login')
Siobhan Tullyce652d02013-10-08 21:52:35 -0400964 #list_display = ('email', 'username','firstname', 'lastname', 'is_admin', 'last_login')
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500965 list_filter = ('site',)
Scott Baker2c3cb642014-05-19 17:55:56 -0700966 inlines = [SlicePrivilegeInline,SitePrivilegeInline,DeploymentPrivilegeInline,UserDashboardViewInline]
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500967
968 fieldListLoginDetails = ['email','site','password','is_readonly','is_amin','public_key']
969 fieldListContactInfo = ['firstname','lastname','phone','timezone']
970
Siobhan Tully53437282013-04-26 19:30:27 -0400971 fieldsets = (
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500972 ('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 -0400973 ('Contact Information', {'fields': ('firstname','lastname','phone', 'timezone'), 'classes':['suit-tab suit-tab-contact']}),
Scott Baker2c3cb642014-05-19 17:55:56 -0700974 #('Dashboard Views', {'fields': ('dashboards',), 'classes':['suit-tab suit-tab-dashboards']}),
Siobhan Tully53437282013-04-26 19:30:27 -0400975 #('Important dates', {'fields': ('last_login',)}),
976 )
977 add_fieldsets = (
978 (None, {
979 'classes': ('wide',),
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500980 'fields': ('email', 'firstname', 'lastname', 'is_readonly', 'phone', 'public_key','password1', 'password2')}
Siobhan Tully53437282013-04-26 19:30:27 -0400981 ),
982 )
983 search_fields = ('email',)
984 ordering = ('email',)
985 filter_horizontal = ()
986
Scott Baker3ca51f62014-05-23 12:05:11 -0700987 user_readonly_fields = fieldListLoginDetails + fieldListContactInfo
Scott Bakered31f672014-05-21 18:14:03 -0700988 user_readonly_inlines = [SlicePrivilegeROInline,SitePrivilegeROInline,DeploymentPrivilegeROInline,UserDashboardViewROInline]
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500989
Scott Baker2c3cb642014-05-19 17:55:56 -0700990 suit_form_tabs =(('general','Login Details'),
991 ('contact','Contact Information'),
992 ('sliceprivileges','Slice Privileges'),
993 ('siteprivileges','Site Privileges'),
994 ('deploymentprivileges','Deployment Privileges'),
995 ('dashboards','Dashboard Views'))
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400996
Tony Mackc2835a92013-05-28 09:18:49 -0400997 def formfield_for_foreignkey(self, db_field, request, **kwargs):
998 if db_field.name == 'site':
Tony Mack5b061472014-02-04 07:57:10 -0500999 kwargs['queryset'] = Site.select_by_user(request.user)
Tony Mackc2835a92013-05-28 09:18:49 -04001000
1001 return super(UserAdmin, self).formfield_for_foreignkey(db_field, request, **kwargs)
1002
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001003 def has_add_permission(self, request, obj=None):
1004 return (not self.__user_is_readonly(request))
1005
1006 def has_delete_permission(self, request, obj=None):
1007 return (not self.__user_is_readonly(request))
1008
1009 def get_actions(self,request):
1010 actions = super(UserAdmin,self).get_actions(request)
1011
1012 if self.__user_is_readonly(request):
1013 if 'delete_selected' in actions:
1014 del actions['delete_selected']
1015
1016 return actions
1017
1018 def change_view(self,request,object_id, extra_context=None):
1019
1020 if self.__user_is_readonly(request):
Scott Bakerf875eba2014-05-23 12:09:15 -07001021 if not hasattr(self, "readonly_save"):
1022 # save the original readonly fields
1023 self.readonly_save = self.readonly_fields
1024 self.inlines_save = self.inlines
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001025 self.readonly_fields=self.user_readonly_fields
1026 self.inlines = self.user_readonly_inlines
Scott Bakerf875eba2014-05-23 12:09:15 -07001027 else:
1028 if hasattr(self, "readonly_save"):
1029 # restore the original readonly fields
1030 self.readonly_fields = self.readonly_save
1031 self.inlines = self.inlines_save
1032
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001033 try:
1034 return super(UserAdmin, self).change_view(request, object_id, extra_context=extra_context)
1035 except PermissionDenied:
1036 pass
1037 if request.method == 'POST':
1038 raise PermissionDenied
1039 request.readonly = True
1040 return super(UserAdmin, self).change_view(request, object_id, extra_context=extra_context)
1041
1042 def __user_is_readonly(self, request):
1043 #groups = [x.name for x in request.user.groups.all() ]
1044 #return "readonly" in groups
1045 return request.user.isReadOnlyUser()
1046
Tony Mack5b061472014-02-04 07:57:10 -05001047 def queryset(self, request):
1048 return User.select_by_user(request.user)
1049
Scott Baker2c3cb642014-05-19 17:55:56 -07001050class DashboardViewAdmin(PlanetStackBaseAdmin):
1051 fieldsets = [('Dashboard View Details',
1052 {'fields': ['name', 'url'],
1053 'classes': ['suit-tab suit-tab-general']})
1054 ]
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001055
Scott Baker2c3cb642014-05-19 17:55:56 -07001056 suit_form_tabs =(('general','Dashboard View Details'),)
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001057
1058class ServiceResourceROInline(ReadOnlyTabularInline):
1059 model = ServiceResource
1060 extra = 0
1061 fields = ['serviceClass', 'name', 'maxUnitsDeployment', 'maxUnitsNode', 'maxDuration', 'bucketInRate', 'bucketMaxSize', 'cost', 'calendarReservable']
1062
Scott Baker0165fac2014-01-13 11:49:26 -08001063class ServiceResourceInline(PlStackTabularInline):
Scott Baker3de3e372013-05-10 16:50:44 -07001064 model = ServiceResource
1065 extra = 0
1066
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001067class ServiceClassAdmin(PlanetStackBaseAdmin):
Scott Baker3de3e372013-05-10 16:50:44 -07001068 list_display = ('name', 'commitment', 'membershipFee')
1069 inlines = [ServiceResourceInline]
1070
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001071 user_readonly_fields = ['name', 'commitment', 'membershipFee']
1072 user_readonly_inlines = []
1073
1074class ReservedResourceROInline(ReadOnlyTabularInline):
1075 model = ReservedResource
1076 extra = 0
1077 fields = ['sliver', 'resource','quantity','reservationSet']
1078 suit_classes = 'suit-tab suit-tab-reservedresources'
1079
Scott Baker0165fac2014-01-13 11:49:26 -08001080class ReservedResourceInline(PlStackTabularInline):
Scott Baker133c9212013-05-17 09:09:11 -07001081 model = ReservedResource
1082 extra = 0
Siobhan Tullybfd11dc2013-09-03 12:59:24 -04001083 suit_classes = 'suit-tab suit-tab-reservedresources'
Scott Baker133c9212013-05-17 09:09:11 -07001084
1085 def formfield_for_foreignkey(self, db_field, request=None, **kwargs):
1086 field = super(ReservedResourceInline, self).formfield_for_foreignkey(db_field, request, **kwargs)
1087
1088 if db_field.name == 'resource':
1089 # restrict resources to those that the slice's service class allows
1090 if request._slice is not None:
1091 field.queryset = field.queryset.filter(serviceClass = request._slice.serviceClass, calendarReservable=True)
1092 if len(field.queryset) > 0:
1093 field.initial = field.queryset.all()[0]
1094 else:
1095 field.queryset = field.queryset.none()
1096 elif db_field.name == 'sliver':
1097 # restrict slivers to those that belong to the slice
1098 if request._slice is not None:
1099 field.queryset = field.queryset.filter(slice = request._slice)
1100 else:
1101 field.queryset = field.queryset.none()
1102
1103 return field
1104
Tony Mack5b061472014-02-04 07:57:10 -05001105 def queryset(self, request):
1106 return ReservedResource.select_by_user(request.user)
1107
Scott Baker133c9212013-05-17 09:09:11 -07001108class ReservationChangeForm(forms.ModelForm):
1109 class Meta:
1110 model = Reservation
Siobhan Tullybfd11dc2013-09-03 12:59:24 -04001111 widgets = {
1112 'slice' : LinkedSelect
1113 }
Scott Baker133c9212013-05-17 09:09:11 -07001114
1115class ReservationAddForm(forms.ModelForm):
1116 slice = forms.ModelChoiceField(queryset=Slice.objects.all(), widget=forms.Select(attrs={"onChange":"document.getElementById('id_refresh').value=1; submit()"}))
1117 refresh = forms.CharField(widget=forms.HiddenInput())
1118
1119 class Media:
1120 css = {'all': ('planetstack.css',)} # .field-refresh { display: none; }
1121
1122 def clean_slice(self):
1123 slice = self.cleaned_data.get("slice")
1124 x = ServiceResource.objects.filter(serviceClass = slice.serviceClass, calendarReservable=True)
1125 if len(x) == 0:
1126 raise forms.ValidationError("The slice you selected does not have a service class that allows reservations")
1127 return slice
1128
1129 class Meta:
1130 model = Reservation
Siobhan Tullybfd11dc2013-09-03 12:59:24 -04001131 widgets = {
1132 'slice' : LinkedSelect
1133 }
1134
Scott Baker133c9212013-05-17 09:09:11 -07001135
1136class ReservationAddRefreshForm(ReservationAddForm):
1137 """ This form is displayed when the Reservation Form receives an update
1138 from the Slice dropdown onChange handler. It doesn't validate the
1139 data and doesn't save the data. This will cause the form to be
1140 redrawn.
1141 """
1142
Scott Baker8737e5f2013-05-17 09:35:32 -07001143 """ don't validate anything other than slice """
1144 dont_validate_fields = ("startTime", "duration")
1145
Scott Baker133c9212013-05-17 09:09:11 -07001146 def full_clean(self):
1147 result = super(ReservationAddForm, self).full_clean()
Scott Baker8737e5f2013-05-17 09:35:32 -07001148
1149 for fieldname in self.dont_validate_fields:
1150 if fieldname in self._errors:
1151 del self._errors[fieldname]
1152
Scott Baker133c9212013-05-17 09:09:11 -07001153 return result
1154
1155 """ don't save anything """
1156 def is_valid(self):
1157 return False
1158
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001159class ReservationAdmin(PlanetStackBaseAdmin):
1160 fieldList = ['slice', 'startTime', 'duration']
1161 fieldsets = [('Reservation Details', {'fields': fieldList, 'classes': ['suit-tab suit-tab-general']})]
Scott Baker133c9212013-05-17 09:09:11 -07001162 list_display = ('startTime', 'duration')
Scott Baker133c9212013-05-17 09:09:11 -07001163 form = ReservationAddForm
1164
Siobhan Tullybfd11dc2013-09-03 12:59:24 -04001165 suit_form_tabs = (('general','Reservation Details'), ('reservedresources','Reserved Resources'))
1166
1167 inlines = [ReservedResourceInline]
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001168 user_readonly_inlines = [ReservedResourceROInline]
1169 user_readonly_fields = fieldList
Siobhan Tullybfd11dc2013-09-03 12:59:24 -04001170
Scott Baker133c9212013-05-17 09:09:11 -07001171 def add_view(self, request, form_url='', extra_context=None):
Scott Bakeracd45142013-05-19 16:19:16 -07001172 timezone.activate(request.user.timezone)
Scott Baker133c9212013-05-17 09:09:11 -07001173 request._refresh = False
1174 request._slice = None
1175 if request.method == 'POST':
Scott Baker8737e5f2013-05-17 09:35:32 -07001176 # "refresh" will be set to "1" if the form was submitted due to
1177 # a change in the Slice dropdown.
Scott Baker133c9212013-05-17 09:09:11 -07001178 if request.POST.get("refresh","1") == "1":
1179 request._refresh = True
1180 request.POST["refresh"] = "0"
Scott Baker8737e5f2013-05-17 09:35:32 -07001181
1182 # Keep track of the slice that was selected, so the
1183 # reservedResource inline can filter items for the slice.
Scott Baker133c9212013-05-17 09:09:11 -07001184 request._slice = request.POST.get("slice",None)
1185 if (request._slice is not None):
1186 request._slice = Slice.objects.get(id=request._slice)
1187
1188 result = super(ReservationAdmin, self).add_view(request, form_url, extra_context)
1189 return result
1190
Scott Bakeracd45142013-05-19 16:19:16 -07001191 def changelist_view(self, request, extra_context = None):
1192 timezone.activate(request.user.timezone)
1193 return super(ReservationAdmin, self).changelist_view(request, extra_context)
1194
Scott Baker133c9212013-05-17 09:09:11 -07001195 def get_form(self, request, obj=None, **kwargs):
Siobhan Tullyd3515752013-06-21 16:34:53 -04001196 request._obj_ = obj
1197 if obj is not None:
1198 # For changes, set request._slice to the slice already set in the
1199 # object.
1200 request._slice = obj.slice
1201 self.form = ReservationChangeForm
1202 else:
1203 if getattr(request, "_refresh", False):
1204 self.form = ReservationAddRefreshForm
1205 else:
1206 self.form = ReservationAddForm
1207 return super(ReservationAdmin, self).get_form(request, obj, **kwargs)
1208
Scott Baker133c9212013-05-17 09:09:11 -07001209 def get_readonly_fields(self, request, obj=None):
Siobhan Tullyd3515752013-06-21 16:34:53 -04001210 if (obj is not None):
1211 # Prevent slice from being changed after the reservation has been
1212 # created.
1213 return ['slice']
1214 else:
Scott Baker133c9212013-05-17 09:09:11 -07001215 return []
Scott Baker3de3e372013-05-10 16:50:44 -07001216
Tony Mack5b061472014-02-04 07:57:10 -05001217 def queryset(self, request):
1218 return Reservation.select_by_user(request.user)
1219
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001220class NetworkParameterTypeAdmin(PlanetStackBaseAdmin):
Scott Baker74d8e622013-07-29 16:04:22 -07001221 list_display = ("name", )
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001222 user_readonly_fields = ['name']
1223 user_readonly_inlines = []
Scott Baker74d8e622013-07-29 16:04:22 -07001224
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001225class RouterAdmin(PlanetStackBaseAdmin):
Scott Baker74d8e622013-07-29 16:04:22 -07001226 list_display = ("name", )
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001227 user_readonly_fields = ['name']
1228 user_readonly_inlines = []
1229
1230class RouterROInline(ReadOnlyTabularInline):
1231 model = Router.networks.through
1232 extra = 0
1233 verbose_name_plural = "Routers"
1234 verbose_name = "Router"
1235 suit_classes = 'suit-tab suit-tab-routers'
1236
1237 fields = ['name', 'owner', 'permittedNetworks', 'networks']
Scott Baker74d8e622013-07-29 16:04:22 -07001238
Scott Baker0165fac2014-01-13 11:49:26 -08001239class RouterInline(PlStackTabularInline):
Scott Baker74d8e622013-07-29 16:04:22 -07001240 model = Router.networks.through
1241 extra = 0
1242 verbose_name_plural = "Routers"
1243 verbose_name = "Router"
Siobhan Tully2d95e482013-09-06 10:56:06 -04001244 suit_classes = 'suit-tab suit-tab-routers'
Scott Baker74d8e622013-07-29 16:04:22 -07001245
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001246class NetworkParameterROInline(ReadOnlyTabularInline):
1247 model = NetworkParameter
1248 extra = 1
1249 verbose_name_plural = "Parameters"
1250 verbose_name = "Parameter"
1251 suit_classes = 'suit-tab suit-tab-netparams'
1252 fields = ['parameter', 'value', 'content_type', 'object_id', 'content_object']
1253
Scott Baker74d8e622013-07-29 16:04:22 -07001254class NetworkParameterInline(generic.GenericTabularInline):
Scott Baker74d8e622013-07-29 16:04:22 -07001255 model = NetworkParameter
1256 extra = 1
1257 verbose_name_plural = "Parameters"
1258 verbose_name = "Parameter"
Siobhan Tully2d95e482013-09-06 10:56:06 -04001259 suit_classes = 'suit-tab suit-tab-netparams'
Scott Baker74d8e622013-07-29 16:04:22 -07001260
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001261class NetworkSliversROInline(ReadOnlyTabularInline):
1262 fields = ['network', 'sliver', 'ip', 'port_id']
1263 model = NetworkSliver
1264 extra = 0
1265 verbose_name_plural = "Slivers"
1266 verbose_name = "Sliver"
1267 suit_classes = 'suit-tab suit-tab-networkslivers'
1268
Scott Baker0165fac2014-01-13 11:49:26 -08001269class NetworkSliversInline(PlStackTabularInline):
Scott Baker74d8e622013-07-29 16:04:22 -07001270 readonly_fields = ("ip", )
1271 model = NetworkSliver
Scott Baker874936e2014-01-13 18:15:34 -08001272 selflink_fieldname = "sliver"
Scott Baker74d8e622013-07-29 16:04:22 -07001273 extra = 0
1274 verbose_name_plural = "Slivers"
1275 verbose_name = "Sliver"
Siobhan Tully2d95e482013-09-06 10:56:06 -04001276 suit_classes = 'suit-tab suit-tab-networkslivers'
Scott Baker74d8e622013-07-29 16:04:22 -07001277
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001278class NetworkSlicesROInline(ReadOnlyTabularInline):
1279 model = NetworkSlice
1280 extra = 0
1281 verbose_name_plural = "Slices"
1282 verbose_name = "Slice"
1283 suit_classes = 'suit-tab suit-tab-networkslices'
1284 fields = ['network','slice']
1285
Scott Baker0165fac2014-01-13 11:49:26 -08001286class NetworkSlicesInline(PlStackTabularInline):
Scott Bakerd7d2a392013-08-06 08:57:30 -07001287 model = NetworkSlice
Scott Baker874936e2014-01-13 18:15:34 -08001288 selflink_fieldname = "slice"
Scott Bakerd7d2a392013-08-06 08:57:30 -07001289 extra = 0
1290 verbose_name_plural = "Slices"
1291 verbose_name = "Slice"
Siobhan Tully2d95e482013-09-06 10:56:06 -04001292 suit_classes = 'suit-tab suit-tab-networkslices'
Scott Bakerd7d2a392013-08-06 08:57:30 -07001293
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001294class NetworkAdmin(PlanetStackBaseAdmin):
Scott Baker74d8e622013-07-29 16:04:22 -07001295 list_display = ("name", "subnet", "ports", "labels")
1296 readonly_fields = ("subnet", )
Siobhan Tully2d95e482013-09-06 10:56:06 -04001297
Scott Bakerd7d2a392013-08-06 08:57:30 -07001298 inlines = [NetworkParameterInline, NetworkSliversInline, NetworkSlicesInline, RouterInline]
Scott Baker74d8e622013-07-29 16:04:22 -07001299
Siobhan Tully2d95e482013-09-06 10:56:06 -04001300 fieldsets = [
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001301 (None, {'fields': ['name','template','ports','labels','owner','guaranteedBandwidth', 'permitAllSlices','permittedSlices','network_id','router_id','subnet_id','subnet'], 'classes':['suit-tab suit-tab-general']}),]
1302
1303 user_readonly_fields = ['name','template','ports','labels','owner','guaranteedBandwidth', 'permitAllSlices','permittedSlices','network_id','router_id','subnet_id','subnet']
1304 user_readonly_inlines = [NetworkParameterROInline, NetworkSliversROInline, NetworkSlicesROInline, RouterROInline]
Siobhan Tully2d95e482013-09-06 10:56:06 -04001305
1306 suit_form_tabs =(
1307 ('general','Network Details'),
1308 ('netparams', 'Parameters'),
1309 ('networkslivers','Slivers'),
1310 ('networkslices','Slices'),
1311 ('routers','Routers'),
1312 )
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001313class NetworkTemplateAdmin(PlanetStackBaseAdmin):
Scott Baker74d8e622013-07-29 16:04:22 -07001314 list_display = ("name", "guaranteedBandwidth", "visibility")
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001315 user_readonly_fields = ["name", "guaranteedBandwidth", "visibility"]
1316 user_readonly_inlines = []
Scott Baker74d8e622013-07-29 16:04:22 -07001317
Tony Mack31c2b8f2013-04-26 20:01:42 -04001318# register a signal that caches the user's credentials when they log in
1319def cache_credentials(sender, user, request, **kwds):
1320 auth = {'username': request.POST['username'],
1321 'password': request.POST['password']}
1322 request.session['auth'] = auth
1323user_logged_in.connect(cache_credentials)
1324
Scott Baker15cddfa2013-12-09 13:45:19 -08001325def dollar_field(fieldName, short_description):
1326 def newFunc(self, obj):
1327 try:
1328 x= "$ %0.2f" % float(getattr(obj, fieldName, 0.0))
1329 except:
1330 x=getattr(obj, fieldName, 0.0)
1331 return x
1332 newFunc.short_description = short_description
1333 return newFunc
1334
1335def right_dollar_field(fieldName, short_description):
1336 def newFunc(self, obj):
1337 try:
1338 #x= '<div align=right style="width:6em">$ %0.2f</div>' % float(getattr(obj, fieldName, 0.0))
1339 x= '<div align=right>$ %0.2f</div>' % float(getattr(obj, fieldName, 0.0))
1340 except:
1341 x=getattr(obj, fieldName, 0.0)
1342 return x
1343 newFunc.short_description = short_description
1344 newFunc.allow_tags = True
1345 return newFunc
Scott Baker43105042013-12-06 23:23:36 -08001346
Scott Baker0165fac2014-01-13 11:49:26 -08001347class InvoiceChargeInline(PlStackTabularInline):
Scott Baker43105042013-12-06 23:23:36 -08001348 model = Charge
Scott Baker15cddfa2013-12-09 13:45:19 -08001349 extra = 0
Scott Baker43105042013-12-06 23:23:36 -08001350 verbose_name_plural = "Charges"
1351 verbose_name = "Charge"
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001352 exclude = ['account']
Scott Baker9cb88a22013-12-09 18:56:00 -08001353 fields = ["date", "kind", "state", "object", "coreHours", "dollar_amount", "slice"]
1354 readonly_fields = ["date", "kind", "state", "object", "coreHours", "dollar_amount", "slice"]
1355 can_delete = False
1356 max_num = 0
1357
1358 dollar_amount = right_dollar_field("amount", "Amount")
Scott Baker43105042013-12-06 23:23:36 -08001359
1360class InvoiceAdmin(admin.ModelAdmin):
1361 list_display = ("date", "account")
1362
1363 inlines = [InvoiceChargeInline]
1364
Scott Baker9cb88a22013-12-09 18:56:00 -08001365 fields = ["date", "account", "dollar_amount"]
1366 readonly_fields = ["date", "account", "dollar_amount"]
1367
1368 dollar_amount = dollar_field("amount", "Amount")
Scott Baker43105042013-12-06 23:23:36 -08001369
Scott Baker0165fac2014-01-13 11:49:26 -08001370class InvoiceInline(PlStackTabularInline):
Scott Baker15cddfa2013-12-09 13:45:19 -08001371 model = Invoice
1372 extra = 0
1373 verbose_name_plural = "Invoices"
1374 verbose_name = "Invoice"
Scott Baker0165fac2014-01-13 11:49:26 -08001375 fields = ["date", "dollar_amount"]
1376 readonly_fields = ["date", "dollar_amount"]
Scott Baker15cddfa2013-12-09 13:45:19 -08001377 suit_classes = 'suit-tab suit-tab-accountinvoice'
1378 can_delete=False
1379 max_num=0
1380
1381 dollar_amount = right_dollar_field("amount", "Amount")
1382
Scott Baker0165fac2014-01-13 11:49:26 -08001383class PendingChargeInline(PlStackTabularInline):
Scott Baker43105042013-12-06 23:23:36 -08001384 model = Charge
Scott Baker15cddfa2013-12-09 13:45:19 -08001385 extra = 0
Scott Baker43105042013-12-06 23:23:36 -08001386 verbose_name_plural = "Charges"
1387 verbose_name = "Charge"
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001388 exclude = ["invoice"]
Scott Baker15cddfa2013-12-09 13:45:19 -08001389 fields = ["date", "kind", "state", "object", "coreHours", "dollar_amount", "slice"]
1390 readonly_fields = ["date", "kind", "state", "object", "coreHours", "dollar_amount", "slice"]
Scott Baker43105042013-12-06 23:23:36 -08001391 suit_classes = 'suit-tab suit-tab-accountpendingcharges'
Scott Baker15cddfa2013-12-09 13:45:19 -08001392 can_delete=False
1393 max_num=0
Scott Baker43105042013-12-06 23:23:36 -08001394
1395 def queryset(self, request):
1396 qs = super(PendingChargeInline, self).queryset(request)
1397 qs = qs.filter(state="pending")
1398 return qs
1399
Scott Baker15cddfa2013-12-09 13:45:19 -08001400 dollar_amount = right_dollar_field("amount", "Amount")
1401
Scott Baker0165fac2014-01-13 11:49:26 -08001402class PaymentInline(PlStackTabularInline):
Scott Baker43105042013-12-06 23:23:36 -08001403 model=Payment
1404 extra = 1
1405 verbose_name_plural = "Payments"
1406 verbose_name = "Payment"
Scott Baker15cddfa2013-12-09 13:45:19 -08001407 fields = ["date", "dollar_amount"]
1408 readonly_fields = ["date", "dollar_amount"]
Scott Baker43105042013-12-06 23:23:36 -08001409 suit_classes = 'suit-tab suit-tab-accountpayments'
Scott Baker15cddfa2013-12-09 13:45:19 -08001410 can_delete=False
1411 max_num=0
1412
1413 dollar_amount = right_dollar_field("amount", "Amount")
1414
Scott Baker43105042013-12-06 23:23:36 -08001415class AccountAdmin(admin.ModelAdmin):
1416 list_display = ("site", "balance_due")
1417
1418 inlines = [InvoiceInline, PaymentInline, PendingChargeInline]
1419
1420 fieldsets = [
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001421 (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 -08001422
Scott Baker15cddfa2013-12-09 13:45:19 -08001423 readonly_fields = ['site', 'dollar_balance_due', 'dollar_total_invoices', 'dollar_total_payments']
Scott Baker43105042013-12-06 23:23:36 -08001424
1425 suit_form_tabs =(
1426 ('general','Account Details'),
1427 ('accountinvoice', 'Invoices'),
1428 ('accountpayments', 'Payments'),
1429 ('accountpendingcharges','Pending Charges'),
1430 )
1431
Scott Baker15cddfa2013-12-09 13:45:19 -08001432 dollar_balance_due = dollar_field("balance_due", "Balance Due")
1433 dollar_total_invoices = dollar_field("total_invoices", "Total Invoices")
1434 dollar_total_payments = dollar_field("total_payments", "Total Payments")
1435
Siobhan Tullyce652d02013-10-08 21:52:35 -04001436
Siobhan Tully53437282013-04-26 19:30:27 -04001437# Now register the new UserAdmin...
Siobhan Tully30fd4292013-05-10 08:59:56 -04001438admin.site.register(User, UserAdmin)
Siobhan Tully53437282013-04-26 19:30:27 -04001439# ... and, since we're not using Django's builtin permissions,
1440# unregister the Group model from admin.
Siobhan Tullyce652d02013-10-08 21:52:35 -04001441#admin.site.unregister(Group)
Siobhan Tully53437282013-04-26 19:30:27 -04001442
Siobhan Tullybf1153a2013-05-27 20:53:48 -04001443#Do not show django evolution in the admin interface
1444from django_evolution.models import Version, Evolution
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001445#admin.site.unregister(Version)
1446#admin.site.unregister(Evolution)
Siobhan Tullybf1153a2013-05-27 20:53:48 -04001447
1448
1449# When debugging it is often easier to see all the classes, but for regular use
1450# only the top-levels should be displayed
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001451showAll = False
Scott Baker43105042013-12-06 23:23:36 -08001452
Siobhan Tullybf1153a2013-05-27 20:53:48 -04001453admin.site.register(Deployment, DeploymentAdmin)
Siobhan Tully4bc09f22013-04-10 21:15:21 -04001454admin.site.register(Site, SiteAdmin)
Siobhan Tully4bc09f22013-04-10 21:15:21 -04001455admin.site.register(Slice, SliceAdmin)
Siobhan Tullyce652d02013-10-08 21:52:35 -04001456admin.site.register(Service, ServiceAdmin)
smbakera3cf70c2013-06-27 02:01:41 -07001457admin.site.register(Reservation, ReservationAdmin)
Scott Baker74d8e622013-07-29 16:04:22 -07001458admin.site.register(Network, NetworkAdmin)
1459admin.site.register(Router, RouterAdmin)
Scott Baker74d8e622013-07-29 16:04:22 -07001460admin.site.register(NetworkTemplate, NetworkTemplateAdmin)
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001461admin.site.register(Account, AccountAdmin)
1462admin.site.register(Invoice, InvoiceAdmin)
Siobhan Tullybf1153a2013-05-27 20:53:48 -04001463
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001464if True:
1465 admin.site.register(NetworkParameterType, NetworkParameterTypeAdmin)
1466 admin.site.register(ServiceClass, ServiceClassAdmin)
Siobhan Tullybfd11dc2013-09-03 12:59:24 -04001467 #admin.site.register(PlanetStack)
Siobhan Tullyd3515752013-06-21 16:34:53 -04001468 admin.site.register(Tag, TagAdmin)
Siobhan Tullyce652d02013-10-08 21:52:35 -04001469 admin.site.register(DeploymentRole)
1470 admin.site.register(SiteRole)
1471 admin.site.register(SliceRole)
1472 admin.site.register(PlanetStackRole)
Siobhan Tullybf1153a2013-05-27 20:53:48 -04001473 admin.site.register(Node, NodeAdmin)
Siobhan Tullybfd11dc2013-09-03 12:59:24 -04001474 #admin.site.register(SlicePrivilege, SlicePrivilegeAdmin)
1475 #admin.site.register(SitePrivilege, SitePrivilegeAdmin)
Siobhan Tullybf1153a2013-05-27 20:53:48 -04001476 admin.site.register(Sliver, SliverAdmin)
Siobhan Tullybf1153a2013-05-27 20:53:48 -04001477 admin.site.register(Image, ImageAdmin)
Scott Baker2c3cb642014-05-19 17:55:56 -07001478 admin.site.register(DashboardView, DashboardViewAdmin)
Tony Mack7130ac32013-03-22 21:58:00 -04001479