create project

This commit is contained in:
2022-07-26 13:46:19 +07:00
parent c6d9f2c32b
commit 9e3a18756c
11 changed files with 600 additions and 84 deletions

View File

@@ -1,63 +0,0 @@
# User authentication using FastAPI (a python frameworks), MongoDB (for database), Docker Compose (for deployment)
## How to start the application
**Watch the video:** (below the video are the commands on how to start the application)
* https://www.youtube.com/watch?v=Bw5rQXgvHYc
**The commands:**
First you have to git clone the files by entering in your terminal:
```
$ git clone https://github.com/AtamanKit/fastapi_users_docker.git
```
Then start the application:
```
$ docker-compose up -d
```
The above command will both create the images and start the containers (2 images and 2 containers - one for the FastAPI application and one for the MongoDB database).
For visualizing the application, open up your browser and enter:
* http://127.0.0.1/docs
In the application we have seven sections:
* For authentication (the right green "Authorize" button from the above);
* For creating users (3 roles are acceptable only: "admin", "dev", "simple mortal", you'll see an error if not respecting the rule);
* For creating tokens by entering user's credentials;
* For listing the users;
* For watching the current user (only if authenticated);
* For modifying user properties (only if authenticated with admin role);
* For deleting the user.
To see the runing containers in docker, enter in the terminal:
```
$ docker ps
```
To see the database and collection created (database name is: myTestDB, collection: users) enter in your terminal:
```
$ docker exec -it <container-id> bash
```
## Configuration and file structure
Our file structure is:
```
.
├── app
│   ├── Dockerfile
│   ├── __init__.py
│   ├── main.py
│   ├── requirements.txt
│   └── src
│   ├── __init__.py
│   ├── dependecies.py
│   ├── models.py
│   ├── routers.py
│   └── settings.py
└── docker-compose.yml
```
In the app directory in ```main.py``` file we make all the dependencies and routers importing from the same name files located in ```src``` directory.
```src``` directory is the one that containes all the needed pydantic models (models.py), database and authentication variables (settings.py).
Authentication is made by using ```bearer``` scheme with ```token``` creation and usage.
```dependecies.py``` is the file containing authentication fucntions (I also made an authentication middleware located in ```main.py``` file in the root directory using ```basic``` scheme, this function serves as an example purpose only).

View File

@@ -7,16 +7,31 @@ from fastapi import (
) )
from src.dependecies import authenticate_user from src.dependecies import authenticate_user
from src.routers import router from src.routers.routers import router
from src.routers.post import post
from src.routers.history_find import history
import base64 import base64
import binascii import binascii
from fastapi.middleware.cors import CORSMiddleware
#------------------ FastAPI variable ---------------------------------- #------------------ FastAPI variable ----------------------------------
app = FastAPI() app = FastAPI()
origins = ["*"]
app.add_middleware(
CORSMiddleware,
allow_origins=origins,
allow_credentials=True,
allow_methods=["*"],
allow_headers=["*"],
)
# ================ Authentication Middleware ======================= # ================ Authentication Middleware =======================
#----------- Here authentication is based on basic scheme, #----------- Here authentication is based on basic scheme,
#----------- another authentication, based on bearer scheme, is used throughout #----------- another authentication, based on bearer scheme, is used throughout
@@ -43,4 +58,6 @@ async def authenticate(request: Request, call_next):
return response return response
# ================= Routers inclusion from src directory =============== # ================= Routers inclusion from src directory ===============
app.include_router(post)
app.include_router(router) app.include_router(router)
app.include_router(history)

View File

@@ -23,3 +23,5 @@ six==1.16.0
starlette==0.14.2 starlette==0.14.2
typing-extensions==3.10.0.0 typing-extensions==3.10.0.0
uvicorn==0.14.0 uvicorn==0.14.0
python-multipart==0.0.5
aiofiles==0.8.0

View File

@@ -17,7 +17,7 @@ def verify_password(plain_password, hashed_password):
async def get_user(id: str): async def get_user(id: str):
if (user := await db["users"].find_one({"_id": id})) is not None: if (user := await db["users"].find_one({"username": id})) is not None:
return user return user

View File

@@ -0,0 +1,91 @@
import json
from bson import ObjectId
from pydantic import BaseModel, Field
from typing import List, Optional, Union
class PyObjectId(ObjectId):
@classmethod
def __get_validators__(cls):
yield cls.validate
@classmethod
def validate(cls, v):
if not ObjectId.is_valid(v):
raise ValueError("Invalid objectid")
return ObjectId(v)
@classmethod
def __modify_schema__(cls, field_schema):
field_schema.update(type="string")
class HistoryFindModel(BaseModel):
id: PyObjectId = Field(default_factory=PyObjectId, alias="_id")
full_name: str
username: Union[str, None] = None
age: int
sick : List[str]
created_at: Optional[str] = None
post_id : str
key_find : str
class Config:
orm_mode = True
case_sensitive = True
allow_population_by_field_name = True
arbitrary_types_allowed = True
json_encoders = {ObjectId: str}
schema_extra = {
"example": {
"full_name": "John",
"username":"",
"age": 20,
"sick": ["simple mortal"],
"post_id" : "",
"key_find": ""
}
}
# class UpdateHistoryFindModel(BaseModel):
# full_name: str
# age: int
# sick : List[str]
# created_at: Optional[str] = None
# post_id : str
# key_find : str
# class Config:
# arbitrary_types_allowed = True
# json_encoders = {ObjectId: str}
# schema_extra = {
# "example": {
# "full_name": "John",
# "age": 20,
# "sick": "simple mortal",
# "key_find": "datetime"
# }
# }
# class ShowPostModel(BaseModel):
# id: PyObjectId = Field(default_factory=PyObjectId, alias="_id")
# full_name: str
# age: int
# sick : List[str]
# created_at: Optional[str] = None
# post_id : str
# key_find : str
# class Config:
# arbitrary_types_allowed = True
# json_encoders = {ObjectId: str}
# schema_extra = {
# "example": {
# "full_name": "John",
# "age": 20,
# "sick": "simple mortal",
# "key_find": "datetime"
# }
# }

View File

@@ -1,6 +1,6 @@
from bson import ObjectId from bson import ObjectId
from pydantic import BaseModel, Field from pydantic import BaseModel, Field
from typing import Optional from typing import Optional, Union
class PyObjectId(ObjectId): class PyObjectId(ObjectId):
@@ -21,8 +21,10 @@ class PyObjectId(ObjectId):
class UserModel(BaseModel): class UserModel(BaseModel):
id: PyObjectId = Field(default_factory=PyObjectId, alias="_id") id: PyObjectId = Field(default_factory=PyObjectId, alias="_id")
username: Union[str, None] = None
first_name: str first_name: str
last_name: str last_name: str
avatar: str
role : str role : str
is_active : str is_active : str
created_at: Optional[str] = None created_at: Optional[str] = None
@@ -35,8 +37,10 @@ class UserModel(BaseModel):
json_encoders = {ObjectId: str} json_encoders = {ObjectId: str}
schema_extra = { schema_extra = {
"example": { "example": {
"username": "",
"first_name": "John", "first_name": "John",
"last_name": "Doe", "last_name": "Doe",
"avatar":"",
"role": "simple mortal", "role": "simple mortal",
"is_active": "false", "is_active": "false",
"created_at": "datetime", "created_at": "datetime",
@@ -49,6 +53,7 @@ class UserModel(BaseModel):
class UpdateUserModel(BaseModel): class UpdateUserModel(BaseModel):
first_name: Optional[str] first_name: Optional[str]
last_name: Optional[str] last_name: Optional[str]
avatar: str
role: Optional[str] role: Optional[str]
is_active: Optional[str] is_active: Optional[str]
created_at: Optional[str] created_at: Optional[str]
@@ -61,6 +66,7 @@ class UpdateUserModel(BaseModel):
"example": { "example": {
"first_name": "John", "first_name": "John",
"last_name": "Doe", "last_name": "Doe",
"avatar":"",
"role": "simple mortal", "role": "simple mortal",
"is_active": "false", "is_active": "false",
"created_at": "datetime", "created_at": "datetime",
@@ -73,6 +79,7 @@ class ShowUserModel(BaseModel):
id: PyObjectId = Field(default_factory=PyObjectId, alias="_id") id: PyObjectId = Field(default_factory=PyObjectId, alias="_id")
first_name: Optional[str] first_name: Optional[str]
last_name: Optional[str] last_name: Optional[str]
avatar: str
role: Optional[str] role: Optional[str]
is_active: Optional[str] is_active: Optional[str]
created_at: Optional[str] created_at: Optional[str]
@@ -85,6 +92,7 @@ class ShowUserModel(BaseModel):
"example": { "example": {
"first_name": "John", "first_name": "John",
"last_name": "Doe", "last_name": "Doe",
"avatar":"",
"role": "simple mortal", "role": "simple mortal",
"created_at": "datetime", "created_at": "datetime",
"last_login": "datetime", "last_login": "datetime",

171
app/src/models/post.py Normal file
View File

@@ -0,0 +1,171 @@
import json
from bson import ObjectId
from pydantic import BaseModel, Field
from typing import List, Optional, Union
class PyObjectId(ObjectId):
@classmethod
def __get_validators__(cls):
yield cls.validate
@classmethod
def validate(cls, v):
if not ObjectId.is_valid(v):
raise ValueError("Invalid objectid")
return ObjectId(v)
@classmethod
def __modify_schema__(cls, field_schema):
field_schema.update(type="string")
class DataPost(BaseModel):
name: str
level: str
content: List[str]
class DataSmallPost(BaseModel):
name: str
level: int
point: int
class Point(BaseModel):
less10 : Optional[int] = 0
form10to20: Optional[int] = 0
form20to30: Optional[int] = 0
form30to40: Optional[int] = 0
form40to50: Optional[int] = 0
form50to60: Optional[int] = 0
bigger60: Optional[int] = 0
total: Optional[int] = 0
class PostModel(BaseModel):
id: PyObjectId = Field(default_factory=PyObjectId, alias="_id")
original_post: Union[str, None] = None
translation_post: Union[str, None] = None
link : Union[str, None] = None
is_active : str
created_at: Optional[str] = None
specialist: str
summary: str
data : List[DataPost]
point : Point
class Config:
orm_mode = True
case_sensitive = True
allow_population_by_field_name = True
arbitrary_types_allowed = True
json_encoders = {ObjectId: str}
schema_extra = {
"example": {
"original_post": "Joh111",
"translation_post": "Doe11111",
"link": "simple mortal111",
"is_active": "false",
"created_at": "07/20/22 02: 26: 54",
"specialist": "",
"summary": "",
"data": [
{
"name": "abc1",
"level": "user",
"content": [
"Hoàng Anh Hoàng Anh Hoàng Anh Hoàng AnhHoàng Anh Hoàng Anh Hoàng Anh Hoàng Anh Hoàng Anh",
"Hoàng Anh Hoàng Anh Hoàng Anh Hoàng AnhHoàng Anh Hoàng Anh Hoàng Anh Hoàng Anh Hoàng Anh",
"Hoàng Anh Hoàng Anh Hoàng Anh Hoàng AnhHoàng Anh Hoàng Anh Hoàng Anh Hoàng Anh Hoàng Anh",
"Hoàng Anh Hoàng Anh Hoàng Anh Hoàng AnhHoàng Anh Hoàng Anh Hoàng Anh Hoàng Anh Hoàng Anh"
]
},
{
"name": "abc2",
"level": "user",
"content": [
"Hoàng Anh Hoàng Anh Hoàng Anh Hoàng AnhHoàng Anh Hoàng Anh Hoàng Anh Hoàng Anh Hoàng Anh",
"Hoàng Anh Hoàng Anh Hoàng Anh Hoàng AnhHoàng Anh Hoàng Anh Hoàng Anh Hoàng Anh Hoàng Anh",
"Hoàng Anh Hoàng Anh Hoàng Anh Hoàng AnhHoàng Anh Hoàng Anh Hoàng Anh Hoàng Anh Hoàng Anh",
"Hoàng Anh Hoàng Anh Hoàng Anh Hoàng AnhHoàng Anh Hoàng Anh Hoàng Anh Hoàng Anh Hoàng Anh"
]
},
{
"name": "abc",
"level": "user",
"content": [
"Hoàng Anh Hoàng Anh Hoàng Anh Hoàng AnhHoàng Anh Hoàng Anh Hoàng Anh Hoàng Anh Hoàng Anh",
"Hoàng Anh Hoàng Anh Hoàng Anh Hoàng AnhHoàng Anh Hoàng Anh Hoàng Anh Hoàng Anh Hoàng Anh",
"Hoàng Anh Hoàng Anh Hoàng Anh Hoàng AnhHoàng Anh Hoàng Anh Hoàng Anh Hoàng Anh Hoàng Anh",
"Hoàng Anh Hoàng Anh Hoàng Anh Hoàng AnhHoàng Anh Hoàng Anh Hoàng Anh Hoàng Anh Hoàng Anh"
]
},
{
"name": "abc3",
"level": "user",
"content": [
"Hoàng Anh Hoàng Anh Hoàng Anh Hoàng AnhHoàng Anh Hoàng Anh Hoàng Anh Hoàng Anh Hoàng Anh",
"Hoàng Anh Hoàng Anh Hoàng Anh Hoàng AnhHoàng Anh Hoàng Anh Hoàng Anh Hoàng Anh Hoàng Anh",
"Hoàng Anh Hoàng Anh Hoàng Anh Hoàng AnhHoàng Anh Hoàng Anh Hoàng Anh Hoàng Anh Hoàng Anh",
"Hoàng Anh Hoàng Anh Hoàng Anh Hoàng AnhHoàng Anh Hoàng Anh Hoàng Anh Hoàng Anh Hoàng Anh"
]
}
],
"point": {
"less10": 0,
"form10to20": 0,
"form20to30": 0,
"form30to40": 0,
"form40to50": 0,
"form50to60": 0,
"bigger60": 0,
"total": 0
}
}
}
class UpdatePostModel(BaseModel):
original_post: Union[str, None] = None
translation_post: Union[str, None] = None
link : Union[str, None] = None
is_active : str
created_at: Optional[str] = None
specialist: str
summary: str
data : List[DataPost]
point : Point
class Config:
arbitrary_types_allowed = True
json_encoders = {ObjectId: str}
schema_extra = {
"example": {
"original_post": "John",
"translation_post": "Doe",
"link": "simple mortal",
"is_active": "false",
"created_at": "datetime",
"specialist": "",
"summary": "",
"data": ""
}
}
class ShowPostModel(BaseModel):
id: PyObjectId = Field(default_factory=PyObjectId, alias="_id")
original_post: Optional[str]
translation_post: Optional[str]
link: Optional[str]
is_active: Optional[str]
specialist: Optional[str]
summary: Optional[str]
data : List[DataSmallPost]
point : Point
class Config:
arbitrary_types_allowed = True
json_encoders = {ObjectId: str}
schema_extra = {
"example": {
"original_post": "John",
"translation_post": "Doe",
"link": "simple mortal",
"is_active": "false",
"created_at": "datetime",
"specialist": "",
"summary": "",
}
}

View File

@@ -0,0 +1,57 @@
from fastapi import (
APIRouter,
Depends,
status,
HTTPException
)
from fastapi.responses import JSONResponse
from fastapi.encoders import jsonable_encoder
from fastapi.security import OAuth2PasswordRequestForm
from src.settings import db, ACCESS_TOKEN_EXPIRE_MINUTES
from ..models.history_find import *
from typing import List
from datetime import datetime, timedelta
from ..models.models import (
UserModel,
ShowUserModel,
UpdateUserModel
)
from ..dependecies import (
get_current_user,
authenticate_user,
create_access_token,
get_password_hash
)
import re
history = APIRouter()
##############################POST###############################################
@history.post("/create_history", response_description="Add new user", response_model=HistoryFindModel)
async def create_history(history: HistoryFindModel, current_user: ShowUserModel = Depends(get_current_user)):
datetime_now = datetime.now()
post.created_at = datetime_now.strftime("%m/%d/%y %H:%M:%S")
post = jsonable_encoder(post)
new_post = await db["history_find"].insert_one(post)
created = await db["history_find"].find_one({"_id": new_post.inserted_id})
return JSONResponse(status_code=status.HTTP_201_CREATED, content=created)
@history.get(
"/list_history", response_description="List all posts", response_model=List[HistoryFindModel]
)
async def list_post(current_user: ShowUserModel = Depends(get_current_user)):
history_find = await db["history_find"].find().to_list(1000)
return history_find
# @post.get(
# "/get_post_by_name", response_description="Get a single posot", response_model=PostModel
# )
# async def show_post(id: str):
# print(id)
# post = await db["posts"].find_one({"_id": id})
# print(post)
# if post is not None:
# return post
# else:
# return None

202
app/src/routers/post.py Normal file
View File

@@ -0,0 +1,202 @@
from email.policy import default
from fastapi import APIRouter,Depends,status,HTTPException,UploadFile, File, Header
from fastapi.responses import JSONResponse, FileResponse, StreamingResponse
from fastapi.encoders import jsonable_encoder
from fastapi.security import OAuth2PasswordRequestForm
import logging
from ..dependecies import (
get_current_user,
authenticate_user,
create_access_token,
get_password_hash
)
from src.settings import db, ACCESS_TOKEN_EXPIRE_MINUTES
from ..models.post import (
PostModel,
UpdatePostModel,
ShowPostModel
)
from ..models.models import (
UserModel,
ShowUserModel,
UpdateUserModel
)
from ..dependecies import (
get_current_user,
authenticate_user,
create_access_token,
get_password_hash
)
from ..models.history_find import *
from typing import List
from datetime import datetime
import os
import re
post = APIRouter()
##############################POST###############################################
@post.post("/create_post", response_description="Add new user", response_model=PostModel)
async def create_post(post: PostModel, current_user: UserModel = Depends(get_current_user)):
try:
datetime_now = datetime.now()
post.created_at = datetime_now.strftime("%m/%d/%y %H:%M:%S")
post = jsonable_encoder(post)
new_post = await db["posts"].insert_one(post)
created_post = await db["posts"].find_one({"_id": new_post.inserted_id})
return JSONResponse(status_code=status.HTTP_201_CREATED, content=created_post)
except NameError:
return NameError
@post.get(
"/list_post", response_description="List all posts", response_model=List[ShowPostModel]
)
async def list_post(current_user: UserModel = Depends(get_current_user)):
posts = await db["posts"].find().to_list(1000)
print(posts)
print(len(posts))
return posts
@post.post(
"/find_list_post", response_description="search list posts", response_model=List[ShowPostModel]
)
async def list_post(history: HistoryFindModel, current_user: UserModel = Depends(get_current_user)):
point_data=["point.less10",
"point.form10to20",
"point.form20to30",
"point.form30to40",
"point.form40to50",
"point.form50to60",
]
age_sort = "point.total"
history = jsonable_encoder(history)
if history.get("age", None) != None:
if history.get("age") >59:
age_sort = "point.bigger60"
else:
age_sort = point_data[history.get("age")//10]
posts = await db["posts"].find({"translation_post": { "$regex": history.get("key_find") } }).sort(age_sort, -1).to_list(100)
print(posts)
return posts
@post.post(
"/get_post_by_name", response_description="Get a single post", response_model=PostModel
)
async def get_post_by_name(history: HistoryFindModel, current_user: UserModel = Depends(get_current_user)
):
datetime_now = datetime.now()
history.created_at = datetime_now.strftime("%m/%d/%y %H:%M:%S")
post = await db["posts"].find_one({"_id": history.post_id})
history = jsonable_encoder(history)
new_his = await db["history_find"].insert_one(history)
created = await db["history_find"].find_one({"_id": new_his.inserted_id})
print(created)
if post is not None:
return post
else:
return None
@post.delete("/delete_post/{id}", response_description="Delete a post")
async def delete_user(id: str, current_user: UserModel = Depends(get_current_user)):
delete_result = await db["posts"].delete_one({"_id": id})
if delete_result.deleted_count == 1:
return JSONResponse(status_code=status.HTTP_204_NO_CONTENT)
raise HTTPException(status_code=404, detail=f"Post {id} not found")
@post.get("/score", response_description="score all post", response_model=List[ShowPostModel])
async def score_all_post( current_user: UserModel = Depends(get_current_user)):
posts = await db["posts"].find().to_list(1000)
for dt_post in posts:
print(dt_post)
data_old = dt_post
dt_post["point"]["less10"] = await db["history_find"].count_documents({"post_id": dt_post["_id"],
"age":{
'$gte': 0, '$lte': 9
}})
dt_post["point"]["form10to20"] = await db["history_find"].count_documents({"post_id": dt_post["_id"],
"age":{
'$gte': 10, '$lte': 19
}})
dt_post["point"]["form20to30"] = await db["history_find"].count_documents({"post_id": dt_post["_id"],
"age":{
'$gte': 20, '$lte': 29
}})
dt_post["point"]["form30to40"] = await db["history_find"].count_documents({"post_id": dt_post["_id"],
"age":{
'$gte': 30, '$lte': 39
}})
dt_post["point"]["form40to50"] = await db["history_find"].count_documents({"post_id": dt_post["_id"],
"age":{
'$gte': 40, '$lte': 49
}})
dt_post["point"]["form50to60"] = await db["history_find"].count_documents({"post_id": dt_post["_id"],
"age":{
'$gte': 50, '$lte': 59
}})
dt_post["point"]["bigger60"] = await db["history_find"].count_documents({"post_id": dt_post["_id"],
"age":{
'$gte': 60
}})
dt_post["point"]["total"] = await db["history_find"].count_documents({"post_id": dt_post["_id"]})
# await db["posts"].update_one(data_old, dt_post)
await db["posts"].update_one({"_id": dt_post["_id"]}, {"$set": {
"point":{
"less10": dt_post["point"]["less10"],
"form10to20": dt_post["point"]["form10to20"],
"form20to30": dt_post["point"]["form20to30"],
"form30to40": dt_post["point"]["form30to40"],
"form40to50": dt_post["point"]["form40to50"],
"form50to60": dt_post["point"]["form50to60"],
"bigger60": dt_post["point"]["bigger60"],
"total": dt_post["point"]["total"]
}
}})
return posts
@post.post("/uploadfiles/")
async def create_upload_files(
files: List[UploadFile] = File(...), current_user: UserModel = Depends(get_current_user)
):
try:
file_name =[]
i = 0
file_location = f"../media/"
for file in files:
now = datetime.now()
current_time = now.strftime("%H:%M:%S_%d-%m-%Y_")
file_save = file_location + current_time + str(i) + file.filename
file_name.append(current_time + str(i) + file.filename)
i = i + 1
with open(file_save, "wb+") as file_object:
file_object.write(file.file.read())
return {"filenames": file_name}
except Exception as e:
return JSONResponse(
status_code = status.HTTP_400_BAD_REQUEST,
content = { 'message' : str(e) }
)
@post.get("/showfile/{name}")
async def show_file(name: str, current_user: UserModel = Depends(get_current_user)):
file_path = f"../media/" + name
if os.path.exists(file_path):
return FileResponse(file_path)
return {"erro": "File not found!"}
@post.get("/showvideo/{file_name}", response_class=FileResponse)
async def main(file_name: str, current_user: UserModel = Depends(get_current_user)):
file_path = f"../media/" + file_name
return file_path
@post.get("/video")
async def video_endpoint(video_name, current_user: UserModel = Depends(get_current_user)):
def iterfile():
video_path = f"../media/" + video_name
with open(video_path, mode="rb") as file_like:
yield from file_like
return StreamingResponse(iterfile(), media_type="video/mp4")

View File

@@ -7,35 +7,43 @@ from fastapi import (
from fastapi.responses import JSONResponse from fastapi.responses import JSONResponse
from fastapi.encoders import jsonable_encoder from fastapi.encoders import jsonable_encoder
from fastapi.security import OAuth2PasswordRequestForm from fastapi.security import OAuth2PasswordRequestForm
from fastapi import File, UploadFile, FastAPI
from .models import ( from ..models.models import (
UserModel, UserModel,
ShowUserModel, ShowUserModel,
UpdateUserModel UpdateUserModel
) )
from .dependecies import ( from ..dependecies import (
get_current_user, get_current_user,
authenticate_user, authenticate_user,
create_access_token, create_access_token,
get_password_hash get_password_hash
) )
from .settings import db, ACCESS_TOKEN_EXPIRE_MINUTES from ..settings import db, ACCESS_TOKEN_EXPIRE_MINUTES
from typing import List from typing import List
from datetime import datetime, timedelta from datetime import datetime, timedelta
import re import re
from pydantic import BaseModel, Field
class LoginRequest(BaseModel):
username: str
password: str
router = APIRouter() router = APIRouter()
# ============= Creating path operations ============== # ============= Creating path operations ==============
@router.post("/", response_description="Add new user", response_model=UserModel) @router.post("/create_user", response_description="Add new user", response_model=UserModel)
async def create_user(user: UserModel): async def create_user(user: UserModel, file: UploadFile = File(...)):
if re.match("admin|dev|simple mortal", user.role): if re.match("admin|dev|simple mortal", user.role):
datetime_now = datetime.now() datetime_now = datetime.now()
user.created_at = datetime_now.strftime("%m/%d/%y %H:%M:%S") user.created_at = datetime_now.strftime("%m/%d/%y %H:%M:%S")
user.password = get_password_hash(user.password) user.password = get_password_hash(user.password)
user = jsonable_encoder(user) user = jsonable_encoder(user)
file_location = f"../media/"
current_time = datetime_now.strftime("%H:%M:%S_%d-%m-%Y_")
file_save = file_location + current_time + file.filename
user.avatar = current_time + file.filename
with open(file_save, "wb+") as file_object:
file_object.write(file.file.read())
new_user = await db["users"].insert_one(user) new_user = await db["users"].insert_one(user)
await db["users"].update_one({"_id": new_user.inserted_id}, { await db["users"].update_one({"_id": new_user.inserted_id}, {
"$rename": {"password": "hashed_pass"}}) "$rename": {"password": "hashed_pass"}})
@@ -47,9 +55,11 @@ async def create_user(user: UserModel):
@router.post("/token") @router.post("/login")
async def login_for_access_token(form_data: OAuth2PasswordRequestForm = Depends()): async def login_for_access_token(body: LoginRequest):
user = await authenticate_user(form_data.username, form_data.password) print(body)
user = await authenticate_user(body.username, body.password)
print(body)
if not user: if not user:
raise HTTPException( raise HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED, status_code=status.HTTP_401_UNAUTHORIZED,
@@ -58,21 +68,41 @@ async def login_for_access_token(form_data: OAuth2PasswordRequestForm = Depends(
) )
access_token_expires = timedelta(minutes=ACCESS_TOKEN_EXPIRE_MINUTES) access_token_expires = timedelta(minutes=ACCESS_TOKEN_EXPIRE_MINUTES)
access_token = create_access_token( access_token = create_access_token(
data={"sub": user["_id"]}, expires_delta=access_token_expires data={"sub": user["username"]}, expires_delta=access_token_expires
) )
await db["users"].update_one({"_id": form_data.username}, {"$set": { await db["users"].update_one({"username": body.username}, {"$set": {
"last_login": datetime.now().strftime("%m/%d/%y %H:%M:%S"), "last_login": datetime.now().strftime("%m/%d/%y %H:%M:%S"),
"is_active": "true" "is_active": "true"
}}) }})
return {"access_token": access_token, "token_type": "bearer"} return {"access_token": access_token, "token_type": "bearer"}
@router.post("/token")
async def login_for_access_token_2(body: LoginRequest):
print(body)
user = await authenticate_user(body.username, body.password)
print(body)
if not user:
raise HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED,
detail="Incorect ID 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
)
await db["users"].update_one({"username": body.username}, {"$set": {
"last_login": datetime.now().strftime("%m/%d/%y %H:%M:%S"),
"is_active": "true"
}})
return {"access_token": access_token, "token_type": "bearer"}
@router.get( @router.get(
"/list", response_description="List all users", response_model=List[ShowUserModel] "/list", response_description="List all users", response_model=List[ShowUserModel]
) )
async def list_users(): async def list_users(current_user: ShowUserModel = Depends(get_current_user)):
users = await db["users"].find().to_list(1000) users = await db["users"].find().to_list(1000)
for user in users: for user in users:
user["is_active"] = "false" user["is_active"] = "false"
@@ -119,10 +149,9 @@ async def update_user(user_id: str, user: UpdateUserModel, current_user: UserMod
@router.delete("/{user_id}", response_description="Delete a user") @router.delete("/delete_user/{user_id}", response_description="Delete a user")
async def delete_user(user_id: str): async def delete_user(user_id: str, current_user: ShowUserModel = Depends(get_current_user)):
delete_result = await db["users"].delete_one({"_id": user_id}) delete_result = await db["users"].delete_one({"_id": user_id})
if delete_result.deleted_count == 1: if delete_result.deleted_count == 1:
return JSONResponse(status_code=status.HTTP_204_NO_CONTENT) return JSONResponse(status_code=status.HTTP_204_NO_CONTENT)

View File

@@ -9,6 +9,8 @@ services:
- DB_URL=mongodb://db/myTestDB - DB_URL=mongodb://db/myTestDB
volumes: volumes:
- ./app:/app - ./app:/app
restart: always
db: db:
image: mongo image: mongo
ports: ports: