╭ changed ──────╮ │src/ui/Fork.zig│ ╰───────────────╯ ╭───────────╮ │← all files│ ╰───────────╯ ╭───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │37 const repos_dir = session.repos_dir orelse return error.NotFound; │ │38 const haxy_moment = session.haxy_moment orelse return error.NoMoment; │ │39 const route_fork = route.forkRoute() orelse return error.UnexpectedRoute; │ │40 + // the route's identity names the forker and the target repo │ │41 const identity = ui.RoutablePage.RepoIdentity.parse(route_fork.name.slice()) orelse return error.NotFound; │ │42 const id = evt.parseEventId(route_fork.id.slice()) catch return error.NotFound; │ │42 - const fork_record = (try evt.Fork.readById(evt.AdminDB, evt.admin_repo_opts.hash, haxy_moment, arena, &id)) orelse return error.NotFound; │ │43 + const gpa = arena.child_allocator; │ │44 + const forker_id = (try evt.User.readIdByName(evt.AdminDB, evt.admin_repo_opts.hash, haxy_moment, identity.owner)) orelse return error.NotFound;│ │45 + const fork_record = (try evt.readForkById(io, gpa, arena, repos_dir, &forker_id, &id)) orelse return error.NotFound; │ │46 if (fork_record.removed) return error.NotFound; │ │47 if (fork_record.event.repo_id.len != evt.event_id_size) return error.NotFound; │ │48 var target_id: [evt.event_id_size]u8 = undefined; │ ╰───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │49 @memcpy(&target_id, fork_record.event.repo_id); │ │50 + const owner_id = fork_record.event.repo_user_id[0..evt.event_id_size]; │ │51 │ │48 - const target_record = (try evt.Repo.readById(evt.AdminDB, evt.admin_repo_opts.hash, haxy_moment, arena, fork_record.event.repo_id)) orelse return error.NotFound;│ │52 + const target_record = (try evt.readRepoById(io, gpa, arena, repos_dir, owner_id, fork_record.event.repo_id)) orelse return error.NotFound; │ │53 // a draft is as readable as the repo it targets │ │54 if (evt.Repo.roleOf(target_record, session.userId()) == .none) return error.NotFound; │ │51 - const owner = (try evt.User.readById(evt.AdminDB, evt.admin_repo_opts.hash, haxy_moment, arena, target_record.event.user_id)) orelse return error.NotFound; │ │52 - if (!std.mem.eql(u8, owner.event.name, identity.owner) or !std.mem.eql(u8, target_record.event.name, identity.name)) return error.NotFound; │ │55 + const owner = (try evt.User.readById(evt.AdminDB, evt.admin_repo_opts.hash, haxy_moment, arena, owner_id)) orelse return error.NotFound; │ │56 + if (!std.mem.eql(u8, target_record.event.name, identity.name)) return error.NotFound; │ │57 │ │58 const aa = arena.allocator(); │ │59 + const target_identity = try std.fmt.allocPrint(aa, "{s}/{s}", .{ owner.event.name, target_record.event.name }); │ │60 const id_hex = std.fmt.bytesToHex(id, .lower); │ │61 const fork_path = try fork.forkPath(aa, repos_dir, &id_hex); │ │62 var fork_repo = try rp.Repo(.xit, .{}).open(io, arena.child_allocator, .{ .path = fork_path, .require_repo_root = true }); │ ╰─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │ 89 .draft = fork_record.event.stage == .draft, │ │ 90 .revision_oid = try aa.dupe(u8, &fork_oid), │ │ 91 .fork_exists = true, │ │ 92 + .forker = identity.owner, │ │ 93 }; │ │ 88 - var patch_data = try Patches.detailResult(aa, identity.identity, retained_entry); │ │ 94 + var patch_data = try Patches.detailResult(aa, target_identity, retained_entry); │ │ 95 │ │ 96 if (target_repo_maybe) |*target_repo| switch (fork_record.event.stage) { │ │ 91 - .draft => if (try Patches.loadDraftEntry(.xit, .{}, arena, io, haxy_moment, &fork_repo, target_repo, id)) |entry| { │ │ 92 - patch_data = try Patches.detailResult(aa, identity.identity, entry); │ │ 97 + .draft => if (try Patches.loadDraftEntry(.xit, .{}, arena, io, haxy_moment, &fork_repo, target_repo, id, identity.owner)) |entry| {│ │ 98 + patch_data = try Patches.detailResult(aa, target_identity, entry); │ │ 99 patch_data.repo_source = target_source; │ │100 }, │ │101 .publish => { │ ╰────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │ 96 - patch_data = Patches.init(.xit, .{}, arena, target_repo, io, haxy_moment, session, target_id, identity.identity, target_branch, "", "", &id_hex, "", 0, "", .open) catch |err| switch (err) {│ │102 + patch_data = Patches.init(.xit, .{}, arena, target_repo, io, haxy_moment, session, target_id, target_identity, target_branch, "", "", &id_hex, "", 0, "", .open) catch |err| switch (err) { │ │103 error.NotFound => patch_data, │ │104 else => |other| return other, │ │105 }; │ ╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │151 }; │ │152 │ │153 return .{ │ │148 - .header = try Header.init(arena, target_record.event.name, owner.event.name, &id_hex, requested_value), │ │154 + .header = try Header.init(arena, target_record.event.name, owner.event.name, identity.owner, &id_hex, requested_value),│ │155 .files = files, │ │156 .commits = commits, │ │157 .patch = patch_data, │ ╰────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯