Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
38 commits
Select commit Hold shift + click to select a range
68a4c50
Init notification-service.
ShirokovNikolay Jun 13, 2026
f623942
Create dockerfile to notification-service.
ShirokovNikolay Jun 13, 2026
0036871
Configure docker-compose using notification service.
ShirokovNikolay Jun 13, 2026
fc2070e
Install aiosmtplib.
ShirokovNikolay Jun 13, 2026
d0c9d66
Add EmailService to send email.
ShirokovNikolay Jun 13, 2026
3752b49
Fix some small bugs.
ShirokovNikolay Jun 13, 2026
887181c
Prepare work to use local maildev.
ShirokovNikolay Jun 14, 2026
aa639da
Send welcome email message on user registration.
ShirokovNikolay Jun 14, 2026
2daec3f
Fix bug: send welcome email anyway.
ShirokovNikolay Jun 14, 2026
8572add
Clean code: mediaservice and notification-service.
ShirokovNikolay Jun 15, 2026
b3c03f3
Final refactor code.
ShirokovNikolay Jun 16, 2026
a48cd53
Add email confirmation by sending a generated code to your email.
ShirokovNikolay Jun 16, 2026
1bf9230
Add frontend to confirmation email.
ShirokovNikolay Jun 17, 2026
39fe888
Add backend to send confirmation email code on auth (frontend tempora…
ShirokovNikolay Jun 18, 2026
b3bf5d5
Add working frontend to 2FA.
ShirokovNikolay Jun 18, 2026
3aadaa6
Rename a lot of files and entities for readable code.
ShirokovNikolay Jun 19, 2026
95ae136
Add reset password endpoint. Union send register, auth and reset pass…
ShirokovNikolay Jun 19, 2026
2229291
Add frontend to reset password endpoint.
ShirokovNikolay Jun 19, 2026
6450f03
Add create temporary jwt tokens for security registration, 2fa, reset…
ShirokovNikolay Jun 20, 2026
b76b557
Use temporary jwt tokens in user registration.
ShirokovNikolay Jun 20, 2026
2f77457
Use temporary jwt tokens in user authentication.
ShirokovNikolay Jun 21, 2026
13cf230
Use temporary jwt tokens to recover account.
ShirokovNikolay Jun 21, 2026
0ef3950
Split auth views to different files: registration_views,login_views, …
ShirokovNikolay Jun 21, 2026
a17044e
Add frontend to registration.
ShirokovNikolay Jun 21, 2026
3a62a63
Add frontend to login.
ShirokovNikolay Jun 21, 2026
c718ab8
Add frontend to recover access to account.
ShirokovNikolay Jun 21, 2026
8077dad
Add autologin after registration.
ShirokovNikolay Jun 21, 2026
7e062c9
Refactor jwt_utils module.
ShirokovNikolay Jun 21, 2026
39f6c8c
Rework create recover/reset jwt token.
ShirokovNikolay Jun 22, 2026
cd20fa4
Fix email messages on registration and login.
ShirokovNikolay Jun 22, 2026
730c68c
Split auth methods from UserService to AuthService and apply it to au…
ShirokovNikolay Jun 22, 2026
2ee4f96
Rename methods, refactor settings object.
ShirokovNikolay Jun 22, 2026
9c1e514
Change mediaservice -> media-service.
ShirokovNikolay Jun 23, 2026
af2cdb6
Add different redis keys on registration, 2fa, recover account.
ShirokovNikolay Jun 23, 2026
364f83e
Add max code confirm attempts.
ShirokovNikolay Jun 23, 2026
c9df8d2
Rework RedisService get method: universal convert to string, integer,…
ShirokovNikolay Jun 23, 2026
0fde32c
Add frontend auth exceptions handlers.
ShirokovNikolay Jun 24, 2026
e7511a3
Final frontend fixes.
ShirokovNikolay Jun 24, 2026
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
7 changes: 5 additions & 2 deletions .github/workflows/python-checks.yml
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,11 @@ jobs:
- name: Run mypy app
run: uv run mypy app

- name: Run mypy mediaservice
run: uv run mypy mediaservice
- name: Run mypy media-service
run: uv run mypy media-service

- name: Run mypy notification-service
run: uv run mypy notification-service

- name: Run mypy packages
run: uv run mypy packages
Expand Down
4 changes: 3 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -221,4 +221,6 @@ __marimo__/

.secrets
config.local.yaml
mediaservice/.env
media-service/.env
notification-service/.env
.env.docker-compose
13 changes: 10 additions & 3 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -24,11 +24,18 @@ repos:
args: ["app"]

- id: mypy
alias: mypy mediaservice
name: Run mypy mediaservice
alias: mypy media-service
name: Run mypy media-service
language: system
exclude: tests
args: ["mediaservice"]
args: ["media-service"]

- id: mypy
alias: mypy notification-service
name: Run mypy notification-service
language: system
exclude: tests
args: ["notification-service"]

- id: mypy
alias: mypy packages
Expand Down
2 changes: 1 addition & 1 deletion app/alembic/env.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@
# ... etc.
config.set_main_option(
"sqlalchemy.url",
settings.database.url_database,
settings.database.url,
)


Expand Down
3 changes: 2 additions & 1 deletion app/api/api_v1/__init__.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
__all__ = ("router",)
from fastapi import APIRouter

from .auth import router as auth_router
from api.api_v1.auth import router as auth_router

from .favorite_movies import router as favorite_movies_router
from .genres import router as genres_router
from .media import router as media_router
Expand Down
76 changes: 0 additions & 76 deletions app/api/api_v1/auth.py

This file was deleted.

17 changes: 17 additions & 0 deletions app/api/api_v1/auth/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
__all__ = ("router",)

from fastapi import APIRouter

from .login_views import router as login_router
from .recover_views import router as recover_account_router
from .refresh_token_views import router as refresh_token_router
from .registration_views import router as registration_router

router = APIRouter(
prefix="/auth",
)

router.include_router(registration_router)
router.include_router(login_router)
router.include_router(recover_account_router)
router.include_router(refresh_token_router)
49 changes: 49 additions & 0 deletions app/api/api_v1/auth/login_views.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
from fastapi import APIRouter
from starlette import status

from dependencies.annotations.security import GetLoginDataDep
from dependencies.annotations.services import AuthServiceDep
from schemas.auth import SendConfirmationCodeRequest, VerifyUserEmail
from schemas.token_info import TemporaryTokenInfo, TokenInfo

router = APIRouter(
prefix="/login",
tags=["Login"],
)


@router.post(
"/",
response_model=TemporaryTokenInfo,
status_code=status.HTTP_200_OK,
)
async def login_user(
login_data: GetLoginDataDep,
auth_service: AuthServiceDep,
) -> TemporaryTokenInfo:
return await auth_service.authenticate_user(login_data)


@router.post(
"/resend-confirmation-code",
status_code=status.HTTP_200_OK,
)
async def resend_authenticate_confirmation_code(
send_confirmation_code_request: SendConfirmationCodeRequest,
auth_service: AuthServiceDep,
) -> None:
await auth_service.send_authenticate_confirmation_code(
send_confirmation_code_request,
)


@router.post(
"/verify",
status_code=status.HTTP_200_OK,
response_model=TokenInfo,
)
async def verify_authenticate_user(
verify_authenticate_user_data: VerifyUserEmail,
auth_service: AuthServiceDep,
) -> TokenInfo:
return await auth_service.verify_authenticate_user(verify_authenticate_user_data)
54 changes: 54 additions & 0 deletions app/api/api_v1/auth/recover_views.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
from fastapi import APIRouter
from starlette import status

from dependencies.annotations.services import AuthServiceDep
from schemas.auth import (
RecoverAccountRequest,
ResetPasswordRequest,
SendConfirmationCodeRequest,
VerifyUserEmail,
)
from schemas.token_info import TemporaryTokenInfo

router = APIRouter(
prefix="/recover",
tags=["Recover"],
)


@router.post(
"/",
response_model=TemporaryTokenInfo,
status_code=status.HTTP_200_OK,
)
async def recover_account(
recover_account_data: RecoverAccountRequest,
auth_service: AuthServiceDep,
) -> TemporaryTokenInfo:
return await auth_service.recover_account(recover_account_data)


@router.post("/resend-confirmation-code")
async def resend_recover_account_confirmation_code(
send_confirmation_code_request: SendConfirmationCodeRequest,
auth_service: AuthServiceDep,
) -> None:
return await auth_service.send_recover_account_confirmation_code(
send_confirmation_code_request,
)


@router.post("/verify")
async def verify_recover_account(
verify_recover_account_data: VerifyUserEmail,
auth_service: AuthServiceDep,
) -> TemporaryTokenInfo:
return await auth_service.verify_recover_account(verify_recover_account_data)


@router.post("/reset-password")
async def reset_password(
reset_password_data: ResetPasswordRequest,
auth_service: AuthServiceDep,
) -> None:
await auth_service.reset_password(reset_password_data)
27 changes: 27 additions & 0 deletions app/api/api_v1/auth/refresh_token_views.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
from fastapi import (
APIRouter,
status,
)

from dependencies.annotations.security import (
AuthUserByRefreshTokenDep,
)
from dependencies.annotations.services import AuthServiceDep
from schemas.token_info import TokenInfo

router = APIRouter(
tags=["Refresh Access Token"],
)


@router.post(
"/refresh",
response_model=TokenInfo,
response_model_exclude_unset=True,
status_code=status.HTTP_200_OK,
)
async def refresh_access_token(
user_id: AuthUserByRefreshTokenDep,
auth_service: AuthServiceDep,
) -> TokenInfo:
return await auth_service.refresh_access_token(user_id)
47 changes: 47 additions & 0 deletions app/api/api_v1/auth/registration_views.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
from fastapi import APIRouter
from starlette import status

from dependencies.annotations.services import AuthServiceDep
from schemas.auth import SendConfirmationCodeRequest, VerifyUserEmail
from schemas.token_info import TemporaryTokenInfo, TokenInfo
from schemas.user import UserRegistration

router = APIRouter(
prefix="/register",
tags=["Registration"],
)


@router.post(
"/",
response_model=TemporaryTokenInfo,
status_code=status.HTTP_200_OK,
)
async def register_user(
registration_user_data: UserRegistration,
auth_service: AuthServiceDep,
) -> TemporaryTokenInfo:
return await auth_service.register_user(registration_user_data)


@router.post(
"/resend-confirmation-code",
status_code=status.HTTP_200_OK,
)
async def resend_register_confirmation_code(
send_confirmation_code_request: SendConfirmationCodeRequest,
auth_service: AuthServiceDep,
) -> None:
await auth_service.send_register_confirmation_code(send_confirmation_code_request)


@router.post(
"/verify",
response_model=TokenInfo,
status_code=status.HTTP_201_CREATED,
)
async def verify_register_user(
verify_register_user_data: VerifyUserEmail,
auth_service: AuthServiceDep,
) -> TokenInfo:
return await auth_service.verify_register_user(verify_register_user_data)
2 changes: 1 addition & 1 deletion app/api/api_v1/media.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ async def get_presign_url(
],
) -> PresignUrlResponse:
return await http_request_service.get_schema_from_request(
url=settings.mediaservice.create_presign_url_endpoint,
url=settings.media_service.create_presign_url_endpoint,
method=MethodType.post.value, # type: ignore[arg-type]
json=presign_url_create.model_dump(),
response_schema=PresignUrlResponse, # type: ignore[arg-type]
Expand Down
4 changes: 2 additions & 2 deletions app/cache_services/favorite_movie.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
from typing import cast

from core.redis.cache_service import CacheService
from core.redis.service import RedisService
from schemas.favorite_movie import (
FavoriteMovieCreate,
FavoriteMovieWithMovieResponse,
Expand All @@ -13,7 +13,7 @@ class FavoriteMovieCacheService:
def __init__(
self,
favorite_movie_service: FavoriteMovieService,
cache_service: CacheService,
cache_service: RedisService,
) -> None:
self.favorite_movie_service = favorite_movie_service
self.cache_service = cache_service
Expand Down
Loading
Loading