Forge
csharp3407750f
1using AgentForge;
2using AgentForge.Abstractions;
3using AgentForge.Plugin.Sdk;
4using AgentForge.Contracts;
5using AgentForge.Data;
6using AgentForge.Data.Entities;
7using AgentForge.Models;
8using AgentForge.Services;
9
10namespace AgentForge.Plugin.Org.Web.Endpoints;
11
12internal static class ForgeOrgEndpoints
13{
14 internal static RouteGroupBuilder MapOrgEndpoints(this RouteGroupBuilder api)
15 {
16 api.MapGet("/orgs", ListOrgs);
17 api.MapPost("/orgs", CreateOrg);
18 api.MapGet("/orgs/{slug}", GetOrg);
19 api.MapGet("/orgs/{slug}/repos", ListOrgRepos);
20 return api;
21 }
22
23 private static IResult ListOrgs(ForgeRepository repository)
24 {
25 var items = repository.ListOrgs()
26 .Select(o => ForgeOrgResponses.ToResponse(o, repository))
27 .ToList();
28 return Results.Ok(new OrgListResponse(items.Count, items));
29 }
30
31 private static IResult CreateOrg(
32 CreateOrgRequest request,
33 HttpContext context,
34 ForgeRepository repository,
35 ForgeRepoAccessService access)
36 {
37 access.EnsureHostAdmin(access.Resolve(context));
38 if (!ForgeSlug.IsValid(request.Slug))
39 throw new ForgeApiException(400, "Invalid org slug. Use lowercase slug: a-z, 0-9, hyphens.");
40 var slug = ForgeSlug.Normalize(request.Slug);
41 if (repository.OrgSlugExists(slug))
42 throw new ForgeApiException(409, $"Organization '{slug}' already exists.");
43
44 var defaultVisibility = RepoVisibilityExtensions.ParseSlugOrDefault(request.DefaultVisibility);
45 var entity = repository.InsertOrg(
46 slug,
47 request.DisplayName?.Trim() ?? slug,
48 request.Description?.Trim() ?? string.Empty,
49 defaultVisibility);
50 return Results.Created($"/api/v1/orgs/{slug}", ForgeOrgResponses.ToResponse(entity, repository));
51 }
52
53 private static IResult GetOrg(string slug, ForgeRepository repository)
54 {
55 var org = repository.GetOrgBySlug(slug)
56 ?? throw new ForgeApiException(404, $"Organization '{slug}' not found.");
57 return Results.Ok(ForgeOrgResponses.ToResponse(org, repository));
58 }
59
60 private static IResult ListOrgRepos(
61 string slug,
62 string? group,
63 ForgeRepository repository,
64 GitRepoService git,
65 ForgeRepoAccessService access,
66 HttpContext http)
67 {
68 var principal = access.Resolve(http);
69 var repos = access.FilterReadable(repository.ListRepos(group, slug), principal)
70 .Select(repo => ForgePluginResponses.ToRepoResponse(repo, git, repository))
71 .ToList();
72 return Results.Ok(new RepoListResponse(repos.Count, repos));
73 }
74}
75
76internal static class ForgeOrgResponses
77{
78 internal static OrgResponse ToResponse(ForgeOrgEntity org, ForgeRepository repository) =>
79 new(
80 org.Slug,
81 org.DisplayName,
82 org.Description,
83 org.DefaultVisibility.ToSlug(),
84 repository.CountReposInOrg(org.Id),
85 repository.ListRepoGroups(org.Id).Count,
86 org.CreatedAt);
87}
88
View only · write via MCP/CIDE