╭──────────╮ │← previous│ ╰──────────╯ ╭ changed ─╮ │src/ui.zig│ ╰──────────╯ ╭──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │864 if (try evt.User.readById(evt.AdminDB, evt.admin_repo_opts.hash, moment, self.arena, user_id)) |user| { │ │865 self.data.enable_ansi = user.enable_ansi; │ │866 } │ │867 + } │ │868 + │ │869 + // the user's email, for authoring event commits │ │870 + pub fn userEmail(self: *Self) ![]const u8 { │ │871 + const user_id = self.data.user_id orelse return "user@haxy"; │ │872 + const moment = self.haxy_moment orelse return "user@haxy"; │ │873 + const user = (try evt.User.readById(evt.AdminDB, evt.admin_repo_opts.hash, moment, self.page_arena, user_id)) orelse unreachable;│ │874 + return user.email; │ │875 } │ │876 │ │877 // queue an action for the host to drain this frame. │ ╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭ changed ─────────────╮ │src/ui/Repo/Issues.zig│ ╰──────────────────────╯ ╭─────────────────────────────────────────────────────────────────────────────────────╮ │1153 const event = evt.EventWithId{ │ │1154 .id = event_id_hex, │ │1155 .timestamp = @intCast(std.Io.Timestamp.now(io, .real).toSeconds()),│ │1156 + .author_email = try self.session.userEmail(), │ │1157 .event = .{ .issue = .{ │ │1158 .title = title, │ │1159 .description = description, │ ╰─────────────────────────────────────────────────────────────────────────────────────╯ ╭─────────────────────────────────────────────────────────────╮ │1215 .title = title, │ │1216 .tags = tags, │ │1217 .description = description, │ │1217 - } }), │ │1218 + } }, try self.session.userEmail()),│ │1219 } │ │1220 }, │ │1221 } │ ╰─────────────────────────────────────────────────────────────╯ ╭───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │1247 var any_repo = try rp.AnyRepo(repo_kind, .{}).open(io, allocator, .{ .path = src.path }); │ │1248 defer any_repo.deinit(io, allocator); │ │1249 switch (any_repo) { │ │1249 - inline else => |*repo| try evt.Issue.update(repo_kind, repo.self_repo_opts, io, allocator, repo, &id_bytes, .{ .status = status }), │ │1250 + inline else => |*repo| try evt.Issue.update(repo_kind, repo.self_repo_opts, io, allocator, repo, &id_bytes, .{ .status = status }, try self.session.userEmail()),│ │1251 } │ │1252 }, │ │1253 } │ ╰───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭ changed ──╮ │src/web.zig│ ╰───────────╯ ╭─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │344 .{ .name = "location", .value = location }, │ │345 }, │ │346 }); │ │347 +} │ │348 + │ │349 +// the email the request's session authors event commits as │ │350 +fn authorEmail( │ │351 + io: std.Io, │ │352 + allocator: std.mem.Allocator, │ │353 + arena: *std.heap.ArenaAllocator, │ │354 + request: *std.http.Server.Request, │ │355 + host: Host, │ │356 +) ![]const u8 { │ │357 + const remote = switch (host) { │ │358 + .remote => |remote| remote, │ │359 + .local => return "user@haxy", │ │360 + }; │ │361 + const token = getCookieValue(request, cookie_name) orelse return "user@haxy"; │ │362 + var user_id: [evt.event_id_size]u8 = undefined; │ │363 + if (!remote.session_store.lookup(token, &user_id)) return "user@haxy"; │ │364 + │ │365 + var repo = try rp.Repo(.xit, evt.admin_repo_opts).open(io, allocator, .{ .path = remote.admin_repo_path }); │ │366 + defer repo.deinit(io, allocator); │ │367 + const moment = try evt.currentMoment(evt.admin_repo_opts, &repo); │ │368 + const user = (try evt.User.readById(evt.AdminDB, evt.admin_repo_opts.hash, moment, arena, &user_id)) orelse unreachable;│ │369 + return user.email; │ │370 } │ │371 │ │372 // create an issue in the repo the form's page names (base is │ ╰─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭────────────────────────────────────────────────────────────────────╮ │407 var id_bytes: [evt.event_id_size]u8 = undefined; │ │408 io.random(&id_bytes); │ │409 const event_id_hex = std.fmt.bytesToHex(id_bytes, .lower); │ │410 + │ │411 + var author_arena = std.heap.ArenaAllocator.init(allocator);│ │412 + defer author_arena.deinit(); │ │413 │ │414 const event = evt.EventWithId{ │ │415 .id = event_id_hex, │ ╰────────────────────────────────────────────────────────────────────╯ ╭──────────────────────────────────────────────────────────────────────────────────────────╮ │416 .timestamp = @intCast(std.Io.Timestamp.now(io, .real).toSeconds()), │ │417 + .author_email = try authorEmail(io, allocator, &author_arena, request, host),│ │418 .event = .{ .issue = .{ │ │419 .title = title, │ │420 .description = description, │ ╰──────────────────────────────────────────────────────────────────────────────────────────╯ ╭──────────────────────────────────╮ │505 host: Host, │ │506 parts: IssueBaseParts, │ │507 update: evt.Issue.Update,│ │508 + author_email: []const u8,│ │509 ) !void { │ │510 switch (host) { │ │511 .remote => |remote| {│ ╰──────────────────────────────────╯ ╭──────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │521 │ │522 var repo = try rp.Repo(.xit, .{}).open(io, allocator, .{ .path = repo_path }); │ │523 defer repo.deinit(io, allocator); │ │496 - try evt.Issue.update(.xit, .{}, io, allocator, &repo, &parts.id_bytes, update); │ │524 + try evt.Issue.update(.xit, .{}, io, allocator, &repo, &parts.id_bytes, update, author_email);│ │525 }, │ │526 .local => |src| { │ │527 // the local forms post to "/issues/<id>/...", so the repo base │ ╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │532 var any_repo = try rp.AnyRepo(repo_kind, .{}).open(io, allocator, .{ .path = src.path }); │ │533 defer any_repo.deinit(io, allocator); │ │534 switch (any_repo) { │ │507 - inline else => |*repo| try evt.Issue.update(repo_kind, repo.self_repo_opts, io, allocator, repo, &parts.id_bytes, update), │ │535 + inline else => |*repo| try evt.Issue.update(repo_kind, repo.self_repo_opts, io, allocator, repo, &parts.id_bytes, update, author_email),│ │536 } │ │537 }, │ │538 } │ ╰─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭──────╮ │next →│ ╰──────╯