╭─────────────╮ │scroll to top│ ╰─────────────╯ ╭ admin.zig ────────────────────────────────────────────────────╮ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ ╰───────────────────────────────────────────────────────────────╯
╭────╮ ╭ clone ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ╮ │http│ ssh │ │ ╰────╯ ╰ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ╯
345 if (cwd.openDir(io, temp_dir_name, .{})) |dir_value| { 346 var dir = dir_value; 347 dir.close(io); 348 try cwd.deleteTree(io, temp_dir_name); 349 } else |_| {} 350 var temp_dir = try cwd.createDirPathOpen(io, temp_dir_name, .{}); 351 defer cwd.deleteTree(io, temp_dir_name) catch {}; 352 defer temp_dir.close(io); 353 354 const cwd_path = try std.process.currentPathAlloc(io, allocator); 355 defer allocator.free(cwd_path); 356 const root = try std.fs.path.join(allocator, &.{ cwd_path, temp_dir_name }); 357 defer allocator.free(root); 358 const repos_dir = try std.fs.path.join(allocator, &.{ root, "repos" }); 359 defer allocator.free(repos_dir); 360 const admin_path = try std.fs.path.join(allocator, &.{ root, "admin" }); 361 defer allocator.free(admin_path); 362 363 var prng = std.Random.DefaultPrng.init(std.testing.random_seed); 364 const user_id = evt.EventWithId.randomId(prng.random()); 365 const repo_id = evt.EventWithId.randomId(prng.random()); 366 const repo_id_hex = std.fmt.bytesToHex(repo_id, .lower); 367 const fork_id = evt.EventWithId.randomId(prng.random()); 368 const fork_id_hex = std.fmt.bytesToHex(fork_id, .lower); 369 370 var admin = try rp.Repo(.xit, evt.admin_repo_opts).init(io, allocator, .{ .path = admin_path }); 371 defer admin.deinit(io, allocator); 372 try evt.consume(.admin, .xit, evt.admin_repo_opts, io, allocator, &admin, evt.events_ref, &.{ 373 .{ 374 .id = std.fmt.bytesToHex(user_id, .lower), 375 .timestamp = 1, 376 .author = author, 377 .event = .{ .user = .{ 378 .name = author.name, 379 .email = author.email, 380 .password_hash = "", 381 } }, 382 }, 383 .{ 384 .id = std.fmt.bytesToHex(repo_id, .lower), 385 .timestamp = 1, 386 .author = author, 387 .event = .{ .repo = .{ 388 .user_id = &user_id, 389 .name = "repo", 390 .description = "", 391 } }, 392 }, 393 }); 394 395 const target_path = try std.fs.path.join(allocator, &.{ repos_dir, &repo_id_hex }); 396 defer allocator.free(target_path); 397 var target = try rp.Repo(.xit, fork_repo_opts).init(io, allocator, .{ .path = target_path }); 398 defer target.deinit(io, allocator); 399 400 const draft_path = try fork.create(fork_repo_opts, io, allocator, repos_dir, &admin, .{ 401 .id = fork_id_hex, 402 .user_id = user_id, 403 .repo_id = repo_id, 404 .title = "add a feature", 405 .description = "a draft patch", 406 .tags = "enhancement", 407 .author = author, 408 .timestamp = 2, 409 }); 410 defer allocator.free(draft_path); 411 412 var arena = std.heap.ArenaAllocator.init(allocator); 413 defer arena.deinit(); 414 var moment = try evt.currentMoment(evt.admin_repo_opts, &admin); 415 var record = (try evt.Fork.readById(evt.AdminDB, evt.admin_repo_opts.hash, moment, &arena, &fork_id)) orelse return error.NotFound; 416 try std.testing.expectEqualSlices(u8, &user_id, record.event.user_id); 417 try std.testing.expectEqualSlices(u8, &repo_id, record.event.repo_id); 418 try std.testing.expectEqual(.draft, record.event.stage); 419 try std.testing.expectEqual(1, try indexedForkCount(moment, evt.Fork.user_id_to_fork_id_set_key, &user_id)); 420 const draft_key = evt.Fork.draftKey(&repo_id, &user_id); 421 try std.testing.expectEqual(1, try indexedForkCount(moment, evt.Fork.repo_user_to_draft_id_set_key, &draft_key)); 422 423 var draft_repo = try rp.Repo(.xit, fork_repo_opts).open(io, allocator, .{ .path = draft_path }); 424 defer draft_repo.deinit(io, allocator); 425 const draft_moment = try evt.currentMoment(fork_repo_opts, &draft_repo); 426 const draft = (try evt.Patch.readById(evt.EventDB(fork_repo_opts.hash), fork_repo_opts.hash, draft_moment, &arena, &fork_id)) orelse return error.NotFound; 427 try std.testing.expectEqualStrings("add a feature", draft.event.title); 428 try std.testing.expectEqual(null, draft.event.revision); 429 430 var wrong_user_id = user_id; 431 wrong_user_id[0] ^= 1; 432 try std.testing.expectError(error.InvalidPatchDraft, fork.remove(io, allocator, repos_dir, &admin, &fork_id_hex, &wrong_user_id, author)); 433 try std.Io.Dir.accessAbsolute(io, draft_path, .{}); 434 435 try fork.remove(io, allocator, repos_dir, &admin, &fork_id_hex, &user_id, author); 436 try std.testing.expectError(error.FileNotFound, std.Io.Dir.accessAbsolute(io, draft_path, .{})); 437 _ = arena.reset(.retain_capacity); 438 moment = try evt.currentMoment(evt.admin_repo_opts, &admin); 439 record = (try evt.Fork.readById(evt.AdminDB, evt.admin_repo_opts.hash, moment, &arena, &fork_id)) orelse return error.NotFound; 440 try std.testing.expect(record.removed); 441 try std.testing.expectEqual(0, try indexedForkCount(moment, evt.Fork.user_id_to_fork_id_set_key, &user_id)); 442 try std.testing.expectEqual(0, try indexedForkCount(moment, evt.Fork.repo_user_to_draft_id_set_key, &draft_key)); 443 444 try fork.remove(io, allocator, repos_dir, &admin, &fork_id_hex, &user_id, author); 445 } 446 447 fn indexedForkCount( 448 moment: evt.AdminDB.HashMap(.read_only), 449 index_key: []const u8, 450 parent_id: []const u8, 451 ) !u64 { 452 const index_cursor = try moment.getCursor(hash.hashInt(evt.admin_repo_opts.hash, index_key)) orelse return 0; 453 const index = try evt.AdminDB.HashMap(.read_only).init(index_cursor); 454 const ids_cursor = try index.getCursor(hash.hashInt(evt.admin_repo_opts.hash, parent_id)) orelse return 0; 455 const ids = try evt.AdminDB.SortedSet(.read_only).init(ids_cursor); 456 return try ids.count(); 457 } 458