Files
ob2qualkard/src/kanboard.ts
Ruben Carlo Benante 10fd1fd9cc
Some checks failed
ob2qualkard CI / build (20.x) (push) Has been cancelled
ob2qualkard CI / build (22.x) (push) Has been cancelled
ob2qualkard CI / build (24.x) (push) Has been cancelled
Release ob2qualkard / build (push) Has been cancelled
new files v0.2
2026-08-05 21:12:33 -03:00

87 lines
3.6 KiB
TypeScript

// *************************************************************************
// * (C)opyright 2026 by Ruben Carlo Benante *
// * *
// * This program is free software; you can redistribute it and/or modify *
// * it under the terms of the GNU General Public License as published by *
// * the Free Software Foundation, either version 3 of the License, or *
// * (at your option) any later version. *
// * *
// * This program is distributed in the hope that it will be useful, *
// * but WITHOUT ANY WARRANTY; without even the implied warranty of *
// * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
// * GNU General Public License for more details. *
// * *
// * You should have received a copy of the GNU General Public License *
// * along with this program. If not, see http://www.gnu.org/licenses/. *
// * *
// * Contact author at: *
// * Ruben Carlo Benante *
// * rcb@beco.cc *
// *************************************************************************
// The only module that touches the network. Uses Obsidian's requestUrl (not
// fetch) so the HTTP Basic auth header and cross-origin call work. The pure
// request/response helpers live in rpc.ts and are unit-tested there.
import { requestUrl } from 'obsidian';
import { buildJsonRpcRequest, parseRpcResult, type RpcAuth } from './rpc';
// Perform a JSON-RPC call and return its `result`, throwing a readable Error
// on transport failures or Kanboard-reported errors.
async function call(
auth: RpcAuth,
method: string,
params: Record<string, unknown>,
): Promise<unknown> {
const req = buildJsonRpcRequest(auth, method, params);
const resp = await requestUrl({
url: req.url,
method: 'POST',
headers: req.headers,
body: req.body,
throw: false,
});
if (resp.status === 401) {
throw new Error('Authentication failed (check username and API token)');
}
let data: unknown;
try {
data = resp.json;
} catch {
throw new Error(`Unexpected response from Kanboard (HTTP ${resp.status})`);
}
return parseRpcResult(data);
}
// Resolve a board (Kanboard project) display name to its numeric id, or null.
export async function getProjectIdByName(
auth: RpcAuth,
name: string,
): Promise<number | null> {
const result = await call(auth, 'getProjectByName', { name });
if (!result || typeof result !== 'object') return null;
const id = (result as { id?: unknown }).id;
return id ? Number(id) : null;
}
// Create a Kanboard task (which QualKard adopts as a new "new" card). Returns
// the new task id. project_id + title are the only required fields; QualKard's
// server-side hook fills in the spaced-repetition state on creation.
export async function createTask(
auth: RpcAuth,
projectId: number,
title: string,
description: string,
): Promise<number> {
const result = await call(auth, 'createTask', {
title,
project_id: projectId,
description,
});
// createTask returns the new task id, or false on a validation failure.
if (!result || typeof result === 'boolean') {
throw new Error('Kanboard rejected the task (no id returned)');
}
return Number(result);
}