from http import HTTPStatus from typing import Annotated from aws_lambda_powertools.event_handler.api_gateway import Router from aws_lambda_powertools.event_handler.openapi.params import Body from layercake.dateutils import now from layercake.dynamodb import DynamoDBPersistenceLayer, KeyPair from api_gateway import JSONResponse from boto3clients import dynamodb_client from config import USER_TABLE from exceptions import ( OrgNotFoundError, SubscriptionConflictError, SubscriptionRequiredError, ) router = Router() dyn = DynamoDBPersistenceLayer(USER_TABLE, dynamodb_client) @router.post('//subscription') def add( org_id: str, name: Annotated[str, Body(embed=True)], billing_day: Annotated[int, Body(embed=True, ge=1, le=31)], subscription_frozen: Annotated[bool, Body(embed=True)] = False, ): now_ = now() with dyn.transact_writer() as transact: transact.update( key=KeyPair(org_id, '0'), update_expr='SET subscription_covered = :true, updated_at = :now', cond_expr='attribute_exists(sk) AND #name = :name', expr_attr_names={ '#name': 'name', }, expr_attr_values={ ':name': name, ':true': True, ':now': now_, }, exc_cls=OrgNotFoundError, ) transact.put( item={ 'id': org_id, 'sk': 'METADATA#SUBSCRIPTION', 'billing_day': billing_day, 'created_at': now_, }, cond_expr='attribute_not_exists(sk)', exc_cls=SubscriptionConflictError, ) transact.put( item={ 'id': 'SUBSCRIPTION', 'sk': f'ORG#{org_id}', 'name': name, 'created_at': now_, }, cond_expr='attribute_not_exists(sk)', exc_cls=SubscriptionConflictError, ) if subscription_frozen: transact.put( item={ 'id': 'SUBSCRIPTION#FROZEN', 'sk': f'ORG#{org_id}', 'created_at': now_, } ) return JSONResponse(status_code=HTTPStatus.CREATED) @router.put('//subscription') def edit( org_id: str, billing_day: Annotated[int, Body(embed=True, ge=1, le=31)], subscription_frozen: Annotated[bool, Body(embed=True)] = False, ): now_ = now() with dyn.transact_writer() as transact: transact.condition( key=KeyPair('SUBSCRIPTION', f'ORG#{org_id}'), cond_expr='attribute_exists(sk)', exc_cls=SubscriptionRequiredError, ) transact.update( key=KeyPair(org_id, 'METADATA#SUBSCRIPTION'), update_expr='SET billing_day = :billing_day, \ updated_at = :now', expr_attr_values={ ':billing_day': billing_day, ':now': now_, }, cond_expr='attribute_exists(sk)', exc_cls=SubscriptionRequiredError, ) if subscription_frozen: transact.put( item={ 'id': 'SUBSCRIPTION#FROZEN', 'sk': f'ORG#{org_id}', 'created_at': now_, } ) else: transact.delete(key=KeyPair('SUBSCRIPTION#FROZEN', f'ORG#{org_id}')) return JSONResponse(status_code=HTTPStatus.NO_CONTENT) @router.delete('//subscription') def remove(org_id: str): now_ = now() with dyn.transact_writer() as transact: transact.update( key=KeyPair(org_id, '0'), update_expr='SET updated_at = :now REMOVE subscription_covered', expr_attr_values={ ':now': now_, }, cond_expr='attribute_exists(sk)', exc_cls=OrgNotFoundError, ) transact.delete(key=KeyPair(org_id, 'METADATA#SUBSCRIPTION')) transact.delete(key=KeyPair('SUBSCRIPTION', f'ORG#{org_id}')) transact.delete(key=KeyPair('SUBSCRIPTION#FROZEN', f'ORG#{org_id}')) return JSONResponse(status_code=HTTPStatus.NO_CONTENT)