diff --git a/.github/workflows/sonarqube.yml b/.github/workflows/sonarqube.yml
index 52e4245..4a88f0a 100644
--- a/.github/workflows/sonarqube.yml
+++ b/.github/workflows/sonarqube.yml
@@ -20,9 +20,19 @@ jobs:
- name: Set up Python
uses: actions/setup-python@v4
with:
- python-version: '3.13'
+ python-version: '3.14'
+
+ - name: Install dependencies
+ run: |
+ pip install uv
+ uv pip install -r src/requirements.txt --system
+ uv pip install -r tests/requirements.txt --system
+
+ - name: Run tests with coverage
+ run: |
+ pytest -v
- uses: SonarSource/sonarqube-scan-action@v6
env:
SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
- SONAR_HOST_URL: ${{ secrets.SONAR_HOST_URL }}
\ No newline at end of file
+ SONAR_HOST_URL: ${{ secrets.SONAR_HOST_URL }}
diff --git a/.gitignore b/.gitignore
index cac8df1..4e1b3ca 100644
--- a/.gitignore
+++ b/.gitignore
@@ -185,9 +185,9 @@ cython_debug/
.abstra/
# Visual Studio Code
-# Visual Studio Code specific template is maintained in a separate VisualStudioCode.gitignore
+# Visual Studio Code specific template is maintained in a separate VisualStudioCode.gitignore
# that can be found at https://github.com/github/gitignore/blob/main/Global/VisualStudioCode.gitignore
-# and can be added to the global gitignore or merged into this file. However, if you prefer,
+# and can be added to the global gitignore or merged into this file. However, if you prefer,
# you could uncomment the following to ignore the entire vscode folder
# .vscode/
diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml
new file mode 100644
index 0000000..81e2bac
--- /dev/null
+++ b/.pre-commit-config.yaml
@@ -0,0 +1,15 @@
+repos:
+ - repo: https://github.com/astral-sh/ruff-pre-commit
+ rev: v0.15.6
+ hooks:
+ - id: ruff
+ args: [--fix]
+ - id: ruff-format
+
+ - repo: https://github.com/pre-commit/pre-commit-hooks
+ rev: v6.0.0
+ hooks:
+ - id: trailing-whitespace
+ - id: end-of-file-fixer
+ - id: check-yaml
+ - id: check-json
diff --git a/.python-version b/.python-version
index 3767b4b..6324d40 100644
--- a/.python-version
+++ b/.python-version
@@ -1 +1 @@
-3.14
\ No newline at end of file
+3.14
diff --git a/Dockerfile b/Dockerfile
index 36e221c..c1a8241 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -21,4 +21,4 @@ RUN addgroup -g 2000 jumpgroup && adduser -S -u 1001 -G jumpgroup jumpstart && \
USER jumpstart
-CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "8000", "--log-config", "/jumpstart/logging_config.yaml", "--proxy-headers","--forwarded-allow-ips","*"]
+CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "8000", "--log-config", "/jumpstart/logging_config.yaml", "--proxy-headers", "--forwarded-allow-ips", "*"]
diff --git a/README.md b/README.md
index 21ec2b2..c8347b6 100644
--- a/README.md
+++ b/README.md
@@ -11,7 +11,7 @@ All information displayed has been authorized to been shown.
Documentation for the project can be found be appended /docs to the url
All HTML requests that are sent in the project can be seen by appending /swag
-This project uses Python, [FastAPI](https://fastapi.tiangolo.com/), HTML/CSS, and Javascript.
+This project uses Python, [FastAPI](https://fastapi.tiangolo.com/), HTML/CSS, and Javascript.
See it live [here](http://jumpstart-cubed.cs.house/)!
## Installing
@@ -46,3 +46,28 @@ Jumpstart also has support for Docker Compose, a extended version of docker that
docker compose up
```
+## Development
+
+### Setup
+1. Install uv on your system if not already on it (this just makes it easy)
+2. Run: `uv venv .venv`
+3. Activate the virtual environment
+ * Bash: `source .venv/bin/activate`
+ * Fish: `source .venv/bin/activate.fish`
+ * Windows: `.venv\Scripts\activate`
+ * Other: Good luck!
+4. Run:
+ * `uv pip install -r dev-requirements.txt`
+ * `uv pip install -r src/requirements.txt`
+ * `uv pip install -r tests/requirements,txt`
+ * `uv pip install -r docs/requirements.txt`
+5. Run: `pre-commit install`
+6. You're all set!
+
+### Testing
+
+We're using the pytest framework to create tests. A good minimum coverage requirement is about <=90%.
+
+To run the tests just run: `pytest`
+
+`coverage.xml` and `htmlcov` should be generated. `coverage.xml` is used for Sonarqube, while `htmlcov` is a local html view into code coverage. The easiest way to view the coverage site is to enter the directory and run: `python -m http.server` and visit the site!
diff --git a/dev-requirements.txt b/dev-requirements.txt
new file mode 100644
index 0000000..89303c8
--- /dev/null
+++ b/dev-requirements.txt
@@ -0,0 +1,2 @@
+pre-commit==4.5.1
+ruff==0.15.6
diff --git a/docs/core/CSH Calendar.md b/docs/core/csh_calendar.md
similarity index 90%
rename from docs/core/CSH Calendar.md
rename to docs/core/csh_calendar.md
index 986b1d9..c9e63e0 100644
--- a/docs/core/CSH Calendar.md
+++ b/docs/core/csh_calendar.md
@@ -1,5 +1,3 @@
-## Overview
-
This core component is used for all the fetching, formatting and structuring for the CSH calendar portion of Jumpstart.
---
@@ -11,4 +9,4 @@ During a fetch of the calendar, if any other clients attempt to connect, they wi
---
### Documentation Overview
-::: core.cshcalendar
\ No newline at end of file
+::: core.cshcalendar
diff --git a/docs/core/Slack.md b/docs/core/slack.md
similarity index 88%
rename from docs/core/Slack.md
rename to docs/core/slack.md
index f2f2e20..bb00ab4 100644
--- a/docs/core/Slack.md
+++ b/docs/core/slack.md
@@ -1,8 +1,6 @@
-## Overview
-
This component handles the Slack Bot and it's related functions. Such as responding to announcments, requesting to upload to Jumpstart, and the other handles with Slack.
---
### Documentation Overview
-::: core.slack
\ No newline at end of file
+::: core.slack
diff --git a/docs/core/Wiki-thoughts.md b/docs/core/wikithoughts.md
similarity index 97%
rename from docs/core/Wiki-thoughts.md
rename to docs/core/wikithoughts.md
index 8842c2f..b38acf5 100644
--- a/docs/core/Wiki-thoughts.md
+++ b/docs/core/wikithoughts.md
@@ -11,4 +11,4 @@ This component handles the fetching, caching and cycling of the CSH Wikithoughts
---
### Documentation Overview
-::: core.wikithoughts
\ No newline at end of file
+::: core.wikithoughts
diff --git a/docs/endpoints/announcements.md b/docs/endpoints/announcements.md
index e37ec0d..c9c7e35 100644
--- a/docs/endpoints/announcements.md
+++ b/docs/endpoints/announcements.md
@@ -1,3 +1,3 @@
-::: api.endpoints.get_announcement
\ No newline at end of file
+::: api.endpoints.get_announcement
diff --git a/docs/endpoints/calendar_endpoint.md b/docs/endpoints/csh_calendar.md
similarity index 95%
rename from docs/endpoints/calendar_endpoint.md
rename to docs/endpoints/csh_calendar.md
index 34704cc..e9d8ff0 100644
--- a/docs/endpoints/calendar_endpoint.md
+++ b/docs/endpoints/csh_calendar.md
@@ -25,4 +25,4 @@ Example error response:
```
### Endpoint Overview
-::: api.endpoints.get_calendar
\ No newline at end of file
+::: api.endpoints.get_calendar
diff --git a/docs/endpoints/slack.md b/docs/endpoints/slack.md
new file mode 100644
index 0000000..aa6a463
--- /dev/null
+++ b/docs/endpoints/slack.md
@@ -0,0 +1,4 @@
+
+::: api.endpoints.get_announcement
+::: api.endpoints.slack_events
+::: api.endpoints.message_actions
\ No newline at end of file
diff --git a/docs/endpoints/slack_bot.md b/docs/endpoints/slack_bot.md
index 5766bbc..063cbf9 100644
--- a/docs/endpoints/slack_bot.md
+++ b/docs/endpoints/slack_bot.md
@@ -1,4 +1,4 @@
::: api.endpoints.slack_events
-::: api.endpoints.message_actions
\ No newline at end of file
+::: api.endpoints.message_actions
diff --git a/docs/endpoints/wikithoughts.md b/docs/endpoints/wikithoughts.md
index fb48abd..f6f46b6 100644
--- a/docs/endpoints/wikithoughts.md
+++ b/docs/endpoints/wikithoughts.md
@@ -18,4 +18,4 @@ In the event of an Error, the API will log an error and display default text
}
```
-::: api.endpoints.wikithought
\ No newline at end of file
+::: api.endpoints.wikithought
diff --git a/docs/getting-started/getting-started.md b/docs/getting-started/getting-started.md
index 4cd1770..0805d77 100644
--- a/docs/getting-started/getting-started.md
+++ b/docs/getting-started/getting-started.md
@@ -2,7 +2,7 @@
## Installing
1. Clone and cd into the repo: git clone https://github.com/WeatherGod3218/jumpstartV2
>> Make another branch if you are working on a large PR
-2.
+2.
## Setup
1. Make sure you have docker installed
@@ -10,7 +10,7 @@
2. Copy the .env.template file, rename it to .env and place it in the root folder
3. Ask an RTP for jumpstart secrets, add them to the .env accordingly
-## Run
+## Run
1. Build the docker file
```
docker build -t Jumpstart .
@@ -23,4 +23,4 @@
### Alternatively, you can run the docker compose file as well
```
docker compose up
-```
\ No newline at end of file
+```
diff --git a/docs/getting-started/setup.md b/docs/getting-started/setup.md
deleted file mode 100644
index e69de29..0000000
diff --git a/docs/index.md b/docs/index.md
index e32af29..64481aa 100644
--- a/docs/index.md
+++ b/docs/index.md
@@ -5,10 +5,10 @@

-A graphical interface that displays information in the elevator lobby of Computer Science House.
+A graphical interface that displays information in the elevator lobby of Computer Science House.
All information displayed has been authorized to been shown.
-This project uses Python, [FastAPI](https://fastapi.tiangolo.com/), HTML/CSS, and Javascript.
+This project uses Python, [FastAPI](https://fastapi.tiangolo.com/), HTML/CSS, and Javascript.
See it live [here](http://jumpstart-squared.cs.house/)!
The application has multiple features:
@@ -23,7 +23,7 @@ The application has multiple features:
5. An informational that displays real-time status information from CSH’s server room.
6. Calendar module that uses the Python ICalendar to display a countdown to the next 10 events from the CSH calendar.
-
+
7. Displays a daily forecast.
### AUTHORS:
diff --git a/docs/requirements.txt b/docs/requirements.txt
index 0eff80d..9044f17 100644
--- a/docs/requirements.txt
+++ b/docs/requirements.txt
@@ -3,4 +3,4 @@ mkdocstrings
mkdocstrings-python
mkdocs-minify-plugin
mkdocs-git-revision-date-localized-plugin
-pymdown-extensions
\ No newline at end of file
+pymdown-extensions
diff --git a/docs/themes/how_to.md b/docs/themes/how_to.md
new file mode 100644
index 0000000..a3903f3
--- /dev/null
+++ b/docs/themes/how_to.md
@@ -0,0 +1,22 @@
+Jumpstart has many different themes displayed on the website, this is a step by step process on how to implement your own!
+
+**Any images that need to be added should be put in src/static/img**
+
+### Adding Background
+
+1. Go to the file: **src/static/js/main.js**
+2. In the function long update, figure out the day, month, and hour of your theme.
+ - hour is in 24H format
+3. Add it into the if statement (please change this in the future)
+ - Make sure it follows the bgImage = "url(../static/img/{**YOUR FILE HERE**})"
+
+### Adding CSS Theme
+1. Go to the file **src/static/css/style.css**
+2. Add a new class for the colors **MAKE SURE IT STARTS WITH {theme-}!!!**
+3. Change the colors in this new class
+4. Repeat the steps in the "Adding Background"
+5. Add a new index into "allThemes" with your css theme, along with any changes to weatherwidget or datadog
+6. change the themeToLoad in the if statement to load your new index
+
+
+
diff --git a/docs/themes/overview.md b/docs/themes/overview.md
new file mode 100644
index 0000000..8cf5595
--- /dev/null
+++ b/docs/themes/overview.md
@@ -0,0 +1,30 @@
+Jumpstart has many different themes displayed on the website. Ranging from the light - dark mode, to full background and color shifts fo events.
+
+### All Themes
+- Light Mode
+ - Default theme between 9 AM and 6 PM
+- Dark Mode
+ - Default theme between 6 PM and 9 AM
+- Valentine's Day
+ - Feburary 12th, 13th and 14th
+ - Changes title to "Constantly Smooching House"
+ - Adds decorative hearts around the logo
+- BANG!
+ - March 13th
+ - Changes title to "BANG! Science"
+ - Gives an orange gradient to the background
+- CSH 50th Anniversary
+ - April 9th, 10th, 11th, and 12
+ - Replaces title with the CSH 50th Anniversary logo
+ - Replaces color scheme with a Golden / Black theme
+- Halloween
+ - October 29th, 30th, and 31st
+ - Changes title to "Computer Spooky House"
+ - Logo is given orange and purple colors
+- Duck!
+ - November 2nd
+ - Duck
+- Winter
+ - November and December
+ - Changes title to "Christmas Season"
+ - Gives a red and green logo with a bright blue background
diff --git a/mkdocs.yml b/mkdocs.yml
index acafb5b..1b7673e 100644
--- a/mkdocs.yml
+++ b/mkdocs.yml
@@ -38,15 +38,17 @@ use_directory_urls: false
nav:
- Home: index.md
- Getting Started: getting-started/getting-started.md
- - Backend:
- - Wikithoughts: core/Wiki-thoughts.md
- - Calendar: core/CSH Calendar.md
- - Slack: core/Slack.md
+ - Backend:
+ - Calendar: core/csh_calendar.md
+ - Slack: core/slack.md
+ - Wikithoughts: core/wikithoughts.md
- Endpoints:
- - Calendar: endpoints/calendar_endpoint.md
- - Announcements: endpoints/announcements.md
- - Slack Bot: endpoints/slack_bot.md
- - Wiki Thoughts: endpoints/wikithoughts.md
+ - Calendar: endpoints/csh_calendar.md
+ - Slack: endpoints/slack.md
+ - Wikithoughts: endpoints/wikithoughts.md
+ - Themes:
+ - Themes: themes/overview.md
+ - Adding Your Own: themes/how_to.md
plugins:
- search
diff --git a/pytest.ini b/pytest.ini
new file mode 100644
index 0000000..c152b9f
--- /dev/null
+++ b/pytest.ini
@@ -0,0 +1,4 @@
+[pytest]
+addopts = -ra
+python_files = test_*.py
+pythonpath = src
diff --git a/ruff.toml b/ruff.toml
index d141539..aa66445 100644
--- a/ruff.toml
+++ b/ruff.toml
@@ -10,4 +10,4 @@ line-length = 88
[format]
quote-style = "double"
indent-style = "tab"
-skip-magic-trailing-comma = false
\ No newline at end of file
+skip-magic-trailing-comma = false
diff --git a/sonar-project.properties b/sonar-project.properties
index 995bea0..e2bc34b 100644
--- a/sonar-project.properties
+++ b/sonar-project.properties
@@ -1 +1,3 @@
-sonar.projectKey=jumpstart-v2
\ No newline at end of file
+sonar.projectKey=jumpstart-v2
+sonar.python.coverage.reportPaths=coverage.xml
+sonar.coverage.exclusions=**/tests/**,**/*test*.py,**/test_*.py
diff --git a/src/__init__.py b/src/__init__.py
index 8b13789..e69de29 100644
--- a/src/__init__.py
+++ b/src/__init__.py
@@ -1 +0,0 @@
-
diff --git a/src/api/endpoints.py b/src/api/endpoints.py
index 887d28d..b5985a6 100644
--- a/src/api/endpoints.py
+++ b/src/api/endpoints.py
@@ -2,8 +2,6 @@
import json
import httpx
-import random
-import textwrap
from fastapi import APIRouter, Request, Form
from fastapi.responses import JSONResponse
@@ -14,8 +12,11 @@
logger: Logger = getLogger(__name__)
router: APIRouter = APIRouter()
+ACCEPT_MESSAGE: str = "Posting right now :^)"
+DENY_MESSAGE: str = "Okay :( maybe next time"
-@router.get("/api/calendar")
+
+@router.get("/calendar")
async def get_calendar() -> JSONResponse:
"""
Returns calendar data.
@@ -24,15 +25,21 @@ async def get_calendar() -> JSONResponse:
JSONResponse: A JSON response containing the calendar data.
"""
- get_future_events_ical: tuple[
- cshcalendar.CalendarInfo
- ] = await cshcalendar.get_future_events()
- formatted_events: dict = cshcalendar.format_events(get_future_events_ical)
+ events: list[dict[str, str]] = []
+
+ try:
+ get_future_events_ical: list[
+ cshcalendar.CalendarInfo
+ ] = await cshcalendar.get_future_events()
+ events = cshcalendar.format_events(get_future_events_ical)
+ except Exception as e:
+ logger.error(f"Error fetching calendar events: {e}")
+ return JSONResponse({"status": "error", "message": str(e)}, status_code=500)
- return JSONResponse(formatted_events)
+ return JSONResponse({"data": events})
-@router.get("/api/announcement")
+@router.get("/announcement")
def get_announcement() -> JSONResponse:
"""
Returns announcement data.
@@ -41,7 +48,7 @@ def get_announcement() -> JSONResponse:
JSONResponse: A JSON response containing the announcement data.
"""
- return JSONResponse({"data": slack.get_announcement()})
+ return JSONResponse(slack.get_announcement())
@router.post("/slack/events")
@@ -57,18 +64,17 @@ async def slack_events(request: Request) -> JSONResponse:
"""
try:
- logger.info("Received Slack event!")
+ logger.debug(f"Received Slack event: {await request.body()}")
body: dict = await request.json()
- logger.info(body)
- logger.info("\n")
+
if request.headers.get("content-type") == "application/json":
if body.get("type") == "url_verification":
logger.info("SLACK EVENT: Was a challenge!")
return JSONResponse({"challenge": body.get("challenge")})
if not body:
- logger.info("SLACK EVENT: Was a challenge, with no body")
+ logger.debug("SLACK EVENT: Was a challenge, with no body")
return JSONResponse({"challenge": body.get("challenge")})
event: dict = body.get("event", {})
@@ -79,8 +85,9 @@ async def slack_events(request: Request) -> JSONResponse:
return JSONResponse({"status": "ignored"})
if event.get("channel", None) not in WATCHED_CHANNELS:
- logger.info("SLACK EVENT: Message was not in a Watched Channel, returning!")
- logger.info(WATCHED_CHANNELS)
+ logger.info(
+ "SLACK EVENT: Message was not in a Watched Channel, ignoring it"
+ )
return JSONResponse({"status": "ignored"})
logger.info("SLACK EVENT: Requesting upload via dm!")
@@ -112,25 +119,34 @@ async def message_actions(payload: str = Form(...)) -> JSONResponse:
return JSONResponse({}, status_code=200)
if slack.convert_user_response_to_bool(form_json):
- logger.info("User approved the announcement!")
- logger.info(f"{form_json}\n\n")
+ logger.info(
+ "User approved the announcement, Adding it to the announcement list!"
+ )
+
message_object: dict[str, dict] = json.loads(
form_json.get("actions", [{}])[0].get("value", '{text:""}')
).get("text", None)
- logger.info(f"Display Object {message_object}")
- slack.add_announcement(message_object)
+
+ user_id = form_json.get("user", {}).get("id")
+
+ username: str = await slack.get_username(user_id=user_id)
+ username = username[:40]
+
+ slack.add_announcement(message_object, username)
if response_url:
- await httpx.post(
- response_url,
- json={"text": "Posting right now :^)", "replace_original": True},
- )
+ async with httpx.AsyncClient() as client:
+ await client.post(
+ response_url,
+ json={"text": ACCEPT_MESSAGE, "replace_original": True},
+ )
else:
if response_url:
- await httpx.post(
- response_url,
- json={"text": "Okay :( maybe next time", "replace_original": True},
- )
+ async with httpx.AsyncClient() as client:
+ await client.post(
+ response_url,
+ json={"text": DENY_MESSAGE, "replace_original": True},
+ )
except Exception as e:
logger.error(f"Error in message_actions: {e}")
@@ -139,7 +155,7 @@ async def message_actions(payload: str = Form(...)) -> JSONResponse:
return JSONResponse({"status": "success"}, status_code=200)
-@router.get("/api/wikithought")
+@router.get("/wikithought")
async def wikithought() -> JSONResponse:
"""
Returns a random CSH wiki thought from the MediaWiki API.
@@ -147,5 +163,13 @@ async def wikithought() -> JSONResponse:
Returns:
JSONResponse: A JSON response containing a random Wiki thought.
"""
- returned_page_data: dict[str, str] = await wikithoughts.get_next_display()
- return JSONResponse(returned_page_data)
+
+ page_data: dict | None = None
+
+ try:
+ page_data = await wikithoughts.get_next_display()
+ except Exception as e:
+ logger.error(f"Error fetching wiki thought: {e}")
+ return JSONResponse({"status": "error", "message": str(e)}, status_code=500)
+
+ return JSONResponse(page_data)
diff --git a/src/config.py b/src/config.py
index b641377..3e3eb81 100644
--- a/src/config.py
+++ b/src/config.py
@@ -1,30 +1,59 @@
import os
import json
+import logging
from dotenv import load_dotenv
-
load_dotenv()
+logger: logging.Logger = logging.getLogger(__name__)
+
+
+def _get_env_variable(name: str, default: str | None = None) -> str | None:
+ """
+ Retrieves an environment variable, with an optional default value.
+
+ Args:
+ name (str): The name of the environment variable to retrieve.
+ default (str | None): An optional default value to return if the environment variable is not set.
+
+ Returns:
+ str | None: The value of the environment variable, or the default value if it is not set.
+ """
+
+ try:
+ value: str = os.getenv(name, default)
+
+ if value in (None, ""):
+ logger.warning(
+ f"Environment variable '{name}' is not set, using default value: '{default if default is not None else 'None'}'"
+ )
+ return default
+
+ return value
+ except Exception as e:
+ logger.error(f"Error retrieving environment variable '{name}': {e}")
+ return default
+
+
BASE_DIR: str = os.path.dirname(os.path.abspath(__file__))
-SLACK_API_TOKEN: str | None = os.getenv("SLACK_API_TOKEN", None)
+SLACK_API_TOKEN: str | None = _get_env_variable("SLACK_API_TOKEN", None)
SLACK_JUMPSTART_MESSAGE: str = "Would you like to post this message to Jumpstart?"
-WATCHED_CHANNELS: tuple[str] = tuple(os.getenv("WATCHED_CHANNELS", "").split(","))
+WATCHED_CHANNELS: tuple[str] = tuple(
+ _get_env_variable("WATCHED_CHANNELS", "").split(",")
+)
SLACK_DM_TEMPLATE: dict | None = None
-CALENDAR_URL: str | None = os.getenv("CALENDAR_URL", None)
-CALENDAR_OUTLOOK_DAYS: int = int(os.getenv("CALENDAR_OUTLOOK_DAYS", "7"))
-CALENDAR_EVENT_MAXIMUM: int = int(os.getenv("CALENDAR_EVENT_MAXIMUM", "10"))
-CALENDAR_TIMEZONE: str = os.getenv("CALENDAR_TIMEZONE", "America/New_York")
-CALENDAR_CACHE_REFRESH: int = int(os.getenv("CALENDAR_CACHE_REFRESH", "10"))
-
-WIKI_API: str | None = os.getenv("WIKI_API", None)
-WIKIBOT_USER: str | None = os.getenv("WIKIBOT_USER", None)
-WIKIBOT_PASSWORD: str | None = os.getenv("WIKIBOT_PASSWORD", None)
-WIKI_CATEGORY: str = os.getenv("WIKI_CATEGORY", "JobAdvice")
+CALENDAR_URL: str | None = _get_env_variable("CALENDAR_URL", None)
+CALENDAR_OUTLOOK_DAYS: int = int(_get_env_variable("CALENDAR_OUTLOOK_DAYS", "7"))
+CALENDAR_EVENT_MAXIMUM: int = int(_get_env_variable("CALENDAR_EVENT_MAXIMUM", "10"))
+CALENDAR_TIMEZONE: str = _get_env_variable("CALENDAR_TIMEZONE", "America/New_York")
+CALENDAR_CACHE_REFRESH: int = int(_get_env_variable("CALENDAR_CACHE_REFRESH", "10"))
-if SLACK_API_TOKEN in (None, ""):
- raise ValueError("Missing SLACK_API_TOKEN")
+WIKI_API: str | None = _get_env_variable("WIKI_API", None)
+WIKIBOT_USER: str | None = _get_env_variable("WIKIBOT_USER", None)
+WIKIBOT_PASSWORD: str | None = _get_env_variable("WIKIBOT_PASSWORD", None)
+WIKI_CATEGORY: str = _get_env_variable("WIKI_CATEGORY", "JobAdvice")
with open(os.path.join(BASE_DIR, "static", "slack", "dm_request_template.json")) as f:
SLACK_DM_TEMPLATE = json.load(f)
diff --git a/src/core/cshcalendar.py b/src/core/cshcalendar.py
index 3434ff8..01b7c34 100644
--- a/src/core/cshcalendar.py
+++ b/src/core/cshcalendar.py
@@ -54,7 +54,7 @@
(WEEK - DAY): f"In %{DAY}% Days",
}
-BORDER_STRING: str = "
"
+BORDER_STRING: str = ''
TIME_PATTERN = re.compile(r"%([^%]+)%")
@@ -89,6 +89,7 @@ def ceil_division(num: int, den: int) -> int:
Returns:
int: the result of the operation
"""
+
return (num + den - 1) // den
@@ -113,6 +114,7 @@ def repl(match: re.Match[str]) -> str:
Returns:
str: The newly formatted string
"""
+
num = int(match.group(1))
return str(round(time_before_event / num))
@@ -134,30 +136,7 @@ def repl(match: re.Match[str]) -> str:
return TIME_PATTERN.sub(repl, unformatted_string)
-
-def calendar_to_html(seg_header: str, seg_content: str) -> str:
- """
- Formats a header and content into the HTML for the calendar front end
-
- Args:
- seg_header (str): The header of the calendar segment
- seg_content (str): The content in the calendar segment
-
- Returns:
- str:
- """
- ret_string: str = (
- """