blob: 4c4a80ce504450490f815297b9c09cbf6e9a52fb [file] [log] [blame]
Matteo Scandoloede125b2017-08-08 13:05:25 -07001
2# Copyright 2017-present Open Networking Foundation
3#
4# Licensed under the Apache License, Version 2.0 (the "License");
5# you may not use this file except in compliance with the License.
6# You may obtain a copy of the License at
7#
8# http://www.apache.org/licenses/LICENSE-2.0
9#
10# Unless required by applicable law or agreed to in writing, software
11# distributed under the License is distributed on an "AS IS" BASIS,
12# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13# See the License for the specific language governing permissions and
14# limitations under the License.
15
16
Scott Baker25467ff2016-08-04 09:50:22 -070017from django.contrib import admin
18
19from django import forms
20from services.hpc.models import HpcService
21from core.admin import ServiceAppAdmin,SliceInline,ServiceAttrAsTabInline, ReadOnlyAwareAdmin, XOSTabularInline, SliderWidget, ServicePrivilegeInline
22from core.middleware import get_request
23
24from functools import update_wrapper
25from django.contrib.admin.views.main import ChangeList
26from django.core.urlresolvers import reverse, NoReverseMatch
27from django.contrib.admin.utils import quote
28
29import threading
30_thread_locals = threading.local()
31
32class FilteredChangeList(ChangeList):
33 """ A special ChangeList with a doctored url_for_result function that
34 points to the filteredchange view instead of the default change
35 view.
36 """
37
38 def __init__(self, request, *args, **kwargs):
39 self.service = getattr(request, "hpcService", None)
40 self.embedded = getattr(request, "embedded", False)
41 super(FilteredChangeList, self).__init__(request, *args, **kwargs)
42
43 def url_for_result(self, result):
44 if (self.service is None):
45 return super(FilteredChangeList, self).url_for_result(result)
46
47 pk = getattr(result, self.pk_attname)
48 if self.embedded:
49 return reverse('admin:%s_%s_embeddedfilteredchange' % (self.opts.app_label,
50 self.opts.model_name),
51 args=(quote(self.service.id), quote(pk),),
52 current_app=self.model_admin.admin_site.name)
53
54 else:
55 return reverse('admin:%s_%s_filteredchange' % (self.opts.app_label,
56 self.opts.model_name),
57 args=(quote(self.service.id), quote(pk),),
58 current_app=self.model_admin.admin_site.name)
59
60class FilteredAdmin(ReadOnlyAwareAdmin):
61 """
62 One approach to filtering the HPC Admin views by HPCService. Encode
63 the HPCService into the URL for the changelist view. Then we could do our
64 custom filtering in self.filtered_changelist_view.
65
66 To make this work, a few changes needed to be made to the change and
67 change_list templates.
68
69 1) "custom_changelist_breadcrumb_url" is used to replace the breadcrumb
70 in change and add views with one that will point back to the filtered
71 list.
72
73 2) "custom_add_url" is used to replace the Add button's URL with one
74 that points to the filtered add view.
75
76 TODO: Save & Add Another,
77 the add link when the changelist is empty
78 """
79
80 @property
81 def change_list_template(self):
82 return _thread_locals.change_list_template
83
84 @property
85 def change_form_template(self):
86 return _thread_locals.change_form_template
87
88 def get_urls(self):
89 from django.conf.urls import patterns, url
90
91 def wrap(view):
92 def wrapper(*args, **kwargs):
93 return self.admin_site.admin_view(view)(*args, **kwargs)
94 return update_wrapper(wrapper, view)
95
96 urls = super(FilteredAdmin, self).get_urls()
97 info = self.model._meta.app_label, self.model._meta.model_name
98 my_urls = [
99 url(r'^(.+)/filteredlist/$', wrap(self.filtered_changelist_view), name="%s_%s_filteredchangelist" % info),
100 url(r'^(.+)/embeddedfilteredlist/$', wrap(self.embedded_filtered_changelist_view), name="%s_%s_embeddedfilteredchangelist" % info),
101 url(r'^(.+)/(.+)/filteredchange$', wrap(self.filtered_change_view), name='%s_%s_filteredchange' % info),
102 url(r'^(.+)/(.+)/embeddedfilteredchange$', wrap(self.embedded_filtered_change_view), name='%s_%s_embeddedfilteredchange' % info),
103 url(r'^(.+)/filteredadd/$', wrap(self.filtered_add_view), name='%s_%s_filteredadd' % info),
104 url(r'^(.+)/embeddedfilteredadd/$', wrap(self.embedded_filtered_add_view), name='%s_%s_embeddedfilteredadd' % info),
105 ]
106 return my_urls + urls
107
108 def add_extra_context(self, request, extra_context):
109 super(FilteredAdmin, self).add_extra_context(request, extra_context)
110
111 if getattr(request,"hpcService",None) is not None:
112 extra_context["custom_changelist_breadcrumb_url"] = "/admin/hpc/%s/%s/filteredlist/" % (self.model._meta.model_name, str(request.hpcService.id))
113 if getattr(request,"embedded",False):
114 extra_context["custom_add_url"] = "/admin/hpc/%s/%s/embeddedfilteredadd/" % (self.model._meta.model_name, str(request.hpcService.id))
115 else:
116 extra_context["custom_add_url"] = "/admin/hpc/%s/%s/filteredadd/" % (self.model._meta.model_name, str(request.hpcService.id))
117 if len(request.resolver_match.args)>1:
118 # this is only useful on change views, not changelist views
119 extra_context["custom_delete_url"] = "/admin/hpc/%s/%s/delete/" % (self.model._meta.model_name, request.resolver_match.args[1])
120
121 extra_context["show_save"] = False
122 extra_context["show_save_and_add_another"] = False
123
124 def changelist_view(self, *args, **kwargs):
125 if "template" in kwargs:
126 _thread_locals.change_list_template = kwargs["template"]
127 del kwargs["template"]
128 else:
129 _thread_locals.change_list_template = "admin/change_list_bc.html"
130 return super(FilteredAdmin, self).changelist_view(*args, **kwargs)
131
132 def filtered_changelist_view(self, request, hpcServiceId, extra_context=None):
133 request.hpcService = HpcService.objects.get(id=hpcServiceId)
134 return self.changelist_view(request, extra_context=extra_context)
135
136 def embedded_filtered_changelist_view(self, request, hpcServiceId, extra_context=None):
137 request.hpcService = HpcService.objects.get(id=hpcServiceId)
138 request.embedded = True
139 return self.changelist_view(request, template="admin/change_list_embedded.html", extra_context=extra_context)
140
141 def change_view(self, *args, **kwargs):
142 if "template" in kwargs:
143 _thread_locals.change_form_template = kwargs["template"]
144 del kwargs["template"]
145 else:
146 _thread_locals.change_form_template = "admin/change_form_bc.html"
147 return super(FilteredAdmin, self).change_view(*args, **kwargs)
148
149 def filtered_change_view(self, request, hpcServiceId, object_id, extra_context=None):
150 request.hpcService = HpcService.objects.get(id=hpcServiceId)
151 return self.change_view(request, object_id, extra_context=extra_context)
152
153 def embedded_filtered_change_view(self, request, hpcServiceId, object_id, extra_context=None):
154 request.hpcService = HpcService.objects.get(id=hpcServiceId)
155 request.embedded = True
156 return self.change_view(request, object_id, template="admin/change_form_embedded.html", extra_context=extra_context)
157
158 def add_view(self, *args, **kwargs):
159 if "template" in kwargs:
160 _thread_locals.change_form_template = kwargs["template"]
161 del kwargs["template"]
162 else:
163 _thread_locals.change_form_template = "admin/change_form_bc.html"
164 return super(FilteredAdmin, self).add_view(*args, **kwargs)
165
166 def filtered_add_view(self, request, hpcServiceId, extra_context=None):
167 request.hpcService = HpcService.objects.get(id=hpcServiceId)
168 return self.add_view(request, extra_context=extra_context)
169
170 def embedded_filtered_add_view(self, request, hpcServiceId, extra_context=None):
171 request.hpcService = HpcService.objects.get(id=hpcServiceId)
172 request.embedded = True
173 return self.add_view(request, template="admin/change_form_embedded.html", extra_context=extra_context)
174
175 def get_queryset(self, request):
176 # request.hpcService will be set in filtered_changelist_view so we can
177 # use it to filter what will be displayed in the list.
178 qs = self.model.objects.all()
179 if (getattr(request,"hpcService",None) is not None) and (hasattr(self.model, "filter_by_hpcService")):
180 qs = self.model.filter_by_hpcService(qs, request.hpcService)
181 return qs
182
183 def get_changelist(self, request, **kwargs):
184 # We implement a custom ChangeList, so the URLs point to the
185 # filtered_change_view rather than the default change_view.
186 return FilteredChangeList
187
188class FilteredInline(XOSTabularInline):
189 def get_change_url(self, id):
190 request = get_request()
191 embedded = getattr(request, "embedded", False)
192 service_id = request.resolver_match.args[0]
193
194 if embedded:
195 reverse_path = "admin:%s_embeddedfilteredchange" % (self.selflink_model._meta.db_table)
196 args = (service_id, id)
197 else:
198 reverse_path = "admin:%s_filteredchange" % (self.selflink_model._meta.db_table)
199 args = (service_id, id)
200
201 try:
202 url = reverse(reverse_path, args=args, current_app=self.selflink_model._meta.app_label)
203 except NoReverseMatch:
204 return None
205
206 return url
207