summary refs log tree commit diff
diff options
context:
space:
mode:
authorJune McEnroe <june@causal.agency>2020-07-11 14:04:25 -0400
committerJune McEnroe <june@causal.agency>2020-07-11 14:04:25 -0400
commit24c7965d9d0aaf27985d29c5cbb12a4e08ac7d9c (patch)
tree2a9e3955d59c375edb7d02ae0bd195bf966d57ea
parentImplement basic search page (diff)
downloadscooper-24c7965d9d0aaf27985d29c5cbb12a4e08ac7d9c.tar.gz
scooper-24c7965d9d0aaf27985d29c5cbb12a4e08ac7d9c.zip
Factor out "scope" of pages
Use this to keep the search query around and hide network and context
from the search results if the scope is already limited.
-rw-r--r--contexts.c14
-rw-r--r--events.c21
-rw-r--r--html.c35
-rw-r--r--networks.c4
-rw-r--r--search.c26
-rw-r--r--server.h22
6 files changed, 65 insertions, 57 deletions
diff --git a/contexts.c b/contexts.c
index d8eb4fd..e17ccfe 100644
--- a/contexts.c
+++ b/contexts.c
@@ -46,22 +46,22 @@ const char *ContextsQuery = SQL(
 );
 
 enum kcgi_err pageContexts(struct kreq *req) {
-	if (!req->fieldmap[Network]) return httpFail(req, KHTTP_400);
+	struct Scope scope = htmlScope(req);
+	if (!scope.network) return httpFail(req, KHTTP_400);
+
 	enum kcgi_err error = httpHead(req, KHTTP_200, KMIME_TEXT_HTML);
 	if (req->method == KMETHOD_HEAD) return error;
 
-	const char *network = req->fieldmap[Network]->parsed.s;
-
 	struct khtmlreq html;
 	error = error
 		|| khttp_body(req)
 		|| khtml_open(&html, req, KHTML_PRETTY)
-		|| htmlHead(&html, network)
-		|| htmlNav(&html, network, NULL);
+		|| htmlHead(&html, scope.network)
+		|| htmlNav(&html, scope);
 	if (error) return error;
 
 	dbBindInt(stmt.contexts, ":recent", pageRecent);
-	dbBindText(stmt.contexts, ":network", network);
+	dbBindText(stmt.contexts, ":network", scope.network);
 	if (pagePublic) dbBindInt(stmt.contexts, ":query", false);
 
 	enum State {
@@ -92,7 +92,7 @@ enum kcgi_err pageContexts(struct kreq *req) {
 
 		char *href = khttp_urlpart(
 			NULL, NULL, Pages[Events],
-			Keys[Network].name, network,
+			Keys[Network].name, scope.network,
 			Keys[Context].name, context,
 			NULL
 		);
diff --git a/events.c b/events.c
index 32e94c2..5e332a3 100644
--- a/events.c
+++ b/events.c
@@ -70,11 +70,8 @@ const char *EventsBeforeQuery = SQL(
 );
 
 enum kcgi_err pageEvents(struct kreq *req) {
-	if (!req->fieldmap[Network] || !req->fieldmap[Context]) {
-		return httpFail(req, KHTTP_400);
-	}
-	const char *network = req->fieldmap[Network]->parsed.s;
-	const char *context = req->fieldmap[Context]->parsed.s;
+	struct Scope scope = htmlScope(req);
+	if (!scope.network || !scope.context) return httpFail(req, KHTTP_400);
 
 	if (!req->fieldmap[After] && !req->fieldmap[Before]) {
 		struct tm *tm = gmtime(&(time_t) { time(NULL) });
@@ -85,8 +82,8 @@ enum kcgi_err pageEvents(struct kreq *req) {
 
 		char *url = khttp_urlpart(
 			NULL, NULL, Pages[Events],
-			Keys[Network].name, network,
-			Keys[Context].name, context,
+			Keys[Network].name, scope.network,
+			Keys[Context].name, scope.context,
 			Keys[Before].name, time,
 			NULL
 		);
@@ -106,16 +103,16 @@ enum kcgi_err pageEvents(struct kreq *req) {
 	error = error
 		|| khttp_body(req)
 		|| khtml_open(&html, req, KHTML_PRETTY)
-		|| htmlHead(&html, context)
-		|| htmlNav(&html, network, context)
+		|| htmlHead(&html, scope.context)
+		|| htmlNav(&html, scope)
 		|| khtml_elem(&html, KELEM_TABLE);
 	if (error) return error;
 
 	sqlite3_stmt *events = stmt.eventsAfter;
 	if (req->fieldmap[Before]) events = stmt.eventsBefore;
 
-	dbBindText(events, ":network", network);
-	dbBindText(events, ":context", context);
+	dbBindText(events, ":network", scope.network);
+	dbBindText(events, ":context", scope.context);
 	if (pagePublic) dbBindInt(events, ":query", false);
 	dbBindText(events, ":time", time);
 	dbBindInt(events, ":limit", pageLimit);
@@ -132,7 +129,7 @@ enum kcgi_err pageEvents(struct kreq *req) {
 			.target = (const char *)sqlite3_column_text(events, 6),
 			.message = (const char *)sqlite3_column_text(events, 7),
 		};
-		error = htmlEvent(&html, event);
+		error = htmlEvent(&html, scope, event);
 		if (error) break;
 	}
 	if (result != SQLITE_DONE) errx(EX_SOFTWARE, "%s", sqlite3_errmsg(db));
diff --git a/html.c b/html.c
index 9386205..562f909 100644
--- a/html.c
+++ b/html.c
@@ -49,7 +49,7 @@ enum kcgi_err htmlHead(struct khtmlreq *html, const char *title) {
 }
 
 enum kcgi_err
-htmlNav(struct khtmlreq *html, const char *network, const char *context) {
+htmlNav(struct khtmlreq *html, struct Scope scope) {
 	enum kcgi_err error = 0
 		|| khtml_elem(html, KELEM_NAV)
 		|| khtml_elem(html, KELEM_OL)
@@ -59,33 +59,33 @@ htmlNav(struct khtmlreq *html, const char *network, const char *context) {
 		|| khtml_closeelem(html, 2);
 	if (error) return error;
 
-	if (network) {
+	if (scope.network) {
 		char *href = khttp_urlpart(
 			NULL, NULL, Pages[Contexts],
-			Keys[Network].name, network,
+			Keys[Network].name, scope.network,
 			NULL
 		);
 		if (!href) err(EX_OSERR, "khttp_urlpart");
 		error = 0
 			|| khtml_elem(html, KELEM_LI)
 			|| khtml_attr(html, KELEM_A, KATTR_HREF, href, KATTR__MAX)
-			|| khtml_puts(html, network)
+			|| khtml_puts(html, scope.network)
 			|| khtml_closeelem(html, 2);
 		if (error) return error;
 	}
 
-	if (network && context) {
+	if (scope.network && scope.context) {
 		char *href = khttp_urlpart(
 			NULL, NULL, Pages[Events],
-			Keys[Network].name, network,
-			Keys[Context].name, context,
+			Keys[Network].name, scope.network,
+			Keys[Context].name, scope.context,
 			NULL
 		);
 		if (!href) err(EX_OSERR, "khttp_urlpart");
 		error = 0
 			|| khtml_elem(html, KELEM_LI)
 			|| khtml_attr(html, KELEM_A, KATTR_HREF, href, KATTR__MAX)
-			|| khtml_puts(html, context)
+			|| khtml_puts(html, scope.context)
 			|| khtml_closeelem(html, 2);
 		if (error) return error;
 	}
@@ -93,7 +93,8 @@ htmlNav(struct khtmlreq *html, const char *network, const char *context) {
 	char label[256];
 	snprintf(
 		label, sizeof(label), "Search%s%s",
-		(network ? " " : ""), (context ? context : network ? network : "")
+		(scope.network ? " " : ""),
+		(scope.context ? scope.context : scope.network ? scope.network : "")
 	);
 
 	error = 0
@@ -108,6 +109,7 @@ htmlNav(struct khtmlreq *html, const char *network, const char *context) {
 			html, KELEM_INPUT,
 			KATTR_TYPE, "search",
 			KATTR_NAME, Keys[Query].name,
+			KATTR_VALUE, (scope.query ? scope.query : ""),
 			KATTR__MAX
 		)
 		|| khtml_attr(
@@ -118,23 +120,23 @@ htmlNav(struct khtmlreq *html, const char *network, const char *context) {
 		);
 	if (error) return error;
 
-	if (network) {
+	if (scope.network) {
 		error = khtml_attr(
 			html, KELEM_INPUT,
 			KATTR_TYPE, "hidden",
 			KATTR_NAME, Keys[Network].name,
-			KATTR_VALUE, network,
+			KATTR_VALUE, scope.network,
 			KATTR__MAX
 		);
 		if (error) return error;
 	}
 
-	if (context) {
+	if (scope.context) {
 		error = khtml_attr(
 			html, KELEM_INPUT,
 			KATTR_TYPE, "hidden",
 			KATTR_NAME, Keys[Context].name,
-			KATTR_VALUE, context,
+			KATTR_VALUE, scope.context,
 			KATTR__MAX
 		);
 		if (error) return error;
@@ -284,7 +286,8 @@ static const char *Types[TypesLen] = {
 #undef X
 };
 
-enum kcgi_err htmlEvent(struct khtmlreq *html, struct Event event) {
+enum kcgi_err
+htmlEvent(struct khtmlreq *html, struct Scope scope, struct Event event) {
 	const char *type = (event.type < TypesLen ? Types[event.type] : "unknown");
 	return 0
 		|| khtml_attrx(
@@ -294,8 +297,8 @@ enum kcgi_err htmlEvent(struct khtmlreq *html, struct Event event) {
 			KATTR__MAX
 		)
 		|| eventTime(html, event)
-		|| eventNetwork(html, event)
-		|| eventContext(html, event)
+		|| (scope.network ? 0 : eventNetwork(html, event))
+		|| (scope.context ? 0 : eventContext(html, event))
 		|| eventNick(html, event)
 		|| eventMessage(html, event)
 		|| khtml_closeelem(html, 1);
diff --git a/networks.c b/networks.c
index 7f974c4..74b9ea2 100644
--- a/networks.c
+++ b/networks.c
@@ -44,6 +44,8 @@ const char *NetworksQuery = SQL(
 );
 
 enum kcgi_err pageNetworks(struct kreq *req) {
+	struct Scope scope = {0};
+
 	enum kcgi_err error = httpHead(req, KHTTP_200, KMIME_TEXT_HTML);
 	if (req->method == KMETHOD_HEAD) return error;
 
@@ -52,7 +54,7 @@ enum kcgi_err pageNetworks(struct kreq *req) {
 		|| khttp_body(req)
 		|| khtml_open(&html, req, KHTML_PRETTY)
 		|| htmlHead(&html, "Litterbox")
-		|| htmlNav(&html, NULL, NULL);
+		|| htmlNav(&html, scope);
 	if (error) return error;
 
 	dbBindInt(stmt.networks, ":recent", pageRecent);
diff --git a/search.c b/search.c
index 767081b..6fba589 100644
--- a/search.c
+++ b/search.c
@@ -46,20 +46,12 @@ const char *SearchQuery = SQL(
 );
 
 enum kcgi_err pageSearch(struct kreq *req) {
-	if (!req->fieldmap[Query]) {
-		return httpFail(req, KHTTP_400);
-	}
-	if (req->fieldmap[Context] && !req->fieldmap[Network]) {
-		return httpFail(req, KHTTP_400);
-	}
-	const char *query = req->fieldmap[Query]->parsed.s;
+	struct Scope scope = htmlScope(req);
+	if (!scope.query) return httpFail(req, KHTTP_400);
+	if (scope.context && !scope.network) return httpFail(req, KHTTP_400);
 
 	int64_t offset = 0;
-	const char *network = NULL;
-	const char *context = NULL;
 	if (req->fieldmap[Offset]) offset = req->fieldmap[Offset]->parsed.i;
-	if (req->fieldmap[Network]) network = req->fieldmap[Network]->parsed.s;
-	if (req->fieldmap[Context]) context = req->fieldmap[Context]->parsed.s;
 
 	enum kcgi_err error = httpHead(req, KHTTP_200, KMIME_TEXT_HTML);
 	if (req->method == KMETHOD_HEAD) return error;
@@ -68,16 +60,16 @@ enum kcgi_err pageSearch(struct kreq *req) {
 	error = error
 		|| khttp_body(req)
 		|| khtml_open(&html, req, KHTML_PRETTY)
-		|| htmlHead(&html, query)
-		|| htmlNav(&html, network, context)
+		|| htmlHead(&html, scope.query)
+		|| htmlNav(&html, scope)
 		|| khtml_elem(&html, KELEM_TABLE);
 	if (error) return error;
 
 	dbBindText(stmt.search, ":highlight", "\26");
-	dbBindText(stmt.search, ":network", network);
-	dbBindText(stmt.search, ":context", context);
+	dbBindText(stmt.search, ":network", scope.network);
+	dbBindText(stmt.search, ":context", scope.context);
 	if (pagePublic) dbBindInt(stmt.search, ":query", false);
-	dbBindText(stmt.search, ":search", query);
+	dbBindText(stmt.search, ":search", scope.query);
 	dbBindInt(stmt.search, ":limit", pageLimit);
 	dbBindInt(stmt.search, ":offset", offset);
 
@@ -95,7 +87,7 @@ enum kcgi_err pageSearch(struct kreq *req) {
 			.target = (const char *)sqlite3_column_text(stmt.search, 8),
 			.message = (const char *)sqlite3_column_text(stmt.search, 9),
 		};
-		error = htmlEvent(&html, event);
+		error = htmlEvent(&html, scope, event);
 		if (error) break;
 	}
 	if (result != SQLITE_DONE) errx(EX_SOFTWARE, "%s", sqlite3_errmsg(db));
diff --git a/server.h b/server.h
index 502e228..318d103 100644
--- a/server.h
+++ b/server.h
@@ -171,10 +171,24 @@ static inline enum kcgi_err httpFail(struct kreq *req, enum khttp http) {
 		|| khttp_printf(req, "%s\n", khttps[http]);
 }
 
+struct Scope {
+	const char *network;
+	const char *context;
+	const char *query;
+};
+
+static inline struct Scope htmlScope(struct kreq *req) {
+	struct Scope s = {0};
+	if (req->fieldmap[Network]) s.network = req->fieldmap[Network]->parsed.s;
+	if (req->fieldmap[Context]) s.context = req->fieldmap[Context]->parsed.s;
+	if (req->fieldmap[Query]) s.query = req->fieldmap[Query]->parsed.s;
+	return s;
+}
+
 extern const char *htmlStylesheet;
 enum kcgi_err htmlHead(struct khtmlreq *html, const char *title);
-enum kcgi_err htmlNav(
-	struct khtmlreq *html, const char *network, const char *context
-);
+enum kcgi_err htmlNav(struct khtmlreq *html, struct Scope scope);
 enum kcgi_err htmlFooter(struct khtmlreq *html);
-enum kcgi_err htmlEvent(struct khtmlreq *html, struct Event event);
+enum kcgi_err htmlEvent(
+	struct khtmlreq *html, struct Scope scope, struct Event event
+);