Forge
csharp3407750f
1using AgentForge;
2using AgentForge.Abstractions;
3using AgentForge.Contracts;
4using AgentForge.Data;
5using AgentForge.Data.Entities;
6using AgentForge.Models;
7using AgentForge.Plugin.Sdk;
8using AgentForge.Services;
9using Microsoft.AspNetCore.Builder;
10using Microsoft.AspNetCore.Http;
11using Microsoft.AspNetCore.Routing;
12
13namespace AgentForge.Plugin.Organization.UserManagement.Endpoints;
14
15internal static class ForgeOrgMemberEndpoints
16{
17 internal static RouteGroupBuilder MapOrgMemberEndpoints(this RouteGroupBuilder api)
18 {
19 api.MapGet("/orgs/{slug}/members", ListMembers);
20 api.MapPost("/orgs/{slug}/members", AddMember);
21 api.MapPatch("/orgs/{slug}/members/{login}", UpdateMember);
22 api.MapDelete("/orgs/{slug}/members/{login}", RemoveMember);
23 return api;
24 }
25
26 private static IResult ListMembers(
27 string slug,
28 HttpContext context,
29 ForgeRepository repository,
30 ForgeRepoAccessService access)
31 {
32 var org = repository.GetOrgBySlug(slug)
33 ?? throw new ForgeApiException(404, $"Organization '{slug}' not found.");
34 access.EnsureOrgCatalogAdmin(org.Id, access.Resolve(context));
35
36 var members = repository.ListOrgMembers(org.Id)
37 .Select(pair => ToResponse(pair.Identity, pair.Member))
38 .ToList();
39 return Results.Ok(new OrgMemberListResponse(members.Count, members));
40 }
41
42 private static IResult AddMember(
43 string slug,
44 AddOrgMemberRequest request,
45 HttpContext context,
46 ForgeRepository repository,
47 ForgeRepoAccessService access)
48 {
49 var org = repository.GetOrgBySlug(slug)
50 ?? throw new ForgeApiException(404, $"Organization '{slug}' not found.");
51 access.EnsureOrgCatalogAdmin(org.Id, access.Resolve(context));
52 if (string.IsNullOrWhiteSpace(request.Provider) || string.IsNullOrWhiteSpace(request.Login))
53 throw new ForgeApiException(400, "provider and login required.");
54
55 var identity = repository.FindIdentityByOAuthLogin(request.Provider.Trim(), request.Login.Trim())
56 ?? throw new ForgeApiException(404, "Identity not found. User must sign in via OAuth first.");
57
58 var role = ForgeOrgRoleExtensions.TryParseSlug(request.Role, out var parsed)
59 ? parsed
60 : ForgeOrgRole.Member;
61
62 var hadMembership = repository.IsOrgMember(org.Id, identity.Id);
63 var member = repository.UpsertOrgMember(org.Id, identity.Id, role);
64 var response = ToResponse(identity, member);
65
66 return hadMembership
67 ? Results.Ok(response)
68 : Results.Created($"/api/v1/orgs/{slug}/members/{identity.Login}", response);
69 }
70
71 private static IResult UpdateMember(
72 string slug,
73 string login,
74 UpdateOrgMemberRequest request,
75 HttpContext context,
76 ForgeRepository repository,
77 ForgeRepoAccessService access)
78 {
79 var org = repository.GetOrgBySlug(slug)
80 ?? throw new ForgeApiException(404, $"Organization '{slug}' not found.");
81 access.EnsureOrgCatalogAdmin(org.Id, access.Resolve(context));
82
83 var identity = repository.FindIdentityByOAuthLogin("github", login.Trim())
84 ?? throw new ForgeApiException(404, "Identity not found.");
85
86 if (!repository.IsOrgMember(org.Id, identity.Id))
87 throw new ForgeApiException(404, "Organization member not found.");
88
89 if (!ForgeOrgRoleExtensions.TryParseSlug(request.Role, out var role))
90 throw new ForgeApiException(400, "role required (member | admin | owner).");
91
92 var member = repository.UpsertOrgMember(org.Id, identity.Id, role);
93 return Results.Ok(ToResponse(identity, member));
94 }
95
96 private static IResult RemoveMember(
97 string slug,
98 string login,
99 HttpContext context,
100 ForgeRepository repository,
101 ForgeRepoAccessService access)
102 {
103 var org = repository.GetOrgBySlug(slug)
104 ?? throw new ForgeApiException(404, $"Organization '{slug}' not found.");
105 access.EnsureOrgCatalogAdmin(org.Id, access.Resolve(context));
106
107 var identity = repository.FindIdentityByOAuthLogin("github", login.Trim())
108 ?? throw new ForgeApiException(404, "Identity not found.");
109
110 if (!repository.RemoveOrgMember(org.Id, identity.Id))
111 throw new ForgeApiException(404, "Organization member not found.");
112
113 return Results.NoContent();
114 }
115
116 private static OrgMemberResponse ToResponse(ForgeIdentityEntity identity, ForgeOrgMemberEntity member) =>
117 new(
118 identity.Login,
119 identity.DisplayName,
120 member.Role.ToSlug(),
121 member.CreatedAt);
122}
123
View only · write via MCP/CIDE