-
Notifications
You must be signed in to change notification settings - Fork 31
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
Projects in Studio #2078
Projects in Studio #2078
Conversation
The latest updates on your projects. Learn more about Vercel for Git ↗︎
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@emranemran @mjh1 kudos for sending the PR early.
I didn't manage to review it all, but I added some first comments. PTAL.
@@ -200,6 +202,13 @@ export async function validateAssetPayload( | |||
} | |||
} | |||
|
|||
if (payload.projectId) { | |||
const project = await getProject(req); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I wonder if we shouldn't add project
to req
in
function authenticator(): RequestHandler { |
My thinking is that now, authenticator()
assigns user
to each request. But from now on, the request (api token) will be associated always with one project, so maybe we should inject it in authenticator()
and then there would be no need to call getProject()
everywhere?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@victorges and I discussed something like that but Victor suggested we need to maintain compatibility with the SDK I believe. I'm still a bit on the fence on this b/c from the dashboard perspective, project is basically a "filter" to categorize the assets, streams, etc. But maybe philosophically what you're saying makes sense. wdyt @victorges?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we can still maintain compatibility but having the projectId added to the request as Rafal suggests will just neaten the code up a bit. User and project would both exist on the request object then, and we can maintain compatibility by checking both in the controllers.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The other thing is we don't want projectId to be part of the payload, we should be taking it from the api key being used. We could potentially leave that for a later PR though and leave this one mainly as just adding the projects controller.
Edit: I'm working on this bit locally atm, including the authenticator()
rafal mentioned (branched off this), let me know if you want to pair etc WIP: #2081
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@mjh1: I saw your edit comment too late and started making simliar changes to my branch - but I scrapped those and just cherry-picked yours here instead. Could we use this branch to pair for integration? I added another commit to make some edits but currently a bit broken when trying to create new api-keys -- see my comment here: #2078 (comment)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Guys, I think you're on the right track!
Wrt what @mjh1 wrote, I think that we should not send projectId
in the payload, because projectId
is derived from API TOKEN. The same way, we don't send userId
in every request.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok cool yep let's just use this branch
@@ -654,6 +674,14 @@ app.get("/", authorizer({}), async (req, res) => { | |||
query.push(sql`asset.data->>'deleted' IS NULL`); | |||
} | |||
|
|||
if (projectId) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If we filter by projectId
, do we also need to filter by userId
in the line 683?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, don't we? We're trying to get all assets beloniging to a specific userId broken down by a specific projectId.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Doesn't one project belong to one user only? Then, filtering by projectId should be enough.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think projectId should be its own queryparam like this, we can add it to the fieldsMap
instead. I also think we should treat it similar to userId in that only admins are allowed to use it. For non-admins we should just take the projectId associated with the api key being used.
if (count) { | ||
fields = fields + ", count(*) OVER() AS count"; | ||
} | ||
const from = `project left join users on project.data->>'userId' = users.id`; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do you think it would be possible to put the SQL queries inside the table? I know it's the same in other controllers, but I wonder if it would make sense to abstract it and put inside the store/*-table.ts
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We could do that - I just followed the existing patterns in other files.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok, that's probably fine, we can try to clean it up for all controllers in some other PR.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks good from my end. You can decide with @victorges on the open discussions.
Plus, please add unit tests.
@mjh1 @leszko: a few questions:
|
project = await db.project.get(projectId); | ||
if (!project || project.deleted) { | ||
return {}; | ||
//throw new NotFoundError(`project not found`); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not sure yet how to handle this case yet....just returning empty object for now.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why doesn't the throwing of NotFoundError
work?
Yeah, I think it make sense, that Bearer is not supported for creating api tokens, because you always need to first create them from the livepeer dashboard (read: jwt). Why doesn't it work in the box? No idea, unfortunately 😞
This is something we started to discuss at some point. And I think we still have these 3 options:
I think that we discussed that the Option 3 probably makes the least sense. But you know better the code now, so hard to suggest what's the best. |
2ed9d17
to
1fa5344
Compare
packages/api/src/middleware/auth.ts
Outdated
@@ -26,7 +27,7 @@ export const EMAIL_VERIFICATION_CUTOFF_DATE = 1695765600000; // 2023-09-26T22:00 | |||
* are set to expire after a short time and the client manages using a refresh | |||
* token for keeping the user logged in. | |||
*/ | |||
export const NEVER_EXPIRING_JWT_CUTOFF_DATE = 1709251200000; // 2024-03-01T00:00:00.000Z | |||
export const NEVER_EXPIRING_JWT_CUTOFF_DATE = 1740820816000; // 2024-03-01T00:00:00.000Z |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
note: just a HACK for now since I wasn't sure why we have this cutoff date.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
AFAIK you don't need to change it. It was only a cutoff for the "old" JWT mechanism, and we're using now the "new" JWT mechanism. But Victor knows best since he updated "old" => "new" :)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah this doesn't need to change! Here's the doc on how the migration works: https://www.notion.so/livepeer/Studio-dashboard-authentication-310a74802de54f538e0ecb633f94ee8e?pvs=4
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
preliminary LGTM! Still missing projectId
on a ton of resources and checks on the APIs
project = await db.project.get(projectId); | ||
if (!project || project.deleted) { | ||
return {}; | ||
//throw new NotFoundError(`project not found`); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why doesn't the throwing of NotFoundError
work?
packages/api/src/middleware/auth.ts
Outdated
@@ -149,6 +155,9 @@ function authenticator(): RequestHandler { | |||
req.token = tokenObject; | |||
req.user = user; | |||
|
|||
project = await getProject(req, projectId); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This probably deserves some caching like user and api key above
packages/api/src/middleware/auth.ts
Outdated
@@ -149,6 +155,9 @@ function authenticator(): RequestHandler { | |||
req.token = tokenObject; | |||
req.user = user; | |||
|
|||
project = await getProject(req, projectId); | |||
req.project = project; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you add this project
field to our Request
type extensions here?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Already have it here actually:
https://github.com/livepeer/studio/pull/2078/files#diff-2ce1dfa11aee18127c26c8ff761f0ca88d79f008f9ec5a4c10c3bc39d8cd489bR45
Did you mean this or something else?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh yeah I meant that. Not sure how i missed it
@@ -1153,6 +1172,10 @@ components: | |||
Name of the asset. This is not necessarily the filename, can be a | |||
custom name or title | |||
example: filename.mp4 | |||
projectId: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Seems like we still miss a bunch of these. They are probably readOnly
too 🤔
So the plan with this PR is to get it ready and merged w/o breaking existing dashboard usage so that @suhailkakar can get started on frontend work. Then follow-up PRs will be used for streams/webhooks/etc and update those code paths for projectId handling. |
429c1d8
to
e15955e
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM
res.status(403); | ||
return res.json({ errors: ["project not found"] }); | ||
} | ||
console.log("YYY here:", project, req.params.id); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
leftover?
const project = await db.project.get(req.params.id, { | ||
useReplica: false, | ||
}); | ||
console.log("YYY :", project, req.params.id); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
leftover?
"user can only request information on their own projects" | ||
); | ||
} | ||
console.log("YYY here here:", project, req.params.id); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
leftover?
Initial set of changes from myself + @mjh1 to enable "Project" environments in Studio:
A few notes:
PS: this is my first large typrscript PR so be gentle :)