georgs #23

Closed
Ghost wants to merge 50 commits from georgs into main
8 changed files with 519 additions and 36 deletions
Showing only changes of commit 2c60a35743 - Show all commits

View File

@@ -7,13 +7,15 @@ from fastapi import FastAPI
from fastapi.middleware.cors import CORSMiddleware
from fastapi.routing import APIRoute
from fastapi.staticfiles import StaticFiles
from sqlalchemy.exc import SQLAlchemyError
from ..errors import ClanError
from . import sql_models
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 .sql_db import engine
from .tags import tags_metadata
origins = [
"http://localhost:3000",
@@ -52,9 +54,13 @@ def setup_app() -> FastAPI:
# Needs to be last in register. Because of wildcard route
app.include_router(root.router)
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")
# Add tag descriptions to the OpenAPI schema
app.openapi_tags = tags_metadata
for route in app.routes:
if isinstance(route, APIRoute):
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.encoders import jsonable_encoder
from fastapi.responses import JSONResponse
from sqlalchemy.exc import SQLAlchemyError
from ..errors import ClanError
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:
log.error("ClanError: %s", exc)
detail = [

View File

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

View File

@@ -1,15 +1,40 @@
from typing import List
from typing import List, Optional
from fastapi import APIRouter, Depends
from sqlalchemy.orm import Session
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.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(
skip: int = 0, limit: int = 100, db: Session = Depends(sql_db.get_db)
) -> List[sql_models.Producer]:
@@ -17,9 +42,122 @@ def get_producers(
return producers
@router.post("/create_producers", response_model=Producer)
def create_producers(
producer: ProducerCreate, db: Session = Depends(sql_db.get_db)
) -> Producer:
@router.get(
"/api/v1/get_producer", response_model=List[Producer], tags=[Tags.producers]
)
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 ...
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 . 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(
@@ -11,15 +27,66 @@ def get_producers(
return db.query(sql_models.Producer).offset(skip).limit(limit).all()
def create_producer(
db: Session, producer: api_outputs.ProducerCreate
) -> sql_models.Producer:
jsonblob_init = {"test_repo": "jsonblob_create"}
db_producer = sql_models.Producer(jsonblob=jsonblob_init)
db.add(db_producer)
def get_producers_by_entity_did(
db: Session, entity_did: str, skip: int = 0, limit: int = 100
) -> List[sql_models.Producer]:
return (
db.query(sql_models.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.refresh(db_producer)
return db_producer
db.refresh(db_consumer)
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(
@@ -28,11 +95,44 @@ def get_repositories(
return db.query(sql_models.Repository).offset(skip).limit(limit).all()
def create_repository(
db: Session, repository: api_outputs.RepositoryCreate, producers_id: int
) -> sql_models.Repository:
db_repository = sql_models.Repository(**repository.dict(), prod_id=producers_id)
db.add(db_repository)
def get_repository_by_uuid(db: Session, uuid: str) -> Optional[sql_models.Repository]:
return (
db.query(sql_models.Repository)
.filter(sql_models.Repository.uuid == uuid)
.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.refresh(db_repository)
return db_repository
db.refresh(db_entity)
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.sql import func
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"
# 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)
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"
id = Column(Integer, primary_key=True, index=True)
jsonblob = Column(JSON)
prod_id = Column(Integer, ForeignKey("producers.id"))
time_created = Column(DateTime(timezone=True), server_default=func.now())
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.",
},
]