Mercurial > paster
changeset 2:65607ae124b1
pasterd: implement /new
author | David Demelier <markand@malikania.fr> |
---|---|
date | Tue, 04 Feb 2020 20:47:00 +0100 |
parents | 836a698946f8 |
children | 80d67d8dbfb2 |
files | database.c http.c themes/minimal/400.html themes/minimal/header.html themes/minimal/new.html |
diffstat | 5 files changed, 402 insertions(+), 30 deletions(-) [+] |
line wrap: on
line diff
--- a/database.c Tue Feb 04 16:44:43 2020 +0100 +++ b/database.c Tue Feb 04 20:47:00 2020 +0100 @@ -61,6 +61,7 @@ " , visible\n" " , duration\n" " FROM paste\n" + " WHERE visible = 1\n" " ORDER BY date\n" " LIMIT ?\n";
--- a/http.c Tue Feb 04 16:44:43 2020 +0100 +++ b/http.c Tue Feb 04 20:47:00 2020 +0100 @@ -23,6 +23,7 @@ #include <stdint.h> #include <stdio.h> #include <stdlib.h> +#include <string.h> #include <unistd.h> #include <kcgi.h> @@ -81,6 +82,213 @@ struct paste paste; }; +static const char *tmpl_index_keywords[] = { + "uuid", + "name", + "author", + "language", + "expiration" +}; + +static const char *tmpl_paste_keywords[] = { + "uuid", + "title", + "author", + "language", + "code", + "timestamp", + "visible", + "duration" +}; + +static const char *tmpl_new_keywords[] = { + "title", /* /fork only */ + "author", /* /fork only */ + "code", /* /fork only */ + "languages" +}; + +static const char *languages[] = { + "1c", + "abnf", + "accesslog", + "actionscript", + "ada", + "apache", + "applescript", + "arduino", + "armasm", + "asciidoc", + "aspectj", + "autohotkey", + "autoit", + "avrasm", + "awk", + "axapta", + "bash", + "basic", + "bnf", + "brainfuck", + "cal", + "capnproto", + "ceylon", + "clean", + "clojure", + "clojure-repl", + "cmake", + "coffeescript", + "coq", + "cos", + "cpp", + "crmsh", + "crystal", + "cs", + "csp", + "css", + "dart", + "delphi", + "diff", + "django", + "d", + "dns", + "dockerfile", + "dos", + "dsconfig", + "dts", + "dust", + "ebnf", + "elixir", + "elm", + "erb", + "erlang", + "erlang-repl", + "excel", + "fix", + "flix", + "fortran", + "fsharp", + "gams", + "gauss", + "gcode", + "gherkin", + "glsl", + "go", + "golo", + "gradle", + "groovy", + "haml", + "handlebars", + "haskell", + "haxe", + "hsp", + "htmlbars", + "http", + "hy", + "inform7", + "ini", + "irpf90", + "java", + "javascript", + "jboss-cli", + "json", + "julia", + "julia-repl", + "kotlin", + "lasso", + "ldif", + "leaf", + "less", + "lisp", + "livecodeserver", + "livescript", + "llvm", + "lsl", + "lua", + "makefile", + "markdown", + "mathematica", + "matlab", + "maxima", + "mel", + "mercury", + "mipsasm", + "mizar", + "mojolicious", + "monkey", + "moonscript", + "n1ql", + "nginx", + "nimrod", + "nix", + "nohighlight", + "nsis", + "objectivec", + "ocaml", + "openscad", + "oxygene", + "parser3", + "perl", + "pf", + "php", + "pony", + "powershell", + "processing", + "profile", + "prolog", + "protobuf", + "puppet", + "purebasic", + "python", + "q", + "qml", + "rib", + "r", + "roboconf", + "routeros", + "rsl", + "ruby", + "ruleslanguage", + "rust", + "scala", + "scheme", + "scilab", + "scss", + "shell", + "smali", + "smalltalk", + "sml", + "sqf", + "sql", + "stan", + "stata", + "step21", + "stylus", + "subunit", + "swift", + "taggerscript", + "tap", + "tcl", + "tex", + "thrift", + "tp", + "twig", + "typescript", + "vala", + "vbnet", + "vbscript-html", + "vbscript", + "verilog", + "vhdl", + "vim", + "x86asm", + "xl", + "xml", + "xquery", + "yaml", + "zephir", + NULL +}; + static const char * template(const char *filename) { @@ -92,6 +300,34 @@ return path; } +static void +header(struct kreq *req) +{ + khttp_template(req, NULL, template("header.html")); +} + +static void +footer(struct kreq *req) +{ + khttp_template(req, NULL, template("footer.html")); +} + +static long long int +duration(const char *val) +{ + if (strcmp(val, "hour") == 0) + return PASTE_HOUR; + if (strcmp(val, "day") == 0) + return PASTE_DAY; + if (strcmp(val, "week") == 0) + return PASTE_WEEK; + if (strcmp(val, "month") == 0) + return PASTE_MONTH; + + /* Default to month. */ + return PASTE_MONTH; +} + static int tmpl_paste(size_t index, void *arg) { @@ -166,15 +402,8 @@ { /* No check, only one index. */ struct tmpl_index *data = arg; - const char *keywords[] = { - "uuid", - "name", - "author", - "language", - "expiration" - }; - struct ktemplate kt = { - .key = keywords, + const struct ktemplate kt = { + .key = tmpl_index_keywords, .keysz = 5, .arg = data, .cb = tmpl_index_pastes @@ -188,16 +417,36 @@ return true; } -static void -header(struct kreq *req) +static int +tmpl_new(size_t index, void *arg) { - khttp_template(req, NULL, template("header.html")); -} + struct tmpl_paste *data = arg; + struct paste *paste = &data->paste; -static void -footer(struct kreq *req) -{ - khttp_template(req, NULL, template("footer.html")); + switch (index) { + case 0: + if (paste->title) + khttp_puts(data->req, paste->title); + break; + case 1: + if (paste->author) + khttp_puts(data->req, paste->author); + break; + case 2: + if (paste->code) + khttp_puts(data->req, paste->code); + break; + case 3: + /* TODO: fragment? */ + for (const char **l = languages; *l != NULL; ++l) + khttp_puts(data->req, + bprintf("<option value=\"%s\">%s</option>", *l, *l)); + break; + default: + break; + }; + + return true; } static void @@ -230,13 +479,97 @@ footer(req); } + for (size_t i = 0; i < data.count; ++i) + paste_finish(&data.pastes[i]); + khttp_free(req); } static void +page_new_get(struct kreq *req) +{ + struct tmpl_paste data = { + .req = req + }; + const struct ktemplate kt = { + .key = tmpl_new_keywords, + .keysz = 4, + .cb = tmpl_new, + .arg = &data + }; + + khttp_head(req, kresps[KRESP_CONTENT_TYPE], "%s", kmimetypes[KMIME_TEXT_HTML]); + khttp_head(req, kresps[KRESP_STATUS], "%s", khttps[KHTTP_200]); + khttp_body(req); + header(req); + khttp_template(req, &kt, template("new.html")); + footer(req); + khttp_free(req); +} + +static void +page_new_post(struct kreq *req) +{ + struct paste paste = { + .visible = true + }; + + for (size_t i = 0; i < req->fieldsz; ++i) { + const char *key = req->fields[i].key; + const char *val = req->fields[i].val; + + if (strcmp(key, "title") == 0) + paste.title = estrdup(val); + else if (strcmp(key, "author") == 0) + paste.author = estrdup(val); + else if (strcmp(key, "language") == 0) + paste.language = estrdup(val); + else if (strcmp(key, "duration") == 0) + paste.duration = duration(val); + else if (strcmp(key, "code") == 0) + paste.code = estrdup(val); + else if (strcmp(key, "private") == 0) + paste.visible = strcmp(val, "on") != 0; + } + + khttp_head(req, kresps[KRESP_CONTENT_TYPE], "%s", kmimetypes[KMIME_TEXT_HTML]); + + if (!paste.title || !paste.author || !paste.language || !paste.code) { + khttp_head(req, kresps[KRESP_STATUS], "%s", khttps[KHTTP_400]); + khttp_body(req); + header(req); + khttp_template(req, NULL, template("400.html")); + footer(req); + } else { + if (!database_insert(&paste)) { + khttp_head(req, kresps[KRESP_STATUS], "%s", khttps[KHTTP_500]); + khttp_body(req); + header(req); + khttp_template(req, NULL, template("500.html")); + footer(req); + } else { + khttp_head(req, kresps[KRESP_STATUS], "%s", khttps[KHTTP_302]); + khttp_head(req, kresps[KRESP_LOCATION], "/paste/%s", paste.uuid); + } + } + + khttp_free(req); + paste_finish(&paste); +} + +static void page_new(struct kreq *req) { - (void)req; + switch (req->method) { + case KMETHOD_GET: + page_new_get(req); + break; + case KMETHOD_POST: + page_new_post(req); + break; + default: + break; + } } static void @@ -259,18 +592,8 @@ khttp_body(req); khttp_template(req, NULL, template("404.html")); } else { - const char *keywords[] = { - "uuid", - "title", - "author", - "language", - "code", - "timestamp", - "visible", - "duration" - }; const struct ktemplate kt = { - .key = keywords, + .key = tmpl_paste_keywords, .keysz = 8, .cb = tmpl_paste, .arg = &data @@ -281,8 +604,10 @@ header(req); khttp_template(req, &kt, template("paste.html")); footer(req); - khttp_free(req); } + + khttp_free(req); + paste_finish(&data.paste); } static void
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/themes/minimal/400.html Tue Feb 04 20:47:00 2020 +0100 @@ -0,0 +1,1 @@ +<h1>Bad request</h1>
--- a/themes/minimal/header.html Tue Feb 04 16:44:43 2020 +0100 +++ b/themes/minimal/header.html Tue Feb 04 20:47:00 2020 +0100 @@ -4,3 +4,8 @@ <meta charset="UTF-8"> </head> <body> + + <h1>Menu</h1> + <ul> + <li><a href="/new">New</a></li> + </ul>
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/themes/minimal/new.html Tue Feb 04 20:47:00 2020 +0100 @@ -0,0 +1,40 @@ + <h1>Create paste</h1> + + <form action="/new" method="post"> + <table> + <tr> + <td>Title</td> + <td><input name="title" type="text" placeholder="Untitled" value="@@title@@" /></td> + </tr> + + <tr> + <td>Author</td> + <td><input name="author" type="text" placeholder="Anonymous" value="@@author@@" /></td> + </tr> + + <tr> + <td>Language</td> + <td><select name="language">@@languages@@</select></td> + </tr> + + <tr> + <td>Expires in</td> + <td> + <select name="duration"> + <option value="month">one month</option> + <option value="week">one week</option> + <option value="day">one day</option> + <option value="hour">one hour</option> + </select> + </td> + </tr> + + <tr> + <td>Private</td> + <td><input type="checkbox" name="private"></input></td> + </tr> + </table> + + <textarea id="code" class="textarea" placeholder="What do you want to share?" rows="10" name="code">@@code@@</textarea> + <button>Submit</button> + </form>