Skip to content

Commit

Permalink
chore: refactor by ruff, black
Browse files Browse the repository at this point in the history
  • Loading branch information
Saveliy committed Jan 29, 2024
1 parent b9b4a51 commit d3ac615
Show file tree
Hide file tree
Showing 22 changed files with 268 additions and 70 deletions.
42 changes: 42 additions & 0 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
# Pre-commit configuration.
# https://pre-commit.com

# pre-commit install
# pre-commit run --all-files

default_install_hook_types:
- pre-push
- pre-commit

default_stages: [ commit, commit-msg, manual, merge-commit, post-checkout, post-commit, post-merge, post-rewrite, prepare-commit-msg, push ]

repos:
# Fix some errors with Ruff
- repo: https://github.com/astral-sh/ruff-pre-commit
rev: v0.0.292
hooks:
- id: ruff
args: [ --fix, --exit-zero, --show-fixes ]
name: "ruff: fixing"

# Reformat Python files with Black
- repo: https://github.com/psf/black
rev: 23.9.1
hooks:
- id: black
name: "black: formatting"

# Lint Python files with Ruff
- repo: https://github.com/astral-sh/ruff-pre-commit
rev: v0.0.292
hooks:
- id: ruff
name: "ruff: linting"

# Check other files
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v4.5.0
hooks:
- id: trailing-whitespace
- id: check-added-large-files
- id: end-of-file-fixer
2 changes: 1 addition & 1 deletion alembic/README
Original file line number Diff line number Diff line change
@@ -1 +1 @@
Generic single-database configuration with an async dbapi.
Generic single-database configuration with an async dbapi.
2 changes: 1 addition & 1 deletion alembic/versions/_2023_12_15_18_47_init_alembic.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
"""init alembic
Revision ID: 5434c5fc5066
Revises:
Revises:
Create Date: 2023-12-15 18:47:16.975938
"""
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,14 @@

def upgrade() -> None:
# ### commands auto generated by Alembic - please adjust! ###
op.add_column("potential_user", sa.Column("id", sa.Integer(), nullable=False, primary_key=True))
op.add_column(
"potential_user",
sa.Column("id", sa.Integer(), nullable=False, primary_key=True),
)
# set email as not unique and not primary key
op.alter_column("potential_user", "email", nullable=False, primary_key=False, unique=False)
op.alter_column(
"potential_user", "email", nullable=False, primary_key=False, unique=False
)
op.drop_constraint("potential_user_pkey", "potential_user", type_="primary")
op.create_primary_key("potential_user_pkey", "potential_user", ["id"])

Expand Down
10 changes: 8 additions & 2 deletions src/api/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,11 @@
servers=[
{"url": settings.APP_ROOT_PATH, "description": "Current"},
],
swagger_ui_parameters={"tryItOutEnabled": True, "persistAuthorization": True, "filter": True},
swagger_ui_parameters={
"tryItOutEnabled": True,
"persistAuthorization": True,
"filter": True,
},
root_path=settings.APP_ROOT_PATH,
root_path_in_servers=False,
swagger_ui_oauth2_redirect_url=None,
Expand All @@ -43,7 +47,9 @@ async def setup_repositories():
auth_repository = SqlAuthRepository(storage)
smtp_repository = SMTPRepository()

Dependencies.register_provider(AbstractParticipantRepository, participant_repository)
Dependencies.register_provider(
AbstractParticipantRepository, participant_repository
)
Dependencies.register_provider(AbstractBookingRepository, booking_repository)
Dependencies.register_provider(AbstractAuthRepository, auth_repository)
Dependencies.register_provider(SMTPRepository, smtp_repository)
Expand Down
13 changes: 10 additions & 3 deletions src/api/auth/dependencies.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,10 @@
from fastapi.security import HTTPAuthorizationCredentials, HTTPBearer
from pydantic import ValidationError

from src.api.auth.telegram import TelegramWidgetData, telegram_webapp_check_authorization
from src.api.auth.telegram import (
TelegramWidgetData,
telegram_webapp_check_authorization,
)
from src.api.dependencies import Dependencies
from src.exceptions import NoCredentialsException, IncorrectCredentialsException
from src.repositories.auth.repository import TokenRepository
Expand Down Expand Up @@ -44,7 +47,9 @@ async def verify_request(
if not bearer:
raise NoCredentialsException()

user_verification_result = await TokenRepository.verify_access_token(bearer.credentials)
user_verification_result = await TokenRepository.verify_access_token(
bearer.credentials
)
if user_verification_result.success:
return user_verification_result

Expand All @@ -53,7 +58,9 @@ async def verify_request(
# replace telegram_id with user_id
participant_repository = Dependencies.get(AbstractParticipantRepository)
telegram_id = str(bot_verification_result.user_id)
bot_verification_result.user_id = await participant_repository.get_participant_id(telegram_id)
bot_verification_result.user_id = (
await participant_repository.get_participant_id(telegram_id)
)
return bot_verification_result

try:
Expand Down
32 changes: 26 additions & 6 deletions src/api/auth/telegram.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,14 +31,26 @@ def parse_from_string(cls, string: str) -> "TelegramWidgetData":

@property
def string_to_hash(self) -> str:
return "\n".join([f"{k}={getattr(self, k)}" for k in sorted(self.model_fields.keys()) if k != "hash"])
return "\n".join(
[
f"{k}={getattr(self, k)}"
for k in sorted(self.model_fields.keys())
if k != "hash"
]
)

@property
def encoded(self) -> bytes:
return self.string_to_hash.encode("utf-8").decode("unicode-escape").encode("ISO-8859-1")
return (
self.string_to_hash.encode("utf-8")
.decode("unicode-escape")
.encode("ISO-8859-1")
)


def telegram_webapp_check_authorization(telegram_data: TelegramWidgetData) -> VerificationResult:
def telegram_webapp_check_authorization(
telegram_data: TelegramWidgetData,
) -> VerificationResult:
"""
Verify telegram data
Expand All @@ -47,12 +59,20 @@ def telegram_webapp_check_authorization(telegram_data: TelegramWidgetData) -> Ve
received_hash = telegram_data.hash
encoded_telegram_data = telegram_data.encoded
token = settings.BOT_TOKEN
secret_key = hmac.new("WebAppData".encode(), token.encode(), hashlib.sha256).digest()
evaluated_hash = hmac.new(secret_key, encoded_telegram_data, hashlib.sha256).hexdigest()
secret_key = hmac.new(
"WebAppData".encode(), token.encode(), hashlib.sha256
).digest()
evaluated_hash = hmac.new(
secret_key, encoded_telegram_data, hashlib.sha256
).hexdigest()

success = evaluated_hash == received_hash

if success:
return VerificationResult(success=success, user_id=telegram_data.user_id, source=VerificationSource.WEBAPP)
return VerificationResult(
success=success,
user_id=telegram_data.user_id,
source=VerificationSource.WEBAPP,
)
else:
return VerificationResult(success=success)
33 changes: 26 additions & 7 deletions src/api/bookings/routes.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,9 @@ def _get_start_of_week() -> datetime.date:


@router.post("/")
async def create_booking(booking: CreateBooking, verified: VerifiedDep) -> ViewBooking | str:
async def create_booking(
booking: CreateBooking, verified: VerifiedDep
) -> ViewBooking | str:
booking_repository = Dependencies.get(AbstractBookingRepository)
participant_repository = Dependencies.get(AbstractParticipantRepository)
user_id = verified.user_id
Expand All @@ -39,16 +41,25 @@ async def create_booking(booking: CreateBooking, verified: VerifiedDep) -> ViewB
if await participant_repository.is_need_to_fill_profile(user_id):
raise IncompleteProfile()

collision = await booking_repository.check_collision(booking.time_start, booking.time_end)
collision = await booking_repository.check_collision(
booking.time_start, booking.time_end
)
if collision is not None:
raise CollisionInBookings()

booking_duration = count_duration(booking.time_start, booking.time_end)

if await participant_repository.remaining_daily_hours(user_id, booking.time_start) - booking_duration < 0:
if (
await participant_repository.remaining_daily_hours(user_id, booking.time_start)
- booking_duration
< 0
):
raise NotEnoughDailyHoursToBook()

if await participant_repository.remaining_weekly_hours(user_id) - booking_duration < 0:
if (
await participant_repository.remaining_weekly_hours(user_id) - booking_duration
< 0
):
raise NotEnoughWeeklyHoursToBook()

if not await is_offset_correct(booking.time_start):
Expand Down Expand Up @@ -82,9 +93,15 @@ async def get_my_bookings(verified: VerifiedDep) -> list[ViewBooking]:
return await booking_repository.get_participant_bookings(verified.user_id)


@router.get("/form_schedule", responses={200: {"content": {"image/png": {}}}}, response_class=Response)
@router.get(
"/form_schedule",
responses={200: {"content": {"image/png": {}}}},
response_class=Response,
)
async def form_schedule(
start_of_week: Optional[datetime.date] = Query(default_factory=_get_start_of_week, example=_get_start_of_week()),
start_of_week: Optional[datetime.date] = Query(
default_factory=_get_start_of_week, example=_get_start_of_week()
),
) -> Response:
booking_repository = Dependencies.get(AbstractBookingRepository)
image_bytes = await booking_repository.form_schedule(start_of_week)
Expand All @@ -99,7 +116,9 @@ async def daily_bookings(date: datetime.date) -> list[ViewBooking]:

@router.get("/")
async def get_bookings_for_week(
start_of_week: Optional[datetime.date] = Query(default_factory=_get_start_of_week, example=_get_start_of_week()),
start_of_week: Optional[datetime.date] = Query(
default_factory=_get_start_of_week, example=_get_start_of_week()
),
) -> list[ViewBooking]:
booking_repository = Dependencies.get(AbstractBookingRepository)
bookings = await booking_repository.get_bookings_for_week(start_of_week)
Expand Down
11 changes: 9 additions & 2 deletions src/api/participants/routes.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,12 @@
from src.api.participants import router
from src.exceptions import ForbiddenException
from src.repositories.participants.abc import AbstractParticipantRepository
from src.schemas import ViewBooking, ViewParticipant, ParticipantStatus, FillParticipantProfile
from src.schemas import (
ViewBooking,
ViewParticipant,
ParticipantStatus,
FillParticipantProfile,
)


# docx
Expand Down Expand Up @@ -85,7 +90,9 @@ async def change_status(
if source.status != ParticipantStatus.LORD:
raise ForbiddenException()

updated_participant = await participant_repository.change_status(participant_id, new_status)
updated_participant = await participant_repository.change_status(
participant_id, new_status
)
return updated_participant


Expand Down
8 changes: 6 additions & 2 deletions src/config_schema.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,9 @@


class Settings(BaseModel):
APP_ROOT_PATH: str = Field("", description='Prefix for the API path (e.g. "/api/v0")')
APP_ROOT_PATH: str = Field(
"", description='Prefix for the API path (e.g. "/api/v0")'
)

DB_URL: str = Field(
"postgresql+asyncpg://postgres:postgres@localhost:5432/postgres",
Expand All @@ -14,7 +16,9 @@ class Settings(BaseModel):

# Authorization
BOT_TOKEN: str = Field(
..., example="xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", description="Bot token from @BotFather"
...,
example="xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
description="Bot token from @BotFather",
)
JWT_PRIVATE_KEY: SecretStr = Field(
...,
Expand Down
11 changes: 9 additions & 2 deletions src/exceptions.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,12 @@ def __init__(self):
detail=self.responses[401]["description"],
)

responses = {401: {"description": "Could not validate credentials", "model": ExceptionWithDetail}}
responses = {
401: {
"description": "Could not validate credentials",
"model": ExceptionWithDetail,
}
}


class ForbiddenException(HTTPException):
Expand All @@ -53,7 +58,9 @@ def __init__(self):
detail=self.responses[403]["description"],
)

responses = {403: {"description": "Not enough permissions", "model": ExceptionWithDetail}}
responses = {
403: {"description": "Not enough permissions", "model": ExceptionWithDetail}
}


class CollisionInBookings(HTTPException):
Expand Down
12 changes: 9 additions & 3 deletions src/repositories/auth/repository.py
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,9 @@ async def verify_access_token(cls, auth_token: str) -> VerificationResult:
if user is None:
return VerificationResult(success=False)

return VerificationResult(success=True, user_id=converted_user_id, source=VerificationSource.USER)
return VerificationResult(
success=True, user_id=converted_user_id, source=VerificationSource.USER
)

@classmethod
def create_access_token(cls, user_id: int) -> str:
Expand All @@ -126,7 +128,9 @@ def _create_access_token(cls, data: dict, expires_delta: datetime.timedelta) ->
issued_at = datetime.datetime.utcnow()
expire = issued_at + expires_delta
payload.update({"exp": expire, "iat": issued_at})
encoded_jwt = jwt.encode({"alg": cls.ALGORITHM}, payload, settings.JWT_PRIVATE_KEY.get_secret_value())
encoded_jwt = jwt.encode(
{"alg": cls.ALGORITHM}, payload, settings.JWT_PRIVATE_KEY.get_secret_value()
)
return str(encoded_jwt, "utf-8")

@classmethod
Expand All @@ -138,6 +142,8 @@ def verify_bot_token(cls, auth_token: str) -> VerificationResult:
else:
user_id = None

return VerificationResult(success=True, user_id=user_id, source=VerificationSource.BOT)
return VerificationResult(
success=True, user_id=user_id, source=VerificationSource.BOT
)
else:
return VerificationResult(success=False)
4 changes: 3 additions & 1 deletion src/repositories/bookings/abc.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,9 @@
class AbstractBookingRepository(metaclass=ABCMeta):
# ------------------- CRUD ------------------- #
@abstractmethod
async def create(self, participant_id: int, booking: "CreateBooking") -> "ViewBooking":
async def create(
self, participant_id: int, booking: "CreateBooking"
) -> "ViewBooking":
...

@abstractmethod
Expand Down
Loading

0 comments on commit d3ac615

Please sign in to comment.