blob: 77fa74415ed7b1d4068a10b2a4712846c102e675 [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
17from django.core.urlresolvers import reverse
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 Baker0165fac2014-01-13 11:49:26 -080081 if (self.fields is None):
82 self.fields = []
83 for f in self.model._meta.fields:
84 if f.editable and f.name != "id":
85 self.fields.append(f.name)
Scott Baker86568322014-01-12 16:53:31 -080086
87 if (self.fields is not None):
88 self.fields = tuple(self.fields) + ("selflink", )
89
90 if self.readonly_fields is None:
91 self.readonly_fields = ()
92
93 self.readonly_fields = tuple(self.readonly_fields) + ("selflink", )
94
95 def selflink(self, obj):
96 if obj.id:
97 reverse_path = "admin:%s_change" % (self.model._meta.db_table)
98 url = reverse(reverse_path, args =(obj.id,))
99 return "<a href='%s'>Details</a>" % str(url)
100 else:
101 return "Not present"
102
103 selflink.allow_tags = True
104 selflink.short_description = "Details"
Siobhan Tullyd3515752013-06-21 16:34:53 -0400105
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500106class ReadOnlyTabularInline(PlStackTabularInline):
107 can_delete = False
108
109 def get_readonly_fields(self, request, obj=None):
110 return self.fields
111
112 def has_add_permission(self, request):
113 return False
114
115class ReservationROInline(ReadOnlyTabularInline):
116 model = Reservation
117 extra = 0
118 suit_classes = 'suit-tab suit-tab-reservations'
119 fields = ['startTime','slice','duration']
120
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400121class ReservationInline(PlStackTabularInline):
122 model = Reservation
123 extra = 0
124 suit_classes = 'suit-tab suit-tab-reservations'
125
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500126class TagROInline(generic.GenericTabularInline):
127 model = Tag
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400128 extra = 0
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500129 suit_classes = 'suit-tab suit-tab-tags'
130 can_delete = False
131 fields = ['service', 'name', 'value']
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400132
133 def get_readonly_fields(self, request, obj=None):
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500134 return self.fields
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400135
136 def has_add_permission(self, request):
137 return False
138
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500139
Siobhan Tullyde5450d2013-06-21 11:35:33 -0400140class TagInline(generic.GenericTabularInline):
141 model = Tag
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400142 extra = 0
143 suit_classes = 'suit-tab suit-tab-tags'
Siobhan Tullyde5450d2013-06-21 11:35:33 -0400144
Scott Baker74d8e622013-07-29 16:04:22 -0700145class NetworkLookerUpper:
Siobhan Tully2c780ad2013-09-06 11:22:40 -0400146 """ This is a callable that looks up a network name in a sliver and returns
147 the ip address for that network.
148 """
149
150 def __init__(self, name):
151 self.short_description = name
152 self.__name__ = name
153 self.network_name = name
154
155 def __call__(self, obj):
156 if obj is not None:
157 for nbs in obj.networksliver_set.all():
158 if (nbs.network.name == self.network_name):
159 return nbs.ip
Scott Baker74d8e622013-07-29 16:04:22 -0700160 return ""
161
162 def __str__(self):
163 return self.network_name
164
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500165class SliverROInline(ReadOnlyTabularInline):
166 model = Sliver
167 fields = ['ip', 'instance_name', 'slice', 'numberCores', 'image', 'node', 'deploymentNetwork']
168 suit_classes = 'suit-tab suit-tab-slivers'
169
Siobhan Tullyd3515752013-06-21 16:34:53 -0400170class SliverInline(PlStackTabularInline):
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400171 model = Sliver
Tony Mackb0d97422013-06-10 09:57:45 -0400172 fields = ['ip', 'instance_name', 'slice', 'numberCores', 'image', 'node', 'deploymentNetwork']
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400173 extra = 0
Tony Mack3777b012013-05-07 21:38:06 -0400174 readonly_fields = ['ip', 'instance_name']
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400175 suit_classes = 'suit-tab suit-tab-slivers'
Scott Baker74d8e622013-07-29 16:04:22 -0700176
Siobhan Tully2d95e482013-09-06 10:56:06 -0400177# Note this is breaking in the admin.py when trying to use an inline to add a node/image
178# def _declared_fieldsets(self):
179# # Return None so django will call get_fieldsets and we can insert our
180# # dynamic fields
181# return None
182#
183# def get_readonly_fields(self, request, obj=None):
184# readonly_fields = super(SliverInline, self).get_readonly_fields(request, obj)
185#
186# # Lookup the networks that are bound to the slivers, and add those
187# # network names to the list of readonly fields.
188#
189# for sliver in obj.slivers.all():
190# for nbs in sliver.networksliver_set.all():
191# if nbs.ip:
192# network_name = nbs.network.name
193# if network_name not in [str(x) for x in readonly_fields]:
194# readonly_fields.append(NetworkLookerUpper(network_name))
195#
196# return readonly_fields
197#
198# def get_fieldsets(self, request, obj=None):
199# form = self.get_formset(request, obj).form
200# # fields = the read/write files + the read-only fields
201# fields = self.fields
202# for fieldName in self.get_readonly_fields(request,obj):
203# if not fieldName in fields:
204# fields.append(fieldName)
205#
206# return [(None, {'fields': fields})]
Scott Baker74d8e622013-07-29 16:04:22 -0700207
Tony Mackc2835a92013-05-28 09:18:49 -0400208
Siobhan Tully567e3e62013-06-21 18:03:16 -0400209
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500210class SiteROInline(ReadOnlyTabularInline):
211 model = Site
212 extra = 0
213 fields = ['name', 'login_base', 'site_url', 'enabled']
214 suit_classes = 'suit-tab suit-tab-sites'
215
Siobhan Tullyd3515752013-06-21 16:34:53 -0400216class SiteInline(PlStackTabularInline):
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400217 model = Site
218 extra = 0
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400219 suit_classes = 'suit-tab suit-tab-sites'
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400220
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500221class UserROInline(ReadOnlyTabularInline):
222 model = User
223 fields = ['email', 'firstname', 'lastname']
224 extra = 0
225 suit_classes = 'suit-tab suit-tab-users'
226
Siobhan Tullyd3515752013-06-21 16:34:53 -0400227class UserInline(PlStackTabularInline):
Siobhan Tully30fd4292013-05-10 08:59:56 -0400228 model = User
Siobhan Tully47ae1b52013-05-10 15:53:14 -0400229 fields = ['email', 'firstname', 'lastname']
Siobhan Tully30fd4292013-05-10 08:59:56 -0400230 extra = 0
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400231 suit_classes = 'suit-tab suit-tab-users'
Siobhan Tully30fd4292013-05-10 08:59:56 -0400232
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500233class SliceROInline(ReadOnlyTabularInline):
234 model = Slice
235 suit_classes = 'suit-tab suit-tab-slices'
236 fields = ['name','site', 'serviceClass', 'service']
237
Siobhan Tullyd3515752013-06-21 16:34:53 -0400238class SliceInline(PlStackTabularInline):
Tony Mack00d361f2013-04-28 10:28:42 -0400239 model = Slice
Siobhan Tullyce652d02013-10-08 21:52:35 -0400240 fields = ['name','site', 'serviceClass', 'service']
Tony Mack00d361f2013-04-28 10:28:42 -0400241 extra = 0
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400242 suit_classes = 'suit-tab suit-tab-slices'
243
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500244class NodeROInline(ReadOnlyTabularInline):
245 model = Node
246 extra = 0
247 suit_classes = 'suit-tab suit-tab-nodes'
248 fields = ['name','deployment']
Tony Mack00d361f2013-04-28 10:28:42 -0400249
Siobhan Tullyd3515752013-06-21 16:34:53 -0400250class NodeInline(PlStackTabularInline):
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400251 model = Node
252 extra = 0
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400253 suit_classes = 'suit-tab suit-tab-nodes'
254
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500255class DeploymentPrivilegeROInline(ReadOnlyTabularInline):
256 model = DeploymentPrivilege
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400257 extra = 0
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500258 suit_classes = 'suit-tab suit-tab-deploymentprivileges'
259 fields = ['user','role']
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400260
261class DeploymentPrivilegeInline(PlStackTabularInline):
262 model = DeploymentPrivilege
263 extra = 0
264 suit_classes = 'suit-tab suit-tab-deploymentprivileges'
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400265
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500266#CLEANUP DOUBLE SitePrivilegeInline
267class SitePrivilegeROInline(ReadOnlyTabularInline):
268 model = SitePrivilege
269 extra = 0
270 suit_classes = 'suit-tab suit-tab-siteprivileges'
271 fields = ['user','site', 'role']
272
Siobhan Tullyd3515752013-06-21 16:34:53 -0400273class SitePrivilegeInline(PlStackTabularInline):
Siobhan Tullyaa1bcd52013-05-10 12:43:09 -0400274 model = SitePrivilege
275 extra = 0
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400276 suit_classes = 'suit-tab suit-tab-siteprivileges'
Siobhan Tullyaa1bcd52013-05-10 12:43:09 -0400277
Tony Mackc2835a92013-05-28 09:18:49 -0400278 def formfield_for_foreignkey(self, db_field, request, **kwargs):
279 if db_field.name == 'site':
280 if not request.user.is_admin:
281 # only show sites where user is an admin or pi
282 roles = Role.objects.filter(role_type__in=['admin', 'pi'])
283 site_privileges = SitePrivilege.objects.filter(user=request.user).filter(role__in=roles)
284 login_bases = [site_privilege.site.login_base for site_privilege in site_privileges]
285 sites = Site.objects.filter(login_base__in=login_bases)
286 kwargs['queryset'] = sites
287
288 if db_field.name == 'user':
289 if not request.user.is_admin:
290 # only show users from sites where caller has admin or pi role
291 roles = Role.objects.filter(role_type__in=['admin', 'pi'])
292 site_privileges = SitePrivilege.objects.filter(user=request.user).filter(role__in=roles)
293 sites = [site_privilege.site for site_privilege in site_privileges]
294 site_privileges = SitePrivilege.objects.filter(site__in=sites)
295 emails = [site_privilege.user.email for site_privilege in site_privileges]
296 users = User.objects.filter(email__in=emails)
297 kwargs['queryset'] = users
298 return super(SitePrivilegeInline, self).formfield_for_foreignkey(db_field, request, **kwargs)
299
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400300class SitePrivilegeInline(PlStackTabularInline):
301 model = SitePrivilege
302 suit_classes = 'suit-tab suit-tab-siteprivileges'
Siobhan Tullyaa1bcd52013-05-10 12:43:09 -0400303 extra = 0
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400304 fields = ('user', 'site','role')
305
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500306class SlicePrivilegeROInline(ReadOnlyTabularInline):
307 model = SlicePrivilege
308 extra = 0
309 suit_classes = 'suit-tab suit-tab-sliceprivileges'
310 fields = ['user', 'slice', 'role']
311
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400312class SlicePrivilegeInline(PlStackTabularInline):
313 model = SlicePrivilege
314 suit_classes = 'suit-tab suit-tab-sliceprivileges'
315 extra = 0
316 fields = ('user', 'slice','role')
Siobhan Tullyaa1bcd52013-05-10 12:43:09 -0400317
Tony Mackc2835a92013-05-28 09:18:49 -0400318 def formfield_for_foreignkey(self, db_field, request, **kwargs):
319 if db_field.name == 'slice':
320 if not request.user.is_admin:
321 # only show slices at sites where caller has admin or pi role
322 roles = Role.objects.filter(role_type__in=['admin', 'pi'])
323 site_privileges = SitePrivilege.objects.filter(user=request.user).filter(role__in=roles)
324 sites = [site_privilege.site for site_privilege in site_privileges]
325 slices = Slice.objects.filter(site__in=sites)
326 kwargs['queryset'] = slices
327 if db_field.name == 'user':
328 if not request.user.is_admin:
329 # only show users from sites where caller has admin or pi role
330 roles = Role.objects.filter(role_type__in=['admin', 'pi'])
331 site_privileges = SitePrivilege.objects.filter(user=request.user).filter(role__in=roles)
332 sites = [site_privilege.site for site_privilege in site_privileges]
333 site_privileges = SitePrivilege.objects.filter(site__in=sites)
334 emails = [site_privilege.user.email for site_privilege in site_privileges]
335 users = User.objects.filter(email__in=emails)
336 kwargs['queryset'] = list(users)
337
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400338 return super(SlicePrivilegeInline, self).formfield_for_foreignkey(db_field, request, **kwargs)
Tony Mackc2835a92013-05-28 09:18:49 -0400339
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500340class SliceNetworkROInline(ReadOnlyTabularInline):
341 model = Network.slices.through
342 extra = 0
343 verbose_name = "Network Connection"
344 verbose_name_plural = "Network Connections"
345 suit_classes = 'suit-tab suit-tab-slicenetworks'
346 fields = ['network']
347
Scott Bakera0015eb2013-08-14 17:28:14 -0700348class SliceNetworkInline(PlStackTabularInline):
Scott Baker74d8e622013-07-29 16:04:22 -0700349 model = Network.slices.through
350 extra = 0
351 verbose_name = "Network Connection"
352 verbose_name_plural = "Network Connections"
Siobhan Tully2d95e482013-09-06 10:56:06 -0400353 suit_classes = 'suit-tab suit-tab-slicenetworks'
Scott Baker74d8e622013-07-29 16:04:22 -0700354
Tony Mack5e71a662013-05-03 23:30:41 -0400355class PlainTextWidget(forms.HiddenInput):
356 input_type = 'hidden'
357
358 def render(self, name, value, attrs=None):
359 if value is None:
360 value = ''
Tony Mack1d6b85f2013-05-07 18:49:14 -0400361 return mark_safe(str(value) + super(PlainTextWidget, self).render(name, value, attrs))
Tony Mack9bcbe4f2013-04-29 08:13:27 -0400362
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500363class PlanetStackBaseAdmin(ReadOnlyAwareAdmin):
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400364 save_on_top = False
365
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400366class SliceRoleAdmin(PlanetStackBaseAdmin):
367 model = SliceRole
368 pass
369
370class SiteRoleAdmin(PlanetStackBaseAdmin):
371 model = SiteRole
372 pass
373
Siobhan Tullybf1153a2013-05-27 20:53:48 -0400374class DeploymentAdminForm(forms.ModelForm):
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400375 sites = forms.ModelMultipleChoiceField(
376 queryset=Site.objects.all(),
377 required=False,
378 widget=FilteredSelectMultiple(
379 verbose_name=('Sites'), is_stacked=False
380 )
381 )
382 class Meta:
Siobhan Tullybf1153a2013-05-27 20:53:48 -0400383 model = Deployment
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400384
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500385class SiteAssocInline(PlStackTabularInline):
386 model = Site.deployments.through
387 extra = 0
388 suit_classes = 'suit-tab suit-tab-sites'
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400389
Siobhan Tullybf1153a2013-05-27 20:53:48 -0400390class DeploymentAdmin(PlanetStackBaseAdmin):
391 form = DeploymentAdminForm
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500392 model = Deployment
393 fieldList = ['name','sites']
394 fieldsets = [(None, {'fields': fieldList, 'classes':['suit-tab suit-tab-sites']})]
Siobhan Tully2d95e482013-09-06 10:56:06 -0400395 inlines = [DeploymentPrivilegeInline,NodeInline,TagInline]
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500396
397 user_readonly_inlines = [DeploymentPrivilegeROInline,NodeROInline,TagROInline]
398 user_readonly_fields = ['name']
399
400 suit_form_tabs =(('sites','Deployment Details'),('nodes','Nodes'),('deploymentprivileges','Privileges'),('tags','Tags'))
401
402class ServiceAttrAsTabROInline(ReadOnlyTabularInline):
403 model = ServiceAttribute
404 fields = ['name','value']
405 extra = 0
406 suit_classes = 'suit-tab suit-tab-serviceattrs'
Tony Mack5cd13202013-05-01 21:48:38 -0400407
Siobhan Tullyce652d02013-10-08 21:52:35 -0400408class ServiceAttrAsTabInline(PlStackTabularInline):
409 model = ServiceAttribute
410 fields = ['name','value']
411 extra = 0
412 suit_classes = 'suit-tab suit-tab-serviceattrs'
413
Siobhan Tullyce652d02013-10-08 21:52:35 -0400414class ServiceAdmin(PlanetStackBaseAdmin):
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500415 list_display = ("name","description","versionNumber","enabled","published")
416 fieldList = ["name","description","versionNumber","enabled","published"]
417 fieldsets = [(None, {'fields': fieldList, 'classes':['suit-tab suit-tab-general']})]
418 inlines = [ServiceAttrAsTabInline,SliceInline]
419
420 user_readonly_fields = fieldList
421 user_readonly_inlines = [ServiceAttrAsTabROInline,SliceROInline]
422
423 suit_form_tabs =(('general', 'Service Details'),
424 ('slices','Slices'),
425 ('serviceattrs','Additional Attributes'),
426 )
Siobhan Tullyce652d02013-10-08 21:52:35 -0400427
Tony Mack0553f282013-06-10 22:54:50 -0400428class SiteAdmin(PlanetStackBaseAdmin):
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500429 fieldList = ['name', 'site_url', 'enabled', 'is_public', 'login_base', 'accountLink','location']
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400430 fieldsets = [
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500431 (None, {'fields': fieldList, 'classes':['suit-tab suit-tab-general']}),
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400432 ('Deployment Networks', {'fields': ['deployments'], 'classes':['suit-tab suit-tab-deployments']}),
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400433 ]
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400434 suit_form_tabs =(('general', 'Site Details'),
435 ('users','Users'),
Siobhan Tully2d95e482013-09-06 10:56:06 -0400436 ('siteprivileges','Privileges'),
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400437 ('deployments','Deployments'),
438 ('slices','Slices'),
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500439 ('nodes','Nodes'),
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400440 ('tags','Tags'),
441 )
Scott Baker545db2a2013-12-09 18:44:43 -0800442 readonly_fields = ['accountLink']
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500443
444 user_readonly_fields = ['name', 'deployments','site_url', 'enabled', 'is_public', 'login_base', 'accountLink']
445 user_readonly_inlines = [SliceROInline,UserROInline,TagROInline, NodeROInline, SitePrivilegeROInline]
446
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400447 list_display = ('name', 'login_base','site_url', 'enabled')
448 filter_horizontal = ('deployments',)
Siobhan Tully2d95e482013-09-06 10:56:06 -0400449 inlines = [SliceInline,UserInline,TagInline, NodeInline, SitePrivilegeInline]
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400450 search_fields = ['name']
451
Tony Mack04062832013-05-10 08:22:44 -0400452 def queryset(self, request):
453 # admins can see all keys. Users can only see sites they belong to.
454 qs = super(SiteAdmin, self).queryset(request)
455 if not request.user.is_admin:
456 valid_sites = [request.user.site.login_base]
457 roles = request.user.get_roles()
458 for tenant_list in roles.values():
459 valid_sites.extend(tenant_list)
460 qs = qs.filter(login_base__in=valid_sites)
461 return qs
462
Tony Mack5cd13202013-05-01 21:48:38 -0400463 def get_formsets(self, request, obj=None):
464 for inline in self.get_inline_instances(request, obj):
465 # hide MyInline in the add view
466 if obj is None:
467 continue
Tony Mack2bd5b412013-06-11 21:05:06 -0400468 if isinstance(inline, SliceInline):
469 inline.model.caller = request.user
470 yield inline.get_formset(request, obj)
471
472 def get_formsets(self, request, obj=None):
473 for inline in self.get_inline_instances(request, obj):
474 # hide MyInline in the add view
475 if obj is None:
476 continue
477 if isinstance(inline, SliverInline):
478 inline.model.caller = request.user
Tony Mack5cd13202013-05-01 21:48:38 -0400479 yield inline.get_formset(request, obj)
480
Scott Baker545db2a2013-12-09 18:44:43 -0800481 def accountLink(self, obj):
482 link_obj = obj.accounts.all()
483 if link_obj:
484 reverse_path = "admin:core_account_change"
485 url = reverse(reverse_path, args =(link_obj[0].id,))
486 return "<a href='%s'>%s</a>" % (url, "view billing details")
487 else:
488 return "no billing data for this site"
489 accountLink.allow_tags = True
490 accountLink.short_description = "Billing"
491
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500492
Tony Mack9bcbe4f2013-04-29 08:13:27 -0400493class SitePrivilegeAdmin(PlanetStackBaseAdmin):
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500494 fieldList = ['user', 'site', 'role']
Tony Mack00d361f2013-04-28 10:28:42 -0400495 fieldsets = [
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500496 (None, {'fields': fieldList, 'classes':['collapse']})
Tony Mack00d361f2013-04-28 10:28:42 -0400497 ]
498 list_display = ('user', 'site', 'role')
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500499 user_readonly_fields = fieldList
500 user_readonly_inlines = []
Tony Mack00d361f2013-04-28 10:28:42 -0400501
Tony Mackc2835a92013-05-28 09:18:49 -0400502 def formfield_for_foreignkey(self, db_field, request, **kwargs):
503 if db_field.name == 'site':
504 if not request.user.is_admin:
505 # only show sites where user is an admin or pi
506 sites = set()
507 for site_privilege in SitePrivilege.objects.filer(user=request.user):
508 if site_privilege.role.role_type in ['admin', 'pi']:
509 sites.add(site_privilege.site)
510 kwargs['queryset'] = Site.objects.filter(site__in=list(sites))
511
512 if db_field.name == 'user':
513 if not request.user.is_admin:
514 # only show users from sites where caller has admin or pi role
515 roles = Role.objects.filter(role_type__in=['admin', 'pi'])
516 site_privileges = SitePrivilege.objects.filter(user=request.user).filter(role__in=roles)
517 sites = [site_privilege.site for site_privilege in site_privileges]
518 site_privileges = SitePrivilege.objects.filter(site__in=sites)
519 emails = [site_privilege.user.email for site_privilege in site_privileges]
520 users = User.objects.filter(email__in=emails)
521 kwargs['queryset'] = users
522
523 return super(SitePrivilegeAdmin, self).formfield_for_foreignkey(db_field, request, **kwargs)
524
Tony Mack04062832013-05-10 08:22:44 -0400525 def queryset(self, request):
526 # admins can see all privileges. Users can only see privileges at sites
Tony Mackc2835a92013-05-28 09:18:49 -0400527 # where they have the admin role or pi role.
Tony Mack04062832013-05-10 08:22:44 -0400528 qs = super(SitePrivilegeAdmin, self).queryset(request)
529 if not request.user.is_admin:
Tony Mackc2835a92013-05-28 09:18:49 -0400530 roles = Role.objects.filter(role_type__in=['admin', 'pi'])
531 site_privileges = SitePrivilege.objects.filter(user=request.user).filter(role__in=roles)
532 login_bases = [site_privilege.site.login_base for site_privilege in site_privileges]
533 sites = Site.objects.filter(login_base__in=login_bases)
534 qs = qs.filter(site__in=sites)
Tony Mack04062832013-05-10 08:22:44 -0400535 return qs
536
Siobhan Tullyce652d02013-10-08 21:52:35 -0400537class SliceForm(forms.ModelForm):
538 class Meta:
539 model = Slice
540 widgets = {
541 'service': LinkedSelect
542 }
543
Tony Mack2bd5b412013-06-11 21:05:06 -0400544class SliceAdmin(PlanetStackBaseAdmin):
Siobhan Tullyce652d02013-10-08 21:52:35 -0400545 form = SliceForm
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500546 fieldList = ['name', 'site', 'serviceClass', 'enabled','description', 'service', 'slice_url']
547 fieldsets = [('Slice Details', {'fields': fieldList, 'classes':['suit-tab suit-tab-general']}),]
Siobhan Tully30fd4292013-05-10 08:59:56 -0400548 list_display = ('name', 'site','serviceClass', 'slice_url')
Siobhan Tully2d95e482013-09-06 10:56:06 -0400549 inlines = [SlicePrivilegeInline,SliverInline, TagInline, ReservationInline,SliceNetworkInline]
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400550
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500551 user_readonly_fields = fieldList
552 user_readonly_inlines = [SlicePrivilegeROInline,SliverROInline,TagROInline, ReservationROInline, SliceNetworkROInline]
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400553
554 suit_form_tabs =(('general', 'Slice Details'),
Siobhan Tully2d95e482013-09-06 10:56:06 -0400555 ('slicenetworks','Networks'),
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400556 ('sliceprivileges','Privileges'),
557 ('slivers','Slivers'),
558 ('tags','Tags'),
559 ('reservations','Reservations'),
560 )
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400561
Tony Mackc2835a92013-05-28 09:18:49 -0400562 def formfield_for_foreignkey(self, db_field, request, **kwargs):
563 if db_field.name == 'site':
564 if not request.user.is_admin:
565 # only show sites where user is a pi or admin
566 roles = Role.objects.filter(role_type__in=['admin', 'pi'])
567 site_privileges = SitePrivilege.objects.filter(user=request.user).filter(role__in=roles)
568 login_bases = [site_privilege.site.login_base for site_privilege in site_privileges]
569 sites = Site.objects.filter(login_base__in=login_bases)
570 kwargs['queryset'] = sites
571
572 return super(SliceAdmin, self).formfield_for_foreignkey(db_field, request, **kwargs)
573
Tony Mack04062832013-05-10 08:22:44 -0400574 def queryset(self, request):
575 # admins can see all keys. Users can only see slices they belong to.
576 qs = super(SliceAdmin, self).queryset(request)
577 if not request.user.is_admin:
578 valid_slices = []
579 roles = request.user.get_roles()
580 for tenant_list in roles.values():
581 valid_slices.extend(tenant_list)
582 qs = qs.filter(name__in=valid_slices)
583 return qs
584
Tony Mack79748612013-05-01 14:52:03 -0400585 def get_formsets(self, request, obj=None):
586 for inline in self.get_inline_instances(request, obj):
587 # hide MyInline in the add view
588 if obj is None:
589 continue
Tony Mack2bd5b412013-06-11 21:05:06 -0400590 if isinstance(inline, SliverInline):
591 inline.model.caller = request.user
Tony Mack79748612013-05-01 14:52:03 -0400592 yield inline.get_formset(request, obj)
593
Tony Mackfdd4d802013-04-27 13:02:33 -0400594 def get_queryset(self, request):
595 qs = super(SliceAdmin, self).get_queryset(request)
596 if request.user.is_superuser:
597 return qs
598 # users can only see slices at their site
Tony Mack2bd5b412013-06-11 21:05:06 -0400599 return qs.filter(site=request.user.site)
600
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400601class SlicePrivilegeAdmin(PlanetStackBaseAdmin):
Tony Mack00d361f2013-04-28 10:28:42 -0400602 fieldsets = [
603 (None, {'fields': ['user', 'slice', 'role']})
604 ]
605 list_display = ('user', 'slice', 'role')
Tony Mack00d361f2013-04-28 10:28:42 -0400606
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500607 user_readonly_fields = ['user', 'slice', 'role']
608 user_readonly_inlines = []
609
Tony Mackc2835a92013-05-28 09:18:49 -0400610 def formfield_for_foreignkey(self, db_field, request, **kwargs):
611 if db_field.name == 'slice':
612 if not request.user.is_admin:
613 # only show slices at sites where caller has admin or pi role
614 roles = Role.objects.filter(role_type__in=['admin', 'pi'])
615 site_privileges = SitePrivilege.objects.filter(user=request.user).filter(role__in=roles)
616 sites = [site_privilege.site for site_privilege in site_privileges]
617 slices = Slice.objects.filter(site__in=sites)
618 kwargs['queryset'] = slices
619
620 if db_field.name == 'user':
621 if not request.user.is_admin:
622 # only show users from sites where caller has admin or pi role
623 roles = Role.objects.filter(role_type__in=['admin', 'pi'])
624 site_privileges = SitePrivilege.objects.filter(user=request.user).filter(role__in=roles)
625 sites = [site_privilege.site for site_privilege in site_privileges]
626 site_privileges = SitePrivilege.objects.filter(site__in=sites)
627 emails = [site_privilege.user.email for site_privilege in site_privileges]
628 users = User.objects.filter(email__in=emails)
629 kwargs['queryset'] = users
630
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400631 return super(SlicePrivilegeAdmin, self).formfield_for_foreignkey(db_field, request, **kwargs)
Tony Mackc2835a92013-05-28 09:18:49 -0400632
Tony Mack04062832013-05-10 08:22:44 -0400633 def queryset(self, request):
634 # admins can see all memberships. Users can only see memberships of
635 # slices where they have the admin role.
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400636 qs = super(SlicePrivilegeAdmin, self).queryset(request)
Tony Mack04062832013-05-10 08:22:44 -0400637 if not request.user.is_admin:
Tony Mackc2835a92013-05-28 09:18:49 -0400638 roles = Role.objects.filter(role_type__in=['admin', 'pi'])
639 site_privileges = SitePrivilege.objects.filter(user=request.user).filter(role__in=roles)
640 login_bases = [site_privilege.site.login_base for site_privilege in site_privileges]
641 sites = Site.objects.filter(login_base__in=login_bases)
642 slices = Slice.objects.filter(site__in=sites)
643 qs = qs.filter(slice__in=slices)
Tony Mack04062832013-05-10 08:22:44 -0400644 return qs
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400645
Tony Mack9bcbe4f2013-04-29 08:13:27 -0400646 def save_model(self, request, obj, form, change):
Tony Mack951dab42013-05-02 19:51:45 -0400647 # update openstack connection to use this site/tenant
648 auth = request.session.get('auth', {})
649 auth['tenant'] = obj.slice.name
650 obj.os_manager = OpenStackManager(auth=auth, caller=request.user)
Tony Mack9bcbe4f2013-04-29 08:13:27 -0400651 obj.save()
652
653 def delete_model(self, request, obj):
Tony Mack951dab42013-05-02 19:51:45 -0400654 # update openstack connection to use this site/tenant
655 auth = request.session.get('auth', {})
656 auth['tenant'] = obj.slice.name
657 obj.os_manager = OpenStackManager(auth=auth, caller=request.user)
Tony Mack9bcbe4f2013-04-29 08:13:27 -0400658 obj.delete()
659
Siobhan Tully567e3e62013-06-21 18:03:16 -0400660
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400661class ImageAdmin(PlanetStackBaseAdmin):
662
663 fieldsets = [('Image Details',
664 {'fields': ['image_id', 'name', 'disk_format', 'container_format'],
665 'classes': ['suit-tab suit-tab-general']})
666 ]
667
668 suit_form_tabs =(('general','Image Details'),('slivers','Slivers'))
669
670 inlines = [SliverInline]
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500671
672 user_readonly_fields = ['image_id', 'name', 'disk_format', 'container_format']
673 user_readonly_inlines = [SliverROInline]
674
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400675class NodeForm(forms.ModelForm):
676 class Meta:
677 widgets = {
678 'site': LinkedSelect,
679 'deployment': LinkedSelect
680 }
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400681
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500682class NodeAdmin(PlanetStackBaseAdmin):
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400683 form = NodeForm
Siobhan Tullybf1153a2013-05-27 20:53:48 -0400684 list_display = ('name', 'site', 'deployment')
685 list_filter = ('deployment',)
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500686
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400687 inlines = [TagInline,SliverInline]
688 fieldsets = [('Node Details', {'fields': ['name','site','deployment'], 'classes':['suit-tab suit-tab-details']})]
689
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500690 user_readonly_fields = ['name','site','deployment']
691 user_readonly_inlines = [TagInline,SliverInline]
692
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400693 suit_form_tabs =(('details','Node Details'),('slivers','Slivers'),('tags','Tags'))
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400694
Siobhan Tully567e3e62013-06-21 18:03:16 -0400695
Tony Mackd90cdbf2013-04-16 22:48:40 -0400696class SliverForm(forms.ModelForm):
697 class Meta:
Tony Mack1d6b85f2013-05-07 18:49:14 -0400698 model = Sliver
Tony Mackd90cdbf2013-04-16 22:48:40 -0400699 ip = forms.CharField(widget=PlainTextWidget)
Tony Mack18261812013-05-02 16:39:20 -0400700 instance_name = forms.CharField(widget=PlainTextWidget)
Tony Mackd90cdbf2013-04-16 22:48:40 -0400701 widgets = {
702 'ip': PlainTextWidget(),
Tony Mack18261812013-05-02 16:39:20 -0400703 'instance_name': PlainTextWidget(),
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400704 'slice': LinkedSelect,
705 'deploymentNetwork': LinkedSelect,
706 'node': LinkedSelect,
707 'image': LinkedSelect
Siobhan Tully53437282013-04-26 19:30:27 -0400708 }
Tony Mackd90cdbf2013-04-16 22:48:40 -0400709
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500710class TagAdmin(PlanetStackBaseAdmin):
Siobhan Tullyce652d02013-10-08 21:52:35 -0400711 list_display = ['service', 'name', 'value', 'content_type', 'content_object',]
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500712 user_readonly_fields = ['service', 'name', 'value', 'content_type', 'content_object',]
713 user_readonly_inlines = []
Siobhan Tullyd3515752013-06-21 16:34:53 -0400714
Tony Mack9bcbe4f2013-04-29 08:13:27 -0400715class SliverAdmin(PlanetStackBaseAdmin):
Tony Mackd90cdbf2013-04-16 22:48:40 -0400716 form = SliverForm
Tony Mackcdec0902013-04-15 00:38:49 -0400717 fieldsets = [
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400718 ('Sliver Details', {'fields': ['slice', 'deploymentNetwork', 'node', 'ip', 'instance_name', 'numberCores', 'image', ], 'classes': ['suit-tab suit-tab-general'], })
Tony Mackcdec0902013-04-15 00:38:49 -0400719 ]
Siobhan Tully5d7dc8d2013-07-02 13:17:33 -0400720 list_display = ['ip', 'instance_name', 'slice', 'numberCores', 'image', 'node', 'deploymentNetwork']
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400721
722 suit_form_tabs =(('general', 'Sliver Details'),
723 ('tags','Tags'),
724 )
725
Siobhan Tullyde5450d2013-06-21 11:35:33 -0400726 inlines = [TagInline]
Tony Mack53106f32013-04-27 16:43:01 -0400727
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500728 user_readonly_fields = ['slice', 'deploymentNetwork', 'node', 'ip', 'instance_name', 'numberCores', 'image']
729 user_readonly_inlines = [TagROInline]
730
Tony Mackc2835a92013-05-28 09:18:49 -0400731 def formfield_for_foreignkey(self, db_field, request, **kwargs):
732 if db_field.name == 'slice':
733 if not request.user.is_admin:
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400734 slices = set([sm.slice.name for sm in SlicePrivilege.objects.filter(user=request.user)])
Tony Mackc2835a92013-05-28 09:18:49 -0400735 kwargs['queryset'] = Slice.objects.filter(name__in=list(slices))
736
737 return super(SliverAdmin, self).formfield_for_foreignkey(db_field, request, **kwargs)
738
Tony Mack04062832013-05-10 08:22:44 -0400739 def queryset(self, request):
740 # admins can see all slivers. Users can only see slivers of
741 # the slices they belong to.
742 qs = super(SliverAdmin, self).queryset(request)
743 if not request.user.is_admin:
744 tenants = []
745 roles = request.user.get_roles()
746 for tenant_list in roles.values():
747 tenants.extend(tenant_list)
748 valid_slices = Slice.objects.filter(name__in=tenants)
749 qs = qs.filter(slice__in=valid_slices)
750 return qs
751
Tony Mack1d6b85f2013-05-07 18:49:14 -0400752 def get_formsets(self, request, obj=None):
753 # make some fields read only if we are updating an existing record
754 if obj == None:
755 #self.readonly_fields = ('ip', 'instance_name')
756 self.readonly_fields = ()
757 else:
Tony Mack1e889462013-05-10 21:34:54 -0400758 self.readonly_fields = ()
759 #self.readonly_fields = ('ip', 'instance_name', 'slice', 'image', 'key')
Tony Mack1d6b85f2013-05-07 18:49:14 -0400760
761 for inline in self.get_inline_instances(request, obj):
762 # hide MyInline in the add view
763 if obj is None:
764 continue
765 # give inline object access to driver and caller
766 auth = request.session.get('auth', {})
767 auth['tenant'] = obj.name # meed to connect using slice's tenant
768 inline.model.os_manager = OpenStackManager(auth=auth, caller=request.user)
769 yield inline.get_formset(request, obj)
Tony Mack53106f32013-04-27 16:43:01 -0400770
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500771 #def save_model(self, request, obj, form, change):
772 # # update openstack connection to use this site/tenant
773 # auth = request.session.get('auth', {})
774 # auth['tenant'] = obj.slice.name
775 # obj.os_manager = OpenStackManager(auth=auth, caller=request.user)
776 # obj.creator = request.user
777 # obj.save()
Tony Mack53106f32013-04-27 16:43:01 -0400778
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500779 #def delete_model(self, request, obj):
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.delete()
Tony Mackcdec0902013-04-15 00:38:49 -0400785
Siobhan Tully53437282013-04-26 19:30:27 -0400786class UserCreationForm(forms.ModelForm):
787 """A form for creating new users. Includes all the required
788 fields, plus a repeated password."""
789 password1 = forms.CharField(label='Password', widget=forms.PasswordInput)
790 password2 = forms.CharField(label='Password confirmation', widget=forms.PasswordInput)
791
792 class Meta:
Siobhan Tully30fd4292013-05-10 08:59:56 -0400793 model = User
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400794 fields = ('email', 'firstname', 'lastname', 'phone', 'public_key')
Siobhan Tully53437282013-04-26 19:30:27 -0400795
796 def clean_password2(self):
797 # Check that the two password entries match
798 password1 = self.cleaned_data.get("password1")
799 password2 = self.cleaned_data.get("password2")
800 if password1 and password2 and password1 != password2:
801 raise forms.ValidationError("Passwords don't match")
802 return password2
803
804 def save(self, commit=True):
805 # Save the provided password in hashed format
806 user = super(UserCreationForm, self).save(commit=False)
Tony Mackf9f4afb2013-05-01 21:02:12 -0400807 user.password = self.cleaned_data["password1"]
808 #user.set_password(self.cleaned_data["password1"])
Siobhan Tully53437282013-04-26 19:30:27 -0400809 if commit:
810 user.save()
811 return user
812
Siobhan Tully567e3e62013-06-21 18:03:16 -0400813
Siobhan Tully53437282013-04-26 19:30:27 -0400814class UserChangeForm(forms.ModelForm):
815 """A form for updating users. Includes all the fields on
816 the user, but replaces the password field with admin's
817 password hash display field.
818 """
Siobhan Tully63b7ba42014-01-12 10:35:11 -0500819 password = ReadOnlyPasswordHashField(label='Password',
820 help_text= '<a href=\"password/\">Change Password</a>.')
Siobhan Tully53437282013-04-26 19:30:27 -0400821
822 class Meta:
Siobhan Tully30fd4292013-05-10 08:59:56 -0400823 model = User
Siobhan Tully53437282013-04-26 19:30:27 -0400824
825 def clean_password(self):
826 # Regardless of what the user provides, return the initial value.
827 # This is done here, rather than on the field, because the
828 # field does not have access to the initial value
829 return self.initial["password"]
830
Tony Mack2bd5b412013-06-11 21:05:06 -0400831class UserAdmin(UserAdmin):
Siobhan Tully53437282013-04-26 19:30:27 -0400832 class Meta:
833 app_label = "core"
834
835 # The forms to add and change user instances
836 form = UserChangeForm
837 add_form = UserCreationForm
838
839 # The fields to be used in displaying the User model.
840 # These override the definitions on the base UserAdmin
841 # that reference specific fields on auth.User.
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500842 list_display = ('email', 'firstname', 'lastname', 'site', 'last_login')
Siobhan Tullyce652d02013-10-08 21:52:35 -0400843 #list_display = ('email', 'username','firstname', 'lastname', 'is_admin', 'last_login')
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500844 list_filter = ('site',)
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400845 inlines = [SlicePrivilegeInline,SitePrivilegeInline,DeploymentPrivilegeInline]
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500846
847 fieldListLoginDetails = ['email','site','password','is_readonly','is_amin','public_key']
848 fieldListContactInfo = ['firstname','lastname','phone','timezone']
849
Siobhan Tully53437282013-04-26 19:30:27 -0400850 fieldsets = (
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500851 ('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 -0400852 ('Contact Information', {'fields': ('firstname','lastname','phone', 'timezone'), 'classes':['suit-tab suit-tab-contact']}),
Siobhan Tully53437282013-04-26 19:30:27 -0400853 #('Important dates', {'fields': ('last_login',)}),
854 )
855 add_fieldsets = (
856 (None, {
857 'classes': ('wide',),
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500858 'fields': ('email', 'firstname', 'lastname', 'is_readonly', 'phone', 'public_key','password1', 'password2')}
Siobhan Tully53437282013-04-26 19:30:27 -0400859 ),
860 )
861 search_fields = ('email',)
862 ordering = ('email',)
863 filter_horizontal = ()
864
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500865 user_readonly_fields = fieldListLoginDetails
866 user_readonly_inlines = [SlicePrivilegeROInline,SitePrivilegeROInline,DeploymentPrivilegeROInline]
867
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400868 suit_form_tabs =(('general','Login Details'),('contact','Contact Information'),('sliceprivileges','Slice Privileges'),('siteprivileges','Site Privileges'),('deploymentprivileges','Deployment Privileges'))
869
Tony Mackc2835a92013-05-28 09:18:49 -0400870 def formfield_for_foreignkey(self, db_field, request, **kwargs):
871 if db_field.name == 'site':
872 if not request.user.is_admin:
873 # show sites where caller is an admin or pi
874 sites = []
875 for site_privilege in SitePrivilege.objects.filer(user=request.user):
876 if site_privilege.role.role_type in ['admin', 'pi']:
877 sites.append(site_privilege.site.login_base)
878 kwargs['queryset'] = Site.objects.filter(login_base__in(list(sites)))
879
880 return super(UserAdmin, self).formfield_for_foreignkey(db_field, request, **kwargs)
881
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500882 def has_add_permission(self, request, obj=None):
883 return (not self.__user_is_readonly(request))
884
885 def has_delete_permission(self, request, obj=None):
886 return (not self.__user_is_readonly(request))
887
888 def get_actions(self,request):
889 actions = super(UserAdmin,self).get_actions(request)
890
891 if self.__user_is_readonly(request):
892 if 'delete_selected' in actions:
893 del actions['delete_selected']
894
895 return actions
896
897 def change_view(self,request,object_id, extra_context=None):
898
899 if self.__user_is_readonly(request):
900 self.readonly_fields=self.user_readonly_fields
901 self.inlines = self.user_readonly_inlines
902 try:
903 return super(UserAdmin, self).change_view(request, object_id, extra_context=extra_context)
904 except PermissionDenied:
905 pass
906 if request.method == 'POST':
907 raise PermissionDenied
908 request.readonly = True
909 return super(UserAdmin, self).change_view(request, object_id, extra_context=extra_context)
910
911 def __user_is_readonly(self, request):
912 #groups = [x.name for x in request.user.groups.all() ]
913 #return "readonly" in groups
914 return request.user.isReadOnlyUser()
915
916
917
918class ServiceResourceROInline(ReadOnlyTabularInline):
919 model = ServiceResource
920 extra = 0
921 fields = ['serviceClass', 'name', 'maxUnitsDeployment', 'maxUnitsNode', 'maxDuration', 'bucketInRate', 'bucketMaxSize', 'cost', 'calendarReservable']
922
Scott Baker0165fac2014-01-13 11:49:26 -0800923class ServiceResourceInline(PlStackTabularInline):
Scott Baker3de3e372013-05-10 16:50:44 -0700924 model = ServiceResource
925 extra = 0
926
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500927class ServiceClassAdmin(PlanetStackBaseAdmin):
Scott Baker3de3e372013-05-10 16:50:44 -0700928 list_display = ('name', 'commitment', 'membershipFee')
929 inlines = [ServiceResourceInline]
930
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500931 user_readonly_fields = ['name', 'commitment', 'membershipFee']
932 user_readonly_inlines = []
933
934class ReservedResourceROInline(ReadOnlyTabularInline):
935 model = ReservedResource
936 extra = 0
937 fields = ['sliver', 'resource','quantity','reservationSet']
938 suit_classes = 'suit-tab suit-tab-reservedresources'
939
Scott Baker0165fac2014-01-13 11:49:26 -0800940class ReservedResourceInline(PlStackTabularInline):
Scott Baker133c9212013-05-17 09:09:11 -0700941 model = ReservedResource
942 extra = 0
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400943 suit_classes = 'suit-tab suit-tab-reservedresources'
Scott Baker133c9212013-05-17 09:09:11 -0700944
945 def formfield_for_foreignkey(self, db_field, request=None, **kwargs):
946 field = super(ReservedResourceInline, self).formfield_for_foreignkey(db_field, request, **kwargs)
947
948 if db_field.name == 'resource':
949 # restrict resources to those that the slice's service class allows
950 if request._slice is not None:
951 field.queryset = field.queryset.filter(serviceClass = request._slice.serviceClass, calendarReservable=True)
952 if len(field.queryset) > 0:
953 field.initial = field.queryset.all()[0]
954 else:
955 field.queryset = field.queryset.none()
956 elif db_field.name == 'sliver':
957 # restrict slivers to those that belong to the slice
958 if request._slice is not None:
959 field.queryset = field.queryset.filter(slice = request._slice)
960 else:
961 field.queryset = field.queryset.none()
962
963 return field
964
965class ReservationChangeForm(forms.ModelForm):
966 class Meta:
967 model = Reservation
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400968 widgets = {
969 'slice' : LinkedSelect
970 }
Scott Baker133c9212013-05-17 09:09:11 -0700971
972class ReservationAddForm(forms.ModelForm):
973 slice = forms.ModelChoiceField(queryset=Slice.objects.all(), widget=forms.Select(attrs={"onChange":"document.getElementById('id_refresh').value=1; submit()"}))
974 refresh = forms.CharField(widget=forms.HiddenInput())
975
976 class Media:
977 css = {'all': ('planetstack.css',)} # .field-refresh { display: none; }
978
979 def clean_slice(self):
980 slice = self.cleaned_data.get("slice")
981 x = ServiceResource.objects.filter(serviceClass = slice.serviceClass, calendarReservable=True)
982 if len(x) == 0:
983 raise forms.ValidationError("The slice you selected does not have a service class that allows reservations")
984 return slice
985
986 class Meta:
987 model = Reservation
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400988 widgets = {
989 'slice' : LinkedSelect
990 }
991
Scott Baker133c9212013-05-17 09:09:11 -0700992
993class ReservationAddRefreshForm(ReservationAddForm):
994 """ This form is displayed when the Reservation Form receives an update
995 from the Slice dropdown onChange handler. It doesn't validate the
996 data and doesn't save the data. This will cause the form to be
997 redrawn.
998 """
999
Scott Baker8737e5f2013-05-17 09:35:32 -07001000 """ don't validate anything other than slice """
1001 dont_validate_fields = ("startTime", "duration")
1002
Scott Baker133c9212013-05-17 09:09:11 -07001003 def full_clean(self):
1004 result = super(ReservationAddForm, self).full_clean()
Scott Baker8737e5f2013-05-17 09:35:32 -07001005
1006 for fieldname in self.dont_validate_fields:
1007 if fieldname in self._errors:
1008 del self._errors[fieldname]
1009
Scott Baker133c9212013-05-17 09:09:11 -07001010 return result
1011
1012 """ don't save anything """
1013 def is_valid(self):
1014 return False
1015
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001016class ReservationAdmin(PlanetStackBaseAdmin):
1017 fieldList = ['slice', 'startTime', 'duration']
1018 fieldsets = [('Reservation Details', {'fields': fieldList, 'classes': ['suit-tab suit-tab-general']})]
Scott Baker133c9212013-05-17 09:09:11 -07001019 list_display = ('startTime', 'duration')
Scott Baker133c9212013-05-17 09:09:11 -07001020 form = ReservationAddForm
1021
Siobhan Tullybfd11dc2013-09-03 12:59:24 -04001022 suit_form_tabs = (('general','Reservation Details'), ('reservedresources','Reserved Resources'))
1023
1024 inlines = [ReservedResourceInline]
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001025 user_readonly_inlines = [ReservedResourceROInline]
1026 user_readonly_fields = fieldList
Siobhan Tullybfd11dc2013-09-03 12:59:24 -04001027
Scott Baker133c9212013-05-17 09:09:11 -07001028 def add_view(self, request, form_url='', extra_context=None):
Scott Bakeracd45142013-05-19 16:19:16 -07001029 timezone.activate(request.user.timezone)
Scott Baker133c9212013-05-17 09:09:11 -07001030 request._refresh = False
1031 request._slice = None
1032 if request.method == 'POST':
Scott Baker8737e5f2013-05-17 09:35:32 -07001033 # "refresh" will be set to "1" if the form was submitted due to
1034 # a change in the Slice dropdown.
Scott Baker133c9212013-05-17 09:09:11 -07001035 if request.POST.get("refresh","1") == "1":
1036 request._refresh = True
1037 request.POST["refresh"] = "0"
Scott Baker8737e5f2013-05-17 09:35:32 -07001038
1039 # Keep track of the slice that was selected, so the
1040 # reservedResource inline can filter items for the slice.
Scott Baker133c9212013-05-17 09:09:11 -07001041 request._slice = request.POST.get("slice",None)
1042 if (request._slice is not None):
1043 request._slice = Slice.objects.get(id=request._slice)
1044
1045 result = super(ReservationAdmin, self).add_view(request, form_url, extra_context)
1046 return result
1047
Scott Bakeracd45142013-05-19 16:19:16 -07001048 def changelist_view(self, request, extra_context = None):
1049 timezone.activate(request.user.timezone)
1050 return super(ReservationAdmin, self).changelist_view(request, extra_context)
1051
Scott Baker133c9212013-05-17 09:09:11 -07001052 def get_form(self, request, obj=None, **kwargs):
Siobhan Tullyd3515752013-06-21 16:34:53 -04001053 request._obj_ = obj
1054 if obj is not None:
1055 # For changes, set request._slice to the slice already set in the
1056 # object.
1057 request._slice = obj.slice
1058 self.form = ReservationChangeForm
1059 else:
1060 if getattr(request, "_refresh", False):
1061 self.form = ReservationAddRefreshForm
1062 else:
1063 self.form = ReservationAddForm
1064 return super(ReservationAdmin, self).get_form(request, obj, **kwargs)
1065
Scott Baker133c9212013-05-17 09:09:11 -07001066 def get_readonly_fields(self, request, obj=None):
Siobhan Tullyd3515752013-06-21 16:34:53 -04001067 if (obj is not None):
1068 # Prevent slice from being changed after the reservation has been
1069 # created.
1070 return ['slice']
1071 else:
Scott Baker133c9212013-05-17 09:09:11 -07001072 return []
Scott Baker3de3e372013-05-10 16:50:44 -07001073
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001074class NetworkParameterTypeAdmin(PlanetStackBaseAdmin):
Scott Baker74d8e622013-07-29 16:04:22 -07001075 list_display = ("name", )
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001076 user_readonly_fields = ['name']
1077 user_readonly_inlines = []
Scott Baker74d8e622013-07-29 16:04:22 -07001078
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001079class RouterAdmin(PlanetStackBaseAdmin):
Scott Baker74d8e622013-07-29 16:04:22 -07001080 list_display = ("name", )
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001081 user_readonly_fields = ['name']
1082 user_readonly_inlines = []
1083
1084class RouterROInline(ReadOnlyTabularInline):
1085 model = Router.networks.through
1086 extra = 0
1087 verbose_name_plural = "Routers"
1088 verbose_name = "Router"
1089 suit_classes = 'suit-tab suit-tab-routers'
1090
1091 fields = ['name', 'owner', 'permittedNetworks', 'networks']
Scott Baker74d8e622013-07-29 16:04:22 -07001092
Scott Baker0165fac2014-01-13 11:49:26 -08001093class RouterInline(PlStackTabularInline):
Scott Baker74d8e622013-07-29 16:04:22 -07001094 model = Router.networks.through
1095 extra = 0
1096 verbose_name_plural = "Routers"
1097 verbose_name = "Router"
Siobhan Tully2d95e482013-09-06 10:56:06 -04001098 suit_classes = 'suit-tab suit-tab-routers'
Scott Baker74d8e622013-07-29 16:04:22 -07001099
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001100class NetworkParameterROInline(ReadOnlyTabularInline):
1101 model = NetworkParameter
1102 extra = 1
1103 verbose_name_plural = "Parameters"
1104 verbose_name = "Parameter"
1105 suit_classes = 'suit-tab suit-tab-netparams'
1106 fields = ['parameter', 'value', 'content_type', 'object_id', 'content_object']
1107
Scott Baker74d8e622013-07-29 16:04:22 -07001108class NetworkParameterInline(generic.GenericTabularInline):
Scott Baker74d8e622013-07-29 16:04:22 -07001109 model = NetworkParameter
1110 extra = 1
1111 verbose_name_plural = "Parameters"
1112 verbose_name = "Parameter"
Siobhan Tully2d95e482013-09-06 10:56:06 -04001113 suit_classes = 'suit-tab suit-tab-netparams'
Scott Baker74d8e622013-07-29 16:04:22 -07001114
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001115class NetworkSliversROInline(ReadOnlyTabularInline):
1116 fields = ['network', 'sliver', 'ip', 'port_id']
1117 model = NetworkSliver
1118 extra = 0
1119 verbose_name_plural = "Slivers"
1120 verbose_name = "Sliver"
1121 suit_classes = 'suit-tab suit-tab-networkslivers'
1122
Scott Baker0165fac2014-01-13 11:49:26 -08001123class NetworkSliversInline(PlStackTabularInline):
Scott Baker74d8e622013-07-29 16:04:22 -07001124 readonly_fields = ("ip", )
1125 model = NetworkSliver
1126 extra = 0
1127 verbose_name_plural = "Slivers"
1128 verbose_name = "Sliver"
Siobhan Tully2d95e482013-09-06 10:56:06 -04001129 suit_classes = 'suit-tab suit-tab-networkslivers'
Scott Baker74d8e622013-07-29 16:04:22 -07001130
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001131class NetworkSlicesROInline(ReadOnlyTabularInline):
1132 model = NetworkSlice
1133 extra = 0
1134 verbose_name_plural = "Slices"
1135 verbose_name = "Slice"
1136 suit_classes = 'suit-tab suit-tab-networkslices'
1137 fields = ['network','slice']
1138
Scott Baker0165fac2014-01-13 11:49:26 -08001139class NetworkSlicesInline(PlStackTabularInline):
Scott Bakerd7d2a392013-08-06 08:57:30 -07001140 model = NetworkSlice
1141 extra = 0
1142 verbose_name_plural = "Slices"
1143 verbose_name = "Slice"
Siobhan Tully2d95e482013-09-06 10:56:06 -04001144 suit_classes = 'suit-tab suit-tab-networkslices'
Scott Bakerd7d2a392013-08-06 08:57:30 -07001145
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001146class NetworkAdmin(PlanetStackBaseAdmin):
Scott Baker74d8e622013-07-29 16:04:22 -07001147 list_display = ("name", "subnet", "ports", "labels")
1148 readonly_fields = ("subnet", )
Siobhan Tully2d95e482013-09-06 10:56:06 -04001149
Scott Bakerd7d2a392013-08-06 08:57:30 -07001150 inlines = [NetworkParameterInline, NetworkSliversInline, NetworkSlicesInline, RouterInline]
Scott Baker74d8e622013-07-29 16:04:22 -07001151
Siobhan Tully2d95e482013-09-06 10:56:06 -04001152 fieldsets = [
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001153 (None, {'fields': ['name','template','ports','labels','owner','guaranteedBandwidth', 'permitAllSlices','permittedSlices','network_id','router_id','subnet_id','subnet'], 'classes':['suit-tab suit-tab-general']}),]
1154
1155 user_readonly_fields = ['name','template','ports','labels','owner','guaranteedBandwidth', 'permitAllSlices','permittedSlices','network_id','router_id','subnet_id','subnet']
1156 user_readonly_inlines = [NetworkParameterROInline, NetworkSliversROInline, NetworkSlicesROInline, RouterROInline]
Siobhan Tully2d95e482013-09-06 10:56:06 -04001157
1158 suit_form_tabs =(
1159 ('general','Network Details'),
1160 ('netparams', 'Parameters'),
1161 ('networkslivers','Slivers'),
1162 ('networkslices','Slices'),
1163 ('routers','Routers'),
1164 )
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001165class NetworkTemplateAdmin(PlanetStackBaseAdmin):
Scott Baker74d8e622013-07-29 16:04:22 -07001166 list_display = ("name", "guaranteedBandwidth", "visibility")
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001167 user_readonly_fields = ["name", "guaranteedBandwidth", "visibility"]
1168 user_readonly_inlines = []
Scott Baker74d8e622013-07-29 16:04:22 -07001169
Tony Mack31c2b8f2013-04-26 20:01:42 -04001170# register a signal that caches the user's credentials when they log in
1171def cache_credentials(sender, user, request, **kwds):
1172 auth = {'username': request.POST['username'],
1173 'password': request.POST['password']}
1174 request.session['auth'] = auth
1175user_logged_in.connect(cache_credentials)
1176
Scott Baker15cddfa2013-12-09 13:45:19 -08001177def dollar_field(fieldName, short_description):
1178 def newFunc(self, obj):
1179 try:
1180 x= "$ %0.2f" % float(getattr(obj, fieldName, 0.0))
1181 except:
1182 x=getattr(obj, fieldName, 0.0)
1183 return x
1184 newFunc.short_description = short_description
1185 return newFunc
1186
1187def right_dollar_field(fieldName, short_description):
1188 def newFunc(self, obj):
1189 try:
1190 #x= '<div align=right style="width:6em">$ %0.2f</div>' % float(getattr(obj, fieldName, 0.0))
1191 x= '<div align=right>$ %0.2f</div>' % float(getattr(obj, fieldName, 0.0))
1192 except:
1193 x=getattr(obj, fieldName, 0.0)
1194 return x
1195 newFunc.short_description = short_description
1196 newFunc.allow_tags = True
1197 return newFunc
Scott Baker43105042013-12-06 23:23:36 -08001198
Scott Baker0165fac2014-01-13 11:49:26 -08001199class InvoiceChargeInline(PlStackTabularInline):
Scott Baker43105042013-12-06 23:23:36 -08001200 model = Charge
Scott Baker15cddfa2013-12-09 13:45:19 -08001201 extra = 0
Scott Baker43105042013-12-06 23:23:36 -08001202 verbose_name_plural = "Charges"
1203 verbose_name = "Charge"
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001204 exclude = ['account']
Scott Baker9cb88a22013-12-09 18:56:00 -08001205 fields = ["date", "kind", "state", "object", "coreHours", "dollar_amount", "slice"]
1206 readonly_fields = ["date", "kind", "state", "object", "coreHours", "dollar_amount", "slice"]
1207 can_delete = False
1208 max_num = 0
1209
1210 dollar_amount = right_dollar_field("amount", "Amount")
Scott Baker43105042013-12-06 23:23:36 -08001211
1212class InvoiceAdmin(admin.ModelAdmin):
1213 list_display = ("date", "account")
1214
1215 inlines = [InvoiceChargeInline]
1216
Scott Baker9cb88a22013-12-09 18:56:00 -08001217 fields = ["date", "account", "dollar_amount"]
1218 readonly_fields = ["date", "account", "dollar_amount"]
1219
1220 dollar_amount = dollar_field("amount", "Amount")
Scott Baker43105042013-12-06 23:23:36 -08001221
Scott Baker0165fac2014-01-13 11:49:26 -08001222class InvoiceInline(PlStackTabularInline):
Scott Baker15cddfa2013-12-09 13:45:19 -08001223 model = Invoice
1224 extra = 0
1225 verbose_name_plural = "Invoices"
1226 verbose_name = "Invoice"
Scott Baker0165fac2014-01-13 11:49:26 -08001227 fields = ["date", "dollar_amount"]
1228 readonly_fields = ["date", "dollar_amount"]
Scott Baker15cddfa2013-12-09 13:45:19 -08001229 suit_classes = 'suit-tab suit-tab-accountinvoice'
1230 can_delete=False
1231 max_num=0
1232
1233 dollar_amount = right_dollar_field("amount", "Amount")
1234
Scott Baker0165fac2014-01-13 11:49:26 -08001235class PendingChargeInline(PlStackTabularInline):
Scott Baker43105042013-12-06 23:23:36 -08001236 model = Charge
Scott Baker15cddfa2013-12-09 13:45:19 -08001237 extra = 0
Scott Baker43105042013-12-06 23:23:36 -08001238 verbose_name_plural = "Charges"
1239 verbose_name = "Charge"
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001240 exclude = ["invoice"]
Scott Baker15cddfa2013-12-09 13:45:19 -08001241 fields = ["date", "kind", "state", "object", "coreHours", "dollar_amount", "slice"]
1242 readonly_fields = ["date", "kind", "state", "object", "coreHours", "dollar_amount", "slice"]
Scott Baker43105042013-12-06 23:23:36 -08001243 suit_classes = 'suit-tab suit-tab-accountpendingcharges'
Scott Baker15cddfa2013-12-09 13:45:19 -08001244 can_delete=False
1245 max_num=0
Scott Baker43105042013-12-06 23:23:36 -08001246
1247 def queryset(self, request):
1248 qs = super(PendingChargeInline, self).queryset(request)
1249 qs = qs.filter(state="pending")
1250 return qs
1251
Scott Baker15cddfa2013-12-09 13:45:19 -08001252 dollar_amount = right_dollar_field("amount", "Amount")
1253
Scott Baker0165fac2014-01-13 11:49:26 -08001254class PaymentInline(PlStackTabularInline):
Scott Baker43105042013-12-06 23:23:36 -08001255 model=Payment
1256 extra = 1
1257 verbose_name_plural = "Payments"
1258 verbose_name = "Payment"
Scott Baker15cddfa2013-12-09 13:45:19 -08001259 fields = ["date", "dollar_amount"]
1260 readonly_fields = ["date", "dollar_amount"]
Scott Baker43105042013-12-06 23:23:36 -08001261 suit_classes = 'suit-tab suit-tab-accountpayments'
Scott Baker15cddfa2013-12-09 13:45:19 -08001262 can_delete=False
1263 max_num=0
1264
1265 dollar_amount = right_dollar_field("amount", "Amount")
1266
Scott Baker43105042013-12-06 23:23:36 -08001267class AccountAdmin(admin.ModelAdmin):
1268 list_display = ("site", "balance_due")
1269
1270 inlines = [InvoiceInline, PaymentInline, PendingChargeInline]
1271
1272 fieldsets = [
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001273 (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 -08001274
Scott Baker15cddfa2013-12-09 13:45:19 -08001275 readonly_fields = ['site', 'dollar_balance_due', 'dollar_total_invoices', 'dollar_total_payments']
Scott Baker43105042013-12-06 23:23:36 -08001276
1277 suit_form_tabs =(
1278 ('general','Account Details'),
1279 ('accountinvoice', 'Invoices'),
1280 ('accountpayments', 'Payments'),
1281 ('accountpendingcharges','Pending Charges'),
1282 )
1283
Scott Baker15cddfa2013-12-09 13:45:19 -08001284 dollar_balance_due = dollar_field("balance_due", "Balance Due")
1285 dollar_total_invoices = dollar_field("total_invoices", "Total Invoices")
1286 dollar_total_payments = dollar_field("total_payments", "Total Payments")
1287
Siobhan Tullyce652d02013-10-08 21:52:35 -04001288
Siobhan Tully53437282013-04-26 19:30:27 -04001289# Now register the new UserAdmin...
Siobhan Tully30fd4292013-05-10 08:59:56 -04001290admin.site.register(User, UserAdmin)
Siobhan Tully53437282013-04-26 19:30:27 -04001291# ... and, since we're not using Django's builtin permissions,
1292# unregister the Group model from admin.
Siobhan Tullyce652d02013-10-08 21:52:35 -04001293#admin.site.unregister(Group)
Siobhan Tully53437282013-04-26 19:30:27 -04001294
Siobhan Tullybf1153a2013-05-27 20:53:48 -04001295#Do not show django evolution in the admin interface
1296from django_evolution.models import Version, Evolution
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001297#admin.site.unregister(Version)
1298#admin.site.unregister(Evolution)
Siobhan Tullybf1153a2013-05-27 20:53:48 -04001299
1300
1301# When debugging it is often easier to see all the classes, but for regular use
1302# only the top-levels should be displayed
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001303showAll = False
Scott Baker43105042013-12-06 23:23:36 -08001304
Siobhan Tullybf1153a2013-05-27 20:53:48 -04001305admin.site.register(Deployment, DeploymentAdmin)
Siobhan Tully4bc09f22013-04-10 21:15:21 -04001306admin.site.register(Site, SiteAdmin)
Siobhan Tully4bc09f22013-04-10 21:15:21 -04001307admin.site.register(Slice, SliceAdmin)
Siobhan Tullyce652d02013-10-08 21:52:35 -04001308admin.site.register(Service, ServiceAdmin)
smbakera3cf70c2013-06-27 02:01:41 -07001309admin.site.register(Reservation, ReservationAdmin)
Scott Baker74d8e622013-07-29 16:04:22 -07001310admin.site.register(Network, NetworkAdmin)
1311admin.site.register(Router, RouterAdmin)
Scott Baker74d8e622013-07-29 16:04:22 -07001312admin.site.register(NetworkTemplate, NetworkTemplateAdmin)
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001313admin.site.register(Account, AccountAdmin)
1314admin.site.register(Invoice, InvoiceAdmin)
Siobhan Tullybf1153a2013-05-27 20:53:48 -04001315
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001316if True:
1317 admin.site.register(NetworkParameterType, NetworkParameterTypeAdmin)
1318 admin.site.register(ServiceClass, ServiceClassAdmin)
Siobhan Tullybfd11dc2013-09-03 12:59:24 -04001319 #admin.site.register(PlanetStack)
Siobhan Tullyd3515752013-06-21 16:34:53 -04001320 admin.site.register(Tag, TagAdmin)
Siobhan Tullyce652d02013-10-08 21:52:35 -04001321 admin.site.register(DeploymentRole)
1322 admin.site.register(SiteRole)
1323 admin.site.register(SliceRole)
1324 admin.site.register(PlanetStackRole)
Siobhan Tullybf1153a2013-05-27 20:53:48 -04001325 admin.site.register(Node, NodeAdmin)
Siobhan Tullybfd11dc2013-09-03 12:59:24 -04001326 #admin.site.register(SlicePrivilege, SlicePrivilegeAdmin)
1327 #admin.site.register(SitePrivilege, SitePrivilegeAdmin)
Siobhan Tullybf1153a2013-05-27 20:53:48 -04001328 admin.site.register(Sliver, SliverAdmin)
Siobhan Tullybf1153a2013-05-27 20:53:48 -04001329 admin.site.register(Image, ImageAdmin)
Tony Mack7130ac32013-03-22 21:58:00 -04001330