blob: 853e5ce19b6b982cf316bdc454879b2b387d1a37 [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
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500348class SlicePrivilegeROInline(ReadOnlyTabularInline):
349 model = SlicePrivilege
350 extra = 0
351 suit_classes = 'suit-tab suit-tab-sliceprivileges'
352 fields = ['user', 'slice', 'role']
353
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400354class SlicePrivilegeInline(PlStackTabularInline):
355 model = SlicePrivilege
356 suit_classes = 'suit-tab suit-tab-sliceprivileges'
357 extra = 0
358 fields = ('user', 'slice','role')
Siobhan Tullyaa1bcd52013-05-10 12:43:09 -0400359
Tony Mackc2835a92013-05-28 09:18:49 -0400360 def formfield_for_foreignkey(self, db_field, request, **kwargs):
361 if db_field.name == 'slice':
Tony Mack5b061472014-02-04 07:57:10 -0500362 kwargs['queryset'] = Slice.select_by_user(request.user)
Tony Mackc2835a92013-05-28 09:18:49 -0400363 if db_field.name == 'user':
Tony Mack5b061472014-02-04 07:57:10 -0500364 kwargs['queryset'] = User.select_by_user(request.user)
Tony Mackc2835a92013-05-28 09:18:49 -0400365
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400366 return super(SlicePrivilegeInline, self).formfield_for_foreignkey(db_field, request, **kwargs)
Tony Mackc2835a92013-05-28 09:18:49 -0400367
Tony Mack5b061472014-02-04 07:57:10 -0500368 def queryset(self, request):
369 return SlicePrivilege.select_by_user(request.user)
370
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500371class SliceNetworkROInline(ReadOnlyTabularInline):
372 model = Network.slices.through
373 extra = 0
374 verbose_name = "Network Connection"
375 verbose_name_plural = "Network Connections"
376 suit_classes = 'suit-tab suit-tab-slicenetworks'
377 fields = ['network']
378
Scott Bakera0015eb2013-08-14 17:28:14 -0700379class SliceNetworkInline(PlStackTabularInline):
Scott Baker74d8e622013-07-29 16:04:22 -0700380 model = Network.slices.through
Scott Baker874936e2014-01-13 18:15:34 -0800381 selflink_fieldname = "network"
Scott Baker74d8e622013-07-29 16:04:22 -0700382 extra = 0
383 verbose_name = "Network Connection"
384 verbose_name_plural = "Network Connections"
Siobhan Tully2d95e482013-09-06 10:56:06 -0400385 suit_classes = 'suit-tab suit-tab-slicenetworks'
Scott Baker74d8e622013-07-29 16:04:22 -0700386
Tony Mack5e71a662013-05-03 23:30:41 -0400387class PlainTextWidget(forms.HiddenInput):
388 input_type = 'hidden'
389
390 def render(self, name, value, attrs=None):
391 if value is None:
392 value = ''
Tony Mack1d6b85f2013-05-07 18:49:14 -0400393 return mark_safe(str(value) + super(PlainTextWidget, self).render(name, value, attrs))
Tony Mack9bcbe4f2013-04-29 08:13:27 -0400394
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500395class PlanetStackBaseAdmin(ReadOnlyAwareAdmin):
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400396 save_on_top = False
Tony Mack332ee1d2014-02-04 15:33:45 -0500397
398 def save_model(self, request, obj, form, change):
399 # update openstack connection to use this site/tenant
400 obj.save_by_user(request.user)
401
402 def delete_model(self, request, obj):
403 obj.delete_by_user(request.user)
404
405 def save_formset(self, request, form, formset, change):
406 instances = formset.save(commit=False)
407 for instance in instances:
408 instance.save_by_user(request.user)
409 formset.save_m2m()
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400410
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400411class SliceRoleAdmin(PlanetStackBaseAdmin):
412 model = SliceRole
413 pass
414
415class SiteRoleAdmin(PlanetStackBaseAdmin):
416 model = SiteRole
417 pass
418
Siobhan Tullybf1153a2013-05-27 20:53:48 -0400419class DeploymentAdminForm(forms.ModelForm):
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400420 sites = forms.ModelMultipleChoiceField(
421 queryset=Site.objects.all(),
422 required=False,
423 widget=FilteredSelectMultiple(
424 verbose_name=('Sites'), is_stacked=False
425 )
426 )
427 class Meta:
Siobhan Tullybf1153a2013-05-27 20:53:48 -0400428 model = Deployment
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400429
Siobhan Tully320b4622014-01-17 15:11:14 -0500430 def __init__(self, *args, **kwargs):
431 super(DeploymentAdminForm, self).__init__(*args, **kwargs)
432
433 if self.instance and self.instance.pk:
434 self.fields['sites'].initial = self.instance.sites.all()
435
436 def save(self, commit=True):
437 deployment = super(DeploymentAdminForm, self).save(commit=False)
438
439 if commit:
440 deployment.save()
441
442 if deployment.pk:
443 deployment.sites = self.cleaned_data['sites']
444 self.save_m2m()
445
446 return deployment
447
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500448class SiteAssocInline(PlStackTabularInline):
449 model = Site.deployments.through
450 extra = 0
451 suit_classes = 'suit-tab suit-tab-sites'
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400452
Siobhan Tullybf1153a2013-05-27 20:53:48 -0400453class DeploymentAdmin(PlanetStackBaseAdmin):
454 form = DeploymentAdminForm
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500455 model = Deployment
456 fieldList = ['name','sites']
457 fieldsets = [(None, {'fields': fieldList, 'classes':['suit-tab suit-tab-sites']})]
Siobhan Tully2d95e482013-09-06 10:56:06 -0400458 inlines = [DeploymentPrivilegeInline,NodeInline,TagInline]
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500459
460 user_readonly_inlines = [DeploymentPrivilegeROInline,NodeROInline,TagROInline]
461 user_readonly_fields = ['name']
462
463 suit_form_tabs =(('sites','Deployment Details'),('nodes','Nodes'),('deploymentprivileges','Privileges'),('tags','Tags'))
464
465class ServiceAttrAsTabROInline(ReadOnlyTabularInline):
466 model = ServiceAttribute
467 fields = ['name','value']
468 extra = 0
469 suit_classes = 'suit-tab suit-tab-serviceattrs'
Tony Mack5cd13202013-05-01 21:48:38 -0400470
Siobhan Tullyce652d02013-10-08 21:52:35 -0400471class ServiceAttrAsTabInline(PlStackTabularInline):
472 model = ServiceAttribute
473 fields = ['name','value']
474 extra = 0
475 suit_classes = 'suit-tab suit-tab-serviceattrs'
476
Siobhan Tullyce652d02013-10-08 21:52:35 -0400477class ServiceAdmin(PlanetStackBaseAdmin):
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500478 list_display = ("name","description","versionNumber","enabled","published")
479 fieldList = ["name","description","versionNumber","enabled","published"]
480 fieldsets = [(None, {'fields': fieldList, 'classes':['suit-tab suit-tab-general']})]
481 inlines = [ServiceAttrAsTabInline,SliceInline]
482
483 user_readonly_fields = fieldList
484 user_readonly_inlines = [ServiceAttrAsTabROInline,SliceROInline]
485
486 suit_form_tabs =(('general', 'Service Details'),
487 ('slices','Slices'),
488 ('serviceattrs','Additional Attributes'),
489 )
Siobhan Tullyce652d02013-10-08 21:52:35 -0400490
Tony Mack0553f282013-06-10 22:54:50 -0400491class SiteAdmin(PlanetStackBaseAdmin):
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500492 fieldList = ['name', 'site_url', 'enabled', 'is_public', 'login_base', 'accountLink','location']
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400493 fieldsets = [
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500494 (None, {'fields': fieldList, 'classes':['suit-tab suit-tab-general']}),
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400495 ('Deployment Networks', {'fields': ['deployments'], 'classes':['suit-tab suit-tab-deployments']}),
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400496 ]
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400497 suit_form_tabs =(('general', 'Site Details'),
498 ('users','Users'),
Siobhan Tully2d95e482013-09-06 10:56:06 -0400499 ('siteprivileges','Privileges'),
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400500 ('deployments','Deployments'),
501 ('slices','Slices'),
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500502 ('nodes','Nodes'),
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400503 ('tags','Tags'),
504 )
Scott Baker545db2a2013-12-09 18:44:43 -0800505 readonly_fields = ['accountLink']
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500506
507 user_readonly_fields = ['name', 'deployments','site_url', 'enabled', 'is_public', 'login_base', 'accountLink']
508 user_readonly_inlines = [SliceROInline,UserROInline,TagROInline, NodeROInline, SitePrivilegeROInline]
509
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400510 list_display = ('name', 'login_base','site_url', 'enabled')
511 filter_horizontal = ('deployments',)
Siobhan Tully2d95e482013-09-06 10:56:06 -0400512 inlines = [SliceInline,UserInline,TagInline, NodeInline, SitePrivilegeInline]
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400513 search_fields = ['name']
514
Tony Mack04062832013-05-10 08:22:44 -0400515 def queryset(self, request):
Tony Mack5b061472014-02-04 07:57:10 -0500516 #print dir(UserInline)
517 return Site.select_by_user(request.user)
Tony Mack04062832013-05-10 08:22:44 -0400518
Tony Mack5cd13202013-05-01 21:48:38 -0400519 def get_formsets(self, request, obj=None):
520 for inline in self.get_inline_instances(request, obj):
521 # hide MyInline in the add view
522 if obj is None:
523 continue
Tony Mack2bd5b412013-06-11 21:05:06 -0400524 if isinstance(inline, SliceInline):
525 inline.model.caller = request.user
526 yield inline.get_formset(request, obj)
527
528 def get_formsets(self, request, obj=None):
529 for inline in self.get_inline_instances(request, obj):
530 # hide MyInline in the add view
531 if obj is None:
532 continue
533 if isinstance(inline, SliverInline):
534 inline.model.caller = request.user
Tony Mack5cd13202013-05-01 21:48:38 -0400535 yield inline.get_formset(request, obj)
536
Scott Baker545db2a2013-12-09 18:44:43 -0800537 def accountLink(self, obj):
538 link_obj = obj.accounts.all()
539 if link_obj:
540 reverse_path = "admin:core_account_change"
541 url = reverse(reverse_path, args =(link_obj[0].id,))
542 return "<a href='%s'>%s</a>" % (url, "view billing details")
543 else:
544 return "no billing data for this site"
545 accountLink.allow_tags = True
546 accountLink.short_description = "Billing"
547
Tony Mack332ee1d2014-02-04 15:33:45 -0500548 def save_model(self, request, obj, form, change):
549 # update openstack connection to use this site/tenant
550 obj.save_by_user(request.user)
551
552 def delete_model(self, request, obj):
553 obj.delete_by_user(request.user)
554
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500555
Tony Mack9bcbe4f2013-04-29 08:13:27 -0400556class SitePrivilegeAdmin(PlanetStackBaseAdmin):
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500557 fieldList = ['user', 'site', 'role']
Tony Mack00d361f2013-04-28 10:28:42 -0400558 fieldsets = [
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500559 (None, {'fields': fieldList, 'classes':['collapse']})
Tony Mack00d361f2013-04-28 10:28:42 -0400560 ]
561 list_display = ('user', 'site', 'role')
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500562 user_readonly_fields = fieldList
563 user_readonly_inlines = []
Tony Mack00d361f2013-04-28 10:28:42 -0400564
Tony Mackc2835a92013-05-28 09:18:49 -0400565 def formfield_for_foreignkey(self, db_field, request, **kwargs):
566 if db_field.name == 'site':
567 if not request.user.is_admin:
568 # only show sites where user is an admin or pi
569 sites = set()
570 for site_privilege in SitePrivilege.objects.filer(user=request.user):
571 if site_privilege.role.role_type in ['admin', 'pi']:
572 sites.add(site_privilege.site)
573 kwargs['queryset'] = Site.objects.filter(site__in=list(sites))
574
575 if db_field.name == 'user':
576 if not request.user.is_admin:
577 # only show users from sites where caller has admin or pi role
578 roles = Role.objects.filter(role_type__in=['admin', 'pi'])
579 site_privileges = SitePrivilege.objects.filter(user=request.user).filter(role__in=roles)
580 sites = [site_privilege.site for site_privilege in site_privileges]
581 site_privileges = SitePrivilege.objects.filter(site__in=sites)
582 emails = [site_privilege.user.email for site_privilege in site_privileges]
583 users = User.objects.filter(email__in=emails)
584 kwargs['queryset'] = users
585
586 return super(SitePrivilegeAdmin, self).formfield_for_foreignkey(db_field, request, **kwargs)
587
Tony Mack04062832013-05-10 08:22:44 -0400588 def queryset(self, request):
589 # admins can see all privileges. Users can only see privileges at sites
Tony Mackc2835a92013-05-28 09:18:49 -0400590 # where they have the admin role or pi role.
Tony Mack04062832013-05-10 08:22:44 -0400591 qs = super(SitePrivilegeAdmin, self).queryset(request)
Tony Mack5b061472014-02-04 07:57:10 -0500592 #if not request.user.is_admin:
593 # roles = Role.objects.filter(role_type__in=['admin', 'pi'])
594 # site_privileges = SitePrivilege.objects.filter(user=request.user).filter(role__in=roles)
595 # login_bases = [site_privilege.site.login_base for site_privilege in site_privileges]
596 # sites = Site.objects.filter(login_base__in=login_bases)
597 # qs = qs.filter(site__in=sites)
Tony Mack04062832013-05-10 08:22:44 -0400598 return qs
599
Siobhan Tullyce652d02013-10-08 21:52:35 -0400600class SliceForm(forms.ModelForm):
601 class Meta:
602 model = Slice
603 widgets = {
604 'service': LinkedSelect
605 }
606
Tony Mack2bd5b412013-06-11 21:05:06 -0400607class SliceAdmin(PlanetStackBaseAdmin):
Siobhan Tullyce652d02013-10-08 21:52:35 -0400608 form = SliceForm
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500609 fieldList = ['name', 'site', 'serviceClass', 'enabled','description', 'service', 'slice_url']
610 fieldsets = [('Slice Details', {'fields': fieldList, 'classes':['suit-tab suit-tab-general']}),]
Siobhan Tully30fd4292013-05-10 08:59:56 -0400611 list_display = ('name', 'site','serviceClass', 'slice_url')
Siobhan Tully2d95e482013-09-06 10:56:06 -0400612 inlines = [SlicePrivilegeInline,SliverInline, TagInline, ReservationInline,SliceNetworkInline]
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400613
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500614 user_readonly_fields = fieldList
615 user_readonly_inlines = [SlicePrivilegeROInline,SliverROInline,TagROInline, ReservationROInline, SliceNetworkROInline]
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400616
617 suit_form_tabs =(('general', 'Slice Details'),
Siobhan Tully2d95e482013-09-06 10:56:06 -0400618 ('slicenetworks','Networks'),
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400619 ('sliceprivileges','Privileges'),
620 ('slivers','Slivers'),
621 ('tags','Tags'),
622 ('reservations','Reservations'),
623 )
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400624
Tony Mackc2835a92013-05-28 09:18:49 -0400625 def formfield_for_foreignkey(self, db_field, request, **kwargs):
626 if db_field.name == 'site':
Tony Mack5b061472014-02-04 07:57:10 -0500627 kwargs['queryset'] = Site.select_by_user(request.user)
628
Tony Mackc2835a92013-05-28 09:18:49 -0400629 return super(SliceAdmin, self).formfield_for_foreignkey(db_field, request, **kwargs)
630
Tony Mack04062832013-05-10 08:22:44 -0400631 def queryset(self, request):
632 # admins can see all keys. Users can only see slices they belong to.
Tony Mack5b061472014-02-04 07:57:10 -0500633 return Slice.select_by_user(request.user)
Tony Mack04062832013-05-10 08:22:44 -0400634
Tony Mack79748612013-05-01 14:52:03 -0400635 def get_formsets(self, request, obj=None):
636 for inline in self.get_inline_instances(request, obj):
637 # hide MyInline in the add view
638 if obj is None:
639 continue
Tony Mack2bd5b412013-06-11 21:05:06 -0400640 if isinstance(inline, SliverInline):
641 inline.model.caller = request.user
Tony Mack79748612013-05-01 14:52:03 -0400642 yield inline.get_formset(request, obj)
643
Tony Mack2bd5b412013-06-11 21:05:06 -0400644
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400645class SlicePrivilegeAdmin(PlanetStackBaseAdmin):
Tony Mack00d361f2013-04-28 10:28:42 -0400646 fieldsets = [
647 (None, {'fields': ['user', 'slice', 'role']})
648 ]
649 list_display = ('user', 'slice', 'role')
Tony Mack00d361f2013-04-28 10:28:42 -0400650
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500651 user_readonly_fields = ['user', 'slice', 'role']
652 user_readonly_inlines = []
653
Tony Mackc2835a92013-05-28 09:18:49 -0400654 def formfield_for_foreignkey(self, db_field, request, **kwargs):
655 if db_field.name == 'slice':
Tony Mack5b061472014-02-04 07:57:10 -0500656 kwargs['queryset'] = Slice.select_by_user(request.user)
Tony Mackc2835a92013-05-28 09:18:49 -0400657
658 if db_field.name == 'user':
Tony Mack5b061472014-02-04 07:57:10 -0500659 kwargs['queryset'] = User.select_by_user(request.user)
Tony Mackc2835a92013-05-28 09:18:49 -0400660
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400661 return super(SlicePrivilegeAdmin, self).formfield_for_foreignkey(db_field, request, **kwargs)
Tony Mackc2835a92013-05-28 09:18:49 -0400662
Tony Mack04062832013-05-10 08:22:44 -0400663 def queryset(self, request):
664 # admins can see all memberships. Users can only see memberships of
665 # slices where they have the admin role.
Tony Mack5b061472014-02-04 07:57:10 -0500666 return SlicePrivilege.select_by_user(request.user)
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400667
Tony Mack9bcbe4f2013-04-29 08:13:27 -0400668 def save_model(self, request, obj, form, change):
Tony Mack951dab42013-05-02 19:51:45 -0400669 # update openstack connection to use this site/tenant
670 auth = request.session.get('auth', {})
671 auth['tenant'] = obj.slice.name
672 obj.os_manager = OpenStackManager(auth=auth, caller=request.user)
Tony Mack9bcbe4f2013-04-29 08:13:27 -0400673 obj.save()
674
675 def delete_model(self, request, obj):
Tony Mack951dab42013-05-02 19:51:45 -0400676 # update openstack connection to use this site/tenant
677 auth = request.session.get('auth', {})
678 auth['tenant'] = obj.slice.name
679 obj.os_manager = OpenStackManager(auth=auth, caller=request.user)
Tony Mack9bcbe4f2013-04-29 08:13:27 -0400680 obj.delete()
681
Siobhan Tully567e3e62013-06-21 18:03:16 -0400682
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400683class ImageAdmin(PlanetStackBaseAdmin):
684
685 fieldsets = [('Image Details',
686 {'fields': ['image_id', 'name', 'disk_format', 'container_format'],
687 'classes': ['suit-tab suit-tab-general']})
688 ]
689
690 suit_form_tabs =(('general','Image Details'),('slivers','Slivers'))
691
692 inlines = [SliverInline]
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500693
694 user_readonly_fields = ['image_id', 'name', 'disk_format', 'container_format']
695 user_readonly_inlines = [SliverROInline]
696
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400697class NodeForm(forms.ModelForm):
698 class Meta:
699 widgets = {
700 'site': LinkedSelect,
701 'deployment': LinkedSelect
702 }
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400703
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500704class NodeAdmin(PlanetStackBaseAdmin):
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400705 form = NodeForm
Siobhan Tullybf1153a2013-05-27 20:53:48 -0400706 list_display = ('name', 'site', 'deployment')
707 list_filter = ('deployment',)
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500708
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400709 inlines = [TagInline,SliverInline]
710 fieldsets = [('Node Details', {'fields': ['name','site','deployment'], 'classes':['suit-tab suit-tab-details']})]
711
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500712 user_readonly_fields = ['name','site','deployment']
713 user_readonly_inlines = [TagInline,SliverInline]
714
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400715 suit_form_tabs =(('details','Node Details'),('slivers','Slivers'),('tags','Tags'))
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400716
Siobhan Tully567e3e62013-06-21 18:03:16 -0400717
Tony Mackd90cdbf2013-04-16 22:48:40 -0400718class SliverForm(forms.ModelForm):
719 class Meta:
Tony Mack1d6b85f2013-05-07 18:49:14 -0400720 model = Sliver
Tony Mackd90cdbf2013-04-16 22:48:40 -0400721 ip = forms.CharField(widget=PlainTextWidget)
Tony Mack18261812013-05-02 16:39:20 -0400722 instance_name = forms.CharField(widget=PlainTextWidget)
Tony Mackd90cdbf2013-04-16 22:48:40 -0400723 widgets = {
724 'ip': PlainTextWidget(),
Tony Mack18261812013-05-02 16:39:20 -0400725 'instance_name': PlainTextWidget(),
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400726 'slice': LinkedSelect,
727 'deploymentNetwork': LinkedSelect,
728 'node': LinkedSelect,
729 'image': LinkedSelect
Siobhan Tully53437282013-04-26 19:30:27 -0400730 }
Tony Mackd90cdbf2013-04-16 22:48:40 -0400731
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500732class TagAdmin(PlanetStackBaseAdmin):
Siobhan Tullyce652d02013-10-08 21:52:35 -0400733 list_display = ['service', 'name', 'value', 'content_type', 'content_object',]
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500734 user_readonly_fields = ['service', 'name', 'value', 'content_type', 'content_object',]
735 user_readonly_inlines = []
Siobhan Tullyd3515752013-06-21 16:34:53 -0400736
Tony Mack9bcbe4f2013-04-29 08:13:27 -0400737class SliverAdmin(PlanetStackBaseAdmin):
Tony Mackd90cdbf2013-04-16 22:48:40 -0400738 form = SliverForm
Tony Mackcdec0902013-04-15 00:38:49 -0400739 fieldsets = [
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400740 ('Sliver Details', {'fields': ['slice', 'deploymentNetwork', 'node', 'ip', 'instance_name', 'numberCores', 'image', ], 'classes': ['suit-tab suit-tab-general'], })
Tony Mackcdec0902013-04-15 00:38:49 -0400741 ]
Siobhan Tully5d7dc8d2013-07-02 13:17:33 -0400742 list_display = ['ip', 'instance_name', 'slice', 'numberCores', 'image', 'node', 'deploymentNetwork']
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400743
744 suit_form_tabs =(('general', 'Sliver Details'),
745 ('tags','Tags'),
746 )
747
Siobhan Tullyde5450d2013-06-21 11:35:33 -0400748 inlines = [TagInline]
Tony Mack53106f32013-04-27 16:43:01 -0400749
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500750 user_readonly_fields = ['slice', 'deploymentNetwork', 'node', 'ip', 'instance_name', 'numberCores', 'image']
751 user_readonly_inlines = [TagROInline]
752
Tony Mackc2835a92013-05-28 09:18:49 -0400753 def formfield_for_foreignkey(self, db_field, request, **kwargs):
754 if db_field.name == 'slice':
Tony Mack5b061472014-02-04 07:57:10 -0500755 kwargs['queryset'] = Slice.select_by_user(request.user)
Tony Mackc2835a92013-05-28 09:18:49 -0400756
757 return super(SliverAdmin, self).formfield_for_foreignkey(db_field, request, **kwargs)
758
Tony Mack04062832013-05-10 08:22:44 -0400759 def queryset(self, request):
760 # admins can see all slivers. Users can only see slivers of
761 # the slices they belong to.
Tony Mack5b061472014-02-04 07:57:10 -0500762 return Sliver.select_by_user(request.user)
763
Tony Mack04062832013-05-10 08:22:44 -0400764
Tony Mack1d6b85f2013-05-07 18:49:14 -0400765 def get_formsets(self, request, obj=None):
766 # make some fields read only if we are updating an existing record
767 if obj == None:
768 #self.readonly_fields = ('ip', 'instance_name')
769 self.readonly_fields = ()
770 else:
Tony Mack1e889462013-05-10 21:34:54 -0400771 self.readonly_fields = ()
772 #self.readonly_fields = ('ip', 'instance_name', 'slice', 'image', 'key')
Tony Mack1d6b85f2013-05-07 18:49:14 -0400773
774 for inline in self.get_inline_instances(request, obj):
775 # hide MyInline in the add view
776 if obj is None:
777 continue
Tony Mack53106f32013-04-27 16:43:01 -0400778
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500779 #def save_model(self, request, obj, form, change):
780 # # update openstack connection to use this site/tenant
781 # auth = request.session.get('auth', {})
782 # auth['tenant'] = obj.slice.name
783 # obj.os_manager = OpenStackManager(auth=auth, caller=request.user)
784 # obj.creator = request.user
785 # obj.save()
Tony Mack53106f32013-04-27 16:43:01 -0400786
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500787 #def delete_model(self, request, obj):
788 # # update openstack connection to use this site/tenant
789 # auth = request.session.get('auth', {})
790 # auth['tenant'] = obj.slice.name
791 # obj.os_manager = OpenStackManager(auth=auth, caller=request.user)
792 # obj.delete()
Tony Mackcdec0902013-04-15 00:38:49 -0400793
Siobhan Tully53437282013-04-26 19:30:27 -0400794class UserCreationForm(forms.ModelForm):
795 """A form for creating new users. Includes all the required
796 fields, plus a repeated password."""
797 password1 = forms.CharField(label='Password', widget=forms.PasswordInput)
798 password2 = forms.CharField(label='Password confirmation', widget=forms.PasswordInput)
799
800 class Meta:
Siobhan Tully30fd4292013-05-10 08:59:56 -0400801 model = User
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400802 fields = ('email', 'firstname', 'lastname', 'phone', 'public_key')
Siobhan Tully53437282013-04-26 19:30:27 -0400803
804 def clean_password2(self):
805 # Check that the two password entries match
806 password1 = self.cleaned_data.get("password1")
807 password2 = self.cleaned_data.get("password2")
808 if password1 and password2 and password1 != password2:
809 raise forms.ValidationError("Passwords don't match")
810 return password2
811
812 def save(self, commit=True):
813 # Save the provided password in hashed format
814 user = super(UserCreationForm, self).save(commit=False)
Tony Mackf9f4afb2013-05-01 21:02:12 -0400815 user.password = self.cleaned_data["password1"]
816 #user.set_password(self.cleaned_data["password1"])
Siobhan Tully53437282013-04-26 19:30:27 -0400817 if commit:
818 user.save()
819 return user
820
Siobhan Tully567e3e62013-06-21 18:03:16 -0400821
Siobhan Tully53437282013-04-26 19:30:27 -0400822class UserChangeForm(forms.ModelForm):
823 """A form for updating users. Includes all the fields on
824 the user, but replaces the password field with admin's
825 password hash display field.
826 """
Siobhan Tully63b7ba42014-01-12 10:35:11 -0500827 password = ReadOnlyPasswordHashField(label='Password',
828 help_text= '<a href=\"password/\">Change Password</a>.')
Siobhan Tully53437282013-04-26 19:30:27 -0400829
830 class Meta:
Siobhan Tully30fd4292013-05-10 08:59:56 -0400831 model = User
Siobhan Tully53437282013-04-26 19:30:27 -0400832
833 def clean_password(self):
834 # Regardless of what the user provides, return the initial value.
835 # This is done here, rather than on the field, because the
836 # field does not have access to the initial value
837 return self.initial["password"]
838
Tony Mack2bd5b412013-06-11 21:05:06 -0400839class UserAdmin(UserAdmin):
Siobhan Tully53437282013-04-26 19:30:27 -0400840 class Meta:
841 app_label = "core"
842
843 # The forms to add and change user instances
844 form = UserChangeForm
845 add_form = UserCreationForm
846
847 # The fields to be used in displaying the User model.
848 # These override the definitions on the base UserAdmin
849 # that reference specific fields on auth.User.
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500850 list_display = ('email', 'firstname', 'lastname', 'site', 'last_login')
Siobhan Tullyce652d02013-10-08 21:52:35 -0400851 #list_display = ('email', 'username','firstname', 'lastname', 'is_admin', 'last_login')
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500852 list_filter = ('site',)
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400853 inlines = [SlicePrivilegeInline,SitePrivilegeInline,DeploymentPrivilegeInline]
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500854
855 fieldListLoginDetails = ['email','site','password','is_readonly','is_amin','public_key']
856 fieldListContactInfo = ['firstname','lastname','phone','timezone']
857
Siobhan Tully53437282013-04-26 19:30:27 -0400858 fieldsets = (
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500859 ('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 -0400860 ('Contact Information', {'fields': ('firstname','lastname','phone', 'timezone'), 'classes':['suit-tab suit-tab-contact']}),
Siobhan Tully53437282013-04-26 19:30:27 -0400861 #('Important dates', {'fields': ('last_login',)}),
862 )
863 add_fieldsets = (
864 (None, {
865 'classes': ('wide',),
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500866 'fields': ('email', 'firstname', 'lastname', 'is_readonly', 'phone', 'public_key','password1', 'password2')}
Siobhan Tully53437282013-04-26 19:30:27 -0400867 ),
868 )
869 search_fields = ('email',)
870 ordering = ('email',)
871 filter_horizontal = ()
872
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500873 user_readonly_fields = fieldListLoginDetails
874 user_readonly_inlines = [SlicePrivilegeROInline,SitePrivilegeROInline,DeploymentPrivilegeROInline]
875
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400876 suit_form_tabs =(('general','Login Details'),('contact','Contact Information'),('sliceprivileges','Slice Privileges'),('siteprivileges','Site Privileges'),('deploymentprivileges','Deployment Privileges'))
877
Tony Mackc2835a92013-05-28 09:18:49 -0400878 def formfield_for_foreignkey(self, db_field, request, **kwargs):
879 if db_field.name == 'site':
Tony Mack5b061472014-02-04 07:57:10 -0500880 kwargs['queryset'] = Site.select_by_user(request.user)
Tony Mackc2835a92013-05-28 09:18:49 -0400881
882 return super(UserAdmin, self).formfield_for_foreignkey(db_field, request, **kwargs)
883
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500884 def has_add_permission(self, request, obj=None):
885 return (not self.__user_is_readonly(request))
886
887 def has_delete_permission(self, request, obj=None):
888 return (not self.__user_is_readonly(request))
889
890 def get_actions(self,request):
891 actions = super(UserAdmin,self).get_actions(request)
892
893 if self.__user_is_readonly(request):
894 if 'delete_selected' in actions:
895 del actions['delete_selected']
896
897 return actions
898
899 def change_view(self,request,object_id, extra_context=None):
900
901 if self.__user_is_readonly(request):
902 self.readonly_fields=self.user_readonly_fields
903 self.inlines = self.user_readonly_inlines
904 try:
905 return super(UserAdmin, self).change_view(request, object_id, extra_context=extra_context)
906 except PermissionDenied:
907 pass
908 if request.method == 'POST':
909 raise PermissionDenied
910 request.readonly = True
911 return super(UserAdmin, self).change_view(request, object_id, extra_context=extra_context)
912
913 def __user_is_readonly(self, request):
914 #groups = [x.name for x in request.user.groups.all() ]
915 #return "readonly" in groups
916 return request.user.isReadOnlyUser()
917
Tony Mack5b061472014-02-04 07:57:10 -0500918 def queryset(self, request):
919 return User.select_by_user(request.user)
920
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500921
922
923class ServiceResourceROInline(ReadOnlyTabularInline):
924 model = ServiceResource
925 extra = 0
926 fields = ['serviceClass', 'name', 'maxUnitsDeployment', 'maxUnitsNode', 'maxDuration', 'bucketInRate', 'bucketMaxSize', 'cost', 'calendarReservable']
927
Scott Baker0165fac2014-01-13 11:49:26 -0800928class ServiceResourceInline(PlStackTabularInline):
Scott Baker3de3e372013-05-10 16:50:44 -0700929 model = ServiceResource
930 extra = 0
931
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500932class ServiceClassAdmin(PlanetStackBaseAdmin):
Scott Baker3de3e372013-05-10 16:50:44 -0700933 list_display = ('name', 'commitment', 'membershipFee')
934 inlines = [ServiceResourceInline]
935
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500936 user_readonly_fields = ['name', 'commitment', 'membershipFee']
937 user_readonly_inlines = []
938
939class ReservedResourceROInline(ReadOnlyTabularInline):
940 model = ReservedResource
941 extra = 0
942 fields = ['sliver', 'resource','quantity','reservationSet']
943 suit_classes = 'suit-tab suit-tab-reservedresources'
944
Scott Baker0165fac2014-01-13 11:49:26 -0800945class ReservedResourceInline(PlStackTabularInline):
Scott Baker133c9212013-05-17 09:09:11 -0700946 model = ReservedResource
947 extra = 0
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400948 suit_classes = 'suit-tab suit-tab-reservedresources'
Scott Baker133c9212013-05-17 09:09:11 -0700949
950 def formfield_for_foreignkey(self, db_field, request=None, **kwargs):
951 field = super(ReservedResourceInline, self).formfield_for_foreignkey(db_field, request, **kwargs)
952
953 if db_field.name == 'resource':
954 # restrict resources to those that the slice's service class allows
955 if request._slice is not None:
956 field.queryset = field.queryset.filter(serviceClass = request._slice.serviceClass, calendarReservable=True)
957 if len(field.queryset) > 0:
958 field.initial = field.queryset.all()[0]
959 else:
960 field.queryset = field.queryset.none()
961 elif db_field.name == 'sliver':
962 # restrict slivers to those that belong to the slice
963 if request._slice is not None:
964 field.queryset = field.queryset.filter(slice = request._slice)
965 else:
966 field.queryset = field.queryset.none()
967
968 return field
969
Tony Mack5b061472014-02-04 07:57:10 -0500970 def queryset(self, request):
971 return ReservedResource.select_by_user(request.user)
972
Scott Baker133c9212013-05-17 09:09:11 -0700973class ReservationChangeForm(forms.ModelForm):
974 class Meta:
975 model = Reservation
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400976 widgets = {
977 'slice' : LinkedSelect
978 }
Scott Baker133c9212013-05-17 09:09:11 -0700979
980class ReservationAddForm(forms.ModelForm):
981 slice = forms.ModelChoiceField(queryset=Slice.objects.all(), widget=forms.Select(attrs={"onChange":"document.getElementById('id_refresh').value=1; submit()"}))
982 refresh = forms.CharField(widget=forms.HiddenInput())
983
984 class Media:
985 css = {'all': ('planetstack.css',)} # .field-refresh { display: none; }
986
987 def clean_slice(self):
988 slice = self.cleaned_data.get("slice")
989 x = ServiceResource.objects.filter(serviceClass = slice.serviceClass, calendarReservable=True)
990 if len(x) == 0:
991 raise forms.ValidationError("The slice you selected does not have a service class that allows reservations")
992 return slice
993
994 class Meta:
995 model = Reservation
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400996 widgets = {
997 'slice' : LinkedSelect
998 }
999
Scott Baker133c9212013-05-17 09:09:11 -07001000
1001class ReservationAddRefreshForm(ReservationAddForm):
1002 """ This form is displayed when the Reservation Form receives an update
1003 from the Slice dropdown onChange handler. It doesn't validate the
1004 data and doesn't save the data. This will cause the form to be
1005 redrawn.
1006 """
1007
Scott Baker8737e5f2013-05-17 09:35:32 -07001008 """ don't validate anything other than slice """
1009 dont_validate_fields = ("startTime", "duration")
1010
Scott Baker133c9212013-05-17 09:09:11 -07001011 def full_clean(self):
1012 result = super(ReservationAddForm, self).full_clean()
Scott Baker8737e5f2013-05-17 09:35:32 -07001013
1014 for fieldname in self.dont_validate_fields:
1015 if fieldname in self._errors:
1016 del self._errors[fieldname]
1017
Scott Baker133c9212013-05-17 09:09:11 -07001018 return result
1019
1020 """ don't save anything """
1021 def is_valid(self):
1022 return False
1023
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001024class ReservationAdmin(PlanetStackBaseAdmin):
1025 fieldList = ['slice', 'startTime', 'duration']
1026 fieldsets = [('Reservation Details', {'fields': fieldList, 'classes': ['suit-tab suit-tab-general']})]
Scott Baker133c9212013-05-17 09:09:11 -07001027 list_display = ('startTime', 'duration')
Scott Baker133c9212013-05-17 09:09:11 -07001028 form = ReservationAddForm
1029
Siobhan Tullybfd11dc2013-09-03 12:59:24 -04001030 suit_form_tabs = (('general','Reservation Details'), ('reservedresources','Reserved Resources'))
1031
1032 inlines = [ReservedResourceInline]
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001033 user_readonly_inlines = [ReservedResourceROInline]
1034 user_readonly_fields = fieldList
Siobhan Tullybfd11dc2013-09-03 12:59:24 -04001035
Scott Baker133c9212013-05-17 09:09:11 -07001036 def add_view(self, request, form_url='', extra_context=None):
Scott Bakeracd45142013-05-19 16:19:16 -07001037 timezone.activate(request.user.timezone)
Scott Baker133c9212013-05-17 09:09:11 -07001038 request._refresh = False
1039 request._slice = None
1040 if request.method == 'POST':
Scott Baker8737e5f2013-05-17 09:35:32 -07001041 # "refresh" will be set to "1" if the form was submitted due to
1042 # a change in the Slice dropdown.
Scott Baker133c9212013-05-17 09:09:11 -07001043 if request.POST.get("refresh","1") == "1":
1044 request._refresh = True
1045 request.POST["refresh"] = "0"
Scott Baker8737e5f2013-05-17 09:35:32 -07001046
1047 # Keep track of the slice that was selected, so the
1048 # reservedResource inline can filter items for the slice.
Scott Baker133c9212013-05-17 09:09:11 -07001049 request._slice = request.POST.get("slice",None)
1050 if (request._slice is not None):
1051 request._slice = Slice.objects.get(id=request._slice)
1052
1053 result = super(ReservationAdmin, self).add_view(request, form_url, extra_context)
1054 return result
1055
Scott Bakeracd45142013-05-19 16:19:16 -07001056 def changelist_view(self, request, extra_context = None):
1057 timezone.activate(request.user.timezone)
1058 return super(ReservationAdmin, self).changelist_view(request, extra_context)
1059
Scott Baker133c9212013-05-17 09:09:11 -07001060 def get_form(self, request, obj=None, **kwargs):
Siobhan Tullyd3515752013-06-21 16:34:53 -04001061 request._obj_ = obj
1062 if obj is not None:
1063 # For changes, set request._slice to the slice already set in the
1064 # object.
1065 request._slice = obj.slice
1066 self.form = ReservationChangeForm
1067 else:
1068 if getattr(request, "_refresh", False):
1069 self.form = ReservationAddRefreshForm
1070 else:
1071 self.form = ReservationAddForm
1072 return super(ReservationAdmin, self).get_form(request, obj, **kwargs)
1073
Scott Baker133c9212013-05-17 09:09:11 -07001074 def get_readonly_fields(self, request, obj=None):
Siobhan Tullyd3515752013-06-21 16:34:53 -04001075 if (obj is not None):
1076 # Prevent slice from being changed after the reservation has been
1077 # created.
1078 return ['slice']
1079 else:
Scott Baker133c9212013-05-17 09:09:11 -07001080 return []
Scott Baker3de3e372013-05-10 16:50:44 -07001081
Tony Mack5b061472014-02-04 07:57:10 -05001082 def queryset(self, request):
1083 return Reservation.select_by_user(request.user)
1084
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001085class NetworkParameterTypeAdmin(PlanetStackBaseAdmin):
Scott Baker74d8e622013-07-29 16:04:22 -07001086 list_display = ("name", )
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001087 user_readonly_fields = ['name']
1088 user_readonly_inlines = []
Scott Baker74d8e622013-07-29 16:04:22 -07001089
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001090class RouterAdmin(PlanetStackBaseAdmin):
Scott Baker74d8e622013-07-29 16:04:22 -07001091 list_display = ("name", )
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001092 user_readonly_fields = ['name']
1093 user_readonly_inlines = []
1094
1095class RouterROInline(ReadOnlyTabularInline):
1096 model = Router.networks.through
1097 extra = 0
1098 verbose_name_plural = "Routers"
1099 verbose_name = "Router"
1100 suit_classes = 'suit-tab suit-tab-routers'
1101
1102 fields = ['name', 'owner', 'permittedNetworks', 'networks']
Scott Baker74d8e622013-07-29 16:04:22 -07001103
Scott Baker0165fac2014-01-13 11:49:26 -08001104class RouterInline(PlStackTabularInline):
Scott Baker74d8e622013-07-29 16:04:22 -07001105 model = Router.networks.through
1106 extra = 0
1107 verbose_name_plural = "Routers"
1108 verbose_name = "Router"
Siobhan Tully2d95e482013-09-06 10:56:06 -04001109 suit_classes = 'suit-tab suit-tab-routers'
Scott Baker74d8e622013-07-29 16:04:22 -07001110
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001111class NetworkParameterROInline(ReadOnlyTabularInline):
1112 model = NetworkParameter
1113 extra = 1
1114 verbose_name_plural = "Parameters"
1115 verbose_name = "Parameter"
1116 suit_classes = 'suit-tab suit-tab-netparams'
1117 fields = ['parameter', 'value', 'content_type', 'object_id', 'content_object']
1118
Scott Baker74d8e622013-07-29 16:04:22 -07001119class NetworkParameterInline(generic.GenericTabularInline):
Scott Baker74d8e622013-07-29 16:04:22 -07001120 model = NetworkParameter
1121 extra = 1
1122 verbose_name_plural = "Parameters"
1123 verbose_name = "Parameter"
Siobhan Tully2d95e482013-09-06 10:56:06 -04001124 suit_classes = 'suit-tab suit-tab-netparams'
Scott Baker74d8e622013-07-29 16:04:22 -07001125
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001126class NetworkSliversROInline(ReadOnlyTabularInline):
1127 fields = ['network', 'sliver', 'ip', 'port_id']
1128 model = NetworkSliver
1129 extra = 0
1130 verbose_name_plural = "Slivers"
1131 verbose_name = "Sliver"
1132 suit_classes = 'suit-tab suit-tab-networkslivers'
1133
Scott Baker0165fac2014-01-13 11:49:26 -08001134class NetworkSliversInline(PlStackTabularInline):
Scott Baker74d8e622013-07-29 16:04:22 -07001135 readonly_fields = ("ip", )
1136 model = NetworkSliver
Scott Baker874936e2014-01-13 18:15:34 -08001137 selflink_fieldname = "sliver"
Scott Baker74d8e622013-07-29 16:04:22 -07001138 extra = 0
1139 verbose_name_plural = "Slivers"
1140 verbose_name = "Sliver"
Siobhan Tully2d95e482013-09-06 10:56:06 -04001141 suit_classes = 'suit-tab suit-tab-networkslivers'
Scott Baker74d8e622013-07-29 16:04:22 -07001142
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001143class NetworkSlicesROInline(ReadOnlyTabularInline):
1144 model = NetworkSlice
1145 extra = 0
1146 verbose_name_plural = "Slices"
1147 verbose_name = "Slice"
1148 suit_classes = 'suit-tab suit-tab-networkslices'
1149 fields = ['network','slice']
1150
Scott Baker0165fac2014-01-13 11:49:26 -08001151class NetworkSlicesInline(PlStackTabularInline):
Scott Bakerd7d2a392013-08-06 08:57:30 -07001152 model = NetworkSlice
Scott Baker874936e2014-01-13 18:15:34 -08001153 selflink_fieldname = "slice"
Scott Bakerd7d2a392013-08-06 08:57:30 -07001154 extra = 0
1155 verbose_name_plural = "Slices"
1156 verbose_name = "Slice"
Siobhan Tully2d95e482013-09-06 10:56:06 -04001157 suit_classes = 'suit-tab suit-tab-networkslices'
Scott Bakerd7d2a392013-08-06 08:57:30 -07001158
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001159class NetworkAdmin(PlanetStackBaseAdmin):
Scott Baker74d8e622013-07-29 16:04:22 -07001160 list_display = ("name", "subnet", "ports", "labels")
1161 readonly_fields = ("subnet", )
Siobhan Tully2d95e482013-09-06 10:56:06 -04001162
Scott Bakerd7d2a392013-08-06 08:57:30 -07001163 inlines = [NetworkParameterInline, NetworkSliversInline, NetworkSlicesInline, RouterInline]
Scott Baker74d8e622013-07-29 16:04:22 -07001164
Siobhan Tully2d95e482013-09-06 10:56:06 -04001165 fieldsets = [
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001166 (None, {'fields': ['name','template','ports','labels','owner','guaranteedBandwidth', 'permitAllSlices','permittedSlices','network_id','router_id','subnet_id','subnet'], 'classes':['suit-tab suit-tab-general']}),]
1167
1168 user_readonly_fields = ['name','template','ports','labels','owner','guaranteedBandwidth', 'permitAllSlices','permittedSlices','network_id','router_id','subnet_id','subnet']
1169 user_readonly_inlines = [NetworkParameterROInline, NetworkSliversROInline, NetworkSlicesROInline, RouterROInline]
Siobhan Tully2d95e482013-09-06 10:56:06 -04001170
1171 suit_form_tabs =(
1172 ('general','Network Details'),
1173 ('netparams', 'Parameters'),
1174 ('networkslivers','Slivers'),
1175 ('networkslices','Slices'),
1176 ('routers','Routers'),
1177 )
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001178class NetworkTemplateAdmin(PlanetStackBaseAdmin):
Scott Baker74d8e622013-07-29 16:04:22 -07001179 list_display = ("name", "guaranteedBandwidth", "visibility")
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001180 user_readonly_fields = ["name", "guaranteedBandwidth", "visibility"]
1181 user_readonly_inlines = []
Scott Baker74d8e622013-07-29 16:04:22 -07001182
Tony Mack31c2b8f2013-04-26 20:01:42 -04001183# register a signal that caches the user's credentials when they log in
1184def cache_credentials(sender, user, request, **kwds):
1185 auth = {'username': request.POST['username'],
1186 'password': request.POST['password']}
1187 request.session['auth'] = auth
1188user_logged_in.connect(cache_credentials)
1189
Scott Baker15cddfa2013-12-09 13:45:19 -08001190def dollar_field(fieldName, short_description):
1191 def newFunc(self, obj):
1192 try:
1193 x= "$ %0.2f" % float(getattr(obj, fieldName, 0.0))
1194 except:
1195 x=getattr(obj, fieldName, 0.0)
1196 return x
1197 newFunc.short_description = short_description
1198 return newFunc
1199
1200def right_dollar_field(fieldName, short_description):
1201 def newFunc(self, obj):
1202 try:
1203 #x= '<div align=right style="width:6em">$ %0.2f</div>' % float(getattr(obj, fieldName, 0.0))
1204 x= '<div align=right>$ %0.2f</div>' % float(getattr(obj, fieldName, 0.0))
1205 except:
1206 x=getattr(obj, fieldName, 0.0)
1207 return x
1208 newFunc.short_description = short_description
1209 newFunc.allow_tags = True
1210 return newFunc
Scott Baker43105042013-12-06 23:23:36 -08001211
Scott Baker0165fac2014-01-13 11:49:26 -08001212class InvoiceChargeInline(PlStackTabularInline):
Scott Baker43105042013-12-06 23:23:36 -08001213 model = Charge
Scott Baker15cddfa2013-12-09 13:45:19 -08001214 extra = 0
Scott Baker43105042013-12-06 23:23:36 -08001215 verbose_name_plural = "Charges"
1216 verbose_name = "Charge"
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001217 exclude = ['account']
Scott Baker9cb88a22013-12-09 18:56:00 -08001218 fields = ["date", "kind", "state", "object", "coreHours", "dollar_amount", "slice"]
1219 readonly_fields = ["date", "kind", "state", "object", "coreHours", "dollar_amount", "slice"]
1220 can_delete = False
1221 max_num = 0
1222
1223 dollar_amount = right_dollar_field("amount", "Amount")
Scott Baker43105042013-12-06 23:23:36 -08001224
1225class InvoiceAdmin(admin.ModelAdmin):
1226 list_display = ("date", "account")
1227
1228 inlines = [InvoiceChargeInline]
1229
Scott Baker9cb88a22013-12-09 18:56:00 -08001230 fields = ["date", "account", "dollar_amount"]
1231 readonly_fields = ["date", "account", "dollar_amount"]
1232
1233 dollar_amount = dollar_field("amount", "Amount")
Scott Baker43105042013-12-06 23:23:36 -08001234
Scott Baker0165fac2014-01-13 11:49:26 -08001235class InvoiceInline(PlStackTabularInline):
Scott Baker15cddfa2013-12-09 13:45:19 -08001236 model = Invoice
1237 extra = 0
1238 verbose_name_plural = "Invoices"
1239 verbose_name = "Invoice"
Scott Baker0165fac2014-01-13 11:49:26 -08001240 fields = ["date", "dollar_amount"]
1241 readonly_fields = ["date", "dollar_amount"]
Scott Baker15cddfa2013-12-09 13:45:19 -08001242 suit_classes = 'suit-tab suit-tab-accountinvoice'
1243 can_delete=False
1244 max_num=0
1245
1246 dollar_amount = right_dollar_field("amount", "Amount")
1247
Scott Baker0165fac2014-01-13 11:49:26 -08001248class PendingChargeInline(PlStackTabularInline):
Scott Baker43105042013-12-06 23:23:36 -08001249 model = Charge
Scott Baker15cddfa2013-12-09 13:45:19 -08001250 extra = 0
Scott Baker43105042013-12-06 23:23:36 -08001251 verbose_name_plural = "Charges"
1252 verbose_name = "Charge"
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001253 exclude = ["invoice"]
Scott Baker15cddfa2013-12-09 13:45:19 -08001254 fields = ["date", "kind", "state", "object", "coreHours", "dollar_amount", "slice"]
1255 readonly_fields = ["date", "kind", "state", "object", "coreHours", "dollar_amount", "slice"]
Scott Baker43105042013-12-06 23:23:36 -08001256 suit_classes = 'suit-tab suit-tab-accountpendingcharges'
Scott Baker15cddfa2013-12-09 13:45:19 -08001257 can_delete=False
1258 max_num=0
Scott Baker43105042013-12-06 23:23:36 -08001259
1260 def queryset(self, request):
1261 qs = super(PendingChargeInline, self).queryset(request)
1262 qs = qs.filter(state="pending")
1263 return qs
1264
Scott Baker15cddfa2013-12-09 13:45:19 -08001265 dollar_amount = right_dollar_field("amount", "Amount")
1266
Scott Baker0165fac2014-01-13 11:49:26 -08001267class PaymentInline(PlStackTabularInline):
Scott Baker43105042013-12-06 23:23:36 -08001268 model=Payment
1269 extra = 1
1270 verbose_name_plural = "Payments"
1271 verbose_name = "Payment"
Scott Baker15cddfa2013-12-09 13:45:19 -08001272 fields = ["date", "dollar_amount"]
1273 readonly_fields = ["date", "dollar_amount"]
Scott Baker43105042013-12-06 23:23:36 -08001274 suit_classes = 'suit-tab suit-tab-accountpayments'
Scott Baker15cddfa2013-12-09 13:45:19 -08001275 can_delete=False
1276 max_num=0
1277
1278 dollar_amount = right_dollar_field("amount", "Amount")
1279
Scott Baker43105042013-12-06 23:23:36 -08001280class AccountAdmin(admin.ModelAdmin):
1281 list_display = ("site", "balance_due")
1282
1283 inlines = [InvoiceInline, PaymentInline, PendingChargeInline]
1284
1285 fieldsets = [
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001286 (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 -08001287
Scott Baker15cddfa2013-12-09 13:45:19 -08001288 readonly_fields = ['site', 'dollar_balance_due', 'dollar_total_invoices', 'dollar_total_payments']
Scott Baker43105042013-12-06 23:23:36 -08001289
1290 suit_form_tabs =(
1291 ('general','Account Details'),
1292 ('accountinvoice', 'Invoices'),
1293 ('accountpayments', 'Payments'),
1294 ('accountpendingcharges','Pending Charges'),
1295 )
1296
Scott Baker15cddfa2013-12-09 13:45:19 -08001297 dollar_balance_due = dollar_field("balance_due", "Balance Due")
1298 dollar_total_invoices = dollar_field("total_invoices", "Total Invoices")
1299 dollar_total_payments = dollar_field("total_payments", "Total Payments")
1300
Siobhan Tullyce652d02013-10-08 21:52:35 -04001301
Siobhan Tully53437282013-04-26 19:30:27 -04001302# Now register the new UserAdmin...
Siobhan Tully30fd4292013-05-10 08:59:56 -04001303admin.site.register(User, UserAdmin)
Siobhan Tully53437282013-04-26 19:30:27 -04001304# ... and, since we're not using Django's builtin permissions,
1305# unregister the Group model from admin.
Siobhan Tullyce652d02013-10-08 21:52:35 -04001306#admin.site.unregister(Group)
Siobhan Tully53437282013-04-26 19:30:27 -04001307
Siobhan Tullybf1153a2013-05-27 20:53:48 -04001308#Do not show django evolution in the admin interface
1309from django_evolution.models import Version, Evolution
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001310#admin.site.unregister(Version)
1311#admin.site.unregister(Evolution)
Siobhan Tullybf1153a2013-05-27 20:53:48 -04001312
1313
1314# When debugging it is often easier to see all the classes, but for regular use
1315# only the top-levels should be displayed
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001316showAll = False
Scott Baker43105042013-12-06 23:23:36 -08001317
Siobhan Tullybf1153a2013-05-27 20:53:48 -04001318admin.site.register(Deployment, DeploymentAdmin)
Siobhan Tully4bc09f22013-04-10 21:15:21 -04001319admin.site.register(Site, SiteAdmin)
Siobhan Tully4bc09f22013-04-10 21:15:21 -04001320admin.site.register(Slice, SliceAdmin)
Siobhan Tullyce652d02013-10-08 21:52:35 -04001321admin.site.register(Service, ServiceAdmin)
smbakera3cf70c2013-06-27 02:01:41 -07001322admin.site.register(Reservation, ReservationAdmin)
Scott Baker74d8e622013-07-29 16:04:22 -07001323admin.site.register(Network, NetworkAdmin)
1324admin.site.register(Router, RouterAdmin)
Scott Baker74d8e622013-07-29 16:04:22 -07001325admin.site.register(NetworkTemplate, NetworkTemplateAdmin)
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001326admin.site.register(Account, AccountAdmin)
1327admin.site.register(Invoice, InvoiceAdmin)
Siobhan Tullybf1153a2013-05-27 20:53:48 -04001328
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001329if True:
1330 admin.site.register(NetworkParameterType, NetworkParameterTypeAdmin)
1331 admin.site.register(ServiceClass, ServiceClassAdmin)
Siobhan Tullybfd11dc2013-09-03 12:59:24 -04001332 #admin.site.register(PlanetStack)
Siobhan Tullyd3515752013-06-21 16:34:53 -04001333 admin.site.register(Tag, TagAdmin)
Siobhan Tullyce652d02013-10-08 21:52:35 -04001334 admin.site.register(DeploymentRole)
1335 admin.site.register(SiteRole)
1336 admin.site.register(SliceRole)
1337 admin.site.register(PlanetStackRole)
Siobhan Tullybf1153a2013-05-27 20:53:48 -04001338 admin.site.register(Node, NodeAdmin)
Siobhan Tullybfd11dc2013-09-03 12:59:24 -04001339 #admin.site.register(SlicePrivilege, SlicePrivilegeAdmin)
1340 #admin.site.register(SitePrivilege, SitePrivilegeAdmin)
Siobhan Tullybf1153a2013-05-27 20:53:48 -04001341 admin.site.register(Sliver, SliverAdmin)
Siobhan Tullybf1153a2013-05-27 20:53:48 -04001342 admin.site.register(Image, ImageAdmin)
Tony Mack7130ac32013-03-22 21:58:00 -04001343