kopia lustrzana https://github.com/bugout-dev/moonstream
Fixed metatx contract routes to work with new db model
rodzic
2d93c307ab
commit
1589c8c65d
|
@ -6,13 +6,21 @@ from datetime import timedelta
|
|||
from typing import Any, Dict, List, Optional, Tuple
|
||||
|
||||
from sqlalchemy import func, text
|
||||
from sqlalchemy.dialects.postgresql import insert
|
||||
from sqlalchemy.engine import Row
|
||||
from sqlalchemy.exc import IntegrityError, NoResultFound
|
||||
from sqlalchemy.orm import Session
|
||||
from web3 import Web3
|
||||
|
||||
from . import data, db
|
||||
from .data import ContractType
|
||||
from .models import Blockchain, CallRequest, CallRequestType, RegisteredContract
|
||||
from .models import (
|
||||
Blockchain,
|
||||
CallRequest,
|
||||
CallRequestType,
|
||||
MetatxHolder,
|
||||
RegisteredContract,
|
||||
)
|
||||
|
||||
logging.basicConfig(level=logging.INFO)
|
||||
logger = logging.getLogger(__name__)
|
||||
|
@ -30,6 +38,12 @@ class InvalidAddressFormat(Exception):
|
|||
"""
|
||||
|
||||
|
||||
class UnsupportedBlockchain(Exception):
|
||||
"""
|
||||
Raised when unsupported blockchain specified.
|
||||
"""
|
||||
|
||||
|
||||
class ContractAlreadyRegistered(Exception):
|
||||
pass
|
||||
|
||||
|
@ -72,23 +86,33 @@ def validate_method_and_params(
|
|||
|
||||
def register_contract(
|
||||
db_session: Session,
|
||||
blockchain: str,
|
||||
blockchain_name: str,
|
||||
address: str,
|
||||
contract_type: ContractType,
|
||||
moonstream_user_id: uuid.UUID,
|
||||
metatx_holder_id: uuid.UUID,
|
||||
title: Optional[str],
|
||||
description: Optional[str],
|
||||
image_uri: Optional[str],
|
||||
) -> data.RegisteredContract:
|
||||
) -> Tuple[RegisteredContract, Blockchain]:
|
||||
"""
|
||||
Register a contract against the Engine instance
|
||||
"""
|
||||
try:
|
||||
blockchain = (
|
||||
db_session.query(Blockchain)
|
||||
.filter(Blockchain.name == blockchain_name)
|
||||
.one_or_none()
|
||||
)
|
||||
if blockchain is None:
|
||||
raise UnsupportedBlockchain("Unsupported blockchain specified")
|
||||
|
||||
metatx_holder_stmt = insert(MetatxHolder.__table__).values(id=metatx_holder_id)
|
||||
metatx_holder_stmt_do_nothing_stmt = metatx_holder_stmt.on_conflict_do_nothing()
|
||||
db_session.execute(metatx_holder_stmt_do_nothing_stmt)
|
||||
|
||||
contract = RegisteredContract(
|
||||
blockchain=blockchain,
|
||||
blockchain_id=blockchain.id,
|
||||
address=Web3.toChecksumAddress(address),
|
||||
contract_type=contract_type.value,
|
||||
moonstream_user_id=moonstream_user_id,
|
||||
metatx_holder_id=metatx_holder_id,
|
||||
title=title,
|
||||
description=description,
|
||||
image_uri=image_uri,
|
||||
|
@ -103,38 +127,42 @@ def register_contract(
|
|||
logger.error(repr(err))
|
||||
raise
|
||||
|
||||
return contract
|
||||
return (contract, blockchain)
|
||||
|
||||
|
||||
def update_registered_contract(
|
||||
db_session: Session,
|
||||
moonstream_user_id: uuid.UUID,
|
||||
metatx_holder_id: uuid.UUID,
|
||||
contract_id: uuid.UUID,
|
||||
title: Optional[str] = None,
|
||||
description: Optional[str] = None,
|
||||
image_uri: Optional[str] = None,
|
||||
ignore_nulls: bool = True,
|
||||
) -> data.RegisteredContract:
|
||||
) -> Tuple[RegisteredContract, Blockchain]:
|
||||
"""
|
||||
Update the registered contract with the given contract ID provided that the user with moonstream_user_id
|
||||
Update the registered contract with the given contract ID provided that the user with metatx_holder_id
|
||||
has access to it.
|
||||
"""
|
||||
query = db_session.query(RegisteredContract).filter(
|
||||
RegisteredContract.id == contract_id,
|
||||
RegisteredContract.moonstream_user_id == moonstream_user_id,
|
||||
contract_with_blockchain = (
|
||||
db_session.query(RegisteredContract, Blockchain)
|
||||
.join(Blockchain, Blockchain.id == RegisteredContract.blockchain_id)
|
||||
.filter(
|
||||
RegisteredContract.id == contract_id,
|
||||
RegisteredContract.metatx_holder_id == metatx_holder_id,
|
||||
)
|
||||
.one()
|
||||
)
|
||||
|
||||
contract = query.one()
|
||||
registered_contract, blockchain = contract_with_blockchain
|
||||
|
||||
if not (title is None and ignore_nulls):
|
||||
contract.title = title
|
||||
registered_contract.title = title
|
||||
if not (description is None and ignore_nulls):
|
||||
contract.description = description
|
||||
registered_contract.description = description
|
||||
if not (image_uri is None and ignore_nulls):
|
||||
contract.image_uri = image_uri
|
||||
registered_contract.image_uri = image_uri
|
||||
|
||||
try:
|
||||
db_session.add(contract)
|
||||
db_session.add(registered_contract)
|
||||
db_session.commit()
|
||||
except Exception as err:
|
||||
logger.error(
|
||||
|
@ -143,24 +171,27 @@ def update_registered_contract(
|
|||
db_session.rollback()
|
||||
raise
|
||||
|
||||
return contract
|
||||
return (registered_contract, blockchain)
|
||||
|
||||
|
||||
def get_registered_contract(
|
||||
db_session: Session,
|
||||
moonstream_user_id: uuid.UUID,
|
||||
metatx_holder_id: uuid.UUID,
|
||||
contract_id: uuid.UUID,
|
||||
) -> RegisteredContract:
|
||||
) -> Tuple[RegisteredContract, Blockchain]:
|
||||
"""
|
||||
Get registered contract by ID.
|
||||
"""
|
||||
contract = (
|
||||
db_session.query(RegisteredContract)
|
||||
.filter(RegisteredContract.moonstream_user_id == moonstream_user_id)
|
||||
contract_with_blockchain = (
|
||||
db_session.query(RegisteredContract, Blockchain)
|
||||
.join(Blockchain, Blockchain.id == RegisteredContract.blockchain_id)
|
||||
.filter(RegisteredContract.metatx_holder_id == metatx_holder_id)
|
||||
.filter(RegisteredContract.id == contract_id)
|
||||
.one()
|
||||
)
|
||||
return contract
|
||||
registered_contract, blockchain = contract_with_blockchain
|
||||
|
||||
return (registered_contract, blockchain)
|
||||
|
||||
|
||||
def lookup_registered_contracts(
|
||||
|
@ -170,7 +201,7 @@ def lookup_registered_contracts(
|
|||
address: Optional[str] = None,
|
||||
limit: int = 10,
|
||||
offset: Optional[int] = None,
|
||||
) -> List[Tuple[RegisteredContract, Blockchain]]:
|
||||
) -> List[Row[Tuple[RegisteredContract, Blockchain]]]:
|
||||
"""
|
||||
Lookup a registered contract
|
||||
"""
|
||||
|
@ -191,35 +222,39 @@ def lookup_registered_contracts(
|
|||
if offset is not None:
|
||||
query = query.offset(offset)
|
||||
|
||||
registered_contracts_with_blockchain = query.limit(limit).all()
|
||||
contracts_with_blockchain = query.limit(limit).all()
|
||||
|
||||
return registered_contracts_with_blockchain
|
||||
return contracts_with_blockchain
|
||||
|
||||
|
||||
def delete_registered_contract(
|
||||
db_session: Session,
|
||||
moonstream_user_id: uuid.UUID,
|
||||
metatx_holder_id: uuid.UUID,
|
||||
registered_contract_id: uuid.UUID,
|
||||
) -> RegisteredContract:
|
||||
) -> Tuple[RegisteredContract, Blockchain]:
|
||||
"""
|
||||
Delete a registered contract
|
||||
"""
|
||||
try:
|
||||
registered_contract = (
|
||||
db_session.query(RegisteredContract)
|
||||
.filter(RegisteredContract.moonstream_user_id == moonstream_user_id)
|
||||
contract_with_blockchain = (
|
||||
db_session.query(RegisteredContract, Blockchain)
|
||||
.join(Blockchain, Blockchain.id == RegisteredContract.blockchain_id)
|
||||
.filter(RegisteredContract.metatx_holder_id == metatx_holder_id)
|
||||
.filter(RegisteredContract.id == registered_contract_id)
|
||||
.one()
|
||||
)
|
||||
contract = contract_with_blockchain[0]
|
||||
|
||||
db_session.delete(registered_contract)
|
||||
db_session.delete(contract)
|
||||
db_session.commit()
|
||||
except Exception as err:
|
||||
db_session.rollback()
|
||||
logger.error(repr(err))
|
||||
raise
|
||||
|
||||
return registered_contract
|
||||
registered_contract, blockchain = contract_with_blockchain
|
||||
|
||||
return (registered_contract, blockchain)
|
||||
|
||||
|
||||
def request_calls(
|
||||
|
|
|
@ -238,7 +238,6 @@ class BlockchainsResponse(BaseModel):
|
|||
class RegisterContractRequest(BaseModel):
|
||||
blockchain: str
|
||||
address: str
|
||||
contract_type: ContractType
|
||||
title: Optional[str] = None
|
||||
description: Optional[str] = None
|
||||
image_uri: Optional[str] = None
|
||||
|
@ -251,29 +250,6 @@ class UpdateContractRequest(BaseModel):
|
|||
ignore_nulls: bool = True
|
||||
|
||||
|
||||
class RegisteredContract(BaseModel):
|
||||
id: UUID
|
||||
blockchain: str
|
||||
address: str
|
||||
metatx_holder_id: UUID
|
||||
title: Optional[str] = None
|
||||
description: Optional[str] = None
|
||||
image_uri: Optional[str] = None
|
||||
created_at: datetime
|
||||
updated_at: datetime
|
||||
|
||||
@validator("id", "metatx_holder_id")
|
||||
def validate_uuids(cls, v):
|
||||
return str(v)
|
||||
|
||||
@validator("created_at", "updated_at")
|
||||
def validate_datetimes(cls, v):
|
||||
return v.isoformat()
|
||||
|
||||
class Config:
|
||||
orm_mode = True
|
||||
|
||||
|
||||
class RegisteredContractResponse(BaseModel):
|
||||
id: UUID
|
||||
blockchain: Optional[str] = None
|
||||
|
|
|
@ -88,7 +88,7 @@ async def blockchains_route(
|
|||
tags=["contracts"],
|
||||
response_model=List[data.RegisteredContractResponse],
|
||||
)
|
||||
async def list_registered_contracts(
|
||||
async def list_registered_contracts_route(
|
||||
request: Request,
|
||||
blockchain: Optional[str] = Query(None),
|
||||
address: Optional[str] = Query(None),
|
||||
|
@ -133,20 +133,20 @@ async def list_registered_contracts(
|
|||
@app.get(
|
||||
"/contracts/{contract_id}",
|
||||
tags=["contracts"],
|
||||
response_model=data.RegisteredContract,
|
||||
response_model=data.RegisteredContractResponse,
|
||||
)
|
||||
async def get_registered_contract(
|
||||
async def get_registered_contract_route(
|
||||
request: Request,
|
||||
contract_id: UUID = Path(...),
|
||||
db_session: Session = Depends(db.yield_db_read_only_session),
|
||||
) -> List[data.RegisteredContract]:
|
||||
) -> List[data.RegisteredContractResponse]:
|
||||
"""
|
||||
Get the contract by ID.
|
||||
"""
|
||||
try:
|
||||
contract = contracts_actions.get_registered_contract(
|
||||
contract_with_blockchain = contracts_actions.get_registered_contract(
|
||||
db_session=db_session,
|
||||
moonstream_user_id=request.state.user.id,
|
||||
metatx_holder_id=request.state.user.id,
|
||||
contract_id=contract_id,
|
||||
)
|
||||
except NoResultFound:
|
||||
|
@ -157,57 +157,87 @@ async def get_registered_contract(
|
|||
except Exception as err:
|
||||
logger.error(repr(err))
|
||||
raise EngineHTTPException(status_code=500)
|
||||
return contract
|
||||
|
||||
return data.RegisteredContractResponse(
|
||||
id=contract_with_blockchain[0].id,
|
||||
blockchain=contract_with_blockchain[1].name,
|
||||
address=contract_with_blockchain[0].address,
|
||||
metatx_holder_id=contract_with_blockchain[0].metatx_holder_id,
|
||||
title=contract_with_blockchain[0].title,
|
||||
description=contract_with_blockchain[0].description,
|
||||
image_uri=contract_with_blockchain[0].image_uri,
|
||||
created_at=contract_with_blockchain[0].created_at,
|
||||
updated_at=contract_with_blockchain[0].updated_at,
|
||||
)
|
||||
|
||||
|
||||
@app.post("/contracts", tags=["contracts"], response_model=data.RegisteredContract)
|
||||
async def register_contract(
|
||||
@app.post(
|
||||
"/contracts", tags=["contracts"], response_model=data.RegisteredContractResponse
|
||||
)
|
||||
async def register_contract_route(
|
||||
request: Request,
|
||||
contract: data.RegisterContractRequest = Body(...),
|
||||
db_session: Session = Depends(db.yield_db_session),
|
||||
) -> data.RegisteredContract:
|
||||
) -> data.RegisteredContractResponse:
|
||||
"""
|
||||
Allows users to register contracts.
|
||||
"""
|
||||
try:
|
||||
registered_contract = contracts_actions.register_contract(
|
||||
contract_with_blockchain = contracts_actions.register_contract(
|
||||
db_session=db_session,
|
||||
moonstream_user_id=request.state.user.id,
|
||||
blockchain=contract.blockchain,
|
||||
metatx_holder_id=request.state.user.id,
|
||||
blockchain_name=contract.blockchain,
|
||||
address=contract.address,
|
||||
contract_type=contract.contract_type,
|
||||
title=contract.title,
|
||||
description=contract.description,
|
||||
image_uri=contract.image_uri,
|
||||
)
|
||||
except contracts_actions.UnsupportedBlockchain:
|
||||
raise EngineHTTPException(
|
||||
status_code=400, detail="Unsupported blockchain specified"
|
||||
)
|
||||
except contracts_actions.ContractAlreadyRegistered:
|
||||
raise EngineHTTPException(
|
||||
status_code=409,
|
||||
detail="Contract already registered",
|
||||
)
|
||||
return registered_contract
|
||||
except Exception as err:
|
||||
logger.error(repr(err))
|
||||
raise EngineHTTPException(status_code=500)
|
||||
|
||||
return data.RegisteredContractResponse(
|
||||
id=contract_with_blockchain[0].id,
|
||||
blockchain=contract_with_blockchain[1].name,
|
||||
address=contract_with_blockchain[0].address,
|
||||
metatx_holder_id=contract_with_blockchain[0].metatx_holder_id,
|
||||
title=contract_with_blockchain[0].title,
|
||||
description=contract_with_blockchain[0].description,
|
||||
image_uri=contract_with_blockchain[0].image_uri,
|
||||
created_at=contract_with_blockchain[0].created_at,
|
||||
updated_at=contract_with_blockchain[0].updated_at,
|
||||
)
|
||||
|
||||
|
||||
@app.put(
|
||||
"/contracts/{contract_id}",
|
||||
tags=["contracts"],
|
||||
response_model=data.RegisteredContract,
|
||||
response_model=data.RegisteredContractResponse,
|
||||
)
|
||||
async def update_contract(
|
||||
async def update_contract_route(
|
||||
request: Request,
|
||||
contract_id: UUID = Path(...),
|
||||
update_info: data.UpdateContractRequest = Body(...),
|
||||
db_session: Session = Depends(db.yield_db_session),
|
||||
) -> data.RegisteredContract:
|
||||
) -> data.RegisteredContractResponse:
|
||||
try:
|
||||
contract = contracts_actions.update_registered_contract(
|
||||
db_session,
|
||||
request.state.user.id,
|
||||
contract_id,
|
||||
update_info.title,
|
||||
update_info.description,
|
||||
update_info.image_uri,
|
||||
update_info.ignore_nulls,
|
||||
contract_with_blockchain = contracts_actions.update_registered_contract(
|
||||
db_session=db_session,
|
||||
metatx_holder_id=request.state.user.id,
|
||||
contract_id=contract_id,
|
||||
title=update_info.title,
|
||||
description=update_info.description,
|
||||
image_uri=update_info.image_uri,
|
||||
ignore_nulls=update_info.ignore_nulls,
|
||||
)
|
||||
except NoResultFound:
|
||||
raise EngineHTTPException(
|
||||
|
@ -218,33 +248,53 @@ async def update_contract(
|
|||
logger.error(repr(err))
|
||||
raise EngineHTTPException(status_code=500)
|
||||
|
||||
return contract
|
||||
return data.RegisteredContractResponse(
|
||||
id=contract_with_blockchain[0].id,
|
||||
blockchain=contract_with_blockchain[1].name,
|
||||
address=contract_with_blockchain[0].address,
|
||||
metatx_holder_id=contract_with_blockchain[0].metatx_holder_id,
|
||||
title=contract_with_blockchain[0].title,
|
||||
description=contract_with_blockchain[0].description,
|
||||
image_uri=contract_with_blockchain[0].image_uri,
|
||||
created_at=contract_with_blockchain[0].created_at,
|
||||
updated_at=contract_with_blockchain[0].updated_at,
|
||||
)
|
||||
|
||||
|
||||
@app.delete(
|
||||
"/contracts/{contract_id}",
|
||||
tags=["contracts"],
|
||||
response_model=data.RegisteredContract,
|
||||
response_model=data.RegisteredContractResponse,
|
||||
)
|
||||
async def delete_contract(
|
||||
async def delete_contract_route(
|
||||
request: Request,
|
||||
contract_id: UUID,
|
||||
contract_id: UUID = Path(...),
|
||||
db_session: Session = Depends(db.yield_db_session),
|
||||
) -> data.RegisteredContract:
|
||||
) -> data.RegisteredContractResponse:
|
||||
"""
|
||||
Allows users to delete contracts that they have registered.
|
||||
"""
|
||||
try:
|
||||
deleted_contract = contracts_actions.delete_registered_contract(
|
||||
deleted_contract_with_blockchain = contracts_actions.delete_registered_contract(
|
||||
db_session=db_session,
|
||||
moonstream_user_id=request.state.user.id,
|
||||
metatx_holder_id=request.state.user.id,
|
||||
registered_contract_id=contract_id,
|
||||
)
|
||||
except Exception as err:
|
||||
logger.error(repr(err))
|
||||
raise EngineHTTPException(status_code=500)
|
||||
|
||||
return deleted_contract
|
||||
return data.RegisteredContractResponse(
|
||||
id=deleted_contract_with_blockchain[0].id,
|
||||
blockchain=deleted_contract_with_blockchain[1].name,
|
||||
address=deleted_contract_with_blockchain[0].address,
|
||||
metatx_holder_id=deleted_contract_with_blockchain[0].metatx_holder_id,
|
||||
title=deleted_contract_with_blockchain[0].title,
|
||||
description=deleted_contract_with_blockchain[0].description,
|
||||
image_uri=deleted_contract_with_blockchain[0].image_uri,
|
||||
created_at=deleted_contract_with_blockchain[0].created_at,
|
||||
updated_at=deleted_contract_with_blockchain[0].updated_at,
|
||||
)
|
||||
|
||||
|
||||
# TODO(kompotkot): route `/contracts/types` deprecated
|
||||
|
|
Ładowanie…
Reference in New Issue