use anyhow::Result;
use crate::{file_manager::save_file_with_content, project_info::ProjectInfo};
fn create_message_model_file() -> String {
r#"from __future__ import annotations
from camel_converter.pydantic_base import CamelBase
class Message(CamelBase):
"""Used for generic messages."""
message: str
"#
.to_string()
}
pub fn save_message_model_file(project_info: &ProjectInfo) -> Result<()> {
let base = &project_info.source_dir_path();
let file_path = base.join("models/message.py");
let file_content = create_message_model_file();
save_file_with_content(&file_path, &file_content)?;
Ok(())
}
fn create_token_models_file() -> String {
r#"from pydantic import BaseModel
class Token(BaseModel):
"""Don't use CamelBase here because FastAPI requires snake case variables for the token."""
access_token: str
token_type: str = "bearer"
class TokenPayload(BaseModel):
"""Contents of the JWT token."""
sub: str | None = None
is_superuser: bool = False
"#
.to_string()
}
pub fn save_token_models_file(project_info: &ProjectInfo) -> Result<()> {
let base = &project_info.source_dir_path();
let file_path = base.join("models/token.py");
let file_content = create_token_models_file();
save_file_with_content(&file_path, &file_content)?;
Ok(())
}
fn create_user_models_file() -> String {
r#"from __future__ import annotations
import re
from datetime import datetime
from camel_converter.pydantic_base import CamelBase
from pydantic import EmailStr, Field, field_validator
class _UserBase(CamelBase):
email: EmailStr = Field(max_length=255)
is_active: bool = True
is_superuser: bool = False
full_name: str = Field(max_length=255)
class UserCreate(_UserBase):
password: str = Field(min_length=8, max_length=255)
@field_validator("password")
@classmethod
def validate_password_requirements(cls, v: str) -> str:
return _validate_password(v)
class UserUpdate(CamelBase):
email: EmailStr | None = Field(default=None, max_length=255)
is_active: bool | None = None
is_superuser: bool | None = None
password: str | None = Field(default=None, min_length=8, max_length=255)
full_name: str | None = Field(default=None, max_length=255)
@field_validator("password")
@classmethod
def validate_password_requirements(cls, v: str) -> str:
return _validate_password(v)
class UserUpdateMe(CamelBase):
email: EmailStr | None = Field(default=None, max_length=255)
full_name: str | None = Field(default=None, max_length=255)
class UpdatePassword(CamelBase):
current_password: str = Field(min_length=8, max_length=255)
new_password: str = Field(min_length=8, max_length=255)
class User(_UserBase):
id: str
hashed_password: str
class UserPublic(_UserBase):
id: str
class UsersPublic(CamelBase):
data: list[UserPublic]
count: int
total_users: int
class UserInDb(_UserBase):
id: str
hashed_password: str
last_login: datetime
def _validate_password(password: str) -> str:
"""Makes sure the password meets the minimum requirements.
Passwords must to contain at least 1 uppercase letter, 1 lowercase letter, a number, and a
special character. They must be a minimum of 8 characters.
"""
if (
not (
re.search(r"[A-Z]", password)
and re.search(r"[a-z]", password)
and re.search(r"\d", password)
and re.search(r"[!@#$%^&*()_+\-=\[\]{};':\"\\|,.<>\/?]", password)
)
or len(password) < 8
):
raise ValueError(
"Password must contain at least one uppercase letter, one lowercase letter, one number, and one special character. They must be a minimum of 8 characters."
)
return password
"#.to_string()
}
pub fn save_user_models_file(project_info: &ProjectInfo) -> Result<()> {
let base = &project_info.source_dir_path();
let file_path = base.join("models/users.py");
let file_content = create_user_models_file();
save_file_with_content(&file_path, &file_content)?;
Ok(())
}