mirror of
https://github.com/rzmk/learnhouse.git
synced 2025-12-18 11:59:26 +00:00
🎉 first commit
This commit is contained in:
parent
8c00f9a074
commit
91f4291d9b
21 changed files with 614 additions and 3 deletions
37
.gitignore
vendored
37
.gitignore
vendored
|
|
@ -20,7 +20,6 @@ parts/
|
|||
sdist/
|
||||
var/
|
||||
wheels/
|
||||
pip-wheel-metadata/
|
||||
share/python-wheels/
|
||||
*.egg-info/
|
||||
.installed.cfg
|
||||
|
|
@ -50,6 +49,7 @@ coverage.xml
|
|||
*.py,cover
|
||||
.hypothesis/
|
||||
.pytest_cache/
|
||||
cover/
|
||||
|
||||
# Translations
|
||||
*.mo
|
||||
|
|
@ -72,6 +72,7 @@ instance/
|
|||
docs/_build/
|
||||
|
||||
# PyBuilder
|
||||
.pybuilder/
|
||||
target/
|
||||
|
||||
# Jupyter Notebook
|
||||
|
|
@ -82,7 +83,9 @@ profile_default/
|
|||
ipython_config.py
|
||||
|
||||
# pyenv
|
||||
.python-version
|
||||
# For a library or package, you might want to ignore these files since the code is
|
||||
# intended to run in multiple environments; otherwise, check them in:
|
||||
# .python-version
|
||||
|
||||
# pipenv
|
||||
# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
|
||||
|
|
@ -91,7 +94,22 @@ ipython_config.py
|
|||
# install all needed dependencies.
|
||||
#Pipfile.lock
|
||||
|
||||
# PEP 582; used by e.g. github.com/David-OConnor/pyflow
|
||||
# poetry
|
||||
# Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control.
|
||||
# This is especially recommended for binary packages to ensure reproducibility, and is more
|
||||
# commonly ignored for libraries.
|
||||
# https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control
|
||||
#poetry.lock
|
||||
|
||||
# pdm
|
||||
# Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control.
|
||||
#pdm.lock
|
||||
# pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it
|
||||
# in version control.
|
||||
# https://pdm.fming.dev/#use-with-ide
|
||||
.pdm.toml
|
||||
|
||||
# PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm
|
||||
__pypackages__/
|
||||
|
||||
# Celery stuff
|
||||
|
|
@ -127,3 +145,16 @@ dmypy.json
|
|||
|
||||
# Pyre type checker
|
||||
.pyre/
|
||||
|
||||
# pytype static type analyzer
|
||||
.pytype/
|
||||
|
||||
# Cython debug symbols
|
||||
cython_debug/
|
||||
|
||||
# PyCharm
|
||||
# JetBrains specific template is maintained in a separate JetBrains.gitignore that can
|
||||
# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
|
||||
# and can be added to the global gitignore or merged into this file. For a more nuclear
|
||||
# option (not recommended) you can uncomment the following to ignore the entire idea folder.
|
||||
#.idea/
|
||||
17
Dockerfile
Normal file
17
Dockerfile
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
#
|
||||
FROM python:3.10.5
|
||||
|
||||
#
|
||||
WORKDIR /usr/learnhouse
|
||||
|
||||
#
|
||||
COPY ./requirements.txt /usr/learnhouse/requirements.txt
|
||||
|
||||
#
|
||||
RUN pip install --no-cache-dir --upgrade -r /usr/learnhouse/requirements.txt
|
||||
|
||||
#
|
||||
COPY ./ /usr/learnhouse
|
||||
|
||||
#
|
||||
CMD ["uvicorn", "app:app", "--host", "0.0.0.0", "--port", "80" , "--reload"]
|
||||
0
__init__.py
Normal file
0
__init__.py
Normal file
20
app.py
Normal file
20
app.py
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
from typing import Union
|
||||
from fastapi import FastAPI
|
||||
from src import main
|
||||
from fastapi.staticfiles import StaticFiles
|
||||
from src.main import global_router
|
||||
import pymongo
|
||||
|
||||
# Init
|
||||
app = FastAPI(
|
||||
title="LearnHouse",
|
||||
description="LearnHouse is a new open-source platform tailored for learning experiences.",
|
||||
version="0.1.0",
|
||||
root_path="/"
|
||||
)
|
||||
|
||||
app.include_router(global_router)
|
||||
|
||||
@app.get("/")
|
||||
async def root():
|
||||
return {"Message": "Welcome to LearnHouse ✨"}
|
||||
0
config/__init__.py
Normal file
0
config/__init__.py
Normal file
0
config/config.py
Normal file
0
config/config.py
Normal file
0
config/config.yml
Normal file
0
config/config.yml
Normal file
25
docker-compose.yml
Normal file
25
docker-compose.yml
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
version: "3.9"
|
||||
services:
|
||||
api:
|
||||
build: .
|
||||
ports:
|
||||
- "1338:80"
|
||||
volumes:
|
||||
- .:/usr/learnhouse
|
||||
mongo:
|
||||
image: mongo:5.0
|
||||
restart: always
|
||||
ports:
|
||||
- "27017:27017"
|
||||
environment:
|
||||
- MONGO_INITDB_ROOT_USERNAME=learnhouse
|
||||
- MONGO_INITDB_ROOT_PASSWORD=learnhouse
|
||||
mongo-express:
|
||||
image: mongo-express
|
||||
restart: always
|
||||
ports:
|
||||
- 8081:8081
|
||||
environment:
|
||||
ME_CONFIG_MONGODB_ADMINUSERNAME: learnhouse
|
||||
ME_CONFIG_MONGODB_ADMINPASSWORD: learnhouse
|
||||
ME_CONFIG_MONGODB_URL: mongodb://learnhouse:learnhouse@mongo:27017/
|
||||
7
requirements.txt
Normal file
7
requirements.txt
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
fastapi==0.78.0
|
||||
pydantic>=1.8.0,<2.0.0
|
||||
uvicorn>=0.15.0,<0.16.0
|
||||
pymongo==4.1.1
|
||||
python-multipart
|
||||
python-jose
|
||||
passlib
|
||||
0
src/__init__.py
Normal file
0
src/__init__.py
Normal file
18
src/main.py
Normal file
18
src/main.py
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
from .routers import users
|
||||
from fastapi import APIRouter
|
||||
from .routers import users, auth, houses
|
||||
from starlette.responses import FileResponse
|
||||
|
||||
|
||||
global_router = APIRouter(prefix="/api")
|
||||
|
||||
|
||||
## API Routes
|
||||
global_router.include_router(users.router, prefix="/users", tags=["users"])
|
||||
global_router.include_router(auth.router, prefix="/auth", tags=["auth"])
|
||||
global_router.include_router(houses.router, prefix="/houses", tags=["houses"])
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
0
src/routers/__init__.py
Normal file
0
src/routers/__init__.py
Normal file
27
src/routers/auth.py
Normal file
27
src/routers/auth.py
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
from fastapi import Depends, FastAPI, APIRouter, HTTPException, status
|
||||
from fastapi.security import OAuth2PasswordBearer, OAuth2PasswordRequestForm
|
||||
from pydantic import BaseModel
|
||||
from ..services.auth import *
|
||||
from ..services.users import *
|
||||
from datetime import datetime, timedelta
|
||||
|
||||
router = APIRouter()
|
||||
|
||||
|
||||
@router.post("/token", response_model=Token)
|
||||
async def login_for_access_token(form_data: OAuth2PasswordRequestForm = Depends()):
|
||||
"""
|
||||
OAuth2 compatible token login, get access token for future requests
|
||||
"""
|
||||
user = await authenticate_user(form_data.username, form_data.password)
|
||||
if not user:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_401_UNAUTHORIZED,
|
||||
detail="Incorrect username or password",
|
||||
headers={"WWW-Authenticate": "Bearer"},
|
||||
)
|
||||
access_token_expires = timedelta(minutes=ACCESS_TOKEN_EXPIRE_MINUTES)
|
||||
access_token = create_access_token(
|
||||
data={"sub": user.username}, expires_delta=access_token_expires
|
||||
)
|
||||
return {"access_token": access_token, "token_type": "bearer"}
|
||||
49
src/routers/houses.py
Normal file
49
src/routers/houses.py
Normal file
|
|
@ -0,0 +1,49 @@
|
|||
from fastapi import APIRouter, Depends
|
||||
from src.services.auth import get_current_user
|
||||
|
||||
from src.services.houses import House, HouseInDB, create_house, get_house, get_houses, update_house, delete_house
|
||||
from src.services.users import User
|
||||
|
||||
|
||||
router = APIRouter()
|
||||
|
||||
|
||||
@router.post("/")
|
||||
async def api_create_house(house_object: House, current_user: User = Depends(get_current_user)):
|
||||
"""
|
||||
Create new house
|
||||
"""
|
||||
return await create_house(house_object, current_user)
|
||||
|
||||
|
||||
@router.get("/{house_id}")
|
||||
async def api_get_house(house_id: str):
|
||||
"""
|
||||
Get single House by house_id
|
||||
"""
|
||||
return await get_house(house_id)
|
||||
|
||||
|
||||
@router.get("/page/{house_id}/limit/{limit}")
|
||||
async def api_get_house_by(page: int, limit: int):
|
||||
"""
|
||||
Get houses by page and limit
|
||||
"""
|
||||
return await get_houses(page, limit)
|
||||
|
||||
|
||||
@router.put("/{house_id}")
|
||||
async def api_update_house(house_object: House, house_id: str, current_user: User = Depends(get_current_user)):
|
||||
"""
|
||||
Update House by house_id
|
||||
"""
|
||||
return await update_house(house_object, house_id, current_user)
|
||||
|
||||
|
||||
@router.delete("/{house_id}")
|
||||
async def api_delete_house(house_id: str, current_user: User = Depends(get_current_user)):
|
||||
"""
|
||||
Delete House by ID
|
||||
"""
|
||||
|
||||
return await delete_house(house_id, current_user)
|
||||
51
src/routers/users.py
Normal file
51
src/routers/users.py
Normal file
|
|
@ -0,0 +1,51 @@
|
|||
from fastapi import Depends, FastAPI, APIRouter
|
||||
from fastapi.security import OAuth2PasswordBearer, OAuth2PasswordRequestForm
|
||||
from pydantic import BaseModel
|
||||
from ..services.auth import *
|
||||
from ..services.users import *
|
||||
|
||||
oauth2_scheme = OAuth2PasswordBearer(tokenUrl="/api/auth/token")
|
||||
|
||||
|
||||
router = APIRouter()
|
||||
|
||||
|
||||
@router.get("/me")
|
||||
async def api_get_current_user(current_user: User = Depends(get_current_user)):
|
||||
"""
|
||||
Get current user
|
||||
"""
|
||||
return current_user.dict()
|
||||
|
||||
|
||||
@router.get("/username/{username}")
|
||||
async def api_get_user_by_username(username: str):
|
||||
"""
|
||||
Get single user by username
|
||||
"""
|
||||
return await get_user(username)
|
||||
|
||||
|
||||
@router.post("/")
|
||||
async def api_create_user(user_object: UserInDB):
|
||||
"""
|
||||
Create new user
|
||||
"""
|
||||
return await create_user(user_object)
|
||||
|
||||
|
||||
@router.delete("/username/{username}")
|
||||
async def api_delete_user(username: str):
|
||||
"""
|
||||
Delete user by ID
|
||||
"""
|
||||
|
||||
return await delete_user(username)
|
||||
|
||||
|
||||
@router.put("/username/{username}")
|
||||
async def api_update_user(user_object: UserInDB):
|
||||
"""
|
||||
Update user by ID
|
||||
"""
|
||||
return await update_user(user_object)
|
||||
0
src/services/__init__.py
Normal file
0
src/services/__init__.py
Normal file
64
src/services/auth.py
Normal file
64
src/services/auth.py
Normal file
|
|
@ -0,0 +1,64 @@
|
|||
from pydantic import BaseModel
|
||||
from fastapi import Depends, FastAPI, APIRouter, HTTPException, status
|
||||
from fastapi.security import OAuth2PasswordBearer, OAuth2PasswordRequestForm
|
||||
from passlib.context import CryptContext
|
||||
from jose import JWTError, jwt
|
||||
from datetime import datetime, timedelta
|
||||
from ..services.users import *
|
||||
from ..services.security import *
|
||||
|
||||
oauth2_scheme = OAuth2PasswordBearer(tokenUrl="/api/auth/token")
|
||||
|
||||
#### Classes ####################################################
|
||||
|
||||
|
||||
class Token(BaseModel):
|
||||
access_token: str
|
||||
token_type: str
|
||||
|
||||
|
||||
class TokenData(BaseModel):
|
||||
username: str | None = None
|
||||
|
||||
#### Classes ####################################################
|
||||
|
||||
|
||||
|
||||
async def authenticate_user(username: str, password: str):
|
||||
user = await security_get_user(username)
|
||||
if not user:
|
||||
return False
|
||||
if not await security_verify_password(password, user.password):
|
||||
return False
|
||||
return user
|
||||
|
||||
|
||||
def create_access_token(data: dict, expires_delta: timedelta | None = None):
|
||||
to_encode = data.copy()
|
||||
if expires_delta:
|
||||
expire = datetime.utcnow() + expires_delta
|
||||
else:
|
||||
expire = datetime.utcnow() + timedelta(minutes=15)
|
||||
to_encode.update({"exp": expire})
|
||||
encoded_jwt = jwt.encode(to_encode, SECRET_KEY, algorithm=ALGORITHM)
|
||||
return encoded_jwt
|
||||
|
||||
|
||||
async def get_current_user(token: str = Depends(oauth2_scheme)):
|
||||
credentials_exception = HTTPException(
|
||||
status_code=status.HTTP_401_UNAUTHORIZED,
|
||||
detail="Could not validate credentials",
|
||||
headers={"WWW-Authenticate": "Bearer"},
|
||||
)
|
||||
try:
|
||||
payload = jwt.decode(token, SECRET_KEY, algorithms=[ALGORITHM])
|
||||
username: str = payload.get("sub")
|
||||
if username is None:
|
||||
raise credentials_exception
|
||||
token_data = TokenData(username=username)
|
||||
except JWTError:
|
||||
raise credentials_exception
|
||||
user = await get_user(username=token_data.username)
|
||||
if user is None:
|
||||
raise credentials_exception
|
||||
return User(**user.dict())
|
||||
27
src/services/database.py
Normal file
27
src/services/database.py
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
import pymongo
|
||||
|
||||
# MongoDB
|
||||
client = pymongo.MongoClient("mongodb://learnhouse:learnhouse@mongo:27017/")
|
||||
learnhouseDB = client["learnhouse"]
|
||||
|
||||
|
||||
async def create_database():
|
||||
learnhouseDB = client["learnhouse"]
|
||||
|
||||
|
||||
async def check_database():
|
||||
# Check if database learnhouse exists
|
||||
|
||||
if "learnhouse" in client.list_database_names():
|
||||
return True
|
||||
else:
|
||||
create_database()
|
||||
|
||||
|
||||
async def create_config_collection():
|
||||
# Create config collection if it doesn't exist
|
||||
|
||||
learnhouseDB = client["learnhouse"]
|
||||
config = learnhouseDB["config"]
|
||||
config.insert_one({"name": "LearnHouse", "date": "2022"})
|
||||
return config.find_one()
|
||||
144
src/services/houses.py
Normal file
144
src/services/houses.py
Normal file
|
|
@ -0,0 +1,144 @@
|
|||
import json
|
||||
from typing import List
|
||||
from uuid import uuid4
|
||||
from pydantic import BaseModel
|
||||
from src.services.users import User
|
||||
from ..services.database import create_config_collection, check_database, create_database, learnhouseDB, learnhouseDB
|
||||
from ..services.security import *
|
||||
from fastapi import FastAPI, HTTPException, status, Request, Response, BackgroundTasks
|
||||
from datetime import datetime
|
||||
|
||||
#### Classes ####################################################
|
||||
|
||||
|
||||
class House(BaseModel):
|
||||
name: str
|
||||
photo: str
|
||||
description: str
|
||||
email: str
|
||||
org: str
|
||||
|
||||
|
||||
class HouseInDB(House):
|
||||
house_id: str
|
||||
owners: List[str]
|
||||
|
||||
#### Classes ####################################################
|
||||
|
||||
|
||||
async def get_house(house_id: str):
|
||||
await check_database()
|
||||
houses = learnhouseDB["houses"]
|
||||
|
||||
house = houses.find_one({"house_id": house_id})
|
||||
|
||||
if not house:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_409_CONFLICT, detail="House does not exist")
|
||||
|
||||
house = House(**house)
|
||||
return house
|
||||
|
||||
|
||||
async def create_house(house_object: House, current_user: User):
|
||||
await check_database()
|
||||
houses = learnhouseDB["houses"]
|
||||
|
||||
# find if house already exists using name
|
||||
isHouseAvailable = houses.find_one({"name": house_object.name})
|
||||
|
||||
if isHouseAvailable:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_409_CONFLICT, detail="House name already exists")
|
||||
|
||||
# generate house_id with uuid4
|
||||
house_id = str(f"house_{uuid4()}")
|
||||
|
||||
house = HouseInDB(house_id=house_id, owners=[
|
||||
current_user.username], **house_object.dict())
|
||||
|
||||
house_in_db = houses.insert_one(house.dict())
|
||||
|
||||
if not house_in_db:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_503_SERVICE_UNAVAILABLE, detail="Unavailable database")
|
||||
|
||||
return house.dict()
|
||||
|
||||
|
||||
async def update_house(house_object: House, house_id: str, current_user: User):
|
||||
await check_database()
|
||||
|
||||
# verify house rights
|
||||
await verify_house_ownership(house_id, current_user)
|
||||
|
||||
houses = learnhouseDB["houses"]
|
||||
|
||||
house = houses.find_one({"house_id": house_id})
|
||||
|
||||
## get owner value from house object database
|
||||
owners = house["owners"]
|
||||
|
||||
if not house:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_409_CONFLICT, detail="House does not exist")
|
||||
|
||||
updated_house = HouseInDB(house_id=house_id, owners=owners, **house_object.dict())
|
||||
|
||||
houses.update_one({"house_id": house_id}, {"$set": updated_house.dict()})
|
||||
|
||||
return HouseInDB(**updated_house.dict())
|
||||
|
||||
|
||||
async def delete_house(house_id: str, current_user: User):
|
||||
await check_database()
|
||||
|
||||
# verify house rights
|
||||
await verify_house_ownership(house_id, current_user)
|
||||
|
||||
houses = learnhouseDB["houses"]
|
||||
|
||||
house = houses.find_one({"house_id": house_id})
|
||||
|
||||
if not house:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_409_CONFLICT, detail="House does not exist")
|
||||
|
||||
isDeleted = houses.delete_one({"house_id": house_id})
|
||||
|
||||
if isDeleted:
|
||||
return {"detail": "House deleted"}
|
||||
else:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_503_SERVICE_UNAVAILABLE, detail="Unavailable database")
|
||||
|
||||
|
||||
async def get_houses(page: int = 1, limit: int = 10):
|
||||
await check_database()
|
||||
houses = learnhouseDB["houses"]
|
||||
|
||||
# get all houses from database
|
||||
all_houses = houses.find().sort("name", 1).skip(10 * (page - 1)).limit(limit)
|
||||
|
||||
return [json.loads(json.dumps(house, default=str)) for house in all_houses]
|
||||
|
||||
|
||||
#### Security ####################################################
|
||||
|
||||
async def verify_house_ownership(house_id: str, current_user: User):
|
||||
await check_database()
|
||||
houses = learnhouseDB["houses"]
|
||||
|
||||
house = houses.find_one({"house_id": house_id})
|
||||
|
||||
if not house:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_409_CONFLICT, detail="House does not exist")
|
||||
|
||||
if current_user.username not in house["owners"]:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_409_CONFLICT, detail="User does not own this house")
|
||||
|
||||
return True
|
||||
|
||||
#### Security ####################################################
|
||||
25
src/services/security.py
Normal file
25
src/services/security.py
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
from passlib.context import CryptContext
|
||||
from jose import JWTError, jwt
|
||||
from passlib.hash import pbkdf2_sha256
|
||||
|
||||
### 🔒 JWT ##############################################################
|
||||
|
||||
pwd_context = CryptContext(schemes=["bcrypt"], deprecated="auto")
|
||||
|
||||
ACCESS_TOKEN_EXPIRE_MINUTES = 30
|
||||
SECRET_KEY = "09d25e094faa6ca2556c818166b7a9563b93f7099f6f0f4caa6cf63b88e8d3e7"
|
||||
ALGORITHM = "HS256"
|
||||
|
||||
### 🔒 JWT ##############################################################
|
||||
|
||||
|
||||
### 🔒 Passwords Hashing ##############################################################
|
||||
|
||||
async def security_hash_password(password: str):
|
||||
return pbkdf2_sha256.hash(password)
|
||||
|
||||
|
||||
async def security_verify_password(plain_password: str, hashed_password: str):
|
||||
return pbkdf2_sha256.verify(plain_password, hashed_password)
|
||||
|
||||
### 🔒 Passwords Hashing ##############################################################
|
||||
106
src/services/users.py
Normal file
106
src/services/users.py
Normal file
|
|
@ -0,0 +1,106 @@
|
|||
from pydantic import BaseModel
|
||||
from ..services.database import create_config_collection, check_database, create_database, learnhouseDB, learnhouseDB
|
||||
from ..services.security import *
|
||||
from fastapi import FastAPI, HTTPException, status, Request, Response, BackgroundTasks
|
||||
from datetime import datetime
|
||||
|
||||
#### Classes ####################################################
|
||||
|
||||
|
||||
class User(BaseModel):
|
||||
username: str
|
||||
email: str
|
||||
full_name: str | None = None
|
||||
disabled: bool | None = None
|
||||
avatar_url: str | None = None
|
||||
verified: bool
|
||||
created_date: str
|
||||
bio : str | None = None
|
||||
|
||||
|
||||
class UserInDB(User):
|
||||
password: str
|
||||
|
||||
#### Classes ####################################################
|
||||
|
||||
|
||||
async def get_user(username: str):
|
||||
check_database()
|
||||
users = learnhouseDB["users"]
|
||||
|
||||
user = users.find_one({"username": username})
|
||||
|
||||
if not user:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_409_CONFLICT, detail="User does not exist")
|
||||
|
||||
user = User(**user)
|
||||
return user
|
||||
|
||||
|
||||
async def security_get_user(username: str):
|
||||
check_database()
|
||||
users = learnhouseDB["users"]
|
||||
|
||||
user = users.find_one({"username": username})
|
||||
|
||||
if not user:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_409_CONFLICT, detail="User does not exist")
|
||||
|
||||
return UserInDB(**user)
|
||||
|
||||
|
||||
async def update_user(user_object: UserInDB):
|
||||
check_database()
|
||||
users = learnhouseDB["users"]
|
||||
|
||||
isUserAvailable = users.find_one({"username": user_object.username})
|
||||
|
||||
if not isUserAvailable:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_409_CONFLICT, detail="User does not exist")
|
||||
|
||||
user_object.password = security_hash_password(user_object.password)
|
||||
|
||||
updated_user = {"$set": user_object.dict()}
|
||||
users.update_one({"username": user_object.username}, updated_user)
|
||||
|
||||
return User(**user_object.dict())
|
||||
|
||||
|
||||
async def delete_user(username: str):
|
||||
check_database()
|
||||
users = learnhouseDB["users"]
|
||||
|
||||
isUserAvailable = users.find_one({"username": username})
|
||||
|
||||
if not isUserAvailable:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_409_CONFLICT, detail="User does not exist")
|
||||
|
||||
users.delete_one({"username": username})
|
||||
|
||||
return {"detail": "User deleted"}
|
||||
|
||||
|
||||
async def create_user(user_object: UserInDB):
|
||||
check_database()
|
||||
users = learnhouseDB["users"]
|
||||
|
||||
isUserAvailable = users.find_one({"username": user_object.username})
|
||||
|
||||
if isUserAvailable:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_409_CONFLICT, detail="User already exists")
|
||||
|
||||
# lowercase username
|
||||
user_object.username = user_object.username.lower()
|
||||
|
||||
user_object.created_date = str(datetime.now())
|
||||
|
||||
user_object.password = await security_hash_password(user_object.password)
|
||||
|
||||
users.insert_one(user_object.dict())
|
||||
|
||||
return User(**user_object.dict())
|
||||
Loading…
Add table
Add a link
Reference in a new issue