add better member name validation, add debug user create endpoint
This commit is contained in:
		
							parent
							
								
									1bd07dd771
								
							
						
					
					
						commit
						afadffbaac
					
				
					 3 changed files with 66 additions and 14 deletions
				
			
		|  | @ -8,9 +8,7 @@ from foxnouns.db import Member | |||
| from foxnouns.db.aio import async_session | ||||
| from foxnouns.db.util import user_from_ref, is_self | ||||
| from foxnouns.exceptions import NotFoundError, ErrorCode | ||||
| from foxnouns.models import BasePatchModel | ||||
| from foxnouns.models.member import FullMemberModel | ||||
| from foxnouns.models.fields import ProfileField, FieldEntry, PronounEntry | ||||
| from foxnouns.models.member import FullMemberModel, MemberPatchModel | ||||
| from foxnouns.settings import BASE_DOMAIN | ||||
| 
 | ||||
| bp = Blueprint("members_v2", __name__) | ||||
|  | @ -27,20 +25,19 @@ async def get_members(user_ref: str): | |||
|         return [FullMemberModel.model_validate(m) for m in user.members] | ||||
| 
 | ||||
| 
 | ||||
| class MemberPostData(BasePatchModel): | ||||
|     name: str = Field(min_length=1, max_length=100)  # TODO: validate member names more | ||||
|     bio: str | None = Field(max_length=1024, default=None) | ||||
| 
 | ||||
|     names: list[FieldEntry] = Field(default=[]) | ||||
|     pronouns: list[PronounEntry] = Field(default=[]) | ||||
|     fields: list[ProfileField] = Field(default=[]) | ||||
| class MemberCreateModel(MemberPatchModel): | ||||
|     name: str = Field( | ||||
|         min_length=1, | ||||
|         max_length=100, | ||||
|         pattern=r"^[^@\?!#\/\\\[\]\"\{\}'$%&()+<=>^|~`,\*]{1,100}$", | ||||
|     ) | ||||
| 
 | ||||
| 
 | ||||
| @bp.post("/api/v2/members", host=BASE_DOMAIN) | ||||
| @require_auth(scope="member.create") | ||||
| @validate_request(MemberPostData) | ||||
| @validate_request(MemberCreateModel) | ||||
| @validate_response(FullMemberModel, 200) | ||||
| async def create_member(data: MemberPostData): | ||||
| async def create_member(data: MemberCreateModel): | ||||
|     async with async_session() as session: | ||||
|         member = Member( | ||||
|             user_id=g.user.id, | ||||
|  |  | |||
|  | @ -6,7 +6,8 @@ from sqlalchemy import select | |||
| from foxnouns.auth import require_auth | ||||
| from foxnouns.db import User | ||||
| from foxnouns.db.aio import async_session | ||||
| from foxnouns.db.util import user_from_ref, is_self | ||||
| from foxnouns.db.snowflake import Snowflake | ||||
| from foxnouns.db.util import user_from_ref, is_self, create_token, generate_token | ||||
| from foxnouns.exceptions import NotFoundError, ErrorCode | ||||
| from foxnouns.models import BasePatchModel | ||||
| from foxnouns.models.user import UserModel, SelfUserModel, check_username | ||||
|  | @ -48,6 +49,8 @@ class EditUserRequest(BasePatchModel): | |||
| @validate_request(EditUserRequest) | ||||
| @validate_response(SelfUserModel, 200) | ||||
| async def edit_user(data: EditUserRequest): | ||||
|     """Updates the current user.""" | ||||
| 
 | ||||
|     async with async_session() as session: | ||||
|         user = await session.scalar(select(User).where(User.id == g.user.id)) | ||||
| 
 | ||||
|  | @ -61,3 +64,32 @@ async def edit_user(data: EditUserRequest): | |||
|         await session.commit() | ||||
| 
 | ||||
|         return SelfUserModel.model_validate(user) | ||||
| 
 | ||||
| 
 | ||||
| class DebugUserData(BasePatchModel): | ||||
|     username: str | ||||
| 
 | ||||
| 
 | ||||
| class DebugUserResponse(SelfUserModel): | ||||
|     token: str | ||||
| 
 | ||||
| 
 | ||||
| @bp.post("/api/v2/users/debug", host=BASE_DOMAIN) | ||||
| @validate_request(DebugUserData) | ||||
| @validate_response(DebugUserResponse, 200) | ||||
| async def debug_create_user(data: DebugUserData): | ||||
|     """Creates a user from just a username, and returns it along with a token. | ||||
|     FIXME: this must be removed **BEFORE** deploying to production (or even public testing) | ||||
|     """ | ||||
| 
 | ||||
|     async with async_session() as session: | ||||
|         user = User(id=Snowflake.generate_int(), username=data.username) | ||||
|         await session.commit() | ||||
| 
 | ||||
|         session.add(user) | ||||
|         token = await create_token(session, user, ["*"]) | ||||
|         await session.commit() | ||||
|         await user.awaitable_attrs.members | ||||
| 
 | ||||
|         user.token = generate_token(token) | ||||
|         return DebugUserResponse.model_validate(user) | ||||
|  |  | |||
|  | @ -1,7 +1,30 @@ | |||
| from pydantic import Field | ||||
| from pydantic import Field, field_validator | ||||
| 
 | ||||
| from . import BasePatchModel | ||||
| from .fields import FieldEntry, ProfileField, PronounEntry | ||||
| from .user import BaseMemberModel, BaseUserModel | ||||
| 
 | ||||
| 
 | ||||
| class FullMemberModel(BaseMemberModel): | ||||
|     user: BaseUserModel | ||||
| 
 | ||||
| 
 | ||||
| class MemberPatchModel(BasePatchModel): | ||||
|     name: str | None = Field( | ||||
|         min_length=1, | ||||
|         max_length=100, | ||||
|         default=None, | ||||
|         pattern=r"^[^@\?!#\/\\\[\]\"\{\}'$%&()+<=>^|~`,\*]{1,100}$", | ||||
|     ) | ||||
|     bio: str | None = Field(max_length=1024, default=None) | ||||
| 
 | ||||
|     names: list[FieldEntry] = Field(default=[]) | ||||
|     pronouns: list[PronounEntry] = Field(default=[]) | ||||
|     fields: list[ProfileField] = Field(default=[]) | ||||
| 
 | ||||
|     @field_validator("name") | ||||
|     @classmethod | ||||
|     def check_name(cls, value): | ||||
|         if value in [".", "..", "edit"]: | ||||
|             raise ValueError("Name is not allowed") | ||||
|         return value | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue