From fb214d0c8096a345f5da30900d9ced0aa777cdc3 Mon Sep 17 00:00:00 2001 From: "C. McEnroe" Date: Thu, 9 Jul 2020 20:14:27 -0400 Subject: Implement very basic events listing --- contexts.c | 5 ++-- events.c | 78 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-- server.c | 3 +++ server.h | 11 ++++++--- 4 files changed, 90 insertions(+), 7 deletions(-) diff --git a/contexts.c b/contexts.c index c75202a..d432cb1 100644 --- a/contexts.c +++ b/contexts.c @@ -29,7 +29,7 @@ const char *ContextsQuery = SQL( ); enum kcgi_err pageContexts(struct kreq *req) { - if (!req->fieldmap[Network]) return httpFail(req, KHTTP_404); + if (!req->fieldmap[Network]) return httpFail(req, KHTTP_400); enum kcgi_err error = httpHead(req, KHTTP_200, KMIME_TEXT_HTML); if (req->method == KMETHOD_HEAD) return error; @@ -59,7 +59,8 @@ enum kcgi_err pageContexts(struct kreq *req) { ); if (!href) err(EX_OSERR, "khttp_urlpart"); - error = khtml_elem(&html, KELEM_LI) + error = 0 + || khtml_elem(&html, KELEM_LI) || khtml_attr(&html, KELEM_A, KATTR_HREF, href, KATTR__MAX) || khtml_puts(&html, context) || khtml_closeelem(&html, 2); diff --git a/events.c b/events.c index 9262225..04fdbf8 100644 --- a/events.c +++ b/events.c @@ -21,9 +21,59 @@ #include "server.h" +const char *EventsAfterQuery = SQL( + SELECT + events.event, + events.time, + events.type, + names.nick, + names.user, + names.host, + events.target, + events.message + FROM events + JOIN contexts USING (context) + JOIN names USING (name) + WHERE contexts.network = :network + AND contexts.name = :context + AND coalesce(contexts.query = :query, true) + AND events.time >= strftime('%s', :time) + ORDER BY events.time + LIMIT :limit; +); + +const char *EventsBeforeQuery = SQL( + WITH before AS ( + SELECT + events.event, + events.time, + events.type, + names.nick, + names.user, + names.host, + events.target, + events.message + FROM events + JOIN contexts USING (context) + JOIN names USING (name) + WHERE contexts.network = :network + AND contexts.name = :context + AND coalesce(contexts.query = :query, true) + AND events.time < strftime('%s', :time) + ORDER BY events.time DESC + LIMIT :limit + ) + SELECT * + FROM before + ORDER BY time; +); + enum kcgi_err pageEvents(struct kreq *req) { if (!req->fieldmap[Network] || !req->fieldmap[Context]) { - return httpFail(req, KHTTP_404); + return httpFail(req, KHTTP_400); + } + if (!req->fieldmap[After] && !req->fieldmap[Before]) { + return httpFail(req, KHTTP_400); } enum kcgi_err error = httpHead(req, KHTTP_200, KMIME_TEXT_HTML); @@ -31,6 +81,9 @@ enum kcgi_err pageEvents(struct kreq *req) { const char *network = req->fieldmap[Network]->parsed.s; const char *context = req->fieldmap[Context]->parsed.s; + const char *time = req->fieldmap[Before] + ? req->fieldmap[Before]->parsed.s + : req->fieldmap[After]->parsed.s; struct khtmlreq html; error = error @@ -41,5 +94,26 @@ enum kcgi_err pageEvents(struct kreq *req) { || htmlSearch(&html, network, context); if (error) return error; - return khtml_close(&html); + sqlite3_stmt *events = stmt.eventsAfter; + if (req->fieldmap[Before]) events = stmt.eventsBefore; + + dbBindText(events, ":network", network); + dbBindText(events, ":context", context); + if (pagePublic) dbBindInt(events, ":query", false); + dbBindText(events, ":time", time); + dbBindInt(events, ":limit", pageLimit); + + int result; + while (SQLITE_ROW == (result = sqlite3_step(events))) { + const char *msg = (const char *)sqlite3_column_text(events, 7); + if (!msg) continue; + error = 0 + || khtml_puts(&html, msg) + || khtml_elem(&html, KELEM_BR); + if (error) break; + } + if (result != SQLITE_DONE) errx(EX_SOFTWARE, "%s", sqlite3_errmsg(db)); + sqlite3_reset(events); + + return error || khtml_close(&html); } diff --git a/server.c b/server.c index de18e7d..3dcdea3 100644 --- a/server.c +++ b/server.c @@ -46,6 +46,7 @@ const struct kvalid Keys[KeysLen] = { }; bool pagePublic; +int pageLimit = 100; static enum kcgi_err request(struct kreq *req) { if (req->method != KMETHOD_HEAD && req->method != KMETHOD_GET) { @@ -94,6 +95,8 @@ int main(int argc, char *argv[]) { prepare(&stmt.networks, NetworksQuery); prepare(&stmt.contexts, ContextsQuery); + prepare(&stmt.eventsAfter, EventsAfterQuery); + prepare(&stmt.eventsBefore, EventsBeforeQuery); if (fastCGI) { struct kfcgi *fcgi; diff --git a/server.h b/server.h index 9b665d7..0e77f7c 100644 --- a/server.h +++ b/server.h @@ -37,20 +37,23 @@ extern sqlite3 *db; extern const char *NetworksQuery; extern const char *ContextsQuery; -extern const char *EventsQuery; +extern const char *EventsAfterQuery; +extern const char *EventsBeforeQuery; extern const char *SearchQuery; extern struct Statements { sqlite3_stmt *networks; sqlite3_stmt *contexts; - sqlite3_stmt *events; + sqlite3_stmt *eventsAfter; + sqlite3_stmt *eventsBefore; sqlite3_stmt *search; } stmt; static inline void dbClose(void) { if (stmt.networks) sqlite3_finalize(stmt.networks); if (stmt.contexts) sqlite3_finalize(stmt.contexts); - if (stmt.events) sqlite3_finalize(stmt.events); + if (stmt.eventsAfter) sqlite3_finalize(stmt.eventsAfter); + if (stmt.eventsBefore) sqlite3_finalize(stmt.eventsBefore); if (stmt.search) sqlite3_finalize(stmt.search); sqlite3_close(db); } @@ -92,6 +95,7 @@ extern const char *Pages[PagesLen]; X(Network, "network", kvalid_stringne) \ X(Context, "context", kvalid_stringne) \ X(After, "after", kvalid_stringne) \ + X(Before, "before", kvalid_stringne) \ X(Query, "query", kvalid_stringne) enum { @@ -104,6 +108,7 @@ enum { extern const struct kvalid Keys[KeysLen]; extern bool pagePublic; +extern int pageLimit; enum kcgi_err pageNetworks(struct kreq *req); enum kcgi_err pageContexts(struct kreq *req); -- cgit 1.4.1