diff --git a/Dockerfile b/Dockerfile index accce95..36e221c 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"] +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/docker-compose.yml b/docker-compose.yml index 40dfeaf..6468237 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -20,4 +20,3 @@ services: - WIKIBOT_USER=${WIKIBOT_USER} - WIKIBOT_PASSWORD=${WIKIBOT_PASSWORD} - WIKI_CATEGORY=${WIKI_CATEGORY} - \ No newline at end of file diff --git a/src/api/endpoints.py b/src/api/endpoints.py index 8ece6b2..887d28d 100644 --- a/src/api/endpoints.py +++ b/src/api/endpoints.py @@ -60,23 +60,30 @@ async def slack_events(request: Request) -> JSONResponse: logger.info("Received Slack event!") 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") return JSONResponse({"challenge": body.get("challenge")}) event: dict = body.get("event", {}) cleaned_text: str = slack.clean_text(event.get("text", "")) if event.get("subtype", None) is not None: + logger.info("SLACK EVENT: Had no subtype, ignoring it") return JSONResponse({"status": "ignored"}) - if event not in WATCHED_CHANNELS: + 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) return JSONResponse({"status": "ignored"}) + logger.info("SLACK EVENT: Requesting upload via dm!") await slack.request_upload_via_dm(event.get("user", ""), cleaned_text) except Exception as e: logger.error(f"Error handling Slack event: {e}") diff --git a/src/core/wikithoughts.py b/src/core/wikithoughts.py index cfd10b8..4173fab 100644 --- a/src/core/wikithoughts.py +++ b/src/core/wikithoughts.py @@ -8,13 +8,17 @@ import random import re -CYCLE_DEBOUNCE_TIME = 12 # How long it takes to resfresh wiki titles +CYCLE_DEBOUNCE_TIME: int = 12 # How long it takes to resfresh wiki titles BATCH_SIZE: int = 50 # max titles per request +REAUTHENTICATE_ATTEMPTS: int = ( + 3 # The amount of times it will attempt to re-authenticare +) HEADERS: dict[str, str] = {"User-Agent": "JumpstartFetcher/1.0"} AUTH: tuple[str] = (WIKIBOT_USER, WIKIBOT_PASSWORD) client: httpx.AsyncClient = httpx.AsyncClient(headers=HEADERS, auth=AUTH) + logger: logging.Logger = logging.getLogger(__name__) bot_authenticated: bool = False @@ -39,7 +43,7 @@ RE_IMAGE: Pattern[str] = re.compile(r"\[\[Image:[^\]]*\]\]", re.IGNORECASE) RE_PAGE_TEXT: Pattern[str] = re.compile(r"\[\[[^\|\]]*\|([^\]]+)\]\]") RE_PAGE: Pattern[str] = re.compile(r"\[\[([^\]]+)\]\]") -RE_CSH: Pattern[str] = re.compile(r"\^\^([^\]]+)\^\^") +RE_CSH: Pattern[str] = re.compile(r"\^\^([^^]+)\^\^") RE_TEMPLATE: Pattern[str] = re.compile(r"\{\{.*?\}\}", re.DOTALL) RE_HTML: Pattern[str] = re.compile(r"<[^>]+>") RE_BOLD_ITALIC: Pattern[str] = re.compile(r"''+") @@ -89,6 +93,9 @@ def batch_iterable(iterable: list, size: int): Generator function for splitting up lists into smaller lists To be frank, found this online when researching about the MediaWiki API + Args: + iterable (list): The iterable to be split up for batches + size (int): the size of the batches Yields: A batch split by the requested size """ @@ -130,6 +137,7 @@ async def auth_bot() -> None: bot_authenticated = True logger.info("Bot was authenticated successfully!") else: + bot_authenticated = False logger.warning("Bot was unable to authenticate!") @@ -172,7 +180,7 @@ def needs_category_refresh(update_time: datetime) -> bool: update_time (datetime): The datetime to be compared against the cache Returns: - boolean: if the cache needs to be refreshed + bool: if the cache needs to be refreshed """ if not bot_authenticated: @@ -186,17 +194,16 @@ def needs_category_refresh(update_time: datetime) -> bool: ) -def process_category_page(response: httpx.Response) -> tuple[list[str], bool | str]: +def process_category_page(r_json: dict[str, str]) -> tuple[list[str], bool | str]: """ Processes a wikithoughts response into a list of title pages Args: - respone (httpx.Response): The response from the wiki to be processed + r_json (dict[str,str]): The JSON from the wiki to be processed Returns: tuple[list[str], bool | str]: The list of titles from the request, along with a possible continutation if needed """ - r_json: dict[str, str] = response.json() titles: list[str] = [] if "query" in r_json: for page in r_json["query"]["categorymembers"]: @@ -239,6 +246,9 @@ async def refresh_category_pages() -> list[str]: headers: dict[str, str] = headers_formatting() # This needs to loop due to mediawiki limitations + + failed_authentication_attempts: int = 0 + while True: response: httpx.Response = await client.get( WIKI_API, params=params, headers=headers @@ -250,7 +260,30 @@ async def refresh_category_pages() -> list[str]: elif response.status_code == 200: headers_formatting(etag, last_modifed) - added, repeat_req = process_category_page(response=response) + r_json: dict[str, str] = response.json() + + if "error" in r_json and r_json["error"].get("code") in ( + "readapidenied", + "notloggedin", + ): + if failed_authentication_attempts > REAUTHENTICATE_ATTEMPTS: + logger.warning( + "Reauthenticating the wikithought bot failed, sending empty response" + ) + return [] + + logger.info(f"Both was unauthenticated, attempting to reauthenticate!") + await auth_bot() + if not (bot_authenticated): + logger.warning( + "Failed to reauthenticate the bot! Attempt: " + + failed_authentication_attempts + ) + + failed_authentication_attempts += 1 + continue + + added, repeat_req = process_category_page(r_json) titles += added if repeat_req not in (None, False, ""): diff --git a/src/static/css/style.css b/src/static/css/style.css index f9e702e..47b7d0a 100644 --- a/src/static/css/style.css +++ b/src/static/css/style.css @@ -1,5 +1,12 @@ body{ background-image: url('/static/img/darkmodeF.png'); + overflow: hidden; +} + +.scroll-container::-webkit-scrollbar { + display: none; + width: 0; /* Ensures no width is reserved for the scrollbar */ + height: 0; /* Ensures no height is reserved for the horizontal scrollbar */ } .panel-primary{ @@ -45,6 +52,7 @@ body{ border: 8px #34495e solid; border-radius: 10px; background-color: #34495e; + margin-bottom: 1.5%; } .datadog{ @@ -56,7 +64,7 @@ body{ width: 760px; height: 580px; float: right; - margin-bottom: 3%; + margin-bottom: 0.5%; } .announcements{ @@ -64,7 +72,7 @@ body{ width: 50%; padding-top: 22%; padding-left: 1%; - min-height: 840px; + min-height: 670px; overflow: hidden; word-wrap: break-word; } diff --git a/src/static/js/main.js b/src/static/js/main.js index d45fa7e..92f0f18 100644 --- a/src/static/js/main.js +++ b/src/static/js/main.js @@ -83,4 +83,4 @@ longUpdate(); setInterval(longUpdate, 60000); setInterval(mediumUpdate, 22000); -setInterval(() => { if (window.__weatherwidget_init) window.__weatherwidget_init(); }, 1800000); \ No newline at end of file +setInterval(() => { if (globalThis.__weatherwidget_init) globalThis.__weatherwidget_init(); }, 1800000); \ No newline at end of file diff --git a/src/templates/index.html b/src/templates/index.html index ca264d1..1c48aa3 100644 --- a/src/templates/index.html +++ b/src/templates/index.html @@ -14,7 +14,7 @@