From 1729332373fb259b075ba31050e22eb5e90d961d Mon Sep 17 00:00:00 2001 From: chiko Date: Tue, 21 Oct 2025 23:34:50 +0200 Subject: [PATCH] removed Python and the Python Script, added the apprise-api docker container to the Docker-compose to send notificaiton --- .gitignore | 1 + Crontab | 2 - Dockerfile | 42 ++++++++++++--------- docker-compose.yml | 9 +++-- docker/Crontab | 2 + docker/cron-bun-log | 8 ++++ entrypoint.sh | 6 --- requirements.txt | 2 - src/app.ts | 79 +++++++++++++++------------------------ src/sendNotification.ts | 40 ++++++++++++-------- src/sendNotificationPy.ts | 16 ++++++++ src/util.ts | 12 ++++++ 12 files changed, 125 insertions(+), 94 deletions(-) delete mode 100644 Crontab create mode 100644 docker/Crontab create mode 100644 docker/cron-bun-log delete mode 100644 entrypoint.sh delete mode 100644 requirements.txt create mode 100644 src/sendNotificationPy.ts diff --git a/.gitignore b/.gitignore index 398a986..5d4c927 100644 --- a/.gitignore +++ b/.gitignore @@ -37,3 +37,4 @@ report.[0-9]_.[0-9]_.[0-9]_.[0-9]_.json *.db *.sqlite +data \ No newline at end of file diff --git a/Crontab b/Crontab deleted file mode 100644 index c1dd39e..0000000 --- a/Crontab +++ /dev/null @@ -1,2 +0,0 @@ -1 * * * * bun run ./src/app.ts --today > /dev/null 2>&1 -0 * * * * bun run ./src/app.ts > /dev/null 2>&1 \ No newline at end of file diff --git a/Dockerfile b/Dockerfile index 19ef720..d23c855 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,9 +1,24 @@ FROM debian:12 AS base +ARG BUILD_DATE +ARG VERSION +LABEL build_version="77th_eventcalendarntfy ${VERSION}, Build-date:- ${BUILD_DATE}" +LABEL maintainer="chiko " WORKDIR /opt/app -RUN apt-get update && \ - # apt-get install -y curl unzip cron ca-certificates python3 python3-pip && \ - apt-get install -y curl unzip cron ca-certificates python3 python3-pip && \ - rm -rf /var/lib/apt/lists/* +RUN set -eux && \ + echo "Updating APT" && \ + apt-get update -y -qq && \ + apt-get upgrade -y -qq && \ + echo "Installing tools" && \ + apt-get install -y -qq \ + curl unzip cron ca-certificates logrotate && \ + echo "Cleaning up" && \ + apt-get --yes autoremove --purge && \ + apt-get clean --yes && \ + rm --recursive --force --verbose /var/lib/apt/lists/* && \ + rm --recursive --force --verbose /tmp/* && \ + rm --recursive --force --verbose /var/tmp/* && \ + rm --recursive --force --verbose /var/cache/apt/archives/* && \ + truncate --size 0 /var/log/*log # install BunJs RUN curl -fsSL https://bun.com/install | bash ENV PATH="/root/.bun/bin:$PATH" @@ -19,33 +34,26 @@ RUN mkdir -p /temp/prod COPY package.json bun.lock /temp/prod/ RUN cd /temp/prod && bun install --frozen-lockfile --production -# and install python dependencies -# COPY ./requirements.txt . -# RUN python3 -m pip install --break-system-packages -r requirements.txt -# RUN python3 -m pip install -U python-dotenv +COPY ./docker/Crontab /etc/cron.d/ +RUN chmod 0644 /etc/cron.d/Crontab +COPY ./docker/cron-bun-log /etc/logrotate.d/ +RUN mkdir /var/log/cron && touch /var/log/cron.log # copy node_modules from temp directory # then copy all (non-ignored) project files into the image FROM base AS prerelease COPY --from=install /temp/dev/node_modules node_modules COPY . ./ - # [optional] tests & build ENV NODE_ENV=production # copy production dependencies and source code into final image FROM base AS release -WORKDIR /opt/app COPY --from=install /temp/prod/node_modules node_modules -COPY --from=prerelease /opt/app/src/app.ts . COPY --from=prerelease /opt/app/package.json . #COPY --from=prerelease .entrypoint.sh . -COPY Crontab /etc/cron.d/ -RUN chmod 0644 /etc/cron.d/Crontab COPY . ./ -# USER bun -RUN touch /var/log/cron.log -# RUN chmod +x entrypoint.sh -# ENTRYPOINT ["./entrypoint.sh"] +RUN mkdir /var/log/cron && touch /var/log/cron.log VOLUME /opt/app/data/db +# VOLUME /var/log/cron CMD bun run ./src/app.ts --today && cron && tail -f /var/log/cron.log \ No newline at end of file diff --git a/docker-compose.yml b/docker-compose.yml index a0fca37..ebcd829 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -3,6 +3,7 @@ services: build: . volumes: - ./data/db:/opt/app/data/db + - ./data/app/log:/var/log env_file: - path: ./.env required: true @@ -23,12 +24,12 @@ services: - ./data/apprise/config:/config - ./data/apprise/plugin:/plugin - ./data/apprise/attach:/attach - ports: - - 8000:8000 + # ports: + #- 8880:8000 healthcheck: test: ["CMD", "curl", "-f", "http://localhost:8000/status"] - interval: 30s - timeout: 10s + interval: 10s + timeout: 5s retries: 5 # networks: # default: diff --git a/docker/Crontab b/docker/Crontab new file mode 100644 index 0000000..0eee489 --- /dev/null +++ b/docker/Crontab @@ -0,0 +1,2 @@ +8 * * * * bun run ./src/app.ts --today > /var/log/cron.log 2>&1 +*/15 * * * * bun run ./src/app.ts > /var/log/cron.log 2>&1 \ No newline at end of file diff --git a/docker/cron-bun-log b/docker/cron-bun-log new file mode 100644 index 0000000..a5f9fb4 --- /dev/null +++ b/docker/cron-bun-log @@ -0,0 +1,8 @@ +/var/log/cron.log { + daily + rotate 7 + compress + missingok + notifempty + copytruncate +} \ No newline at end of file diff --git a/entrypoint.sh b/entrypoint.sh deleted file mode 100644 index f3fc625..0000000 --- a/entrypoint.sh +++ /dev/null @@ -1,6 +0,0 @@ -#!/bin/bash -crontab -l > mycron -echo "0 8 * * * bun run ./src/app.ts --today > /dev/null 2>&1" >> mycron -echo "0 * * * * bun run ./src/app.ts > /dev/null 2>&1" >> mycron -crontab mycron -rm mycron \ No newline at end of file diff --git a/requirements.txt b/requirements.txt deleted file mode 100644 index b4d8f3e..0000000 --- a/requirements.txt +++ /dev/null @@ -1,2 +0,0 @@ -apprise -python-dotenv \ No newline at end of file diff --git a/src/app.ts b/src/app.ts index 86f295e..723d77b 100644 --- a/src/app.ts +++ b/src/app.ts @@ -1,31 +1,25 @@ import { TEventType } from "./component/event/event.types"; import { db } from "./sql"; import { Event, type TEventEntityNew, type TGetEventsOptions } from "./component/event/events"; +import { createPlaceholders, getTsNow, pad_l2 } from "./util"; import { sendNotification } from "./sendNotification"; -import { createPlaceholders, pad_l2 } from "./util"; const argv = require('minimist')(process.argv.slice(2)); -console.dir(argv) +console.log("App started"); +console.dir({argv}) -// const TS_TODAY = new Date(); - -function getTsNow() { - const now = new Date(); - const rtn = { - year: now.getFullYear(), - month: now.getMonth() + 1, - day: now.getDate(), - minute: now.getMinutes(), - seconds: now.getSeconds() - } - return rtn; -} - -async function main( ) { +async function main ( ) { + console.log("Excecuting main()"); const TODAY = getTsNow(); + console.dir(TODAY); const events_currentMonth = await Event.fetch_events( TODAY.year, TODAY.month , -120 ); + console.log("events_currentMonth.length:" + events_currentMonth.length ); const events_nextMonth = await Event.fetch_events( TODAY.year, TODAY.month + 1 , -120 ); + console.log("events_nextMonth.length:" + events_nextMonth.length ); const events = [...events_currentMonth, ...events_nextMonth]; + console.log("events.length:" + events.length ); + + // const TS_TODAY = new Date(); // Write to JSON File Section START // const data = JSON.stringify(events, null, 2); // const TS = `${TS_TODAY.getFullYear()}-${TS_TODAY.getMonth() + 1}-${TS_TODAY.getDate()}_${TS_TODAY.getHours()}-${TS_TODAY.getMinutes()}-${TS_TODAY.getSeconds()}`; @@ -33,16 +27,19 @@ async function main( ) { // Write to JSON File Section END const allEventUids = events.map( event => { return event.uid; }); + console.dir(allEventUids ); const placeholders = createPlaceholders( allEventUids ); const getAllRelevantEventsQuery = db.query( `SELECT * FROM events WHERE uid IN (${placeholders}); ` ).as(Event ); const AllRelevantEvents = getAllRelevantEventsQuery.all(...allEventUids); - + console.log("AllRelevantEvents.length:" + AllRelevantEvents.length ); const eventsToInsert: TEventEntityNew[] = []; for ( const ev of events ) { + console.log("loop ev: " + [ ev.uid, ev.title, ev.date_at ].join( ", " ) ); const found = AllRelevantEvents.find(event => event.uid === ev.uid); if ( found ) { + console.log("loop ev found: " + [ found.uid, found.title, found.date_at ].join( ", " ) ); if ( found.title != ev.title || found.description != ev.description || @@ -55,29 +52,34 @@ async function main( ) { found.timezone != ev.timezone || found.link != ev.link ) { + console.log("loop ev different (changed): " + [ ev.uid, ev.title, ev.date_at ].join( ", " ) ); const newEventToInsert: TEventEntityNew = {... ev, notification: "changed"}; eventsToInsert.push( newEventToInsert ); } } else { + console.log("loop ev added (new): " + [ ev.uid, ev.title, ev.date_at ].join( ", " ) ); const newEventToInsert: TEventEntityNew = {... ev, notification: "new"}; eventsToInsert.push( newEventToInsert ); } } - + console.dir(eventsToInsert) Event.insert( eventsToInsert, db); - const options: TGetEventsOptions = { - } - if (argv.today) { - options.date = { + const where: TGetEventsOptions = {} + where.notification = ["new", "changed"] + if ( argv.today ) { + where.date = { year: TODAY.year, month: TODAY.month, day: TODAY.day } - } else { - options.notification = ["new", "changed"] } - const list_of_events = Event.get_events( options, db ); + const list_of_events = Event.get_events( where, db ); + console.dir({ + list_of_events, + where + }); for ( const ev of list_of_events ) { + console.log("loop list_of_events - ev: " + [ev.uid, ev.title, ev.date_at, "notification:" + ev.notification].join( ", " ) ); const body = [ `Title: ${ev.title}`, `Location: ${ev.location}`, @@ -87,6 +89,7 @@ async function main( ) { `By: ${ev.posted_by}`, `Link: ${ev.link}`, ].join("\n"); + console.log("loop list_of_events - ev 'body': " + body ); const notification_prefix = ( (event: Event) => { switch( event.notification) { case "new": @@ -113,28 +116,8 @@ async function main( ) { return false; })( ev ); const title = `${today_prefix ? "TODAY " : ""}${notification_prefix ? notification_prefix + ": " : ""} ${ev.title} (${ TEventType[ ev.event_type ] })`; - - await fetch("http://apprise:8000/notify", { - method: "POST", - headers: { - "Content-Type": "application/json" - }, - body: JSON.stringify({ - urls: [ - `ntfys://${process.env.ntfy_username}:${process.env.ntfy_password}@${process.env.ntfy_host}/${process.env.ntfy_topic}${ ev.link ? `?click=${ev.link}`: "?click=https://77th-jsoc.com/#/events" }`, - `discord://${process.env.dc_webhook}?avatar_url=${process.env.dc_avatar_url}&botname=${process.env.dc_botname}` - ].join(","), - title: title, - body: body, - format: "text" - }) - }); - - // await sendNotification( - // title, - // body - // // `${ev.link || "https://77th-jsoc.com/#/events"}` - // ); + console.log("loop list_of_events - ev 'title': " + title ); + await sendNotification( title, body, ev.link ? ev.link : null); ev.set_notification("done", db); } }; diff --git a/src/sendNotification.ts b/src/sendNotification.ts index 639ff21..66e61d4 100644 --- a/src/sendNotification.ts +++ b/src/sendNotification.ts @@ -1,16 +1,26 @@ -import * as Bun from "bun"; - -export async function sendNotification(title: string, body: string, click?: string | null) { - const command = [ - "python3", - "./src/notification.py", - `--title=${title}`, - `--body=${body}`, - ]; - if ( click ) { - command.push(`--click=${click}`); +export async function sendNotification(title: string, body: string, link?: string | null) { + console.dir({ + sendNotification: { + title, + body, + link } - const proc = Bun.spawn(command); - const text = await proc.stdout.text(); - console.log("sendNotification: " + text); -} + }); + const response = await fetch("http://apprise:8000/notify", { + method: "POST", + headers: { + "Content-Type": "application/json" + }, + body: JSON.stringify({ + urls: [ + `ntfys://${process.env.ntfy_username}:${process.env.ntfy_password}@${process.env.ntfy_host}/${process.env.ntfy_topic}${ link ? `?click=${link}`: "?click=https://77th-jsoc.com/#/events" }`, + `discord://${process.env.dc_webhook}?avatar_url=${process.env.dc_avatar_url}&botname=${process.env.dc_botname}` + ].join(","), + title: title, + body: body, + format: "text" + }) + }); + const responseBody = await response.json(); + return responseBody; +} \ No newline at end of file diff --git a/src/sendNotificationPy.ts b/src/sendNotificationPy.ts new file mode 100644 index 0000000..2fbf339 --- /dev/null +++ b/src/sendNotificationPy.ts @@ -0,0 +1,16 @@ +import * as Bun from "bun"; + +export async function sendNotificationPy(title: string, body: string, click?: string | null) { + const command = [ + "python3", + "./src/notification.py", + `--title=${title}`, + `--body=${body}`, + ]; + if ( click ) { + command.push(`--click=${click}`); + } + const proc = Bun.spawn(command); + const text = await proc.stdout.text(); + console.log("sendNotification: " + text); +} diff --git a/src/util.ts b/src/util.ts index 7d3314a..6f2f7ed 100644 --- a/src/util.ts +++ b/src/util.ts @@ -26,4 +26,16 @@ export function pad_l2 ( _thing: string | number ): string { _thing = JSON.stringify(_thing); }; return _thing.padStart(2, "0"); +} + +export function getTsNow() { + const now = new Date(); + const rtn = { + year: now.getFullYear(), + month: now.getMonth() + 1, + day: now.getDate(), + minute: now.getMinutes(), + seconds: now.getSeconds() + } + return rtn; } \ No newline at end of file