diff --git a/src/pages/blog/loader.ts b/src/pages/blog/loader.ts index aadddb0..27325be 100644 --- a/src/pages/blog/loader.ts +++ b/src/pages/blog/loader.ts @@ -1,8 +1,7 @@ -import { filterForEventsTaggingId, NDKFilter } from '@nostr-dev-kit/ndk' +import { NDKFilter } from '@nostr-dev-kit/ndk' import { NDKContextType } from 'contexts/NDKContext' import { kinds, nip19 } from 'nostr-tools' import { LoaderFunctionArgs, redirect } from 'react-router-dom' -import { toast } from 'react-toastify' import { appRoutes } from 'routes' import { store } from 'store' import { BlogPageLoaderResult, FilterOptions, NSFWFilter } from 'types' @@ -16,28 +15,43 @@ import { extractBlogCardDetails, extractBlogDetails } from 'utils/blog' export const blogRouteLoader = (ndkContext: NDKContextType) => - async ({ params }: LoaderFunctionArgs) => { + async ({ params, request }: LoaderFunctionArgs) => { const { naddr } = params if (!naddr) { log(true, LogType.Error, 'Required naddr.') return redirect(appRoutes.blogs) } - // Decode author from naddr - const decoded = nip19.decode<'naddr'>(naddr as `naddr1${string}`) - const { pubkey } = decoded.data + // Decode author and identifier from naddr + let pubkey: string | undefined + let identifier: string | undefined + try { + const decoded = nip19.decode<'naddr'>(naddr as `naddr1${string}`) + pubkey = decoded.data.pubkey + identifier = decoded.data.identifier + } catch (error) { + log(true, LogType.Error, `Failed to decode naddr: ${naddr}`, error) + throw new Error('Failed to fetch the blog. The address might be wrong') + } + + const userState = store.getState().user + const loggedInUserPubkey = userState?.user?.pubkey as string | undefined + + // Check if editing and the user is the original author + // Redirect if NOT + const url = new URL(request.url) + const isEditMode = url.pathname.endsWith('/edit') + if (isEditMode && loggedInUserPubkey !== pubkey) { + return redirect(appRoutes.blogs) + } try { - // Get the filter with #a from naddr for the main blog content - const filter = filterForEventsTaggingId(naddr) - if (!filter) { - log(true, LogType.Error, 'Unable to create filter from blog naddr.') - return redirect(appRoutes.blogs) + // Set the filter for the main blog content + const filter = { + kinds: [kinds.LongFormArticle], + authors: [pubkey], + '#d': [identifier] } - // Update kinds to make sure we fetch correct event kind - filter.kinds = [kinds.LongFormArticle] - - const userState = store.getState().user // Get the blog filter options for latest blogs const filterOptions = JSON.parse( @@ -68,7 +82,7 @@ export const blogRouteLoader = const settled = await Promise.allSettled([ ndkContext.fetchEvent(filter), ndkContext.fetchEvents(latestModsFilter), - ndkContext.getMuteLists(userState?.user?.pubkey as string), + ndkContext.getMuteLists(loggedInUserPubkey), // Pass pubkey for logged-in users ndkContext.getNSFWList() ]) @@ -93,6 +107,12 @@ export const blogRouteLoader = ) } + // Throw an error if we are missing the main blog result + // Handle it with the react-router's errorComponent + if (!result.blog) { + throw new Error('We are unable to find the blog on the relays') + } + // Check the lateast blog events const fetchEventsResult = settled[1] if (fetchEventsResult.status === 'fulfilled' && fetchEventsResult.value) { @@ -165,13 +185,11 @@ export const blogRouteLoader = return result } catch (error) { - log( - true, - LogType.Error, - 'An error occurred in fetching blog details from relays', - error - ) - toast.error('An error occurred in fetching blog details from relays') - return redirect(appRoutes.blogs) + let message = 'An error occurred in fetching blog details from relays' + log(true, LogType.Error, message, error) + if (error instanceof Error) { + message = error.message + throw new Error(message) + } } } diff --git a/src/routes/index.tsx b/src/routes/index.tsx index 5c14fd0..aec86c6 100644 --- a/src/routes/index.tsx +++ b/src/routes/index.tsx @@ -103,13 +103,15 @@ export const routerWithNdkContext = (context: NDKContextType) => path: appRoutes.blog, element: , loader: blogRouteLoader(context), - action: blogRouteAction(context) + action: blogRouteAction(context), + errorElement: }, { path: appRoutes.blogEdit, element: , loader: blogRouteLoader(context), - action: writeRouteAction(context) + action: writeRouteAction(context), + errorElement: }, { path: appRoutes.blogReport_actionOnly,