| 16 | |
| 17 | |
| 18 | class UserGeneralForm(StarletteForm): |
| 19 | name = StringField(_l("Display name"), validators=[Length(max=256)]) |
| 20 | username = StringField( |
| 21 | _l("Username"), |
| 22 | validators=[ |
| 23 | DataRequired(), |
| 24 | Length(min=1, max=50), |
| 25 | Regexp( |
| 26 | r"^[A-Za-z0-9][A-Za-z0-9._-]*[A-Za-z0-9]$", |
| 27 | message=_l( |
| 28 | "Usernames can only contain letters, numbers, hyphens, underscores and dots. They cannot start or end with a dot, underscore or hyphen." |
| 29 | ), |
| 30 | ), |
| 31 | ], |
| 32 | ) |
| 33 | avatar = FileField(_l("Avatar")) |
| 34 | delete_avatar = BooleanField(_l("Delete avatar"), default=False) |
| 35 | |
| 36 | def __init__(self, *args, db: AsyncSession, user: User, **kwargs): |
| 37 | super().__init__(*args, **kwargs) |
| 38 | self.db = db |
| 39 | self.user = user |
| 40 | |
| 41 | async def async_validate_username(self, field): |
| 42 | if self.db and self.user: |
| 43 | if self.user.username != field.data: |
| 44 | result = await self.db.execute( |
| 45 | select(User).where( |
| 46 | func.lower(User.username) == field.data.lower(), |
| 47 | User.status != "deleted", |
| 48 | User.id != self.user.id, |
| 49 | ) |
| 50 | ) |
| 51 | if result.scalar_one_or_none(): |
| 52 | raise ValidationError( |
| 53 | _("A user with this username already exists.") |
| 54 | ) |
| 55 | |
| 56 | def validate_avatar(self, field): |
| 57 | if field.data: |
| 58 | if field.data.content_type not in [ |
| 59 | "image/jpeg", |
| 60 | "image/png", |
| 61 | "image/gif", |
| 62 | "image/webp", |
| 63 | ]: |
| 64 | raise ValidationError( |
| 65 | _( |
| 66 | "Invalid file type. Only JPEG, PNG, GIF and WebP images are allowed." |
| 67 | ) |
| 68 | ) |
| 69 | if field.data.size > 10 * 1024 * 1024: # 10MB |
| 70 | raise ValidationError( |
| 71 | _("File size exceeds the maximum allowed (10MB).") |
| 72 | ) |
| 73 | |
| 74 | |
| 75 | class UserEmailForm(StarletteForm): |
nothing calls this directly
no outgoing calls
no test coverage detected