summaryrefslogtreecommitdiff
path: root/backend
diff options
context:
space:
mode:
Diffstat (limited to 'backend')
-rw-r--r--backend/__pycache__/main.cpython-314.pycbin22196 -> 34213 bytes
-rw-r--r--backend/__pycache__/notif.cpython-314.pycbin0 -> 3576 bytes
-rw-r--r--backend/db.db-journalbin0 -> 8720 bytes
-rw-r--r--backend/main.py167
-rw-r--r--backend/notif.py15
-rw-r--r--backend/notif_test.py33
6 files changed, 178 insertions, 37 deletions
diff --git a/backend/__pycache__/main.cpython-314.pyc b/backend/__pycache__/main.cpython-314.pyc
index 088aec4..f65235c 100644
--- a/backend/__pycache__/main.cpython-314.pyc
+++ b/backend/__pycache__/main.cpython-314.pyc
Binary files differ
diff --git a/backend/__pycache__/notif.cpython-314.pyc b/backend/__pycache__/notif.cpython-314.pyc
new file mode 100644
index 0000000..e05be83
--- /dev/null
+++ b/backend/__pycache__/notif.cpython-314.pyc
Binary files differ
diff --git a/backend/db.db-journal b/backend/db.db-journal
new file mode 100644
index 0000000..e58d84d
--- /dev/null
+++ b/backend/db.db-journal
Binary files differ
diff --git a/backend/main.py b/backend/main.py
index dd36299..e242389 100644
--- a/backend/main.py
+++ b/backend/main.py
@@ -19,6 +19,7 @@ from dotenv import load_dotenv
from os import getenv
import yaml
import notif # import notif.py
+import bcrypt
# ## API, db, and scheduler initialisation
app = fastapi.FastAPI(title="Victoria Hall LaundryWeb", description="LaundryWeb Backend API", version="0.1")
@@ -30,6 +31,7 @@ scheduler.start()
origins = [
"http://localhost",
+ "http://localhost:8081",
"http://localhost:998",
"http://localhost:5173",
"http://127.0.0.1",
@@ -59,6 +61,13 @@ CREATE TABLE IF NOT EXISTS timers (
subscription_id TEXT NOT NULL
);""") # block is either 1 or 2, machine (1-4), odd is dryer, even is machine.
+cursor.execute("""
+CREATE TABLE IF NOT EXISTS admin_cookies (
+ cookie VARCHAR(64) PRIMARY KEY
+);
+""")
+
+cursor.execute("DELETE FROM admin_cookies;")
class RowIndices(IntEnum):
TIMER_ID = 0,
@@ -123,6 +132,12 @@ class FinishRequestData(BaseModel):
id: int
+class OverrideMachineData(BaseModel):
+ block: int
+ machine_id: int
+ disabled: bool
+
+
class Status(Enum):
EMPTY = 0,
FINISHED = 1,
@@ -130,6 +145,10 @@ class Status(Enum):
OUTOFSERVICE = 3,
+class PlaintextPasswordData(BaseModel):
+ password: str
+
+
URI_TO_MACHINES = {
"h1-status": [1, None],
"h1-dryer1": [1, 1],
@@ -194,9 +213,15 @@ def reminder_timer_finished(timer_id):
out = cursor.fetchall()
print(out)
- #scheduler.add_job(final_timer_finished, 'date', run_date=out[0][RowIndices.END_TIME], id=str(timer_id), args=[timer_id])
+ scheduler.add_job(final_timer_finished, 'date', run_date=out[0][RowIndices.END_TIME], id=str(timer_id), args=[timer_id])
- notif.send_notification(out[0][RowIndices.SUBSCRIPTION_ID])
+ notif.send_notification(
+ out[0][RowIndices.SUBSCRIPTION_ID],
+ {
+ "title": "Laundry Reminder",
+ "body": "Your laundry is almost finished.",
+ }
+ )
def final_timer_finished(timer_id):
print("timer finished!1", timer_id)
@@ -206,7 +231,15 @@ def final_timer_finished(timer_id):
for row in out:
machine_status[row[RowIndices.BLOCK] - 1][row[RowIndices.MACHINE] - 1] = Status.FINISHED.name
- notif.send_notification(out[0][RowIndices.SUBSCRIPTION_ID])
+ notif.send_notification(
+ out[0][RowIndices.SUBSCRIPTION_ID],
+ {
+ "title": "Laundry Finished",
+ "body": "Your laundry is finished! Please collect your laundry.",
+ "requireInteraction": True,
+ "timerId": timer_id,
+ }
+ )
# sec min hrs days
COOKIE_MAX_AGE = 60 * 60 * 24 * 30 # 30 days
@@ -275,7 +308,7 @@ def start_new_timer(data: RequestData, response: fastapi.Response, session_key:
try:
print("session key valid", session_key)
- end_date = now + datetime.timedelta(seconds=(data.duration * 30))
+ end_date = now + datetime.timedelta(minutes=(data.duration * 30))
cursor.execute("""
INSERT INTO timers (user_id, start_time, end_time, block, machine, status, subscription_id)
VALUES (?, ?, ?, ?, ?, ?, ?)""", (session_key, now.isoformat(), end_date.isoformat(), block, machine, 'RUNNING', subscription_endpoint,))
@@ -295,7 +328,7 @@ def start_new_timer(data: RequestData, response: fastapi.Response, session_key:
return "something went wrong during sql stuff"
try:
- scheduler.add_job(reminder_timer_finished, 'date', run_date=end_date - datetime.timedelta(seconds=5), id=timer_id, args=[timer_id])
+ scheduler.add_job(reminder_timer_finished, 'date', run_date=end_date - datetime.timedelta(minutes=5), id=timer_id, args=[timer_id])
except Exception as exception:
print("err @ scheduler //", exception)
response.status_code = fastapi.status.HTTP_500_INTERNAL_SERVER_ERROR
@@ -440,6 +473,124 @@ def uri_to_information(data: InformationRequestData, response: fastapi.Response,
# --- subscribe
@app.post("/notifsubscribe", response_class=PlainTextResponse)
def notif_subscribe(data: notif.PushSubscriptionData, response: fastapi.Response):
- endpoint = notif.subscribe(data)
- response.set_cookie(key="subscription_endpoint", value=endpoint, max_age=COOKIE_MAX_AGE, domain="laundryweb.altafcreator.com", samesite="none", secure=True, path="/")
- return "do i need to return something perhaps"
+ try:
+ endpoint = notif.subscribe(data)
+ response.set_cookie(key="subscription_endpoint", value=endpoint, max_age=COOKIE_MAX_AGE, domain="laundryweb.altafcreator.com", samesite="none", secure=True, path="/")
+ response.status_code = fastapi.status.HTTP_200_OK
+ return "subscription saved."
+ except Exception as err:
+ response.status_code = fastapi.status.HTTP_500_INTERNAL_SERVER_ERROR
+ return f"error, failed to save subscription {err}"
+
+
+# #### ADMIN PANEL API END POINTS ####
+
+# ## ADMIN PANEL SCHEDULER METHODS ##
+
+
+def delete_cookie_scheduler(cookie):
+ pass
+
+
+def authenticate_admin_check(cookie):
+ cursor.execute("SELECT * FROM admin_cookies WHERE cookie = ?", (cookie,))
+ rows = cursor.fetchall()
+
+ return len(rows) > 0
+
+
+# --- admin login
+@app.post("/admin_login", response_class=PlainTextResponse)
+def admin_login(data: PlaintextPasswordData, response: fastapi.Response):
+ print(data.password)
+
+ pwd = data.password.encode('utf-8')
+ stored_hash_pwd = getenv("ADMIN_PASSWORD_HASH").encode('utf-8')
+
+ if bcrypt.checkpw(pwd, stored_hash_pwd):
+ response.status_code = fastapi.status.HTTP_202_ACCEPTED
+
+ auth_cookie_str = secrets.token_hex(32)
+ AUTH_MAX_AGE = 60 * 10 # 10 minutes
+ response.set_cookie(key="admin_auth", value=auth_cookie_str, secure=True, max_age=AUTH_MAX_AGE, domain="backend.laundryweb.altafcreator.com", samesite="none")
+ cursor.execute("""INSERT INTO admin_cookies (cookie) VALUES (?);""", (auth_cookie_str,))
+ conn.commit()
+ cursor.execute("SELECT * FROM admin_cookies")
+ print(cursor.fetchall())
+
+ now = datetime.datetime.now(ZoneInfo(TZ))
+ end_date = now + datetime.timedelta(seconds=(AUTH_MAX_AGE))
+ scheduler.add_job(delete_cookie_scheduler, 'date', run_date=end_date, args=[auth_cookie_str])
+
+ return "hi admin you are Authenticated!!!11"
+
+ response.status_code = fastapi.status.HTTP_403_FORBIDDEN
+ return "Forbidden."
+
+
+# --- admin auth check
+@app.post("/admin_check", response_class=PlainTextResponse)
+def admin_check(response: fastapi.Response, admin_auth: Annotated[str | None, fastapi.Cookie()] = None):
+ print("admin check request, ", admin_auth)
+
+ if authenticate_admin_check(admin_auth):
+ response.status_code = fastapi.status.HTTP_202_ACCEPTED
+ return "Authorised."
+ else:
+ response.status_code = fastapi.status.HTTP_401_UNAUTHORIZED
+ return "Get out."
+
+
+# --- override each machine status
+@app.post("/override_status", response_class=PlainTextResponse)
+def override_status(data: OverrideMachineData, response: fastapi.Response, admin_auth: Annotated[str | None, fastapi.Cookie()] = None):
+ if not admin_auth:
+ response.status_code = fastapi.status.HTTP_401_UNAUTHORIZED
+ return "Unauthorised."
+
+ if authenticate_admin_check(admin_auth):
+ if (data.disabled):
+ machine_status[data.block - 1][data.machine_id - 1] = Status.OUTOFSERVICE.name
+ else:
+ cursor.execute("SELECT * FROM timers WHERE ((block = ?) AND (machine = ?))", (data.block, data.machine_id))
+ rows = cursor.fetchall()
+
+ if len(rows) > 0:
+ machine_status[data.block - 1][data.machine_id - 1] = Status.RUNNING.name
+ else:
+ machine_status[data.block - 1][data.machine_id - 1] = Status.EMPTY.name
+
+ response.status_code = fastapi.status.HTTP_200_OK
+ return "Set!"
+
+ print("set machine", data.machine_id, "of block", data.block, ".", machine_status)
+ else:
+ response.status_code = fastapi.status.HTTP_403_FORBIDDEN
+ return "Forbidden."
+
+
+# --- change admin password
+@app.post("/admin_change_password", response_class=PlainTextResponse)
+def admin_change_password(data: PlaintextPasswordData, response: fastapi.Response, admin_auth: Annotated[str | None, fastapi.Cookie()] = None):
+ if not admin_auth:
+ response.status_code = fastapi.status.HTTP_401_UNAUTHORIZED
+ return "Unauthorised."
+
+ if authenticate_admin_check(admin_auth):
+ pass
+ else:
+ pass
+
+
+# --- get all blocks machine status for admin
+@app.post("/admin_machine_status")
+def admin_machine_status(response: fastapi.Response, admin_auth: Annotated[str | None, fastapi.Cookie()] = None):
+ if not admin_auth:
+ response.status_code = fastapi.status.HTTP_401_UNAUTHORIZED
+ return """{"reply": "Unauthorised."}"""
+
+ if authenticate_admin_check(admin_auth):
+ return machine_status
+ else:
+ response.status_code = fastapi.status.HTTP_403_FORBIDDEN
+ return """{"reply": "Forbidden."}"""
diff --git a/backend/notif.py b/backend/notif.py
index 57ccc23..eb25793 100644
--- a/backend/notif.py
+++ b/backend/notif.py
@@ -3,6 +3,7 @@ import sqlite3
from pywebpush import webpush
from dotenv import load_dotenv
from os import getenv
+import json
class PushSubscriptionData(BaseModel):
endpoint: str
@@ -37,7 +38,7 @@ def subscribe(data: PushSubscriptionData):
VALUES (?, ?, ?)""", (data.endpoint, data.keys["p256dh"], data.keys["auth"]))
conn.commit()
- cursor.execute("SELECT * FROM subscriptions");
+ cursor.execute("SELECT * FROM subscriptions")
result = cursor.fetchall()
for row in result:
@@ -48,8 +49,8 @@ def subscribe(data: PushSubscriptionData):
# --- send notification
# ---- not used yet
-def send_notification(endpoint: str):
- cursor.execute("SELECT * FROM subscriptions WHERE endpoint = ?", (endpoint,))
+def send_notification(endpoint: str, notification_payload: object):
+ cursor.execute(f"""SELECT * FROM subscriptions WHERE endpoint = \"{endpoint}\"""")
row = cursor.fetchall()[0]
print(row)
@@ -64,16 +65,12 @@ def send_notification(endpoint: str):
try:
webpush(
subscription_info=subscription_info,
- data="""
- {
- "title": "Hello, world!",
- "body": "Hello, Victoria Hall!"
- }
- """,
+ data=json.dumps(notification_payload),
vapid_private_key=PRIVATE_VAPID_KEY,
vapid_claims={
"sub": "mailto:dev@altafcreator.com",
},
+ headers={"Urgency": "high"}
)
except Exception as exception:
print(exception)
diff --git a/backend/notif_test.py b/backend/notif_test.py
index cf5391f..b6f843e 100644
--- a/backend/notif_test.py
+++ b/backend/notif_test.py
@@ -1,21 +1,14 @@
-from dotenv import load_dotenv
-from os import getenv
-import onesignal
-from onesignal.api import default_api
-from onesignal.model.notification import Notification
-
-load_dotenv()
-
-onesignal_configuration = onesignal.Configuration(
- rest_api_key=getenv("REST_API_KEY"),
- organization_api_key=getenv("ORGANIZATION_API_KEY"),
+import notif
+
+endpoint_to_test = "https://fcm.googleapis.com/fcm/send/f4Cw12WAYnE:APA91bHOZvh8HkExsem20UK_5uhzgCu0dEo01YV8G8-9hFBjEdsk1M49JVLD7Z51BDP7gxn_UAXVwvmYxIWajwQ9VyTS3ghNQzx92jex-isbz5IvzcpI0QOxaVnmoURLtK-qYt36ebic"
+endpoint_to_test = "https://fcm.googleapis.com/preprod/wp/dP2ULA5s2Fk:APA91bE6toPxR5LbakAronwoI2QfdSe6NIEAzVBoIq0Q5jUF8hkFskAT_PyHYwwUiJpJgF8xcCr_8CEzE83YTsUGZWyvcI53DiwjkDD4IK1UseK2bX-WaXVRRXBLM5wTHCKs1ZfG2rME"
+
+notif.send_notification(
+ endpoint_to_test,
+ {
+ "title": "Test Notification",
+ "body": "Hello, world pls work",
+ "requireInteraction": True,
+ "timerId": 0,
+ }
)
-
-api_client = onesignal.ApiClient(onesignal_configuration)
-api_instance = default_api.DefaultApi(api_client)
-
-ONESIGNAL_APP_ID = "83901cc7-d964-475a-90ec-9f854df4ba52"
-
-# yes that's my subscription id. probably outdated by now
-notification = Notification(app_id=ONESIGNAL_APP_ID, include_subscription_ids=['86f24e73-8887-4e29-b607-31e1a8f25b93'], contents={'en': 'hello world'}, headings={'en': 'Laundry Finished!'}, priority=10)
-print(api_instance.create_notification(notification))