diff --git a/backend/moonstream/data.py b/backend/moonstream/data.py index aba1ca8b..85c902b2 100644 --- a/backend/moonstream/data.py +++ b/backend/moonstream/data.py @@ -1,11 +1,41 @@ """ Pydantic schemas for the Moonstream HTTP API """ -from typing import List +from enum import Enum +from typing import List, Optional + from pydantic import BaseModel, Field +class SubscriptionTypeResourceData(BaseModel): + id: str + name: str + description: str + subscription_plan_id: Optional[str] = None + active: bool = False + + +class SubscriptionTypesListResponce(BaseModel): + subscriptions: List[SubscriptionTypeResourceData] = Field(default_factory=list) + + +class SubscriptionResourceData(BaseModel): + id: str + address: str + color: str + label: str + user_id: str + subscription_type_id: str + + +class CreateSubscriptionRequest(BaseModel): + address: str + color: str + label: str + subscription_type_id: str + + class PingResponse(BaseModel): """ Schema for ping response @@ -40,4 +70,4 @@ class SubscriptionResponse(BaseModel): class SubscriptionsListResponse(BaseModel): - subscriptions: List[SubscriptionResponse] = Field(default_factory=list) + subscriptions: List[SubscriptionResourceData] = Field(default_factory=list) diff --git a/backend/moonstream/routes/subscriptions.py b/backend/moonstream/routes/subscriptions.py index 22ea4b34..3c2959ac 100644 --- a/backend/moonstream/routes/subscriptions.py +++ b/backend/moonstream/routes/subscriptions.py @@ -2,11 +2,11 @@ The Moonstream subscriptions HTTP API """ import logging -from typing import Dict +from typing import Dict, List from bugout.data import BugoutResource, BugoutResources from bugout.exceptions import BugoutResponseException -from fastapi import Body, FastAPI, HTTPException, Request +from fastapi import Body, FastAPI, HTTPException, Request, Form from fastapi.middleware.cors import CORSMiddleware from .. import data @@ -49,18 +49,57 @@ whitelist_paths.update(DOCS_PATHS) app.add_middleware(BroodAuthMiddleware, whitelist=whitelist_paths) -@app.post("/", tags=["subscriptions"], response_model=data.SubscriptionResponse) +@app.post("/", tags=["subscriptions"], response_model=data.SubscriptionResourceData) async def add_subscription_handler( - request: Request, subscription_data: data.SubscriptionRequest = Body(...) -) -> data.SubscriptionResponse: + request: Request, # subscription_data: data.CreateSubscriptionRequest = Body(...) + address: str = Form(...), + color: str = Form(...), + label: str = Form(...), + subscription_type_id: str = Form(...), +) -> data.SubscriptionResourceData: """ Add subscription to blockchain stream data for user. """ + subscription_data = data.CreateSubscriptionRequest( + address=address, + color=color, + label=label, + subscription_type_id=subscription_type_id, + ) + token = request.state.token + + params = {"type": "subscription_type"} + + # request availble subscriptions + try: + subscription_resources: BugoutResources = bc.list_resources( + token=token, params=params + ) + except BugoutResponseException as e: + raise HTTPException(status_code=e.status_code, detail=e.detail) + except Exception as e: + raise HTTPException(status_code=500) + + # allowed subscriptions + subscription_ids_list = [ + resource.resource_data["id"] for resource in subscription_resources.resources + ] + + if subscription_data.subscription_type_id not in subscription_ids_list: + raise HTTPException( + status_code=403, detail="Subscription type is not avilable." + ) + user = request.state.user + + # chek if that contract not already setted up + resource_data = {"user_id": str(user.id)} resource_data.update(subscription_data) + try: + resource: BugoutResource = bc.create_resource( token=token, application_id=MOONSTREAM_APPLICATION_ID, @@ -70,9 +109,42 @@ async def add_subscription_handler( raise HTTPException(status_code=e.status_code, detail=e.detail) except Exception as e: raise HTTPException(status_code=500) - return data.SubscriptionResponse( + + return data.SubscriptionResourceData( + id=str(resource.id), user_id=resource.resource_data["user_id"], - blockchain=resource.resource_data["blockchain"], + address=resource.resource_data["address"], + color=resource.resource_data["color"], + label=resource.resource_data["label"], + subscription_type_id=resource.resource_data["subscription_type_id"], + ) + + +@app.delete( + "/{subscription_id}", + tags=["subscriptions"], + response_model=data.SubscriptionResourceData, +) +async def delete_subscription_handler(request: Request, subscription_id: str): + """ + Delete subscriptions. + """ + + token = request.state.token + try: + deleted_resource = bc.delete_resource(token=token, resource_id=subscription_id) + except BugoutResponseException as e: + raise HTTPException(status_code=e.status_code, detail=e.detail) + except Exception as e: + raise HTTPException(status_code=500) + + return data.SubscriptionResourceData( + id=str(deleted_resource.id), + user_id=deleted_resource.resource_data["user_id"], + address=deleted_resource.resource_data["address"], + color=deleted_resource.resource_data["color"], + label=deleted_resource.resource_data["label"], + subscription_type_id=deleted_resource.resource_data["subscription_type_id"], ) @@ -86,15 +158,48 @@ async def get_subscriptions_handler(request: Request) -> data.SubscriptionsListR try: resources: BugoutResources = bc.list_resources(token=token, params=params) except BugoutResponseException as e: + if e.detail == "Resources not found": + return data.SubscriptionsListResponse(subscriptions=[]) raise HTTPException(status_code=e.status_code, detail=e.detail) except Exception as e: raise HTTPException(status_code=500) + return data.SubscriptionsListResponse( subscriptions=[ - data.SubscriptionResponse( + data.SubscriptionResourceData( + id=str(resource.id), user_id=resource.resource_data["user_id"], - blockchain=resource.resource_data["blockchain"], + address=resource.resource_data["address"], + color=resource.resource_data["color"], + label=resource.resource_data["label"], + subscription_type_id=resource.resource_data["subscription_type_id"], ) for resource in resources.resources ] ) + + +@app.get( + "/types", tags=["subscriptions"], response_model=data.SubscriptionTypesListResponce +) +async def get_available_subscriptions_type( + request: Request, +) -> data.SubscriptionTypesListResponce: + + """ + Get available's subscriptions types. + """ + token = request.state.token + params = {"type": "subscription_type"} + try: + resources: BugoutResources = bc.list_resources(token=token, params=params) + except BugoutResponseException as e: + raise HTTPException(status_code=e.status_code, detail=e.detail) + except Exception as e: + raise HTTPException(status_code=500) + return data.SubscriptionTypesListResponce( + subscriptions=[ + data.SubscriptionTypeResourceData.validate(resource.resource_data) + for resource in resources.resources + ] + )