get all main changes

This commit is contained in:
Georg-Stahn
2023-11-27 20:07:37 +01:00
8 changed files with 519 additions and 36 deletions

View File

@@ -7,13 +7,15 @@ from fastapi import FastAPI
from fastapi.middleware.cors import CORSMiddleware from fastapi.middleware.cors import CORSMiddleware
from fastapi.routing import APIRoute from fastapi.routing import APIRoute
from fastapi.staticfiles import StaticFiles from fastapi.staticfiles import StaticFiles
from sqlalchemy.exc import SQLAlchemyError
from ..errors import ClanError from ..errors import ClanError
from . import sql_models from . import sql_models
from .assets import asset_path from .assets import asset_path
from .error_handlers import clan_error_handler from .error_handlers import clan_error_handler, sql_error_handler
from .routers import health, root, socket_manager2, sql_connect # sql router hinzufügen from .routers import health, root, socket_manager2, sql_connect # sql router hinzufügen
from .sql_db import engine from .sql_db import engine
from .tags import tags_metadata
origins = [ origins = [
"http://localhost:3000", "http://localhost:3000",
@@ -52,9 +54,13 @@ def setup_app() -> FastAPI:
# Needs to be last in register. Because of wildcard route # Needs to be last in register. Because of wildcard route
app.include_router(root.router) app.include_router(root.router)
app.add_exception_handler(ClanError, clan_error_handler) # type: ignore app.add_exception_handler(ClanError, clan_error_handler) # type: ignore
app.add_exception_handler(SQLAlchemyError, sql_error_handler) # type: ignore
app.mount("/static", StaticFiles(directory=asset_path()), name="static") app.mount("/static", StaticFiles(directory=asset_path()), name="static")
# Add tag descriptions to the OpenAPI schema
app.openapi_tags = tags_metadata
for route in app.routes: for route in app.routes:
if isinstance(route, APIRoute): if isinstance(route, APIRoute):
route.operation_id = route.name # in this case, 'read_items' route.operation_id = route.name # in this case, 'read_items'

View File

@@ -3,12 +3,27 @@ import logging
from fastapi import Request, status from fastapi import Request, status
from fastapi.encoders import jsonable_encoder from fastapi.encoders import jsonable_encoder
from fastapi.responses import JSONResponse from fastapi.responses import JSONResponse
from sqlalchemy.exc import SQLAlchemyError
from ..errors import ClanError from ..errors import ClanError
log = logging.getLogger(__name__) log = logging.getLogger(__name__)
def sql_error_handler(request: Request, exc: SQLAlchemyError) -> JSONResponse:
log.exception(exc)
detail = [
{
"loc": [],
"msg": exc._message(),
}
]
return JSONResponse(
status_code=status.HTTP_422_UNPROCESSABLE_ENTITY,
content=jsonable_encoder(dict(detail=detail)),
)
def clan_error_handler(request: Request, exc: ClanError) -> JSONResponse: def clan_error_handler(request: Request, exc: ClanError) -> JSONResponse:
log.error("ClanError: %s", exc) log.error("ClanError: %s", exc)
detail = [ detail = [

View File

@@ -1,6 +1,6 @@
from fastapi import APIRouter from fastapi import APIRouter
from ..api_outputs import Machine, Status from ..schemas import Machine, Status
router = APIRouter() router = APIRouter()

View File

@@ -1,15 +1,40 @@
from typing import List from typing import List, Optional
from fastapi import APIRouter, Depends from fastapi import APIRouter, Depends
from sqlalchemy.orm import Session from sqlalchemy.orm import Session
from .. import sql_crud, sql_db, sql_models from .. import sql_crud, sql_db, sql_models
from ..api_outputs import Producer, ProducerCreate from ..schemas import (
Consumer,
ConsumerCreate,
Entity,
EntityCreate,
Producer,
ProducerCreate,
Repository,
RepositoryCreate,
)
from ..tags import Tags
router = APIRouter() router = APIRouter()
@router.get("/get_producers", response_model=List[Producer]) #########################
# #
# Producer #
# #
#########################
@router.post("/api/v1/create_producer", response_model=Producer, tags=[Tags.producers])
def create_producer(
producer: ProducerCreate, db: Session = Depends(sql_db.get_db)
) -> Producer:
# todo checken ob schon da ...
return sql_crud.create_producer(db=db, producer=producer)
@router.get(
"/api/v1/get_producers", response_model=List[Producer], tags=[Tags.producers]
)
def get_producers( def get_producers(
skip: int = 0, limit: int = 100, db: Session = Depends(sql_db.get_db) skip: int = 0, limit: int = 100, db: Session = Depends(sql_db.get_db)
) -> List[sql_models.Producer]: ) -> List[sql_models.Producer]:
@@ -17,9 +42,122 @@ def get_producers(
return producers return producers
@router.post("/create_producers", response_model=Producer) @router.get(
def create_producers( "/api/v1/get_producer", response_model=List[Producer], tags=[Tags.producers]
producer: ProducerCreate, db: Session = Depends(sql_db.get_db) )
) -> Producer: def get_producer(
entity_did: str = "did:sov:test:1234",
skip: int = 0,
limit: int = 100,
db: Session = Depends(sql_db.get_db),
) -> List[sql_models.Producer]:
producer = sql_crud.get_producers_by_entity_did(db, entity_did=entity_did)
return producer
#########################
# #
# Consumer #
# #
#########################
@router.post("/api/v1/create_consumer", response_model=Consumer, tags=[Tags.consumers])
def create_consumer(
consumer: ConsumerCreate, db: Session = Depends(sql_db.get_db)
) -> Consumer:
# todo checken ob schon da ... # todo checken ob schon da ...
return sql_crud.create_producer(db=db, producer=producer) return sql_crud.create_consumer(db=db, consumer=consumer)
@router.get(
"/api/v1/get_consumers", response_model=List[Consumer], tags=[Tags.consumers]
)
def get_consumers(
skip: int = 0, limit: int = 100, db: Session = Depends(sql_db.get_db)
) -> List[sql_models.Consumer]:
consumers = sql_crud.get_consumers(db, skip=skip, limit=limit)
return consumers
@router.get(
"/api/v1/get_consumer", response_model=List[Consumer], tags=[Tags.consumers]
)
def get_consumer(
entity_did: str = "did:sov:test:1234",
skip: int = 0,
limit: int = 100,
db: Session = Depends(sql_db.get_db),
) -> List[sql_models.Consumer]:
consumer = sql_crud.get_consumers_by_entity_did(db, entity_did=entity_did)
return consumer
#########################
# #
# REPOSITORY #
# #
#########################
@router.post(
"/api/v1/create_repository", response_model=Repository, tags=[Tags.repositories]
)
def create_repository(
repository: RepositoryCreate, db: Session = Depends(sql_db.get_db)
) -> sql_models.Repository:
# todo checken ob schon da ...
return sql_crud.create_repository(db=db, repository=repository)
@router.get(
"/api/v1/get_repositories",
response_model=List[Repository],
tags=[Tags.repositories],
)
def get_repositories(
skip: int = 0, limit: int = 100, db: Session = Depends(sql_db.get_db)
) -> List[sql_models.Repository]:
repositories = sql_crud.get_repositories(db, skip=skip, limit=limit)
return repositories
@router.get(
"/api/v1/get_repository", response_model=List[Repository], tags=[Tags.repositories]
)
def get_repository(
entity_did: str = "did:sov:test:1234",
skip: int = 0,
limit: int = 100,
db: Session = Depends(sql_db.get_db),
) -> List[sql_models.Repository]:
repository = sql_crud.get_repository_by_did(db, did=entity_did)
return repository
#########################
# #
# Entity #
# #
#########################
@router.post("/api/v1/create_entity", response_model=Entity, tags=[Tags.entities])
def create_entity(
entity: EntityCreate, db: Session = Depends(sql_db.get_db)
) -> EntityCreate:
# todo checken ob schon da ...
return sql_crud.create_entity(db, entity)
@router.get("/api/v1/get_entities", response_model=List[Entity], tags=[Tags.entities])
def get_entities(
skip: int = 0, limit: int = 100, db: Session = Depends(sql_db.get_db)
) -> List[sql_models.Entity]:
entities = sql_crud.get_entities(db, skip=skip, limit=limit)
return entities
@router.get("/api/v1/get_entity", response_model=Optional[Entity], tags=[Tags.entities])
def get_entity(
entity_did: str = "did:sov:test:1234",
skip: int = 0,
limit: int = 100,
db: Session = Depends(sql_db.get_db),
) -> Optional[sql_models.Entity]:
entity = sql_crud.get_entity_by_did(db, did=entity_did)
return entity

View File

@@ -0,0 +1,107 @@
from datetime import datetime
from enum import Enum
from typing import List, Optional
from pydantic import BaseModel
class Status(Enum):
ONLINE = "online"
OFFLINE = "offline"
UNKNOWN = "unknown"
class Machine(BaseModel):
name: str
status: Status
#########################
# #
# Producer #
# #
#########################
class ProducerBase(BaseModel):
uuid: str = "8e285c0c-4e40-430a-a477-26b3b81e30df"
service_name: str = "Carlo's Printing"
service_type: str = "3D Printing"
endpoint_url: str = "http://127.0.0.1:8000"
status: str = "unknown"
other: dict = {"test": "test"}
class ProducerCreate(ProducerBase):
entity_did: str = "did:sov:test:1234"
class Producer(ProducerCreate):
class Config:
orm_mode = True
#########################
# #
# Consumer #
# #
#########################
class ConsumerBase(BaseModel):
entity_did: str = "did:sov:test:1234"
producer_uuid: str = "8e285c0c-4e40-430a-a477-26b3b81e30df"
other: dict = {"test": "test"}
class ConsumerCreate(ConsumerBase):
pass
class Consumer(ConsumerCreate):
id: int
class Config:
orm_mode = True
#########################
# #
# REPOSITORY #
# #
#########################
class RepositoryBase(ProducerBase):
pass
class RepositoryCreate(RepositoryBase):
entity_did: str = "did:sov:test:1234"
class Repository(RepositoryCreate):
time_created: datetime
class Config:
orm_mode = True
#########################
# #
# Entity #
# #
#########################
class EntityBase(BaseModel):
did: str = "did:sov:test:1234"
name: str = "C1"
ip: str = "127.0.0.1"
attached: bool = False
other: dict = {"test": "test"}
class EntityCreate(EntityBase):
pass
class Entity(EntityCreate):
producers: List[Producer] = []
consumers: List[Consumer] = []
repository: Optional[Repository] = None
class Config:
orm_mode = True

View File

@@ -1,8 +1,24 @@
from typing import List from typing import List, Optional
from sqlalchemy.orm import Session from sqlalchemy.orm import Session
from . import api_outputs, sql_models from . import schemas, sql_models
#########################
# #
# Producer #
# #
#########################
def create_producer(
db: Session, producer: schemas.ProducerCreate
) -> sql_models.Producer:
db_producer = sql_models.Producer(**producer.dict())
db.add(db_producer)
db.commit()
db.refresh(db_producer)
return db_producer
def get_producers( def get_producers(
@@ -11,15 +27,66 @@ def get_producers(
return db.query(sql_models.Producer).offset(skip).limit(limit).all() return db.query(sql_models.Producer).offset(skip).limit(limit).all()
def create_producer( def get_producers_by_entity_did(
db: Session, producer: api_outputs.ProducerCreate db: Session, entity_did: str, skip: int = 0, limit: int = 100
) -> sql_models.Producer: ) -> List[sql_models.Producer]:
jsonblob_init = {"test_repo": "jsonblob_create"} return (
db_producer = sql_models.Producer(jsonblob=jsonblob_init) db.query(sql_models.Producer)
db.add(db_producer) .filter(sql_models.Producer.entity_did == entity_did)
.offset(skip)
.limit(limit)
.all()
)
#########################
# #
# Consumer #
# #
#########################
def create_consumer(
db: Session, consumer: schemas.ConsumerCreate
) -> sql_models.Consumer:
db_consumer = sql_models.Consumer(**consumer.dict())
db.add(db_consumer)
db.commit() db.commit()
db.refresh(db_producer) db.refresh(db_consumer)
return db_producer return db_consumer
def get_consumers(
db: Session, skip: int = 0, limit: int = 100
) -> List[sql_models.Consumer]:
return db.query(sql_models.Consumer).offset(skip).limit(limit).all()
def get_consumers_by_entity_did(
db: Session, entity_did: str, skip: int = 0, limit: int = 100
) -> List[sql_models.Consumer]:
return (
db.query(sql_models.Consumer)
.filter(sql_models.Consumer.entity_did == entity_did)
.offset(skip)
.limit(limit)
.all()
)
#########################
# #
# REPOSITORY #
# #
#########################
def create_repository(
db: Session, repository: schemas.RepositoryCreate
) -> sql_models.Repository:
db_repository = sql_models.Repository(**repository.dict())
db.add(db_repository)
db.commit()
db.refresh(db_repository)
return db_repository
def get_repositories( def get_repositories(
@@ -28,11 +95,44 @@ def get_repositories(
return db.query(sql_models.Repository).offset(skip).limit(limit).all() return db.query(sql_models.Repository).offset(skip).limit(limit).all()
def create_repository( def get_repository_by_uuid(db: Session, uuid: str) -> Optional[sql_models.Repository]:
db: Session, repository: api_outputs.RepositoryCreate, producers_id: int return (
) -> sql_models.Repository: db.query(sql_models.Repository)
db_repository = sql_models.Repository(**repository.dict(), prod_id=producers_id) .filter(sql_models.Repository.uuid == uuid)
db.add(db_repository) .first()
)
def get_repository_by_did(
db: Session, did: str, skip: int = 0, limit: int = 100
) -> List[sql_models.Repository]:
return (
db.query(sql_models.Repository)
.filter(sql_models.Repository.entity_did == did)
.offset(skip)
.limit(limit)
.all()
)
#########################
# #
# Entity #
# #
#########################
def create_entity(db: Session, entity: schemas.EntityCreate) -> sql_models.Entity:
db_entity = sql_models.Entity(**entity.dict())
db.add(db_entity)
db.commit() db.commit()
db.refresh(db_repository) db.refresh(db_entity)
return db_repository return db_entity
def get_entities(
db: Session, skip: int = 0, limit: int = 100
) -> List[sql_models.Entity]:
return db.query(sql_models.Entity).offset(skip).limit(limit).all()
def get_entity_by_did(db: Session, did: str) -> Optional[sql_models.Entity]:
return db.query(sql_models.Entity).filter(sql_models.Entity.did == did).first()

View File

@@ -1,23 +1,108 @@
from sqlalchemy import JSON, Column, ForeignKey, Integer from sqlalchemy import (
JSON,
Boolean,
Column,
DateTime,
ForeignKey,
Integer,
String,
Text,
UniqueConstraint,
)
from sqlalchemy.orm import relationship from sqlalchemy.orm import relationship
from sqlalchemy.sql import func
from .sql_db import Base from .sql_db import Base
# Relationsship example
# https://dev.to/freddiemazzilli/flask-sqlalchemy-relationships-exploring-relationship-associations-igo
class Producer(Base):
class Entity(Base):
__tablename__ = "entities"
## Queryable body ##
did = Column(String, primary_key=True, index=True)
name = Column(String, index=True)
ip = Column(String, index=True)
attached = Column(Boolean, index=True)
## Non queryable body ##
# In here we deposit: Network, Roles, Visible, etc.
other = Column(JSON)
## Relations ##
producers = relationship("Producer", back_populates="entity")
consumers = relationship("Consumer", back_populates="entity")
repository = relationship("Repository", uselist=False, back_populates="entity")
class ProducerAbstract(Base):
__abstract__ = True
# Queryable body
uuid = Column(Text(length=36), primary_key=True, index=True)
service_name = Column(String, index=True)
service_type = Column(String, index=True)
endpoint_url = Column(String, index=True)
status = Column(String, index=True)
## Non queryable body ##
# In here we deposit: Action
other = Column(JSON)
class Producer(ProducerAbstract):
__tablename__ = "producers" __tablename__ = "producers"
# Usage is the consumers column
## Relations ##
# One entity can have many producers
entity = relationship("Entity", back_populates="producers")
entity_did = Column(String, ForeignKey("entities.did"))
# One producer has many consumers
consumers = relationship("Consumer", back_populates="producer")
class Consumer(Base):
__tablename__ = "consumers"
## Queryable body ##
id = Column(Integer, primary_key=True, index=True) id = Column(Integer, primary_key=True, index=True)
jsonblob = Column(JSON)
repos = relationship("Repository", back_populates="producer") ## Non queryable body ##
other = Column(JSON)
## Relations ##
# one entity can have many consumers
entity = relationship("Entity", back_populates="consumers")
entity_did = Column(String, ForeignKey("entities.did"))
# one consumer has one producer
producer = relationship("Producer", back_populates="consumers")
producer_uuid = Column(String, ForeignKey("producers.uuid"))
__table_args__ = (UniqueConstraint("producer_uuid", "entity_did"),)
class Repository(Base): class Repository(ProducerAbstract):
__tablename__ = "repositories" __tablename__ = "repositories"
id = Column(Integer, primary_key=True, index=True) time_created = Column(DateTime(timezone=True), server_default=func.now())
jsonblob = Column(JSON)
prod_id = Column(Integer, ForeignKey("producers.id"))
producer = relationship("Producer", back_populates="repos") # one repository has one entity
entity = relationship("Entity", back_populates="repository")
entity_did = Column(Integer, ForeignKey("entities.did"))
# TODO: Ask how this works exactly
class Resolution(Base):
__tablename__ = "resolutions"
id = Column(Integer, primary_key=True)
requester_name = Column(String, index=True)
requester_did = Column(String, index=True)
resolved_did = Column(String, index=True)
timestamp = Column(DateTime, index=True)

View File

@@ -0,0 +1,32 @@
from enum import Enum
from typing import Any, Dict, List
class Tags(Enum):
producers = "producers"
consumers = "consumers"
entities = "entities"
repositories = "repositories"
def __str__(self) -> str:
return self.value
tags_metadata: List[Dict[str, Any]] = [
{
"name": str(Tags.producers),
"description": "Operations on a producer.",
},
{
"name": str(Tags.consumers),
"description": "Operations on a consumer.",
},
{
"name": str(Tags.entities),
"description": "Operations on an entity.",
},
{
"name": str(Tags.repositories),
"description": "Operations on a repository.",
},
]