| 1 | using System.Text; |
| 2 | using AgentForge.Data; |
| 3 | using AgentForge.Models; |
| 4 | using AgentForge.Plugin.Issue.Pages; |
| 5 | using AgentForge.Plugin.Sdk; |
| 6 | using AgentForge.Abstractions; |
| 7 | using AgentForge.Plugin.View; |
| 8 | using AgentForge.Services; |
| 9 | using Microsoft.AspNetCore.Builder; |
| 10 | using Microsoft.Extensions.DependencyInjection; |
| 11 | |
| 12 | namespace AgentForge.Plugin.Issue; |
| 13 | |
| 14 | public static class ForgeIssueViewEndpoints |
| 15 | { |
| 16 | public static void Map(WebApplication app) |
| 17 | { |
| 18 | app.MapGet($"/view/repos/{ForgeRepoRouting.Pattern}/issues/{{number:int}}", RenderIssueView); |
| 19 | app.MapPost($"/view/repos/{ForgeRepoRouting.Pattern}/issues/{{number:int}}/comment", CommentOnIssueFromView); |
| 20 | } |
| 21 | |
| 22 | private static IResult RenderIssueView( |
| 23 | string name, |
| 24 | int number, |
| 25 | ForgeRepository repository, |
| 26 | ForgeUrls urls, |
| 27 | GitRepoService git, |
| 28 | HttpContext http) |
| 29 | { |
| 30 | var repo = ForgePluginEndpoints.RequireRepo(repository, name, http); |
| 31 | var issue = repository.GetIssueByNumber(repo.Id, number) |
| 32 | ?? throw new ForgeApiException(404, $"Issue #{number} not found."); |
| 33 | var defaultBranch = git.BareRepoExists(repo.Name) ? git.GetDefaultBranch(repo.Name) : null; |
| 34 | var comments = repository.ListIssueComments(issue.Id) |
| 35 | .Select(c => (c.Author, c.Body, c.CreatedAt)) |
| 36 | .ToList(); |
| 37 | |
| 38 | var iop = new StringBuilder(); |
| 39 | ForgeIopViewRenderer.AppendIssuePanel(iop, name, issue, comments); |
| 40 | var body = ForgeIssuePage.Render(name, number, issue, defaultBranch, urls, comments, iop.ToString()); |
| 41 | return ForgeViewPresenter.RepoPage($"Issue #{number}", repo, "issues", repository, body, http); |
| 42 | } |
| 43 | |
| 44 | private static async Task<IResult> CommentOnIssueFromView( |
| 45 | string name, |
| 46 | int number, |
| 47 | HttpContext http, |
| 48 | ForgeRepository repository, |
| 49 | CiWebhookService ci, |
| 50 | CancellationToken cancellationToken) |
| 51 | { |
| 52 | var repo = ForgePluginEndpoints.RequireRepo(repository, name, http); |
| 53 | var body = http.Request.Form["body"].ToString().Trim(); |
| 54 | if (body.Length == 0) |
| 55 | return Results.Redirect($"/view/repos/{Uri.EscapeDataString(name)}/issues/{number}"); |
| 56 | |
| 57 | var token = ForgeViewSession.TryGetToken(http, http.RequestServices.GetRequiredService<ForgeAuthService>()); |
| 58 | var author = token is not null ? ForgeActorResolver.NormalizeAgentIdentity(token.Name) : "human"; |
| 59 | var comment = repository.InsertIssueComment(repo.Id, number, body, author); |
| 60 | await ci.EmitIopAsync( |
| 61 | ForgeIopEvent.ForIssue("issue.comment", repo.Name, number, ForgePluginResponses.ToCommentResponse(comment), author), |
| 62 | cancellationToken).ConfigureAwait(false); |
| 63 | return Results.Redirect($"/view/repos/{Uri.EscapeDataString(name)}/issues/{number}"); |
| 64 | } |
| 65 | } |
| 66 | |