From 03463de7431151ceeafee96a53ed5b3328a40f75 Mon Sep 17 00:00:00 2001 From: jaina heartles Date: Tue, 13 Dec 2022 02:05:00 -0800 Subject: [PATCH 1/8] Support types that can't be zero-initialized --- src/template/lib.zig | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/template/lib.zig b/src/template/lib.zig index bfcf5d3..b9d6acb 100644 --- a/src/template/lib.zig +++ b/src/template/lib.zig @@ -304,7 +304,11 @@ fn AddCapture(comptime Root: type, comptime name: []const u8, comptime Val: type fn addCapture(root: anytype, comptime name: []const u8, val: anytype) AddCapture(@TypeOf(root), name, @TypeOf(val)) { if (comptime std.mem.eql(u8, name, "_")) return root; - var result = std.mem.zeroInit(AddCapture(@TypeOf(root), name, @TypeOf(val)), root); + + var result: AddCapture(@TypeOf(root), name, @TypeOf(val)) = undefined; + inline for (std.meta.fields(@TypeOf(root))) |f| { + @field(result, f.name) = @field(root, f.name); + } @field(result, name) = val; return result; } From a49131f6bf16e3a0553a349bfffcaf2354b23c22 Mon Sep 17 00:00:00 2001 From: jaina heartles Date: Tue, 13 Dec 2022 02:05:37 -0800 Subject: [PATCH 2/8] Basic drive folder page --- src/main/controllers/web.zig | 24 +++++++++++++++++++ .../controllers/web/drive/directory.tmpl.html | 18 ++++++++++++++ 2 files changed, 42 insertions(+) create mode 100644 src/main/controllers/web/drive/directory.tmpl.html diff --git a/src/main/controllers/web.zig b/src/main/controllers/web.zig index 7e5d23d..eed3e5f 100644 --- a/src/main/controllers/web.zig +++ b/src/main/controllers/web.zig @@ -17,6 +17,7 @@ pub const routes = .{ controllers.apiEndpoint(cluster.overview), controllers.apiEndpoint(cluster.communities.create.page), controllers.apiEndpoint(cluster.communities.create.submit), + controllers.apiEndpoint(drive.details), }; const static = struct { @@ -229,6 +230,29 @@ const user_details = struct { } }; +const drive = struct { + const details = struct { + pub const path = "/drive/:path*"; + pub const method = .GET; + + pub const Args = struct { + path: []const u8, + }; + + pub const dir_tmpl = @embedFile("./web/drive/directory.tmpl.html"); + + pub fn handler(req: anytype, res: anytype, srv: anytype) !void { + const info = try srv.driveGet(req.args.path); + defer util.deepFree(srv.allocator, info); + + switch (info) { + .dir => |dir| try res.template(.ok, srv, dir_tmpl, .{ .dir = dir }), + else => unreachable, + } + } + }; +}; + const cluster = struct { const overview = struct { pub const path = "/cluster/overview"; diff --git a/src/main/controllers/web/drive/directory.tmpl.html b/src/main/controllers/web/drive/directory.tmpl.html new file mode 100644 index 0000000..7eb3621 --- /dev/null +++ b/src/main/controllers/web/drive/directory.tmpl.html @@ -0,0 +1,18 @@ +
+ + {#for .dir.children.? |$child| =} + + {#switch $child case dir |$dir| =} + + + {#case file |$file| =} + + + + + + {/switch =} + + {/for=} +
{$dir.name.?}{$file.name.?}{#if $file.meta.content_type |$t|}{$t}{/if}{$file.meta.size}{$file.meta.created_at}
+
From 07413747c290d1879a4ab539617ffe0391246fe7 Mon Sep 17 00:00:00 2001 From: jaina heartles Date: Tue, 13 Dec 2022 02:16:13 -0800 Subject: [PATCH 3/8] Use an eye icon for sensitive images --- src/main/controllers/web/drive/directory.tmpl.html | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/main/controllers/web/drive/directory.tmpl.html b/src/main/controllers/web/drive/directory.tmpl.html index 7eb3621..86d1784 100644 --- a/src/main/controllers/web/drive/directory.tmpl.html +++ b/src/main/controllers/web/drive/directory.tmpl.html @@ -6,7 +6,12 @@ {$dir.name.?} {#case file |$file| =} - + + {= #if $file.meta.sensitive =} + + {= #else =} + + {= /if =} {$file.name.?} {#if $file.meta.content_type |$t|}{$t}{/if} {$file.meta.size} From 620608964fe4de8c357e223fd984589dc564fd02 Mon Sep 17 00:00:00 2001 From: jaina heartles Date: Tue, 13 Dec 2022 02:28:25 -0800 Subject: [PATCH 4/8] Add user details to template context --- src/main/controllers.zig | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/main/controllers.zig b/src/main/controllers.zig index b34a95f..98cbcf5 100644 --- a/src/main/controllers.zig +++ b/src/main/controllers.zig @@ -223,6 +223,9 @@ pub const Response = struct { pub fn template(self: *Self, status_code: http.Status, srv: anytype, comptime templ: []const u8, data: anytype) !void { try self.headers.put("Content-Type", "text/html"); + const user = if (srv.user_id) |uid| try srv.getUser(uid) else null; + defer util.deepFree(srv.allocator, user); + var stream = try self.open(status_code); defer stream.close(); @@ -237,6 +240,7 @@ pub const Response = struct { data, .{ .community = srv.community, + .user = user, .user_id = srv.user_id, }, ); From 434b0e07d03b1a4c504bbf4685bc329bf7909ade Mon Sep 17 00:00:00 2001 From: jaina heartles Date: Tue, 13 Dec 2022 02:28:37 -0800 Subject: [PATCH 5/8] use std.meta.eql for equality --- src/template/lib.zig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/template/lib.zig b/src/template/lib.zig index b9d6acb..dced9ec 100644 --- a/src/template/lib.zig +++ b/src/template/lib.zig @@ -273,7 +273,7 @@ fn evaluateExpression( return std.mem.eql(u8, lhs, rhs); } else if (comptime std.meta.trait.isContainer(T) and @hasDecl(T, "eql")) { return T.eql(lhs, rhs); - } else return lhs == rhs; + } else return std.meta.eql(lhs, rhs); }, .builtin => |call| switch (call.*) { .isTag => |hdr| { From 8edf661afe81ebd7e185f788cda159242e7a34b0 Mon Sep 17 00:00:00 2001 From: jaina heartles Date: Tue, 13 Dec 2022 02:29:11 -0800 Subject: [PATCH 6/8] Add icon for headers and avis --- .../controllers/web/drive/directory.tmpl.html | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/src/main/controllers/web/drive/directory.tmpl.html b/src/main/controllers/web/drive/directory.tmpl.html index 86d1784..54f2136 100644 --- a/src/main/controllers/web/drive/directory.tmpl.html +++ b/src/main/controllers/web/drive/directory.tmpl.html @@ -3,15 +3,26 @@ {#for .dir.children.? |$child| =} {#switch $child case dir |$dir| =} + {$dir.name.?} - {#case file |$file| =} + {#case file |$file|} + + {= #if %user |$u|} + {#if $u.avatar_file_id == $file.meta.id =} + + {= #elif $u.header_file_id == $file.meta.id =} + + {= /if =} + {= /if =} + {= #if $file.meta.sensitive =} - + {= #else =} - + {= /if =} + {$file.name.?} {#if $file.meta.content_type |$t|}{$t}{/if} {$file.meta.size} From 0f5751e7ed520ac28cee6fa9833727f6283788fe Mon Sep 17 00:00:00 2001 From: jaina heartles Date: Wed, 14 Dec 2022 00:20:25 -0800 Subject: [PATCH 7/8] Put mount base url in context --- src/http/middleware.zig | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/src/http/middleware.zig b/src/http/middleware.zig index 825f3c7..fb3095a 100644 --- a/src/http/middleware.zig +++ b/src/http/middleware.zig @@ -465,7 +465,16 @@ pub fn Mount(comptime route: []const u8) type { var new_ctx = ctx; new_ctx.path = args.path; - return next.handle(req, res, new_ctx, {}); + if (@hasField(@TypeOf(new_ctx), "mounted_at")) { + new_ctx.mounted_at = try std.fmt.allocPrint(ctx.allocator, "/{s}/{s}", .{ + std.mem.trim(u8, ctx.mounted_at, "/"), + std.mem.trim(u8, route, "/"), + }); + defer ctx.allocator.free(new_ctx.mounted_at); + return next.handle(req, res, new_ctx, {}); + } else { + return next.handle(req, res, addField(new_ctx, "mounted_at", std.mem.trim(u8, route, "/")), {}); + } } }; } From 1269aeeac19daa7a5fe9cec627109a8a98b85982 Mon Sep 17 00:00:00 2001 From: jaina heartles Date: Wed, 14 Dec 2022 00:46:24 -0800 Subject: [PATCH 8/8] Add slice builtin --- src/template/lib.zig | 46 ++++++++++++++++++++++++++++++++++---- src/template/test.tmp.html | 2 ++ 2 files changed, 44 insertions(+), 4 deletions(-) diff --git a/src/template/lib.zig b/src/template/lib.zig index dced9ec..77460bd 100644 --- a/src/template/lib.zig +++ b/src/template/lib.zig @@ -8,11 +8,13 @@ pub fn main() !void { @embedFile("./test.tmp.html"), .{ .community = .{ .name = "" }, - .foo = [_][]const u8{ "5", "4", "3", "2", "1" }, - .baz = [_][]const []const u8{ + .foo = &[_][]const u8{ "5", "4", "3", "2", "1" }, + .baz = &[_][]const []const u8{ &.{ "5", "4", "3", "2", "1" }, &.{ "5", "4", "3", "2", "1" }, }, + .start = 1, + .end = 3, .bar = .{ .x = "x" }, .qux = false, .quxx = true, @@ -236,7 +238,7 @@ fn deref(arg: anytype, comptime names: []const DerefDecl) DerefError!Deref(@Type } } -const ExpressionError = DerefError; +const ExpressionError = error{IndexOutOfBounds} || DerefError; fn EvaluateExpression( comptime expression: Expression, @@ -251,6 +253,7 @@ fn EvaluateExpression( .equals => bool, .builtin => |call| switch (call.*) { .isTag => bool, + .slice => |sl| []const std.meta.Elem(EvaluateExpression(sl.iterable, Args, Captures, Context)), }, }; } @@ -280,6 +283,15 @@ fn evaluateExpression( const val = try evaluateExpression(hdr.expression, args, captures, context); return std.meta.isTag(val, hdr.tag); }, + .slice => |sl| { + const iterable = try evaluateExpression(sl.iterable, args, captures, context); + const start = try evaluateExpression(sl.start, args, captures, context); + const end = try evaluateExpression(sl.end, args, captures, context); + + if (comptime std.meta.trait.is(.Array)(@TypeOf(iterable))) @compileError("Cannot slice an array, pass a slice or pointer to array instead"); + if (start > iterable.len or end > iterable.len) return error.IndexOutOfBounds; + return iterable[start..end]; + }, }, }; } @@ -635,7 +647,7 @@ fn parseBuiltin(comptime tokens: ControlTokenIter) ParseResult(ControlTokenIter, const call = switch (builtin) { .isTag => blk: { const expr = parseExpression(iter); - iter = expr.new_iter; + iter = skipWhitespace(expr.new_iter); expectToken(iter.next(), .comma); iter = skipWhitespace(iter); const tag = iter.next(); @@ -647,6 +659,26 @@ fn parseBuiltin(comptime tokens: ControlTokenIter) ParseResult(ControlTokenIter, }, }; }, + .slice => blk: { + const expr = parseExpression(iter); + iter = skipWhitespace(expr.new_iter); + expectToken(iter.next(), .comma); + iter = skipWhitespace(iter); + const start = parseExpression(iter); + iter = skipWhitespace(start.new_iter); + expectToken(iter.next(), .comma); + iter = skipWhitespace(iter); + const end = parseExpression(iter); + iter = skipWhitespace(end.new_iter); + + break :blk .{ + .slice = .{ + .iterable = expr.item, + .start = start.item, + .end = end.item, + }, + }; + }, }; iter = skipWhitespace(iter); expectToken(iter.next(), .close_paren); @@ -1165,6 +1197,7 @@ const EndKeyword = enum { const Builtin = enum { isTag, + slice, }; const BuiltinCall = union(Builtin) { @@ -1172,6 +1205,11 @@ const BuiltinCall = union(Builtin) { tag: []const u8, expression: Expression, }, + slice: struct { + iterable: Expression, + start: Expression, + end: Expression, + }, }; const ControlToken = union(enum) { diff --git a/src/template/test.tmp.html b/src/template/test.tmp.html index 995fc79..1b484b9 100644 --- a/src/template/test.tmp.html +++ b/src/template/test.tmp.html @@ -26,6 +26,8 @@ neither {=/if} + sliced: {#for @slice(.foo, .start, .end) |$s|}{$s}, {/for} + format: {#format "s" .x} {#switch .snap case foo =}