╭ changed ────╮ │src/event.zig│ ╰─────────────╯ ╭───────────╮ │← all files│ ╰───────────╯ ╭────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │2071 .timestamp = @intCast(std.Io.Timestamp.now(io, .real).toSeconds()), │ │2072 .author = author, │ │2073 .event = .{ .repo = event }, │ │2074 + }}); │ │2075 +} │ │2076 + │ │2077 +// grant `user_id` `role` on the repo `repo_id` in its owner's user repo, │ │2078 +// replacing any role they held │ │2079 +pub fn grantRole( │ │2080 + io: std.Io, │ │2081 + allocator: std.mem.Allocator, │ │2082 + users_dir: []const u8, │ │2083 + owner_id: *const [event_id_size]u8, │ │2084 + repo_id: *const [event_id_size]u8, │ │2085 + user_id: *const [event_id_size]u8, │ │2086 + role: Repo.Role, │ │2087 + author: CommitAuthor, │ │2088 +) !void { │ │2089 + var user_repo = (try openUserRepo(io, allocator, users_dir, owner_id)) orelse return error.NotFound; │ │2090 + defer user_repo.deinit(io, allocator); │ │2091 + try consume(.{ .server = .{ .users_dir = users_dir } }, .user, .xit, user_repo_opts, io, allocator, &user_repo, events_ref, &[_]EventWithId{.{ │ │2092 + .id = std.fmt.bytesToHex(Grant.idOf(repo_id, user_id), .lower), │ │2093 + .timestamp = @intCast(std.Io.Timestamp.now(io, .real).toSeconds()), │ │2094 + .author = author, │ │2095 + .event = .{ .grant = .{ .target_id = repo_id, .user_id = user_id, .role = role } }, │ │2096 }}); │ │2097 +} │ │2098 + │ │2099 +// revoke `user_id`'s grant on the repo `repo_id` in its owner's user repo │ │2100 +pub fn revokeRole( │ │2101 + io: std.Io, │ │2102 + allocator: std.mem.Allocator, │ │2103 + users_dir: []const u8, │ │2104 + owner_id: *const [event_id_size]u8, │ │2105 + repo_id: *const [event_id_size]u8, │ │2106 + user_id: *const [event_id_size]u8, │ │2107 + author: CommitAuthor, │ │2108 +) !void { │ │2109 + var user_repo = (try openUserRepo(io, allocator, users_dir, owner_id)) orelse return error.NotFound; │ │2110 + defer user_repo.deinit(io, allocator); │ │2111 + // a revoked grant stays in the kind index, which is all `remove` checks │ │2112 + { │ │2113 + var arena = std.heap.ArenaAllocator.init(allocator); │ │2114 + defer arena.deinit(); │ │2115 + const moment = (try userMoment(&user_repo)) orelse return error.EventNotFound; │ │2116 + if (try Grant.readRole(UserDB, user_repo_opts.hash, moment, &arena, repo_id, user_id) == null) return error.EventNotFound; │ │2117 + } │ │2118 + try remove(.{ .server = .{ .users_dir = users_dir } }, .user, .xit, user_repo_opts, io, allocator, &user_repo, &Grant.idOf(repo_id, user_id), .grant, author);│ │2119 } │ │2120 │ │2121 // create a user and their user repo, returning the new user's id │ ╰────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯