Redirect to login when groups or accounts 403
This commit is contained in:
parent
5ffaaa4c3a
commit
bcac58b9c3
7 changed files with 68 additions and 10 deletions
|
@ -1,3 +1,6 @@
|
||||||
|
import { useEffect } from 'react';
|
||||||
|
import { useHistory } from 'react-router-dom';
|
||||||
|
|
||||||
import { Entities } from 'soapbox/entity-store/entities';
|
import { Entities } from 'soapbox/entity-store/entities';
|
||||||
import { useEntity } from 'soapbox/entity-store/hooks';
|
import { useEntity } from 'soapbox/entity-store/hooks';
|
||||||
import { useFeatures, useLoggedIn } from 'soapbox/hooks';
|
import { useFeatures, useLoggedIn } from 'soapbox/hooks';
|
||||||
|
@ -12,11 +15,12 @@ interface UseAccountOpts {
|
||||||
|
|
||||||
function useAccount(accountId?: string, opts: UseAccountOpts = {}) {
|
function useAccount(accountId?: string, opts: UseAccountOpts = {}) {
|
||||||
const api = useApi();
|
const api = useApi();
|
||||||
|
const history = useHistory();
|
||||||
const features = useFeatures();
|
const features = useFeatures();
|
||||||
const { me } = useLoggedIn();
|
const { me } = useLoggedIn();
|
||||||
const { withRelationship } = opts;
|
const { withRelationship } = opts;
|
||||||
|
|
||||||
const { entity: account, ...result } = useEntity<Account>(
|
const { entity: account, isUnauthorized, ...result } = useEntity<Account>(
|
||||||
[Entities.ACCOUNTS, accountId!],
|
[Entities.ACCOUNTS, accountId!],
|
||||||
() => api.get(`/api/v1/accounts/${accountId}`),
|
() => api.get(`/api/v1/accounts/${accountId}`),
|
||||||
{ schema: accountSchema, enabled: !!accountId },
|
{ schema: accountSchema, enabled: !!accountId },
|
||||||
|
@ -30,10 +34,17 @@ function useAccount(accountId?: string, opts: UseAccountOpts = {}) {
|
||||||
const isBlocked = account?.relationship?.blocked_by === true;
|
const isBlocked = account?.relationship?.blocked_by === true;
|
||||||
const isUnavailable = (me === account?.id) ? false : (isBlocked && !features.blockersVisible);
|
const isUnavailable = (me === account?.id) ? false : (isBlocked && !features.blockersVisible);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (isUnauthorized) {
|
||||||
|
history.push('/login');
|
||||||
|
}
|
||||||
|
}, [isUnauthorized]);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
...result,
|
...result,
|
||||||
isLoading: result.isLoading,
|
isLoading: result.isLoading,
|
||||||
isRelationshipLoading,
|
isRelationshipLoading,
|
||||||
|
isUnauthorized,
|
||||||
isUnavailable,
|
isUnavailable,
|
||||||
account: account ? { ...account, relationship } : undefined,
|
account: account ? { ...account, relationship } : undefined,
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,3 +1,6 @@
|
||||||
|
import { useEffect } from 'react';
|
||||||
|
import { useHistory } from 'react-router-dom';
|
||||||
|
|
||||||
import { Entities } from 'soapbox/entity-store/entities';
|
import { Entities } from 'soapbox/entity-store/entities';
|
||||||
import { useEntityLookup } from 'soapbox/entity-store/hooks';
|
import { useEntityLookup } from 'soapbox/entity-store/hooks';
|
||||||
import { useFeatures, useLoggedIn } from 'soapbox/hooks';
|
import { useFeatures, useLoggedIn } from 'soapbox/hooks';
|
||||||
|
@ -13,10 +16,11 @@ interface UseAccountLookupOpts {
|
||||||
function useAccountLookup(acct: string | undefined, opts: UseAccountLookupOpts = {}) {
|
function useAccountLookup(acct: string | undefined, opts: UseAccountLookupOpts = {}) {
|
||||||
const api = useApi();
|
const api = useApi();
|
||||||
const features = useFeatures();
|
const features = useFeatures();
|
||||||
|
const history = useHistory();
|
||||||
const { me } = useLoggedIn();
|
const { me } = useLoggedIn();
|
||||||
const { withRelationship } = opts;
|
const { withRelationship } = opts;
|
||||||
|
|
||||||
const { entity: account, ...result } = useEntityLookup<Account>(
|
const { entity: account, isUnauthorized, ...result } = useEntityLookup<Account>(
|
||||||
Entities.ACCOUNTS,
|
Entities.ACCOUNTS,
|
||||||
(account) => account.acct === acct,
|
(account) => account.acct === acct,
|
||||||
() => api.get(`/api/v1/accounts/lookup?acct=${acct}`),
|
() => api.get(`/api/v1/accounts/lookup?acct=${acct}`),
|
||||||
|
@ -31,10 +35,17 @@ function useAccountLookup(acct: string | undefined, opts: UseAccountLookupOpts =
|
||||||
const isBlocked = account?.relationship?.blocked_by === true;
|
const isBlocked = account?.relationship?.blocked_by === true;
|
||||||
const isUnavailable = (me === account?.id) ? false : (isBlocked && !features.blockersVisible);
|
const isUnavailable = (me === account?.id) ? false : (isBlocked && !features.blockersVisible);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (isUnauthorized) {
|
||||||
|
history.push('/login');
|
||||||
|
}
|
||||||
|
}, [isUnauthorized]);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
...result,
|
...result,
|
||||||
isLoading: result.isLoading,
|
isLoading: result.isLoading,
|
||||||
isRelationshipLoading,
|
isRelationshipLoading,
|
||||||
|
isUnauthorized,
|
||||||
isUnavailable,
|
isUnavailable,
|
||||||
account: account ? { ...account, relationship } : undefined,
|
account: account ? { ...account, relationship } : undefined,
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,3 +1,6 @@
|
||||||
|
import { useEffect } from 'react';
|
||||||
|
import { useHistory } from 'react-router-dom';
|
||||||
|
|
||||||
import { Entities } from 'soapbox/entity-store/entities';
|
import { Entities } from 'soapbox/entity-store/entities';
|
||||||
import { useEntity } from 'soapbox/entity-store/hooks';
|
import { useEntity } from 'soapbox/entity-store/hooks';
|
||||||
import { useApi } from 'soapbox/hooks';
|
import { useApi } from 'soapbox/hooks';
|
||||||
|
@ -7,8 +10,9 @@ import { useGroupRelationship } from './useGroupRelationship';
|
||||||
|
|
||||||
function useGroup(groupId: string, refetch = true) {
|
function useGroup(groupId: string, refetch = true) {
|
||||||
const api = useApi();
|
const api = useApi();
|
||||||
|
const history = useHistory();
|
||||||
|
|
||||||
const { entity: group, ...result } = useEntity<Group>(
|
const { entity: group, isUnauthorized, ...result } = useEntity<Group>(
|
||||||
[Entities.GROUPS, groupId],
|
[Entities.GROUPS, groupId],
|
||||||
() => api.get(`/api/v1/groups/${groupId}`),
|
() => api.get(`/api/v1/groups/${groupId}`),
|
||||||
{
|
{
|
||||||
|
@ -19,8 +23,15 @@ function useGroup(groupId: string, refetch = true) {
|
||||||
);
|
);
|
||||||
const { groupRelationship: relationship } = useGroupRelationship(groupId);
|
const { groupRelationship: relationship } = useGroupRelationship(groupId);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (isUnauthorized) {
|
||||||
|
history.push('/login');
|
||||||
|
}
|
||||||
|
}, [isUnauthorized]);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
...result,
|
...result,
|
||||||
|
isUnauthorized,
|
||||||
group: group ? { ...group, relationship: relationship || null } : undefined,
|
group: group ? { ...group, relationship: relationship || null } : undefined,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,24 +1,37 @@
|
||||||
|
import { useEffect } from 'react';
|
||||||
|
import { useHistory } from 'react-router-dom';
|
||||||
|
|
||||||
import { Entities } from 'soapbox/entity-store/entities';
|
import { Entities } from 'soapbox/entity-store/entities';
|
||||||
import { useEntityLookup } from 'soapbox/entity-store/hooks';
|
import { useEntityLookup } from 'soapbox/entity-store/hooks';
|
||||||
import { useApi } from 'soapbox/hooks/useApi';
|
import { useApi } from 'soapbox/hooks/useApi';
|
||||||
|
import { useFeatures } from 'soapbox/hooks/useFeatures';
|
||||||
import { groupSchema } from 'soapbox/schemas';
|
import { groupSchema } from 'soapbox/schemas';
|
||||||
|
|
||||||
import { useGroupRelationship } from './useGroupRelationship';
|
import { useGroupRelationship } from './useGroupRelationship';
|
||||||
|
|
||||||
function useGroupLookup(slug: string) {
|
function useGroupLookup(slug: string) {
|
||||||
const api = useApi();
|
const api = useApi();
|
||||||
|
const features = useFeatures();
|
||||||
|
const history = useHistory();
|
||||||
|
|
||||||
const { entity: group, ...result } = useEntityLookup(
|
const { entity: group, isUnauthorized, ...result } = useEntityLookup(
|
||||||
Entities.GROUPS,
|
Entities.GROUPS,
|
||||||
(group) => group.slug === slug,
|
(group) => group.slug === slug,
|
||||||
() => api.get(`/api/v1/groups/lookup?name=${slug}`),
|
() => api.get(`/api/v1/groups/lookup?name=${slug}`),
|
||||||
{ schema: groupSchema, enabled: !!slug },
|
{ schema: groupSchema, enabled: features.groups && !!slug },
|
||||||
);
|
);
|
||||||
|
|
||||||
const { groupRelationship: relationship } = useGroupRelationship(group?.id);
|
const { groupRelationship: relationship } = useGroupRelationship(group?.id);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (isUnauthorized) {
|
||||||
|
history.push('/login');
|
||||||
|
}
|
||||||
|
}, [isUnauthorized]);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
...result,
|
...result,
|
||||||
|
isUnauthorized,
|
||||||
entity: group ? { ...group, relationship: relationship || null } : undefined,
|
entity: group ? { ...group, relationship: relationship || null } : undefined,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
import { useEffect } from 'react';
|
import { AxiosError } from 'axios';
|
||||||
|
import { useEffect, useState } from 'react';
|
||||||
import z from 'zod';
|
import z from 'zod';
|
||||||
|
|
||||||
import { useAppDispatch, useAppSelector, useLoading } from 'soapbox/hooks';
|
import { useAppDispatch, useAppSelector, useLoading } from 'soapbox/hooks';
|
||||||
|
@ -24,6 +25,8 @@ function useEntity<TEntity extends Entity>(
|
||||||
opts: UseEntityOpts<TEntity> = {},
|
opts: UseEntityOpts<TEntity> = {},
|
||||||
) {
|
) {
|
||||||
const [isFetching, setPromise] = useLoading(true);
|
const [isFetching, setPromise] = useLoading(true);
|
||||||
|
const [error, setError] = useState<unknown>();
|
||||||
|
|
||||||
const dispatch = useAppDispatch();
|
const dispatch = useAppDispatch();
|
||||||
|
|
||||||
const [entityType, entityId] = path;
|
const [entityType, entityId] = path;
|
||||||
|
@ -35,6 +38,7 @@ function useEntity<TEntity extends Entity>(
|
||||||
|
|
||||||
const isEnabled = opts.enabled ?? true;
|
const isEnabled = opts.enabled ?? true;
|
||||||
const isLoading = isFetching && !entity;
|
const isLoading = isFetching && !entity;
|
||||||
|
const isLoaded = !isFetching && !!entity;
|
||||||
|
|
||||||
const fetchEntity = async () => {
|
const fetchEntity = async () => {
|
||||||
try {
|
try {
|
||||||
|
@ -42,7 +46,7 @@ function useEntity<TEntity extends Entity>(
|
||||||
const entity = schema.parse(response.data);
|
const entity = schema.parse(response.data);
|
||||||
dispatch(importEntities([entity], entityType));
|
dispatch(importEntities([entity], entityType));
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
// do nothing
|
setError(e);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -58,6 +62,10 @@ function useEntity<TEntity extends Entity>(
|
||||||
fetchEntity,
|
fetchEntity,
|
||||||
isFetching,
|
isFetching,
|
||||||
isLoading,
|
isLoading,
|
||||||
|
isLoaded,
|
||||||
|
error,
|
||||||
|
isUnauthorized: error instanceof AxiosError && error.response?.status === 401,
|
||||||
|
isForbidden: error instanceof AxiosError && error.response?.status === 403,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
import { useEffect } from 'react';
|
import { AxiosError } from 'axios';
|
||||||
|
import { useEffect, useState } from 'react';
|
||||||
import { z } from 'zod';
|
import { z } from 'zod';
|
||||||
|
|
||||||
import { useAppDispatch, useAppSelector, useLoading } from 'soapbox/hooks';
|
import { useAppDispatch, useAppSelector, useLoading } from 'soapbox/hooks';
|
||||||
|
@ -23,6 +24,7 @@ function useEntityLookup<TEntity extends Entity>(
|
||||||
|
|
||||||
const dispatch = useAppDispatch();
|
const dispatch = useAppDispatch();
|
||||||
const [isFetching, setPromise] = useLoading(true);
|
const [isFetching, setPromise] = useLoading(true);
|
||||||
|
const [error, setError] = useState<unknown>();
|
||||||
|
|
||||||
const entity = useAppSelector(state => findEntity(state, entityType, lookupFn));
|
const entity = useAppSelector(state => findEntity(state, entityType, lookupFn));
|
||||||
const isEnabled = opts.enabled ?? true;
|
const isEnabled = opts.enabled ?? true;
|
||||||
|
@ -34,7 +36,7 @@ function useEntityLookup<TEntity extends Entity>(
|
||||||
const entity = schema.parse(response.data);
|
const entity = schema.parse(response.data);
|
||||||
dispatch(importEntities([entity], entityType));
|
dispatch(importEntities([entity], entityType));
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
// do nothing
|
setError(e);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -51,6 +53,8 @@ function useEntityLookup<TEntity extends Entity>(
|
||||||
fetchEntity,
|
fetchEntity,
|
||||||
isFetching,
|
isFetching,
|
||||||
isLoading,
|
isLoading,
|
||||||
|
isUnauthorized: error instanceof AxiosError && error.response?.status === 401,
|
||||||
|
isForbidden: error instanceof AxiosError && error.response?.status === 403,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -327,7 +327,7 @@ const SwitchingColumnsArea: React.FC<ISwitchingColumnsArea> = ({ children }) =>
|
||||||
|
|
||||||
{features.groupsTags && <WrappedRoute path='/group/:groupSlug/tags' exact page={GroupPage} component={GroupTagsSlug} content={children} />}
|
{features.groupsTags && <WrappedRoute path='/group/:groupSlug/tags' exact page={GroupPage} component={GroupTagsSlug} content={children} />}
|
||||||
{features.groupsTags && <WrappedRoute path='/group/:groupSlug/tag/:tagId' exact page={GroupsPendingPage} component={GroupTagTimelineSlug} content={children} />}
|
{features.groupsTags && <WrappedRoute path='/group/:groupSlug/tag/:tagId' exact page={GroupsPendingPage} component={GroupTagTimelineSlug} content={children} />}
|
||||||
{features.groups && <WrappedRoute path='/group/:groupSlug' exact page={GroupPage} component={GroupTimelineSlug} content={children} />}
|
{features.groups && <WrappedRoute path='/group/:groupSlug' publicRoute exact page={GroupPage} component={GroupTimelineSlug} content={children} />}
|
||||||
{features.groups && <WrappedRoute path='/group/:groupSlug/members' exact page={GroupPage} component={GroupMembersSlug} content={children} />}
|
{features.groups && <WrappedRoute path='/group/:groupSlug/members' exact page={GroupPage} component={GroupMembersSlug} content={children} />}
|
||||||
{features.groups && <WrappedRoute path='/group/:groupSlug/media' publicRoute={!authenticatedProfile} component={GroupGallerySlug} page={GroupPage} content={children} />}
|
{features.groups && <WrappedRoute path='/group/:groupSlug/media' publicRoute={!authenticatedProfile} component={GroupGallerySlug} page={GroupPage} content={children} />}
|
||||||
{features.groups && <WrappedRoute path='/group/:groupSlug/manage' exact page={ManageGroupsPage} component={ManageGroupSlug} content={children} />}
|
{features.groups && <WrappedRoute path='/group/:groupSlug/manage' exact page={ManageGroupsPage} component={ManageGroupSlug} content={children} />}
|
||||||
|
|
Loading…
Reference in a new issue