╭ changed ──╮ │src/web.zig│ ╰───────────╯ ╭───────────╮ │← all files│ ╰───────────╯ ╭──────────╮ │← previous│ ╰──────────╯ ╭───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │1086 defer admin_repo.deinit(io, allocator); │ │1087 const id = std.fmt.bytesToHex(parts.thread_id, .lower); │ │1088 switch (target_repo) { │ │1077 - inline else => |*repo| try pch.publish(repo.self_repo_opts, io, allocator, server.users_dir, &admin_repo, repo, .{ │ │1089 + inline else => |*repo| try pch.publish(repo.self_repo_opts, io, allocator, host.event().server, &admin_repo, repo, .{│ │1090 .id = id, │ │1091 .user_id = user_id, │ │1092 .repo_id = repo_id, │ ╰───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭─────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │1110 ) !void { │ │1111 const parts = commentBaseParts(host, base) orelse return respondRemoveNotFound(request); │ │1112 if (parts.thread_kind != .patch or parts.comment_id != null) return respondRemoveNotFound(request);│ │1101 - const server = switch (host) { │ │1113 + const server = switch (host.event()) { │ │1114 .server => |server| server, │ │1115 .local => return respondRemoveNotFound(request), │ │1116 }; │ ╰─────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │1125 │ │1126 const id = std.fmt.bytesToHex(parts.thread_id, .lower); │ │1127 const merged = switch (target_repo) { │ │1116 - inline else => |*repo| pch.mergeAndRemoveFork(repo.self_repo_opts, io, allocator, server.users_dir, repo, .{│ │1128 + inline else => |*repo| pch.mergeAndRemoveFork(repo.self_repo_opts, io, allocator, server, repo, .{ │ │1129 .id = id, │ │1130 .revision = revision, │ │1131 .author = author, │ ╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │1519 }, │ │1520 } │ │1521 try request.respond("", .{ .status = .see_other, .keep_alive = false, .extra_headers = &.{.{ .name = "location", .value = thread_url }} });│ │1522 +} │ │1523 + │ │1524 +// subscribe the logged-in user to the thread the url names, or mute it, then reload it │ │1525 +fn handleNotify( │ │1526 + io: std.Io, │ │1527 + request: *std.http.Server.Request, │ │1528 + allocator: std.mem.Allocator, │ │1529 + base: []const u8, │ │1530 + host: Host, │ │1531 + users_dir: []const u8, │ │1532 + mode: ui.NotifyAction, │ │1533 +) !void { │ │1534 + const parts = commentBaseParts(host, base) orelse return respondRemoveNotFound(request); │ │1535 + if (parts.comment_id != null) return respondRemoveNotFound(request); │ │1536 + │ │1537 + var arena = std.heap.ArenaAllocator.init(allocator); │ │1538 + defer arena.deinit(); │ │1539 + const actor = (try authorizeWrite(io, allocator, &arena, request, host, parts.repo_base, .read, null)) orelse return; │ │1540 + const request_repo = (try requestRepoSource(io, allocator, host, parts.repo_base)) orelse return respondRemoveNotFound(request); │ │1541 + defer request_repo.deinit(allocator); │ │1542 + // a server actor always has both ids │ │1543 + const user_id = actor.user_id orelse unreachable; │ │1544 + const location: evt.RepoLocation = .{ │ │1545 + .owner_id = actor.repo_user_id orelse unreachable, │ │1546 + .repo_id = evt.parseEventId(std.Io.Dir.path.basename(request_repo.source.path)) catch return respondRemoveNotFound(request), │ │1547 + }; │ │1548 + │ │1549 + switch (mode) { │ │1550 + .subscribe => try notify.subscribe(io, allocator, users_dir, &user_id, location, &parts.thread_id, actor.author), │ │1551 + .mute => try notify.mute(io, allocator, users_dir, &user_id, location, &parts.thread_id, actor.author), │ │1552 + } │ │1553 + try request.respond("", .{ .status = .see_other, .keep_alive = false, .extra_headers = &.{.{ .name = "location", .value = base }} }); │ │1554 } │ │1555 │ │1556 // the name the upload declares for its file, percent-encoded so it survives a │ ╰─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯