From da7623b55ef1609e36bdc0c0b0c61836bb9f799f Mon Sep 17 00:00:00 2001 From: Will Hellinger Date: Wed, 4 Mar 2026 01:40:31 -0500 Subject: [PATCH 1/2] Add endpoints --- src/api/endpoints.py | 92 ++++++++++++++++++++++++++++++++++++++++++++ src/main.py | 15 +++++++- src/requirements.txt | 3 +- 3 files changed, 108 insertions(+), 2 deletions(-) diff --git a/src/api/endpoints.py b/src/api/endpoints.py index e69de29..83036da 100644 --- a/src/api/endpoints.py +++ b/src/api/endpoints.py @@ -0,0 +1,92 @@ +from logging import getLogger, Logger + +import random +import textwrap +import requests + +from fastapi import APIRouter, Query +from fastapi.responses import JSONResponse + +from core import google, slack + +logger: Logger = getLogger(__name__) + +router: APIRouter = APIRouter() + +@router.get("/calendar") +def get_calendar() -> JSONResponse: + """ + Returns calendar data. + """ + + pass + + +@router.get("/announcement") +def get_announcement() -> JSONResponse: + """ + Returns announcement data. + """ + + pass + + +@router.put("/announcement") +def update_announcement() -> JSONResponse: + """ + Updates an existing announcement. + """ + + pass + + +@router.get("/harold") +def get_harold() -> JSONResponse: + """ + Returns harold data. + """ + + pass + + +@router.put("/harold") +def update_harold() -> JSONResponse: + """ + Updates harold data. + """ + + pass + + +@router.get("/showerthoughts") +def showerthoughts() -> JSONResponse: + """ + Returns a random shower thought from the Reddit API. + + Returns: + JSONResponse: A JSON response containing a random shower thought. + """ + + response: dict = {"data": "No shower thoughts found."} + + try: + logger.info("Fetching shower thoughts from Reddit API...") + + reddit_data: requests.Response = requests.get( + "https://www.reddit.com/r/showerthoughts/top.json", + headers={"User-agent": "Showerthoughtbot 0.1"}, + ) + + if len(reddit_data.json()["data"]["children"]) == 0: + logger.warning("No shower thoughts found in Reddit API response.") + return JSONResponse(response) + + shower_thought: str = textwrap.fill( + (random.choice(reddit_data.json()["data"]["children"])["data"]["title"]), 50 + ) + + response["data"] = shower_thought + except Exception as e: + logger.error(f"Error fetching shower thoughts: {e}") + + return JSONResponse(response) diff --git a/src/main.py b/src/main.py index 70ed170..85d2c81 100644 --- a/src/main.py +++ b/src/main.py @@ -1,6 +1,19 @@ """ Jumpstart V2 Used for the Dashboard seen upon entering DSP Floor 3 -Authors: Eli Mares,Nikolai Strong, Will Hellinger, +Authors: Eli Mares,Nikolai Strong, Will Hellinger, V1 Authors: Beckett Jenen """ + +from fastapi import FastAPI +from fastapi.staticfiles import StaticFiles +from fastapi.templating import Jinja2Templates + + +from api import endpoints + +app: FastAPI = FastAPI() +app.include_router(endpoints.router, prefix="/api") + +app.mount("/static", StaticFiles(directory="static"), name="static") +templates: Jinja2Templates = Jinja2Templates(directory="templates") \ No newline at end of file diff --git a/src/requirements.txt b/src/requirements.txt index 5282376..0aecbaa 100644 --- a/src/requirements.txt +++ b/src/requirements.txt @@ -1,3 +1,4 @@ fastapi==0.135.1 uvicorn==0.41.0 -logging==0.4.9.6 \ No newline at end of file +logging==0.4.9.6 +requests==2.32.5 From 27ec9f73f3aac70bb7e24e90c77bac5b56bcc096 Mon Sep 17 00:00:00 2001 From: Will Hellinger Date: Thu, 5 Mar 2026 01:58:44 -0500 Subject: [PATCH 2/2] Add basic website support, update environmental variables, change python-version to just 3.14 --- .env.template | 3 +++ .python-version | 2 +- Dockerfile | 7 +++---- README.md | 11 +++++++++++ docker-compose.yml | 5 ++++- src/api/endpoints.py | 2 +- src/config.py | 13 ++++++++++--- src/core/calendar.py | 2 -- src/main.py | 20 +++++++++++++++++--- src/requirements.txt | 4 ++++ src/templates/index.html | 10 +++++----- 11 files changed, 59 insertions(+), 20 deletions(-) create mode 100644 .env.template diff --git a/.env.template b/.env.template new file mode 100644 index 0000000..d592a32 --- /dev/null +++ b/.env.template @@ -0,0 +1,3 @@ +CALENDAR_URL= +CALENDAR_OUTLOOK_DAYS= +CALENDAT_EVENT_MAXIMUM= \ No newline at end of file diff --git a/.python-version b/.python-version index c47b345..3767b4b 100644 --- a/.python-version +++ b/.python-version @@ -1 +1 @@ -3.14.2 \ No newline at end of file +3.14 \ No newline at end of file diff --git a/Dockerfile b/Dockerfile index 7f92370..1ddbfd3 100644 --- a/Dockerfile +++ b/Dockerfile @@ -3,9 +3,8 @@ FROM ghcr.io/astral-sh/uv:python3.14-alpine COPY src /jumpstart WORKDIR /jumpstart -RUN addgroup -g 2000 jumpgroup -RUN adduser -S -u 1001 -G jumpgroup jumpstart +RUN addgroup -g 2000 jumpgroup && adduser -S -u 1001 -G jumpgroup jumpstart -RUN uv pip install --no-cache-dir -r requirements.txt --system +RUN uv pip install --no-cache-dir -r requirements.txt --system && rm requirements.txt -CMD ["echo", ":)"] \ No newline at end of file +CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "8000", "--log-config", "/jumpstart/logging_config.yaml"] diff --git a/README.md b/README.md index 7f9cea7..717ccff 100644 --- a/README.md +++ b/README.md @@ -11,6 +11,17 @@ This is a backend re-write of the previous jumpstart. See it live [here](https://jumpstart.csh.rit.edu)! +## Setup + +1. Setup .env + +```bash +cp .env.template .env +``` + +adjust .env config variables as needed. + + ## Install Uhhh diff --git a/docker-compose.yml b/docker-compose.yml index faf2981..ebf095b 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -6,4 +6,7 @@ services: container_name: Jumpstart ports: - "8000:8000" - \ No newline at end of file + environment: + - CALENDAR_URL=${CALENDAR_URL} + - CALENDAR_OUTLOOK_DAYS=${CALENDAR_OUTLOOK_DAYS} + - CALENDAT_EVENT_MAXIMUM=${CALENDAT_EVENT_MAXIMUM} \ No newline at end of file diff --git a/src/api/endpoints.py b/src/api/endpoints.py index 83036da..f3a86f2 100644 --- a/src/api/endpoints.py +++ b/src/api/endpoints.py @@ -7,7 +7,7 @@ from fastapi import APIRouter, Query from fastapi.responses import JSONResponse -from core import google, slack +from core import calendar, slack logger: Logger = getLogger(__name__) diff --git a/src/config.py b/src/config.py index 1163bd8..0a481b7 100644 --- a/src/config.py +++ b/src/config.py @@ -1,3 +1,10 @@ -CALENDAR_URL = "https://calendar.google.com/calendar/ical/rti648k5hv7j3ae3a3rum8potk%40group.calendar.google.com/public/basic.ics" -CALENDAR_OUTLOOK_DAYS = 7 #The amount of days to go through -CALENDAT_EVENT_MAXIMUM = 10 #The amount of events needed to be displayed +import os +from dotenv import load_dotenv + +load_dotenv() + +BASE_DIR: str = os.path.dirname(os.path.abspath(__file__)) + +CALENDAR_URL: str | None = os.getenv("CALENDAR_URL", None) +CALENDAR_OUTLOOK_DAYS: int = int(os.getenv("CALENDAR_OUTLOOK_DAYS", "7")) +CALENDAT_EVENT_MAXIMUM: int = int(os.getenv("CALENDAT_EVENT_MAXIMUM", "10")) diff --git a/src/core/calendar.py b/src/core/calendar.py index 61965a7..28618ef 100644 --- a/src/core/calendar.py +++ b/src/core/calendar.py @@ -82,8 +82,6 @@ def get_future_events_ical() -> list: report_timing("FINISHED") return returned_events -get_future_events_ical() - '''def get_future_events_google(): now = datetime.now() events_result = calendar_service.events().list( diff --git a/src/main.py b/src/main.py index 85d2c81..9898d11 100644 --- a/src/main.py +++ b/src/main.py @@ -5,15 +5,29 @@ V1 Authors: Beckett Jenen """ -from fastapi import FastAPI +import os + +from fastapi import FastAPI, Request from fastapi.staticfiles import StaticFiles from fastapi.templating import Jinja2Templates +from fastapi.responses import HTMLResponse + +from config import BASE_DIR from api import endpoints app: FastAPI = FastAPI() + +app.mount( + "/static", + StaticFiles(directory=os.path.join(BASE_DIR, "static")), + name="static" +) +templates = Jinja2Templates(directory=os.path.join(BASE_DIR, "templates")) + app.include_router(endpoints.router, prefix="/api") -app.mount("/static", StaticFiles(directory="static"), name="static") -templates: Jinja2Templates = Jinja2Templates(directory="templates") \ No newline at end of file +@app.get("/", response_class=HTMLResponse) +async def read_index(request: Request): + return templates.TemplateResponse("index.html", {"request": request}) \ No newline at end of file diff --git a/src/requirements.txt b/src/requirements.txt index 7906d5c..6511729 100644 --- a/src/requirements.txt +++ b/src/requirements.txt @@ -1,6 +1,10 @@ fastapi==0.135.1 uvicorn==0.41.0 logging==0.4.9.6 +jinja2==3.1.6 +requests==2.32.5 +dotenv==0.9.9 +pyyaml==6.0.3 google-api-python-client==2.191.0 icalendar==7.0.3 recurring-ical-events==3.8.1 diff --git a/src/templates/index.html b/src/templates/index.html index 96e24e8..9bcb9fa 100644 --- a/src/templates/index.html +++ b/src/templates/index.html @@ -8,7 +8,7 @@ - + @@ -83,7 +83,7 @@ $("body").css("background-image", "url(../static/css/darkmodeF.png)"); } - fetch('/calendar', { + fetch('/api/calendar', { method: 'GET', mode:'cors', dataType: 'json' @@ -120,7 +120,7 @@ } function mediumUpdate(){ - fetch('/showerthoughts', { + fetch('/api/showerthoughts', { method: 'GET', mode:'cors', dataType: 'json' @@ -131,7 +131,7 @@ }) .catch(err => console.log(err)) - fetch('/get-announcement', { + fetch('/api/announcement', { method: 'GET', mode:'cors', dataType: 'json' @@ -144,7 +144,7 @@ } function shortUpdate(){ - fetch('/get-harold', { + fetch('/api/harold', { method: 'GET', mode:'cors', dataType: 'json'