summaryrefslogtreecommitdiffstats
path: root/bitbake/lib/toaster/toastergui/views.py
diff options
context:
space:
mode:
authorAlexandru DAMIAN <alexandru.damian@intel.com>2015-05-19 16:14:29 +0100
committerRichard Purdie <richard.purdie@linuxfoundation.org>2015-06-12 00:01:47 +0100
commitafe06e313eac61f598f65e622ceb5951a9fabc9a (patch)
tree02e37805b7b10a30c77fc3c82987bf435b221423 /bitbake/lib/toaster/toastergui/views.py
parent94aa0d5408f71a2e9fd48fd2c0e283acfc9ac2a2 (diff)
downloadpoky-afe06e313eac61f598f65e622ceb5951a9fabc9a.tar.gz
bitbake: toaster: move project data typeahead to the REST API
This patch enables JSON requests on the project REST endpoint, and replaces the universal queries "xhr_datatypeahead" with the `project` type to the REST project endpoint. The patch adds a decorator that takes a context returned by a view and either renders the template specified as the decorator argument, or converts the context to JSON. Normal "search", "filter" and "order" options for view work as normal on the JSON API format. To enable the JSON return, set the "format" GET parameter to "json". In order to demonstrate the functionality, the "New build" button is switched from using the xhr_datatypeahead to the project REST API with JSON formatting. Additionally, the XHR APIs that perform actions with the project id passed as parameter are removed, and the needed URLs are populated from the project JSON API returns after the project has been selected. (Bitbake rev: 15a2274eba13d19b864f337057d61c75ff7849cc) Signed-off-by: Alexandru DAMIAN <alexandru.damian@intel.com> Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
Diffstat (limited to 'bitbake/lib/toaster/toastergui/views.py')
-rwxr-xr-xbitbake/lib/toaster/toastergui/views.py89
1 files changed, 56 insertions, 33 deletions
diff --git a/bitbake/lib/toaster/toastergui/views.py b/bitbake/lib/toaster/toastergui/views.py
index 0e248a7435..d4a9b4ca0d 100755
--- a/bitbake/lib/toaster/toastergui/views.py
+++ b/bitbake/lib/toaster/toastergui/views.py
@@ -129,7 +129,19 @@ def _redirect_parameters(view, g, mandatory_parameters, *args, **kwargs):
129 if not i in params: 129 if not i in params:
130 params[i] = urllib.unquote(str(mandatory_parameters[i])) 130 params[i] = urllib.unquote(str(mandatory_parameters[i]))
131 131
132 return redirect(url + "?%s" % urllib.urlencode(params), *args, **kwargs) 132 return redirect(url + "?%s" % urllib.urlencode(params), permanent = False, *args, **kwargs)
133
134class RedirectException(Exception):
135 def __init__(self, view, g, mandatory_parameters, *args, **kwargs):
136 super(RedirectException, self).__init__()
137 self.view = view
138 self.g = g
139 self.mandatory_parameters = mandatory_parameters
140 self.oargs = args
141 self.okwargs = kwargs
142
143 def get_redirect_response(self):
144 return _redirect_parameters(self.view, self.g, self.mandatory_parameters, self.oargs, self.okwargs)
133 145
134FIELD_SEPARATOR = ":" 146FIELD_SEPARATOR = ":"
135AND_VALUE_SEPARATOR = "!" 147AND_VALUE_SEPARATOR = "!"
@@ -2200,14 +2212,6 @@ if toastermain.settings.MANAGED:
2200 response['Pragma'] = "no-cache" 2212 response['Pragma'] = "no-cache"
2201 return response 2213 return response
2202 2214
2203 # This is a wrapper for xhr_projectbuild which allows for a project id
2204 # which only becomes known client side.
2205 def xhr_build(request):
2206 if request.POST.has_key("project_id"):
2207 pid = request.POST['project_id']
2208 return xhr_projectbuild(request, pid)
2209 else:
2210 raise BadParameterException("invalid project id")
2211 2215
2212 def xhr_projectbuild(request, pid): 2216 def xhr_projectbuild(request, pid):
2213 try: 2217 try:
@@ -2333,7 +2337,7 @@ if toastermain.settings.MANAGED:
2333 # returns layers for current project release that are not in the project set, matching the name 2337 # returns layers for current project release that are not in the project set, matching the name
2334 if request.GET['type'] == "layers": 2338 if request.GET['type'] == "layers":
2335 # all layers for the current project 2339 # all layers for the current project
2336 queryset_all = prj.compatible_layerversions().filter(layer__name__icontains=request.GET.get('value','')) 2340 queryset_all = prj.compatible_layerversions().filter(layer__name__icontains=request.GET.get('search',''))
2337 2341
2338 # but not layers with equivalent layers already in project 2342 # but not layers with equivalent layers already in project
2339 if not request.GET.has_key('include_added'): 2343 if not request.GET.has_key('include_added'):
@@ -2348,7 +2352,7 @@ if toastermain.settings.MANAGED:
2348 # returns layer dependencies for a layer, excluding current project layers 2352 # returns layer dependencies for a layer, excluding current project layers
2349 if request.GET['type'] == "layerdeps": 2353 if request.GET['type'] == "layerdeps":
2350 queryset = prj.compatible_layerversions().exclude(pk__in = [x.id for x in prj.projectlayer_equivalent_set()]).filter( 2354 queryset = prj.compatible_layerversions().exclude(pk__in = [x.id for x in prj.projectlayer_equivalent_set()]).filter(
2351 layer__name__in = [ x.depends_on.layer.name for x in LayerVersionDependency.objects.filter(layer_version_id = request.GET['value'])]) 2355 layer__name__in = [ x.depends_on.layer.name for x in LayerVersionDependency.objects.filter(layer_version_id = request.GET['search'])])
2352 2356
2353 final_list = set([x.get_equivalents_wpriority(prj)[0] for x in queryset]) 2357 final_list = set([x.get_equivalents_wpriority(prj)[0] for x in queryset])
2354 2358
@@ -2361,7 +2365,7 @@ if toastermain.settings.MANAGED:
2361 2365
2362 retval = [] 2366 retval = []
2363 for i in prj.projectlayer_set.all(): 2367 for i in prj.projectlayer_set.all():
2364 lv = prj.compatible_layerversions(release = Release.objects.get(pk=request.GET['value'])).filter(layer__name = i.layercommit.layer.name) 2368 lv = prj.compatible_layerversions(release = Release.objects.get(pk=request.GET['search'])).filter(layer__name = i.layercommit.layer.name)
2365 # there is no layer_version with the new release id, and the same name 2369 # there is no layer_version with the new release id, and the same name
2366 if lv.count() < 1: 2370 if lv.count() < 1:
2367 retval.append(i) 2371 retval.append(i)
@@ -2374,10 +2378,10 @@ if toastermain.settings.MANAGED:
2374 # returns layer versions that provide the named targets 2378 # returns layer versions that provide the named targets
2375 if request.GET['type'] == "layers4target": 2379 if request.GET['type'] == "layers4target":
2376 # we return data only if the recipe can't be provided by the current project layer set 2380 # we return data only if the recipe can't be provided by the current project layer set
2377 if reduce(lambda x, y: x + y, [x.recipe_layer_version.filter(name=request.GET['value']).count() for x in prj.projectlayer_equivalent_set()], 0): 2381 if reduce(lambda x, y: x + y, [x.recipe_layer_version.filter(name=request.GET['search']).count() for x in prj.projectlayer_equivalent_set()], 0):
2378 final_list = [] 2382 final_list = []
2379 else: 2383 else:
2380 queryset_all = prj.compatible_layerversions().filter(recipe_layer_version__name = request.GET['value']) 2384 queryset_all = prj.compatible_layerversions().filter(recipe_layer_version__name = request.GET['search'])
2381 2385
2382 # exclude layers in the project 2386 # exclude layers in the project
2383 queryset_all = queryset_all.exclude(pk__in = [x.id for x in prj.projectlayer_equivalent_set()]) 2387 queryset_all = queryset_all.exclude(pk__in = [x.id for x in prj.projectlayer_equivalent_set()])
@@ -2389,7 +2393,7 @@ if toastermain.settings.MANAGED:
2389 2393
2390 # returns targets provided by current project layers 2394 # returns targets provided by current project layers
2391 if request.GET['type'] == "targets": 2395 if request.GET['type'] == "targets":
2392 search_token = request.GET.get('value','') 2396 search_token = request.GET.get('search','')
2393 queryset_all = Recipe.objects.filter(layer_version__layer__name__in = [x.layercommit.layer.name for x in prj.projectlayer_set.all().select_related("layercommit__layer")]).filter(Q(name__icontains=search_token) | Q(layer_version__layer__name__icontains=search_token)) 2397 queryset_all = Recipe.objects.filter(layer_version__layer__name__in = [x.layercommit.layer.name for x in prj.projectlayer_set.all().select_related("layercommit__layer")]).filter(Q(name__icontains=search_token) | Q(layer_version__layer__name__icontains=search_token))
2394 2398
2395# layer_equivalent_set = [] 2399# layer_equivalent_set = []
@@ -2420,7 +2424,7 @@ if toastermain.settings.MANAGED:
2420 if 'project_id' in request.session: 2424 if 'project_id' in request.session:
2421 queryset_all = queryset_all.filter(layer_version__in = prj.projectlayer_equivalent_set()).order_by("name") 2425 queryset_all = queryset_all.filter(layer_version__in = prj.projectlayer_equivalent_set()).order_by("name")
2422 2426
2423 search_token = request.GET.get('value','') 2427 search_token = request.GET.get('search','')
2424 queryset_all = queryset_all.filter(Q(name__icontains=search_token) | Q(description__icontains=search_token)) 2428 queryset_all = queryset_all.filter(Q(name__icontains=search_token) | Q(description__icontains=search_token))
2425 2429
2426 return HttpResponse(jsonfilter({ "error":"ok", 2430 return HttpResponse(jsonfilter({ "error":"ok",
@@ -2432,15 +2436,6 @@ if toastermain.settings.MANAGED:
2432 ) 2436 )
2433 }), content_type = "application/json") 2437 }), content_type = "application/json")
2434 2438
2435 # returns all projects
2436 if request.GET['type'] == "projects":
2437 queryset_all = Project.objects.all()
2438 ret = { "error": "ok",
2439 "list": map (lambda x: {"id":x.pk, "name": x.name},
2440 queryset_all.filter(name__icontains=request.GET.get('value',''))[:8])}
2441
2442 return HttpResponse(jsonfilter(ret), content_type = "application/json")
2443
2444 raise Exception("Unknown request! " + request.GET.get('type', "No parameter supplied")) 2439 raise Exception("Unknown request! " + request.GET.get('type', "No parameter supplied"))
2445 except Exception as e: 2440 except Exception as e:
2446 return HttpResponse(jsonfilter({"error":str(e) + "\n" + traceback.format_exc()}), content_type = "application/json") 2441 return HttpResponse(jsonfilter({"error":str(e) + "\n" + traceback.format_exc()}), content_type = "application/json")
@@ -2866,14 +2861,38 @@ if toastermain.settings.MANAGED:
2866 return build_mru 2861 return build_mru
2867 2862
2868 2863
2869 def projects(request): 2864 def template_renderer(template):
2870 template="projects.html" 2865 def func_wrapper(view):
2866 def returned_wrapper(request, *args, **kwargs):
2867 try:
2868 context = view(request, *args, **kwargs)
2869 except RedirectException as e:
2870 return e.get_redirect_response()
2871
2872 if request.GET.get('format', None) == 'json':
2873 # objects is a special keyword - it's a Page, but we need the actual objects here
2874 # in XHR, the objects come in the "list" property
2875 if "objects" in context:
2876 context["list"] = context["objects"].object_list
2877 del context["objects"]
2878
2879 # we're about to return; to keep up with the XHR API, we set the error to OK
2880 context["error"] = "ok"
2881
2882 return HttpResponse(jsonfilter(context, default=lambda obj: obj.isoformat() if isinstance(obj, datetime) else obj.__dict__ ),
2883 content_type = "application/json; charset=utf-8")
2884 else:
2885 return render(request, template, context)
2886 return returned_wrapper
2887 return func_wrapper
2871 2888
2889 @template_renderer("projects.html")
2890 def projects(request):
2872 (pagesize, orderby) = _get_parameters_values(request, 10, 'updated:-') 2891 (pagesize, orderby) = _get_parameters_values(request, 10, 'updated:-')
2873 mandatory_parameters = { 'count': pagesize, 'page' : 1, 'orderby' : orderby } 2892 mandatory_parameters = { 'count': pagesize, 'page' : 1, 'orderby' : orderby }
2874 retval = _verify_parameters( request.GET, mandatory_parameters ) 2893 retval = _verify_parameters( request.GET, mandatory_parameters )
2875 if retval: 2894 if retval:
2876 return _redirect_parameters( 'all-projects', request.GET, mandatory_parameters) 2895 raise RedirectException( 'all-projects', request.GET, mandatory_parameters )
2877 2896
2878 queryset_all = Project.objects.all() 2897 queryset_all = Project.objects.all()
2879 2898
@@ -2886,6 +2905,14 @@ if toastermain.settings.MANAGED:
2886 # retrieve the objects that will be displayed in the table; projects a paginator and gets a page range to display 2905 # retrieve the objects that will be displayed in the table; projects a paginator and gets a page range to display
2887 project_info = _build_page_range(Paginator(queryset, pagesize), request.GET.get('page', 1)) 2906 project_info = _build_page_range(Paginator(queryset, pagesize), request.GET.get('page', 1))
2888 2907
2908 # add fields needed in JSON dumps for API call support
2909 for p in project_info.object_list:
2910 p.id = p.pk
2911 p.xhrProjectDataTypeaheadUrl = reverse('xhr_datatypeahead', args=(p.id,))
2912 p.projectPageUrl = reverse('project', args=(p.id,))
2913 p.xhrProjectEditUrl = reverse('xhr_projectedit', args=(p.id,))
2914 p.projectBuildUrl = reverse('xhr_projectbuild', args=(p.id,))
2915
2889 # build view-specific information; this is rendered specifically in the builds page, at the top of the page (i.e. Recent builds) 2916 # build view-specific information; this is rendered specifically in the builds page, at the top of the page (i.e. Recent builds)
2890 build_mru = _managed_get_latest_builds() 2917 build_mru = _managed_get_latest_builds()
2891 2918
@@ -2965,9 +2992,8 @@ if toastermain.settings.MANAGED:
2965 ] 2992 ]
2966 } 2993 }
2967 2994
2968 response = render(request, template, context)
2969 _set_parameters_values(pagesize, orderby, request) 2995 _set_parameters_values(pagesize, orderby, request)
2970 return response 2996 return context
2971 2997
2972 def buildrequestdetails(request, pid, brid): 2998 def buildrequestdetails(request, pid, brid):
2973 template = "buildrequestdetails.html" 2999 template = "buildrequestdetails.html"
@@ -3185,9 +3211,6 @@ else:
3185 def xhr_projectbuild(request, pid): 3211 def xhr_projectbuild(request, pid):
3186 return render(request, 'landing_not_managed.html') 3212 return render(request, 'landing_not_managed.html')
3187 3213
3188 def xhr_build(request):
3189 return render(request, 'landing_not_managed.html')
3190
3191 def xhr_projectinfo(request): 3214 def xhr_projectinfo(request):
3192 return render(request, 'landing_not_managed.html') 3215 return render(request, 'landing_not_managed.html')
3193 3216