Skip to content

Commit

Permalink
add Job HTML response (fixes #779)
Browse files Browse the repository at this point in the history
  • Loading branch information
fmigneault committed Jan 24, 2025
1 parent 5a4805e commit 58bacbc
Show file tree
Hide file tree
Showing 5 changed files with 215 additions and 9 deletions.
2 changes: 1 addition & 1 deletion CHANGES.rst
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ Changes

Changes:
--------
- No change.
- Add `Job` status `HTML` response (resolves `#779 <https://github.com/crim-ca/weaver/issues/779>`_).

Fixes:
------
Expand Down
38 changes: 35 additions & 3 deletions weaver/wps_restapi/jobs/jobs.py
Original file line number Diff line number Diff line change
Expand Up @@ -317,6 +317,16 @@ def trigger_job_execution(request):
return submit_job_dispatch_task(job, container=request, force_submit=True)


@sd.provider_jobs_service.get(
tags=[sd.TAG_JOBS, sd.TAG_STATUS, sd.TAG_PROVIDERS],
schema=sd.GetProviderJobEndpoint(),
accept=ContentType.TEXT_HTML,
renderer="weaver.wps_restapi:templates/responses/job_status.mako",
response_schemas=sd.derive_responses(
sd.get_provider_single_job_status_responses,
sd.GenericHTMLResponse(name="HTMLProviderJobStatus", description="Job status.")
),
)
@sd.provider_job_service.get(
tags=[sd.TAG_JOBS, sd.TAG_STATUS, sd.TAG_PROVIDERS],
schema=sd.GetProviderJobEndpoint(),
Expand All @@ -328,7 +338,17 @@ def trigger_job_execution(request):
response_schemas=sd.get_provider_single_job_status_responses,
)
@sd.process_job_service.get(
tags=[sd.TAG_PROCESSES, sd.TAG_JOBS, sd.TAG_STATUS],
tags=[sd.TAG_JOBS, sd.TAG_STATUS, sd.TAG_PROCESSES],
schema=sd.GetProcessJobEndpoint(),
accept=ContentType.TEXT_HTML,
renderer="weaver.wps_restapi:templates/responses/job_status.mako",
response_schemas=sd.derive_responses(
sd.get_single_job_status_responses,
sd.GenericHTMLResponse(name="HTMLProcessJobStatus", description="Job status.")
),
)
@sd.process_job_service.get(
tags=[sd.TAG_JOBS, sd.TAG_STATUS, sd.TAG_PROCESSES],
schema=sd.GetProcessJobEndpoint(),
accept=[ContentType.APP_JSON] + [
f"{ContentType.APP_JSON}; profile={profile}"
Expand All @@ -337,6 +357,16 @@ def trigger_job_execution(request):
renderer=OutputFormat.JSON,
response_schemas=sd.get_single_job_status_responses,
)
@sd.job_service.get(
tags=[sd.TAG_JOBS, sd.TAG_STATUS],
schema=sd.GetJobEndpoint(),
accept=ContentType.TEXT_HTML,
renderer="weaver.wps_restapi:templates/responses/job_status.mako",
response_schemas=sd.derive_responses(
sd.get_single_job_status_responses,
sd.GenericHTMLResponse(name="HTMLJobStatus", description="Job status.")
),
)
@sd.job_service.get(
tags=[sd.TAG_JOBS, sd.TAG_STATUS],
schema=sd.GetJobEndpoint(),
Expand All @@ -349,7 +379,7 @@ def trigger_job_execution(request):
)
@log_unhandled_exceptions(logger=LOGGER, message=sd.InternalServerErrorResponseSchema.description)
def get_job_status(request):
# type: (PyramidRequest) -> HTTPOk
# type: (PyramidRequest) -> AnyViewResponse
"""
Retrieve the status of a job.
"""
Expand All @@ -358,7 +388,9 @@ def get_job_status(request):
schema, headers = get_job_status_schema(request)
if schema == JobStatusSchema.OPENEO:
job_body["status"] = map_status(job_body["status"], StatusCompliant.OPENEO)
return HTTPOk(json=job_body, headers=headers)
if ContentType.APP_JSON in str(headers.get("Content-Type")):
return HTTPOk(json=job_body, headers=headers)
return Box(**job_body, job=job, box_intact_types=[Job])


@sd.provider_job_service.patch(
Expand Down
8 changes: 4 additions & 4 deletions weaver/wps_restapi/jobs/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -333,10 +333,8 @@ def get_job_status_schema(request):
def make_headers(resolved_schema):
# type: (JobStatusSchemaType) -> HeadersType
content_type = clean_media_type_format(content_accept.split(",")[0], strip_parameters=True)
# FIXME: support HTML or XML
# (allow transparently for browsers types since Accept did not raise earlier, and no other supported yet)
if content_type in ContentType.ANY_XML | {ContentType.TEXT_HTML}:
content_type = ContentType.APP_JSON
return {"Content-Type": content_type}
content_profile = f"{content_type}; profile={resolved_schema}"
content_headers = {"Content-Type": content_profile}
if resolved_schema == JobStatusSchema.OGC:
Expand All @@ -356,7 +354,9 @@ def make_headers(resolved_schema):
return schema, headers
ctype = get_header("Accept", request.headers)
if not ctype:
return JobStatusSchema.OGC, {}
schema = JobStatusSchema.OGC
headers = make_headers(schema)
return schema, headers
params = parse_kvp(ctype)
profile = params.get("profile")
if not profile:
Expand Down
163 changes: 163 additions & 0 deletions weaver/wps_restapi/templates/responses/job_status.mako
Original file line number Diff line number Diff line change
@@ -0,0 +1,163 @@
<%inherit file="weaver.wps_restapi:templates/responses/base.mako"/>
<%namespace name="util" file="weaver.wps_restapi:templates/responses/util.mako"/>

<%block name="breadcrumbs">
<li><a href="${weaver.wps_restapi_url}?f=html">Home</a></li>
<li><a href="${util.get_jobs_link(query='f=html')}">Jobs</a></li>
<li><a href="${util.get_job_link(job.id, query='f=html')}">Job [${job.id}]</a></li>
</%block>

<h2 id="job-status" class="page-title">
<a href="#job-status">Job Status</a>
</h2>

<div class="format-link">
(<a href="${util.get_job_link(job.id, query='f=json')}">JSON</a>)
</div>

<div class="job-status">

<div class="content-section nav-menu">
<ul>
<li>
<div class="nav-link">
Return to <a href="${weaver.wps_restapi_url}?f=html">API Frontpage</a>.
</div>
</li>
<li>
<div class="nav-link">
Return to <a href="${util.get_jobs_link(query='f=html')}">Jobs list</a>.
</div>
</li>
<li>
<div class="nav-link">
Go to <a href="#job-metadata">Job Metadata</a>
</div>
</li>
<li>
<div class="nav-link">
Go to <a href="#job-results">Job Results</a>
</div>
</li>
<li>
<div class="nav-link">
Go to <a href="#job-statistics">Job Statistics</a>
</div>
</li>
<li>
<div class="nav-link">
Go to <a href="#job-logs">Job Logs</a>
</div>
</li>
<li>
<div class="nav-link">
Go to <a href="#job-provenance">Job Provenance</a>
</div>
</li>
${util.get_paging_links()}
</ul>
</div>

<div class="content-section">
<h3 id="job-metadata">
<a href="#job-metadata">Job Metadata</a>
</h3>
<table class="table-job-status">
<tr class="table-job-status-item ">
<td class="table-job-status-field field-key">Job ID</td>
<td class="table-job-status-field code">${job.id}</td>
</tr>
<tr class="table-job-status-item ">
<td class="table-job-status-field field-key">Process ID</td>
<td class="table-job-status-field code">
<a href="${util.get_process_link(job.process, job.service, query='f=html')}"
>${job.process}</a>
</td>
</tr>
<tr class="table-job-status-item ">
<td class="table-job-status-field field-key">Provider ID</td>
<td class="table-job-status-field code">
%if job.service:
<a
href="${util.get_provider_link(job.service, query='f=html')}"
>${job.service}</a>
%else:
<span class="undefined"><abbr title="Local Process">n/a</abbr></span>
%endif
</td>
</tr>
<tr class="table-job-status-item ">
<td class="table-job-status-field field-key">Status</td>
<td class="table-job-status-field">
${util.render_status(status)}
</td>
</tr>
<tr class="table-job-status-item ">
<td class="table-job-status-field field-key">Message</td>
<td class="table-job-status-field">
${message}
</td>
</tr>
<tr class="table-job-status-item ">
<td class="table-job-status-field field-key">Progress</td>
<td class="table-job-status-field">
${util.render_progress(job.progress, job.status)}
</td>
</tr>
<tr class="table-job-status-item ">
<td class="table-job-status-field field-key">Duration</td>
<td class="table-job-status-field code">
${job.duration}
</td>
</tr>
%for field in ["created", "started", "updated", "finished"]:
<tr class="table-job-status-item ">
<td class="table-job-status-field field-key">${field.capitalize()}</td>
<td class="table-job-status-field code">
%if job.get(field):
${job.get(field)}
%else:
<span class="undefined">n/a</span>
%endif
</td>
</tr>
%endfor
</table>
</div>

<div class="content-section">
<h3 id="job-results">
<a href="#job-results">Job Results</a>
</h3>
<!-- fill data here -->
</div>

<div class="content-section">
<h3 id="job-logs">
<a href="#job-logs">Job Logs</a>
</h3>
<!-- fill data here -->
</div>

<div class="content-section">
<h3 id="job-statistics">
<a href="#job-statistics">Job Statistics</a>
</h3>
<!-- fill data here -->
</div>

<div class="content-section">
<h3 id="job-logs">
<a href="#job-logs">Job Logs</a>
</h3>
<!-- fill data here -->
</div>

<div class="content-section">
<h3 id="job-provenance">
<a href="#job-provenance">Job Provenance</a>
</h3>
<!-- fill data here -->
</div>

</div>
13 changes: 12 additions & 1 deletion weaver/wps_restapi/templates/static/style.css
Original file line number Diff line number Diff line change
Expand Up @@ -168,6 +168,7 @@ body {
margin-left: 1em;
}

.job-title > .code,
.process-title .code {
font-size: 130%;
}
Expand All @@ -191,7 +192,17 @@ body {
padding: 1em;
}

.table-jobs-field {
.table-job-status,
.table-job-status th,
.table-job-status td {
border-style: solid;
border-width: 1px;
border-collapse: collapse;
padding: 1em;
}

.table-jobs-field,
.table-job-status-field {
font-size: 90%;
text-align: justify;
}
Expand Down

0 comments on commit 58bacbc

Please sign in to comment.