separation of production and development

environments
Adding new migrations for renaming and adding fields
to the database schema
persistent uuid for simclient
This commit is contained in:
2025-07-16 08:50:42 +00:00
parent 84a92ab9c2
commit 1a6faaa104
7 changed files with 116 additions and 12 deletions

View File

@@ -23,7 +23,7 @@ services:
networks: networks:
- infoscreen-net - infoscreen-net
proxy: proxy:
image: nginx:1.27 image: nginx:stable
container_name: infoscreen-proxy container_name: infoscreen-proxy
ports: ports:
- "80:80" - "80:80"
@@ -38,7 +38,7 @@ services:
- infoscreen-net - infoscreen-net
db: db:
image: mariadb:11.4.7 image: mariadb:lts
container_name: infoscreen-db container_name: infoscreen-db
restart: unless-stopped restart: unless-stopped
environment: environment:

View File

@@ -30,6 +30,7 @@ class ClientGroup(Base):
__tablename__ = 'client_groups' __tablename__ = 'client_groups'
id = Column(Integer, primary_key=True, autoincrement=True) id = Column(Integer, primary_key=True, autoincrement=True)
name = Column(String(100), unique=True, nullable=False) name = Column(String(100), unique=True, nullable=False)
description = Column(String(255), nullable=True) # Manuell zu setzen
created_at = Column(TIMESTAMP(timezone=True), created_at = Column(TIMESTAMP(timezone=True),
server_default=func.current_timestamp()) server_default=func.current_timestamp())
is_active = Column(Boolean, default=True, nullable=False) is_active = Column(Boolean, default=True, nullable=False)
@@ -46,6 +47,7 @@ class Client(Base):
software_version = Column(String(100), nullable=True) software_version = Column(String(100), nullable=True)
macs = Column(String(255), nullable=True) macs = Column(String(255), nullable=True)
model = Column(String(100), nullable=True) model = Column(String(100), nullable=True)
description = Column(String(255), nullable=True) # Manuell zu setzen
registration_time = Column(TIMESTAMP( registration_time = Column(TIMESTAMP(
timezone=True), server_default=func.current_timestamp(), nullable=False) timezone=True), server_default=func.current_timestamp(), nullable=False)
last_alive = Column(TIMESTAMP(timezone=True), server_default=func.current_timestamp( last_alive = Column(TIMESTAMP(timezone=True), server_default=func.current_timestamp(

View File

@@ -0,0 +1,36 @@
"""Rename location to description in client_groups, add description to clients
Revision ID: 0c47280d3e2d
Revises: 3a09ef909689
Create Date: 2025-07-16 08:47:00.355445
"""
from typing import Sequence, Union
from alembic import op
import sqlalchemy as sa
from sqlalchemy.dialects import mysql
# revision identifiers, used by Alembic.
revision: str = '0c47280d3e2d'
down_revision: Union[str, None] = '3a09ef909689'
branch_labels: Union[str, Sequence[str], None] = None
depends_on: Union[str, Sequence[str], None] = None
def upgrade() -> None:
"""Upgrade schema."""
# ### commands auto generated by Alembic - please adjust! ###
op.add_column('client_groups', sa.Column('description', sa.String(length=255), nullable=True))
op.drop_column('client_groups', 'location')
op.add_column('clients', sa.Column('description', sa.String(length=255), nullable=True))
# ### end Alembic commands ###
def downgrade() -> None:
"""Downgrade schema."""
# ### commands auto generated by Alembic - please adjust! ###
op.drop_column('clients', 'description')
op.add_column('client_groups', sa.Column('location', mysql.VARCHAR(length=100), nullable=True))
op.drop_column('client_groups', 'description')
# ### end Alembic commands ###

View File

@@ -0,0 +1,32 @@
"""Add location to client_groups
Revision ID: 3a09ef909689
Revises: 207f5b190f93
Create Date: 2025-07-16 08:36:08.535836
"""
from typing import Sequence, Union
from alembic import op
import sqlalchemy as sa
# revision identifiers, used by Alembic.
revision: str = '3a09ef909689'
down_revision: Union[str, None] = '207f5b190f93'
branch_labels: Union[str, Sequence[str], None] = None
depends_on: Union[str, Sequence[str], None] = None
def upgrade() -> None:
"""Upgrade schema."""
# ### commands auto generated by Alembic - please adjust! ###
op.add_column('client_groups', sa.Column('location', sa.String(length=100), nullable=True))
# ### end Alembic commands ###
def downgrade() -> None:
"""Downgrade schema."""
# ### commands auto generated by Alembic - please adjust! ###
op.drop_column('client_groups', 'location')
# ### end Alembic commands ###

View File

@@ -1,11 +1,11 @@
import bcrypt
from dotenv import load_dotenv
import os
from models.models import Base, User, UserRole, ClientGroup
from sqlalchemy.orm import sessionmaker
from sqlalchemy import create_engine, text
import sys import sys
sys.path.insert(0, '/workspace') sys.path.insert(0, '/workspace')
from sqlalchemy import create_engine, text
from sqlalchemy.orm import sessionmaker
from models.models import Base, User, UserRole
import os
from dotenv import load_dotenv
import bcrypt
# .env laden # .env laden
load_dotenv() load_dotenv()
@@ -24,7 +24,8 @@ admin_conn_str = f"mysql+pymysql://{DB_USER}:{DB_PASSWORD}@{DB_HOST}/"
admin_engine = create_engine(admin_conn_str, echo=True) admin_engine = create_engine(admin_conn_str, echo=True)
with admin_engine.connect() as conn: with admin_engine.connect() as conn:
conn.execute(text(f"CREATE DATABASE IF NOT EXISTS {DB_NAME} CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;")) conn.execute(text(
f"CREATE DATABASE IF NOT EXISTS {DB_NAME} CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;"))
# Jetzt mit Datenbank verbinden # Jetzt mit Datenbank verbinden
db_conn_str = f"mysql+pymysql://{DB_USER}:{DB_PASSWORD}@{DB_HOST}/{DB_NAME}" db_conn_str = f"mysql+pymysql://{DB_USER}:{DB_PASSWORD}@{DB_HOST}/{DB_NAME}"
@@ -33,16 +34,35 @@ engine = create_engine(db_conn_str, echo=True)
# Tabellen anlegen # Tabellen anlegen
# Base.metadata.create_all(engine) # wird von alembic verwaltet # Base.metadata.create_all(engine) # wird von alembic verwaltet
# Session erstellen # Session erstellen
Session = sessionmaker(bind=engine) Session = sessionmaker(bind=engine)
session = Session() session = Session()
# Default-ClientGroup anlegen, falls nicht vorhanden
DEFAULT_GROUP_ID = 1
DEFAULT_GROUP_NAME = "Nicht zugeordnet"
existing_group = session.query(ClientGroup).filter_by(
id=DEFAULT_GROUP_ID).first()
if not existing_group:
default_group = ClientGroup(
id=DEFAULT_GROUP_ID, name=DEFAULT_GROUP_NAME, is_active=True)
session.add(default_group)
session.commit()
print(
f"Default-ClientGroup '{DEFAULT_GROUP_NAME}' mit id={DEFAULT_GROUP_ID} wurde angelegt.")
else:
print(
f"Default-ClientGroup '{DEFAULT_GROUP_NAME}' mit id={DEFAULT_GROUP_ID} existiert bereits.")
# Prüfen, ob der User bereits existiert # Prüfen, ob der User bereits existiert
existing_user = session.query(User).filter_by(username=DEFAULT_ADMIN_USERNAME).first() existing_user = session.query(User).filter_by(
username=DEFAULT_ADMIN_USERNAME).first()
if not existing_user: if not existing_user:
# Passwort hashen # Passwort hashen
hashed_pw = bcrypt.hashpw(DEFAULT_ADMIN_PASSWORD.encode('utf-8'), bcrypt.gensalt()) hashed_pw = bcrypt.hashpw(
DEFAULT_ADMIN_PASSWORD.encode('utf-8'), bcrypt.gensalt())
# Neuen User anlegen # Neuen User anlegen
admin_user = User( admin_user = User(

View File

@@ -1 +1,2 @@
paho-mqtt paho-mqtt
dotenv

View File

@@ -142,9 +142,22 @@ def send_discovery(client, client_id, hardware_token, ip_addr):
logging.info(f"Discovery-Nachricht gesendet: {discovery_msg}") logging.info(f"Discovery-Nachricht gesendet: {discovery_msg}")
def get_persistent_uuid(uuid_path="/data/client_uuid.txt"):
# Prüfe, ob die Datei existiert
if os.path.exists(uuid_path):
with open(uuid_path, "r") as f:
return f.read().strip()
# Generiere neue UUID und speichere sie
new_uuid = str(uuid.uuid4())
os.makedirs(os.path.dirname(uuid_path), exist_ok=True)
with open(uuid_path, "w") as f:
f.write(new_uuid)
return new_uuid
def main(): def main():
global discovered global discovered
client_id = str(uuid.uuid4()) client_id = get_persistent_uuid()
hardware_token = get_hardware_token() hardware_token = get_hardware_token()
ip_addr = get_ip() ip_addr = get_ip()
client = mqtt.Client(protocol=mqtt.MQTTv311, callback_api_version=2) client = mqtt.Client(protocol=mqtt.MQTTv311, callback_api_version=2)