╭──────────╮ │← previous│ ╰──────────╯ ╭ changed ───────╮ │src/test/net.zig│ ╰────────────────╯ ╭────────────────────────────────────────────────╮ │555 + .repo_user_id = user_id, │ │556 .title = "add a feature", │ │557 .description = "a draft patch",│ │558 .labels = "enhancement", │ ╰────────────────────────────────────────────────╯ ╭─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │618 { │ │619 var admin = try rp.Repo(.xit, evt.admin_repo_opts).open(io, allocator, .{ .path = admin_path }); │ │620 defer admin.deinit(io, allocator); │ │621 + var user_repo = (try evt.openUserRepo(io, allocator, repos_dir, &user_id)) orelse return error.NotFound;│ │622 + defer user_repo.deinit(io, allocator); │ │623 var target = try rp.Repo(.xit, repo_opts).open(io, allocator, .{ .path = target_path }); │ │624 defer target.deinit(io, allocator); │ │625 // pushing a draft does not create haxy state or a mergeability cache │ ╰─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │626 try std.testing.expectError(error.NotFound, evt.currentMoment(repo_opts, &target)); │ │627 try std.testing.expectEqual(null, try (try target.core.latestMoment()).getCursor(hash.hashInt(hash_kind, evt.Patch.patch_id_to_mergeability_key)));│ │628 try target.addBranch(io, .{ .name = "feature" }); │ │624 - try pch.publish(repo_opts, io, allocator, &admin, &target, draft_path, .{ │ │629 + try pch.publish(repo_opts, io, allocator, &admin, &user_repo, &target, draft_path, .{ │ │630 .id = fork_id_hex, │ │631 .user_id = user_id, │ │632 .repo_id = repo_id, │ ╰────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │796 // │ │797 │ │798 { │ │794 - var admin = try rp.Repo(.xit, evt.admin_repo_opts).open(io, allocator, .{ .path = admin_path }); │ │795 - defer admin.deinit(io, allocator); │ │796 - try evt.remove(.server, .admin, .xit, evt.admin_repo_opts, io, allocator, &admin, &repo_id, .repo, .{ .name = "admin", .email = "admin@example.test" }); │ │799 + var user_repo = (try evt.openUserRepo(io, allocator, repos_dir, &user_id)) orelse return error.NotFound; │ │800 + defer user_repo.deinit(io, allocator); │ │801 + try evt.remove(.server, .user, .xit, evt.user_repo_opts, io, allocator, &user_repo, &repo_id, .repo, .{ .name = "admin", .email = "admin@example.test" });│ │802 } │ │803 const clone_path = try std.fs.path.join(allocator, &.{ temp_path, "fork-clone" }); │ │804 defer allocator.free(clone_path); │ ╰───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │815 try std.testing.expectEqualStrings(&third_source_oid, &(try fork_clone.readRef(io, fork.ref) orelse return error.NotFound));│ │816 │ │817 { │ │813 - var admin = try rp.Repo(.xit, evt.admin_repo_opts).open(io, allocator, .{ .path = admin_path }); │ │814 - defer admin.deinit(io, allocator); │ │815 - try evt.consume(.server, .admin, .xit, evt.admin_repo_opts, io, allocator, &admin, evt.events_ref, &.{ │ │818 + var user_repo = (try evt.openUserRepo(io, allocator, repos_dir, &user_id)) orelse return error.NotFound; │ │819 + defer user_repo.deinit(io, allocator); │ │820 + try evt.consume(.server, .user, .xit, evt.user_repo_opts, io, allocator, &user_repo, evt.events_ref, &.{ │ │821 .{ │ │822 .id = std.fmt.bytesToHex(repo_id, .lower), │ │823 .timestamp = 2, │ ╰─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭───────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │828 .description = "", │ │829 } }, │ │830 }, │ │831 + }); │ │832 + var admin = try rp.Repo(.xit, evt.admin_repo_opts).open(io, allocator, .{ .path = admin_path }); │ │833 + defer admin.deinit(io, allocator); │ │834 + try evt.consume(.server, .admin, .xit, evt.admin_repo_opts, io, allocator, &admin, evt.events_ref, &.{│ │835 .{ │ │836 .id = std.fmt.bytesToHex(user_id, .lower), │ │837 .timestamp = 2, │ ╰───────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │1624 // the dev SSH public key matching the private key written by runServer │ │1625 const admin_ssh_key = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIKeIs8mJqigBZ5y84J4COgnAJJ5bHPKy+lM2SliMXbYm radar@roark";│ │1626 │ │1618 -// create the admin event repo with a user holding the dev SSH public key │ │1627 +// create the admin event repo with a user holding the dev SSH public key, plus │ │1628 +// that user's repo │ │1629 fn setupAdmin(io: std.Io, allocator: std.mem.Allocator, data_path: []const u8) !void { │ │1630 const admin_repo_path = try std.fs.path.join(allocator, &.{ data_path, "admin" }); │ │1631 defer allocator.free(admin_repo_path); │ ╰───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭──────────────────────────────────────────────────────────────────────────────────────╮ │1652 .ssh_keys = admin_ssh_key, │ │1653 } }, │ │1654 }}); │ │1655 + │ │1656 + const repos_dir = try std.fs.path.join(allocator, &.{ data_path, "repos" });│ │1657 + defer allocator.free(repos_dir); │ │1658 + const user_repo_path = try evt.userRepoPath(allocator, repos_dir, &user_id);│ │1659 + defer allocator.free(user_repo_path); │ │1660 + var user_repo = try evt.initUserRepo(io, allocator, user_repo_path); │ │1661 + defer user_repo.deinit(io, allocator); │ │1662 } │ │1663 │ │1664 // resolve admin/<repo_name> to its on-disk directory under <data_dir>/repos via│ ╰──────────────────────────────────────────────────────────────────────────────────────╯ ╭ changed ────────╮ │src/test/undo.zig│ ╰─────────────────╯ ╭─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │76 .{ .id = std.fmt.bytesToHex(owner, .lower), .author = author, .event = .{ .user = .{ .name = "alice", .email = "alice@example.test", .password_hash = "unused" } } }, │ │77 .{ .id = writer_hex, .author = author, .event = .{ .user = .{ .name = "writer", .email = "writer@example.test", .password_hash = "unused" } } }, │ │78 .{ .id = std.fmt.bytesToHex(reader, .lower), .author = author, .event = .{ .user = .{ .name = "reader", .email = "reader@example.test", .password_hash = "unused" } } }, │ │79 - .{ .id = std.fmt.bytesToHex(repo_id, .lower), .author = author, .event = .{ .repo = repo_event } }, │ │79 }; │ │80 try evt.consume(.server, .admin, .xit, evt.admin_repo_opts, io, allocator, &admin, evt.events_ref, &seed); │ │81 + var user_repo = try evt.initUserRepo(io, allocator, try evt.userRepoPath(aa, repos_dir, &owner)); │ │82 + defer user_repo.deinit(io, allocator); │ │83 + try evt.consume(.server, .user, .xit, evt.user_repo_opts, io, allocator, &user_repo, evt.events_ref, &.{.{ .id = std.fmt.bytesToHex(repo_id, .lower), .author = author, .event = .{ .repo = repo_event } }});│ │84 const repo_hex = std.fmt.bytesToHex(repo_id, .lower); │ │85 const path = try std.fs.path.join(aa, &.{ repos_dir, &repo_hex }); │ │86 { │ ╰─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │128 } │ │129 // keep the old session/page moment, but transfer ownership to the writer. │ │130 repo_event.user_id = &writer; │ │129 - try evt.consume(.server, .admin, .xit, evt.admin_repo_opts, io, allocator, &admin, evt.events_ref, &.{.{ .id = std.fmt.bytesToHex(repo_id, .lower), .author = author, .event = .{ .repo = repo_event } }}); │ │131 + try evt.consume(.server, .user, .xit, evt.user_repo_opts, io, allocator, &user_repo, evt.events_ref, &.{.{ .id = std.fmt.bytesToHex(repo_id, .lower), .author = author, .event = .{ .repo = repo_event } }});│ │132 session.next_page = null; │ │133 Undo.handleRequest(allocator, &session, ui.RoutablePage.repoUndoRoute("alice/demo", 1).?.repo_undo); │ │134 try std.testing.expectEqualStrings("Forbidden", session.data.undo_failure.?); │ ╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭──────╮ │next →│ ╰──────╯