255 lines
8.4 KiB
TypeScript
255 lines
8.4 KiB
TypeScript
import { Database } from "bun:sqlite";
|
|
import { TEventType, type TEvent } from "./event.types";
|
|
import { getTsNow, pad_l2, transformArray, formatTimeDiff, isEuropeanDST, subtractHours } from "../../util";
|
|
|
|
const BASE_URL = "https://77th-jsoc.com/service.php?action=get_events";
|
|
|
|
export type TGetEventsOptions = {
|
|
notification?: TEventEntity["notification"][] | null,
|
|
date?: {
|
|
year: number,
|
|
month: number,
|
|
day: number
|
|
},
|
|
month?: {
|
|
year: number,
|
|
month: number,
|
|
},
|
|
deleted?: boolean
|
|
}
|
|
export type TEventEntity = TEvent & {
|
|
event_uid: number
|
|
notification: "new" | "changed" | "removed" | "done" | "deleted"
|
|
}
|
|
|
|
export type TEventEntityNew = Omit<TEventEntity, "event_uid">
|
|
|
|
export class Event implements TEventEntity {
|
|
static table_name: "events"
|
|
event_uid: number;
|
|
uid: string;
|
|
title: string;
|
|
description: string;
|
|
date_at: string;
|
|
time_start: string;
|
|
time_end: string;
|
|
posted_by: string;
|
|
location: string;
|
|
event_type: TEventEntity["event_type"];
|
|
timezone: string;
|
|
link: string;
|
|
notification: TEventEntity["notification"];
|
|
deleteDate: TEventEntity["deleteDate"];
|
|
|
|
static createTable (db: Database): void {
|
|
const query = db.query(`CREATE TABLE IF NOT EXISTS "events" (
|
|
"event_uid" INTEGER PRIMARY KEY,
|
|
"uid" TEXT NOT NULL UNIQUE,
|
|
"title" TEXT NOT NULL,
|
|
"date_at" DATETIME NOT NULL,
|
|
"time_start" TEXT NOT NULL,
|
|
"time_end" TEXT NOT NULL,
|
|
"posted_by" TEXT NOT NULL,
|
|
"location" TEXT NOT NULL,
|
|
"event_type" TEXT NOT NULL,
|
|
"link" TEXT NOT NULL,
|
|
"description" TEXT NOT NULL,
|
|
"timezone" TEXT NOT NULL,
|
|
"notification" TEXT NOT NULL,
|
|
"deleteDate" INTEGER NULL
|
|
);`);
|
|
query.run();
|
|
}
|
|
|
|
static insert ( events: TEventEntityNew[], db: Database ) {
|
|
const insert = db.prepare( [
|
|
"INSERT OR REPLACE INTO events",
|
|
"(uid, title, date_at, time_start, time_end, posted_by, location, event_type, link, description, timezone, notification)",
|
|
"VALUES",
|
|
"($uid, $title, $date_at, $time_start, $time_end, $posted_by, $location, $event_type, $link, $description, $timezone, $notification)"
|
|
].join(" "));
|
|
const insertEvents = db.transaction(events => {
|
|
for (const event of events) insert.run(event);
|
|
return events.length;
|
|
});
|
|
|
|
const transforedEventArray = transformArray( events );
|
|
const count = insertEvents(transforedEventArray);
|
|
|
|
console.log(`Inserted ${count} events`);
|
|
}
|
|
|
|
static async fetch_events( _year_: number, _month_: number, timezone: number): Promise<TEvent[]> {
|
|
const url = `${BASE_URL}&year=${_year_}&month=${_month_}&timezone=${timezone}`
|
|
const response = await fetch(url, {
|
|
method: "GET",
|
|
});
|
|
const body = await response.json() as {events: TEvent[] };
|
|
const events = body.events.sort( ( a, b ) => ( new Date(a.date_at) < new Date(b.date_at ) ) ? -1 : 1 );
|
|
return events;
|
|
}
|
|
|
|
static get_events ( options: TGetEventsOptions, db: Database ) {
|
|
const whereConditions: string[] = [];
|
|
if ( options.notification ) {
|
|
whereConditions.push( `notification IN ('${ options.notification.join("', '") }')` )
|
|
}
|
|
if ( options.date ) {
|
|
whereConditions.push(`date_at = "${options.date.year}-${options.date.month}-${options.date.day}"`);
|
|
}
|
|
if ( options.month ) {
|
|
whereConditions.push( `strftime('%Y-%m', date_at) = '${options.month.year}-${options.month.month}'`)
|
|
}
|
|
|
|
const where = ( () => {
|
|
let str = "WHERE ";
|
|
if ( options.deleted === true ) {
|
|
str += "deleteDate IS NOT NULL AND ";
|
|
} else if ( options.deleted === false ) {
|
|
str += "deleteDate IS NULL AND ";
|
|
}
|
|
if ( whereConditions.length >= 1 ) {
|
|
return str += `( ${ whereConditions.join(" OR ") } )`;
|
|
}
|
|
return null;
|
|
})()
|
|
const query = db.query(`SELECT * FROM events${ where ? ( " " + where ) : ""};`).as(Event);
|
|
console.dir({ db: { action: {get_events: query} } })
|
|
return query.all();
|
|
}
|
|
|
|
constructor(event_uid: number, uid: string, title: string, description: string, date_at: string, time_start: string, time_end: string, posted_by: string, location: string, event_type: TEventEntity["event_type"], timezone: string, link: string, notification: TEventEntity["notification"], deleteDate: TEventEntity["deleteDate"]) {
|
|
this.event_uid = event_uid;
|
|
this.uid = uid;
|
|
this.title = title;
|
|
this.description = description;
|
|
this.date_at = date_at;
|
|
this.time_start = time_start;
|
|
this.time_end = time_end;
|
|
this.posted_by = posted_by;
|
|
this.location = location;
|
|
this.event_type = event_type;
|
|
this.timezone = timezone;
|
|
this.link = link;
|
|
this.notification = notification;
|
|
this.deleteDate = deleteDate;
|
|
}
|
|
toString() {
|
|
return {
|
|
event_uid: this.event_uid,
|
|
uid: this.uid,
|
|
title: this.title,
|
|
description: this.description,
|
|
date_at: this.date_at,
|
|
time_start: this.time_start,
|
|
time_end: this.time_end,
|
|
posted_by: this.posted_by,
|
|
location: this.location,
|
|
event_type: this.event_type,
|
|
timezone: this.timezone,
|
|
link: this.link,
|
|
notification: this.notification,
|
|
deleteDate: this.deleteDate
|
|
}
|
|
}
|
|
|
|
syncWithDb ( db: Database ) {
|
|
const query = db.prepare( `SELECT * FROM events WHERE event_uid = $event_uid;`).as(Event);
|
|
const entity = query.get({$event_uid: this.event_uid });
|
|
if ( ! entity ) { throw new Error(`Could not find Event with event_uid ${this.event_uid} in DB!`); }
|
|
this.uid = entity.uid;
|
|
this.title = entity.title;
|
|
this.description = entity.description;
|
|
this.date_at = entity.date_at;
|
|
this.time_start = entity.time_start;
|
|
this.time_end = entity.time_end;
|
|
this.posted_by = entity.posted_by;
|
|
this.location = entity.location;
|
|
this.event_type = entity.event_type;
|
|
this.timezone = entity.timezone;
|
|
this.link = entity.link;
|
|
this.notification = entity.notification;
|
|
this.deleteDate = entity.deleteDate;
|
|
return this;
|
|
}
|
|
|
|
set_notification ( newValue: TEventEntity["notification"], db: Database ) {
|
|
const query = db.prepare(
|
|
`UPDATE events
|
|
SET notification = $notification
|
|
WHERE event_uid = $event_uid;`
|
|
);
|
|
query.get({$notification: newValue, $event_uid: this.event_uid });
|
|
return this.syncWithDb( db );
|
|
}
|
|
set_deleted ( db: Database ) {
|
|
const query = db.prepare(
|
|
`UPDATE events
|
|
SET notification = 'deleted',
|
|
deleteDate = $deleteDate
|
|
WHERE event_uid = $event_uid;`
|
|
);
|
|
query.get({
|
|
$deleteDate: Math.floor((new Date()).getTime() / 1000),
|
|
$event_uid: this.event_uid
|
|
});
|
|
return this.syncWithDb( db );
|
|
}
|
|
get_title() {
|
|
const type_of_notification = ( (event: Event) => {
|
|
switch ( event.notification ) {
|
|
case "new":
|
|
return "New";
|
|
case "changed":
|
|
return "Changed";
|
|
case "removed":
|
|
return "Removed";
|
|
default:
|
|
return null;
|
|
}
|
|
} ) ( this );
|
|
const title_prefix_arr = [];
|
|
if ( type_of_notification ) title_prefix_arr.push( "<" + type_of_notification + ">" );
|
|
if ( this.isEventToday() ) title_prefix_arr.push( "<TODAY>" )
|
|
return `${title_prefix_arr.length >= 1 ? ( title_prefix_arr.join(" " ) + " - ") : "" }${this.title} (${ TEventType[ this.event_type ] })`;
|
|
}
|
|
get_body() {
|
|
const BaseTime = new Date(`${this.date_at} 21:00`);
|
|
const RelativeEventTime = new Date(`${this.date_at} ${this.get_time_start()}`);
|
|
const TimeDiff = formatTimeDiff( BaseTime, RelativeEventTime);
|
|
const body = [
|
|
`Title: ${this.title}`,
|
|
`Date: ${this.date_at}`,
|
|
`Time: ${this.get_time_start()} (OP Time${ TimeDiff != "00:00" ? ` ${TimeDiff}` : "" })`,
|
|
`Type: ${ TEventType[ this.event_type ] }`,
|
|
`Location: ${this.location}`,
|
|
`By: ${this.posted_by}`,
|
|
`Link: ${this.link}`,
|
|
].join("\n");
|
|
return body;
|
|
}
|
|
|
|
isEventToday ( ) {
|
|
const now = getTsNow();
|
|
const [year, month, day] = this.date_at.split("-")
|
|
if (
|
|
year == String(now.year) &&
|
|
month == pad_l2( String(now.month) ) &&
|
|
day == pad_l2( String( now.day ) )
|
|
) {
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
get_time_start () {
|
|
const date = new Date( `${this.date_at} ${this.time_start}` );
|
|
if ( ! isEuropeanDST( date ) ) {
|
|
const newDate = subtractHours( date, 1);
|
|
const hours = newDate.getHours();
|
|
const minutes = newDate.getMinutes();
|
|
return `${pad_l2(hours)}:${pad_l2(minutes)}`;
|
|
}
|
|
return this.time_start;
|
|
}
|
|
} |