initial wip
This commit is contained in:
13
.idea/runConfigurations/latest.xml
generated
Normal file
13
.idea/runConfigurations/latest.xml
generated
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
<component name="ProjectRunConfigurationManager">
|
||||||
|
<configuration default="false" name="latest" type="docker-deploy" factoryName="dockerfile" server-name="Docker">
|
||||||
|
<deployment type="dockerfile">
|
||||||
|
<settings>
|
||||||
|
<option name="imageTag" value="docker.ctmapp.kiongroup.net/vpsx-db:latest" />
|
||||||
|
<option name="buildOnly" value="true" />
|
||||||
|
<option name="containerName" value="" />
|
||||||
|
<option name="sourceFilePath" value="Dockerfile" />
|
||||||
|
</settings>
|
||||||
|
</deployment>
|
||||||
|
<method v="2" />
|
||||||
|
</configuration>
|
||||||
|
</component>
|
||||||
19
Dockerfile
Normal file
19
Dockerfile
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
FROM python:3
|
||||||
|
|
||||||
|
LABEL authors="Bernhard Radermacher"
|
||||||
|
|
||||||
|
RUN pip install mariadb pymysql sqlmodel uvicorn fastapi
|
||||||
|
|
||||||
|
ENV DB_USER="must be set" \
|
||||||
|
DB_PASSWORD="must be set" \
|
||||||
|
DB_HOST="mariadb" \
|
||||||
|
DB_PORT=3306 \
|
||||||
|
DB_DATABASE="vpsx"
|
||||||
|
|
||||||
|
COPY src /src
|
||||||
|
|
||||||
|
COPY main.py /
|
||||||
|
|
||||||
|
|
||||||
|
ENTRYPOINT ["/usr/local/bin/uvicorn", "main:app", "--host", "0.0.0.0"]
|
||||||
|
|
||||||
33
main.py
Normal file
33
main.py
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
import datetime
|
||||||
|
from contextlib import asynccontextmanager
|
||||||
|
|
||||||
|
from fastapi import FastAPI
|
||||||
|
from fastapi.middleware.cors import CORSMiddleware
|
||||||
|
|
||||||
|
from src.populate import populate
|
||||||
|
import src.routers as routers
|
||||||
|
|
||||||
|
@asynccontextmanager
|
||||||
|
async def lifespan(app: FastAPI):
|
||||||
|
populate()
|
||||||
|
yield
|
||||||
|
|
||||||
|
updated = datetime.datetime.now(tz=datetime.timezone.utc)
|
||||||
|
|
||||||
|
app = FastAPI(lifespan=lifespan)
|
||||||
|
|
||||||
|
app.add_middleware(
|
||||||
|
CORSMiddleware,
|
||||||
|
allow_origins=["*"],
|
||||||
|
allow_credentials=True,
|
||||||
|
allow_methods=["*"],
|
||||||
|
allow_headers=["*"],
|
||||||
|
)
|
||||||
|
|
||||||
|
app.include_router(routers.status)
|
||||||
|
|
||||||
|
#
|
||||||
|
# @app.get("/info/updated", tags=["info"])
|
||||||
|
# async def get_timestamp_of_last_update():
|
||||||
|
# """Timestamp of last update (YYYY-MM-DD HH:MM:SS UTC)."""
|
||||||
|
# return updated.strftime("%Y-%m-%d %H:%M:%S")
|
||||||
12
pyproject.toml
Normal file
12
pyproject.toml
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
[project]
|
||||||
|
name = "vpsx-db"
|
||||||
|
version = "0.1.0"
|
||||||
|
description = "Add your description here"
|
||||||
|
requires-python = ">=3.13"
|
||||||
|
dependencies = [
|
||||||
|
"fastapi>=0.116.1",
|
||||||
|
"mariadb>=1.1.13",
|
||||||
|
"pymysql>=1.1.2",
|
||||||
|
"sqlmodel>=0.0.24",
|
||||||
|
"uvicorn>=0.35.0",
|
||||||
|
]
|
||||||
0
src/__init__.py
Normal file
0
src/__init__.py
Normal file
4
src/model/__init__.py
Normal file
4
src/model/__init__.py
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
from .contact import Contact
|
||||||
|
from .status import Status
|
||||||
|
|
||||||
|
from .util import get_session, count_rows
|
||||||
9
src/model/contact.py
Normal file
9
src/model/contact.py
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
from sqlmodel import Field, SQLModel, Text
|
||||||
|
|
||||||
|
|
||||||
|
class Contact(SQLModel, table=True):
|
||||||
|
id: int = Field(primary_key=True)
|
||||||
|
address: str = Field(max_length=256, unique=True)
|
||||||
|
description: str = Field(max_length=512)
|
||||||
|
notes: Text
|
||||||
|
status_id: str = Field(foreign_key="status.id")
|
||||||
7
src/model/status.py
Normal file
7
src/model/status.py
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
from sqlmodel import SQLModel, Field
|
||||||
|
|
||||||
|
|
||||||
|
class Status(SQLModel, table=True):
|
||||||
|
id: str = Field(max_length=3, primary_key=True)
|
||||||
|
name: str = Field(max_length=30, unique=True)
|
||||||
|
|
||||||
29
src/model/util.py
Normal file
29
src/model/util.py
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
from sqlalchemy import func, select, URL
|
||||||
|
|
||||||
|
import os
|
||||||
|
|
||||||
|
from sqlmodel import create_engine, SQLModel, Session
|
||||||
|
|
||||||
|
|
||||||
|
def get_engine():
|
||||||
|
engine_url = URL.create(
|
||||||
|
drivername="mariadb+pymysql",
|
||||||
|
username=os.getenv("DB_USER"),
|
||||||
|
password=os.getenv("DB_PASSWORD"),
|
||||||
|
host=os.getenv("DB_HOST"),
|
||||||
|
port=int(os.getenv("DB_PORT")),
|
||||||
|
database=os.getenv("DB_DATABASE"),
|
||||||
|
query={'charset': 'utf8mb4'},
|
||||||
|
)
|
||||||
|
engine = create_engine(engine_url)
|
||||||
|
SQLModel.metadata.create_all(engine)
|
||||||
|
return engine
|
||||||
|
|
||||||
|
engine = get_engine()
|
||||||
|
|
||||||
|
def get_session():
|
||||||
|
with Session(engine) as session:
|
||||||
|
yield session
|
||||||
|
|
||||||
|
def count_rows(session, cls) -> int:
|
||||||
|
return session.execute(select(func.count()).select_from(cls)).scalar()
|
||||||
37
src/populate.py
Normal file
37
src/populate.py
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
from sqlmodel import Session
|
||||||
|
|
||||||
|
from .model.util import engine
|
||||||
|
from src.model import count_rows, Status, Contact
|
||||||
|
|
||||||
|
|
||||||
|
def populate_contact(session):
|
||||||
|
if count_rows(session, Contact) == 0:
|
||||||
|
for kwargs in (
|
||||||
|
dict(address="Active"),
|
||||||
|
dict(id="I", name="Inactive"),
|
||||||
|
dict(id="N", name="New"),
|
||||||
|
dict(id="P", name="Prepared"),
|
||||||
|
dict(id="X", name="eXcluded"),
|
||||||
|
):
|
||||||
|
session.add(Status(**kwargs))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
def populate_status(session):
|
||||||
|
if count_rows(session, Status) == 0:
|
||||||
|
for kwargs in (
|
||||||
|
dict(id="A", name="Active"),
|
||||||
|
dict(id="I", name="Inactive"),
|
||||||
|
dict(id="N", name="New"),
|
||||||
|
dict(id="P", name="Prepared"),
|
||||||
|
dict(id="X", name="eXcluded"),
|
||||||
|
):
|
||||||
|
session.add(Status(**kwargs))
|
||||||
|
|
||||||
|
|
||||||
|
def populate():
|
||||||
|
with Session(engine) as session:
|
||||||
|
|
||||||
|
populate_status(session)
|
||||||
|
|
||||||
|
session.commit()
|
||||||
1
src/routers/__init__.py
Normal file
1
src/routers/__init__.py
Normal file
@@ -0,0 +1 @@
|
|||||||
|
from .status import router as status
|
||||||
26
src/routers/status.py
Normal file
26
src/routers/status.py
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
|
||||||
|
|
||||||
|
from fastapi import APIRouter, Depends, HTTPException, Path, Query
|
||||||
|
from sqlmodel import select
|
||||||
|
|
||||||
|
from ..model import Status, get_session
|
||||||
|
|
||||||
|
router = APIRouter(
|
||||||
|
prefix="/status",
|
||||||
|
tags=["status"],
|
||||||
|
)
|
||||||
|
|
||||||
|
@router.get("/", response_model=list[Status])
|
||||||
|
async def get_statuses(session=Depends(get_session)):
|
||||||
|
"""List of Statuses"""
|
||||||
|
return session.exec(select(Status)).all()
|
||||||
|
|
||||||
|
@router.get("/{status}", response_model=Status, responses={404: {"description": "Not found"}})
|
||||||
|
async def get_status(
|
||||||
|
status: str,
|
||||||
|
session=Depends(get_session)):
|
||||||
|
"""Get a Status"""
|
||||||
|
result = session.get(Status, status)
|
||||||
|
if not result:
|
||||||
|
raise HTTPException(status_code=404, detail=f"Status {status!r} not found")
|
||||||
|
return result
|
||||||
26
test_main.http
Normal file
26
test_main.http
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
# Test your FastAPI endpoints
|
||||||
|
|
||||||
|
GET http://localhost:8888/info/updated
|
||||||
|
Accept: application/json
|
||||||
|
|
||||||
|
###
|
||||||
|
|
||||||
|
#GET http://localhost:8888/calendar
|
||||||
|
#Accept: application/json
|
||||||
|
#
|
||||||
|
####
|
||||||
|
#
|
||||||
|
#GET http://localhost:8888/calendar/1/dates/
|
||||||
|
#Accept: application/json
|
||||||
|
#
|
||||||
|
####
|
||||||
|
#
|
||||||
|
#GET http://localhost:8888/calendar/1/dates?offset=1
|
||||||
|
#Accept: application/json
|
||||||
|
#
|
||||||
|
####
|
||||||
|
#
|
||||||
|
#GET http://localhost:8888/calendar/1/dates?offset=-1
|
||||||
|
#Accept: application/json
|
||||||
|
#
|
||||||
|
####
|
||||||
Reference in New Issue
Block a user