mirror of
https://github.com/Abdulazizzn/n8n-enterprise-unlocked.git
synced 2025-12-18 02:21:13 +00:00
refactor(editor): Migrate users.store to composition API (no-changelog) (#9960)
This commit is contained in:
@@ -1376,13 +1376,6 @@ export interface IVersionsState {
|
|||||||
currentVersion: IVersion | undefined;
|
currentVersion: IVersion | undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IUsersState {
|
|
||||||
initialized: boolean;
|
|
||||||
currentUserId: null | string;
|
|
||||||
users: { [userId: string]: IUser };
|
|
||||||
currentUserCloudInfo: Cloud.UserAccount | null;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface IWorkflowsState {
|
export interface IWorkflowsState {
|
||||||
currentWorkflowExecutions: ExecutionSummary[];
|
currentWorkflowExecutions: ExecutionSummary[];
|
||||||
activeWorkflowExecution: ExecutionSummary | null;
|
activeWorkflowExecution: ExecutionSummary | null;
|
||||||
|
|||||||
@@ -119,7 +119,7 @@ export default defineComponent({
|
|||||||
...mapStores(useUsersStore, useProjectsStore),
|
...mapStores(useUsersStore, useProjectsStore),
|
||||||
userToDelete(): IUser | null {
|
userToDelete(): IUser | null {
|
||||||
if (!this.activeId) return null;
|
if (!this.activeId) return null;
|
||||||
return this.usersStore.getUserById(this.activeId);
|
return this.usersStore.usersById[this.activeId];
|
||||||
},
|
},
|
||||||
isPending(): boolean {
|
isPending(): boolean {
|
||||||
return this.userToDelete ? this.userToDelete && !this.userToDelete.firstName : false;
|
return this.userToDelete ? this.userToDelete && !this.userToDelete.firstName : false;
|
||||||
|
|||||||
@@ -254,7 +254,7 @@ const onSetupClick = async () => {
|
|||||||
|
|
||||||
const getMfaQR = async () => {
|
const getMfaQR = async () => {
|
||||||
try {
|
try {
|
||||||
const response = await userStore.getMfaQR();
|
const response = await userStore.fetchMfaQR();
|
||||||
qrCode.value = response.qrCode;
|
qrCode.value = response.qrCode;
|
||||||
secret.value = response.secret;
|
secret.value = response.secret;
|
||||||
recoveryCodes.value = response.recoveryCodes;
|
recoveryCodes.value = response.recoveryCodes;
|
||||||
|
|||||||
@@ -69,7 +69,7 @@ const firstLicensedRole = computed(() => projectRoles.value.find((role) => role.
|
|||||||
|
|
||||||
const onAddMember = (userId: string) => {
|
const onAddMember = (userId: string) => {
|
||||||
isDirty.value = true;
|
isDirty.value = true;
|
||||||
const user = usersStore.getUserById(userId);
|
const user = usersStore.usersById[userId];
|
||||||
if (!user) return;
|
if (!user) return;
|
||||||
|
|
||||||
const { id, firstName, lastName, email } = user;
|
const { id, firstName, lastName, email } = user;
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ const initialState = {
|
|||||||
},
|
},
|
||||||
[STORES.USERS]: {
|
[STORES.USERS]: {
|
||||||
currentUserId: 'aaa-bbb',
|
currentUserId: 'aaa-bbb',
|
||||||
users: {
|
usersById: {
|
||||||
'aaa-bbb': {
|
'aaa-bbb': {
|
||||||
id: 'aaa-bbb',
|
id: 'aaa-bbb',
|
||||||
role: ROLE.Owner,
|
role: ROLE.Owner,
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ const pinia = createTestingPinia({
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
[STORES.USERS]: {
|
[STORES.USERS]: {
|
||||||
users: {
|
usersById: {
|
||||||
123: {
|
123: {
|
||||||
email: 'john@doe.com',
|
email: 'john@doe.com',
|
||||||
firstName: 'John',
|
firstName: 'John',
|
||||||
|
|||||||
@@ -23,9 +23,8 @@ describe('V1 Banner', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('should render banner with dismiss call if user is owner', () => {
|
it('should render banner with dismiss call if user is owner', () => {
|
||||||
vi.spyOn(usersStore, 'currentUser', 'get').mockReturnValue({
|
usersStore.usersById = { '1': { role: ROLE.Owner } as IUser };
|
||||||
role: ROLE.Owner,
|
usersStore.currentUserId = '1';
|
||||||
} as IUser);
|
|
||||||
|
|
||||||
const { container } = render(V1Banner);
|
const { container } = render(V1Banner);
|
||||||
expect(container).toMatchSnapshot();
|
expect(container).toMatchSnapshot();
|
||||||
|
|||||||
@@ -45,7 +45,7 @@ function setCurrentUser() {
|
|||||||
|
|
||||||
function resetStores() {
|
function resetStores() {
|
||||||
useSettingsStore().$reset();
|
useSettingsStore().$reset();
|
||||||
useUsersStore().$reset();
|
useUsersStore().reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
function setup() {
|
function setup() {
|
||||||
|
|||||||
@@ -1,32 +1,11 @@
|
|||||||
import type { IUpdateUserSettingsReqPayload, UpdateGlobalRolePayload } from '@/api/users';
|
import type { IUpdateUserSettingsReqPayload, UpdateGlobalRolePayload } from '@/api/users';
|
||||||
import {
|
import * as usersApi from '@/api/users';
|
||||||
changePassword,
|
|
||||||
deleteUser,
|
|
||||||
getPasswordResetLink,
|
|
||||||
getUsers,
|
|
||||||
login,
|
|
||||||
loginCurrentUser,
|
|
||||||
logout,
|
|
||||||
sendForgotPasswordEmail,
|
|
||||||
setupOwner,
|
|
||||||
submitPersonalizationSurvey,
|
|
||||||
updateCurrentUser,
|
|
||||||
updateCurrentUserPassword,
|
|
||||||
updateCurrentUserSettings,
|
|
||||||
updateOtherUserSettings,
|
|
||||||
validatePasswordToken,
|
|
||||||
validateSignupToken,
|
|
||||||
updateGlobalRole,
|
|
||||||
} from '@/api/users';
|
|
||||||
import { PERSONALIZATION_MODAL_KEY, STORES, ROLE } from '@/constants';
|
import { PERSONALIZATION_MODAL_KEY, STORES, ROLE } from '@/constants';
|
||||||
import type {
|
import type {
|
||||||
Cloud,
|
Cloud,
|
||||||
IInviteResponse,
|
|
||||||
IPersonalizationLatestVersion,
|
IPersonalizationLatestVersion,
|
||||||
IRole,
|
|
||||||
IUser,
|
IUser,
|
||||||
IUserResponse,
|
IUserResponse,
|
||||||
IUsersState,
|
|
||||||
CurrentUserResponse,
|
CurrentUserResponse,
|
||||||
InvitableRoleName,
|
InvitableRoleName,
|
||||||
} from '@/Interface';
|
} from '@/Interface';
|
||||||
@@ -37,344 +16,410 @@ import { usePostHog } from './posthog.store';
|
|||||||
import { useSettingsStore } from './settings.store';
|
import { useSettingsStore } from './settings.store';
|
||||||
import { useUIStore } from './ui.store';
|
import { useUIStore } from './ui.store';
|
||||||
import { useCloudPlanStore } from './cloudPlan.store';
|
import { useCloudPlanStore } from './cloudPlan.store';
|
||||||
import { disableMfa, enableMfa, getMfaQR, verifyMfaToken } from '@/api/mfa';
|
import * as mfaApi from '@/api/mfa';
|
||||||
import { confirmEmail, getCloudUserInfo } from '@/api/cloudPlans';
|
import * as cloudApi from '@/api/cloudPlans';
|
||||||
import { useRBACStore } from '@/stores/rbac.store';
|
import { useRBACStore } from '@/stores/rbac.store';
|
||||||
import type { Scope } from '@n8n/permissions';
|
import type { Scope } from '@n8n/permissions';
|
||||||
import { inviteUsers, acceptInvitation } from '@/api/invitation';
|
import * as invitationsApi from '@/api/invitation';
|
||||||
import { useNpsSurveyStore } from './npsSurvey.store';
|
import { useNpsSurveyStore } from './npsSurvey.store';
|
||||||
|
import { computed, ref } from 'vue';
|
||||||
|
|
||||||
const isPendingUser = (user: IUserResponse | null) => !!user?.isPending;
|
const _isPendingUser = (user: IUserResponse | null) => !!user?.isPending;
|
||||||
const isInstanceOwner = (user: IUserResponse | null) => user?.role === ROLE.Owner;
|
const _isInstanceOwner = (user: IUserResponse | null) => user?.role === ROLE.Owner;
|
||||||
const isDefaultUser = (user: IUserResponse | null) => isInstanceOwner(user) && isPendingUser(user);
|
const _isDefaultUser = (user: IUserResponse | null) =>
|
||||||
|
_isInstanceOwner(user) && _isPendingUser(user);
|
||||||
|
|
||||||
export const useUsersStore = defineStore(STORES.USERS, {
|
export const useUsersStore = defineStore(STORES.USERS, () => {
|
||||||
state: (): IUsersState => ({
|
const initialized = ref(false);
|
||||||
initialized: false,
|
const currentUserId = ref<string | null>(null);
|
||||||
currentUserId: null,
|
const usersById = ref<Record<string, IUser>>({});
|
||||||
users: {},
|
const currentUserCloudInfo = ref<Cloud.UserAccount | null>(null);
|
||||||
currentUserCloudInfo: null,
|
|
||||||
}),
|
|
||||||
getters: {
|
|
||||||
allUsers(): IUser[] {
|
|
||||||
return Object.values(this.users);
|
|
||||||
},
|
|
||||||
userActivated(): boolean {
|
|
||||||
return Boolean(this.currentUser?.settings?.userActivated);
|
|
||||||
},
|
|
||||||
currentUser(): IUser | null {
|
|
||||||
return this.currentUserId ? this.users[this.currentUserId] : null;
|
|
||||||
},
|
|
||||||
isDefaultUser(): boolean {
|
|
||||||
return isDefaultUser(this.currentUser);
|
|
||||||
},
|
|
||||||
isInstanceOwner(): boolean {
|
|
||||||
return isInstanceOwner(this.currentUser);
|
|
||||||
},
|
|
||||||
mfaEnabled(): boolean {
|
|
||||||
return this.currentUser?.mfaEnabled ?? false;
|
|
||||||
},
|
|
||||||
getUserById(state) {
|
|
||||||
return (userId: string): IUser | null => state.users[userId];
|
|
||||||
},
|
|
||||||
globalRoleName(): IRole {
|
|
||||||
return this.currentUser?.role ?? 'default';
|
|
||||||
},
|
|
||||||
personalizedNodeTypes(): string[] {
|
|
||||||
const user = this.currentUser;
|
|
||||||
if (!user) {
|
|
||||||
return [];
|
|
||||||
}
|
|
||||||
|
|
||||||
const answers = user.personalizationAnswers;
|
// Stores
|
||||||
if (!answers) {
|
|
||||||
return [];
|
|
||||||
}
|
|
||||||
return getPersonalizedNodeTypes(answers);
|
|
||||||
},
|
|
||||||
},
|
|
||||||
actions: {
|
|
||||||
async initialize() {
|
|
||||||
if (this.initialized) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
const RBACStore = useRBACStore();
|
||||||
await this.loginWithCookie();
|
const npsSurveyStore = useNpsSurveyStore();
|
||||||
this.initialized = true;
|
const uiStore = useUIStore();
|
||||||
} catch (e) {}
|
const rootStore = useRootStore();
|
||||||
},
|
const settingsStore = useSettingsStore();
|
||||||
setCurrentUser(user: CurrentUserResponse) {
|
const cloudPlanStore = useCloudPlanStore();
|
||||||
this.addUsers([user]);
|
|
||||||
this.currentUserId = user.id;
|
|
||||||
|
|
||||||
const defaultScopes: Scope[] = [];
|
// Composables
|
||||||
useRBACStore().setGlobalScopes(user.globalScopes || defaultScopes);
|
|
||||||
usePostHog().init(user.featureFlags);
|
|
||||||
useNpsSurveyStore().setupNpsSurveyOnLogin(user.id, user.settings);
|
|
||||||
},
|
|
||||||
unsetCurrentUser() {
|
|
||||||
this.currentUserId = null;
|
|
||||||
this.currentUserCloudInfo = null;
|
|
||||||
useRBACStore().setGlobalScopes([]);
|
|
||||||
},
|
|
||||||
addUsers(users: IUserResponse[]) {
|
|
||||||
users.forEach((userResponse: IUserResponse) => {
|
|
||||||
const prevUser = this.users[userResponse.id] || {};
|
|
||||||
const updatedUser = {
|
|
||||||
...prevUser,
|
|
||||||
...userResponse,
|
|
||||||
};
|
|
||||||
const user: IUser = {
|
|
||||||
...updatedUser,
|
|
||||||
fullName: userResponse.firstName
|
|
||||||
? `${updatedUser.firstName} ${updatedUser.lastName || ''}`
|
|
||||||
: undefined,
|
|
||||||
isDefaultUser: isDefaultUser(updatedUser),
|
|
||||||
isPendingUser: isPendingUser(updatedUser),
|
|
||||||
};
|
|
||||||
|
|
||||||
this.users = {
|
const postHogStore = usePostHog();
|
||||||
...this.users,
|
|
||||||
[user.id]: user,
|
|
||||||
};
|
|
||||||
});
|
|
||||||
},
|
|
||||||
deleteUserById(userId: string): void {
|
|
||||||
const { [userId]: _, ...users } = this.users;
|
|
||||||
this.users = users;
|
|
||||||
},
|
|
||||||
setPersonalizationAnswers(answers: IPersonalizationLatestVersion): void {
|
|
||||||
if (!this.currentUser) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
this.users = {
|
// Computed
|
||||||
...this.users,
|
|
||||||
[this.currentUser.id]: {
|
const allUsers = computed(() => Object.values(usersById.value));
|
||||||
...this.currentUser,
|
|
||||||
personalizationAnswers: answers,
|
const currentUser = computed(() =>
|
||||||
},
|
currentUserId.value ? usersById.value[currentUserId.value] : null,
|
||||||
|
);
|
||||||
|
|
||||||
|
const userActivated = computed(() => Boolean(currentUser.value?.settings?.userActivated));
|
||||||
|
|
||||||
|
const isDefaultUser = computed(() => _isDefaultUser(currentUser.value));
|
||||||
|
|
||||||
|
const isInstanceOwner = computed(() => _isInstanceOwner(currentUser.value));
|
||||||
|
|
||||||
|
const mfaEnabled = computed(() => currentUser.value?.mfaEnabled ?? false);
|
||||||
|
|
||||||
|
const globalRoleName = computed(() => currentUser.value?.role ?? 'default');
|
||||||
|
|
||||||
|
const personalizedNodeTypes = computed(() => {
|
||||||
|
const user = currentUser.value;
|
||||||
|
if (!user) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
const answers = user.personalizationAnswers;
|
||||||
|
if (!answers) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
return getPersonalizedNodeTypes(answers);
|
||||||
|
});
|
||||||
|
|
||||||
|
// Methods
|
||||||
|
|
||||||
|
const addUsers = (newUsers: IUserResponse[]) => {
|
||||||
|
newUsers.forEach((userResponse: IUserResponse) => {
|
||||||
|
const prevUser = usersById.value[userResponse.id] || {};
|
||||||
|
const updatedUser = {
|
||||||
|
...prevUser,
|
||||||
|
...userResponse,
|
||||||
|
};
|
||||||
|
const user: IUser = {
|
||||||
|
...updatedUser,
|
||||||
|
fullName: userResponse.firstName
|
||||||
|
? `${updatedUser.firstName} ${updatedUser.lastName || ''}`
|
||||||
|
: undefined,
|
||||||
|
isDefaultUser: _isDefaultUser(updatedUser),
|
||||||
|
isPendingUser: _isPendingUser(updatedUser),
|
||||||
};
|
};
|
||||||
},
|
|
||||||
async loginWithCookie(): Promise<void> {
|
|
||||||
const rootStore = useRootStore();
|
|
||||||
const user = await loginCurrentUser(rootStore.restApiContext);
|
|
||||||
if (!user) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
this.setCurrentUser(user);
|
usersById.value = {
|
||||||
},
|
...usersById.value,
|
||||||
async loginWithCreds(params: {
|
[user.id]: user,
|
||||||
email: string;
|
};
|
||||||
password: string;
|
});
|
||||||
mfaToken?: string;
|
};
|
||||||
mfaRecoveryCode?: string;
|
|
||||||
}): Promise<void> {
|
|
||||||
const rootStore = useRootStore();
|
|
||||||
const user = await login(rootStore.restApiContext, params);
|
|
||||||
if (!user) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
this.setCurrentUser(user);
|
const setCurrentUser = (user: CurrentUserResponse) => {
|
||||||
},
|
addUsers([user]);
|
||||||
async logout(): Promise<void> {
|
currentUserId.value = user.id;
|
||||||
const rootStore = useRootStore();
|
|
||||||
await logout(rootStore.restApiContext);
|
const defaultScopes: Scope[] = [];
|
||||||
this.unsetCurrentUser();
|
RBACStore.setGlobalScopes(user.globalScopes || defaultScopes);
|
||||||
useCloudPlanStore().reset();
|
postHogStore.init(user.featureFlags);
|
||||||
usePostHog().reset();
|
npsSurveyStore.setupNpsSurveyOnLogin(user.id, user.settings);
|
||||||
useUIStore().clearBannerStack();
|
};
|
||||||
useNpsSurveyStore().resetNpsSurveyOnLogOut();
|
|
||||||
},
|
const loginWithCookie = async () => {
|
||||||
async createOwner(params: {
|
const user = await usersApi.loginCurrentUser(rootStore.restApiContext);
|
||||||
firstName: string;
|
if (!user) {
|
||||||
lastName: string;
|
return;
|
||||||
email: string;
|
}
|
||||||
password: string;
|
|
||||||
}): Promise<void> {
|
setCurrentUser(user);
|
||||||
const rootStore = useRootStore();
|
};
|
||||||
const user = await setupOwner(rootStore.restApiContext, params);
|
|
||||||
const settingsStore = useSettingsStore();
|
const initialize = async () => {
|
||||||
if (user) {
|
if (initialized.value) {
|
||||||
this.setCurrentUser(user);
|
return;
|
||||||
settingsStore.stopShowingSetupPage();
|
}
|
||||||
}
|
|
||||||
},
|
try {
|
||||||
async validateSignupToken(params: {
|
await loginWithCookie();
|
||||||
inviteeId: string;
|
initialized.value = true;
|
||||||
inviterId: string;
|
} catch (e) {}
|
||||||
}): Promise<{ inviter: { firstName: string; lastName: string } }> {
|
};
|
||||||
const rootStore = useRootStore();
|
|
||||||
return await validateSignupToken(rootStore.restApiContext, params);
|
const unsetCurrentUser = () => {
|
||||||
},
|
currentUserId.value = null;
|
||||||
async acceptInvitation(params: {
|
currentUserCloudInfo.value = null;
|
||||||
inviteeId: string;
|
RBACStore.setGlobalScopes([]);
|
||||||
inviterId: string;
|
};
|
||||||
firstName: string;
|
|
||||||
lastName: string;
|
const deleteUserById = (userId: string) => {
|
||||||
password: string;
|
const { [userId]: _, ...rest } = usersById.value;
|
||||||
}): Promise<void> {
|
usersById.value = rest;
|
||||||
const rootStore = useRootStore();
|
};
|
||||||
const user = await acceptInvitation(rootStore.restApiContext, params);
|
|
||||||
if (user) {
|
const setPersonalizationAnswers = (answers: IPersonalizationLatestVersion) => {
|
||||||
this.setCurrentUser(user);
|
if (!currentUser.value) {
|
||||||
}
|
return;
|
||||||
},
|
}
|
||||||
async sendForgotPasswordEmail(params: { email: string }): Promise<void> {
|
|
||||||
const rootStore = useRootStore();
|
usersById.value = {
|
||||||
await sendForgotPasswordEmail(rootStore.restApiContext, params);
|
...usersById.value,
|
||||||
},
|
[currentUser.value.id]: {
|
||||||
async validatePasswordToken(params: { token: string }): Promise<void> {
|
...currentUser.value,
|
||||||
const rootStore = useRootStore();
|
personalizationAnswers: answers,
|
||||||
await validatePasswordToken(rootStore.restApiContext, params);
|
},
|
||||||
},
|
};
|
||||||
async changePassword(params: {
|
};
|
||||||
token: string;
|
|
||||||
password: string;
|
const loginWithCreds = async (params: {
|
||||||
mfaToken?: string;
|
email: string;
|
||||||
}): Promise<void> {
|
password: string;
|
||||||
const rootStore = useRootStore();
|
mfaToken?: string;
|
||||||
await changePassword(rootStore.restApiContext, params);
|
mfaRecoveryCode?: string;
|
||||||
},
|
}) => {
|
||||||
async updateUser(params: {
|
const user = await usersApi.login(rootStore.restApiContext, params);
|
||||||
id: string;
|
if (!user) {
|
||||||
firstName: string;
|
return;
|
||||||
lastName: string;
|
}
|
||||||
email: string;
|
|
||||||
}): Promise<void> {
|
setCurrentUser(user);
|
||||||
const rootStore = useRootStore();
|
};
|
||||||
const user = await updateCurrentUser(rootStore.restApiContext, params);
|
|
||||||
this.addUsers([user]);
|
const logout = async () => {
|
||||||
},
|
await usersApi.logout(rootStore.restApiContext);
|
||||||
async updateUserSettings(settings: IUpdateUserSettingsReqPayload): Promise<void> {
|
unsetCurrentUser();
|
||||||
const rootStore = useRootStore();
|
cloudPlanStore.reset();
|
||||||
const updatedSettings = await updateCurrentUserSettings(rootStore.restApiContext, settings);
|
postHogStore.reset();
|
||||||
if (this.currentUser) {
|
uiStore.clearBannerStack();
|
||||||
this.currentUser.settings = updatedSettings;
|
npsSurveyStore.resetNpsSurveyOnLogOut();
|
||||||
this.addUsers([this.currentUser]);
|
};
|
||||||
}
|
|
||||||
},
|
const createOwner = async (params: {
|
||||||
async updateOtherUserSettings(
|
firstName: string;
|
||||||
userId: string,
|
lastName: string;
|
||||||
settings: IUpdateUserSettingsReqPayload,
|
email: string;
|
||||||
): Promise<void> {
|
password: string;
|
||||||
const rootStore = useRootStore();
|
}) => {
|
||||||
const updatedSettings = await updateOtherUserSettings(
|
const user = await usersApi.setupOwner(rootStore.restApiContext, params);
|
||||||
rootStore.restApiContext,
|
if (user) {
|
||||||
userId,
|
setCurrentUser(user);
|
||||||
settings,
|
settingsStore.stopShowingSetupPage();
|
||||||
);
|
}
|
||||||
this.users[userId].settings = updatedSettings;
|
};
|
||||||
this.addUsers([this.users[userId]]);
|
|
||||||
},
|
const validateSignupToken = async (params: { inviteeId: string; inviterId: string }) => {
|
||||||
async updateCurrentUserPassword({
|
return await usersApi.validateSignupToken(rootStore.restApiContext, params);
|
||||||
password,
|
};
|
||||||
|
|
||||||
|
const acceptInvitation = async (params: {
|
||||||
|
inviteeId: string;
|
||||||
|
inviterId: string;
|
||||||
|
firstName: string;
|
||||||
|
lastName: string;
|
||||||
|
password: string;
|
||||||
|
}) => {
|
||||||
|
const user = await invitationsApi.acceptInvitation(rootStore.restApiContext, params);
|
||||||
|
if (user) {
|
||||||
|
setCurrentUser(user);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const sendForgotPasswordEmail = async (params: { email: string }) => {
|
||||||
|
await usersApi.sendForgotPasswordEmail(rootStore.restApiContext, params);
|
||||||
|
};
|
||||||
|
|
||||||
|
const validatePasswordToken = async (params: { token: string }) => {
|
||||||
|
await usersApi.validatePasswordToken(rootStore.restApiContext, params);
|
||||||
|
};
|
||||||
|
|
||||||
|
const changePassword = async (params: { token: string; password: string; mfaToken?: string }) => {
|
||||||
|
await usersApi.changePassword(rootStore.restApiContext, params);
|
||||||
|
};
|
||||||
|
|
||||||
|
const updateUser = async (params: {
|
||||||
|
id: string;
|
||||||
|
firstName: string;
|
||||||
|
lastName: string;
|
||||||
|
email: string;
|
||||||
|
}) => {
|
||||||
|
const user = await usersApi.updateCurrentUser(rootStore.restApiContext, params);
|
||||||
|
addUsers([user]);
|
||||||
|
};
|
||||||
|
|
||||||
|
const updateUserSettings = async (settings: IUpdateUserSettingsReqPayload) => {
|
||||||
|
const updatedSettings = await usersApi.updateCurrentUserSettings(
|
||||||
|
rootStore.restApiContext,
|
||||||
|
settings,
|
||||||
|
);
|
||||||
|
if (currentUser.value) {
|
||||||
|
currentUser.value.settings = updatedSettings;
|
||||||
|
addUsers([currentUser.value]);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const updateOtherUserSettings = async (
|
||||||
|
userId: string,
|
||||||
|
settings: IUpdateUserSettingsReqPayload,
|
||||||
|
) => {
|
||||||
|
const updatedSettings = await usersApi.updateOtherUserSettings(
|
||||||
|
rootStore.restApiContext,
|
||||||
|
userId,
|
||||||
|
settings,
|
||||||
|
);
|
||||||
|
usersById.value[userId].settings = updatedSettings;
|
||||||
|
addUsers([usersById.value[userId]]);
|
||||||
|
};
|
||||||
|
|
||||||
|
const updateCurrentUserPassword = async ({
|
||||||
|
password,
|
||||||
|
currentPassword,
|
||||||
|
}: {
|
||||||
|
password: string;
|
||||||
|
currentPassword: string;
|
||||||
|
}) => {
|
||||||
|
await usersApi.updateCurrentUserPassword(rootStore.restApiContext, {
|
||||||
|
newPassword: password,
|
||||||
currentPassword,
|
currentPassword,
|
||||||
}: {
|
});
|
||||||
password: string;
|
};
|
||||||
currentPassword: string;
|
|
||||||
}): Promise<void> {
|
|
||||||
const rootStore = useRootStore();
|
|
||||||
await updateCurrentUserPassword(rootStore.restApiContext, {
|
|
||||||
newPassword: password,
|
|
||||||
currentPassword,
|
|
||||||
});
|
|
||||||
},
|
|
||||||
async deleteUser(params: { id: string; transferId?: string }): Promise<void> {
|
|
||||||
const rootStore = useRootStore();
|
|
||||||
await deleteUser(rootStore.restApiContext, params);
|
|
||||||
this.deleteUserById(params.id);
|
|
||||||
},
|
|
||||||
async fetchUsers(): Promise<void> {
|
|
||||||
const rootStore = useRootStore();
|
|
||||||
const users = await getUsers(rootStore.restApiContext);
|
|
||||||
this.addUsers(users);
|
|
||||||
},
|
|
||||||
async inviteUsers(
|
|
||||||
params: Array<{ email: string; role: InvitableRoleName }>,
|
|
||||||
): Promise<IInviteResponse[]> {
|
|
||||||
const rootStore = useRootStore();
|
|
||||||
const users = await inviteUsers(rootStore.restApiContext, params);
|
|
||||||
this.addUsers(
|
|
||||||
users.map(({ user }, index) => ({
|
|
||||||
isPending: true,
|
|
||||||
globalRole: { name: params[index].role },
|
|
||||||
...user,
|
|
||||||
})),
|
|
||||||
);
|
|
||||||
return users;
|
|
||||||
},
|
|
||||||
async reinviteUser({ email, role }: { email: string; role: InvitableRoleName }): Promise<void> {
|
|
||||||
const rootStore = useRootStore();
|
|
||||||
const invitationResponse = await inviteUsers(rootStore.restApiContext, [{ email, role }]);
|
|
||||||
if (!invitationResponse[0].user.emailSent) {
|
|
||||||
throw Error(invitationResponse[0].error);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
async getUserPasswordResetLink(params: { id: string }): Promise<{ link: string }> {
|
|
||||||
const rootStore = useRootStore();
|
|
||||||
return await getPasswordResetLink(rootStore.restApiContext, params);
|
|
||||||
},
|
|
||||||
async submitPersonalizationSurvey(results: IPersonalizationLatestVersion): Promise<void> {
|
|
||||||
const rootStore = useRootStore();
|
|
||||||
await submitPersonalizationSurvey(rootStore.restApiContext, results);
|
|
||||||
this.setPersonalizationAnswers(results);
|
|
||||||
},
|
|
||||||
async showPersonalizationSurvey(): Promise<void> {
|
|
||||||
const settingsStore = useSettingsStore();
|
|
||||||
const surveyEnabled = settingsStore.isPersonalizationSurveyEnabled;
|
|
||||||
const currentUser = this.currentUser;
|
|
||||||
if (surveyEnabled && currentUser && !currentUser.personalizationAnswers) {
|
|
||||||
const uiStore = useUIStore();
|
|
||||||
uiStore.openModal(PERSONALIZATION_MODAL_KEY);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
async getMfaQR(): Promise<{ qrCode: string; secret: string; recoveryCodes: string[] }> {
|
|
||||||
const rootStore = useRootStore();
|
|
||||||
return await getMfaQR(rootStore.restApiContext);
|
|
||||||
},
|
|
||||||
async verifyMfaToken(data: { token: string }): Promise<void> {
|
|
||||||
const rootStore = useRootStore();
|
|
||||||
return await verifyMfaToken(rootStore.restApiContext, data);
|
|
||||||
},
|
|
||||||
async enableMfa(data: { token: string }) {
|
|
||||||
const rootStore = useRootStore();
|
|
||||||
const usersStore = useUsersStore();
|
|
||||||
await enableMfa(rootStore.restApiContext, data);
|
|
||||||
const currentUser = usersStore.currentUser;
|
|
||||||
if (currentUser) {
|
|
||||||
currentUser.mfaEnabled = true;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
async disabledMfa() {
|
|
||||||
const rootStore = useRootStore();
|
|
||||||
const usersStore = useUsersStore();
|
|
||||||
await disableMfa(rootStore.restApiContext);
|
|
||||||
const currentUser = usersStore.currentUser;
|
|
||||||
if (currentUser) {
|
|
||||||
currentUser.mfaEnabled = false;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
async fetchUserCloudAccount() {
|
|
||||||
let cloudUser: Cloud.UserAccount | null = null;
|
|
||||||
try {
|
|
||||||
cloudUser = await getCloudUserInfo(useRootStore().restApiContext);
|
|
||||||
this.currentUserCloudInfo = cloudUser;
|
|
||||||
} catch (error) {
|
|
||||||
throw new Error(error);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
async confirmEmail() {
|
|
||||||
await confirmEmail(useRootStore().restApiContext);
|
|
||||||
},
|
|
||||||
|
|
||||||
async updateGlobalRole({ id, newRoleName }: UpdateGlobalRolePayload) {
|
const deleteUser = async (params: { id: string; transferId?: string }) => {
|
||||||
const rootStore = useRootStore();
|
await usersApi.deleteUser(rootStore.restApiContext, params);
|
||||||
await updateGlobalRole(rootStore.restApiContext, { id, newRoleName });
|
deleteUserById(params.id);
|
||||||
await this.fetchUsers();
|
};
|
||||||
},
|
|
||||||
},
|
const fetchUsers = async () => {
|
||||||
|
const users = await usersApi.getUsers(rootStore.restApiContext);
|
||||||
|
addUsers(users);
|
||||||
|
};
|
||||||
|
|
||||||
|
const inviteUsers = async (params: Array<{ email: string; role: InvitableRoleName }>) => {
|
||||||
|
const invitedUsers = await invitationsApi.inviteUsers(rootStore.restApiContext, params);
|
||||||
|
addUsers(
|
||||||
|
invitedUsers.map(({ user }, index) => ({
|
||||||
|
isPending: true,
|
||||||
|
globalRole: { name: params[index].role },
|
||||||
|
...user,
|
||||||
|
})),
|
||||||
|
);
|
||||||
|
return invitedUsers;
|
||||||
|
};
|
||||||
|
|
||||||
|
const reinviteUser = async ({ email, role }: { email: string; role: InvitableRoleName }) => {
|
||||||
|
const invitationResponse = await invitationsApi.inviteUsers(rootStore.restApiContext, [
|
||||||
|
{ email, role },
|
||||||
|
]);
|
||||||
|
if (!invitationResponse[0].user.emailSent) {
|
||||||
|
throw Error(invitationResponse[0].error);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const getUserPasswordResetLink = async (params: { id: string }) => {
|
||||||
|
return await usersApi.getPasswordResetLink(rootStore.restApiContext, params);
|
||||||
|
};
|
||||||
|
|
||||||
|
const submitPersonalizationSurvey = async (results: IPersonalizationLatestVersion) => {
|
||||||
|
await usersApi.submitPersonalizationSurvey(rootStore.restApiContext, results);
|
||||||
|
setPersonalizationAnswers(results);
|
||||||
|
};
|
||||||
|
|
||||||
|
const showPersonalizationSurvey = async () => {
|
||||||
|
const surveyEnabled = settingsStore.isPersonalizationSurveyEnabled;
|
||||||
|
if (surveyEnabled && currentUser.value && !currentUser.value.personalizationAnswers) {
|
||||||
|
uiStore.openModal(PERSONALIZATION_MODAL_KEY);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const fetchMfaQR = async () => {
|
||||||
|
return await mfaApi.getMfaQR(rootStore.restApiContext);
|
||||||
|
};
|
||||||
|
|
||||||
|
const verifyMfaToken = async (data: { token: string }) => {
|
||||||
|
return await mfaApi.verifyMfaToken(rootStore.restApiContext, data);
|
||||||
|
};
|
||||||
|
|
||||||
|
const enableMfa = async (data: { token: string }) => {
|
||||||
|
await mfaApi.enableMfa(rootStore.restApiContext, data);
|
||||||
|
if (currentUser.value) {
|
||||||
|
currentUser.value.mfaEnabled = true;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const disableMfa = async () => {
|
||||||
|
await mfaApi.disableMfa(rootStore.restApiContext);
|
||||||
|
if (currentUser.value) {
|
||||||
|
currentUser.value.mfaEnabled = false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const disabledMfa = async () => {
|
||||||
|
await mfaApi.disableMfa(rootStore.restApiContext);
|
||||||
|
if (currentUser.value) {
|
||||||
|
currentUser.value.mfaEnabled = false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const fetchUserCloudAccount = async () => {
|
||||||
|
let cloudUser: Cloud.UserAccount | null = null;
|
||||||
|
try {
|
||||||
|
cloudUser = await cloudApi.getCloudUserInfo(rootStore.restApiContext);
|
||||||
|
currentUserCloudInfo.value = cloudUser;
|
||||||
|
} catch (error) {
|
||||||
|
throw new Error(error);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const confirmEmail = async () => {
|
||||||
|
await cloudApi.confirmEmail(rootStore.restApiContext);
|
||||||
|
};
|
||||||
|
|
||||||
|
const updateGlobalRole = async ({ id, newRoleName }: UpdateGlobalRolePayload) => {
|
||||||
|
await usersApi.updateGlobalRole(rootStore.restApiContext, { id, newRoleName });
|
||||||
|
await fetchUsers();
|
||||||
|
};
|
||||||
|
|
||||||
|
const reset = () => {
|
||||||
|
initialized.value = false;
|
||||||
|
currentUserId.value = null;
|
||||||
|
usersById.value = {};
|
||||||
|
currentUserCloudInfo.value = null;
|
||||||
|
};
|
||||||
|
|
||||||
|
return {
|
||||||
|
initialized,
|
||||||
|
currentUserId,
|
||||||
|
usersById,
|
||||||
|
currentUserCloudInfo,
|
||||||
|
allUsers,
|
||||||
|
currentUser,
|
||||||
|
userActivated,
|
||||||
|
isDefaultUser,
|
||||||
|
isInstanceOwner,
|
||||||
|
mfaEnabled,
|
||||||
|
globalRoleName,
|
||||||
|
personalizedNodeTypes,
|
||||||
|
addUsers,
|
||||||
|
setCurrentUser,
|
||||||
|
loginWithCookie,
|
||||||
|
initialize,
|
||||||
|
unsetCurrentUser,
|
||||||
|
deleteUserById,
|
||||||
|
setPersonalizationAnswers,
|
||||||
|
loginWithCreds,
|
||||||
|
logout,
|
||||||
|
createOwner,
|
||||||
|
validateSignupToken,
|
||||||
|
acceptInvitation,
|
||||||
|
sendForgotPasswordEmail,
|
||||||
|
validatePasswordToken,
|
||||||
|
changePassword,
|
||||||
|
updateUser,
|
||||||
|
updateUserSettings,
|
||||||
|
updateOtherUserSettings,
|
||||||
|
updateCurrentUserPassword,
|
||||||
|
deleteUser,
|
||||||
|
fetchUsers,
|
||||||
|
inviteUsers,
|
||||||
|
reinviteUser,
|
||||||
|
getUserPasswordResetLink,
|
||||||
|
submitPersonalizationSurvey,
|
||||||
|
showPersonalizationSurvey,
|
||||||
|
fetchMfaQR,
|
||||||
|
verifyMfaToken,
|
||||||
|
enableMfa,
|
||||||
|
disableMfa,
|
||||||
|
fetchUserCloudAccount,
|
||||||
|
confirmEmail,
|
||||||
|
updateGlobalRole,
|
||||||
|
disabledMfa,
|
||||||
|
reset,
|
||||||
|
};
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -216,13 +216,13 @@ export default defineComponent({
|
|||||||
this.uiStore.openModal(INVITE_USER_MODAL_KEY);
|
this.uiStore.openModal(INVITE_USER_MODAL_KEY);
|
||||||
},
|
},
|
||||||
async onDelete(userId: string) {
|
async onDelete(userId: string) {
|
||||||
const user = this.usersStore.getUserById(userId);
|
const user = this.usersStore.usersById[userId];
|
||||||
if (user) {
|
if (user) {
|
||||||
this.uiStore.openDeleteUserModal(userId);
|
this.uiStore.openDeleteUserModal(userId);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
async onReinvite(userId: string) {
|
async onReinvite(userId: string) {
|
||||||
const user = this.usersStore.getUserById(userId);
|
const user = this.usersStore.usersById[userId];
|
||||||
if (user?.email && user?.role) {
|
if (user?.email && user?.role) {
|
||||||
if (!['global:admin', 'global:member'].includes(user.role)) {
|
if (!['global:admin', 'global:member'].includes(user.role)) {
|
||||||
throw new Error('Invalid role name on reinvite');
|
throw new Error('Invalid role name on reinvite');
|
||||||
@@ -245,7 +245,7 @@ export default defineComponent({
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
async onCopyInviteLink(userId: string) {
|
async onCopyInviteLink(userId: string) {
|
||||||
const user = this.usersStore.getUserById(userId);
|
const user = this.usersStore.usersById[userId];
|
||||||
if (user?.inviteAcceptUrl) {
|
if (user?.inviteAcceptUrl) {
|
||||||
void this.clipboard.copy(user.inviteAcceptUrl);
|
void this.clipboard.copy(user.inviteAcceptUrl);
|
||||||
|
|
||||||
@@ -257,7 +257,7 @@ export default defineComponent({
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
async onCopyPasswordResetLink(userId: string) {
|
async onCopyPasswordResetLink(userId: string) {
|
||||||
const user = this.usersStore.getUserById(userId);
|
const user = this.usersStore.usersById[userId];
|
||||||
if (user) {
|
if (user) {
|
||||||
const url = await this.usersStore.getUserPasswordResetLink(user);
|
const url = await this.usersStore.getUserPasswordResetLink(user);
|
||||||
void this.clipboard.copy(url.link);
|
void this.clipboard.copy(url.link);
|
||||||
@@ -270,7 +270,7 @@ export default defineComponent({
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
async onAllowSSOManualLogin(userId: string) {
|
async onAllowSSOManualLogin(userId: string) {
|
||||||
const user = this.usersStore.getUserById(userId);
|
const user = this.usersStore.usersById[userId];
|
||||||
if (user) {
|
if (user) {
|
||||||
if (!user.settings) {
|
if (!user.settings) {
|
||||||
user.settings = {};
|
user.settings = {};
|
||||||
@@ -286,7 +286,7 @@ export default defineComponent({
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
async onDisallowSSOManualLogin(userId: string) {
|
async onDisallowSSOManualLogin(userId: string) {
|
||||||
const user = this.usersStore.getUserById(userId);
|
const user = this.usersStore.usersById[userId];
|
||||||
if (user?.settings) {
|
if (user?.settings) {
|
||||||
user.settings.allowSSOManualLogin = false;
|
user.settings.allowSSOManualLogin = false;
|
||||||
await this.usersStore.updateOtherUserSettings(userId, user.settings);
|
await this.usersStore.updateOtherUserSettings(userId, user.settings);
|
||||||
|
|||||||
@@ -41,7 +41,7 @@ describe('SettingsPersonalView', () => {
|
|||||||
usersStore = useUsersStore(pinia);
|
usersStore = useUsersStore(pinia);
|
||||||
uiStore = useUIStore(pinia);
|
uiStore = useUIStore(pinia);
|
||||||
|
|
||||||
usersStore.users[currentUser.id] = currentUser;
|
usersStore.usersById[currentUser.id] = currentUser;
|
||||||
usersStore.currentUserId = currentUser.id;
|
usersStore.currentUserId = currentUser.id;
|
||||||
|
|
||||||
await settingsStore.getSettings();
|
await settingsStore.getSettings();
|
||||||
|
|||||||
Reference in New Issue
Block a user