// (C) 2007-2020 GoodData Corporation import { XhrModule, ApiResponseError, ApiResponse } from "./xhr"; import { ProjectModule } from "./project"; import qs from "qs"; export interface IUserConfigsSettingItem { settingItem: { key: string; links: { self: string; }; source: string; value: string; }; } export interface IUserConfigsResponse { settings: { items: IUserConfigsSettingItem[]; }; } export class UserModule { constructor(private xhr: XhrModule) {} /** * Find out whether a user is logged in * * @return {Promise} resolves with true if user logged in, false otherwise * @method isLoggedIn */ public isLoggedIn(): Promise { return new Promise((resolve, reject) => { this.xhr.get("/gdc/account/token").then( r => { if (r.response.ok) { resolve(true); } resolve(false); }, (err: any) => { if (err.response.status === 401) { resolve(false); } else { reject(err); } }, ); }); } /** * Find out whether a specified project is available to a currently logged user * * @method isLoggedInProject * @param {String} projectId A project identifier * @return {Promise} Resolves with true if user logged in and project available, * resolves with false if user logged in and project not available, * rejects if user not logged in */ public isLoggedInProject(projectId: string) { return this.getCurrentProfile().then(profile => { return new Promise((resolve, reject) => { const projectModule = new ProjectModule(this.xhr); projectModule.getProjects(profile.links.self.split("/")[4]).then( projects => { if (projects.find((p: any) => p.links.self === `/gdc/projects/${projectId}`)) { resolve(true); } else { resolve(false); } }, (err: ApiResponseError) => { reject(err); }, ); }); }); } /** * This function provides an authentication entry point to the GD API. It is needed to authenticate * by calling this function prior any other API calls. After providing valid credentials * every subsequent API call in a current session will be authenticated. * * @method login * @param {String} username * @param {String} password */ public login(username: string, password: string) { return this.xhr .post("/gdc/account/login", { body: JSON.stringify({ postUserLogin: { login: username, password, remember: 1, captcha: "", verifyCaptcha: "", }, }), }) .then(r => r.getData()); } /** * This function provides an authentication entry point to the GD API via SSO * https://help.gooddata.com/display/developer/GoodData+PGP+Single+Sign-On * * @method loginSso * @param {String} encryptedClaims PGP message * @param {String} ssoProvider * @param {String} targetUrl */ public loginSso(encryptedClaims: string, ssoProvider: string, targetUrl: string) { return this.xhr.post("/gdc/account/customerlogin", { data: { pgpLoginRequest: { targetUrl, ssoProvider, encryptedClaims, }, }, }); } /** * Logs out current user * @method logout */ public logout(): Promise { return this.isLoggedIn().then( (loggedIn: boolean): Promise => { if (loggedIn) { return this.xhr.get("/gdc/app/account/bootstrap").then((result: any) => { const data = result.getData(); const userUri = data.bootstrapResource.accountSetting.links.self; const userId = userUri.match(/([^\/]+)\/?$/)[1]; return this.xhr.del(`/gdc/account/login/${userId}`); }); } return Promise.resolve(); }, (err: ApiResponseError) => Promise.reject(err), ); } /** * Gets current user's profile * @method getCurrentProfile * @return {Promise} Resolves with account setting object */ public getCurrentProfile() { return this.xhr.get("/gdc/account/profile/current").then(r => r.getData().accountSetting); } /** * Updates user's profile settings * @method updateProfileSettings * @param {String} profileId - User profile identifier * @param {Object} profileSetting */ public updateProfileSettings(profileId: string, profileSetting: any): Promise { // TODO return this.xhr.put(`/gdc/account/profile/${profileId}/settings`, { body: profileSetting, }); } /** * Returns info about currently logged in user from bootstrap resource * @method getAccountInfo */ public getAccountInfo() { return this.xhr.get("/gdc/app/account/bootstrap").then((result: any) => { const data = result.getData(); return this.getAccountInfoInBootstrap(data); }); } /** * Returns current user info from bootstrapData * @method getAccountInfoInBootstrap * @param bootstrapData - data was got from bootstrap resource */ public getAccountInfoInBootstrap(bootstrapData: any) { const { bootstrapResource: { accountSetting: { login, firstName, lastName, links: { self: profileUri }, }, current: { loginMD5 }, settings: { organizationName }, }, } = bootstrapData; return { login, loginMD5, firstName, lastName, organizationName, profileUri, }; } /** * Gets user configs including user specific feature flags * * @param {String} userId - A user identifier * @return {IUserConfigsSettingItem[]} An array of user configs setting item */ public getUserConfigs(userId: string): Promise { return this.xhr.get(`/gdc/account/profile/${userId}/config`).then((apiResponse: ApiResponse) => { const userConfigs: IUserConfigsResponse = apiResponse.getData(); const { settings: { items }, } = userConfigs; return items || []; }); } /** * Returns the feature flags valid for the currently logged in user. * @method getFeatureFlags */ public getFeatureFlags() { return this.xhr .get("/gdc/app/account/bootstrap") .then((r: any) => r.getData()) .then((result: any) => result.bootstrapResource.current.featureFlags); } /** * Initiates SPI SAML SSO * @param relayState URL of the page where the user is redirected after a successful login */ public initiateSamlSso(relayState: string) { this.xhr .get(`/gdc/account/samlrequest?${qs.stringify({ relayState })}`) .then(data => data.getData()) .then(response => { const loginUrl = response.samlRequests.items[0].samlRequest.loginUrl; window.location.assign(loginUrl); }); } }