blob: 996e22d860b2738f0cfccc4bd8e67d705b187640 [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):
46
47 if self.__user_is_readonly(request):
48 self.readonly_fields=self.user_readonly_fields
49 self.inlines = self.user_readonly_inlines
50
51 try:
52 return super(ReadOnlyAwareAdmin, self).change_view(request, object_id, extra_context=extra_context)
53 except PermissionDenied:
54 pass
55 if request.method == 'POST':
56 raise PermissionDenied
57 request.readonly = True
58 return super(ReadOnlyAwareAdmin, self).change_view(request, object_id, extra_context=extra_context)
59
60
61 def __user_is_readonly(self, request):
62 return request.user.isReadOnlyUser()
63
Siobhan Tullyce652d02013-10-08 21:52:35 -040064class SingletonAdmin (admin.ModelAdmin):
65 def has_add_permission(self, request):
66 num_objects = self.model.objects.count()
67 if num_objects >= 1:
68 return False
69 else:
70 return True
71
72
Siobhan Tullyd3515752013-06-21 16:34:53 -040073class PlStackTabularInline(admin.TabularInline):
Scott Baker86568322014-01-12 16:53:31 -080074 def __init__(self, *args, **kwargs):
75 super(PlStackTabularInline, self).__init__(*args, **kwargs)
76
77 # InlineModelAdmin as no get_fields() method, so in order to add
78 # the selflink field, we override __init__ to modify self.fields and
79 # self.readonly_fields.
80
Scott Bakere2bbf7e2014-01-13 12:09:31 -080081 self.setup_selflink()
82
Scott Baker874936e2014-01-13 18:15:34 -080083 def get_change_url(self, model, id):
84 """ Get the URL to a change form in the admin for this model """
85 reverse_path = "admin:%s_change" % (model._meta.db_table)
Scott Bakere2bbf7e2014-01-13 12:09:31 -080086 try:
Scott Baker874936e2014-01-13 18:15:34 -080087 url = reverse(reverse_path, args=(id,))
Scott Bakere2bbf7e2014-01-13 12:09:31 -080088 except NoReverseMatch:
Scott Baker874936e2014-01-13 18:15:34 -080089 return None
90
91 return url
92
93 def setup_selflink(self):
94 if hasattr(self, "selflink_fieldname"):
95 """ self.selflink_model can be defined to punch through a relation
96 to its target object. For example, in SliceNetworkInline, set
97 selflink_model = "network", and the URL will lead to the Network
98 object instead of trying to bring up a change view of the
99 SliceNetwork object.
100 """
101 self.selflink_model = getattr(self.model,self.selflink_fieldname).field.rel.to
102 else:
103 self.selflink_model = self.model
104
105 url = self.get_change_url(self.selflink_model, 0)
106
107 # We don't have an admin for this object, so don't create the
108 # selflink.
109 if (url == None):
Scott Bakere2bbf7e2014-01-13 12:09:31 -0800110 return
111
Scott Baker874936e2014-01-13 18:15:34 -0800112 # Since we need to add "selflink" to the field list, we need to create
113 # self.fields if it is None.
Scott Baker0165fac2014-01-13 11:49:26 -0800114 if (self.fields is None):
115 self.fields = []
116 for f in self.model._meta.fields:
117 if f.editable and f.name != "id":
118 self.fields.append(f.name)
Scott Baker86568322014-01-12 16:53:31 -0800119
Scott Baker874936e2014-01-13 18:15:34 -0800120 self.fields = tuple(self.fields) + ("selflink", )
Scott Baker86568322014-01-12 16:53:31 -0800121
Scott Baker874936e2014-01-13 18:15:34 -0800122 if self.readonly_fields is None:
123 self.readonly_fields = ()
Scott Baker86568322014-01-12 16:53:31 -0800124
Scott Baker874936e2014-01-13 18:15:34 -0800125 self.readonly_fields = tuple(self.readonly_fields) + ("selflink", )
Scott Baker86568322014-01-12 16:53:31 -0800126
127 def selflink(self, obj):
Scott Baker874936e2014-01-13 18:15:34 -0800128 if hasattr(self, "selflink_fieldname"):
129 obj = getattr(obj, self.selflink_fieldname)
130
Scott Baker86568322014-01-12 16:53:31 -0800131 if obj.id:
Scott Baker874936e2014-01-13 18:15:34 -0800132 url = self.get_change_url(self.selflink_model, obj.id)
133 return "<a href='%s'>Details</a>" % str(url)
Scott Baker86568322014-01-12 16:53:31 -0800134 else:
Scott Bakere2bbf7e2014-01-13 12:09:31 -0800135 return "Not present"
Scott Baker86568322014-01-12 16:53:31 -0800136
137 selflink.allow_tags = True
138 selflink.short_description = "Details"
Siobhan Tullyd3515752013-06-21 16:34:53 -0400139
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500140class ReadOnlyTabularInline(PlStackTabularInline):
141 can_delete = False
142
143 def get_readonly_fields(self, request, obj=None):
144 return self.fields
145
146 def has_add_permission(self, request):
147 return False
148
149class ReservationROInline(ReadOnlyTabularInline):
150 model = Reservation
151 extra = 0
152 suit_classes = 'suit-tab suit-tab-reservations'
153 fields = ['startTime','slice','duration']
154
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400155class ReservationInline(PlStackTabularInline):
156 model = Reservation
157 extra = 0
158 suit_classes = 'suit-tab suit-tab-reservations'
Tony Mack5b061472014-02-04 07:57:10 -0500159
160 def queryset(self, request):
161 return Reservation.select_by_user(request.user)
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400162
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500163class TagROInline(generic.GenericTabularInline):
164 model = Tag
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400165 extra = 0
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500166 suit_classes = 'suit-tab suit-tab-tags'
167 can_delete = False
168 fields = ['service', 'name', 'value']
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400169
170 def get_readonly_fields(self, request, obj=None):
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500171 return self.fields
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400172
173 def has_add_permission(self, request):
174 return False
175
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500176
Siobhan Tullyde5450d2013-06-21 11:35:33 -0400177class TagInline(generic.GenericTabularInline):
178 model = Tag
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400179 extra = 0
180 suit_classes = 'suit-tab suit-tab-tags'
Tony Mack5b061472014-02-04 07:57:10 -0500181 fields = ['service', 'name', 'value']
182
183 def queryset(self, request):
184 return Tag.select_by_user(request.user)
Siobhan Tullyde5450d2013-06-21 11:35:33 -0400185
Scott Baker74d8e622013-07-29 16:04:22 -0700186class NetworkLookerUpper:
Siobhan Tully2c780ad2013-09-06 11:22:40 -0400187 """ This is a callable that looks up a network name in a sliver and returns
188 the ip address for that network.
189 """
190
191 def __init__(self, name):
192 self.short_description = name
193 self.__name__ = name
194 self.network_name = name
195
196 def __call__(self, obj):
197 if obj is not None:
198 for nbs in obj.networksliver_set.all():
199 if (nbs.network.name == self.network_name):
200 return nbs.ip
Scott Baker74d8e622013-07-29 16:04:22 -0700201 return ""
202
203 def __str__(self):
204 return self.network_name
205
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500206class SliverROInline(ReadOnlyTabularInline):
207 model = Sliver
208 fields = ['ip', 'instance_name', 'slice', 'numberCores', 'image', 'node', 'deploymentNetwork']
209 suit_classes = 'suit-tab suit-tab-slivers'
210
Siobhan Tullyd3515752013-06-21 16:34:53 -0400211class SliverInline(PlStackTabularInline):
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400212 model = Sliver
Tony Mackb0d97422013-06-10 09:57:45 -0400213 fields = ['ip', 'instance_name', 'slice', 'numberCores', 'image', 'node', 'deploymentNetwork']
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400214 extra = 0
Tony Mack3777b012013-05-07 21:38:06 -0400215 readonly_fields = ['ip', 'instance_name']
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400216 suit_classes = 'suit-tab suit-tab-slivers'
Scott Baker74d8e622013-07-29 16:04:22 -0700217
Tony Mack5b061472014-02-04 07:57:10 -0500218 def queryset(self, request):
219 return Sliver.select_by_user(request.user)
220
Siobhan Tully2d95e482013-09-06 10:56:06 -0400221# Note this is breaking in the admin.py when trying to use an inline to add a node/image
222# def _declared_fieldsets(self):
223# # Return None so django will call get_fieldsets and we can insert our
224# # dynamic fields
225# return None
226#
227# def get_readonly_fields(self, request, obj=None):
228# readonly_fields = super(SliverInline, self).get_readonly_fields(request, obj)
229#
230# # Lookup the networks that are bound to the slivers, and add those
231# # network names to the list of readonly fields.
232#
233# for sliver in obj.slivers.all():
234# for nbs in sliver.networksliver_set.all():
235# if nbs.ip:
236# network_name = nbs.network.name
237# if network_name not in [str(x) for x in readonly_fields]:
238# readonly_fields.append(NetworkLookerUpper(network_name))
239#
240# return readonly_fields
241#
242# def get_fieldsets(self, request, obj=None):
243# form = self.get_formset(request, obj).form
244# # fields = the read/write files + the read-only fields
245# fields = self.fields
246# for fieldName in self.get_readonly_fields(request,obj):
247# if not fieldName in fields:
248# fields.append(fieldName)
249#
250# return [(None, {'fields': fields})]
Scott Baker74d8e622013-07-29 16:04:22 -0700251
Tony Mackc2835a92013-05-28 09:18:49 -0400252
Siobhan Tully567e3e62013-06-21 18:03:16 -0400253
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500254class SiteROInline(ReadOnlyTabularInline):
255 model = Site
256 extra = 0
257 fields = ['name', 'login_base', 'site_url', 'enabled']
258 suit_classes = 'suit-tab suit-tab-sites'
259
Siobhan Tullyd3515752013-06-21 16:34:53 -0400260class SiteInline(PlStackTabularInline):
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400261 model = Site
262 extra = 0
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400263 suit_classes = 'suit-tab suit-tab-sites'
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400264
Tony Mack5b061472014-02-04 07:57:10 -0500265 def queryset(self, request):
266 return Site.select_by_user(request.user)
267
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500268class UserROInline(ReadOnlyTabularInline):
269 model = User
270 fields = ['email', 'firstname', 'lastname']
271 extra = 0
272 suit_classes = 'suit-tab suit-tab-users'
273
Siobhan Tullyd3515752013-06-21 16:34:53 -0400274class UserInline(PlStackTabularInline):
Siobhan Tully30fd4292013-05-10 08:59:56 -0400275 model = User
Siobhan Tully47ae1b52013-05-10 15:53:14 -0400276 fields = ['email', 'firstname', 'lastname']
Siobhan Tully30fd4292013-05-10 08:59:56 -0400277 extra = 0
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400278 suit_classes = 'suit-tab suit-tab-users'
Siobhan Tully30fd4292013-05-10 08:59:56 -0400279
Tony Mack5b061472014-02-04 07:57:10 -0500280 def queryset(self, request):
281 return User.select_by_user(request.user)
282
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500283class SliceROInline(ReadOnlyTabularInline):
284 model = Slice
285 suit_classes = 'suit-tab suit-tab-slices'
286 fields = ['name','site', 'serviceClass', 'service']
287
Siobhan Tullyd3515752013-06-21 16:34:53 -0400288class SliceInline(PlStackTabularInline):
Tony Mack00d361f2013-04-28 10:28:42 -0400289 model = Slice
Siobhan Tullyce652d02013-10-08 21:52:35 -0400290 fields = ['name','site', 'serviceClass', 'service']
Tony Mack00d361f2013-04-28 10:28:42 -0400291 extra = 0
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400292 suit_classes = 'suit-tab suit-tab-slices'
293
Tony Mack5b061472014-02-04 07:57:10 -0500294 def queryset(self, request):
295 return Slice.select_by_user(request.user)
296
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500297class NodeROInline(ReadOnlyTabularInline):
298 model = Node
299 extra = 0
300 suit_classes = 'suit-tab suit-tab-nodes'
301 fields = ['name','deployment']
Tony Mack00d361f2013-04-28 10:28:42 -0400302
Siobhan Tullyd3515752013-06-21 16:34:53 -0400303class NodeInline(PlStackTabularInline):
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400304 model = Node
305 extra = 0
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400306 suit_classes = 'suit-tab suit-tab-nodes'
Tony Mack5b061472014-02-04 07:57:10 -0500307 fields = ['name','deployment']
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400308
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500309class DeploymentPrivilegeROInline(ReadOnlyTabularInline):
310 model = DeploymentPrivilege
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400311 extra = 0
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500312 suit_classes = 'suit-tab suit-tab-deploymentprivileges'
313 fields = ['user','role']
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400314
315class DeploymentPrivilegeInline(PlStackTabularInline):
316 model = DeploymentPrivilege
317 extra = 0
318 suit_classes = 'suit-tab suit-tab-deploymentprivileges'
Tony Mack5b061472014-02-04 07:57:10 -0500319 fields = ['user','role']
320
321 def queryset(self, request):
322 return DeploymentPrivilege.select_by_user(request.user)
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400323
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500324#CLEANUP DOUBLE SitePrivilegeInline
325class SitePrivilegeROInline(ReadOnlyTabularInline):
326 model = SitePrivilege
327 extra = 0
328 suit_classes = 'suit-tab suit-tab-siteprivileges'
329 fields = ['user','site', 'role']
330
Siobhan Tullyd3515752013-06-21 16:34:53 -0400331class SitePrivilegeInline(PlStackTabularInline):
Siobhan Tullyaa1bcd52013-05-10 12:43:09 -0400332 model = SitePrivilege
333 extra = 0
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400334 suit_classes = 'suit-tab suit-tab-siteprivileges'
Tony Mack5b061472014-02-04 07:57:10 -0500335 fields = ['user','site', 'role']
Siobhan Tullyaa1bcd52013-05-10 12:43:09 -0400336
Tony Mackc2835a92013-05-28 09:18:49 -0400337 def formfield_for_foreignkey(self, db_field, request, **kwargs):
338 if db_field.name == 'site':
Tony Mack5b061472014-02-04 07:57:10 -0500339 kwargs['queryset'] = Site.select_by_user(request.user)
Tony Mackc2835a92013-05-28 09:18:49 -0400340
341 if db_field.name == 'user':
Tony Mack5b061472014-02-04 07:57:10 -0500342 kwargs['queryset'] = User.select_by_user(request.user)
Tony Mackc2835a92013-05-28 09:18:49 -0400343 return super(SitePrivilegeInline, self).formfield_for_foreignkey(db_field, request, **kwargs)
344
Tony Mack5b061472014-02-04 07:57:10 -0500345 def queryset(self, request):
346 return SitePrivilege.select_by_user(request.user)
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400347
Tony Macke4be32f2014-03-11 20:45:25 -0400348class SiteDeploymentROInline(ReadOnlyTabularInline):
349 model = SiteDeployments
350 #model = Site.deployments.through
351 extra = 0
352 suit_classes = 'suit-tab suit-tab-sitedeployments'
353 fields = ['deployment','site']
354
355class SiteDeploymentInline(PlStackTabularInline):
356 model = SiteDeployments
357 #model = Site.deployments.through
358 extra = 0
359 suit_classes = 'suit-tab suit-tab-deployments'
360 fields = ['deployment','site']
361
362 def formfield_for_foreignkey(self, db_field, request, **kwargs):
363 if db_field.name == 'site':
364 kwargs['queryset'] = Site.select_by_user(request.user)
365
366 if db_field.name == 'deployment':
367 kwargs['queryset'] = Deployment.select_by_user(request.user)
368 return super(SiteDeploymentInline, self).formfield_for_foreignkey(db_field, request, **kwargs)
369
370 def queryset(self, request):
371 return SiteDeployments.select_by_user(request.user)
372
373
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500374class SlicePrivilegeROInline(ReadOnlyTabularInline):
375 model = SlicePrivilege
376 extra = 0
377 suit_classes = 'suit-tab suit-tab-sliceprivileges'
378 fields = ['user', 'slice', 'role']
379
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400380class SlicePrivilegeInline(PlStackTabularInline):
381 model = SlicePrivilege
382 suit_classes = 'suit-tab suit-tab-sliceprivileges'
383 extra = 0
384 fields = ('user', 'slice','role')
Siobhan Tullyaa1bcd52013-05-10 12:43:09 -0400385
Tony Mackc2835a92013-05-28 09:18:49 -0400386 def formfield_for_foreignkey(self, db_field, request, **kwargs):
387 if db_field.name == 'slice':
Tony Mack5b061472014-02-04 07:57:10 -0500388 kwargs['queryset'] = Slice.select_by_user(request.user)
Tony Mackc2835a92013-05-28 09:18:49 -0400389 if db_field.name == 'user':
Tony Mack5b061472014-02-04 07:57:10 -0500390 kwargs['queryset'] = User.select_by_user(request.user)
Tony Mackc2835a92013-05-28 09:18:49 -0400391
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400392 return super(SlicePrivilegeInline, self).formfield_for_foreignkey(db_field, request, **kwargs)
Tony Mackc2835a92013-05-28 09:18:49 -0400393
Tony Mack5b061472014-02-04 07:57:10 -0500394 def queryset(self, request):
395 return SlicePrivilege.select_by_user(request.user)
396
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500397class SliceNetworkROInline(ReadOnlyTabularInline):
398 model = Network.slices.through
399 extra = 0
400 verbose_name = "Network Connection"
401 verbose_name_plural = "Network Connections"
402 suit_classes = 'suit-tab suit-tab-slicenetworks'
403 fields = ['network']
404
Scott Bakera0015eb2013-08-14 17:28:14 -0700405class SliceNetworkInline(PlStackTabularInline):
Scott Baker74d8e622013-07-29 16:04:22 -0700406 model = Network.slices.through
Scott Baker874936e2014-01-13 18:15:34 -0800407 selflink_fieldname = "network"
Scott Baker74d8e622013-07-29 16:04:22 -0700408 extra = 0
409 verbose_name = "Network Connection"
410 verbose_name_plural = "Network Connections"
Siobhan Tully2d95e482013-09-06 10:56:06 -0400411 suit_classes = 'suit-tab suit-tab-slicenetworks'
Scott Baker74d8e622013-07-29 16:04:22 -0700412
Tony Mack5e71a662013-05-03 23:30:41 -0400413class PlainTextWidget(forms.HiddenInput):
414 input_type = 'hidden'
415
416 def render(self, name, value, attrs=None):
417 if value is None:
418 value = ''
Tony Mack1d6b85f2013-05-07 18:49:14 -0400419 return mark_safe(str(value) + super(PlainTextWidget, self).render(name, value, attrs))
Tony Mack9bcbe4f2013-04-29 08:13:27 -0400420
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500421class PlanetStackBaseAdmin(ReadOnlyAwareAdmin):
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400422 save_on_top = False
Tony Mack332ee1d2014-02-04 15:33:45 -0500423
424 def save_model(self, request, obj, form, change):
425 # update openstack connection to use this site/tenant
426 obj.save_by_user(request.user)
427
428 def delete_model(self, request, obj):
429 obj.delete_by_user(request.user)
430
431 def save_formset(self, request, form, formset, change):
432 instances = formset.save(commit=False)
433 for instance in instances:
434 instance.save_by_user(request.user)
435 formset.save_m2m()
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400436
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400437class SliceRoleAdmin(PlanetStackBaseAdmin):
438 model = SliceRole
439 pass
440
441class SiteRoleAdmin(PlanetStackBaseAdmin):
442 model = SiteRole
443 pass
444
Siobhan Tullybf1153a2013-05-27 20:53:48 -0400445class DeploymentAdminForm(forms.ModelForm):
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400446 sites = forms.ModelMultipleChoiceField(
447 queryset=Site.objects.all(),
448 required=False,
449 widget=FilteredSelectMultiple(
450 verbose_name=('Sites'), is_stacked=False
451 )
452 )
453 class Meta:
Siobhan Tullybf1153a2013-05-27 20:53:48 -0400454 model = Deployment
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400455
Siobhan Tully320b4622014-01-17 15:11:14 -0500456 def __init__(self, *args, **kwargs):
457 super(DeploymentAdminForm, self).__init__(*args, **kwargs)
458
459 if self.instance and self.instance.pk:
460 self.fields['sites'].initial = self.instance.sites.all()
461
462 def save(self, commit=True):
463 deployment = super(DeploymentAdminForm, self).save(commit=False)
464
465 if commit:
466 deployment.save()
467
468 if deployment.pk:
469 deployment.sites = self.cleaned_data['sites']
470 self.save_m2m()
471
472 return deployment
473
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500474class SiteAssocInline(PlStackTabularInline):
475 model = Site.deployments.through
476 extra = 0
477 suit_classes = 'suit-tab suit-tab-sites'
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400478
Siobhan Tullybf1153a2013-05-27 20:53:48 -0400479class DeploymentAdmin(PlanetStackBaseAdmin):
480 form = DeploymentAdminForm
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500481 model = Deployment
482 fieldList = ['name','sites']
483 fieldsets = [(None, {'fields': fieldList, 'classes':['suit-tab suit-tab-sites']})]
Siobhan Tully2d95e482013-09-06 10:56:06 -0400484 inlines = [DeploymentPrivilegeInline,NodeInline,TagInline]
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500485
486 user_readonly_inlines = [DeploymentPrivilegeROInline,NodeROInline,TagROInline]
487 user_readonly_fields = ['name']
488
489 suit_form_tabs =(('sites','Deployment Details'),('nodes','Nodes'),('deploymentprivileges','Privileges'),('tags','Tags'))
490
491class ServiceAttrAsTabROInline(ReadOnlyTabularInline):
492 model = ServiceAttribute
493 fields = ['name','value']
494 extra = 0
495 suit_classes = 'suit-tab suit-tab-serviceattrs'
Tony Mack5cd13202013-05-01 21:48:38 -0400496
Siobhan Tullyce652d02013-10-08 21:52:35 -0400497class ServiceAttrAsTabInline(PlStackTabularInline):
498 model = ServiceAttribute
499 fields = ['name','value']
500 extra = 0
501 suit_classes = 'suit-tab suit-tab-serviceattrs'
502
Siobhan Tullyce652d02013-10-08 21:52:35 -0400503class ServiceAdmin(PlanetStackBaseAdmin):
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500504 list_display = ("name","description","versionNumber","enabled","published")
505 fieldList = ["name","description","versionNumber","enabled","published"]
506 fieldsets = [(None, {'fields': fieldList, 'classes':['suit-tab suit-tab-general']})]
507 inlines = [ServiceAttrAsTabInline,SliceInline]
508
509 user_readonly_fields = fieldList
510 user_readonly_inlines = [ServiceAttrAsTabROInline,SliceROInline]
511
512 suit_form_tabs =(('general', 'Service Details'),
513 ('slices','Slices'),
514 ('serviceattrs','Additional Attributes'),
515 )
Siobhan Tullyce652d02013-10-08 21:52:35 -0400516
Tony Mack0553f282013-06-10 22:54:50 -0400517class SiteAdmin(PlanetStackBaseAdmin):
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500518 fieldList = ['name', 'site_url', 'enabled', 'is_public', 'login_base', 'accountLink','location']
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400519 fieldsets = [
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500520 (None, {'fields': fieldList, 'classes':['suit-tab suit-tab-general']}),
Tony Macke4be32f2014-03-11 20:45:25 -0400521 #('Deployment Networks', {'fields': ['deployments'], 'classes':['suit-tab suit-tab-deployments']}),
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400522 ]
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400523 suit_form_tabs =(('general', 'Site Details'),
524 ('users','Users'),
Siobhan Tully2d95e482013-09-06 10:56:06 -0400525 ('siteprivileges','Privileges'),
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400526 ('deployments','Deployments'),
527 ('slices','Slices'),
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500528 ('nodes','Nodes'),
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400529 ('tags','Tags'),
530 )
Scott Baker545db2a2013-12-09 18:44:43 -0800531 readonly_fields = ['accountLink']
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500532
533 user_readonly_fields = ['name', 'deployments','site_url', 'enabled', 'is_public', 'login_base', 'accountLink']
Tony Macke4be32f2014-03-11 20:45:25 -0400534 user_readonly_inlines = [SliceROInline,UserROInline,TagROInline, NodeROInline, SitePrivilegeROInline,SiteDeploymentROInline]
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500535
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400536 list_display = ('name', 'login_base','site_url', 'enabled')
537 filter_horizontal = ('deployments',)
Tony Macke4be32f2014-03-11 20:45:25 -0400538 inlines = [SliceInline,UserInline,TagInline, NodeInline, SitePrivilegeInline, SiteDeploymentInline]
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400539 search_fields = ['name']
540
Tony Mack04062832013-05-10 08:22:44 -0400541 def queryset(self, request):
Tony Mack5b061472014-02-04 07:57:10 -0500542 #print dir(UserInline)
543 return Site.select_by_user(request.user)
Tony Mack04062832013-05-10 08:22:44 -0400544
Tony Mack5cd13202013-05-01 21:48:38 -0400545 def get_formsets(self, request, obj=None):
546 for inline in self.get_inline_instances(request, obj):
547 # hide MyInline in the add view
548 if obj is None:
549 continue
Tony Mack2bd5b412013-06-11 21:05:06 -0400550 if isinstance(inline, SliceInline):
551 inline.model.caller = request.user
552 yield inline.get_formset(request, obj)
553
554 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
559 if isinstance(inline, SliverInline):
560 inline.model.caller = request.user
Tony Mack5cd13202013-05-01 21:48:38 -0400561 yield inline.get_formset(request, obj)
562
Scott Baker545db2a2013-12-09 18:44:43 -0800563 def accountLink(self, obj):
564 link_obj = obj.accounts.all()
565 if link_obj:
566 reverse_path = "admin:core_account_change"
567 url = reverse(reverse_path, args =(link_obj[0].id,))
568 return "<a href='%s'>%s</a>" % (url, "view billing details")
569 else:
570 return "no billing data for this site"
571 accountLink.allow_tags = True
572 accountLink.short_description = "Billing"
573
Tony Mack332ee1d2014-02-04 15:33:45 -0500574 def save_model(self, request, obj, form, change):
575 # update openstack connection to use this site/tenant
576 obj.save_by_user(request.user)
577
578 def delete_model(self, request, obj):
579 obj.delete_by_user(request.user)
580
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500581
Tony Mack9bcbe4f2013-04-29 08:13:27 -0400582class SitePrivilegeAdmin(PlanetStackBaseAdmin):
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500583 fieldList = ['user', 'site', 'role']
Tony Mack00d361f2013-04-28 10:28:42 -0400584 fieldsets = [
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500585 (None, {'fields': fieldList, 'classes':['collapse']})
Tony Mack00d361f2013-04-28 10:28:42 -0400586 ]
587 list_display = ('user', 'site', 'role')
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500588 user_readonly_fields = fieldList
589 user_readonly_inlines = []
Tony Mack00d361f2013-04-28 10:28:42 -0400590
Tony Mackc2835a92013-05-28 09:18:49 -0400591 def formfield_for_foreignkey(self, db_field, request, **kwargs):
592 if db_field.name == 'site':
593 if not request.user.is_admin:
594 # only show sites where user is an admin or pi
595 sites = set()
596 for site_privilege in SitePrivilege.objects.filer(user=request.user):
597 if site_privilege.role.role_type in ['admin', 'pi']:
598 sites.add(site_privilege.site)
599 kwargs['queryset'] = Site.objects.filter(site__in=list(sites))
600
601 if db_field.name == 'user':
602 if not request.user.is_admin:
603 # only show users from sites where caller has admin or pi role
604 roles = Role.objects.filter(role_type__in=['admin', 'pi'])
605 site_privileges = SitePrivilege.objects.filter(user=request.user).filter(role__in=roles)
606 sites = [site_privilege.site for site_privilege in site_privileges]
607 site_privileges = SitePrivilege.objects.filter(site__in=sites)
608 emails = [site_privilege.user.email for site_privilege in site_privileges]
609 users = User.objects.filter(email__in=emails)
610 kwargs['queryset'] = users
611
612 return super(SitePrivilegeAdmin, self).formfield_for_foreignkey(db_field, request, **kwargs)
613
Tony Mack04062832013-05-10 08:22:44 -0400614 def queryset(self, request):
615 # admins can see all privileges. Users can only see privileges at sites
Tony Mackc2835a92013-05-28 09:18:49 -0400616 # where they have the admin role or pi role.
Tony Mack04062832013-05-10 08:22:44 -0400617 qs = super(SitePrivilegeAdmin, self).queryset(request)
Tony Mack5b061472014-02-04 07:57:10 -0500618 #if not request.user.is_admin:
619 # roles = Role.objects.filter(role_type__in=['admin', 'pi'])
620 # site_privileges = SitePrivilege.objects.filter(user=request.user).filter(role__in=roles)
621 # login_bases = [site_privilege.site.login_base for site_privilege in site_privileges]
622 # sites = Site.objects.filter(login_base__in=login_bases)
623 # qs = qs.filter(site__in=sites)
Tony Mack04062832013-05-10 08:22:44 -0400624 return qs
625
Siobhan Tullyce652d02013-10-08 21:52:35 -0400626class SliceForm(forms.ModelForm):
627 class Meta:
628 model = Slice
629 widgets = {
630 'service': LinkedSelect
631 }
632
Tony Mack2bd5b412013-06-11 21:05:06 -0400633class SliceAdmin(PlanetStackBaseAdmin):
Siobhan Tullyce652d02013-10-08 21:52:35 -0400634 form = SliceForm
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500635 fieldList = ['name', 'site', 'serviceClass', 'enabled','description', 'service', 'slice_url']
636 fieldsets = [('Slice Details', {'fields': fieldList, 'classes':['suit-tab suit-tab-general']}),]
Siobhan Tully30fd4292013-05-10 08:59:56 -0400637 list_display = ('name', 'site','serviceClass', 'slice_url')
Siobhan Tully2d95e482013-09-06 10:56:06 -0400638 inlines = [SlicePrivilegeInline,SliverInline, TagInline, ReservationInline,SliceNetworkInline]
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400639
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500640 user_readonly_fields = fieldList
641 user_readonly_inlines = [SlicePrivilegeROInline,SliverROInline,TagROInline, ReservationROInline, SliceNetworkROInline]
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400642
643 suit_form_tabs =(('general', 'Slice Details'),
Siobhan Tully2d95e482013-09-06 10:56:06 -0400644 ('slicenetworks','Networks'),
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400645 ('sliceprivileges','Privileges'),
646 ('slivers','Slivers'),
647 ('tags','Tags'),
648 ('reservations','Reservations'),
649 )
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400650
Tony Mackc2835a92013-05-28 09:18:49 -0400651 def formfield_for_foreignkey(self, db_field, request, **kwargs):
652 if db_field.name == 'site':
Tony Mack5b061472014-02-04 07:57:10 -0500653 kwargs['queryset'] = Site.select_by_user(request.user)
654
Tony Mackc2835a92013-05-28 09:18:49 -0400655 return super(SliceAdmin, self).formfield_for_foreignkey(db_field, request, **kwargs)
656
Tony Mack04062832013-05-10 08:22:44 -0400657 def queryset(self, request):
658 # admins can see all keys. Users can only see slices they belong to.
Tony Mack5b061472014-02-04 07:57:10 -0500659 return Slice.select_by_user(request.user)
Tony Mack04062832013-05-10 08:22:44 -0400660
Tony Mack79748612013-05-01 14:52:03 -0400661 def get_formsets(self, request, obj=None):
662 for inline in self.get_inline_instances(request, obj):
663 # hide MyInline in the add view
664 if obj is None:
665 continue
Tony Mack2bd5b412013-06-11 21:05:06 -0400666 if isinstance(inline, SliverInline):
667 inline.model.caller = request.user
Tony Mack79748612013-05-01 14:52:03 -0400668 yield inline.get_formset(request, obj)
669
Tony Mack2bd5b412013-06-11 21:05:06 -0400670
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400671class SlicePrivilegeAdmin(PlanetStackBaseAdmin):
Tony Mack00d361f2013-04-28 10:28:42 -0400672 fieldsets = [
673 (None, {'fields': ['user', 'slice', 'role']})
674 ]
675 list_display = ('user', 'slice', 'role')
Tony Mack00d361f2013-04-28 10:28:42 -0400676
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500677 user_readonly_fields = ['user', 'slice', 'role']
678 user_readonly_inlines = []
679
Tony Mackc2835a92013-05-28 09:18:49 -0400680 def formfield_for_foreignkey(self, db_field, request, **kwargs):
681 if db_field.name == 'slice':
Tony Mack5b061472014-02-04 07:57:10 -0500682 kwargs['queryset'] = Slice.select_by_user(request.user)
Tony Mackc2835a92013-05-28 09:18:49 -0400683
684 if db_field.name == 'user':
Tony Mack5b061472014-02-04 07:57:10 -0500685 kwargs['queryset'] = User.select_by_user(request.user)
Tony Mackc2835a92013-05-28 09:18:49 -0400686
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400687 return super(SlicePrivilegeAdmin, self).formfield_for_foreignkey(db_field, request, **kwargs)
Tony Mackc2835a92013-05-28 09:18:49 -0400688
Tony Mack04062832013-05-10 08:22:44 -0400689 def queryset(self, request):
690 # admins can see all memberships. Users can only see memberships of
691 # slices where they have the admin role.
Tony Mack5b061472014-02-04 07:57:10 -0500692 return SlicePrivilege.select_by_user(request.user)
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400693
Tony Mack9bcbe4f2013-04-29 08:13:27 -0400694 def save_model(self, request, obj, form, change):
Tony Mack951dab42013-05-02 19:51:45 -0400695 # update openstack connection to use this site/tenant
696 auth = request.session.get('auth', {})
697 auth['tenant'] = obj.slice.name
698 obj.os_manager = OpenStackManager(auth=auth, caller=request.user)
Tony Mack9bcbe4f2013-04-29 08:13:27 -0400699 obj.save()
700
701 def delete_model(self, request, obj):
Tony Mack951dab42013-05-02 19:51:45 -0400702 # update openstack connection to use this site/tenant
703 auth = request.session.get('auth', {})
704 auth['tenant'] = obj.slice.name
705 obj.os_manager = OpenStackManager(auth=auth, caller=request.user)
Tony Mack9bcbe4f2013-04-29 08:13:27 -0400706 obj.delete()
707
Siobhan Tully567e3e62013-06-21 18:03:16 -0400708
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400709class ImageAdmin(PlanetStackBaseAdmin):
710
711 fieldsets = [('Image Details',
712 {'fields': ['image_id', 'name', 'disk_format', 'container_format'],
713 'classes': ['suit-tab suit-tab-general']})
714 ]
715
716 suit_form_tabs =(('general','Image Details'),('slivers','Slivers'))
717
718 inlines = [SliverInline]
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500719
720 user_readonly_fields = ['image_id', 'name', 'disk_format', 'container_format']
721 user_readonly_inlines = [SliverROInline]
722
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400723class NodeForm(forms.ModelForm):
724 class Meta:
725 widgets = {
726 'site': LinkedSelect,
727 'deployment': LinkedSelect
728 }
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400729
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500730class NodeAdmin(PlanetStackBaseAdmin):
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400731 form = NodeForm
Siobhan Tullybf1153a2013-05-27 20:53:48 -0400732 list_display = ('name', 'site', 'deployment')
733 list_filter = ('deployment',)
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500734
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400735 inlines = [TagInline,SliverInline]
736 fieldsets = [('Node Details', {'fields': ['name','site','deployment'], 'classes':['suit-tab suit-tab-details']})]
737
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500738 user_readonly_fields = ['name','site','deployment']
739 user_readonly_inlines = [TagInline,SliverInline]
740
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400741 suit_form_tabs =(('details','Node Details'),('slivers','Slivers'),('tags','Tags'))
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400742
Siobhan Tully567e3e62013-06-21 18:03:16 -0400743
Tony Mackd90cdbf2013-04-16 22:48:40 -0400744class SliverForm(forms.ModelForm):
745 class Meta:
Tony Mack1d6b85f2013-05-07 18:49:14 -0400746 model = Sliver
Tony Mackd90cdbf2013-04-16 22:48:40 -0400747 ip = forms.CharField(widget=PlainTextWidget)
Tony Mack18261812013-05-02 16:39:20 -0400748 instance_name = forms.CharField(widget=PlainTextWidget)
Tony Mackd90cdbf2013-04-16 22:48:40 -0400749 widgets = {
750 'ip': PlainTextWidget(),
Tony Mack18261812013-05-02 16:39:20 -0400751 'instance_name': PlainTextWidget(),
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400752 'slice': LinkedSelect,
753 'deploymentNetwork': LinkedSelect,
754 'node': LinkedSelect,
755 'image': LinkedSelect
Siobhan Tully53437282013-04-26 19:30:27 -0400756 }
Tony Mackd90cdbf2013-04-16 22:48:40 -0400757
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500758class TagAdmin(PlanetStackBaseAdmin):
Siobhan Tullyce652d02013-10-08 21:52:35 -0400759 list_display = ['service', 'name', 'value', 'content_type', 'content_object',]
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500760 user_readonly_fields = ['service', 'name', 'value', 'content_type', 'content_object',]
761 user_readonly_inlines = []
Siobhan Tullyd3515752013-06-21 16:34:53 -0400762
Tony Mack9bcbe4f2013-04-29 08:13:27 -0400763class SliverAdmin(PlanetStackBaseAdmin):
Tony Mackd90cdbf2013-04-16 22:48:40 -0400764 form = SliverForm
Tony Mackcdec0902013-04-15 00:38:49 -0400765 fieldsets = [
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400766 ('Sliver Details', {'fields': ['slice', 'deploymentNetwork', 'node', 'ip', 'instance_name', 'numberCores', 'image', ], 'classes': ['suit-tab suit-tab-general'], })
Tony Mackcdec0902013-04-15 00:38:49 -0400767 ]
Siobhan Tully5d7dc8d2013-07-02 13:17:33 -0400768 list_display = ['ip', 'instance_name', 'slice', 'numberCores', 'image', 'node', 'deploymentNetwork']
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400769
770 suit_form_tabs =(('general', 'Sliver Details'),
771 ('tags','Tags'),
772 )
773
Siobhan Tullyde5450d2013-06-21 11:35:33 -0400774 inlines = [TagInline]
Tony Mack53106f32013-04-27 16:43:01 -0400775
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500776 user_readonly_fields = ['slice', 'deploymentNetwork', 'node', 'ip', 'instance_name', 'numberCores', 'image']
777 user_readonly_inlines = [TagROInline]
778
Tony Mackc2835a92013-05-28 09:18:49 -0400779 def formfield_for_foreignkey(self, db_field, request, **kwargs):
780 if db_field.name == 'slice':
Tony Mack5b061472014-02-04 07:57:10 -0500781 kwargs['queryset'] = Slice.select_by_user(request.user)
Tony Mackc2835a92013-05-28 09:18:49 -0400782
783 return super(SliverAdmin, self).formfield_for_foreignkey(db_field, request, **kwargs)
784
Tony Mack04062832013-05-10 08:22:44 -0400785 def queryset(self, request):
786 # admins can see all slivers. Users can only see slivers of
787 # the slices they belong to.
Tony Mack5b061472014-02-04 07:57:10 -0500788 return Sliver.select_by_user(request.user)
789
Tony Mack04062832013-05-10 08:22:44 -0400790
Tony Mack1d6b85f2013-05-07 18:49:14 -0400791 def get_formsets(self, request, obj=None):
792 # make some fields read only if we are updating an existing record
793 if obj == None:
794 #self.readonly_fields = ('ip', 'instance_name')
795 self.readonly_fields = ()
796 else:
Tony Mack1e889462013-05-10 21:34:54 -0400797 self.readonly_fields = ()
798 #self.readonly_fields = ('ip', 'instance_name', 'slice', 'image', 'key')
Tony Mack1d6b85f2013-05-07 18:49:14 -0400799
800 for inline in self.get_inline_instances(request, obj):
801 # hide MyInline in the add view
802 if obj is None:
803 continue
Tony Mack53106f32013-04-27 16:43:01 -0400804
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500805 #def save_model(self, request, obj, form, change):
806 # # update openstack connection to use this site/tenant
807 # auth = request.session.get('auth', {})
808 # auth['tenant'] = obj.slice.name
809 # obj.os_manager = OpenStackManager(auth=auth, caller=request.user)
810 # obj.creator = request.user
811 # obj.save()
Tony Mack53106f32013-04-27 16:43:01 -0400812
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500813 #def delete_model(self, request, obj):
814 # # update openstack connection to use this site/tenant
815 # auth = request.session.get('auth', {})
816 # auth['tenant'] = obj.slice.name
817 # obj.os_manager = OpenStackManager(auth=auth, caller=request.user)
818 # obj.delete()
Tony Mackcdec0902013-04-15 00:38:49 -0400819
Siobhan Tully53437282013-04-26 19:30:27 -0400820class UserCreationForm(forms.ModelForm):
821 """A form for creating new users. Includes all the required
822 fields, plus a repeated password."""
823 password1 = forms.CharField(label='Password', widget=forms.PasswordInput)
824 password2 = forms.CharField(label='Password confirmation', widget=forms.PasswordInput)
825
826 class Meta:
Siobhan Tully30fd4292013-05-10 08:59:56 -0400827 model = User
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400828 fields = ('email', 'firstname', 'lastname', 'phone', 'public_key')
Siobhan Tully53437282013-04-26 19:30:27 -0400829
830 def clean_password2(self):
831 # Check that the two password entries match
832 password1 = self.cleaned_data.get("password1")
833 password2 = self.cleaned_data.get("password2")
834 if password1 and password2 and password1 != password2:
835 raise forms.ValidationError("Passwords don't match")
836 return password2
837
838 def save(self, commit=True):
839 # Save the provided password in hashed format
840 user = super(UserCreationForm, self).save(commit=False)
Tony Mackf9f4afb2013-05-01 21:02:12 -0400841 user.password = self.cleaned_data["password1"]
842 #user.set_password(self.cleaned_data["password1"])
Siobhan Tully53437282013-04-26 19:30:27 -0400843 if commit:
844 user.save()
845 return user
846
Siobhan Tully567e3e62013-06-21 18:03:16 -0400847
Siobhan Tully53437282013-04-26 19:30:27 -0400848class UserChangeForm(forms.ModelForm):
849 """A form for updating users. Includes all the fields on
850 the user, but replaces the password field with admin's
851 password hash display field.
852 """
Siobhan Tully63b7ba42014-01-12 10:35:11 -0500853 password = ReadOnlyPasswordHashField(label='Password',
854 help_text= '<a href=\"password/\">Change Password</a>.')
Siobhan Tully53437282013-04-26 19:30:27 -0400855
856 class Meta:
Siobhan Tully30fd4292013-05-10 08:59:56 -0400857 model = User
Siobhan Tully53437282013-04-26 19:30:27 -0400858
859 def clean_password(self):
860 # Regardless of what the user provides, return the initial value.
861 # This is done here, rather than on the field, because the
862 # field does not have access to the initial value
863 return self.initial["password"]
864
Tony Mack2bd5b412013-06-11 21:05:06 -0400865class UserAdmin(UserAdmin):
Siobhan Tully53437282013-04-26 19:30:27 -0400866 class Meta:
867 app_label = "core"
868
869 # The forms to add and change user instances
870 form = UserChangeForm
871 add_form = UserCreationForm
872
873 # The fields to be used in displaying the User model.
874 # These override the definitions on the base UserAdmin
875 # that reference specific fields on auth.User.
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500876 list_display = ('email', 'firstname', 'lastname', 'site', 'last_login')
Siobhan Tullyce652d02013-10-08 21:52:35 -0400877 #list_display = ('email', 'username','firstname', 'lastname', 'is_admin', 'last_login')
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500878 list_filter = ('site',)
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400879 inlines = [SlicePrivilegeInline,SitePrivilegeInline,DeploymentPrivilegeInline]
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500880
881 fieldListLoginDetails = ['email','site','password','is_readonly','is_amin','public_key']
882 fieldListContactInfo = ['firstname','lastname','phone','timezone']
883
Siobhan Tully53437282013-04-26 19:30:27 -0400884 fieldsets = (
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500885 ('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 -0400886 ('Contact Information', {'fields': ('firstname','lastname','phone', 'timezone'), 'classes':['suit-tab suit-tab-contact']}),
Siobhan Tully53437282013-04-26 19:30:27 -0400887 #('Important dates', {'fields': ('last_login',)}),
888 )
889 add_fieldsets = (
890 (None, {
891 'classes': ('wide',),
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500892 'fields': ('email', 'firstname', 'lastname', 'is_readonly', 'phone', 'public_key','password1', 'password2')}
Siobhan Tully53437282013-04-26 19:30:27 -0400893 ),
894 )
895 search_fields = ('email',)
896 ordering = ('email',)
897 filter_horizontal = ()
898
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500899 user_readonly_fields = fieldListLoginDetails
900 user_readonly_inlines = [SlicePrivilegeROInline,SitePrivilegeROInline,DeploymentPrivilegeROInline]
901
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400902 suit_form_tabs =(('general','Login Details'),('contact','Contact Information'),('sliceprivileges','Slice Privileges'),('siteprivileges','Site Privileges'),('deploymentprivileges','Deployment Privileges'))
903
Tony Mackc2835a92013-05-28 09:18:49 -0400904 def formfield_for_foreignkey(self, db_field, request, **kwargs):
905 if db_field.name == 'site':
Tony Mack5b061472014-02-04 07:57:10 -0500906 kwargs['queryset'] = Site.select_by_user(request.user)
Tony Mackc2835a92013-05-28 09:18:49 -0400907
908 return super(UserAdmin, self).formfield_for_foreignkey(db_field, request, **kwargs)
909
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500910 def has_add_permission(self, request, obj=None):
911 return (not self.__user_is_readonly(request))
912
913 def has_delete_permission(self, request, obj=None):
914 return (not self.__user_is_readonly(request))
915
916 def get_actions(self,request):
917 actions = super(UserAdmin,self).get_actions(request)
918
919 if self.__user_is_readonly(request):
920 if 'delete_selected' in actions:
921 del actions['delete_selected']
922
923 return actions
924
925 def change_view(self,request,object_id, extra_context=None):
926
927 if self.__user_is_readonly(request):
928 self.readonly_fields=self.user_readonly_fields
929 self.inlines = self.user_readonly_inlines
930 try:
931 return super(UserAdmin, self).change_view(request, object_id, extra_context=extra_context)
932 except PermissionDenied:
933 pass
934 if request.method == 'POST':
935 raise PermissionDenied
936 request.readonly = True
937 return super(UserAdmin, self).change_view(request, object_id, extra_context=extra_context)
938
939 def __user_is_readonly(self, request):
940 #groups = [x.name for x in request.user.groups.all() ]
941 #return "readonly" in groups
942 return request.user.isReadOnlyUser()
943
Tony Mack5b061472014-02-04 07:57:10 -0500944 def queryset(self, request):
945 return User.select_by_user(request.user)
946
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500947
948
949class ServiceResourceROInline(ReadOnlyTabularInline):
950 model = ServiceResource
951 extra = 0
952 fields = ['serviceClass', 'name', 'maxUnitsDeployment', 'maxUnitsNode', 'maxDuration', 'bucketInRate', 'bucketMaxSize', 'cost', 'calendarReservable']
953
Scott Baker0165fac2014-01-13 11:49:26 -0800954class ServiceResourceInline(PlStackTabularInline):
Scott Baker3de3e372013-05-10 16:50:44 -0700955 model = ServiceResource
956 extra = 0
957
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500958class ServiceClassAdmin(PlanetStackBaseAdmin):
Scott Baker3de3e372013-05-10 16:50:44 -0700959 list_display = ('name', 'commitment', 'membershipFee')
960 inlines = [ServiceResourceInline]
961
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500962 user_readonly_fields = ['name', 'commitment', 'membershipFee']
963 user_readonly_inlines = []
964
965class ReservedResourceROInline(ReadOnlyTabularInline):
966 model = ReservedResource
967 extra = 0
968 fields = ['sliver', 'resource','quantity','reservationSet']
969 suit_classes = 'suit-tab suit-tab-reservedresources'
970
Scott Baker0165fac2014-01-13 11:49:26 -0800971class ReservedResourceInline(PlStackTabularInline):
Scott Baker133c9212013-05-17 09:09:11 -0700972 model = ReservedResource
973 extra = 0
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400974 suit_classes = 'suit-tab suit-tab-reservedresources'
Scott Baker133c9212013-05-17 09:09:11 -0700975
976 def formfield_for_foreignkey(self, db_field, request=None, **kwargs):
977 field = super(ReservedResourceInline, self).formfield_for_foreignkey(db_field, request, **kwargs)
978
979 if db_field.name == 'resource':
980 # restrict resources to those that the slice's service class allows
981 if request._slice is not None:
982 field.queryset = field.queryset.filter(serviceClass = request._slice.serviceClass, calendarReservable=True)
983 if len(field.queryset) > 0:
984 field.initial = field.queryset.all()[0]
985 else:
986 field.queryset = field.queryset.none()
987 elif db_field.name == 'sliver':
988 # restrict slivers to those that belong to the slice
989 if request._slice is not None:
990 field.queryset = field.queryset.filter(slice = request._slice)
991 else:
992 field.queryset = field.queryset.none()
993
994 return field
995
Tony Mack5b061472014-02-04 07:57:10 -0500996 def queryset(self, request):
997 return ReservedResource.select_by_user(request.user)
998
Scott Baker133c9212013-05-17 09:09:11 -0700999class ReservationChangeForm(forms.ModelForm):
1000 class Meta:
1001 model = Reservation
Siobhan Tullybfd11dc2013-09-03 12:59:24 -04001002 widgets = {
1003 'slice' : LinkedSelect
1004 }
Scott Baker133c9212013-05-17 09:09:11 -07001005
1006class ReservationAddForm(forms.ModelForm):
1007 slice = forms.ModelChoiceField(queryset=Slice.objects.all(), widget=forms.Select(attrs={"onChange":"document.getElementById('id_refresh').value=1; submit()"}))
1008 refresh = forms.CharField(widget=forms.HiddenInput())
1009
1010 class Media:
1011 css = {'all': ('planetstack.css',)} # .field-refresh { display: none; }
1012
1013 def clean_slice(self):
1014 slice = self.cleaned_data.get("slice")
1015 x = ServiceResource.objects.filter(serviceClass = slice.serviceClass, calendarReservable=True)
1016 if len(x) == 0:
1017 raise forms.ValidationError("The slice you selected does not have a service class that allows reservations")
1018 return slice
1019
1020 class Meta:
1021 model = Reservation
Siobhan Tullybfd11dc2013-09-03 12:59:24 -04001022 widgets = {
1023 'slice' : LinkedSelect
1024 }
1025
Scott Baker133c9212013-05-17 09:09:11 -07001026
1027class ReservationAddRefreshForm(ReservationAddForm):
1028 """ This form is displayed when the Reservation Form receives an update
1029 from the Slice dropdown onChange handler. It doesn't validate the
1030 data and doesn't save the data. This will cause the form to be
1031 redrawn.
1032 """
1033
Scott Baker8737e5f2013-05-17 09:35:32 -07001034 """ don't validate anything other than slice """
1035 dont_validate_fields = ("startTime", "duration")
1036
Scott Baker133c9212013-05-17 09:09:11 -07001037 def full_clean(self):
1038 result = super(ReservationAddForm, self).full_clean()
Scott Baker8737e5f2013-05-17 09:35:32 -07001039
1040 for fieldname in self.dont_validate_fields:
1041 if fieldname in self._errors:
1042 del self._errors[fieldname]
1043
Scott Baker133c9212013-05-17 09:09:11 -07001044 return result
1045
1046 """ don't save anything """
1047 def is_valid(self):
1048 return False
1049
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001050class ReservationAdmin(PlanetStackBaseAdmin):
1051 fieldList = ['slice', 'startTime', 'duration']
1052 fieldsets = [('Reservation Details', {'fields': fieldList, 'classes': ['suit-tab suit-tab-general']})]
Scott Baker133c9212013-05-17 09:09:11 -07001053 list_display = ('startTime', 'duration')
Scott Baker133c9212013-05-17 09:09:11 -07001054 form = ReservationAddForm
1055
Siobhan Tullybfd11dc2013-09-03 12:59:24 -04001056 suit_form_tabs = (('general','Reservation Details'), ('reservedresources','Reserved Resources'))
1057
1058 inlines = [ReservedResourceInline]
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001059 user_readonly_inlines = [ReservedResourceROInline]
1060 user_readonly_fields = fieldList
Siobhan Tullybfd11dc2013-09-03 12:59:24 -04001061
Scott Baker133c9212013-05-17 09:09:11 -07001062 def add_view(self, request, form_url='', extra_context=None):
Scott Bakeracd45142013-05-19 16:19:16 -07001063 timezone.activate(request.user.timezone)
Scott Baker133c9212013-05-17 09:09:11 -07001064 request._refresh = False
1065 request._slice = None
1066 if request.method == 'POST':
Scott Baker8737e5f2013-05-17 09:35:32 -07001067 # "refresh" will be set to "1" if the form was submitted due to
1068 # a change in the Slice dropdown.
Scott Baker133c9212013-05-17 09:09:11 -07001069 if request.POST.get("refresh","1") == "1":
1070 request._refresh = True
1071 request.POST["refresh"] = "0"
Scott Baker8737e5f2013-05-17 09:35:32 -07001072
1073 # Keep track of the slice that was selected, so the
1074 # reservedResource inline can filter items for the slice.
Scott Baker133c9212013-05-17 09:09:11 -07001075 request._slice = request.POST.get("slice",None)
1076 if (request._slice is not None):
1077 request._slice = Slice.objects.get(id=request._slice)
1078
1079 result = super(ReservationAdmin, self).add_view(request, form_url, extra_context)
1080 return result
1081
Scott Bakeracd45142013-05-19 16:19:16 -07001082 def changelist_view(self, request, extra_context = None):
1083 timezone.activate(request.user.timezone)
1084 return super(ReservationAdmin, self).changelist_view(request, extra_context)
1085
Scott Baker133c9212013-05-17 09:09:11 -07001086 def get_form(self, request, obj=None, **kwargs):
Siobhan Tullyd3515752013-06-21 16:34:53 -04001087 request._obj_ = obj
1088 if obj is not None:
1089 # For changes, set request._slice to the slice already set in the
1090 # object.
1091 request._slice = obj.slice
1092 self.form = ReservationChangeForm
1093 else:
1094 if getattr(request, "_refresh", False):
1095 self.form = ReservationAddRefreshForm
1096 else:
1097 self.form = ReservationAddForm
1098 return super(ReservationAdmin, self).get_form(request, obj, **kwargs)
1099
Scott Baker133c9212013-05-17 09:09:11 -07001100 def get_readonly_fields(self, request, obj=None):
Siobhan Tullyd3515752013-06-21 16:34:53 -04001101 if (obj is not None):
1102 # Prevent slice from being changed after the reservation has been
1103 # created.
1104 return ['slice']
1105 else:
Scott Baker133c9212013-05-17 09:09:11 -07001106 return []
Scott Baker3de3e372013-05-10 16:50:44 -07001107
Tony Mack5b061472014-02-04 07:57:10 -05001108 def queryset(self, request):
1109 return Reservation.select_by_user(request.user)
1110
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001111class NetworkParameterTypeAdmin(PlanetStackBaseAdmin):
Scott Baker74d8e622013-07-29 16:04:22 -07001112 list_display = ("name", )
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001113 user_readonly_fields = ['name']
1114 user_readonly_inlines = []
Scott Baker74d8e622013-07-29 16:04:22 -07001115
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001116class RouterAdmin(PlanetStackBaseAdmin):
Scott Baker74d8e622013-07-29 16:04:22 -07001117 list_display = ("name", )
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001118 user_readonly_fields = ['name']
1119 user_readonly_inlines = []
1120
1121class RouterROInline(ReadOnlyTabularInline):
1122 model = Router.networks.through
1123 extra = 0
1124 verbose_name_plural = "Routers"
1125 verbose_name = "Router"
1126 suit_classes = 'suit-tab suit-tab-routers'
1127
1128 fields = ['name', 'owner', 'permittedNetworks', 'networks']
Scott Baker74d8e622013-07-29 16:04:22 -07001129
Scott Baker0165fac2014-01-13 11:49:26 -08001130class RouterInline(PlStackTabularInline):
Scott Baker74d8e622013-07-29 16:04:22 -07001131 model = Router.networks.through
1132 extra = 0
1133 verbose_name_plural = "Routers"
1134 verbose_name = "Router"
Siobhan Tully2d95e482013-09-06 10:56:06 -04001135 suit_classes = 'suit-tab suit-tab-routers'
Scott Baker74d8e622013-07-29 16:04:22 -07001136
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001137class NetworkParameterROInline(ReadOnlyTabularInline):
1138 model = NetworkParameter
1139 extra = 1
1140 verbose_name_plural = "Parameters"
1141 verbose_name = "Parameter"
1142 suit_classes = 'suit-tab suit-tab-netparams'
1143 fields = ['parameter', 'value', 'content_type', 'object_id', 'content_object']
1144
Scott Baker74d8e622013-07-29 16:04:22 -07001145class NetworkParameterInline(generic.GenericTabularInline):
Scott Baker74d8e622013-07-29 16:04:22 -07001146 model = NetworkParameter
1147 extra = 1
1148 verbose_name_plural = "Parameters"
1149 verbose_name = "Parameter"
Siobhan Tully2d95e482013-09-06 10:56:06 -04001150 suit_classes = 'suit-tab suit-tab-netparams'
Scott Baker74d8e622013-07-29 16:04:22 -07001151
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001152class NetworkSliversROInline(ReadOnlyTabularInline):
1153 fields = ['network', 'sliver', 'ip', 'port_id']
1154 model = NetworkSliver
1155 extra = 0
1156 verbose_name_plural = "Slivers"
1157 verbose_name = "Sliver"
1158 suit_classes = 'suit-tab suit-tab-networkslivers'
1159
Scott Baker0165fac2014-01-13 11:49:26 -08001160class NetworkSliversInline(PlStackTabularInline):
Scott Baker74d8e622013-07-29 16:04:22 -07001161 readonly_fields = ("ip", )
1162 model = NetworkSliver
Scott Baker874936e2014-01-13 18:15:34 -08001163 selflink_fieldname = "sliver"
Scott Baker74d8e622013-07-29 16:04:22 -07001164 extra = 0
1165 verbose_name_plural = "Slivers"
1166 verbose_name = "Sliver"
Siobhan Tully2d95e482013-09-06 10:56:06 -04001167 suit_classes = 'suit-tab suit-tab-networkslivers'
Scott Baker74d8e622013-07-29 16:04:22 -07001168
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001169class NetworkSlicesROInline(ReadOnlyTabularInline):
1170 model = NetworkSlice
1171 extra = 0
1172 verbose_name_plural = "Slices"
1173 verbose_name = "Slice"
1174 suit_classes = 'suit-tab suit-tab-networkslices'
1175 fields = ['network','slice']
1176
Scott Baker0165fac2014-01-13 11:49:26 -08001177class NetworkSlicesInline(PlStackTabularInline):
Scott Bakerd7d2a392013-08-06 08:57:30 -07001178 model = NetworkSlice
Scott Baker874936e2014-01-13 18:15:34 -08001179 selflink_fieldname = "slice"
Scott Bakerd7d2a392013-08-06 08:57:30 -07001180 extra = 0
1181 verbose_name_plural = "Slices"
1182 verbose_name = "Slice"
Siobhan Tully2d95e482013-09-06 10:56:06 -04001183 suit_classes = 'suit-tab suit-tab-networkslices'
Scott Bakerd7d2a392013-08-06 08:57:30 -07001184
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001185class NetworkAdmin(PlanetStackBaseAdmin):
Scott Baker74d8e622013-07-29 16:04:22 -07001186 list_display = ("name", "subnet", "ports", "labels")
1187 readonly_fields = ("subnet", )
Siobhan Tully2d95e482013-09-06 10:56:06 -04001188
Scott Bakerd7d2a392013-08-06 08:57:30 -07001189 inlines = [NetworkParameterInline, NetworkSliversInline, NetworkSlicesInline, RouterInline]
Scott Baker74d8e622013-07-29 16:04:22 -07001190
Siobhan Tully2d95e482013-09-06 10:56:06 -04001191 fieldsets = [
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001192 (None, {'fields': ['name','template','ports','labels','owner','guaranteedBandwidth', 'permitAllSlices','permittedSlices','network_id','router_id','subnet_id','subnet'], 'classes':['suit-tab suit-tab-general']}),]
1193
1194 user_readonly_fields = ['name','template','ports','labels','owner','guaranteedBandwidth', 'permitAllSlices','permittedSlices','network_id','router_id','subnet_id','subnet']
1195 user_readonly_inlines = [NetworkParameterROInline, NetworkSliversROInline, NetworkSlicesROInline, RouterROInline]
Siobhan Tully2d95e482013-09-06 10:56:06 -04001196
1197 suit_form_tabs =(
1198 ('general','Network Details'),
1199 ('netparams', 'Parameters'),
1200 ('networkslivers','Slivers'),
1201 ('networkslices','Slices'),
1202 ('routers','Routers'),
1203 )
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001204class NetworkTemplateAdmin(PlanetStackBaseAdmin):
Scott Baker74d8e622013-07-29 16:04:22 -07001205 list_display = ("name", "guaranteedBandwidth", "visibility")
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001206 user_readonly_fields = ["name", "guaranteedBandwidth", "visibility"]
1207 user_readonly_inlines = []
Scott Baker74d8e622013-07-29 16:04:22 -07001208
Tony Mack31c2b8f2013-04-26 20:01:42 -04001209# register a signal that caches the user's credentials when they log in
1210def cache_credentials(sender, user, request, **kwds):
1211 auth = {'username': request.POST['username'],
1212 'password': request.POST['password']}
1213 request.session['auth'] = auth
1214user_logged_in.connect(cache_credentials)
1215
Scott Baker15cddfa2013-12-09 13:45:19 -08001216def dollar_field(fieldName, short_description):
1217 def newFunc(self, obj):
1218 try:
1219 x= "$ %0.2f" % float(getattr(obj, fieldName, 0.0))
1220 except:
1221 x=getattr(obj, fieldName, 0.0)
1222 return x
1223 newFunc.short_description = short_description
1224 return newFunc
1225
1226def right_dollar_field(fieldName, short_description):
1227 def newFunc(self, obj):
1228 try:
1229 #x= '<div align=right style="width:6em">$ %0.2f</div>' % float(getattr(obj, fieldName, 0.0))
1230 x= '<div align=right>$ %0.2f</div>' % float(getattr(obj, fieldName, 0.0))
1231 except:
1232 x=getattr(obj, fieldName, 0.0)
1233 return x
1234 newFunc.short_description = short_description
1235 newFunc.allow_tags = True
1236 return newFunc
Scott Baker43105042013-12-06 23:23:36 -08001237
Scott Baker0165fac2014-01-13 11:49:26 -08001238class InvoiceChargeInline(PlStackTabularInline):
Scott Baker43105042013-12-06 23:23:36 -08001239 model = Charge
Scott Baker15cddfa2013-12-09 13:45:19 -08001240 extra = 0
Scott Baker43105042013-12-06 23:23:36 -08001241 verbose_name_plural = "Charges"
1242 verbose_name = "Charge"
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001243 exclude = ['account']
Scott Baker9cb88a22013-12-09 18:56:00 -08001244 fields = ["date", "kind", "state", "object", "coreHours", "dollar_amount", "slice"]
1245 readonly_fields = ["date", "kind", "state", "object", "coreHours", "dollar_amount", "slice"]
1246 can_delete = False
1247 max_num = 0
1248
1249 dollar_amount = right_dollar_field("amount", "Amount")
Scott Baker43105042013-12-06 23:23:36 -08001250
1251class InvoiceAdmin(admin.ModelAdmin):
1252 list_display = ("date", "account")
1253
1254 inlines = [InvoiceChargeInline]
1255
Scott Baker9cb88a22013-12-09 18:56:00 -08001256 fields = ["date", "account", "dollar_amount"]
1257 readonly_fields = ["date", "account", "dollar_amount"]
1258
1259 dollar_amount = dollar_field("amount", "Amount")
Scott Baker43105042013-12-06 23:23:36 -08001260
Scott Baker0165fac2014-01-13 11:49:26 -08001261class InvoiceInline(PlStackTabularInline):
Scott Baker15cddfa2013-12-09 13:45:19 -08001262 model = Invoice
1263 extra = 0
1264 verbose_name_plural = "Invoices"
1265 verbose_name = "Invoice"
Scott Baker0165fac2014-01-13 11:49:26 -08001266 fields = ["date", "dollar_amount"]
1267 readonly_fields = ["date", "dollar_amount"]
Scott Baker15cddfa2013-12-09 13:45:19 -08001268 suit_classes = 'suit-tab suit-tab-accountinvoice'
1269 can_delete=False
1270 max_num=0
1271
1272 dollar_amount = right_dollar_field("amount", "Amount")
1273
Scott Baker0165fac2014-01-13 11:49:26 -08001274class PendingChargeInline(PlStackTabularInline):
Scott Baker43105042013-12-06 23:23:36 -08001275 model = Charge
Scott Baker15cddfa2013-12-09 13:45:19 -08001276 extra = 0
Scott Baker43105042013-12-06 23:23:36 -08001277 verbose_name_plural = "Charges"
1278 verbose_name = "Charge"
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001279 exclude = ["invoice"]
Scott Baker15cddfa2013-12-09 13:45:19 -08001280 fields = ["date", "kind", "state", "object", "coreHours", "dollar_amount", "slice"]
1281 readonly_fields = ["date", "kind", "state", "object", "coreHours", "dollar_amount", "slice"]
Scott Baker43105042013-12-06 23:23:36 -08001282 suit_classes = 'suit-tab suit-tab-accountpendingcharges'
Scott Baker15cddfa2013-12-09 13:45:19 -08001283 can_delete=False
1284 max_num=0
Scott Baker43105042013-12-06 23:23:36 -08001285
1286 def queryset(self, request):
1287 qs = super(PendingChargeInline, self).queryset(request)
1288 qs = qs.filter(state="pending")
1289 return qs
1290
Scott Baker15cddfa2013-12-09 13:45:19 -08001291 dollar_amount = right_dollar_field("amount", "Amount")
1292
Scott Baker0165fac2014-01-13 11:49:26 -08001293class PaymentInline(PlStackTabularInline):
Scott Baker43105042013-12-06 23:23:36 -08001294 model=Payment
1295 extra = 1
1296 verbose_name_plural = "Payments"
1297 verbose_name = "Payment"
Scott Baker15cddfa2013-12-09 13:45:19 -08001298 fields = ["date", "dollar_amount"]
1299 readonly_fields = ["date", "dollar_amount"]
Scott Baker43105042013-12-06 23:23:36 -08001300 suit_classes = 'suit-tab suit-tab-accountpayments'
Scott Baker15cddfa2013-12-09 13:45:19 -08001301 can_delete=False
1302 max_num=0
1303
1304 dollar_amount = right_dollar_field("amount", "Amount")
1305
Scott Baker43105042013-12-06 23:23:36 -08001306class AccountAdmin(admin.ModelAdmin):
1307 list_display = ("site", "balance_due")
1308
1309 inlines = [InvoiceInline, PaymentInline, PendingChargeInline]
1310
1311 fieldsets = [
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001312 (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 -08001313
Scott Baker15cddfa2013-12-09 13:45:19 -08001314 readonly_fields = ['site', 'dollar_balance_due', 'dollar_total_invoices', 'dollar_total_payments']
Scott Baker43105042013-12-06 23:23:36 -08001315
1316 suit_form_tabs =(
1317 ('general','Account Details'),
1318 ('accountinvoice', 'Invoices'),
1319 ('accountpayments', 'Payments'),
1320 ('accountpendingcharges','Pending Charges'),
1321 )
1322
Scott Baker15cddfa2013-12-09 13:45:19 -08001323 dollar_balance_due = dollar_field("balance_due", "Balance Due")
1324 dollar_total_invoices = dollar_field("total_invoices", "Total Invoices")
1325 dollar_total_payments = dollar_field("total_payments", "Total Payments")
1326
Siobhan Tullyce652d02013-10-08 21:52:35 -04001327
Siobhan Tully53437282013-04-26 19:30:27 -04001328# Now register the new UserAdmin...
Siobhan Tully30fd4292013-05-10 08:59:56 -04001329admin.site.register(User, UserAdmin)
Siobhan Tully53437282013-04-26 19:30:27 -04001330# ... and, since we're not using Django's builtin permissions,
1331# unregister the Group model from admin.
Siobhan Tullyce652d02013-10-08 21:52:35 -04001332#admin.site.unregister(Group)
Siobhan Tully53437282013-04-26 19:30:27 -04001333
Siobhan Tullybf1153a2013-05-27 20:53:48 -04001334#Do not show django evolution in the admin interface
1335from django_evolution.models import Version, Evolution
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001336#admin.site.unregister(Version)
1337#admin.site.unregister(Evolution)
Siobhan Tullybf1153a2013-05-27 20:53:48 -04001338
1339
1340# When debugging it is often easier to see all the classes, but for regular use
1341# only the top-levels should be displayed
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001342showAll = False
Scott Baker43105042013-12-06 23:23:36 -08001343
Siobhan Tullybf1153a2013-05-27 20:53:48 -04001344admin.site.register(Deployment, DeploymentAdmin)
Siobhan Tully4bc09f22013-04-10 21:15:21 -04001345admin.site.register(Site, SiteAdmin)
Siobhan Tully4bc09f22013-04-10 21:15:21 -04001346admin.site.register(Slice, SliceAdmin)
Siobhan Tullyce652d02013-10-08 21:52:35 -04001347admin.site.register(Service, ServiceAdmin)
smbakera3cf70c2013-06-27 02:01:41 -07001348admin.site.register(Reservation, ReservationAdmin)
Scott Baker74d8e622013-07-29 16:04:22 -07001349admin.site.register(Network, NetworkAdmin)
1350admin.site.register(Router, RouterAdmin)
Scott Baker74d8e622013-07-29 16:04:22 -07001351admin.site.register(NetworkTemplate, NetworkTemplateAdmin)
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001352admin.site.register(Account, AccountAdmin)
1353admin.site.register(Invoice, InvoiceAdmin)
Siobhan Tullybf1153a2013-05-27 20:53:48 -04001354
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001355if True:
1356 admin.site.register(NetworkParameterType, NetworkParameterTypeAdmin)
1357 admin.site.register(ServiceClass, ServiceClassAdmin)
Siobhan Tullybfd11dc2013-09-03 12:59:24 -04001358 #admin.site.register(PlanetStack)
Siobhan Tullyd3515752013-06-21 16:34:53 -04001359 admin.site.register(Tag, TagAdmin)
Siobhan Tullyce652d02013-10-08 21:52:35 -04001360 admin.site.register(DeploymentRole)
1361 admin.site.register(SiteRole)
1362 admin.site.register(SliceRole)
1363 admin.site.register(PlanetStackRole)
Siobhan Tullybf1153a2013-05-27 20:53:48 -04001364 admin.site.register(Node, NodeAdmin)
Siobhan Tullybfd11dc2013-09-03 12:59:24 -04001365 #admin.site.register(SlicePrivilege, SlicePrivilegeAdmin)
1366 #admin.site.register(SitePrivilege, SitePrivilegeAdmin)
Siobhan Tullybf1153a2013-05-27 20:53:48 -04001367 admin.site.register(Sliver, SliverAdmin)
Siobhan Tullybf1153a2013-05-27 20:53:48 -04001368 admin.site.register(Image, ImageAdmin)
Tony Mack7130ac32013-03-22 21:58:00 -04001369