╭ changed ─────────╮ │src/event/Repo.zig│ ╰──────────────────╯ ╭──────────────────────────────────────────────────────────────────────────╮ │10 write_access: Access = .private, │ │11 read_user_ids: []const u8 = "", │ │12 write_user_ids: []const u8 = "", │ │13 +// collaborators who hold the owner's role without being the creator │ │14 +owner_user_ids: []const u8 = "", │ │15 │ │16 // what the db stores: the event's data plus the commit-derived fields│ │17 pub const Record = struct { │ ╰──────────────────────────────────────────────────────────────────────────╯ ╭────────────────────────────────────────────────────────────────────────────────────────────────╮ │65 if (std.mem.eql(u8, event.user_id, &user_id)) return .owner; │ │66 │ │67 const user_id_hex = std.fmt.bytesToHex(user_id, .lower); │ │68 + if (containsUserId(event.owner_user_ids, &user_id_hex)) return .owner; │ │69 if (base == .write or containsUserId(event.write_user_ids, &user_id_hex)) return .write;│ │70 if (base == .read or containsUserId(event.read_user_ids, &user_id_hex)) return .read; │ │71 return .none; │ ╰────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │132 try validateName(record_to_write.event.name); │ │133 try validateUserIds(record_to_write.event.read_user_ids); │ │134 try validateUserIds(record_to_write.event.write_user_ids); │ │135 + try validateUserIds(record_to_write.event.owner_user_ids); │ │136 } │ │137 │ │138 const user_id_to_repo_id_set_cursor = try haxy_moment.putCursor(hash.hashInt(hash_kind, "user-id->repo-id-set"));│ ╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭ changed ────────╮ │src/serve_ssh.zig│ ╰─────────────────╯ ╭─────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │597 ) !?UserWithKey { │ │598 if (try userWithKey(moment, arena, repo.user_id, fingerprint)) |user| return user; │ │599 │ │600 - for ([_][]const u8{ repo.write_user_ids, repo.read_user_ids }) |user_ids| { │ │600 + for ([_][]const u8{ repo.owner_user_ids, repo.write_user_ids, repo.read_user_ids }) |user_ids| {│ │601 var lines = std.mem.tokenizeScalar(u8, user_ids, '\n'); │ │602 while (lines.next()) |id| { │ │603 const user_id = try evt.parseEventId(id); │ ╰─────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭ changed ──╮ │src/try.zig│ ╰───────────╯ ╭──────────────────────────────────────────────────────────────────────────────────────╮ │229 }, │ │230 }; │ │231 } │ │232 - // admin collaborates on every repo, so it can write everywhere while the│ │233 - // other users can only write to their own │ │232 + // admin co-owns every repo, so it has full privileges everywhere │ │233 + // (including undo) while the other users only own their own │ │234 const admin_user_id_hex = std.fmt.bytesToHex(admin_user_id, .lower); │ │235 for (repo_data, 0..) |r, i| { │ │236 events_to_consume[user_data.len + i] = .{ │ ╰──────────────────────────────────────────────────────────────────────────────────────╯ ╭──────────────────────────────────────────────────────────────────╮ │243 .name = r.name, │ │244 .description = r.description, │ │245 .read_access = r.read_access, │ │246 - .write_user_ids = &admin_user_id_hex,│ │246 + .owner_user_ids = &admin_user_id_hex,│ │247 }, │ │248 }, │ │249 }; │ ╰──────────────────────────────────────────────────────────────────╯