From 831ce1dbc84a3ec7e5b1337c43955e7a9ace228a Mon Sep 17 00:00:00 2001 From: michivonah Date: Wed, 26 Mar 2025 11:17:10 +0100 Subject: [PATCH] beginn new version webservice --- .gitignore | 160 ++++++++++++++++++++++++++++++++++++ webservice/dbfunctions.py | 35 ++++++++ webservice/requirements.txt | 6 +- webservice/webservice.py | 123 +++++++++------------------ 4 files changed, 237 insertions(+), 87 deletions(-) create mode 100644 .gitignore create mode 100644 webservice/dbfunctions.py diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..6769e21 --- /dev/null +++ b/.gitignore @@ -0,0 +1,160 @@ +# Byte-compiled / optimized / DLL files +__pycache__/ +*.py[cod] +*$py.class + +# C extensions +*.so + +# Distribution / packaging +.Python +build/ +develop-eggs/ +dist/ +downloads/ +eggs/ +.eggs/ +lib/ +lib64/ +parts/ +sdist/ +var/ +wheels/ +share/python-wheels/ +*.egg-info/ +.installed.cfg +*.egg +MANIFEST + +# PyInstaller +# Usually these files are written by a python script from a template +# before PyInstaller builds the exe, so as to inject date/other infos into it. +*.manifest +*.spec + +# Installer logs +pip-log.txt +pip-delete-this-directory.txt + +# Unit test / coverage reports +htmlcov/ +.tox/ +.nox/ +.coverage +.coverage.* +.cache +nosetests.xml +coverage.xml +*.cover +*.py,cover +.hypothesis/ +.pytest_cache/ +cover/ + +# Translations +*.mo +*.pot + +# Django stuff: +*.log +local_settings.py +db.sqlite3 +db.sqlite3-journal + +# Flask stuff: +instance/ +.webassets-cache + +# Scrapy stuff: +.scrapy + +# Sphinx documentation +docs/_build/ + +# PyBuilder +.pybuilder/ +target/ + +# Jupyter Notebook +.ipynb_checkpoints + +# IPython +profile_default/ +ipython_config.py + +# pyenv +# For a library or package, you might want to ignore these files since the code is +# intended to run in multiple environments; otherwise, check them in: +# .python-version + +# pipenv +# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. +# However, in case of collaboration, if having platform-specific dependencies or dependencies +# having no cross-platform support, pipenv may install dependencies that don't work, or not +# install all needed dependencies. +#Pipfile.lock + +# poetry +# Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control. +# This is especially recommended for binary packages to ensure reproducibility, and is more +# commonly ignored for libraries. +# https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control +#poetry.lock + +# pdm +# Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control. +#pdm.lock +# pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it +# in version control. +# https://pdm.fming.dev/#use-with-ide +.pdm.toml + +# PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm +__pypackages__/ + +# Celery stuff +celerybeat-schedule +celerybeat.pid + +# SageMath parsed files +*.sage.py + +# Environments +.env +.venv +env/ +venv/ +ENV/ +env.bak/ +venv.bak/ + +# Spyder project settings +.spyderproject +.spyproject + +# Rope project settings +.ropeproject + +# mkdocs documentation +/site + +# mypy +.mypy_cache/ +.dmypy.json +dmypy.json + +# Pyre type checker +.pyre/ + +# pytype static type analyzer +.pytype/ + +# Cython debug symbols +cython_debug/ + +# PyCharm +# JetBrains specific template is maintained in a separate JetBrains.gitignore that can +# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore +# and can be added to the global gitignore or merged into this file. For a more nuclear +# option (not recommended) you can uncomment the following to ignore the entire idea folder. +#.idea/ \ No newline at end of file diff --git a/webservice/dbfunctions.py b/webservice/dbfunctions.py new file mode 100644 index 0000000..de349b1 --- /dev/null +++ b/webservice/dbfunctions.py @@ -0,0 +1,35 @@ +import psycopg2 +from psycopg2.extras import execute_values +import os +from dotenv import load_dotenv + +load_dotenv() + +# Create a database connection +def connectDatabase(): + conn = psycopg2.connect( + host=os.getenv('DBHOST'), + database=os.getenv('DBNAME'), + user=os.getenv('DBUSER'), + password=os.getenv('DBPASSWORD'), + port=os.getenv('DBPORT'),) + conn.autocommit = True + cursor = conn.cursor() + return cursor + +# Execute database query +def executeQuery(query): + conn = connectDatabase() + conn.execute(query) + result = conn.fetchall() + return result + +# Execute database query without fetching data +def executeWithoutFetch(query): + conn = connectDatabase() + conn.execute(query) + return None + +def bulkInsert(query, data): + conn = connectDatabase() + return execute_values(conn, query, data) \ No newline at end of file diff --git a/webservice/requirements.txt b/webservice/requirements.txt index 7cae057..098b87b 100644 --- a/webservice/requirements.txt +++ b/webservice/requirements.txt @@ -1,5 +1,7 @@ -fastapi +fastapi[standard]==0.115.12 uvicorn sqlalchemy psycopg2-binary - +psycopg2-binary==2.9.9 +python-dotenv==1.0.0 +requests \ No newline at end of file diff --git a/webservice/webservice.py b/webservice/webservice.py index 3a88f04..5e3bf83 100644 --- a/webservice/webservice.py +++ b/webservice/webservice.py @@ -1,94 +1,47 @@ -from fastapi import FastAPI, Depends, HTTPException -from sqlalchemy import Column, Integer, Float, String, DateTime, create_engine, ForeignKey -from sqlalchemy.orm import sessionmaker, declarative_base, Session, relationship +# Webservice +# INP21b - Timo Weber & Michael von Ah + +from fastapi import FastAPI, HTTPException +from pydantic import BaseModel +import psycopg2 +import dbfunctions as db +import requests, secrets, hashlib, re, string, random, os +from datetime import datetime, timedelta, date, time +import json from datetime import datetime -import os DATABASE_URL = os.getenv("DB_CONNECTION_STRING", "postgresql://user:password@localhost/sensordb") -Base = declarative_base() -engine = create_engine(DATABASE_URL) -SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine) +""" class apiFunctions: + def __init__(self) -> None: + self.alternativeImage = "https://cdn.ep.neodym.dev/media/20240505-halloween.jpeg" -app = FastAPI() + def getAttractionList(self): + query = 'SELECT "name", "id", "imageurl", "description" FROM "attraction" ORDER BY "name";' + attractions = db.executeQuery(query) + if attractions: + return attractions + else: + raise Exception("Cannot generate list of attractions. Request invalid") """ + -# Neue Clients-Tabelle -class Client(Base): - __tablename__ = "clients" +#### API #### +app = FastAPI( + title="M241-M245-BBZW-Horizion", + description="BBZW-Horizon", + summary="BBZW-Horizon", + version="0.0.1" +) - id = Column(Integer, primary_key=True, index=True) - name = Column(String, unique=True, index=True) +class Session(BaseModel): + username: str = None + token: str = None + message: str = None + timestamp: datetime = datetime.now() -class SensorData(Base): - __tablename__ = "sensor_data" - - id = Column(Integer, primary_key=True, index=True) - clientid = Column(Integer, ForeignKey("clients.id"), index=True) - timestamp = Column(DateTime, default=datetime.utcnow) - temperature = Column(Float) - humidity = Column(Float) - pressure = Column(Float) - voc = Column(Float) - gas = Column(Float) - - client = relationship("Client") - -class SessionToken(Base): - __tablename__ = "sessions" - - id = Column(Integer, primary_key=True, index=True) - token = Column(String, unique=True, index=True) - validuntil = Column(DateTime) - userid = Column(Integer, ForeignKey("user.id")) - -def get_db(): - db = SessionLocal() +@app.post("/account/new-session", tags=["account"]) +async def initNewSessionApi(username: str, password: str) -> Session: try: - yield db - finally: - db.close() - -def verify_token(token: str, db: Session): - session = db.query(SessionToken).filter(SessionToken.token == token).first() - if not session or session.validuntil < datetime.utcnow(): - raise HTTPException(status_code=401, detail="Invalid or expired token") - return session - -@app.post("/sensor-data/") -def receive_sensor_data( - token: str, - clientname: str, # Ändert clientid zu clientname - temperature: float, - humidity: float, - pressure: float, - voc: float, - gas: float, - db: Session = Depends(get_db) -): - verify_token(token, db) - - # Suche die Client-ID anhand des Client-Namens - client = db.query(Client).filter(Client.name == clientname).first() - if not client: - raise HTTPException(status_code=404, detail="Client not found") - - sensor_data = SensorData( - clientid=client.id, # Verwende die gefundene ID - temperature=temperature, - humidity=humidity, - pressure=pressure, - voc=voc, - gas=gas - ) - db.add(sensor_data) - db.commit() - db.refresh(sensor_data) - return {"message": "Data received", "id": sensor_data.id} - -@app.get("/sensor-data/") -def get_sensor_data(db: Session = Depends(get_db)): - data = db.query(SensorData).all() - return data - -# Erstelle die Tabellen, falls sie noch nicht existieren -Base.metadata.create_all(bind=engine) + return Session(username="username", token="sessionToken", message="Session initiated successfully") + except Exception as error: + raise HTTPException(status_code=401, detail=f"{error}") \ No newline at end of file