blob: 3b87dc888dabb6179652cd1fffa944c4054fe196 [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
Scott Baker526b71e2014-05-13 13:18:01 -0700813 if isinstance(inline, SliverInline):
814 inline.model.caller = request.user
815 yield inline.get_formset(request, obj)
Tony Mack53106f32013-04-27 16:43:01 -0400816
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500817 #def save_model(self, request, obj, form, change):
818 # # update openstack connection to use this site/tenant
819 # auth = request.session.get('auth', {})
820 # auth['tenant'] = obj.slice.name
821 # obj.os_manager = OpenStackManager(auth=auth, caller=request.user)
822 # obj.creator = request.user
823 # obj.save()
Tony Mack53106f32013-04-27 16:43:01 -0400824
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500825 #def delete_model(self, request, obj):
826 # # update openstack connection to use this site/tenant
827 # auth = request.session.get('auth', {})
828 # auth['tenant'] = obj.slice.name
829 # obj.os_manager = OpenStackManager(auth=auth, caller=request.user)
830 # obj.delete()
Tony Mackcdec0902013-04-15 00:38:49 -0400831
Siobhan Tully53437282013-04-26 19:30:27 -0400832class UserCreationForm(forms.ModelForm):
833 """A form for creating new users. Includes all the required
834 fields, plus a repeated password."""
835 password1 = forms.CharField(label='Password', widget=forms.PasswordInput)
836 password2 = forms.CharField(label='Password confirmation', widget=forms.PasswordInput)
837
838 class Meta:
Siobhan Tully30fd4292013-05-10 08:59:56 -0400839 model = User
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400840 fields = ('email', 'firstname', 'lastname', 'phone', 'public_key')
Siobhan Tully53437282013-04-26 19:30:27 -0400841
842 def clean_password2(self):
843 # Check that the two password entries match
844 password1 = self.cleaned_data.get("password1")
845 password2 = self.cleaned_data.get("password2")
846 if password1 and password2 and password1 != password2:
847 raise forms.ValidationError("Passwords don't match")
848 return password2
849
850 def save(self, commit=True):
851 # Save the provided password in hashed format
852 user = super(UserCreationForm, self).save(commit=False)
Tony Mackf9f4afb2013-05-01 21:02:12 -0400853 user.password = self.cleaned_data["password1"]
854 #user.set_password(self.cleaned_data["password1"])
Siobhan Tully53437282013-04-26 19:30:27 -0400855 if commit:
856 user.save()
857 return user
858
Siobhan Tully567e3e62013-06-21 18:03:16 -0400859
Siobhan Tully53437282013-04-26 19:30:27 -0400860class UserChangeForm(forms.ModelForm):
861 """A form for updating users. Includes all the fields on
862 the user, but replaces the password field with admin's
863 password hash display field.
864 """
Siobhan Tully63b7ba42014-01-12 10:35:11 -0500865 password = ReadOnlyPasswordHashField(label='Password',
866 help_text= '<a href=\"password/\">Change Password</a>.')
Siobhan Tully53437282013-04-26 19:30:27 -0400867
868 class Meta:
Siobhan Tully30fd4292013-05-10 08:59:56 -0400869 model = User
Siobhan Tully53437282013-04-26 19:30:27 -0400870
871 def clean_password(self):
872 # Regardless of what the user provides, return the initial value.
873 # This is done here, rather than on the field, because the
874 # field does not have access to the initial value
875 return self.initial["password"]
876
Tony Mack2bd5b412013-06-11 21:05:06 -0400877class UserAdmin(UserAdmin):
Siobhan Tully53437282013-04-26 19:30:27 -0400878 class Meta:
879 app_label = "core"
880
881 # The forms to add and change user instances
882 form = UserChangeForm
883 add_form = UserCreationForm
884
885 # The fields to be used in displaying the User model.
886 # These override the definitions on the base UserAdmin
887 # that reference specific fields on auth.User.
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500888 list_display = ('email', 'firstname', 'lastname', 'site', 'last_login')
Siobhan Tullyce652d02013-10-08 21:52:35 -0400889 #list_display = ('email', 'username','firstname', 'lastname', 'is_admin', 'last_login')
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500890 list_filter = ('site',)
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400891 inlines = [SlicePrivilegeInline,SitePrivilegeInline,DeploymentPrivilegeInline]
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500892
893 fieldListLoginDetails = ['email','site','password','is_readonly','is_amin','public_key']
894 fieldListContactInfo = ['firstname','lastname','phone','timezone']
895
Siobhan Tully53437282013-04-26 19:30:27 -0400896 fieldsets = (
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500897 ('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 -0400898 ('Contact Information', {'fields': ('firstname','lastname','phone', 'timezone'), 'classes':['suit-tab suit-tab-contact']}),
Siobhan Tully53437282013-04-26 19:30:27 -0400899 #('Important dates', {'fields': ('last_login',)}),
900 )
901 add_fieldsets = (
902 (None, {
903 'classes': ('wide',),
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500904 'fields': ('email', 'firstname', 'lastname', 'is_readonly', 'phone', 'public_key','password1', 'password2')}
Siobhan Tully53437282013-04-26 19:30:27 -0400905 ),
906 )
907 search_fields = ('email',)
908 ordering = ('email',)
909 filter_horizontal = ()
910
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500911 user_readonly_fields = fieldListLoginDetails
912 user_readonly_inlines = [SlicePrivilegeROInline,SitePrivilegeROInline,DeploymentPrivilegeROInline]
913
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400914 suit_form_tabs =(('general','Login Details'),('contact','Contact Information'),('sliceprivileges','Slice Privileges'),('siteprivileges','Site Privileges'),('deploymentprivileges','Deployment Privileges'))
915
Tony Mackc2835a92013-05-28 09:18:49 -0400916 def formfield_for_foreignkey(self, db_field, request, **kwargs):
917 if db_field.name == 'site':
Tony Mack5b061472014-02-04 07:57:10 -0500918 kwargs['queryset'] = Site.select_by_user(request.user)
Tony Mackc2835a92013-05-28 09:18:49 -0400919
920 return super(UserAdmin, self).formfield_for_foreignkey(db_field, request, **kwargs)
921
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500922 def has_add_permission(self, request, obj=None):
923 return (not self.__user_is_readonly(request))
924
925 def has_delete_permission(self, request, obj=None):
926 return (not self.__user_is_readonly(request))
927
928 def get_actions(self,request):
929 actions = super(UserAdmin,self).get_actions(request)
930
931 if self.__user_is_readonly(request):
932 if 'delete_selected' in actions:
933 del actions['delete_selected']
934
935 return actions
936
937 def change_view(self,request,object_id, extra_context=None):
938
939 if self.__user_is_readonly(request):
940 self.readonly_fields=self.user_readonly_fields
941 self.inlines = self.user_readonly_inlines
942 try:
943 return super(UserAdmin, self).change_view(request, object_id, extra_context=extra_context)
944 except PermissionDenied:
945 pass
946 if request.method == 'POST':
947 raise PermissionDenied
948 request.readonly = True
949 return super(UserAdmin, self).change_view(request, object_id, extra_context=extra_context)
950
951 def __user_is_readonly(self, request):
952 #groups = [x.name for x in request.user.groups.all() ]
953 #return "readonly" in groups
954 return request.user.isReadOnlyUser()
955
Tony Mack5b061472014-02-04 07:57:10 -0500956 def queryset(self, request):
957 return User.select_by_user(request.user)
958
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500959
960
961class ServiceResourceROInline(ReadOnlyTabularInline):
962 model = ServiceResource
963 extra = 0
964 fields = ['serviceClass', 'name', 'maxUnitsDeployment', 'maxUnitsNode', 'maxDuration', 'bucketInRate', 'bucketMaxSize', 'cost', 'calendarReservable']
965
Scott Baker0165fac2014-01-13 11:49:26 -0800966class ServiceResourceInline(PlStackTabularInline):
Scott Baker3de3e372013-05-10 16:50:44 -0700967 model = ServiceResource
968 extra = 0
969
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500970class ServiceClassAdmin(PlanetStackBaseAdmin):
Scott Baker3de3e372013-05-10 16:50:44 -0700971 list_display = ('name', 'commitment', 'membershipFee')
972 inlines = [ServiceResourceInline]
973
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500974 user_readonly_fields = ['name', 'commitment', 'membershipFee']
975 user_readonly_inlines = []
976
977class ReservedResourceROInline(ReadOnlyTabularInline):
978 model = ReservedResource
979 extra = 0
980 fields = ['sliver', 'resource','quantity','reservationSet']
981 suit_classes = 'suit-tab suit-tab-reservedresources'
982
Scott Baker0165fac2014-01-13 11:49:26 -0800983class ReservedResourceInline(PlStackTabularInline):
Scott Baker133c9212013-05-17 09:09:11 -0700984 model = ReservedResource
985 extra = 0
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400986 suit_classes = 'suit-tab suit-tab-reservedresources'
Scott Baker133c9212013-05-17 09:09:11 -0700987
988 def formfield_for_foreignkey(self, db_field, request=None, **kwargs):
989 field = super(ReservedResourceInline, self).formfield_for_foreignkey(db_field, request, **kwargs)
990
991 if db_field.name == 'resource':
992 # restrict resources to those that the slice's service class allows
993 if request._slice is not None:
994 field.queryset = field.queryset.filter(serviceClass = request._slice.serviceClass, calendarReservable=True)
995 if len(field.queryset) > 0:
996 field.initial = field.queryset.all()[0]
997 else:
998 field.queryset = field.queryset.none()
999 elif db_field.name == 'sliver':
1000 # restrict slivers to those that belong to the slice
1001 if request._slice is not None:
1002 field.queryset = field.queryset.filter(slice = request._slice)
1003 else:
1004 field.queryset = field.queryset.none()
1005
1006 return field
1007
Tony Mack5b061472014-02-04 07:57:10 -05001008 def queryset(self, request):
1009 return ReservedResource.select_by_user(request.user)
1010
Scott Baker133c9212013-05-17 09:09:11 -07001011class ReservationChangeForm(forms.ModelForm):
1012 class Meta:
1013 model = Reservation
Siobhan Tullybfd11dc2013-09-03 12:59:24 -04001014 widgets = {
1015 'slice' : LinkedSelect
1016 }
Scott Baker133c9212013-05-17 09:09:11 -07001017
1018class ReservationAddForm(forms.ModelForm):
1019 slice = forms.ModelChoiceField(queryset=Slice.objects.all(), widget=forms.Select(attrs={"onChange":"document.getElementById('id_refresh').value=1; submit()"}))
1020 refresh = forms.CharField(widget=forms.HiddenInput())
1021
1022 class Media:
1023 css = {'all': ('planetstack.css',)} # .field-refresh { display: none; }
1024
1025 def clean_slice(self):
1026 slice = self.cleaned_data.get("slice")
1027 x = ServiceResource.objects.filter(serviceClass = slice.serviceClass, calendarReservable=True)
1028 if len(x) == 0:
1029 raise forms.ValidationError("The slice you selected does not have a service class that allows reservations")
1030 return slice
1031
1032 class Meta:
1033 model = Reservation
Siobhan Tullybfd11dc2013-09-03 12:59:24 -04001034 widgets = {
1035 'slice' : LinkedSelect
1036 }
1037
Scott Baker133c9212013-05-17 09:09:11 -07001038
1039class ReservationAddRefreshForm(ReservationAddForm):
1040 """ This form is displayed when the Reservation Form receives an update
1041 from the Slice dropdown onChange handler. It doesn't validate the
1042 data and doesn't save the data. This will cause the form to be
1043 redrawn.
1044 """
1045
Scott Baker8737e5f2013-05-17 09:35:32 -07001046 """ don't validate anything other than slice """
1047 dont_validate_fields = ("startTime", "duration")
1048
Scott Baker133c9212013-05-17 09:09:11 -07001049 def full_clean(self):
1050 result = super(ReservationAddForm, self).full_clean()
Scott Baker8737e5f2013-05-17 09:35:32 -07001051
1052 for fieldname in self.dont_validate_fields:
1053 if fieldname in self._errors:
1054 del self._errors[fieldname]
1055
Scott Baker133c9212013-05-17 09:09:11 -07001056 return result
1057
1058 """ don't save anything """
1059 def is_valid(self):
1060 return False
1061
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001062class ReservationAdmin(PlanetStackBaseAdmin):
1063 fieldList = ['slice', 'startTime', 'duration']
1064 fieldsets = [('Reservation Details', {'fields': fieldList, 'classes': ['suit-tab suit-tab-general']})]
Scott Baker133c9212013-05-17 09:09:11 -07001065 list_display = ('startTime', 'duration')
Scott Baker133c9212013-05-17 09:09:11 -07001066 form = ReservationAddForm
1067
Siobhan Tullybfd11dc2013-09-03 12:59:24 -04001068 suit_form_tabs = (('general','Reservation Details'), ('reservedresources','Reserved Resources'))
1069
1070 inlines = [ReservedResourceInline]
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001071 user_readonly_inlines = [ReservedResourceROInline]
1072 user_readonly_fields = fieldList
Siobhan Tullybfd11dc2013-09-03 12:59:24 -04001073
Scott Baker133c9212013-05-17 09:09:11 -07001074 def add_view(self, request, form_url='', extra_context=None):
Scott Bakeracd45142013-05-19 16:19:16 -07001075 timezone.activate(request.user.timezone)
Scott Baker133c9212013-05-17 09:09:11 -07001076 request._refresh = False
1077 request._slice = None
1078 if request.method == 'POST':
Scott Baker8737e5f2013-05-17 09:35:32 -07001079 # "refresh" will be set to "1" if the form was submitted due to
1080 # a change in the Slice dropdown.
Scott Baker133c9212013-05-17 09:09:11 -07001081 if request.POST.get("refresh","1") == "1":
1082 request._refresh = True
1083 request.POST["refresh"] = "0"
Scott Baker8737e5f2013-05-17 09:35:32 -07001084
1085 # Keep track of the slice that was selected, so the
1086 # reservedResource inline can filter items for the slice.
Scott Baker133c9212013-05-17 09:09:11 -07001087 request._slice = request.POST.get("slice",None)
1088 if (request._slice is not None):
1089 request._slice = Slice.objects.get(id=request._slice)
1090
1091 result = super(ReservationAdmin, self).add_view(request, form_url, extra_context)
1092 return result
1093
Scott Bakeracd45142013-05-19 16:19:16 -07001094 def changelist_view(self, request, extra_context = None):
1095 timezone.activate(request.user.timezone)
1096 return super(ReservationAdmin, self).changelist_view(request, extra_context)
1097
Scott Baker133c9212013-05-17 09:09:11 -07001098 def get_form(self, request, obj=None, **kwargs):
Siobhan Tullyd3515752013-06-21 16:34:53 -04001099 request._obj_ = obj
1100 if obj is not None:
1101 # For changes, set request._slice to the slice already set in the
1102 # object.
1103 request._slice = obj.slice
1104 self.form = ReservationChangeForm
1105 else:
1106 if getattr(request, "_refresh", False):
1107 self.form = ReservationAddRefreshForm
1108 else:
1109 self.form = ReservationAddForm
1110 return super(ReservationAdmin, self).get_form(request, obj, **kwargs)
1111
Scott Baker133c9212013-05-17 09:09:11 -07001112 def get_readonly_fields(self, request, obj=None):
Siobhan Tullyd3515752013-06-21 16:34:53 -04001113 if (obj is not None):
1114 # Prevent slice from being changed after the reservation has been
1115 # created.
1116 return ['slice']
1117 else:
Scott Baker133c9212013-05-17 09:09:11 -07001118 return []
Scott Baker3de3e372013-05-10 16:50:44 -07001119
Tony Mack5b061472014-02-04 07:57:10 -05001120 def queryset(self, request):
1121 return Reservation.select_by_user(request.user)
1122
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001123class NetworkParameterTypeAdmin(PlanetStackBaseAdmin):
Scott Baker74d8e622013-07-29 16:04:22 -07001124 list_display = ("name", )
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001125 user_readonly_fields = ['name']
1126 user_readonly_inlines = []
Scott Baker74d8e622013-07-29 16:04:22 -07001127
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001128class RouterAdmin(PlanetStackBaseAdmin):
Scott Baker74d8e622013-07-29 16:04:22 -07001129 list_display = ("name", )
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001130 user_readonly_fields = ['name']
1131 user_readonly_inlines = []
1132
1133class RouterROInline(ReadOnlyTabularInline):
1134 model = Router.networks.through
1135 extra = 0
1136 verbose_name_plural = "Routers"
1137 verbose_name = "Router"
1138 suit_classes = 'suit-tab suit-tab-routers'
1139
1140 fields = ['name', 'owner', 'permittedNetworks', 'networks']
Scott Baker74d8e622013-07-29 16:04:22 -07001141
Scott Baker0165fac2014-01-13 11:49:26 -08001142class RouterInline(PlStackTabularInline):
Scott Baker74d8e622013-07-29 16:04:22 -07001143 model = Router.networks.through
1144 extra = 0
1145 verbose_name_plural = "Routers"
1146 verbose_name = "Router"
Siobhan Tully2d95e482013-09-06 10:56:06 -04001147 suit_classes = 'suit-tab suit-tab-routers'
Scott Baker74d8e622013-07-29 16:04:22 -07001148
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001149class NetworkParameterROInline(ReadOnlyTabularInline):
1150 model = NetworkParameter
1151 extra = 1
1152 verbose_name_plural = "Parameters"
1153 verbose_name = "Parameter"
1154 suit_classes = 'suit-tab suit-tab-netparams'
1155 fields = ['parameter', 'value', 'content_type', 'object_id', 'content_object']
1156
Scott Baker74d8e622013-07-29 16:04:22 -07001157class NetworkParameterInline(generic.GenericTabularInline):
Scott Baker74d8e622013-07-29 16:04:22 -07001158 model = NetworkParameter
1159 extra = 1
1160 verbose_name_plural = "Parameters"
1161 verbose_name = "Parameter"
Siobhan Tully2d95e482013-09-06 10:56:06 -04001162 suit_classes = 'suit-tab suit-tab-netparams'
Scott Baker74d8e622013-07-29 16:04:22 -07001163
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001164class NetworkSliversROInline(ReadOnlyTabularInline):
1165 fields = ['network', 'sliver', 'ip', 'port_id']
1166 model = NetworkSliver
1167 extra = 0
1168 verbose_name_plural = "Slivers"
1169 verbose_name = "Sliver"
1170 suit_classes = 'suit-tab suit-tab-networkslivers'
1171
Scott Baker0165fac2014-01-13 11:49:26 -08001172class NetworkSliversInline(PlStackTabularInline):
Scott Baker74d8e622013-07-29 16:04:22 -07001173 readonly_fields = ("ip", )
1174 model = NetworkSliver
Scott Baker874936e2014-01-13 18:15:34 -08001175 selflink_fieldname = "sliver"
Scott Baker74d8e622013-07-29 16:04:22 -07001176 extra = 0
1177 verbose_name_plural = "Slivers"
1178 verbose_name = "Sliver"
Siobhan Tully2d95e482013-09-06 10:56:06 -04001179 suit_classes = 'suit-tab suit-tab-networkslivers'
Scott Baker74d8e622013-07-29 16:04:22 -07001180
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001181class NetworkSlicesROInline(ReadOnlyTabularInline):
1182 model = NetworkSlice
1183 extra = 0
1184 verbose_name_plural = "Slices"
1185 verbose_name = "Slice"
1186 suit_classes = 'suit-tab suit-tab-networkslices'
1187 fields = ['network','slice']
1188
Scott Baker0165fac2014-01-13 11:49:26 -08001189class NetworkSlicesInline(PlStackTabularInline):
Scott Bakerd7d2a392013-08-06 08:57:30 -07001190 model = NetworkSlice
Scott Baker874936e2014-01-13 18:15:34 -08001191 selflink_fieldname = "slice"
Scott Bakerd7d2a392013-08-06 08:57:30 -07001192 extra = 0
1193 verbose_name_plural = "Slices"
1194 verbose_name = "Slice"
Siobhan Tully2d95e482013-09-06 10:56:06 -04001195 suit_classes = 'suit-tab suit-tab-networkslices'
Scott Bakerd7d2a392013-08-06 08:57:30 -07001196
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001197class NetworkAdmin(PlanetStackBaseAdmin):
Scott Baker74d8e622013-07-29 16:04:22 -07001198 list_display = ("name", "subnet", "ports", "labels")
1199 readonly_fields = ("subnet", )
Siobhan Tully2d95e482013-09-06 10:56:06 -04001200
Scott Bakerd7d2a392013-08-06 08:57:30 -07001201 inlines = [NetworkParameterInline, NetworkSliversInline, NetworkSlicesInline, RouterInline]
Scott Baker74d8e622013-07-29 16:04:22 -07001202
Siobhan Tully2d95e482013-09-06 10:56:06 -04001203 fieldsets = [
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001204 (None, {'fields': ['name','template','ports','labels','owner','guaranteedBandwidth', 'permitAllSlices','permittedSlices','network_id','router_id','subnet_id','subnet'], 'classes':['suit-tab suit-tab-general']}),]
1205
1206 user_readonly_fields = ['name','template','ports','labels','owner','guaranteedBandwidth', 'permitAllSlices','permittedSlices','network_id','router_id','subnet_id','subnet']
1207 user_readonly_inlines = [NetworkParameterROInline, NetworkSliversROInline, NetworkSlicesROInline, RouterROInline]
Siobhan Tully2d95e482013-09-06 10:56:06 -04001208
1209 suit_form_tabs =(
1210 ('general','Network Details'),
1211 ('netparams', 'Parameters'),
1212 ('networkslivers','Slivers'),
1213 ('networkslices','Slices'),
1214 ('routers','Routers'),
1215 )
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001216class NetworkTemplateAdmin(PlanetStackBaseAdmin):
Scott Baker74d8e622013-07-29 16:04:22 -07001217 list_display = ("name", "guaranteedBandwidth", "visibility")
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001218 user_readonly_fields = ["name", "guaranteedBandwidth", "visibility"]
1219 user_readonly_inlines = []
Scott Baker74d8e622013-07-29 16:04:22 -07001220
Tony Mack31c2b8f2013-04-26 20:01:42 -04001221# register a signal that caches the user's credentials when they log in
1222def cache_credentials(sender, user, request, **kwds):
1223 auth = {'username': request.POST['username'],
1224 'password': request.POST['password']}
1225 request.session['auth'] = auth
1226user_logged_in.connect(cache_credentials)
1227
Scott Baker15cddfa2013-12-09 13:45:19 -08001228def dollar_field(fieldName, short_description):
1229 def newFunc(self, obj):
1230 try:
1231 x= "$ %0.2f" % float(getattr(obj, fieldName, 0.0))
1232 except:
1233 x=getattr(obj, fieldName, 0.0)
1234 return x
1235 newFunc.short_description = short_description
1236 return newFunc
1237
1238def right_dollar_field(fieldName, short_description):
1239 def newFunc(self, obj):
1240 try:
1241 #x= '<div align=right style="width:6em">$ %0.2f</div>' % float(getattr(obj, fieldName, 0.0))
1242 x= '<div align=right>$ %0.2f</div>' % float(getattr(obj, fieldName, 0.0))
1243 except:
1244 x=getattr(obj, fieldName, 0.0)
1245 return x
1246 newFunc.short_description = short_description
1247 newFunc.allow_tags = True
1248 return newFunc
Scott Baker43105042013-12-06 23:23:36 -08001249
Scott Baker0165fac2014-01-13 11:49:26 -08001250class InvoiceChargeInline(PlStackTabularInline):
Scott Baker43105042013-12-06 23:23:36 -08001251 model = Charge
Scott Baker15cddfa2013-12-09 13:45:19 -08001252 extra = 0
Scott Baker43105042013-12-06 23:23:36 -08001253 verbose_name_plural = "Charges"
1254 verbose_name = "Charge"
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001255 exclude = ['account']
Scott Baker9cb88a22013-12-09 18:56:00 -08001256 fields = ["date", "kind", "state", "object", "coreHours", "dollar_amount", "slice"]
1257 readonly_fields = ["date", "kind", "state", "object", "coreHours", "dollar_amount", "slice"]
1258 can_delete = False
1259 max_num = 0
1260
1261 dollar_amount = right_dollar_field("amount", "Amount")
Scott Baker43105042013-12-06 23:23:36 -08001262
1263class InvoiceAdmin(admin.ModelAdmin):
1264 list_display = ("date", "account")
1265
1266 inlines = [InvoiceChargeInline]
1267
Scott Baker9cb88a22013-12-09 18:56:00 -08001268 fields = ["date", "account", "dollar_amount"]
1269 readonly_fields = ["date", "account", "dollar_amount"]
1270
1271 dollar_amount = dollar_field("amount", "Amount")
Scott Baker43105042013-12-06 23:23:36 -08001272
Scott Baker0165fac2014-01-13 11:49:26 -08001273class InvoiceInline(PlStackTabularInline):
Scott Baker15cddfa2013-12-09 13:45:19 -08001274 model = Invoice
1275 extra = 0
1276 verbose_name_plural = "Invoices"
1277 verbose_name = "Invoice"
Scott Baker0165fac2014-01-13 11:49:26 -08001278 fields = ["date", "dollar_amount"]
1279 readonly_fields = ["date", "dollar_amount"]
Scott Baker15cddfa2013-12-09 13:45:19 -08001280 suit_classes = 'suit-tab suit-tab-accountinvoice'
1281 can_delete=False
1282 max_num=0
1283
1284 dollar_amount = right_dollar_field("amount", "Amount")
1285
Scott Baker0165fac2014-01-13 11:49:26 -08001286class PendingChargeInline(PlStackTabularInline):
Scott Baker43105042013-12-06 23:23:36 -08001287 model = Charge
Scott Baker15cddfa2013-12-09 13:45:19 -08001288 extra = 0
Scott Baker43105042013-12-06 23:23:36 -08001289 verbose_name_plural = "Charges"
1290 verbose_name = "Charge"
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001291 exclude = ["invoice"]
Scott Baker15cddfa2013-12-09 13:45:19 -08001292 fields = ["date", "kind", "state", "object", "coreHours", "dollar_amount", "slice"]
1293 readonly_fields = ["date", "kind", "state", "object", "coreHours", "dollar_amount", "slice"]
Scott Baker43105042013-12-06 23:23:36 -08001294 suit_classes = 'suit-tab suit-tab-accountpendingcharges'
Scott Baker15cddfa2013-12-09 13:45:19 -08001295 can_delete=False
1296 max_num=0
Scott Baker43105042013-12-06 23:23:36 -08001297
1298 def queryset(self, request):
1299 qs = super(PendingChargeInline, self).queryset(request)
1300 qs = qs.filter(state="pending")
1301 return qs
1302
Scott Baker15cddfa2013-12-09 13:45:19 -08001303 dollar_amount = right_dollar_field("amount", "Amount")
1304
Scott Baker0165fac2014-01-13 11:49:26 -08001305class PaymentInline(PlStackTabularInline):
Scott Baker43105042013-12-06 23:23:36 -08001306 model=Payment
1307 extra = 1
1308 verbose_name_plural = "Payments"
1309 verbose_name = "Payment"
Scott Baker15cddfa2013-12-09 13:45:19 -08001310 fields = ["date", "dollar_amount"]
1311 readonly_fields = ["date", "dollar_amount"]
Scott Baker43105042013-12-06 23:23:36 -08001312 suit_classes = 'suit-tab suit-tab-accountpayments'
Scott Baker15cddfa2013-12-09 13:45:19 -08001313 can_delete=False
1314 max_num=0
1315
1316 dollar_amount = right_dollar_field("amount", "Amount")
1317
Scott Baker43105042013-12-06 23:23:36 -08001318class AccountAdmin(admin.ModelAdmin):
1319 list_display = ("site", "balance_due")
1320
1321 inlines = [InvoiceInline, PaymentInline, PendingChargeInline]
1322
1323 fieldsets = [
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001324 (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 -08001325
Scott Baker15cddfa2013-12-09 13:45:19 -08001326 readonly_fields = ['site', 'dollar_balance_due', 'dollar_total_invoices', 'dollar_total_payments']
Scott Baker43105042013-12-06 23:23:36 -08001327
1328 suit_form_tabs =(
1329 ('general','Account Details'),
1330 ('accountinvoice', 'Invoices'),
1331 ('accountpayments', 'Payments'),
1332 ('accountpendingcharges','Pending Charges'),
1333 )
1334
Scott Baker15cddfa2013-12-09 13:45:19 -08001335 dollar_balance_due = dollar_field("balance_due", "Balance Due")
1336 dollar_total_invoices = dollar_field("total_invoices", "Total Invoices")
1337 dollar_total_payments = dollar_field("total_payments", "Total Payments")
1338
Siobhan Tullyce652d02013-10-08 21:52:35 -04001339
Siobhan Tully53437282013-04-26 19:30:27 -04001340# Now register the new UserAdmin...
Siobhan Tully30fd4292013-05-10 08:59:56 -04001341admin.site.register(User, UserAdmin)
Siobhan Tully53437282013-04-26 19:30:27 -04001342# ... and, since we're not using Django's builtin permissions,
1343# unregister the Group model from admin.
Siobhan Tullyce652d02013-10-08 21:52:35 -04001344#admin.site.unregister(Group)
Siobhan Tully53437282013-04-26 19:30:27 -04001345
Siobhan Tullybf1153a2013-05-27 20:53:48 -04001346#Do not show django evolution in the admin interface
1347from django_evolution.models import Version, Evolution
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001348#admin.site.unregister(Version)
1349#admin.site.unregister(Evolution)
Siobhan Tullybf1153a2013-05-27 20:53:48 -04001350
1351
1352# When debugging it is often easier to see all the classes, but for regular use
1353# only the top-levels should be displayed
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001354showAll = False
Scott Baker43105042013-12-06 23:23:36 -08001355
Siobhan Tullybf1153a2013-05-27 20:53:48 -04001356admin.site.register(Deployment, DeploymentAdmin)
Siobhan Tully4bc09f22013-04-10 21:15:21 -04001357admin.site.register(Site, SiteAdmin)
Siobhan Tully4bc09f22013-04-10 21:15:21 -04001358admin.site.register(Slice, SliceAdmin)
Siobhan Tullyce652d02013-10-08 21:52:35 -04001359admin.site.register(Service, ServiceAdmin)
smbakera3cf70c2013-06-27 02:01:41 -07001360admin.site.register(Reservation, ReservationAdmin)
Scott Baker74d8e622013-07-29 16:04:22 -07001361admin.site.register(Network, NetworkAdmin)
1362admin.site.register(Router, RouterAdmin)
Scott Baker74d8e622013-07-29 16:04:22 -07001363admin.site.register(NetworkTemplate, NetworkTemplateAdmin)
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001364admin.site.register(Account, AccountAdmin)
1365admin.site.register(Invoice, InvoiceAdmin)
Siobhan Tullybf1153a2013-05-27 20:53:48 -04001366
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001367if True:
1368 admin.site.register(NetworkParameterType, NetworkParameterTypeAdmin)
1369 admin.site.register(ServiceClass, ServiceClassAdmin)
Siobhan Tullybfd11dc2013-09-03 12:59:24 -04001370 #admin.site.register(PlanetStack)
Siobhan Tullyd3515752013-06-21 16:34:53 -04001371 admin.site.register(Tag, TagAdmin)
Siobhan Tullyce652d02013-10-08 21:52:35 -04001372 admin.site.register(DeploymentRole)
1373 admin.site.register(SiteRole)
1374 admin.site.register(SliceRole)
1375 admin.site.register(PlanetStackRole)
Siobhan Tullybf1153a2013-05-27 20:53:48 -04001376 admin.site.register(Node, NodeAdmin)
Siobhan Tullybfd11dc2013-09-03 12:59:24 -04001377 #admin.site.register(SlicePrivilege, SlicePrivilegeAdmin)
1378 #admin.site.register(SitePrivilege, SitePrivilegeAdmin)
Siobhan Tullybf1153a2013-05-27 20:53:48 -04001379 admin.site.register(Sliver, SliverAdmin)
Siobhan Tullybf1153a2013-05-27 20:53:48 -04001380 admin.site.register(Image, ImageAdmin)
Tony Mack7130ac32013-03-22 21:58:00 -04001381