From 8490e073f64f9aa0e63f642ffbc0547cb36a3091 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Pluta?= Date: Fri, 17 Jan 2025 16:54:47 +0100 Subject: [PATCH] Add support for tags and priorities + make default query and mapper --- src/backend/ntfy.ts | 24 +++++++++++++++++++++--- src/database/serializer.ts | 19 ++++++++++++++++--- src/loader/index.ts | 12 ++---------- src/types/config.ts | 4 ++-- src/types/notification.ts | 8 +++++--- src/util/index.ts | 4 ++++ 6 files changed, 50 insertions(+), 21 deletions(-) create mode 100644 src/util/index.ts diff --git a/src/backend/ntfy.ts b/src/backend/ntfy.ts index 1401b86..fcf8d0f 100644 --- a/src/backend/ntfy.ts +++ b/src/backend/ntfy.ts @@ -2,6 +2,7 @@ import fs from "fs"; import { BackendSettings } from "../types/config"; import { Notification } from "../types/notification"; import { Backend } from "./base"; +import { TaskPriority } from "../types/task"; type Config = { url: string; @@ -20,10 +21,27 @@ export class NtfySH extends Backend { fetch(`https://${config.url}/${config.topic || 'obsidian'}`, { method: 'POST', body: notification.text, - headers: { - 'Title': notification.title, - 'Authorization': `Bearer ${token}` + headers: { + 'Authorization': `Bearer ${token}`, + 'Title': notification.title ?? "", + 'Priority': mapPriority(notification.priority), + 'Tags': notification.tags?.join(",") ?? "" } }) } +} + +function mapPriority(priority?: TaskPriority): string { + if (!priority) { + return 'default'; + } + + return { + [TaskPriority.LOWEST]: 'min', + [TaskPriority.LOW]: 'low', + [TaskPriority.NORMAL]: 'default', + [TaskPriority.MEDIUM]: 'default', + [TaskPriority.HIGH]: 'high', + [TaskPriority.HIGHEST]: 'max', + }[priority]; } \ No newline at end of file diff --git a/src/database/serializer.ts b/src/database/serializer.ts index 9d9ef45..f42e5e0 100644 --- a/src/database/serializer.ts +++ b/src/database/serializer.ts @@ -1,11 +1,13 @@ import fs from "fs"; import { Task } from "../types/task"; import { Notification, NotificationDatabase } from "../types/notification"; +import { jsMapper } from "../util"; + /** * Applies the mapper for each task from list, groups them by time and dumps the data into JSON formatted file. */ -export function dumpDatabase(file: string, tasks: Task[], mapper: string) { +export function dumpDatabase(file: string, tasks: Task[], mapper?: string) { const data = serializeDatabase(tasks, mapper); fs.writeFileSync(file, data); } @@ -13,8 +15,10 @@ export function dumpDatabase(file: string, tasks: Task[], mapper: string) { /** * Applies the mapper for each task from list, groups them by time and serializes into JSON format. */ -export function serializeDatabase(tasks: Task[], mapper: string): string { - const transformer = new Function("$", `return ${mapper}`) as (task: Task) => Notification; +export function serializeDatabase(tasks: Task[], mapper?: string): string { + const transformer = mapper + ? jsMapper(mapper, {}) + : defaultMapper; const output = tasks.map(wrapWithTimeFiller(transformer)).reduce((acc, n) => { if (n.time) { @@ -36,4 +40,13 @@ function wrapWithTimeFiller(mapper: (task: Task) => Notification): (task: Task) time: task.reminder ?? notification.time, } }; +} + +function defaultMapper(task: Task): Notification { + return { + title: "Obsidian Tasks Reminder", + text: task.label, + priority: task.priority, + tags: task.tags, + }; } \ No newline at end of file diff --git a/src/loader/index.ts b/src/loader/index.ts index a3884d5..d640e73 100644 --- a/src/loader/index.ts +++ b/src/loader/index.ts @@ -5,6 +5,7 @@ import { parse } from "../generated/grammar/task"; import { Task as DefaultTask } from "../model"; import { ParseResult } from "../types/grammar"; import { Task, TaskPriority } from "../types/task"; +import { jsMapper } from "../util"; /** * Returns all tasks from specified directory and filters them with optional query. @@ -20,21 +21,12 @@ export async function loadTasks(directories: string[], query?: string): Promise< HIGHEST: TaskPriority.HIGHEST }; - const filter = query && createFilter(query, ctx); + const filter = query && jsMapper(query, ctx); const tasks = await Promise.all(directories.map(readTasksFromDirectory)); return tasks.flat().filter(t => filter ? filter(t) : true); } -/** - * Creates a filter function for tasks using a query string and context object. - * All context' properties will be passed as variables to the query string. - */ -function createFilter(query: string, context: Record): (task: Task) => boolean { - const filter = new Function('$', ...Object.keys(context), `return ${query};`); - return (task: Task) => filter(task, ...Object.values(context)); -} - /** * Read all files in specific directory and returns all tasks from those files. */ diff --git a/src/types/config.ts b/src/types/config.ts index fb08a65..87e081d 100644 --- a/src/types/config.ts +++ b/src/types/config.ts @@ -1,7 +1,7 @@ export type Config = { sources: string[]; - query: string; - mapper: string; + query?: string; + mapper?: string; databaseFile: string; backend: Record; }; diff --git a/src/types/notification.ts b/src/types/notification.ts index 85511d7..115993a 100644 --- a/src/types/notification.ts +++ b/src/types/notification.ts @@ -1,9 +1,11 @@ -import dayjs, { Dayjs } from "dayjs" +import { TaskPriority } from "./task"; export type Notification = { - time?: string; - title: string; text: string; + time?: string; + title?: string; + priority?: TaskPriority; + tags?: string[]; }; export type NotificationDatabase = Record; \ No newline at end of file diff --git a/src/util/index.ts b/src/util/index.ts new file mode 100644 index 0000000..f6b4eee --- /dev/null +++ b/src/util/index.ts @@ -0,0 +1,4 @@ +export function jsMapper(code: string, context: Record): (task: I) => O { + const filter = new Function('$', ...Object.keys(context), `return ${code};`); + return (task: I) => filter(task, ...Object.values(context)); +} \ No newline at end of file