Problems to implement file protection functionality.
siqueira-gustavo opened this issue ยท 9 comments
Hi. I'm trying to implement file protection functionality, but I'm having problems with ctx.
It looks like I can't access the context of it.
.path(({ ctx, input }) => [{ type: input.type }, { owner: ctx.userId }])
But when I try to upload files without this context, it works.
.path(({ input }) => [{ type: input.type }])
I really liked edgestore. And I think it will make things much easier. So, I'd like some help.
Here's my code:
import { initEdgeStore } from '@edgestore/server'
import {
CreateContextOptions,
createEdgeStoreNextHandler,
} from '@edgestore/server/adapters/next/app'
// import { useSession } from 'next-auth/react'
import { z } from 'zod'
type Context = {
userId: string
userRole: 'admin' | 'user'
}
const inputSchema = z.object({
type: z.enum(['post', 'profile', 'rdo']),
})
function createContext({ req }: CreateContextOptions): Context {
// const { data } = useSession()
// if (!data || !data.user) {
// return {
// userId: '',
// userRole: 'user',
// }
// }
return {
userId: '123',
userRole: 'admin',
}
}
const es = initEdgeStore.context<Context>().create()
const imageBucketConfig = {
maxSize: 5 * 1024 * 1024,
accept: ['image/jpeg', 'image/jpg', 'image/png'],
}
function createMetadata(ctx: Context, input: { type: string }) {
return {
userRole: ctx.userRole,
userId: ctx.userId,
type: input.type,
}
}
const edgeStoreRouter = es.router({
publicImages: es
.imageBucket(imageBucketConfig)
.input(inputSchema)
.path(({ ctx, input }) => [{ type: input.type }, { owner: ctx.userId }])
.metadata(({ ctx, input }) => createMetadata(ctx, input)),
protectedFiles: es
.fileBucket(imageBucketConfig)
.input(inputSchema)
.path(({ ctx, input }) => [{ type: input.type }, { owner: ctx.userId }])
.metadata(({ ctx, input }) => createMetadata(ctx, input))
.accessControl({
OR: [{ userId: { path: 'owner' } }, { userRole: { eq: 'admin' } }],
}),
})
const handler = createEdgeStoreNextHandler({
router: edgeStoreRouter,
createContext,
})
export { handler as GET, handler as POST }
export type EdgeStoreRouter = typeof edgeStoreRouter
And this is how it is implemented on frontend:
<MultiFileDropzone
className='bg-slate-100 dark:bg-slate-900'
value={fileStates}
onChange={(files) => {
setFileStates(files)
}}
onFilesAdded={async (addedFiles) => {
setFileStates([...fileStates, ...addedFiles])
await Promise.all(
addedFiles.map(async (addedFileState) => {
try {
const res = await edgestore.protectedFiles.upload({
file: addedFileState.file,
options: {
temporary: true,
},
input: { type: 'rdo' },
onProgressChange: async (progress: number) => {
updateFileProgress(addedFileState.key, progress)
if (progress === 100) {
// wait 1 second to set it to complete
// so that the user can see the progress bar at 100%
await new Promise((resolve) =>
setTimeout(resolve, 1000),
)
updateFileProgress(
addedFileState.key,
'COMPLETE',
)
}
},
})
setUrls((urls) => [...urls, res.url])
console.log(res)
} catch (err) {
console.log(
'๐ ~ file: NewRDOModal.tsx:219 ~ addedFiles.map ~ err:',
(err as Error).message,
)
updateFileProgress(addedFileState.key, 'ERROR')
}
}),
)
}}
/>
Thanks in advance.
@siqueira-gustavo Thank you for creating the issue and for using edgestore!
I couldn't find any problems with the code just by looking at it.
I'll try it out and report back as soon as I can.
@siqueira-gustavo I just tried your router configuration in an example app and it worked as expected.
I pushed the changes into the tmp/issue-10 branch here:
4f9a16c
If you want to try to run this example, you can do it following these steps:
- clone the repo and checkout to the
tmp/issue-10
branch - run
pnpm install
- add your environment variables to
examples/components/.env.local
- run
pnpm components:dev
- access the page at http://localhost:3000/components/multi-file-instant
if the example app works in your machine, we would need to try to find the difference in the project that's making it fail.
Thanks for your reply!
I followed your instructions, but I'm still having problems... starting to think it's something here with my configs...
I made a video...
https://github.com/edgestorejs/edgestore/assets/69218857/96a2a1cc-39a0-490f-822f-c2a829dda967
@siqueira-gustavo strange.. I think I need to take a look in the network tab. and also see the server side logs to understand what's going on..
maybe it would be better if you could share your screen on Discord to make it easier to debug.
If you're open to it, join the Discord server and DM me so we can find a time that can fit both our schedules.
@perfectbase yeah... really strange.
I have a Linux machine I'll try to setup to test it in there when I have time.
Now for some reason it is sending a response to the (protected) bucket, but it is pointing to localhost instead of the accessUrl...
I made another video to show it.
edgestrore-problems.mp4
Not sure if the quality is good, because max size to upload videos here is only 10MB.
Btw, sessions userId should've be my name, not '123' as it shown in the network tab.
And if you try to click the link, it's just a plain text.
I'll try to reach you on Discord.
@siqueira-gustavo Oh! Now I think I understand what's happening.
The upload is successful, but you can't show the image on the screen right!? I think it's because you are trying to use next/image
to show it, but it doesn't forward the cookies.
I believe all you need to know is in this "Good to know" section:
Tell me if it helps.
@perfectbase you're right! It's working! Thanks a lot!
edgestrore-solution.mp4
I actually read this part of documentation, but not so carefully as I should... ๐
I only have one more question: in public files table we have links to access the uploaded files but in protected table there are no links. Is it the expected behavior?
@siqueira-gustavo Nice! Glad that it worked!
Yes, this is the correct behavior right now. The reason is that even if I put the links there, you would only see "access denied" because you don't have the cookies to access the file.
Eventually I plan to improve this page so that you can see more details and maybe access the file with a signed url (that doesn't need the cookies)
@perfectbase Oh, I see... I really liked this project!
Maybe I'll be able to contribute in a near future. ๐๐
Thanks again!
I'm closing this issue now. See you!