blob: 6a8341bfd5b2b2f5dfae8edbf933c9d19ad12ff8 [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
68
69 def __user_is_readonly(self, request):
70 return request.user.isReadOnlyUser()
71
Siobhan Tullyce652d02013-10-08 21:52:35 -040072class SingletonAdmin (admin.ModelAdmin):
73 def has_add_permission(self, request):
74 num_objects = self.model.objects.count()
75 if num_objects >= 1:
76 return False
77 else:
78 return True
79
80
Siobhan Tullyd3515752013-06-21 16:34:53 -040081class PlStackTabularInline(admin.TabularInline):
Scott Baker86568322014-01-12 16:53:31 -080082 def __init__(self, *args, **kwargs):
83 super(PlStackTabularInline, self).__init__(*args, **kwargs)
84
85 # InlineModelAdmin as no get_fields() method, so in order to add
86 # the selflink field, we override __init__ to modify self.fields and
87 # self.readonly_fields.
88
Scott Bakere2bbf7e2014-01-13 12:09:31 -080089 self.setup_selflink()
90
Scott Baker874936e2014-01-13 18:15:34 -080091 def get_change_url(self, model, id):
92 """ Get the URL to a change form in the admin for this model """
93 reverse_path = "admin:%s_change" % (model._meta.db_table)
Scott Bakere2bbf7e2014-01-13 12:09:31 -080094 try:
Scott Baker874936e2014-01-13 18:15:34 -080095 url = reverse(reverse_path, args=(id,))
Scott Bakere2bbf7e2014-01-13 12:09:31 -080096 except NoReverseMatch:
Scott Baker874936e2014-01-13 18:15:34 -080097 return None
98
99 return url
100
101 def setup_selflink(self):
102 if hasattr(self, "selflink_fieldname"):
103 """ self.selflink_model can be defined to punch through a relation
104 to its target object. For example, in SliceNetworkInline, set
105 selflink_model = "network", and the URL will lead to the Network
106 object instead of trying to bring up a change view of the
107 SliceNetwork object.
108 """
109 self.selflink_model = getattr(self.model,self.selflink_fieldname).field.rel.to
110 else:
111 self.selflink_model = self.model
112
113 url = self.get_change_url(self.selflink_model, 0)
114
115 # We don't have an admin for this object, so don't create the
116 # selflink.
117 if (url == None):
Scott Bakere2bbf7e2014-01-13 12:09:31 -0800118 return
119
Scott Baker874936e2014-01-13 18:15:34 -0800120 # Since we need to add "selflink" to the field list, we need to create
121 # self.fields if it is None.
Scott Baker0165fac2014-01-13 11:49:26 -0800122 if (self.fields is None):
123 self.fields = []
124 for f in self.model._meta.fields:
125 if f.editable and f.name != "id":
126 self.fields.append(f.name)
Scott Baker86568322014-01-12 16:53:31 -0800127
Scott Baker874936e2014-01-13 18:15:34 -0800128 self.fields = tuple(self.fields) + ("selflink", )
Scott Baker86568322014-01-12 16:53:31 -0800129
Scott Baker874936e2014-01-13 18:15:34 -0800130 if self.readonly_fields is None:
131 self.readonly_fields = ()
Scott Baker86568322014-01-12 16:53:31 -0800132
Scott Baker874936e2014-01-13 18:15:34 -0800133 self.readonly_fields = tuple(self.readonly_fields) + ("selflink", )
Scott Baker86568322014-01-12 16:53:31 -0800134
135 def selflink(self, obj):
Scott Baker874936e2014-01-13 18:15:34 -0800136 if hasattr(self, "selflink_fieldname"):
137 obj = getattr(obj, self.selflink_fieldname)
138
Scott Baker86568322014-01-12 16:53:31 -0800139 if obj.id:
Scott Baker874936e2014-01-13 18:15:34 -0800140 url = self.get_change_url(self.selflink_model, obj.id)
141 return "<a href='%s'>Details</a>" % str(url)
Scott Baker86568322014-01-12 16:53:31 -0800142 else:
Scott Bakere2bbf7e2014-01-13 12:09:31 -0800143 return "Not present"
Scott Baker86568322014-01-12 16:53:31 -0800144
145 selflink.allow_tags = True
146 selflink.short_description = "Details"
Siobhan Tullyd3515752013-06-21 16:34:53 -0400147
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500148class ReadOnlyTabularInline(PlStackTabularInline):
149 can_delete = False
150
151 def get_readonly_fields(self, request, obj=None):
152 return self.fields
153
154 def has_add_permission(self, request):
155 return False
156
157class ReservationROInline(ReadOnlyTabularInline):
158 model = Reservation
159 extra = 0
160 suit_classes = 'suit-tab suit-tab-reservations'
161 fields = ['startTime','slice','duration']
162
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400163class ReservationInline(PlStackTabularInline):
164 model = Reservation
165 extra = 0
166 suit_classes = 'suit-tab suit-tab-reservations'
Tony Mack5b061472014-02-04 07:57:10 -0500167
168 def queryset(self, request):
169 return Reservation.select_by_user(request.user)
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400170
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500171class TagROInline(generic.GenericTabularInline):
172 model = Tag
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400173 extra = 0
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500174 suit_classes = 'suit-tab suit-tab-tags'
175 can_delete = False
176 fields = ['service', 'name', 'value']
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400177
178 def get_readonly_fields(self, request, obj=None):
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500179 return self.fields
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400180
181 def has_add_permission(self, request):
182 return False
183
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500184
Siobhan Tullyde5450d2013-06-21 11:35:33 -0400185class TagInline(generic.GenericTabularInline):
186 model = Tag
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400187 extra = 0
188 suit_classes = 'suit-tab suit-tab-tags'
Tony Mack5b061472014-02-04 07:57:10 -0500189 fields = ['service', 'name', 'value']
190
191 def queryset(self, request):
192 return Tag.select_by_user(request.user)
Siobhan Tullyde5450d2013-06-21 11:35:33 -0400193
Scott Baker74d8e622013-07-29 16:04:22 -0700194class NetworkLookerUpper:
Siobhan Tully2c780ad2013-09-06 11:22:40 -0400195 """ This is a callable that looks up a network name in a sliver and returns
196 the ip address for that network.
197 """
198
199 def __init__(self, name):
200 self.short_description = name
201 self.__name__ = name
202 self.network_name = name
203
204 def __call__(self, obj):
205 if obj is not None:
206 for nbs in obj.networksliver_set.all():
207 if (nbs.network.name == self.network_name):
208 return nbs.ip
Scott Baker74d8e622013-07-29 16:04:22 -0700209 return ""
210
211 def __str__(self):
212 return self.network_name
213
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500214class SliverROInline(ReadOnlyTabularInline):
215 model = Sliver
216 fields = ['ip', 'instance_name', 'slice', 'numberCores', 'image', 'node', 'deploymentNetwork']
217 suit_classes = 'suit-tab suit-tab-slivers'
218
Siobhan Tullyd3515752013-06-21 16:34:53 -0400219class SliverInline(PlStackTabularInline):
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400220 model = Sliver
Tony Mackb0d97422013-06-10 09:57:45 -0400221 fields = ['ip', 'instance_name', 'slice', 'numberCores', 'image', 'node', 'deploymentNetwork']
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400222 extra = 0
Tony Mack3777b012013-05-07 21:38:06 -0400223 readonly_fields = ['ip', 'instance_name']
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400224 suit_classes = 'suit-tab suit-tab-slivers'
Scott Baker74d8e622013-07-29 16:04:22 -0700225
Tony Mack5b061472014-02-04 07:57:10 -0500226 def queryset(self, request):
227 return Sliver.select_by_user(request.user)
228
Siobhan Tully2d95e482013-09-06 10:56:06 -0400229# Note this is breaking in the admin.py when trying to use an inline to add a node/image
230# def _declared_fieldsets(self):
231# # Return None so django will call get_fieldsets and we can insert our
232# # dynamic fields
233# return None
234#
235# def get_readonly_fields(self, request, obj=None):
236# readonly_fields = super(SliverInline, self).get_readonly_fields(request, obj)
237#
238# # Lookup the networks that are bound to the slivers, and add those
239# # network names to the list of readonly fields.
240#
241# for sliver in obj.slivers.all():
242# for nbs in sliver.networksliver_set.all():
243# if nbs.ip:
244# network_name = nbs.network.name
245# if network_name not in [str(x) for x in readonly_fields]:
246# readonly_fields.append(NetworkLookerUpper(network_name))
247#
248# return readonly_fields
249#
250# def get_fieldsets(self, request, obj=None):
251# form = self.get_formset(request, obj).form
252# # fields = the read/write files + the read-only fields
253# fields = self.fields
254# for fieldName in self.get_readonly_fields(request,obj):
255# if not fieldName in fields:
256# fields.append(fieldName)
257#
258# return [(None, {'fields': fields})]
Scott Baker74d8e622013-07-29 16:04:22 -0700259
Tony Mackc2835a92013-05-28 09:18:49 -0400260
Siobhan Tully567e3e62013-06-21 18:03:16 -0400261
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500262class SiteROInline(ReadOnlyTabularInline):
263 model = Site
264 extra = 0
265 fields = ['name', 'login_base', 'site_url', 'enabled']
266 suit_classes = 'suit-tab suit-tab-sites'
267
Siobhan Tullyd3515752013-06-21 16:34:53 -0400268class SiteInline(PlStackTabularInline):
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400269 model = Site
270 extra = 0
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400271 suit_classes = 'suit-tab suit-tab-sites'
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400272
Tony Mack5b061472014-02-04 07:57:10 -0500273 def queryset(self, request):
274 return Site.select_by_user(request.user)
275
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500276class UserROInline(ReadOnlyTabularInline):
277 model = User
278 fields = ['email', 'firstname', 'lastname']
279 extra = 0
280 suit_classes = 'suit-tab suit-tab-users'
281
Siobhan Tullyd3515752013-06-21 16:34:53 -0400282class UserInline(PlStackTabularInline):
Siobhan Tully30fd4292013-05-10 08:59:56 -0400283 model = User
Siobhan Tully47ae1b52013-05-10 15:53:14 -0400284 fields = ['email', 'firstname', 'lastname']
Siobhan Tully30fd4292013-05-10 08:59:56 -0400285 extra = 0
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400286 suit_classes = 'suit-tab suit-tab-users'
Siobhan Tully30fd4292013-05-10 08:59:56 -0400287
Tony Mack5b061472014-02-04 07:57:10 -0500288 def queryset(self, request):
289 return User.select_by_user(request.user)
290
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500291class SliceROInline(ReadOnlyTabularInline):
292 model = Slice
293 suit_classes = 'suit-tab suit-tab-slices'
294 fields = ['name','site', 'serviceClass', 'service']
295
Siobhan Tullyd3515752013-06-21 16:34:53 -0400296class SliceInline(PlStackTabularInline):
Tony Mack00d361f2013-04-28 10:28:42 -0400297 model = Slice
Siobhan Tullyce652d02013-10-08 21:52:35 -0400298 fields = ['name','site', 'serviceClass', 'service']
Tony Mack00d361f2013-04-28 10:28:42 -0400299 extra = 0
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400300 suit_classes = 'suit-tab suit-tab-slices'
301
Tony Mack5b061472014-02-04 07:57:10 -0500302 def queryset(self, request):
303 return Slice.select_by_user(request.user)
304
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500305class NodeROInline(ReadOnlyTabularInline):
306 model = Node
307 extra = 0
308 suit_classes = 'suit-tab suit-tab-nodes'
309 fields = ['name','deployment']
Tony Mack00d361f2013-04-28 10:28:42 -0400310
Siobhan Tullyd3515752013-06-21 16:34:53 -0400311class NodeInline(PlStackTabularInline):
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400312 model = Node
313 extra = 0
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400314 suit_classes = 'suit-tab suit-tab-nodes'
Tony Mack5b061472014-02-04 07:57:10 -0500315 fields = ['name','deployment']
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400316
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500317class DeploymentPrivilegeROInline(ReadOnlyTabularInline):
318 model = DeploymentPrivilege
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400319 extra = 0
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500320 suit_classes = 'suit-tab suit-tab-deploymentprivileges'
321 fields = ['user','role']
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400322
323class DeploymentPrivilegeInline(PlStackTabularInline):
324 model = DeploymentPrivilege
325 extra = 0
326 suit_classes = 'suit-tab suit-tab-deploymentprivileges'
Tony Mack5b061472014-02-04 07:57:10 -0500327 fields = ['user','role']
328
329 def queryset(self, request):
330 return DeploymentPrivilege.select_by_user(request.user)
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400331
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500332#CLEANUP DOUBLE SitePrivilegeInline
333class SitePrivilegeROInline(ReadOnlyTabularInline):
334 model = SitePrivilege
335 extra = 0
336 suit_classes = 'suit-tab suit-tab-siteprivileges'
337 fields = ['user','site', 'role']
338
Siobhan Tullyd3515752013-06-21 16:34:53 -0400339class SitePrivilegeInline(PlStackTabularInline):
Siobhan Tullyaa1bcd52013-05-10 12:43:09 -0400340 model = SitePrivilege
341 extra = 0
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400342 suit_classes = 'suit-tab suit-tab-siteprivileges'
Tony Mack5b061472014-02-04 07:57:10 -0500343 fields = ['user','site', 'role']
Siobhan Tullyaa1bcd52013-05-10 12:43:09 -0400344
Tony Mackc2835a92013-05-28 09:18:49 -0400345 def formfield_for_foreignkey(self, db_field, request, **kwargs):
346 if db_field.name == 'site':
Tony Mack5b061472014-02-04 07:57:10 -0500347 kwargs['queryset'] = Site.select_by_user(request.user)
Tony Mackc2835a92013-05-28 09:18:49 -0400348
349 if db_field.name == 'user':
Tony Mack5b061472014-02-04 07:57:10 -0500350 kwargs['queryset'] = User.select_by_user(request.user)
Tony Mackc2835a92013-05-28 09:18:49 -0400351 return super(SitePrivilegeInline, self).formfield_for_foreignkey(db_field, request, **kwargs)
352
Tony Mack5b061472014-02-04 07:57:10 -0500353 def queryset(self, request):
354 return SitePrivilege.select_by_user(request.user)
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400355
Tony Macke4be32f2014-03-11 20:45:25 -0400356class SiteDeploymentROInline(ReadOnlyTabularInline):
357 model = SiteDeployments
358 #model = Site.deployments.through
359 extra = 0
360 suit_classes = 'suit-tab suit-tab-sitedeployments'
361 fields = ['deployment','site']
362
363class SiteDeploymentInline(PlStackTabularInline):
364 model = SiteDeployments
365 #model = Site.deployments.through
366 extra = 0
367 suit_classes = 'suit-tab suit-tab-deployments'
368 fields = ['deployment','site']
369
370 def formfield_for_foreignkey(self, db_field, request, **kwargs):
371 if db_field.name == 'site':
372 kwargs['queryset'] = Site.select_by_user(request.user)
373
374 if db_field.name == 'deployment':
375 kwargs['queryset'] = Deployment.select_by_user(request.user)
376 return super(SiteDeploymentInline, self).formfield_for_foreignkey(db_field, request, **kwargs)
377
378 def queryset(self, request):
379 return SiteDeployments.select_by_user(request.user)
380
381
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500382class SlicePrivilegeROInline(ReadOnlyTabularInline):
383 model = SlicePrivilege
384 extra = 0
385 suit_classes = 'suit-tab suit-tab-sliceprivileges'
386 fields = ['user', 'slice', 'role']
387
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400388class SlicePrivilegeInline(PlStackTabularInline):
389 model = SlicePrivilege
390 suit_classes = 'suit-tab suit-tab-sliceprivileges'
391 extra = 0
392 fields = ('user', 'slice','role')
Siobhan Tullyaa1bcd52013-05-10 12:43:09 -0400393
Tony Mackc2835a92013-05-28 09:18:49 -0400394 def formfield_for_foreignkey(self, db_field, request, **kwargs):
395 if db_field.name == 'slice':
Tony Mack5b061472014-02-04 07:57:10 -0500396 kwargs['queryset'] = Slice.select_by_user(request.user)
Tony Mackc2835a92013-05-28 09:18:49 -0400397 if db_field.name == 'user':
Tony Mack5b061472014-02-04 07:57:10 -0500398 kwargs['queryset'] = User.select_by_user(request.user)
Tony Mackc2835a92013-05-28 09:18:49 -0400399
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400400 return super(SlicePrivilegeInline, self).formfield_for_foreignkey(db_field, request, **kwargs)
Tony Mackc2835a92013-05-28 09:18:49 -0400401
Tony Mack5b061472014-02-04 07:57:10 -0500402 def queryset(self, request):
403 return SlicePrivilege.select_by_user(request.user)
404
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500405class SliceNetworkROInline(ReadOnlyTabularInline):
406 model = Network.slices.through
407 extra = 0
408 verbose_name = "Network Connection"
409 verbose_name_plural = "Network Connections"
410 suit_classes = 'suit-tab suit-tab-slicenetworks'
411 fields = ['network']
412
Scott Bakera0015eb2013-08-14 17:28:14 -0700413class SliceNetworkInline(PlStackTabularInline):
Scott Baker74d8e622013-07-29 16:04:22 -0700414 model = Network.slices.through
Scott Baker874936e2014-01-13 18:15:34 -0800415 selflink_fieldname = "network"
Scott Baker74d8e622013-07-29 16:04:22 -0700416 extra = 0
417 verbose_name = "Network Connection"
418 verbose_name_plural = "Network Connections"
Siobhan Tully2d95e482013-09-06 10:56:06 -0400419 suit_classes = 'suit-tab suit-tab-slicenetworks'
Scott Baker74d8e622013-07-29 16:04:22 -0700420
Tony Mack5e71a662013-05-03 23:30:41 -0400421class PlainTextWidget(forms.HiddenInput):
422 input_type = 'hidden'
423
424 def render(self, name, value, attrs=None):
425 if value is None:
426 value = ''
Tony Mack1d6b85f2013-05-07 18:49:14 -0400427 return mark_safe(str(value) + super(PlainTextWidget, self).render(name, value, attrs))
Tony Mack9bcbe4f2013-04-29 08:13:27 -0400428
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500429class PlanetStackBaseAdmin(ReadOnlyAwareAdmin):
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400430 save_on_top = False
Tony Mack332ee1d2014-02-04 15:33:45 -0500431
432 def save_model(self, request, obj, form, change):
Tony Mack3d042792014-03-17 19:18:37 -0400433 obj.caller = request.user
Tony Mack332ee1d2014-02-04 15:33:45 -0500434 # update openstack connection to use this site/tenant
435 obj.save_by_user(request.user)
436
437 def delete_model(self, request, obj):
438 obj.delete_by_user(request.user)
439
440 def save_formset(self, request, form, formset, change):
441 instances = formset.save(commit=False)
442 for instance in instances:
443 instance.save_by_user(request.user)
444 formset.save_m2m()
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400445
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400446class SliceRoleAdmin(PlanetStackBaseAdmin):
447 model = SliceRole
448 pass
449
450class SiteRoleAdmin(PlanetStackBaseAdmin):
451 model = SiteRole
452 pass
453
Siobhan Tullybf1153a2013-05-27 20:53:48 -0400454class DeploymentAdminForm(forms.ModelForm):
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400455 sites = forms.ModelMultipleChoiceField(
456 queryset=Site.objects.all(),
457 required=False,
458 widget=FilteredSelectMultiple(
459 verbose_name=('Sites'), is_stacked=False
460 )
461 )
462 class Meta:
Siobhan Tullybf1153a2013-05-27 20:53:48 -0400463 model = Deployment
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400464
Siobhan Tully320b4622014-01-17 15:11:14 -0500465 def __init__(self, *args, **kwargs):
466 super(DeploymentAdminForm, self).__init__(*args, **kwargs)
467
468 if self.instance and self.instance.pk:
Tony Mack0cd67e82014-04-02 16:02:45 -0400469 self.fields['sites'].initial = self.instance.sitedeployments_set.all()
Siobhan Tully320b4622014-01-17 15:11:14 -0500470
471 def save(self, commit=True):
472 deployment = super(DeploymentAdminForm, self).save(commit=False)
473
474 if commit:
475 deployment.save()
476
477 if deployment.pk:
478 deployment.sites = self.cleaned_data['sites']
479 self.save_m2m()
480
481 return deployment
482
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500483class SiteAssocInline(PlStackTabularInline):
484 model = Site.deployments.through
485 extra = 0
486 suit_classes = 'suit-tab suit-tab-sites'
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400487
Siobhan Tullybf1153a2013-05-27 20:53:48 -0400488class DeploymentAdmin(PlanetStackBaseAdmin):
489 form = DeploymentAdminForm
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500490 model = Deployment
491 fieldList = ['name','sites']
492 fieldsets = [(None, {'fields': fieldList, 'classes':['suit-tab suit-tab-sites']})]
Siobhan Tully2d95e482013-09-06 10:56:06 -0400493 inlines = [DeploymentPrivilegeInline,NodeInline,TagInline]
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500494
495 user_readonly_inlines = [DeploymentPrivilegeROInline,NodeROInline,TagROInline]
496 user_readonly_fields = ['name']
497
498 suit_form_tabs =(('sites','Deployment Details'),('nodes','Nodes'),('deploymentprivileges','Privileges'),('tags','Tags'))
499
500class ServiceAttrAsTabROInline(ReadOnlyTabularInline):
501 model = ServiceAttribute
502 fields = ['name','value']
503 extra = 0
504 suit_classes = 'suit-tab suit-tab-serviceattrs'
Tony Mack5cd13202013-05-01 21:48:38 -0400505
Siobhan Tullyce652d02013-10-08 21:52:35 -0400506class ServiceAttrAsTabInline(PlStackTabularInline):
507 model = ServiceAttribute
508 fields = ['name','value']
509 extra = 0
510 suit_classes = 'suit-tab suit-tab-serviceattrs'
511
Siobhan Tullyce652d02013-10-08 21:52:35 -0400512class ServiceAdmin(PlanetStackBaseAdmin):
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500513 list_display = ("name","description","versionNumber","enabled","published")
514 fieldList = ["name","description","versionNumber","enabled","published"]
515 fieldsets = [(None, {'fields': fieldList, 'classes':['suit-tab suit-tab-general']})]
516 inlines = [ServiceAttrAsTabInline,SliceInline]
517
518 user_readonly_fields = fieldList
519 user_readonly_inlines = [ServiceAttrAsTabROInline,SliceROInline]
520
521 suit_form_tabs =(('general', 'Service Details'),
522 ('slices','Slices'),
523 ('serviceattrs','Additional Attributes'),
524 )
Siobhan Tullyce652d02013-10-08 21:52:35 -0400525
Tony Mack0553f282013-06-10 22:54:50 -0400526class SiteAdmin(PlanetStackBaseAdmin):
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500527 fieldList = ['name', 'site_url', 'enabled', 'is_public', 'login_base', 'accountLink','location']
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400528 fieldsets = [
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500529 (None, {'fields': fieldList, 'classes':['suit-tab suit-tab-general']}),
Tony Macke4be32f2014-03-11 20:45:25 -0400530 #('Deployment Networks', {'fields': ['deployments'], 'classes':['suit-tab suit-tab-deployments']}),
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400531 ]
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400532 suit_form_tabs =(('general', 'Site Details'),
533 ('users','Users'),
Siobhan Tully2d95e482013-09-06 10:56:06 -0400534 ('siteprivileges','Privileges'),
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400535 ('deployments','Deployments'),
536 ('slices','Slices'),
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500537 ('nodes','Nodes'),
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400538 ('tags','Tags'),
539 )
Scott Baker545db2a2013-12-09 18:44:43 -0800540 readonly_fields = ['accountLink']
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500541
542 user_readonly_fields = ['name', 'deployments','site_url', 'enabled', 'is_public', 'login_base', 'accountLink']
Tony Macke4be32f2014-03-11 20:45:25 -0400543 user_readonly_inlines = [SliceROInline,UserROInline,TagROInline, NodeROInline, SitePrivilegeROInline,SiteDeploymentROInline]
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500544
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400545 list_display = ('name', 'login_base','site_url', 'enabled')
546 filter_horizontal = ('deployments',)
Tony Macke4be32f2014-03-11 20:45:25 -0400547 inlines = [SliceInline,UserInline,TagInline, NodeInline, SitePrivilegeInline, SiteDeploymentInline]
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400548 search_fields = ['name']
549
Tony Mack04062832013-05-10 08:22:44 -0400550 def queryset(self, request):
Tony Mack5b061472014-02-04 07:57:10 -0500551 #print dir(UserInline)
552 return Site.select_by_user(request.user)
Tony Mack04062832013-05-10 08:22:44 -0400553
Tony Mack5cd13202013-05-01 21:48:38 -0400554 def get_formsets(self, request, obj=None):
555 for inline in self.get_inline_instances(request, obj):
556 # hide MyInline in the add view
557 if obj is None:
558 continue
Tony Mack2bd5b412013-06-11 21:05:06 -0400559 if isinstance(inline, SliceInline):
560 inline.model.caller = request.user
561 yield inline.get_formset(request, obj)
562
563 def get_formsets(self, request, obj=None):
564 for inline in self.get_inline_instances(request, obj):
565 # hide MyInline in the add view
566 if obj is None:
567 continue
568 if isinstance(inline, SliverInline):
569 inline.model.caller = request.user
Tony Mack5cd13202013-05-01 21:48:38 -0400570 yield inline.get_formset(request, obj)
571
Scott Baker545db2a2013-12-09 18:44:43 -0800572 def accountLink(self, obj):
573 link_obj = obj.accounts.all()
574 if link_obj:
575 reverse_path = "admin:core_account_change"
576 url = reverse(reverse_path, args =(link_obj[0].id,))
577 return "<a href='%s'>%s</a>" % (url, "view billing details")
578 else:
579 return "no billing data for this site"
580 accountLink.allow_tags = True
581 accountLink.short_description = "Billing"
582
Tony Mack332ee1d2014-02-04 15:33:45 -0500583 def save_model(self, request, obj, form, change):
584 # update openstack connection to use this site/tenant
585 obj.save_by_user(request.user)
586
587 def delete_model(self, request, obj):
588 obj.delete_by_user(request.user)
589
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500590
Tony Mack9bcbe4f2013-04-29 08:13:27 -0400591class SitePrivilegeAdmin(PlanetStackBaseAdmin):
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500592 fieldList = ['user', 'site', 'role']
Tony Mack00d361f2013-04-28 10:28:42 -0400593 fieldsets = [
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500594 (None, {'fields': fieldList, 'classes':['collapse']})
Tony Mack00d361f2013-04-28 10:28:42 -0400595 ]
596 list_display = ('user', 'site', 'role')
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500597 user_readonly_fields = fieldList
598 user_readonly_inlines = []
Tony Mack00d361f2013-04-28 10:28:42 -0400599
Tony Mackc2835a92013-05-28 09:18:49 -0400600 def formfield_for_foreignkey(self, db_field, request, **kwargs):
601 if db_field.name == 'site':
602 if not request.user.is_admin:
603 # only show sites where user is an admin or pi
604 sites = set()
605 for site_privilege in SitePrivilege.objects.filer(user=request.user):
606 if site_privilege.role.role_type in ['admin', 'pi']:
607 sites.add(site_privilege.site)
608 kwargs['queryset'] = Site.objects.filter(site__in=list(sites))
609
610 if db_field.name == 'user':
611 if not request.user.is_admin:
612 # only show users from sites where caller has admin or pi role
613 roles = Role.objects.filter(role_type__in=['admin', 'pi'])
614 site_privileges = SitePrivilege.objects.filter(user=request.user).filter(role__in=roles)
615 sites = [site_privilege.site for site_privilege in site_privileges]
616 site_privileges = SitePrivilege.objects.filter(site__in=sites)
617 emails = [site_privilege.user.email for site_privilege in site_privileges]
618 users = User.objects.filter(email__in=emails)
619 kwargs['queryset'] = users
620
621 return super(SitePrivilegeAdmin, self).formfield_for_foreignkey(db_field, request, **kwargs)
622
Tony Mack04062832013-05-10 08:22:44 -0400623 def queryset(self, request):
624 # admins can see all privileges. Users can only see privileges at sites
Tony Mackc2835a92013-05-28 09:18:49 -0400625 # where they have the admin role or pi role.
Tony Mack04062832013-05-10 08:22:44 -0400626 qs = super(SitePrivilegeAdmin, self).queryset(request)
Tony Mack5b061472014-02-04 07:57:10 -0500627 #if not request.user.is_admin:
628 # roles = Role.objects.filter(role_type__in=['admin', 'pi'])
629 # site_privileges = SitePrivilege.objects.filter(user=request.user).filter(role__in=roles)
630 # login_bases = [site_privilege.site.login_base for site_privilege in site_privileges]
631 # sites = Site.objects.filter(login_base__in=login_bases)
632 # qs = qs.filter(site__in=sites)
Tony Mack04062832013-05-10 08:22:44 -0400633 return qs
634
Siobhan Tullyce652d02013-10-08 21:52:35 -0400635class SliceForm(forms.ModelForm):
636 class Meta:
637 model = Slice
638 widgets = {
639 'service': LinkedSelect
640 }
641
Tony Mack2bd5b412013-06-11 21:05:06 -0400642class SliceAdmin(PlanetStackBaseAdmin):
Siobhan Tullyce652d02013-10-08 21:52:35 -0400643 form = SliceForm
Tony Mack29bf5e82014-04-29 21:40:24 -0400644 fieldList = ['name', 'site', 'serviceClass', 'enabled','description', 'service', 'slice_url', 'max_slivers']
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500645 fieldsets = [('Slice Details', {'fields': fieldList, 'classes':['suit-tab suit-tab-general']}),]
Tony Mack29bf5e82014-04-29 21:40:24 -0400646 list_display = ('name', 'site','serviceClass', 'slice_url', 'max_slivers')
Siobhan Tully2d95e482013-09-06 10:56:06 -0400647 inlines = [SlicePrivilegeInline,SliverInline, TagInline, ReservationInline,SliceNetworkInline]
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400648
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500649 user_readonly_fields = fieldList
650 user_readonly_inlines = [SlicePrivilegeROInline,SliverROInline,TagROInline, ReservationROInline, SliceNetworkROInline]
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400651
652 suit_form_tabs =(('general', 'Slice Details'),
Siobhan Tully2d95e482013-09-06 10:56:06 -0400653 ('slicenetworks','Networks'),
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400654 ('sliceprivileges','Privileges'),
655 ('slivers','Slivers'),
656 ('tags','Tags'),
657 ('reservations','Reservations'),
658 )
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400659
Tony Mackc2835a92013-05-28 09:18:49 -0400660 def formfield_for_foreignkey(self, db_field, request, **kwargs):
661 if db_field.name == 'site':
Tony Mack5b061472014-02-04 07:57:10 -0500662 kwargs['queryset'] = Site.select_by_user(request.user)
663
Tony Mackc2835a92013-05-28 09:18:49 -0400664 return super(SliceAdmin, self).formfield_for_foreignkey(db_field, request, **kwargs)
665
Tony Mack04062832013-05-10 08:22:44 -0400666 def queryset(self, request):
667 # admins can see all keys. Users can only see slices they belong to.
Tony Mack5b061472014-02-04 07:57:10 -0500668 return Slice.select_by_user(request.user)
Tony Mack04062832013-05-10 08:22:44 -0400669
Tony Mack79748612013-05-01 14:52:03 -0400670 def get_formsets(self, request, obj=None):
671 for inline in self.get_inline_instances(request, obj):
672 # hide MyInline in the add view
673 if obj is None:
674 continue
Tony Mack2bd5b412013-06-11 21:05:06 -0400675 if isinstance(inline, SliverInline):
676 inline.model.caller = request.user
Tony Mack79748612013-05-01 14:52:03 -0400677 yield inline.get_formset(request, obj)
678
Tony Mack2bd5b412013-06-11 21:05:06 -0400679
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400680class SlicePrivilegeAdmin(PlanetStackBaseAdmin):
Tony Mack00d361f2013-04-28 10:28:42 -0400681 fieldsets = [
682 (None, {'fields': ['user', 'slice', 'role']})
683 ]
684 list_display = ('user', 'slice', 'role')
Tony Mack00d361f2013-04-28 10:28:42 -0400685
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500686 user_readonly_fields = ['user', 'slice', 'role']
687 user_readonly_inlines = []
688
Tony Mackc2835a92013-05-28 09:18:49 -0400689 def formfield_for_foreignkey(self, db_field, request, **kwargs):
690 if db_field.name == 'slice':
Tony Mack5b061472014-02-04 07:57:10 -0500691 kwargs['queryset'] = Slice.select_by_user(request.user)
Tony Mackc2835a92013-05-28 09:18:49 -0400692
693 if db_field.name == 'user':
Tony Mack5b061472014-02-04 07:57:10 -0500694 kwargs['queryset'] = User.select_by_user(request.user)
Tony Mackc2835a92013-05-28 09:18:49 -0400695
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400696 return super(SlicePrivilegeAdmin, self).formfield_for_foreignkey(db_field, request, **kwargs)
Tony Mackc2835a92013-05-28 09:18:49 -0400697
Tony Mack04062832013-05-10 08:22:44 -0400698 def queryset(self, request):
699 # admins can see all memberships. Users can only see memberships of
700 # slices where they have the admin role.
Tony Mack5b061472014-02-04 07:57:10 -0500701 return SlicePrivilege.select_by_user(request.user)
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400702
Tony Mack9bcbe4f2013-04-29 08:13:27 -0400703 def save_model(self, request, obj, form, change):
Tony Mack951dab42013-05-02 19:51:45 -0400704 # update openstack connection to use this site/tenant
705 auth = request.session.get('auth', {})
706 auth['tenant'] = obj.slice.name
707 obj.os_manager = OpenStackManager(auth=auth, caller=request.user)
Tony Mack9bcbe4f2013-04-29 08:13:27 -0400708 obj.save()
709
710 def delete_model(self, request, obj):
Tony Mack951dab42013-05-02 19:51:45 -0400711 # update openstack connection to use this site/tenant
712 auth = request.session.get('auth', {})
713 auth['tenant'] = obj.slice.name
714 obj.os_manager = OpenStackManager(auth=auth, caller=request.user)
Tony Mack9bcbe4f2013-04-29 08:13:27 -0400715 obj.delete()
716
Siobhan Tully567e3e62013-06-21 18:03:16 -0400717
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400718class ImageAdmin(PlanetStackBaseAdmin):
719
720 fieldsets = [('Image Details',
Scott Baker00b00b32014-05-07 08:47:54 -0700721 {'fields': ['name', 'disk_format', 'container_format'],
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400722 'classes': ['suit-tab suit-tab-general']})
723 ]
724
725 suit_form_tabs =(('general','Image Details'),('slivers','Slivers'))
726
727 inlines = [SliverInline]
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500728
Tony Mack32e1ce32014-05-07 13:29:41 -0400729 user_readonly_fields = ['name', 'disk_format', 'container_format']
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500730 user_readonly_inlines = [SliverROInline]
731
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400732class NodeForm(forms.ModelForm):
733 class Meta:
734 widgets = {
735 'site': LinkedSelect,
736 'deployment': LinkedSelect
737 }
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400738
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500739class NodeAdmin(PlanetStackBaseAdmin):
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400740 form = NodeForm
Siobhan Tullybf1153a2013-05-27 20:53:48 -0400741 list_display = ('name', 'site', 'deployment')
742 list_filter = ('deployment',)
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500743
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400744 inlines = [TagInline,SliverInline]
745 fieldsets = [('Node Details', {'fields': ['name','site','deployment'], 'classes':['suit-tab suit-tab-details']})]
746
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500747 user_readonly_fields = ['name','site','deployment']
748 user_readonly_inlines = [TagInline,SliverInline]
749
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400750 suit_form_tabs =(('details','Node Details'),('slivers','Slivers'),('tags','Tags'))
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400751
Siobhan Tully567e3e62013-06-21 18:03:16 -0400752
Tony Mackd90cdbf2013-04-16 22:48:40 -0400753class SliverForm(forms.ModelForm):
754 class Meta:
Tony Mack1d6b85f2013-05-07 18:49:14 -0400755 model = Sliver
Tony Mackd90cdbf2013-04-16 22:48:40 -0400756 ip = forms.CharField(widget=PlainTextWidget)
Tony Mack18261812013-05-02 16:39:20 -0400757 instance_name = forms.CharField(widget=PlainTextWidget)
Tony Mackd90cdbf2013-04-16 22:48:40 -0400758 widgets = {
759 'ip': PlainTextWidget(),
Tony Mack18261812013-05-02 16:39:20 -0400760 'instance_name': PlainTextWidget(),
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400761 'slice': LinkedSelect,
762 'deploymentNetwork': LinkedSelect,
763 'node': LinkedSelect,
764 'image': LinkedSelect
Siobhan Tully53437282013-04-26 19:30:27 -0400765 }
Tony Mackd90cdbf2013-04-16 22:48:40 -0400766
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500767class TagAdmin(PlanetStackBaseAdmin):
Siobhan Tullyce652d02013-10-08 21:52:35 -0400768 list_display = ['service', 'name', 'value', 'content_type', 'content_object',]
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500769 user_readonly_fields = ['service', 'name', 'value', 'content_type', 'content_object',]
770 user_readonly_inlines = []
Siobhan Tullyd3515752013-06-21 16:34:53 -0400771
Tony Mack9bcbe4f2013-04-29 08:13:27 -0400772class SliverAdmin(PlanetStackBaseAdmin):
Tony Mackd90cdbf2013-04-16 22:48:40 -0400773 form = SliverForm
Tony Mackcdec0902013-04-15 00:38:49 -0400774 fieldsets = [
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400775 ('Sliver Details', {'fields': ['slice', 'deploymentNetwork', 'node', 'ip', 'instance_name', 'numberCores', 'image', ], 'classes': ['suit-tab suit-tab-general'], })
Tony Mackcdec0902013-04-15 00:38:49 -0400776 ]
Siobhan Tully5d7dc8d2013-07-02 13:17:33 -0400777 list_display = ['ip', 'instance_name', 'slice', 'numberCores', 'image', 'node', 'deploymentNetwork']
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400778
779 suit_form_tabs =(('general', 'Sliver Details'),
780 ('tags','Tags'),
781 )
782
Siobhan Tullyde5450d2013-06-21 11:35:33 -0400783 inlines = [TagInline]
Tony Mack53106f32013-04-27 16:43:01 -0400784
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500785 user_readonly_fields = ['slice', 'deploymentNetwork', 'node', 'ip', 'instance_name', 'numberCores', 'image']
786 user_readonly_inlines = [TagROInline]
787
Tony Mackc2835a92013-05-28 09:18:49 -0400788 def formfield_for_foreignkey(self, db_field, request, **kwargs):
789 if db_field.name == 'slice':
Tony Mack5b061472014-02-04 07:57:10 -0500790 kwargs['queryset'] = Slice.select_by_user(request.user)
Tony Mackc2835a92013-05-28 09:18:49 -0400791
792 return super(SliverAdmin, self).formfield_for_foreignkey(db_field, request, **kwargs)
793
Tony Mack04062832013-05-10 08:22:44 -0400794 def queryset(self, request):
795 # admins can see all slivers. Users can only see slivers of
796 # the slices they belong to.
Tony Mack5b061472014-02-04 07:57:10 -0500797 return Sliver.select_by_user(request.user)
798
Tony Mack04062832013-05-10 08:22:44 -0400799
Tony Mack1d6b85f2013-05-07 18:49:14 -0400800 def get_formsets(self, request, obj=None):
801 # make some fields read only if we are updating an existing record
802 if obj == None:
803 #self.readonly_fields = ('ip', 'instance_name')
804 self.readonly_fields = ()
805 else:
Tony Mack1e889462013-05-10 21:34:54 -0400806 self.readonly_fields = ()
807 #self.readonly_fields = ('ip', 'instance_name', 'slice', 'image', 'key')
Tony Mack1d6b85f2013-05-07 18:49:14 -0400808
809 for inline in self.get_inline_instances(request, obj):
810 # hide MyInline in the add view
811 if obj is None:
812 continue
Tony Mack53106f32013-04-27 16:43:01 -0400813
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500814 #def save_model(self, request, obj, form, change):
815 # # update openstack connection to use this site/tenant
816 # auth = request.session.get('auth', {})
817 # auth['tenant'] = obj.slice.name
818 # obj.os_manager = OpenStackManager(auth=auth, caller=request.user)
819 # obj.creator = request.user
820 # obj.save()
Tony Mack53106f32013-04-27 16:43:01 -0400821
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500822 #def delete_model(self, request, obj):
823 # # update openstack connection to use this site/tenant
824 # auth = request.session.get('auth', {})
825 # auth['tenant'] = obj.slice.name
826 # obj.os_manager = OpenStackManager(auth=auth, caller=request.user)
827 # obj.delete()
Tony Mackcdec0902013-04-15 00:38:49 -0400828
Siobhan Tully53437282013-04-26 19:30:27 -0400829class UserCreationForm(forms.ModelForm):
830 """A form for creating new users. Includes all the required
831 fields, plus a repeated password."""
832 password1 = forms.CharField(label='Password', widget=forms.PasswordInput)
833 password2 = forms.CharField(label='Password confirmation', widget=forms.PasswordInput)
834
835 class Meta:
Siobhan Tully30fd4292013-05-10 08:59:56 -0400836 model = User
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400837 fields = ('email', 'firstname', 'lastname', 'phone', 'public_key')
Siobhan Tully53437282013-04-26 19:30:27 -0400838
839 def clean_password2(self):
840 # Check that the two password entries match
841 password1 = self.cleaned_data.get("password1")
842 password2 = self.cleaned_data.get("password2")
843 if password1 and password2 and password1 != password2:
844 raise forms.ValidationError("Passwords don't match")
845 return password2
846
847 def save(self, commit=True):
848 # Save the provided password in hashed format
849 user = super(UserCreationForm, self).save(commit=False)
Tony Mackf9f4afb2013-05-01 21:02:12 -0400850 user.password = self.cleaned_data["password1"]
851 #user.set_password(self.cleaned_data["password1"])
Siobhan Tully53437282013-04-26 19:30:27 -0400852 if commit:
853 user.save()
854 return user
855
Siobhan Tully567e3e62013-06-21 18:03:16 -0400856
Siobhan Tully53437282013-04-26 19:30:27 -0400857class UserChangeForm(forms.ModelForm):
858 """A form for updating users. Includes all the fields on
859 the user, but replaces the password field with admin's
860 password hash display field.
861 """
Siobhan Tully63b7ba42014-01-12 10:35:11 -0500862 password = ReadOnlyPasswordHashField(label='Password',
863 help_text= '<a href=\"password/\">Change Password</a>.')
Siobhan Tully53437282013-04-26 19:30:27 -0400864
865 class Meta:
Siobhan Tully30fd4292013-05-10 08:59:56 -0400866 model = User
Siobhan Tully53437282013-04-26 19:30:27 -0400867
868 def clean_password(self):
869 # Regardless of what the user provides, return the initial value.
870 # This is done here, rather than on the field, because the
871 # field does not have access to the initial value
872 return self.initial["password"]
873
Tony Mack2bd5b412013-06-11 21:05:06 -0400874class UserAdmin(UserAdmin):
Siobhan Tully53437282013-04-26 19:30:27 -0400875 class Meta:
876 app_label = "core"
877
878 # The forms to add and change user instances
879 form = UserChangeForm
880 add_form = UserCreationForm
881
882 # The fields to be used in displaying the User model.
883 # These override the definitions on the base UserAdmin
884 # that reference specific fields on auth.User.
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500885 list_display = ('email', 'firstname', 'lastname', 'site', 'last_login')
Siobhan Tullyce652d02013-10-08 21:52:35 -0400886 #list_display = ('email', 'username','firstname', 'lastname', 'is_admin', 'last_login')
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500887 list_filter = ('site',)
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400888 inlines = [SlicePrivilegeInline,SitePrivilegeInline,DeploymentPrivilegeInline]
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500889
890 fieldListLoginDetails = ['email','site','password','is_readonly','is_amin','public_key']
891 fieldListContactInfo = ['firstname','lastname','phone','timezone']
892
Siobhan Tully53437282013-04-26 19:30:27 -0400893 fieldsets = (
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500894 ('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 -0400895 ('Contact Information', {'fields': ('firstname','lastname','phone', 'timezone'), 'classes':['suit-tab suit-tab-contact']}),
Siobhan Tully53437282013-04-26 19:30:27 -0400896 #('Important dates', {'fields': ('last_login',)}),
897 )
898 add_fieldsets = (
899 (None, {
900 'classes': ('wide',),
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500901 'fields': ('email', 'firstname', 'lastname', 'is_readonly', 'phone', 'public_key','password1', 'password2')}
Siobhan Tully53437282013-04-26 19:30:27 -0400902 ),
903 )
904 search_fields = ('email',)
905 ordering = ('email',)
906 filter_horizontal = ()
907
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500908 user_readonly_fields = fieldListLoginDetails
909 user_readonly_inlines = [SlicePrivilegeROInline,SitePrivilegeROInline,DeploymentPrivilegeROInline]
910
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400911 suit_form_tabs =(('general','Login Details'),('contact','Contact Information'),('sliceprivileges','Slice Privileges'),('siteprivileges','Site Privileges'),('deploymentprivileges','Deployment Privileges'))
912
Tony Mackc2835a92013-05-28 09:18:49 -0400913 def formfield_for_foreignkey(self, db_field, request, **kwargs):
914 if db_field.name == 'site':
Tony Mack5b061472014-02-04 07:57:10 -0500915 kwargs['queryset'] = Site.select_by_user(request.user)
Tony Mackc2835a92013-05-28 09:18:49 -0400916
917 return super(UserAdmin, self).formfield_for_foreignkey(db_field, request, **kwargs)
918
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500919 def has_add_permission(self, request, obj=None):
920 return (not self.__user_is_readonly(request))
921
922 def has_delete_permission(self, request, obj=None):
923 return (not self.__user_is_readonly(request))
924
925 def get_actions(self,request):
926 actions = super(UserAdmin,self).get_actions(request)
927
928 if self.__user_is_readonly(request):
929 if 'delete_selected' in actions:
930 del actions['delete_selected']
931
932 return actions
933
934 def change_view(self,request,object_id, extra_context=None):
935
936 if self.__user_is_readonly(request):
937 self.readonly_fields=self.user_readonly_fields
938 self.inlines = self.user_readonly_inlines
939 try:
940 return super(UserAdmin, self).change_view(request, object_id, extra_context=extra_context)
941 except PermissionDenied:
942 pass
943 if request.method == 'POST':
944 raise PermissionDenied
945 request.readonly = True
946 return super(UserAdmin, self).change_view(request, object_id, extra_context=extra_context)
947
948 def __user_is_readonly(self, request):
949 #groups = [x.name for x in request.user.groups.all() ]
950 #return "readonly" in groups
951 return request.user.isReadOnlyUser()
952
Tony Mack5b061472014-02-04 07:57:10 -0500953 def queryset(self, request):
954 return User.select_by_user(request.user)
955
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500956
957
958class ServiceResourceROInline(ReadOnlyTabularInline):
959 model = ServiceResource
960 extra = 0
961 fields = ['serviceClass', 'name', 'maxUnitsDeployment', 'maxUnitsNode', 'maxDuration', 'bucketInRate', 'bucketMaxSize', 'cost', 'calendarReservable']
962
Scott Baker0165fac2014-01-13 11:49:26 -0800963class ServiceResourceInline(PlStackTabularInline):
Scott Baker3de3e372013-05-10 16:50:44 -0700964 model = ServiceResource
965 extra = 0
966
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500967class ServiceClassAdmin(PlanetStackBaseAdmin):
Scott Baker3de3e372013-05-10 16:50:44 -0700968 list_display = ('name', 'commitment', 'membershipFee')
969 inlines = [ServiceResourceInline]
970
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500971 user_readonly_fields = ['name', 'commitment', 'membershipFee']
972 user_readonly_inlines = []
973
974class ReservedResourceROInline(ReadOnlyTabularInline):
975 model = ReservedResource
976 extra = 0
977 fields = ['sliver', 'resource','quantity','reservationSet']
978 suit_classes = 'suit-tab suit-tab-reservedresources'
979
Scott Baker0165fac2014-01-13 11:49:26 -0800980class ReservedResourceInline(PlStackTabularInline):
Scott Baker133c9212013-05-17 09:09:11 -0700981 model = ReservedResource
982 extra = 0
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400983 suit_classes = 'suit-tab suit-tab-reservedresources'
Scott Baker133c9212013-05-17 09:09:11 -0700984
985 def formfield_for_foreignkey(self, db_field, request=None, **kwargs):
986 field = super(ReservedResourceInline, self).formfield_for_foreignkey(db_field, request, **kwargs)
987
988 if db_field.name == 'resource':
989 # restrict resources to those that the slice's service class allows
990 if request._slice is not None:
991 field.queryset = field.queryset.filter(serviceClass = request._slice.serviceClass, calendarReservable=True)
992 if len(field.queryset) > 0:
993 field.initial = field.queryset.all()[0]
994 else:
995 field.queryset = field.queryset.none()
996 elif db_field.name == 'sliver':
997 # restrict slivers to those that belong to the slice
998 if request._slice is not None:
999 field.queryset = field.queryset.filter(slice = request._slice)
1000 else:
1001 field.queryset = field.queryset.none()
1002
1003 return field
1004
Tony Mack5b061472014-02-04 07:57:10 -05001005 def queryset(self, request):
1006 return ReservedResource.select_by_user(request.user)
1007
Scott Baker133c9212013-05-17 09:09:11 -07001008class ReservationChangeForm(forms.ModelForm):
1009 class Meta:
1010 model = Reservation
Siobhan Tullybfd11dc2013-09-03 12:59:24 -04001011 widgets = {
1012 'slice' : LinkedSelect
1013 }
Scott Baker133c9212013-05-17 09:09:11 -07001014
1015class ReservationAddForm(forms.ModelForm):
1016 slice = forms.ModelChoiceField(queryset=Slice.objects.all(), widget=forms.Select(attrs={"onChange":"document.getElementById('id_refresh').value=1; submit()"}))
1017 refresh = forms.CharField(widget=forms.HiddenInput())
1018
1019 class Media:
1020 css = {'all': ('planetstack.css',)} # .field-refresh { display: none; }
1021
1022 def clean_slice(self):
1023 slice = self.cleaned_data.get("slice")
1024 x = ServiceResource.objects.filter(serviceClass = slice.serviceClass, calendarReservable=True)
1025 if len(x) == 0:
1026 raise forms.ValidationError("The slice you selected does not have a service class that allows reservations")
1027 return slice
1028
1029 class Meta:
1030 model = Reservation
Siobhan Tullybfd11dc2013-09-03 12:59:24 -04001031 widgets = {
1032 'slice' : LinkedSelect
1033 }
1034
Scott Baker133c9212013-05-17 09:09:11 -07001035
1036class ReservationAddRefreshForm(ReservationAddForm):
1037 """ This form is displayed when the Reservation Form receives an update
1038 from the Slice dropdown onChange handler. It doesn't validate the
1039 data and doesn't save the data. This will cause the form to be
1040 redrawn.
1041 """
1042
Scott Baker8737e5f2013-05-17 09:35:32 -07001043 """ don't validate anything other than slice """
1044 dont_validate_fields = ("startTime", "duration")
1045
Scott Baker133c9212013-05-17 09:09:11 -07001046 def full_clean(self):
1047 result = super(ReservationAddForm, self).full_clean()
Scott Baker8737e5f2013-05-17 09:35:32 -07001048
1049 for fieldname in self.dont_validate_fields:
1050 if fieldname in self._errors:
1051 del self._errors[fieldname]
1052
Scott Baker133c9212013-05-17 09:09:11 -07001053 return result
1054
1055 """ don't save anything """
1056 def is_valid(self):
1057 return False
1058
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001059class ReservationAdmin(PlanetStackBaseAdmin):
1060 fieldList = ['slice', 'startTime', 'duration']
1061 fieldsets = [('Reservation Details', {'fields': fieldList, 'classes': ['suit-tab suit-tab-general']})]
Scott Baker133c9212013-05-17 09:09:11 -07001062 list_display = ('startTime', 'duration')
Scott Baker133c9212013-05-17 09:09:11 -07001063 form = ReservationAddForm
1064
Siobhan Tullybfd11dc2013-09-03 12:59:24 -04001065 suit_form_tabs = (('general','Reservation Details'), ('reservedresources','Reserved Resources'))
1066
1067 inlines = [ReservedResourceInline]
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001068 user_readonly_inlines = [ReservedResourceROInline]
1069 user_readonly_fields = fieldList
Siobhan Tullybfd11dc2013-09-03 12:59:24 -04001070
Scott Baker133c9212013-05-17 09:09:11 -07001071 def add_view(self, request, form_url='', extra_context=None):
Scott Bakeracd45142013-05-19 16:19:16 -07001072 timezone.activate(request.user.timezone)
Scott Baker133c9212013-05-17 09:09:11 -07001073 request._refresh = False
1074 request._slice = None
1075 if request.method == 'POST':
Scott Baker8737e5f2013-05-17 09:35:32 -07001076 # "refresh" will be set to "1" if the form was submitted due to
1077 # a change in the Slice dropdown.
Scott Baker133c9212013-05-17 09:09:11 -07001078 if request.POST.get("refresh","1") == "1":
1079 request._refresh = True
1080 request.POST["refresh"] = "0"
Scott Baker8737e5f2013-05-17 09:35:32 -07001081
1082 # Keep track of the slice that was selected, so the
1083 # reservedResource inline can filter items for the slice.
Scott Baker133c9212013-05-17 09:09:11 -07001084 request._slice = request.POST.get("slice",None)
1085 if (request._slice is not None):
1086 request._slice = Slice.objects.get(id=request._slice)
1087
1088 result = super(ReservationAdmin, self).add_view(request, form_url, extra_context)
1089 return result
1090
Scott Bakeracd45142013-05-19 16:19:16 -07001091 def changelist_view(self, request, extra_context = None):
1092 timezone.activate(request.user.timezone)
1093 return super(ReservationAdmin, self).changelist_view(request, extra_context)
1094
Scott Baker133c9212013-05-17 09:09:11 -07001095 def get_form(self, request, obj=None, **kwargs):
Siobhan Tullyd3515752013-06-21 16:34:53 -04001096 request._obj_ = obj
1097 if obj is not None:
1098 # For changes, set request._slice to the slice already set in the
1099 # object.
1100 request._slice = obj.slice
1101 self.form = ReservationChangeForm
1102 else:
1103 if getattr(request, "_refresh", False):
1104 self.form = ReservationAddRefreshForm
1105 else:
1106 self.form = ReservationAddForm
1107 return super(ReservationAdmin, self).get_form(request, obj, **kwargs)
1108
Scott Baker133c9212013-05-17 09:09:11 -07001109 def get_readonly_fields(self, request, obj=None):
Siobhan Tullyd3515752013-06-21 16:34:53 -04001110 if (obj is not None):
1111 # Prevent slice from being changed after the reservation has been
1112 # created.
1113 return ['slice']
1114 else:
Scott Baker133c9212013-05-17 09:09:11 -07001115 return []
Scott Baker3de3e372013-05-10 16:50:44 -07001116
Tony Mack5b061472014-02-04 07:57:10 -05001117 def queryset(self, request):
1118 return Reservation.select_by_user(request.user)
1119
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001120class NetworkParameterTypeAdmin(PlanetStackBaseAdmin):
Scott Baker74d8e622013-07-29 16:04:22 -07001121 list_display = ("name", )
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001122 user_readonly_fields = ['name']
1123 user_readonly_inlines = []
Scott Baker74d8e622013-07-29 16:04:22 -07001124
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001125class RouterAdmin(PlanetStackBaseAdmin):
Scott Baker74d8e622013-07-29 16:04:22 -07001126 list_display = ("name", )
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001127 user_readonly_fields = ['name']
1128 user_readonly_inlines = []
1129
1130class RouterROInline(ReadOnlyTabularInline):
1131 model = Router.networks.through
1132 extra = 0
1133 verbose_name_plural = "Routers"
1134 verbose_name = "Router"
1135 suit_classes = 'suit-tab suit-tab-routers'
1136
1137 fields = ['name', 'owner', 'permittedNetworks', 'networks']
Scott Baker74d8e622013-07-29 16:04:22 -07001138
Scott Baker0165fac2014-01-13 11:49:26 -08001139class RouterInline(PlStackTabularInline):
Scott Baker74d8e622013-07-29 16:04:22 -07001140 model = Router.networks.through
1141 extra = 0
1142 verbose_name_plural = "Routers"
1143 verbose_name = "Router"
Siobhan Tully2d95e482013-09-06 10:56:06 -04001144 suit_classes = 'suit-tab suit-tab-routers'
Scott Baker74d8e622013-07-29 16:04:22 -07001145
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001146class NetworkParameterROInline(ReadOnlyTabularInline):
1147 model = NetworkParameter
1148 extra = 1
1149 verbose_name_plural = "Parameters"
1150 verbose_name = "Parameter"
1151 suit_classes = 'suit-tab suit-tab-netparams'
1152 fields = ['parameter', 'value', 'content_type', 'object_id', 'content_object']
1153
Scott Baker74d8e622013-07-29 16:04:22 -07001154class NetworkParameterInline(generic.GenericTabularInline):
Scott Baker74d8e622013-07-29 16:04:22 -07001155 model = NetworkParameter
1156 extra = 1
1157 verbose_name_plural = "Parameters"
1158 verbose_name = "Parameter"
Siobhan Tully2d95e482013-09-06 10:56:06 -04001159 suit_classes = 'suit-tab suit-tab-netparams'
Scott Baker74d8e622013-07-29 16:04:22 -07001160
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001161class NetworkSliversROInline(ReadOnlyTabularInline):
1162 fields = ['network', 'sliver', 'ip', 'port_id']
1163 model = NetworkSliver
1164 extra = 0
1165 verbose_name_plural = "Slivers"
1166 verbose_name = "Sliver"
1167 suit_classes = 'suit-tab suit-tab-networkslivers'
1168
Scott Baker0165fac2014-01-13 11:49:26 -08001169class NetworkSliversInline(PlStackTabularInline):
Scott Baker74d8e622013-07-29 16:04:22 -07001170 readonly_fields = ("ip", )
1171 model = NetworkSliver
Scott Baker874936e2014-01-13 18:15:34 -08001172 selflink_fieldname = "sliver"
Scott Baker74d8e622013-07-29 16:04:22 -07001173 extra = 0
1174 verbose_name_plural = "Slivers"
1175 verbose_name = "Sliver"
Siobhan Tully2d95e482013-09-06 10:56:06 -04001176 suit_classes = 'suit-tab suit-tab-networkslivers'
Scott Baker74d8e622013-07-29 16:04:22 -07001177
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001178class NetworkSlicesROInline(ReadOnlyTabularInline):
1179 model = NetworkSlice
1180 extra = 0
1181 verbose_name_plural = "Slices"
1182 verbose_name = "Slice"
1183 suit_classes = 'suit-tab suit-tab-networkslices'
1184 fields = ['network','slice']
1185
Scott Baker0165fac2014-01-13 11:49:26 -08001186class NetworkSlicesInline(PlStackTabularInline):
Scott Bakerd7d2a392013-08-06 08:57:30 -07001187 model = NetworkSlice
Scott Baker874936e2014-01-13 18:15:34 -08001188 selflink_fieldname = "slice"
Scott Bakerd7d2a392013-08-06 08:57:30 -07001189 extra = 0
1190 verbose_name_plural = "Slices"
1191 verbose_name = "Slice"
Siobhan Tully2d95e482013-09-06 10:56:06 -04001192 suit_classes = 'suit-tab suit-tab-networkslices'
Scott Bakerd7d2a392013-08-06 08:57:30 -07001193
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001194class NetworkAdmin(PlanetStackBaseAdmin):
Scott Baker74d8e622013-07-29 16:04:22 -07001195 list_display = ("name", "subnet", "ports", "labels")
1196 readonly_fields = ("subnet", )
Siobhan Tully2d95e482013-09-06 10:56:06 -04001197
Scott Bakerd7d2a392013-08-06 08:57:30 -07001198 inlines = [NetworkParameterInline, NetworkSliversInline, NetworkSlicesInline, RouterInline]
Scott Baker74d8e622013-07-29 16:04:22 -07001199
Siobhan Tully2d95e482013-09-06 10:56:06 -04001200 fieldsets = [
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001201 (None, {'fields': ['name','template','ports','labels','owner','guaranteedBandwidth', 'permitAllSlices','permittedSlices','network_id','router_id','subnet_id','subnet'], 'classes':['suit-tab suit-tab-general']}),]
1202
1203 user_readonly_fields = ['name','template','ports','labels','owner','guaranteedBandwidth', 'permitAllSlices','permittedSlices','network_id','router_id','subnet_id','subnet']
1204 user_readonly_inlines = [NetworkParameterROInline, NetworkSliversROInline, NetworkSlicesROInline, RouterROInline]
Siobhan Tully2d95e482013-09-06 10:56:06 -04001205
1206 suit_form_tabs =(
1207 ('general','Network Details'),
1208 ('netparams', 'Parameters'),
1209 ('networkslivers','Slivers'),
1210 ('networkslices','Slices'),
1211 ('routers','Routers'),
1212 )
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001213class NetworkTemplateAdmin(PlanetStackBaseAdmin):
Scott Baker74d8e622013-07-29 16:04:22 -07001214 list_display = ("name", "guaranteedBandwidth", "visibility")
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001215 user_readonly_fields = ["name", "guaranteedBandwidth", "visibility"]
1216 user_readonly_inlines = []
Scott Baker74d8e622013-07-29 16:04:22 -07001217
Tony Mack31c2b8f2013-04-26 20:01:42 -04001218# register a signal that caches the user's credentials when they log in
1219def cache_credentials(sender, user, request, **kwds):
1220 auth = {'username': request.POST['username'],
1221 'password': request.POST['password']}
1222 request.session['auth'] = auth
1223user_logged_in.connect(cache_credentials)
1224
Scott Baker15cddfa2013-12-09 13:45:19 -08001225def dollar_field(fieldName, short_description):
1226 def newFunc(self, obj):
1227 try:
1228 x= "$ %0.2f" % float(getattr(obj, fieldName, 0.0))
1229 except:
1230 x=getattr(obj, fieldName, 0.0)
1231 return x
1232 newFunc.short_description = short_description
1233 return newFunc
1234
1235def right_dollar_field(fieldName, short_description):
1236 def newFunc(self, obj):
1237 try:
1238 #x= '<div align=right style="width:6em">$ %0.2f</div>' % float(getattr(obj, fieldName, 0.0))
1239 x= '<div align=right>$ %0.2f</div>' % float(getattr(obj, fieldName, 0.0))
1240 except:
1241 x=getattr(obj, fieldName, 0.0)
1242 return x
1243 newFunc.short_description = short_description
1244 newFunc.allow_tags = True
1245 return newFunc
Scott Baker43105042013-12-06 23:23:36 -08001246
Scott Baker0165fac2014-01-13 11:49:26 -08001247class InvoiceChargeInline(PlStackTabularInline):
Scott Baker43105042013-12-06 23:23:36 -08001248 model = Charge
Scott Baker15cddfa2013-12-09 13:45:19 -08001249 extra = 0
Scott Baker43105042013-12-06 23:23:36 -08001250 verbose_name_plural = "Charges"
1251 verbose_name = "Charge"
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001252 exclude = ['account']
Scott Baker9cb88a22013-12-09 18:56:00 -08001253 fields = ["date", "kind", "state", "object", "coreHours", "dollar_amount", "slice"]
1254 readonly_fields = ["date", "kind", "state", "object", "coreHours", "dollar_amount", "slice"]
1255 can_delete = False
1256 max_num = 0
1257
1258 dollar_amount = right_dollar_field("amount", "Amount")
Scott Baker43105042013-12-06 23:23:36 -08001259
1260class InvoiceAdmin(admin.ModelAdmin):
1261 list_display = ("date", "account")
1262
1263 inlines = [InvoiceChargeInline]
1264
Scott Baker9cb88a22013-12-09 18:56:00 -08001265 fields = ["date", "account", "dollar_amount"]
1266 readonly_fields = ["date", "account", "dollar_amount"]
1267
1268 dollar_amount = dollar_field("amount", "Amount")
Scott Baker43105042013-12-06 23:23:36 -08001269
Scott Baker0165fac2014-01-13 11:49:26 -08001270class InvoiceInline(PlStackTabularInline):
Scott Baker15cddfa2013-12-09 13:45:19 -08001271 model = Invoice
1272 extra = 0
1273 verbose_name_plural = "Invoices"
1274 verbose_name = "Invoice"
Scott Baker0165fac2014-01-13 11:49:26 -08001275 fields = ["date", "dollar_amount"]
1276 readonly_fields = ["date", "dollar_amount"]
Scott Baker15cddfa2013-12-09 13:45:19 -08001277 suit_classes = 'suit-tab suit-tab-accountinvoice'
1278 can_delete=False
1279 max_num=0
1280
1281 dollar_amount = right_dollar_field("amount", "Amount")
1282
Scott Baker0165fac2014-01-13 11:49:26 -08001283class PendingChargeInline(PlStackTabularInline):
Scott Baker43105042013-12-06 23:23:36 -08001284 model = Charge
Scott Baker15cddfa2013-12-09 13:45:19 -08001285 extra = 0
Scott Baker43105042013-12-06 23:23:36 -08001286 verbose_name_plural = "Charges"
1287 verbose_name = "Charge"
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001288 exclude = ["invoice"]
Scott Baker15cddfa2013-12-09 13:45:19 -08001289 fields = ["date", "kind", "state", "object", "coreHours", "dollar_amount", "slice"]
1290 readonly_fields = ["date", "kind", "state", "object", "coreHours", "dollar_amount", "slice"]
Scott Baker43105042013-12-06 23:23:36 -08001291 suit_classes = 'suit-tab suit-tab-accountpendingcharges'
Scott Baker15cddfa2013-12-09 13:45:19 -08001292 can_delete=False
1293 max_num=0
Scott Baker43105042013-12-06 23:23:36 -08001294
1295 def queryset(self, request):
1296 qs = super(PendingChargeInline, self).queryset(request)
1297 qs = qs.filter(state="pending")
1298 return qs
1299
Scott Baker15cddfa2013-12-09 13:45:19 -08001300 dollar_amount = right_dollar_field("amount", "Amount")
1301
Scott Baker0165fac2014-01-13 11:49:26 -08001302class PaymentInline(PlStackTabularInline):
Scott Baker43105042013-12-06 23:23:36 -08001303 model=Payment
1304 extra = 1
1305 verbose_name_plural = "Payments"
1306 verbose_name = "Payment"
Scott Baker15cddfa2013-12-09 13:45:19 -08001307 fields = ["date", "dollar_amount"]
1308 readonly_fields = ["date", "dollar_amount"]
Scott Baker43105042013-12-06 23:23:36 -08001309 suit_classes = 'suit-tab suit-tab-accountpayments'
Scott Baker15cddfa2013-12-09 13:45:19 -08001310 can_delete=False
1311 max_num=0
1312
1313 dollar_amount = right_dollar_field("amount", "Amount")
1314
Scott Baker43105042013-12-06 23:23:36 -08001315class AccountAdmin(admin.ModelAdmin):
1316 list_display = ("site", "balance_due")
1317
1318 inlines = [InvoiceInline, PaymentInline, PendingChargeInline]
1319
1320 fieldsets = [
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001321 (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 -08001322
Scott Baker15cddfa2013-12-09 13:45:19 -08001323 readonly_fields = ['site', 'dollar_balance_due', 'dollar_total_invoices', 'dollar_total_payments']
Scott Baker43105042013-12-06 23:23:36 -08001324
1325 suit_form_tabs =(
1326 ('general','Account Details'),
1327 ('accountinvoice', 'Invoices'),
1328 ('accountpayments', 'Payments'),
1329 ('accountpendingcharges','Pending Charges'),
1330 )
1331
Scott Baker15cddfa2013-12-09 13:45:19 -08001332 dollar_balance_due = dollar_field("balance_due", "Balance Due")
1333 dollar_total_invoices = dollar_field("total_invoices", "Total Invoices")
1334 dollar_total_payments = dollar_field("total_payments", "Total Payments")
1335
Siobhan Tullyce652d02013-10-08 21:52:35 -04001336
Siobhan Tully53437282013-04-26 19:30:27 -04001337# Now register the new UserAdmin...
Siobhan Tully30fd4292013-05-10 08:59:56 -04001338admin.site.register(User, UserAdmin)
Siobhan Tully53437282013-04-26 19:30:27 -04001339# ... and, since we're not using Django's builtin permissions,
1340# unregister the Group model from admin.
Siobhan Tullyce652d02013-10-08 21:52:35 -04001341#admin.site.unregister(Group)
Siobhan Tully53437282013-04-26 19:30:27 -04001342
Siobhan Tullybf1153a2013-05-27 20:53:48 -04001343#Do not show django evolution in the admin interface
1344from django_evolution.models import Version, Evolution
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001345#admin.site.unregister(Version)
1346#admin.site.unregister(Evolution)
Siobhan Tullybf1153a2013-05-27 20:53:48 -04001347
1348
1349# When debugging it is often easier to see all the classes, but for regular use
1350# only the top-levels should be displayed
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001351showAll = False
Scott Baker43105042013-12-06 23:23:36 -08001352
Siobhan Tullybf1153a2013-05-27 20:53:48 -04001353admin.site.register(Deployment, DeploymentAdmin)
Siobhan Tully4bc09f22013-04-10 21:15:21 -04001354admin.site.register(Site, SiteAdmin)
Siobhan Tully4bc09f22013-04-10 21:15:21 -04001355admin.site.register(Slice, SliceAdmin)
Siobhan Tullyce652d02013-10-08 21:52:35 -04001356admin.site.register(Service, ServiceAdmin)
smbakera3cf70c2013-06-27 02:01:41 -07001357admin.site.register(Reservation, ReservationAdmin)
Scott Baker74d8e622013-07-29 16:04:22 -07001358admin.site.register(Network, NetworkAdmin)
1359admin.site.register(Router, RouterAdmin)
Scott Baker74d8e622013-07-29 16:04:22 -07001360admin.site.register(NetworkTemplate, NetworkTemplateAdmin)
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001361admin.site.register(Account, AccountAdmin)
1362admin.site.register(Invoice, InvoiceAdmin)
Siobhan Tullybf1153a2013-05-27 20:53:48 -04001363
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001364if True:
1365 admin.site.register(NetworkParameterType, NetworkParameterTypeAdmin)
1366 admin.site.register(ServiceClass, ServiceClassAdmin)
Siobhan Tullybfd11dc2013-09-03 12:59:24 -04001367 #admin.site.register(PlanetStack)
Siobhan Tullyd3515752013-06-21 16:34:53 -04001368 admin.site.register(Tag, TagAdmin)
Siobhan Tullyce652d02013-10-08 21:52:35 -04001369 admin.site.register(DeploymentRole)
1370 admin.site.register(SiteRole)
1371 admin.site.register(SliceRole)
1372 admin.site.register(PlanetStackRole)
Siobhan Tullybf1153a2013-05-27 20:53:48 -04001373 admin.site.register(Node, NodeAdmin)
Siobhan Tullybfd11dc2013-09-03 12:59:24 -04001374 #admin.site.register(SlicePrivilege, SlicePrivilegeAdmin)
1375 #admin.site.register(SitePrivilege, SitePrivilegeAdmin)
Siobhan Tullybf1153a2013-05-27 20:53:48 -04001376 admin.site.register(Sliver, SliverAdmin)
Siobhan Tullybf1153a2013-05-27 20:53:48 -04001377 admin.site.register(Image, ImageAdmin)
Tony Mack7130ac32013-03-22 21:58:00 -04001378