create project
This commit is contained in:
63
README.md
63
README.md
@@ -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).
|
||||
|
||||
21
app/main.py
21
app/main.py
@@ -7,16 +7,31 @@ from fastapi import (
|
||||
)
|
||||
|
||||
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 binascii
|
||||
|
||||
from fastapi.middleware.cors import CORSMiddleware
|
||||
|
||||
#------------------ FastAPI variable ----------------------------------
|
||||
app = FastAPI()
|
||||
|
||||
|
||||
|
||||
origins = ["*"]
|
||||
|
||||
app.add_middleware(
|
||||
CORSMiddleware,
|
||||
allow_origins=origins,
|
||||
allow_credentials=True,
|
||||
allow_methods=["*"],
|
||||
allow_headers=["*"],
|
||||
)
|
||||
|
||||
|
||||
# ================ Authentication Middleware =======================
|
||||
#----------- Here authentication is based on basic scheme,
|
||||
#----------- another authentication, based on bearer scheme, is used throughout
|
||||
@@ -43,4 +58,6 @@ async def authenticate(request: Request, call_next):
|
||||
return response
|
||||
|
||||
# ================= Routers inclusion from src directory ===============
|
||||
app.include_router(router)
|
||||
app.include_router(post)
|
||||
app.include_router(router)
|
||||
app.include_router(history)
|
||||
@@ -23,3 +23,5 @@ six==1.16.0
|
||||
starlette==0.14.2
|
||||
typing-extensions==3.10.0.0
|
||||
uvicorn==0.14.0
|
||||
python-multipart==0.0.5
|
||||
aiofiles==0.8.0
|
||||
@@ -17,7 +17,7 @@ def verify_password(plain_password, hashed_password):
|
||||
|
||||
|
||||
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
|
||||
|
||||
|
||||
|
||||
91
app/src/models/history_find.py
Normal file
91
app/src/models/history_find.py
Normal 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"
|
||||
# }
|
||||
# }
|
||||
@@ -1,6 +1,6 @@
|
||||
from bson import ObjectId
|
||||
from pydantic import BaseModel, Field
|
||||
from typing import Optional
|
||||
from typing import Optional, Union
|
||||
|
||||
|
||||
class PyObjectId(ObjectId):
|
||||
@@ -21,8 +21,10 @@ class PyObjectId(ObjectId):
|
||||
|
||||
class UserModel(BaseModel):
|
||||
id: PyObjectId = Field(default_factory=PyObjectId, alias="_id")
|
||||
username: Union[str, None] = None
|
||||
first_name: str
|
||||
last_name: str
|
||||
avatar: str
|
||||
role : str
|
||||
is_active : str
|
||||
created_at: Optional[str] = None
|
||||
@@ -35,8 +37,10 @@ class UserModel(BaseModel):
|
||||
json_encoders = {ObjectId: str}
|
||||
schema_extra = {
|
||||
"example": {
|
||||
"username": "",
|
||||
"first_name": "John",
|
||||
"last_name": "Doe",
|
||||
"avatar":"",
|
||||
"role": "simple mortal",
|
||||
"is_active": "false",
|
||||
"created_at": "datetime",
|
||||
@@ -49,6 +53,7 @@ class UserModel(BaseModel):
|
||||
class UpdateUserModel(BaseModel):
|
||||
first_name: Optional[str]
|
||||
last_name: Optional[str]
|
||||
avatar: str
|
||||
role: Optional[str]
|
||||
is_active: Optional[str]
|
||||
created_at: Optional[str]
|
||||
@@ -61,6 +66,7 @@ class UpdateUserModel(BaseModel):
|
||||
"example": {
|
||||
"first_name": "John",
|
||||
"last_name": "Doe",
|
||||
"avatar":"",
|
||||
"role": "simple mortal",
|
||||
"is_active": "false",
|
||||
"created_at": "datetime",
|
||||
@@ -73,6 +79,7 @@ class ShowUserModel(BaseModel):
|
||||
id: PyObjectId = Field(default_factory=PyObjectId, alias="_id")
|
||||
first_name: Optional[str]
|
||||
last_name: Optional[str]
|
||||
avatar: str
|
||||
role: Optional[str]
|
||||
is_active: Optional[str]
|
||||
created_at: Optional[str]
|
||||
@@ -85,6 +92,7 @@ class ShowUserModel(BaseModel):
|
||||
"example": {
|
||||
"first_name": "John",
|
||||
"last_name": "Doe",
|
||||
"avatar":"",
|
||||
"role": "simple mortal",
|
||||
"created_at": "datetime",
|
||||
"last_login": "datetime",
|
||||
171
app/src/models/post.py
Normal file
171
app/src/models/post.py
Normal 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": "",
|
||||
}
|
||||
}
|
||||
57
app/src/routers/history_find.py
Normal file
57
app/src/routers/history_find.py
Normal 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
202
app/src/routers/post.py
Normal 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")
|
||||
@@ -7,35 +7,43 @@ from fastapi import (
|
||||
from fastapi.responses import JSONResponse
|
||||
from fastapi.encoders import jsonable_encoder
|
||||
from fastapi.security import OAuth2PasswordRequestForm
|
||||
|
||||
from .models import (
|
||||
from fastapi import File, UploadFile, FastAPI
|
||||
from ..models.models import (
|
||||
UserModel,
|
||||
ShowUserModel,
|
||||
UpdateUserModel
|
||||
)
|
||||
from .dependecies import (
|
||||
from ..dependecies import (
|
||||
get_current_user,
|
||||
authenticate_user,
|
||||
create_access_token,
|
||||
get_password_hash
|
||||
)
|
||||
from .settings import db, ACCESS_TOKEN_EXPIRE_MINUTES
|
||||
from ..settings import db, ACCESS_TOKEN_EXPIRE_MINUTES
|
||||
|
||||
from typing import List
|
||||
from datetime import datetime, timedelta
|
||||
|
||||
import re
|
||||
|
||||
from pydantic import BaseModel, Field
|
||||
class LoginRequest(BaseModel):
|
||||
username: str
|
||||
password: str
|
||||
router = APIRouter()
|
||||
|
||||
# ============= Creating path operations ==============
|
||||
@router.post("/", response_description="Add new user", response_model=UserModel)
|
||||
async def create_user(user: UserModel):
|
||||
@router.post("/create_user", response_description="Add new user", response_model=UserModel)
|
||||
async def create_user(user: UserModel, file: UploadFile = File(...)):
|
||||
if re.match("admin|dev|simple mortal", user.role):
|
||||
datetime_now = datetime.now()
|
||||
user.created_at = datetime_now.strftime("%m/%d/%y %H:%M:%S")
|
||||
user.password = get_password_hash(user.password)
|
||||
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)
|
||||
await db["users"].update_one({"_id": new_user.inserted_id}, {
|
||||
"$rename": {"password": "hashed_pass"}})
|
||||
@@ -47,9 +55,11 @@ async def create_user(user: UserModel):
|
||||
|
||||
|
||||
|
||||
@router.post("/token")
|
||||
async def login_for_access_token(form_data: OAuth2PasswordRequestForm = Depends()):
|
||||
user = await authenticate_user(form_data.username, form_data.password)
|
||||
@router.post("/login")
|
||||
async def login_for_access_token(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,
|
||||
@@ -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 = 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"),
|
||||
"is_active": "true"
|
||||
}})
|
||||
|
||||
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(
|
||||
"/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)
|
||||
for user in users:
|
||||
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")
|
||||
async def delete_user(user_id: str):
|
||||
@router.delete("/delete_user/{user_id}", response_description="Delete a user")
|
||||
async def delete_user(user_id: str, current_user: ShowUserModel = Depends(get_current_user)):
|
||||
delete_result = await db["users"].delete_one({"_id": user_id})
|
||||
|
||||
if delete_result.deleted_count == 1:
|
||||
return JSONResponse(status_code=status.HTTP_204_NO_CONTENT)
|
||||
|
||||
@@ -9,6 +9,8 @@ services:
|
||||
- DB_URL=mongodb://db/myTestDB
|
||||
volumes:
|
||||
- ./app:/app
|
||||
restart: always
|
||||
|
||||
db:
|
||||
image: mongo
|
||||
ports:
|
||||
|
||||
Reference in New Issue
Block a user