╭ changed ────╮ │src/event.zig│ ╰─────────────╯ ╭───────────────────────────────────────────────────────────────────────────────────╮ │59 patchrev, │ │60 patch, │ │61 }; │ │62 + │ │63 +pub const RepoRole = enum { │ │64 + admin, │ │65 + repo, │ │66 + fork, │ │67 │ │68 + fn allows(self: RepoRole, kind: EventKind) bool { │ │69 + return switch (self) { │ │70 + .admin => switch (kind) { │ │71 + .user, .repo, .fork => true, │ │72 + else => false, │ │73 + }, │ │74 + .repo => switch (kind) { │ │75 + .issue, .discuss, .comment, .attach, .patchrev, .patch => true,│ │76 + else => false, │ │77 + }, │ │78 + .fork => switch (kind) { │ │79 + .patchrev, .patch => true, │ │80 + else => false, │ │81 + }, │ │82 + }; │ │83 + } │ │84 +}; │ │85 + │ │86 // every logical event's kind and creation-ordered active/removed id sets │ │87 pub const event_index_key = "event-id->kind"; │ │88 pub const active_event_id_set_key = "active-event-id-set"; │ ╰───────────────────────────────────────────────────────────────────────────────────╯ ╭────────────────────────────────────────────────────╮ │232 │ │233 // remove an event by emitting a null payload │ │234 pub fn remove( │ │235 + comptime role: RepoRole, │ │236 comptime repo_kind: rp.RepoKind, │ │237 comptime repo_opts: rp.RepoOpts(repo_kind),│ │238 io: std.Io, │ ╰────────────────────────────────────────────────────╯ ╭───────────────────────────────────────────────────────────────────────────────────────╮ │269 .patchrev => .{ .patchrev = null }, │ │270 .patch => .{ .patch = null }, │ │271 }; │ │248 - try consume(repo_kind, repo_opts, io, allocator, repo, events_ref, &.{.{ │ │272 + try consume(role, repo_kind, repo_opts, io, allocator, repo, events_ref, &.{.{│ │273 .id = std.fmt.bytesToHex(id.*, .lower), │ │274 .timestamp = @intCast(std.Io.Timestamp.now(io, .real).toSeconds()), │ │275 .author = author, │ ╰───────────────────────────────────────────────────────────────────────────────────────╯ ╭───────────────────────────────────────────────────────────────────────────────────╮ │282 // xit repo, or the standalone event db next to a git repo. for a xit repo the│ │283 // commits and the consume run in one transaction. │ │284 pub fn consume( │ │285 + comptime role: RepoRole, │ │286 comptime repo_kind: rp.RepoKind, │ │287 comptime repo_opts: rp.RepoOpts(repo_kind), │ │288 io: std.Io, │ ╰───────────────────────────────────────────────────────────────────────────────────╯ ╭─────────────────────────────────────────────────────────────────────────────────────────────────╮ │291 ref: rf.Ref, │ │292 events: []const EventWithId, │ │293 ) !void { │ │294 + for (events) |event| { │ │295 + if (!role.allows(std.meta.activeTag(event.event))) return error.EventKindNotAllowed;│ │296 + } │ │297 + │ │298 var resolved_remote_name: ?[]u8 = null; │ │299 defer if (resolved_remote_name) |name| allocator.free(name); │ │300 │ ╰─────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │347 const state = State(.read_write){ .core = ctx.core, .extra = .{ .moment = &moment } }; │ │348 │ │349 try commitEvents(.xit, repo_opts, state, ctx.io, ctx.allocator, ctx.ref, ctx.events, ctx.first_parent_oids); │ │321 - if (!try consumeInTransaction(.xit, repo_opts, state, &ctx.core.db, &moment, ctx.io, ctx.allocator, ctx.ref)) return error.CancelTransaction; │ │350 + if (!try consumeInTransaction(role, .xit, repo_opts, state, &ctx.core.db, &moment, ctx.io, ctx.allocator, ctx.ref)) return error.CancelTransaction;│ │351 try xit.undo.writeMessage(repo_opts, state, .{ .custom = "event" }); │ │352 │ │353 // fsync the chunk store, so any chunks written by the │ ╰────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │592 // no-op consume must not cancel here, since the push shares the │ │593 // transaction and must commit regardless. │ │594 if (null == try rf.readRecur(.xit, repo_opts, state.readOnly(), ctx.io, .{ .ref = events_ref })) return; │ │566 - _ = try consumeInTransaction(.xit, repo_opts, state, &ctx.core.db, &moment, ctx.io, ctx.allocator, events_ref); │ │595 + _ = try consumeInTransaction(.repo, .xit, repo_opts, state, &ctx.core.db, &moment, ctx.io, ctx.allocator, events_ref);│ │596 } │ │597 }; │ │598 │ ╰───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │696 pub fn run(ctx: @This(), cursor: *DB.Cursor(.read_write)) !void { │ │697 var moment = try DB.HashMap(.read_write).init(cursor.*); │ │698 const state = rp.Repo(repo_kind, repo_opts).State(.read_write){ .core = &ctx.repo.core, .extra = .{} }; │ │670 - if (!try consumeInTransaction(repo_kind, repo_opts, state, ctx.db, &moment, ctx.io, ctx.allocator, ctx.ref)) return error.CancelTransaction; │ │699 + if (!try consumeInTransaction(.repo, repo_kind, repo_opts, state, ctx.db, &moment, ctx.io, ctx.allocator, ctx.ref)) return error.CancelTransaction;│ │700 } │ │701 }; │ │702 │ ╰────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭─────────────────────────────────────────────────────────────────────────╮ │720 // needn't be the repo backing the db — that's how a local (possibly│ │721 // git-backed) repo's events land in a standalone db. │ │722 pub fn consumeInTransaction( │ │723 + comptime role: RepoRole, │ │724 comptime repo_kind: rp.RepoKind, │ │725 comptime repo_opts: rp.RepoOpts(repo_kind), │ │726 state: rp.Repo(repo_kind, repo_opts).State(.read_write), │ ╰─────────────────────────────────────────────────────────────────────────╯ ╭─────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │933 try commit_object.readMessage(arena.allocator(), &message, .limited(max_event_size)); │ │934 │ │935 const event_with_id = try EventWithId.fromString(&arena, message.items); │ │936 + if (!role.allows(std.meta.activeTag(event_with_id.event))) return error.EventKindNotAllowed;│ │937 │ │938 const current_event_id = try parseEventId(&event_with_id.id); │ │939 │ ╰─────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭──────╮ │next →│ ╰──────╯