d74e05ee493cfaea8177083f4a5fe55d23b53791
[arvados-workbench2.git] / src / store / users / users-actions.ts
1 // Copyright (C) The Arvados Authors. All rights reserved.
2 //
3 // SPDX-License-Identifier: AGPL-3.0
4
5 import { Dispatch } from "redux";
6 import { bindDataExplorerActions } from 'store/data-explorer/data-explorer-action';
7 import { RootState } from 'store/store';
8 import { getUserUuid } from "common/getuser";
9 import { ServiceRepository } from "services/services";
10 import { dialogActions } from 'store/dialog/dialog-actions';
11 import { startSubmit, reset, stopSubmit } from "redux-form";
12 import { snackbarActions, SnackbarKind } from 'store/snackbar/snackbar-actions';
13 import { UserResource } from "models/user";
14 import { getResource } from 'store/resources/resources';
15 import { navigateTo, navigateToUsers, navigateToRootProject } from "store/navigation/navigation-action";
16 import { authActions } from 'store/auth/auth-action';
17 import { getTokenV2 } from "models/api-client-authorization";
18 import { VIRTUAL_MACHINE_ADD_LOGIN_GROUPS_FIELD, VIRTUAL_MACHINE_ADD_LOGIN_VM_FIELD } from "store/virtual-machines/virtual-machines-actions";
19 import { PermissionLevel } from "models/permission";
20 import { updateResources } from "store/resources/resources-actions";
21
22 export const USERS_PANEL_ID = 'usersPanel';
23 export const USER_ATTRIBUTES_DIALOG = 'userAttributesDialog';
24 export const USER_CREATE_FORM_NAME = 'userCreateFormName';
25
26 export interface UserCreateFormDialogData {
27     email: string;
28     [VIRTUAL_MACHINE_ADD_LOGIN_VM_FIELD]: string;
29     [VIRTUAL_MACHINE_ADD_LOGIN_GROUPS_FIELD]: string[];
30 }
31
32 export const userBindedActions = bindDataExplorerActions(USERS_PANEL_ID);
33
34 export const openUserAttributes = (uuid: string) =>
35     (dispatch: Dispatch, getState: () => RootState, services: ServiceRepository) => {
36         const { resources } = getState();
37         const data = getResource<UserResource>(uuid)(resources);
38         dispatch(dialogActions.OPEN_DIALOG({ id: USER_ATTRIBUTES_DIALOG, data }));
39     };
40
41 export const loginAs = (uuid: string) =>
42     async (dispatch: Dispatch, getState: () => RootState, services: ServiceRepository) => {
43         const userUuid = getUserUuid(getState());
44         if (userUuid === uuid) {
45             dispatch(snackbarActions.OPEN_SNACKBAR({
46                 message: 'You are already logged in as this user',
47                 kind: SnackbarKind.WARNING
48             }));
49         } else {
50             try {
51                 const { resources } = getState();
52                 const data = getResource<UserResource>(uuid)(resources);
53                 const client = await services.apiClientAuthorizationService.create({ ownerUuid: uuid }, false);
54                 if (data) {
55                     dispatch<any>(authActions.INIT_USER({ user: data, token: getTokenV2(client) }));
56                     window.location.reload();
57                     dispatch<any>(navigateToRootProject);
58                 }
59             } catch (e) {
60                 if (e.status === 403) {
61                     dispatch(snackbarActions.OPEN_SNACKBAR({
62                         message: 'You do not have permission to login as this user',
63                         kind: SnackbarKind.WARNING
64                     }));
65                 } else {
66                     dispatch(snackbarActions.OPEN_SNACKBAR({
67                         message: 'Failed to login as this user',
68                         kind: SnackbarKind.ERROR
69                     }));
70                 }
71             }
72         }
73     };
74
75 export const openUserCreateDialog = () =>
76     async (dispatch: Dispatch, getState: () => RootState, services: ServiceRepository) => {
77         const userUuid = getUserUuid(getState());
78         if (!userUuid) { return; }
79         const user = await services.userService.get(userUuid!);
80         const virtualMachines = await services.virtualMachineService.list();
81         dispatch(reset(USER_CREATE_FORM_NAME));
82         dispatch(dialogActions.OPEN_DIALOG({ id: USER_CREATE_FORM_NAME, data: { user, ...virtualMachines } }));
83     };
84
85 export const openUserProjects = (uuid: string) =>
86     async (dispatch: Dispatch, getState: () => RootState, services: ServiceRepository) => {
87         dispatch<any>(navigateTo(uuid));
88     };
89
90 export const createUser = (data: UserCreateFormDialogData) =>
91     async (dispatch: Dispatch, getState: () => RootState, services: ServiceRepository) => {
92         dispatch(startSubmit(USER_CREATE_FORM_NAME));
93         try {
94             const newUser = await services.userService.create({
95                 email: data.email,
96             });
97             dispatch(updateResources([newUser]));
98
99             if (data[VIRTUAL_MACHINE_ADD_LOGIN_VM_FIELD]) {
100                 const permission = await services.permissionService.create({
101                     headUuid: data[VIRTUAL_MACHINE_ADD_LOGIN_VM_FIELD],
102                     tailUuid: newUser.uuid,
103                     name: PermissionLevel.CAN_LOGIN,
104                     properties: {
105                         username: newUser.username,
106                         groups: data.groups,
107                     }
108                 });
109                 dispatch(updateResources([permission]));
110             }
111
112             dispatch(dialogActions.CLOSE_DIALOG({ id: USER_CREATE_FORM_NAME }));
113             dispatch(reset(USER_CREATE_FORM_NAME));
114             dispatch(snackbarActions.OPEN_SNACKBAR({ message: "User has been successfully created.", hideDuration: 2000, kind: SnackbarKind.SUCCESS }));
115             dispatch<any>(loadUsersPanel());
116             dispatch(userBindedActions.REQUEST_ITEMS());
117             return newUser;
118         } catch (e) {
119             return;
120         } finally {
121             dispatch(stopSubmit(USER_CREATE_FORM_NAME));
122         }
123     };
124
125 export const openUserPanel = () =>
126     async (dispatch: Dispatch, getState: () => RootState, services: ServiceRepository) => {
127         const user = getState().auth.user;
128         if (user && user.isAdmin) {
129             dispatch<any>(navigateToUsers);
130         } else {
131             dispatch<any>(navigateToRootProject);
132             dispatch(snackbarActions.OPEN_SNACKBAR({ message: "You don't have permissions to view this page", hideDuration: 2000 }));
133         }
134     };
135
136 export const toggleIsAdmin = (uuid: string) =>
137     async (dispatch: Dispatch, getState: () => RootState, services: ServiceRepository) => {
138         const { resources } = getState();
139         const data = getResource<UserResource>(uuid)(resources);
140         const isAdmin = data!.isAdmin;
141         const newActivity = await services.userService.update(uuid, { isAdmin: !isAdmin });
142         dispatch<any>(loadUsersPanel());
143         return newActivity;
144     };
145
146 export const loadUsersPanel = () =>
147     (dispatch: Dispatch) => {
148         dispatch(userBindedActions.REQUEST_ITEMS());
149     };