diff --git a/server.py b/server.py index 4407fc2..67c995a 100644 --- a/server.py +++ b/server.py @@ -18,6 +18,8 @@ from datetime import datetime import dotenv from authlib.integrations.flask_client import OAuth from flask_caching import Cache +from tools.cloud import getUserQuota +from tools.immich import get_immich_stats dotenv.load_dotenv() @@ -201,6 +203,37 @@ def api_data(): return jsonify(data) +@app.route("/api/v1/cloud_quota", methods=["GET"]) +def api_cloud_quota(): + """ + API endpoint to get the user's cloud quota information. + """ + + user = session.get("user") + if not user: + return jsonify({"error": "Unauthorized"}), 401 + + quota_info = getUserQuota(user["preferred_username"]) + if "error" in quota_info: + return jsonify(quota_info), 500 + return jsonify(quota_info) + + +@app.route("/api/v1/immich", methods=["GET"]) +def api_immich_stats(): + """ + API endpoint to get the user's Immich stats. + """ + + user = session.get("user") + if not user: + return jsonify({"error": "Unauthorized"}), 401 + stats = get_immich_stats(user["sub"]) + if "error" in stats: + return jsonify(stats), 500 + return jsonify(stats) + + # endregion diff --git a/services.json b/services.json index 788c8db..96cd6ce 100644 --- a/services.json +++ b/services.json @@ -29,7 +29,8 @@ "id": "podcast", "name": "WVAC Podcast", "url": "https://podcast.woodburn.au", - "description": "WVAC Podcast" + "description": "WVAC Podcast", + "icon": "https://ya.c.woodburn.au/assets/img/favicon.png" }, { "id": "transfer_sh", diff --git a/templates/assets/css/index.css b/templates/assets/css/index.css index 7613dab..5593aa9 100644 --- a/templates/assets/css/index.css +++ b/templates/assets/css/index.css @@ -39,11 +39,13 @@ a:hover { flex-direction: column; align-items: center; gap: 10px; + text-decoration: none; } .service-card:hover { transform: translateY(-5px); background-color: #333; + text-decoration: none; } .service-icon { @@ -66,6 +68,13 @@ a:hover { margin: 0; } +.service-note { + font-size: 0.9em; + color: #555; + margin: 0; + +} + .section-title { text-align: center; margin-top: 40px; diff --git a/templates/assets/js/index.js b/templates/assets/js/index.js new file mode 100644 index 0000000..7f647ea --- /dev/null +++ b/templates/assets/js/index.js @@ -0,0 +1,45 @@ +document.addEventListener("DOMContentLoaded", () => { + // If the user is logged in, fetch their cloud quota and display it + const cloudLink = document.getElementById("cloud"); + if (cloudLink) { + fetch("/api/v1/cloud_quota") + .then(response => response.json()) + .then(data => { + if (!data.error) { + // Create a new span element to display the quota + const quotaLabel = document.createElement("p"); + quotaLabel.classList.add("service-note"); + quotaLabel.textContent = `${data.used} GB used / ${data.total} GB total`; + // Append the quota span to the cloud link + cloudLink.appendChild(quotaLabel); + } else { + console.error("Error fetching cloud quota:", data.error); + } + }) + .catch(error => { + console.error("Error fetching cloud quota:", error); + }); + } + + // Fetch Immich stats and display them + const immichLink = document.getElementById("immich"); + if (immichLink) { + fetch("/api/v1/immich") + .then(response => response.json()) + .then(data => { + if (!data.error) { + // Create a new span element to display the stats + const statsLabel = document.createElement("p"); + statsLabel.classList.add("service-note"); + statsLabel.textContent = `Images: ${data.images}, Videos: ${data.videos}`; + // Append the stats span to the Immich link + immichLink.appendChild(statsLabel); + } else { + console.error("Error fetching Immich stats:", data.error); + } + }) + .catch(error => { + console.error("Error fetching Immich stats:", error); + }); + } +}); \ No newline at end of file diff --git a/templates/index.html b/templates/index.html index 9f163ff..ce780e1 100644 --- a/templates/index.html +++ b/templates/index.html @@ -7,6 +7,7 @@ Woodburn/ + @@ -25,7 +26,7 @@
-

External Services

+

Services

{% for service in services.external %} @@ -40,7 +41,7 @@

Internal Services

{% for service in services.internal %} - + {{ service.name }}

{{ service.name }}

{{ service.description }}

diff --git a/tools/adventure.py b/tools/adventure.py new file mode 100644 index 0000000..56b0d56 --- /dev/null +++ b/tools/adventure.py @@ -0,0 +1,35 @@ +import os +import requests + +IMMICH_API_KEY = os.getenv("IMMICH_API_KEY") + + +def get_immich_stats(user_sub: str) -> dict[str, int | str]: + """ + Get the user's Immich stats from the API. + """ + if not IMMICH_API_KEY: + return {"error": "IMMICH_API_KEY environment variable not set"} + headers = {"x-api-key": IMMICH_API_KEY, "Accept": "application/json"} + response = requests.get( + "https://immich.woodburn.au/api/admin/users", headers=headers + ) + if response.status_code != 200: + return {"error": f"Failed to fetch Immich stats: {response.status_code}"} + data = response.json() + user_id = None + for user in data: + if user.get("oauthId") == user_sub: + user_id = user.get("id") + break + if not user_id: + return {"error": "User not found in Immich"} + # Get user stats + response = requests.get( + f"https://immich.woodburn.au/api/admin/users/{user_id}/statistics", + headers=headers, + ) + if response.status_code != 200: + return {"error": f"Failed to fetch Immich user stats: {response.status_code}"} + stats = response.json() + return stats diff --git a/tools/cloud.py b/tools/cloud.py new file mode 100644 index 0000000..17e0ab0 --- /dev/null +++ b/tools/cloud.py @@ -0,0 +1,49 @@ +import os +import requests + +login = os.getenv("WOODBURN_USER") + + +def getUserQuota(user: str) -> dict[str, int | str]: + """ + Get the user's quota information from the environment variable. + Returns a dictionary with 'used' and 'total' as integers. + """ + headers = {"OCS-APIRequest": "true", "Accept": "application/json"} + if not login: + return { + "used": 0, + "total": 5, + "percentage": "0.0", + "error": "WOODBURN_USER environment variable not set", + } + # curl -u user https://cloud.woodburn.au/ocs/v1.php/cloud/users/nathan OCS-APIRequest:true + response = requests.get( + f"https://cloud.woodburn.au/ocs/v1.php/cloud/users/{user}", + headers=headers, + auth=(login.split(":")[0], login.split(":")[1]), + ) + if response.status_code != 200: + return { + "used": 0, + "total": 5, + "percentage": "0.0", + "error": f"Failed to fetch quota: {response.status_code}", + } + data = response.json() + # If the request failed + if data.get("ocs", {}).get("meta", {}).get("status") != "ok": + return { + "used": 0, + "total": 5, + "percentage": "0.0", + "error": data.get("ocs", {}) + .get("meta", {}) + .get("message", "Unknown error"), + } + + quota = data.get("ocs", {}).get("data", {}).get("quota", {}) + # Convert to GB + used = int(quota.get("used", 0)) // (1024 * 1024 * 1024) + total = int(quota.get("total", 0)) // (1024 * 1024 * 1024) + return {"used": used, "total": total, "percentage": quota.get("relative", "0.0")} diff --git a/tools/immich.py b/tools/immich.py new file mode 100644 index 0000000..56b0d56 --- /dev/null +++ b/tools/immich.py @@ -0,0 +1,35 @@ +import os +import requests + +IMMICH_API_KEY = os.getenv("IMMICH_API_KEY") + + +def get_immich_stats(user_sub: str) -> dict[str, int | str]: + """ + Get the user's Immich stats from the API. + """ + if not IMMICH_API_KEY: + return {"error": "IMMICH_API_KEY environment variable not set"} + headers = {"x-api-key": IMMICH_API_KEY, "Accept": "application/json"} + response = requests.get( + "https://immich.woodburn.au/api/admin/users", headers=headers + ) + if response.status_code != 200: + return {"error": f"Failed to fetch Immich stats: {response.status_code}"} + data = response.json() + user_id = None + for user in data: + if user.get("oauthId") == user_sub: + user_id = user.get("id") + break + if not user_id: + return {"error": "User not found in Immich"} + # Get user stats + response = requests.get( + f"https://immich.woodburn.au/api/admin/users/{user_id}/statistics", + headers=headers, + ) + if response.status_code != 200: + return {"error": f"Failed to fetch Immich user stats: {response.status_code}"} + stats = response.json() + return stats