🐛 Fix forbidden error on notifications fetch #491 #492
Tim Izzo tim@octree.ch
Fri, 16 Feb 2024 08:52:17 +0000
9 files changed,
88 insertions(+),
60 deletions(-)
jump to
A
backend/src/api/notification/policies/check-find.ts
@@ -0,0 +1,11 @@
+import { errors } from "@strapi/utils"; + +export default async (policyContext) => { + const user = policyContext.state.user; + if (!user) throw new errors.ForbiddenError(); + + policyContext.args.filters = { + ...(policyContext.args || {}), + user: { id: { eq: user.id } }, + }; +};
M
backend/src/api/travel/policies/check-update.ts
→
backend/src/api/travel/policies/check-update.ts
@@ -15,7 +15,7 @@
const event = travel.event; const eventId = policyContext.args?.data?.event; - if (eventId !== event.id) + if (!!eventId && eventId !== event.id) throw new errors.UnauthorizedError("Can't change travel linked event"); if (event.enabled_modules?.includes("caroster-plus")) {
M
backend/src/graphql/notification/index.ts
→
backend/src/graphql/notification/index.ts
@@ -55,6 +55,10 @@ },
}, }, resolversConfig: { + "Query.notifications": { + auth: true, + policies: ["api::notification.check-find"], + }, "Mutation.readNotifications": { auth: true, },
M
backend/src/graphql/user/index.ts
→
backend/src/graphql/user/index.ts
@@ -125,27 +125,35 @@ "UsersPermissionsUser.vehicles": {
auth: true, }, "UsersPermissionsUser.events": { + auth: true, policies: [checkAuthUser], }, "UsersPermissionsUser.notifications": { + auth: true, policies: [checkAuthUser], }, "UsersPermissionsUser.confirmed": { + auth: true, policies: [checkAuthUser], }, "UsersPermissionsUser.provider": { + auth: true, policies: [checkAuthUser], }, "UsersPermissionsUser.newsletterConsent": { + auth: true, policies: [checkAuthUser], }, "UsersPermissionsUser.createdAt": { + auth: true, policies: [checkAuthUser], }, "UsersPermissionsUser.onboardingCreator": { + auth: true, policies: [checkAuthUser], }, "UsersPermissionsUser.onboardingUser": { + auth: true, policies: [checkAuthUser], }, },
M
frontend/containers/DrawerNotification/CardNotification.tsx
→
frontend/containers/DrawerNotification/CardNotification.tsx
@@ -29,10 +29,6 @@ router.push(`/e/${notification.attributes.event.data.attributes.uuid}`);
onClose(); }; - const showBadge = !notification.attributes.read; - const notificationContentKey = `notification.type.${notification.attributes.type}.content`; - const notificationContent = t(notificationContentKey); - return ( <Box padding={2}@@ -51,7 +47,7 @@ justifyContent="space-between"
spacing={2} > <Box display="flex" alignItems="center" sx={{width: '168px'}}> - {showBadge && ( + {!notification.attributes.read && ( <Badge sx={{pr: 2}} color="error"@@ -71,7 +67,9 @@ <Typography variant="overline" color="text.secondary">
{formatDate(notification.attributes.createdAt)} </Typography> </Stack> - <Typography>{notificationContent}</Typography> + <Typography> + {t(`notification.type.${notification.attributes.type}.content`)} + </Typography> </Box> </Box> );
M
frontend/containers/DrawerNotification/DrawerContent.tsx
→
frontend/containers/DrawerNotification/DrawerContent.tsx
@@ -1,7 +1,6 @@
import {Drawer, Box, Icon, Typography} from '@mui/material/'; import useMediaQuery from '@mui/material/useMediaQuery'; import { - useUserNotificationsQuery, useReadNotificationsMutation, NotificationEntity, } from '../../generated/graphql';@@ -12,22 +11,20 @@
interface Props { isOpen: boolean; onClose: () => void; - notification: NotificationEntity; + notifications: NotificationEntity[]; } -const DrawerContent = ({isOpen, onClose}: Props) => { - const {data} = useUserNotificationsQuery(); - const [readNotifications] = useReadNotificationsMutation(); +const DrawerContent = ({isOpen, onClose, notifications}: Props) => { + const isMobile = useMediaQuery('(max-width:400px)'); const {t} = useTranslation(); - const notifications = data?.me?.profile?.notifications?.data || []; const hasNotifications = notifications.length > 0; - const markAllRead = () => { - readNotifications({refetchQueries: ['UserNotifications']}); - }; + const [readNotifications] = useReadNotificationsMutation(); const isAllRead = notifications.every( notification => notification.attributes.read ); - const isMobile = useMediaQuery('(max-width:400px)'); + + const markAllRead = () => + readNotifications({refetchQueries: ['UserNotifications']}); return ( <Drawer@@ -55,12 +52,11 @@ disabled={isAllRead}
/> <Box> {hasNotifications ? ( - notifications.map((notification, index) => ( + notifications.map(notification => ( <CardNotification key={notification.id} onClose={onClose} notification={notification} - isRead={readNotifications[index]} /> )) ) : (
M
frontend/containers/DrawerNotification/index.tsx
→
frontend/containers/DrawerNotification/index.tsx
@@ -1,18 +1,21 @@
import Icon from '@mui/material/Icon'; import IconButton from '@mui/material/IconButton'; import React, {useState} from 'react'; -import {useUserNotificationsQuery} from '../../generated/graphql'; +import { + NotificationEntity, + useUserNotificationsQuery, +} from '../../generated/graphql'; import Badge from '@mui/material/Badge'; import DrawerContent from './DrawerContent'; + +const POLL_INTERVAL = 30000; const DrawerNotification = () => { - const POLL_INTERVAL = 30000; + const [isDrawerOpen, setIsDrawerOpen] = useState(false); const {data} = useUserNotificationsQuery({ pollInterval: POLL_INTERVAL, }); - const [isDrawerOpen, setIsDrawerOpen] = useState(false); - - const notifications = data?.me?.profile?.notifications?.data || []; + const notifications = data?.notifications?.data || []; const hasUnreadNotifications = notifications.some( notification => !notification.attributes.read@@ -40,6 +43,7 @@
<DrawerContent isOpen={isDrawerOpen} onClose={() => setIsDrawerOpen(false)} + notifications={notifications as NotificationEntity[]} /> </> );
M
frontend/generated/graphql.tsx
→
frontend/generated/graphql.tsx
@@ -2121,7 +2121,7 @@ maxItems?: InputMaybe<Scalars['Int']['input']>;
}>; -export type UserNotificationsQuery = { __typename?: 'Query', me?: { __typename?: 'UsersPermissionsMe', profile?: { __typename?: 'UsersPermissionsUser', notifications?: { __typename?: 'NotificationRelationResponseCollection', data: Array<{ __typename?: 'NotificationEntity', id?: string | null, attributes?: { __typename?: 'Notification', type: Enum_Notification_Type, read?: boolean | null, createdAt?: any | null, event?: { __typename?: 'EventEntityResponse', data?: { __typename?: 'EventEntity', id?: string | null, attributes?: { __typename?: 'Event', name: string, uuid?: string | null } | null } | null } | null } | null }> } | null } | null } | null }; +export type UserNotificationsQuery = { __typename?: 'Query', notifications?: { __typename?: 'NotificationEntityResponseCollection', data: Array<{ __typename?: 'NotificationEntity', id?: string | null, attributes?: { __typename?: 'Notification', type: Enum_Notification_Type, read?: boolean | null, createdAt?: any | null, user?: { __typename?: 'UsersPermissionsUserEntityResponse', data?: { __typename?: 'UsersPermissionsUserEntity', id?: string | null, attributes?: { __typename?: 'UsersPermissionsUser', email: string } | null } | null } | null, event?: { __typename?: 'EventEntityResponse', data?: { __typename?: 'EventEntity', id?: string | null, attributes?: { __typename?: 'Event', name: string, uuid?: string | null } | null } | null } | null } | null }> } | null }; export type ReadNotificationsMutationVariables = Exact<{ id?: InputMaybe<Scalars['ID']['input']>;@@ -2828,23 +2828,27 @@ export type ModuleLazyQueryHookResult = ReturnType<typeof useModuleLazyQuery>;
export type ModuleQueryResult = Apollo.QueryResult<ModuleQuery, ModuleQueryVariables>; export const UserNotificationsDocument = gql` query UserNotifications($maxItems: Int = 20) { - me { - profile { - notifications(pagination: {limit: $maxItems}, sort: "createdAt:DESC") { - data { - id - attributes { - type - read - createdAt - event { - data { - id - attributes { - name - uuid - } - } + notifications(pagination: {limit: $maxItems}, sort: "createdAt:DESC") { + data { + id + attributes { + type + read + createdAt + user { + data { + id + attributes { + email + } + } + } + event { + data { + id + attributes { + name + uuid } } }
M
frontend/graphql/notifications.gql
→
frontend/graphql/notifications.gql
@@ -1,21 +1,25 @@
query UserNotifications($maxItems: Int = 20) { - me { - profile { - notifications(pagination: {limit: $maxItems}, sort: "createdAt:DESC") { - data { - id - attributes { - type - read - createdAt - event { - data { - id - attributes { - name - uuid - } - } + notifications(pagination: {limit: $maxItems}, sort: "createdAt:DESC") { + data { + id + attributes { + type + read + createdAt + user { + data { + id + attributes { + email + } + } + } + event { + data { + id + attributes { + name + uuid } } }@@ -35,4 +39,3 @@ }
} } } -