Skip to content

Commit

Permalink
chore: apply code-quality
Browse files Browse the repository at this point in the history
  • Loading branch information
guifry committed Jan 15, 2025
1 parent 15e5fb4 commit dba84bb
Show file tree
Hide file tree
Showing 42 changed files with 223 additions and 172 deletions.
11 changes: 2 additions & 9 deletions .github/workflows/code-quality.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -22,15 +22,8 @@ jobs:
run: |
poetry install --only ci
- name: Run pre-commit (Python + TS checks)
run: |
poetry run pre-commit run --all-files
- name: Python checks
run: |
poetry run black --check .
poetry run ruff .
poetry run mypy .
- name: Run code quality checks
run: make code-quality-check

- uses: actions/setup-node@v3
with:
Expand Down
8 changes: 3 additions & 5 deletions .ruff.toml
Original file line number Diff line number Diff line change
@@ -1,9 +1,7 @@
[tool.ruff]
extend-exclude = ["migrations", "dist", "build"]
exclude = ["migrations", "dist", "build"]
ignore-init-module-imports = true
select = ["E", "F", "I", "B", "C4", "SIM", "N", "UP"]

[tool.ruff.isort]
[isort]
force-single-line = false
combine_as_imports = true
line_length = 88
combine-as-imports = true
30 changes: 23 additions & 7 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,11 @@ help:
@echo " make docker-run Run the Docker container for specified app"
@echo " make clean Clean up Docker images and containers"
@echo " make code-quality Run Python and TypeScript checks and formatting"
@echo " make code-quality-fix Fix code quality issues"
@echo " make code-quality-check Check code quality issues"

# Global commands
.PHONY: install lint test code-quality
.PHONY: install lint test code-quality code-quality-fix code-quality-check
install:
@echo "Installing dependencies..."
$(PYTHON_RUNNER) install
Expand All @@ -33,18 +35,32 @@ test:
@echo "Running tests..."
pytest

code-quality:
code-quality-fix:
# Python
poetry install --only ci
poetry run ruff --fix .
poetry run black .
# Or run pre-commit directly:
# poetry run pre-commit run --all-files
poetry run ruff --fix . || true
poetry run black . || true

# TypeScript
cd client && npm ci
cd client && npm run lint -- --fix || true
cd client && npm run format || true

code-quality-check:
# Python
poetry install --only ci
poetry run ruff .
poetry run black --check .

# TypeScript
cd client && npm ci
cd client && npm run lint
cd client && npm run format
cd client && npm run format -- --check

code-quality:
@echo "Running code-quality-fix and code-quality-check..."
make code-quality-fix
make code-quality-check

# Docker commands
.PHONY: docker-build docker-run
Expand Down
1 change: 0 additions & 1 deletion apps/consent-api/app.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
from fastapi import FastAPI
from fastapi.middleware.cors import CORSMiddleware

from src.consents.router import router as consents_router
from src.origins.router import router as origins_router

Expand Down
21 changes: 13 additions & 8 deletions apps/consent-api/migrations/versions/de84fe4ee0a6_.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,24 +11,29 @@


# revision identifiers, used by Alembic.
revision = 'de84fe4ee0a6'
down_revision = '1a04197c5206'
revision = "de84fe4ee0a6"
down_revision = "1a04197c5206"
branch_labels = None
depends_on = None


def upgrade() -> None:
# ### commands auto generated by Alembic - please adjust! ###
op.create_table('origin',
sa.Column('created_at', sa.DateTime(), server_default=sa.text('now()'), nullable=True),
sa.Column('updated_at', sa.DateTime(), server_default=sa.text('now()'), nullable=True),
sa.Column('origin', sqlmodel.sql.sqltypes.AutoString(), nullable=False),
sa.PrimaryKeyConstraint('origin')
op.create_table(
"origin",
sa.Column(
"created_at", sa.DateTime(), server_default=sa.text("now()"), nullable=True
),
sa.Column(
"updated_at", sa.DateTime(), server_default=sa.text("now()"), nullable=True
),
sa.Column("origin", sqlmodel.sql.sqltypes.AutoString(), nullable=False),
sa.PrimaryKeyConstraint("origin"),
)
# ### end Alembic commands ###


def downgrade() -> None:
# ### commands auto generated by Alembic - please adjust! ###
op.drop_table('origin')
op.drop_table("origin")
# ### end Alembic commands ###
1 change: 0 additions & 1 deletion apps/consent-api/src/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,3 @@
"DATABASE_URL",
"postgresql+asyncpg://postgres:postgres@localhost:5433/postgres",
)

8 changes: 5 additions & 3 deletions apps/consent-api/src/consents/application/dto.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
from pydantic import BaseModel
from fastapi import Form
import json

from fastapi import Form
from pydantic import BaseModel


class CreateConsentDTO(BaseModel):
essential: bool
Expand All @@ -23,7 +24,8 @@ class ConsentStatusDTO(BaseModel):
settings: bool
usage: bool
campaigns: bool



class ConsentResponseDTO(BaseModel):
uid: str
status: ConsentStatusDTO
7 changes: 3 additions & 4 deletions apps/consent-api/src/consents/application/service.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,12 @@
from dataclasses import dataclass

from src.consents.domain import UserConsent
from src.consents.domain import CookieConsent
from src.consents.domain.exceptions import ConsentNotFoundException
from src.consents.application.dto import (
CreateConsentDTO,
ConsentResponseDTO,
ConsentStatusDTO,
CreateConsentDTO,
)
from src.consents.domain import CookieConsent, UserConsent
from src.consents.domain.exceptions import ConsentNotFoundException
from src.consents.repositories.consents_repository import IConsentsRepository
from src.consents.utils import generate_uid

Expand Down
8 changes: 7 additions & 1 deletion apps/consent-api/src/consents/dependencies.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,18 @@
from typing import Callable

from fastapi import Depends
from src.consents.repositories.consents_repository import ConsentsRepositorySQL, IConsentsRepository
from src.consents.application.service import ConsentsService
from src.consents.repositories.consents_repository import (
ConsentsRepositorySQL,
IConsentsRepository,
)
from src.db_utils import db_context


async def get_db_session() -> Callable:
return db_context


def get_consents_service(db: Callable = Depends(get_db_session)) -> ConsentsService:
repo: IConsentsRepository = ConsentsRepositorySQL(db)
return ConsentsService(repo=repo)
3 changes: 2 additions & 1 deletion apps/consent-api/src/consents/domain/__init__.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
from dataclasses import dataclass


@dataclass
class CookieConsent:
essential: bool = True
Expand All @@ -12,7 +13,7 @@ def to_dict(self):
"essential": self.essential,
"settings": self.settings,
"usage": self.usage,
"campaigns": self.campaigns
"campaigns": self.campaigns,
}


Expand Down
1 change: 1 addition & 0 deletions apps/consent-api/src/consents/domain/exceptions.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
class ConsentsDomainException(Exception):
pass


class ConsentNotFoundException(ConsentsDomainException):
def __init__(self, uid: str):
super().__init__(f"Consent record with UID {uid} not found")
Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,11 @@
from abc import ABC, abstractmethod
from typing import Callable
from sqlmodel import select

from src.consents.domain import UserConsent
from src.consents.domain import CookieConsent

from sqlmodel import select
from src.consents.domain import CookieConsent, UserConsent
from src.consents.repositories.models import UserConsentModel


class IConsentsRepository(ABC):
@abstractmethod
async def save_user_consents(self, user_consent: UserConsent) -> None:
Expand All @@ -30,10 +29,11 @@ async def save_user_consents(self, user_consent: UserConsent) -> None:
await session.merge(db_obj)
await session.commit()


async def fetch_user_consents_by_uid(self, uid: str) -> UserConsent | None:
async with self.session_maker() as session:
result = await session.execute(select(UserConsentModel).where(UserConsentModel.uid == uid))
result = await session.execute(
select(UserConsentModel).where(UserConsentModel.uid == uid)
)
db_obj = result.scalar_one_or_none()
if db_obj:
c = CookieConsent(**db_obj.consent)
Expand Down
16 changes: 6 additions & 10 deletions apps/consent-api/src/consents/repositories/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,11 @@

import datetime
import json
from dataclasses import asdict
from dataclasses import dataclass
from dataclasses import fields
from dataclasses import asdict, dataclass, fields
from typing import ClassVar

from sqlalchemy import Column
from sqlalchemy import func
from sqlmodel import JSON
from sqlmodel import Field
from sqlmodel import SQLModel
from sqlalchemy import Column, func
from sqlmodel import JSON, Field, SQLModel


@dataclass
Expand Down Expand Up @@ -47,8 +42,9 @@ def parse_json(cls, data: str) -> CookieConsent:
return CookieConsent(**json.loads(data))



CookieConsentModel.ACCEPT_ALL = CookieConsentModel(*([True] * len(fields(CookieConsentModel))))
CookieConsentModel.ACCEPT_ALL = CookieConsentModel(
*([True] * len(fields(CookieConsentModel)))
)
CookieConsentModel.REJECT_ALL = CookieConsentModel()


Expand Down
7 changes: 4 additions & 3 deletions apps/consent-api/src/consents/router.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
from fastapi import APIRouter, Depends, Response, status
from src.consents.application.dto import CreateConsentDTO
from src.consents.domain.exceptions import ConsentNotFoundException
from src.consents.dependencies import get_consents_service
from src.consents.application.service import ConsentsService
from src.consents.dependencies import get_consents_service
from src.consents.domain.exceptions import ConsentNotFoundException

router = APIRouter()


@router.post("/", status_code=status.HTTP_201_CREATED)
async def create_user_consents(
dto: CreateConsentDTO = Depends(CreateConsentDTO.from_form_data),
Expand Down Expand Up @@ -38,4 +39,4 @@ async def set_user_consents(
return await service.update_user_consents(uid, dto)
except ConsentNotFoundException:
response.status_code = status.HTTP_404_NOT_FOUND
return None
return None
1 change: 1 addition & 0 deletions apps/consent-api/src/consents/utils.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import base64
import uuid


def generate_uid() -> str:
return base64.urlsafe_b64encode(uuid.uuid4().bytes).decode("utf8").rstrip("=")
8 changes: 4 additions & 4 deletions apps/consent-api/src/db_utils.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
from sqlalchemy.ext.asyncio import AsyncSession
from sqlalchemy.ext.asyncio import create_async_engine
from sqlalchemy.orm import sessionmaker
from essentials.json import FriendlyEncoder
from contextlib import asynccontextmanager

from essentials.json import FriendlyEncoder
from sqlalchemy.ext.asyncio import AsyncSession, create_async_engine
from sqlalchemy.orm import sessionmaker
from src import config

engine = create_async_engine(
Expand All @@ -18,6 +17,7 @@
class_=AsyncSession,
)


async def db_session():
"""Get a database session."""
async with async_session() as session:
Expand Down
7 changes: 5 additions & 2 deletions apps/consent-api/src/origins/dependencies.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,16 @@
from typing import Callable

from fastapi import Depends
from sqlalchemy.ext.asyncio import AsyncSession
from src.origins.repository import OriginsRepositorySQL, IOriginsRepository
from src.origins.service import OriginsService
from src.db_utils import db_context
from src.origins.repository import IOriginsRepository, OriginsRepositorySQL
from src.origins.service import OriginsService


async def get_db_session() -> Callable:
return db_context


def get_origins_service(db: AsyncSession = Depends(get_db_session)) -> OriginsService:
repo: IOriginsRepository = OriginsRepositorySQL(db)
return OriginsService(repo=repo)
6 changes: 4 additions & 2 deletions apps/consent-api/src/origins/models.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
from __future__ import annotations

import datetime

from sqlalchemy import func
from sqlmodel import Field
from sqlmodel import SQLModel
from sqlmodel import Field, SQLModel


class Timestamped(SQLModel):
"""Mixin to add created and update timestamps to models."""
Expand All @@ -18,6 +19,7 @@ class Timestamped(SQLModel):
},
)


class OriginModel(Timestamped, SQLModel, table=True):
"""
Origin represents a service origin (scheme, domain name, port number).
Expand Down
3 changes: 3 additions & 0 deletions apps/consent-api/src/origins/repository.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,16 @@
from abc import ABC, abstractmethod

from sqlalchemy.ext.asyncio import AsyncSession
from sqlmodel import select
from src.origins.models import OriginModel


class IOriginsRepository(ABC):
@abstractmethod
async def fetch_all(self) -> list[str]:
pass


class OriginsRepositorySQL(IOriginsRepository):
def __init__(self, session: AsyncSession):
self.session = session
Expand Down
1 change: 1 addition & 0 deletions apps/consent-api/src/origins/router.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

router = APIRouter()


@router.get("/")
async def known_origins(service: OriginsService = Depends(get_origins_service)):
return await service.list_origins()
Loading

0 comments on commit dba84bb

Please sign in to comment.