33from dataclasses import dataclass
44from typing import Any
55
6- from sanic import HTTPResponse , Request , json
6+ from sanic import HTTPResponse , Request
77from sanic .response import JSONResponse
88from sanic_ext import validate
99from ulid import ULID
1313from renku_data_services .base_api .auth import (
1414 authenticate ,
1515 only_authenticated ,
16- validate_path_project_id ,
1716 validate_path_user_id ,
1817)
1918from renku_data_services .base_api .blueprint import BlueprintFactoryResponse , CustomBlueprint
@@ -93,7 +92,7 @@ async def _get_one(
9392 headers = {"ETag" : project .etag } if project .etag is not None else None
9493 return validated_json (apispec .Project , self ._dump_project (project ), headers = headers )
9594
96- return "/projects/<project_id>" , ["GET" ], _get_one
95+ return "/projects/<project_id:ulid >" , ["GET" ], _get_one
9796
9897 def get_one_by_namespace_slug (self ) -> BlueprintFactoryResponse :
9998 """Get a specific project by namespace/slug."""
@@ -111,35 +110,33 @@ async def _get_one_by_namespace_slug(
111110 headers = {"ETag" : project .etag } if project .etag is not None else None
112111 return validated_json (apispec .Project , self ._dump_project (project ), headers = headers )
113112
114- return "/projects /<namespace>/<slug:renku_slug>" , ["GET" ], _get_one_by_namespace_slug
113+ return "/namespaces /<namespace>/projects /<slug:renku_slug>" , ["GET" ], _get_one_by_namespace_slug
115114
116115 def delete (self ) -> BlueprintFactoryResponse :
117116 """Delete a specific project."""
118117
119118 @authenticate (self .authenticator )
120119 @only_authenticated
121- @validate_path_project_id
122- async def _delete (_ : Request , user : base_models .APIUser , project_id : str ) -> HTTPResponse :
123- await self .project_repo .delete_project (user = user , project_id = ULID .from_str (project_id ))
120+ async def _delete (_ : Request , user : base_models .APIUser , project_id : ULID ) -> HTTPResponse :
121+ await self .project_repo .delete_project (user = user , project_id = project_id )
124122 return HTTPResponse (status = 204 )
125123
126- return "/projects/<project_id>" , ["DELETE" ], _delete
124+ return "/projects/<project_id:ulid >" , ["DELETE" ], _delete
127125
128126 def patch (self ) -> BlueprintFactoryResponse :
129127 """Partially update a specific project."""
130128
131129 @authenticate (self .authenticator )
132130 @only_authenticated
133- @validate_path_project_id
134131 @if_match_required
135132 @validate (json = apispec .ProjectPatch )
136133 async def _patch (
137- _ : Request , user : base_models .APIUser , project_id : str , body : apispec .ProjectPatch , etag : str
134+ _ : Request , user : base_models .APIUser , project_id : ULID , body : apispec .ProjectPatch , etag : str
138135 ) -> JSONResponse :
139136 body_dict = body .model_dump (exclude_none = True )
140137
141138 project_update = await self .project_repo .update_project (
142- user = user , project_id = ULID . from_str ( project_id ) , etag = etag , payload = body_dict
139+ user = user , project_id = project_id , etag = etag , payload = body_dict
143140 )
144141 if not isinstance (project_update , project_models .ProjectUpdate ):
145142 raise errors .ProgrammingError (
@@ -150,15 +147,14 @@ async def _patch(
150147 updated_project = project_update .new
151148 return validated_json (apispec .Project , self ._dump_project (updated_project ))
152149
153- return "/projects/<project_id>" , ["PATCH" ], _patch
150+ return "/projects/<project_id:ulid >" , ["PATCH" ], _patch
154151
155152 def get_all_members (self ) -> BlueprintFactoryResponse :
156153 """List all project members."""
157154
158155 @authenticate (self .authenticator )
159- @validate_path_project_id
160- async def _get_all_members (_ : Request , user : base_models .APIUser , project_id : str ) -> JSONResponse :
161- members = await self .project_member_repo .get_members (user , ULID .from_str (project_id ))
156+ async def _get_all_members (_ : Request , user : base_models .APIUser , project_id : ULID ) -> JSONResponse :
157+ members = await self .project_member_repo .get_members (user , project_id )
162158
163159 users = []
164160
@@ -178,35 +174,33 @@ async def _get_all_members(_: Request, user: base_models.APIUser, project_id: st
178174 ).model_dump (exclude_none = True , mode = "json" )
179175 users .append (user_with_id )
180176
181- return json ( users )
177+ return validated_json ( apispec . ProjectMemberListResponse , users )
182178
183- return "/projects/<project_id>/members" , ["GET" ], _get_all_members
179+ return "/projects/<project_id:ulid >/members" , ["GET" ], _get_all_members
184180
185181 def update_members (self ) -> BlueprintFactoryResponse :
186182 """Update or add project members."""
187183
188184 @authenticate (self .authenticator )
189- @validate_path_project_id
190185 @validate_body_root_model (json = apispec .ProjectMemberListPatchRequest )
191186 async def _update_members (
192- _ : Request , user : base_models .APIUser , project_id : str , body : apispec .ProjectMemberListPatchRequest
187+ _ : Request , user : base_models .APIUser , project_id : ULID , body : apispec .ProjectMemberListPatchRequest
193188 ) -> HTTPResponse :
194189 members = [Member (Role (i .role .value ), i .id , project_id ) for i in body .root ]
195- await self .project_member_repo .update_members (user , ULID . from_str ( project_id ) , members )
190+ await self .project_member_repo .update_members (user , project_id , members )
196191 return HTTPResponse (status = 200 )
197192
198- return "/projects/<project_id>/members" , ["PATCH" ], _update_members
193+ return "/projects/<project_id:ulid >/members" , ["PATCH" ], _update_members
199194
200195 def delete_member (self ) -> BlueprintFactoryResponse :
201196 """Delete a specific project."""
202197
203198 @authenticate (self .authenticator )
204- @validate_path_project_id
205199 @validate_path_user_id
206200 async def _delete_member (
207- _ : Request , user : base_models .APIUser , project_id : str , member_id : str
201+ _ : Request , user : base_models .APIUser , project_id : ULID , member_id : str
208202 ) -> HTTPResponse :
209- await self .project_member_repo .delete_members (user , ULID . from_str ( project_id ) , [member_id ])
203+ await self .project_member_repo .delete_members (user , project_id , [member_id ])
210204 return HTTPResponse (status = 204 )
211205
212206 return "/projects/<project_id>/members/<member_id>" , ["DELETE" ], _delete_member
0 commit comments