Skip to content

Commit ee582a0

Browse files
committed
use info endpoint because it contains payload!
1 parent 529b6a4 commit ee582a0

6 files changed

Lines changed: 69 additions & 168 deletions

File tree

x-pack/plugins/reporting/common/types/url.ts

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,7 @@ export type DownloadReportFn = (jobId: JobId) => DownloadLink;
1414
type ManagementLink = string;
1515
export type ManagementLinkFn = () => ManagementLink;
1616

17-
export interface LocatorParams<
18-
P extends SerializableRecord = SerializableRecord & { forceNow?: string }
19-
> {
17+
export interface LocatorParams<P extends SerializableRecord = SerializableRecord> {
2018
id: string;
2119
version: string;
2220
params: P;

x-pack/plugins/reporting/public/lib/job.tsx

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import moment from 'moment';
1212
import React from 'react';
1313
import { JOB_STATUSES } from '../../common/constants';
1414
import {
15+
BaseParamsV2,
1516
JobId,
1617
ReportApiJSON,
1718
ReportOutput,
@@ -58,6 +59,8 @@ export class Job {
5859
public max_size_reached?: TaskRunResult['max_size_reached'];
5960
public warnings?: TaskRunResult['warnings'];
6061

62+
public locatorParams?: BaseParamsV2['locatorParams'];
63+
6164
constructor(report: ReportApiJSON) {
6265
this.id = report.id;
6366
this.index = report.index;
@@ -87,6 +90,7 @@ export class Job {
8790
this.csv_contains_formulas = report.output?.csv_contains_formulas;
8891
this.max_size_reached = report.output?.max_size_reached;
8992
this.warnings = report.output?.warnings;
93+
this.locatorParams = (report.payload as BaseParamsV2).locatorParams;
9094
}
9195

9296
getStatusMessage() {

x-pack/plugins/reporting/public/lib/reporting_api_client/reporting_api_client.ts

Lines changed: 13 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,6 @@ import {
2222
} from '../../../common/constants';
2323
import {
2424
BaseParams,
25-
BasePayloadV2,
2625
DownloadReportFn,
2726
JobId,
2827
ManagementLinkFn,
@@ -60,8 +59,6 @@ interface IReportingAPI {
6059
getInfo(jobId: string): Promise<Job>;
6160
findForJobIds(jobIds: string[]): Promise<Job[]>;
6261

63-
getLocatorParams(jobId: string): Promise<BasePayloadV2['locatorParams']>;
64-
6562
// Function props
6663
getManagementLink: ManagementLinkFn;
6764
getDownloadLink: DownloadReportFn;
@@ -78,19 +75,6 @@ export class ReportingAPIClient implements IReportingAPI {
7875
private kibanaVersion: string
7976
) {}
8077

81-
public getReportURL(jobId: string) {
82-
const apiBaseUrl = this.http.basePath.prepend(API_LIST_URL);
83-
const downloadLink = `${apiBaseUrl}/download/${jobId}`;
84-
85-
return downloadLink;
86-
}
87-
88-
public downloadReport(jobId: string) {
89-
const location = this.getReportURL(jobId);
90-
91-
window.open(location);
92-
}
93-
9478
public getKibanaAppHref(job: Job): string {
9579
const searchParams = stringify({ jobId: job.id });
9680

@@ -104,6 +88,19 @@ export class ReportingAPIClient implements IReportingAPI {
10488
return href;
10589
}
10690

91+
public getReportURL(jobId: string) {
92+
const apiBaseUrl = this.http.basePath.prepend(API_LIST_URL);
93+
const downloadLink = `${apiBaseUrl}/download/${jobId}`;
94+
95+
return downloadLink;
96+
}
97+
98+
public downloadReport(jobId: string) {
99+
const location = this.getReportURL(jobId);
100+
101+
window.open(location);
102+
}
103+
107104
public async deleteReport(jobId: string) {
108105
return await this.http.delete<void>(`${API_LIST_URL}/delete/${jobId}`, {
109106
asSystemRequest: true,
@@ -152,16 +149,6 @@ export class ReportingAPIClient implements IReportingAPI {
152149
return new Job(report);
153150
}
154151

155-
public async getLocatorParams(jobId: string) {
156-
const payload: BasePayloadV2['locatorParams'] = await this.http.get(
157-
`${API_LIST_URL}/locatorParams/${jobId}`,
158-
{
159-
asSystemRequest: true,
160-
}
161-
);
162-
return payload;
163-
}
164-
165152
public async findForJobIds(jobIds: JobId[]) {
166153
const reports: ReportApiJSON[] = await this.http.fetch(`${API_LIST_URL}/list`, {
167154
query: { page: 0, ids: jobIds.join(',') },

x-pack/plugins/reporting/public/redirect/redirect_app.tsx

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -45,12 +45,13 @@ export const RedirectApp: FunctionComponent<Props> = ({ share, apiClient }) => {
4545
useEffect(() => {
4646
(async () => {
4747
try {
48-
let locatorParams: LocatorParams;
48+
let locatorParams: undefined | LocatorParams;
4949

5050
const { jobId } = parse(window.location.search);
5151

5252
if (jobId) {
53-
locatorParams = (await apiClient.getLocatorParams(jobId as string))[0];
53+
const result = await apiClient.getInfo(jobId as string);
54+
locatorParams = result?.locatorParams?.[0];
5455
} else {
5556
locatorParams = (window as unknown as Record<string, LocatorParams>)[
5657
REPORTING_REDIRECT_LOCATOR_STORE_KEY

x-pack/plugins/reporting/server/routes/lib/jobs_query.ts

Lines changed: 35 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ import { ElasticsearchClient } from 'src/core/server';
1919
import { PromiseType } from 'utility-types';
2020
import { ReportingCore } from '../../';
2121
import { REPORTING_SYSTEM_INDEX } from '../../../common/constants';
22-
import { ReportApiJSON, ReportSource, BasePayloadV2 } from '../../../common/types';
22+
import { ReportApiJSON, ReportSource } from '../../../common/types';
2323
import { statuses } from '../../lib/statuses';
2424
import { Report } from '../../lib/store';
2525
import { ReportingUser } from '../../types';
@@ -51,11 +51,7 @@ interface JobsQueryFactory {
5151
jobIds: string[] | null
5252
): Promise<ReportApiJSON[]>;
5353
count(jobTypes: string[], user: ReportingUser): Promise<number>;
54-
get(user: ReportingUser, id: string): Promise<ReportApiJSON | undefined>;
55-
getLocatorParams(
56-
user: ReportingUser,
57-
id: string
58-
): Promise<BasePayloadV2['locatorParams'] | undefined>;
54+
get(user: ReportingUser, id: string): Promise<ReportApiJSON | void>;
5955
getError(id: string): Promise<string>;
6056
delete(deleteIndex: string, id: string): Promise<TransportResult<DeleteResponse>>;
6157
}
@@ -65,41 +61,6 @@ export function jobsQueryFactory(reportingCore: ReportingCore): JobsQueryFactory
6561
return `${REPORTING_SYSTEM_INDEX}-*`;
6662
}
6763

68-
async function getReport(user: ReportingUser, id: string) {
69-
const { logger } = reportingCore.getPluginSetupDeps();
70-
if (!id) {
71-
logger.warning(`No ID provided for GET`);
72-
return;
73-
}
74-
75-
const username = getUsername(user);
76-
77-
const body = getSearchBody({
78-
query: {
79-
constant_score: {
80-
filter: {
81-
bool: {
82-
must: [{ term: { _id: id } }, { term: { created_by: username } }],
83-
},
84-
},
85-
},
86-
},
87-
size: 1,
88-
});
89-
90-
const response = await execQuery((elasticsearchClient) =>
91-
elasticsearchClient.search<ReportSource>({ body, index: getIndex() })
92-
);
93-
94-
const result = response?.body.hits?.hits?.[0];
95-
if (!result?._source) {
96-
logger.warning(`No hits resulted in search`);
97-
return;
98-
}
99-
100-
return new Report({ ...result, ...result._source });
101-
}
102-
10364
async function execQuery<
10465
T extends (client: ElasticsearchClient) => Promise<PromiseType<ReturnType<T>> | undefined>
10566
>(callback: T): Promise<UnwrapPromise<ReturnType<T>> | undefined> {
@@ -116,7 +77,7 @@ export function jobsQueryFactory(reportingCore: ReportingCore): JobsQueryFactory
11677
}
11778
}
11879

119-
const factory: JobsQueryFactory = {
80+
return {
12081
async list(jobTypes, user, page = 0, size = defaultSize, jobIds) {
12182
const username = getUsername(user);
12283
const body = getSearchBody({
@@ -176,17 +137,39 @@ export function jobsQueryFactory(reportingCore: ReportingCore): JobsQueryFactory
176137
},
177138

178139
async get(user, id) {
179-
const report = await getReport(user, id);
180-
return report?.toApiJSON();
181-
},
140+
const { logger } = reportingCore.getPluginSetupDeps();
141+
if (!id) {
142+
logger.warning(`No ID provided for GET`);
143+
return;
144+
}
182145

183-
/**
184-
* @note If this returns `undefined` it means that either the V2 report does not have locatorParams (big issue) or the
185-
* report is not a V2 report.
186-
*/
187-
async getLocatorParams(user, id) {
188-
const report = await getReport(user, id);
189-
return (report?.payload as unknown as BasePayloadV2)?.locatorParams;
146+
const username = getUsername(user);
147+
148+
const body = getSearchBody({
149+
query: {
150+
constant_score: {
151+
filter: {
152+
bool: {
153+
must: [{ term: { _id: id } }, { term: { created_by: username } }],
154+
},
155+
},
156+
},
157+
},
158+
size: 1,
159+
});
160+
161+
const response = await execQuery((elasticsearchClient) =>
162+
elasticsearchClient.search<ReportSource>({ body, index: getIndex() })
163+
);
164+
165+
const result = response?.body.hits?.hits?.[0];
166+
if (!result?._source) {
167+
logger.warning(`No hits resulted in search`);
168+
return;
169+
}
170+
171+
const report = new Report({ ...result, ...result._source });
172+
return report.toApiJSON();
190173
},
191174

192175
async getError(id) {
@@ -235,6 +218,4 @@ export function jobsQueryFactory(reportingCore: ReportingCore): JobsQueryFactory
235218
}
236219
},
237220
};
238-
239-
return factory;
240221
}

x-pack/plugins/reporting/server/routes/management/jobs.ts

Lines changed: 13 additions & 83 deletions
Original file line numberDiff line numberDiff line change
@@ -8,15 +8,8 @@
88
import { schema } from '@kbn/config-schema';
99
import { i18n } from '@kbn/i18n';
1010
import { ReportingCore } from '../../';
11-
import {
12-
IKibanaResponse,
13-
kibanaResponseFactory,
14-
ResponseError,
15-
} from '../../../../../../src/core/server';
1611
import { ROUTE_TAG_CAN_REDIRECT } from '../../../../security/server';
1712
import { API_BASE_URL } from '../../../common/constants';
18-
import { Report } from '../../lib/store';
19-
import type { ReportApiJSON } from '../../lib/store/report';
2013
import { authorizedUserPreRouting } from '../lib/authorized_user_pre_routing';
2114
import { jobsQueryFactory } from '../lib/jobs_query';
2215
import { deleteJobResponseHandler, downloadJobResponseHandler } from '../lib/job_response_handler';
@@ -92,38 +85,6 @@ export function registerJobInfoRoutes(reporting: ReportingCore) {
9285
})
9386
);
9487

95-
/**
96-
* Returns appropriate {@link IKibanaResponse<ResponseError>} if the requested job is not valid either because:
97-
* 1. It was not found
98-
* 2. It is not permitted under the current licensing
99-
*/
100-
const validateJobIsAvailable = async (
101-
job?: Report | ReportApiJSON
102-
): Promise<undefined | IKibanaResponse<ResponseError>> => {
103-
if (!job) {
104-
// Bad result
105-
return kibanaResponseFactory.notFound();
106-
}
107-
108-
const { jobtype: jobType } = job;
109-
const {
110-
management: { jobTypes = [] },
111-
} = await reporting.getLicenseInfo();
112-
113-
if (!jobTypes.includes(jobType)) {
114-
// Bad result
115-
return kibanaResponseFactory.forbidden({
116-
body: i18n.translate('xpack.reporting.jobsQuery.infoError.unauthorizedErrorMessage', {
117-
defaultMessage: 'Sorry, you are not authorized to view {jobType} info',
118-
values: { jobType },
119-
}),
120-
});
121-
}
122-
123-
// Good result
124-
return;
125-
};
126-
12788
// return some info about the job
12889
router.get(
12990
{
@@ -141,60 +102,29 @@ export function registerJobInfoRoutes(reporting: ReportingCore) {
141102
}
142103

143104
const { docId } = req.params;
105+
const {
106+
management: { jobTypes = [] },
107+
} = await reporting.getLicenseInfo();
144108

145109
const result = await jobsQuery.get(user, docId);
146110

147-
const validationResult = await validateJobIsAvailable(result);
148-
if (validationResult) {
149-
return validationResult;
150-
}
151-
152-
return res.ok({
153-
body: result!,
154-
headers: {
155-
'content-type': 'application/json',
156-
},
157-
});
158-
})
159-
);
160-
161-
router.get(
162-
{
163-
path: `${MAIN_ENTRY}/locatorParams/{docId}`,
164-
validate: {
165-
params: schema.object({
166-
docId: schema.string({ minLength: 2 }),
167-
}),
168-
},
169-
},
170-
authorizedUserPreRouting(reporting, async (user, context, req, res) => {
171-
// ensure the async dependencies are loaded
172-
if (!context.reporting) {
173-
return res.custom({ statusCode: 503 });
111+
if (!result) {
112+
return res.notFound();
174113
}
175114

176-
const { docId } = req.params;
115+
const { jobtype: jobType } = result;
177116

178-
const locatorParams = await jobsQuery.getLocatorParams(user, docId);
179-
180-
if (!locatorParams || !locatorParams.length) {
181-
return res.notFound({
182-
body: {
183-
message: i18n.translate(
184-
'xpack.reporting.jobsQuery.locatorParams.notFoundErrorMessage',
185-
{
186-
defaultMessage: `Locator params not found for {docId}`,
187-
values: {
188-
docId,
189-
},
190-
}
191-
),
192-
},
117+
if (!jobTypes.includes(jobType)) {
118+
return res.forbidden({
119+
body: i18n.translate('xpack.reporting.jobsQuery.infoError.unauthorizedErrorMessage', {
120+
defaultMessage: 'Sorry, you are not authorized to view {jobType} info',
121+
values: { jobType },
122+
}),
193123
});
194124
}
195125

196126
return res.ok({
197-
body: locatorParams,
127+
body: result,
198128
headers: {
199129
'content-type': 'application/json',
200130
},

0 commit comments

Comments
 (0)