Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 | 4x 4x 4x 4x 29x 4x 29x 29x 29x 29x 29x 29x 29x 29x 29x 29x 29x 29x 29x 29x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x | /*---------------------------------------------------------------------------------------------
* Copyright (c) Bentley Systems, Incorporated. All rights reserved.
* See LICENSE.md in the project root for license terms and full copyright notice.
*--------------------------------------------------------------------------------------------*/
import { IModelApp } from "@itwin/core-frontend";
import type { EC3JobStatus, IEC3ConfigurationsClient, IEC3JobsClient, IOdataClient, IReportsClient, Report } from "@itwin/insights-client";
import { CARBON_CALCULATION_BASE_PATH, EC3ConfigurationsClient, EC3JobsClient, ODataClient, REPORTING_BASE_PATH, ReportsClient } from "@itwin/insights-client";
import type { GetAccessTokenFn } from "../context/APIContext";
import type { EC3Token } from "./EC3Token";
export const EC3URI = "https://buildingtransparency.org/";
/**
* EC3 Config Common Props
* @beta
*/
export interface EC3ConfigCommonProps {
/**
* The OAuth client ID used to authenticate with the EC3 API.
*/
clientId: string;
iTwinId: string;
/**
* A callback function that returns an access token for authenticating API requests.
* If not specified, it defaults to the authorizationClient of the IModelApp.
*/
getAccessToken?: GetAccessTokenFn;
/**
* The URI of the EC3 API. If not specified, it defaults to "https://buildingtransparency.org/".
*/
ec3Uri?: string;
/**
* The base path for the Reporting API endpoints. If not specified, it defaults to REPORTING_BASE_PATH from @itwin/insights-client.
*/
reportingBasePath?: string;
/**
* The base path for the Carbon Calculation API endpoints. If not specified, it defaults to CARBON_CALCULATION_BASE_PATH from @itwin/insights-client.
*/
carbonCalculationBasePath?: string;
/**
* A custom implementation of ReportsClient. If provided, reportingBasePath is ignored.
*/
reportsClient?: IReportsClient;
/**
* A custom implementation of OdataClient. If provided, reportingBasePath is ignored.
*/
oDataClient?: IOdataClient;
/**
* A custom implementation of EC3JobsClient. If provided, carbonCalculationBasePath is ignored.
*/
ec3JobsClient?: IEC3JobsClient;
/**
* A custom implementation of EC3ConfigurationClient. If provided, carbonCalculationBasePath is ignored.
*/
ec3ConfigurationsClient?: IEC3ConfigurationsClient;
}
/**
* EC3 Config Props with Redirect URI
* @beta
*/
export type EC3ConfigPropsWithRedirectUri = EC3ConfigCommonProps & {
/**
* The OAuth redirect URI used to authenticate with the EC3 API.
*/
redirectUri: string;
};
/**
* EC3 Config Props with EC3 Access Token
* @beta
*/
export type EC3ConfigPropsWithGetEC3AccessToken = EC3ConfigCommonProps & {
/**
* A callback function that returns an access token for the EC3 API.
*/
getEC3AccessToken: GetAccessTokenFn;
};
/**
* EC3 Config Props with default report
* @beta
*/
export type EC3ConfigPropsWithDefaultReport = EC3ConfigCommonProps & {
/**
* The default report to be used for EC3 configuration
*/
defaultReport?: Report;
};
export type EC3ConfigPropsWithCallbacks = EC3ConfigCommonProps & {
/**
* The callback function for export status.
*/
onExportResult?: (status: EC3JobStatus, templateId: string | undefined) => void;
};
/**
* EC3 Config Props
* @beta
*/
export type EC3ConfigProps =
| EC3ConfigPropsWithRedirectUri
| EC3ConfigPropsWithGetEC3AccessToken
| EC3ConfigPropsWithDefaultReport
| EC3ConfigPropsWithCallbacks;
export const getDefaultEC3Uri = (ec3Uri?: string) => {
return ec3Uri ?? EC3URI;
};
export class EC3Config {
public readonly clientId: string;
public readonly scope = "read%20write";
public readonly ec3Uri?: string;
public readonly reportingBasePath: string;
public readonly carbonCalculationBasePath: string;
public readonly iTwinId: string;
public readonly getAccessToken: GetAccessTokenFn;
public readonly getEC3AccessToken: GetAccessTokenFn;
public readonly defaultReport?: Report;
private token?: EC3Token;
private readonly redirectUri?: string;
public readonly reportsClient: IReportsClient;
public readonly oDataClient: IOdataClient;
public readonly ec3JobsClient: IEC3JobsClient;
public readonly ec3ConfigurationsClient: IEC3ConfigurationsClient;
constructor(props: EC3ConfigProps) {
this.clientId = props.clientId;
this.ec3Uri = getDefaultEC3Uri(props.ec3Uri);
this.iTwinId = props.iTwinId;
this.reportingBasePath = props.reportingBasePath ? REPORTING_BASE_PATH.replace("https://api.bentley.com", props.reportingBasePath) : REPORTING_BASE_PATH;
this.carbonCalculationBasePath = props.carbonCalculationBasePath
? CARBON_CALCULATION_BASE_PATH.replace("https://api.bentley.com", props.carbonCalculationBasePath)
: CARBON_CALCULATION_BASE_PATH;
this.getAccessToken = props.getAccessToken ?? (async () => (IModelApp.authorizationClient ? IModelApp.authorizationClient.getAccessToken() : ""));
this.redirectUri = "redirectUri" in props ? props.redirectUri : undefined;
this.getEC3AccessToken = "getEC3AccessToken" in props ? props.getEC3AccessToken : this.getAuthWindowToken.bind(this);
this.defaultReport = "defaultReport" in props ? props.defaultReport : undefined;
this.reportsClient = props.reportsClient ?? new ReportsClient(this.reportingBasePath);
this.oDataClient = props.oDataClient ?? new ODataClient(this.reportingBasePath);
this.ec3JobsClient = props.ec3JobsClient ?? new EC3JobsClient(this.carbonCalculationBasePath);
this.ec3ConfigurationsClient = props.ec3ConfigurationsClient ?? new EC3ConfigurationsClient(this.carbonCalculationBasePath);
}
private tokenExpired(): boolean {
const EXPIRATION_REDUCTION_BY_MS = 300000; // 5 minutes in milliseconds
return !(this.token && this.token.exp - EXPIRATION_REDUCTION_BY_MS > Date.now());
}
private async getAuthWindowToken(): Promise<string> {
return new Promise((resolve, reject) => {
if (this.tokenExpired()) {
let authWindow: Window | null = null;
const receiveMessage = (event: MessageEvent<EC3Token>) => {
Iif (event.data.source !== "ec3-auth") return;
authWindow?.close();
window.removeEventListener("message", receiveMessage, false);
Iif (!event.data.token) {
reject("Invalid token received");
return;
}
this.token = event.data;
resolve(event.data.token);
};
window.addEventListener("message", receiveMessage, false);
const url = this.getAuthorizationUrl();
authWindow = window.open(url, "_blank", "toolbar=0,location=0,menubar=0,width=800,height=700");
} else E{
resolve(this.token!.token);
}
});
}
private getAuthorizationUrl(): string {
return `${this.ec3Uri}oauth2/authorize?client_id=${this.clientId}&redirect_uri=${this.redirectUri}&response_type=code&scope=${this.scope}`;
}
}
|