diff options
author | June McEnroe <june@causal.agency> | 2020-07-10 14:54:45 -0400 |
---|---|---|
committer | June McEnroe <june@causal.agency> | 2020-07-10 14:54:45 -0400 |
commit | 3926094bc216277ff6c58e6e9efba64fc7af91da (patch) | |
tree | 55362740094489c3e59fbc125ed181dd18cf0077 | |
parent | Add -l and -r options (diff) | |
download | scooper-3926094bc216277ff6c58e6e9efba64fc7af91da.tar.gz scooper-3926094bc216277ff6c58e6e9efba64fc7af91da.zip |
Implement partial table output of events
This should work for both events and search pages.
-rw-r--r-- | default.css | 17 | ||||
-rw-r--r-- | events.c | 19 | ||||
-rw-r--r-- | html.c | 103 | ||||
-rw-r--r-- | server.h | 34 |
4 files changed, 167 insertions, 6 deletions
diff --git a/default.css b/default.css index 449132f..40d9e88 100644 --- a/default.css +++ b/default.css @@ -36,7 +36,24 @@ nav form { margin-top: 1em; } +td.nick { + text-align: right; +} +tr.privmsg td.nick span::before { + content: '<'; +} +tr.privmsg td.nick span::after { + content: '>'; +} +tr.action td.nick span::before { + content: '* '; +} +tr.notice td.nick span::before, tr.notice td.nick span::after { + content: '-'; +} + footer { + margin-top: 1em; display: flex; flex-wrap: wrap; justify-content: space-between; diff --git a/events.c b/events.c index 7962ab3..32e94c2 100644 --- a/events.c +++ b/events.c @@ -107,7 +107,8 @@ enum kcgi_err pageEvents(struct kreq *req) { || khttp_body(req) || khtml_open(&html, req, KHTML_PRETTY) || htmlHead(&html, context) - || htmlNav(&html, network, context); + || htmlNav(&html, network, context) + || khtml_elem(&html, KELEM_TABLE); if (error) return error; sqlite3_stmt *events = stmt.eventsAfter; @@ -121,11 +122,17 @@ enum kcgi_err pageEvents(struct kreq *req) { 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); + struct Event event = { + .event = sqlite3_column_int64(events, 0), + .time = sqlite3_column_int64(events, 1), + .type = sqlite3_column_int(events, 2), + .nick = (const char *)sqlite3_column_text(events, 3), + .user = (const char *)sqlite3_column_text(events, 4), + .host = (const char *)sqlite3_column_text(events, 5), + .target = (const char *)sqlite3_column_text(events, 6), + .message = (const char *)sqlite3_column_text(events, 7), + }; + error = htmlEvent(&html, event); if (error) break; } if (result != SQLITE_DONE) errx(EX_SOFTWARE, "%s", sqlite3_errmsg(db)); diff --git a/html.c b/html.c index 6141514..9f929e6 100644 --- a/html.c +++ b/html.c @@ -15,9 +15,11 @@ */ #include <err.h> +#include <inttypes.h> #include <stdio.h> #include <stdlib.h> #include <sysexits.h> +#include <time.h> #include "server.h" @@ -168,3 +170,104 @@ enum kcgi_err htmlFooter(struct khtmlreq *html) { || khtml_puts(html, "Columns") || khtml_closeto(html, 0); } + +static enum kcgi_err eventTime(struct khtmlreq *html, struct Event event) { + char time[sizeof("0000-00-00 00:00:00")]; + strftime(time, sizeof(time), "%F %T", gmtime(&event.time)); + + char *base = NULL; + if (event.network && event.context) { + base = khttp_urlpart( + NULL, NULL, Pages[Events], + Keys[Network].name, event.network, + Keys[Context].name, event.context, + Keys[After].name, time, + NULL + ); + if (!base) err(EX_OSERR, "khttp_urlpart"); + } + char *href = NULL; + asprintf(&href, "%s#%" PRId64, (base ? base : ""), event.event); + if (!href) err(EX_OSERR, "asprintf"); + if (base) free(base); + + enum kcgi_err error = 0 + || khtml_attr(html, KELEM_TD, KATTR_CLASS, "time", KATTR__MAX) + || khtml_attr(html, KELEM_A, KATTR_HREF, href, KATTR__MAX) + || khtml_attr(html, KELEM_TIME, KATTR_DATETIME, time, KATTR__MAX) + || khtml_puts(html, time) + || khtml_closeelem(html, 3); + + free(href); + return error; +} + +static enum kcgi_err eventNetwork(struct khtmlreq *html, struct Event event) { + if (!event.network) return KCGI_OK; + char *href = khttp_urlpart( + NULL, NULL, Pages[Contexts], + Keys[Network].name, event.network, + NULL + ); + if (!href) err(EX_OSERR, "khttp_urlpart"); + enum kcgi_err error = 0 + || khtml_attr(html, KELEM_TD, KATTR_CLASS, "network", KATTR__MAX) + || khtml_attr(html, KELEM_A, KATTR_HREF, href, KATTR__MAX) + || khtml_puts(html, event.network) + || khtml_closeelem(html, 2); + free(href); + return error; +} + +static enum kcgi_err eventContext(struct khtmlreq *html, struct Event event) { + if (!event.network || !event.context) return KCGI_OK; + char *href = khttp_urlpart( + NULL, NULL, Pages[Events], + Keys[Network].name, event.network, + Keys[Context].name, event.context, + NULL + ); + if (!href) err(EX_OSERR, "khttp_urlpart"); + enum kcgi_err error = 0 + || khtml_attr(html, KELEM_TD, KATTR_CLASS, "context", KATTR__MAX) + || khtml_attr(html, KELEM_A, KATTR_HREF, href, KATTR__MAX) + || khtml_puts(html, event.context) + || khtml_closeelem(html, 2); + free(href); + return error; +} + +static enum kcgi_err eventNick(struct khtmlreq *html, struct Event event) { + char *mask = NULL; + asprintf(&mask, "%s!%s@%s", event.nick, event.user, event.host); + if (!mask) err(EX_OSERR, "asprintf"); + enum kcgi_err error = 0 + || khtml_attr(html, KELEM_TD, KATTR_CLASS, "nick", KATTR__MAX) + || khtml_attr(html, KELEM_SPAN, KATTR_TITLE, mask, KATTR__MAX) + || khtml_puts(html, event.nick) + || khtml_closeelem(html, 2); + free(mask); + return error; +} + +static const char *Types[TypesLen] = { +#define X(id, name) [id] = name, + ENUM_TYPE +#undef X +}; + +enum kcgi_err htmlEvent(struct khtmlreq *html, struct Event event) { + const char *type = (event.type < TypesLen ? Types[event.type] : "unknown"); + return 0 + || khtml_attrx( + html, KELEM_TR, + KATTR_ID, KATTRX_INT, event.event, + KATTR_CLASS, KATTRX_STRING, type, + KATTR__MAX + ) + || eventTime(html, event) + || eventNetwork(html, event) + || eventContext(html, event) + || eventNick(html, event) + || khtml_closeelem(html, 1); +} diff --git a/server.h b/server.h index ba08a89..bb9bc60 100644 --- a/server.h +++ b/server.h @@ -33,6 +33,39 @@ enum { DatabaseVersion = 4 }; +#define ENUM_TYPE \ + X(Privmsg, "privmsg") \ + X(Notice, "notice") \ + X(Action, "action") \ + X(Join, "join") \ + X(Part, "part") \ + X(Quit, "quit") \ + X(Kick, "kick") \ + X(Nick, "nick") \ + X(Topic, "topic") \ + X(Ban, "ban") \ + X(Unban, "unban") + +enum Type { +#define X(id, name) id, + ENUM_TYPE +#undef X + TypesLen, +}; + +struct Event { + int64_t event; + time_t time; + const char *network; + const char *context; + enum Type type; + const char *nick; + const char *user; + const char *host; + const char *target; + const char *message; +}; + extern sqlite3 *db; extern const char *NetworksQuery; @@ -143,3 +176,4 @@ enum kcgi_err htmlNav( struct khtmlreq *html, const char *network, const char *context ); enum kcgi_err htmlFooter(struct khtmlreq *html); +enum kcgi_err htmlEvent(struct khtmlreq *html, struct Event event); |