/* webui_store.h — SQLite-backed persistence for all web-UI-owned state: * accounts, the category/tag taxonomy, and RSS feeds/rules/indexers. * * Owned entirely by the webui plugin (the daemon persists none of this). * Account passwords are PBKDF2-HMAC-SHA256 with a per-user random salt. All * calls are thread-safe (the store serializes access to its SQLite handle). */ #ifndef NAUT_WEBUI_STORE_H #define NAUT_WEBUI_STORE_H #include #include #include typedef struct webui_store webui_store; /* Open (creating if needed) the account database at `path`. Returns NULL on * failure. The schema is created/migrated on open. */ webui_store *webui_store_open(const char *path); void webui_store_close(webui_store *s); /* Number of accounts, or -1 on error. */ int webui_store_user_count(webui_store *s); /* Number of admin accounts, or -1 on error. */ int webui_store_admin_count(webui_store *s); bool webui_store_user_exists(webui_store *s, const char *username); /* Verify a username/password pair (constant-time). On success, copies the * account's role ("admin"/"user") into role_out. */ bool webui_store_verify(webui_store *s, const char *username, const char *password, char *role_out, size_t role_sz); /* Create an account. `role` must be "admin" or "user" (defaults to "user" if * NULL/invalid). Returns false if the username already exists or on error. */ bool webui_store_create_user(webui_store *s, const char *username, const char *password, const char *role); bool webui_store_set_password(webui_store *s, const char *username, const char *password); /* Change an account's role ("admin"/"user"). */ bool webui_store_set_role(webui_store *s, const char *username, const char *role); bool webui_store_delete_user(webui_store *s, const char *username); /* Append {username, role, createdAt} objects (sorted by username) to the * json array `out`. Returns false on error. */ bool webui_store_list_users(webui_store *s, json_t *out); /* --- category / tag taxonomy (web-UI organization, owned here) ------------- * * The save_* calls replace the whole list atomically; the load_* calls append * to the (array) `out`. Categories are {name, savePath}; tags are strings. */ bool webui_store_save_categories(webui_store *s, json_t *cats); bool webui_store_load_categories(webui_store *s, json_t *out); bool webui_store_save_tags(webui_store *s, json_t *tags); bool webui_store_load_tags(webui_store *s, json_t *out); /* --- RSS: feeds, articles, auto-download rules, Torznab indexers ----------- * * Fully relational: articles live in their own table (deduped by feed+key, * indexed), and a rule's feed scope lives in a rule_feeds join table. The web * layer operates on rows, not whole-list blobs. */ /* Feeds. upsert preserves an existing feed's lastUpdate (only the url changes); * remove also drops the feed's articles. feed_list appends * {name,url,lastUpdate,articles:[...]} (newest article first). feed_targets * appends lightweight {name,url} objects for the poller. */ bool webui_store_feed_upsert(webui_store *s, const char *name, const char *url); bool webui_store_feed_remove(webui_store *s, const char *name); bool webui_store_feed_set_updated(webui_store *s, const char *name, long ts); bool webui_store_feed_list(webui_store *s, json_t *out); bool webui_store_feed_targets(webui_store *s, json_t *out); bool webui_store_feed_exists(webui_store *s, const char *name); /* Articles. add inserts unless (feed,key) already exists: returns 1 if newly * inserted, 0 if a duplicate, -1 on error. trim keeps the newest `keep` for a * feed. mark_grabbed flags every article with this key. ungrabbed appends * {feed,key,title,magnet,torrentUrl} for not-yet-grabbed articles. */ int webui_store_article_add(webui_store *s, const char *feed, json_t *article); bool webui_store_article_trim(webui_store *s, const char *feed, int keep); bool webui_store_article_mark_grabbed(webui_store *s, const char *key); bool webui_store_articles_ungrabbed(webui_store *s, json_t *out); /* Rules. upsert replaces the rule row and its feed scope; list/get assemble the * rule with its affectedFeeds array. */ bool webui_store_rule_upsert(webui_store *s, json_t *rule); bool webui_store_rule_remove(webui_store *s, const char *name); bool webui_store_rule_list(webui_store *s, json_t *out); json_t *webui_store_rule_get(webui_store *s, const char *name); bool webui_store_rule_set_match(webui_store *s, const char *name, long ts); /* Torznab indexers. */ bool webui_store_indexer_upsert(webui_store *s, json_t *indexer); bool webui_store_indexer_remove(webui_store *s, const char *name); bool webui_store_indexer_list(webui_store *s, json_t *out); #endif /* NAUT_WEBUI_STORE_H */