refactoring - 1
This commit is contained in:
parent
fb3763b910
commit
6742c963ab
@ -1,7 +1,7 @@
|
|||||||
from sqlalchemy.orm import Session
|
from sqlalchemy.orm import Session
|
||||||
from typing import Annotated
|
from typing import Annotated
|
||||||
from fastapi import Depends
|
from fastapi import Depends
|
||||||
from . import models, schemas, utils
|
from . import auth_utils, orm_models, pydantic_schemas
|
||||||
import random
|
import random
|
||||||
import datetime
|
import datetime
|
||||||
|
|
||||||
@ -35,7 +35,7 @@ def add_poems_to_db(db: Session):
|
|||||||
flag = True
|
flag = True
|
||||||
else:
|
else:
|
||||||
author += str1
|
author += str1
|
||||||
poem = models.Poems(title=name, text=stixi, author=author)
|
poem = orm_models.Poems(title=name, text=stixi, author=author)
|
||||||
# В конце каждой итерации добавляем в базу данных
|
# В конце каждой итерации добавляем в базу данных
|
||||||
db.add(poem)
|
db.add(poem)
|
||||||
db.commit()
|
db.commit()
|
||||||
@ -44,23 +44,30 @@ def add_poems_to_db(db: Session):
|
|||||||
f1.close()
|
f1.close()
|
||||||
|
|
||||||
|
|
||||||
def filter_ann(schema: schemas.SortAnnouncements, db: Annotated[Session, Depends(utils.get_db)]):
|
def filter_ann(schema: pydantic_schemas.SortAnnouncements, db: Annotated[Session, Depends(auth_utils.get_db)]):
|
||||||
"""Функция для последовательного применения различных фильтров (через схему SortAnnouncements)"""
|
"""Функция для последовательного применения различных фильтров (через схему SortAnnouncements)"""
|
||||||
res = db.query(models.Announcement)
|
res = db.query(orm_models.Announcement)
|
||||||
fields = schema.__dict__ # параметры передоваемой схемы SortAnnouncements (ключи и значения)
|
fields = schema.__dict__ # параметры передоваемой схемы SortAnnouncements (ключи и значения)
|
||||||
|
# проходим по названиям фильтров и их значениям
|
||||||
for name, filt in fields.items():
|
for name, filt in fields.items():
|
||||||
|
# если фильтр задан
|
||||||
if filt is not None:
|
if filt is not None:
|
||||||
d = {name: filt}
|
d = {name: filt}
|
||||||
|
# фильтруем
|
||||||
res = res.filter_by(**d)
|
res = res.filter_by(**d)
|
||||||
|
# возвращаем все подходящие объявления
|
||||||
return res.all()
|
return res.all()
|
||||||
|
|
||||||
|
|
||||||
def check_obsolete(db: Annotated[Session, Depends(utils.get_db)], current_date: datetime.date):
|
def check_obsolete(db: Annotated[Session, Depends(auth_utils.get_db)], current_date: datetime.date):
|
||||||
"""
|
"""
|
||||||
Обновляем поле obsolete у всех объявлений раз в сутки
|
Функция участвует в процессе обновления поля obsolete у всех объявлений раз в сутки
|
||||||
"""
|
"""
|
||||||
announcements = db.query(models.Announcement).all()
|
# обращаемся ко всем объявлениям бд
|
||||||
|
announcements = db.query(orm_models.Announcement).all()
|
||||||
|
# для каждого объявления
|
||||||
for ann in announcements:
|
for ann in announcements:
|
||||||
|
# если просрочено
|
||||||
if ann.best_by < current_date:
|
if ann.best_by < current_date:
|
||||||
ann.obsolete = True
|
ann.obsolete = True
|
||||||
db.commit()
|
db.commit()
|
131
back/api.py
131
back/api.py
@ -1,12 +1,12 @@
|
|||||||
#подключение библиотек
|
#подключение библиотек
|
||||||
from fastapi import FastAPI, Response, Path, Depends, Body, Form, Query, status, HTTPException, APIRouter, UploadFile, File
|
from fastapi import FastAPI, Depends, Form, status, HTTPException, APIRouter, UploadFile
|
||||||
from fastapi.responses import HTMLResponse, FileResponse, JSONResponse, RedirectResponse
|
from fastapi.responses import HTMLResponse, FileResponse, JSONResponse, RedirectResponse
|
||||||
from fastapi.staticfiles import StaticFiles
|
from fastapi.staticfiles import StaticFiles
|
||||||
from fastapi.security import OAuth2PasswordRequestForm, OAuth2PasswordBearer
|
from fastapi.security import OAuth2PasswordRequestForm
|
||||||
from fastapi.templating import Jinja2Templates
|
from fastapi.templating import Jinja2Templates
|
||||||
from fastapi.requests import Request
|
from fastapi.requests import Request
|
||||||
|
|
||||||
from pydantic import json
|
|
||||||
from typing import Any, Annotated, List, Union
|
from typing import Any, Annotated, List, Union
|
||||||
from starlette.staticfiles import StaticFiles
|
from starlette.staticfiles import StaticFiles
|
||||||
from sqlalchemy.orm import Session
|
from sqlalchemy.orm import Session
|
||||||
@ -22,56 +22,60 @@ import pathlib
|
|||||||
import shutil
|
import shutil
|
||||||
import os
|
import os
|
||||||
|
|
||||||
from . import schemas, models, utils, service
|
from .db import database
|
||||||
|
from . import add_poems_and_filters, auth_utils, orm_models, pydantic_schemas
|
||||||
|
|
||||||
|
# создаем приложение Fastapi
|
||||||
app = FastAPI()
|
app = FastAPI()
|
||||||
|
|
||||||
|
# Jinja2 - шаблоны
|
||||||
templates = Jinja2Templates(directory="./front/dist")
|
templates = Jinja2Templates(directory="./front/dist")
|
||||||
|
|
||||||
|
# создаем эндпоинт для хранения статических файлов
|
||||||
app.mount("/static", StaticFiles(directory = "./front/dist"))
|
app.mount("/static", StaticFiles(directory = "./front/dist"))
|
||||||
|
# проверяем, что папка uploads еще не создана
|
||||||
if not os.path.exists("./uploads"):
|
if not os.path.exists("./uploads"):
|
||||||
os.mkdir("./uploads")
|
os.mkdir("./uploads")
|
||||||
|
# создаем эндпоинт для хранения файлов пользователя
|
||||||
app.mount("/uploads", StaticFiles(directory = "./uploads"))
|
app.mount("/uploads", StaticFiles(directory = "./uploads"))
|
||||||
|
|
||||||
# Записываем стихи в базу данных, если их еще нет (запускать только если стихов в базе нет).
|
|
||||||
from .db import database
|
|
||||||
|
|
||||||
|
# получение списка объявлений
|
||||||
@app.get("/api/announcements", response_model=List[schemas.Announcement])#адрес объявлений
|
@app.get("/api/announcements", response_model=List[pydantic_schemas.Announcement])#адрес объявлений
|
||||||
def announcements_list(db: Annotated[Session, Depends(utils.get_db)], obsolete: Union[bool, None] = False, user_id: Union[int, None] = None,
|
def announcements_list(db: Annotated[Session, Depends(auth_utils.get_db)], obsolete: Union[bool, None] = False, user_id: Union[int, None] = None,
|
||||||
metro: Union[str, None] = None,category: Union[str, None] = None):
|
metro: Union[str, None] = None,category: Union[str, None] = None):
|
||||||
# параметры для сортировки (схема pydantic schemas.SortAnnouncements)
|
# параметры для сортировки (схема pydantic schemas.SortAnnouncements)
|
||||||
params_to_sort = schemas.SortAnnouncements(obsolete=obsolete, user_id=user_id, metro=metro, category=category)
|
params_to_sort = pydantic_schemas.SortAnnouncements(obsolete=obsolete, user_id=user_id, metro=metro, category=category)
|
||||||
# получаем результат
|
# получаем результат
|
||||||
result = service.filter_ann(db=db, schema=params_to_sort)
|
result = add_poems_and_filters.filter_ann(db=db, schema=params_to_sort)
|
||||||
|
|
||||||
return result
|
return result
|
||||||
|
|
||||||
|
|
||||||
@app.get("/api/announcement") #
|
# получаем данные одного объявления
|
||||||
def single_announcement(ann_id:int, db: Annotated[Session, Depends(utils.get_db)]): # передаем индекс обявления
|
@app.get("/api/announcement", response_model=pydantic_schemas.AnnResponce)
|
||||||
|
def single_announcement(ann_id:int, db: Annotated[Session, Depends(auth_utils.get_db)]): # передаем индекс обявления
|
||||||
# Считываем данные из Body и отображаем их на странице.
|
# Считываем данные из Body и отображаем их на странице.
|
||||||
# В последствии будем вставлять данные в html-форму
|
# В последствии будем вставлять данные в html-форму
|
||||||
try:
|
try:
|
||||||
announcement = db.get(models.Announcement, ann_id)
|
announcement = db.get(orm_models.Announcement, ann_id)
|
||||||
return {"id": announcement.id, "user_id": announcement.user_id, "name": announcement.name,
|
return announcement
|
||||||
"category": announcement.category, "best_by": announcement.best_by, "address": announcement.address,
|
|
||||||
"description": announcement.description, "metro": announcement.metro, "latitude": announcement.latitude,
|
|
||||||
"longtitude":announcement.longtitude, "trashId": announcement.trashId, "src":announcement.src,
|
|
||||||
"booked_by":announcement.booked_by}
|
|
||||||
except:
|
except:
|
||||||
return {"Answer" : False} #если неуданый доступ, то сообщаем об этом
|
return {"Answer" : False} #если неуданый доступ, то сообщаем об этом
|
||||||
|
|
||||||
|
|
||||||
# Занести объявление в базу данных
|
# Занести объявление в базу данных
|
||||||
@app.put("/api/announcement")#адрес объявлений
|
@app.put("/api/announcement")
|
||||||
def put_in_db(name: Annotated[str, Form()], category: Annotated[str, Form()], bestBy: Annotated[datetime.date, Form()],
|
def put_in_db(name: Annotated[str, Form()], category: Annotated[str, Form()], bestBy: Annotated[datetime.date, Form()],
|
||||||
address: Annotated[str, Form()], longtitude: Annotated[float, Form()], latitude: Annotated[float, Form()],
|
address: Annotated[str, Form()], longtitude: Annotated[float, Form()], latitude: Annotated[float, Form()],
|
||||||
description: Annotated[str, Form()], metro: Annotated[str, Form()], current_user: Annotated[schemas.User, Depends(utils.get_current_active_user)],
|
description: Annotated[str, Form()], metro: Annotated[str, Form()], current_user: Annotated[pydantic_schemas.User, Depends(auth_utils.get_current_active_user)],
|
||||||
db: Annotated[Session, Depends(utils.get_db)], src: Union[UploadFile, None] = None, trashId: Annotated[int, Form()] = None):
|
db: Annotated[Session, Depends(auth_utils.get_db)], src: Union[UploadFile, None] = None, trashId: Annotated[int, Form()] = None):
|
||||||
try:
|
try:
|
||||||
|
# имя загруженного файла по умолчанию - пустая строка
|
||||||
uploaded_name = ""
|
uploaded_name = ""
|
||||||
|
# если пользователь загрузил картинку
|
||||||
if src:
|
if src:
|
||||||
|
# процесс сохранения картинки
|
||||||
f = src.file
|
f = src.file
|
||||||
f.seek(0, os.SEEK_END)
|
f.seek(0, os.SEEK_END)
|
||||||
if f.tell() > 0:
|
if f.tell() > 0:
|
||||||
@ -80,9 +84,11 @@ def put_in_db(name: Annotated[str, Form()], category: Annotated[str, Form()], be
|
|||||||
with destination.open('wb') as buffer:
|
with destination.open('wb') as buffer:
|
||||||
shutil.copyfileobj(f, buffer)
|
shutil.copyfileobj(f, buffer)
|
||||||
|
|
||||||
uploaded_name = "/uploads/"+destination.name
|
# изменяем название директории загруженного файла
|
||||||
|
uploaded_name = "/uploads/" + destination.name
|
||||||
|
|
||||||
temp_ancmt = models.Announcement(user_id=current_user.id, name=name, category=category, best_by=bestBy,
|
# создаем объект Announcement
|
||||||
|
temp_ancmt = orm_models.Announcement(user_id=current_user.id, name=name, category=category, best_by=bestBy,
|
||||||
address=address, longtitude=longtitude, latitude=latitude, description=description, metro=metro,
|
address=address, longtitude=longtitude, latitude=latitude, description=description, metro=metro,
|
||||||
trashId=trashId, src=uploaded_name, booked_by=0)
|
trashId=trashId, src=uploaded_name, booked_by=0)
|
||||||
db.add(temp_ancmt) # добавляем в бд
|
db.add(temp_ancmt) # добавляем в бд
|
||||||
@ -95,9 +101,10 @@ def put_in_db(name: Annotated[str, Form()], category: Annotated[str, Form()], be
|
|||||||
|
|
||||||
# Удалить объявления из базы
|
# Удалить объявления из базы
|
||||||
@app.delete("/api/announcement") #адрес объявления
|
@app.delete("/api/announcement") #адрес объявления
|
||||||
def delete_from_db(announcement: schemas.DelAnnouncement, db: Annotated[Session, Depends(utils.get_db)]): # функция удаления объекта из БД
|
def delete_from_db(announcement: pydantic_schemas.DelAnnouncement, db: Annotated[Session, Depends(auth_utils.get_db)]): # функция удаления объекта из БД
|
||||||
try:
|
try:
|
||||||
to_delete = db.query(models.Announcement).filter(models.Announcement.id==announcement.id).first()
|
# находим объект с заданным id в бд
|
||||||
|
to_delete = db.query(orm_models.Announcement).filter(orm_models.Announcement.id==announcement.id).first()
|
||||||
db.delete(to_delete) # удаление из БД
|
db.delete(to_delete) # удаление из БД
|
||||||
db.commit() # сохраняем изменения
|
db.commit() # сохраняем изменения
|
||||||
return {"Answer" : True}
|
return {"Answer" : True}
|
||||||
@ -107,10 +114,10 @@ def delete_from_db(announcement: schemas.DelAnnouncement, db: Annotated[Session,
|
|||||||
|
|
||||||
# Забронировать объявление
|
# Забронировать объявление
|
||||||
@app.post("/api/book")
|
@app.post("/api/book")
|
||||||
def change_book_status(data: schemas.Book, current_user: Annotated[schemas.User, Depends(utils.get_current_user)],
|
def change_book_status(data: pydantic_schemas.Book, current_user: Annotated[pydantic_schemas.User, Depends(auth_utils.get_current_user)],
|
||||||
db: Annotated[Session, Depends(utils.get_db)]):
|
db: Annotated[Session, Depends(auth_utils.get_db)]):
|
||||||
# Находим объявление по данному id
|
# Находим объявление по данному id
|
||||||
announcement_to_change = db.query(models.Announcement).filter(models.Announcement.id == data.id).first()
|
announcement_to_change = db.query(orm_models.Announcement).filter(orm_models.Announcement.id == data.id).first()
|
||||||
# Проверяем, что объявление с данным id существует
|
# Проверяем, что объявление с данным id существует
|
||||||
if not announcement_to_change:
|
if not announcement_to_change:
|
||||||
raise HTTPException(status_code=404, detail="Item not found")
|
raise HTTPException(status_code=404, detail="Item not found")
|
||||||
@ -120,20 +127,23 @@ def change_book_status(data: schemas.Book, current_user: Annotated[schemas.User,
|
|||||||
else:
|
else:
|
||||||
# Инкрементируем поле booked_by на 1
|
# Инкрементируем поле booked_by на 1
|
||||||
announcement_to_change.booked_by += 1
|
announcement_to_change.booked_by += 1
|
||||||
|
# фиксируем изменения в бд
|
||||||
db.commit()
|
db.commit()
|
||||||
db.refresh(announcement_to_change)
|
db.refresh(announcement_to_change)
|
||||||
return {"Success": True}
|
return {"Success": True}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# reginstration
|
# reginstration
|
||||||
@app.post("/api/signup")
|
@app.post("/api/signup")
|
||||||
def create_user(nickname: Annotated[str, Form()], password: Annotated[str, Form()], db: Annotated[Session, Depends(utils.get_db)],
|
def create_user(nickname: Annotated[str, Form()], password: Annotated[str, Form()], db: Annotated[Session, Depends(auth_utils.get_db)],
|
||||||
name: Annotated[str, Form()]=None, surname: Annotated[str, Form()]=None, avatar: Annotated[UploadFile, Form()]=None):
|
name: Annotated[str, Form()]=None, surname: Annotated[str, Form()]=None, avatar: Annotated[UploadFile, Form()]=None):
|
||||||
|
|
||||||
if db.query(models.User).filter(models.User.nickname == nickname).first() == None:
|
# проверяем, что юзера с введенным никнеймом не существует в бд
|
||||||
new_user = models.User(nickname=nickname, hashed_password=utils.get_password_hash(password),
|
if db.query(orm_models.User).filter(orm_models.User.nickname == nickname).first() == None:
|
||||||
|
# создаем нового юзера
|
||||||
|
new_user = orm_models.User(nickname=nickname, hashed_password=auth_utils.get_password_hash(password),
|
||||||
name=name, surname=surname, reg_date=datetime.date.today())
|
name=name, surname=surname, reg_date=datetime.date.today())
|
||||||
|
# добавляем в бд
|
||||||
db.add(new_user)
|
db.add(new_user)
|
||||||
db.commit()
|
db.commit()
|
||||||
db.refresh(new_user) # обновляем состояние объекта
|
db.refresh(new_user) # обновляем состояние объекта
|
||||||
@ -141,34 +151,41 @@ def create_user(nickname: Annotated[str, Form()], password: Annotated[str, Form(
|
|||||||
return {"Success": False, "Message": "Пользователь с таким email уже зарегестрирован"}
|
return {"Success": False, "Message": "Пользователь с таким email уже зарегестрирован"}
|
||||||
|
|
||||||
|
|
||||||
@app.post("/api/token", response_model=schemas.Token)
|
# функция для генерации токена после успешного входа пользователя
|
||||||
|
@app.post("/api/token", response_model=pydantic_schemas.Token)
|
||||||
async def login_for_access_token(
|
async def login_for_access_token(
|
||||||
form_data: Annotated[OAuth2PasswordRequestForm, Depends()], db: Annotated[Session, Depends(utils.get_db)]
|
form_data: Annotated[OAuth2PasswordRequestForm, Depends()], db: Annotated[Session, Depends(auth_utils.get_db)]
|
||||||
):
|
):
|
||||||
user = utils.authenticate_user(db, form_data.username, form_data.password)
|
# пробуем найти юзера в бд по введенным паролю и никнейму
|
||||||
|
user = auth_utils.authenticate_user(db, form_data.username, form_data.password)
|
||||||
|
# если не нашли - кидаем ошибку
|
||||||
if not user:
|
if not user:
|
||||||
raise HTTPException(
|
raise HTTPException(
|
||||||
status_code=status.HTTP_401_UNAUTHORIZED,
|
status_code=status.HTTP_401_UNAUTHORIZED,
|
||||||
detail="Incorrect username or password",
|
detail="Incorrect username or password",
|
||||||
headers={"WWW-Authenticate": "Bearer"},
|
headers={"WWW-Authenticate": "Bearer"},
|
||||||
)
|
)
|
||||||
access_token_expires = utils.timedelta(minutes=utils.ACCESS_TOKEN_EXPIRE_MINUTES)
|
# задаем временной интервал, в течение которого токен можно использовать
|
||||||
access_token = utils.create_access_token(
|
access_token_expires = auth_utils.timedelta(minutes=auth_utils.ACCESS_TOKEN_EXPIRE_MINUTES)
|
||||||
|
# создаем токен
|
||||||
|
access_token = auth_utils.create_access_token(
|
||||||
data={"user_id": user.id}, expires_delta=access_token_expires
|
data={"user_id": user.id}, expires_delta=access_token_expires
|
||||||
)
|
)
|
||||||
return {"access_token":access_token}
|
return {"access_token":access_token}
|
||||||
|
|
||||||
|
|
||||||
@app.get("/api/users/me", response_model=schemas.User) #
|
# получаем данные успешно вошедшего пользователя
|
||||||
async def read_users_me(current_user: Annotated[schemas.User, Depends(utils.get_current_active_user)]):
|
@app.get("/api/users/me", response_model=pydantic_schemas.User) #
|
||||||
|
async def read_users_me(current_user: Annotated[pydantic_schemas.User, Depends(auth_utils.get_current_active_user)]):
|
||||||
return current_user
|
return current_user
|
||||||
|
|
||||||
|
|
||||||
# изменяем рейтинг пользователя
|
# изменяем рейтинг пользователя
|
||||||
@app.post("/api/user/rating")
|
@app.post("/api/user/rating")
|
||||||
def add_points(data: schemas.AddRating, current_user: Annotated[schemas.User, Depends(utils.get_current_user)], db: Annotated[Session, Depends(utils.get_db)]):
|
def add_points(data: pydantic_schemas.AddRating, current_user: Annotated[pydantic_schemas.User, Depends(auth_utils.get_current_user)], db: Annotated[Session, Depends(auth_utils.get_db)]):
|
||||||
|
# проверяем,
|
||||||
if current_user.id != data.user_id:
|
if current_user.id != data.user_id:
|
||||||
user = utils.get_user_by_id(db, data.user_id)
|
user = auth_utils.get_user_by_id(db, data.user_id)
|
||||||
if not user:
|
if not user:
|
||||||
raise HTTPException(status_code=404, detail="Item not found")
|
raise HTTPException(status_code=404, detail="Item not found")
|
||||||
user.rating = (user.rating*user.num_of_ratings + data.rate)/(user.num_of_ratings + 1)
|
user.rating = (user.rating*user.num_of_ratings + data.rate)/(user.num_of_ratings + 1)
|
||||||
@ -180,28 +197,28 @@ def add_points(data: schemas.AddRating, current_user: Annotated[schemas.User, De
|
|||||||
|
|
||||||
# получаем рейтинг пользователя
|
# получаем рейтинг пользователя
|
||||||
@app.get("/api/user/rating")
|
@app.get("/api/user/rating")
|
||||||
def add_points(user_id: int, db: Annotated[Session, Depends(utils.get_db)]):
|
def add_points(user_id: int, db: Annotated[Session, Depends(auth_utils.get_db)]):
|
||||||
user = utils.get_user_by_id(db, user_id=user_id)
|
user = auth_utils.get_user_by_id(db, user_id=user_id)
|
||||||
if not user:
|
if not user:
|
||||||
raise HTTPException(status_code=404, detail="Item not found")
|
raise HTTPException(status_code=404, detail="Item not found")
|
||||||
return {"rating": user.rating}
|
return {"rating": user.rating}
|
||||||
|
|
||||||
|
|
||||||
# Отправляем стихи
|
# Отправляем стихи
|
||||||
@app.get("/api/user/poem", response_model=schemas.Poem) # пока не работает
|
@app.get("/api/user/poem", response_model=pydantic_schemas.Poem) # пока не работает
|
||||||
def poems_to_front(db: Annotated[Session, Depends(utils.get_db)]): # db: Annotated[Session, Depends(utils.get_db)]
|
def poems_to_front(db: Annotated[Session, Depends(auth_utils.get_db)]): # db: Annotated[Session, Depends(utils.get_db)]
|
||||||
num_of_poems = db.query(models.Poems).count() # определяем кол-во стихов в бд
|
num_of_poems = db.query(orm_models.Poems).count() # определяем кол-во стихов в бд
|
||||||
if num_of_poems < 1:
|
if num_of_poems < 1:
|
||||||
service.add_poems_to_db(database) # добавляем поэмы в базу данных
|
add_poems_and_filters.add_poems_to_db(database) # добавляем поэмы в базу данных
|
||||||
rand_id = random.randint(1, num_of_poems) # генерируем номер стихотворения
|
rand_id = random.randint(1, num_of_poems) # генерируем номер стихотворения
|
||||||
poem = db.query(models.Poems).filter(models.Poems.id == rand_id).first() # находим стих в бд
|
poem = db.query(orm_models.Poems).filter(orm_models.Poems.id == rand_id).first() # находим стих в бд
|
||||||
if not poem:
|
if not poem:
|
||||||
raise HTTPException(status_code=404, detail="Poem not found")
|
raise HTTPException(status_code=404, detail="Poem not found")
|
||||||
return poem
|
return poem
|
||||||
|
|
||||||
|
|
||||||
@app.get("/api/trashbox", response_model=List[schemas.TrashboxResponse])
|
@app.get("/api/trashbox", response_model=List[pydantic_schemas.TrashboxResponse])
|
||||||
def get_trashboxes(data: schemas.TrashboxRequest = Depends()):#крутая функция для работы с api
|
def get_trashboxes(data: pydantic_schemas.TrashboxRequest = Depends()):#крутая функция для работы с api
|
||||||
# json, передаваемый стороннему API
|
# json, передаваемый стороннему API
|
||||||
BASE_URL= "https://geointelect2.gate.petersburg.ru"
|
BASE_URL= "https://geointelect2.gate.petersburg.ru"
|
||||||
my_token="eyJhbGciOiJSUzI1NiIsInR5cCIgOiAiSldUIiwia2lkIiA6ICJhU1RaZm42bHpTdURYcUttRkg1SzN5UDFhT0FxUkhTNm9OendMUExaTXhFIn0.eyJleHAiOjE3ODYyMjUzMzMsImlhdCI6MTY5MTUzMDkzMywianRpIjoiYjU0MmU3MTQtYzJkMS00NTY2LWJkY2MtYmQ5NzA0ODY1ZjgzIiwiaXNzIjoiaHR0cHM6Ly9rYy5wZXRlcnNidXJnLnJ1L3JlYWxtcy9lZ3MtYXBpIiwiYXVkIjoiYWNjb3VudCIsInN1YiI6ImJjYjQ2NzljLTU3ZGItNDU5ZC1iNWUxLWRlOGI4Yzg5MTMwMyIsInR5cCI6IkJlYXJlciIsImF6cCI6ImFkbWluLXJlc3QtY2xpZW50Iiwic2Vzc2lvbl9zdGF0ZSI6IjJhOTgwMzUyLTY1M2QtNGZlZC1iMDI1LWQ1N2U0NDRjZmM3NiIsImFjciI6IjEiLCJhbGxvd2VkLW9yaWdpbnMiOlsiLyoiXSwicmVhbG1fYWNjZXNzIjp7InJvbGVzIjpbImRlZmF1bHQtcm9sZXMtZWdzLWFwaSIsIm9mZmxpbmVfYWNjZXNzIiwidW1hX2F1dGhvcml6YXRpb24iXX0sInJlc291cmNlX2FjY2VzcyI6eyJhY2NvdW50Ijp7InJvbGVzIjpbIm1hbmFnZS1hY2NvdW50IiwibWFuYWdlLWFjY291bnQtbGlua3MiLCJ2aWV3LXByb2ZpbGUiXX19LCJzY29wZSI6ImVtYWlsIHByb2ZpbGUiLCJzaWQiOiIyYTk4MDM1Mi02NTNkLTRmZWQtYjAyNS1kNTdlNDQ0Y2ZjNzYiLCJlbWFpbF92ZXJpZmllZCI6ZmFsc2UsIm5hbWUiOiLQktC70LDQtNC40LzQuNGAINCv0LrQvtCy0LvQtdCyIiwicHJlZmVycmVkX3VzZXJuYW1lIjoiZTBmYzc2OGRhOTA4MjNiODgwZGQzOGVhMDJjMmQ5NTciLCJnaXZlbl9uYW1lIjoi0JLQu9Cw0LTQuNC80LjRgCIsImZhbWlseV9uYW1lIjoi0K_QutC-0LLQu9C10LIifQ.FTKiC1hpWcOkmSW9QZpC-RY7Ko50jw1mDMfXIWYxlQ-zehLm2CLmOnHvYoOoI39k2OzeCIAB9ZdRrrGZc6G9Z1eFELUjNGEqKxSC1Phj9ATemKgbOKEttk-OGc-rFr9VPA8_SnfvLts6wTI2YK33YBIxCF5nCbnr4Qj3LeEQ0d6Hy8PO4ATrBF5EOeuAZRprvIEjXe_f8N9ONKckCPB-xFB4P2pZlVXGoCNoewGEcY3zXH4khezN6zcVr6tpc6G8dBv9EqT_v92IDSg-aXQk6ysA0cO0-6x5w1-_qU0iHGIAPsLNV9IKBoFbjc0JH6cWabldPRH12NP1trvYfqKDGQ"
|
my_token="eyJhbGciOiJSUzI1NiIsInR5cCIgOiAiSldUIiwia2lkIiA6ICJhU1RaZm42bHpTdURYcUttRkg1SzN5UDFhT0FxUkhTNm9OendMUExaTXhFIn0.eyJleHAiOjE3ODYyMjUzMzMsImlhdCI6MTY5MTUzMDkzMywianRpIjoiYjU0MmU3MTQtYzJkMS00NTY2LWJkY2MtYmQ5NzA0ODY1ZjgzIiwiaXNzIjoiaHR0cHM6Ly9rYy5wZXRlcnNidXJnLnJ1L3JlYWxtcy9lZ3MtYXBpIiwiYXVkIjoiYWNjb3VudCIsInN1YiI6ImJjYjQ2NzljLTU3ZGItNDU5ZC1iNWUxLWRlOGI4Yzg5MTMwMyIsInR5cCI6IkJlYXJlciIsImF6cCI6ImFkbWluLXJlc3QtY2xpZW50Iiwic2Vzc2lvbl9zdGF0ZSI6IjJhOTgwMzUyLTY1M2QtNGZlZC1iMDI1LWQ1N2U0NDRjZmM3NiIsImFjciI6IjEiLCJhbGxvd2VkLW9yaWdpbnMiOlsiLyoiXSwicmVhbG1fYWNjZXNzIjp7InJvbGVzIjpbImRlZmF1bHQtcm9sZXMtZWdzLWFwaSIsIm9mZmxpbmVfYWNjZXNzIiwidW1hX2F1dGhvcml6YXRpb24iXX0sInJlc291cmNlX2FjY2VzcyI6eyJhY2NvdW50Ijp7InJvbGVzIjpbIm1hbmFnZS1hY2NvdW50IiwibWFuYWdlLWFjY291bnQtbGlua3MiLCJ2aWV3LXByb2ZpbGUiXX19LCJzY29wZSI6ImVtYWlsIHByb2ZpbGUiLCJzaWQiOiIyYTk4MDM1Mi02NTNkLTRmZWQtYjAyNS1kNTdlNDQ0Y2ZjNzYiLCJlbWFpbF92ZXJpZmllZCI6ZmFsc2UsIm5hbWUiOiLQktC70LDQtNC40LzQuNGAINCv0LrQvtCy0LvQtdCyIiwicHJlZmVycmVkX3VzZXJuYW1lIjoiZTBmYzc2OGRhOTA4MjNiODgwZGQzOGVhMDJjMmQ5NTciLCJnaXZlbl9uYW1lIjoi0JLQu9Cw0LTQuNC80LjRgCIsImZhbWlseV9uYW1lIjoi0K_QutC-0LLQu9C10LIifQ.FTKiC1hpWcOkmSW9QZpC-RY7Ko50jw1mDMfXIWYxlQ-zehLm2CLmOnHvYoOoI39k2OzeCIAB9ZdRrrGZc6G9Z1eFELUjNGEqKxSC1Phj9ATemKgbOKEttk-OGc-rFr9VPA8_SnfvLts6wTI2YK33YBIxCF5nCbnr4Qj3LeEQ0d6Hy8PO4ATrBF5EOeuAZRprvIEjXe_f8N9ONKckCPB-xFB4P2pZlVXGoCNoewGEcY3zXH4khezN6zcVr6tpc6G8dBv9EqT_v92IDSg-aXQk6ysA0cO0-6x5w1-_qU0iHGIAPsLNV9IKBoFbjc0JH6cWabldPRH12NP1trvYfqKDGQ"
|
||||||
@ -250,7 +267,7 @@ def get_trashboxes(data: schemas.TrashboxRequest = Depends()):#крутая фу
|
|||||||
for a in list_of_category:
|
for a in list_of_category:
|
||||||
if a in temp_dict["Categories"] and temp_dict not in trashboxes:
|
if a in temp_dict["Categories"] and temp_dict not in trashboxes:
|
||||||
trashboxes.append(temp_dict)
|
trashboxes.append(temp_dict)
|
||||||
uniq_trashboxes = [schemas.TrashboxResponse(**ast.literal_eval(el1)) for el1 in set([str(el2) for el2 in trashboxes])]
|
uniq_trashboxes = [pydantic_schemas.TrashboxResponse(**ast.literal_eval(el1)) for el1 in set([str(el2) for el2 in trashboxes])]
|
||||||
return uniq_trashboxes
|
return uniq_trashboxes
|
||||||
|
|
||||||
|
|
||||||
@ -260,22 +277,22 @@ async def react_app(req: Request, rest_of_path: str):
|
|||||||
|
|
||||||
|
|
||||||
@app.post("/api/announcement/dispose")
|
@app.post("/api/announcement/dispose")
|
||||||
def dispose(data: schemas.DisposeRequest, current_user_schema: Annotated[schemas.User, Depends(utils.get_current_user)],
|
def dispose(data: pydantic_schemas.DisposeRequest, current_user_schema: Annotated[pydantic_schemas.User, Depends(auth_utils.get_current_user)],
|
||||||
db: Annotated[Session, Depends(utils.get_db)]):
|
db: Annotated[Session, Depends(auth_utils.get_db)]):
|
||||||
# Находим в бд текущего юзера
|
# Находим в бд текущего юзера
|
||||||
current_user = utils.get_user_by_id(db, current_user_schema.id)
|
current_user = auth_utils.get_user_by_id(db, current_user_schema.id)
|
||||||
# Начисляем баллы пользователю за утилизацию
|
# Начисляем баллы пользователю за утилизацию
|
||||||
current_user.points += 60
|
current_user.points += 60
|
||||||
# В полученном json переходим к данным мусорки
|
# В полученном json переходим к данным мусорки
|
||||||
data_trashbox = data.trashbox
|
data_trashbox = data.trashbox
|
||||||
# создаем запись models.Trashbox
|
# создаем запись models.Trashbox
|
||||||
new_trashox = models.Trashbox(user_id=current_user.id, date_of_choice=datetime.date.today(), name=data_trashbox.Name,
|
new_trashox = orm_models.Trashbox(user_id=current_user.id, date_of_choice=datetime.date.today(), name=data_trashbox.Name,
|
||||||
latitude=data_trashbox.Lat, longtitude=data_trashbox.Lng, address=data_trashbox.Address, category=data_trashbox.Category)
|
latitude=data_trashbox.Lat, longtitude=data_trashbox.Lng, address=data_trashbox.Address, category=data_trashbox.Category)
|
||||||
# добавляем в бд
|
# добавляем в бд
|
||||||
db.add(new_trashox)
|
db.add(new_trashox)
|
||||||
# в соответствии с логикой api, после утилизации объявление пользователя удаляется
|
# в соответствии с логикой api, после утилизации объявление пользователя удаляется
|
||||||
# находим объявление с айди data.ann_id
|
# находим объявление с айди data.ann_id
|
||||||
ann_to_del = db.query(models.Announcement).filter(models.Announcement.id == data.ann_id).first() # находим стих в бд
|
ann_to_del = db.query(orm_models.Announcement).filter(orm_models.Announcement.id == data.ann_id).first() # находим стих в бд
|
||||||
if not ann_to_del:
|
if not ann_to_del:
|
||||||
raise HTTPException(status_code=404, detail="Announcement not found")
|
raise HTTPException(status_code=404, detail="Announcement not found")
|
||||||
# удаляем объявление из бд
|
# удаляем объявление из бд
|
||||||
|
@ -1,97 +1,97 @@
|
|||||||
from datetime import datetime, timedelta
|
from datetime import datetime, timedelta
|
||||||
from typing import Annotated, Union
|
from typing import Annotated, Union
|
||||||
|
|
||||||
from fastapi import Depends, HTTPException, status
|
from fastapi import Depends, HTTPException, status
|
||||||
from fastapi.security import OAuth2PasswordBearer
|
from fastapi.security import OAuth2PasswordBearer
|
||||||
from jose import JWTError, jwt
|
from jose import JWTError, jwt
|
||||||
from passlib.context import CryptContext
|
from passlib.context import CryptContext
|
||||||
from sqlalchemy.orm import Session
|
from sqlalchemy.orm import Session
|
||||||
|
|
||||||
from .db import database
|
from .db import database
|
||||||
from . import models, schemas
|
from . import orm_models, pydantic_schemas
|
||||||
|
|
||||||
|
|
||||||
SECRET_KEY = "SECRET"
|
SECRET_KEY = "651a52941cf5de14d48ef5d7af115709"
|
||||||
ALGORITHM = "HS256"
|
ALGORITHM = "HS256"
|
||||||
ACCESS_TOKEN_EXPIRE_MINUTES = 30
|
ACCESS_TOKEN_EXPIRE_MINUTES = 1440
|
||||||
pwd_context = CryptContext(schemes=["bcrypt"], deprecated="auto")
|
pwd_context = CryptContext(schemes=["bcrypt"], deprecated="auto")
|
||||||
oauth2_scheme = OAuth2PasswordBearer(tokenUrl="/api/token")
|
oauth2_scheme = OAuth2PasswordBearer(tokenUrl="/api/token")
|
||||||
|
|
||||||
|
|
||||||
def get_db():
|
def get_db():
|
||||||
db = database
|
db = database
|
||||||
try:
|
try:
|
||||||
yield db
|
yield db
|
||||||
finally:
|
finally:
|
||||||
db.close()
|
db.close()
|
||||||
|
|
||||||
|
|
||||||
def verify_password(plain_password, hashed_password):
|
def verify_password(plain_password, hashed_password):
|
||||||
return pwd_context.verify(plain_password, hashed_password)
|
return pwd_context.verify(plain_password, hashed_password)
|
||||||
|
|
||||||
|
|
||||||
def get_password_hash(password):
|
def get_password_hash(password):
|
||||||
return pwd_context.hash(password)
|
return pwd_context.hash(password)
|
||||||
|
|
||||||
|
|
||||||
def get_user_by_nickname(db: Annotated[Session, Depends(get_db)], nickname: str):
|
def get_user_by_nickname(db: Annotated[Session, Depends(get_db)], nickname: str):
|
||||||
user_with_required_id = db.query(models.User).filter(models.User.nickname == nickname).first()
|
user_with_required_id = db.query(orm_models.User).filter(orm_models.User.nickname == nickname).first()
|
||||||
if user_with_required_id:
|
if user_with_required_id:
|
||||||
return user_with_required_id
|
return user_with_required_id
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
|
||||||
def get_user_by_id(db: Annotated[Session, Depends(get_db)], user_id: int):
|
def get_user_by_id(db: Annotated[Session, Depends(get_db)], user_id: int):
|
||||||
user_with_required_id = db.query(models.User).filter(models.User.id == user_id).first()
|
user_with_required_id = db.query(orm_models.User).filter(orm_models.User.id == user_id).first()
|
||||||
if user_with_required_id:
|
if user_with_required_id:
|
||||||
return user_with_required_id
|
return user_with_required_id
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
|
||||||
def authenticate_user(db: Annotated[Session, Depends(get_db)], nickname: str, password: str):
|
def authenticate_user(db: Annotated[Session, Depends(get_db)], nickname: str, password: str):
|
||||||
user = get_user_by_nickname(db=db, nickname=nickname)
|
user = get_user_by_nickname(db=db, nickname=nickname)
|
||||||
if not user:
|
if not user:
|
||||||
return False
|
return False
|
||||||
if not verify_password(password, user.hashed_password):
|
if not verify_password(password, user.hashed_password):
|
||||||
return False
|
return False
|
||||||
return user
|
return user
|
||||||
|
|
||||||
|
|
||||||
def create_access_token(data: dict, expires_delta: Union[timedelta, None] = None):
|
def create_access_token(data: dict, expires_delta: Union[timedelta, None] = None):
|
||||||
to_encode = data.copy()
|
to_encode = data.copy()
|
||||||
if expires_delta:
|
if expires_delta:
|
||||||
expire = datetime.utcnow() + expires_delta
|
expire = datetime.utcnow() + expires_delta
|
||||||
else:
|
else:
|
||||||
expire = datetime.utcnow() + timedelta(minutes=15)
|
expire = datetime.utcnow() + timedelta(minutes=15)
|
||||||
to_encode.update({"exp": expire})
|
to_encode.update({"exp": expire})
|
||||||
encoded_jwt = jwt.encode(to_encode, SECRET_KEY, algorithm=ALGORITHM)
|
encoded_jwt = jwt.encode(to_encode, SECRET_KEY, algorithm=ALGORITHM)
|
||||||
return encoded_jwt
|
return encoded_jwt
|
||||||
|
|
||||||
|
|
||||||
async def get_current_user(db: Annotated[Session, Depends(get_db)], token: Annotated[str, Depends(oauth2_scheme)]):
|
async def get_current_user(db: Annotated[Session, Depends(get_db)], token: Annotated[str, Depends(oauth2_scheme)]):
|
||||||
credentials_exception = HTTPException(
|
credentials_exception = HTTPException(
|
||||||
status_code=status.HTTP_401_UNAUTHORIZED,
|
status_code=status.HTTP_401_UNAUTHORIZED,
|
||||||
detail="Could not validate credentials",
|
detail="Could not validate credentials",
|
||||||
headers={"WWW-Authenticate": "Bearer"},
|
headers={"WWW-Authenticate": "Bearer"},
|
||||||
)
|
)
|
||||||
try:
|
try:
|
||||||
payload = jwt.decode(token, SECRET_KEY, algorithms=[ALGORITHM])
|
payload = jwt.decode(token, SECRET_KEY, algorithms=[ALGORITHM])
|
||||||
user_id: int = payload.get("user_id")
|
user_id: int = payload.get("user_id")
|
||||||
if user_id is None:
|
if user_id is None:
|
||||||
raise credentials_exception
|
raise credentials_exception
|
||||||
token_data = schemas.TokenData(user_id=user_id)
|
token_data = pydantic_schemas.TokenData(user_id=user_id)
|
||||||
except JWTError:
|
except JWTError:
|
||||||
raise credentials_exception
|
raise credentials_exception
|
||||||
user = get_user_by_id(db, user_id=token_data.user_id)
|
user = get_user_by_id(db, user_id=token_data.user_id)
|
||||||
if user is None:
|
if user is None:
|
||||||
raise credentials_exception
|
raise credentials_exception
|
||||||
return schemas.User(id=user.id, nickname=user.nickname, name=user.name, surname=user.surname,
|
return pydantic_schemas.User(id=user.id, nickname=user.nickname, name=user.name, surname=user.surname,
|
||||||
disabled=user.disabled, items=user.announcements, reg_date=user.reg_date, points=user.points)
|
disabled=user.disabled, items=user.announcements, reg_date=user.reg_date, points=user.points)
|
||||||
|
|
||||||
|
|
||||||
async def get_current_active_user(
|
async def get_current_active_user(
|
||||||
current_user: Annotated[schemas.User, Depends(get_current_user)]
|
current_user: Annotated[pydantic_schemas.User, Depends(get_current_user)]
|
||||||
):
|
):
|
||||||
if current_user.disabled:
|
if current_user.disabled:
|
||||||
raise HTTPException(status_code=400, detail="Inactive user")
|
raise HTTPException(status_code=400, detail="Inactive user")
|
||||||
return current_user
|
return current_user
|
2
back/auxiliary_for_alembic.py
Normal file
2
back/auxiliary_for_alembic.py
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
from .db import Base
|
||||||
|
from .orm_models import User, Announcement, Trashbox
|
@ -1,2 +0,0 @@
|
|||||||
from .db import Base
|
|
||||||
from .models import User, Announcement, Trashbox
|
|
@ -1,6 +0,0 @@
|
|||||||
from .models import Poems
|
|
||||||
from .db import database
|
|
||||||
|
|
||||||
to_delete = database.query(Poems).filter(Poems.id > 110)
|
|
||||||
database.delete(to_delete)
|
|
||||||
database.commit()
|
|
@ -1,12 +0,0 @@
|
|||||||
from sqlalchemy import Table, MetaData, text
|
|
||||||
from .db import engine, Base
|
|
||||||
|
|
||||||
# tbl = Table('Poems', MetaData(), autoload_with=engine)
|
|
||||||
# tbl.drop(engine, checkfirst=False)
|
|
||||||
# a = input()
|
|
||||||
|
|
||||||
# Base.metadata.drop_all(bind=engine)
|
|
||||||
|
|
||||||
with engine.connect() as conn:
|
|
||||||
conn.execute(text("DELETE FROM alembic_version"))
|
|
||||||
conn.commit()
|
|
@ -33,6 +33,27 @@ class Announcement(BaseModel):
|
|||||||
arbitrary_types_allowed=True
|
arbitrary_types_allowed=True
|
||||||
|
|
||||||
|
|
||||||
|
# для "/api/announcement"
|
||||||
|
class AnnResponce(BaseModel):
|
||||||
|
id: int
|
||||||
|
user_id: int
|
||||||
|
name: str
|
||||||
|
category: str
|
||||||
|
best_by: date
|
||||||
|
address: str
|
||||||
|
longtitude: float
|
||||||
|
latitude: float
|
||||||
|
description: str
|
||||||
|
src: Union[str, None] = None #изображение продукта в объявлении
|
||||||
|
metro: str #ближайщее метро от адреса нахождения продукта
|
||||||
|
trashId: Union[int, None] = None
|
||||||
|
booked_by: Union[int, None] = 0 #статус бронирования (либо 0, либо айди бронирующего)
|
||||||
|
|
||||||
|
class Config:
|
||||||
|
orm_mode = True
|
||||||
|
|
||||||
|
|
||||||
|
# Схемы для токенов
|
||||||
class Token(BaseModel):
|
class Token(BaseModel):
|
||||||
access_token: str
|
access_token: str
|
||||||
# token_type: str
|
# token_type: str
|
||||||
@ -42,6 +63,7 @@ class TokenData(BaseModel):
|
|||||||
user_id: Union[int, None] = None
|
user_id: Union[int, None] = None
|
||||||
|
|
||||||
|
|
||||||
|
# Схемы юзера
|
||||||
class User(BaseModel):
|
class User(BaseModel):
|
||||||
id: int
|
id: int
|
||||||
nickname: str
|
nickname: str
|
||||||
@ -54,9 +76,11 @@ class User(BaseModel):
|
|||||||
orm_mode = True
|
orm_mode = True
|
||||||
arbitrary_types_allowed=True
|
arbitrary_types_allowed=True
|
||||||
|
|
||||||
|
|
||||||
class UserInDB(User):
|
class UserInDB(User):
|
||||||
hashed_password: str
|
hashed_password: str
|
||||||
|
|
||||||
|
# Схема для стиха
|
||||||
class Poem(BaseModel):
|
class Poem(BaseModel):
|
||||||
id: int
|
id: int
|
||||||
title: str
|
title: str
|
@ -1,4 +1,4 @@
|
|||||||
from . import service
|
from . import add_poems_and_filters
|
||||||
from rocketry import Rocketry
|
from rocketry import Rocketry
|
||||||
from rocketry.conds import daily
|
from rocketry.conds import daily
|
||||||
import datetime
|
import datetime
|
||||||
@ -10,5 +10,5 @@ app = Rocketry(execution="async")
|
|||||||
@app.task('daily')
|
@app.task('daily')
|
||||||
async def daily_check():
|
async def daily_check():
|
||||||
# Фильтруем по сроку годности
|
# Фильтруем по сроку годности
|
||||||
service.check_obsolete(database, current_date=datetime.date.today())
|
add_poems_and_filters.check_obsolete(database, current_date=datetime.date.today())
|
||||||
|
|
||||||
|
@ -6,7 +6,7 @@ from sqlalchemy import pool
|
|||||||
from alembic import context
|
from alembic import context
|
||||||
|
|
||||||
|
|
||||||
from back import db, base
|
from back import auxiliary_for_alembic, db
|
||||||
|
|
||||||
# this is the Alembic Config object, which provides
|
# this is the Alembic Config object, which provides
|
||||||
# access to the values within the .ini file in use.
|
# access to the values within the .ini file in use.
|
||||||
@ -17,7 +17,7 @@ config = context.config
|
|||||||
if config.config_file_name is not None:
|
if config.config_file_name is not None:
|
||||||
fileConfig(config.config_file_name)
|
fileConfig(config.config_file_name)
|
||||||
|
|
||||||
target_metadata = base.Base.metadata
|
target_metadata = auxiliary_for_alembic.Base.metadata
|
||||||
|
|
||||||
# other values from the config, defined by the needs of env.py,
|
# other values from the config, defined by the needs of env.py,
|
||||||
# can be acquired:
|
# can be acquired:
|
||||||
|
Loading…
x
Reference in New Issue
Block a user