remove old db

This commit is contained in:
Jörn-Michael Miehe 2022-03-28 01:34:15 +00:00
parent 0619f00f6a
commit b4a74aca5f
7 changed files with 0 additions and 453 deletions

View file

@ -1,4 +0,0 @@
from . import models, schemata
from .connection import Connection
__all__ = ["Connection", "models", "schemata"]

View file

@ -1,75 +0,0 @@
"""
Utilities for handling SQLAlchemy database connections.
"""
from typing import Generator
from sqlalchemy.engine import Engine
from sqlalchemy.orm import Session, sessionmaker
from .models import ORMBaseModel
class SessionManager:
"""
Simple context manager for an ORM session.
"""
__session: Session
def __init__(self, session: Session) -> None:
self.__session = session
def __enter__(self) -> Session:
return self.__session
def __exit__(self, *args) -> None:
self.__session.close()
class Connection:
"""
Namespace for the database connection.
"""
engine: Engine | None = None
session_local: sessionmaker | None = None
@classmethod
def connect(cls, engine: Engine) -> None:
"""
Connect ORM to a database engine.
"""
cls.engine = engine
cls.session_local = sessionmaker(
autocommit=False, autoflush=False, bind=engine,
)
ORMBaseModel.metadata.create_all(bind=engine)
@classmethod
def use(cls) -> SessionManager | None:
"""
Create an ORM session using a context manager.
"""
if cls.session_local is None:
return None
return SessionManager(cls.session_local())
@classmethod
async def get(cls) -> Generator[Session | None, None, None]:
"""
Create an ORM session using a FastAPI compatible async generator.
"""
if cls.session_local is None:
yield None
else:
db = cls.session_local()
try:
yield db
finally:
db.close()

View file

@ -1,82 +0,0 @@
"""
SQLAlchemy representation of database contents.
"""
from __future__ import annotations
from sqlalchemy import (Column, DateTime, ForeignKey, Integer, String,
UniqueConstraint)
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import Session, relationship
ORMBaseModel = declarative_base()
class UserCapability(ORMBaseModel):
__tablename__ = "user_capabilities"
user_name = Column(
String,
ForeignKey("users.name"),
primary_key=True,
index=True,
)
capability = Column(String, primary_key=True)
class User(ORMBaseModel):
__tablename__ = "users"
name = Column(String, primary_key=True, index=True)
password = Column(String, nullable=False)
email = Column(String)
country = Column(String(2))
state = Column(String)
city = Column(String)
organization = Column(String)
organizational_unit = Column(String)
capabilities: list[UserCapability] = relationship(
"UserCapability", lazy="joined", cascade="all, delete-orphan"
)
devices: list[Device] = relationship(
"Device", lazy="select", back_populates="owner"
)
@classmethod
def from_db(
cls,
db: Session,
name: str,
) -> User | None:
"""
Load user from database by name.
"""
return (
db
.query(cls)
.filter(cls.name == name)
.first()
)
class Device(ORMBaseModel):
__tablename__ = "devices"
id = Column(Integer, primary_key=True, autoincrement=True)
owner_name = Column(String, ForeignKey("users.name"))
name = Column(String)
type = Column(String)
expiry = Column(DateTime)
owner: User = relationship(
"User", lazy="joined", back_populates="devices"
)
UniqueConstraint(
owner_name,
name,
)

View file

@ -1,6 +0,0 @@
from .device import Device, DeviceBase, DeviceCreate
from .user import User, UserBase, UserCreate
from .user_capability import UserCapability
__all__ = ["Device", "DeviceBase", "DeviceCreate",
"User", "UserBase", "UserCreate", "UserCapability"]

View file

@ -1,79 +0,0 @@
"""
Pydantic representation of database contents.
"""
from __future__ import annotations
from datetime import datetime
from pydantic import BaseModel
from sqlalchemy.exc import IntegrityError
from sqlalchemy.orm import Session
from .. import models
class DeviceBase(BaseModel):
name: str
type: str
expiry: datetime
class DeviceCreate(DeviceBase):
owner_name: str
class Device(DeviceBase):
class Config:
orm_mode = True
@classmethod
def create(
cls,
db: Session,
device: DeviceCreate,
) -> Device | None:
"""
Create a new device in the database.
"""
try:
db_device = models.Device(
owner_name=device.owner_name,
name=device.name,
type=device.type,
expiry=device.expiry,
)
db.add(db_device)
db.commit()
db.refresh(db_device)
return cls.from_orm(db_device)
except IntegrityError:
# device already existed
return None
def delete(
self,
db: Session,
) -> bool:
"""
Delete this device from the database.
"""
db_device = models.Device(
# owner_name=
name=self.name,
)
db.refresh(db_device)
if db_device is None:
# nonexistent device
return False
db.delete(db_device)
db.commit()
return True

View file

@ -1,164 +0,0 @@
"""
Pydantic representation of database contents.
"""
from __future__ import annotations
from typing import Any
from passlib.context import CryptContext
from pydantic import BaseModel, Field, validator
from sqlalchemy.exc import IntegrityError
from sqlalchemy.orm import Session
from .. import models
from .device import Device
from .user_capability import UserCapability
class UserBase(BaseModel):
name: str
email: str
capabilities: list[UserCapability] = []
country: str | None = Field(default=None, repr=False)
state: str | None = Field(default=None, repr=False)
city: str | None = Field(default=None, repr=False)
organization: str | None = Field(default=None, repr=False)
organizational_unit: str | None = Field(default=None, repr=False)
class UserCreate(UserBase):
password: str
class User(UserBase):
devices: list[Device] = Field(
default=[], repr=False
)
class Config:
orm_mode = True
@validator("capabilities", pre=True)
@classmethod
def unify_capabilities(cls, value: list[Any]) -> list[UserCapability]:
"""
Import the capabilities from various formats
"""
return [
UserCapability.from_value(capability)
for capability in value
]
@classmethod
def from_db(
cls,
db: Session,
name: str,
) -> User | None:
"""
Load user from database by name.
"""
if (db_user := models.User.from_db(db, name)) is None:
return None
return cls.from_orm(db_user)
@classmethod
def create(
cls,
db: Session,
user: UserCreate,
crypt_context: CryptContext,
) -> User | None:
"""
Create a new user in the database.
"""
try:
db_user = models.User(
name=user.name,
password=crypt_context.hash(user.password),
email=user.email,
capabilities=[
capability.model
for capability in user.capabilities
],
)
db.add(db_user)
db.commit()
db.refresh(db_user)
return cls.from_orm(db_user)
except IntegrityError:
# user already existed
return None
def is_admin(self) -> bool:
return UserCapability.admin in self.capabilities
def authenticate(
self,
db: Session,
password: str,
crypt_context: CryptContext,
) -> User | None:
"""
Authenticate with name/password against users in database.
"""
if (db_user := models.User.from_db(db, self.name)) is None:
# nonexistent user, fake doing password verification
crypt_context.dummy_verify()
return False
if not crypt_context.verify(password, db_user.password):
# password hash mismatch
return False
self.from_orm(db_user)
return True
def update(
self,
db: Session,
) -> None:
"""
Update this user in the database.
"""
if (db_user := models.User.from_db(db, self.name)) is None:
return None
for capability in db_user.capabilities:
db.delete(capability)
db_user.capabilities = [
capability.model
for capability in self.capabilities
]
db.commit()
def delete(
self,
db: Session,
) -> bool:
"""
Delete this user from the database.
"""
if (db_user := models.User.from_db(db, self.name)) is None:
# nonexistent user
return False
db.delete(db_user)
db.commit()
return True

View file

@ -1,43 +0,0 @@
"""
Pydantic representation of database contents.
"""
from __future__ import annotations
from enum import Enum
from .. import models
class UserCapability(Enum):
admin = "admin"
login = "login"
issue = "issue"
renew = "renew"
def __repr__(self) -> str:
return self.value
@classmethod
def from_value(cls, value) -> UserCapability:
"""
Create UserCapability from various formats
"""
if isinstance(value, cls):
# value is already a UserCapability, use that
return value
elif isinstance(value, models.UserCapability):
# create from db format
return cls(value.capability)
else:
# create from string representation
return cls(str(value))
@property
def model(self) -> models.UserCapability:
return models.UserCapability(
capability=self.value,
)