blob: 5c5257891377f9ab46c1d2d8556d47a6d2391fd2 [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
51 self.readonly_fields=self.user_readonly_fields
52 self.inlines = self.user_readonly_inlines
53 else:
54 if hasattr(self, "readonly_save"):
55 # restore the original readonly fields
56 self.readonly_fields = self.readonly_save
57 self.inlines = self.inlines_save
Siobhan Tullycf04fb62014-01-11 11:25:57 -050058
59 try:
60 return super(ReadOnlyAwareAdmin, self).change_view(request, object_id, extra_context=extra_context)
61 except PermissionDenied:
62 pass
63 if request.method == 'POST':
64 raise PermissionDenied
65 request.readonly = True
66 return super(ReadOnlyAwareAdmin, self).change_view(request, object_id, extra_context=extra_context)
67
Siobhan Tullycf04fb62014-01-11 11:25:57 -050068 def __user_is_readonly(self, request):
69 return request.user.isReadOnlyUser()
70
Siobhan Tullyce652d02013-10-08 21:52:35 -040071class SingletonAdmin (admin.ModelAdmin):
72 def has_add_permission(self, request):
73 num_objects = self.model.objects.count()
74 if num_objects >= 1:
75 return False
76 else:
77 return True
78
79
Siobhan Tullyd3515752013-06-21 16:34:53 -040080class PlStackTabularInline(admin.TabularInline):
Scott Baker86568322014-01-12 16:53:31 -080081 def __init__(self, *args, **kwargs):
82 super(PlStackTabularInline, self).__init__(*args, **kwargs)
83
84 # InlineModelAdmin as no get_fields() method, so in order to add
85 # the selflink field, we override __init__ to modify self.fields and
86 # self.readonly_fields.
87
Scott Bakere2bbf7e2014-01-13 12:09:31 -080088 self.setup_selflink()
89
Scott Baker874936e2014-01-13 18:15:34 -080090 def get_change_url(self, model, id):
91 """ Get the URL to a change form in the admin for this model """
92 reverse_path = "admin:%s_change" % (model._meta.db_table)
Scott Bakere2bbf7e2014-01-13 12:09:31 -080093 try:
Scott Baker874936e2014-01-13 18:15:34 -080094 url = reverse(reverse_path, args=(id,))
Scott Bakere2bbf7e2014-01-13 12:09:31 -080095 except NoReverseMatch:
Scott Baker874936e2014-01-13 18:15:34 -080096 return None
97
98 return url
99
100 def setup_selflink(self):
101 if hasattr(self, "selflink_fieldname"):
102 """ self.selflink_model can be defined to punch through a relation
103 to its target object. For example, in SliceNetworkInline, set
104 selflink_model = "network", and the URL will lead to the Network
105 object instead of trying to bring up a change view of the
106 SliceNetwork object.
107 """
108 self.selflink_model = getattr(self.model,self.selflink_fieldname).field.rel.to
109 else:
110 self.selflink_model = self.model
111
112 url = self.get_change_url(self.selflink_model, 0)
113
114 # We don't have an admin for this object, so don't create the
115 # selflink.
116 if (url == None):
Scott Bakere2bbf7e2014-01-13 12:09:31 -0800117 return
118
Scott Baker874936e2014-01-13 18:15:34 -0800119 # Since we need to add "selflink" to the field list, we need to create
120 # self.fields if it is None.
Scott Baker0165fac2014-01-13 11:49:26 -0800121 if (self.fields is None):
122 self.fields = []
123 for f in self.model._meta.fields:
124 if f.editable and f.name != "id":
125 self.fields.append(f.name)
Scott Baker86568322014-01-12 16:53:31 -0800126
Scott Baker874936e2014-01-13 18:15:34 -0800127 self.fields = tuple(self.fields) + ("selflink", )
Scott Baker86568322014-01-12 16:53:31 -0800128
Scott Baker874936e2014-01-13 18:15:34 -0800129 if self.readonly_fields is None:
130 self.readonly_fields = ()
Scott Baker86568322014-01-12 16:53:31 -0800131
Scott Baker874936e2014-01-13 18:15:34 -0800132 self.readonly_fields = tuple(self.readonly_fields) + ("selflink", )
Scott Baker86568322014-01-12 16:53:31 -0800133
134 def selflink(self, obj):
Scott Baker874936e2014-01-13 18:15:34 -0800135 if hasattr(self, "selflink_fieldname"):
136 obj = getattr(obj, self.selflink_fieldname)
137
Scott Baker86568322014-01-12 16:53:31 -0800138 if obj.id:
Scott Baker874936e2014-01-13 18:15:34 -0800139 url = self.get_change_url(self.selflink_model, obj.id)
140 return "<a href='%s'>Details</a>" % str(url)
Scott Baker86568322014-01-12 16:53:31 -0800141 else:
Scott Bakere2bbf7e2014-01-13 12:09:31 -0800142 return "Not present"
Scott Baker86568322014-01-12 16:53:31 -0800143
144 selflink.allow_tags = True
145 selflink.short_description = "Details"
Siobhan Tullyd3515752013-06-21 16:34:53 -0400146
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500147class ReadOnlyTabularInline(PlStackTabularInline):
148 can_delete = False
149
150 def get_readonly_fields(self, request, obj=None):
151 return self.fields
152
153 def has_add_permission(self, request):
154 return False
155
156class ReservationROInline(ReadOnlyTabularInline):
157 model = Reservation
158 extra = 0
159 suit_classes = 'suit-tab suit-tab-reservations'
160 fields = ['startTime','slice','duration']
161
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400162class ReservationInline(PlStackTabularInline):
163 model = Reservation
164 extra = 0
165 suit_classes = 'suit-tab suit-tab-reservations'
Tony Mack5b061472014-02-04 07:57:10 -0500166
167 def queryset(self, request):
168 return Reservation.select_by_user(request.user)
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400169
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500170class TagROInline(generic.GenericTabularInline):
171 model = Tag
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400172 extra = 0
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500173 suit_classes = 'suit-tab suit-tab-tags'
174 can_delete = False
175 fields = ['service', 'name', 'value']
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400176
177 def get_readonly_fields(self, request, obj=None):
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500178 return self.fields
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400179
180 def has_add_permission(self, request):
181 return False
182
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500183
Siobhan Tullyde5450d2013-06-21 11:35:33 -0400184class TagInline(generic.GenericTabularInline):
185 model = Tag
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400186 extra = 0
187 suit_classes = 'suit-tab suit-tab-tags'
Tony Mack5b061472014-02-04 07:57:10 -0500188 fields = ['service', 'name', 'value']
189
190 def queryset(self, request):
191 return Tag.select_by_user(request.user)
Siobhan Tullyde5450d2013-06-21 11:35:33 -0400192
Scott Baker74d8e622013-07-29 16:04:22 -0700193class NetworkLookerUpper:
Siobhan Tully2c780ad2013-09-06 11:22:40 -0400194 """ This is a callable that looks up a network name in a sliver and returns
195 the ip address for that network.
196 """
197
198 def __init__(self, name):
199 self.short_description = name
200 self.__name__ = name
201 self.network_name = name
202
203 def __call__(self, obj):
204 if obj is not None:
205 for nbs in obj.networksliver_set.all():
206 if (nbs.network.name == self.network_name):
207 return nbs.ip
Scott Baker74d8e622013-07-29 16:04:22 -0700208 return ""
209
210 def __str__(self):
211 return self.network_name
212
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500213class SliverROInline(ReadOnlyTabularInline):
214 model = Sliver
215 fields = ['ip', 'instance_name', 'slice', 'numberCores', 'image', 'node', 'deploymentNetwork']
216 suit_classes = 'suit-tab suit-tab-slivers'
217
Siobhan Tullyd3515752013-06-21 16:34:53 -0400218class SliverInline(PlStackTabularInline):
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400219 model = Sliver
Tony Mackb0d97422013-06-10 09:57:45 -0400220 fields = ['ip', 'instance_name', 'slice', 'numberCores', 'image', 'node', 'deploymentNetwork']
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400221 extra = 0
Tony Mack3777b012013-05-07 21:38:06 -0400222 readonly_fields = ['ip', 'instance_name']
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400223 suit_classes = 'suit-tab suit-tab-slivers'
Scott Baker74d8e622013-07-29 16:04:22 -0700224
Tony Mack5b061472014-02-04 07:57:10 -0500225 def queryset(self, request):
226 return Sliver.select_by_user(request.user)
227
Siobhan Tully2d95e482013-09-06 10:56:06 -0400228# Note this is breaking in the admin.py when trying to use an inline to add a node/image
229# def _declared_fieldsets(self):
230# # Return None so django will call get_fieldsets and we can insert our
231# # dynamic fields
232# return None
233#
234# def get_readonly_fields(self, request, obj=None):
235# readonly_fields = super(SliverInline, self).get_readonly_fields(request, obj)
236#
237# # Lookup the networks that are bound to the slivers, and add those
238# # network names to the list of readonly fields.
239#
240# for sliver in obj.slivers.all():
241# for nbs in sliver.networksliver_set.all():
242# if nbs.ip:
243# network_name = nbs.network.name
244# if network_name not in [str(x) for x in readonly_fields]:
245# readonly_fields.append(NetworkLookerUpper(network_name))
246#
247# return readonly_fields
248#
249# def get_fieldsets(self, request, obj=None):
250# form = self.get_formset(request, obj).form
251# # fields = the read/write files + the read-only fields
252# fields = self.fields
253# for fieldName in self.get_readonly_fields(request,obj):
254# if not fieldName in fields:
255# fields.append(fieldName)
256#
257# return [(None, {'fields': fields})]
Scott Baker74d8e622013-07-29 16:04:22 -0700258
Tony Mackc2835a92013-05-28 09:18:49 -0400259
Siobhan Tully567e3e62013-06-21 18:03:16 -0400260
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500261class SiteROInline(ReadOnlyTabularInline):
262 model = Site
263 extra = 0
264 fields = ['name', 'login_base', 'site_url', 'enabled']
265 suit_classes = 'suit-tab suit-tab-sites'
266
Siobhan Tullyd3515752013-06-21 16:34:53 -0400267class SiteInline(PlStackTabularInline):
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400268 model = Site
269 extra = 0
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400270 suit_classes = 'suit-tab suit-tab-sites'
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400271
Tony Mack5b061472014-02-04 07:57:10 -0500272 def queryset(self, request):
273 return Site.select_by_user(request.user)
274
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500275class UserROInline(ReadOnlyTabularInline):
276 model = User
277 fields = ['email', 'firstname', 'lastname']
278 extra = 0
279 suit_classes = 'suit-tab suit-tab-users'
280
Siobhan Tullyd3515752013-06-21 16:34:53 -0400281class UserInline(PlStackTabularInline):
Siobhan Tully30fd4292013-05-10 08:59:56 -0400282 model = User
Siobhan Tully47ae1b52013-05-10 15:53:14 -0400283 fields = ['email', 'firstname', 'lastname']
Siobhan Tully30fd4292013-05-10 08:59:56 -0400284 extra = 0
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400285 suit_classes = 'suit-tab suit-tab-users'
Siobhan Tully30fd4292013-05-10 08:59:56 -0400286
Tony Mack5b061472014-02-04 07:57:10 -0500287 def queryset(self, request):
288 return User.select_by_user(request.user)
289
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500290class SliceROInline(ReadOnlyTabularInline):
291 model = Slice
292 suit_classes = 'suit-tab suit-tab-slices'
293 fields = ['name','site', 'serviceClass', 'service']
294
Siobhan Tullyd3515752013-06-21 16:34:53 -0400295class SliceInline(PlStackTabularInline):
Tony Mack00d361f2013-04-28 10:28:42 -0400296 model = Slice
Siobhan Tullyce652d02013-10-08 21:52:35 -0400297 fields = ['name','site', 'serviceClass', 'service']
Tony Mack00d361f2013-04-28 10:28:42 -0400298 extra = 0
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400299 suit_classes = 'suit-tab suit-tab-slices'
300
Tony Mack5b061472014-02-04 07:57:10 -0500301 def queryset(self, request):
302 return Slice.select_by_user(request.user)
303
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500304class NodeROInline(ReadOnlyTabularInline):
305 model = Node
306 extra = 0
307 suit_classes = 'suit-tab suit-tab-nodes'
308 fields = ['name','deployment']
Tony Mack00d361f2013-04-28 10:28:42 -0400309
Siobhan Tullyd3515752013-06-21 16:34:53 -0400310class NodeInline(PlStackTabularInline):
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400311 model = Node
312 extra = 0
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400313 suit_classes = 'suit-tab suit-tab-nodes'
Tony Mack5b061472014-02-04 07:57:10 -0500314 fields = ['name','deployment']
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400315
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500316class DeploymentPrivilegeROInline(ReadOnlyTabularInline):
317 model = DeploymentPrivilege
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400318 extra = 0
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500319 suit_classes = 'suit-tab suit-tab-deploymentprivileges'
320 fields = ['user','role']
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400321
322class DeploymentPrivilegeInline(PlStackTabularInline):
323 model = DeploymentPrivilege
324 extra = 0
325 suit_classes = 'suit-tab suit-tab-deploymentprivileges'
Tony Mack5b061472014-02-04 07:57:10 -0500326 fields = ['user','role']
327
328 def queryset(self, request):
329 return DeploymentPrivilege.select_by_user(request.user)
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400330
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500331#CLEANUP DOUBLE SitePrivilegeInline
332class SitePrivilegeROInline(ReadOnlyTabularInline):
333 model = SitePrivilege
334 extra = 0
335 suit_classes = 'suit-tab suit-tab-siteprivileges'
336 fields = ['user','site', 'role']
337
Siobhan Tullyd3515752013-06-21 16:34:53 -0400338class SitePrivilegeInline(PlStackTabularInline):
Siobhan Tullyaa1bcd52013-05-10 12:43:09 -0400339 model = SitePrivilege
340 extra = 0
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400341 suit_classes = 'suit-tab suit-tab-siteprivileges'
Tony Mack5b061472014-02-04 07:57:10 -0500342 fields = ['user','site', 'role']
Siobhan Tullyaa1bcd52013-05-10 12:43:09 -0400343
Tony Mackc2835a92013-05-28 09:18:49 -0400344 def formfield_for_foreignkey(self, db_field, request, **kwargs):
345 if db_field.name == 'site':
Tony Mack5b061472014-02-04 07:57:10 -0500346 kwargs['queryset'] = Site.select_by_user(request.user)
Tony Mackc2835a92013-05-28 09:18:49 -0400347
348 if db_field.name == 'user':
Tony Mack5b061472014-02-04 07:57:10 -0500349 kwargs['queryset'] = User.select_by_user(request.user)
Tony Mackc2835a92013-05-28 09:18:49 -0400350 return super(SitePrivilegeInline, self).formfield_for_foreignkey(db_field, request, **kwargs)
351
Tony Mack5b061472014-02-04 07:57:10 -0500352 def queryset(self, request):
353 return SitePrivilege.select_by_user(request.user)
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400354
Tony Macke4be32f2014-03-11 20:45:25 -0400355class SiteDeploymentROInline(ReadOnlyTabularInline):
356 model = SiteDeployments
357 #model = Site.deployments.through
358 extra = 0
359 suit_classes = 'suit-tab suit-tab-sitedeployments'
360 fields = ['deployment','site']
361
362class SiteDeploymentInline(PlStackTabularInline):
363 model = SiteDeployments
364 #model = Site.deployments.through
365 extra = 0
366 suit_classes = 'suit-tab suit-tab-deployments'
367 fields = ['deployment','site']
368
369 def formfield_for_foreignkey(self, db_field, request, **kwargs):
370 if db_field.name == 'site':
371 kwargs['queryset'] = Site.select_by_user(request.user)
372
373 if db_field.name == 'deployment':
374 kwargs['queryset'] = Deployment.select_by_user(request.user)
375 return super(SiteDeploymentInline, self).formfield_for_foreignkey(db_field, request, **kwargs)
376
377 def queryset(self, request):
378 return SiteDeployments.select_by_user(request.user)
379
380
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500381class SlicePrivilegeROInline(ReadOnlyTabularInline):
382 model = SlicePrivilege
383 extra = 0
384 suit_classes = 'suit-tab suit-tab-sliceprivileges'
385 fields = ['user', 'slice', 'role']
386
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400387class SlicePrivilegeInline(PlStackTabularInline):
388 model = SlicePrivilege
389 suit_classes = 'suit-tab suit-tab-sliceprivileges'
390 extra = 0
391 fields = ('user', 'slice','role')
Siobhan Tullyaa1bcd52013-05-10 12:43:09 -0400392
Tony Mackc2835a92013-05-28 09:18:49 -0400393 def formfield_for_foreignkey(self, db_field, request, **kwargs):
394 if db_field.name == 'slice':
Tony Mack5b061472014-02-04 07:57:10 -0500395 kwargs['queryset'] = Slice.select_by_user(request.user)
Tony Mackc2835a92013-05-28 09:18:49 -0400396 if db_field.name == 'user':
Tony Mack5b061472014-02-04 07:57:10 -0500397 kwargs['queryset'] = User.select_by_user(request.user)
Tony Mackc2835a92013-05-28 09:18:49 -0400398
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400399 return super(SlicePrivilegeInline, self).formfield_for_foreignkey(db_field, request, **kwargs)
Tony Mackc2835a92013-05-28 09:18:49 -0400400
Tony Mack5b061472014-02-04 07:57:10 -0500401 def queryset(self, request):
402 return SlicePrivilege.select_by_user(request.user)
403
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500404class SliceNetworkROInline(ReadOnlyTabularInline):
405 model = Network.slices.through
406 extra = 0
407 verbose_name = "Network Connection"
408 verbose_name_plural = "Network Connections"
409 suit_classes = 'suit-tab suit-tab-slicenetworks'
410 fields = ['network']
411
Scott Bakera0015eb2013-08-14 17:28:14 -0700412class SliceNetworkInline(PlStackTabularInline):
Scott Baker74d8e622013-07-29 16:04:22 -0700413 model = Network.slices.through
Scott Baker874936e2014-01-13 18:15:34 -0800414 selflink_fieldname = "network"
Scott Baker74d8e622013-07-29 16:04:22 -0700415 extra = 0
416 verbose_name = "Network Connection"
417 verbose_name_plural = "Network Connections"
Siobhan Tully2d95e482013-09-06 10:56:06 -0400418 suit_classes = 'suit-tab suit-tab-slicenetworks'
Scott Baker74d8e622013-07-29 16:04:22 -0700419
Tony Mack5e71a662013-05-03 23:30:41 -0400420class PlainTextWidget(forms.HiddenInput):
421 input_type = 'hidden'
422
423 def render(self, name, value, attrs=None):
424 if value is None:
425 value = ''
Tony Mack1d6b85f2013-05-07 18:49:14 -0400426 return mark_safe(str(value) + super(PlainTextWidget, self).render(name, value, attrs))
Tony Mack9bcbe4f2013-04-29 08:13:27 -0400427
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500428class PlanetStackBaseAdmin(ReadOnlyAwareAdmin):
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400429 save_on_top = False
Tony Mack332ee1d2014-02-04 15:33:45 -0500430
431 def save_model(self, request, obj, form, change):
Tony Mack3d042792014-03-17 19:18:37 -0400432 obj.caller = request.user
Tony Mack332ee1d2014-02-04 15:33:45 -0500433 # update openstack connection to use this site/tenant
434 obj.save_by_user(request.user)
435
436 def delete_model(self, request, obj):
437 obj.delete_by_user(request.user)
438
439 def save_formset(self, request, form, formset, change):
440 instances = formset.save(commit=False)
441 for instance in instances:
442 instance.save_by_user(request.user)
443 formset.save_m2m()
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400444
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400445class SliceRoleAdmin(PlanetStackBaseAdmin):
446 model = SliceRole
447 pass
448
449class SiteRoleAdmin(PlanetStackBaseAdmin):
450 model = SiteRole
451 pass
452
Siobhan Tullybf1153a2013-05-27 20:53:48 -0400453class DeploymentAdminForm(forms.ModelForm):
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400454 sites = forms.ModelMultipleChoiceField(
455 queryset=Site.objects.all(),
456 required=False,
457 widget=FilteredSelectMultiple(
458 verbose_name=('Sites'), is_stacked=False
459 )
460 )
461 class Meta:
Siobhan Tullybf1153a2013-05-27 20:53:48 -0400462 model = Deployment
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400463
Siobhan Tully320b4622014-01-17 15:11:14 -0500464 def __init__(self, *args, **kwargs):
465 super(DeploymentAdminForm, self).__init__(*args, **kwargs)
466
467 if self.instance and self.instance.pk:
Scott Bakerc9b14f72014-05-22 13:44:20 -0700468 self.fields['sites'].initial = [x.site for x in self.instance.sitedeployments_set.all()]
Siobhan Tully320b4622014-01-17 15:11:14 -0500469
470 def save(self, commit=True):
471 deployment = super(DeploymentAdminForm, self).save(commit=False)
472
473 if commit:
474 deployment.save()
475
476 if deployment.pk:
Scott Bakerc9b14f72014-05-22 13:44:20 -0700477 # save_m2m() doesn't seem to work with 'through' relations. So we
478 # create/destroy the through models ourselves. There has to be
479 # a better way...
480
481 sites = self.cleaned_data['sites']
482
483 existing_sites = []
484 for sdp in list(deployment.sitedeployments_set.all()):
485 if sdp.site not in sites:
486 #print "deleting site", sdp.site
487 sdp.delete()
488 else:
489 existing_sites.append(sdp.site)
490
491 for site in sites:
492 if site not in existing_sites:
493 #print "adding site", site
494 sdp = SiteDeployments(site=site, deployment=deployment)
495 sdp.save()
496
Siobhan Tully320b4622014-01-17 15:11:14 -0500497 self.save_m2m()
498
499 return deployment
500
Scott Bakerff5e0f32014-05-22 14:40:27 -0700501class DeploymentAdminROForm(DeploymentAdminForm):
502 def save(self, commit=True):
503 raise PermissionDenied
504
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500505class SiteAssocInline(PlStackTabularInline):
506 model = Site.deployments.through
507 extra = 0
508 suit_classes = 'suit-tab suit-tab-sites'
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400509
Siobhan Tullybf1153a2013-05-27 20:53:48 -0400510class DeploymentAdmin(PlanetStackBaseAdmin):
Scott Bakerff5e0f32014-05-22 14:40:27 -0700511 #form = DeploymentAdminForm
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500512 model = Deployment
513 fieldList = ['name','sites']
514 fieldsets = [(None, {'fields': fieldList, 'classes':['suit-tab suit-tab-sites']})]
Siobhan Tully2d95e482013-09-06 10:56:06 -0400515 inlines = [DeploymentPrivilegeInline,NodeInline,TagInline]
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500516
517 user_readonly_inlines = [DeploymentPrivilegeROInline,NodeROInline,TagROInline]
518 user_readonly_fields = ['name']
519
520 suit_form_tabs =(('sites','Deployment Details'),('nodes','Nodes'),('deploymentprivileges','Privileges'),('tags','Tags'))
521
Scott Bakerff5e0f32014-05-22 14:40:27 -0700522 def get_form(self, request, obj=None, **kwargs):
523 if request.user.isReadOnlyUser():
524 kwargs["form"] = DeploymentAdminROForm
525 else:
526 kwargs["form"] = DeploymentAdminForm
527 return super(DeploymentAdmin,self).get_form(request, obj, **kwargs)
528
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500529class ServiceAttrAsTabROInline(ReadOnlyTabularInline):
530 model = ServiceAttribute
531 fields = ['name','value']
532 extra = 0
533 suit_classes = 'suit-tab suit-tab-serviceattrs'
Tony Mack5cd13202013-05-01 21:48:38 -0400534
Siobhan Tullyce652d02013-10-08 21:52:35 -0400535class ServiceAttrAsTabInline(PlStackTabularInline):
536 model = ServiceAttribute
537 fields = ['name','value']
538 extra = 0
539 suit_classes = 'suit-tab suit-tab-serviceattrs'
540
Siobhan Tullyce652d02013-10-08 21:52:35 -0400541class ServiceAdmin(PlanetStackBaseAdmin):
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500542 list_display = ("name","description","versionNumber","enabled","published")
543 fieldList = ["name","description","versionNumber","enabled","published"]
544 fieldsets = [(None, {'fields': fieldList, 'classes':['suit-tab suit-tab-general']})]
545 inlines = [ServiceAttrAsTabInline,SliceInline]
546
547 user_readonly_fields = fieldList
548 user_readonly_inlines = [ServiceAttrAsTabROInline,SliceROInline]
549
550 suit_form_tabs =(('general', 'Service Details'),
551 ('slices','Slices'),
552 ('serviceattrs','Additional Attributes'),
553 )
Siobhan Tullyce652d02013-10-08 21:52:35 -0400554
Tony Mack0553f282013-06-10 22:54:50 -0400555class SiteAdmin(PlanetStackBaseAdmin):
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500556 fieldList = ['name', 'site_url', 'enabled', 'is_public', 'login_base', 'accountLink','location']
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400557 fieldsets = [
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500558 (None, {'fields': fieldList, 'classes':['suit-tab suit-tab-general']}),
Tony Macke4be32f2014-03-11 20:45:25 -0400559 #('Deployment Networks', {'fields': ['deployments'], 'classes':['suit-tab suit-tab-deployments']}),
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400560 ]
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400561 suit_form_tabs =(('general', 'Site Details'),
562 ('users','Users'),
Siobhan Tully2d95e482013-09-06 10:56:06 -0400563 ('siteprivileges','Privileges'),
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400564 ('deployments','Deployments'),
565 ('slices','Slices'),
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500566 ('nodes','Nodes'),
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400567 ('tags','Tags'),
568 )
Scott Baker545db2a2013-12-09 18:44:43 -0800569 readonly_fields = ['accountLink']
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500570
571 user_readonly_fields = ['name', 'deployments','site_url', 'enabled', 'is_public', 'login_base', 'accountLink']
Tony Macke4be32f2014-03-11 20:45:25 -0400572 user_readonly_inlines = [SliceROInline,UserROInline,TagROInline, NodeROInline, SitePrivilegeROInline,SiteDeploymentROInline]
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500573
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400574 list_display = ('name', 'login_base','site_url', 'enabled')
575 filter_horizontal = ('deployments',)
Tony Macke4be32f2014-03-11 20:45:25 -0400576 inlines = [SliceInline,UserInline,TagInline, NodeInline, SitePrivilegeInline, SiteDeploymentInline]
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400577 search_fields = ['name']
578
Tony Mack04062832013-05-10 08:22:44 -0400579 def queryset(self, request):
Tony Mack5b061472014-02-04 07:57:10 -0500580 #print dir(UserInline)
581 return Site.select_by_user(request.user)
Tony Mack04062832013-05-10 08:22:44 -0400582
Tony Mack5cd13202013-05-01 21:48:38 -0400583 def get_formsets(self, request, obj=None):
584 for inline in self.get_inline_instances(request, obj):
585 # hide MyInline in the add view
586 if obj is None:
587 continue
Tony Mack2bd5b412013-06-11 21:05:06 -0400588 if isinstance(inline, SliceInline):
589 inline.model.caller = request.user
590 yield inline.get_formset(request, obj)
591
592 def get_formsets(self, request, obj=None):
593 for inline in self.get_inline_instances(request, obj):
594 # hide MyInline in the add view
595 if obj is None:
596 continue
597 if isinstance(inline, SliverInline):
598 inline.model.caller = request.user
Tony Mack5cd13202013-05-01 21:48:38 -0400599 yield inline.get_formset(request, obj)
600
Scott Baker545db2a2013-12-09 18:44:43 -0800601 def accountLink(self, obj):
602 link_obj = obj.accounts.all()
603 if link_obj:
604 reverse_path = "admin:core_account_change"
605 url = reverse(reverse_path, args =(link_obj[0].id,))
606 return "<a href='%s'>%s</a>" % (url, "view billing details")
607 else:
608 return "no billing data for this site"
609 accountLink.allow_tags = True
610 accountLink.short_description = "Billing"
611
Tony Mack332ee1d2014-02-04 15:33:45 -0500612 def save_model(self, request, obj, form, change):
613 # update openstack connection to use this site/tenant
614 obj.save_by_user(request.user)
615
616 def delete_model(self, request, obj):
617 obj.delete_by_user(request.user)
618
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500619
Tony Mack9bcbe4f2013-04-29 08:13:27 -0400620class SitePrivilegeAdmin(PlanetStackBaseAdmin):
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500621 fieldList = ['user', 'site', 'role']
Tony Mack00d361f2013-04-28 10:28:42 -0400622 fieldsets = [
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500623 (None, {'fields': fieldList, 'classes':['collapse']})
Tony Mack00d361f2013-04-28 10:28:42 -0400624 ]
625 list_display = ('user', 'site', 'role')
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500626 user_readonly_fields = fieldList
627 user_readonly_inlines = []
Tony Mack00d361f2013-04-28 10:28:42 -0400628
Tony Mackc2835a92013-05-28 09:18:49 -0400629 def formfield_for_foreignkey(self, db_field, request, **kwargs):
630 if db_field.name == 'site':
631 if not request.user.is_admin:
632 # only show sites where user is an admin or pi
633 sites = set()
634 for site_privilege in SitePrivilege.objects.filer(user=request.user):
635 if site_privilege.role.role_type in ['admin', 'pi']:
636 sites.add(site_privilege.site)
637 kwargs['queryset'] = Site.objects.filter(site__in=list(sites))
638
639 if db_field.name == 'user':
640 if not request.user.is_admin:
641 # only show users from sites where caller has admin or pi role
642 roles = Role.objects.filter(role_type__in=['admin', 'pi'])
643 site_privileges = SitePrivilege.objects.filter(user=request.user).filter(role__in=roles)
644 sites = [site_privilege.site for site_privilege in site_privileges]
645 site_privileges = SitePrivilege.objects.filter(site__in=sites)
646 emails = [site_privilege.user.email for site_privilege in site_privileges]
647 users = User.objects.filter(email__in=emails)
648 kwargs['queryset'] = users
649
650 return super(SitePrivilegeAdmin, self).formfield_for_foreignkey(db_field, request, **kwargs)
651
Tony Mack04062832013-05-10 08:22:44 -0400652 def queryset(self, request):
653 # admins can see all privileges. Users can only see privileges at sites
Tony Mackc2835a92013-05-28 09:18:49 -0400654 # where they have the admin role or pi role.
Tony Mack04062832013-05-10 08:22:44 -0400655 qs = super(SitePrivilegeAdmin, self).queryset(request)
Tony Mack5b061472014-02-04 07:57:10 -0500656 #if not request.user.is_admin:
657 # roles = Role.objects.filter(role_type__in=['admin', 'pi'])
658 # site_privileges = SitePrivilege.objects.filter(user=request.user).filter(role__in=roles)
659 # login_bases = [site_privilege.site.login_base for site_privilege in site_privileges]
660 # sites = Site.objects.filter(login_base__in=login_bases)
661 # qs = qs.filter(site__in=sites)
Tony Mack04062832013-05-10 08:22:44 -0400662 return qs
663
Siobhan Tullyce652d02013-10-08 21:52:35 -0400664class SliceForm(forms.ModelForm):
665 class Meta:
666 model = Slice
667 widgets = {
668 'service': LinkedSelect
669 }
670
Tony Mack2bd5b412013-06-11 21:05:06 -0400671class SliceAdmin(PlanetStackBaseAdmin):
Siobhan Tullyce652d02013-10-08 21:52:35 -0400672 form = SliceForm
Tony Mack29bf5e82014-04-29 21:40:24 -0400673 fieldList = ['name', 'site', 'serviceClass', 'enabled','description', 'service', 'slice_url', 'max_slivers']
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500674 fieldsets = [('Slice Details', {'fields': fieldList, 'classes':['suit-tab suit-tab-general']}),]
Tony Mack29bf5e82014-04-29 21:40:24 -0400675 list_display = ('name', 'site','serviceClass', 'slice_url', 'max_slivers')
Siobhan Tully2d95e482013-09-06 10:56:06 -0400676 inlines = [SlicePrivilegeInline,SliverInline, TagInline, ReservationInline,SliceNetworkInline]
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400677
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500678 user_readonly_fields = fieldList
679 user_readonly_inlines = [SlicePrivilegeROInline,SliverROInline,TagROInline, ReservationROInline, SliceNetworkROInline]
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400680
681 suit_form_tabs =(('general', 'Slice Details'),
Siobhan Tully2d95e482013-09-06 10:56:06 -0400682 ('slicenetworks','Networks'),
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400683 ('sliceprivileges','Privileges'),
684 ('slivers','Slivers'),
685 ('tags','Tags'),
686 ('reservations','Reservations'),
687 )
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400688
Tony Mackc2835a92013-05-28 09:18:49 -0400689 def formfield_for_foreignkey(self, db_field, request, **kwargs):
690 if db_field.name == 'site':
Tony Mack5b061472014-02-04 07:57:10 -0500691 kwargs['queryset'] = Site.select_by_user(request.user)
692
Tony Mackc2835a92013-05-28 09:18:49 -0400693 return super(SliceAdmin, self).formfield_for_foreignkey(db_field, request, **kwargs)
694
Tony Mack04062832013-05-10 08:22:44 -0400695 def queryset(self, request):
696 # admins can see all keys. Users can only see slices they belong to.
Tony Mack5b061472014-02-04 07:57:10 -0500697 return Slice.select_by_user(request.user)
Tony Mack04062832013-05-10 08:22:44 -0400698
Tony Mack79748612013-05-01 14:52:03 -0400699 def get_formsets(self, request, obj=None):
700 for inline in self.get_inline_instances(request, obj):
701 # hide MyInline in the add view
702 if obj is None:
703 continue
Tony Mack2bd5b412013-06-11 21:05:06 -0400704 if isinstance(inline, SliverInline):
705 inline.model.caller = request.user
Tony Mack79748612013-05-01 14:52:03 -0400706 yield inline.get_formset(request, obj)
707
Tony Mack2bd5b412013-06-11 21:05:06 -0400708
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400709class SlicePrivilegeAdmin(PlanetStackBaseAdmin):
Tony Mack00d361f2013-04-28 10:28:42 -0400710 fieldsets = [
711 (None, {'fields': ['user', 'slice', 'role']})
712 ]
713 list_display = ('user', 'slice', 'role')
Tony Mack00d361f2013-04-28 10:28:42 -0400714
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500715 user_readonly_fields = ['user', 'slice', 'role']
716 user_readonly_inlines = []
717
Tony Mackc2835a92013-05-28 09:18:49 -0400718 def formfield_for_foreignkey(self, db_field, request, **kwargs):
719 if db_field.name == 'slice':
Tony Mack5b061472014-02-04 07:57:10 -0500720 kwargs['queryset'] = Slice.select_by_user(request.user)
Tony Mackc2835a92013-05-28 09:18:49 -0400721
722 if db_field.name == 'user':
Tony Mack5b061472014-02-04 07:57:10 -0500723 kwargs['queryset'] = User.select_by_user(request.user)
Tony Mackc2835a92013-05-28 09:18:49 -0400724
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400725 return super(SlicePrivilegeAdmin, self).formfield_for_foreignkey(db_field, request, **kwargs)
Tony Mackc2835a92013-05-28 09:18:49 -0400726
Tony Mack04062832013-05-10 08:22:44 -0400727 def queryset(self, request):
728 # admins can see all memberships. Users can only see memberships of
729 # slices where they have the admin role.
Tony Mack5b061472014-02-04 07:57:10 -0500730 return SlicePrivilege.select_by_user(request.user)
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400731
Tony Mack9bcbe4f2013-04-29 08:13:27 -0400732 def save_model(self, request, obj, form, change):
Tony Mack951dab42013-05-02 19:51:45 -0400733 # update openstack connection to use this site/tenant
734 auth = request.session.get('auth', {})
735 auth['tenant'] = obj.slice.name
736 obj.os_manager = OpenStackManager(auth=auth, caller=request.user)
Tony Mack9bcbe4f2013-04-29 08:13:27 -0400737 obj.save()
738
739 def delete_model(self, request, obj):
Tony Mack951dab42013-05-02 19:51:45 -0400740 # update openstack connection to use this site/tenant
741 auth = request.session.get('auth', {})
742 auth['tenant'] = obj.slice.name
743 obj.os_manager = OpenStackManager(auth=auth, caller=request.user)
Tony Mack9bcbe4f2013-04-29 08:13:27 -0400744 obj.delete()
745
Siobhan Tully567e3e62013-06-21 18:03:16 -0400746
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400747class ImageAdmin(PlanetStackBaseAdmin):
748
749 fieldsets = [('Image Details',
Scott Baker00b00b32014-05-07 08:47:54 -0700750 {'fields': ['name', 'disk_format', 'container_format'],
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400751 'classes': ['suit-tab suit-tab-general']})
752 ]
753
754 suit_form_tabs =(('general','Image Details'),('slivers','Slivers'))
755
756 inlines = [SliverInline]
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500757
Tony Mack32e1ce32014-05-07 13:29:41 -0400758 user_readonly_fields = ['name', 'disk_format', 'container_format']
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500759 user_readonly_inlines = [SliverROInline]
760
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400761class NodeForm(forms.ModelForm):
762 class Meta:
763 widgets = {
764 'site': LinkedSelect,
765 'deployment': LinkedSelect
766 }
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400767
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500768class NodeAdmin(PlanetStackBaseAdmin):
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400769 form = NodeForm
Siobhan Tullybf1153a2013-05-27 20:53:48 -0400770 list_display = ('name', 'site', 'deployment')
771 list_filter = ('deployment',)
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500772
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400773 inlines = [TagInline,SliverInline]
774 fieldsets = [('Node Details', {'fields': ['name','site','deployment'], 'classes':['suit-tab suit-tab-details']})]
775
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500776 user_readonly_fields = ['name','site','deployment']
777 user_readonly_inlines = [TagInline,SliverInline]
778
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400779 suit_form_tabs =(('details','Node Details'),('slivers','Slivers'),('tags','Tags'))
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400780
Siobhan Tully567e3e62013-06-21 18:03:16 -0400781
Tony Mackd90cdbf2013-04-16 22:48:40 -0400782class SliverForm(forms.ModelForm):
783 class Meta:
Tony Mack1d6b85f2013-05-07 18:49:14 -0400784 model = Sliver
Tony Mackd90cdbf2013-04-16 22:48:40 -0400785 ip = forms.CharField(widget=PlainTextWidget)
Tony Mack18261812013-05-02 16:39:20 -0400786 instance_name = forms.CharField(widget=PlainTextWidget)
Tony Mackd90cdbf2013-04-16 22:48:40 -0400787 widgets = {
788 'ip': PlainTextWidget(),
Tony Mack18261812013-05-02 16:39:20 -0400789 'instance_name': PlainTextWidget(),
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400790 'slice': LinkedSelect,
791 'deploymentNetwork': LinkedSelect,
792 'node': LinkedSelect,
793 'image': LinkedSelect
Siobhan Tully53437282013-04-26 19:30:27 -0400794 }
Tony Mackd90cdbf2013-04-16 22:48:40 -0400795
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500796class TagAdmin(PlanetStackBaseAdmin):
Siobhan Tullyce652d02013-10-08 21:52:35 -0400797 list_display = ['service', 'name', 'value', 'content_type', 'content_object',]
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500798 user_readonly_fields = ['service', 'name', 'value', 'content_type', 'content_object',]
799 user_readonly_inlines = []
Siobhan Tullyd3515752013-06-21 16:34:53 -0400800
Tony Mack9bcbe4f2013-04-29 08:13:27 -0400801class SliverAdmin(PlanetStackBaseAdmin):
Tony Mackd90cdbf2013-04-16 22:48:40 -0400802 form = SliverForm
Tony Mackcdec0902013-04-15 00:38:49 -0400803 fieldsets = [
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400804 ('Sliver Details', {'fields': ['slice', 'deploymentNetwork', 'node', 'ip', 'instance_name', 'numberCores', 'image', ], 'classes': ['suit-tab suit-tab-general'], })
Tony Mackcdec0902013-04-15 00:38:49 -0400805 ]
Siobhan Tully5d7dc8d2013-07-02 13:17:33 -0400806 list_display = ['ip', 'instance_name', 'slice', 'numberCores', 'image', 'node', 'deploymentNetwork']
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400807
808 suit_form_tabs =(('general', 'Sliver Details'),
809 ('tags','Tags'),
810 )
811
Siobhan Tullyde5450d2013-06-21 11:35:33 -0400812 inlines = [TagInline]
Tony Mack53106f32013-04-27 16:43:01 -0400813
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500814 user_readonly_fields = ['slice', 'deploymentNetwork', 'node', 'ip', 'instance_name', 'numberCores', 'image']
815 user_readonly_inlines = [TagROInline]
816
Tony Mackc2835a92013-05-28 09:18:49 -0400817 def formfield_for_foreignkey(self, db_field, request, **kwargs):
818 if db_field.name == 'slice':
Tony Mack5b061472014-02-04 07:57:10 -0500819 kwargs['queryset'] = Slice.select_by_user(request.user)
Tony Mackc2835a92013-05-28 09:18:49 -0400820
821 return super(SliverAdmin, self).formfield_for_foreignkey(db_field, request, **kwargs)
822
Tony Mack04062832013-05-10 08:22:44 -0400823 def queryset(self, request):
824 # admins can see all slivers. Users can only see slivers of
825 # the slices they belong to.
Tony Mack5b061472014-02-04 07:57:10 -0500826 return Sliver.select_by_user(request.user)
827
Tony Mack04062832013-05-10 08:22:44 -0400828
Tony Mack1d6b85f2013-05-07 18:49:14 -0400829 def get_formsets(self, request, obj=None):
830 # make some fields read only if we are updating an existing record
831 if obj == None:
832 #self.readonly_fields = ('ip', 'instance_name')
833 self.readonly_fields = ()
834 else:
Tony Mack1e889462013-05-10 21:34:54 -0400835 self.readonly_fields = ()
836 #self.readonly_fields = ('ip', 'instance_name', 'slice', 'image', 'key')
Tony Mack1d6b85f2013-05-07 18:49:14 -0400837
838 for inline in self.get_inline_instances(request, obj):
839 # hide MyInline in the add view
840 if obj is None:
841 continue
Scott Baker526b71e2014-05-13 13:18:01 -0700842 if isinstance(inline, SliverInline):
843 inline.model.caller = request.user
844 yield inline.get_formset(request, obj)
Tony Mack53106f32013-04-27 16:43:01 -0400845
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500846 #def save_model(self, request, obj, form, change):
847 # # update openstack connection to use this site/tenant
848 # auth = request.session.get('auth', {})
849 # auth['tenant'] = obj.slice.name
850 # obj.os_manager = OpenStackManager(auth=auth, caller=request.user)
851 # obj.creator = request.user
852 # obj.save()
Tony Mack53106f32013-04-27 16:43:01 -0400853
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500854 #def delete_model(self, request, obj):
855 # # update openstack connection to use this site/tenant
856 # auth = request.session.get('auth', {})
857 # auth['tenant'] = obj.slice.name
858 # obj.os_manager = OpenStackManager(auth=auth, caller=request.user)
859 # obj.delete()
Tony Mackcdec0902013-04-15 00:38:49 -0400860
Siobhan Tully53437282013-04-26 19:30:27 -0400861class UserCreationForm(forms.ModelForm):
862 """A form for creating new users. Includes all the required
863 fields, plus a repeated password."""
864 password1 = forms.CharField(label='Password', widget=forms.PasswordInput)
865 password2 = forms.CharField(label='Password confirmation', widget=forms.PasswordInput)
866
867 class Meta:
Siobhan Tully30fd4292013-05-10 08:59:56 -0400868 model = User
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400869 fields = ('email', 'firstname', 'lastname', 'phone', 'public_key')
Siobhan Tully53437282013-04-26 19:30:27 -0400870
871 def clean_password2(self):
872 # Check that the two password entries match
873 password1 = self.cleaned_data.get("password1")
874 password2 = self.cleaned_data.get("password2")
875 if password1 and password2 and password1 != password2:
876 raise forms.ValidationError("Passwords don't match")
877 return password2
878
879 def save(self, commit=True):
880 # Save the provided password in hashed format
881 user = super(UserCreationForm, self).save(commit=False)
Tony Mackf9f4afb2013-05-01 21:02:12 -0400882 user.password = self.cleaned_data["password1"]
883 #user.set_password(self.cleaned_data["password1"])
Siobhan Tully53437282013-04-26 19:30:27 -0400884 if commit:
885 user.save()
886 return user
887
Siobhan Tully567e3e62013-06-21 18:03:16 -0400888
Siobhan Tully53437282013-04-26 19:30:27 -0400889class UserChangeForm(forms.ModelForm):
890 """A form for updating users. Includes all the fields on
891 the user, but replaces the password field with admin's
892 password hash display field.
893 """
Siobhan Tully63b7ba42014-01-12 10:35:11 -0500894 password = ReadOnlyPasswordHashField(label='Password',
895 help_text= '<a href=\"password/\">Change Password</a>.')
Siobhan Tully53437282013-04-26 19:30:27 -0400896
897 class Meta:
Siobhan Tully30fd4292013-05-10 08:59:56 -0400898 model = User
Siobhan Tully53437282013-04-26 19:30:27 -0400899
900 def clean_password(self):
901 # Regardless of what the user provides, return the initial value.
902 # This is done here, rather than on the field, because the
903 # field does not have access to the initial value
904 return self.initial["password"]
905
Scott Baker2c3cb642014-05-19 17:55:56 -0700906class UserDashboardViewInline(PlStackTabularInline):
907 model = UserDashboardView
908 extra = 0
909 suit_classes = 'suit-tab suit-tab-dashboards'
910 fields = ['user', 'dashboardView', 'order']
911
Scott Bakered31f672014-05-21 18:14:03 -0700912class UserDashboardViewROInline(ReadOnlyTabularInline):
913 model = UserDashboardView
914 extra = 0
915 suit_classes = 'suit-tab suit-tab-dashboards'
916 fields = ['user', 'dashboardView', 'order']
917
Tony Mack2bd5b412013-06-11 21:05:06 -0400918class UserAdmin(UserAdmin):
Siobhan Tully53437282013-04-26 19:30:27 -0400919 class Meta:
920 app_label = "core"
921
922 # The forms to add and change user instances
923 form = UserChangeForm
924 add_form = UserCreationForm
925
926 # The fields to be used in displaying the User model.
927 # These override the definitions on the base UserAdmin
928 # that reference specific fields on auth.User.
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500929 list_display = ('email', 'firstname', 'lastname', 'site', 'last_login')
Siobhan Tullyce652d02013-10-08 21:52:35 -0400930 #list_display = ('email', 'username','firstname', 'lastname', 'is_admin', 'last_login')
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500931 list_filter = ('site',)
Scott Baker2c3cb642014-05-19 17:55:56 -0700932 inlines = [SlicePrivilegeInline,SitePrivilegeInline,DeploymentPrivilegeInline,UserDashboardViewInline]
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500933
934 fieldListLoginDetails = ['email','site','password','is_readonly','is_amin','public_key']
935 fieldListContactInfo = ['firstname','lastname','phone','timezone']
936
Siobhan Tully53437282013-04-26 19:30:27 -0400937 fieldsets = (
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500938 ('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 -0400939 ('Contact Information', {'fields': ('firstname','lastname','phone', 'timezone'), 'classes':['suit-tab suit-tab-contact']}),
Scott Baker2c3cb642014-05-19 17:55:56 -0700940 #('Dashboard Views', {'fields': ('dashboards',), 'classes':['suit-tab suit-tab-dashboards']}),
Siobhan Tully53437282013-04-26 19:30:27 -0400941 #('Important dates', {'fields': ('last_login',)}),
942 )
943 add_fieldsets = (
944 (None, {
945 'classes': ('wide',),
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500946 'fields': ('email', 'firstname', 'lastname', 'is_readonly', 'phone', 'public_key','password1', 'password2')}
Siobhan Tully53437282013-04-26 19:30:27 -0400947 ),
948 )
949 search_fields = ('email',)
950 ordering = ('email',)
951 filter_horizontal = ()
952
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500953 user_readonly_fields = fieldListLoginDetails
Scott Bakered31f672014-05-21 18:14:03 -0700954 user_readonly_inlines = [SlicePrivilegeROInline,SitePrivilegeROInline,DeploymentPrivilegeROInline,UserDashboardViewROInline]
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500955
Scott Baker2c3cb642014-05-19 17:55:56 -0700956 suit_form_tabs =(('general','Login Details'),
957 ('contact','Contact Information'),
958 ('sliceprivileges','Slice Privileges'),
959 ('siteprivileges','Site Privileges'),
960 ('deploymentprivileges','Deployment Privileges'),
961 ('dashboards','Dashboard Views'))
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400962
Tony Mackc2835a92013-05-28 09:18:49 -0400963 def formfield_for_foreignkey(self, db_field, request, **kwargs):
964 if db_field.name == 'site':
Tony Mack5b061472014-02-04 07:57:10 -0500965 kwargs['queryset'] = Site.select_by_user(request.user)
Tony Mackc2835a92013-05-28 09:18:49 -0400966
967 return super(UserAdmin, self).formfield_for_foreignkey(db_field, request, **kwargs)
968
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500969 def has_add_permission(self, request, obj=None):
970 return (not self.__user_is_readonly(request))
971
972 def has_delete_permission(self, request, obj=None):
973 return (not self.__user_is_readonly(request))
974
975 def get_actions(self,request):
976 actions = super(UserAdmin,self).get_actions(request)
977
978 if self.__user_is_readonly(request):
979 if 'delete_selected' in actions:
980 del actions['delete_selected']
981
982 return actions
983
984 def change_view(self,request,object_id, extra_context=None):
985
986 if self.__user_is_readonly(request):
987 self.readonly_fields=self.user_readonly_fields
988 self.inlines = self.user_readonly_inlines
989 try:
990 return super(UserAdmin, self).change_view(request, object_id, extra_context=extra_context)
991 except PermissionDenied:
992 pass
993 if request.method == 'POST':
994 raise PermissionDenied
995 request.readonly = True
996 return super(UserAdmin, self).change_view(request, object_id, extra_context=extra_context)
997
998 def __user_is_readonly(self, request):
999 #groups = [x.name for x in request.user.groups.all() ]
1000 #return "readonly" in groups
1001 return request.user.isReadOnlyUser()
1002
Tony Mack5b061472014-02-04 07:57:10 -05001003 def queryset(self, request):
1004 return User.select_by_user(request.user)
1005
Scott Baker2c3cb642014-05-19 17:55:56 -07001006class DashboardViewAdmin(PlanetStackBaseAdmin):
1007 fieldsets = [('Dashboard View Details',
1008 {'fields': ['name', 'url'],
1009 'classes': ['suit-tab suit-tab-general']})
1010 ]
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001011
Scott Baker2c3cb642014-05-19 17:55:56 -07001012 suit_form_tabs =(('general','Dashboard View Details'),)
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001013
1014class ServiceResourceROInline(ReadOnlyTabularInline):
1015 model = ServiceResource
1016 extra = 0
1017 fields = ['serviceClass', 'name', 'maxUnitsDeployment', 'maxUnitsNode', 'maxDuration', 'bucketInRate', 'bucketMaxSize', 'cost', 'calendarReservable']
1018
Scott Baker0165fac2014-01-13 11:49:26 -08001019class ServiceResourceInline(PlStackTabularInline):
Scott Baker3de3e372013-05-10 16:50:44 -07001020 model = ServiceResource
1021 extra = 0
1022
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001023class ServiceClassAdmin(PlanetStackBaseAdmin):
Scott Baker3de3e372013-05-10 16:50:44 -07001024 list_display = ('name', 'commitment', 'membershipFee')
1025 inlines = [ServiceResourceInline]
1026
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001027 user_readonly_fields = ['name', 'commitment', 'membershipFee']
1028 user_readonly_inlines = []
1029
1030class ReservedResourceROInline(ReadOnlyTabularInline):
1031 model = ReservedResource
1032 extra = 0
1033 fields = ['sliver', 'resource','quantity','reservationSet']
1034 suit_classes = 'suit-tab suit-tab-reservedresources'
1035
Scott Baker0165fac2014-01-13 11:49:26 -08001036class ReservedResourceInline(PlStackTabularInline):
Scott Baker133c9212013-05-17 09:09:11 -07001037 model = ReservedResource
1038 extra = 0
Siobhan Tullybfd11dc2013-09-03 12:59:24 -04001039 suit_classes = 'suit-tab suit-tab-reservedresources'
Scott Baker133c9212013-05-17 09:09:11 -07001040
1041 def formfield_for_foreignkey(self, db_field, request=None, **kwargs):
1042 field = super(ReservedResourceInline, self).formfield_for_foreignkey(db_field, request, **kwargs)
1043
1044 if db_field.name == 'resource':
1045 # restrict resources to those that the slice's service class allows
1046 if request._slice is not None:
1047 field.queryset = field.queryset.filter(serviceClass = request._slice.serviceClass, calendarReservable=True)
1048 if len(field.queryset) > 0:
1049 field.initial = field.queryset.all()[0]
1050 else:
1051 field.queryset = field.queryset.none()
1052 elif db_field.name == 'sliver':
1053 # restrict slivers to those that belong to the slice
1054 if request._slice is not None:
1055 field.queryset = field.queryset.filter(slice = request._slice)
1056 else:
1057 field.queryset = field.queryset.none()
1058
1059 return field
1060
Tony Mack5b061472014-02-04 07:57:10 -05001061 def queryset(self, request):
1062 return ReservedResource.select_by_user(request.user)
1063
Scott Baker133c9212013-05-17 09:09:11 -07001064class ReservationChangeForm(forms.ModelForm):
1065 class Meta:
1066 model = Reservation
Siobhan Tullybfd11dc2013-09-03 12:59:24 -04001067 widgets = {
1068 'slice' : LinkedSelect
1069 }
Scott Baker133c9212013-05-17 09:09:11 -07001070
1071class ReservationAddForm(forms.ModelForm):
1072 slice = forms.ModelChoiceField(queryset=Slice.objects.all(), widget=forms.Select(attrs={"onChange":"document.getElementById('id_refresh').value=1; submit()"}))
1073 refresh = forms.CharField(widget=forms.HiddenInput())
1074
1075 class Media:
1076 css = {'all': ('planetstack.css',)} # .field-refresh { display: none; }
1077
1078 def clean_slice(self):
1079 slice = self.cleaned_data.get("slice")
1080 x = ServiceResource.objects.filter(serviceClass = slice.serviceClass, calendarReservable=True)
1081 if len(x) == 0:
1082 raise forms.ValidationError("The slice you selected does not have a service class that allows reservations")
1083 return slice
1084
1085 class Meta:
1086 model = Reservation
Siobhan Tullybfd11dc2013-09-03 12:59:24 -04001087 widgets = {
1088 'slice' : LinkedSelect
1089 }
1090
Scott Baker133c9212013-05-17 09:09:11 -07001091
1092class ReservationAddRefreshForm(ReservationAddForm):
1093 """ This form is displayed when the Reservation Form receives an update
1094 from the Slice dropdown onChange handler. It doesn't validate the
1095 data and doesn't save the data. This will cause the form to be
1096 redrawn.
1097 """
1098
Scott Baker8737e5f2013-05-17 09:35:32 -07001099 """ don't validate anything other than slice """
1100 dont_validate_fields = ("startTime", "duration")
1101
Scott Baker133c9212013-05-17 09:09:11 -07001102 def full_clean(self):
1103 result = super(ReservationAddForm, self).full_clean()
Scott Baker8737e5f2013-05-17 09:35:32 -07001104
1105 for fieldname in self.dont_validate_fields:
1106 if fieldname in self._errors:
1107 del self._errors[fieldname]
1108
Scott Baker133c9212013-05-17 09:09:11 -07001109 return result
1110
1111 """ don't save anything """
1112 def is_valid(self):
1113 return False
1114
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001115class ReservationAdmin(PlanetStackBaseAdmin):
1116 fieldList = ['slice', 'startTime', 'duration']
1117 fieldsets = [('Reservation Details', {'fields': fieldList, 'classes': ['suit-tab suit-tab-general']})]
Scott Baker133c9212013-05-17 09:09:11 -07001118 list_display = ('startTime', 'duration')
Scott Baker133c9212013-05-17 09:09:11 -07001119 form = ReservationAddForm
1120
Siobhan Tullybfd11dc2013-09-03 12:59:24 -04001121 suit_form_tabs = (('general','Reservation Details'), ('reservedresources','Reserved Resources'))
1122
1123 inlines = [ReservedResourceInline]
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001124 user_readonly_inlines = [ReservedResourceROInline]
1125 user_readonly_fields = fieldList
Siobhan Tullybfd11dc2013-09-03 12:59:24 -04001126
Scott Baker133c9212013-05-17 09:09:11 -07001127 def add_view(self, request, form_url='', extra_context=None):
Scott Bakeracd45142013-05-19 16:19:16 -07001128 timezone.activate(request.user.timezone)
Scott Baker133c9212013-05-17 09:09:11 -07001129 request._refresh = False
1130 request._slice = None
1131 if request.method == 'POST':
Scott Baker8737e5f2013-05-17 09:35:32 -07001132 # "refresh" will be set to "1" if the form was submitted due to
1133 # a change in the Slice dropdown.
Scott Baker133c9212013-05-17 09:09:11 -07001134 if request.POST.get("refresh","1") == "1":
1135 request._refresh = True
1136 request.POST["refresh"] = "0"
Scott Baker8737e5f2013-05-17 09:35:32 -07001137
1138 # Keep track of the slice that was selected, so the
1139 # reservedResource inline can filter items for the slice.
Scott Baker133c9212013-05-17 09:09:11 -07001140 request._slice = request.POST.get("slice",None)
1141 if (request._slice is not None):
1142 request._slice = Slice.objects.get(id=request._slice)
1143
1144 result = super(ReservationAdmin, self).add_view(request, form_url, extra_context)
1145 return result
1146
Scott Bakeracd45142013-05-19 16:19:16 -07001147 def changelist_view(self, request, extra_context = None):
1148 timezone.activate(request.user.timezone)
1149 return super(ReservationAdmin, self).changelist_view(request, extra_context)
1150
Scott Baker133c9212013-05-17 09:09:11 -07001151 def get_form(self, request, obj=None, **kwargs):
Siobhan Tullyd3515752013-06-21 16:34:53 -04001152 request._obj_ = obj
1153 if obj is not None:
1154 # For changes, set request._slice to the slice already set in the
1155 # object.
1156 request._slice = obj.slice
1157 self.form = ReservationChangeForm
1158 else:
1159 if getattr(request, "_refresh", False):
1160 self.form = ReservationAddRefreshForm
1161 else:
1162 self.form = ReservationAddForm
1163 return super(ReservationAdmin, self).get_form(request, obj, **kwargs)
1164
Scott Baker133c9212013-05-17 09:09:11 -07001165 def get_readonly_fields(self, request, obj=None):
Siobhan Tullyd3515752013-06-21 16:34:53 -04001166 if (obj is not None):
1167 # Prevent slice from being changed after the reservation has been
1168 # created.
1169 return ['slice']
1170 else:
Scott Baker133c9212013-05-17 09:09:11 -07001171 return []
Scott Baker3de3e372013-05-10 16:50:44 -07001172
Tony Mack5b061472014-02-04 07:57:10 -05001173 def queryset(self, request):
1174 return Reservation.select_by_user(request.user)
1175
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001176class NetworkParameterTypeAdmin(PlanetStackBaseAdmin):
Scott Baker74d8e622013-07-29 16:04:22 -07001177 list_display = ("name", )
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001178 user_readonly_fields = ['name']
1179 user_readonly_inlines = []
Scott Baker74d8e622013-07-29 16:04:22 -07001180
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001181class RouterAdmin(PlanetStackBaseAdmin):
Scott Baker74d8e622013-07-29 16:04:22 -07001182 list_display = ("name", )
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001183 user_readonly_fields = ['name']
1184 user_readonly_inlines = []
1185
1186class RouterROInline(ReadOnlyTabularInline):
1187 model = Router.networks.through
1188 extra = 0
1189 verbose_name_plural = "Routers"
1190 verbose_name = "Router"
1191 suit_classes = 'suit-tab suit-tab-routers'
1192
1193 fields = ['name', 'owner', 'permittedNetworks', 'networks']
Scott Baker74d8e622013-07-29 16:04:22 -07001194
Scott Baker0165fac2014-01-13 11:49:26 -08001195class RouterInline(PlStackTabularInline):
Scott Baker74d8e622013-07-29 16:04:22 -07001196 model = Router.networks.through
1197 extra = 0
1198 verbose_name_plural = "Routers"
1199 verbose_name = "Router"
Siobhan Tully2d95e482013-09-06 10:56:06 -04001200 suit_classes = 'suit-tab suit-tab-routers'
Scott Baker74d8e622013-07-29 16:04:22 -07001201
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001202class NetworkParameterROInline(ReadOnlyTabularInline):
1203 model = NetworkParameter
1204 extra = 1
1205 verbose_name_plural = "Parameters"
1206 verbose_name = "Parameter"
1207 suit_classes = 'suit-tab suit-tab-netparams'
1208 fields = ['parameter', 'value', 'content_type', 'object_id', 'content_object']
1209
Scott Baker74d8e622013-07-29 16:04:22 -07001210class NetworkParameterInline(generic.GenericTabularInline):
Scott Baker74d8e622013-07-29 16:04:22 -07001211 model = NetworkParameter
1212 extra = 1
1213 verbose_name_plural = "Parameters"
1214 verbose_name = "Parameter"
Siobhan Tully2d95e482013-09-06 10:56:06 -04001215 suit_classes = 'suit-tab suit-tab-netparams'
Scott Baker74d8e622013-07-29 16:04:22 -07001216
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001217class NetworkSliversROInline(ReadOnlyTabularInline):
1218 fields = ['network', 'sliver', 'ip', 'port_id']
1219 model = NetworkSliver
1220 extra = 0
1221 verbose_name_plural = "Slivers"
1222 verbose_name = "Sliver"
1223 suit_classes = 'suit-tab suit-tab-networkslivers'
1224
Scott Baker0165fac2014-01-13 11:49:26 -08001225class NetworkSliversInline(PlStackTabularInline):
Scott Baker74d8e622013-07-29 16:04:22 -07001226 readonly_fields = ("ip", )
1227 model = NetworkSliver
Scott Baker874936e2014-01-13 18:15:34 -08001228 selflink_fieldname = "sliver"
Scott Baker74d8e622013-07-29 16:04:22 -07001229 extra = 0
1230 verbose_name_plural = "Slivers"
1231 verbose_name = "Sliver"
Siobhan Tully2d95e482013-09-06 10:56:06 -04001232 suit_classes = 'suit-tab suit-tab-networkslivers'
Scott Baker74d8e622013-07-29 16:04:22 -07001233
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001234class NetworkSlicesROInline(ReadOnlyTabularInline):
1235 model = NetworkSlice
1236 extra = 0
1237 verbose_name_plural = "Slices"
1238 verbose_name = "Slice"
1239 suit_classes = 'suit-tab suit-tab-networkslices'
1240 fields = ['network','slice']
1241
Scott Baker0165fac2014-01-13 11:49:26 -08001242class NetworkSlicesInline(PlStackTabularInline):
Scott Bakerd7d2a392013-08-06 08:57:30 -07001243 model = NetworkSlice
Scott Baker874936e2014-01-13 18:15:34 -08001244 selflink_fieldname = "slice"
Scott Bakerd7d2a392013-08-06 08:57:30 -07001245 extra = 0
1246 verbose_name_plural = "Slices"
1247 verbose_name = "Slice"
Siobhan Tully2d95e482013-09-06 10:56:06 -04001248 suit_classes = 'suit-tab suit-tab-networkslices'
Scott Bakerd7d2a392013-08-06 08:57:30 -07001249
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001250class NetworkAdmin(PlanetStackBaseAdmin):
Scott Baker74d8e622013-07-29 16:04:22 -07001251 list_display = ("name", "subnet", "ports", "labels")
1252 readonly_fields = ("subnet", )
Siobhan Tully2d95e482013-09-06 10:56:06 -04001253
Scott Bakerd7d2a392013-08-06 08:57:30 -07001254 inlines = [NetworkParameterInline, NetworkSliversInline, NetworkSlicesInline, RouterInline]
Scott Baker74d8e622013-07-29 16:04:22 -07001255
Siobhan Tully2d95e482013-09-06 10:56:06 -04001256 fieldsets = [
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001257 (None, {'fields': ['name','template','ports','labels','owner','guaranteedBandwidth', 'permitAllSlices','permittedSlices','network_id','router_id','subnet_id','subnet'], 'classes':['suit-tab suit-tab-general']}),]
1258
1259 user_readonly_fields = ['name','template','ports','labels','owner','guaranteedBandwidth', 'permitAllSlices','permittedSlices','network_id','router_id','subnet_id','subnet']
1260 user_readonly_inlines = [NetworkParameterROInline, NetworkSliversROInline, NetworkSlicesROInline, RouterROInline]
Siobhan Tully2d95e482013-09-06 10:56:06 -04001261
1262 suit_form_tabs =(
1263 ('general','Network Details'),
1264 ('netparams', 'Parameters'),
1265 ('networkslivers','Slivers'),
1266 ('networkslices','Slices'),
1267 ('routers','Routers'),
1268 )
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001269class NetworkTemplateAdmin(PlanetStackBaseAdmin):
Scott Baker74d8e622013-07-29 16:04:22 -07001270 list_display = ("name", "guaranteedBandwidth", "visibility")
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001271 user_readonly_fields = ["name", "guaranteedBandwidth", "visibility"]
1272 user_readonly_inlines = []
Scott Baker74d8e622013-07-29 16:04:22 -07001273
Tony Mack31c2b8f2013-04-26 20:01:42 -04001274# register a signal that caches the user's credentials when they log in
1275def cache_credentials(sender, user, request, **kwds):
1276 auth = {'username': request.POST['username'],
1277 'password': request.POST['password']}
1278 request.session['auth'] = auth
1279user_logged_in.connect(cache_credentials)
1280
Scott Baker15cddfa2013-12-09 13:45:19 -08001281def dollar_field(fieldName, short_description):
1282 def newFunc(self, obj):
1283 try:
1284 x= "$ %0.2f" % float(getattr(obj, fieldName, 0.0))
1285 except:
1286 x=getattr(obj, fieldName, 0.0)
1287 return x
1288 newFunc.short_description = short_description
1289 return newFunc
1290
1291def right_dollar_field(fieldName, short_description):
1292 def newFunc(self, obj):
1293 try:
1294 #x= '<div align=right style="width:6em">$ %0.2f</div>' % float(getattr(obj, fieldName, 0.0))
1295 x= '<div align=right>$ %0.2f</div>' % float(getattr(obj, fieldName, 0.0))
1296 except:
1297 x=getattr(obj, fieldName, 0.0)
1298 return x
1299 newFunc.short_description = short_description
1300 newFunc.allow_tags = True
1301 return newFunc
Scott Baker43105042013-12-06 23:23:36 -08001302
Scott Baker0165fac2014-01-13 11:49:26 -08001303class InvoiceChargeInline(PlStackTabularInline):
Scott Baker43105042013-12-06 23:23:36 -08001304 model = Charge
Scott Baker15cddfa2013-12-09 13:45:19 -08001305 extra = 0
Scott Baker43105042013-12-06 23:23:36 -08001306 verbose_name_plural = "Charges"
1307 verbose_name = "Charge"
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001308 exclude = ['account']
Scott Baker9cb88a22013-12-09 18:56:00 -08001309 fields = ["date", "kind", "state", "object", "coreHours", "dollar_amount", "slice"]
1310 readonly_fields = ["date", "kind", "state", "object", "coreHours", "dollar_amount", "slice"]
1311 can_delete = False
1312 max_num = 0
1313
1314 dollar_amount = right_dollar_field("amount", "Amount")
Scott Baker43105042013-12-06 23:23:36 -08001315
1316class InvoiceAdmin(admin.ModelAdmin):
1317 list_display = ("date", "account")
1318
1319 inlines = [InvoiceChargeInline]
1320
Scott Baker9cb88a22013-12-09 18:56:00 -08001321 fields = ["date", "account", "dollar_amount"]
1322 readonly_fields = ["date", "account", "dollar_amount"]
1323
1324 dollar_amount = dollar_field("amount", "Amount")
Scott Baker43105042013-12-06 23:23:36 -08001325
Scott Baker0165fac2014-01-13 11:49:26 -08001326class InvoiceInline(PlStackTabularInline):
Scott Baker15cddfa2013-12-09 13:45:19 -08001327 model = Invoice
1328 extra = 0
1329 verbose_name_plural = "Invoices"
1330 verbose_name = "Invoice"
Scott Baker0165fac2014-01-13 11:49:26 -08001331 fields = ["date", "dollar_amount"]
1332 readonly_fields = ["date", "dollar_amount"]
Scott Baker15cddfa2013-12-09 13:45:19 -08001333 suit_classes = 'suit-tab suit-tab-accountinvoice'
1334 can_delete=False
1335 max_num=0
1336
1337 dollar_amount = right_dollar_field("amount", "Amount")
1338
Scott Baker0165fac2014-01-13 11:49:26 -08001339class PendingChargeInline(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 = ["invoice"]
Scott Baker15cddfa2013-12-09 13:45:19 -08001345 fields = ["date", "kind", "state", "object", "coreHours", "dollar_amount", "slice"]
1346 readonly_fields = ["date", "kind", "state", "object", "coreHours", "dollar_amount", "slice"]
Scott Baker43105042013-12-06 23:23:36 -08001347 suit_classes = 'suit-tab suit-tab-accountpendingcharges'
Scott Baker15cddfa2013-12-09 13:45:19 -08001348 can_delete=False
1349 max_num=0
Scott Baker43105042013-12-06 23:23:36 -08001350
1351 def queryset(self, request):
1352 qs = super(PendingChargeInline, self).queryset(request)
1353 qs = qs.filter(state="pending")
1354 return qs
1355
Scott Baker15cddfa2013-12-09 13:45:19 -08001356 dollar_amount = right_dollar_field("amount", "Amount")
1357
Scott Baker0165fac2014-01-13 11:49:26 -08001358class PaymentInline(PlStackTabularInline):
Scott Baker43105042013-12-06 23:23:36 -08001359 model=Payment
1360 extra = 1
1361 verbose_name_plural = "Payments"
1362 verbose_name = "Payment"
Scott Baker15cddfa2013-12-09 13:45:19 -08001363 fields = ["date", "dollar_amount"]
1364 readonly_fields = ["date", "dollar_amount"]
Scott Baker43105042013-12-06 23:23:36 -08001365 suit_classes = 'suit-tab suit-tab-accountpayments'
Scott Baker15cddfa2013-12-09 13:45:19 -08001366 can_delete=False
1367 max_num=0
1368
1369 dollar_amount = right_dollar_field("amount", "Amount")
1370
Scott Baker43105042013-12-06 23:23:36 -08001371class AccountAdmin(admin.ModelAdmin):
1372 list_display = ("site", "balance_due")
1373
1374 inlines = [InvoiceInline, PaymentInline, PendingChargeInline]
1375
1376 fieldsets = [
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001377 (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 -08001378
Scott Baker15cddfa2013-12-09 13:45:19 -08001379 readonly_fields = ['site', 'dollar_balance_due', 'dollar_total_invoices', 'dollar_total_payments']
Scott Baker43105042013-12-06 23:23:36 -08001380
1381 suit_form_tabs =(
1382 ('general','Account Details'),
1383 ('accountinvoice', 'Invoices'),
1384 ('accountpayments', 'Payments'),
1385 ('accountpendingcharges','Pending Charges'),
1386 )
1387
Scott Baker15cddfa2013-12-09 13:45:19 -08001388 dollar_balance_due = dollar_field("balance_due", "Balance Due")
1389 dollar_total_invoices = dollar_field("total_invoices", "Total Invoices")
1390 dollar_total_payments = dollar_field("total_payments", "Total Payments")
1391
Siobhan Tullyce652d02013-10-08 21:52:35 -04001392
Siobhan Tully53437282013-04-26 19:30:27 -04001393# Now register the new UserAdmin...
Siobhan Tully30fd4292013-05-10 08:59:56 -04001394admin.site.register(User, UserAdmin)
Siobhan Tully53437282013-04-26 19:30:27 -04001395# ... and, since we're not using Django's builtin permissions,
1396# unregister the Group model from admin.
Siobhan Tullyce652d02013-10-08 21:52:35 -04001397#admin.site.unregister(Group)
Siobhan Tully53437282013-04-26 19:30:27 -04001398
Siobhan Tullybf1153a2013-05-27 20:53:48 -04001399#Do not show django evolution in the admin interface
1400from django_evolution.models import Version, Evolution
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001401#admin.site.unregister(Version)
1402#admin.site.unregister(Evolution)
Siobhan Tullybf1153a2013-05-27 20:53:48 -04001403
1404
1405# When debugging it is often easier to see all the classes, but for regular use
1406# only the top-levels should be displayed
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001407showAll = False
Scott Baker43105042013-12-06 23:23:36 -08001408
Siobhan Tullybf1153a2013-05-27 20:53:48 -04001409admin.site.register(Deployment, DeploymentAdmin)
Siobhan Tully4bc09f22013-04-10 21:15:21 -04001410admin.site.register(Site, SiteAdmin)
Siobhan Tully4bc09f22013-04-10 21:15:21 -04001411admin.site.register(Slice, SliceAdmin)
Siobhan Tullyce652d02013-10-08 21:52:35 -04001412admin.site.register(Service, ServiceAdmin)
smbakera3cf70c2013-06-27 02:01:41 -07001413admin.site.register(Reservation, ReservationAdmin)
Scott Baker74d8e622013-07-29 16:04:22 -07001414admin.site.register(Network, NetworkAdmin)
1415admin.site.register(Router, RouterAdmin)
Scott Baker74d8e622013-07-29 16:04:22 -07001416admin.site.register(NetworkTemplate, NetworkTemplateAdmin)
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001417admin.site.register(Account, AccountAdmin)
1418admin.site.register(Invoice, InvoiceAdmin)
Siobhan Tullybf1153a2013-05-27 20:53:48 -04001419
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001420if True:
1421 admin.site.register(NetworkParameterType, NetworkParameterTypeAdmin)
1422 admin.site.register(ServiceClass, ServiceClassAdmin)
Siobhan Tullybfd11dc2013-09-03 12:59:24 -04001423 #admin.site.register(PlanetStack)
Siobhan Tullyd3515752013-06-21 16:34:53 -04001424 admin.site.register(Tag, TagAdmin)
Siobhan Tullyce652d02013-10-08 21:52:35 -04001425 admin.site.register(DeploymentRole)
1426 admin.site.register(SiteRole)
1427 admin.site.register(SliceRole)
1428 admin.site.register(PlanetStackRole)
Siobhan Tullybf1153a2013-05-27 20:53:48 -04001429 admin.site.register(Node, NodeAdmin)
Siobhan Tullybfd11dc2013-09-03 12:59:24 -04001430 #admin.site.register(SlicePrivilege, SlicePrivilegeAdmin)
1431 #admin.site.register(SitePrivilege, SitePrivilegeAdmin)
Siobhan Tullybf1153a2013-05-27 20:53:48 -04001432 admin.site.register(Sliver, SliverAdmin)
Siobhan Tullybf1153a2013-05-27 20:53:48 -04001433 admin.site.register(Image, ImageAdmin)
Scott Baker2c3cb642014-05-19 17:55:56 -07001434 admin.site.register(DashboardView, DashboardViewAdmin)
Tony Mack7130ac32013-03-22 21:58:00 -04001435