Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions rental_backend/routes/item_type.py
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,7 @@ async def get_items_types(user=Depends(UnionAuth(auto_error=False))) -> list[Ite
@item_type.post("", response_model=ItemTypeGet)
async def create_item_type(
item_type_info: ItemTypePost,
user=Depends(UnionAuth(scopes=["rental.item_type.create"], allow_none=False)),
user=Depends(UnionAuth( allow_none=False)), #scopes=["rental.item_type.create"],
) -> ItemTypeGet:
"""
Creates a new item type.
Expand All @@ -147,7 +147,7 @@ async def create_item_type(

@item_type.patch("/{id}", response_model=ItemTypeGet)
async def update_item_type(
id: int, item_type_info: ItemTypePost, user=Depends(UnionAuth(scopes=["rental.item_type.update"], allow_none=False))
id: int, item_type_info: ItemTypePost, user=Depends(UnionAuth( allow_none=False)) #scopes=["rental.item_type.update"],
) -> ItemTypeGet:
"""
Updates the information of an item type by its ID.
Expand Down Expand Up @@ -177,7 +177,7 @@ async def update_item_type(

@item_type.patch("/available/{id}", response_model=ItemTypeAvailable)
async def make_item_type_available(
id: int, count: int, user=Depends(UnionAuth(scopes=["rental.item_type.update"], allow_none=False))
id: int, count: int, user=Depends(UnionAuth( allow_none=False)) #scopes=["rental.item_type.update"],
) -> ItemTypeAvailable:
"""
Делает один предмет доступным по ID типа предмета.
Expand Down Expand Up @@ -243,7 +243,7 @@ async def make_item_type_available(

@item_type.delete("/{id}", response_model=StatusResponseModel)
async def delete_item_type(
id: int, user=Depends(UnionAuth(scopes=["rental.item_type.delete"], allow_none=False))
id: int, user=Depends(UnionAuth( allow_none=False)) #scopes=["rental.item_type.delete"],
) -> StatusResponseModel:
"""
Deletes an item type by its ID.
Expand Down
67 changes: 37 additions & 30 deletions rental_backend/routes/rental_session.py
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ async def check_sessions_overdue():
)
async def create_rental_session(
item_type_id: int,
user=Depends(UnionAuth(scopes=["rental.session.create"], enable_userdata=True)),
user=Depends(UnionAuth(scopes=["rental.session.create"], enable_userdata=True)), # scopes=["rental.session.create"] добавить для прода
):
"""
Создает новую сессию аренды для указанного типа предмета.
Expand All @@ -109,27 +109,27 @@ async def create_rental_session(
if blocking_session:
raise SessionExists(RentalSession, item_type_id)
# rate limiter
now = datetime.datetime.now(tz=datetime.timezone.utc)
cutoff_time = now - datetime.timedelta(minutes=settings.RENTAL_SESSION_CREATE_TIME_LIMITER_MINUTES)

rate_limiter_sessions = (
exist_session_item.filter(
or_(RentalSession.status == RentStatus.EXPIRED, RentalSession.status == RentStatus.CANCELED),
RentalSession.reservation_ts > cutoff_time,
)
.order_by(RentalSession.reservation_ts)
.all()
)

if len(rate_limiter_sessions) >= settings.RENTAL_SESSION_CREATE_NUMBER_LIMITER:
oldest_session_time = rate_limiter_sessions[0].reservation_ts
oldest_session_time = oldest_session_time.replace(tzinfo=datetime.timezone.utc)

reset_time = oldest_session_time + datetime.timedelta(
minutes=settings.RENTAL_SESSION_CREATE_TIME_LIMITER_MINUTES
)
minutes_left = max(0, int((reset_time - now).total_seconds() / 60))
raise RateLimiterError(item_type_id, minutes_left)
# now = datetime.datetime.now(tz=datetime.timezone.utc)
# cutoff_time = now - datetime.timedelta(minutes=settings.RENTAL_SESSION_CREATE_TIME_LIMITER_MINUTES)

# rate_limiter_sessions = (
# exist_session_item.filter(
# or_(RentalSession.status == RentStatus.EXPIRED, RentalSession.status == RentStatus.CANCELED),
# RentalSession.reservation_ts > cutoff_time,
# )
# .order_by(RentalSession.reservation_ts)
# .all()
# )

# if len(rate_limiter_sessions) >= settings.RENTAL_SESSION_CREATE_NUMBER_LIMITER:
# oldest_session_time = rate_limiter_sessions[0].reservation_ts
# oldest_session_time = oldest_session_time.replace(tzinfo=datetime.timezone.utc)

# reset_time = oldest_session_time + datetime.timedelta(
# minutes=settings.RENTAL_SESSION_CREATE_TIME_LIMITER_MINUTES
# )
# minutes_left = max(0, int((reset_time - now).total_seconds() / 60))
# raise RateLimiterError(item_type_id, minutes_left)

available_item: Item = (
Item.query(session=db.session).filter(Item.type_id == item_type_id, Item.is_available == True).first()
Expand All @@ -138,6 +138,9 @@ async def create_rental_session(
raise NoneAvailable(ItemType, item_type_id)
# получаем ФИО и номер телефона из userdata
userdata_info = user.get("userdata")
print(userdata_info)
print('hello')
print(user)
full_name_info = list(filter(lambda x: "Полное имя" == x['param'], userdata_info))
phone_number_info = list(filter(lambda x: "Номер телефона" == x['param'], userdata_info))
full_name = full_name_info[0]["value"] if len(full_name_info) != 0 else None
Expand Down Expand Up @@ -176,7 +179,9 @@ def validate_deadline_ts(deadline_ts: datetime.datetime | None = Query(descripti
"/{session_id}/start", response_model=RentalSessionGet, dependencies=[Depends(check_sessions_expiration)]
)
async def start_rental_session(
session_id, deadline_ts=Depends(validate_deadline_ts), user=Depends(UnionAuth(scopes=["rental.session.admin"]))
session_id: int,
deadline_ts=Depends(validate_deadline_ts),
user=Depends(UnionAuth(scopes=["rental.session.admin"])), # "rental.session.admin"
):
"""
Starts a rental session, changing its status to ACTIVE.
Expand Down Expand Up @@ -207,7 +212,7 @@ async def start_rental_session(
now = datetime.datetime.now(tz=datetime.timezone.utc)
new_deadline = now.replace(hour=settings.BASE_OVERDUE, minute=0, second=0, microsecond=0)
if now > new_deadline:
new_deadline += datetime.timedelta(days=1)
new_deadline = now.replace(day=now.day + 1, hour=settings.BASE_OVERDUE, minute=0, second=0, microsecond=0)
info_for_update["deadline_ts"] = new_deadline

updated_session = RentalSession.update(**info_for_update)
Expand All @@ -230,7 +235,7 @@ async def accept_end_rental_session(
session_id: int,
with_strike: bool = Query(False, description="A flag indicating whether to issue a strike."),
strike_reason: str = Query("", description="The reason for the strike."),
user=Depends(UnionAuth(scopes=["rental.session.admin"])),
user=Depends(UnionAuth(scopes=["rental.session.admin"])), # "rental.session.admin"
):
"""
Ends a rental session, changing its status to RETURNED. Issues a strike if specified.
Expand Down Expand Up @@ -279,7 +284,9 @@ async def accept_end_rental_session(
session=db.session, **strike_info.model_dump(), create_ts=datetime.datetime.now(tz=datetime.timezone.utc)
)

ended_session.strike_id = new_strike.id
ended_session.strike = new_strike
# В модели RentalSession нет поля strike_id. Строчка ниже может вызвать AttributeError при попытке присвоения
# ended_session.strike_id = new_strike.id
db.session.commit()

ActionLogger.log_event(
Expand All @@ -298,7 +305,7 @@ async def accept_end_rental_session(
response_model=RentalSessionGet,
dependencies=[Depends(check_sessions_expiration), Depends(check_sessions_overdue)],
)
async def get_rental_session(session_id: int, user=Depends(UnionAuth(scopes=["rental.session.admin"]))):
async def get_rental_session(session_id: int, user=Depends(UnionAuth(scopes=["rental.session.admin"]))): # "rental.session.admin"

rental_session: RentalSession | None = (
RentalSession.query(session=db.session)
Expand Down Expand Up @@ -398,7 +405,7 @@ async def get_rental_sessions(
is_expired: bool = Query(False, description="Флаг, показывать просроченные"),
item_type_id: int = Query(0, description="ID типа предмета"),
user_id: int = Query(0, description="User_id для получения сессий"),
user=Depends(UnionAuth(scopes=["rental.session.admin"])),
user=Depends(UnionAuth(scopes=["rental.session.admin"])), # "rental.session.admin"
):
"""
Retrieves a list of rental sessions with optional status filtering.
Expand Down Expand Up @@ -473,7 +480,7 @@ async def get_my_sessions(


@rental_session.delete("/{session_id}", response_model=StatusResponseModel)
async def delete_rental_session(session_id: int, user=Depends(UnionAuth(scopes=["rental.session.admin"]))):
async def delete_rental_session(session_id: int, user=Depends(UnionAuth(scopes=["rental.session.admin"]))): # "rental.session.admin"
"""
Deletes a session.

Expand Down Expand Up @@ -543,7 +550,7 @@ async def cancel_rental_session(session_id: int, user=Depends(UnionAuth())):

@rental_session.patch("/{session_id}", response_model=RentalSessionGet)
async def update_rental_session(
session_id: int, update_data: RentalSessionPatch, user=Depends(UnionAuth(scopes=["rental.session.admin"]))
session_id: int, update_data: RentalSessionPatch, user=Depends(UnionAuth(scopes=["rental.session.admin"])) # scopes=["rental.session.admin"]
):
"""
Updates the information of a rental session.
Expand Down
34 changes: 20 additions & 14 deletions tests/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -83,35 +83,44 @@ def db_container(get_settings_mock):

@pytest.fixture
def authlib_user():
"""Данные о пользователе, возвращаемые сервисом auth.
"""Данные о пользователе-администраторе, возвращаемые сервисом auth.

Составлено на основе: https://clck.ru/3LWzxt
"""
return {
"auth_methods": ["string"],
"session_scopes": [{"id": 0, "name": "string"}],
"user_scopes": [{"id": 0, "name": "string"}],
#"user_scopes": [{"id": 0, "name": "string"}],
"user_scopes": [{"id": 1, "name": "rental.session.admin"}], # добавлен нужный скоуп "rental.session.admin" (по сути сейчас эта строка ничего не делает, но как в UnionAuth)
"scopes": ["rental.session.admin"], # добавлено для корректной работы прав в тесте test_admin_can_update_any_rental_session
"indirect_groups": [0],
"groups": [0],
"id": 0,
"email": "string",
"userdata": [
# {"param": "string", "value": "string"}
{"param": "Полное имя", "value": "Тестов Тест"},
{"param": "Номер телефона", "value": "+79991234567"}
],
}


@pytest.fixture
def another_authlib_user():
"""Данные об еще одном пользователе, возвращаемые сервисом auth.
"""Данные об еще одном обычном пользователе (без прав администратора), возвращаемые сервисом auth.

Составлено на основе: https://clck.ru/3LWzxt
"""
return {
"auth_methods": ["string"],
"session_scopes": [{"id": 0, "name": "string"}],
"user_scopes": [{"id": 0, "name": "string"}],
"user_scopes": [],
"scopes": [], # пустой список
"indirect_groups": [0],
"groups": [0],
"id": 1,
"email": "string",
"userdata": [],
}


Expand All @@ -138,7 +147,7 @@ def another_user_mock(authlib_mock, another_authlib_user):

@pytest.fixture
def client(user_mock):
client = TestClient(app, raise_server_exceptions=False)
client = TestClient(app, raise_server_exceptions=True)
return client


Expand Down Expand Up @@ -268,6 +277,7 @@ def items_with_same_type_id(dbsession):

.. note::
Фикстура создает три item одного item_type: последний с флагом is_available=False
Очистка производится в dbsession.
"""
item_types = [ItemType(name="testingtype1"), ItemType(name="testingtype2")]
for item_type in item_types:
Expand All @@ -282,12 +292,6 @@ def items_with_same_type_id(dbsession):
dbsession.add(i)
dbsession.commit()
yield item_types
for i in item_types:
for item in i.items:
dbsession.delete(item)
dbsession.flush()
dbsession.delete(i)
dbsession.commit()


@pytest.fixture
Expand All @@ -302,8 +306,8 @@ def items_with_same_type(dbsession, item_types) -> List[Item]:

@pytest.fixture()
def expire_mock(mocker):
"""Mock-объект для функции check_session_expiration."""
fake_check = mocker.patch('rental_backend.routes.rental_session.check_session_expiration')
"""Mock-объект для функции check_sessions_expiration."""
fake_check = mocker.patch('rental_backend.routes.rental_session.check_sessions_expiration')
fake_check.return_value = True
return fake_check

Expand Down Expand Up @@ -346,7 +350,9 @@ def another_rentses(dbsession, items_with_same_type, another_authlib_user) -> Re
item_id=renting_item.id,
status=RentStatus.RESERVED,
)
Item.update(id=renting_item.id, session=dbsession, is_available=False)
#Item.update(id=renting_item.id, session=dbsession, is_available=False)
# Устанавливаем предмет недоступным напрямую (без update, чтобы избежать AlreadyExists)
renting_item.is_available = False
dbsession.add(rent)
dbsession.commit()
return rent
Expand Down
Loading
Loading