From 1d2f786a8a71f621fd042b6840f7c211e059d2a5 Mon Sep 17 00:00:00 2001 From: DmitryGantimurov Date: Thu, 31 Aug 2023 19:16:45 +0300 Subject: [PATCH 01/23] begin implementing async --- back/add_poems_and_filters.py | 4 ++-- back/api.py | 40 +++++++++++++++++++--------------- back/auth_utils.py | 41 ++++++++++++++++++----------------- back/db.py | 35 ++++++++++-------------------- back/delete_db.py | 6 +++++ back/orm_models.py | 21 ------------------ back/scheduler.py | 2 +- back/unimportant.env | 5 ++++- 8 files changed, 68 insertions(+), 86 deletions(-) create mode 100644 back/delete_db.py diff --git a/back/add_poems_and_filters.py b/back/add_poems_and_filters.py index 6c6116f..cdeee8a 100644 --- a/back/add_poems_and_filters.py +++ b/back/add_poems_and_filters.py @@ -43,7 +43,7 @@ def add_poems_to_db(db: Session): f1.close() -def filter_ann(schema: pydantic_schemas.SortAnnouncements, db: Annotated[Session, Depends(auth_utils.get_db)]): +def filter_ann(schema: pydantic_schemas.SortAnnouncements, db: Annotated[Session, Depends(auth_utils.get_session)]): """Функция для последовательного применения различных фильтров (через схему SortAnnouncements)""" res = db.query(orm_models.Announcement) fields = schema.__dict__ # параметры передоваемой схемы SortAnnouncements (ключи и значения) @@ -58,7 +58,7 @@ def filter_ann(schema: pydantic_schemas.SortAnnouncements, db: Annotated[Session return res.all() -def check_obsolete(db: Annotated[Session, Depends(auth_utils.get_db)], current_date: datetime.date): +def check_obsolete(db: Annotated[Session, Depends(auth_utils.get_session)], current_date: datetime.date): """ Функция участвует в процессе обновления поля obsolete у всех объявлений раз в сутки """ diff --git a/back/api.py b/back/api.py index 177373d..9fa745b 100644 --- a/back/api.py +++ b/back/api.py @@ -22,7 +22,6 @@ import pathlib import shutil import os -from .db import database from . import add_poems_and_filters, auth_utils, orm_models, pydantic_schemas # создаем приложение Fastapi @@ -31,6 +30,9 @@ app = FastAPI() # Jinja2 - шаблоны templates = Jinja2Templates(directory="./front/dist") + +# хранение картинок для стихов +app.mount("/poem_pic", StaticFiles(directory = "./poem_pic")) # создаем эндпоинт для хранения статических файлов app.mount("/static", StaticFiles(directory = "./front/dist")) # проверяем, что папка uploads еще не создана @@ -42,7 +44,7 @@ app.mount("/uploads", StaticFiles(directory = "./uploads")) # получение списка объявлений @app.get("/api/announcements", response_model=List[pydantic_schemas.Announcement])#адрес объявлений -def announcements_list(db: Annotated[Session, Depends(auth_utils.get_db)], obsolete: Union[bool, None] = False, user_id: Union[int, None] = None, +async def announcements_list(db: Annotated[Session, Depends(auth_utils.get_session)], obsolete: Union[bool, None] = False, user_id: Union[int, None] = None, metro: Union[str, None] = None,category: Union[str, None] = None): # параметры для сортировки (схема pydantic schemas.SortAnnouncements) params_to_sort = pydantic_schemas.SortAnnouncements(obsolete=obsolete, user_id=user_id, metro=metro, category=category) @@ -54,7 +56,7 @@ def announcements_list(db: Annotated[Session, Depends(auth_utils.get_db)], obsol # получаем данные одного объявления @app.get("/api/announcement", response_model=pydantic_schemas.AnnResponce) -def single_announcement(ann_id:int, db: Annotated[Session, Depends(auth_utils.get_db)]): # передаем индекс обявления +async def single_announcement(ann_id:int, db: Annotated[Session, Depends(auth_utils.get_session)]): # передаем индекс обявления # Считываем данные из Body и отображаем их на странице. # В последствии будем вставлять данные в html-форму try: @@ -66,10 +68,10 @@ def single_announcement(ann_id:int, db: Annotated[Session, Depends(auth_utils.ge # Занести объявление в базу данных @app.put("/api/announcement") -def put_in_db(name: Annotated[str, Form()], category: Annotated[str, Form()], bestBy: Annotated[datetime.date, Form()], +async 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()], 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(auth_utils.get_db)], src: Union[UploadFile, None] = None, trashId: Annotated[int, Form()] = None): + db: Annotated[Session, Depends(auth_utils.get_session)], src: Union[UploadFile, None] = None, trashId: Annotated[int, Form()] = None): try: # имя загруженного файла по умолчанию - пустая строка uploaded_name = "" @@ -101,7 +103,7 @@ def put_in_db(name: Annotated[str, Form()], category: Annotated[str, Form()], be # Удалить объявления из базы @app.delete("/api/announcement") #адрес объявления -def delete_from_db(announcement: pydantic_schemas.DelAnnouncement, db: Annotated[Session, Depends(auth_utils.get_db)]): # функция удаления объекта из БД +async def delete_from_db(announcement: pydantic_schemas.DelAnnouncement, db: Annotated[Session, Depends(auth_utils.get_session)]): # функция удаления объекта из БД try: # находим объект с заданным id в бд to_delete = db.query(orm_models.Announcement).filter(orm_models.Announcement.id==announcement.id).first() @@ -114,8 +116,8 @@ def delete_from_db(announcement: pydantic_schemas.DelAnnouncement, db: Annotated # Забронировать объявление @app.post("/api/book") -def change_book_status(data: pydantic_schemas.Book, current_user: Annotated[pydantic_schemas.User, Depends(auth_utils.get_current_user)], - db: Annotated[Session, Depends(auth_utils.get_db)]): +async def change_book_status(data: pydantic_schemas.Book, current_user: Annotated[pydantic_schemas.User, Depends(auth_utils.get_current_user)], + db: Annotated[Session, Depends(auth_utils.get_session)]): # Находим объявление по данному id announcement_to_change = db.query(orm_models.Announcement).filter(orm_models.Announcement.id == data.id).first() # Проверяем, что объявление с данным id существует @@ -135,7 +137,7 @@ def change_book_status(data: pydantic_schemas.Book, current_user: Annotated[pyda # reginstration @app.post("/api/signup") -def create_user(nickname: Annotated[str, Form()], password: Annotated[str, Form()], db: Annotated[Session, Depends(auth_utils.get_db)], +async def create_user(nickname: Annotated[str, Form()], password: Annotated[str, Form()], db: Annotated[Session, Depends(auth_utils.get_session)], name: Annotated[str, Form()]=None, surname: Annotated[str, Form()]=None, avatar: Annotated[UploadFile, Form()]=None): # проверяем, что юзера с введенным никнеймом не существует в бд @@ -154,7 +156,7 @@ def create_user(nickname: Annotated[str, Form()], password: Annotated[str, Form( # функция для генерации токена после успешного входа пользователя @app.post("/api/token", response_model=pydantic_schemas.Token) async def login_for_access_token( - form_data: Annotated[OAuth2PasswordRequestForm, Depends()], db: Annotated[Session, Depends(auth_utils.get_db)] + form_data: Annotated[OAuth2PasswordRequestForm, Depends()], db: Annotated[Session, Depends(auth_utils.get_session)] ): # пробуем найти юзера в бд по введенным паролю и никнейму user = auth_utils.authenticate_user(db, form_data.username, form_data.password) @@ -182,7 +184,7 @@ async def read_users_me(current_user: Annotated[pydantic_schemas.User, Depends(a # изменяем рейтинг пользователя @app.post("/api/user/rating") -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)]): +async 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_session)]): # проверяем, if current_user.id != data.user_id: user = auth_utils.get_user_by_id(db, data.user_id) @@ -197,7 +199,7 @@ def add_points(data: pydantic_schemas.AddRating, current_user: Annotated[pydanti # получаем рейтинг пользователя @app.get("/api/user/rating") -def add_points(user_id: int, db: Annotated[Session, Depends(auth_utils.get_db)]): +async def add_points(user_id: int, db: Annotated[Session, Depends(auth_utils.get_session)]): user = auth_utils.get_user_by_id(db, user_id=user_id) if not user: raise HTTPException(status_code=404, detail="Item not found") @@ -205,11 +207,13 @@ def add_points(user_id: int, db: Annotated[Session, Depends(auth_utils.get_db)]) # Отправляем стихи -@app.get("/api/user/poem", response_model=pydantic_schemas.Poem) # пока не работает -def poems_to_front(db: Annotated[Session, Depends(auth_utils.get_db)]): # db: Annotated[Session, Depends(utils.get_db)] +@app.get("/api/user/poem", response_model=pydantic_schemas.Poem) +async def poems_to_front(db: Annotated[Session, Depends(auth_utils.get_session)]): num_of_poems = db.query(orm_models.Poems).count() # определяем кол-во стихов в бд + # если стихов в бд нет if num_of_poems < 1: - add_poems_and_filters.add_poems_to_db(database) # добавляем поэмы в базу данных + add_poems_and_filters.add_poems_to_db(db) # добавляем поэмы в базу данных + num_of_poems = db.query(orm_models.Poems).count() # определяем кол-во стихов в бд rand_id = random.randint(1, num_of_poems) # генерируем номер стихотворения poem = db.query(orm_models.Poems).filter(orm_models.Poems.id == rand_id).first() # находим стих в бд if not poem: @@ -218,7 +222,7 @@ def poems_to_front(db: Annotated[Session, Depends(auth_utils.get_db)]): # db: An @app.get("/api/trashbox", response_model=List[pydantic_schemas.TrashboxResponse]) -def get_trashboxes(data: pydantic_schemas.TrashboxRequest = Depends()):#крутая функция для работы с api +async def get_trashboxes(data: pydantic_schemas.TrashboxRequest = Depends()):#крутая функция для работы с api # json, передаваемый стороннему API 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" @@ -277,8 +281,8 @@ async def react_app(req: Request, rest_of_path: str): @app.post("/api/announcement/dispose") -def dispose(data: pydantic_schemas.DisposeRequest, current_user_schema: Annotated[pydantic_schemas.User, Depends(auth_utils.get_current_user)], - db: Annotated[Session, Depends(auth_utils.get_db)]): +async def dispose(data: pydantic_schemas.DisposeRequest, current_user_schema: Annotated[pydantic_schemas.User, Depends(auth_utils.get_current_user)], + db: Annotated[Session, Depends(auth_utils.get_session)]): # Находим в бд текущего юзера current_user = auth_utils.get_user_by_id(db, current_user_schema.id) # Начисляем баллы пользователю за утилизацию diff --git a/back/auth_utils.py b/back/auth_utils.py index 594627c..bf5d95e 100644 --- a/back/auth_utils.py +++ b/back/auth_utils.py @@ -1,54 +1,55 @@ from datetime import datetime, timedelta from typing import Annotated, Union +import os from fastapi import Depends, HTTPException, status from fastapi.security import OAuth2PasswordBearer from jose import JWTError, jwt from passlib.context import CryptContext +from sqlalchemy import select from sqlalchemy.orm import Session +from sqlalchemy.ext.asyncio import AsyncSession +from dotenv import load_dotenv -from .db import database +from .db import SessionLocal from . import orm_models, pydantic_schemas - -SECRET_KEY = "651a52941cf5de14d48ef5d7af115709" -ALGORITHM = "HS256" -ACCESS_TOKEN_EXPIRE_MINUTES = 1440 +load_dotenv("unimportant.env") +SECRET_KEY = os.getenv("SECRET_KEY") +ALGORITHM = os.getenv("ALGORITHM") +ACCESS_TOKEN_EXPIRE_MINUTES = os.getenv("ACCESS_TOKEN_EXPIRE_MINUTES") pwd_context = CryptContext(schemes=["bcrypt"], deprecated="auto") oauth2_scheme = OAuth2PasswordBearer(tokenUrl="/api/token") -def get_db(): - db = database - try: - yield db - finally: - db.close() +async def get_session() -> AsyncSession: + async with SessionLocal() as session: + yield session -def verify_password(plain_password, hashed_password): +async def verify_password(plain_password, hashed_password): return pwd_context.verify(plain_password, hashed_password) -def get_password_hash(password): +async def get_password_hash(password): return pwd_context.hash(password) -def get_user_by_nickname(db: Annotated[Session, Depends(get_db)], nickname: str): - user_with_required_id = db.query(orm_models.User).filter(orm_models.User.nickname == nickname).first() +async def get_user_by_nickname(db: Annotated[AsyncSession, Depends(get_session)], nickname: str): + user_with_required_id = db.select(orm_models.User).where(orm_models.User.nickname == nickname).first() if user_with_required_id: return user_with_required_id return None -def get_user_by_id(db: Annotated[Session, Depends(get_db)], user_id: int): - user_with_required_id = db.query(orm_models.User).filter(orm_models.User.id == user_id).first() +async def get_user_by_id(db: Annotated[AsyncSession, Depends(get_session)], user_id: int): + user_with_required_id = db.select(orm_models.User).where(orm_models.User.id == user_id).first() if user_with_required_id: return user_with_required_id return None -def authenticate_user(db: Annotated[Session, Depends(get_db)], nickname: str, password: str): +async def authenticate_user(db: Annotated[AsyncSession, Depends(get_session)], nickname: str, password: str): user = get_user_by_nickname(db=db, nickname=nickname) if not user: return False @@ -57,7 +58,7 @@ def authenticate_user(db: Annotated[Session, Depends(get_db)], nickname: str, pa return user -def create_access_token(data: dict, expires_delta: Union[timedelta, None] = None): +async def create_access_token(data: dict, expires_delta: Union[timedelta, None] = None): to_encode = data.copy() if expires_delta: expire = datetime.utcnow() + expires_delta @@ -68,7 +69,7 @@ def create_access_token(data: dict, expires_delta: Union[timedelta, None] = None 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[AsyncSession, Depends(get_session)], token: Annotated[str, Depends(oauth2_scheme)]): credentials_exception = HTTPException( status_code=status.HTTP_401_UNAUTHORIZED, detail="Could not validate credentials", diff --git a/back/db.py b/back/db.py index 12d83a7..a2a3b41 100644 --- a/back/db.py +++ b/back/db.py @@ -1,32 +1,21 @@ -from typing import AsyncGenerator - -from sqlalchemy import create_engine, MetaData -# from sqlalchemy.ext.asyncio import AsyncSession, async_sessionmaker, create_async_engine -from sqlalchemy.orm import sessionmaker, DeclarativeBase +from asyncio import current_task +from sqlalchemy.ext.asyncio import AsyncSession, async_scoped_session, create_async_engine +from sqlalchemy.orm import sessionmaker from sqlalchemy.ext.declarative import declarative_base -SQLALCHEMY_DATABASE_URL = "sqlite:///./sql_app.db" +SQLALCHEMY_DATABASE_URL = 'postgresql+asyncpg://postgres:D560c34V112Ak@localhost/porridger' -engine = create_engine( - SQLALCHEMY_DATABASE_URL, connect_args={"check_same_thread": False} -) +engine = create_async_engine(SQLALCHEMY_DATABASE_URL, echo=True) -SessionLocal = sessionmaker(bind=engine, autoflush=True, autocommit=False) +SessionLocal = sessionmaker(bind=engine, class_=AsyncSession, expire_on_commit=False) -database = SessionLocal() +async_session = async_scoped_session(SessionLocal, scopefunc=current_task) Base = declarative_base() -# # add your model's MetaData object here -# # for 'autogenerate' support -# # in your application's model: - -# class Base(DeclarativeBase): -# metadata = MetaData(naming_convention={ -# "ix": "ix_%(column_0_label)s", -# "uq": "uq_%(table_name)s_%(column_0_name)s", -# "ck": "ck_%(table_name)s_`%(constraint_name)s`", -# "fk": "fk_%(table_name)s_%(column_0_name)s_%(referred_table_name)s", -# "pk": "pk_%(table_name)s" -# }) \ No newline at end of file +# Создаем таблицы +async def init_models(): + async with engine.begin() as conn: + await conn.run_sync(Base.metadata.drop_all) + await conn.run_sync(Base.metadata.create_all) \ No newline at end of file diff --git a/back/delete_db.py b/back/delete_db.py new file mode 100644 index 0000000..5b22d85 --- /dev/null +++ b/back/delete_db.py @@ -0,0 +1,6 @@ +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() diff --git a/back/orm_models.py b/back/orm_models.py index 1e807f9..c866d6f 100644 --- a/back/orm_models.py +++ b/back/orm_models.py @@ -66,24 +66,3 @@ class Poems(Base):#класс поэзии author = Column(String) # автор стихотворения -# Создаем описанные выше таблицы -Base.metadata.create_all(bind=engine) - - - -# from typing import AsyncGenerator -# from sqlalchemy.ext.asyncio import AsyncSession, async_sessionmaker, create_async_engine -# from fastapi_users.db import SQLAlchemyBaseUserTableUUID, SQLAlchemyUserDatabase -# # This function can be called during the initialization of the FastAPI app. -# async def create_db_and_tables(): -# async with engine.begin() as conn: -# await conn.run_sync(Base.metadata.create_all) - - -# async def get_async_session() -> AsyncGenerator[AsyncSession, None]: -# async with async_session_maker() as session: -# yield session - - -# async def get_user_db(session: AsyncSession = Depends(get_async_session)): -# yield SQLAlchemyUserDatabase(session, User) \ No newline at end of file diff --git a/back/scheduler.py b/back/scheduler.py index deb1b92..0ec340d 100644 --- a/back/scheduler.py +++ b/back/scheduler.py @@ -7,7 +7,7 @@ from .db import database app = Rocketry(execution="async") # Create task: -@app.task('daily') +@app.task('minutely') async def daily_check(): # Фильтруем по сроку годности add_poems_and_filters.check_obsolete(database, current_date=datetime.date.today()) diff --git a/back/unimportant.env b/back/unimportant.env index 3e418f7..419962b 100644 --- a/back/unimportant.env +++ b/back/unimportant.env @@ -1,2 +1,5 @@ TOKEN = "eyJhbGciOiJSUzI1NiIsInR5cCIgOiAiSldUIiwia2lkIiA6ICJhU1RaZm42bHpTdURYcUttRkg1SzN5UDFhT0FxUkhTNm9OendMUExaTXhFIn0.eyJleHAiOjE3ODYyMjUzMzMsImlhdCI6MTY5MTUzMDkzMywianRpIjoiYjU0MmU3MTQtYzJkMS00NTY2LWJkY2MtYmQ5NzA0ODY1ZjgzIiwiaXNzIjoiaHR0cHM6Ly9rYy5wZXRlcnNidXJnLnJ1L3JlYWxtcy9lZ3MtYXBpIiwiYXVkIjoiYWNjb3VudCIsInN1YiI6ImJjYjQ2NzljLTU3ZGItNDU5ZC1iNWUxLWRlOGI4Yzg5MTMwMyIsInR5cCI6IkJlYXJlciIsImF6cCI6ImFkbWluLXJlc3QtY2xpZW50Iiwic2Vzc2lvbl9zdGF0ZSI6IjJhOTgwMzUyLTY1M2QtNGZlZC1iMDI1LWQ1N2U0NDRjZmM3NiIsImFjciI6IjEiLCJhbGxvd2VkLW9yaWdpbnMiOlsiLyoiXSwicmVhbG1fYWNjZXNzIjp7InJvbGVzIjpbImRlZmF1bHQtcm9sZXMtZWdzLWFwaSIsIm9mZmxpbmVfYWNjZXNzIiwidW1hX2F1dGhvcml6YXRpb24iXX0sInJlc291cmNlX2FjY2VzcyI6eyJhY2NvdW50Ijp7InJvbGVzIjpbIm1hbmFnZS1hY2NvdW50IiwibWFuYWdlLWFjY291bnQtbGlua3MiLCJ2aWV3LXByb2ZpbGUiXX19LCJzY29wZSI6ImVtYWlsIHByb2ZpbGUiLCJzaWQiOiIyYTk4MDM1Mi02NTNkLTRmZWQtYjAyNS1kNTdlNDQ0Y2ZjNzYiLCJlbWFpbF92ZXJpZmllZCI6ZmFsc2UsIm5hbWUiOiLQktC70LDQtNC40LzQuNGAINCv0LrQvtCy0LvQtdCyIiwicHJlZmVycmVkX3VzZXJuYW1lIjoiZTBmYzc2OGRhOTA4MjNiODgwZGQzOGVhMDJjMmQ5NTciLCJnaXZlbl9uYW1lIjoi0JLQu9Cw0LTQuNC80LjRgCIsImZhbWlseV9uYW1lIjoi0K_QutC-0LLQu9C10LIifQ.FTKiC1hpWcOkmSW9QZpC-RY7Ko50jw1mDMfXIWYxlQ-zehLm2CLmOnHvYoOoI39k2OzeCIAB9ZdRrrGZc6G9Z1eFELUjNGEqKxSC1Phj9ATemKgbOKEttk-OGc-rFr9VPA8_SnfvLts6wTI2YK33YBIxCF5nCbnr4Qj3LeEQ0d6Hy8PO4ATrBF5EOeuAZRprvIEjXe_f8N9ONKckCPB-xFB4P2pZlVXGoCNoewGEcY3zXH4khezN6zcVr6tpc6G8dBv9EqT_v92IDSg-aXQk6ysA0cO0-6x5w1-_qU0iHGIAPsLNV9IKBoFbjc0JH6cWabldPRH12NP1trvYfqKDGQ" -DOMAIN = "https://geointelect2.gate.petersburg.ru" \ No newline at end of file +DOMAIN = "https://geointelect2.gate.petersburg.ru" +SECRET_KEY = "651a52941cf5de14d48ef5d7af115709" +ALGORITHM = "HS256" +ACCESS_TOKEN_EXPIRE_MINUTES = 1440 \ No newline at end of file From 30cce3608ae05cb92f72a88d322ad68fbd89cc5c Mon Sep 17 00:00:00 2001 From: DmitryGantimurov Date: Thu, 31 Aug 2023 19:22:16 +0300 Subject: [PATCH 02/23] begin implementing async --- back/api.py | 1 - 1 file changed, 1 deletion(-) diff --git a/back/api.py b/back/api.py index 9fa745b..44bebba 100644 --- a/back/api.py +++ b/back/api.py @@ -30,7 +30,6 @@ app = FastAPI() # Jinja2 - шаблоны templates = Jinja2Templates(directory="./front/dist") - # хранение картинок для стихов app.mount("/poem_pic", StaticFiles(directory = "./poem_pic")) # создаем эндпоинт для хранения статических файлов From c43814ccd4777d9eb94abcf0d1c657bd95053f49 Mon Sep 17 00:00:00 2001 From: MatManSky Date: Thu, 31 Aug 2023 21:05:38 +0300 Subject: [PATCH 03/23] =?UTF-8?q?=D0=9D=D0=B0=D1=80=D0=B0=D0=B1=D0=BE?= =?UTF-8?q?=D1=82=D0=BA=D0=B8=20=D0=B2=D0=BE=D0=B2=D1=8B=20=D0=B8=20=D0=B4?= =?UTF-8?q?=D0=B8=D0=BC=D1=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- back/add_poems_and_filters.py | 16 ++++----- back/api.py | 61 ++++++++++++++++++++--------------- 2 files changed, 43 insertions(+), 34 deletions(-) diff --git a/back/add_poems_and_filters.py b/back/add_poems_and_filters.py index cdeee8a..2a9910f 100644 --- a/back/add_poems_and_filters.py +++ b/back/add_poems_and_filters.py @@ -1,6 +1,7 @@ from sqlalchemy.orm import Session from typing import Annotated from fastapi import Depends +from sqlalchemy import select from . import auth_utils, orm_models, pydantic_schemas import datetime @@ -11,7 +12,7 @@ BASE_URL='https://geointelect2.gate.petersburg.ru'#адрес сайта и мо my_token='eyJhbGciOiJSUzI1NiIsInR5cCIgOiAiSldUIiwia2lkIiA6ICJhU1RaZm42bHpTdURYcUttRkg1SzN5UDFhT0FxUkhTNm9OendMUExaTXhFIn0.eyJleHAiOjE3ODM3ODk4NjgsImlhdCI6MTY4OTA5NTQ2OCwianRpIjoiNDUzNjQzZTgtYTkyMi00NTI4LWIzYmMtYWJiYTNmYjkyNTkxIiwiaXNzIjoiaHR0cHM6Ly9rYy5wZXRlcnNidXJnLnJ1L3JlYWxtcy9lZ3MtYXBpIiwiYXVkIjoiYWNjb3VudCIsInN1YiI6ImJjYjQ2NzljLTU3ZGItNDU5ZC1iNWUxLWRlOGI4Yzg5MTMwMyIsInR5cCI6IkJlYXJlciIsImF6cCI6ImFkbWluLXJlc3QtY2xpZW50Iiwic2Vzc2lvbl9zdGF0ZSI6ImM2ZDJiOTZhLWMxNjMtNDAxZS05ZjMzLTI0MmE0NDcxMDY5OCIsImFjciI6IjEiLCJhbGxvd2VkLW9yaWdpbnMiOlsiLyoiXSwicmVhbG1fYWNjZXNzIjp7InJvbGVzIjpbImRlZmF1bHQtcm9sZXMtZWdzLWFwaSIsIm9mZmxpbmVfYWNjZXNzIiwidW1hX2F1dGhvcml6YXRpb24iXX0sInJlc291cmNlX2FjY2VzcyI6eyJhY2NvdW50Ijp7InJvbGVzIjpbIm1hbmFnZS1hY2NvdW50IiwibWFuYWdlLWFjY291bnQtbGlua3MiLCJ2aWV3LXByb2ZpbGUiXX19LCJzY29wZSI6ImVtYWlsIHByb2ZpbGUiLCJzaWQiOiJjNmQyYjk2YS1jMTYzLTQwMWUtOWYzMy0yNDJhNDQ3MTA2OTgiLCJlbWFpbF92ZXJpZmllZCI6ZmFsc2UsIm5hbWUiOiLQktC70LDQtNC40LzQuNGAINCv0LrQvtCy0LvQtdCyIiwicHJlZmVycmVkX3VzZXJuYW1lIjoiZTBmYzc2OGRhOTA4MjNiODgwZGQzOGVhMDJjMmQ5NTciLCJnaXZlbl9uYW1lIjoi0JLQu9Cw0LTQuNC80LjRgCIsImZhbWlseV9uYW1lIjoi0K_QutC-0LLQu9C10LIifQ.E2bW0B-c6W5Lj63eP_G8eI453NlDMnW05l11TZT0GSsAtGayXGaolHtWrmI90D5Yxz7v9FGkkCmcUZYy1ywAdO9dDt_XrtFEJWFpG-3csavuMjXmqfQQ9SmPwDw-3toO64NuZVv6qVqoUlPPj57sLx4bLtVbB4pdqgyJYcrDHg7sgwz4d1Z3tAeUfSpum9s5ZfELequfpLoZMXn6CaYZhePaoK-CxeU3KPBPTPOVPKZZ19s7QY10VdkxLULknqf9opdvLs4j8NMimtwoIiHNBFlgQz10Cr7bhDKWugfvSRsICouniIiBJo76wrj5T92s-ztf1FShJuqnQcKE_QLd2A' # Загружаем стихи -def add_poems_to_db(db: Session): +async def add_poems_to_db(db: Session): f1 = open('text121.txt', encoding='utf-8', mode='r')#открыть фаил для чтения на русском for a in range(1, 110): f1.seek(0)#перейти к началу @@ -42,10 +43,9 @@ def add_poems_to_db(db: Session): # close the file f1.close() - -def filter_ann(schema: pydantic_schemas.SortAnnouncements, db: Annotated[Session, Depends(auth_utils.get_session)]): +async def filter_ann(schema: pydantic_schemas.SortAnnouncements, db: Annotated[Session, Depends(auth_utils.get_session)]): """Функция для последовательного применения различных фильтров (через схему SortAnnouncements)""" - res = db.query(orm_models.Announcement) + res = await db.execute(select(orm_models.Announcement)).scalars().all() fields = schema.__dict__ # параметры передоваемой схемы SortAnnouncements (ключи и значения) # проходим по названиям фильтров и их значениям for name, filt in fields.items(): @@ -53,17 +53,17 @@ def filter_ann(schema: pydantic_schemas.SortAnnouncements, db: Annotated[Session if filt is not None: d = {name: filt} # фильтруем - res = res.filter_by(**d) + res = await res.filter_by(**d) # возвращаем все подходящие объявления - return res.all() + await res.all() -def check_obsolete(db: Annotated[Session, Depends(auth_utils.get_session)], current_date: datetime.date): +async def check_obsolete(db: Annotated[Session, Depends(auth_utils.get_session)], current_date: datetime.date): """ Функция участвует в процессе обновления поля obsolete у всех объявлений раз в сутки """ # обращаемся ко всем объявлениям бд - announcements = db.query(orm_models.Announcement).all() + announcements = await db.execute(select(orm_models.Announcement)).scalars().all() # для каждого объявления for ann in announcements: # если просрочено diff --git a/back/api.py b/back/api.py index 44bebba..e3440e8 100644 --- a/back/api.py +++ b/back/api.py @@ -10,6 +10,7 @@ from fastapi.requests import Request from typing import Any, Annotated, List, Union from starlette.staticfiles import StaticFiles from sqlalchemy.orm import Session +from sqlalchemy import select import requests from uuid import uuid4 @@ -48,9 +49,9 @@ async def announcements_list(db: Annotated[Session, Depends(auth_utils.get_sessi # параметры для сортировки (схема pydantic schemas.SortAnnouncements) params_to_sort = pydantic_schemas.SortAnnouncements(obsolete=obsolete, user_id=user_id, metro=metro, category=category) # получаем результат - result = add_poems_and_filters.filter_ann(db=db, schema=params_to_sort) + result = await add_poems_and_filters.filter_ann(db=db, schema=params_to_sort) - return result + await result # получаем данные одного объявления @@ -60,9 +61,10 @@ async def single_announcement(ann_id:int, db: Annotated[Session, Depends(auth_ut # В последствии будем вставлять данные в html-форму try: announcement = db.get(orm_models.Announcement, ann_id) - return announcement + #announcement = await db.execute(select(orm_models.Announcement)).scalars().all() + await announcement except: - return {"Answer" : False} #если неуданый доступ, то сообщаем об этом + await {"Answer" : False} #если неуданый доступ, то сообщаем об этом # Занести объявление в базу данных @@ -95,9 +97,9 @@ async def put_in_db(name: Annotated[str, Form()], category: Annotated[str, Form( db.add(temp_ancmt) # добавляем в бд db.commit() # сохраняем изменения db.refresh(temp_ancmt) # обновляем состояние объекта - return {"Answer" : True} + await {"Answer" : True} except: - return {"Answer" : False} + await {"Answer" : False} # Удалить объявления из базы @@ -105,12 +107,13 @@ async def put_in_db(name: Annotated[str, Form()], category: Annotated[str, Form( async def delete_from_db(announcement: pydantic_schemas.DelAnnouncement, db: Annotated[Session, Depends(auth_utils.get_session)]): # функция удаления объекта из БД try: # находим объект с заданным id в бд - to_delete = db.query(orm_models.Announcement).filter(orm_models.Announcement.id==announcement.id).first() + #to_delete = db.query(orm_models.Announcement).filter(orm_models.Announcement.id==announcement.id).first() + to_delete = await db.execute(select(orm_models.Announcement)).scalars().filter(orm_models.Announcement.id==announcement.id).first() db.delete(to_delete) # удаление из БД db.commit() # сохраняем изменения - return {"Answer" : True} + await {"Answer" : True} except: - return {"Answer" : False} + await {"Answer" : False} # Забронировать объявление @@ -118,7 +121,8 @@ async def delete_from_db(announcement: pydantic_schemas.DelAnnouncement, db: Ann async def change_book_status(data: pydantic_schemas.Book, current_user: Annotated[pydantic_schemas.User, Depends(auth_utils.get_current_user)], db: Annotated[Session, Depends(auth_utils.get_session)]): # Находим объявление по данному id - announcement_to_change = db.query(orm_models.Announcement).filter(orm_models.Announcement.id == data.id).first() + #announcement_to_change = db.query(orm_models.Announcement).filter(orm_models.Announcement.id == data.id).first() + announcement_to_change = await db.execute(select(orm_models.Announcement).where(orm_models.Announcement.id == data.id)).scalars().first() # Проверяем, что объявление с данным id существует if not announcement_to_change: raise HTTPException(status_code=404, detail="Item not found") @@ -131,7 +135,7 @@ async def change_book_status(data: pydantic_schemas.Book, current_user: Annotate # фиксируем изменения в бд db.commit() db.refresh(announcement_to_change) - return {"Success": True} + await {"Success": True} # reginstration @@ -140,7 +144,8 @@ async def create_user(nickname: Annotated[str, Form()], password: Annotated[str, name: Annotated[str, Form()]=None, surname: Annotated[str, Form()]=None, avatar: Annotated[UploadFile, Form()]=None): # проверяем, что юзера с введенным никнеймом не существует в бд - if db.query(orm_models.User).filter(orm_models.User.nickname == nickname).first() == None: + #if db.query(orm_models.User).filter(orm_models.User.nickname == nickname).first() == None: + if await db.execute(select(orm_models.User).where(orm_models.User.nickname == nickname)).scalars().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()) @@ -148,8 +153,8 @@ async def create_user(nickname: Annotated[str, Form()], password: Annotated[str, db.add(new_user) db.commit() db.refresh(new_user) # обновляем состояние объекта - return {"Success": True} - return {"Success": False, "Message": "Пользователь с таким email уже зарегестрирован"} + await {"Success": True} + await {"Success": False, "Message": "Пользователь с таким email уже зарегестрирован"} # функция для генерации токена после успешного входа пользователя @@ -172,13 +177,13 @@ async def login_for_access_token( access_token = auth_utils.create_access_token( data={"user_id": user.id}, expires_delta=access_token_expires ) - return {"access_token":access_token} + await {"access_token":access_token} # получаем данные успешно вошедшего пользователя @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 + await current_user # изменяем рейтинг пользователя @@ -193,7 +198,7 @@ async def add_points(data: pydantic_schemas.AddRating, current_user: Annotated[p user.num_of_ratings += 1 db.commit() db.refresh(user) # обновляем состояние объекта - return {"Success": True} + await {"Success": True} # получаем рейтинг пользователя @@ -202,22 +207,25 @@ async def add_points(user_id: int, db: Annotated[Session, Depends(auth_utils.get user = auth_utils.get_user_by_id(db, user_id=user_id) if not user: raise HTTPException(status_code=404, detail="Item not found") - return {"rating": user.rating} + await {"rating": user.rating} # Отправляем стихи @app.get("/api/user/poem", response_model=pydantic_schemas.Poem) async def poems_to_front(db: Annotated[Session, Depends(auth_utils.get_session)]): - num_of_poems = db.query(orm_models.Poems).count() # определяем кол-во стихов в бд + #num_of_poems = db.query(orm_models.Poems).count() # определяем кол-во стихов в бд + num_of_poems = await db.execute(select(orm_models.Poems)).scalars().count() # определяем кол-во стихов в бд # если стихов в бд нет if num_of_poems < 1: add_poems_and_filters.add_poems_to_db(db) # добавляем поэмы в базу данных - num_of_poems = db.query(orm_models.Poems).count() # определяем кол-во стихов в бд + num_of_poems = await db.execute(select(orm_models.Poems)).scalars().count() # определяем кол-во стихов в бд + #num_of_poems = db.query(orm_models.Poems).count() # определяем кол-во стихов в бд rand_id = random.randint(1, num_of_poems) # генерируем номер стихотворения - poem = db.query(orm_models.Poems).filter(orm_models.Poems.id == rand_id).first() # находим стих в бд + #poem = db.query(orm_models.Poems).filter(orm_models.Poems.id == rand_id).first() # находим стих в бд + poem = await db.execute(select(orm_models.Poems).where(orm_models.Poems.id == rand_id)).scalars().first() # находим стих в бд if not poem: raise HTTPException(status_code=404, detail="Poem not found") - return poem + await poem @app.get("/api/trashbox", response_model=List[pydantic_schemas.TrashboxResponse]) @@ -271,12 +279,12 @@ async def get_trashboxes(data: pydantic_schemas.TrashboxRequest = Depends()):#к if a in temp_dict["Categories"] and temp_dict not in trashboxes: trashboxes.append(temp_dict) uniq_trashboxes = [pydantic_schemas.TrashboxResponse(**ast.literal_eval(el1)) for el1 in set([str(el2) for el2 in trashboxes])] - return uniq_trashboxes + await uniq_trashboxes @app.get("/{rest_of_path:path}") async def react_app(req: Request, rest_of_path: str): - return templates.TemplateResponse('index.html', { 'request': req }) + await templates.TemplateResponse('index.html', { 'request': req }) @app.post("/api/announcement/dispose") @@ -295,12 +303,13 @@ async def dispose(data: pydantic_schemas.DisposeRequest, current_user_schema: An db.add(new_trashox) # в соответствии с логикой api, после утилизации объявление пользователя удаляется # находим объявление с айди data.ann_id - ann_to_del = db.query(orm_models.Announcement).filter(orm_models.Announcement.id == data.ann_id).first() # находим стих в бд + #ann_to_del = db.query(orm_models.Announcement).filter(orm_models.Announcement.id == data.ann_id).first() # находим стих в бд + ann_to_del = await db.execute(select(orm_models.Announcement).where(orm_models.Announcement.id == data.ann_id)).scalars().first() # находим стих в бд if not ann_to_del: raise HTTPException(status_code=404, detail="Announcement not found") # удаляем объявление из бд db.delete(ann_to_del) db.commit() db.refresh(new_trashox) # обновляем состояние объекта - return {"Success": True} + await {"Success": True} From ee79b9d4c5bfb1d883ff72aa7734677d3593a453 Mon Sep 17 00:00:00 2001 From: MatManSky Date: Thu, 31 Aug 2023 21:08:23 +0300 Subject: [PATCH 04/23] =?UTF-8?q?=D0=BD=D0=B0=D1=80=D0=B0=D0=B1=D0=BE?= =?UTF-8?q?=D1=82=D0=BA=D0=B8=20=D0=92=D0=BE=D0=B2=D1=8B=20=D0=B8=20=D0=94?= =?UTF-8?q?=D0=B8=D0=BC=D1=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- back/db.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/back/db.py b/back/db.py index a2a3b41..5840936 100644 --- a/back/db.py +++ b/back/db.py @@ -4,8 +4,7 @@ from sqlalchemy.orm import sessionmaker from sqlalchemy.ext.declarative import declarative_base -SQLALCHEMY_DATABASE_URL = 'postgresql+asyncpg://postgres:D560c34V112Ak@localhost/porridger' - +SQLALCHEMY_DATABASE_URL = "sqlite+aiosqlite:///./sql_app.db" engine = create_async_engine(SQLALCHEMY_DATABASE_URL, echo=True) SessionLocal = sessionmaker(bind=engine, class_=AsyncSession, expire_on_commit=False) From 834b0f27bb288301dd633d693759db6081f02dc9 Mon Sep 17 00:00:00 2001 From: DmitryGantimurov Date: Thu, 31 Aug 2023 21:34:42 +0300 Subject: [PATCH 05/23] add_poems_to_db function made async type --- back/add_poems_and_filters.py | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/back/add_poems_and_filters.py b/back/add_poems_and_filters.py index cdeee8a..ad6d980 100644 --- a/back/add_poems_and_filters.py +++ b/back/add_poems_and_filters.py @@ -1,4 +1,5 @@ from sqlalchemy.orm import Session +from sqlalchemy.ext.asyncio import AsyncSession from typing import Annotated from fastapi import Depends from . import auth_utils, orm_models, pydantic_schemas @@ -11,7 +12,7 @@ BASE_URL='https://geointelect2.gate.petersburg.ru'#адрес сайта и мо my_token='eyJhbGciOiJSUzI1NiIsInR5cCIgOiAiSldUIiwia2lkIiA6ICJhU1RaZm42bHpTdURYcUttRkg1SzN5UDFhT0FxUkhTNm9OendMUExaTXhFIn0.eyJleHAiOjE3ODM3ODk4NjgsImlhdCI6MTY4OTA5NTQ2OCwianRpIjoiNDUzNjQzZTgtYTkyMi00NTI4LWIzYmMtYWJiYTNmYjkyNTkxIiwiaXNzIjoiaHR0cHM6Ly9rYy5wZXRlcnNidXJnLnJ1L3JlYWxtcy9lZ3MtYXBpIiwiYXVkIjoiYWNjb3VudCIsInN1YiI6ImJjYjQ2NzljLTU3ZGItNDU5ZC1iNWUxLWRlOGI4Yzg5MTMwMyIsInR5cCI6IkJlYXJlciIsImF6cCI6ImFkbWluLXJlc3QtY2xpZW50Iiwic2Vzc2lvbl9zdGF0ZSI6ImM2ZDJiOTZhLWMxNjMtNDAxZS05ZjMzLTI0MmE0NDcxMDY5OCIsImFjciI6IjEiLCJhbGxvd2VkLW9yaWdpbnMiOlsiLyoiXSwicmVhbG1fYWNjZXNzIjp7InJvbGVzIjpbImRlZmF1bHQtcm9sZXMtZWdzLWFwaSIsIm9mZmxpbmVfYWNjZXNzIiwidW1hX2F1dGhvcml6YXRpb24iXX0sInJlc291cmNlX2FjY2VzcyI6eyJhY2NvdW50Ijp7InJvbGVzIjpbIm1hbmFnZS1hY2NvdW50IiwibWFuYWdlLWFjY291bnQtbGlua3MiLCJ2aWV3LXByb2ZpbGUiXX19LCJzY29wZSI6ImVtYWlsIHByb2ZpbGUiLCJzaWQiOiJjNmQyYjk2YS1jMTYzLTQwMWUtOWYzMy0yNDJhNDQ3MTA2OTgiLCJlbWFpbF92ZXJpZmllZCI6ZmFsc2UsIm5hbWUiOiLQktC70LDQtNC40LzQuNGAINCv0LrQvtCy0LvQtdCyIiwicHJlZmVycmVkX3VzZXJuYW1lIjoiZTBmYzc2OGRhOTA4MjNiODgwZGQzOGVhMDJjMmQ5NTciLCJnaXZlbl9uYW1lIjoi0JLQu9Cw0LTQuNC80LjRgCIsImZhbWlseV9uYW1lIjoi0K_QutC-0LLQu9C10LIifQ.E2bW0B-c6W5Lj63eP_G8eI453NlDMnW05l11TZT0GSsAtGayXGaolHtWrmI90D5Yxz7v9FGkkCmcUZYy1ywAdO9dDt_XrtFEJWFpG-3csavuMjXmqfQQ9SmPwDw-3toO64NuZVv6qVqoUlPPj57sLx4bLtVbB4pdqgyJYcrDHg7sgwz4d1Z3tAeUfSpum9s5ZfELequfpLoZMXn6CaYZhePaoK-CxeU3KPBPTPOVPKZZ19s7QY10VdkxLULknqf9opdvLs4j8NMimtwoIiHNBFlgQz10Cr7bhDKWugfvSRsICouniIiBJo76wrj5T92s-ztf1FShJuqnQcKE_QLd2A' # Загружаем стихи -def add_poems_to_db(db: Session): +async def add_poems_to_db(async_db: AsyncSession): f1 = open('text121.txt', encoding='utf-8', mode='r')#открыть фаил для чтения на русском for a in range(1, 110): f1.seek(0)#перейти к началу @@ -34,16 +35,18 @@ def add_poems_to_db(db: Session): flag = True else: author += str1 - poem = orm_models.Poems(title=name, text=stixi, author=author) - # В конце каждой итерации добавляем в базу данных - db.add(poem) - db.commit() - # db.refresh(poem) + async with async_db() as session: + async with session.begin(): + poem = orm_models.Poems(title=name, text=stixi, author=author) + # В конце каждой итерации добавляем в базу данных + session.add(poem) + session.commit() + # close the file f1.close() -def filter_ann(schema: pydantic_schemas.SortAnnouncements, db: Annotated[Session, Depends(auth_utils.get_session)]): +async def filter_ann(schema: pydantic_schemas.SortAnnouncements, db: Annotated[Session, Depends(auth_utils.get_session)]): """Функция для последовательного применения различных фильтров (через схему SortAnnouncements)""" res = db.query(orm_models.Announcement) fields = schema.__dict__ # параметры передоваемой схемы SortAnnouncements (ключи и значения) From 4326c70dbc085c304fd250b6f7f9d1aeac411407 Mon Sep 17 00:00:00 2001 From: DmitryGantimurov Date: Thu, 31 Aug 2023 22:32:50 +0300 Subject: [PATCH 06/23] trying to make api work - 1 --- back/add_poems_and_filters.py | 8 +-- back/api.py | 104 ++++++++++++++++++---------------- back/auth_utils.py | 20 ++++--- back/db.py | 5 +- back/scheduler.py | 4 +- 5 files changed, 75 insertions(+), 66 deletions(-) diff --git a/back/add_poems_and_filters.py b/back/add_poems_and_filters.py index c29d6c3..9c90f7b 100644 --- a/back/add_poems_and_filters.py +++ b/back/add_poems_and_filters.py @@ -46,7 +46,7 @@ async def add_poems_to_db(async_db: AsyncSession): # close the file f1.close() -async def filter_ann(schema: pydantic_schemas.SortAnnouncements, db: Annotated[Session, Depends(auth_utils.get_session)]): +async def filter_ann(schema: pydantic_schemas.SortAnnouncements, db: AsyncSession): """Функция для последовательного применения различных фильтров (через схему SortAnnouncements)""" res = await db.execute(select(orm_models.Announcement)).scalars().all() fields = schema.__dict__ # параметры передоваемой схемы SortAnnouncements (ключи и значения) @@ -61,7 +61,7 @@ async def filter_ann(schema: pydantic_schemas.SortAnnouncements, db: Annotated[S await res.all() -async def check_obsolete(db: Annotated[Session, Depends(auth_utils.get_session)], current_date: datetime.date): +async def check_obsolete(db: AsyncSession, current_date: datetime.date): """ Функция участвует в процессе обновления поля obsolete у всех объявлений раз в сутки """ @@ -72,7 +72,7 @@ async def check_obsolete(db: Annotated[Session, Depends(auth_utils.get_session)] # если просрочено if ann.best_by < current_date: ann.obsolete = True - db.commit() - db.refresh(ann) # обновляем состояние объекта + await db.commit() + await db.refresh(ann) # обновляем состояние объекта diff --git a/back/api.py b/back/api.py index e3440e8..6ee2dcf 100644 --- a/back/api.py +++ b/back/api.py @@ -51,7 +51,7 @@ async def announcements_list(db: Annotated[Session, Depends(auth_utils.get_sessi # получаем результат result = await add_poems_and_filters.filter_ann(db=db, schema=params_to_sort) - await result + return result # получаем данные одного объявления @@ -60,11 +60,11 @@ async def single_announcement(ann_id:int, db: Annotated[Session, Depends(auth_ut # Считываем данные из Body и отображаем их на странице. # В последствии будем вставлять данные в html-форму try: - announcement = db.get(orm_models.Announcement, ann_id) + announcement = await db.get(orm_models.Announcement, ann_id) #announcement = await db.execute(select(orm_models.Announcement)).scalars().all() - await announcement + return announcement except: - await {"Answer" : False} #если неуданый доступ, то сообщаем об этом + return {"Answer" : False} #если неуданый доступ, то сообщаем об этом # Занести объявление в базу данных @@ -84,7 +84,7 @@ async def put_in_db(name: Annotated[str, Form()], category: Annotated[str, Form( if f.tell() > 0: f.seek(0) destination = pathlib.Path("./uploads/" + str(hash(f)) + pathlib.Path(src.filename).suffix.lower()) - with destination.open('wb') as buffer: + async with destination.open('wb') as buffer: shutil.copyfileobj(f, buffer) # изменяем название директории загруженного файла @@ -94,12 +94,12 @@ async def put_in_db(name: Annotated[str, Form()], category: Annotated[str, Form( 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, trashId=trashId, src=uploaded_name, booked_by=0) - db.add(temp_ancmt) # добавляем в бд - db.commit() # сохраняем изменения - db.refresh(temp_ancmt) # обновляем состояние объекта - await {"Answer" : True} + await db.add(temp_ancmt) # добавляем в бд + await db.commit() # сохраняем изменения + await db.refresh(temp_ancmt) # обновляем состояние объекта + return {"Answer" : True} except: - await {"Answer" : False} + return {"Answer" : False} # Удалить объявления из базы @@ -108,12 +108,13 @@ async def delete_from_db(announcement: pydantic_schemas.DelAnnouncement, db: Ann try: # находим объект с заданным id в бд #to_delete = db.query(orm_models.Announcement).filter(orm_models.Announcement.id==announcement.id).first() - to_delete = await db.execute(select(orm_models.Announcement)).scalars().filter(orm_models.Announcement.id==announcement.id).first() - db.delete(to_delete) # удаление из БД - db.commit() # сохраняем изменения - await {"Answer" : True} + query = await db.execute(select(orm_models.Announcement).where(orm_models.Announcement.id==announcement.id)) + to_delete = query.scalars().first() + await db.delete(to_delete) # удаление из БД + await db.commit() # сохраняем изменения + return {"Answer" : True} except: - await {"Answer" : False} + return {"Answer" : False} # Забронировать объявление @@ -122,7 +123,8 @@ async def change_book_status(data: pydantic_schemas.Book, current_user: Annotate db: Annotated[Session, Depends(auth_utils.get_session)]): # Находим объявление по данному id #announcement_to_change = db.query(orm_models.Announcement).filter(orm_models.Announcement.id == data.id).first() - announcement_to_change = await db.execute(select(orm_models.Announcement).where(orm_models.Announcement.id == data.id)).scalars().first() + query = await db.execute(select(orm_models.Announcement).where(orm_models.Announcement.id == data.id)) + announcement_to_change = query.scalars().first() # Проверяем, что объявление с данным id существует if not announcement_to_change: raise HTTPException(status_code=404, detail="Item not found") @@ -133,9 +135,9 @@ async def change_book_status(data: pydantic_schemas.Book, current_user: Annotate # Инкрементируем поле booked_by на 1 announcement_to_change.booked_by += 1 # фиксируем изменения в бд - db.commit() - db.refresh(announcement_to_change) - await {"Success": True} + await db.commit() + await db.refresh(announcement_to_change) + return {"Success": True} # reginstration @@ -145,16 +147,18 @@ async def create_user(nickname: Annotated[str, Form()], password: Annotated[str, # проверяем, что юзера с введенным никнеймом не существует в бд #if db.query(orm_models.User).filter(orm_models.User.nickname == nickname).first() == None: - if await db.execute(select(orm_models.User).where(orm_models.User.nickname == nickname)).scalars().first() == None: + query_user = await db.execute(select(orm_models.User).where(orm_models.User.nickname == nickname)) + user_with_entered_nick = query_user.scalars().first() + if user_with_entered_nick == 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()) # добавляем в бд - db.add(new_user) - db.commit() - db.refresh(new_user) # обновляем состояние объекта - await {"Success": True} - await {"Success": False, "Message": "Пользователь с таким email уже зарегестрирован"} + await db.add(new_user) + await db.commit() + await db.refresh(new_user) # обновляем состояние объекта + return {"Success": True} + return {"Success": False, "Message": "Пользователь с таким email уже зарегестрирован"} # функция для генерации токена после успешного входа пользователя @@ -163,7 +167,7 @@ async def login_for_access_token( form_data: Annotated[OAuth2PasswordRequestForm, Depends()], db: Annotated[Session, Depends(auth_utils.get_session)] ): # пробуем найти юзера в бд по введенным паролю и никнейму - user = auth_utils.authenticate_user(db, form_data.username, form_data.password) + user = await auth_utils.authenticate_user(db, form_data.username, form_data.password) # если не нашли - кидаем ошибку if not user: raise HTTPException( @@ -172,18 +176,18 @@ async def login_for_access_token( headers={"WWW-Authenticate": "Bearer"}, ) # задаем временной интервал, в течение которого токен можно использовать - access_token_expires = auth_utils.timedelta(minutes=auth_utils.ACCESS_TOKEN_EXPIRE_MINUTES) + access_token_expires = await auth_utils.timedelta(minutes=auth_utils.ACCESS_TOKEN_EXPIRE_MINUTES) # создаем токен - access_token = auth_utils.create_access_token( + access_token = await auth_utils.create_access_token( data={"user_id": user.id}, expires_delta=access_token_expires ) - await {"access_token":access_token} + return {"access_token":access_token} # получаем данные успешно вошедшего пользователя @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)]): - await current_user + return current_user # изменяем рейтинг пользователя @@ -191,23 +195,23 @@ async def read_users_me(current_user: Annotated[pydantic_schemas.User, Depends(a async 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_session)]): # проверяем, if current_user.id != data.user_id: - user = auth_utils.get_user_by_id(db, data.user_id) + user = await auth_utils.get_user_by_id(db, data.user_id) if not user: 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.num_of_ratings += 1 - db.commit() - db.refresh(user) # обновляем состояние объекта - await {"Success": True} + await db.commit() + await db.refresh(user) # обновляем состояние объекта + return {"Success": True} # получаем рейтинг пользователя @app.get("/api/user/rating") async def add_points(user_id: int, db: Annotated[Session, Depends(auth_utils.get_session)]): - user = auth_utils.get_user_by_id(db, user_id=user_id) + user = await auth_utils.get_user_by_id(db, user_id=user_id) if not user: raise HTTPException(status_code=404, detail="Item not found") - await {"rating": user.rating} + return {"rating": user.rating} # Отправляем стихи @@ -222,10 +226,11 @@ async def poems_to_front(db: Annotated[Session, Depends(auth_utils.get_session)] #num_of_poems = db.query(orm_models.Poems).count() # определяем кол-во стихов в бд rand_id = random.randint(1, num_of_poems) # генерируем номер стихотворения #poem = db.query(orm_models.Poems).filter(orm_models.Poems.id == rand_id).first() # находим стих в бд - poem = await db.execute(select(orm_models.Poems).where(orm_models.Poems.id == rand_id)).scalars().first() # находим стих в бд + query_poem = await db.execute(select(orm_models.Poems).where(orm_models.Poems.id == rand_id)) # находим стих в бд + poem = query_poem.scalars().first() if not poem: raise HTTPException(status_code=404, detail="Poem not found") - await poem + return poem @app.get("/api/trashbox", response_model=List[pydantic_schemas.TrashboxResponse]) @@ -260,7 +265,7 @@ async def get_trashboxes(data: pydantic_schemas.TrashboxRequest = Depends()):#к list_of_category = ["Металл", "Бумага", "Стекло", "Иное", "Тетра Пак", "Батарейки", "Крышечки", "Шины", "Опасные отходы", "Лампочки", "Пластик"] # Получение ответа от стороннего апи - response = requests.post(f"{BASE_URL}/nearest_recycling/get", headers=head, data=my_data, timeout=10) + response = await requests.post(f"{BASE_URL}/nearest_recycling/get", headers=head, data=my_data, timeout=10) infos = response.json() # Чтение ответа trashboxes = [] @@ -278,8 +283,8 @@ async def get_trashboxes(data: pydantic_schemas.TrashboxRequest = Depends()):#к for a in list_of_category: if a in temp_dict["Categories"] and temp_dict not in trashboxes: trashboxes.append(temp_dict) - uniq_trashboxes = [pydantic_schemas.TrashboxResponse(**ast.literal_eval(el1)) for el1 in set([str(el2) for el2 in trashboxes])] - await uniq_trashboxes + uniq_trashboxes = await [pydantic_schemas.TrashboxResponse(**ast.literal_eval(el1)) for el1 in set([str(el2) for el2 in trashboxes])] + return uniq_trashboxes @app.get("/{rest_of_path:path}") @@ -291,7 +296,7 @@ async def react_app(req: Request, rest_of_path: str): async def dispose(data: pydantic_schemas.DisposeRequest, current_user_schema: Annotated[pydantic_schemas.User, Depends(auth_utils.get_current_user)], db: Annotated[Session, Depends(auth_utils.get_session)]): # Находим в бд текущего юзера - current_user = auth_utils.get_user_by_id(db, current_user_schema.id) + current_user = await auth_utils.get_user_by_id(db, current_user_schema.id) # Начисляем баллы пользователю за утилизацию current_user.points += 60 # В полученном json переходим к данным мусорки @@ -300,16 +305,17 @@ async def dispose(data: pydantic_schemas.DisposeRequest, current_user_schema: An 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) # добавляем в бд - db.add(new_trashox) + await db.add(new_trashox) # в соответствии с логикой api, после утилизации объявление пользователя удаляется # находим объявление с айди data.ann_id - #ann_to_del = db.query(orm_models.Announcement).filter(orm_models.Announcement.id == data.ann_id).first() # находим стих в бд - ann_to_del = await db.execute(select(orm_models.Announcement).where(orm_models.Announcement.id == data.ann_id)).scalars().first() # находим стих в бд + #ann_to_del = db.query(orm_models.Announcement).filter(orm_models.Announcement.id == data.ann_id).first() # + query_ann = await db.execute(select(orm_models.Announcement).where(orm_models.Announcement.id == data.ann_id)) # находим объявление в бд + ann_to_del = query_ann.scalars().first() if not ann_to_del: raise HTTPException(status_code=404, detail="Announcement not found") # удаляем объявление из бд - db.delete(ann_to_del) - db.commit() - db.refresh(new_trashox) # обновляем состояние объекта - await {"Success": True} + await db.delete(ann_to_del) + await db.commit() + await db.refresh(new_trashox) # обновляем состояние объекта + return {"Success": True} diff --git a/back/auth_utils.py b/back/auth_utils.py index bf5d95e..e7678f8 100644 --- a/back/auth_utils.py +++ b/back/auth_utils.py @@ -36,21 +36,23 @@ async def get_password_hash(password): async def get_user_by_nickname(db: Annotated[AsyncSession, Depends(get_session)], nickname: str): - user_with_required_id = db.select(orm_models.User).where(orm_models.User.nickname == nickname).first() - if user_with_required_id: - return user_with_required_id + query = db.execute(select(orm_models.User).where(orm_models.User.nickname == nickname)) + user_with_required_nickname = query.scalars().first() + if user_with_required_nickname: + return user_with_required_nickname return None async def get_user_by_id(db: Annotated[AsyncSession, Depends(get_session)], user_id: int): - user_with_required_id = db.select(orm_models.User).where(orm_models.User.id == user_id).first() + query = db.execute(select(orm_models.User).where(orm_models.User.id == user_id)) + user_with_required_id = query.scalars().first() if user_with_required_id: return user_with_required_id return None async def authenticate_user(db: Annotated[AsyncSession, Depends(get_session)], nickname: str, password: str): - user = get_user_by_nickname(db=db, nickname=nickname) + user = await get_user_by_nickname(db=db, nickname=nickname) if not user: return False if not verify_password(password, user.hashed_password): @@ -65,7 +67,7 @@ async def create_access_token(data: dict, expires_delta: Union[timedelta, None] else: expire = datetime.utcnow() + timedelta(minutes=15) to_encode.update({"exp": expire}) - encoded_jwt = jwt.encode(to_encode, SECRET_KEY, algorithm=ALGORITHM) + encoded_jwt = await jwt.encode(to_encode, SECRET_KEY, algorithm=ALGORITHM) return encoded_jwt @@ -76,14 +78,14 @@ async def get_current_user(db: Annotated[AsyncSession, Depends(get_session)], to headers={"WWW-Authenticate": "Bearer"}, ) try: - payload = jwt.decode(token, SECRET_KEY, algorithms=[ALGORITHM]) - user_id: int = payload.get("user_id") + payload = await jwt.decode(token, SECRET_KEY, algorithms=[ALGORITHM]) + user_id: int = await payload.get("user_id") if user_id is None: raise credentials_exception token_data = pydantic_schemas.TokenData(user_id=user_id) except JWTError: raise credentials_exception - user = get_user_by_id(db, user_id=token_data.user_id) + user = await get_user_by_id(db, user_id=token_data.user_id) if user is None: raise credentials_exception return pydantic_schemas.User(id=user.id, nickname=user.nickname, name=user.name, surname=user.surname, diff --git a/back/db.py b/back/db.py index 5840936..c76508f 100644 --- a/back/db.py +++ b/back/db.py @@ -4,12 +4,13 @@ from sqlalchemy.orm import sessionmaker from sqlalchemy.ext.declarative import declarative_base -SQLALCHEMY_DATABASE_URL = "sqlite+aiosqlite:///./sql_app.db" +SQLALCHEMY_DATABASE_URL = "postgresql+asyncpg://postgres:D560c34V112Ak@localhost/porridger" engine = create_async_engine(SQLALCHEMY_DATABASE_URL, echo=True) SessionLocal = sessionmaker(bind=engine, class_=AsyncSession, expire_on_commit=False) -async_session = async_scoped_session(SessionLocal, scopefunc=current_task) +async_session = SessionLocal() +# async_session = async_scoped_session(SessionLocal, scopefunc=current_task) Base = declarative_base() diff --git a/back/scheduler.py b/back/scheduler.py index 0ec340d..cd44620 100644 --- a/back/scheduler.py +++ b/back/scheduler.py @@ -2,7 +2,7 @@ from . import add_poems_and_filters from rocketry import Rocketry from rocketry.conds import daily import datetime -from .db import database +from .db import async_session app = Rocketry(execution="async") @@ -10,5 +10,5 @@ app = Rocketry(execution="async") @app.task('minutely') async def daily_check(): # Фильтруем по сроку годности - add_poems_and_filters.check_obsolete(database, current_date=datetime.date.today()) + await add_poems_and_filters.check_obsolete(async_session, current_date=datetime.date.today()) From 2c870ee98333a87bdf34083d73b9e029fe184aa8 Mon Sep 17 00:00:00 2001 From: DmitryGantimurov Date: Thu, 31 Aug 2023 23:41:48 +0300 Subject: [PATCH 07/23] making async api - 2 --- back/add_poems_and_filters.py | 3 ++- back/api.py | 13 +++++++++++-- back/auth_utils.py | 21 ++++++++++++--------- back/db.py | 4 ++-- 4 files changed, 27 insertions(+), 14 deletions(-) diff --git a/back/add_poems_and_filters.py b/back/add_poems_and_filters.py index 9c90f7b..3cae199 100644 --- a/back/add_poems_and_filters.py +++ b/back/add_poems_and_filters.py @@ -48,7 +48,8 @@ async def add_poems_to_db(async_db: AsyncSession): async def filter_ann(schema: pydantic_schemas.SortAnnouncements, db: AsyncSession): """Функция для последовательного применения различных фильтров (через схему SortAnnouncements)""" - res = await db.execute(select(orm_models.Announcement)).scalars().all() + res = await db.execute(select(orm_models.Announcement)) + res = res.fetchall() fields = schema.__dict__ # параметры передоваемой схемы SortAnnouncements (ключи и значения) # проходим по названиям фильтров и их значениям for name, filt in fields.items(): diff --git a/back/api.py b/back/api.py index 6ee2dcf..307e55a 100644 --- a/back/api.py +++ b/back/api.py @@ -11,6 +11,7 @@ from typing import Any, Annotated, List, Union from starlette.staticfiles import StaticFiles from sqlalchemy.orm import Session from sqlalchemy import select +from dotenv import load_dotenv, dotenv_values import requests from uuid import uuid4 @@ -41,6 +42,14 @@ if not os.path.exists("./uploads"): # создаем эндпоинт для хранения файлов пользователя app.mount("/uploads", StaticFiles(directory = "./uploads")) +# load_dotenv("unimportant.env") +# ACCESS_TOKEN_EXPIRE_MINUTES = os.getenv("ACCESS_TOKEN_EXPIRE_MINUTES") +ACCESS_TOKEN_EXPIRE_MINUTES = 1440 + +# эндпоинт для возвращения согласия в pdf +@app.get("/privacy_policy.pdf") +async def privacy_policy(): + return FileResponse("privacy_policy.pdf") # получение списка объявлений @app.get("/api/announcements", response_model=List[pydantic_schemas.Announcement])#адрес объявлений @@ -176,7 +185,7 @@ async def login_for_access_token( headers={"WWW-Authenticate": "Bearer"}, ) # задаем временной интервал, в течение которого токен можно использовать - access_token_expires = await auth_utils.timedelta(minutes=auth_utils.ACCESS_TOKEN_EXPIRE_MINUTES) + access_token_expires = auth_utils.timedelta(minutes=auth_utils.ACCESS_TOKEN_EXPIRE_MINUTES) # создаем токен access_token = await auth_utils.create_access_token( data={"user_id": user.id}, expires_delta=access_token_expires @@ -289,7 +298,7 @@ async def get_trashboxes(data: pydantic_schemas.TrashboxRequest = Depends()):#к @app.get("/{rest_of_path:path}") async def react_app(req: Request, rest_of_path: str): - await templates.TemplateResponse('index.html', { 'request': req }) + return templates.TemplateResponse('index.html', { 'request': req }) @app.post("/api/announcement/dispose") diff --git a/back/auth_utils.py b/back/auth_utils.py index e7678f8..1fbdb6b 100644 --- a/back/auth_utils.py +++ b/back/auth_utils.py @@ -14,10 +14,13 @@ from dotenv import load_dotenv from .db import SessionLocal from . import orm_models, pydantic_schemas -load_dotenv("unimportant.env") -SECRET_KEY = os.getenv("SECRET_KEY") -ALGORITHM = os.getenv("ALGORITHM") -ACCESS_TOKEN_EXPIRE_MINUTES = os.getenv("ACCESS_TOKEN_EXPIRE_MINUTES") +# load_dotenv("unimportant.env") +# SECRET_KEY = os.getenv("SECRET_KEY") +# ALGORITHM = os.getenv("ALGORITHM") +# ACCESS_TOKEN_EXPIRE_MINUTES = os.getenv("ACCESS_TOKEN_EXPIRE_MINUTES") +ACCESS_TOKEN_EXPIRE_MINUTES = 1440 +SECRET_KEY = "651a52941cf5de14d48ef5d7af115709" +ALGORITHM = "HS256" pwd_context = CryptContext(schemes=["bcrypt"], deprecated="auto") oauth2_scheme = OAuth2PasswordBearer(tokenUrl="/api/token") @@ -36,7 +39,7 @@ async def get_password_hash(password): async def get_user_by_nickname(db: Annotated[AsyncSession, Depends(get_session)], nickname: str): - query = db.execute(select(orm_models.User).where(orm_models.User.nickname == nickname)) + query = await db.execute(select(orm_models.User).where(orm_models.User.nickname == nickname)) user_with_required_nickname = query.scalars().first() if user_with_required_nickname: return user_with_required_nickname @@ -44,7 +47,7 @@ async def get_user_by_nickname(db: Annotated[AsyncSession, Depends(get_session)] async def get_user_by_id(db: Annotated[AsyncSession, Depends(get_session)], user_id: int): - query = db.execute(select(orm_models.User).where(orm_models.User.id == user_id)) + query = await db.execute(select(orm_models.User).where(orm_models.User.id == user_id)) user_with_required_id = query.scalars().first() if user_with_required_id: return user_with_required_id @@ -67,7 +70,7 @@ async def create_access_token(data: dict, expires_delta: Union[timedelta, None] else: expire = datetime.utcnow() + timedelta(minutes=15) to_encode.update({"exp": expire}) - encoded_jwt = await jwt.encode(to_encode, SECRET_KEY, algorithm=ALGORITHM) + encoded_jwt = jwt.encode(to_encode, SECRET_KEY, algorithm=ALGORITHM) return encoded_jwt @@ -78,8 +81,8 @@ async def get_current_user(db: Annotated[AsyncSession, Depends(get_session)], to headers={"WWW-Authenticate": "Bearer"}, ) try: - payload = await jwt.decode(token, SECRET_KEY, algorithms=[ALGORITHM]) - user_id: int = await payload.get("user_id") + payload = jwt.decode(token, SECRET_KEY, algorithms=[ALGORITHM]) + user_id: int = payload.get("user_id") if user_id is None: raise credentials_exception token_data = pydantic_schemas.TokenData(user_id=user_id) diff --git a/back/db.py b/back/db.py index c76508f..048b539 100644 --- a/back/db.py +++ b/back/db.py @@ -3,8 +3,8 @@ from sqlalchemy.ext.asyncio import AsyncSession, async_scoped_session, create_as from sqlalchemy.orm import sessionmaker from sqlalchemy.ext.declarative import declarative_base - -SQLALCHEMY_DATABASE_URL = "postgresql+asyncpg://postgres:D560c34V112Ak@localhost/porridger" +SQLALCHEMY_DATABASE_URL = "sqlite+aiosqlite:///./sql_app.db" +# SQLALCHEMY_DATABASE_URL = "postgresql+asyncpg://postgres:D560c34V112Ak@localhost/porridger" engine = create_async_engine(SQLALCHEMY_DATABASE_URL, echo=True) SessionLocal = sessionmaker(bind=engine, class_=AsyncSession, expire_on_commit=False) From f744cce71321be6cd7d494238ca8b63978bb2f0d Mon Sep 17 00:00:00 2001 From: DmitryGantimurov Date: Sat, 2 Sep 2023 15:32:20 +0300 Subject: [PATCH 08/23] fixing ann_filters function --- back/add_poems_and_filters.py | 53 +++++++++++++++++++++++++++-------- 1 file changed, 41 insertions(+), 12 deletions(-) diff --git a/back/add_poems_and_filters.py b/back/add_poems_and_filters.py index 3cae199..ee92a0b 100644 --- a/back/add_poems_and_filters.py +++ b/back/add_poems_and_filters.py @@ -1,4 +1,5 @@ from sqlalchemy.orm import Session +from sqlalchemy.sql import text, literal_column from sqlalchemy.ext.asyncio import AsyncSession from typing import Annotated from fastapi import Depends @@ -48,18 +49,45 @@ async def add_poems_to_db(async_db: AsyncSession): async def filter_ann(schema: pydantic_schemas.SortAnnouncements, db: AsyncSession): """Функция для последовательного применения различных фильтров (через схему SortAnnouncements)""" - res = await db.execute(select(orm_models.Announcement)) - res = res.fetchall() - fields = schema.__dict__ # параметры передоваемой схемы SortAnnouncements (ключи и значения) - # проходим по названиям фильтров и их значениям - for name, filt in fields.items(): - # если фильтр задан - if filt is not None: - d = {name: filt} - # фильтруем - res = await res.filter_by(**d) + # fields = schema.__dict__ # параметры передоваемой схемы SortAnnouncements (ключи и значения) + # # проходим по названиям фильтров и их значениям + # for name, filt_val in fields.items(): + # # создаем выражение sql запроса + # statement = text("SELECT * FROM announcements ") + # # выбираем все строки + # query = await db.execute(statement) + # res = query.all() + # # если фильтр задан + # if filt_val is not None: + # to_intersect_query = await db.execute(select(orm_models.Announcement).where(literal_column(f"announcements.{name}") == filt_val)) + # to_intersect = to_intersect_query.all() + # res = res.intersect(to_intersect) + + # отфильтровываем подходящие объявления + res = await db.execute(select(orm_models.Announcement) + .where(schema.obsolete != None and orm_models.Announcement.obsolete == schema.obsolete + and schema.user_id != None and orm_models.Announcement.user_id == schema.user_id + and schema.metro != None and orm_models.Announcement.metro == schema.metro + and ) + # .where(schema.user_id != None and orm_models.Announcement.user_id == schema.user_id) + # .where(schema.metro != None and orm_models.Announcement.metro == schema.metro) + # .where(schema.category != None and orm_models.Announcement.category == schema.category) + ) + # statement = text("SELECT * FROM announcements " + # "WHERE announcements.obsolete = :obsolete " + # "AND announcements.user_id == :user_id " + # "AND announcements.metro == :metro " + # "AND announcements.category == :category") + + # res = await db.execute(statement, + # {"obsolete": schema.obsolete, + # "user_id": schema.user_id, + # "metro": schema.metro, + # "category": schema.category} + # ) # возвращаем все подходящие объявления - await res.all() + + return res.scalars().all() async def check_obsolete(db: AsyncSession, current_date: datetime.date): @@ -67,7 +95,8 @@ async def check_obsolete(db: AsyncSession, current_date: datetime.date): Функция участвует в процессе обновления поля obsolete у всех объявлений раз в сутки """ # обращаемся ко всем объявлениям бд - announcements = await db.execute(select(orm_models.Announcement)).scalars().all() + query_announcements = await db.execute(select(orm_models.Announcement)) + announcements = query_announcements.scalars().all() # для каждого объявления for ann in announcements: # если просрочено From 37d219c516c76b4fe46b96bb2a8321b57d2bf3f8 Mon Sep 17 00:00:00 2001 From: DmitryGantimurov Date: Sat, 2 Sep 2023 19:04:30 +0300 Subject: [PATCH 09/23] filter_ann almost fixed --- back/add_poems_and_filters.py | 60 ++++++++++++++++++++--------------- back/db.py | 2 +- 2 files changed, 35 insertions(+), 27 deletions(-) diff --git a/back/add_poems_and_filters.py b/back/add_poems_and_filters.py index ee92a0b..f0366df 100644 --- a/back/add_poems_and_filters.py +++ b/back/add_poems_and_filters.py @@ -3,7 +3,7 @@ from sqlalchemy.sql import text, literal_column from sqlalchemy.ext.asyncio import AsyncSession from typing import Annotated from fastapi import Depends -from sqlalchemy import select +from sqlalchemy import select, or_, and_ from . import auth_utils, orm_models, pydantic_schemas import datetime @@ -49,35 +49,43 @@ async def add_poems_to_db(async_db: AsyncSession): async def filter_ann(schema: pydantic_schemas.SortAnnouncements, db: AsyncSession): """Функция для последовательного применения различных фильтров (через схему SortAnnouncements)""" - # fields = schema.__dict__ # параметры передоваемой схемы SortAnnouncements (ключи и значения) - # # проходим по названиям фильтров и их значениям - # for name, filt_val in fields.items(): - # # создаем выражение sql запроса - # statement = text("SELECT * FROM announcements ") - # # выбираем все строки - # query = await db.execute(statement) - # res = query.all() - # # если фильтр задан - # if filt_val is not None: - # to_intersect_query = await db.execute(select(orm_models.Announcement).where(literal_column(f"announcements.{name}") == filt_val)) - # to_intersect = to_intersect_query.all() - # res = res.intersect(to_intersect) + fields = schema.__dict__ # параметры передоваемой схемы SortAnnouncements (ключи и значения) + # проходим по названиям фильтров и их значениям + # выбираем все строки + query = await db.execute(select(orm_models.Announcement)) + res = set(query.scalars().all()) + for name, filt_val in fields.items(): + # res = await db.execute(statement) + # если фильтр задан + if filt_val is not None: + filter_query = await db.execute(select(orm_models.Announcement).where(literal_column(f"announcements.{name}") == filt_val)) + filtered = set(filter_query.scalars().all()) + res = res.intersection(filtered) + # # отфильтровываем подходящие объявления + # res = await db.execute( + # select(orm_models.Announcement).where( + # ((schema.obsolete == None) | ((schema.obsolete != None) & (orm_models.Announcement.obsolete == schema.obsolete))) + # & ((schema.user_id == None) | ((schema.user_id != None) & (orm_models.Announcement.user_id == schema.user_id))) + # & ((schema.metro == None) | ((schema.metro != None) & (orm_models.Announcement.metro == schema.metro))) + # & ((schema.category == None) | ((schema.category != None) & (orm_models.Announcement.category == schema.category))) + # ) + # ) + - # отфильтровываем подходящие объявления - res = await db.execute(select(orm_models.Announcement) - .where(schema.obsolete != None and orm_models.Announcement.obsolete == schema.obsolete - and schema.user_id != None and orm_models.Announcement.user_id == schema.user_id - and schema.metro != None and orm_models.Announcement.metro == schema.metro - and ) # .where(schema.user_id != None and orm_models.Announcement.user_id == schema.user_id) # .where(schema.metro != None and orm_models.Announcement.metro == schema.metro) # .where(schema.category != None and orm_models.Announcement.category == schema.category) - ) # statement = text("SELECT * FROM announcements " # "WHERE announcements.obsolete = :obsolete " - # "AND announcements.user_id == :user_id " - # "AND announcements.metro == :metro " - # "AND announcements.category == :category") + # "INTERSECT" + # "SELECT * FROM announcements " + # "WHERE announcements.user_id == :user_id " + # "INTERSECT" + # "SELECT * FROM announcements " + # "WHERE announcements.metro == :metro " + # "INTERSECT" + # "SELECT * FROM announcements " + # "WHERE announcements.category == :category") # res = await db.execute(statement, # {"obsolete": schema.obsolete, @@ -85,9 +93,9 @@ async def filter_ann(schema: pydantic_schemas.SortAnnouncements, db: AsyncSessio # "metro": schema.metro, # "category": schema.category} # ) + # возвращаем все подходящие объявления - - return res.scalars().all() + return res async def check_obsolete(db: AsyncSession, current_date: datetime.date): diff --git a/back/db.py b/back/db.py index 048b539..132e973 100644 --- a/back/db.py +++ b/back/db.py @@ -5,7 +5,7 @@ from sqlalchemy.ext.declarative import declarative_base SQLALCHEMY_DATABASE_URL = "sqlite+aiosqlite:///./sql_app.db" # SQLALCHEMY_DATABASE_URL = "postgresql+asyncpg://postgres:D560c34V112Ak@localhost/porridger" -engine = create_async_engine(SQLALCHEMY_DATABASE_URL, echo=True) +engine = create_async_engine(SQLALCHEMY_DATABASE_URL) SessionLocal = sessionmaker(bind=engine, class_=AsyncSession, expire_on_commit=False) From 7453a60eee126572b1b3d955925faee8e7eda012 Mon Sep 17 00:00:00 2001 From: DmitryGantimurov Date: Sun, 3 Sep 2023 00:29:17 +0300 Subject: [PATCH 10/23] async completely fixed --- alembic.ini | 18 ++++++-- back/api.py | 18 ++++---- back/orm_models.py | 4 +- migrations/README | 2 +- migrations/env.py | 44 ++++++++++++------- migrations/script.py.mako | 14 +++--- ...e6b8_lazy_selectin_added_to_user_table_.py | 30 +++++++++++++ 7 files changed, 93 insertions(+), 37 deletions(-) create mode 100644 migrations/versions/8e631a2fe6b8_lazy_selectin_added_to_user_table_.py diff --git a/alembic.ini b/alembic.ini index e041d95..3bbc0cf 100644 --- a/alembic.ini +++ b/alembic.ini @@ -4,8 +4,9 @@ # path to migration scripts script_location = migrations -# template used to generate migration files -# file_template = %%(rev)s_%%(slug)s +# template used to generate migration file names; The default value is %%(rev)s_%%(slug)s +# Uncomment the line below if you want the files to be prepended with date and time +# file_template = %%(year)d_%%(month).2d_%%(day).2d_%%(hour).2d%%(minute).2d-%%(rev)s_%%(slug)s # sys.path path, will be prepended to sys.path if present. # defaults to the current working directory. @@ -48,11 +49,16 @@ prepend_sys_path = . # version_path_separator = space version_path_separator = os # Use os.pathsep. Default configuration used for new projects. +# set to 'true' to search source files recursively +# in each "version_locations" directory +# new in Alembic version 1.10 +# recursive_version_locations = false + # the output encoding used when revision files # are written from script.py.mako # output_encoding = utf-8 -# sqlalchemy.url = driver://user:pass@localhost/dbname +; sqlalchemy.url = driver://user:pass@localhost/dbname [post_write_hooks] @@ -66,6 +72,12 @@ version_path_separator = os # Use os.pathsep. Default configuration used for ne # black.entrypoint = black # black.options = -l 79 REVISION_SCRIPT_FILENAME +# lint with attempts to fix using "ruff" - use the exec runner, execute a binary +# hooks = ruff +# ruff.type = exec +# ruff.executable = %(here)s/.venv/bin/ruff +# ruff.options = --fix REVISION_SCRIPT_FILENAME + # Logging configuration [loggers] keys = root,sqlalchemy,alembic diff --git a/back/api.py b/back/api.py index 307e55a..cfa585e 100644 --- a/back/api.py +++ b/back/api.py @@ -103,7 +103,7 @@ async def put_in_db(name: Annotated[str, Form()], category: Annotated[str, Form( 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, trashId=trashId, src=uploaded_name, booked_by=0) - await db.add(temp_ancmt) # добавляем в бд + db.add(temp_ancmt) # добавляем в бд await db.commit() # сохраняем изменения await db.refresh(temp_ancmt) # обновляем состояние объекта return {"Answer" : True} @@ -227,12 +227,14 @@ async def add_points(user_id: int, db: Annotated[Session, Depends(auth_utils.get @app.get("/api/user/poem", response_model=pydantic_schemas.Poem) async def poems_to_front(db: Annotated[Session, Depends(auth_utils.get_session)]): #num_of_poems = db.query(orm_models.Poems).count() # определяем кол-во стихов в бд - num_of_poems = await db.execute(select(orm_models.Poems)).scalars().count() # определяем кол-во стихов в бд + query = await db.execute(select(orm_models.Poems)) # определяем кол-во стихов в бд + num_of_poems = len(query.scalars().all()) # если стихов в бд нет if num_of_poems < 1: add_poems_and_filters.add_poems_to_db(db) # добавляем поэмы в базу данных - num_of_poems = await db.execute(select(orm_models.Poems)).scalars().count() # определяем кол-во стихов в бд - #num_of_poems = db.query(orm_models.Poems).count() # определяем кол-во стихов в бд + # после добавления стихов снова определяем кол-во стихов в бд + query = await db.execute(select(orm_models.Poems)) + num_of_poems = len(query.scalars().all()) rand_id = random.randint(1, num_of_poems) # генерируем номер стихотворения #poem = db.query(orm_models.Poems).filter(orm_models.Poems.id == rand_id).first() # находим стих в бд query_poem = await db.execute(select(orm_models.Poems).where(orm_models.Poems.id == rand_id)) # находим стих в бд @@ -246,7 +248,7 @@ async def poems_to_front(db: Annotated[Session, Depends(auth_utils.get_session)] async def get_trashboxes(data: pydantic_schemas.TrashboxRequest = Depends()):#крутая функция для работы с api # json, передаваемый стороннему API 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.eyJleHAiOjE3ODgzODM1NzQsImlhdCI6MTY5MzY4OTE3NCwianRpIjoiNTIxNTE4ODYtZjJiMy00MWQ2LWE2OTYtN2JjNjg1YzRmZDBjIiwiaXNzIjoiaHR0cHM6Ly9rYy5wZXRlcnNidXJnLnJ1L3JlYWxtcy9lZ3MtYXBpIiwiYXVkIjoiYWNjb3VudCIsInN1YiI6ImJjYjQ2NzljLTU3ZGItNDU5ZC1iNWUxLWRlOGI4Yzg5MTMwMyIsInR5cCI6IkJlYXJlciIsImF6cCI6ImFkbWluLXJlc3QtY2xpZW50Iiwic2Vzc2lvbl9zdGF0ZSI6IjMyNmZlYjNjLWJhMDktNDU4NC05M2JiLTgzZjMyMTRjOTdkNSIsImFjciI6IjEiLCJhbGxvd2VkLW9yaWdpbnMiOlsiLyoiXSwicmVhbG1fYWNjZXNzIjp7InJvbGVzIjpbImRlZmF1bHQtcm9sZXMtZWdzLWFwaSIsIm9mZmxpbmVfYWNjZXNzIiwidW1hX2F1dGhvcml6YXRpb24iXX0sInJlc291cmNlX2FjY2VzcyI6eyJhY2NvdW50Ijp7InJvbGVzIjpbIm1hbmFnZS1hY2NvdW50IiwibWFuYWdlLWFjY291bnQtbGlua3MiLCJ2aWV3LXByb2ZpbGUiXX19LCJzY29wZSI6ImVtYWlsIHByb2ZpbGUiLCJzaWQiOiIzMjZmZWIzYy1iYTA5LTQ1ODQtOTNiYi04M2YzMjE0Yzk3ZDUiLCJlbWFpbF92ZXJpZmllZCI6ZmFsc2UsIm5hbWUiOiLQktC70LDQtNC40LzQuNGAINCv0LrQvtCy0LvQtdCyIiwicHJlZmVycmVkX3VzZXJuYW1lIjoiZTBmYzc2OGRhOTA4MjNiODgwZGQzOGVhMDJjMmQ5NTciLCJnaXZlbl9uYW1lIjoi0JLQu9Cw0LTQuNC80LjRgCIsImZhbWlseV9uYW1lIjoi0K_QutC-0LLQu9C10LIifQ.SpFC8EufKYV4tHWSvaeypZ-j-Lqhpva3tvilMba_Yh79EzT1EUOomeT5pC7PNJPlfsuXvOyutPBXG9Fpo7tazY2K5ymxQubYrsYt1m6KrPAJYAvDVGiZl5762-7zH1NoENgxLOjNc8eqN_cZBlcqImPyGiGAIqXaZ_Bwns-Jx5qHrYipFOQ3yXtehvy8-l84ZFhO0VhUHoZZnlfXz5x3OuOTVLU1-NjUclZEYc7t3ZlOl5m-r8jAfAdTnY-V-JDfLMbwqjouAAzauUNm4-1uiZjntrShuBsYoJcVaXcW8cSWnVk5NgWQNxwHoel4AhGIGBWPQ6gmJw2jkXBBjzXbqA" head = {'Authorization': 'Bearer {}'.format(my_token)} # Данные пользователя (местоположение, количество мусорок, которое пользователь хочет видеть) my_data={ @@ -274,7 +276,7 @@ async def get_trashboxes(data: pydantic_schemas.TrashboxRequest = Depends()):#к list_of_category = ["Металл", "Бумага", "Стекло", "Иное", "Тетра Пак", "Батарейки", "Крышечки", "Шины", "Опасные отходы", "Лампочки", "Пластик"] # Получение ответа от стороннего апи - response = await requests.post(f"{BASE_URL}/nearest_recycling/get", headers=head, data=my_data, timeout=10) + response = requests.post(f"{BASE_URL}/nearest_recycling/get", headers=head, data=my_data, timeout=10) infos = response.json() # Чтение ответа trashboxes = [] @@ -292,7 +294,7 @@ async def get_trashboxes(data: pydantic_schemas.TrashboxRequest = Depends()):#к for a in list_of_category: if a in temp_dict["Categories"] and temp_dict not in trashboxes: trashboxes.append(temp_dict) - uniq_trashboxes = await [pydantic_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 @@ -314,7 +316,7 @@ async def dispose(data: pydantic_schemas.DisposeRequest, current_user_schema: An 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) # добавляем в бд - await db.add(new_trashox) + db.add(new_trashox) # в соответствии с логикой api, после утилизации объявление пользователя удаляется # находим объявление с айди data.ann_id #ann_to_del = db.query(orm_models.Announcement).filter(orm_models.Announcement.id == data.ann_id).first() # diff --git a/back/orm_models.py b/back/orm_models.py index c866d6f..7d43413 100644 --- a/back/orm_models.py +++ b/back/orm_models.py @@ -17,8 +17,8 @@ class User(Base):#класс пользователя num_of_ratings = Column(Integer, default=0) # количество оценок (т.е. то, сколько раз другие пользователи оценили текущего) reg_date = Column(Date) # дата регистрации - announcements = relationship("Announcement", back_populates="user") - trashboxes_chosen = relationship("Trashbox", back_populates="user") + announcements = relationship("Announcement", back_populates="user", lazy='selectin') + trashboxes_chosen = relationship("Trashbox", back_populates="user", lazy='selectin') class Announcement(Base): #класс объявления __tablename__ = "announcements" diff --git a/migrations/README b/migrations/README index 98e4f9c..e0d0858 100644 --- a/migrations/README +++ b/migrations/README @@ -1 +1 @@ -Generic single-database configuration. \ No newline at end of file +Generic single-database configuration with an async dbapi. \ No newline at end of file diff --git a/migrations/env.py b/migrations/env.py index bfa8186..7523a7e 100644 --- a/migrations/env.py +++ b/migrations/env.py @@ -1,11 +1,12 @@ +import asyncio from logging.config import fileConfig -from sqlalchemy import engine_from_config from sqlalchemy import pool +from sqlalchemy.engine import Connection +from sqlalchemy.ext.asyncio import async_engine_from_config from alembic import context - from back import auxiliary_for_alembic, db # this is the Alembic Config object, which provides @@ -17,6 +18,10 @@ config = context.config if config.config_file_name is not None: fileConfig(config.config_file_name) +# add your model's MetaData object here +# for 'autogenerate' support +# from myapp import mymodel +# target_metadata = mymodel.Base.metadata target_metadata = auxiliary_for_alembic.Base.metadata # other values from the config, defined by the needs of env.py, @@ -25,7 +30,7 @@ target_metadata = auxiliary_for_alembic.Base.metadata # ... etc. -def run_migrations_offline(): +def run_migrations_offline() -> None: """Run migrations in 'offline' mode. This configures the context with just a URL @@ -37,44 +42,49 @@ def run_migrations_offline(): script output. """ - # url = config.get_main_option("sqlalchemy.url") url = config.get_main_option(db.SQLALCHEMY_DATABASE_URL) context.configure( url=url, target_metadata=target_metadata, literal_binds=True, dialect_opts={"paramstyle": "named"}, - render_as_batch=True ) with context.begin_transaction(): context.run_migrations() -def run_migrations_online(): - """Run migrations in 'online' mode. +def do_run_migrations(connection: Connection) -> None: + context.configure(connection=connection, target_metadata=target_metadata) - In this scenario we need to create an Engine + with context.begin_transaction(): + context.run_migrations() + + +async def run_async_migrations() -> None: + """In this scenario we need to create an Engine and associate a connection with the context. """ + configuration = config.get_section(config.config_ini_section) configuration['sqlalchemy.url'] = db.SQLALCHEMY_DATABASE_URL - connectable = engine_from_config( + connectable = async_engine_from_config( configuration, prefix="sqlalchemy.", poolclass=pool.NullPool, ) - with connectable.connect() as connection: - context.configure( - connection=connection, - target_metadata=target_metadata, - render_as_batch=True - ) + async with connectable.connect() as connection: + await connection.run_sync(do_run_migrations) - with context.begin_transaction(): - context.run_migrations() + await connectable.dispose() + + +def run_migrations_online() -> None: + """Run migrations in 'online' mode.""" + + asyncio.run(run_async_migrations()) if context.is_offline_mode(): diff --git a/migrations/script.py.mako b/migrations/script.py.mako index 2c01563..fbc4b07 100644 --- a/migrations/script.py.mako +++ b/migrations/script.py.mako @@ -5,20 +5,22 @@ Revises: ${down_revision | comma,n} Create Date: ${create_date} """ +from typing import Sequence, Union + from alembic import op import sqlalchemy as sa ${imports if imports else ""} # revision identifiers, used by Alembic. -revision = ${repr(up_revision)} -down_revision = ${repr(down_revision)} -branch_labels = ${repr(branch_labels)} -depends_on = ${repr(depends_on)} +revision: str = ${repr(up_revision)} +down_revision: Union[str, None] = ${repr(down_revision)} +branch_labels: Union[str, Sequence[str], None] = ${repr(branch_labels)} +depends_on: Union[str, Sequence[str], None] = ${repr(depends_on)} -def upgrade(): +def upgrade() -> None: ${upgrades if upgrades else "pass"} -def downgrade(): +def downgrade() -> None: ${downgrades if downgrades else "pass"} diff --git a/migrations/versions/8e631a2fe6b8_lazy_selectin_added_to_user_table_.py b/migrations/versions/8e631a2fe6b8_lazy_selectin_added_to_user_table_.py new file mode 100644 index 0000000..736e5a3 --- /dev/null +++ b/migrations/versions/8e631a2fe6b8_lazy_selectin_added_to_user_table_.py @@ -0,0 +1,30 @@ +"""lazy=selectin added to user table relationships + +Revision ID: 8e631a2fe6b8 +Revises: +Create Date: 2023-09-02 23:45:08.799366 + +""" +from typing import Sequence, Union + +from alembic import op +import sqlalchemy as sa + + +# revision identifiers, used by Alembic. +revision: str = '8e631a2fe6b8' +down_revision: Union[str, None] = None +branch_labels: Union[str, Sequence[str], None] = None +depends_on: Union[str, Sequence[str], None] = None + + +def upgrade() -> None: + # ### commands auto generated by Alembic - please adjust! ### + pass + # ### end Alembic commands ### + + +def downgrade() -> None: + # ### commands auto generated by Alembic - please adjust! ### + pass + # ### end Alembic commands ### From c922c8611edf032d3fa3677f076e3351c035d513 Mon Sep 17 00:00:00 2001 From: dm1sh Date: Fri, 8 Sep 2023 19:40:23 +0300 Subject: [PATCH 11/23] Fixed async-await bugs --- back/add_poems_and_filters.py | 10 ++++------ back/api.py | 12 ++++++------ back/auth_utils.py | 8 ++++---- requirements.txt | 2 ++ 4 files changed, 16 insertions(+), 16 deletions(-) diff --git a/back/add_poems_and_filters.py b/back/add_poems_and_filters.py index f0366df..67847f3 100644 --- a/back/add_poems_and_filters.py +++ b/back/add_poems_and_filters.py @@ -37,12 +37,10 @@ async def add_poems_to_db(async_db: AsyncSession): flag = True else: author += str1 - async with async_db() as session: - async with session.begin(): - poem = orm_models.Poems(title=name, text=stixi, author=author) - # В конце каждой итерации добавляем в базу данных - session.add(poem) - session.commit() + poem = orm_models.Poems(title=name, text=stixi, author=author) + # В конце каждой итерации добавляем в базу данных + async_db.add(poem) + async_db.commit() # close the file f1.close() diff --git a/back/api.py b/back/api.py index cfa585e..c29b676 100644 --- a/back/api.py +++ b/back/api.py @@ -93,7 +93,7 @@ async def put_in_db(name: Annotated[str, Form()], category: Annotated[str, Form( if f.tell() > 0: f.seek(0) destination = pathlib.Path("./uploads/" + str(hash(f)) + pathlib.Path(src.filename).suffix.lower()) - async with destination.open('wb') as buffer: + with destination.open('wb') as buffer: shutil.copyfileobj(f, buffer) # изменяем название директории загруженного файла @@ -163,7 +163,7 @@ async def create_user(nickname: Annotated[str, Form()], password: Annotated[str, new_user = orm_models.User(nickname=nickname, hashed_password=auth_utils.get_password_hash(password), name=name, surname=surname, reg_date=datetime.date.today()) # добавляем в бд - await db.add(new_user) + db.add(new_user) await db.commit() await db.refresh(new_user) # обновляем состояние объекта return {"Success": True} @@ -187,7 +187,7 @@ async def login_for_access_token( # задаем временной интервал, в течение которого токен можно использовать access_token_expires = auth_utils.timedelta(minutes=auth_utils.ACCESS_TOKEN_EXPIRE_MINUTES) # создаем токен - access_token = await auth_utils.create_access_token( + access_token = auth_utils.create_access_token( data={"user_id": user.id}, expires_delta=access_token_expires ) return {"access_token":access_token} @@ -195,7 +195,7 @@ async def login_for_access_token( # получаем данные успешно вошедшего пользователя @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)]): +def read_users_me(current_user: Annotated[pydantic_schemas.User, Depends(auth_utils.get_current_active_user)]): return current_user @@ -231,9 +231,9 @@ async def poems_to_front(db: Annotated[Session, Depends(auth_utils.get_session)] num_of_poems = len(query.scalars().all()) # если стихов в бд нет if num_of_poems < 1: - add_poems_and_filters.add_poems_to_db(db) # добавляем поэмы в базу данных + await add_poems_and_filters.add_poems_to_db(db) # добавляем поэмы в базу данных # после добавления стихов снова определяем кол-во стихов в бд - query = await db.execute(select(orm_models.Poems)) + query = await db.execute(select(orm_models.Poems)) num_of_poems = len(query.scalars().all()) rand_id = random.randint(1, num_of_poems) # генерируем номер стихотворения #poem = db.query(orm_models.Poems).filter(orm_models.Poems.id == rand_id).first() # находим стих в бд diff --git a/back/auth_utils.py b/back/auth_utils.py index 1fbdb6b..9a34646 100644 --- a/back/auth_utils.py +++ b/back/auth_utils.py @@ -30,11 +30,11 @@ async def get_session() -> AsyncSession: yield session -async def verify_password(plain_password, hashed_password): +def verify_password(plain_password, hashed_password): return pwd_context.verify(plain_password, hashed_password) -async def get_password_hash(password): +def get_password_hash(password): return pwd_context.hash(password) @@ -63,7 +63,7 @@ async def authenticate_user(db: Annotated[AsyncSession, Depends(get_session)], n return user -async 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() if expires_delta: expire = datetime.utcnow() + expires_delta @@ -95,7 +95,7 @@ async def get_current_user(db: Annotated[AsyncSession, Depends(get_session)], to disabled=user.disabled, items=user.announcements, reg_date=user.reg_date, points=user.points) -async def get_current_active_user( +def get_current_active_user( current_user: Annotated[pydantic_schemas.User, Depends(get_current_user)] ): if current_user.disabled: diff --git a/requirements.txt b/requirements.txt index 2a1c749..9c3358a 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,5 +1,7 @@ +aiosqlite==0.19.0 annotated-types==0.5.0 anyio==3.7.1 +asyncpg==0.28.0 certifi==2023.7.22 charset-normalizer==3.2.0 click==8.1.6 From 0df1d506125cb874a325c1e2092ea830f3436e5b Mon Sep 17 00:00:00 2001 From: dm1sh Date: Fri, 8 Sep 2023 19:40:29 +0300 Subject: [PATCH 12/23] Added config loading from .env file --- back/add_poems_and_filters.py | 5 ----- back/api.py | 13 ++++--------- back/auth_utils.py | 11 ++--------- back/config.py | 13 +++++++++++++ back/db.py | 4 ++-- requirements.txt | 1 + 6 files changed, 22 insertions(+), 25 deletions(-) create mode 100644 back/config.py diff --git a/back/add_poems_and_filters.py b/back/add_poems_and_filters.py index 67847f3..9380918 100644 --- a/back/add_poems_and_filters.py +++ b/back/add_poems_and_filters.py @@ -7,11 +7,6 @@ from sqlalchemy import select, or_, and_ from . import auth_utils, orm_models, pydantic_schemas import datetime -# Переменные для получения данных о мусорках с внешнего API -# url API -BASE_URL='https://geointelect2.gate.petersburg.ru'#адрес сайта и мой токин -# токен для получения данных -my_token='eyJhbGciOiJSUzI1NiIsInR5cCIgOiAiSldUIiwia2lkIiA6ICJhU1RaZm42bHpTdURYcUttRkg1SzN5UDFhT0FxUkhTNm9OendMUExaTXhFIn0.eyJleHAiOjE3ODM3ODk4NjgsImlhdCI6MTY4OTA5NTQ2OCwianRpIjoiNDUzNjQzZTgtYTkyMi00NTI4LWIzYmMtYWJiYTNmYjkyNTkxIiwiaXNzIjoiaHR0cHM6Ly9rYy5wZXRlcnNidXJnLnJ1L3JlYWxtcy9lZ3MtYXBpIiwiYXVkIjoiYWNjb3VudCIsInN1YiI6ImJjYjQ2NzljLTU3ZGItNDU5ZC1iNWUxLWRlOGI4Yzg5MTMwMyIsInR5cCI6IkJlYXJlciIsImF6cCI6ImFkbWluLXJlc3QtY2xpZW50Iiwic2Vzc2lvbl9zdGF0ZSI6ImM2ZDJiOTZhLWMxNjMtNDAxZS05ZjMzLTI0MmE0NDcxMDY5OCIsImFjciI6IjEiLCJhbGxvd2VkLW9yaWdpbnMiOlsiLyoiXSwicmVhbG1fYWNjZXNzIjp7InJvbGVzIjpbImRlZmF1bHQtcm9sZXMtZWdzLWFwaSIsIm9mZmxpbmVfYWNjZXNzIiwidW1hX2F1dGhvcml6YXRpb24iXX0sInJlc291cmNlX2FjY2VzcyI6eyJhY2NvdW50Ijp7InJvbGVzIjpbIm1hbmFnZS1hY2NvdW50IiwibWFuYWdlLWFjY291bnQtbGlua3MiLCJ2aWV3LXByb2ZpbGUiXX19LCJzY29wZSI6ImVtYWlsIHByb2ZpbGUiLCJzaWQiOiJjNmQyYjk2YS1jMTYzLTQwMWUtOWYzMy0yNDJhNDQ3MTA2OTgiLCJlbWFpbF92ZXJpZmllZCI6ZmFsc2UsIm5hbWUiOiLQktC70LDQtNC40LzQuNGAINCv0LrQvtCy0LvQtdCyIiwicHJlZmVycmVkX3VzZXJuYW1lIjoiZTBmYzc2OGRhOTA4MjNiODgwZGQzOGVhMDJjMmQ5NTciLCJnaXZlbl9uYW1lIjoi0JLQu9Cw0LTQuNC80LjRgCIsImZhbWlseV9uYW1lIjoi0K_QutC-0LLQu9C10LIifQ.E2bW0B-c6W5Lj63eP_G8eI453NlDMnW05l11TZT0GSsAtGayXGaolHtWrmI90D5Yxz7v9FGkkCmcUZYy1ywAdO9dDt_XrtFEJWFpG-3csavuMjXmqfQQ9SmPwDw-3toO64NuZVv6qVqoUlPPj57sLx4bLtVbB4pdqgyJYcrDHg7sgwz4d1Z3tAeUfSpum9s5ZfELequfpLoZMXn6CaYZhePaoK-CxeU3KPBPTPOVPKZZ19s7QY10VdkxLULknqf9opdvLs4j8NMimtwoIiHNBFlgQz10Cr7bhDKWugfvSRsICouniIiBJo76wrj5T92s-ztf1FShJuqnQcKE_QLd2A' # Загружаем стихи async def add_poems_to_db(async_db: AsyncSession): diff --git a/back/api.py b/back/api.py index c29b676..2a038c0 100644 --- a/back/api.py +++ b/back/api.py @@ -11,7 +11,6 @@ from typing import Any, Annotated, List, Union from starlette.staticfiles import StaticFiles from sqlalchemy.orm import Session from sqlalchemy import select -from dotenv import load_dotenv, dotenv_values import requests from uuid import uuid4 @@ -26,6 +25,8 @@ import os from . import add_poems_and_filters, auth_utils, orm_models, pydantic_schemas +from .config import TRASHBOXES_BASE_URL, TRASHBOXES_TOKEN + # создаем приложение Fastapi app = FastAPI() @@ -42,10 +43,6 @@ if not os.path.exists("./uploads"): # создаем эндпоинт для хранения файлов пользователя app.mount("/uploads", StaticFiles(directory = "./uploads")) -# load_dotenv("unimportant.env") -# ACCESS_TOKEN_EXPIRE_MINUTES = os.getenv("ACCESS_TOKEN_EXPIRE_MINUTES") -ACCESS_TOKEN_EXPIRE_MINUTES = 1440 - # эндпоинт для возвращения согласия в pdf @app.get("/privacy_policy.pdf") async def privacy_policy(): @@ -247,9 +244,7 @@ async def poems_to_front(db: Annotated[Session, Depends(auth_utils.get_session)] @app.get("/api/trashbox", response_model=List[pydantic_schemas.TrashboxResponse]) async def get_trashboxes(data: pydantic_schemas.TrashboxRequest = Depends()):#крутая функция для работы с api # json, передаваемый стороннему API - BASE_URL= "https://geointelect2.gate.petersburg.ru" - my_token="eyJhbGciOiJSUzI1NiIsInR5cCIgOiAiSldUIiwia2lkIiA6ICJhU1RaZm42bHpTdURYcUttRkg1SzN5UDFhT0FxUkhTNm9OendMUExaTXhFIn0.eyJleHAiOjE3ODgzODM1NzQsImlhdCI6MTY5MzY4OTE3NCwianRpIjoiNTIxNTE4ODYtZjJiMy00MWQ2LWE2OTYtN2JjNjg1YzRmZDBjIiwiaXNzIjoiaHR0cHM6Ly9rYy5wZXRlcnNidXJnLnJ1L3JlYWxtcy9lZ3MtYXBpIiwiYXVkIjoiYWNjb3VudCIsInN1YiI6ImJjYjQ2NzljLTU3ZGItNDU5ZC1iNWUxLWRlOGI4Yzg5MTMwMyIsInR5cCI6IkJlYXJlciIsImF6cCI6ImFkbWluLXJlc3QtY2xpZW50Iiwic2Vzc2lvbl9zdGF0ZSI6IjMyNmZlYjNjLWJhMDktNDU4NC05M2JiLTgzZjMyMTRjOTdkNSIsImFjciI6IjEiLCJhbGxvd2VkLW9yaWdpbnMiOlsiLyoiXSwicmVhbG1fYWNjZXNzIjp7InJvbGVzIjpbImRlZmF1bHQtcm9sZXMtZWdzLWFwaSIsIm9mZmxpbmVfYWNjZXNzIiwidW1hX2F1dGhvcml6YXRpb24iXX0sInJlc291cmNlX2FjY2VzcyI6eyJhY2NvdW50Ijp7InJvbGVzIjpbIm1hbmFnZS1hY2NvdW50IiwibWFuYWdlLWFjY291bnQtbGlua3MiLCJ2aWV3LXByb2ZpbGUiXX19LCJzY29wZSI6ImVtYWlsIHByb2ZpbGUiLCJzaWQiOiIzMjZmZWIzYy1iYTA5LTQ1ODQtOTNiYi04M2YzMjE0Yzk3ZDUiLCJlbWFpbF92ZXJpZmllZCI6ZmFsc2UsIm5hbWUiOiLQktC70LDQtNC40LzQuNGAINCv0LrQvtCy0LvQtdCyIiwicHJlZmVycmVkX3VzZXJuYW1lIjoiZTBmYzc2OGRhOTA4MjNiODgwZGQzOGVhMDJjMmQ5NTciLCJnaXZlbl9uYW1lIjoi0JLQu9Cw0LTQuNC80LjRgCIsImZhbWlseV9uYW1lIjoi0K_QutC-0LLQu9C10LIifQ.SpFC8EufKYV4tHWSvaeypZ-j-Lqhpva3tvilMba_Yh79EzT1EUOomeT5pC7PNJPlfsuXvOyutPBXG9Fpo7tazY2K5ymxQubYrsYt1m6KrPAJYAvDVGiZl5762-7zH1NoENgxLOjNc8eqN_cZBlcqImPyGiGAIqXaZ_Bwns-Jx5qHrYipFOQ3yXtehvy8-l84ZFhO0VhUHoZZnlfXz5x3OuOTVLU1-NjUclZEYc7t3ZlOl5m-r8jAfAdTnY-V-JDfLMbwqjouAAzauUNm4-1uiZjntrShuBsYoJcVaXcW8cSWnVk5NgWQNxwHoel4AhGIGBWPQ6gmJw2jkXBBjzXbqA" - head = {'Authorization': 'Bearer {}'.format(my_token)} + head = {'Authorization': 'Bearer ' + TRASHBOXES_TOKEN} # Данные пользователя (местоположение, количество мусорок, которое пользователь хочет видеть) my_data={ 'x' : f"{data.Lng}", @@ -276,7 +271,7 @@ async def get_trashboxes(data: pydantic_schemas.TrashboxRequest = Depends()):#к list_of_category = ["Металл", "Бумага", "Стекло", "Иное", "Тетра Пак", "Батарейки", "Крышечки", "Шины", "Опасные отходы", "Лампочки", "Пластик"] # Получение ответа от стороннего апи - response = requests.post(f"{BASE_URL}/nearest_recycling/get", headers=head, data=my_data, timeout=10) + response = requests.post(TRASHBOXES_BASE_URL + "/nearest_recycling/get", headers=head, data=my_data, timeout=10) infos = response.json() # Чтение ответа trashboxes = [] diff --git a/back/auth_utils.py b/back/auth_utils.py index 9a34646..942bc4a 100644 --- a/back/auth_utils.py +++ b/back/auth_utils.py @@ -1,6 +1,5 @@ from datetime import datetime, timedelta from typing import Annotated, Union -import os from fastapi import Depends, HTTPException, status from fastapi.security import OAuth2PasswordBearer @@ -9,18 +8,12 @@ from passlib.context import CryptContext from sqlalchemy import select from sqlalchemy.orm import Session from sqlalchemy.ext.asyncio import AsyncSession -from dotenv import load_dotenv from .db import SessionLocal from . import orm_models, pydantic_schemas +from .config import SECRET_KEY, ALGORITHM, ACCESS_TOKEN_EXPIRE_MINUTES + -# load_dotenv("unimportant.env") -# SECRET_KEY = os.getenv("SECRET_KEY") -# ALGORITHM = os.getenv("ALGORITHM") -# ACCESS_TOKEN_EXPIRE_MINUTES = os.getenv("ACCESS_TOKEN_EXPIRE_MINUTES") -ACCESS_TOKEN_EXPIRE_MINUTES = 1440 -SECRET_KEY = "651a52941cf5de14d48ef5d7af115709" -ALGORITHM = "HS256" pwd_context = CryptContext(schemes=["bcrypt"], deprecated="auto") oauth2_scheme = OAuth2PasswordBearer(tokenUrl="/api/token") diff --git a/back/config.py b/back/config.py new file mode 100644 index 0000000..3c90b68 --- /dev/null +++ b/back/config.py @@ -0,0 +1,13 @@ +import os +from dotenv import load_dotenv + +load_dotenv('.env') + +TRASHBOXES_TOKEN = os.environ.get("TRASHBOXES_TOKEN") +TRASHBOXES_BASE_URL = os.environ.get("TRASHBOXES_BASE_URL") + +SECRET_KEY = os.environ.get("SECRET_KEY") +ALGORITHM = os.environ.get("ALGORITHM") +ACCESS_TOKEN_EXPIRE_MINUTES = int(os.environ.get("ACCESS_TOKEN_EXPIRE_MINUTES")) + +SQLALCHEMY_DATABASE_URL = os.environ.get("SQLALCHEMY_DATABASE_URL") \ No newline at end of file diff --git a/back/db.py b/back/db.py index 132e973..6e13214 100644 --- a/back/db.py +++ b/back/db.py @@ -3,8 +3,8 @@ from sqlalchemy.ext.asyncio import AsyncSession, async_scoped_session, create_as from sqlalchemy.orm import sessionmaker from sqlalchemy.ext.declarative import declarative_base -SQLALCHEMY_DATABASE_URL = "sqlite+aiosqlite:///./sql_app.db" -# SQLALCHEMY_DATABASE_URL = "postgresql+asyncpg://postgres:D560c34V112Ak@localhost/porridger" +from .config import SQLALCHEMY_DATABASE_URL + engine = create_async_engine(SQLALCHEMY_DATABASE_URL) SessionLocal = sessionmaker(bind=engine, class_=AsyncSession, expire_on_commit=False) diff --git a/requirements.txt b/requirements.txt index 9c3358a..2ac0161 100644 --- a/requirements.txt +++ b/requirements.txt @@ -17,6 +17,7 @@ pyasn1==0.5.0 pydantic==1.10.10 pydantic_core==2.4.0 python-dateutil==2.8.2 +python-dotenv==1.0.0 python-jose==3.3.0 python-multipart==0.0.6 redbird==0.7.1 From 543b7b0c46029ac007270cc520ae0d74a17a9a66 Mon Sep 17 00:00:00 2001 From: dm1sh Date: Fri, 8 Sep 2023 19:40:33 +0300 Subject: [PATCH 13/23] Fixed assets mounting in app and container --- .containerignore | 3 +++ .gitignore | 2 ++ README.md | 2 +- back/add_poems_and_filters.py | 2 +- back/api.py | 2 +- text121.txt => poems.txt | 0 privacy_policy.pdf | Bin 0 -> 208526 bytes 7 files changed, 8 insertions(+), 3 deletions(-) rename text121.txt => poems.txt (100%) create mode 100644 privacy_policy.pdf diff --git a/.containerignore b/.containerignore index cb19d53..1f26113 100644 --- a/.containerignore +++ b/.containerignore @@ -29,4 +29,7 @@ dist-ssr uploads/ .env +poems.txt +poem_pic/ + __pycache__ \ No newline at end of file diff --git a/.gitignore b/.gitignore index cb19d53..a6bbd50 100644 --- a/.gitignore +++ b/.gitignore @@ -29,4 +29,6 @@ dist-ssr uploads/ .env +poem_pic/ + __pycache__ \ No newline at end of file diff --git a/README.md b/README.md index b546806..db0fda9 100644 --- a/README.md +++ b/README.md @@ -35,5 +35,5 @@ Only docker/podman are required ```sh docker build . -t porridger:build -docker run --name porridger -p 8000:8000 -v ./sql_app.db:/srv/sql_app.db -v uploads:/srv/uploads -v poem_pic:/srv/poem_pic porridger:build +docker run --name porridger -p 8000:8000 -v ./sql_app.db:/srv/sql_app.db -v ./poems.txt:/srv/poems.txt -v ./poem_pic:/srv/poem_pic -v uploads:/srv/uploads porridger:build ``` diff --git a/back/add_poems_and_filters.py b/back/add_poems_and_filters.py index 9380918..61e5fa4 100644 --- a/back/add_poems_and_filters.py +++ b/back/add_poems_and_filters.py @@ -10,7 +10,7 @@ import datetime # Загружаем стихи async def add_poems_to_db(async_db: AsyncSession): - f1 = open('text121.txt', encoding='utf-8', mode='r')#открыть фаил для чтения на русском + f1 = open('poems.txt', encoding='utf-8', mode='r')#открыть фаил для чтения на русском for a in range(1, 110): f1.seek(0)#перейти к началу i=0 diff --git a/back/api.py b/back/api.py index 2a038c0..32e8cb6 100644 --- a/back/api.py +++ b/back/api.py @@ -46,7 +46,7 @@ app.mount("/uploads", StaticFiles(directory = "./uploads")) # эндпоинт для возвращения согласия в pdf @app.get("/privacy_policy.pdf") async def privacy_policy(): - return FileResponse("privacy_policy.pdf") + return FileResponse("./privacy_policy.pdf") # получение списка объявлений @app.get("/api/announcements", response_model=List[pydantic_schemas.Announcement])#адрес объявлений diff --git a/text121.txt b/poems.txt similarity index 100% rename from text121.txt rename to poems.txt diff --git a/privacy_policy.pdf b/privacy_policy.pdf new file mode 100644 index 0000000000000000000000000000000000000000..b4aa2a4c8707c17dbcf74d5dd87a851d988b2ab3 GIT binary patch literal 208526 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
sf|1p5) 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

5g3O+XO%R1 zpiR37^%%35rEAl6ohHUqASIy@gA0|>I5MkCd?*&z%+j*cq`6UgPWhLpK2Dx@bqH*J z<)SER=pE)mL}P!YF}(*Uv_`vW?YHq zM$H06yM_4UOf zTUuCZkG?tL5tN7QyfxRowy-9S?`)hJxjP~@vM(rWt!yo^j*9;k{}$ixuo&=hglRA$ zPVQA%zS?BH2wgly?%Jf%=yV1%W;51s|E8Yey70W<-dAHmg+dKdI{rFi8mD%({U|WX zXoY^i4p*waaGcMr%{TEtFa-FZ`?AK^;b3LduGfO*`YOGG2X?r(438NHD?Klydj;>$ z-EAQ_li05()hiyp6L{;=lhB*Diw7Ni!?(acsb>k|@8YMo96mTN;j>NDtpkg76MC zcZmezm}oHkiD>w4+k}cDsrP&_yOvW9ZBj(u2>-SpvC|`g;c_5%hf+dG5#I&=z@5V` z-^rT{g@ev(NqOEy<8$7>4?7^szSDRhJ|^?7;LLD(cikroq@@<;ht}^C z)10S=)~ASRksZKj$a0h zC!*G^I$D#_vN~@VONWTb*Tc0g-k2P}DvO4A`#FZwqt_9>Y6 zH^OwgiH%9#Hm0X6NqIJ^lsCj^s=`1}@*ieis;YjFC z1g+?<=&s#mOR#g;%&~K9;dnBhqUSTdI8CvQyUDTDo#v1@HO>8_Q#qTQY1?)DR#V&? zPCJLfp@GT6^ok9sL4m=xX!Gk@g$qMAAoVPPP`UgMXNY-A3Em~~b0~}K=8)HYCLa%# z&|flUevp}dRxp#FqLV=tf(1GqUvM7(IMS0wf1&%7CaaQ^aH4!`DmP|t_43nZnKb^G zPuKiNtS2{Dx|r63Y=1=?-}p*PRbOYjw%TED=2O;y8Lmtm)z;tQQW#Lq0Q zi76?7MLu-*m0i8>fF*ei&=p9oaMf0eT6-JX?9d5ZX@QqF^#d*mUcEtiZGX-|bC6n8 zsfH_Y^olJb3stib&jV{U{qx`YxYPX`UIkYAG{#s;xj_M0_eux4fs}7rIiaSy9+zG7 z2uGn-R4(AkSF7gcW28LlhFz*Y{m@z6;Gfi8rBe1Y{P8sIS%Le^Il+b@wJIWx;22$7L&_JC&%m*Ob!;K#Flj(*Qu@Xz}o#iA{E2kmjch+@%)vn3cpy?u^y zNYc;xS$jrSW=X3xI@mk65%ZOF@5)vF=gey#cg% z$@!&jqO0K6#z9^O&}^nW>$Ij6Tc`W%G;*UEy+tk}Akb#lc)V%Ye?Z1#Mp8{Z zwX<_}xoT#)YH_*hX=DEMa_EtqoPI~AirM8*cuo$f;aZnjV&lQreac>!gaz<&o&0)mK#q6 z#|^yOdow^Xq5vIz@s_c+()DK~^SdLh4?SczN8$zfpWN8^Llf*zK`%hF?2Awt@^A8B znCM_nbvtWMFZHuNF`j@pnYyimJXjtk4=9SMTL%S&0~a89Yjx8=uONBI*YlGOTJVzy zeFFoCu@M3SIcWex>7!s^5XcCPHa-bOLm|dG|J?#`@SnxWz$oZH#mL}2n!xywW8(@Bg# z!h`w~qE+9S6n%P**pt)4_hc93n4Fc&W&5@(je4<$vPF#DBf_w{A~+xYc1ndol=V?W zNQ%)NFZE){n{W9c?28|h0A}w^R#P!A8<4j#MKuKM{UOtV1UOq z9|$m-D;5L{&TR+hVTXWl_eG+){i2Xu;~~LN^!8YgPzVad z;BB=9U_fF1Gfx2wwY@F@2(`WT0Spb=?gPM}+iK>s9Rd)i{Cn*~KnMgde}7@&p{_pu zo}ohf0L92J4+7NxeE0vdzq^Kpf7uWrAS4Ka5Zb4xXk=+DwC~Sd5+t Date: Fri, 8 Sep 2023 19:40:38 +0300 Subject: [PATCH 14/23] Refactored trash category convertion --- back/add_poems_and_filters.py | 3 ++- back/api.py | 34 +++++++++++++++------------------- back/orm_models.py | 3 ++- 3 files changed, 19 insertions(+), 21 deletions(-) diff --git a/back/add_poems_and_filters.py b/back/add_poems_and_filters.py index 61e5fa4..69daafb 100644 --- a/back/add_poems_and_filters.py +++ b/back/add_poems_and_filters.py @@ -4,9 +4,10 @@ from sqlalchemy.ext.asyncio import AsyncSession from typing import Annotated from fastapi import Depends from sqlalchemy import select, or_, and_ -from . import auth_utils, orm_models, pydantic_schemas import datetime +from . import auth_utils, orm_models, pydantic_schemas + # Загружаем стихи async def add_poems_to_db(async_db: AsyncSession): diff --git a/back/api.py b/back/api.py index 32e8cb6..882a9bd 100644 --- a/back/api.py +++ b/back/api.py @@ -240,9 +240,20 @@ async def poems_to_front(db: Annotated[Session, Depends(auth_utils.get_session)] raise HTTPException(status_code=404, detail="Poem not found") return poem +trashboxes_category = { + "PORRIDGE": ["Опасные отходы", "Иное"], + "conspects": ["Бумага"], + "milk": ["Стекло", "Тетра Пак", "Иное"], + "bred": ["Пластик", "Иное"], + "wathing": ["Пластик", "Опасные отходы", "Иное"], + "cloth": ["Одежда"], + "fruits_vegatables": ["Иное"], + "other_things": ["Металл", "Бумага", "Стекло", "Иное", "Тетра Пак", "Батарейки", "Крышечки", "Шины", + "Опасные отходы", "Лампочки", "Пластик"] +} @app.get("/api/trashbox", response_model=List[pydantic_schemas.TrashboxResponse]) -async def get_trashboxes(data: pydantic_schemas.TrashboxRequest = Depends()):#крутая функция для работы с api +async def get_trashboxes(data: pydantic_schemas.TrashboxRequest = Depends()): #крутая функция для работы с api # json, передаваемый стороннему API head = {'Authorization': 'Bearer ' + TRASHBOXES_TOKEN} # Данные пользователя (местоположение, количество мусорок, которое пользователь хочет видеть) @@ -252,27 +263,12 @@ async def get_trashboxes(data: pydantic_schemas.TrashboxRequest = Depends()):#к 'limit' : '1' } # Перевод категории с фронта на категорию с сайта - match data.Category: - case "PORRIDGE": - list_of_category = ["Опасные отходы", "Иное"] - case "conspects": - list_of_category = ["Бумага"] - case "milk": - list_of_category = ["Стекло", "Тетра Пак", "Иное"] - case "bred": - list_of_category = ["Пластик", "Иное"] - case "wathing": - list_of_category = ["Пластик", "Опасные отходы", "Иное"] - case "cloth": - list_of_category = ["Одежда"] - case "fruits_vegatables": - list_of_category = ["Иное"] - case "other_things": - list_of_category = ["Металл", "Бумага", "Стекло", "Иное", "Тетра Пак", "Батарейки", "Крышечки", "Шины", - "Опасные отходы", "Лампочки", "Пластик"] + list_of_category = trashboxes_category[data.Category] + # Получение ответа от стороннего апи response = requests.post(TRASHBOXES_BASE_URL + "/nearest_recycling/get", headers=head, data=my_data, timeout=10) infos = response.json() + # Чтение ответа trashboxes = [] for trashbox in infos["results"]: diff --git a/back/orm_models.py b/back/orm_models.py index 7d43413..1c7a7b3 100644 --- a/back/orm_models.py +++ b/back/orm_models.py @@ -1,7 +1,8 @@ from sqlalchemy import Column, Integer, String, Boolean, Float, Date, ForeignKey -from .db import Base, engine from sqlalchemy.orm import relationship +from .db import Base, engine + class User(Base):#класс пользователя __tablename__ = "users" From acd0a8fbf7570dd10b215fc1096860ba4655a657 Mon Sep 17 00:00:00 2001 From: dm1sh Date: Fri, 8 Sep 2023 19:40:41 +0300 Subject: [PATCH 15/23] Fixed initial tables creation --- back/db.py | 3 +-- back/main.py | 5 +++++ 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/back/db.py b/back/db.py index 6e13214..a0dcf4b 100644 --- a/back/db.py +++ b/back/db.py @@ -17,5 +17,4 @@ Base = declarative_base() # Создаем таблицы async def init_models(): async with engine.begin() as conn: - await conn.run_sync(Base.metadata.drop_all) - await conn.run_sync(Base.metadata.create_all) \ No newline at end of file + await conn.run_sync(Base.metadata.create_all) diff --git a/back/main.py b/back/main.py index 564539b..23d2504 100644 --- a/back/main.py +++ b/back/main.py @@ -3,6 +3,8 @@ import uvicorn from .api import app as app_fastapi from .scheduler import app as app_rocketry +from .db import init_models + class Server(uvicorn.Server): """Customized uvicorn.Server @@ -16,6 +18,9 @@ class Server(uvicorn.Server): async def main(): "Run scheduler and the API" + + await init_models() + server = Server(config=uvicorn.Config(app_fastapi, workers=1, loop="asyncio", host="0.0.0.0")) api = asyncio.create_task(server.serve()) From 64a84d7c70bd30b3a06c71121320011db1271881 Mon Sep 17 00:00:00 2001 From: dm1sh Date: Fri, 8 Sep 2023 19:40:44 +0300 Subject: [PATCH 16/23] Switched obsolete checking period to daily --- back/scheduler.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/back/scheduler.py b/back/scheduler.py index cd44620..9842d9f 100644 --- a/back/scheduler.py +++ b/back/scheduler.py @@ -7,7 +7,7 @@ from .db import async_session app = Rocketry(execution="async") # Create task: -@app.task('minutely') +@app.task('daily') async def daily_check(): # Фильтруем по сроку годности await add_poems_and_filters.check_obsolete(async_session, current_date=datetime.date.today()) From 558922dcf4a46de4b207ffe583976e61ae72cbaa Mon Sep 17 00:00:00 2001 From: dm1sh Date: Fri, 8 Sep 2023 19:40:46 +0300 Subject: [PATCH 17/23] Removed useless files --- back/text121.txt | 2706 ------------------------------------------ back/unimportant.env | 5 - 2 files changed, 2711 deletions(-) delete mode 100644 back/text121.txt delete mode 100644 back/unimportant.env diff --git a/back/text121.txt b/back/text121.txt deleted file mode 100644 index 228dbff..0000000 --- a/back/text121.txt +++ /dev/null @@ -1,2706 +0,0 @@ - -стих 1 -К Чаадаеву - -Любви, надежды, тихой славы -Недолго нежил нас обман, -Исчезли юные забавы, -Как сон, как утренний туман; -Но в нас горит еще желанье, -Под гнетом власти роковой -Нетерпеливою душой -Отчизны внемлем призыванье. -Мы ждем с томленьем упованья -Минуты вольности святой, -Как ждет любовник молодой -Минуты верного свиданья. -Пока свободою горим, -Пока сердца для чести живы, -Мой друг, отчизне посвятим -Души прекрасные порывы! -Товарищ, верь: взойдет она, -Звезда пленительного счастья, -Россия вспрянет ото сна, -И на обломках самовластья -Напишут наши имена! - -Александр Сергеевич Пушкин -(1799-1837) - -стих 2 -Отрывок из «Разговора с фининспектором о поэзии» - -— Поэзия - — вся! — - езда в незнаемое. -Поэзия — - та же добыча радия. -В грамм добыча, - в год труды. -Изводишь - единого слова ради -тысячи тонн - словесной руды. -Но как - испепеляюще - слов этих жжение -рядом - с тлением - слова-сырца. -Эти слова - приводят в движение -тысячи лет - миллионов сердца. - -Владимир Владимирович Маяковский -(1893-1930) - -стих 3 -Фабрика - -В соседнем доме окна жолты. -По вечерам — по вечерам -Скрипят задумчивые болты, -Подходят люди к воротам. -И глухо заперты ворота, -А на стене — а на стене -Недвижный кто-то, черный кто-то -Людей считает в тишине. -Я слышу всё с моей вершины: -Он медным голосом зовет -Согнуть измученные спины -Внизу собравшийся народ. -Они войдут и разбредутся, -Навалят на спины кули. -И в желтых окнах засмеются, -Что этих нищих провели. - -Александр Александрович Блок -(1880-1921) - -стих 4 -Надпись к статуе Петра Великого - -Се образ изваян премудрого героя, -Что, ради подданных лишив себя покоя, -Последний принял чин и царствуя служил, -Свои законы сам примером утвердил, -Рожденны к скипетру, простер в работу руки, -Монаршу власть скрывал, чтоб нам открыть науки. -Когда он строил град, сносил труды в войнах, -В землях далеких был и странствовал в морях, -Художников сбирал и обучал солдатов, -Домашних побеждал и внешних сопостатов; -И словом, се есть Петр, отечества Отец; -Земное божество Россия почитает, -И столько олтарей пред зраком сим пылает, -Коль много есть ему обязанных сердец. - -Михаил Васильевич Ломоносов -(1711-1765) - -стих 5 -Пчелка - -Пчелка златая! -Что ты жужжишь? -Всё вкруг летая, -Прочь не летишь? -Или ты любишь -Лизу мою? -Соты ль душисты -В желтых власах, -Розы ль огнисты -В алых устах, -Сахар ли белый -Грудь у нее? -Пчелка златая! -Что ты жужжишь? -Слышу, вздыхая, -Мне говоришь: -«К меду прилипнув, -С ним и умру». - -Гавриил Романович Державин -(1711-1765) - -стих 6 -Не позволяй душе лениться - -Не позволяй душе лениться! -Чтоб в ступе воду не толочь, -Душа обязана трудиться -И день и ночь, и день и ночь! - -Гони ее от дома к дому, -Тащи с этапа на этап, -По пустырю, по бурелому -Через сугроб, через ухаб! - -Не разрешай ей спать в постели -При свете утренней звезды, -Держи лентяйку в черном теле -И не снимай с нее узды! - -Коль дать ей вздумаешь поблажку, -Освобождая от работ, -Она последнюю рубашку -С тебя без жалости сорвет. - -А ты хватай ее за плечи, -Учи и мучай дотемна, -Чтоб жить с тобой по-человечьи -Училась заново она. - -Она рабыня и царица, -Она работница и дочь, -Она обязана трудиться -И день и ночь, и день и ночь! - -Николай Алексеевич Заболоцкий -(1903-1958) - -стих 7 -Апреля первое число - -Апреля в первый день обман, -Забава общая в народе, -На выдумки лукавить дан, -Нагая правда в нем не в моде, -И всё обманом заросло -Апреля в первое число.Одни шлют радостную весть, -Друзей к досаде утешают, -Другие лгут и чем ни есть -Друзей к досаде устрашают. -Лукавство враки принесло -Апреля в первое число.На что сей только день один -Обмана праздником уставлен? -Без самых малых он причин -Излишне столько препрославлен, -Весь год такое ремесло, -Так целый год сие число. - -Александр Петрович Сумароков -(1717-1777) - -стих 8 -Малютка-жизнь - -Я жизнь люблю и умереть боюсь. -Взглянули бы, как я под током бьюсь -И гнусь, как язь в руках у рыболова, -Когда я перевоплощаюсь в слово. -Но я не рыба и не рыболов. -И я из обитателей углов, -Похожий на Раскольникова с виду. -Как скрипку я держу свою обиду. -Терзай меня — не изменюсь в лице. -Жизнь хороша, особенно в конце, -Хоть под дождем и без гроша в кармане, -Хоть в Судный день — с иголкою в гортани. -А! Этот сон! Малютка-жизнь, дыши, -Возьми мои последние гроши, -Не отпускай меня вниз головою -В пространство мировое, шаровое! - -Арсений Александрович Тарковский -(1907–1989) - -стих 9 -Лес осенью - -Меж редеющих верхушек -Показалась синева. -Зашумела у опушек -Ярко-желтая листва. -Птиц не слышно. Треснет мелкий -Обломившийся сучок, -И, хвостом мелькая, белка -Легкий делает прыжок. -Стала ель в лесу заметней – -Бережет густую тень. -Подосиновик последний -Сдвинул шапку набекрень. - -Александр Трифонович Твардовский -(1910-1971) - -стих 10 -Дружба - -Скатившись с горной высоты, -Лежал на прахе дуб, перунами разбитый; -А с ним и гибкий плющ, кругом его обвитый. -О Дружба, это ты! - -Василий Андреевич Жуковский -(1783-1852) - -стих 11 -Я пришел к тебе с приветом… - -Я пришёл к тебе с приветом, -Рассказать, что солнце встало, -Что оно горячим светом -По листам затрепетало; -Рассказать, что лес проснулся, -Весь проснулся, веткой каждой, -Каждой птицей встрепенулся -И весенней полон жаждой; -Рассказать, что с той же страстью, -Как вчера, пришёл я снова, -Что душа всё так же счастью -И тебе служить готова; -Рассказать, что отовсюду -На меня весельем веет, -Что не знаю сам, что́ буду -Петь — но только песня зреет. - -Афанасий Афанасьевич Шеншин -(1820-1892) - -стих 12 -Неохотно и несмело… - -Неохотно и несмело -Солнце смотрит на поля — -Чу! за тучей прогремело, -Принахмурилась земля. -Ветра теплого порывы — -Дальний гром и дождь порой… -Зеленеющие нивы -Зеленее под грозой. -Вот пробилась из-за тучи -Синей молнии струя — -Пламень белый и летучий -Окаймил ее края. -Чаще капли дождевые, -Вихрем пыль летит с полей, -И раскаты громовые -Все сердитей и смелей… -Солнце раз еще взглянуло -Исподлобья на поля, -И в сиянье потонула -Вся смятенная земля. - -Фёдор Иванович Тютчев -(1803-1873) - -стих 13 -Ананасы в шампанском!.. - -Ананасы в шампанском! Ананасы в шампанском! -Удивительно вкусно, искристо и остро! -Весь я в чем-то норвежском! Весь я в чем-то испанском! -Вдохновляюсь порывно! И берусь за перо! - - -Стрекот аэропланов! Беги автомобилей! -Ветропросвист экспрессов! Крылолёт буеров! -Кто-то здесь зацелован! Там кого-то побили! -Ананасы в шампанском — это пульс вечеров! - - -В группе девушек нервных, в остром обществе дамском -Я трагедию жизни претворю в грезофарс… -Ананасы в шампанском! Ананасы в шампанском! -Из Москвы — в Нагасаки! Из Нью-Йорка — на Марс! - -Игорь-Северянин -(1887-1941) - -стих 14 -В палате наркоманов - -Не писать мне повестей, романов, -Не читать фантастику в углу, - -Я лежу в палате наркоманов, -Чувствую — сам сяду на иглу. - -Кто-то раны лечил боевые, -Кто-то так, обеспечил тылы… -Эх вы парни мои шировые, -Поскорее слезайте с иглы! - -В душу мне сомнения запали, -Голову вопросами сверлят, - -Я лежу в палате, где глотали, -Нюхали, кололи все подряд. - -Кто-то там проколол свою душу, -Кто-то просто остался один… -Эй вы парни, бросайте "морфушу" - -Перейдите на апоморфин! - -Рядом незнакомый шизофреник - -В него тайно няня влюблена - -Говорит: "Когда не будет денег - -Перейду на капли Зимина". - -Кто-то там проколол свою совесть, -Кто-то в сердце вкурил анашу… -Эх вы парни, про вас нужно повесть, -Жалко, повестей я не пишу. - -Владимир Семёнович Высоцкий -(1938-1980) - -стих 15 -Отрывок из «Рассказа о неизвестном герое» - -Ищут пожарные, -Ищет милиция, -Ищут фотографы -В нашей столице, -Ищут давно, -Но не могут найти -Парня какого-то -Лет двадцати. -Среднего роста, -Плечистый и крепкий, -Ходит он в белой -Футболке и кепке. -Знак «ГТО» -На груди у него. -Больше не знают -О нем ничего. -Многие парни -Плечисты и крепки. -Многие носят -Футболки и кепки. -Много в столице -Таких же значков. -Каждый -К труду-обороне -Готов. - -Самуил Яковлевич Маршак -(1887-1964) - -стих 16 -Изволь ведать, что скорбь есть смертельная всяко - -Изволь ведать, что скорбь есть смертельная всяко, -Когда кто любит верно, -Но жестоку безмерно, -И котора смеется над ним всюду тако. -Можно ль жить любовнику, чтоб милу не видеть? -Могу ль я в надежде быть, -Чтоб вас ныне умолить? -Но ежели я како возмог вас обидеть, -За то я чрез мою скорбь довольно наказан. -Извольте умилиться, -Со мною помириться: -Ибо я к тебе вечно чрез любовь привязан. - -Василий Кириллович Тредиаковский -(1703-1768) - -стих 17 -Гамлет - -Гул затих. Я вышел на подмостки. -Прислонясь к дверному косяку, -Я ловлю в далеком отголоске, -Что случится на моем веку. -На меня наставлен сумрак ночи -Тысячью биноклей на оси. -Если только можно, Авва Отче, -Чашу эту мимо пронеси. -Я люблю твой замысел упрямый -И играть согласен эту роль. -Но сейчас идет другая драма, -И на этот раз меня уволь. -Но продуман распорядок действий, -И неотвратим конец пути. -Я один, все тонет в фарисействе. -Жизнь прожить — не поле перейти. -Борис Леонидович Пастернак -(1890-1960) - -стих 18 -Обращение писателя к читателям и Кремлёвские звёзды -Я к вам обращаюсь, товарищи, дети: -Полезнее книги нет вещи на свете! -Пусть книги друзьями заходят в дома, -Читайте всю жизнь, набирайтесь ума! -___________________________________ -Кремлёвские звёзды -Над нами горят, -Повсюду доходит их свет! -Хорошая Родина есть у ребят, -И лучше той Родины -Нет! - -Сергей Владимирович Михалков -(1913-2009) - -стих 19 -Гроза идет - -Движется нахмуренная туча, -Обложив полнеба вдалеке, -Движется, огромна и тягуча, -С фонарем в приподнятой руке. - -Сколько раз она меня ловила, -Сколько раз, сверкая серебром, -Сломанными молниями била, -Каменный выкатывала гром! - -Сколько раз, ее увидев в поле, -Замедлял я робкие шаги -И стоял, сливаясь поневоле -С белым блеском вольтовой дуги! - -Вот он — кедр у нашего балкона. -Надвое громами расщеплен, -Он стоит, и мертвая корона -Подпирает темный небосклон. - -Сквозь живое сердце древесины -Пролегает рана от огня, -Иглы почерневшие с вершины -Осыпают звездами меня. - -Пой мне песню, дерево печали! -Я, как ты, ворвался в высоту, -Но меня лишь молнии встречали -И огнем сжигали на лету. - -Почему же, надвое расколот, -Я, как ты, не умер у крыльца, -И в душе все тот же лютый голод, -И любовь, и песни до конца! - -Николай Алексеевич Заболоцкий -(1903-1958) - -стих 20 -Зимняя дорога -Сквозь волнистые туманы -Пробирается луна, -На печальные поляны -Льет печально свет она. - -По дороге зимней, скучной -Тройка борзая бежит, -Колокольчик однозвучный -Утомительно гремит. - -Что-то слышится родное -В долгих песнях ямщика: -То разгулье удалое, -То сердечная тоска… - -Ни огня, ни черной хаты, -Глушь и снег… Навстречу мне -Только версты полосаты -Попадаются одне… - -Скучно, грустно… Завтра, Нина, -Завтра к милой возвратясь, -Я забудусь у камина, -Загляжусь не наглядясь. - -Звучно стрелка часовая -Мерный круг свой совершит, -И, докучных удаляя, -Полночь нас не разлучит. - -Грустно, Нина: путь мой скучен, -Дремля смолкнул мой ямщик, -Колокольчик однозвучен, -Отуманен лунный лик. - -Александр Сергеевич Пушкин -(1799-1837) - -стих 21 -На день города - -Город хмурых улыбок -Сойджаков и чадов. -Жизнь глыбы гранита -Петрова начала. - -Жёлтая краска -На мокром холсте. -Этот вызов природе -Стоит на Ниве. - -Велик Петербург! -Он — культуры завод, -Где Цой кочегарил, -Где актёрствовал Блок. - -Ведь с Рубинштейна -Идут культуры мосты. -Туда Ленин спрятал -Бункер русской души. - -Вито Царе -(1411-1478) - -стих 22 -На тленность - -Река времён в своём стремленьи -Уносит все дела людей -И топит в пропасти забвенья -Народы, царства и царей. -А если что и остаётся -Чрез звуки лиры и трубы, -То вечности жерлом пожрётся -И общей не уйдёт судьбы. - -Гавриил Романович Державин -(1743-1816) - -стих 23 -Петербургским цензорам - -Перед вами нуль Тимковский! -В вашей славе он погас; -Вы по совести поповской, -Цензируя, жмете нас. -Славьтесь, Бируков, Красовский! -Вам дивится даже князь! -Член тюремный и Библейский -Цензор, мистик и срамец, -Он с душонкою еврейской, -Наш гонитель, князя льстец. -Славься, славься, дух лакейский, -Славься, доблестный подлец! -Вас и дух святый робеет; -Он, как мы у вас в когтях; -Появиться он не смеет -Даже в Глинкиных стихах. -Вот как семя злое зреет! -Вот как всё у нас в тисках! -Ни угрозою, ни лаской, -Видно, вас не уломать; -Олин и Григорий Спасский -Подозренья в вас родят. -Славьтесь цензорской указкой! -Таски вам не миновать. - -Антон Антонович Дельвиг -(1798-1831) - -стих 24 -Мой Ленинград - -Над Россиею -Небо синее, -Небо синее над Невой, -В целом мире нет, -Нет красивее -Ленинграда моего. - -Нам всё помнится: в ночи зимние -Над Россией, над родимою страной, -Весь израненный, в снежном инее -Гордо высился печальный город мой. - -Славы города, где сражались мы, -Никому ты, как винтовки, не отдашь. -Вместе с солнышком пробуждается -Наша песня, наша слава, город наш! - -Алексей Иванович Фатьянов -(1919-1959) - -стих 25 -Лето ленинградское в неволе - -Лето ленинградское в неволе. -Всё брожу по новым пустырям, -И сухой репейник на подоле -Приношу я в сумерках к дверям. - -Белой ночью всё зудит комарик, -На обиды жалуется мне. -За окном шаги на тротуаре — -Кто-то возвращается к жене. - -И всю ночь далекий запах гари -Не дает забыть мне о войне. - -Наталья Крандиевская-Толстая -(1888-1963) - -стих 26 -Ленинград - -Есть в Ленинграде, кроме неба и Невы, -Простора площадей, разросшейся листвы, -И кроме статуй, и мостов, и снов державы, -И кроме незакрывшейся, как рана, славы, -Которая проходит ночью по проспектам, -Почти незримая, из серебра и пепла, — -Есть в Ленинграде жесткие глаза и та, -Для прошлого загадочная, немота, -Тот горько сжатый рот, те обручи на сердце, -Что, может быть, одни спасли его от смерти. -И если ты — гранит, учись у глаз горячих: -Они сухи, сухи, когда и камни плачут. - -Илья Григорьевич Эренбург -(1891-1967) - -стих 27 -В небе тают облака - -В небе тают облака, -И, лучистая на зное, -В искрах катится река, -Словно зеркало стальное… - -Час от часу жар сильней, -Тень ушла к немым дубровам, -И с белеющих полей -Веет запахом медовым. - -Чудный день! Пройдут века — -Так же будут, в вечном строе, -Течь и искриться река -И поля дышать на зное. - -Фёдор Иванович Тютчев -(1803-1873) - -стих 28 -Майская ночь - -Отсталых туч над нами пролетает -Последняя толпа. -Прозрачный их отрезок мягко тает -У лунного серпа. - -Царит весны таинственная сила -С звездами на челе.- -Ты, нежная! Ты счастье мне сулила -На суетной земле. - -А счастье где? Не здесь, в среде убогой, -А вон оно — как дым. -За ним! за ним! воздушною дорогой — -И в вечность улетим! - -Афанасий Афанасьевич Шеншин -(1820-1892) - -стих 29 -Кинжал - -Люблю тебя, булатный мой кинжал, -Товарищ светлый и холодный. -Задумчивый грузин на месть тебя ковал, -На грозный бой точил черкес свободный. - -Лилейная рука тебя мне поднесла -В знак памяти, в минуту расставанья, -И в первый раз не кровь вдоль по тебе текла, -Но светлая слеза — жемчужина страданья. - -И черные глаза, остановясь на мне, -Исполнены таинственной печали, -Как сталь твоя при трепетном огне, -То вдруг тускнели, то сверкали. - -Ты дан мне в спутники, любви залог немой, -И страннику в тебе пример не бесполезный: -Да, я не изменюсь и буду тверд душой, -Как ты, как ты, мой друг железный. - -Михаил Юрьевич Лермонтов -(1814-1841) - -стих 30 -Туманы - -Туманы таяли и вновь росли над лугом, -Ползли, холодные, над мертвою травой, -И бледные цветы шепталися друг с другом, -Скорбя застывшею листвой. - -Они хотели жить, блистая лепестками, -Вздыхать, дышать, гореть, лелеять аромат, -Любиться с пчелами, дрожать под мотыльками, -Из мира сделать пышный сад. - -Они изнемогли под сыростью тумана, -И жаждали зари, и жаждали огня, -И плакали, что смерть приходит слишком рано, -Что поздно вспыхнут краски дня. - -И день забрезжился. Туманы задрожали, -Воздушным кораблем повисли над землей. -И ветры буйные, смеясь, его качали, -И свет боролся с тусклой мглой. - -Все жарче день пылал сверкающим приветом, -Холодный круг земли дыханьем горяча,- -И облако зажглось, пронизанное светом -Непобедимого луча! - -Константин Дмитриевич Бальмонт -(1867-1942) - -стих 31 -Голос - -Такая жизненная полоса, -а, может быть, предначертанье свыше. -Других я различаю голоса, -а собственного голоса не слышу. -И все же он, как близкая родня, -единственный, -кто согревает в стужу. -До смерти будет он внутри меня. -Да и потом -не вырвется наружу. - -Роберт Иванович Рождественский -(1938-1994) - -стих 32 -Горький - -Талант смеялся… Бирюзовый штиль, -Сияющий прозрачностью зеркальной, -Сменялся в нём вспенённостью сверкальной, -Морской травой и солью пахнул стиль. - -Сласть слёз солёных знала Изергиль, -И сладость волн солёных впита Мальвой. -Под каждой кофточкой, под каждой тальмой — -Цветов сердец зиждительная пыль. - -Всю жизнь ничьих сокровищ не наследник, -Живописал высокий исповедник -Души, смотря на мир не свысока. - -Прислушайтесь: в Сорренто, как на Капри, -Ещё хрустальные сочатся капли -Ключистого таланта босяка. - -Игорь-Северянин -(1887-1941) - -стих 33 -Бюрократ и смерть - -За Бюрократом Смерть пришла, -Полдня в приемной прождала, -Полдня в приемной просидела, -Полдня на очередь глядела, - -Что всё росла, - -А не редела… -И, не дождавшись… померла! - -«Что-о? Бюрократ сильнее Смерти?» -Нет! -Но живучи всё же, черти! - -Сергей Владимирович Михалков -(1913-2009) - -стих 34 -Ласточки пропали - -Ласточки пропали, -А вчера зарёй -Всё грачи летали -Да, как сеть, мелькали -Вон над той горой. - -С вечера все спится, -На дворе темно. -Лист сухой валится, -Ночью ветер злится -Да стучит в окно. - -Лучше б снег да вьюгу -Встретить грудью рад! -Словно как с испугу -Раскричавшись, к югу -Журавли летят. - -Выйдешь — поневоле -Тяжело — хоть плачь! -Смотришь — через поле -Перекати-поле -Прыгает, как мяч. - -Афанасий Афанасьевич Шеншин -(1820-1892) - -стих 35 -Вечернее размышления... - -Лице свое скрывает день, -Поля покрыла мрачна ночь; -Взошла на горы черна тень, -Лучи от нас склонились прочь. -Открылась бездна звезд полна; -Звездам числа нет, бездне дна. - -Песчинка как в морских волнах, -Как мала искра в вечном льде, -Как в сильном вихре тонкий прах, -В свирепом как перо огне, -Так я, в сей бездне углублен, -Теряюсь, мысльми утомлен! - -Уста премудрых нам гласят: -«Там разных множество светов, -Несчетны солнца там горят, -Народы там и круг веков; -Для общей славы божества -Там равна сила естества». - -Но где ж, натура, твой закон? -С полночных стран встает заря! -Не солнце ль ставит там свой трон? -Не льдисты ль мещут огнь моря? -Се хладный пламень нас покрыл! -Се в ночь на землю день вступил! - -О вы, которых быстрый зрак -Пронзает в книгу вечных прав, -Которым малый вещи знак -Являет естества устав, -Вам путь известен всех планет; -Скажите, что нас так мятет? - -Что зыблет ясный ночью луч? -Что тонкий пламень в твердь разит? -Как молния без грозных туч -Стремится от земли в зенит? -Как может быть, чтоб мерзлый пар -Среди зимы рождал пожар? - -Там спорит жирна мгла с водой; -Иль солнечны лучи блестят, -Склонясь сквозь воздух к нам густой; -Иль тучных гор верьхи горят; -Иль в море дуть престал зефир, -И гладки волны бьют в ефир. - -Сомнений полон ваш ответ -О том, что окрест ближних мест. -Скажите ж, коль пространен свет? -И что малейших дале звезд? -Несведом тварей вам конец? -Скажите ж, коль велик Творец? - -Михаил Васильевич Ломоносов -(1711-1765) - -стих 36 -Фонтан - -Смотри, как облаком живым -Фонтан сияющий клубится; -Как пламенеет, как дробится -Его на солнце влажный дым. -Лучом поднявшись к небу, он -Коснулся высоты заветной — -И снова пылью огнецветной -Ниспасть на землю осужден. -О смертной мысли водомет, -О водомет неистощимый! -Какой закон непостижимый -Тебя стремит, тебя мятет? -Как жадно к небу рвешься ты!.. -Но длань незримо-роковая, -Твой луч упорный преломляя, -Свергает в брызгах с высоты… - -Фёдор Иванович Тютчев -(1803-1873) - -стих 37 -Стань самим собой - -Когда тебе придется туго, -Найдешь и сто рублей и друга. -Себя найти куда трудней, -Чем друга или сто рублей. - -Ты вывернешься наизнанку, -Себя обшаришь спозаранку, -В одно смешаешь явь и сны, -Увидишь мир со стороны. - -И все и всех найдешь в порядке. -А ты — как ряженый на святки — -Играешь в прятки сам с собой, -С твоим искусством и судьбой. - -В чужом костюме ходит Гамлет -И кое-что про что-то мямлит,- -Он хочет Моиси играть, -А не врагов отца карать. - -Из миллиона вероятий -Тебе одно придется кстати, -Но не дается, как назло -Твое заветное число. - -Загородил полнеба гений, -Не по тебе его ступени, -Но даже под его стопой -Ты должен стать самим собой. - -Найдешь и у пророка слово, -Но слово лучше у немого, -И ярче краска у слепца, -Когда отыскан угол зренья -И ты при вспышки озаренья -Собой угадан до конца. - -Арсений Александрович Тарковский -(1907-1989) - -стих 38 -Бабочка - -Ты прав. Одним воздушным очертаньем -Я так мила. -Весь бархат мой с его живым миганьем — -Лишь два крыла. - -Не спрашивай: откуда появилась? -Куда спешу? -Здесь на цветок я легкий опустилась -И вот — дышу. - -Надолго ли, без цели, без усилья, -Дышать хочу? -Вот-вот сейчас, сверкнув, раскину крылья -И улечу. - -Афанасий Афанасьевич Шеншин -(1820-1892) - -стих 39 -Зачем, не только в то лишь время… - -Зачем, не только в то лишь время, -Когда его тягчило бремя -Фемидиных несносных уз, -Отрекся он от милых муз -И с ними разорвал любезный, -Для всех питомцев их полезный, -Скрепленный славою союз? - -Но даже, посреди свободы, -Сестер парнасских хороводы -Его уж боле не манят? -Но пусть неблагодарный знает, -Что хоть он их и забывает, -Они взаимно не хотят -Платить любимцу их забвеньем -И с нежным дружеским терпеньем -Бессмертный лавр ему хранят. - -Василий Васильевич Капнист -(1758-1823) - -стих 40 -На смерть Блока - -Мгновенья высокой красы! — -Совсем незнакомый, чужой, -В одиннадцатом году, -Прислал мне «Ночные часы». -Я надпись его приведу: -«Поэту с открытой душой». - -Десятый кончается год -С тех пор. Мы не сблизились с ним. -Встречаясь, друг к другу не шли: -Не стужа ль безгранных высот -Смущала поэта земли?.. -Но дух его свято храним -Раздвоенным духом моим. - -Теперь пережить мне дано -Кончину еще одного -Собрата-гиганта. О, Русь -Согбенная! горбь, еще горбь -Болящую спину. Кого -Теряешь ты ныне? Боюсь, -Не слишком ли многое? Но -Удел твой — победная скорбь. - -Пусть варваром Запад зовет -Ему непосильный Восток! -Пусть смотрит с презреньем в лорнет -На русскую душу: глубок -Страданьем очищенный взлет, -Какого у Запада нет. -Вселенную, знайте, спасет -Наш варварский русский Восток! - -Игорь-Северянин -(1887-1941) - -стих 41 -Жарбог - -Жарбог! Жарбог! -Я в тебя грезитвой мечу, -Дола славный стаедей, -О, взметни ты мне навстречу -Стаю вольных жарирей. -Жарбог! Жарбог! -Волю видеть огнезарную -Стаю легких жарирей, -Дабы радугой стожарною -Вспыхнул морок наших дней. - -Велимир Хлебников -(1885-1922) - -стих 42 -Эхо - -Ревет ли зверь в лесу глухом, -Трубит ли рог, гремит ли гром, -Поет ли дева за холмом — -На всякий звук -Свой отклик в воздухе пустом -Родишь ты вдруг. - -Ты внемлешь грохоту громов, -И гласу бури и валов, -И крику сельских пастухов — -И шлешь ответ; -Тебе ж нет отзыва… Таков -И ты, поэт! - -Александр Сергеевич Пушкин -(1799-1837) - -стих 43 -Ветер принес издалёка - -Ветер принес издалёка -Песни весенней намек, -Где-то светло и глубоко -Неба открылся клочок. - -В этой бездонной лазури, -В сумерках близкой весны -Плакали зимние бури, -Реяли звездные сны. - -Робко, темно и глубоко -Плакали струны мои. -Ветер принес издалёка -Звучные песни твои. - -Александр Александрович Блок -(1880-1921) - -стих 44 -Похороны - -Толпы рабочих в волнах золотого заката. -Яркие стяги свиваются, плещутся, пляшут. - -На фонарях, над железной решеткой, -С крыш над домами -Платками -Машут. - -Смеркается. -Месяц серебряный, юный -Поднимается. - -Темною лентой толпа извивается. -Скачут драгуны. - -Вдоль оград, тротуаров,- вдоль скверов, -Над железной решеткой,- -Частый, короткий -Треск -Револьверов. - -Свищут пули, кося… -Ясный блеск -Там по взвизгнувшим саблям взвился. - -Глуше напев похорон. -Пули и плачут, и косят. -Новые тучи кровавых знамен — -Там, в отдаленье — проносят. - -Андрей Белый -(1880-1934) - -стих 45 -Лжи на свете нет меры - -Лжи на свете нет меры, -То ж лукавство да то ж. -Где ни ступишь, тут ложь; -Скроюсь вечно в пещеры, -В мир не помня дверей: -Люди злее зверей. - -Я сокроюсь от мира, -В мире дружба — лишь лесть -И притворная честь; -И под видом зефира -Скрыта злоба и яд, -В райском образе ад. - -В нем крючок богатится, -Правду в рынок нося -И законы кося; -Льстец у бар там лестится, -Припадая к ногам, -Их подобя богам. - -Там Кащей горько плачет: -«Кожу, кожу дерут!» -Долг с Кащея берут; -Он мешки в стену прячет, -А лишась тех вещей, -Стонет, стонет Кащей. - -Александр Петрович Сумароков -(1717-1777) - -стих 46 -Пробуждение - -Зефир последний свеял сон -С ресниц, окованных мечтами, -Но я — не к счастью пробужден -Зефира тихими крылами. -Ни сладость розовых лучей -Предтечи утреннего Феба, -Ни кроткий блеск лазури неба, -Ни запах, веющий с полей, -Ни быстрый лёт коня ретива -По скату бархатных лугов, -И гончих лай, и звон рогов -Вокруг пустынного залива — -Ничто души не веселит, -Души, встревоженной мечтами, -И гордый ум не победит -Любви — холодными словами. - -Константин Николаевич Батюшков -(1787-1855) - -стих 47 -Не более, чем сон - -Мне удивительный вчера приснился сон: -Я ехал с девушкой, стихи читавшей Блока. -Лошадка тихо шла. Шуршало колесо. -И слёзы капали. И вился русый локон. - -И больше ничего мой сон не содержал. -Но, потрясённый им, взволнованный глубоко, -Весь день я думаю, встревоженно дрожа, -О странной девушке, не позабывшей Блока. - -Игорь-Северянин -(1887-1941) - -стих 48 -Зреет рожь над жаркой нивой - -Зреет рожь над жаркой нивой, -И от нивы и до нивы -Гонит ветер прихотливый -Золотые переливы. - -Робко месяц смотрит в очи, -Изумлен, что день не минул, -Но широко в область ночи -День объятия раскинул. - -Над безбрежной жатвой хлеба -Меж заката и востока -Лишь на миг смежает небо -Огнедышащее око. - -Афанасий Афанасьевич Шеншин -(1820-1892) - -стих 49 -Девушка пела в церковном хоре - -Девушка пела в церковном хоре -О всех усталых в чужом краю, -О всех кораблях, ушедших в море, -О всех, забывших радость свою. - -Так пел ее голос, летящий в купол, -И луч сиял на белом плече, -И каждый из мрака смотрел и слушал, -Как белое платье пело в луче. - -И всем казалось, что радость будет, -Что в тихой заводи все корабли, -Что на чужбине усталые люди -Светлую жизнь себе обрели. - -И голос был сладок, и луч был тонок, -И только высоко, у Царских Врат, -Причастный Тайнам,- плакал ребенок -О том, что никто не придет назад. - -Александр Александрович Блок -(1880-1921) - -стих 50 -Опять стою я над Невой - -Опять стою я над Невой, -И снова, как в былые годы, -Смотрю и я, как бы живой, -На эти дремлющие воды. - -Нет искр в небесной синеве, -Все стихло в бледном обаянье, -Лишь по задумчивой Неве -Струится лунное сиянье. - -Во сне ль все это снится мне, -Или гляжу я в самом деле, -На что при этой же луне -С тобой живые мы глядели? - -Федор Иванович Тютчев -(1803-1873) - -стих 51 -Одним толчком согнать ладью живую - -Одним толчком согнать ладью живую -С наглаженных отливами песков, -Одной волной подняться в жизнь иную, -Учуять ветр с цветущих берегов, - -Тоскливый сон прервать единым звуком, -Упиться вдруг неведомым, родным, -Дать жизни вздох, дать сладость тайным мукам, -Чужое вмиг почувствовать своим, - -Шепнуть о том, пред чем язык немеет, -Усилить бой бестрепетных сердец — -Вот чем певец лишь избранный владеет, -Вот в чем его и признак и венец! - -Афанасий Афанасьевич Фет -(1820-1892) - -стих 52 -Закат Солнца - -Уж солнышко садится -За дальный неба круг, -И тень с горы ложится -На пестровидный луг. -Светильник дня прекрасный! -Ложись и ты, почий: -С зарею новой ясны -Ты вновь прострешь лучи. - -Не тот удел светилу -Дней смертного сужден: -Погас ли — в тьму унылу -Навек он погружен. -Так должно ль о беспрочной -Светильне нам жалеть, -Когда лишь краткосрочно -Назначено ей тлеть? - -Пускай, кто счастье, радость -Мнит в жизни сей обресть, -Кто льстится тем, что младость -Не может вдруг отцвесть,— -Пускай, пленясь мечтами, -Тот алчет долго жить -И обвивать цветами -Лишь паутинну нить; - -А мне, кого печалью -Свирепый рок гнетет, -Почто пленяться далью, -Где терн один растет? -Светильник дня прекрасный, -Ложися, опочий, -Но от страдальца ясны -Сокрой навек лучи. - -Василий Васильевич Капнист -(1758-1823) - -стих 53 -Шумит кустарник - -Шумит кустарник… На утес -Олень веселый выбегает, -Пугливо он подножный лес -С вершины острой озирает, -Глядит на светлые луга, -Глядит на синий свод небесный -И на днепровские брега, -Венчанны чащею древесной. -Недвижим, строен он стоит -И чутким ухом шевелит… - -Но дрогнул он — незапный звук -Его коснулся — боязливо -Он шею вытянул и вдруг -С вершины прянул… - -Александр Сергеевич Пушкин -(1799-1837) - -стих 54 -В цирке - -Клоун в огненном кольце… -Хохот мерзкий, как проказа, -И на гипсовом лице -Два горящих болью глаза. - -Лязг оркестра; свист и стук. -Точно каждый озабочен -Заглушить позорный звук -Мокро хлещущих пощечин. - -Как огонь, подвижный круг… -Люди — звери, люди — гады, -Как стоглазый, злой паук, -Заплетают в кольца взгляды. - -Все крикливо, все пестро… -Мне б хотелось вызвать снова -Образ бледного, больного, -Грациозного Пьеро… - -В лунном свете с мандолиной -Он поет в своем окне -Песню страсти лебединой -Коломбине и луне. - -Хохот мерзкий, как проказа; -Клоун в огненном кольце. -И на гипсовом лице -Два горящих болью глаза… - -Максимилиан Александрович Волошин -(1877-1932) - -стих 55 -Поэза о незабудках - -Поет Июнь, и песни этой зной -Палит мне грудь, и грезы, и рассудок. -Я изнемог и жажду незабудок, -Детей канав, что грезят под луной -Иным цветком, иною стороной. -Я их хочу: сирени запах жуток. -Он грудь пьянит несбыточной весной; -Я их хочу: их взор лазурный чуток, -И аромат целебен, как простор. -Как я люблю участливый их взор! -Стыдливые, как томны ваши чары… -Нарвите мне смеющийся букет, -В нем будет то, чего в сирени нет, -А ты, сирень, увянь в тоске нектара. - -Игорь-Северянин -(1887-1941) - -стих 56 -Властителям и судиям - -Восстал всевышний бог, да судит -Земных богов во сонме их; -Доколе, рек, доколь вам будет -Щадить неправедных и злых? - -Ваш долг есть: сохранять законы, -На лица сильных не взирать, -Без помощи, без обороны -Сирот и вдов не оставлять. - -Ваш долг: спасать от бед невинных, -Несчастливым подать покров; -От сильных защищать бессильных, -Исторгнуть бедных из оков. - -Не внемлют! видят — и не знают! -Покрыты мздою очеса: -Злодействы землю потрясают, -Неправда зыблет небеса. - -Цари! Я мнил, вы боги властны, -Никто над вами не судья, -Но вы, как я подобно, страстны, -И так же смертны, как и я. - -И вы подобно так падете, -Как с древ увядший лист падет! -И вы подобно так умрете, -Как ваш последний раб умрет! - -Воскресни, боже! боже правых! -И их молению внемли: -Приди, суди, карай лукавых, -И будь един царем земли! - -Гавриил Романович Державин -(1743-1816) - -стих 57 -Уж ты нива моя, нивушка - -Уж ты нива моя, нивушка, -Не скосить тебя с маху единого, -Не связать тебя всю во единый сноп! -Уж вы думы мои, думушки, -Не стряхнуть вас разом с плеч долой, -Одной речью-то вас не высказать! -По тебе ль, нива, ветер разгуливал, -Гнул колосья твои до земли, -Зрелые зерна все разметывал! -Широко вы, думы, порассыпались, -Куда пала какая думушка, -Там всходила люта печаль-трава, -Вырастало горе горючее. - -Алексей Константинович Толстой -(1817-1875) - -стих 58 -Мщение - -Изменой слуга паладина убил: -Убийце завиден сан рыцаря был. - -Свершилось убийство ночною порой — -И труп поглощен был глубокой рекой. - -И шпоры и латы убийца надел -И в них на коня паладинова сел. - -И мост на коне проскакать он спешит, -Но конь поднялся на дыбы и храпит. - -Он шпоры вонзает в крутые бока — -Конь бешеный сбросил в реку седока. - -Он выплыть из всех напрягается сил, -Но панцирь тяжелый его утопил. - -Перевод стихотворения Людвига Уланда -от Василия Андреевича Жуковского -(1783-1852) - -стих 59 -Паучок - -Я привёз из Каракумов -Очень злого паучка, -Он зовётся каракуртом — -Он из жителей песка. - -Им укушенный верблюд -Не живёт пяти минут. - -Я привёз из Каракумов -Очень злого паучка, -Он зовётся «чёрной смертью» — -Житель жёлтого песка. - -Если кто меня разлюбит, -Паучок того погубит. - -Сергей Владимирович Михалков -(1913-2009) - -стих 60 -Была пора, и лед потока - - -Была пора, и лед потока -Лежал под снежной пеленой, -Недосягаемо для ока -Таился речки бег живой. - -Пришла весна, ее дыханье -Над снежным пронеслось ковром, -И стали видны содроганья -Струи, бегущей подо льдом. - -И близки дни, когда все блага -К нам низведет пора любви, -И мне зарей раскроет влага -Объятья чистые свои. - -Афанасий Афанасьевич Фет -(1820-1892) - -стих 61 -Наш век - -Не плоть, а дух растлился в наши дни, -И человек отчаянно тоскует… -Он к свету рвется из ночной тени -И, свет обретши, ропщет и бунтует. - -Безверием палим и иссушен, -Невыносимое он днесь выносит… -И сознает свою погибель он, -И жаждет веры… но о ней не просит… - -Не скажет ввек, с молитвой и слезой, -Как ни скорбит перед замкнутой дверью: -«Впусти меня!- Я верю, боже мой! -Приди на помощь моему неверью!..» - -Федор Иванович Тютчев -(1803-1873) - -стих 62 -Человек - -Все творенья в божьем мире -Так прекрасны, хороши! -Но прекрасней человека -Ничего нет на земли! - -То себя он ненавидит; -То собой он дорожит; -То полюбит, то разлюбит; -За миг жизни век дрожит… - -Даст желаньям ли свободу, – -Землю кровью напоит; -Буйной воле даст ли волю, – -Под ним море закипит. - -Но изменятся стремленья, -Озарится светом ум, — -И своей он красотою -Всё на свете помрачит… - -Алексей Васильевич Кольцов -(1809-1842) - -стих 63 -Жизнь - -Умом легко нам свет обнять; -В нем мыслью вольной мы летаем; -Что не дано нам понимать – -Мы все как будто понимаем. - -И резко судим обо всём, -С веков покрова не снимая; -Дошло, — что людям нипочем -Сказать: вот тайна мировая! - -Как свет стоит, до этих пор -Всего мы много пережили; -Страстей мы видели напор; -За царством царство схоронили. - -Живя, проникли глубоко -В тайник природы чудотворной; -Одни познанья взяли мы легко, -Другие — силою упорной… - -Но всё ж успех наш не велик. -Что до преданий? — мы не знаем. -Вперед что будет — кто проник? -Что мы теперь? — не разгадаем. - -Один лишь опыт говорит, -Что прежде нас здесь люди жили, — -И мы живём — и будут жить. -Вот каковы все наши были!.. - -Алексей Васильевич Кольцов -(1809-1842) - -стих 64 -Подражание Пушкину - -Лентин к дьякону бежит, -Лентин дьякону кричит: -«Дьякон, где бы нам напиться, -Как бы нам распорядиться?» -Дьякон Лентину в ответ: -«Знаю где, да денег нет! -У Степана Бардакова -Штофа три вина простова, -Где достал и вкус каков, -Знает, верно, Бердышов -И Катюха повариха, -И Устинья столяриха, -Знает Зубов Андреян, -Знает Храпов, но он пьян -И не скажет нам ни слова, -А жаль случая такова!» - -Иван Петрович Мятлев -(1796-1844) - -стих 65 -Розы - -Как хороши, как свежи были розы -В моем саду! Как взор прельщали мой! -Как я молил весенние морозы -Не трогать их холодною рукой! - -Как я берег, как я лелеял младость -Моих цветов заветных, дорогих; -Казалось мне, в них расцветала радость, -Казалось мне, любовь дышала в них. - -Но в мире мне явилась дева рая, -Прелестная, как ангел красоты, -Венка из роз искала молодая, -И я сорвал заветные цветы. - -И мне в венке цветы еще казались -На радостном челе красивее, свежей, -Как хорошо, как мило соплетались -С душистою волной каштановых кудрей! - -И заодно они цвели с девицей! -Среди подруг, средь плясок и пиров, -В венке из роз она была царицей, -Вокруг ее вились и радость и любовь. - -В ее очах — веселье, жизни пламень; -Ей счастье долгое сулил, казалось, рок. -И где ж она?.. В погосте белый камень, -На камне — роз моих завянувший венок. - -Иван Петрович Мятлев -(1796-1844) - -стих 66 -Ангел - -В дверях эдема ангел нежный -Главой поникшею сиял, -А демон мрачный и мятежный -Над адской бездною летал. - -Дух отрицанья, дух сомненья -На духа чистого взирал -И жар невольный умиленья -Впервые смутно познавал. - -«Прости, — он рек, — тебя я видел, -И ты недаром мне сиял: -Не все я в небе ненавидел, -Не все я в мире презирал». - -Александр Сергеевич Пушкин -(1799-1837) - -стих 67 -Асе -Те же — приречные мрежи, -Серые сосны и пни; -Те же песчаники; те же — -Сирые, тихие дни; - -Те же немеют с отвеса -Крыши поникнувших хат; -Синие линии леса -Немо темнеют в закат. - -А над немым перелеском, -Где разредились кусты, -Там проясняешься блеском -Неугасимым — Ты! - -Струями ярких рубинов -Жарко бежишь по крови: -Кроет крыло серафимов -Пламенно очи мои. - -Бегом развернутых крылий -Стала крылатая кровь. -Давние, давние были -Приоткрываются вновь. - -В давнем грядущие встречи; -В будущем — давность мечты; -Неизреченные речи, -Неизъяснимая — Ты! - -Андрей Белый -(1880-1934) - -стих 68 -29 января 1837 - -Из чьей руки свинец смертельный -Поэту сердце растерзал? -Кто сей божественный фиал -Разрушил, как сосуд скудельный? -Будь прав или виновен он -Пред нашей правдою земною, -Навек он высшею рукою -В «цареубийцы» заклеймен. - -Но ты, в безвременную тьму -Вдруг поглощенная со света, -Мир, мир тебе, о тень поэта, -Мир светлый праху твоему!.. -Назло людскому суесловью -Велик и свят был жребий твой!.. -Ты был богов орган живой, -Но с кровью в жилах… знойной кровью. - -И сею кровью благородной -Ты жажду чести утолил — -И осененный опочил -Хоругвью горести народной. -Вражду твою пусть тот рассудит, -Кто слышит пролитую кровь… -Тебя ж, как первую любовь, -России сердце не забудет!.. - -Федор Иванович Тютчев -(1803-1873) - -стих 69 -Пророк - -Не говори: «Забыл он осторожность! -Он будет сам судьбы своей виной!..» -Не хуже нас он видит невозможность -Служить добру, не жертвуя собой. - -Но любит он возвышенней и шире, -В его душе нет помыслов мирских. -«Жить для себя возможно только в мире, -Но умереть возможно для других!» - -Так мыслит он — и смерть ему любезна. -Не скажет он, что жизнь его нужна, -Не скажет он, что гибель бесполезна: -Его судьба давно ему ясна… - -Его еще покамест не распяли, -Но час придет — он будет на кресте; -Его послал бог Гнева и Печали -Рабам земли напомнить о Христе. - -Николай Алексеевич Некрасов -(1821-1878) - -стих 70 -Маскарад - -Брал мальчика отец с собою в маскарад, -А мальчик узнавать умел людей под маской -Пляской, -Какой бы кто ни вздел сокрыть себя наряд. -Неладно прыгая, всей тушей там тряхнулся, -Упал, расшиб он лоб, расквасил мозг, рехнулся, -Но выздоровел бы по-прежнему плясать, -Когда бы без ума не стал стихов писать. -Склад был безмерно гнусен, -Не видывал еще никто подобных врак. -О мальчик! узнавать ты был людей искусен, -Но знаешь ли теперь, что ты парнасский рак? -Ты в масках прежде знал людей по виду пляски, -А ныне сам себя не знаешь и без маски. -Брось музу, если быть не хочешь ты дурак. - -Александр Петрович Сумароков -(1717-1777) - -стих 71 -Шумит на дворе непогода - -Шумит на дворе непогода, -А в доме давно уже спят; -К окошку, вздохнув, подхожу я — -Чуть виден чернеющий сад; - -На небе так темно, так темно -И звездочки нет ни одной, -А в доме старинном так грустно -Среди непогоды ночной! - -Дождь бьет, барабаня, по крыше, -Хрустальные люстры дрожат, -За шкапом проворные мыши -В бумажных обоях шумят; - -Они себе чуют раздолье: -Как скоро хозяин умрет, -Наследник покинет поместье, -Где жил его доблестный род, - -И дом навсегда запустеет, -Заглохнут ступени травой… -И думать об этом так грустно -Среди непогоды ночной! - -Алексей Константинович Толстой -(1817-1875) - -стих 72 -То было раннею весной - -То было раннею весной, -Трава едва всходила, -Ручьи текли, не парил зной, -И зелень рощ сквозила; - -Труба пастушья поутру -Еще не пела звонко, -И в завитках еще в бору -Был папоротник тонкий. - -То было раннею весной, -В тени берез то было, -Когда с улыбкой предо мной -Ты очи опустила. - -То на любовь мою в ответ -Ты опустила вежды — -О жизнь! о лес! о солнца свет! -О юность! о надежды! - -И плакал я перед тобой, -На лик твой глядя милый,- -То было раннею весной, -В тени берез то было! - -То было утро наших лет — -О счастие! о слезы! -О лес! о жизнь! о солнца свет! -О свежий дух березы! - -Алексей Константинович Толстой -(1817-1875) - -стих 73 -Классические розы - -В те времена, когда роились грезы -В сердцах людей, прозрачны и ясны, -Как хороши, как свежи были розы -Моей любви, и славы, и весны! - -Прошли лета, и всюду льются слезы… -Нет ни страны, ни тех, кто жил в стране… -Как хороши, как свежи ныне розы -Воспоминаний о минувшем дне! - -Но дни идут — уже стихают грозы. -Вернуться в дом Россия ищет троп… -Как хороши, как свежи будут розы, -Моей страной мне брошенные в гроб! - -Игорь-Северянин -(1887-1941) - -стих 74 -Зимнее небо - -Талый снег налетал и слетал, -Разгораясь, румянились щеки, -Я не думал, что месяц так мал -И что тучи так дымно-далеки… - -Я уйду, ни о чем не спросив, -Потому что мой вынулся жребий, -Я не думал, что месяц красив, -Так красив и тревожен на небе. - -Скоро полночь. Никто и ничей, -Утомлен самым призраком жизни, -Я любуюсь на дымы лучей -Там, в моей обманувшей отчизне. - -Иннокентий Федорович Анненский -(1855-1909) - -стих 75 -В вагоне - -Довольно дел, довольно слов, -Побудем молча, без улыбок, -Снежит из низких облаков, -А горний свет уныл и зыбок. - -В непостижимой им борьбе -Мятутся черные ракиты. -«До завтра,- говорю тебе,- -Сегодня мы с тобою квиты». - -Хочу, не грезя, не моля, -Пускай безмерно виноватый, -Глядеть на белые поля -Через стекло с налипшей ватой. - -А ты красуйся, ты — гори… -Ты уверяй, что ты простила, -Гори полоской той зари, -Вокруг которой всё застыло. - -Иннокентий Федорович Анненский -(1855-1909) - -стих 76 -Два великана - -В шапке золота литого -Старый русский великан -Поджидал к себе другого -Из далёких чуждых стран. - -За горами, за долами -Уж гремел об нём рассказ, -И померяться главами -Захотелось им хоть раз. - -И пришёл с грозой военной -Трёхнедельный удалец — -И рукою дерзновенной -Хвать за вражеский венец. - -Но улыбкой роковою -Русский витязь отвечал; -Посмотрел — тряхнул главою… -Ахнул дерзкий — и упал! - -Но упал он в дальнем море -На неведомый гранит, -Там, где буря на просторе -Над пучиною шумит. - -Михаил Юрьевич Лермонтов -(1814-1841) - -стих 77 -Смерть Орфеева - -Нимфы, плачьте! Нет Орфея!.. -Ветр унылый, тихо вея, -Нам вещает: «Нет его!» -Ярость фурий исступленных, -Гнусной страстью воспаленных, -Прекратила жизнь того, -Кто пленял своей игрою -Кровожаждущих зверей, -Гармонической струною -Трогал сердце лютых грей -И для нежной Эвридики -В Тартар мрачный нисходил. -Ах, стенайте! – берег дикий -Прах его в себя вместил. -Сиротеющая лира -От дыхания зефира -Звук печальный издает: -«Нет певца! Орфея нет!» -Эхо повторяет: нет! -Над могилою священной, -Мягким дерном покровенной, -Филомела слезы льет. - -Николай Михайлович Карамзин -(1766-1826) - -стих 78 -Врубелю - -Так тихо-долго шла жизнь на убыль -В душе, исканьем обворованной… -Так странно тихо растаял Врубель, -Так безнадежно очарованный… - -Ему фиалки струили дымки -Лица трагически-безликого… -Душа впитала все невидимки, -Дрожа в преддверии великого… - -Но дерзновенье слепило кисти, -А кисть дразнила дерзновенное… -Он тихо таял, — он золотистей -Пылал душою вдохновенною… - -Цветов побольше на крышку гроба; -В гробу — венчанье!.. Отныне оба — -Мечта и кисть — в немой гармонии, -Как лейтмотив больной симфонии. - -Игорь-Северянин -(1887-1941) - -стих 79 -Чкалов - -Изо всех больших имен геройских, -Что известны нам наперечет, -Как-то по-особому, по-свойски, -Это имя называл народ. - -Попросту — мы так его любили, -И для всех он был таким своим, -Будто все мы в личной дружбе были, -Пили, ели и летали с ним… - -Богатырским мужеством и нравом -Был он славен — Сталинский пилот. -И казалось так, что эта слава — -Не года, уже века живет. - -Что она из повестей старинных -Поднялась сквозь вековую тьму, -Что она от витязей былинных -По наследству перешла к нему. - -Пусть же по наследству и по праву -В память о делах твоих, пилот, -Чкаловское мужество и слава -Чкаловским питомцам перейдет! - -Александр Трифонович Твардовский -(1910-1971) - -стих 80 -Пушкину - -Мечтая о могучем даре -Того, кто русской стал судьбой, -Стою я на Тверском бульваре, -Стою и говорю с собой. - -Блондинистый, почти белесый, -В легендах ставший как туман, -О Александр! Ты был повеса, -Как я сегодня хулиган. - -Но эти милые забавы -Не затемнили образ твой, -И в бронзе выкованной славы -Трясешь ты гордой головой. - -А я стою, как пред причастьем, -И говорю в ответ тебе: -Я умер бы сейчас от счастья, -Сподобленный такой судьбе. - -Но, обреченный на гоненье, -Еще я долго буду петь… -Чтоб и мое степное пенье -Сумело бронзой прозвенеть. - -Сергей Александрович Есенин -(1895-1925) - -стих 81 -Как неожиданно и ярко - -Как неожиданно и ярко, -На влажной неба синеве, -Воздушная воздвиглась арка -В своем минутном торжестве! -Один конец в леса вонзила, -Другим за облака ушла — -Она полнеба обхватила -И в высоте изнемогла. - -О, в этом радужном виденье -Какая нега для очей! -Оно дано нам на мгновенье, -Лови его — лови скорей! -Смотри — оно уж побледнело, -Еще минута, две — и что ж? -Ушло, как то уйдет всецело, -Чем ты и дышишь и живёшь. - -Федор Иванович Тютчев -(1803-1873) - -стих 82 -Не множеством картин старинных мастеров - -Не множеством картин старинных мастеров -Украсить я всегда желал свою обитель, -Чтоб суеверно им дивился посетитель, -Внимая важному сужденью знатоков. - -В простом углу моем, средь медленных трудов, -Одной картины я желал быть вечно зритель, -Одной: чтоб на меня с холста, как с облаков, -Пречистая и наш божественный спаситель — - -Она с величием, он с разумом в очах — -Взирали, кроткие, во славе и в лучах, -Одни, без ангелов, под пальмою Сиона. - -Исполнились мои желания. Творец -Тебя мне ниспослал, тебя, моя Мадонна, -Чистейшей прелести чистейший образец. - -Александр Сергеевич Пушкин -(1799-1837) - -стих 83 -Юмористам отечественных записок - -Поморная муза резва: -В стихах, понимаете, надо -Уметь, как расставить слова, -Чтоб свистнуло с первого взгляда. - -Умеючи надо шутить -С богиней веселых мелодий; -Как вам нужно кушать и пить, -Так нужен размер для пародий. - -Богине мелодий верны, -Поморные я все староверы -И скромно, как все свистуны, -Свистят, соблюдая размеры. - -За то им богинею дан, -Надежнее стали звенящей, -Для битвы с врагом талисман: -Стих, мягко и нежно свистящий, - -Одним услаждающий слух, -Других повергающий в холод, -И главное: легкий, как пух, -Но пошлость дробящий, как молот - -Василий Степанович Курочкин -(1831-1875) - -стих 84 -На смерть князя Мещерского - -Глагол времен! металла звон! -Твой страшный глас меня смущает, -Зовет меня, зовет твой стон, -Зовет — и к гробу приближает. -Едва увидел я сей свет, -Уже зубами смерть скрежещет, -Как молнией, косою блещет -И дни мои, как злак, сечет. - -Ничто от роковых кохтей, -Никая тварь не убегает: -Монарх и узник — снедь червей, -Гробницы злость стихий снедает; -Зияет время славу стерть: -Как в море льются быстры воды, -Так в вечность льются дни и годы; -Глотает царства алчна смерть. - -Скользим мы бездны на краю, -В которую стремглав свалимся; -Приемлем с жизнью смерть свою, -На то, чтоб умереть, родимся. -Без жалости все смерть разит: -И звезды ею сокрушатся, -И солнцы ею потушатся, -И всем мирам она грозит. - -Не мнит лишь смертный умирать -И быть себя он вечным чает; -Приходит смерть к нему, как тать, -И жизнь внезапу похищает. -Увы! где меньше страха нам, -Там может смерть постичь скорее; -Ее и громы не быстрее -Слетают к гордым вышинам. - -Сын роскоши, прохлад и нег, -Куда, Мещерский! ты сокрылся? -Оставил ты сей жизни брег, -К брегам ты мертвых удалился; -Здесь персть твоя, а духа нет. -Где ж он? — Он там.- Где там? — Не знаем. -Мы только плачем и взываем: -«О, горе нам, рожденным в свет!» - -Утехи, радость и любовь -Где купно с здравием блистали, -У всех там цепенеет кровь -И дух мятется от печали. -Где стол был яств, там гроб стоит; -Где пиршеств раздавались лики, -Надгробные там воют клики, -И бледна смерть на всех глядит. - -Глядит на всех — и на царей, -Кому в державу тесны миры; -Глядит на пышных богачей, -Что в злате и сребре кумиры; -Глядит на прелесть и красы, -Глядит на разум возвышенный, -Глядит на силы дерзновенны -И точит лезвие косы. - -Смерть, трепет естества и страх! -Мы — гордость, с бедностью совместна; -Сегодня бог, а завтра прах; -Сегодня льстит надежда лестна, -А завтра: где ты, человек? -Едва часы протечь успели, -Хаоса в бездну улетели, -И весь, как сон, прошел твой век. - -Как сон, как сладкая мечта, -Исчезла и моя уж младость; -Не сильно нежит красота, -Не столько восхищает радость, -Не столько легкомыслен ум, -Не столько я благополучен; -Желанием честей размучен, -Зовет, я слышу, славы шум. - -Но так и мужество пройдет -И вместе к славе с ним стремленье; -Богатств стяжание минет, -И в сердце всех страстей волненье -Прейдет, прейдет в чреду свою. -Подите счастьи прочь возможны, -Вы все пременны здесь и ложны: -Я в дверях вечности стою. - -Сей день иль завтра умереть, -Перфильев! должно нам конечно,- -Почто ж терзаться и скорбеть, -Что смертный друг твой жил не вечно? -Жизнь есть небес мгновенный дар; -Устрой ее себе к покою -И с чистою твоей душою -Благословляй судеб удар. - -Гавриил Романович Державин -(1743-1816) - -стих 85 -Отрывок из «Бродяги» - -День вечерел. Косая тень -Ложилась низко и широко… -Заутра праздник, вещий день -Ильи, гремящего пророка… - -Приди ты, немощный, -Приди ты, радостный! -Звонят ко всенощной, -К молитве благостной. -И звон смиряющий -Всем в душу просится, -Окрест сзывающий, -В полях разносится! - -В Холмах, селе большом, -Есть церковь новая; -Воздвигла божий дом -Сума торговая; -И службы божие -Богато справлены, -Икон подножия -Свечьми уставлены. -И стар и млад войдет — -Сперва помолится, -Поклон земной кладет, -Кругом поклонится; - -Аксаков Иван Сергеевич -(1823-1886) - -стих 86 -Воззвание - -Приди ты, немощный, -Приди ты, радостный. - -Приди — не знающий -Любостяжания, -Приди — не чающий -С истцов даяния, -Виновных жёнами -Не соблазнившийся -И лишь законами -Руководившийся, -Злом не торгующий, -Добра не давящий, -Споспешествующий -И правоправящий! -Придите, сильные, -Придите, слабые, -Правдообильные! -Придите — дабы я -Деянья честности, -Душевной ясности -Обрек известности -Посредством гласности! - -Василий Степанович Курочкин -(1831-1875) - -стих 87 -Царскосельская статуя - -Урну с водой уронив, об утес ее дева разбила. -Дева печально сидит, праздный держа черепок. -Чудо! не сякнет вода, изливаясь из урны разбитой; -Дева, над вечной струей, вечно печальна сидит. - -Александр Сергеевич Пушкин - (1799-1837) - -стих 88 -Преданность - -Преданность вечно была в характере русского люда. -Кто же не предан теперь? Ни одного не найдешь. -Каждый, кто глуп или подл, предан, конечно, престолу; -Каждый, кто честен, умен, предан будет суду. - -Михаил Ларионович Михайлов - (1829-1865) - -стих 89 -И скучно и грустно - -И скучно и грустно, и некому руку подать -В минуту душевной невзгоды… -Желанья!.. что пользы напрасно и вечно желать?.. -А годы проходят — все лучшие годы! - -Любить… но кого же?.. на время — не стоит труда, -А вечно любить невозможно. -В себя ли заглянешь? — там прошлого нет и следа: -И радость, и муки, и всё там ничтожно… - -Что страсти? — ведь рано иль поздно их сладкий недуг -Исчезнет при слове рассудка; -И жизнь, как посмотришь с холодным вниманьем вокруг — -Такая пустая и глупая шутка… - -Михаил Юрьевич Лермонтов -(1814-1841) - -стих 90 -Как океан меняет цвет - -Как океан меняет цвет, -Когда в нагроможденной туче -Вдруг полыхнет мигнувший свет,一 -Так сердце под грозой певучей -Меняет строй, боясь вздохнуть, -И кровь бросается в ланиты, -И слезы счастья душат грудь -Перед явленьем Карменситы. - -Александр Александрович Блок -(1880-1921) - -стих 91 -Плюшевые волки - -Плюшевые волки, -Зайцы, погремушки. -Детям дарят с елки -Детские игрушки. - -И, состарясь, дети -До смерти без толку -Все на белом свете -Ищут эту елку. - -Где жар-птица в клетке, -Золотые слитки, -Где висит на ветке -Счастье их на нитке. - -Только дед-мороза -Нету на макушке, -Чтоб в ответ на слезы -Сверху снял игрушки. - -Желтые иголки -На пол опадают… -Всё я жду, что с ёлки -Мне тебя подарят. - -Константин Михайлович Симонов -(1915-1979) - -стих 92 -Глупой красавице - -Амур спросил меня однажды, -Хочу ль испить его вина, — -Я не имел в то время жажды, -Но выпил кубок весь до дна. - -Теперь желал бы я напрасно -Смочить горящие уста, -Затем что чаша влаги страстной, -Как голова твоя, — пуста. - -Михаил Юрьевич Лермонтов -(1814-1841) - -стих 93 -Статуя - -Лошадь влекли под уздцы на чугунный -Мост. Под копытом чернела вода. -Лошадь храпела, и воздух безлунный -Храп сохранял на мосту навсегда. -Песни воды и хрипящие звуки -Тут же вблизи расплывались в хаос. -Их раздирали незримые руки. -В черной воде отраженье неслось. -Мерный чугун отвечал однотонно. -Разность отпала. И вечность спала. -Черная ночь неподвижно, бездонно — -Лопнувший в бездну ремень увлекла. -Всё пребывало. Движенья, страданья -Не было. Лошадь храпела навек. -И на узде в напряженьи молчанья -Вечно застывший висел человек. - -Александр Александрович Блок -(1880-1921) - -стих 94 -Соловей, галки и вороны - -Прошедшею весною, -Вечернею зарею -В лесочке сем певал любезный соловей. -Пришла опять весна: где друг души моей? -Ах, нет его! Зачем он скрылся? -Зачем? В лесочке поселился -Хор галок и ворон. Они и день и ночь -Кричат, усталости не знают, -И слух людей (увы!) безжалостно терзают! -Что ж делать соловью? — Лететь подале прочь! -Жестокие врали и прозой и стихами! -Какому соловью петь можно вместе с вами? - -Николай Михайлович Карамзин -(1766-1826) - -стих 95 -С поляны коршун поднялся - -С поляны коршун поднялся, -Высоко к небу он взвился; -Всё выше, дале вьется он — -И вот ушел за небосклон! - -Природа-мать ему дала -Два мощных, два живых крыла — -А я здесь в поте и в пыли. -Я, царь земли, прирос к земли!.. - -Фёдор Иванович Тютчев -(1803-1873) - -стих 96 -Синица - -Синица на море пустилась: -Она хвалилась, -Что хочет море сжечь. -Расславилась тотчас о том по свету речь. -Страх обнял жителей Нептуновой столицы; -Летят стадами птицы; -А звери из лесов сбегаются смотреть, -Как будет Океан, и жарко ли гореть. -И даже, говорят, на слух молвы крылатой, -Охотники таскаться по пирам -Из первых с ложками явились к берегам, -Чтоб похлебать ухи такой богатой, -Какой-де откупщик и самый тароватый -Не давывал секретарям. -Толпятся: чуду всяк заранее дивится, -Молчит и, на море глаза уставя, ждет; -Лишь изредка иной шепнет: -«Вот закипит, вот тотчас загорится!» -Не тут-то: море не горит. -Кипит ли хоть? — и не кипит. -И чем же кончились затеи величавы? -Синица со стыдом восвояси уплыла; -Наделала Синица славы, -А море не зажгла. -_____________________________________________ -Примолвить к речи здесь годится, -Но ничьего не трогая лица: -Что делом, не сведя конца, -Не надобно хвалиться. - -Иван Андреевич Крылов -(1769-1844) - -стих 97 -Разлука - -Вытерла заплаканное личико, -Ситцевое платьице взяла, -Вышла — и, как птичка–невеличка, -В басенку, как в башенку, пошла. - -И теперь мне постоянно снится, -Будто ты из басенки ушла, -Будто я женат был на синице, -Что когда–то море подожгла. - -Михаил Аркадьевич Светлов -(1903-1964) - -стих 98 -Муха - -Бык с плугом на покой тащился по трудах; -А Муха у него сидела на рогах, -И Муху же они дорогой повстречали. -«Откуда ты, сестра?» — от этой был вопрос. -А та, поднявши нос, -В ответ ей говорит: «Откуда? — мы пахали!» - -От басни завсегда -Нечаянно дойдешь до были. -Случалось ли подчас вам слышать, господа: -«Мы сбили! Мы решили!» - -Иван Иванович Дмитриев -(1760-1837) - -стих 99 -Снегири - -Тихо-тихо сидят снегири на снегу -меж стеблей прошлогодней крапивы; -я тебе до конца описать не смогу, -как они и бедны и красивы! - -Тихо-тихо клюют на крапиве зерно,— -без кормежки прожить не шутки!— -пусть крапивы зерно, хоть не сытно оно, -да хоть что-нибудь будет в желудке. - -Тихо-тихо сидят на снегу снегири — -на головках бобровые шапочки; -у самца на груди отраженье зари, -скромно-серые перья на самочке. - -Поскакали вприпрыжку один за другой -по своей падкрапивенской улице; -небо взмыло над ними высокой дугой, -снег последний поземкою курится. - -И такая вокруг снегирей тишина, -так они никого не пугаются, -и так явен их поиск скупого зерна, -что понятно: весна надвигается! - -Николай Николаевич Асеев -(1889-1963) - -стих 100 -Изрек пророк - -Изрек пророк: -— Нет бога, кроме бога!- -Я говорю: -— Нет мамы, кроме мамы!..- -Никто меня не встретит у порога, -Где сходятся тропинки, словно шрамы. - -Вхожу и вижу четки, -на которых -Она в разлуке, сидя одиноко, -Считала ночи, черные, как порох, -И белы дни, летящие с востока. - -Кто разожжет теперь огонь в камине, -Чтобы зимой согрелся я с дороги? -Кто мне, любя, грехи отпустит ныне -И за меня помолится в тревоге? - -Я в руки взял Коран, тисненный строго, -Пред ним склонялись грозные имамы. -Он говорит: -— Нет бога, кроме бога!- -Я говорю: -— Нет мамы, кроме мамы! - -Расул Гамзатович Гамзатов -(1929-2003) - -стих 101 -«Walking Time» - -Январский мороз, -Лицо полно слёз. -Мне не согреться, -Погасло сердце. - -От неё иду, -Чувства во льду. -Она поняла, -С меня спали рога. - -Глаза вскрыли боль: -Была она нагой, -С ней лежал другой. -Туда больше не ногой. - -Разрушен дуэт, -Простыл любви след. -Друг другу мы никто, -Теперь всё прошло. - -Нет, я должен простить, -Восстановить нить -Любви между нами, -Двумя полюсами. - -Она как родня, -Мне жизнью верна. -Немного ошиблась, -Погорячилась. - -Куплю ей айфон -И буду прощен. -С кредиткой от Альфа, -Так больше кайфа! - -Тимур Вульфов -(200X-XXXX) - -стих 102 diff --git a/back/unimportant.env b/back/unimportant.env deleted file mode 100644 index 419962b..0000000 --- a/back/unimportant.env +++ /dev/null @@ -1,5 +0,0 @@ -TOKEN = "eyJhbGciOiJSUzI1NiIsInR5cCIgOiAiSldUIiwia2lkIiA6ICJhU1RaZm42bHpTdURYcUttRkg1SzN5UDFhT0FxUkhTNm9OendMUExaTXhFIn0.eyJleHAiOjE3ODYyMjUzMzMsImlhdCI6MTY5MTUzMDkzMywianRpIjoiYjU0MmU3MTQtYzJkMS00NTY2LWJkY2MtYmQ5NzA0ODY1ZjgzIiwiaXNzIjoiaHR0cHM6Ly9rYy5wZXRlcnNidXJnLnJ1L3JlYWxtcy9lZ3MtYXBpIiwiYXVkIjoiYWNjb3VudCIsInN1YiI6ImJjYjQ2NzljLTU3ZGItNDU5ZC1iNWUxLWRlOGI4Yzg5MTMwMyIsInR5cCI6IkJlYXJlciIsImF6cCI6ImFkbWluLXJlc3QtY2xpZW50Iiwic2Vzc2lvbl9zdGF0ZSI6IjJhOTgwMzUyLTY1M2QtNGZlZC1iMDI1LWQ1N2U0NDRjZmM3NiIsImFjciI6IjEiLCJhbGxvd2VkLW9yaWdpbnMiOlsiLyoiXSwicmVhbG1fYWNjZXNzIjp7InJvbGVzIjpbImRlZmF1bHQtcm9sZXMtZWdzLWFwaSIsIm9mZmxpbmVfYWNjZXNzIiwidW1hX2F1dGhvcml6YXRpb24iXX0sInJlc291cmNlX2FjY2VzcyI6eyJhY2NvdW50Ijp7InJvbGVzIjpbIm1hbmFnZS1hY2NvdW50IiwibWFuYWdlLWFjY291bnQtbGlua3MiLCJ2aWV3LXByb2ZpbGUiXX19LCJzY29wZSI6ImVtYWlsIHByb2ZpbGUiLCJzaWQiOiIyYTk4MDM1Mi02NTNkLTRmZWQtYjAyNS1kNTdlNDQ0Y2ZjNzYiLCJlbWFpbF92ZXJpZmllZCI6ZmFsc2UsIm5hbWUiOiLQktC70LDQtNC40LzQuNGAINCv0LrQvtCy0LvQtdCyIiwicHJlZmVycmVkX3VzZXJuYW1lIjoiZTBmYzc2OGRhOTA4MjNiODgwZGQzOGVhMDJjMmQ5NTciLCJnaXZlbl9uYW1lIjoi0JLQu9Cw0LTQuNC80LjRgCIsImZhbWlseV9uYW1lIjoi0K_QutC-0LLQu9C10LIifQ.FTKiC1hpWcOkmSW9QZpC-RY7Ko50jw1mDMfXIWYxlQ-zehLm2CLmOnHvYoOoI39k2OzeCIAB9ZdRrrGZc6G9Z1eFELUjNGEqKxSC1Phj9ATemKgbOKEttk-OGc-rFr9VPA8_SnfvLts6wTI2YK33YBIxCF5nCbnr4Qj3LeEQ0d6Hy8PO4ATrBF5EOeuAZRprvIEjXe_f8N9ONKckCPB-xFB4P2pZlVXGoCNoewGEcY3zXH4khezN6zcVr6tpc6G8dBv9EqT_v92IDSg-aXQk6ysA0cO0-6x5w1-_qU0iHGIAPsLNV9IKBoFbjc0JH6cWabldPRH12NP1trvYfqKDGQ" -DOMAIN = "https://geointelect2.gate.petersburg.ru" -SECRET_KEY = "651a52941cf5de14d48ef5d7af115709" -ALGORITHM = "HS256" -ACCESS_TOKEN_EXPIRE_MINUTES = 1440 \ No newline at end of file From 60e5463028580b5767796b650f65b7011532222a Mon Sep 17 00:00:00 2001 From: DmitryGantimurov Date: Tue, 12 Sep 2023 00:19:52 +0300 Subject: [PATCH 18/23] HTTP exceptions added (intead of just True or False answers) --- back/api.py | 68 ++++++++++++++++++++++++++--------------------------- 1 file changed, 34 insertions(+), 34 deletions(-) diff --git a/back/api.py b/back/api.py index cfa585e..52cbdc9 100644 --- a/back/api.py +++ b/back/api.py @@ -68,12 +68,11 @@ async def announcements_list(db: Annotated[Session, Depends(auth_utils.get_sessi async def single_announcement(ann_id:int, db: Annotated[Session, Depends(auth_utils.get_session)]): # передаем индекс обявления # Считываем данные из Body и отображаем их на странице. # В последствии будем вставлять данные в html-форму - try: - announcement = await db.get(orm_models.Announcement, ann_id) - #announcement = await db.execute(select(orm_models.Announcement)).scalars().all() - return announcement - except: - return {"Answer" : False} #если неуданый доступ, то сообщаем об этом + announcement = await db.get(orm_models.Announcement, ann_id) + #announcement = await db.execute(select(orm_models.Announcement)).scalars().all() + if not announcement: + raise HTTPException(status_code=404, detail="Item not found") + return announcement # Занести объявление в базу данных @@ -82,48 +81,49 @@ async def put_in_db(name: Annotated[str, Form()], category: Annotated[str, Form( address: Annotated[str, Form()], longtitude: Annotated[float, Form()], latitude: Annotated[float, Form()], 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(auth_utils.get_session)], src: Union[UploadFile, None] = None, trashId: Annotated[int, Form()] = None): + + # имя загруженного файла по умолчанию - пустая строка + uploaded_name = "" + # если пользователь загрузил картинку + if src: + # процесс сохранения картинки + f = src.file + f.seek(0, os.SEEK_END) + if f.tell() > 0: + f.seek(0) + destination = pathlib.Path("./uploads/" + str(hash(f)) + pathlib.Path(src.filename).suffix.lower()) + async with destination.open('wb') as buffer: + shutil.copyfileobj(f, buffer) + + # изменяем название директории загруженного файла + uploaded_name = "/uploads/" + destination.name + + # создаем объект 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, + trashId=trashId, src=uploaded_name, booked_by=0) try: - # имя загруженного файла по умолчанию - пустая строка - uploaded_name = "" - # если пользователь загрузил картинку - if src: - # процесс сохранения картинки - f = src.file - f.seek(0, os.SEEK_END) - if f.tell() > 0: - f.seek(0) - destination = pathlib.Path("./uploads/" + str(hash(f)) + pathlib.Path(src.filename).suffix.lower()) - async with destination.open('wb') as buffer: - shutil.copyfileobj(f, buffer) - - # изменяем название директории загруженного файла - uploaded_name = "/uploads/" + destination.name - - # создаем объект 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, - trashId=trashId, src=uploaded_name, booked_by=0) db.add(temp_ancmt) # добавляем в бд await db.commit() # сохраняем изменения await db.refresh(temp_ancmt) # обновляем состояние объекта - return {"Answer" : True} except: - return {"Answer" : False} + raise HTTPException(status_code=500, detail="problem with adding object to db") # Удалить объявления из базы @app.delete("/api/announcement") #адрес объявления async def delete_from_db(announcement: pydantic_schemas.DelAnnouncement, db: Annotated[Session, Depends(auth_utils.get_session)]): # функция удаления объекта из БД + # находим объект с заданным id в бд + #to_delete = db.query(orm_models.Announcement).filter(orm_models.Announcement.id==announcement.id).first() + query = await db.execute(select(orm_models.Announcement).where(orm_models.Announcement.id==announcement.id)) + to_delete = query.scalars().first() + if not to_delete: + raise HTTPException(status_code=404, detail="Item not found. Can't delete") try: - # находим объект с заданным id в бд - #to_delete = db.query(orm_models.Announcement).filter(orm_models.Announcement.id==announcement.id).first() - query = await db.execute(select(orm_models.Announcement).where(orm_models.Announcement.id==announcement.id)) - to_delete = query.scalars().first() await db.delete(to_delete) # удаление из БД await db.commit() # сохраняем изменения - return {"Answer" : True} except: - return {"Answer" : False} + raise HTTPException(status_code=500, detail="Problem with adding to database") # Забронировать объявление From e6b34d684a82680f959175f0234287594357c24b Mon Sep 17 00:00:00 2001 From: DmitryGantimurov Date: Tue, 12 Sep 2023 00:22:36 +0300 Subject: [PATCH 19/23] HTTP exceptions added to endpoints (instead of just True, False responces) --- back/api.py | 1 + 1 file changed, 1 insertion(+) diff --git a/back/api.py b/back/api.py index 52cbdc9..64abd72 100644 --- a/back/api.py +++ b/back/api.py @@ -26,6 +26,7 @@ import os from . import add_poems_and_filters, auth_utils, orm_models, pydantic_schemas + # создаем приложение Fastapi app = FastAPI() From f74199b0646b117f4d609106b9add23c1acf2d84 Mon Sep 17 00:00:00 2001 From: DmitryGantimurov Date: Tue, 12 Sep 2023 00:31:53 +0300 Subject: [PATCH 20/23] HTTP exceptions added instead of True, False responces --- back/api.py | 1 - 1 file changed, 1 deletion(-) diff --git a/back/api.py b/back/api.py index 64abd72..52cbdc9 100644 --- a/back/api.py +++ b/back/api.py @@ -26,7 +26,6 @@ import os from . import add_poems_and_filters, auth_utils, orm_models, pydantic_schemas - # создаем приложение Fastapi app = FastAPI() From a60ff39c435ddf43934dfd24b676cb68513bb053 Mon Sep 17 00:00:00 2001 From: DmitryGantimurov Date: Tue, 12 Sep 2023 21:29:55 +0300 Subject: [PATCH 21/23] postgres related error fixed in filter_ann --- back/add_poems_and_filters.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/back/add_poems_and_filters.py b/back/add_poems_and_filters.py index 69daafb..6098811 100644 --- a/back/add_poems_and_filters.py +++ b/back/add_poems_and_filters.py @@ -52,6 +52,8 @@ async def filter_ann(schema: pydantic_schemas.SortAnnouncements, db: AsyncSessio # res = await db.execute(statement) # если фильтр задан if filt_val is not None: + if name == "obsolete": + filt_val = bool(filt_val) filter_query = await db.execute(select(orm_models.Announcement).where(literal_column(f"announcements.{name}") == filt_val)) filtered = set(filter_query.scalars().all()) res = res.intersection(filtered) From 2b001579c579a84012f1709869858f9fc67948d3 Mon Sep 17 00:00:00 2001 From: dm1sh Date: Wed, 13 Sep 2023 22:26:53 +0300 Subject: [PATCH 22/23] Fixed front ann book and delete err handling Button no longer pre-updates on err File uploading fix --- back/api.py | 6 +++++- front/src/hooks/api/useAddAnnouncement.ts | 4 ++-- front/src/hooks/api/useBook.ts | 4 ++-- front/src/hooks/useSendButtonCaption.ts | 2 +- 4 files changed, 10 insertions(+), 6 deletions(-) diff --git a/back/api.py b/back/api.py index 8811152..3bb1904 100644 --- a/back/api.py +++ b/back/api.py @@ -89,7 +89,7 @@ async def put_in_db(name: Annotated[str, Form()], category: Annotated[str, Form( if f.tell() > 0: f.seek(0) destination = pathlib.Path("./uploads/" + str(hash(f)) + pathlib.Path(src.filename).suffix.lower()) - async with destination.open('wb') as buffer: + with destination.open('wb') as buffer: shutil.copyfileobj(f, buffer) # изменяем название директории загруженного файла @@ -103,6 +103,8 @@ async def put_in_db(name: Annotated[str, Form()], category: Annotated[str, Form( db.add(temp_ancmt) # добавляем в бд await db.commit() # сохраняем изменения await db.refresh(temp_ancmt) # обновляем состояние объекта + + return {"Success": True} except: raise HTTPException(status_code=500, detail="problem with adding object to db") @@ -119,6 +121,8 @@ async def delete_from_db(announcement: pydantic_schemas.DelAnnouncement, db: Ann try: await db.delete(to_delete) # удаление из БД await db.commit() # сохраняем изменения + + return {"Success": True} except: raise HTTPException(status_code=500, detail="Problem with adding to database") diff --git a/front/src/hooks/api/useAddAnnouncement.ts b/front/src/hooks/api/useAddAnnouncement.ts index c8701b0..5680439 100644 --- a/front/src/hooks/api/useAddAnnouncement.ts +++ b/front/src/hooks/api/useAddAnnouncement.ts @@ -14,8 +14,8 @@ function useAddAnnouncement() { processPutAnnouncement ) - function handleAdd(formData: FormData) { - void doSend({}, { + async function handleAdd(formData: FormData) { + await doSend({}, { body: formData, }) } diff --git a/front/src/hooks/api/useBook.ts b/front/src/hooks/api/useBook.ts index 5a1e091..53a0eea 100644 --- a/front/src/hooks/api/useBook.ts +++ b/front/src/hooks/api/useBook.ts @@ -15,8 +15,8 @@ function useBook() { processBook, ) - const handleBook = useCallback((id: number) => { - void doSend({}, { + const handleBook = useCallback(async (id: number) => { + await doSend({}, { body: JSON.stringify({ id, }), diff --git a/front/src/hooks/useSendButtonCaption.ts b/front/src/hooks/useSendButtonCaption.ts index 55e1fa0..25b7041 100644 --- a/front/src/hooks/useSendButtonCaption.ts +++ b/front/src/hooks/useSendButtonCaption.ts @@ -12,7 +12,7 @@ function useSendButtonCaption( const [title, setTitle] = useState(initial) const update = useCallback(>(data: T | null | undefined) => { - if (data !== undefined) { // not loading + if (data !== undefined && data !== null) { // not loading or error setCaption(result) setTitle('Отправить ещё раз') From 18a7a0cbb950936565b4efd71ff5b7db17875cce Mon Sep 17 00:00:00 2001 From: dm1sh Date: Wed, 13 Sep 2023 22:41:53 +0300 Subject: [PATCH 23/23] Renamed Answer to Success return fields on front --- front/src/api/putAnnouncement/index.ts | 2 +- front/src/api/putAnnouncement/types.ts | 4 ++-- front/src/api/removeAnnouncement/index.ts | 4 ++-- front/src/api/removeAnnouncement/types.ts | 4 ++-- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/front/src/api/putAnnouncement/index.ts b/front/src/api/putAnnouncement/index.ts index 0cc2cb4..c4de6e9 100644 --- a/front/src/api/putAnnouncement/index.ts +++ b/front/src/api/putAnnouncement/index.ts @@ -6,7 +6,7 @@ const composePutAnnouncementURL = () => ( ) const processPutAnnouncement = (data: PutAnnouncementResponse): PutAnnouncement => { - return data.Answer + return data.Success } export { composePutAnnouncementURL, processPutAnnouncement } diff --git a/front/src/api/putAnnouncement/types.ts b/front/src/api/putAnnouncement/types.ts index 9339351..dc2b676 100644 --- a/front/src/api/putAnnouncement/types.ts +++ b/front/src/api/putAnnouncement/types.ts @@ -1,12 +1,12 @@ import { isObject } from '../../utils/types' type PutAnnouncementResponse = { - Answer: boolean, + Success: boolean, } const isPutAnnouncementResponse = (obj: unknown): obj is PutAnnouncementResponse => ( isObject(obj, { - 'Answer': 'boolean', + 'Success': 'boolean', }) ) diff --git a/front/src/api/removeAnnouncement/index.ts b/front/src/api/removeAnnouncement/index.ts index dd52f7a..0aee986 100644 --- a/front/src/api/removeAnnouncement/index.ts +++ b/front/src/api/removeAnnouncement/index.ts @@ -6,11 +6,11 @@ const composeRemoveAnnouncementURL = () => ( ) function processRemoveAnnouncement(data: RemoveAnnouncementResponse): RemoveAnnouncement { - if (!data.Answer) { + if (!data.Success) { throw new Error('Не удалось закрыть объявление') } - return data.Answer + return data.Success } export { composeRemoveAnnouncementURL, processRemoveAnnouncement } diff --git a/front/src/api/removeAnnouncement/types.ts b/front/src/api/removeAnnouncement/types.ts index 016379a..4a02fd8 100644 --- a/front/src/api/removeAnnouncement/types.ts +++ b/front/src/api/removeAnnouncement/types.ts @@ -1,12 +1,12 @@ import { isObject } from '../../utils/types' type RemoveAnnouncementResponse = { - Answer: boolean, + Success: boolean, } const isRemoveAnnouncementResponse = (obj: unknown): obj is RemoveAnnouncementResponse => ( isObject(obj, { - 'Answer': 'boolean', + 'Success': 'boolean', }) )