Skip to content
This repository has been archived by the owner on Aug 9, 2022. It is now read-only.

Commit

Permalink
Backport the feature to support reporting with tenant panel chatbox t…
Browse files Browse the repository at this point in the history
…o 7.9.1 from opendistro-1.13.0.0 (#337)

* add security_tenant info into url (#323)

* add global tenant for report definition urls (#324)

* update target
  • Loading branch information
zhongnansu authored Mar 1, 2021
1 parent 1bb6fcc commit 81c5cd6
Show file tree
Hide file tree
Showing 8 changed files with 3,214 additions and 1,749 deletions.
114 changes: 97 additions & 17 deletions kibana-reports/public/components/context_menu/context_menu.js
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ import {
} from './context_menu_ui';
import uuidv4 from 'uuid/v4';
import { timeRangeMatcher } from '../utils/utils';
import { parse } from 'url';

const replaceQueryURL = () => {
let url = location.pathname + location.hash;
Expand All @@ -51,14 +52,25 @@ const replaceQueryURL = () => {
return url;
};

const generateInContextReport = (
const generateInContextReport = async (
timeRanges,
queryUrl,
fileFormat,
rest = {}
) => {
displayLoadingModal();
const baseUrl = queryUrl.substr(0, queryUrl.indexOf('?'));
// Add selected tenant info to url
try {
const tenant = await getTenantInfoIfExists();
if (tenant) {
queryUrl = addTenantToURL(queryUrl, tenant);
}
} catch (error) {
addSuccessOrFailureToast('failure');
console.log(`failed to get user tenant: ${error}`);
}

let reportSource = '';
if (baseUrl.includes('dashboard')) {
reportSource = 'Dashboard';
Expand Down Expand Up @@ -228,32 +240,39 @@ $(function () {
});

const isDiscoverNavMenu = (navMenu) => {
return navMenu[0].children.length === 5 &&
return (
navMenu[0].children.length === 5 &&
($('[data-test-subj="breadcrumb first"]').prop('title') === 'Discover' ||
$('[data-test-subj="breadcrumb first last"]').prop('title') === 'Discover')
}
$('[data-test-subj="breadcrumb first last"]').prop('title') ===
'Discover')
);
};

const isDashboardNavMenu = (navMenu) => {
return (navMenu[0].children.length === 4 || navMenu[0].children.length === 6) &&
($('[data-test-subj="breadcrumb first"]').prop('title') === 'Dashboard')
}
return (
(navMenu[0].children.length === 4 || navMenu[0].children.length === 6) &&
$('[data-test-subj="breadcrumb first"]').prop('title') === 'Dashboard'
);
};

const isVisualizationNavMenu = (navMenu) => {
return navMenu[0].children.length === 3
&& ($('[data-test-subj="breadcrumb first"]').prop('title') === 'Visualize')
}


return (
navMenu[0].children.length === 3 &&
$('[data-test-subj="breadcrumb first"]').prop('title') === 'Visualize'
);
};

function locationHashChanged() {
const observer = new MutationObserver(function (mutations) {
const navMenu = document.querySelectorAll(
'span.kbnTopNavMenu__wrapper > div.euiFlexGroup'
);
if (navMenu && navMenu.length && (
isDiscoverNavMenu(navMenu) ||
isDashboardNavMenu(navMenu) ||
isVisualizationNavMenu(navMenu))
if (
navMenu &&
navMenu.length &&
(isDiscoverNavMenu(navMenu) ||
isDashboardNavMenu(navMenu) ||
isVisualizationNavMenu(navMenu))
) {
try {
if ($('#downloadReport').length) {
Expand Down Expand Up @@ -285,7 +304,7 @@ const getUuidFromUrl = () =>
);
const isDiscover = () => window.location.href.includes('discover');

$(window).one('hashchange', function( e ) {
$(window).one('hashchange', function (e) {
locationHashChanged();
});
/**
Expand All @@ -305,3 +324,64 @@ $(window).one('hashchange', function( e ) {
window.onpopstate = history.onpushstate = () => {
locationHashChanged();
};

async function getTenantInfoIfExists() {
const res = await fetch(`../api/v1/multitenancy/tenant`, {
headers: {
'Content-Type': 'application/json',
'kbn-version': '7.9.1',
accept: '*/*',
'accept-language': 'en-US,en;q=0.9,zh-CN;q=0.8,zh;q=0.7,zh-TW;q=0.6',
pragma: 'no-cache',
'sec-fetch-dest': 'empty',
'sec-fetch-mode': 'cors',
'sec-fetch-site': 'same-origin',
},
method: 'GET',
referrerPolicy: 'strict-origin-when-cross-origin',
mode: 'cors',
credentials: 'include',
})
.then((response) => {
if (response.status === 404) {
// endpoint doesn't exist, security plugin is not enabled.
return undefined;
} else {
return response.text();
}
})
.then((tenant) => {
if (tenant === '') {
tenant = 'global';
} else if (tenant === '__user__') {
tenant = 'private';
}
return tenant;
});

return res;
}

// helper function to add tenant info to url(if tenant is available)
function addTenantToURL(url, userRequestedTenant) {
// build fake url from relative url
const fakeUrl = `http://opendistro.com${url}`;
const tenantKey = 'security_tenant';
const tenantKeyAndValue =
tenantKey + '=' + encodeURIComponent(userRequestedTenant);

const { pathname, search } = parse(fakeUrl);
const queryDelimiter = !search ? '?' : '&';
// The url parser returns null if the search is empty. Change that to an empty
// string so that we can use it to build the values later
if (search && search.toLowerCase().indexOf(tenantKey) > -1) {
// If we for some reason already have a tenant in the URL we skip any updates
return url;
}

// A helper for finding the part in the string that we want to extend/replace
const valueToReplace = pathname + (search || '');
const replaceWith = valueToReplace + queryDelimiter + tenantKeyAndValue;

return url.replace(valueToReplace, replaceWith);
}
1 change: 1 addition & 0 deletions kibana-reports/server/model/backendModel.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ export type BackendReportInstanceType = {
beginTimeMs: number;
endTimeMs: number;
access?: string[];
tenant?: string;
status: BACKEND_REPORT_STATE;
statusText?: string;
inContextDownloadUrlPath?: string;
Expand Down
47 changes: 42 additions & 5 deletions kibana-reports/server/routes/utils/converters/backendToUi.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ import {
TRIGGER_TYPE,
} from '../constants';
import moment from 'moment';
import { parse } from 'url';

export const backendToUiReport = (
backendReportInstance: BackendReportInstanceType
Expand All @@ -56,6 +57,7 @@ export const backendToUiReport = (
inContextDownloadUrlPath,
beginTimeMs,
endTimeMs,
tenant,
status,
lastUpdatedTimeMs: reportLastUpdatedTimeMs,
createdTimeMs: reportCreatedTimeMs,
Expand All @@ -73,9 +75,9 @@ export const backendToUiReport = (

let report: ReportSchemaType = {
// inContextDownloadUrlPath may not exist for report instance created from scheduled job
query_url: inContextDownloadUrlPath
? inContextDownloadUrlPath
: getUiQueryUrl(baseUrl, beginTimeMs, endTimeMs),
query_url:
inContextDownloadUrlPath ||
getUiQueryUrl(baseUrl, beginTimeMs, endTimeMs, tenant),
time_from: beginTimeMs,
time_to: endTimeMs,
last_updated: reportLastUpdatedTimeMs,
Expand Down Expand Up @@ -199,11 +201,21 @@ const getVisualReportCoreParams = (
const getUiQueryUrl = (
baseUrl: string,
beginTimeMs: number,
endTimeMs: number
endTimeMs: number,
tenant?: string
) => {
const timeFrom = moment(beginTimeMs).toISOString();
const timeTo = moment(endTimeMs).toISOString();
const queryUrl = `${baseUrl}?_g=(time:(from:'${timeFrom}',to:'${timeTo}'))`;
let queryUrl = `${baseUrl}?_g=(time:(from:'${timeFrom}',to:'${timeTo}'))`;
if (tenant !== undefined) {
if (tenant === '') {
tenant = 'global';
} else if (tenant === '__user__') {
tenant = 'private';
}
queryUrl = addTenantToURL(queryUrl, tenant);
}

return queryUrl;
};

Expand Down Expand Up @@ -352,3 +364,28 @@ const getUiDeliveryParams = (
}
return params;
};

// helper function to add tenant info to url(if tenant is available)
const addTenantToURL = (url: string, userRequestedTenant: string) => {
// build fake url from relative url
const fakeUrl = `http://opendistro.com${url}`;
const tenantKey = 'security_tenant';
const tenantKeyAndValue =
tenantKey + '=' + encodeURIComponent(userRequestedTenant);

const { pathname, search } = parse(fakeUrl);
const queryDelimiter = !search ? '?' : '&';

// The url parser returns null if the search is empty. Change that to an empty
// string so that we can use it to build the values later
if (search && search.toLowerCase().indexOf(tenantKey) > -1) {
// If we for some reason already have a tenant in the URL we skip any updates
return url;
}

// A helper for finding the part in the string that we want to extend/replace
const valueToReplace = pathname! + (search || '');
const replaceWith = valueToReplace + queryDelimiter + tenantKeyAndValue;

return url.replace(valueToReplace, replaceWith);
};
2 changes: 1 addition & 1 deletion kibana-reports/server/utils/validationHelper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ export const isValidRelativeUrl = (relativeUrl: string) => {
export const regexDuration = /^(-?)P(?=\d|T\d)(?:(\d+)Y)?(?:(\d+)M)?(?:(\d+)([DW]))?(?:T(?:(\d+)H)?(?:(\d+)M)?(?:(\d+(?:\.\d+)?)S)?)?$/;
export const regexEmailAddress = /\S+@\S+\.\S+/;
export const regexReportName = /^[\w\-\s\(\)\[\]\,\_\-+]+$/;
export const regexRelativeUrl = /^\/(_plugin\/kibana\/app|app)\/(dashboards|visualize|discover)#\/(view|edit)\/[^\/]+$/;
export const regexRelativeUrl = /^\/(_plugin\/kibana\/app|app)\/(dashboards|visualize|discover)(\?security_tenant=.+|)#\/(view|edit)\/[^\/]+$/;

export const validateReport = async (
client: ILegacyScopedClusterClient,
Expand Down
Loading

0 comments on commit 81c5cd6

Please sign in to comment.