mirror of
https://github.com/fromchat-messenger/web.git
synced 2026-09-22 19:15:08 +03:00
Fix profile
This commit is contained in:
@@ -8,9 +8,15 @@ import io
|
|||||||
|
|
||||||
from dependencies import get_db, get_current_user
|
from dependencies import get_db, get_current_user
|
||||||
from models import User, UpdateBioRequest, UserProfileResponse
|
from models import User, UpdateBioRequest, UserProfileResponse
|
||||||
|
from pydantic import BaseModel
|
||||||
|
|
||||||
router = APIRouter()
|
router = APIRouter()
|
||||||
|
|
||||||
|
# Request models
|
||||||
|
class UpdateProfileRequest(BaseModel):
|
||||||
|
nickname: str | None = None
|
||||||
|
description: str | None = None
|
||||||
|
|
||||||
# Create uploads directory if it doesn't exist
|
# Create uploads directory if it doesn't exist
|
||||||
PROFILE_PICTURES_DIR = Path("data/uploads/pfp")
|
PROFILE_PICTURES_DIR = Path("data/uploads/pfp")
|
||||||
|
|
||||||
@@ -98,6 +104,56 @@ async def get_user_profile(
|
|||||||
"created_at": current_user.created_at
|
"created_at": current_user.created_at
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@router.put("/user/profile")
|
||||||
|
async def update_user_profile(
|
||||||
|
request: UpdateProfileRequest,
|
||||||
|
current_user: User = Depends(get_current_user),
|
||||||
|
db: Session = Depends(get_db)
|
||||||
|
):
|
||||||
|
"""
|
||||||
|
Update current user's profile information
|
||||||
|
"""
|
||||||
|
updated = False
|
||||||
|
|
||||||
|
# Update username if provided
|
||||||
|
if request.nickname is not None:
|
||||||
|
nickname = request.nickname.strip()
|
||||||
|
if len(nickname) < 3:
|
||||||
|
raise HTTPException(status_code=400, detail="Username must be at least 3 characters long")
|
||||||
|
if len(nickname) > 50:
|
||||||
|
raise HTTPException(status_code=400, detail="Username must be 50 characters or less")
|
||||||
|
|
||||||
|
# Check if username is already taken by another user
|
||||||
|
existing_user = db.query(User).filter(User.username == nickname, User.id != current_user.id).first()
|
||||||
|
if existing_user:
|
||||||
|
raise HTTPException(status_code=400, detail="Username already taken")
|
||||||
|
|
||||||
|
current_user.username = nickname
|
||||||
|
updated = True
|
||||||
|
|
||||||
|
# Update bio if provided
|
||||||
|
if request.description is not None:
|
||||||
|
bio = request.description.strip()
|
||||||
|
if len(bio) > 500:
|
||||||
|
raise HTTPException(status_code=400, detail="Bio must be 500 characters or less")
|
||||||
|
|
||||||
|
current_user.bio = bio
|
||||||
|
updated = True
|
||||||
|
|
||||||
|
if updated:
|
||||||
|
db.commit()
|
||||||
|
return {
|
||||||
|
"message": "Profile updated successfully",
|
||||||
|
"username": current_user.username,
|
||||||
|
"bio": current_user.bio
|
||||||
|
}
|
||||||
|
else:
|
||||||
|
return {
|
||||||
|
"message": "No changes made",
|
||||||
|
"username": current_user.username,
|
||||||
|
"bio": current_user.bio
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
@router.put("/user/bio")
|
@router.put("/user/bio")
|
||||||
async def update_user_bio(
|
async def update_user_bio(
|
||||||
|
|||||||
@@ -25,7 +25,13 @@ export async function loadProfile(): Promise<ProfileData | null> {
|
|||||||
});
|
});
|
||||||
|
|
||||||
if (response.ok) {
|
if (response.ok) {
|
||||||
return await response.json();
|
const data = await response.json();
|
||||||
|
// Map backend fields to frontend fields
|
||||||
|
return {
|
||||||
|
profile_picture: data.profile_picture,
|
||||||
|
nickname: data.username,
|
||||||
|
description: data.bio
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
@@ -83,10 +89,19 @@ export async function uploadProfilePicture(file: Blob): Promise<UploadResponse |
|
|||||||
*/
|
*/
|
||||||
export async function updateProfile(data: Partial<ProfileData>): Promise<boolean> {
|
export async function updateProfile(data: Partial<ProfileData>): Promise<boolean> {
|
||||||
try {
|
try {
|
||||||
|
// Map frontend fields to backend fields
|
||||||
|
const backendData = {
|
||||||
|
nickname: data.nickname,
|
||||||
|
description: data.description
|
||||||
|
};
|
||||||
|
|
||||||
const response = await fetch('/api/user/profile', {
|
const response = await fetch('/api/user/profile', {
|
||||||
method: 'PUT',
|
method: 'PUT',
|
||||||
headers: getAuthHeaders(),
|
headers: {
|
||||||
body: JSON.stringify(data)
|
...getAuthHeaders(),
|
||||||
|
'Content-Type': 'application/json'
|
||||||
|
},
|
||||||
|
body: JSON.stringify(backendData)
|
||||||
});
|
});
|
||||||
|
|
||||||
return response.ok;
|
return response.ok;
|
||||||
|
|||||||
@@ -22,7 +22,13 @@ export async function loadProfile(token: string): Promise<ProfileData | null> {
|
|||||||
});
|
});
|
||||||
|
|
||||||
if (response.ok) {
|
if (response.ok) {
|
||||||
return await response.json();
|
const data = await response.json();
|
||||||
|
// Map backend fields to frontend fields
|
||||||
|
return {
|
||||||
|
profile_picture: data.profile_picture,
|
||||||
|
nickname: data.username,
|
||||||
|
description: data.bio
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
@@ -61,10 +67,19 @@ export async function uploadProfilePicture(token: string, file: Blob): Promise<U
|
|||||||
*/
|
*/
|
||||||
export async function updateProfile(token: string, data: Partial<ProfileData>): Promise<boolean> {
|
export async function updateProfile(token: string, data: Partial<ProfileData>): Promise<boolean> {
|
||||||
try {
|
try {
|
||||||
|
// Map frontend fields to backend fields
|
||||||
|
const backendData = {
|
||||||
|
nickname: data.nickname,
|
||||||
|
description: data.description
|
||||||
|
};
|
||||||
|
|
||||||
const response = await fetch(`${API_BASE_URL}/user/profile`, {
|
const response = await fetch(`${API_BASE_URL}/user/profile`, {
|
||||||
method: 'PUT',
|
method: 'PUT',
|
||||||
headers: getAuthHeaders(token),
|
headers: {
|
||||||
body: JSON.stringify(data)
|
...getAuthHeaders(token),
|
||||||
|
'Content-Type': 'application/json'
|
||||||
|
},
|
||||||
|
body: JSON.stringify(backendData)
|
||||||
});
|
});
|
||||||
|
|
||||||
return response.ok;
|
return response.ok;
|
||||||
|
|||||||
@@ -9,8 +9,9 @@ import { MaterialTextField } from "../core/TextField";
|
|||||||
|
|
||||||
export function ProfileDialog({ isOpen, onOpenChange }: DialogProps) {
|
export function ProfileDialog({ isOpen, onOpenChange }: DialogProps) {
|
||||||
const { profileData, isLoading, isUpdating, updateProfileData, uploadProfilePictureData } = useProfile();
|
const { profileData, isLoading, isUpdating, updateProfileData, uploadProfilePictureData } = useProfile();
|
||||||
const [username, setUsername] = useState("");
|
|
||||||
const [description, setDescription] = useState("");
|
const [username, setUsername] = useState(profileData?.nickname ?? "");
|
||||||
|
const [description, setDescription] = useState(profileData?.description ?? "");
|
||||||
const [selectedImage, setSelectedImage] = useState<File | null>(null);
|
const [selectedImage, setSelectedImage] = useState<File | null>(null);
|
||||||
const [showCropper, setShowCropper] = useState(false);
|
const [showCropper, setShowCropper] = useState(false);
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user