Skip to content
Merged
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
3 changes: 2 additions & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[project]
name = "oxutils"
version = "0.5.0"
version = "0.5.1"
description = "Production-ready utilities for Django applications in the Oxiliere ecosystem"
readme = "README.md"
license = "LGPL-3.0-only"
Expand Down Expand Up @@ -100,6 +100,7 @@ dev = [
"ruff>=0.8.0",
"twine>=6.0.0",
"psycopg[binary]>=3.3.2",
"django-stubs>=6.0.7",
]


Expand Down
4 changes: 2 additions & 2 deletions src/oxutils/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
- Structured logging with correlation IDs, request metadata binding,
and pre-built ``LOGGING`` configuration (structlog)
- Audit log export to S3 with export-state tracking and status history
- Cursor-based pagination for Django Ninja APIs
- Paginated APIs via Django Ninja Extra (``PageNumberPaginationExtra``)
- PDF generation via WeasyPrint (``Printer`` class and ``WeasyTemplateView``)
- Multi-currency support with rate syncing (BCC, Open Exchange Rates)
- Celery app with task auto-discovery and structlog integration
Expand All @@ -40,7 +40,7 @@
image validation, bound-request detection
"""

__version__ = "0.5.0"
__version__ = "0.5.1"

from oxutils.conf import AUDIT_MIDDLEWARE, UTILS_APPS
from oxutils.settings import oxi_settings
Expand Down
2 changes: 1 addition & 1 deletion src/oxutils/oxiliere/authorization.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ def grant_manager_access_to_owners(tenant: BaseTenant):
tenant=tenant, is_owner=True
)

access_scope = settings.ACCESS_MANAGER_SCOPE
access_scope = getattr(settings, "ACCESS_MANAGER_SCOPE", "access")

# Vérifier qu'il y a des RoleGrants pour ce scope
role_grants = list(RoleGrant.objects.filter(scope=access_scope))
Expand Down
36 changes: 18 additions & 18 deletions src/oxutils/oxiliere/controllers.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,43 +2,43 @@

from ninja_extra import (
api_controller,
http_delete,
http_get,
http_put,
http_delete,
)
from ninja_extra.permissions import (
IsAuthenticated,
)
from ninja_extra.pagination import (
paginate,
PaginatedResponseSchema,
PageNumberPaginationExtra,
PaginatedResponseSchema,
paginate,
)
from ninja_extra.permissions import (
IsAuthenticated,
)

from oxutils.oxiliere.permissions import (
IsTenantAdmin,
IsTenantOwner,
)

from .schemas import (
get_tenant_user_list_schema,
get_tenant_user_detail_schema,
UpdateTenantUserSchema,
SetAdminSchema,
SetOwnerSchema,
UpdateTenantUserSchema,
get_tenant_user_detail_schema,
get_tenant_user_list_schema,
)
from .services import TenantUserService


TenantUserListSchema = get_tenant_user_list_schema()
TenantUserDetailSchema = get_tenant_user_detail_schema()

service = TenantUserService()


@api_controller('/users')
@api_controller("/users")
class UserController:

@http_get(
'',
"",
response=PaginatedResponseSchema[TenantUserListSchema],
permissions=[IsAuthenticated, IsTenantAdmin],
)
Expand All @@ -47,39 +47,39 @@ def list_users(self):
return service.list()

@http_get(
'/{user_id}',
"/{user_id}",
response=TenantUserDetailSchema,
permissions=[IsAuthenticated, IsTenantAdmin],
)
def get_user(self, user_id: UUID):
return service.get(user_id)

@http_put(
'/{user_id}',
"/{user_id}",
response=TenantUserDetailSchema,
permissions=[IsAuthenticated, IsTenantOwner],
)
def update_user(self, user_id: UUID, payload: UpdateTenantUserSchema):
return service.update(user_id, payload.dict(exclude_unset=True))

@http_put(
'/{user_id}/set-admin',
"/{user_id}/set-admin",
response=TenantUserDetailSchema,
permissions=[IsAuthenticated, IsTenantOwner],
)
def set_admin(self, user_id: UUID, payload: SetAdminSchema):
return service.set_admin(user_id, payload.is_admin)

@http_put(
'/{user_id}/set-owner',
"/{user_id}/set-owner",
response=TenantUserDetailSchema,
permissions=[IsAuthenticated, IsTenantOwner],
)
def set_owner(self, user_id: UUID, payload: SetOwnerSchema):
return service.set_owner(user_id, payload.is_owner)

@http_delete(
'/{user_id}',
"/{user_id}",
response={204: None},
permissions=[IsAuthenticated, IsTenantOwner],
)
Expand Down
10 changes: 7 additions & 3 deletions src/oxutils/oxiliere/services.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
"""
Oxiliere services — TenantUser management + Tenant lifecycle.
"""
import structlog
from typing import Optional

from uuid import UUID

import structlog
from django.contrib.auth.models import AbstractBaseUser
from django.db import transaction
from django.db.models import QuerySet
Expand All @@ -19,6 +19,7 @@

# ── TenantUserService (existing) ────────────────────────────────────


class TenantUserService(BaseService):
logger = logger

Expand Down Expand Up @@ -98,6 +99,7 @@ def remove(self, pk: UUID):

# ── TenantService (new) ─────────────────────────────────────────────


class TenantService:
"""Thin service layer for tenant lifecycle operations."""

Expand Down Expand Up @@ -127,7 +129,9 @@ def suspend(tenant) -> None:
tenant.save(update_fields=["status", "is_active"])

@staticmethod
def add_user(tenant, user: AbstractBaseUser, is_owner: bool = False, is_admin: bool = False) -> None:
def add_user(
tenant, user: AbstractBaseUser, is_owner: bool = False, is_admin: bool = False
) -> None:
tenant.add_user(user, is_owner=is_owner, is_admin=is_admin)

@staticmethod
Expand Down
Empty file removed src/oxutils/pagination/__init__.py
Empty file.
Loading
Loading