Skip to content
This repository has been archived by the owner on Feb 18, 2021. It is now read-only.

Commit

Permalink
Move querying AI data from the client side to the server side (so we …
Browse files Browse the repository at this point in the history
…won't pass the apiKey in the request)
  • Loading branch information
Yair Ripshtos committed Nov 8, 2017
1 parent 755e8a2 commit fd2f276
Show file tree
Hide file tree
Showing 7 changed files with 233 additions and 127 deletions.
13 changes: 7 additions & 6 deletions client/src/data-sources/plugins/ApplicationInsights/Query.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { appInsightsUri } from './common';
import ApplicationInsightsConnection from '../../connections/application-insights';
import { DataSourceConnector, IDataSource } from '../../DataSourceConnector';
import * as formats from '../../../utils/data-formats';
import ConfigurationsStore from '../../../stores/ConfigurationsStore';

let connectionType = new ApplicationInsightsConnection();

Expand Down Expand Up @@ -98,19 +99,19 @@ export default class ApplicationInsightsQuery extends DataSourcePlugin<IQueryPar
});
}

var url = `${appInsightsUri}/${appId}/query?timespan=${queryTimespan}`;
var dashboardId = ConfigurationsStore.getState().dashboard.id;

return (dispatch) => {
request(
url,
'/applicationInsights/query',
{
method: 'POST',
json: true,
headers: {
'x-api-key': apiKey
},
body: {
query
query,
queryTimespan,
appId,
dashboardId
}
},
(error, json) => {
Expand Down
2 changes: 2 additions & 0 deletions server/app.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ const apiRouter = require('./routes/api');
const graphQLRouter = require('./routes/graphql');
const cosmosDBRouter = require('./routes/cosmos-db');
const azureRouter = require('./routes/azure');
const applicationInsightsRouter = require('./routes/applicationInsights');

const app = express();

Expand All @@ -34,6 +35,7 @@ app.use('/api', apiRouter.router);
app.use('/cosmosdb', cosmosDBRouter.router);
app.use('/azure', azureRouter.router);
app.use('/graphql', graphQLRouter.router);
app.use('/applicationinsights', applicationInsightsRouter.router);

app.use(express.static(path.resolve(__dirname, '..', 'build')));

Expand Down
12 changes: 12 additions & 0 deletions server/common/paths.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
const path = require('path');

const resourcesPaths = () => ({
persistentFolder: path.join(__dirname, '..', 'dashboards', 'persistent'),
privateDashboard: path.join(__dirname, '..', 'dashboards','persistent','private'),
preconfDashboard: path.join(__dirname, '..', 'dashboards', 'preconfigured'),
privateTemplate: path.join(__dirname, '..', 'dashboards','persistent', 'customTemplates')
});

module.exports = {
resourcesPaths
}
55 changes: 55 additions & 0 deletions server/helpers/filesHelpers.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
const fs = require('fs');
const path = require('path');
const resourceFieldProvider = require('./resourceFieldProvider');

function getResourceFileNameById(dir, id, overwrite) {
let files = fs.readdirSync(dir) || [];

// Make sure the array only contains files
files = files.filter(fileName => fs.statSync(path.join(dir, fileName)).isFile());
if (!files || files.length === 0) {
return null;
}

let dashboardFile = null;
files.every(fileName => {
const filePath = path.join(dir, fileName);
if (isValidFile(filePath)) {
let dashboardId = undefined;
if (overwrite === true) {
dashboardId = path.parse(fileName).name;
if (dashboardId.endsWith('.private')) {
dashboardId = path.parse(dashboardId).name;
}
} else {
const fileContents = getFileContents(filePath);
dashboardId = resourceFieldProvider.getField('id', fileContents);
}
if (dashboardId && dashboardId === id) {
dashboardFile = fileName;
return false;
}
}
return true;
});

return dashboardFile;
}

function isValidFile(filePath) {
const stats = fs.statSync(filePath);
return stats.isFile() && (filePath.endsWith('.js') || filePath.endsWith('.ts'));
}

function getFileContents(filePath) {
let contents = fs.readFileSync(filePath, 'utf8');
return filePath.endsWith(".ts")
? "return " + contents.slice(contents.indexOf("/*return*/ {") + 10)
: contents;
}

module.exports = {
getResourceFileNameById,
isValidFile,
getFileContents
}
46 changes: 46 additions & 0 deletions server/helpers/resourceFieldProvider.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
// Template/Dashboard metadata is stored inside the files
// To read the metadata we could eval() the files, but that's dangerous.
// Instead, we use regular expressions to pull them out
// Assumes that:
// * the metadata comes before config information
// * fields in the file look like fieldname: "string" or fieldname: 'string'
// * or, special case, html: `string`

const fields = {
id: /\s*id:\s*("|')(.*)("|')/,
name: /\s*name:\s*("|')(.*)("|')/,
description: /\s*description:\s*("|')(.*)("|')/,
icon: /\s*icon:\s*("|')(.*)("|')/,
logo: /\s*logo:\s*("|')(.*)("|')/,
url: /\s*url:\s*("|')(.*)("|')/,
preview: /\s*preview:\s*("|')(.*)("|')/,
category: /\s*category:\s*("|')(.*)("|')/,
html: /\s*html:\s*(`)([\s\S]*?)(`)/gm,
featured: /\s*featured:\s*(true|false)/,
connections: /\s*connections:( )([\S\s]*)(,)\s*layout:/
}

const getField = (fieldName, text) => {
regExp = fields[fieldName];
regExp.lastIndex = 0;

const matches = regExp.exec(text);
let match = matches && matches.length >= 3 && matches[2];
if (!match) {
match = matches && matches.length > 0 && matches[0];
}
return match;
}

const getMetadata = (text) => {
const metadata = {}
for (key in fields) {
metadata[key] = getField(key, text);
}
return metadata;
}

module.exports = {
getField,
getMetadata
}
Loading

0 comments on commit fd2f276

Please sign in to comment.