export default function()

in dashboards-reports/server/routes/report.ts [26:331]


export default function (router: IRouter, config: ReportingConfig) {
  const protocol = config.get('osd_server', 'protocol');
  const hostname = config.get('osd_server', 'hostname');
  const port = config.get('osd_server', 'port');
  const basePath = config.osdConfig.get('server', 'basePath');
  // generate report (with provided metadata)
  router.post(
    {
      path: `${API_PREFIX}/generateReport`,
      validate: {
        body: schema.any(),
        query: schema.object({
          timezone: schema.maybe(schema.string()),
          dateFormat: schema.maybe(schema.string()),
          csvSeparator: schema.maybe(schema.string()),
        }),
      },
    },
    async (
      context,
      request,
      response
    ): Promise<IOpenSearchDashboardsResponse<any | ResponseError>> => {
      addToMetric('report', 'create', 'count');
      //@ts-ignore
      const logger: Logger = context.reporting_plugin.logger;
      let report = request.body;
      // input validation
      try {
        report.report_definition.report_params.core_params.origin = `${protocol}://${hostname}:${port}${basePath}`;
        report = await validateReport(
          context.core.opensearch.legacy.client,
          report,
          basePath
        );
      } catch (error) {
        logger.error(`Failed input validation for create report ${error}`);
        addToMetric('report', 'create', 'user_error');
        return response.badRequest({ body: error });
      }

      try {
        const reportData = await createReport(request, context, report, config);

        // if not deliver to user himself , no need to send actual file data to client
        const delivery = report.report_definition.delivery;
        addToMetric('report', 'create', 'count', report);
        return response.ok({
          body: {
            data: reportData.dataUrl,
            filename: reportData.fileName,
          },
        });
      } catch (error) {
        // TODO: better error handling for delivery and stages in generating report, pass logger to deeper level
        logger.error(`Failed to generate report: ${error}`);
        logger.error(error);
        addToMetric('report', 'create', checkErrorType(error));
        return errorResponse(response, error);
      }
    }
  );

  // generate report from report id
  router.get(
    {
      path: `${API_PREFIX}/generateReport/{reportId}`,
      validate: {
        params: schema.object({
          reportId: schema.string(),
        }),
        query: schema.object({
          timezone: schema.string(),
          dateFormat: schema.string(),
          csvSeparator: schema.string(),
        }),
      },
    },
    async (
      context,
      request,
      response
    ): Promise<IOpenSearchDashboardsResponse<any | ResponseError>> => {
      addToMetric('report', 'download', 'count');
      //@ts-ignore
      const logger: Logger = context.reporting_plugin.logger;
      try {
        const savedReportId = request.params.reportId;
        // @ts-ignore
        const opensearchReportsClient: ILegacyScopedClusterClient = context.reporting_plugin.opensearchReportsClient.asScoped(
          request
        );
        // get report
        const opensearchResp = await opensearchReportsClient.callAsCurrentUser(
          'opensearch_reports.getReportById',
          {
            reportInstanceId: savedReportId,
          }
        );
        // convert report to use UI model
        const report = backendToUiReport(
          opensearchResp.reportInstance,
          basePath
        );
        // generate report
        const reportData = await createReport(
          request,
          context,
          report,
          config,
          savedReportId
        );
        addToMetric('report', 'download', 'count', report);

        return response.ok({
          body: {
            data: reportData.dataUrl,
            filename: reportData.fileName,
          },
        });
      } catch (error) {
        logger.error(`Failed to generate report by id: ${error}`);
        logger.error(error);
        addToMetric('report', 'download', checkErrorType(error));
        return errorResponse(response, error);
      }
    }
  );

  // create report from existing report definition
  router.post(
    {
      path: `${API_PREFIX}/generateReport/{reportDefinitionId}`,
      validate: {
        params: schema.object({
          reportDefinitionId: schema.string(),
        }),
        query: schema.object({
          timezone: schema.string(),
          dateFormat: schema.string(),
          csvSeparator: schema.string(),
        }),
      },
    },
    async (
      context,
      request,
      response
    ): Promise<IOpenSearchDashboardsResponse<any | ResponseError>> => {
      addToMetric('report', 'create_from_definition', 'count');
      //@ts-ignore
      const logger: Logger = context.reporting_plugin.logger;
      const reportDefinitionId = request.params.reportDefinitionId;
      let report: any;
      try {
        // @ts-ignore
        const opensearchReportsClient: ILegacyScopedClusterClient = context.reporting_plugin.opensearchReportsClient.asScoped(
          request
        );
        // call OpenSearch API to create report from definition
        const opensearchResp = await opensearchReportsClient.callAsCurrentUser(
          'opensearch_reports.createReportFromDefinition',
          {
            reportDefinitionId: reportDefinitionId,
            body: {
              reportDefinitionId: reportDefinitionId,
            },
          }
        );
        const reportId = opensearchResp.reportInstance.id;
        // convert report to use UI model
        const report = backendToUiReport(
          opensearchResp.reportInstance,
          basePath
        );
        // generate report
        const reportData = await createReport(
          request,
          context,
          report,
          config,
          reportId
        );
        addToMetric('report', 'create_from_definition', 'count', report);

        return response.ok({
          body: {
            data: reportData.dataUrl,
            filename: reportData.fileName,
          },
        });
      } catch (error) {
        logger.error(
          `Failed to generate report from reportDefinition id ${reportDefinitionId} : ${error}`
        );
        logger.error(error);
        addToMetric('report', 'create_from_definition', checkErrorType(error));
        return errorResponse(response, error);
      }
    }
  );

  // get all reports details
  router.get(
    {
      path: `${API_PREFIX}/reports`,
      validate: {
        query: schema.object({
          fromIndex: schema.maybe(schema.number()),
          maxItems: schema.maybe(schema.number()),
        }),
      },
    },
    async (
      context,
      request,
      response
    ): Promise<IOpenSearchDashboardsResponse<any | ResponseError>> => {
      addToMetric('report', 'list', 'count');
      const { fromIndex, maxItems } = request.query as {
        fromIndex: number;
        maxItems: number;
      };

      try {
        // @ts-ignore
        const opensearchReportsClient: ILegacyScopedClusterClient = context.reporting_plugin.opensearchReportsClient.asScoped(
          request
        );
        const opensearchResp = await opensearchReportsClient.callAsCurrentUser(
          'opensearch_reports.getReports',
          {
            fromIndex: fromIndex,
            maxItems: maxItems || DEFAULT_MAX_SIZE,
          }
        );

        const reportsList = backendToUiReportsList(
          opensearchResp.reportInstanceList,
          basePath
        );

        return response.ok({
          body: {
            data: reportsList,
          },
        });
      } catch (error) {
        //@ts-ignore
        context.reporting_plugin.logger.error(
          `Failed to get reports details: ${error}`
        );
        addToMetric('report', 'list', checkErrorType(error));
        return errorResponse(response, error);
      }
    }
  );

  // get single report details by id
  router.get(
    {
      path: `${API_PREFIX}/reports/{reportId}`,
      validate: {
        params: schema.object({
          reportId: schema.string(),
        }),
      },
    },
    async (
      context,
      request,
      response
    ): Promise<IOpenSearchDashboardsResponse<any | ResponseError>> => {
      addToMetric('report', 'info', 'count');
      try {
        // @ts-ignore
        const opensearchReportsClient: ILegacyScopedClusterClient = context.reporting_plugin.opensearchReportsClient.asScoped(
          request
        );

        const opensearchResp = await opensearchReportsClient.callAsCurrentUser(
          'opensearch_reports.getReportById',
          {
            reportInstanceId: request.params.reportId,
          }
        );

        const report = backendToUiReport(
          opensearchResp.reportInstance,
          basePath
        );

        return response.ok({
          body: report,
        });
      } catch (error) {
        //@ts-ignore
        context.reporting_plugin.logger.error(
          `Failed to get single report details: ${error}`
        );
        addToMetric('report', 'info', checkErrorType(error));
        return errorResponse(response, error);
      }
    }
  );
}