blob: 842cd17f63f7e86d32b4f0a7586018f86c3a39a2 [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
Scott Bakercbfb6002014-10-03 00:32:37 -070011from django.contrib.auth.forms import ReadOnlyPasswordHashField, AdminPasswordChangeForm
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
Scott Baker3cde7372014-10-21 21:03:08 -070018from cgi import escape as html_escape
Tony Mack7130ac32013-03-22 21:58:00 -040019
Scott Baker36f50872014-08-21 13:01:25 -070020import django_evolution
Scott Baker0a5633b2014-10-06 17:51:20 -070021import threading
22
23# thread locals necessary to work around a django-suit issue
24_thread_locals = threading.local()
Scott Baker36f50872014-08-21 13:01:25 -070025
Scott Baker40c00762014-08-21 16:55:59 -070026def backend_icon(obj): # backend_status, enacted, updated):
27 #return "%s %s %s" % (str(obj.updated), str(obj.enacted), str(obj.backend_status))
28 if (obj.enacted is not None) and obj.enacted >= obj.updated:
Scott Bakerfbf06642014-09-09 10:38:15 -070029 return '<span style="min-width:16px;"><img src="/static/admin/img/icon_success.gif"></span>'
Scott Baker40c00762014-08-21 16:55:59 -070030 else:
31 if obj.backend_status == "Provisioning in progress" or obj.backend_status=="":
Scott Bakerfbf06642014-09-09 10:38:15 -070032 return '<span style="min-width:16px;" title="%s"><img src="/static/admin/img/icon_clock.gif"></span>' % obj.backend_status
Scott Baker63d1a552014-08-21 15:19:07 -070033 else:
Scott Baker3cde7372014-10-21 21:03:08 -070034 return '<span style="min-width:16px;" title="%s"><img src="/static/admin/img/icon_error.gif"></span>' % html_escape(obj.backend_status, quote=True)
Scott Baker40c00762014-08-21 16:55:59 -070035
36def backend_text(obj):
37 icon = backend_icon(obj)
38 if (obj.enacted is not None) and obj.enacted >= obj.updated:
Scott Baker3cde7372014-10-21 21:03:08 -070039 return "%s %s" % (icon, "successfully enacted")
Scott Baker40c00762014-08-21 16:55:59 -070040 else:
Scott Baker3cde7372014-10-21 21:03:08 -070041 return "%s %s" % (icon, html_escape(obj.backend_status, quote=True))
Scott Baker63d1a552014-08-21 15:19:07 -070042
Scott Baker36f50872014-08-21 13:01:25 -070043class PlainTextWidget(forms.HiddenInput):
44 input_type = 'hidden'
45
46 def render(self, name, value, attrs=None):
47 if value is None:
48 value = ''
49 return mark_safe(str(value) + super(PlainTextWidget, self).render(name, value, attrs))
50
Scott Baker86c83ab2014-10-03 13:10:47 -070051class PermissionCheckingAdminMixin(object):
Scott Bakercbfb6002014-10-03 00:32:37 -070052 # call save_by_user and delete_by_user instead of save and delete
Siobhan Tullycf04fb62014-01-11 11:25:57 -050053
54 def has_add_permission(self, request, obj=None):
55 return (not self.__user_is_readonly(request))
Scott Baker36f50872014-08-21 13:01:25 -070056
Siobhan Tullycf04fb62014-01-11 11:25:57 -050057 def has_delete_permission(self, request, obj=None):
58 return (not self.__user_is_readonly(request))
59
60 def save_model(self, request, obj, form, change):
61 if self.__user_is_readonly(request):
Scott Bakercbfb6002014-10-03 00:32:37 -070062 # this 'if' might be redundant if save_by_user is implemented right
Siobhan Tullycf04fb62014-01-11 11:25:57 -050063 raise PermissionDenied
Scott Bakercbfb6002014-10-03 00:32:37 -070064
65 obj.caller = request.user
66 # update openstack connection to use this site/tenant
67 obj.save_by_user(request.user)
68
69 def delete_model(self, request, obj):
70 obj.delete_by_user(request.user)
71
72 def save_formset(self, request, form, formset, change):
73 instances = formset.save(commit=False)
74 for instance in instances:
75 instance.save_by_user(request.user)
76
77 # BUG in django 1.7? Objects are not deleted by formset.save if
78 # commit is False. So let's delete them ourselves.
79 #
80 # code from forms/models.py save_existing_objects()
81 try:
82 forms_to_delete = formset.deleted_forms
83 except AttributeError:
84 forms_to_delete = []
85 if formset.initial_forms:
86 for form in formset.initial_forms:
87 obj = form.instance
88 if form in forms_to_delete:
89 if obj.pk is None:
90 continue
91 formset.deleted_objects.append(obj)
92 obj.delete()
93
94 formset.save_m2m()
Siobhan Tullycf04fb62014-01-11 11:25:57 -050095
96 def get_actions(self,request):
Scott Baker86c83ab2014-10-03 13:10:47 -070097 actions = super(PermissionCheckingAdminMixin,self).get_actions(request)
Siobhan Tullycf04fb62014-01-11 11:25:57 -050098
99 if self.__user_is_readonly(request):
100 if 'delete_selected' in actions:
101 del actions['delete_selected']
102
103 return actions
104
105 def change_view(self,request,object_id, extra_context=None):
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500106 if self.__user_is_readonly(request):
Scott Bakeraf73e102014-04-22 22:40:07 -0700107 if not hasattr(self, "readonly_save"):
108 # save the original readonly fields
109 self.readonly_save = self.readonly_fields
110 self.inlines_save = self.inlines
Scott Bakere8859f92014-05-23 12:42:40 -0700111 if hasattr(self, "user_readonly_fields"):
112 self.readonly_fields=self.user_readonly_fields
113 if hasattr(self, "user_readonly_inlines"):
114 self.inlines = self.user_readonly_inlines
Scott Bakeraf73e102014-04-22 22:40:07 -0700115 else:
116 if hasattr(self, "readonly_save"):
117 # restore the original readonly fields
118 self.readonly_fields = self.readonly_save
Scott Bakere8859f92014-05-23 12:42:40 -0700119 if hasattr(self, "inlines_save"):
Scott Bakeraf73e102014-04-22 22:40:07 -0700120 self.inlines = self.inlines_save
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500121
122 try:
Scott Baker86c83ab2014-10-03 13:10:47 -0700123 return super(PermissionCheckingAdminMixin, self).change_view(request, object_id, extra_context=extra_context)
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500124 except PermissionDenied:
125 pass
126 if request.method == 'POST':
127 raise PermissionDenied
128 request.readonly = True
Scott Baker86c83ab2014-10-03 13:10:47 -0700129 return super(PermissionCheckingAdminMixin, self).change_view(request, object_id, extra_context=extra_context)
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500130
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500131 def __user_is_readonly(self, request):
132 return request.user.isReadOnlyUser()
133
Scott Baker40c00762014-08-21 16:55:59 -0700134 def backend_status_text(self, obj):
135 return mark_safe(backend_text(obj))
Scott Baker36f50872014-08-21 13:01:25 -0700136
Scott Baker63d1a552014-08-21 15:19:07 -0700137 def backend_status_icon(self, obj):
Scott Baker40c00762014-08-21 16:55:59 -0700138 return mark_safe(backend_icon(obj))
Scott Baker63d1a552014-08-21 15:19:07 -0700139 backend_status_icon.short_description = ""
140
Scott Baker5c432692014-10-16 00:57:55 -0700141 def get_form(self, request, obj=None):
142 # Save obj and request in thread-local storage, so suit_form_tabs can
143 # use it to determine whether we're in edit or add mode, and can
144 # determine whether the user is an admin.
145 _thread_locals.request = request
146 _thread_locals.obj = obj
147 return super(PermissionCheckingAdminMixin, self).get_form(request, obj)
148
149 def get_inline_instances(self, request, obj=None):
150 inlines = super(PermissionCheckingAdminMixin, self).get_inline_instances(request, obj)
151
152 # inlines that should only be shown to an admin user
153 if request.user.is_admin:
154 for inline_class in getattr(self, "admin_inlines", []):
155 inlines.append(inline_class(self.model, self.admin_site))
156
157 return inlines
158
Scott Baker86c83ab2014-10-03 13:10:47 -0700159class ReadOnlyAwareAdmin(PermissionCheckingAdminMixin, admin.ModelAdmin):
160 # Note: Make sure PermissionCheckingAdminMixin is listed before
161 # admin.ModelAdmin in the class declaration.
162
Scott Bakercbfb6002014-10-03 00:32:37 -0700163 pass
164
165class PlanetStackBaseAdmin(ReadOnlyAwareAdmin):
166 save_on_top = False
Scott Baker36f50872014-08-21 13:01:25 -0700167
Scott Bakere8859f92014-05-23 12:42:40 -0700168class SingletonAdmin (ReadOnlyAwareAdmin):
Siobhan Tullyce652d02013-10-08 21:52:35 -0400169 def has_add_permission(self, request):
Scott Bakere8859f92014-05-23 12:42:40 -0700170 if not super(SingletonAdmin, self).has_add_permission(request):
171 return False
172
Siobhan Tullyce652d02013-10-08 21:52:35 -0400173 num_objects = self.model.objects.count()
174 if num_objects >= 1:
175 return False
176 else:
177 return True
178
Siobhan Tullyd3515752013-06-21 16:34:53 -0400179class PlStackTabularInline(admin.TabularInline):
Scott Baker86568322014-01-12 16:53:31 -0800180 def __init__(self, *args, **kwargs):
181 super(PlStackTabularInline, self).__init__(*args, **kwargs)
182
183 # InlineModelAdmin as no get_fields() method, so in order to add
184 # the selflink field, we override __init__ to modify self.fields and
185 # self.readonly_fields.
186
Scott Bakere2bbf7e2014-01-13 12:09:31 -0800187 self.setup_selflink()
188
Scott Baker874936e2014-01-13 18:15:34 -0800189 def get_change_url(self, model, id):
190 """ Get the URL to a change form in the admin for this model """
191 reverse_path = "admin:%s_change" % (model._meta.db_table)
Scott Bakere2bbf7e2014-01-13 12:09:31 -0800192 try:
Scott Baker874936e2014-01-13 18:15:34 -0800193 url = reverse(reverse_path, args=(id,))
Scott Bakere2bbf7e2014-01-13 12:09:31 -0800194 except NoReverseMatch:
Scott Baker874936e2014-01-13 18:15:34 -0800195 return None
196
197 return url
198
199 def setup_selflink(self):
200 if hasattr(self, "selflink_fieldname"):
201 """ self.selflink_model can be defined to punch through a relation
202 to its target object. For example, in SliceNetworkInline, set
203 selflink_model = "network", and the URL will lead to the Network
204 object instead of trying to bring up a change view of the
205 SliceNetwork object.
206 """
207 self.selflink_model = getattr(self.model,self.selflink_fieldname).field.rel.to
208 else:
209 self.selflink_model = self.model
210
211 url = self.get_change_url(self.selflink_model, 0)
212
213 # We don't have an admin for this object, so don't create the
214 # selflink.
215 if (url == None):
Scott Bakere2bbf7e2014-01-13 12:09:31 -0800216 return
217
Scott Baker874936e2014-01-13 18:15:34 -0800218 # Since we need to add "selflink" to the field list, we need to create
219 # self.fields if it is None.
Scott Baker0165fac2014-01-13 11:49:26 -0800220 if (self.fields is None):
221 self.fields = []
222 for f in self.model._meta.fields:
223 if f.editable and f.name != "id":
224 self.fields.append(f.name)
Scott Baker86568322014-01-12 16:53:31 -0800225
Scott Baker874936e2014-01-13 18:15:34 -0800226 self.fields = tuple(self.fields) + ("selflink", )
Scott Baker86568322014-01-12 16:53:31 -0800227
Scott Baker874936e2014-01-13 18:15:34 -0800228 if self.readonly_fields is None:
229 self.readonly_fields = ()
Scott Baker86568322014-01-12 16:53:31 -0800230
Scott Baker874936e2014-01-13 18:15:34 -0800231 self.readonly_fields = tuple(self.readonly_fields) + ("selflink", )
Scott Baker86568322014-01-12 16:53:31 -0800232
233 def selflink(self, obj):
Scott Baker874936e2014-01-13 18:15:34 -0800234 if hasattr(self, "selflink_fieldname"):
235 obj = getattr(obj, self.selflink_fieldname)
236
Scott Baker86568322014-01-12 16:53:31 -0800237 if obj.id:
Scott Baker874936e2014-01-13 18:15:34 -0800238 url = self.get_change_url(self.selflink_model, obj.id)
239 return "<a href='%s'>Details</a>" % str(url)
Scott Baker86568322014-01-12 16:53:31 -0800240 else:
Scott Bakere2bbf7e2014-01-13 12:09:31 -0800241 return "Not present"
Scott Baker86568322014-01-12 16:53:31 -0800242
243 selflink.allow_tags = True
244 selflink.short_description = "Details"
Siobhan Tullyd3515752013-06-21 16:34:53 -0400245
Scott Bakerb27b62c2014-08-15 16:29:16 -0700246 def has_add_permission(self, request):
247 return not request.user.isReadOnlyUser()
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500248
249 def get_readonly_fields(self, request, obj=None):
Scott Bakerb27b62c2014-08-15 16:29:16 -0700250 readonly_fields = list(self.readonly_fields)[:]
251 if request.user.isReadOnlyUser():
252 for field in self.fields:
253 if not field in readonly_fields:
254 readonly_fields.append(field)
255 return readonly_fields
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500256
Scott Baker40c00762014-08-21 16:55:59 -0700257 def backend_status_icon(self, obj):
258 return mark_safe(backend_icon(obj))
259 backend_status_icon.short_description = ""
Scott Baker36f50872014-08-21 13:01:25 -0700260
Scott Bakerb27b62c2014-08-15 16:29:16 -0700261class PlStackGenericTabularInline(generic.GenericTabularInline):
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500262 def has_add_permission(self, request):
Scott Bakerb27b62c2014-08-15 16:29:16 -0700263 return not request.user.isReadOnlyUser()
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500264
Scott Bakerb27b62c2014-08-15 16:29:16 -0700265 def get_readonly_fields(self, request, obj=None):
266 readonly_fields = list(self.readonly_fields)[:]
267 if request.user.isReadOnlyUser():
268 for field in self.fields:
269 if not field in readonly_fields:
270 readonly_fields.append(field)
271 return readonly_fields
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500272
Scott Baker40c00762014-08-21 16:55:59 -0700273 def backend_status_icon(self, obj):
274 return mark_safe(backend_icon(obj))
275 backend_status_icon.short_description = ""
276
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400277class ReservationInline(PlStackTabularInline):
278 model = Reservation
279 extra = 0
280 suit_classes = 'suit-tab suit-tab-reservations'
Scott Baker36f50872014-08-21 13:01:25 -0700281
Tony Mack5b061472014-02-04 07:57:10 -0500282 def queryset(self, request):
283 return Reservation.select_by_user(request.user)
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400284
Scott Bakerb27b62c2014-08-15 16:29:16 -0700285class TagInline(PlStackGenericTabularInline):
Siobhan Tullyde5450d2013-06-21 11:35:33 -0400286 model = Tag
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400287 extra = 0
288 suit_classes = 'suit-tab suit-tab-tags'
Tony Mack5b061472014-02-04 07:57:10 -0500289 fields = ['service', 'name', 'value']
290
291 def queryset(self, request):
292 return Tag.select_by_user(request.user)
Siobhan Tullyde5450d2013-06-21 11:35:33 -0400293
Scott Baker74d8e622013-07-29 16:04:22 -0700294class NetworkLookerUpper:
Siobhan Tully2c780ad2013-09-06 11:22:40 -0400295 """ This is a callable that looks up a network name in a sliver and returns
296 the ip address for that network.
297 """
298
Scott Baker434ca7e2014-08-15 12:29:20 -0700299 byNetworkName = {} # class variable
300
Siobhan Tully2c780ad2013-09-06 11:22:40 -0400301 def __init__(self, name):
302 self.short_description = name
303 self.__name__ = name
304 self.network_name = name
305
306 def __call__(self, obj):
307 if obj is not None:
308 for nbs in obj.networksliver_set.all():
309 if (nbs.network.name == self.network_name):
310 return nbs.ip
Scott Baker74d8e622013-07-29 16:04:22 -0700311 return ""
312
313 def __str__(self):
314 return self.network_name
315
Scott Baker434ca7e2014-08-15 12:29:20 -0700316 @staticmethod
317 def get(network_name):
318 """ We want to make sure we alwars return the same NetworkLookerUpper
319 because sometimes django will cause them to be instantiated multiple
320 times (and we don't want different ones in form.fields vs
321 SliverInline.readonly_fields).
322 """
323 if network_name not in NetworkLookerUpper.byNetworkName:
324 NetworkLookerUpper.byNetworkName[network_name] = NetworkLookerUpper(network_name)
325 return NetworkLookerUpper.byNetworkName[network_name]
326
Siobhan Tullyd3515752013-06-21 16:34:53 -0400327class SliverInline(PlStackTabularInline):
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400328 model = Sliver
Scott Baker7a61dc42014-09-02 17:08:20 -0700329 fields = ['backend_status_icon', 'all_ips_string', 'instance_name', 'slice', 'deploymentNetwork', 'flavor', 'image', 'node']
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400330 extra = 0
Scott Baker40c00762014-08-21 16:55:59 -0700331 readonly_fields = ['backend_status_icon', 'all_ips_string', 'instance_name']
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400332 suit_classes = 'suit-tab suit-tab-slivers'
Scott Baker74d8e622013-07-29 16:04:22 -0700333
Tony Mack5b061472014-02-04 07:57:10 -0500334 def queryset(self, request):
335 return Sliver.select_by_user(request.user)
336
Scott Bakerb24cc932014-06-09 10:51:16 -0700337 def formfield_for_foreignkey(self, db_field, request=None, **kwargs):
Scott Bakerb24cc932014-06-09 10:51:16 -0700338 if db_field.name == 'deploymentNetwork':
Scott Baker3b678742014-06-09 13:11:54 -0700339 kwargs['queryset'] = Deployment.select_by_acl(request.user)
Scott Baker7a61dc42014-09-02 17:08:20 -0700340 kwargs['widget'] = forms.Select(attrs={'onChange': "sliver_deployment_changed(this);"})
Scott Baker32481312014-09-08 12:14:14 -0700341 elif db_field.name == 'flavor':
342 kwargs['widget'] = forms.Select(attrs={'onChange': "sliver_flavor_changed(this);"})
Scott Baker3b678742014-06-09 13:11:54 -0700343
344 field = super(SliverInline, self).formfield_for_foreignkey(db_field, request, **kwargs)
Scott Bakerb24cc932014-06-09 10:51:16 -0700345
346 return field
347
Siobhan Tullyd3515752013-06-21 16:34:53 -0400348class SiteInline(PlStackTabularInline):
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400349 model = Site
350 extra = 0
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400351 suit_classes = 'suit-tab suit-tab-sites'
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400352
Tony Mack5b061472014-02-04 07:57:10 -0500353 def queryset(self, request):
354 return Site.select_by_user(request.user)
355
Siobhan Tullyd3515752013-06-21 16:34:53 -0400356class UserInline(PlStackTabularInline):
Siobhan Tully30fd4292013-05-10 08:59:56 -0400357 model = User
Scott Baker40c00762014-08-21 16:55:59 -0700358 fields = ['backend_status_icon', 'email', 'firstname', 'lastname']
359 readonly_fields = ('backend_status_icon', )
Siobhan Tully30fd4292013-05-10 08:59:56 -0400360 extra = 0
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400361 suit_classes = 'suit-tab suit-tab-users'
Siobhan Tully30fd4292013-05-10 08:59:56 -0400362
Tony Mack5b061472014-02-04 07:57:10 -0500363 def queryset(self, request):
364 return User.select_by_user(request.user)
365
Siobhan Tullyd3515752013-06-21 16:34:53 -0400366class SliceInline(PlStackTabularInline):
Tony Mack00d361f2013-04-28 10:28:42 -0400367 model = Slice
Scott Baker40c00762014-08-21 16:55:59 -0700368 fields = ['backend_status_icon', 'name', 'site', 'serviceClass', 'service']
369 readonly_fields = ('backend_status_icon', )
Tony Mack00d361f2013-04-28 10:28:42 -0400370 extra = 0
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400371 suit_classes = 'suit-tab suit-tab-slices'
372
Tony Mack5b061472014-02-04 07:57:10 -0500373 def queryset(self, request):
374 return Slice.select_by_user(request.user)
375
Siobhan Tullyd3515752013-06-21 16:34:53 -0400376class NodeInline(PlStackTabularInline):
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400377 model = Node
378 extra = 0
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400379 suit_classes = 'suit-tab suit-tab-nodes'
Scott Baker40c00762014-08-21 16:55:59 -0700380 fields = ['backend_status_icon', 'name','deployment','site']
381 readonly_fields = ('backend_status_icon', )
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400382
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400383class DeploymentPrivilegeInline(PlStackTabularInline):
384 model = DeploymentPrivilege
385 extra = 0
386 suit_classes = 'suit-tab suit-tab-deploymentprivileges'
Scott Baker40c00762014-08-21 16:55:59 -0700387 fields = ['backend_status_icon', 'user','role','deployment']
388 readonly_fields = ('backend_status_icon', )
Tony Mack5b061472014-02-04 07:57:10 -0500389
390 def queryset(self, request):
391 return DeploymentPrivilege.select_by_user(request.user)
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400392
Siobhan Tullyd3515752013-06-21 16:34:53 -0400393class SitePrivilegeInline(PlStackTabularInline):
Siobhan Tullyaa1bcd52013-05-10 12:43:09 -0400394 model = SitePrivilege
395 extra = 0
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400396 suit_classes = 'suit-tab suit-tab-siteprivileges'
Scott Baker40c00762014-08-21 16:55:59 -0700397 fields = ['backend_status_icon', 'user','site', 'role']
398 readonly_fields = ('backend_status_icon', )
Siobhan Tullyaa1bcd52013-05-10 12:43:09 -0400399
Tony Mackc2835a92013-05-28 09:18:49 -0400400 def formfield_for_foreignkey(self, db_field, request, **kwargs):
401 if db_field.name == 'site':
Tony Mack5b061472014-02-04 07:57:10 -0500402 kwargs['queryset'] = Site.select_by_user(request.user)
Tony Mackc2835a92013-05-28 09:18:49 -0400403
404 if db_field.name == 'user':
Tony Mack5b061472014-02-04 07:57:10 -0500405 kwargs['queryset'] = User.select_by_user(request.user)
Tony Mackc2835a92013-05-28 09:18:49 -0400406 return super(SitePrivilegeInline, self).formfield_for_foreignkey(db_field, request, **kwargs)
407
Tony Mack5b061472014-02-04 07:57:10 -0500408 def queryset(self, request):
409 return SitePrivilege.select_by_user(request.user)
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400410
Tony Macke4be32f2014-03-11 20:45:25 -0400411class SiteDeploymentInline(PlStackTabularInline):
412 model = SiteDeployments
Tony Macke4be32f2014-03-11 20:45:25 -0400413 extra = 0
414 suit_classes = 'suit-tab suit-tab-deployments'
Scott Baker40c00762014-08-21 16:55:59 -0700415 fields = ['backend_status_icon', 'deployment','site']
416 readonly_fields = ('backend_status_icon', )
Tony Macke4be32f2014-03-11 20:45:25 -0400417
418 def formfield_for_foreignkey(self, db_field, request, **kwargs):
419 if db_field.name == 'site':
420 kwargs['queryset'] = Site.select_by_user(request.user)
421
422 if db_field.name == 'deployment':
423 kwargs['queryset'] = Deployment.select_by_user(request.user)
424 return super(SiteDeploymentInline, self).formfield_for_foreignkey(db_field, request, **kwargs)
425
426 def queryset(self, request):
427 return SiteDeployments.select_by_user(request.user)
428
429
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400430class SlicePrivilegeInline(PlStackTabularInline):
431 model = SlicePrivilege
432 suit_classes = 'suit-tab suit-tab-sliceprivileges'
433 extra = 0
Scott Baker40c00762014-08-21 16:55:59 -0700434 fields = ('backend_status_icon', 'user', 'slice', 'role')
435 readonly_fields = ('backend_status_icon', )
Siobhan Tullyaa1bcd52013-05-10 12:43:09 -0400436
Tony Mackc2835a92013-05-28 09:18:49 -0400437 def formfield_for_foreignkey(self, db_field, request, **kwargs):
438 if db_field.name == 'slice':
Scott Baker36f50872014-08-21 13:01:25 -0700439 kwargs['queryset'] = Slice.select_by_user(request.user)
Tony Mackc2835a92013-05-28 09:18:49 -0400440 if db_field.name == 'user':
Scott Baker36f50872014-08-21 13:01:25 -0700441 kwargs['queryset'] = User.select_by_user(request.user)
Tony Mackc2835a92013-05-28 09:18:49 -0400442
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400443 return super(SlicePrivilegeInline, self).formfield_for_foreignkey(db_field, request, **kwargs)
Tony Mackc2835a92013-05-28 09:18:49 -0400444
Tony Mack5b061472014-02-04 07:57:10 -0500445 def queryset(self, request):
446 return SlicePrivilege.select_by_user(request.user)
447
Scott Bakera0015eb2013-08-14 17:28:14 -0700448class SliceNetworkInline(PlStackTabularInline):
Scott Baker74d8e622013-07-29 16:04:22 -0700449 model = Network.slices.through
Scott Baker874936e2014-01-13 18:15:34 -0800450 selflink_fieldname = "network"
Scott Baker74d8e622013-07-29 16:04:22 -0700451 extra = 0
452 verbose_name = "Network Connection"
453 verbose_name_plural = "Network Connections"
Siobhan Tully2d95e482013-09-06 10:56:06 -0400454 suit_classes = 'suit-tab suit-tab-slicenetworks'
Scott Baker40c00762014-08-21 16:55:59 -0700455 fields = ['backend_status_icon', 'network']
456 readonly_fields = ('backend_status_icon', )
Scott Baker2170b972014-06-03 12:14:07 -0700457
458class ImageDeploymentsInline(PlStackTabularInline):
459 model = ImageDeployments
460 extra = 0
461 verbose_name = "Image Deployments"
462 verbose_name_plural = "Image Deployments"
463 suit_classes = 'suit-tab suit-tab-imagedeployments'
Scott Baker40c00762014-08-21 16:55:59 -0700464 fields = ['backend_status_icon', 'image', 'deployment', 'glance_image_id']
465 readonly_fields = ['backend_status_icon', 'glance_image_id']
Scott Baker74d8e622013-07-29 16:04:22 -0700466
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400467class SliceRoleAdmin(PlanetStackBaseAdmin):
468 model = SliceRole
469 pass
470
471class SiteRoleAdmin(PlanetStackBaseAdmin):
472 model = SiteRole
473 pass
474
Siobhan Tullybf1153a2013-05-27 20:53:48 -0400475class DeploymentAdminForm(forms.ModelForm):
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400476 sites = forms.ModelMultipleChoiceField(
477 queryset=Site.objects.all(),
478 required=False,
Scott Baker70983182014-06-09 22:10:00 -0700479 help_text="Select which sites are allowed to host nodes in this deployment",
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400480 widget=FilteredSelectMultiple(
481 verbose_name=('Sites'), is_stacked=False
482 )
483 )
Scott Bakerde0f4412014-06-11 15:40:26 -0700484 images = forms.ModelMultipleChoiceField(
485 queryset=Image.objects.all(),
486 required=False,
487 help_text="Select which images should be deployed on this deployment",
488 widget=FilteredSelectMultiple(
489 verbose_name=('Images'), is_stacked=False
490 )
491 )
Scott Baker37b47902014-09-02 14:37:41 -0700492 flavors = forms.ModelMultipleChoiceField(
493 queryset=Flavor.objects.all(),
494 required=False,
495 help_text="Select which flavors should be usable on this deployment",
496 widget=FilteredSelectMultiple(
497 verbose_name=('Flavors'), is_stacked=False
498 )
499 )
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400500 class Meta:
Siobhan Tullybf1153a2013-05-27 20:53:48 -0400501 model = Deployment
Scott Baker37b47902014-09-02 14:37:41 -0700502 many_to_many = ["flavors",]
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400503
Siobhan Tully320b4622014-01-17 15:11:14 -0500504 def __init__(self, *args, **kwargs):
Scott Baker5380c522014-06-06 14:49:43 -0700505 request = kwargs.pop('request', None)
Siobhan Tully320b4622014-01-17 15:11:14 -0500506 super(DeploymentAdminForm, self).__init__(*args, **kwargs)
507
Scott Baker5380c522014-06-06 14:49:43 -0700508 self.fields['accessControl'].initial = "allow site " + request.user.site.name
509
Siobhan Tully320b4622014-01-17 15:11:14 -0500510 if self.instance and self.instance.pk:
Scott Bakerc9b14f72014-05-22 13:44:20 -0700511 self.fields['sites'].initial = [x.site for x in self.instance.sitedeployments_set.all()]
Scott Bakerde0f4412014-06-11 15:40:26 -0700512 self.fields['images'].initial = [x.image for x in self.instance.imagedeployments_set.all()]
Scott Baker37b47902014-09-02 14:37:41 -0700513 self.fields['flavors'].initial = self.instance.flavors.all()
Scott Bakerde0f4412014-06-11 15:40:26 -0700514
515 def manipulate_m2m_objs(self, this_obj, selected_objs, all_relations, relation_class, local_attrname, foreign_attrname):
516 """ helper function for handling m2m relations from the MultipleChoiceField
517
518 this_obj: the source object we want to link from
519
520 selected_objs: a list of destination objects we want to link to
521
522 all_relations: the full set of relations involving this_obj, including ones we don't want
523
524 relation_class: the class that implements the relation from source to dest
525
526 local_attrname: field name representing this_obj in relation_class
527
528 foreign_attrname: field name representing selected_objs in relation_class
529
530 This function will remove all newobjclass relations from this_obj
531 that are not contained in selected_objs, and add any relations that
532 are in selected_objs but don't exist in the data model yet.
533 """
534
535 existing_dest_objs = []
536 for relation in list(all_relations):
537 if getattr(relation, foreign_attrname) not in selected_objs:
538 #print "deleting site", sdp.site
539 relation.delete()
540 else:
541 existing_dest_objs.append(getattr(relation, foreign_attrname))
542
543 for dest_obj in selected_objs:
544 if dest_obj not in existing_dest_objs:
545 #print "adding site", site
546 kwargs = {foreign_attrname: dest_obj, local_attrname: this_obj}
547 relation = relation_class(**kwargs)
548 relation.save()
Siobhan Tully320b4622014-01-17 15:11:14 -0500549
550 def save(self, commit=True):
551 deployment = super(DeploymentAdminForm, self).save(commit=False)
552
553 if commit:
554 deployment.save()
Scott Baker61b6aec2014-10-06 17:17:40 -0700555 # this has to be done after save() if/when a deployment is first created
556 deployment.flavors = self.cleaned_data['flavors']
Siobhan Tully320b4622014-01-17 15:11:14 -0500557
558 if deployment.pk:
Scott Bakerc9b14f72014-05-22 13:44:20 -0700559 # save_m2m() doesn't seem to work with 'through' relations. So we
560 # create/destroy the through models ourselves. There has to be
561 # a better way...
562
Scott Bakerde0f4412014-06-11 15:40:26 -0700563 self.manipulate_m2m_objs(deployment, self.cleaned_data['sites'], deployment.sitedeployments_set.all(), SiteDeployments, "deployment", "site")
564 self.manipulate_m2m_objs(deployment, self.cleaned_data['images'], deployment.imagedeployments_set.all(), ImageDeployments, "deployment", "image")
Scott Bakerc9b14f72014-05-22 13:44:20 -0700565
Scott Baker37b47902014-09-02 14:37:41 -0700566 self.save_m2m()
Siobhan Tully320b4622014-01-17 15:11:14 -0500567
568 return deployment
569
Scott Bakerff5e0f32014-05-22 14:40:27 -0700570class DeploymentAdminROForm(DeploymentAdminForm):
571 def save(self, commit=True):
572 raise PermissionDenied
573
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500574class SiteAssocInline(PlStackTabularInline):
575 model = Site.deployments.through
576 extra = 0
577 suit_classes = 'suit-tab suit-tab-sites'
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400578
Siobhan Tullybf1153a2013-05-27 20:53:48 -0400579class DeploymentAdmin(PlanetStackBaseAdmin):
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500580 model = Deployment
Tony Mack2cbd3802014-09-29 16:10:52 -0400581 fieldList = ['backend_status_text', 'name', 'availability_zone', 'sites', 'images', 'flavors', 'accessControl']
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500582 fieldsets = [(None, {'fields': fieldList, 'classes':['suit-tab suit-tab-sites']})]
Scott Bakerde0f4412014-06-11 15:40:26 -0700583 inlines = [DeploymentPrivilegeInline,NodeInline,TagInline] # ,ImageDeploymentsInline]
Scott Baker63d1a552014-08-21 15:19:07 -0700584 list_display = ['backend_status_icon', 'name']
585 list_display_links = ('backend_status_icon', 'name', )
Scott Baker40c00762014-08-21 16:55:59 -0700586 readonly_fields = ('backend_status_text', )
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500587
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500588 user_readonly_fields = ['name']
589
Scott Bakerde0f4412014-06-11 15:40:26 -0700590 suit_form_tabs =(('sites','Deployment Details'),('nodes','Nodes'),('deploymentprivileges','Privileges'),('tags','Tags')) # ,('imagedeployments','Images'))
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500591
Scott Bakerff5e0f32014-05-22 14:40:27 -0700592 def get_form(self, request, obj=None, **kwargs):
593 if request.user.isReadOnlyUser():
594 kwargs["form"] = DeploymentAdminROForm
595 else:
596 kwargs["form"] = DeploymentAdminForm
Scott Baker5380c522014-06-06 14:49:43 -0700597 adminForm = super(DeploymentAdmin,self).get_form(request, obj, **kwargs)
598
599 # from stackexchange: pass the request object into the form
600
601 class AdminFormMetaClass(adminForm):
602 def __new__(cls, *args, **kwargs):
603 kwargs['request'] = request
604 return adminForm(*args, **kwargs)
605
606 return AdminFormMetaClass
607
Siobhan Tullyce652d02013-10-08 21:52:35 -0400608class ServiceAttrAsTabInline(PlStackTabularInline):
609 model = ServiceAttribute
610 fields = ['name','value']
611 extra = 0
612 suit_classes = 'suit-tab suit-tab-serviceattrs'
613
Siobhan Tullyce652d02013-10-08 21:52:35 -0400614class ServiceAdmin(PlanetStackBaseAdmin):
Scott Baker63d1a552014-08-21 15:19:07 -0700615 list_display = ("backend_status_icon","name","description","versionNumber","enabled","published")
616 list_display_links = ('backend_status_icon', 'name', )
Scott Baker40c00762014-08-21 16:55:59 -0700617 fieldList = ["backend_status_text","name","description","versionNumber","enabled","published"]
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500618 fieldsets = [(None, {'fields': fieldList, 'classes':['suit-tab suit-tab-general']})]
619 inlines = [ServiceAttrAsTabInline,SliceInline]
Scott Baker40c00762014-08-21 16:55:59 -0700620 readonly_fields = ('backend_status_text', )
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500621
622 user_readonly_fields = fieldList
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500623
624 suit_form_tabs =(('general', 'Service Details'),
625 ('slices','Slices'),
626 ('serviceattrs','Additional Attributes'),
627 )
Siobhan Tullyce652d02013-10-08 21:52:35 -0400628
Tony Mack0553f282013-06-10 22:54:50 -0400629class SiteAdmin(PlanetStackBaseAdmin):
Scott Baker40c00762014-08-21 16:55:59 -0700630 fieldList = ['backend_status_text', 'name', 'site_url', 'enabled', 'is_public', 'login_base', 'accountLink','location']
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400631 fieldsets = [
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500632 (None, {'fields': fieldList, 'classes':['suit-tab suit-tab-general']}),
Tony Macke4be32f2014-03-11 20:45:25 -0400633 #('Deployment Networks', {'fields': ['deployments'], 'classes':['suit-tab suit-tab-deployments']}),
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400634 ]
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400635 suit_form_tabs =(('general', 'Site Details'),
636 ('users','Users'),
Siobhan Tully2d95e482013-09-06 10:56:06 -0400637 ('siteprivileges','Privileges'),
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400638 ('deployments','Deployments'),
639 ('slices','Slices'),
Scott Baker36f50872014-08-21 13:01:25 -0700640 ('nodes','Nodes'),
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400641 ('tags','Tags'),
642 )
Scott Baker40c00762014-08-21 16:55:59 -0700643 readonly_fields = ['backend_status_text', 'accountLink']
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500644
645 user_readonly_fields = ['name', 'deployments','site_url', 'enabled', 'is_public', 'login_base', 'accountLink']
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500646
Scott Baker63d1a552014-08-21 15:19:07 -0700647 list_display = ('backend_status_icon', 'name', 'login_base','site_url', 'enabled')
648 list_display_links = ('backend_status_icon', 'name', )
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400649 filter_horizontal = ('deployments',)
Tony Macke4be32f2014-03-11 20:45:25 -0400650 inlines = [SliceInline,UserInline,TagInline, NodeInline, SitePrivilegeInline, SiteDeploymentInline]
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400651 search_fields = ['name']
652
Tony Mack04062832013-05-10 08:22:44 -0400653 def queryset(self, request):
Tony Mack5b061472014-02-04 07:57:10 -0500654 return Site.select_by_user(request.user)
Tony Mack04062832013-05-10 08:22:44 -0400655
Tony Mack5cd13202013-05-01 21:48:38 -0400656 def get_formsets(self, request, obj=None):
657 for inline in self.get_inline_instances(request, obj):
658 # hide MyInline in the add view
659 if obj is None:
660 continue
Tony Mack2bd5b412013-06-11 21:05:06 -0400661 if isinstance(inline, SliverInline):
662 inline.model.caller = request.user
Tony Mack5cd13202013-05-01 21:48:38 -0400663 yield inline.get_formset(request, obj)
664
Scott Baker545db2a2013-12-09 18:44:43 -0800665 def accountLink(self, obj):
666 link_obj = obj.accounts.all()
667 if link_obj:
668 reverse_path = "admin:core_account_change"
669 url = reverse(reverse_path, args =(link_obj[0].id,))
670 return "<a href='%s'>%s</a>" % (url, "view billing details")
671 else:
672 return "no billing data for this site"
673 accountLink.allow_tags = True
674 accountLink.short_description = "Billing"
675
Tony Mack332ee1d2014-02-04 15:33:45 -0500676 def save_model(self, request, obj, form, change):
677 # update openstack connection to use this site/tenant
678 obj.save_by_user(request.user)
679
680 def delete_model(self, request, obj):
681 obj.delete_by_user(request.user)
682
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500683
Tony Mack9bcbe4f2013-04-29 08:13:27 -0400684class SitePrivilegeAdmin(PlanetStackBaseAdmin):
Scott Baker40c00762014-08-21 16:55:59 -0700685 fieldList = ['backend_status_text', 'user', 'site', 'role']
Tony Mack00d361f2013-04-28 10:28:42 -0400686 fieldsets = [
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500687 (None, {'fields': fieldList, 'classes':['collapse']})
Tony Mack00d361f2013-04-28 10:28:42 -0400688 ]
Scott Baker40c00762014-08-21 16:55:59 -0700689 readonly_fields = ('backend_status_text', )
Scott Baker63d1a552014-08-21 15:19:07 -0700690 list_display = ('backend_status_icon', 'user', 'site', 'role')
691 list_display_links = list_display
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500692 user_readonly_fields = fieldList
693 user_readonly_inlines = []
Tony Mack00d361f2013-04-28 10:28:42 -0400694
Tony Mackc2835a92013-05-28 09:18:49 -0400695 def formfield_for_foreignkey(self, db_field, request, **kwargs):
696 if db_field.name == 'site':
697 if not request.user.is_admin:
698 # only show sites where user is an admin or pi
699 sites = set()
700 for site_privilege in SitePrivilege.objects.filer(user=request.user):
701 if site_privilege.role.role_type in ['admin', 'pi']:
702 sites.add(site_privilege.site)
703 kwargs['queryset'] = Site.objects.filter(site__in=list(sites))
704
705 if db_field.name == 'user':
706 if not request.user.is_admin:
707 # only show users from sites where caller has admin or pi role
708 roles = Role.objects.filter(role_type__in=['admin', 'pi'])
709 site_privileges = SitePrivilege.objects.filter(user=request.user).filter(role__in=roles)
710 sites = [site_privilege.site for site_privilege in site_privileges]
711 site_privileges = SitePrivilege.objects.filter(site__in=sites)
712 emails = [site_privilege.user.email for site_privilege in site_privileges]
713 users = User.objects.filter(email__in=emails)
714 kwargs['queryset'] = users
715
716 return super(SitePrivilegeAdmin, self).formfield_for_foreignkey(db_field, request, **kwargs)
717
Tony Mack04062832013-05-10 08:22:44 -0400718 def queryset(self, request):
719 # admins can see all privileges. Users can only see privileges at sites
Tony Mackc2835a92013-05-28 09:18:49 -0400720 # where they have the admin role or pi role.
Tony Mack04062832013-05-10 08:22:44 -0400721 qs = super(SitePrivilegeAdmin, self).queryset(request)
Tony Mack5b061472014-02-04 07:57:10 -0500722 #if not request.user.is_admin:
723 # roles = Role.objects.filter(role_type__in=['admin', 'pi'])
724 # site_privileges = SitePrivilege.objects.filter(user=request.user).filter(role__in=roles)
725 # login_bases = [site_privilege.site.login_base for site_privilege in site_privileges]
726 # sites = Site.objects.filter(login_base__in=login_bases)
727 # qs = qs.filter(site__in=sites)
Tony Mack04062832013-05-10 08:22:44 -0400728 return qs
729
Siobhan Tullyce652d02013-10-08 21:52:35 -0400730class SliceForm(forms.ModelForm):
731 class Meta:
732 model = Slice
733 widgets = {
Scott Baker36f50872014-08-21 13:01:25 -0700734 'service': LinkedSelect
Siobhan Tullyce652d02013-10-08 21:52:35 -0400735 }
736
Tony Mack2cbd3802014-09-29 16:10:52 -0400737 def clean(self):
738 cleaned_data = super(SliceForm, self).clean()
739 name = cleaned_data.get('name')
Scott Baker6efad462014-10-06 23:09:59 -0700740 site = cleaned_data.get('site')
741 if (not isinstance(site,Site)):
742 # previous code indicates 'site' could be a site_id and not a site?
743 site = Slice.objects.get(id=site.id)
Tony Mack2cbd3802014-09-29 16:10:52 -0400744 if not name.startswith(site.login_base):
745 raise forms.ValidationError('slice name must begin with %s' % site.login_base)
746 return cleaned_data
747
Scott Bakerc4efdc72014-10-15 16:54:04 -0700748class SliceDeploymentsInline(PlStackTabularInline):
749 model = SliceDeployments
750 extra = 0
751 verbose_name = "Slice Deployment"
752 verbose_name_plural = "Slice Deployments"
753 suit_classes = 'suit-tab suit-tab-admin-only'
754 fields = ['backend_status_icon', 'deployment', 'tenant_id']
755 readonly_fields = ('backend_status_icon', )
756
Tony Mack2bd5b412013-06-11 21:05:06 -0400757class SliceAdmin(PlanetStackBaseAdmin):
Siobhan Tullyce652d02013-10-08 21:52:35 -0400758 form = SliceForm
Tony Mackfbb26fc2014-09-02 07:03:27 -0400759 fieldList = ['backend_status_text', 'site', 'name', 'serviceClass', 'enabled','description', 'service', 'slice_url', 'max_slivers']
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500760 fieldsets = [('Slice Details', {'fields': fieldList, 'classes':['suit-tab suit-tab-general']}),]
Scott Baker40c00762014-08-21 16:55:59 -0700761 readonly_fields = ('backend_status_text', )
Tony Mack7d459902014-09-03 13:18:57 -0400762 list_display = ('backend_status_icon', 'name', 'site','serviceClass', 'slice_url', 'max_slivers')
763 list_display_links = ('backend_status_icon', 'name', )
Siobhan Tully2d95e482013-09-06 10:56:06 -0400764 inlines = [SlicePrivilegeInline,SliverInline, TagInline, ReservationInline,SliceNetworkInline]
Scott Bakerc4efdc72014-10-15 16:54:04 -0700765 admin_inlines = [SliceDeploymentsInline]
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400766
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500767 user_readonly_fields = fieldList
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400768
Scott Bakerc4efdc72014-10-15 16:54:04 -0700769 @property
770 def suit_form_tabs(self):
771 tabs =[('general', 'Slice Details'),
772 ('slicenetworks','Networks'),
773 ('sliceprivileges','Privileges'),
774 ('slivers','Slivers'),
775 ('tags','Tags'),
776 ('reservations','Reservations'),
777 ]
778
779 request=getattr(_thread_locals, "request", None)
780 if request and request.user.is_admin:
781 tabs.append( ('admin-only', 'Admin-Only') )
782
783 return tabs
Tony Mack7b8505a2014-10-22 11:54:29 -0400784
785 def add_view(self, request, form_url='', extra_context=None):
786 # revert to default read-only fields
787 self.readonly_fields = ('backend_status_text',)
788 return super(SliceAdmin, self).add_view(request, form_url, extra_context=extra_context)
789
790 def change_view(self, request, object_id, form_url='', extra_context=None):
791 print object_id
792 # cannot change the site of an existing slice so make the site field read only
793 if object_id:
794 self.readonly_fields = ('backend_status_text','site')
795 return super(SliceAdmin, self).change_view(request, object_id, form_url)
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400796
Scott Baker510fdbb2014-08-05 17:19:24 -0700797 def render_change_form(self, request, context, add=False, change=False, form_url='', obj=None):
Scott Baker510fdbb2014-08-05 17:19:24 -0700798 deployment_nodes = []
799 for node in Node.objects.all():
800 deployment_nodes.append( (node.deployment.id, node.id, node.name) )
801
Scott Baker7a61dc42014-09-02 17:08:20 -0700802 deployment_flavors = []
803 for flavor in Flavor.objects.all():
804 for deployment in flavor.deployments.all():
805 deployment_flavors.append( (deployment.id, flavor.id, flavor.name) )
806
Scott Baker93e80cd2014-09-09 09:58:49 -0700807 deployment_images = []
808 for image in Image.objects.all():
809 for imageDeployment in image.imagedeployments_set.all():
810 deployment_images.append( (imageDeployment.deployment.id, image.id, image.name) )
811
Tony Mackec23b992014-09-02 21:18:45 -0400812 site_login_bases = []
813 for site in Site.objects.all():
Scott Baker93e80cd2014-09-09 09:58:49 -0700814 site_login_bases.append((site.id, site.login_base))
815
Scott Baker510fdbb2014-08-05 17:19:24 -0700816 context["deployment_nodes"] = deployment_nodes
Scott Baker7a61dc42014-09-02 17:08:20 -0700817 context["deployment_flavors"] = deployment_flavors
Scott Baker93e80cd2014-09-09 09:58:49 -0700818 context["deployment_images"] = deployment_images
Tony Mackec23b992014-09-02 21:18:45 -0400819 context["site_login_bases"] = site_login_bases
Scott Baker510fdbb2014-08-05 17:19:24 -0700820 return super(SliceAdmin, self).render_change_form(request, context, add, change, form_url, obj)
821
Tony Mackc2835a92013-05-28 09:18:49 -0400822 def formfield_for_foreignkey(self, db_field, request, **kwargs):
823 if db_field.name == 'site':
Tony Mack5b061472014-02-04 07:57:10 -0500824 kwargs['queryset'] = Site.select_by_user(request.user)
Tony Mackec23b992014-09-02 21:18:45 -0400825 kwargs['widget'] = forms.Select(attrs={'onChange': "update_slice_prefix(this, $($(this).closest('fieldset')[0]).find('.field-name input')[0].id)"})
Scott Baker40c00762014-08-21 16:55:59 -0700826
Tony Mackc2835a92013-05-28 09:18:49 -0400827 return super(SliceAdmin, self).formfield_for_foreignkey(db_field, request, **kwargs)
828
Tony Mack04062832013-05-10 08:22:44 -0400829 def queryset(self, request):
830 # admins can see all keys. Users can only see slices they belong to.
Tony Mack5b061472014-02-04 07:57:10 -0500831 return Slice.select_by_user(request.user)
Tony Mack04062832013-05-10 08:22:44 -0400832
Tony Mack79748612013-05-01 14:52:03 -0400833 def get_formsets(self, request, obj=None):
834 for inline in self.get_inline_instances(request, obj):
835 # hide MyInline in the add view
836 if obj is None:
837 continue
Tony Mack2bd5b412013-06-11 21:05:06 -0400838 if isinstance(inline, SliverInline):
839 inline.model.caller = request.user
Tony Mack79748612013-05-01 14:52:03 -0400840 yield inline.get_formset(request, obj)
841
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400842class SlicePrivilegeAdmin(PlanetStackBaseAdmin):
Tony Mack00d361f2013-04-28 10:28:42 -0400843 fieldsets = [
Scott Baker40c00762014-08-21 16:55:59 -0700844 (None, {'fields': ['backend_status_text', 'user', 'slice', 'role']})
Tony Mack00d361f2013-04-28 10:28:42 -0400845 ]
Scott Baker40c00762014-08-21 16:55:59 -0700846 readonly_fields = ('backend_status_text', )
Scott Baker63d1a552014-08-21 15:19:07 -0700847 list_display = ('backend_status_icon', 'user', 'slice', 'role')
848 list_display_links = list_display
Tony Mack00d361f2013-04-28 10:28:42 -0400849
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500850 user_readonly_fields = ['user', 'slice', 'role']
851 user_readonly_inlines = []
852
Tony Mackc2835a92013-05-28 09:18:49 -0400853 def formfield_for_foreignkey(self, db_field, request, **kwargs):
854 if db_field.name == 'slice':
Tony Mack5b061472014-02-04 07:57:10 -0500855 kwargs['queryset'] = Slice.select_by_user(request.user)
Tony Mackc2835a92013-05-28 09:18:49 -0400856
857 if db_field.name == 'user':
Tony Mack5b061472014-02-04 07:57:10 -0500858 kwargs['queryset'] = User.select_by_user(request.user)
Tony Mackc2835a92013-05-28 09:18:49 -0400859
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400860 return super(SlicePrivilegeAdmin, self).formfield_for_foreignkey(db_field, request, **kwargs)
Tony Mackc2835a92013-05-28 09:18:49 -0400861
Tony Mack04062832013-05-10 08:22:44 -0400862 def queryset(self, request):
863 # admins can see all memberships. Users can only see memberships of
864 # slices where they have the admin role.
Tony Mack5b061472014-02-04 07:57:10 -0500865 return SlicePrivilege.select_by_user(request.user)
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400866
Tony Mack9bcbe4f2013-04-29 08:13:27 -0400867 def save_model(self, request, obj, form, change):
Tony Mack951dab42013-05-02 19:51:45 -0400868 # update openstack connection to use this site/tenant
869 auth = request.session.get('auth', {})
Tony Mackf7f79a12014-08-11 11:21:42 -0400870 auth['tenant'] = obj.slice.slicename
Tony Mack951dab42013-05-02 19:51:45 -0400871 obj.os_manager = OpenStackManager(auth=auth, caller=request.user)
Tony Mack9bcbe4f2013-04-29 08:13:27 -0400872 obj.save()
873
874 def delete_model(self, request, obj):
Tony Mack951dab42013-05-02 19:51:45 -0400875 # update openstack connection to use this site/tenant
876 auth = request.session.get('auth', {})
Tony Mackf7f79a12014-08-11 11:21:42 -0400877 auth['tenant'] = obj.slice.slicename
Tony Mack951dab42013-05-02 19:51:45 -0400878 obj.os_manager = OpenStackManager(auth=auth, caller=request.user)
Tony Mack9bcbe4f2013-04-29 08:13:27 -0400879 obj.delete()
880
Siobhan Tully567e3e62013-06-21 18:03:16 -0400881
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400882class ImageAdmin(PlanetStackBaseAdmin):
883
Scott Baker36f50872014-08-21 13:01:25 -0700884 fieldsets = [('Image Details',
Scott Baker40c00762014-08-21 16:55:59 -0700885 {'fields': ['backend_status_text', 'name', 'disk_format', 'container_format'],
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400886 'classes': ['suit-tab suit-tab-general']})
887 ]
Scott Baker40c00762014-08-21 16:55:59 -0700888 readonly_fields = ('backend_status_text', )
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400889
Scott Baker2170b972014-06-03 12:14:07 -0700890 suit_form_tabs =(('general','Image Details'),('slivers','Slivers'),('imagedeployments','Deployments'))
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400891
Scott Baker2170b972014-06-03 12:14:07 -0700892 inlines = [SliverInline, ImageDeploymentsInline]
Scott Bakerb6f99242014-06-11 11:34:44 -0700893
Tony Mack32e1ce32014-05-07 13:29:41 -0400894 user_readonly_fields = ['name', 'disk_format', 'container_format']
Scott Bakerb27b62c2014-08-15 16:29:16 -0700895
Scott Baker63d1a552014-08-21 15:19:07 -0700896 list_display = ['backend_status_icon', 'name']
897 list_display_links = ('backend_status_icon', 'name', )
898
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400899class NodeForm(forms.ModelForm):
900 class Meta:
901 widgets = {
902 'site': LinkedSelect,
903 'deployment': LinkedSelect
904 }
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400905
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500906class NodeAdmin(PlanetStackBaseAdmin):
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400907 form = NodeForm
Scott Baker63d1a552014-08-21 15:19:07 -0700908 list_display = ('backend_status_icon', 'name', 'site', 'deployment')
909 list_display_links = ('backend_status_icon', 'name', )
Siobhan Tullybf1153a2013-05-27 20:53:48 -0400910 list_filter = ('deployment',)
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500911
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400912 inlines = [TagInline,SliverInline]
Scott Baker40c00762014-08-21 16:55:59 -0700913 fieldsets = [('Node Details', {'fields': ['backend_status_text', 'name','site','deployment'], 'classes':['suit-tab suit-tab-details']})]
914 readonly_fields = ('backend_status_text', )
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400915
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500916 user_readonly_fields = ['name','site','deployment']
917 user_readonly_inlines = [TagInline,SliverInline]
918
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400919 suit_form_tabs =(('details','Node Details'),('slivers','Slivers'),('tags','Tags'))
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400920
Siobhan Tully567e3e62013-06-21 18:03:16 -0400921
Tony Mackd90cdbf2013-04-16 22:48:40 -0400922class SliverForm(forms.ModelForm):
923 class Meta:
Tony Mack1d6b85f2013-05-07 18:49:14 -0400924 model = Sliver
Tony Mackd90cdbf2013-04-16 22:48:40 -0400925 ip = forms.CharField(widget=PlainTextWidget)
Tony Mack18261812013-05-02 16:39:20 -0400926 instance_name = forms.CharField(widget=PlainTextWidget)
Tony Mackd90cdbf2013-04-16 22:48:40 -0400927 widgets = {
928 'ip': PlainTextWidget(),
Tony Mack18261812013-05-02 16:39:20 -0400929 'instance_name': PlainTextWidget(),
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400930 'slice': LinkedSelect,
931 'deploymentNetwork': LinkedSelect,
932 'node': LinkedSelect,
933 'image': LinkedSelect
Siobhan Tully53437282013-04-26 19:30:27 -0400934 }
Tony Mackd90cdbf2013-04-16 22:48:40 -0400935
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500936class TagAdmin(PlanetStackBaseAdmin):
Scott Baker63d1a552014-08-21 15:19:07 -0700937 list_display = ['backend_status_icon', 'service', 'name', 'value', 'content_type', 'content_object',]
938 list_display_links = list_display
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500939 user_readonly_fields = ['service', 'name', 'value', 'content_type', 'content_object',]
940 user_readonly_inlines = []
Siobhan Tullyd3515752013-06-21 16:34:53 -0400941
Tony Mack9bcbe4f2013-04-29 08:13:27 -0400942class SliverAdmin(PlanetStackBaseAdmin):
Tony Mackd90cdbf2013-04-16 22:48:40 -0400943 form = SliverForm
Tony Mackcdec0902013-04-15 00:38:49 -0400944 fieldsets = [
Scott Baker7a61dc42014-09-02 17:08:20 -0700945 ('Sliver Details', {'fields': ['backend_status_text', 'slice', 'deploymentNetwork', 'node', 'ip', 'instance_name', 'flavor', 'image', ], 'classes': ['suit-tab suit-tab-general'], })
Tony Mackcdec0902013-04-15 00:38:49 -0400946 ]
Scott Baker40c00762014-08-21 16:55:59 -0700947 readonly_fields = ('backend_status_text', )
Scott Baker7a61dc42014-09-02 17:08:20 -0700948 list_display = ['backend_status_icon', 'ip', 'instance_name', 'slice', 'flavor', 'image', 'node', 'deploymentNetwork']
Scott Baker63d1a552014-08-21 15:19:07 -0700949 list_display_links = ('backend_status_icon', 'ip',)
Siobhan Tullybfd11dc2013-09-03 12:59:24 -0400950
951 suit_form_tabs =(('general', 'Sliver Details'),
952 ('tags','Tags'),
953 )
954
Siobhan Tullyde5450d2013-06-21 11:35:33 -0400955 inlines = [TagInline]
Tony Mack53106f32013-04-27 16:43:01 -0400956
Scott Baker7a61dc42014-09-02 17:08:20 -0700957 user_readonly_fields = ['slice', 'deploymentNetwork', 'node', 'ip', 'instance_name', 'flavor', 'image']
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500958
Tony Mackc2835a92013-05-28 09:18:49 -0400959 def formfield_for_foreignkey(self, db_field, request, **kwargs):
960 if db_field.name == 'slice':
Tony Mack5b061472014-02-04 07:57:10 -0500961 kwargs['queryset'] = Slice.select_by_user(request.user)
Tony Mackc2835a92013-05-28 09:18:49 -0400962
963 return super(SliverAdmin, self).formfield_for_foreignkey(db_field, request, **kwargs)
964
Tony Mack04062832013-05-10 08:22:44 -0400965 def queryset(self, request):
Scott Baker36f50872014-08-21 13:01:25 -0700966 # admins can see all slivers. Users can only see slivers of
Tony Mack04062832013-05-10 08:22:44 -0400967 # the slices they belong to.
Tony Mack5b061472014-02-04 07:57:10 -0500968 return Sliver.select_by_user(request.user)
969
Tony Mack04062832013-05-10 08:22:44 -0400970
Tony Mack1d6b85f2013-05-07 18:49:14 -0400971 def get_formsets(self, request, obj=None):
972 # make some fields read only if we are updating an existing record
973 if obj == None:
Scott Baker36f50872014-08-21 13:01:25 -0700974 #self.readonly_fields = ('ip', 'instance_name')
Scott Bakerfbb45862014-10-17 16:27:23 -0700975 self.readonly_fields = ('backend_status_text',)
Tony Mack1d6b85f2013-05-07 18:49:14 -0400976 else:
Scott Bakerfbb45862014-10-17 16:27:23 -0700977 self.readonly_fields = ('backend_status_text',)
Scott Baker36f50872014-08-21 13:01:25 -0700978 #self.readonly_fields = ('ip', 'instance_name', 'slice', 'image', 'key')
Tony Mack1d6b85f2013-05-07 18:49:14 -0400979
980 for inline in self.get_inline_instances(request, obj):
981 # hide MyInline in the add view
982 if obj is None:
983 continue
Scott Baker526b71e2014-05-13 13:18:01 -0700984 if isinstance(inline, SliverInline):
985 inline.model.caller = request.user
986 yield inline.get_formset(request, obj)
Tony Mack53106f32013-04-27 16:43:01 -0400987
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500988 #def save_model(self, request, obj, form, change):
989 # # update openstack connection to use this site/tenant
990 # auth = request.session.get('auth', {})
991 # auth['tenant'] = obj.slice.name
992 # obj.os_manager = OpenStackManager(auth=auth, caller=request.user)
993 # obj.creator = request.user
994 # obj.save()
Tony Mack53106f32013-04-27 16:43:01 -0400995
Siobhan Tullycf04fb62014-01-11 11:25:57 -0500996 #def delete_model(self, request, obj):
997 # # update openstack connection to use this site/tenant
998 # auth = request.session.get('auth', {})
999 # auth['tenant'] = obj.slice.name
1000 # obj.os_manager = OpenStackManager(auth=auth, caller=request.user)
1001 # obj.delete()
Tony Mackcdec0902013-04-15 00:38:49 -04001002
Siobhan Tully53437282013-04-26 19:30:27 -04001003class UserCreationForm(forms.ModelForm):
1004 """A form for creating new users. Includes all the required
1005 fields, plus a repeated password."""
1006 password1 = forms.CharField(label='Password', widget=forms.PasswordInput)
1007 password2 = forms.CharField(label='Password confirmation', widget=forms.PasswordInput)
1008
1009 class Meta:
Siobhan Tully30fd4292013-05-10 08:59:56 -04001010 model = User
Siobhan Tullybfd11dc2013-09-03 12:59:24 -04001011 fields = ('email', 'firstname', 'lastname', 'phone', 'public_key')
Siobhan Tully53437282013-04-26 19:30:27 -04001012
1013 def clean_password2(self):
1014 # Check that the two password entries match
1015 password1 = self.cleaned_data.get("password1")
1016 password2 = self.cleaned_data.get("password2")
1017 if password1 and password2 and password1 != password2:
1018 raise forms.ValidationError("Passwords don't match")
1019 return password2
1020
1021 def save(self, commit=True):
1022 # Save the provided password in hashed format
1023 user = super(UserCreationForm, self).save(commit=False)
Tony Mackf9f4afb2013-05-01 21:02:12 -04001024 user.password = self.cleaned_data["password1"]
1025 #user.set_password(self.cleaned_data["password1"])
Siobhan Tully53437282013-04-26 19:30:27 -04001026 if commit:
1027 user.save()
1028 return user
1029
Siobhan Tully567e3e62013-06-21 18:03:16 -04001030
Siobhan Tully53437282013-04-26 19:30:27 -04001031class UserChangeForm(forms.ModelForm):
1032 """A form for updating users. Includes all the fields on
1033 the user, but replaces the password field with admin's
1034 password hash display field.
1035 """
Siobhan Tully63b7ba42014-01-12 10:35:11 -05001036 password = ReadOnlyPasswordHashField(label='Password',
1037 help_text= '<a href=\"password/\">Change Password</a>.')
Siobhan Tully53437282013-04-26 19:30:27 -04001038
1039 class Meta:
Siobhan Tully30fd4292013-05-10 08:59:56 -04001040 model = User
Siobhan Tully53437282013-04-26 19:30:27 -04001041
1042 def clean_password(self):
1043 # Regardless of what the user provides, return the initial value.
1044 # This is done here, rather than on the field, because the
1045 # field does not have access to the initial value
1046 return self.initial["password"]
1047
Scott Baker2c3cb642014-05-19 17:55:56 -07001048class UserDashboardViewInline(PlStackTabularInline):
1049 model = UserDashboardView
1050 extra = 0
1051 suit_classes = 'suit-tab suit-tab-dashboards'
1052 fields = ['user', 'dashboardView', 'order']
1053
Scott Baker86c83ab2014-10-03 13:10:47 -07001054class UserAdmin(PermissionCheckingAdminMixin, UserAdmin):
1055 # Note: Make sure PermissionCheckingAdminMixin is listed before
1056 # admin.ModelAdmin in the class declaration.
1057
Siobhan Tully53437282013-04-26 19:30:27 -04001058 class Meta:
1059 app_label = "core"
1060
1061 # The forms to add and change user instances
1062 form = UserChangeForm
1063 add_form = UserCreationForm
1064
1065 # The fields to be used in displaying the User model.
1066 # These override the definitions on the base UserAdmin
1067 # that reference specific fields on auth.User.
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001068 list_display = ('email', 'firstname', 'lastname', 'site', 'last_login')
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001069 list_filter = ('site',)
Scott Baker2c3cb642014-05-19 17:55:56 -07001070 inlines = [SlicePrivilegeInline,SitePrivilegeInline,DeploymentPrivilegeInline,UserDashboardViewInline]
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001071
Scott Bakercbfb6002014-10-03 00:32:37 -07001072 fieldListLoginDetails = ['backend_status_text', 'email','site','password','is_active','is_readonly','is_admin','public_key']
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001073 fieldListContactInfo = ['firstname','lastname','phone','timezone']
1074
Siobhan Tully53437282013-04-26 19:30:27 -04001075 fieldsets = (
Scott Baker40c00762014-08-21 16:55:59 -07001076 ('Login Details', {'fields': ['backend_status_text', 'email', 'site','password', 'is_active', 'is_readonly', 'is_admin', 'public_key'], 'classes':['suit-tab suit-tab-general']}),
Siobhan Tullybfd11dc2013-09-03 12:59:24 -04001077 ('Contact Information', {'fields': ('firstname','lastname','phone', 'timezone'), 'classes':['suit-tab suit-tab-contact']}),
Scott Baker2c3cb642014-05-19 17:55:56 -07001078 #('Dashboard Views', {'fields': ('dashboards',), 'classes':['suit-tab suit-tab-dashboards']}),
Siobhan Tully53437282013-04-26 19:30:27 -04001079 #('Important dates', {'fields': ('last_login',)}),
1080 )
1081 add_fieldsets = (
1082 (None, {
1083 'classes': ('wide',),
Scott Baker0a5633b2014-10-06 17:51:20 -07001084 'fields': ('email', 'firstname', 'lastname', 'is_readonly', 'phone', 'public_key','password1', 'password2')},
Siobhan Tully53437282013-04-26 19:30:27 -04001085 ),
1086 )
Scott Baker40c00762014-08-21 16:55:59 -07001087 readonly_fields = ('backend_status_text', )
Siobhan Tully53437282013-04-26 19:30:27 -04001088 search_fields = ('email',)
1089 ordering = ('email',)
1090 filter_horizontal = ()
1091
Scott Baker3ca51f62014-05-23 12:05:11 -07001092 user_readonly_fields = fieldListLoginDetails + fieldListContactInfo
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001093
Scott Baker0a5633b2014-10-06 17:51:20 -07001094 @property
1095 def suit_form_tabs(self):
1096 if getattr(_thread_locals, "obj", None) is None:
1097 return []
1098 else:
1099 return (('general','Login Details'),
1100 ('contact','Contact Information'),
1101 ('sliceprivileges','Slice Privileges'),
1102 ('siteprivileges','Site Privileges'),
1103 ('deploymentprivileges','Deployment Privileges'),
1104 ('dashboards','Dashboard Views'))
Siobhan Tullybfd11dc2013-09-03 12:59:24 -04001105
Tony Mackc2835a92013-05-28 09:18:49 -04001106 def formfield_for_foreignkey(self, db_field, request, **kwargs):
1107 if db_field.name == 'site':
Tony Mack5b061472014-02-04 07:57:10 -05001108 kwargs['queryset'] = Site.select_by_user(request.user)
Tony Mackc2835a92013-05-28 09:18:49 -04001109
1110 return super(UserAdmin, self).formfield_for_foreignkey(db_field, request, **kwargs)
1111
Tony Mack5b061472014-02-04 07:57:10 -05001112 def queryset(self, request):
1113 return User.select_by_user(request.user)
1114
Scott Baker2c3cb642014-05-19 17:55:56 -07001115class DashboardViewAdmin(PlanetStackBaseAdmin):
1116 fieldsets = [('Dashboard View Details',
Scott Baker40c00762014-08-21 16:55:59 -07001117 {'fields': ['backend_status_text', 'name', 'url'],
Scott Baker2c3cb642014-05-19 17:55:56 -07001118 'classes': ['suit-tab suit-tab-general']})
1119 ]
Scott Baker40c00762014-08-21 16:55:59 -07001120 readonly_fields = ('backend_status_text', )
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001121
Scott Baker2c3cb642014-05-19 17:55:56 -07001122 suit_form_tabs =(('general','Dashboard View Details'),)
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001123
Scott Baker0165fac2014-01-13 11:49:26 -08001124class ServiceResourceInline(PlStackTabularInline):
Scott Baker3de3e372013-05-10 16:50:44 -07001125 model = ServiceResource
1126 extra = 0
1127
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001128class ServiceClassAdmin(PlanetStackBaseAdmin):
Scott Baker63d1a552014-08-21 15:19:07 -07001129 list_display = ('backend_status_icon', 'name', 'commitment', 'membershipFee')
1130 list_display_links = ('backend_status_icon', 'name', )
Scott Baker3de3e372013-05-10 16:50:44 -07001131 inlines = [ServiceResourceInline]
1132
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001133 user_readonly_fields = ['name', 'commitment', 'membershipFee']
1134 user_readonly_inlines = []
1135
Scott Baker0165fac2014-01-13 11:49:26 -08001136class ReservedResourceInline(PlStackTabularInline):
Scott Baker133c9212013-05-17 09:09:11 -07001137 model = ReservedResource
1138 extra = 0
Siobhan Tullybfd11dc2013-09-03 12:59:24 -04001139 suit_classes = 'suit-tab suit-tab-reservedresources'
Scott Baker133c9212013-05-17 09:09:11 -07001140
1141 def formfield_for_foreignkey(self, db_field, request=None, **kwargs):
1142 field = super(ReservedResourceInline, self).formfield_for_foreignkey(db_field, request, **kwargs)
1143
1144 if db_field.name == 'resource':
1145 # restrict resources to those that the slice's service class allows
1146 if request._slice is not None:
1147 field.queryset = field.queryset.filter(serviceClass = request._slice.serviceClass, calendarReservable=True)
1148 if len(field.queryset) > 0:
1149 field.initial = field.queryset.all()[0]
1150 else:
1151 field.queryset = field.queryset.none()
1152 elif db_field.name == 'sliver':
1153 # restrict slivers to those that belong to the slice
1154 if request._slice is not None:
1155 field.queryset = field.queryset.filter(slice = request._slice)
1156 else:
1157 field.queryset = field.queryset.none()
1158
1159 return field
1160
Tony Mack5b061472014-02-04 07:57:10 -05001161 def queryset(self, request):
1162 return ReservedResource.select_by_user(request.user)
1163
Scott Baker133c9212013-05-17 09:09:11 -07001164class ReservationChangeForm(forms.ModelForm):
1165 class Meta:
1166 model = Reservation
Siobhan Tullybfd11dc2013-09-03 12:59:24 -04001167 widgets = {
1168 'slice' : LinkedSelect
1169 }
Scott Baker133c9212013-05-17 09:09:11 -07001170
1171class ReservationAddForm(forms.ModelForm):
1172 slice = forms.ModelChoiceField(queryset=Slice.objects.all(), widget=forms.Select(attrs={"onChange":"document.getElementById('id_refresh').value=1; submit()"}))
1173 refresh = forms.CharField(widget=forms.HiddenInput())
1174
1175 class Media:
1176 css = {'all': ('planetstack.css',)} # .field-refresh { display: none; }
1177
1178 def clean_slice(self):
1179 slice = self.cleaned_data.get("slice")
1180 x = ServiceResource.objects.filter(serviceClass = slice.serviceClass, calendarReservable=True)
1181 if len(x) == 0:
1182 raise forms.ValidationError("The slice you selected does not have a service class that allows reservations")
1183 return slice
1184
1185 class Meta:
1186 model = Reservation
Siobhan Tullybfd11dc2013-09-03 12:59:24 -04001187 widgets = {
1188 'slice' : LinkedSelect
1189 }
1190
Scott Baker133c9212013-05-17 09:09:11 -07001191
1192class ReservationAddRefreshForm(ReservationAddForm):
1193 """ This form is displayed when the Reservation Form receives an update
1194 from the Slice dropdown onChange handler. It doesn't validate the
1195 data and doesn't save the data. This will cause the form to be
1196 redrawn.
1197 """
1198
Scott Baker8737e5f2013-05-17 09:35:32 -07001199 """ don't validate anything other than slice """
1200 dont_validate_fields = ("startTime", "duration")
1201
Scott Baker133c9212013-05-17 09:09:11 -07001202 def full_clean(self):
1203 result = super(ReservationAddForm, self).full_clean()
Scott Baker8737e5f2013-05-17 09:35:32 -07001204
1205 for fieldname in self.dont_validate_fields:
1206 if fieldname in self._errors:
1207 del self._errors[fieldname]
1208
Scott Baker133c9212013-05-17 09:09:11 -07001209 return result
1210
1211 """ don't save anything """
1212 def is_valid(self):
1213 return False
1214
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001215class ReservationAdmin(PlanetStackBaseAdmin):
Scott Baker40c00762014-08-21 16:55:59 -07001216 fieldList = ['backend_status_text', 'slice', 'startTime', 'duration']
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001217 fieldsets = [('Reservation Details', {'fields': fieldList, 'classes': ['suit-tab suit-tab-general']})]
Scott Baker40c00762014-08-21 16:55:59 -07001218 readonly_fields = ('backend_status_text', )
Scott Baker133c9212013-05-17 09:09:11 -07001219 list_display = ('startTime', 'duration')
Scott Baker133c9212013-05-17 09:09:11 -07001220 form = ReservationAddForm
1221
Siobhan Tullybfd11dc2013-09-03 12:59:24 -04001222 suit_form_tabs = (('general','Reservation Details'), ('reservedresources','Reserved Resources'))
1223
1224 inlines = [ReservedResourceInline]
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001225 user_readonly_fields = fieldList
Siobhan Tullybfd11dc2013-09-03 12:59:24 -04001226
Scott Baker133c9212013-05-17 09:09:11 -07001227 def add_view(self, request, form_url='', extra_context=None):
Scott Bakeracd45142013-05-19 16:19:16 -07001228 timezone.activate(request.user.timezone)
Scott Baker133c9212013-05-17 09:09:11 -07001229 request._refresh = False
1230 request._slice = None
1231 if request.method == 'POST':
Scott Baker8737e5f2013-05-17 09:35:32 -07001232 # "refresh" will be set to "1" if the form was submitted due to
1233 # a change in the Slice dropdown.
Scott Baker133c9212013-05-17 09:09:11 -07001234 if request.POST.get("refresh","1") == "1":
1235 request._refresh = True
1236 request.POST["refresh"] = "0"
Scott Baker8737e5f2013-05-17 09:35:32 -07001237
1238 # Keep track of the slice that was selected, so the
1239 # reservedResource inline can filter items for the slice.
Scott Baker133c9212013-05-17 09:09:11 -07001240 request._slice = request.POST.get("slice",None)
1241 if (request._slice is not None):
1242 request._slice = Slice.objects.get(id=request._slice)
1243
1244 result = super(ReservationAdmin, self).add_view(request, form_url, extra_context)
1245 return result
1246
Scott Bakeracd45142013-05-19 16:19:16 -07001247 def changelist_view(self, request, extra_context = None):
1248 timezone.activate(request.user.timezone)
1249 return super(ReservationAdmin, self).changelist_view(request, extra_context)
1250
Scott Baker133c9212013-05-17 09:09:11 -07001251 def get_form(self, request, obj=None, **kwargs):
Siobhan Tullyd3515752013-06-21 16:34:53 -04001252 request._obj_ = obj
1253 if obj is not None:
1254 # For changes, set request._slice to the slice already set in the
1255 # object.
1256 request._slice = obj.slice
1257 self.form = ReservationChangeForm
1258 else:
1259 if getattr(request, "_refresh", False):
1260 self.form = ReservationAddRefreshForm
1261 else:
1262 self.form = ReservationAddForm
1263 return super(ReservationAdmin, self).get_form(request, obj, **kwargs)
1264
Scott Baker133c9212013-05-17 09:09:11 -07001265 def get_readonly_fields(self, request, obj=None):
Siobhan Tullyd3515752013-06-21 16:34:53 -04001266 if (obj is not None):
1267 # Prevent slice from being changed after the reservation has been
1268 # created.
1269 return ['slice']
1270 else:
Scott Baker133c9212013-05-17 09:09:11 -07001271 return []
Scott Baker3de3e372013-05-10 16:50:44 -07001272
Tony Mack5b061472014-02-04 07:57:10 -05001273 def queryset(self, request):
1274 return Reservation.select_by_user(request.user)
1275
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001276class NetworkParameterTypeAdmin(PlanetStackBaseAdmin):
Scott Baker63d1a552014-08-21 15:19:07 -07001277 list_display = ("backend_status_icon", "name", )
1278 list_display_links = ('backend_status_icon', 'name', )
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001279 user_readonly_fields = ['name']
1280 user_readonly_inlines = []
Scott Baker74d8e622013-07-29 16:04:22 -07001281
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001282class RouterAdmin(PlanetStackBaseAdmin):
Scott Baker63d1a552014-08-21 15:19:07 -07001283 list_display = ("backend_status_icon", "name", )
1284 list_display_links = ('backend_status_icon', 'name', )
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001285 user_readonly_fields = ['name']
1286 user_readonly_inlines = []
1287
Scott Baker0165fac2014-01-13 11:49:26 -08001288class RouterInline(PlStackTabularInline):
Scott Baker74d8e622013-07-29 16:04:22 -07001289 model = Router.networks.through
1290 extra = 0
1291 verbose_name_plural = "Routers"
1292 verbose_name = "Router"
Siobhan Tully2d95e482013-09-06 10:56:06 -04001293 suit_classes = 'suit-tab suit-tab-routers'
Scott Baker74d8e622013-07-29 16:04:22 -07001294
Scott Bakerb27b62c2014-08-15 16:29:16 -07001295class NetworkParameterInline(PlStackGenericTabularInline):
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001296 model = NetworkParameter
Scott Baker618e3792014-08-15 13:42:29 -07001297 extra = 0
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001298 verbose_name_plural = "Parameters"
1299 verbose_name = "Parameter"
1300 suit_classes = 'suit-tab suit-tab-netparams'
Scott Baker40c00762014-08-21 16:55:59 -07001301 fields = ['backend_status_icon', 'parameter', 'value']
1302 readonly_fields = ('backend_status_icon', )
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001303
Scott Baker0165fac2014-01-13 11:49:26 -08001304class NetworkSliversInline(PlStackTabularInline):
Scott Baker40c00762014-08-21 16:55:59 -07001305 fields = ['backend_status_icon', 'network','sliver','ip']
1306 readonly_fields = ("backend_status_icon", "ip", )
Scott Baker74d8e622013-07-29 16:04:22 -07001307 model = NetworkSliver
Scott Baker874936e2014-01-13 18:15:34 -08001308 selflink_fieldname = "sliver"
Scott Baker74d8e622013-07-29 16:04:22 -07001309 extra = 0
1310 verbose_name_plural = "Slivers"
1311 verbose_name = "Sliver"
Siobhan Tully2d95e482013-09-06 10:56:06 -04001312 suit_classes = 'suit-tab suit-tab-networkslivers'
Scott Baker74d8e622013-07-29 16:04:22 -07001313
Scott Baker0165fac2014-01-13 11:49:26 -08001314class NetworkSlicesInline(PlStackTabularInline):
Scott Bakerd7d2a392013-08-06 08:57:30 -07001315 model = NetworkSlice
Scott Baker874936e2014-01-13 18:15:34 -08001316 selflink_fieldname = "slice"
Scott Bakerd7d2a392013-08-06 08:57:30 -07001317 extra = 0
1318 verbose_name_plural = "Slices"
1319 verbose_name = "Slice"
Siobhan Tully2d95e482013-09-06 10:56:06 -04001320 suit_classes = 'suit-tab suit-tab-networkslices'
Scott Baker40c00762014-08-21 16:55:59 -07001321 fields = ['backend_status_icon', 'network','slice']
1322 readonly_fields = ('backend_status_icon', )
Scott Bakerd7d2a392013-08-06 08:57:30 -07001323
Scott Bakerfbb45862014-10-17 16:27:23 -07001324class NetworkDeploymentsInline(PlStackTabularInline):
1325 model = NetworkDeployments
1326 extra = 0
1327 verbose_name_plural = "Network Deployments"
1328 verbose_name = "Network Deployment"
1329 suit_classes = 'suit-tab suit-tab-admin-only'
1330 fields = ['backend_status_icon', 'deployment','net_id','subnet_id']
1331 readonly_fields = ('backend_status_icon', )
1332
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001333class NetworkAdmin(PlanetStackBaseAdmin):
Scott Baker63d1a552014-08-21 15:19:07 -07001334 list_display = ("backend_status_icon", "name", "subnet", "ports", "labels")
1335 list_display_links = ('backend_status_icon', 'name', )
Scott Baker74d8e622013-07-29 16:04:22 -07001336 readonly_fields = ("subnet", )
Siobhan Tully2d95e482013-09-06 10:56:06 -04001337
Scott Bakerd7d2a392013-08-06 08:57:30 -07001338 inlines = [NetworkParameterInline, NetworkSliversInline, NetworkSlicesInline, RouterInline]
Scott Bakerfbb45862014-10-17 16:27:23 -07001339 admin_inlines = [NetworkDeploymentsInline]
Scott Baker74d8e622013-07-29 16:04:22 -07001340
Siobhan Tully2d95e482013-09-06 10:56:06 -04001341 fieldsets = [
Scott Baker40c00762014-08-21 16:55:59 -07001342 (None, {'fields': ['backend_status_text', 'name','template','ports','labels','owner','guaranteedBandwidth', 'permitAllSlices','permittedSlices','network_id','router_id','subnet_id','subnet'], 'classes':['suit-tab suit-tab-general']}),]
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001343
Scott Baker40c00762014-08-21 16:55:59 -07001344 readonly_fields = ('backend_status_text', )
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001345 user_readonly_fields = ['name','template','ports','labels','owner','guaranteedBandwidth', 'permitAllSlices','permittedSlices','network_id','router_id','subnet_id','subnet']
Siobhan Tully2d95e482013-09-06 10:56:06 -04001346
Scott Bakerfbb45862014-10-17 16:27:23 -07001347 @property
1348 def suit_form_tabs(self):
1349 tabs=[('general','Network Details'),
1350 ('netparams', 'Parameters'),
1351 ('networkslivers','Slivers'),
1352 ('networkslices','Slices'),
1353 ('routers','Routers'),
1354 ]
1355
1356 request=getattr(_thread_locals, "request", None)
1357 if request and request.user.is_admin:
1358 tabs.append( ('admin-only', 'Admin-Only') )
1359
1360 return tabs
1361
1362
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001363class NetworkTemplateAdmin(PlanetStackBaseAdmin):
Scott Baker63d1a552014-08-21 15:19:07 -07001364 list_display = ("backend_status_icon", "name", "guaranteedBandwidth", "visibility")
1365 list_display_links = ('backend_status_icon', 'name', )
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001366 user_readonly_fields = ["name", "guaranteedBandwidth", "visibility"]
1367 user_readonly_inlines = []
Scott Baker74d8e622013-07-29 16:04:22 -07001368
Scott Baker37b47902014-09-02 14:37:41 -07001369class FlavorAdmin(PlanetStackBaseAdmin):
1370 list_display = ("backend_status_icon", "name", "flavor", "order", "default")
1371 list_display_links = ("backend_status_icon", "name")
1372 user_readonly_fields = ("name", "flavor")
1373 fields = ("name", "description", "flavor", "order", "default")
1374
Tony Mack31c2b8f2013-04-26 20:01:42 -04001375# register a signal that caches the user's credentials when they log in
1376def cache_credentials(sender, user, request, **kwds):
1377 auth = {'username': request.POST['username'],
1378 'password': request.POST['password']}
1379 request.session['auth'] = auth
1380user_logged_in.connect(cache_credentials)
1381
Scott Baker15cddfa2013-12-09 13:45:19 -08001382def dollar_field(fieldName, short_description):
1383 def newFunc(self, obj):
1384 try:
1385 x= "$ %0.2f" % float(getattr(obj, fieldName, 0.0))
1386 except:
1387 x=getattr(obj, fieldName, 0.0)
1388 return x
1389 newFunc.short_description = short_description
1390 return newFunc
1391
1392def right_dollar_field(fieldName, short_description):
1393 def newFunc(self, obj):
1394 try:
1395 #x= '<div align=right style="width:6em">$ %0.2f</div>' % float(getattr(obj, fieldName, 0.0))
1396 x= '<div align=right>$ %0.2f</div>' % float(getattr(obj, fieldName, 0.0))
1397 except:
1398 x=getattr(obj, fieldName, 0.0)
1399 return x
1400 newFunc.short_description = short_description
1401 newFunc.allow_tags = True
1402 return newFunc
Scott Baker43105042013-12-06 23:23:36 -08001403
Scott Baker0165fac2014-01-13 11:49:26 -08001404class InvoiceChargeInline(PlStackTabularInline):
Scott Baker43105042013-12-06 23:23:36 -08001405 model = Charge
Scott Baker15cddfa2013-12-09 13:45:19 -08001406 extra = 0
Scott Baker43105042013-12-06 23:23:36 -08001407 verbose_name_plural = "Charges"
1408 verbose_name = "Charge"
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001409 exclude = ['account']
Scott Baker9cb88a22013-12-09 18:56:00 -08001410 fields = ["date", "kind", "state", "object", "coreHours", "dollar_amount", "slice"]
1411 readonly_fields = ["date", "kind", "state", "object", "coreHours", "dollar_amount", "slice"]
1412 can_delete = False
1413 max_num = 0
1414
1415 dollar_amount = right_dollar_field("amount", "Amount")
Scott Baker43105042013-12-06 23:23:36 -08001416
1417class InvoiceAdmin(admin.ModelAdmin):
1418 list_display = ("date", "account")
1419
1420 inlines = [InvoiceChargeInline]
1421
Scott Baker9cb88a22013-12-09 18:56:00 -08001422 fields = ["date", "account", "dollar_amount"]
1423 readonly_fields = ["date", "account", "dollar_amount"]
1424
1425 dollar_amount = dollar_field("amount", "Amount")
Scott Baker43105042013-12-06 23:23:36 -08001426
Scott Baker0165fac2014-01-13 11:49:26 -08001427class InvoiceInline(PlStackTabularInline):
Scott Baker15cddfa2013-12-09 13:45:19 -08001428 model = Invoice
1429 extra = 0
1430 verbose_name_plural = "Invoices"
1431 verbose_name = "Invoice"
Scott Baker0165fac2014-01-13 11:49:26 -08001432 fields = ["date", "dollar_amount"]
1433 readonly_fields = ["date", "dollar_amount"]
Scott Baker15cddfa2013-12-09 13:45:19 -08001434 suit_classes = 'suit-tab suit-tab-accountinvoice'
1435 can_delete=False
1436 max_num=0
1437
1438 dollar_amount = right_dollar_field("amount", "Amount")
1439
Scott Baker0165fac2014-01-13 11:49:26 -08001440class PendingChargeInline(PlStackTabularInline):
Scott Baker43105042013-12-06 23:23:36 -08001441 model = Charge
Scott Baker15cddfa2013-12-09 13:45:19 -08001442 extra = 0
Scott Baker43105042013-12-06 23:23:36 -08001443 verbose_name_plural = "Charges"
1444 verbose_name = "Charge"
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001445 exclude = ["invoice"]
Scott Baker15cddfa2013-12-09 13:45:19 -08001446 fields = ["date", "kind", "state", "object", "coreHours", "dollar_amount", "slice"]
1447 readonly_fields = ["date", "kind", "state", "object", "coreHours", "dollar_amount", "slice"]
Scott Baker43105042013-12-06 23:23:36 -08001448 suit_classes = 'suit-tab suit-tab-accountpendingcharges'
Scott Baker15cddfa2013-12-09 13:45:19 -08001449 can_delete=False
1450 max_num=0
Scott Baker43105042013-12-06 23:23:36 -08001451
1452 def queryset(self, request):
1453 qs = super(PendingChargeInline, self).queryset(request)
1454 qs = qs.filter(state="pending")
1455 return qs
1456
Scott Baker15cddfa2013-12-09 13:45:19 -08001457 dollar_amount = right_dollar_field("amount", "Amount")
1458
Scott Baker0165fac2014-01-13 11:49:26 -08001459class PaymentInline(PlStackTabularInline):
Scott Baker43105042013-12-06 23:23:36 -08001460 model=Payment
1461 extra = 1
1462 verbose_name_plural = "Payments"
1463 verbose_name = "Payment"
Scott Baker15cddfa2013-12-09 13:45:19 -08001464 fields = ["date", "dollar_amount"]
1465 readonly_fields = ["date", "dollar_amount"]
Scott Baker43105042013-12-06 23:23:36 -08001466 suit_classes = 'suit-tab suit-tab-accountpayments'
Scott Baker15cddfa2013-12-09 13:45:19 -08001467 can_delete=False
1468 max_num=0
1469
1470 dollar_amount = right_dollar_field("amount", "Amount")
1471
Scott Baker43105042013-12-06 23:23:36 -08001472class AccountAdmin(admin.ModelAdmin):
1473 list_display = ("site", "balance_due")
1474
1475 inlines = [InvoiceInline, PaymentInline, PendingChargeInline]
1476
1477 fieldsets = [
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001478 (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 -08001479
Scott Baker15cddfa2013-12-09 13:45:19 -08001480 readonly_fields = ['site', 'dollar_balance_due', 'dollar_total_invoices', 'dollar_total_payments']
Scott Baker43105042013-12-06 23:23:36 -08001481
1482 suit_form_tabs =(
1483 ('general','Account Details'),
1484 ('accountinvoice', 'Invoices'),
1485 ('accountpayments', 'Payments'),
1486 ('accountpendingcharges','Pending Charges'),
1487 )
1488
Scott Baker15cddfa2013-12-09 13:45:19 -08001489 dollar_balance_due = dollar_field("balance_due", "Balance Due")
1490 dollar_total_invoices = dollar_field("total_invoices", "Total Invoices")
1491 dollar_total_payments = dollar_field("total_payments", "Total Payments")
1492
Siobhan Tully53437282013-04-26 19:30:27 -04001493# Now register the new UserAdmin...
Siobhan Tully30fd4292013-05-10 08:59:56 -04001494admin.site.register(User, UserAdmin)
Siobhan Tully53437282013-04-26 19:30:27 -04001495# ... and, since we're not using Django's builtin permissions,
1496# unregister the Group model from admin.
Siobhan Tullyce652d02013-10-08 21:52:35 -04001497#admin.site.unregister(Group)
Siobhan Tully53437282013-04-26 19:30:27 -04001498
Siobhan Tullybf1153a2013-05-27 20:53:48 -04001499#Do not show django evolution in the admin interface
1500from django_evolution.models import Version, Evolution
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001501#admin.site.unregister(Version)
1502#admin.site.unregister(Evolution)
Siobhan Tullybf1153a2013-05-27 20:53:48 -04001503
1504
1505# When debugging it is often easier to see all the classes, but for regular use
1506# only the top-levels should be displayed
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001507showAll = False
Scott Baker43105042013-12-06 23:23:36 -08001508
Siobhan Tullybf1153a2013-05-27 20:53:48 -04001509admin.site.register(Deployment, DeploymentAdmin)
Siobhan Tully4bc09f22013-04-10 21:15:21 -04001510admin.site.register(Site, SiteAdmin)
Siobhan Tully4bc09f22013-04-10 21:15:21 -04001511admin.site.register(Slice, SliceAdmin)
Siobhan Tullyce652d02013-10-08 21:52:35 -04001512admin.site.register(Service, ServiceAdmin)
smbakera3cf70c2013-06-27 02:01:41 -07001513admin.site.register(Reservation, ReservationAdmin)
Scott Baker74d8e622013-07-29 16:04:22 -07001514admin.site.register(Network, NetworkAdmin)
1515admin.site.register(Router, RouterAdmin)
Scott Baker74d8e622013-07-29 16:04:22 -07001516admin.site.register(NetworkTemplate, NetworkTemplateAdmin)
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001517admin.site.register(Account, AccountAdmin)
1518admin.site.register(Invoice, InvoiceAdmin)
Siobhan Tullybf1153a2013-05-27 20:53:48 -04001519
Siobhan Tullycf04fb62014-01-11 11:25:57 -05001520if True:
1521 admin.site.register(NetworkParameterType, NetworkParameterTypeAdmin)
1522 admin.site.register(ServiceClass, ServiceClassAdmin)
Siobhan Tullybfd11dc2013-09-03 12:59:24 -04001523 #admin.site.register(PlanetStack)
Siobhan Tullyd3515752013-06-21 16:34:53 -04001524 admin.site.register(Tag, TagAdmin)
Siobhan Tullyce652d02013-10-08 21:52:35 -04001525 admin.site.register(DeploymentRole)
1526 admin.site.register(SiteRole)
1527 admin.site.register(SliceRole)
1528 admin.site.register(PlanetStackRole)
Siobhan Tullybf1153a2013-05-27 20:53:48 -04001529 admin.site.register(Node, NodeAdmin)
Siobhan Tullybfd11dc2013-09-03 12:59:24 -04001530 #admin.site.register(SlicePrivilege, SlicePrivilegeAdmin)
1531 #admin.site.register(SitePrivilege, SitePrivilegeAdmin)
Siobhan Tullybf1153a2013-05-27 20:53:48 -04001532 admin.site.register(Sliver, SliverAdmin)
Siobhan Tullybf1153a2013-05-27 20:53:48 -04001533 admin.site.register(Image, ImageAdmin)
Scott Baker2c3cb642014-05-19 17:55:56 -07001534 admin.site.register(DashboardView, DashboardViewAdmin)
Scott Baker37b47902014-09-02 14:37:41 -07001535 admin.site.register(Flavor, FlavorAdmin)
Tony Mack7130ac32013-03-22 21:58:00 -04001536