| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356 |
- // PicoNotes Plugin for ShadowMan
- // API v2.0.0 — Consolidated tools (3 instead of 19)
- var config = shadowman.config.get();
- var apiKey = config.api_key;
- var baseUrl = 'https://piconotes.eu';
- shadowman.log.info('PicoNotes plugin loaded (API v2.0.0, consolidated)');
- shadowman.log.info('API key configured: ' + (apiKey ? 'yes (length: ' + apiKey.length + ', prefix: ' + apiKey.substring(0, 8) + ')' : 'NO!'));
- // ── Helpers ──────────────────────────────────────────────────────────────
- function apiRequest(method, path, body, contentType) {
- // Authorization: PicoNotes API key format
- var headers = {
- 'Authorization': 'API ' + apiKey,
- 'Prefer': 'return=representation'
- };
-
- // Content-Type for POST/PATCH requests
- if (method !== 'GET' && method !== 'DELETE') {
- if (contentType) {
- headers['Content-Type'] = contentType;
- } else {
- headers['Content-Type'] = 'application/json';
- }
- }
- var url = baseUrl + path;
- var response;
- shadowman.log.debug('API Request: ' + method + ' ' + path);
- if (method === 'GET') {
- response = shadowman.http.get(url, { headers: headers });
- } else if (method === 'POST') {
- if (contentType && contentType !== 'application/json') {
- response = shadowman.http.request(url, { method: 'POST', body: body, headers: headers });
- } else {
- shadowman.log.debug('POST body: ' + JSON.stringify(body));
- response = shadowman.http.request(url, {
- method: 'POST',
- body: JSON.stringify(body),
- headers: headers
- });
- }
- } else if (method === 'PATCH') {
- response = shadowman.http.request(url, { method: 'PATCH', body: JSON.stringify(body), headers: headers });
- } else if (method === 'DELETE') {
- response = shadowman.http.del(url, { headers: headers });
- }
- shadowman.log.debug('API Response: ' + response.status + ' - ' + (response.body ? response.body : 'empty'));
- if (response.status >= 400) {
- var errorDetail = response.body;
- try {
- var errorJson = JSON.parse(response.body);
- if (errorJson.error) errorDetail = errorJson.error;
- if (errorJson.message) errorDetail = errorJson.message;
- if (errorJson.detail) errorDetail = errorJson.detail;
- } catch (e) {}
- shadowman.log.error('API Error ' + response.status + ': ' + errorDetail);
- return { error: 'API error ' + response.status, details: errorDetail, status: response.status };
- }
- try {
- return response.json();
- } catch (e) {
- return response.body || { success: true, status: response.status };
- }
- }
- function getPageUserId(pageId) {
- shadowman.log.info('Getting user_id for page: ' + pageId);
- var result = apiRequest('GET', '/api/pages/' + pageId);
- if (result.error) {
- shadowman.log.error('Failed to get page: ' + result.error + ' - ' + result.details);
- return result;
- }
-
- // API v2.0.0: a válasz lehet { data: {...} }, { ... }, vagy [ {...} ]
- var page = result;
- if (result.data) {
- page = result.data;
- } else if (Array.isArray(result)) {
- page = result[0];
- }
-
- shadowman.log.debug('Page data: ' + JSON.stringify(page));
-
- if (!page) {
- shadowman.log.error('Page not found: ' + pageId);
- return { error: 'Page not found: ' + pageId };
- }
- if (!page.user_id) {
- shadowman.log.error('Page missing user_id: ' + JSON.stringify(page));
- return { error: 'Could not resolve user_id for page ' + pageId };
- }
-
- shadowman.log.info('Resolved user_id: ' + page.user_id);
- return { user_id: page.user_id };
- }
- // ── Tool 1: pages ─────────────────────────────────────────────
- shadowman.tools.register('pages', function(args) {
- var action = args.action;
- // ─── list ───
- if (action === 'list') {
- var params = [];
- if (args.parent_id !== undefined) {
- if (args.parent_id === 'null' || args.parent_id === null) {
- params.push('parent_id=is.null');
- } else {
- params.push('parent_id=eq.' + args.parent_id);
- }
- }
- params.push('order=' + (args.order || 'sort_order.asc'));
- params.push('select=id,title,icon,parent_id,sort_order,created_at,updated_at,user_id');
- return apiRequest('GET', '/api/pages?' + params.join('&'));
- }
- // ─── get ───
- if (action === 'get') {
- if (!args.page_id) return { error: 'page_id is required' };
- return apiRequest('GET', '/api/pages/' + args.page_id);
- }
- // ─── create ───
- if (action === 'create') {
- if (!args.title) return { error: 'title is required' };
-
- // Fix: resolve user_id from list if not provided
- var userId = '0v2AJNrePA8VGUlL';
-
- var page = { title: args.title, user_id: userId };
- if (args.id) page.id = args.id;
- if (args.icon) page.icon = args.icon;
- if (args.parent_id !== undefined) page.parent_id = args.parent_id;
- if (args.sort_order !== undefined) page.sort_order = args.sort_order;
- if (args.is_template !== undefined) page.is_template = args.is_template;
-
- shadowman.log.info('Creating page with user_id: ' + JSON.stringify(page));
- return apiRequest('POST', '/api/pages', page);
- }
- // ─── update ───
- if (action === 'update') {
- if (!args.page_id) return { error: 'page_id is required' };
- var updates = {};
- if (args.title !== undefined) updates.title = args.title;
- if (args.icon !== undefined) updates.icon = args.icon;
- if (args.parent_id !== undefined) updates.parent_id = args.parent_id;
- if (args.sort_order !== undefined) updates.sort_order = args.sort_order;
- return apiRequest('PATCH', '/api/pages/' + args.page_id, updates);
- }
- // ─── delete ───
- if (action === 'delete') {
- if (!args.page_id) return { error: 'page_id is required' };
- return apiRequest('DELETE', '/api/pages/' + args.page_id);
- }
- // ─── get_content ───
- if (action === 'get_content') {
- if (!args.page_id) return { error: 'page_id is required' };
- shadowman.log.info('get_content called for page: ' + args.page_id);
-
- var u = getPageUserId(args.page_id);
- if (u.error) return u;
-
- var storageUrl = '/api/storage/pages/' + u.user_id + '/' + args.page_id + '.md';
- shadowman.log.info('Fetching content from: ' + storageUrl);
-
- var resp = shadowman.http.get(baseUrl + storageUrl, { headers: { 'Authorization': 'API ' + apiKey } });
- shadowman.log.debug('Storage response: ' + resp.status);
-
- if (resp.status >= 400) {
- var errDetail = resp.body;
- try {
- var errJson = JSON.parse(resp.body);
- if (errJson.error) errDetail = errJson.error;
- if (errJson.message) errDetail = errJson.message;
- } catch (e) {}
- shadowman.log.error('Failed to get content: ' + resp.status + ' - ' + errDetail);
- return { error: 'Failed to get content: ' + resp.status, details: errDetail, status: resp.status };
- }
- return { page_id: args.page_id, content: resp.body };
- }
- // ─── update_content ───
- if (action === 'update_content') {
- if (!args.page_id) return { error: 'page_id is required' };
- if (!args.content && args.content !== '') return { error: 'content is required' };
- shadowman.log.info('update_content called for page: ' + args.page_id);
-
- var u2 = getPageUserId(args.page_id);
- if (u2.error) return u2;
-
- var storageUrl2 = baseUrl + '/api/storage/pages/' + u2.user_id + '/' + args.page_id + '.md?upsert=true';
- shadowman.log.info('Updating content at: ' + storageUrl2);
-
- var resp2 = shadowman.http.request(storageUrl2, {
- method: 'POST',
- headers: { 'Authorization': 'API ' + apiKey, 'Content-Type': 'text/markdown' },
- body: args.content
- });
- shadowman.log.debug('Storage update response: ' + resp2.status);
-
- if (resp2.status >= 400) {
- var errDetail2 = resp2.body;
- try {
- var errJson2 = JSON.parse(resp2.body);
- if (errJson2.error) errDetail2 = errJson2.error;
- if (errJson2.message) errDetail2 = errJson2.message;
- } catch (e) {}
- shadowman.log.error('Failed to update content: ' + resp2.status + ' - ' + errDetail2);
- return { error: 'Failed to update content: ' + resp2.status, details: errDetail2, status: resp2.status };
- }
- return { success: true, page_id: args.page_id };
- }
- // ─── list_versions ───
- if (action === 'list_versions') {
- if (!args.page_id) return { error: 'page_id is required' };
- shadowman.log.info('list_versions called for page: ' + args.page_id);
-
- var u3 = getPageUserId(args.page_id);
- if (u3.error) return u3;
-
- var versionsUrl = '/api/storage/pages/' + u3.user_id + '/' + args.page_id + '.md/versions';
- shadowman.log.info('Fetching versions from: ' + versionsUrl);
-
- return apiRequest('GET', versionsUrl);
- }
- return { error: 'Unknown action: ' + action + '. Valid: list, get, create, update, delete, get_content, update_content, list_versions' };
- });
- // ── Tool 2: sharing ───────────────────────────────────────────
- shadowman.tools.register('sharing', function(args) {
- var action = args.action;
- // ─── list_links ───
- if (action === 'list_links') {
- if (!args.page_id) return { error: 'page_id is required' };
- return apiRequest('GET', '/api/page_share_links?page_id=' + args.page_id);
- }
- // ─── create_link ───
- if (action === 'create_link') {
- if (!args.page_id) return { error: 'page_id is required' };
- var link = { page_id: args.page_id };
- if (args.permission) link.permission = args.permission;
- if (args.short_code) link.short_code = args.short_code;
- if (args.expires_at) link.expires_at = args.expires_at;
- return apiRequest('POST', '/api/page_share_links', link);
- }
- // ─── delete_link ───
- if (action === 'delete_link') {
- if (!args.link_id) return { error: 'link_id is required' };
- return apiRequest('DELETE', '/api/page_share_links/' + args.link_id);
- }
- // ─── check_lock ───
- if (action === 'check_lock') {
- if (!args.page_id) return { error: 'page_id is required' };
- return apiRequest('GET', '/api/page_locks?page_id=' + args.page_id);
- }
- // ─── acquire_lock ───
- if (action === 'acquire_lock') {
- if (!args.page_id) return { error: 'page_id is required' };
- return apiRequest('POST', '/api/page_locks', {
- page_id: args.page_id,
- display_name: args.display_name || 'ShadowMan'
- });
- }
- // ─── release_lock ───
- if (action === 'release_lock') {
- if (!args.page_id) return { error: 'page_id is required' };
- return apiRequest('DELETE', '/api/page_locks/' + args.page_id);
- }
- return { error: 'Unknown action: ' + action + '. Valid: list_links, create_link, delete_link, check_lock, acquire_lock, release_lock' };
- });
- // ── Tool 3: images ────────────────────────────────────────────
- shadowman.tools.register('images', function(args) {
- var action = args.action;
- // ─── list ───
- if (action === 'list') {
- return apiRequest('GET', '/api/storage/images');
- }
- // ─── upload ───
- if (action === 'upload') {
- if (!args.filename) return { error: 'filename is required' };
- if (!args.content_type) return { error: 'content_type is required' };
- if (!args.image_data) return { error: 'image_data (base64) is required' };
- shadowman.log.info('Uploading image: ' + args.filename);
- var imageData = shadowman.utils.base64DecodeBytes(args.image_data);
- var resp = shadowman.http.request(baseUrl + '/api/storage/images/' + args.filename, {
- method: 'POST',
- headers: { 'Authorization': 'API ' + apiKey, 'Content-Type': args.content_type },
- body: imageData
- });
- if (resp.status >= 400) {
- var errDetail = resp.body;
- try {
- var errJson = JSON.parse(resp.body);
- if (errJson.error) errDetail = errJson.error;
- if (errJson.message) errDetail = errJson.message;
- } catch (e) {}
- shadowman.log.error('Upload failed: ' + resp.status + ' - ' + errDetail);
- return { error: 'Upload failed: ' + resp.status, details: errDetail };
- }
- try { return resp.json(); } catch (e) { return { success: true, status: resp.status }; }
- }
- // ─── delete ───
- if (action === 'delete') {
- if (!args.filename) return { error: 'filename is required' };
- return apiRequest('DELETE', '/api/storage/images/' + args.filename);
- }
- // ─── create_alias ───
- if (action === 'create_alias') {
- if (!args.image_path) return { error: 'image_path is required' };
- return apiRequest('POST', '/api/storage/alias', { bucket: 'images', path: args.image_path });
- }
- // ─── list_usage ───
- if (action === 'list_usage') {
- if (!args.page_id) return { error: 'page_id is required' };
- return apiRequest('GET', '/api/page_image_usage?page_id=' + args.page_id);
- }
- // ─── track_usage ───
- if (action === 'track_usage') {
- if (!args.file_id) return { error: 'file_id is required' };
- if (!args.page_id) return { error: 'page_id is required' };
- var usage = { file_id: args.file_id, page_id: args.page_id };
- if (args.alias_url) usage.alias_url = args.alias_url;
- return apiRequest('POST', '/api/page_image_usage', usage);
- }
- return { error: 'Unknown action: ' + action + '. Valid: list, upload, delete, create_alias, list_usage, track_usage' };
- });
|