╭──────────╮ │← previous│ ╰──────────╯ ╭ changed ───────────────╮ │src/ui/widget/thread.zig│ ╰────────────────────────╯ ╭──────────────────────────────────────────────────────────────────────────────────────────╮ │464 arena: *std.heap.ArenaAllocator, │ │465 admin_moment: ?evt.AdminDB.HashMap(.read_only), │ │466 haxy_moment: evt.EventDB(hash_kind).HashMap(.read_only), │ │466 - thread_id: []const u8, │ │467 + thread_id: *const [evt.event_id_size]u8, │ │468 ) ![]const ui.Assignee { │ │469 const emails = try evt.Assignment.load(hash_kind, arena, haxy_moment, thread_id);│ │470 const assignees = try arena.allocator().alloc(ui.Assignee, emails.len); │ ╰──────────────────────────────────────────────────────────────────────────────────────────╯ ╭ changed ──╮ │src/web.zig│ ╰───────────╯ ╭──────────────────────────────────────────────────────────────────────────────────────╮ │1343 }); │ │1344 } │ │1345 │ │1346 -fn respondAttachmentParentNotFound(request: *std.http.Server.Request) !void { │ │1347 - try request.respond("attachment parent not found", .{ │ │1346 +fn respondAttachmentTargetNotFound(request: *std.http.Server.Request) !void { │ │1347 + try request.respond("attachment target not found", .{ │ │1348 .status = .not_found, │ │1349 .keep_alive = false, │ │1350 .extra_headers = &.{.{ .name = "content-type", .value = "text/plain" }},│ ╰──────────────────────────────────────────────────────────────────────────────────────╯ ╭────────────────────────────────────────────────────────────────────────────────────╮ │1354 // the upload declares its file's name here, since the body is the file itself│ │1355 const attachment_name_header = "x-attachment-name"; │ │1356 │ │1357 -const AttachParentParts = struct { │ │1357 +const AttachTargetParts = struct { │ │1358 repo_base: []const u8, │ │1359 kind: evt.EventKind, │ │1360 id_bytes: [evt.event_id_size]u8, │ ╰────────────────────────────────────────────────────────────────────────────────────╯ ╭──────────────────────────────────────────────────────────────────────────────────────────╮ │1362 │ │1363 // what an attachment hangs off: the `<kind>:<id>` segment the form's page ends │ │1364 // with, whatever kind that is │ │1365 -fn attachParentParts(base: []const u8) ?AttachParentParts { │ │1365 +fn attachTargetParts(base: []const u8) ?AttachTargetParts { │ │1366 const segment_at = std.mem.lastIndexOfScalar(u8, base, '/') orelse return null; │ │1367 const segment = base[segment_at + 1 ..]; │ │1368 const colon_at = std.mem.lastIndexOfScalar(u8, segment, ':') orelse return null;│ ╰──────────────────────────────────────────────────────────────────────────────────────────╯ ╭───────────────────────────────────────────────────────────────────────────────────────────────────────╮ │1381 base: []const u8, │ │1382 host: Host, │ │1383 ) !void { │ │1384 - const parts = attachParentParts(base) orelse return respondAttachmentParentNotFound(request);│ │1384 + const parts = attachTargetParts(base) orelse return respondAttachmentTargetNotFound(request);│ │1385 │ │1386 var author_arena = std.heap.ArenaAllocator.init(allocator); │ │1387 defer author_arena.deinit(); │ ╰───────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │1388 const actor = (try authorizeWrite(io, allocator, &author_arena, request, host, parts.repo_base, .read, parts.kind)) orelse return; │ │1389 const author = actor.author; │ │1390 // an attachment changes the event it hangs off │ │1391 - const request_repo = (try requestRepoSource(io, allocator, host, parts.repo_base)) orelse return respondAttachmentParentNotFound(request);│ │1391 + const request_repo = (try requestRepoSource(io, allocator, host, parts.repo_base)) orelse return respondAttachmentTargetNotFound(request);│ │1392 defer request_repo.deinit(allocator); │ │1393 const source = request_repo.source; │ │1394 if (!try source.canModify(io, allocator, actor, parts.kind, &parts.id_bytes)) return respondForbidden(request); │ ╰────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │1401 if (size == 0) return respondUploadError(request, .bad_request, "attachment is empty"); │ │1402 if (size > evt.Attachment.max_size) return respondUploadError(request, .payload_too_large, "attachment is too large");│ │1403 │ │1404 - const parent_id_hex = std.fmt.bytesToHex(parts.id_bytes, .lower); │ │1404 + const target_id_hex = std.fmt.bytesToHex(parts.id_bytes, .lower); │ │1405 │ │1406 var body_buf: [4096]u8 = undefined; │ │1407 const blob: evt.Blob = .{ .name = name, .size = size, .reader = try request.readerExpectContinue(&body_buf) }; │ ╰────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │1411 var any_repo = try rp.AnyRepo(repo_kind, .{}).open(io, allocator, source.localInitOpts()); │ │1412 defer any_repo.deinit(io, allocator); │ │1413 switch (any_repo) { │ │1414 - inline else => |*repo| _ = evt.Attachment.create(host.event(), repo_kind, repo.self_repo_opts, io, allocator, repo, parts.kind, &parent_id_hex, blob, author) catch |err| switch (err) {│ │1415 - error.ParentNotFound => return respondAttachmentParentNotFound(request), │ │1414 + inline else => |*repo| _ = evt.Attachment.create(host.event(), repo_kind, repo.self_repo_opts, io, allocator, repo, parts.kind, &target_id_hex, blob, author) catch |err| switch (err) {│ │1415 + error.TargetNotFound => return respondAttachmentTargetNotFound(request), │ │1416 else => return err, │ │1417 }, │ │1418 } │ ╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭────────────────────────────────────────────────────────────────────────────────────────╮ │1705 // split a remove url into the repo and event it names │ │1706 fn removeParts(host: Host, base: []const u8) ?RemoveParts { │ │1707 if (attachmentRequest(base)) |attachment| { │ │1708 - const parent = attachParentParts(attachment.repo_base) orelse return null;│ │1708 + const target = attachTargetParts(attachment.repo_base) orelse return null;│ │1709 return .{ │ │1710 - .repo_base = parent.repo_base, │ │1710 + .repo_base = target.repo_base, │ │1711 .kind = .attach, │ │1712 - .thread_kind = parent.kind, │ │1713 - .thread_id = parent.id_bytes, │ │1712 + .thread_kind = target.kind, │ │1713 + .thread_id = target.id_bytes, │ │1714 .id = attachment.id, │ │1715 }; │ │1716 } │ ╰────────────────────────────────────────────────────────────────────────────────────────╯