╭ changed ──╮ │src/web.zig│ ╰───────────╯ ╭───────────╮ │← all files│ ╰───────────╯ ╭────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │141 switch (host) { │ │142 .server => |server| { │ │143 // "repo/new" and "user/new" come before "new", which would claim them │ │144 - const PostRoute = enum { login, logout, @"repo/new", @"user/new", new, edit, remove, open, close, resolve, publish, merge, squash, attach, undo, clear }; │ │144 + const PostRoute = enum { login, logout, @"repo/new", @"user/new", repo, new, edit, remove, open, close, resolve, publish, merge, squash, attach, undo, clear };│ │145 inline for (@typeInfo(PostRoute).@"enum".fields) |field| { │ │146 const suffix = "/" ++ field.name; │ │147 if (std.mem.endsWith(u8, path, suffix)) { │ ╰────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │151 .logout => handleLogout(request, base, server.session_store), │ │152 .@"repo/new" => handleRepoNew(io, request, allocator, path, server.admin_repo_path, server.users_dir, server.session_store),│ │153 .@"user/new" => handleUserNew(io, request, allocator, path, server.admin_repo_path, server.users_dir, server.session_store),│ │154 + .repo => handleRepoSettings(io, request, allocator, path, base, host), │ │155 .new => handleNew(io, request, allocator, base, host), │ │156 .edit => handleEdit(io, request, allocator, base, host), │ │157 .remove => handleRemove(io, request, allocator, base, host), │ ╰─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │646 try request.respond("", .{ │ │647 .status = .see_other, │ │648 .extra_headers = &.{.{ .name = "location", .value = location }}, │ │649 + }); │ │650 +} │ │651 + │ │652 +// change the repo `repo_base` names as its owner, then redirect to its │ │653 +// settings under its new name. a failure goes back to the settings page. │ │654 +fn handleRepoSettings( │ │655 + io: std.Io, │ │656 + request: *std.http.Server.Request, │ │657 + allocator: std.mem.Allocator, │ │658 + form_location: []const u8, │ │659 + repo_base: []const u8, │ │660 + host: Host, │ │661 +) !void { │ │662 + const server = switch (host) { │ │663 + .server => |server| server, │ │664 + .local => return respondRepoNotFound(request), │ │665 + }; │ │666 + var arena = std.heap.ArenaAllocator.init(allocator); │ │667 + defer arena.deinit(); │ │668 + const actor = (try authorizeWrite(io, allocator, &arena, request, host, repo_base, .owner)) orelse return; │ │669 + │ │670 + const body = try readFormBody(request, allocator); │ │671 + defer allocator.free(body); │ │672 + const name = (try parseFormField(allocator, body, "name")) orelse try allocator.dupe(u8, ""); │ │673 + defer allocator.free(name); │ │674 + const description = (try parseFormField(allocator, body, "description")) orelse try allocator.dupe(u8, ""); │ │675 + defer allocator.free(description); │ │676 + const access_value = (try parseFormField(allocator, body, "access")) orelse try allocator.dupe(u8, ""); │ │677 + defer allocator.free(access_value); │ │678 + const access = std.meta.stringToEnum(evt.Repo.Access, access_value) orelse return request.respond("invalid access", .{ .status = .bad_request, .extra_headers = &.{.{ .name = "content-type", .value = "text/plain" }} });│ │679 + │ │680 + const repo_prefix = "/repo/"; │ │681 + const route = ui.Repo.Settings.update(io, allocator, server.users_dir, actor, repo_base[repo_prefix.len..], name, description, access) catch |err| switch (err) { │ │682 + error.NotFound => return respondRepoNotFound(request), │ │683 + else => { │ │684 + const failure = ui.Session.FormFeedback.RepoFailure.fromError(err) orelse return err; │ │685 + return respondFormFailure(request, allocator, server.session_store, form_location, .{ .repo_settings = .{ .failure = failure, .fields = .{ │ │686 + .name = name, │ │687 + .description = description, │ │688 + .access = access, │ │689 + } } }); │ │690 + }, │ │691 + }; │ │692 + │ │693 + try request.respond("", .{ │ │694 + .status = .see_other, │ │695 + .extra_headers = &.{.{ .name = "location", .value = try route.toUrl(&arena) }}, │ │696 }); │ │697 } │ │698 │ ╰───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯