Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[FIX] Redirect to login after delete own account #22499

Merged
merged 6 commits into from
Jul 5, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
53 changes: 32 additions & 21 deletions client/contexts/UserContext.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
import { useMutableCallback } from '@rocket.chat/fuselage-hooks';
import { FilterQuery } from 'mongodb';
import { createContext, useContext, useMemo } from 'react';
import { useSubscription, Subscription, Unsubscribe } from 'use-subscription';

import { IRoom } from '../../definition/IRoom';
import { ISubscription } from '../../definition/ISubscription';
import { useRoute } from './RouterContext';

type SubscriptionQuery =
| {
Expand Down Expand Up @@ -34,6 +36,7 @@ type UserContextValue = {
userId: string | null;
user: Meteor.User | null;
loginWithPassword: (user: string | object, password: string) => Promise<void>;
logout: () => Promise<void>;
queryPreference: <T>(
key: string | Mongo.ObjectID,
defaultValue?: T,
Expand All @@ -58,6 +61,7 @@ export const UserContext = createContext<UserContextValue>({
userId: null,
user: null,
loginWithPassword: async () => undefined,
logout: () => Promise.resolve(),
queryPreference: () => ({
getCurrentValue: (): undefined => undefined,
subscribe: (): Unsubscribe => (): void => undefined,
Expand Down Expand Up @@ -85,23 +89,33 @@ export const useLoginWithPassword = (): ((
password: string,
) => Promise<void>) => useContext(UserContext).loginWithPassword;

export const useLogout = (): (() => void) => {
const router = useRoute('home');
const { logout } = useContext(UserContext);

const handleLogout = useMutableCallback(() => {
logout();
router.push({});
});

return handleLogout;
};

export const useUserPreference = <T>(key: string, defaultValue?: T): T | undefined => {
const { queryPreference } = useContext(UserContext);
const subscription = useMemo(() => queryPreference(key, defaultValue), [
queryPreference,
key,
defaultValue,
]);
const subscription = useMemo(
() => queryPreference(key, defaultValue),
[queryPreference, key, defaultValue],
);
return useSubscription(subscription);
};

export const useUserSubscription = (rid: string, fields: Fields): ISubscription | undefined => {
const { querySubscription } = useContext(UserContext);
const subscription = useMemo(() => querySubscription({ rid }, fields), [
querySubscription,
rid,
fields,
]);
const subscription = useMemo(
() => querySubscription({ rid }, fields),
[querySubscription, rid, fields],
);
return useSubscription(subscription);
};

Expand All @@ -116,11 +130,10 @@ export const useUserSubscriptions = (
options?: FindOptions,
): Array<ISubscription> | [] => {
const { querySubscriptions } = useContext(UserContext);
const subscription = useMemo(() => querySubscriptions(query, options), [
querySubscriptions,
query,
options,
]);
const subscription = useMemo(
() => querySubscriptions(query, options),
[querySubscriptions, query, options],
);
return useSubscription(subscription);
};

Expand All @@ -130,11 +143,9 @@ export const useUserSubscriptionByName = (
sort?: Sort,
): ISubscription | undefined => {
const { querySubscription } = useContext(UserContext);
const subscription = useMemo(() => querySubscription({ name }, fields, sort), [
querySubscription,
name,
fields,
sort,
]);
const subscription = useMemo(
() => querySubscription({ name }, fields, sort),
[querySubscription, name, fields, sort],
);
return useSubscription(subscription);
};
16 changes: 16 additions & 0 deletions client/providers/UserProvider.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { Meteor } from 'meteor/meteor';
import React, { useMemo, FC } from 'react';

import { callbacks } from '../../app/callbacks/client';
import { Subscriptions, Rooms } from '../../app/models/client';
import { getUserPreference } from '../../app/utils/client';
import { IRoom } from '../../definition/IRoom';
Expand Down Expand Up @@ -29,6 +30,20 @@ const loginWithPassword = (user: string | object, password: string): Promise<voi
);
});

const logout = (): Promise<void> =>
new Promise((resolve) => {
const user = Meteor.user();

if (!user) {
return resolve();
}

Meteor.logout(() => {
callbacks.run('afterLogoutCleanUp', user);
Meteor.call('logoutCleanUp', user, resolve);
});
});

const UserProvider: FC = ({ children }) => {
const userId = useReactiveValue(getUserId);
const user = useReactiveValue(getUser);
Expand All @@ -37,6 +52,7 @@ const UserProvider: FC = ({ children }) => {
userId,
user,
loginWithPassword,
logout,
queryPreference: createReactiveSubscriptionFactory((key, defaultValue) =>
getUserPreference(userId, key, defaultValue),
),
Expand Down
19 changes: 8 additions & 11 deletions client/sidebar/header/UserDropdown.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import { Box, Margins, Divider, Option } from '@rocket.chat/fuselage';
import { useMutableCallback } from '@rocket.chat/fuselage-hooks';
import { FlowRouter } from 'meteor/kadira:flow-router';
import { Meteor } from 'meteor/meteor';
import React from 'react';

import { callbacks } from '../../../app/callbacks/client';
Expand All @@ -14,6 +13,7 @@ import { useAtLeastOnePermission } from '../../contexts/AuthorizationContext';
import { useRoute } from '../../contexts/RouterContext';
import { useSetting } from '../../contexts/SettingsContext';
import { useTranslation } from '../../contexts/TranslationContext';
import { useLogout } from '../../contexts/UserContext';
import { useReactiveValue } from '../../hooks/useReactiveValue';

const ADMIN_PERMISSIONS = [
Expand Down Expand Up @@ -47,10 +47,11 @@ const getItems = () => AccountBox.getItems();

const UserDropdown = ({ user, onClose }) => {
const t = useTranslation();
const homeRoute = useRoute('home');
const accountRoute = useRoute('account');
const adminRoute = useRoute('admin');

const logout = useLogout();

const { name, username, avatarETag, status, statusText } = user;

const useRealName = useSetting('UI_Use_Real_Name');
Expand Down Expand Up @@ -78,15 +79,6 @@ const UserDropdown = ({ user, onClose }) => {
onClose();
});

const handleLogout = useMutableCallback(() => {
Meteor.logout(() => {
callbacks.run('afterLogoutCleanUp', user);
Meteor.call('logoutCleanUp', user);
homeRoute.push({});
popover.close();
});
});

const handleMyAccount = useMutableCallback(() => {
accountRoute.push({});
popover.close();
Expand All @@ -97,6 +89,11 @@ const UserDropdown = ({ user, onClose }) => {
popover.close();
});

const handleLogout = useMutableCallback(() => {
logout();
popover.close();
});

const accountBoxItems = useReactiveValue(getItems);

return (
Expand Down
21 changes: 16 additions & 5 deletions client/views/account/AccountProfilePage.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import { useMethod } from '../../contexts/ServerContext';
import { useSetting } from '../../contexts/SettingsContext';
import { useToastMessageDispatch } from '../../contexts/ToastMessagesContext';
import { useTranslation } from '../../contexts/TranslationContext';
import { useUser } from '../../contexts/UserContext';
import { useUser, useLogout } from '../../contexts/UserContext';
import { useForm } from '../../hooks/useForm';
import { useUpdateAvatar } from '../../hooks/useUpdateAvatar';
import AccountProfileForm from './AccountProfileForm';
Expand All @@ -37,9 +37,10 @@ const AccountProfilePage = () => {

const user = useUser();

const { values, handlers, hasUnsavedChanges, commit } = useForm(getInitialValues(user));
const { values, handlers, hasUnsavedChanges, commit } = useForm(getInitialValues(user ?? {}));
const [canSave, setCanSave] = useState(true);
const setModal = useSetModal();
const logout = useLogout();
const [loggingOut, setLoggingOut] = useState(false);

const logoutOtherClients = useMethod('logoutOtherClients');
Expand Down Expand Up @@ -114,7 +115,7 @@ const AccountProfilePage = () => {

const { handleAvatar, handlePassword, handleConfirmationPassword } = handlers;

const updateAvatar = useUpdateAvatar(avatar, user._id);
const updateAvatar = useUpdateAvatar(avatar, user?._id);

const onSave = useCallback(async () => {
const save = async (typedPassword) => {
Expand Down Expand Up @@ -192,6 +193,7 @@ const AccountProfilePage = () => {
try {
await deleteOwnAccount(SHA256(passwordOrUsername));
dispatchToastMessage({ type: 'success', message: t('User_has_been_deleted') });
logout();
} catch (error) {
if (error.error === 'user-last-owner') {
const { shouldChangeOwner, shouldBeRemoved } = error.details;
Expand Down Expand Up @@ -233,7 +235,16 @@ const AccountProfilePage = () => {
text={t('If_you_are_sure_type_in_your_username')}
/>
));
}, [closeModal, deleteOwnAccount, dispatchToastMessage, erasureType, localPassword, t, setModal]);
}, [
closeModal,
deleteOwnAccount,
dispatchToastMessage,
erasureType,
localPassword,
t,
logout,
setModal,
]);

return (
<Page>
Expand All @@ -249,7 +260,7 @@ const AccountProfilePage = () => {
<AccountProfileForm
values={values}
handlers={handlers}
user={user}
user={user ?? { emails: [] }}
settings={settings}
onSaveStateChange={setCanSave}
/>
Expand Down
14 changes: 11 additions & 3 deletions client/views/account/ActionConfirmModal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ import {
PasswordInput,
TextInput,
Modal,
FieldGroup,
Field,
} from '@rocket.chat/fuselage';
import React, { useState, useCallback, FC } from 'react';

Expand Down Expand Up @@ -45,16 +47,22 @@ const ActionConfirmModal: FC<ActionConfirmModalProps> = ({
</Modal.Header>
<Modal.Content fontScale='p1'>
<Box mb='x8'>{text}</Box>
{isPassword && <PasswordInput w='full' value={inputText} onChange={handleChange} />}
{!isPassword && <TextInput w='full' value={inputText} onChange={handleChange} />}
<FieldGroup w='full'>
<Field>
<Field.Row>
{isPassword && <PasswordInput value={inputText} onChange={handleChange} />}
{!isPassword && <TextInput value={inputText} onChange={handleChange} />}
</Field.Row>
</Field>
</FieldGroup>
</Modal.Content>
<Modal.Footer>
<ButtonGroup align='end'>
<Button ghost onClick={onCancel}>
{t('Cancel')}
</Button>
<Button primary danger onClick={handleSave}>
{t('Continue')}
{t('Delete')}
</Button>
</ButtonGroup>
</Modal.Footer>
Expand Down