timekeeper

[Abandoned unfinished] CGI web application in C for time tracking. (My first, just a learning project)
Log | Files | Refs | README

commit 074e9c6c7b8abab17a0c9178b4031c31210183ed
parent 879ba90362fefcfcda2b1898ac1e7be930060311
Author: Jacob R. Edwards <jacob@jacobedwards.org>
Date:   Mon, 11 Mar 2024 01:18:34 -0700

Add export page

This page exports timesheets to TSV. By default times are serialized
to the ISO 8601 format (i.e. "2002-10-02T13:00:00Z"), but I also
made it possible to output times as seconds since the UNIX epoch.

Diffstat:
MMakefile | 2+-
Mkey.c | 3++-
Mkey.h | 1+
Apages/export.c | 90+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Mpages/pages.h | 2++
Mtimekeeper.c | 2++
6 files changed, 98 insertions(+), 2 deletions(-)

diff --git a/Makefile b/Makefile @@ -5,7 +5,7 @@ lddflags = ${LDDFLAGS} -static -L/usr/local/lib -lkcgi -lkcgihtml -lz -lsqlbox - prefix = /var/www/htdocs/${name}.primus.lan pages = pages/index.c pages/404.c pages/login.c pages/logout.c \ - pages/account.c pages/main.c + pages/account.c pages/main.c pages/export.c hdrsrc = page.c html.c user.c stmt.c key.c times.c src = ${hdrsrc} ${pages} pages/util.c hdr = ${hdrsrc:.c=.h} util.h pages/util.h pages/pages.h diff --git a/key.c b/key.c @@ -39,5 +39,6 @@ struct kvalid keys[] = { [KeyHash] = { kvalid_stringne, "hash" }, [KeyCreate] = { kvalid_stringne, "create" }, [KeyDelete] = { kvalid_stringne, "delete" }, - [KeyTime] = { kvalid_stringne, "time" } + [KeyTime] = { kvalid_stringne, "time" }, + [KeyFormat] = { kvalid_stringne, "format" } }; diff --git a/key.h b/key.h @@ -5,6 +5,7 @@ enum http_key { KeyCreate, /* Whether to create a new user in login page */ KeyDelete, /* Delete account in account page */ KeyTime, /* one of start, startbreak, endbreak, end */ + KeyFormat, /* currently either tsv;epoch or ;epoch for /export */ KeyMax }; diff --git a/pages/export.c b/pages/export.c @@ -0,0 +1,90 @@ +#define const + +#include <stdlib.h> +#include <string.h> + +#include "common.h" +#include "../times.h" + +/* useful for scripting and such */ +enum kcgi_err +serialize_epoch(struct pagedata *pd, time_t time) +{ + return khttp_printf(&pd->req, "%lld", time); +} + +enum kcgi_err +serialize_ustr(struct pagedata *pd, time_t time) +{ + char buf[64]; + + if (!khttp_epoch2ustr(time, buf, sizeof(buf))) + return KCGI_SYSTEM; + return khttp_puts(&pd->req, buf); +} + +enum kcgi_err +pageexport(struct pagedata *pd) +{ + enum kcgi_err status; + time_t *times; + size_t len; + size_t a, i; + int b; + char *tmp; + enum kcgi_err (*serialize)(struct pagedata *, time_t) = serialize_ustr; + + if (!pd->user) + return errorpage(pd, KHTTP_401); + + if (pd->req.fieldmap[KeyFormat]) { + /* + * format.timeformat + * i.e. csv.epoch + */ + tmp = pd->req.fieldmap[KeyFormat]->parsed.s; + if (strcmp(tmp, ".epoch") != 0 && strcmp(tmp, "tsv.epoch") != 0) + return errorpage(pd, KHTTP_415); + serialize = serialize_epoch; + } + + times = gettimes(pd, pd->user->hash, &len); + if (!times) + return errorpage(pd, KHTTP_500); + + if ((status = khttp_head(&pd->req, kresps[KRESP_STATUS], + "%s", khttps[KHTTP_200])) != KCGI_OK || + (status = khttp_head(&pd->req, kresps[KRESP_CONTENT_TYPE], + "text/tsv")) != KCGI_OK || + (status = khttp_head(&pd->req, kresps[KRESP_CONTENT_DISPOSITION], + "attachment; filename=\"timekeeper-times.tsv\"")) != KCGI_OK || + (status = khttp_body(&pd->req)) != KCGI_OK) { + free(times); + return status; + } + + for (a = 0; a < len / 4; ++a) { + for (b = 0; b < 4; ++b) { + if (b && (status = khttp_putc(&pd->req, '\t')) != KCGI_OK) { + free(times); + return status; + } + + i = (a * 4) + b; + if (times[i]) { + status = serialize(pd, times[i]); + if (status != KCGI_OK) { + free(times); + return status; + } + } + } + if ((status = khttp_putc(&pd->req, '\n')) != KCGI_OK) { + free(times); + return status; + } + } + + free(times); + return KCGI_OK; +} diff --git a/pages/pages.h b/pages/pages.h @@ -4,6 +4,7 @@ enum Page { PageLogout, PageAccount, PageMain, + PageExport, Page404, PageMax }; @@ -13,4 +14,5 @@ enum kcgi_err pageindex(struct pagedata *pd); enum kcgi_err pagelogin(struct pagedata *pd); enum kcgi_err pagelogout(struct pagedata *pd); enum kcgi_err pageaccount(struct pagedata *pd); +enum kcgi_err pageexport(struct pagedata *pd); enum kcgi_err pagemain(struct pagedata *pd); diff --git a/timekeeper.c b/timekeeper.c @@ -34,6 +34,7 @@ static char *pages[] = { [PageLogout] = "logout", [PageAccount] = "account", [PageMain] = "main", + [PageExport] = "export", [Page404] = "404" }; @@ -67,6 +68,7 @@ main(void) [PageLogout] = pagelogout, [PageAccount] = pageaccount, [PageMain] = pagemain, + [PageExport] = pageexport, [Page404] = page404 };