1 | // (C) 2007-2020 GoodData Corporation
|
2 | import { XhrModule, ApiResponseError, ApiResponse } from "./xhr";
|
3 | import { ProjectModule } from "./project";
|
4 | import qs from "qs";
|
5 |
|
6 | export interface IUserConfigsSettingItem {
|
7 | settingItem: {
|
8 | key: string;
|
9 | links: {
|
10 | self: string;
|
11 | };
|
12 | source: string;
|
13 | value: string;
|
14 | };
|
15 | }
|
16 |
|
17 | export interface IUserConfigsResponse {
|
18 | settings: {
|
19 | items: IUserConfigsSettingItem[];
|
20 | };
|
21 | }
|
22 |
|
23 | export class UserModule {
|
24 | constructor(private xhr: XhrModule) {}
|
25 |
|
26 | /**
|
27 | * Find out whether a user is logged in
|
28 | *
|
29 | * @return {Promise} resolves with true if user logged in, false otherwise
|
30 | * @method isLoggedIn
|
31 | */
|
32 | public isLoggedIn(): Promise<boolean> {
|
33 | return new Promise((resolve, reject) => {
|
34 | this.xhr.get("/gdc/account/token").then(
|
35 | r => {
|
36 | if (r.response.ok) {
|
37 | resolve(true);
|
38 | }
|
39 |
|
40 | resolve(false);
|
41 | },
|
42 | (err: any) => {
|
43 | if (err.response.status === 401) {
|
44 | resolve(false);
|
45 | } else {
|
46 | reject(err);
|
47 | }
|
48 | },
|
49 | );
|
50 | });
|
51 | }
|
52 |
|
53 | /**
|
54 | * Find out whether a specified project is available to a currently logged user
|
55 | *
|
56 | * @method isLoggedInProject
|
57 | * @param {String} projectId A project identifier
|
58 | * @return {Promise} Resolves with true if user logged in and project available,
|
59 | * resolves with false if user logged in and project not available,
|
60 | * rejects if user not logged in
|
61 | */
|
62 | public isLoggedInProject(projectId: string) {
|
63 | return this.getCurrentProfile().then(profile => {
|
64 | return new Promise((resolve, reject) => {
|
65 | const projectModule = new ProjectModule(this.xhr);
|
66 |
|
67 | projectModule.getProjects(profile.links.self.split("/")[4]).then(
|
68 | projects => {
|
69 | if (projects.find((p: any) => p.links.self === `/gdc/projects/${projectId}`)) {
|
70 | resolve(true);
|
71 | } else {
|
72 | resolve(false);
|
73 | }
|
74 | },
|
75 | (err: ApiResponseError) => {
|
76 | reject(err);
|
77 | },
|
78 | );
|
79 | });
|
80 | });
|
81 | }
|
82 |
|
83 | /**
|
84 | * This function provides an authentication entry point to the GD API. It is needed to authenticate
|
85 | * by calling this function prior any other API calls. After providing valid credentials
|
86 | * every subsequent API call in a current session will be authenticated.
|
87 | *
|
88 | * @method login
|
89 | * @param {String} username
|
90 | * @param {String} password
|
91 | */
|
92 | public login(username: string, password: string) {
|
93 | return this.xhr
|
94 | .post("/gdc/account/login", {
|
95 | body: JSON.stringify({
|
96 | postUserLogin: {
|
97 | login: username,
|
98 | password,
|
99 | remember: 1,
|
100 | captcha: "",
|
101 | verifyCaptcha: "",
|
102 | },
|
103 | }),
|
104 | })
|
105 | .then(r => r.getData());
|
106 | }
|
107 |
|
108 | /**
|
109 | * This function provides an authentication entry point to the GD API via SSO
|
110 | * https://help.gooddata.com/display/developer/GoodData+PGP+Single+Sign-On
|
111 | *
|
112 | * @method loginSso
|
113 | * @param {String} encryptedClaims PGP message
|
114 | * @param {String} ssoProvider
|
115 | * @param {String} targetUrl
|
116 | */
|
117 | public loginSso(encryptedClaims: string, ssoProvider: string, targetUrl: string) {
|
118 | return this.xhr.post("/gdc/account/customerlogin", {
|
119 | data: {
|
120 | pgpLoginRequest: {
|
121 | targetUrl,
|
122 | ssoProvider,
|
123 | encryptedClaims,
|
124 | },
|
125 | },
|
126 | });
|
127 | }
|
128 |
|
129 | /**
|
130 | * Logs out current user
|
131 | * @method logout
|
132 | */
|
133 | public logout(): Promise<ApiResponse | void> {
|
134 | return this.isLoggedIn().then(
|
135 | (loggedIn: boolean): Promise<ApiResponse | void> => {
|
136 | if (loggedIn) {
|
137 | return this.xhr.get("/gdc/app/account/bootstrap").then((result: any) => {
|
138 | const data = result.getData();
|
139 | const userUri = data.bootstrapResource.accountSetting.links.self;
|
140 | const userId = userUri.match(/([^\/]+)\/?$/)[1];
|
141 |
|
142 | return this.xhr.del(`/gdc/account/login/${userId}`);
|
143 | });
|
144 | }
|
145 |
|
146 | return Promise.resolve();
|
147 | },
|
148 | (err: ApiResponseError) => Promise.reject(err),
|
149 | );
|
150 | }
|
151 |
|
152 | /**
|
153 | * Gets current user's profile
|
154 | * @method getCurrentProfile
|
155 | * @return {Promise} Resolves with account setting object
|
156 | */
|
157 | public getCurrentProfile() {
|
158 | return this.xhr.get("/gdc/account/profile/current").then(r => r.getData().accountSetting);
|
159 | }
|
160 |
|
161 | /**
|
162 | * Updates user's profile settings
|
163 | * @method updateProfileSettings
|
164 | * @param {String} profileId - User profile identifier
|
165 | * @param {Object} profileSetting
|
166 | */
|
167 | public updateProfileSettings(profileId: string, profileSetting: any): Promise<ApiResponse> {
|
168 | // TODO
|
169 | return this.xhr.put(`/gdc/account/profile/${profileId}/settings`, {
|
170 | body: profileSetting,
|
171 | });
|
172 | }
|
173 |
|
174 | /**
|
175 | * Returns info about currently logged in user from bootstrap resource
|
176 | * @method getAccountInfo
|
177 | */
|
178 | public getAccountInfo() {
|
179 | return this.xhr.get("/gdc/app/account/bootstrap").then((result: any) => {
|
180 | const data = result.getData();
|
181 | return this.getAccountInfoInBootstrap(data);
|
182 | });
|
183 | }
|
184 |
|
185 | /**
|
186 | * Returns current user info from bootstrapData
|
187 | * @method getAccountInfoInBootstrap
|
188 | * @param bootstrapData - data was got from bootstrap resource
|
189 | */
|
190 | public getAccountInfoInBootstrap(bootstrapData: any) {
|
191 | const {
|
192 | bootstrapResource: {
|
193 | accountSetting: {
|
194 | login,
|
195 | firstName,
|
196 | lastName,
|
197 | links: { self: profileUri },
|
198 | },
|
199 | current: { loginMD5 },
|
200 | settings: { organizationName },
|
201 | },
|
202 | } = bootstrapData;
|
203 | return {
|
204 | login,
|
205 | loginMD5,
|
206 | firstName,
|
207 | lastName,
|
208 | organizationName,
|
209 | profileUri,
|
210 | };
|
211 | }
|
212 |
|
213 | /**
|
214 | * Gets user configs including user specific feature flags
|
215 | *
|
216 | * @param {String} userId - A user identifier
|
217 | * @return {IUserConfigsSettingItem[]} An array of user configs setting item
|
218 | */
|
219 | public getUserConfigs(userId: string): Promise<IUserConfigsSettingItem[]> {
|
220 | return this.xhr.get(`/gdc/account/profile/${userId}/config`).then((apiResponse: ApiResponse) => {
|
221 | const userConfigs: IUserConfigsResponse = apiResponse.getData();
|
222 | const {
|
223 | settings: { items },
|
224 | } = userConfigs;
|
225 |
|
226 | return items || [];
|
227 | });
|
228 | }
|
229 |
|
230 | /**
|
231 | * Returns the feature flags valid for the currently logged in user.
|
232 | * @method getFeatureFlags
|
233 | */
|
234 | public getFeatureFlags() {
|
235 | return this.xhr
|
236 | .get("/gdc/app/account/bootstrap")
|
237 | .then((r: any) => r.getData())
|
238 | .then((result: any) => result.bootstrapResource.current.featureFlags);
|
239 | }
|
240 |
|
241 | /**
|
242 | * Initiates SPI SAML SSO
|
243 | * @param relayState URL of the page where the user is redirected after a successful login
|
244 | */
|
245 | public initiateSamlSso(relayState: string) {
|
246 | this.xhr
|
247 | .get(`/gdc/account/samlrequest?${qs.stringify({ relayState })}`)
|
248 | .then(data => data.getData())
|
249 | .then(response => {
|
250 | const loginUrl = response.samlRequests.items[0].samlRequest.loginUrl;
|
251 | window.location.assign(loginUrl);
|
252 | });
|
253 | }
|
254 | }
|