diff --git a/Src/WitsmlExplorer.Api/HttpHandlers/JobHandler.cs b/Src/WitsmlExplorer.Api/HttpHandlers/JobHandler.cs index 2769f9d7b..04ae99502 100644 --- a/Src/WitsmlExplorer.Api/HttpHandlers/JobHandler.cs +++ b/Src/WitsmlExplorer.Api/HttpHandlers/JobHandler.cs @@ -3,6 +3,8 @@ using System.Linq; using System.Threading.Tasks; +using Amazon.Runtime; + using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; using Microsoft.Extensions.Configuration; @@ -12,6 +14,7 @@ using WitsmlExplorer.Api.Jobs; using WitsmlExplorer.Api.Middleware; using WitsmlExplorer.Api.Models; +using WitsmlExplorer.Api.Models.Reports; using WitsmlExplorer.Api.Services; namespace WitsmlExplorer.Api.HttpHandlers @@ -101,10 +104,22 @@ public static IResult CancelJob(string jobId, IJobCache jobCache) return TypedResults.NotFound(); } - [Produces(typeof(IEnumerable))] - public static IResult GetReportItems(string jobId, IJobCache jobCache) + [Produces(typeof(BaseReport))] + public static IResult GetReport(string jobId, IJobCache jobCache, HttpRequest httpRequest, IConfiguration configuration, ICredentialsService credentialsService) { - return TypedResults.Ok(jobCache.GetReportItems(jobId)); + EssentialHeaders eh = new(httpRequest); + bool useOAuth2 = StringHelpers.ToBoolean(configuration[ConfigConstants.OAuth2Enabled]); + string userName = useOAuth2 ? credentialsService.GetClaimFromToken(eh.GetBearerToken(), "upn") : eh.TargetUsername; + if (!useOAuth2) + { + credentialsService.VerifyUserIsLoggedIn(eh, ServerType.Target); + } + JobInfo job = jobCache.GetJobInfoById(jobId); + if (job.Username != userName && (!useOAuth2 || !IsAdminOrDeveloper(eh.GetBearerToken()))) + { + return TypedResults.Forbid(); + } + return TypedResults.Ok(jobCache.GetReportByJobId(jobId)); } } } diff --git a/Src/WitsmlExplorer.Api/Jobs/JobInfo.cs b/Src/WitsmlExplorer.Api/Jobs/JobInfo.cs index 181392b57..6a5f7aca4 100644 --- a/Src/WitsmlExplorer.Api/Jobs/JobInfo.cs +++ b/Src/WitsmlExplorer.Api/Jobs/JobInfo.cs @@ -49,6 +49,7 @@ public JobInfo() public double Progress { get; set; } + [JsonIgnore] public BaseReport Report { get; set; } public bool IsCancelable { get; internal set; } = false; @@ -73,6 +74,17 @@ public JobStatus Status } } + public string LinkType + { + get + { + if (Report?.DownloadImmediately == true) + { + return "Donwload file"; + } + return "Report"; + } + } } public enum JobStatus diff --git a/Src/WitsmlExplorer.Api/Models/Reports/BaseReport.cs b/Src/WitsmlExplorer.Api/Models/Reports/BaseReport.cs index bd3f6b382..d55f178f5 100644 --- a/Src/WitsmlExplorer.Api/Models/Reports/BaseReport.cs +++ b/Src/WitsmlExplorer.Api/Models/Reports/BaseReport.cs @@ -9,6 +9,6 @@ public class BaseReport public IEnumerable ReportItems { get; init; } public string WarningMessage { get; init; } public bool DownloadImmediately { get; init; } = false; - public string ReportHeader { get; init; } = null; + public string ReportHeader { get; init; } } } diff --git a/Src/WitsmlExplorer.Api/Routes.cs b/Src/WitsmlExplorer.Api/Routes.cs index 650cce85d..930dc5849 100644 --- a/Src/WitsmlExplorer.Api/Routes.cs +++ b/Src/WitsmlExplorer.Api/Routes.cs @@ -95,7 +95,7 @@ public static void ConfigureApi(this WebApplication app, IConfiguration configur app.MapGet("/jobs/userjobinfo/{jobId}", JobHandler.GetUserJobInfo, useOAuth2); app.MapGet("/jobs/alljobinfos", JobHandler.GetAllJobInfos, useOAuth2, AuthorizationPolicyRoles.ADMINORDEVELOPER); app.MapPost("/jobs/cancel/{jobId}", JobHandler.CancelJob, useOAuth2); - app.MapGet("/jobs/getreportitems/{jobId}", JobHandler.GetReportItems, useOAuth2); + app.MapGet("/jobs/getreport/{jobId}", JobHandler.GetReport, useOAuth2); app.MapGet("/credentials/authorize", AuthorizeHandler.Authorize, useOAuth2); app.MapGet("/credentials/deauthorize", AuthorizeHandler.Deauthorize, useOAuth2); diff --git a/Src/WitsmlExplorer.Api/Services/JobCache.cs b/Src/WitsmlExplorer.Api/Services/JobCache.cs index 8526bd41e..d49c65125 100644 --- a/Src/WitsmlExplorer.Api/Services/JobCache.cs +++ b/Src/WitsmlExplorer.Api/Services/JobCache.cs @@ -19,7 +19,7 @@ public interface IJobCache ICollection GetJobInfosByUser(string username); JobInfo GetJobInfoById(string jobId); ICollection GetAllJobInfos(); - IEnumerable GetReportItems(string jobId); + BaseReport GetReportByJobId(string jobId); } public class JobCache : IJobCache @@ -53,8 +53,7 @@ public void CacheJob(JobInfo jobInfo) public ICollection GetJobInfosByUser(string username) { - var allJobs = _jobs.Values.Where(job => job.Username == username).ToList(); - return HandleBigData(allJobs); + return _jobs.Values.Where(job => job.Username == username).ToList(); } public JobInfo GetJobInfoById(string jobId) @@ -64,17 +63,15 @@ public JobInfo GetJobInfoById(string jobId) public ICollection GetAllJobInfos() { - var allJobs = _jobs.Values.ToList(); - return HandleBigData(allJobs); + return _jobs.Values.ToList(); } - public IEnumerable GetReportItems(string jobId) + public BaseReport GetReportByJobId(string jobId) { var job = _jobs[jobId]; if (job != null) { - var reportItems = job.Report?.ReportItems; - return reportItems; + return job.Report; } return null; } @@ -102,20 +99,5 @@ private void Cleanup() } _logger.LogInformation("JobCache cleanup finished, deleted: {deleted}, failed: {failed}, remaining: {remaining}", deleted, failed, _jobs.Count); } - - private static ICollection HandleBigData(ICollection allJobs) - { - var resultJobs = new List(); - foreach (var job in allJobs) - { - if (job.Report != null && job.Report.DownloadImmediately) - { - var copyJob = job with { Report = new BaseReport() { Title = job.Report?.Title, ReportHeader = job.Report?.ReportHeader, DownloadImmediately = true } }; - resultJobs.Add(copyJob); - } - else { resultJobs.Add(job); } - } - return resultJobs; - } } } diff --git a/Src/WitsmlExplorer.Api/Workers/DownloadAllLogDataWorker.cs b/Src/WitsmlExplorer.Api/Workers/DownloadAllLogDataWorker.cs index 6811fd274..139aa3f5b 100644 --- a/Src/WitsmlExplorer.Api/Workers/DownloadAllLogDataWorker.cs +++ b/Src/WitsmlExplorer.Api/Workers/DownloadAllLogDataWorker.cs @@ -1,7 +1,6 @@ using System; using System.Collections.Generic; using System.Linq; -using System.Text; using System.Threading; using System.Threading.Tasks; diff --git a/Src/WitsmlExplorer.Frontend/__testUtils__/testUtils.tsx b/Src/WitsmlExplorer.Frontend/__testUtils__/testUtils.tsx index 03d3c3e8a..45a2d68ed 100644 --- a/Src/WitsmlExplorer.Frontend/__testUtils__/testUtils.tsx +++ b/Src/WitsmlExplorer.Frontend/__testUtils__/testUtils.tsx @@ -194,6 +194,7 @@ export function getJobInfo(overrides?: Partial): JobInfo { report: null, progress: 0, isCancelable: false, + linkType: "", ...overrides }; } diff --git a/Src/WitsmlExplorer.Frontend/components/ContentViews/JobsView.tsx b/Src/WitsmlExplorer.Frontend/components/ContentViews/JobsView.tsx index 2c136665c..593b92a85 100644 --- a/Src/WitsmlExplorer.Frontend/components/ContentViews/JobsView.tsx +++ b/Src/WitsmlExplorer.Frontend/components/ContentViews/JobsView.tsx @@ -19,7 +19,6 @@ import { refreshJobInfoQuery } from "hooks/query/queryRefreshHelpers"; import { useGetJobInfo } from "hooks/query/useGetJobInfo"; import { useGetServers } from "hooks/query/useGetServers"; import useExport from "hooks/useExport"; -import BaseReport from "models/reports/BaseReport"; import { Server } from "models/server"; import { adminRole, @@ -67,10 +66,13 @@ export const JobsView = (): React.ReactElement => { }); }; - const onClickReport = async (report: BaseReport, jobId: string) => { + const onClickReport = async (jobId: string) => { + const report = await JobService.getReport(jobId); if (report.downloadImmediately === true) { - const reportItems = await JobService.getReportItems(jobId); - const reportProperties = generateReport(reportItems, report.reportHeader); + const reportProperties = generateReport( + report.reportItems, + report.reportHeader + ); exportData( report.title, reportProperties.exportColumns, @@ -130,10 +132,6 @@ export const JobsView = (): React.ReactElement => { wellName: jobInfo.wellName, wellboreName: jobInfo.wellboreName, objectName: jobInfo.objectName, - status: - jobInfo.progress && jobInfo.status === "Started" - ? `${Math.round(jobInfo.progress * 100)}%` - : jobInfo.status, startTime: formatDateString( jobInfo.startTime, timeZone, @@ -146,15 +144,12 @@ export const JobsView = (): React.ReactElement => { ), targetServer: serverUrlToName(servers, jobInfo.targetServer), sourceServer: serverUrlToName(servers, jobInfo.sourceServer), - report: jobInfo.report ? ( - onClickReport(jobInfo.report, jobInfo.id)} - > - {jobInfo.report.downloadImmediately === true - ? "Donwload file" - : "Report"} - - ) : null, + report: + jobInfo.status === "Finished" ? ( + onClickReport(jobInfo.id)}> + {jobInfo.linkType} + + ) : null, jobInfo: jobInfo }; }) diff --git a/Src/WitsmlExplorer.Frontend/components/Modals/ReportModal.tsx b/Src/WitsmlExplorer.Frontend/components/Modals/ReportModal.tsx index 1d9520671..ccc8c41d2 100644 --- a/Src/WitsmlExplorer.Frontend/components/Modals/ReportModal.tsx +++ b/Src/WitsmlExplorer.Frontend/components/Modals/ReportModal.tsx @@ -179,14 +179,15 @@ export const useGetReportOnJobFinished = (jobId: string): BaseReport => { ) ); } else { - setReport(jobInfo.report); - if (jobInfo.report.downloadImmediately === true) { + const report = await JobService.getReport(jobId); + setReport(report); + if (report.downloadImmediately === true) { const reportProperties = generateReport( - jobInfo.report.reportItems, - jobInfo.report.reportHeader + report.reportItems, + report.reportHeader ); exportData( - jobInfo.report.title, + report.title, reportProperties.exportColumns, reportProperties.data ); diff --git a/Src/WitsmlExplorer.Frontend/models/jobs/jobInfo.tsx b/Src/WitsmlExplorer.Frontend/models/jobs/jobInfo.tsx index 16ad3cc9f..b2e7aaf9a 100644 --- a/Src/WitsmlExplorer.Frontend/models/jobs/jobInfo.tsx +++ b/Src/WitsmlExplorer.Frontend/models/jobs/jobInfo.tsx @@ -20,4 +20,5 @@ export default interface JobInfo { report: BaseReport; progress: number; isCancelable: boolean; + linkType: string; } diff --git a/Src/WitsmlExplorer.Frontend/services/jobService.tsx b/Src/WitsmlExplorer.Frontend/services/jobService.tsx index e8ae6ca1c..cd7b8017e 100644 --- a/Src/WitsmlExplorer.Frontend/services/jobService.tsx +++ b/Src/WitsmlExplorer.Frontend/services/jobService.tsx @@ -1,4 +1,5 @@ import JobInfo from "models/jobs/jobInfo"; +import BaseReport from "models/reports/BaseReport"; import { Server } from "models/server"; import { ApiClient, throwError } from "services/apiClient"; import AuthorizationService from "services/authorizationService"; @@ -108,12 +109,12 @@ export default class JobService { } } - public static async getReportItems( + public static async getReport( jobId: string, abortSignal?: AbortSignal - ): Promise { + ): Promise { const response = await ApiClient.get( - `/api/jobs/getreportitems/${jobId}`, + `/api/jobs/getreport/${jobId}`, abortSignal ); if (response.ok) {