Skip to content
Snippets Groups Projects
Commit 81b3780b authored by hanfi's avatar hanfi
Browse files

Merge branch 'staging' into 'main'

backend api v2

See merge request !8
parents acbcc31c 4f86471e
No related branches found
No related tags found
1 merge request!8backend api v2
# Chaos Parcel Serivce: Backend
## Deployment
This assumes you run the code as user *www-data*
Do **not** checkout this code as the same user.
checkout the code (main branch for production)
cd into the directory
```
mkdir instance
chown www-data:www-data instance
```
create a file .env with content
```
# the database location relative to the repository root
database_url = "sqlite:///instance/paketshop.db"
# the url for the customer frontend (the people sending parcels)
customer_url = "https://bgp.events.ccc.de"
# the url this app will be run under
backend_url = "https://backend.bgp.events.ccc.de"
# the url for the people handling the parcels
worker_url = "https://intern.bgp.events.ccc.de"
# a shared secret for the workers
shared_secret = "{{ bgp_secrets.shared_secret }}"
# a deployment wide secret key.
# can be created with:
# python3 -c 'import os; print(os.urandom(16).hex())'
signing_key = "{{ bgp_secrets.signing_key }}"
# how long workers are logged in.
token_lifetime = "180"
```
create a venv and install requirements:
```
python -m venv venv
. venv/bin/activate
pip install -r requirements.txt
```
We suggest to use gunicorn to server the python app, so install it
```
pip install gunicorn
```
create a runtime directory to allow the webserver to forward calls to
```
mdkir /run/bgp
chown www-data:www-data /run/bgp
```
create a systemd service file to serve the app:
```
[Unit]
Description=Gunicorn instance to serve bgp backend fastapi app
After=network.target
[Service]
User=www-data
Group=www-data
WorkingDirectory=/srv/backend
ExecStart=/srv/backend/venv/bin/gunicorn -k uvicorn.workers.UvicornWorker --bind unix:/run/bgp/socket backend.main:app
[Install]
WantedBy=multi-user.target
```
...@@ -8,9 +8,15 @@ class Settings(BaseSettings): ...@@ -8,9 +8,15 @@ class Settings(BaseSettings):
backend_url: str = "http://localhost:8000" backend_url: str = "http://localhost:8000"
customer_url: str = "http://localhost:3000" customer_url: str = "http://localhost:3000"
worker_url: str = "http://localhost:3002" worker_url: str = "http://localhost:3002"
# well known password for workers
shared_secret: str = "worker_secret" shared_secret: str = "worker_secret"
# app data signing key (global for all users. keep this secret)
signing_key: str = "2d18526256a001bc0553c9957897d75d" signing_key: str = "2d18526256a001bc0553c9957897d75d"
token_lifetime: int = 60 # auth token lifetime # lifetime for auth tokens
token_lifetime: int = 60
# length of delivery tags (address-tag, keep this short but unique)
tag_length: int = 8
class Config: class Config:
env_file = ".env" env_file = ".env"
......
from typing import List
from uuid import UUID from uuid import UUID
from fastapi import Depends, FastAPI, HTTPException, Request, UploadFile, status from fastapi import Depends, FastAPI, HTTPException, Request, UploadFile, status
...@@ -47,6 +48,13 @@ def get_db(): ...@@ -47,6 +48,13 @@ def get_db():
db.close() db.close()
# oauth2/token handling
@app.get("/token")
def check_token_validity(token: str = Depends(oauth2_scheme)):
check_token(token, None)
# TODO: move this to utils.py?
def check_token(token: str, item_uuid: str): def check_token(token: str, item_uuid: str):
try: try:
auth_data = oauth2_tokener.loads(token, max_age=settings.token_lifetime * 60) auth_data = oauth2_tokener.loads(token, max_age=settings.token_lifetime * 60)
...@@ -63,141 +71,223 @@ def check_token(token: str, item_uuid: str): ...@@ -63,141 +71,223 @@ def check_token(token: str, item_uuid: str):
) )
# Routes @app.post("/token")
@app.post("/item/prepare", response_model=schemas.Item) def verify_supporter(form_data: OAuth2PasswordRequestForm = Depends()):
if form_data.password != settings.shared_secret:
raise HTTPException(status_code=400, detail="Incorrect username or password")
return {
"access_token": oauth2_tokener.dumps("all"),
"token_type": "bearer",
}
# TODO: merge this with the supporter login? we want a single endpoint for all of this.
@app.post("/login")
def verify_customer(
login_data: schemas.LoginData, db: Session = Depends(get_db)
): # item_uuid: str, signature: str):
print(login_data)
delivery = utils.get_delivery_by_uuid(db, UUID(login_data.delivery_uuid))
if not delivery:
raise HTTPException(status_code=404, detail="Item not found")
if not utils.verify_signature(delivery, delivery.uuid, login_data.signature):
raise HTTPException(status_code=400, detail="Invalid signature")
return {
"access_token": oauth2_tokener.dumps(str(delivery.uuid)),
"token_type": "bearer",
}
# main app
@app.post("/delivery", response_model=schemas.Delivery)
@limiter.limit("2/minute") @limiter.limit("2/minute")
def add_item( def prepare_delivery(
request: Request, request: Request, delivery: schemas.DeliveryBase, db: Session = Depends(get_db)
item: schemas.ItemCreatePrepareShipping, ):
return utils.prepare_delivery(db, delivery.verification)
@app.get("/delivery/{delivery_uuid}", response_model=schemas.Delivery)
def get_delivery_by_uuid(
delivery_uuid: str,
token: str = Depends(oauth2_scheme),
db: Session = Depends(get_db), db: Session = Depends(get_db),
): ):
return utils.prepare_item_shipping(db, item) check_token(token, delivery_uuid)
delivery = utils.get_delivery_by_uuid(db, UUID(delivery_uuid))
if not delivery:
raise HTTPException(status_code=404, detail="Item not found")
return delivery
@app.post("/item/register", response_model=schemas.Item) @app.get("/tag/{delivery_tag}", response_model=schemas.Delivery)
def add_item_with_image( def get_delivery_by_tag(
image: UploadFile, delivery_tag: str,
token: str = Depends(oauth2_scheme), token: str = Depends(oauth2_scheme),
db: Session = Depends(get_db), db: Session = Depends(get_db),
): ):
check_token(token, None) delivery = utils.get_delivery_by_tag(db, delivery_tag)
print(image.file) check_token(token, delivery.uuid)
return utils.add_item_with_image(db, image) return delivery
@app.post("/item/update/{item_uuid}", response_model=schemas.Item) @app.put("/delivery/{delivery_uuid}", response_model=schemas.Delivery)
def update_item( def update_delivery(
item_uuid: str, delivery_uuid: str,
data: schemas.ItemUpdate, data: schemas.DeliveryUpdate,
token: str = Depends(oauth2_scheme), token: str = Depends(oauth2_scheme),
db: Session = Depends(get_db), db: Session = Depends(get_db),
): ):
check_token(token, item_uuid) check_token(token, delivery_uuid)
item = utils.get_item_by_uuid(db, UUID(item_uuid)) delivery = utils.update_delivery_data(db, UUID(delivery_uuid), data)
if not item: return delivery
raise HTTPException(status_code=404, detail="Item not found")
return utils.update_item(db, item, data)
@app.post("/item", response_model=schemas.Item)
def add_item(
item: schemas.ItemAdd,
token: str = Depends(oauth2_scheme),
db: Session = Depends(get_db),
):
check_token(token, None)
delivery = utils.get_delivery_by_uuid(db, item.delivery_uuid)
storage = utils.get_storage_by_name(db, item.storage_name)
if not delivery:
raise HTTPException(status_code=404, detail="Delivery not found")
if not storage:
raise HTTPException(status_code=404, detail="Storage not found")
return utils.add_item_for_delivery_at_storage(
db, item.delivery_uuid, item.storage_name
)
@app.get("/item/{item_uuid}", response_model=schemas.Item) @app.get("/item/{item_uuid}", response_model=schemas.Item)
def get_item( def get_item(
item_uuid: str, token: str = Depends(oauth2_scheme), db: Session = Depends(get_db) item_uuid: str, token: str = Depends(oauth2_scheme), db: Session = Depends(get_db)
): ):
item = utils.get_item_by_uuid(db, UUID(item_uuid)) return utils.get_item_by_uuid(db, UUID(item_uuid))
if not item:
raise HTTPException(status_code=404, detail="Item not found")
return item
@app.get("/items", response_model=list[schemas.Item])
def get_items(token: str = Depends(oauth2_scheme), db: Session = Depends(get_db)):
print(token)
check_token(token, None)
return utils.get_stored_items(db)
@app.get("/tag/{tag}", response_model=schemas.Item) @app.delete("/item/{item_uuid}", response_model=schemas.Item)
def get_item_by_tag( def deploy_item(
tag: str, token: str = Depends(oauth2_scheme), db: Session = Depends(get_db) item_uuid: str, token: str = Depends(oauth2_scheme), db: Session = Depends(get_db)
): ):
check_token(token, None) check_token(token, None)
item = utils.get_item_by_tag(db, tag) return utils.deploy_item(db, UUID(item_uuid))
if not item:
raise HTTPException(status_code=404, detail="Item not found")
return item
@app.get("/storage/{storage_name}", response_model=list[schemas.Item]) @app.get("/storage/{storage_name}", response_model=schemas.Storage)
def get_storage( def get_storage(
storage_name: str, storage_name: str,
token: str = Depends(oauth2_scheme), token: str = Depends(oauth2_scheme),
db: Session = Depends(get_db), db: Session = Depends(get_db),
): ):
check_token(token, None) check_token(token, None)
return utils.get_items_for_storage(db, storage_name) return utils.get_storage_by_name(db, storage_name)
@app.get("/storages", response_model=list[schemas.Storage])
def list_storages(token: str = Depends(oauth2_scheme), db: Session = Depends(get_db)):
check_token(token, None)
return utils.get_storages(db)
@app.post("/checkin", response_model=schemas.Item) @app.get("/storages", response_model=List[schemas.Storage])
def checkin_item_by_uuid( def get_storages(
checkin: schemas.ItemCheckin,
token: str = Depends(oauth2_scheme), token: str = Depends(oauth2_scheme),
db: Session = Depends(get_db), db: Session = Depends(get_db),
): ):
check_token(token, None) check_token(token, None)
item = utils.get_item_by_uuid(db, UUID(checkin.item_uuid)) return utils.get_storages(db)
if item is None:
raise HTTPException(status_code=404, detail="Item not found")
storage = utils.get_storage(db, checkin.storage_name)
if storage is None:
raise HTTPException(status_code=404, detail="Storage not found")
return utils.receive_item(db, item, storage)
@app.get("/checkout/{item_uuid}", response_model=schemas.Item) @app.post("/item/register", response_model=schemas.Delivery)
def checkout_item( def add_item_with_image(
item_uuid: str, image: UploadFile,
token: str = Depends(oauth2_scheme), token: str = Depends(oauth2_scheme),
db: Session = Depends(get_db), db: Session = Depends(get_db),
): ):
check_token(token, None) check_token(token, None)
item = utils.get_item_by_uuid(db, UUID(item_uuid)) print(image.file)
if item is None: return False # utils.add_item_with_image(db, image)
raise HTTPException(status_code=404, detail="Item not found")
return utils.deliver_item(db, item)
# @app.post("/item/update/{item_uuid}", response_model=schemas.Delivery)
# def update_item(
@app.post("/token") # item_uuid: str,
def verify_supporter(form_data: OAuth2PasswordRequestForm = Depends()): # data: schemas.ItemUpdate,
if form_data.password != settings.shared_secret: # token: str = Depends(oauth2_scheme),
raise HTTPException(status_code=400, detail="Incorrect username or password") # db: Session = Depends(get_db),
return { # ):
"access_token": oauth2_tokener.dumps("all"), # check_token(token, item_uuid)
"token_type": "bearer", # item = utils.get_item_by_uuid(db, UUID(item_uuid))
} # if not item:
# raise HTTPException(status_code=404, detail="Item not found")
# return utils.update_item(db, item, data)
@app.post("/login")
def verify_customer(
login_data: schemas.LoginData, db: Session = Depends(get_db) # @app.get("/item/{item_uuid}", response_model=schemas.Delivery)
): # item_uuid: str, signature: str): # def get_item(
print(login_data) # item_uuid: str, token: str = Depends(oauth2_scheme), db: Session = Depends(get_db)
item = utils.get_item_by_uuid(db, UUID(login_data.item_uuid)) # ):
if not item: # item = utils.get_item_by_uuid(db, UUID(item_uuid))
raise HTTPException(status_code=404, detail="Item not found") # if not item:
if not utils.verify_signature(item, login_data.signature): # raise HTTPException(status_code=404, detail="Item not found")
raise HTTPException(status_code=400, detail="Invalid signature") # return item
return {
"access_token": oauth2_tokener.dumps(str(item.uuid)),
"token_type": "bearer", # @app.get("/items", response_model=list[schemas.Delivery])
} # def get_items(token: str = Depends(oauth2_scheme), db: Session = Depends(get_db)):
# print(token)
# check_token(token, None)
@app.get("/token/check") # return utils.get_stored_items(db)
def check_token_validity(token: str = Depends(oauth2_scheme)):
check_token(token, None)
# @app.get("/tag/{tag}", response_model=schemas.Delivery)
# def get_item_by_tag(
# tag: str, token: str = Depends(oauth2_scheme), db: Session = Depends(get_db)
# ):
# check_token(token, None)
# item = utils.get_item_by_tag(db, tag)
# if not item:
# raise HTTPException(status_code=404, detail="Item not found")
# return item
# @app.get("/storage/{storage_name}", response_model=list[schemas.Delivery])
# def get_storage(
# storage_name: str,
# token: str = Depends(oauth2_scheme),
# db: Session = Depends(get_db),
# ):
# check_token(token, None)
# return utils.get_items_for_storage(db, storage_name)
# @app.get("/storages", response_model=list[schemas.Storage])
# def list_storages(token: str = Depends(oauth2_scheme), db: Session = Depends(get_db)):
# check_token(token, None)
# return utils.get_storages(db)
# @app.post("/checkin", response_model=schemas.Delivery)
# def checkin_item_by_uuid(
# checkin: schemas.ItemCheckin,
# token: str = Depends(oauth2_scheme),
# db: Session = Depends(get_db),
# ):
# check_token(token, None)
# item = utils.get_item_by_uuid(db, UUID(checkin.item_uuid))
# if item is None:
# raise HTTPException(status_code=404, detail="Item not found")
# storage = utils.get_storage(db, checkin.storage_name)
# if storage is None:
# raise HTTPException(status_code=404, detail="Storage not found")
# return utils.receive_item(db, item, storage)
# @app.get("/checkout/{item_uuid}", response_model=schemas.Delivery)
# def checkout_item(
# item_uuid: str,
# token: str = Depends(oauth2_scheme),
# db: Session = Depends(get_db),
# ):
# check_token(token, None)
# item = utils.get_item_by_uuid(db, UUID(item_uuid))
# if item is None:
# raise HTTPException(status_code=404, detail="Item not found")
# return utils.deliver_item(db, item)
...@@ -3,38 +3,38 @@ from uuid import uuid4 ...@@ -3,38 +3,38 @@ from uuid import uuid4
from sqlalchemy import Column as sql_Column from sqlalchemy import Column as sql_Column
from sqlalchemy import DateTime as sql_DateTime from sqlalchemy import DateTime as sql_DateTime
from sqlalchemy import ForeignKey as sql_ForeignKey from sqlalchemy import ForeignKey as sql_ForeignKey
from sqlalchemy import Integer as sql_Integer
from sqlalchemy import String as sql_String from sqlalchemy import String as sql_String
from sqlalchemy import Uuid as sql_Uuid from sqlalchemy import Uuid as sql_Uuid
from sqlalchemy.orm import relationship as sql_relationship from sqlalchemy.orm import relationship as sql_relationship
from sqlalchemy.sql.functions import now as sql_now from sqlalchemy.sql.functions import now as sql_now
from .config import settings
from .database import Base as db_Base from .database import Base as db_Base
class Item(db_Base): class Item(db_Base):
__tablename__ = "items" __tablename__ = "items"
uuid = sql_Column(sql_Uuid, primary_key=True, default=uuid4) uuid = sql_Column(sql_Uuid, primary_key=True, default=uuid4)
amount = sql_Column(sql_Integer, default=1) received_at = sql_Column(sql_DateTime(timezone=True), server_default=sql_now())
received_amount = sql_Column(sql_Integer, nullable=True, default=None)
created_at = sql_Column(sql_DateTime(timezone=True), server_default=sql_now())
received_at = sql_Column(sql_DateTime(timezone=True), nullable=True, default=None)
addressee = sql_Column(sql_String(64), nullable=True, default=None)
team = sql_Column(sql_String(16), nullable=True, default=None)
images = sql_relationship("Image", back_populates="item") images = sql_relationship("Image", back_populates="item")
deployed = sql_Column(sql_String(64), nullable=True, default=None)
deployed_at = sql_Column(sql_DateTime(timezone=True), nullable=True, default=None) deployed_at = sql_Column(sql_DateTime(timezone=True), nullable=True, default=None)
storage_name = sql_Column(sql_String(16), sql_ForeignKey("store.name"))
stored_at = sql_relationship(
"Storage", back_populates="items", foreign_keys=[storage_name]
)
delivery_uuid = sql_Column(sql_Uuid, sql_ForeignKey("deliveries.uuid"))
part_of = sql_relationship("Delivery", back_populates="items")
verification = sql_Column(sql_String(114), nullable=True, default=None)
tag = sql_Column(sql_String(6), nullable=True, default=None)
storage = sql_Column( class Delivery(db_Base):
sql_String(16), sql_ForeignKey("store.name"), nullable=True, default=None __tablename__ = "deliveries"
)
stored_at = sql_relationship("Storage", back_populates="items") uuid = sql_Column(sql_Uuid, primary_key=True, default=uuid4)
addressee = sql_Column(sql_String(64), nullable=True, default=None)
team = sql_Column(sql_String(16), nullable=True, default=None)
verification = sql_Column(sql_String(114), nullable=True, default=None)
tag = sql_Column(sql_String(settings.tag_length), nullable=True, default=None)
items = sql_relationship("Item", back_populates="part_of")
class Storage(db_Base): class Storage(db_Base):
......
...@@ -11,59 +11,49 @@ class Image(BaseModel): ...@@ -11,59 +11,49 @@ class Image(BaseModel):
orm_mode = True orm_mode = True
class ItemCreatePrepareShipping(BaseModel): class ItemAdd(BaseModel):
verification: str delivery_uuid: UUID4
addressee: Union[str, None] = None storage_name: str
team: Union[str, None] = None
class ItemCreateByImageAtStorage(BaseModel): class Item(ItemAdd):
image_uuid: UUID4 uuid: UUID4
storage_uuid: UUID4 received_at: datetime
images: List[Image]
deployed_at: Union[datetime, None] = None
storage_name: str
delivery_uuid: UUID4
class Config:
orm_mode = True
class ItemCheckin(BaseModel):
item_uuid: str
storage_name: str
amount: Union[int, None] = 1
class Storage(BaseModel):
name: str
items: List[Item]
class ItemUpdate(BaseModel): class Config:
addressee: Union[str, None] = None orm_mode = True
team: Union[str, None] = None
amount: Union[int, None] = None
class Item(BaseModel): class DeliveryBase(BaseModel):
uuid: UUID4 verification: Union[str, None] = None
amount: int
created_at: datetime
received_at: Union[datetime, None] = None
class DeliveryUpdate(BaseModel):
addressee: Union[str, None] = None addressee: Union[str, None] = None
team: Union[str, None] = None team: Union[str, None] = None
images: List[Image] = []
deployed: Union[str, None] = None
deployed_at: Union[datetime, None] = None
verification: Union[str, None] = None class Delivery(DeliveryBase, DeliveryUpdate):
uuid: UUID4
tag: Union[str, None] = None tag: Union[str, None] = None
items: List[Item]
storage: Union[str, None] = None
class Config: class Config:
orm_mode = True orm_mode = True
class LoginData(BaseModel): class LoginData(BaseModel):
item_uuid: str delivery_uuid: str
signature: str signature: str
class Storage(BaseModel):
name: str
items: List[Item]
class Config:
orm_mode = True
from datetime import datetime from datetime import datetime
from html import escape from html import escape
from secrets import token_hex from random import choices
from shutil import copyfileobj
from tempfile import SpooledTemporaryFile # from shutil import copyfileobj
from string import digits
from cryptography.exceptions import InvalidSignature from cryptography.exceptions import InvalidSignature
from cryptography.hazmat.primitives.asymmetric.ed448 import Ed448PublicKey from cryptography.hazmat.primitives.asymmetric.ed448 import Ed448PublicKey
...@@ -10,120 +11,159 @@ from pydantic import UUID4 ...@@ -10,120 +11,159 @@ from pydantic import UUID4
from sqlalchemy.orm import Session from sqlalchemy.orm import Session
from . import models, schemas from . import models, schemas
from .config import settings
# from tempfile import SpooledTemporaryFile
def get_item_by_uuid(db: Session, item_uuid: UUID4):
return db.get(models.Item, item_uuid)
def get_item_by_tag(db: Session, item_tag: str):
return db.query(models.Item).filter(models.Item.tag == item_tag).first()
# helpers
def generate_tag():
return "".join(choices(digits, k=settings.tag_length))
def get_storage(db: Session, storage_name: str):
return db.get(models.Storage, storage_name)
def verify_signature(delivery: schemas.Delivery, data: str, signature: str):
def get_stored_items(db: Session): public_key = Ed448PublicKey.from_public_bytes(bytes.fromhex(delivery.verification))
return ( try:
db.query(models.Item) public_key.verify(bytes.fromhex(signature), bytes(str(data), "utf-8"))
.filter(models.Item.received_at != None) # noqa: E711 except InvalidSignature:
.filter(models.Item.deployed_at == None) # noqa: E711 return False
.order_by(models.Item.storage, models.Item.addressee) return True
.all()
)
def get_items_for_storage(db: Session, storage_name: str): # main functions
return ( def get_image_by_uuid(db: Session, image_uuid: UUID4):
db.query(models.Item) return db.get(models.Image, image_uuid)
.filter(models.Item.storage == storage_name)
.filter(models.Item.received_at != None) # noqa: E711
.filter(models.Item.deployed_at == None) # noqa: E711
.all()
)
def get_storages(db: Session): def get_item_by_uuid(db: Session, item_uuid: UUID4):
return db.query(models.Storage).all() return db.get(models.Item, item_uuid)
def prepare_item_shipping(db: Session, item: schemas.ItemCreatePrepareShipping): def get_storage_by_name(db: Session, storage_name: str):
# we want the tag to be unique. storage = db.get(models.Storage, storage_name)
# FIXME: this may never finish. if storage:
tag = token_hex(3) storage.items = [
while db.query(models.Item).filter(models.Item.tag == tag).count() > 0: item for item in storage.items if item.deployed_at == None # noqa: E711
tag = token_hex(3) ]
new_item = models.Item(**item.dict(), tag=tag) return storage
db.add(new_item)
db.commit()
db.refresh(new_item)
return new_item
def add_item_with_image(db: Session, image: SpooledTemporaryFile): def get_storages(db: Session):
db_item = models.Item() storages = db.query(models.Storage).all()
db.add(db_item) for storage in storages:
storage.items = [
item for item in storage.items if item.deployed_at == None # noqa: E711
]
return storages
def get_delivery_by_uuid(db: Session, delivery_uuid: UUID4):
delivery = db.get(models.Delivery, delivery_uuid)
if delivery:
delivery.amount = len(delivery.items)
delivery.items = [
item for item in delivery.items if item.deployed_at == None # noqa: E711
]
return delivery
def get_delivery_by_tag(db: Session, delivery_tag: str):
delivery = (
db.query(models.Delivery).filter(models.Delivery.tag == delivery_tag).first()
)
if delivery:
delivery.amount = len(delivery.items)
delivery.items = [
item for item in delivery.items if item.deployed_at == None # noqa: E711
]
return delivery
def prepare_delivery(db: Session, verification: str):
tag = generate_tag()
while db.query(models.Delivery).filter(models.Delivery.tag == tag).count() > 0:
tag = generate_tag()
delivery = models.Delivery(verification=verification, tag=tag)
db.add(delivery)
db.commit() db.commit()
db_image = models.Image(item_uuid=db_item.uuid) db.refresh(delivery)
db.add(db_image) return delivery
def update_delivery_data(
db: Session, delivery_uuid: UUID4, update_data: schemas.DeliveryUpdate
):
delivery = db.get(models.Delivery, delivery_uuid)
if delivery:
if update_data.addressee:
delivery.addressee = escape(update_data.addressee)
if update_data.team:
delivery.team = escape(update_data.team)
db.commit() db.commit()
db.refresh(db_image) db.refresh(delivery)
print(db_item.uuid) delivery.amount = len(delivery.items)
print(db_image.uuid) delivery.items = [
with open(f"./images/{ db_image.uuid }", "wb") as destination: item for item in delivery.items if item.deployed_at == None # noqa: E711
try: ]
copyfileobj(image.file, destination) return delivery
finally:
image.file.close
return db_item def add_item_for_delivery_at_storage(
db: Session, delivery_uuid: UUID4, storage_name: str
):
def verify_signature(item: str, signature: str): delivery = db.get(models.Delivery, delivery_uuid)
public_key = Ed448PublicKey.from_public_bytes(bytes.fromhex(item.verification)) storage = db.get(models.Storage, storage_name)
print(str(item.uuid)) item = models.Item(storage_name=storage_name, stored_at=storage, part_of=delivery)
print(signature) db.add(item)
try:
public_key.verify(bytes.fromhex(signature), bytes(str(item.uuid), "utf-8"))
except InvalidSignature:
return False
return True
def update_item(db: Session, item: schemas.Item, data: schemas.ItemUpdate):
if data.addressee:
item.addressee = escape(data.addressee)
if data.team:
item.team = escape(data.team)
if data.amount:
item.amount = data.amount
db.commit() db.commit()
db.refresh(item) db.refresh(item)
return item return item
def receive_item_with_image(db: Session, item: schemas.ItemCreateByImageAtStorage): def deploy_item(db: Session, item_uuid: UUID4):
new_item = models.Item(storage_uuid=item.storage_uuid) item = db.get(models.Item, item_uuid)
db.add(new_item) item.deployed_at = datetime.now()
db.commit()
db.refresh(new_item)
new_image = models.Image(item_uuid=new_item.uuid)
db.add(new_image)
db.commit()
return new_item
def receive_item(db: Session, item: schemas.Item, storage: schemas.Storage):
item.received_at = datetime.now()
item.deployed_at = None
item.storage = storage.name
db.commit() db.commit()
db.refresh(item) db.refresh(item)
return item return item
def deliver_item(db: Session, item: schemas.Item): # def add_item_with_image(db: Session, image: SpooledTemporaryFile):
item.deployed_at = datetime.now() # db_item = models.Delivery()
db.commit() # db.add(db_item)
db.refresh(item) # db.commit()
return item # db_image = models.Image(item_uuid=db_item.uuid)
# db.add(db_image)
# db.commit()
# db.refresh(db_image)
# print(db_item.uuid)
# print(db_image.uuid)
# with open(f"./images/{ db_image.uuid }", "wb") as destination:
# try:
# copyfileobj(image.file, destination)
# finally:
# image.file.close
# return db_item
#
#
#
# def update_item(db: Session, item: schemas.Delivery, data: schemas.ItemUpdate):
# if data.addressee:
# item.addressee = escape(data.addressee)
# if data.team:
# item.team = escape(data.team)
# if data.amount:
# item.amount = data.amount
# db.commit()
# db.refresh(item)
# return item
#
#
# def receive_item_with_image(db: Session, item: schemas.ItemCreateByImageAtStorage):
# new_item = models.Delivery(storage_uuid=item.storage_uuid)
# db.add(new_item)
# db.commit()
# db.refresh(new_item)
# new_image = models.Image(item_uuid=new_item.uuid)
# db.add(new_image)
# db.commit()
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment