feat(api): add bulk user creation endpoint
This commit is contained in:
@ -1,5 +1,6 @@
|
|||||||
|
import re
|
||||||
from typing import Optional, List
|
from typing import Optional, List
|
||||||
from pydantic import BaseModel, RootModel, Field
|
from pydantic import BaseModel, RootModel, Field, field_validator
|
||||||
|
|
||||||
|
|
||||||
class UserInfoResponse(BaseModel):
|
class UserInfoResponse(BaseModel):
|
||||||
@ -26,6 +27,27 @@ class AddUserInputBody(BaseModel):
|
|||||||
creation_date: Optional[str] = None
|
creation_date: Optional[str] = None
|
||||||
unlimited: bool = False
|
unlimited: bool = False
|
||||||
|
|
||||||
|
@field_validator('username')
|
||||||
|
def validate_username(cls, v):
|
||||||
|
if not re.match(r"^[a-zA-Z0-9_]+$", v):
|
||||||
|
raise ValueError('Username can only contain letters, numbers, and underscores.')
|
||||||
|
return v
|
||||||
|
|
||||||
|
|
||||||
|
class AddBulkUsersInputBody(BaseModel):
|
||||||
|
traffic_gb: float
|
||||||
|
expiration_days: int
|
||||||
|
count: int
|
||||||
|
prefix: str
|
||||||
|
start_number: int = 1
|
||||||
|
unlimited: bool = False
|
||||||
|
|
||||||
|
@field_validator('prefix')
|
||||||
|
def validate_prefix(cls, v):
|
||||||
|
if not re.match(r"^[a-zA-Z0-9_]*$", v):
|
||||||
|
raise ValueError('Prefix can only contain letters, numbers, and underscores.')
|
||||||
|
return v
|
||||||
|
|
||||||
|
|
||||||
class EditUserInputBody(BaseModel):
|
class EditUserInputBody(BaseModel):
|
||||||
new_username: Optional[str] = None
|
new_username: Optional[str] = None
|
||||||
@ -36,6 +58,12 @@ class EditUserInputBody(BaseModel):
|
|||||||
blocked: Optional[bool] = None
|
blocked: Optional[bool] = None
|
||||||
unlimited_ip: Optional[bool] = None
|
unlimited_ip: Optional[bool] = None
|
||||||
|
|
||||||
|
@field_validator('new_username')
|
||||||
|
def validate_new_username(cls, v):
|
||||||
|
if v and not re.match(r"^[a-zA-Z0-9_]+$", v):
|
||||||
|
raise ValueError('Username can only contain letters, numbers, and underscores.')
|
||||||
|
return v
|
||||||
|
|
||||||
class NodeUri(BaseModel):
|
class NodeUri(BaseModel):
|
||||||
name: str
|
name: str
|
||||||
uri: str
|
uri: str
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
import json
|
import json
|
||||||
from fastapi import APIRouter, HTTPException
|
from fastapi import APIRouter, HTTPException
|
||||||
|
|
||||||
from .schema.user import UserListResponse, UserInfoResponse, AddUserInputBody, EditUserInputBody, UserUriResponse
|
from .schema.user import UserListResponse, UserInfoResponse, AddUserInputBody, EditUserInputBody, UserUriResponse, AddBulkUsersInputBody
|
||||||
from .schema.response import DetailResponse
|
from .schema.response import DetailResponse
|
||||||
import cli_api
|
import cli_api
|
||||||
|
|
||||||
@ -57,6 +57,29 @@ async def add_user_api(body: AddUserInputBody):
|
|||||||
detail=f"An unexpected error occurred while adding user '{body.username}': {str(e)}")
|
detail=f"An unexpected error occurred while adding user '{body.username}': {str(e)}")
|
||||||
|
|
||||||
|
|
||||||
|
@router.post('/bulk/', response_model=DetailResponse, status_code=201)
|
||||||
|
async def add_bulk_users_api(body: AddBulkUsersInputBody):
|
||||||
|
"""
|
||||||
|
Add multiple users in bulk.
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
cli_api.bulk_user_add(
|
||||||
|
traffic_gb=body.traffic_gb,
|
||||||
|
expiration_days=body.expiration_days,
|
||||||
|
count=body.count,
|
||||||
|
prefix=body.prefix,
|
||||||
|
start_number=body.start_number,
|
||||||
|
unlimited=body.unlimited
|
||||||
|
)
|
||||||
|
return DetailResponse(detail=f"Successfully started adding {body.count} users with prefix '{body.prefix}'.")
|
||||||
|
except cli_api.CommandExecutionError as e:
|
||||||
|
raise HTTPException(status_code=400,
|
||||||
|
detail=f'Failed to add bulk users: {str(e)}')
|
||||||
|
except Exception as e:
|
||||||
|
raise HTTPException(status_code=500,
|
||||||
|
detail=f"An unexpected error occurred while adding bulk users: {str(e)}")
|
||||||
|
|
||||||
|
|
||||||
@router.get('/{username}', response_model=UserInfoResponse)
|
@router.get('/{username}', response_model=UserInfoResponse)
|
||||||
async def get_user_api(username: str):
|
async def get_user_api(username: str):
|
||||||
"""
|
"""
|
||||||
@ -191,4 +214,4 @@ async def show_user_uri_api(username: str):
|
|||||||
except HTTPException:
|
except HTTPException:
|
||||||
raise
|
raise
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
raise HTTPException(status_code=400, detail=f'Unexpected error: {str(e)}')
|
raise HTTPException(status_code=400, detail=f'Unexpected error: {str(e)}')
|
||||||
Reference in New Issue
Block a user