mirror of
https://github.com/rzmk/learnhouse.git
synced 2025-12-19 04:19:25 +00:00
feat: implement backend avatar update
This commit is contained in:
parent
cec178c479
commit
a51a128fcb
11 changed files with 103 additions and 19 deletions
2
apps/api/.gitignore
vendored
2
apps/api/.gitignore
vendored
|
|
@ -10,7 +10,7 @@ __pycache__/
|
||||||
.vscode/
|
.vscode/
|
||||||
|
|
||||||
# Learnhouse
|
# Learnhouse
|
||||||
content/org_*
|
content/*
|
||||||
|
|
||||||
# Flyio
|
# Flyio
|
||||||
fly.toml
|
fly.toml
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
from typing import Literal
|
from typing import Literal
|
||||||
from fastapi import APIRouter, Depends, Request
|
from fastapi import APIRouter, Depends, Request, UploadFile
|
||||||
from sqlmodel import Session
|
from sqlmodel import Session
|
||||||
from src.security.auth import get_current_user
|
from src.security.auth import get_current_user
|
||||||
from src.core.events.database import get_db_session
|
from src.core.events.database import get_db_session
|
||||||
|
|
@ -22,6 +22,7 @@ from src.services.users.users import (
|
||||||
read_user_by_id,
|
read_user_by_id,
|
||||||
read_user_by_uuid,
|
read_user_by_uuid,
|
||||||
update_user,
|
update_user,
|
||||||
|
update_user_avatar,
|
||||||
update_user_password,
|
update_user_password,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -137,6 +138,20 @@ async def api_update_user(
|
||||||
return await update_user(request, db_session, user_id, current_user, user_object)
|
return await update_user(request, db_session, user_id, current_user, user_object)
|
||||||
|
|
||||||
|
|
||||||
|
@router.put("/update_avatar/{user_id}", response_model=UserRead, tags=["users"])
|
||||||
|
async def api_update_avatar_user(
|
||||||
|
*,
|
||||||
|
request: Request,
|
||||||
|
db_session: Session = Depends(get_db_session),
|
||||||
|
current_user: PublicUser = Depends(get_current_user),
|
||||||
|
avatar_file: UploadFile | None = None,
|
||||||
|
) -> UserRead:
|
||||||
|
"""
|
||||||
|
Update User
|
||||||
|
"""
|
||||||
|
return await update_user_avatar(request, db_session, current_user, avatar_file)
|
||||||
|
|
||||||
|
|
||||||
@router.put("/change_password/{user_id}", response_model=UserRead, tags=["users"])
|
@router.put("/change_password/{user_id}", response_model=UserRead, tags=["users"])
|
||||||
async def api_update_user_password(
|
async def api_update_user_password(
|
||||||
*,
|
*,
|
||||||
|
|
|
||||||
|
|
@ -50,7 +50,8 @@ async def upload_file_and_return_file_object(
|
||||||
|
|
||||||
await upload_content(
|
await upload_content(
|
||||||
f"courses/{course_uuid}/activities/{activity_uuid}/dynamic/blocks/{type_of_block}/{block_id}",
|
f"courses/{course_uuid}/activities/{activity_uuid}/dynamic/blocks/{type_of_block}/{block_id}",
|
||||||
org_uuid=org_uuid,
|
type_of_dir='orgs',
|
||||||
|
uuid=org_uuid,
|
||||||
file_binary=file_binary,
|
file_binary=file_binary,
|
||||||
file_and_format=f"{file_id}.{file_format}",
|
file_and_format=f"{file_id}.{file_format}",
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -8,6 +8,7 @@ async def upload_pdf(pdf_file, activity_uuid, org_uuid, course_uuid):
|
||||||
try:
|
try:
|
||||||
await upload_content(
|
await upload_content(
|
||||||
f"courses/{course_uuid}/activities/{activity_uuid}/documentpdf",
|
f"courses/{course_uuid}/activities/{activity_uuid}/documentpdf",
|
||||||
|
"orgs",
|
||||||
org_uuid,
|
org_uuid,
|
||||||
contents,
|
contents,
|
||||||
f"documentpdf.{pdf_format}",
|
f"documentpdf.{pdf_format}",
|
||||||
|
|
|
||||||
|
|
@ -10,6 +10,7 @@ async def upload_video(video_file, activity_uuid, org_uuid, course_uuid):
|
||||||
await upload_content(
|
await upload_content(
|
||||||
f"courses/{course_uuid}/activities/{activity_uuid}/video",
|
f"courses/{course_uuid}/activities/{activity_uuid}/video",
|
||||||
org_uuid,
|
org_uuid,
|
||||||
|
org_uuid,
|
||||||
contents,
|
contents,
|
||||||
f"video.{video_format}",
|
f"video.{video_format}",
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -213,7 +213,7 @@ async def update_course_thumbnail(
|
||||||
if thumbnail_file and thumbnail_file.filename:
|
if thumbnail_file and thumbnail_file.filename:
|
||||||
name_in_disk = f"{course_uuid}_thumbnail_{uuid4()}.{thumbnail_file.filename.split('.')[-1]}"
|
name_in_disk = f"{course_uuid}_thumbnail_{uuid4()}.{thumbnail_file.filename.split('.')[-1]}"
|
||||||
await upload_thumbnail(
|
await upload_thumbnail(
|
||||||
thumbnail_file, name_in_disk, org.org_uuid, course.course_uuid
|
thumbnail_file, name_in_disk, 'users', course.course_uuid
|
||||||
)
|
)
|
||||||
|
|
||||||
# Update course
|
# Update course
|
||||||
|
|
|
||||||
|
|
@ -1,13 +1,13 @@
|
||||||
|
|
||||||
from src.services.utils.upload_content import upload_content
|
from src.services.utils.upload_content import upload_content
|
||||||
|
|
||||||
|
|
||||||
async def upload_thumbnail(thumbnail_file, name_in_disk, org_id, course_id):
|
async def upload_thumbnail(thumbnail_file, name_in_disk, org_uuid, course_id):
|
||||||
contents = thumbnail_file.file.read()
|
contents = thumbnail_file.file.read()
|
||||||
try:
|
try:
|
||||||
await upload_content(
|
await upload_content(
|
||||||
f"courses/{course_id}/thumbnails",
|
f"courses/{course_id}/thumbnails",
|
||||||
org_id,
|
"orgs",
|
||||||
|
org_uuid,
|
||||||
contents,
|
contents,
|
||||||
f"{name_in_disk}",
|
f"{name_in_disk}",
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -10,6 +10,7 @@ async def upload_org_logo(logo_file, org_uuid):
|
||||||
await upload_content(
|
await upload_content(
|
||||||
"logos",
|
"logos",
|
||||||
org_uuid,
|
org_uuid,
|
||||||
|
org_uuid,
|
||||||
contents,
|
contents,
|
||||||
name_in_disk,
|
name_in_disk,
|
||||||
)
|
)
|
||||||
|
|
|
||||||
16
apps/api/src/services/users/avatars.py
Normal file
16
apps/api/src/services/users/avatars.py
Normal file
|
|
@ -0,0 +1,16 @@
|
||||||
|
from src.services.utils.upload_content import upload_content
|
||||||
|
|
||||||
|
|
||||||
|
async def upload_avatar(avatar_file, name_in_disk, user_uuid):
|
||||||
|
contents = avatar_file.file.read()
|
||||||
|
try:
|
||||||
|
await upload_content(
|
||||||
|
f"avatars",
|
||||||
|
"users",
|
||||||
|
user_uuid,
|
||||||
|
contents,
|
||||||
|
f"{name_in_disk}",
|
||||||
|
)
|
||||||
|
|
||||||
|
except Exception:
|
||||||
|
return {"message": "There was an error uploading the file"}
|
||||||
|
|
@ -1,8 +1,9 @@
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
from typing import Literal
|
from typing import Literal
|
||||||
from uuid import uuid4
|
from uuid import uuid4
|
||||||
from fastapi import HTTPException, Request, status
|
from fastapi import HTTPException, Request, UploadFile, status
|
||||||
from sqlmodel import Session, select
|
from sqlmodel import Session, select
|
||||||
|
from src.services.users.avatars import upload_avatar
|
||||||
from src.db.roles import Role, RoleRead
|
from src.db.roles import Role, RoleRead
|
||||||
from src.security.rbac.rbac import (
|
from src.security.rbac.rbac import (
|
||||||
authorization_verify_based_on_roles_and_authorship,
|
authorization_verify_based_on_roles_and_authorship,
|
||||||
|
|
@ -195,6 +196,49 @@ async def update_user(
|
||||||
return user
|
return user
|
||||||
|
|
||||||
|
|
||||||
|
async def update_user_avatar(
|
||||||
|
request: Request,
|
||||||
|
db_session: Session,
|
||||||
|
current_user: PublicUser | AnonymousUser,
|
||||||
|
avatar_file: UploadFile | None = None,
|
||||||
|
):
|
||||||
|
# Get user
|
||||||
|
statement = select(User).where(User.id == current_user.id)
|
||||||
|
user = db_session.exec(statement).first()
|
||||||
|
|
||||||
|
if not user:
|
||||||
|
raise HTTPException(
|
||||||
|
status_code=400,
|
||||||
|
detail="User does not exist",
|
||||||
|
)
|
||||||
|
|
||||||
|
# RBAC check
|
||||||
|
await rbac_check(request, current_user, "update", user.user_uuid, db_session)
|
||||||
|
|
||||||
|
# Upload thumbnail
|
||||||
|
if avatar_file and avatar_file.filename:
|
||||||
|
name_in_disk = f"{user.user_uuid}_avatar_{uuid4()}.{avatar_file.filename.split('.')[-1]}"
|
||||||
|
await upload_avatar(avatar_file, name_in_disk, user.user_uuid)
|
||||||
|
|
||||||
|
# Update course
|
||||||
|
if name_in_disk:
|
||||||
|
user.avatar_image = name_in_disk
|
||||||
|
else:
|
||||||
|
raise HTTPException(
|
||||||
|
status_code=500,
|
||||||
|
detail="Issue with Avatar upload",
|
||||||
|
)
|
||||||
|
|
||||||
|
# Update user in database
|
||||||
|
db_session.add(user)
|
||||||
|
db_session.commit()
|
||||||
|
db_session.refresh(user)
|
||||||
|
|
||||||
|
user = UserRead.from_orm(user)
|
||||||
|
|
||||||
|
return user
|
||||||
|
|
||||||
|
|
||||||
async def update_user_password(
|
async def update_user_password(
|
||||||
request: Request,
|
request: Request,
|
||||||
db_session: Session,
|
db_session: Session,
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,4 @@
|
||||||
|
from typing import Literal
|
||||||
import boto3
|
import boto3
|
||||||
from botocore.exceptions import ClientError
|
from botocore.exceptions import ClientError
|
||||||
import os
|
import os
|
||||||
|
|
@ -6,7 +7,11 @@ from config.config import get_learnhouse_config
|
||||||
|
|
||||||
|
|
||||||
async def upload_content(
|
async def upload_content(
|
||||||
directory: str, org_uuid: str, file_binary: bytes, file_and_format: str
|
directory: str,
|
||||||
|
type_of_dir: Literal["orgs", "users"],
|
||||||
|
uuid: str, # org_uuid or user_uuid
|
||||||
|
file_binary: bytes,
|
||||||
|
file_and_format: str,
|
||||||
):
|
):
|
||||||
# Get Learnhouse Config
|
# Get Learnhouse Config
|
||||||
learnhouse_config = get_learnhouse_config()
|
learnhouse_config = get_learnhouse_config()
|
||||||
|
|
@ -16,12 +21,12 @@ async def upload_content(
|
||||||
|
|
||||||
if content_delivery == "filesystem":
|
if content_delivery == "filesystem":
|
||||||
# create folder for activity
|
# create folder for activity
|
||||||
if not os.path.exists(f"content/{org_uuid}/{directory}"):
|
if not os.path.exists(f"content/{type_of_dir}/{uuid}/{directory}"):
|
||||||
# create folder for activity
|
# create folder for activity
|
||||||
os.makedirs(f"content/{org_uuid}/{directory}")
|
os.makedirs(f"content/{type_of_dir}/{uuid}/{directory}")
|
||||||
# upload file to server
|
# upload file to server
|
||||||
with open(
|
with open(
|
||||||
f"content/{org_uuid}/{directory}/{file_and_format}",
|
f"content/{type_of_dir}/{uuid}/{directory}/{file_and_format}",
|
||||||
"wb",
|
"wb",
|
||||||
) as f:
|
) as f:
|
||||||
f.write(file_binary)
|
f.write(file_binary)
|
||||||
|
|
@ -37,13 +42,13 @@ async def upload_content(
|
||||||
)
|
)
|
||||||
|
|
||||||
# Create folder for activity
|
# Create folder for activity
|
||||||
if not os.path.exists(f"content/{org_uuid}/{directory}"):
|
if not os.path.exists(f"content/{type_of_dir}/{uuid}/{directory}"):
|
||||||
# create folder for activity
|
# create folder for activity
|
||||||
os.makedirs(f"content/{org_uuid}/{directory}")
|
os.makedirs(f"content/{type_of_dir}/{uuid}/{directory}")
|
||||||
|
|
||||||
# Upload file to server
|
# Upload file to server
|
||||||
with open(
|
with open(
|
||||||
f"content/{org_uuid}/{directory}/{file_and_format}",
|
f"content/{type_of_dir}/{uuid}/{directory}/{file_and_format}",
|
||||||
"wb",
|
"wb",
|
||||||
) as f:
|
) as f:
|
||||||
f.write(file_binary)
|
f.write(file_binary)
|
||||||
|
|
@ -52,9 +57,9 @@ async def upload_content(
|
||||||
print("Uploading to s3 using boto3...")
|
print("Uploading to s3 using boto3...")
|
||||||
try:
|
try:
|
||||||
s3.upload_file(
|
s3.upload_file(
|
||||||
f"content/{org_uuid}/{directory}/{file_and_format}",
|
f"content/{type_of_dir}/{uuid}/{directory}/{file_and_format}",
|
||||||
"learnhouse-media",
|
"learnhouse-media",
|
||||||
f"content/{org_uuid}/{directory}/{file_and_format}",
|
f"content/{type_of_dir}/{uuid}/{directory}/{file_and_format}",
|
||||||
)
|
)
|
||||||
except ClientError as e:
|
except ClientError as e:
|
||||||
print(e)
|
print(e)
|
||||||
|
|
@ -63,7 +68,7 @@ async def upload_content(
|
||||||
try:
|
try:
|
||||||
s3.head_object(
|
s3.head_object(
|
||||||
Bucket="learnhouse-media",
|
Bucket="learnhouse-media",
|
||||||
Key=f"content/{org_uuid}/{directory}/{file_and_format}",
|
Key=f"content/{type_of_dir}/{uuid}/{directory}/{file_and_format}",
|
||||||
)
|
)
|
||||||
print("File upload successful!")
|
print("File upload successful!")
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue