summaryrefslogtreecommitdiffstats
path: root/bitbake
diff options
context:
space:
mode:
authorAlexandru DAMIAN <alexandru.damian@intel.com>2015-06-02 12:23:12 +0100
committerRichard Purdie <richard.purdie@linuxfoundation.org>2015-06-12 00:01:47 +0100
commit751e9182ac7f37506c3d85cade00ef6f3986eb7a (patch)
treef668ca76c534a09b5e3fc43b3bb7b67eb0c7416b /bitbake
parentafe06e313eac61f598f65e622ceb5951a9fabc9a (diff)
downloadpoky-751e9182ac7f37506c3d85cade00ef6f3986eb7a.tar.gz
bitbake: convert all project-based view to JSON APIs
This patch converts all-project views that are REST-style URLs to support JSON encoding if the "format=json" parameter is supplied. The formatting code is enhanced to prevent following Django foreign keys, to convert enum-values from int to string, and support for timedelta. (Bitbake rev: 7a6eb36b82c5f2e342777e479d9c401ded42453d) Signed-off-by: Alexandru DAMIAN <alexandru.damian@intel.com> Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
Diffstat (limited to 'bitbake')
-rwxr-xr-xbitbake/lib/toaster/toastergui/views.py164
1 files changed, 99 insertions, 65 deletions
diff --git a/bitbake/lib/toaster/toastergui/views.py b/bitbake/lib/toaster/toastergui/views.py
index d4a9b4ca0d..f2626f8521 100755
--- a/bitbake/lib/toaster/toastergui/views.py
+++ b/bitbake/lib/toaster/toastergui/views.py
@@ -87,6 +87,55 @@ def _project_recent_build_list(prj):
87 list(prj.buildrequest_set.filter(state__in=[BuildRequest.REQ_COMPLETED, BuildRequest.REQ_FAILED]).order_by("-pk")[:3])) 87 list(prj.buildrequest_set.filter(state__in=[BuildRequest.REQ_COMPLETED, BuildRequest.REQ_FAILED]).order_by("-pk")[:3]))
88 88
89 89
90def _template_renderer(template):
91 def func_wrapper(view):
92 def returned_wrapper(request, *args, **kwargs):
93 try:
94 context = view(request, *args, **kwargs)
95 except RedirectException as e:
96 return e.get_redirect_response()
97
98 if request.GET.get('format', None) == 'json':
99 # objects is a special keyword - it's a Page, but we need the actual objects here
100 # in XHR, the objects come in the "list" property
101 if "objects" in context:
102 context["list"] = context["objects"].object_list
103 del context["objects"]
104
105 # we're about to return; to keep up with the XHR API, we set the error to OK
106 context["error"] = "ok"
107 def _objtojson(obj):
108 from django.db.models.query import QuerySet
109 from django.db.models import Model, IntegerField
110 if isinstance(obj, datetime):
111 return obj.isoformat()
112 elif isinstance(obj, timedelta):
113 return obj.total_seconds()
114 elif isinstance(obj, QuerySet) or isinstance(obj, set):
115 return list(obj)
116 elif hasattr( obj, '__dict__'):
117 d = obj.__dict__
118 nd = dict(d)
119 for di in d:
120 if di.startswith("_"):
121 del nd[di]
122 elif isinstance(d[di], Model):
123 nd[di] = d[di].pk
124 elif isinstance(d[di], int) and hasattr(obj, "get_%s_display" % di):
125 nd[di] = getattr(obj, "get_%s_display" % di)()
126 return nd
127 else:
128 raise TypeError("Unserializable object %s of type %s" % ( obj, type(obj)))
129
130 return HttpResponse(jsonfilter(context, default=_objtojson ),
131 content_type = "application/json; charset=utf-8")
132 else:
133 return render(request, template, context)
134 return returned_wrapper
135 return func_wrapper
136
137
138
90def _build_page_range(paginator, index = 1): 139def _build_page_range(paginator, index = 1):
91 try: 140 try:
92 page = paginator.page(index) 141 page = paginator.page(index)
@@ -129,7 +178,7 @@ def _redirect_parameters(view, g, mandatory_parameters, *args, **kwargs):
129 if not i in params: 178 if not i in params:
130 params[i] = urllib.unquote(str(mandatory_parameters[i])) 179 params[i] = urllib.unquote(str(mandatory_parameters[i]))
131 180
132 return redirect(url + "?%s" % urllib.urlencode(params), permanent = False, *args, **kwargs) 181 return redirect(url + "?%s" % urllib.urlencode(params), permanent = False, **kwargs)
133 182
134class RedirectException(Exception): 183class RedirectException(Exception):
135 def __init__(self, view, g, mandatory_parameters, *args, **kwargs): 184 def __init__(self, view, g, mandatory_parameters, *args, **kwargs):
@@ -141,7 +190,7 @@ class RedirectException(Exception):
141 self.okwargs = kwargs 190 self.okwargs = kwargs
142 191
143 def get_redirect_response(self): 192 def get_redirect_response(self):
144 return _redirect_parameters(self.view, self.g, self.mandatory_parameters, self.oargs, self.okwargs) 193 return _redirect_parameters(self.view, self.g, self.mandatory_parameters, self.oargs, **self.okwargs)
145 194
146FIELD_SEPARATOR = ":" 195FIELD_SEPARATOR = ":"
147AND_VALUE_SEPARATOR = "!" 196AND_VALUE_SEPARATOR = "!"
@@ -1839,8 +1888,8 @@ if toastermain.settings.MANAGED:
1839 1888
1840 1889
1841 # shows the "all builds" page for managed mode; it displays build requests (at least started!) instead of actual builds 1890 # shows the "all builds" page for managed mode; it displays build requests (at least started!) instead of actual builds
1891 @_template_renderer("managed_builds.html")
1842 def builds(request): 1892 def builds(request):
1843 template = 'managed_builds.html'
1844 # define here what parameters the view needs in the GET portion in order to 1893 # define here what parameters the view needs in the GET portion in order to
1845 # be able to display something. 'count' and 'page' are mandatory for all views 1894 # be able to display something. 'count' and 'page' are mandatory for all views
1846 # that use paginators. 1895 # that use paginators.
@@ -1850,12 +1899,10 @@ if toastermain.settings.MANAGED:
1850 try: 1899 try:
1851 context, pagesize, orderby = _build_list_helper(request, buildrequests, True) 1900 context, pagesize, orderby = _build_list_helper(request, buildrequests, True)
1852 except InvalidRequestException as e: 1901 except InvalidRequestException as e:
1853 return _redirect_parameters( builds, request.GET, e.response) 1902 raise RedirectException( builds, request.GET, e.response)
1854 1903
1855 response = render(request, template, context)
1856 _set_parameters_values(pagesize, orderby, request) 1904 _set_parameters_values(pagesize, orderby, request)
1857 return response 1905 return context
1858
1859 1906
1860 1907
1861 # helper function, to be used on "all builds" and "project builds" pages 1908 # helper function, to be used on "all builds" and "project builds" pages
@@ -2151,8 +2198,8 @@ if toastermain.settings.MANAGED:
2151 2198
2152 2199
2153 # Shows the edit project page 2200 # Shows the edit project page
2201 @_template_renderer('project.html')
2154 def project(request, pid): 2202 def project(request, pid):
2155 template = "project.html"
2156 try: 2203 try:
2157 prj = Project.objects.get(id = pid) 2204 prj = Project.objects.get(id = pid)
2158 except Project.DoesNotExist: 2205 except Project.DoesNotExist:
@@ -2207,10 +2254,7 @@ if toastermain.settings.MANAGED:
2207 except ProjectVariable.DoesNotExist: 2254 except ProjectVariable.DoesNotExist:
2208 context["distro"] = "-- not set yet" 2255 context["distro"] = "-- not set yet"
2209 2256
2210 response = render(request, template, context) 2257 return context
2211 response['Cache-Control'] = "no-cache, must-revalidate, no-store"
2212 response['Pragma'] = "no-cache"
2213 return response
2214 2258
2215 2259
2216 def xhr_projectbuild(request, pid): 2260 def xhr_projectbuild(request, pid):
@@ -2680,8 +2724,8 @@ if toastermain.settings.MANAGED:
2680 2724
2681 return(vars_managed,sorted(vars_fstypes),vars_blacklist) 2725 return(vars_managed,sorted(vars_fstypes),vars_blacklist)
2682 2726
2727 @_template_renderer("projectconf.html")
2683 def projectconf(request, pid): 2728 def projectconf(request, pid):
2684 template = "projectconf.html"
2685 2729
2686 try: 2730 try:
2687 prj = Project.objects.get(id = pid) 2731 prj = Project.objects.get(id = pid)
@@ -2730,21 +2774,20 @@ if toastermain.settings.MANAGED:
2730 except ProjectVariable.DoesNotExist: 2774 except ProjectVariable.DoesNotExist:
2731 pass 2775 pass
2732 2776
2733 return render(request, template, context) 2777 return context
2734 2778
2779 @_template_renderer('projectbuilds.html')
2735 def projectbuilds(request, pid): 2780 def projectbuilds(request, pid):
2736 template = 'projectbuilds.html'
2737 buildrequests = BuildRequest.objects.filter(project_id = pid).exclude(state__lte = BuildRequest.REQ_INPROGRESS).exclude(state=BuildRequest.REQ_DELETED) 2781 buildrequests = BuildRequest.objects.filter(project_id = pid).exclude(state__lte = BuildRequest.REQ_INPROGRESS).exclude(state=BuildRequest.REQ_DELETED)
2738 2782
2739 try: 2783 try:
2740 context, pagesize, orderby = _build_list_helper(request, buildrequests, False) 2784 context, pagesize, orderby = _build_list_helper(request, buildrequests, False)
2741 except InvalidRequestException as e: 2785 except InvalidRequestException as e:
2742 return _redirect_parameters(projectbuilds, request.GET, e.response, pid = pid) 2786 raise RedirectException('projectbuilds', request.GET, e.response, pid = pid)
2743 2787
2744 response = render(request, template, context)
2745 _set_parameters_values(pagesize, orderby, request) 2788 _set_parameters_values(pagesize, orderby, request)
2746 2789
2747 return response 2790 return context
2748 2791
2749 2792
2750 def _file_name_for_artifact(b, artifact_type, artifact_id): 2793 def _file_name_for_artifact(b, artifact_type, artifact_id):
@@ -2861,32 +2904,8 @@ if toastermain.settings.MANAGED:
2861 return build_mru 2904 return build_mru
2862 2905
2863 2906
2864 def template_renderer(template):
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
2888 2907
2889 @template_renderer("projects.html") 2908 @_template_renderer("projects.html")
2890 def projects(request): 2909 def projects(request):
2891 (pagesize, orderby) = _get_parameters_values(request, 10, 'updated:-') 2910 (pagesize, orderby) = _get_parameters_values(request, 10, 'updated:-')
2892 mandatory_parameters = { 'count': pagesize, 'page' : 1, 'orderby' : orderby } 2911 mandatory_parameters = { 'count': pagesize, 'page' : 1, 'orderby' : orderby }
@@ -2995,18 +3014,19 @@ if toastermain.settings.MANAGED:
2995 _set_parameters_values(pagesize, orderby, request) 3014 _set_parameters_values(pagesize, orderby, request)
2996 return context 3015 return context
2997 3016
3017 @_template_renderer("buildrequestdetails.html")
2998 def buildrequestdetails(request, pid, brid): 3018 def buildrequestdetails(request, pid, brid):
2999 template = "buildrequestdetails.html"
3000 context = { 3019 context = {
3001 'buildrequest' : BuildRequest.objects.get(pk = brid, project_id = pid) 3020 'buildrequest' : BuildRequest.objects.get(pk = brid, project_id = pid)
3002 } 3021 }
3003 return render(request, template, context) 3022 return context
3004 3023
3005 3024
3006else: 3025else:
3007 # shows the "all builds" page for interactive mode; this is the old code, simply moved 3026 # shows the "all builds" page for interactive mode; this is the old code, simply moved
3027
3028 @_template_renderer('build.html')
3008 def builds(request): 3029 def builds(request):
3009 template = 'build.html'
3010 # define here what parameters the view needs in the GET portion in order to 3030 # define here what parameters the view needs in the GET portion in order to
3011 # be able to display something. 'count' and 'page' are mandatory for all views 3031 # be able to display something. 'count' and 'page' are mandatory for all views
3012 # that use paginators. 3032 # that use paginators.
@@ -3014,7 +3034,7 @@ else:
3014 mandatory_parameters = { 'count': pagesize, 'page' : 1, 'orderby' : orderby } 3034 mandatory_parameters = { 'count': pagesize, 'page' : 1, 'orderby' : orderby }
3015 retval = _verify_parameters( request.GET, mandatory_parameters ) 3035 retval = _verify_parameters( request.GET, mandatory_parameters )
3016 if retval: 3036 if retval:
3017 return _redirect_parameters( 'all-builds', request.GET, mandatory_parameters) 3037 raise RedirectException( 'all-builds', request.GET, mandatory_parameters)
3018 3038
3019 # boilerplate code that takes a request for an object type and returns a queryset 3039 # boilerplate code that takes a request for an object type and returns a queryset
3020 # for that object type. copypasta for all needed table searches 3040 # for that object type. copypasta for all needed table searches
@@ -3194,55 +3214,69 @@ else:
3194 3214
3195 # merge daterange values 3215 # merge daterange values
3196 context.update(context_date) 3216 context.update(context_date)
3197
3198 response = render(request, template, context)
3199 _set_parameters_values(pagesize, orderby, request) 3217 _set_parameters_values(pagesize, orderby, request)
3200 return response 3218
3219 return context
3201 3220
3202 3221
3203 3222
3204 3223
3224 @_template_renderer('landing_not_managed.html')
3205 def newproject(request): 3225 def newproject(request):
3206 return render(request, 'landing_not_managed.html') 3226 return {}
3207 3227
3228 @_template_renderer('landing_not_managed.html')
3208 def project(request, pid): 3229 def project(request, pid):
3209 return render(request, 'landing_not_managed.html') 3230 return {}
3210 3231
3232 @_template_renderer('landing_not_managed.html')
3211 def xhr_projectbuild(request, pid): 3233 def xhr_projectbuild(request, pid):
3212 return render(request, 'landing_not_managed.html') 3234 return {}
3213 3235
3236 @_template_renderer('landing_not_managed.html')
3214 def xhr_projectinfo(request): 3237 def xhr_projectinfo(request):
3215 return render(request, 'landing_not_managed.html') 3238 return {}
3216 3239
3240 @_template_renderer('landing_not_managed.html')
3217 def xhr_projectedit(request, pid): 3241 def xhr_projectedit(request, pid):
3218 return render(request, 'landing_not_managed.html') 3242 return {}
3219 3243
3244 @_template_renderer('landing_not_managed.html')
3220 def xhr_datatypeahead(request): 3245 def xhr_datatypeahead(request):
3221 return render(request, 'landing_not_managed.html') 3246 return {}
3222 3247
3248 @_template_renderer('landing_not_managed.html')
3223 def xhr_configvaredit(request, pid): 3249 def xhr_configvaredit(request, pid):
3224 return render(request, 'landing_not_managed.html') 3250 return {}
3225 3251
3252 @_template_renderer('landing_not_managed.html')
3226 def importlayer(request): 3253 def importlayer(request):
3227 return render(request, 'landing_not_managed.html') 3254 return {}
3228 3255
3256 @_template_renderer('landing_not_managed.html')
3229 def projectconf(request, pid): 3257 def projectconf(request, pid):
3230 return render(request, 'landing_not_managed.html') 3258 return {}
3231 3259
3260 @_template_renderer('landing_not_managed.html')
3232 def projectbuilds(request, pid): 3261 def projectbuilds(request, pid):
3233 return render(request, 'landing_not_managed.html') 3262 return {}
3234 3263
3264 @_template_renderer('landing_not_managed.html')
3235 def build_artifact(request, build_id, artifact_type, artifact_id): 3265 def build_artifact(request, build_id, artifact_type, artifact_id):
3236 return render(request, 'landing_not_managed.html') 3266 return {}
3237 3267
3268 @_template_renderer('landing_not_managed.html')
3238 def projects(request): 3269 def projects(request):
3239 return render(request, 'landing_not_managed.html') 3270 return {}
3240 3271
3272 @_template_renderer('landing_not_managed.html')
3241 def xhr_importlayer(request): 3273 def xhr_importlayer(request):
3242 return render(request, 'landing_not_managed.html') 3274 return {}
3243 3275
3276 @_template_renderer('landing_not_managed.html')
3244 def xhr_updatelayer(request): 3277 def xhr_updatelayer(request):
3245 return render(request, 'landing_not_managed.html') 3278 return {}
3246 3279
3280 @_template_renderer('landing_not_managed.html')
3247 def buildrequestdetails(request, pid, brid): 3281 def buildrequestdetails(request, pid, brid):
3248 return render(request, 'landing_not_managed.html') 3282 return {}