Skip to content

Commit cb8d84b

Browse files
author
Clément VALENTIN
committed
Merge branch 'main' of github.com:MyElectricalData/myelectricaldata_new
2 parents b70ec39 + 4e97130 commit cb8d84b

File tree

5 files changed

+50
-21
lines changed

5 files changed

+50
-21
lines changed
Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,12 @@
1-
from .auth import get_current_user
1+
from .auth import get_current_user, require_not_demo, is_demo_user, DEMO_EMAIL
22
from .admin import require_admin, require_permission, require_action
33

4-
__all__ = ["get_current_user", "require_admin", "require_permission", "require_action"]
4+
__all__ = [
5+
"get_current_user",
6+
"require_admin",
7+
"require_permission",
8+
"require_action",
9+
"require_not_demo",
10+
"is_demo_user",
11+
"DEMO_EMAIL",
12+
]

apps/api/src/middleware/auth.py

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,9 @@
1515

1616
logger = logging.getLogger(__name__)
1717

18+
# Demo account email constant
19+
DEMO_EMAIL = "[email protected]"
20+
1821
oauth2_scheme = OAuth2(
1922
flows=OAuthFlowsModel(
2023
clientCredentials={
@@ -133,3 +136,21 @@ async def get_current_user_optional(
133136
return user
134137

135138
return None
139+
140+
141+
def is_demo_user(user: User) -> bool:
142+
"""Check if the user is a demo account"""
143+
return user.email == DEMO_EMAIL
144+
145+
146+
async def require_not_demo(current_user: User = Depends(get_current_user)) -> User:
147+
"""
148+
Middleware that blocks demo accounts from performing write operations.
149+
Use this dependency on any endpoint that modifies data.
150+
"""
151+
if is_demo_user(current_user):
152+
raise HTTPException(
153+
status_code=status.HTTP_403_FORBIDDEN,
154+
detail="Le compte de démonstration est en lecture seule"
155+
)
156+
return current_user

apps/api/src/routers/accounts.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
from sqlalchemy.orm import selectinload
1010

1111
from ..config import settings
12-
from ..middleware import get_current_user
12+
from ..middleware import get_current_user, require_not_demo
1313
from ..models import User, PDL, Token, EmailVerificationToken, PasswordResetToken, Role
1414
from ..models.database import get_db
1515
from ..schemas import (
@@ -314,7 +314,7 @@ async def get_credentials(current_user: User = Depends(get_current_user)) -> API
314314

315315
@router.delete("/me", response_model=APIResponse)
316316
async def delete_account(
317-
current_user: User = Depends(get_current_user), db: AsyncSession = Depends(get_db)
317+
current_user: User = Depends(require_not_demo), db: AsyncSession = Depends(get_db)
318318
) -> APIResponse:
319319
"""Delete user account and all associated data"""
320320
# Delete cache for all user's PDLs
@@ -436,7 +436,7 @@ async def resend_verification(
436436

437437
@router.post("/regenerate-secret", response_model=APIResponse)
438438
async def regenerate_secret(
439-
current_user: User = Depends(get_current_user), db: AsyncSession = Depends(get_db)
439+
current_user: User = Depends(require_not_demo), db: AsyncSession = Depends(get_db)
440440
) -> APIResponse:
441441
"""Regenerate client_secret and clear all cache"""
442442
# Generate new client_secret
@@ -589,7 +589,7 @@ async def reset_password(request: Request, db: AsyncSession = Depends(get_db)) -
589589
@router.post("/update-password", response_model=APIResponse)
590590
async def update_password(
591591
request: Request,
592-
current_user: User = Depends(get_current_user),
592+
current_user: User = Depends(require_not_demo),
593593
db: AsyncSession = Depends(get_db)
594594
) -> APIResponse:
595595
"""Update password for authenticated user (requires old password verification)"""

apps/api/src/routers/energy_offers.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
from ..models import User, EnergyProvider, EnergyOffer, OfferContribution, ContributionMessage
66
from ..models.database import get_db
77
from ..schemas import APIResponse, ErrorDetail
8-
from ..middleware import get_current_user, require_permission, require_action
8+
from ..middleware import get_current_user, require_permission, require_action, require_not_demo
99
from ..services.email import email_service
1010
from ..config import settings
1111
import logging
@@ -112,7 +112,7 @@ async def list_offers(
112112
# Contribution endpoints
113113
@router.post("/contribute", response_model=APIResponse, status_code=status.HTTP_201_CREATED)
114114
async def create_contribution(
115-
contribution_data: dict, current_user: User = Depends(get_current_user), db: AsyncSession = Depends(get_db)
115+
contribution_data: dict, current_user: User = Depends(require_not_demo), db: AsyncSession = Depends(get_db)
116116
) -> APIResponse:
117117
"""Submit a new contribution for review"""
118118
logger.info(f"[CONTRIBUTION] New contribution from user: {current_user.email}")
@@ -168,7 +168,7 @@ async def create_contribution(
168168
async def update_contribution(
169169
contribution_id: str = Path(..., description="Contribution ID"),
170170
contribution_data: dict = Body(...),
171-
current_user: User = Depends(get_current_user),
171+
current_user: User = Depends(require_not_demo),
172172
db: AsyncSession = Depends(get_db),
173173
) -> APIResponse:
174174
"""Update an existing contribution (only pending or rejected ones owned by the user)"""
@@ -303,7 +303,7 @@ async def list_my_contributions(current_user: User = Depends(get_current_user),
303303
async def reply_to_contribution(
304304
contribution_id: str,
305305
body: dict = Body(...),
306-
current_user: User = Depends(get_current_user),
306+
current_user: User = Depends(require_not_demo),
307307
db: AsyncSession = Depends(get_db),
308308
) -> APIResponse:
309309
"""Allow contributor to reply to admin messages on their own contribution"""

apps/api/src/routers/pdl.py

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
from ..models.database import get_db
88
from ..schemas import PDLCreate, PDLResponse, APIResponse, ErrorDetail
99
from ..schemas.requests import AdminPDLCreate
10-
from ..middleware import get_current_user, require_admin, require_permission
10+
from ..middleware import get_current_user, require_admin, require_permission, require_not_demo
1111
from ..routers.enedis import get_valid_token
1212
from ..adapters import enedis_adapter
1313
import logging
@@ -129,7 +129,7 @@ async def create_pdl(
129129
}
130130
}
131131
),
132-
current_user: User = Depends(get_current_user),
132+
current_user: User = Depends(require_not_demo),
133133
db: AsyncSession = Depends(get_db)
134134
) -> APIResponse:
135135
"""Add a new PDL to current user"""
@@ -364,7 +364,7 @@ async def get_pdl(
364364
@router.delete("/{pdl_id}", response_model=APIResponse)
365365
async def delete_pdl(
366366
pdl_id: str = Path(..., description="PDL ID (UUID)", openapi_examples={"example_uuid": {"summary": "Example UUID", "value": "550e8400-e29b-41d4-a716-446655440000"}}),
367-
current_user: User = Depends(get_current_user),
367+
current_user: User = Depends(require_not_demo),
368368
db: AsyncSession = Depends(get_db)
369369
) -> APIResponse:
370370
"""Delete a PDL"""
@@ -384,7 +384,7 @@ async def delete_pdl(
384384
async def update_pdl_name(
385385
pdl_id: str = Path(..., description="PDL ID (UUID)", openapi_examples={"example_uuid": {"summary": "Example UUID", "value": "550e8400-e29b-41d4-a716-446655440000"}}),
386386
name_data: PDLUpdateName = Body(..., openapi_examples={"update_name": {"summary": "Update name", "value": {"name": "Nouveau nom de compteur"}}}),
387-
current_user: User = Depends(get_current_user),
387+
current_user: User = Depends(require_not_demo),
388388
db: AsyncSession = Depends(get_db),
389389
) -> APIResponse:
390390
"""Update PDL custom name"""
@@ -417,7 +417,7 @@ async def update_pdl_type(
417417
"production_only": {"summary": "Production only", "value": {"has_consumption": False, "has_production": True}},
418418
"both": {"summary": "Both consumption and production", "value": {"has_consumption": True, "has_production": True}}
419419
}),
420-
current_user: User = Depends(get_current_user),
420+
current_user: User = Depends(require_not_demo),
421421
db: AsyncSession = Depends(get_db),
422422
) -> APIResponse:
423423
"""Update PDL type (consumption and/or production)"""
@@ -451,7 +451,7 @@ async def toggle_pdl_active(
451451
"activate": {"summary": "Activate PDL", "value": {"is_active": True}},
452452
"deactivate": {"summary": "Deactivate PDL", "value": {"is_active": False}}
453453
}),
454-
current_user: User = Depends(get_current_user),
454+
current_user: User = Depends(require_not_demo),
455455
db: AsyncSession = Depends(get_db),
456456
) -> APIResponse:
457457
"""Toggle PDL active/inactive status"""
@@ -487,7 +487,7 @@ async def update_pdl_pricing_option(
487487
"hc_weekend": {"summary": "HC Nuit & Week-end", "value": {"pricing_option": "HC_WEEKEND"}},
488488
"clear": {"summary": "Remove pricing option", "value": {"pricing_option": None}}
489489
}),
490-
current_user: User = Depends(get_current_user),
490+
current_user: User = Depends(require_not_demo),
491491
db: AsyncSession = Depends(get_db),
492492
) -> APIResponse:
493493
"""
@@ -539,7 +539,7 @@ async def update_pdl_selected_offer(
539539
"select_offer": {"summary": "Select an energy offer", "value": {"selected_offer_id": "550e8400-e29b-41d4-a716-446655440001"}},
540540
"clear": {"summary": "Remove selected offer", "value": {"selected_offer_id": None}}
541541
}),
542-
current_user: User = Depends(get_current_user),
542+
current_user: User = Depends(require_not_demo),
543543
db: AsyncSession = Depends(get_db),
544544
) -> APIResponse:
545545
"""
@@ -608,7 +608,7 @@ async def link_production_pdl(
608608
"link": {"summary": "Link to production PDL", "value": {"linked_production_pdl_id": "550e8400-e29b-41d4-a716-446655440001"}},
609609
"unlink": {"summary": "Unlink production PDL", "value": {"linked_production_pdl_id": None}}
610610
}),
611-
current_user: User = Depends(get_current_user),
611+
current_user: User = Depends(require_not_demo),
612612
db: AsyncSession = Depends(get_db),
613613
) -> APIResponse:
614614
"""
@@ -723,7 +723,7 @@ async def update_pdl_contract(
723723
}
724724
}
725725
),
726-
current_user: User = Depends(get_current_user),
726+
current_user: User = Depends(require_not_demo),
727727
db: AsyncSession = Depends(get_db),
728728
) -> APIResponse:
729729
"""Update PDL contract information (subscribed power and offpeak hours)"""
@@ -770,7 +770,7 @@ async def reorder_pdls(
770770
}
771771
}
772772
),
773-
current_user: User = Depends(get_current_user),
773+
current_user: User = Depends(require_not_demo),
774774
db: AsyncSession = Depends(get_db),
775775
) -> APIResponse:
776776
"""Update display order for multiple PDLs"""

0 commit comments

Comments
 (0)