< Summary

Information
Class: Chronicis.Api.Controllers.CampaignSummaryController
Assembly: Chronicis.Api
File(s): /home/runner/work/chronicis/chronicis/src/Chronicis.Api/Controllers/EntitySummaryControllers.cs
Line coverage
0%
Covered lines: 0
Uncovered lines: 49
Coverable lines: 49
Total lines: 430
Line coverage: 0%
Branch coverage
0%
Covered branches: 0
Total branches: 14
Branch coverage: 0%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
.ctor(...)100%210%
GetSummary()0%2040%
GetEstimate()0%620%
GenerateSummary()0%2040%
ClearSummary()0%2040%
HasAccessAsync()100%210%

File(s)

/home/runner/work/chronicis/chronicis/src/Chronicis.Api/Controllers/EntitySummaryControllers.cs

#LineLine coverage
 1using Chronicis.Api.Data;
 2using Chronicis.Api.Infrastructure;
 3using Chronicis.Api.Services;
 4using Chronicis.Shared.DTOs;
 5using Microsoft.AspNetCore.Authorization;
 6using Microsoft.AspNetCore.Mvc;
 7using Microsoft.EntityFrameworkCore;
 8
 9namespace Chronicis.Api.Controllers;
 10
 11/// <summary>
 12/// API endpoints for Article Summary operations.
 13/// These are nested under /api/articles/{id}/summary/* as expected by the client.
 14/// </summary>
 15[ApiController]
 16[Route("articles/{articleId:guid}/summary")]
 17[Authorize]
 18public class ArticleSummaryController : ControllerBase
 19{
 20    private readonly ISummaryService _summaryService;
 21    private readonly ChronicisDbContext _context;
 22    private readonly ICurrentUserService _currentUserService;
 23    private readonly ILogger<ArticleSummaryController> _logger;
 24
 25    public ArticleSummaryController(
 26        ISummaryService summaryService,
 27        ChronicisDbContext context,
 28        ICurrentUserService currentUserService,
 29        ILogger<ArticleSummaryController> logger)
 30    {
 31        _summaryService = summaryService;
 32        _context = context;
 33        _currentUserService = currentUserService;
 34        _logger = logger;
 35    }
 36
 37    /// <summary>
 38    /// GET /api/articles/{articleId}/summary - Get the current summary for an article.
 39    /// </summary>
 40    [HttpGet]
 41    public async Task<ActionResult<ArticleSummaryDto>> GetSummary(Guid articleId)
 42    {
 43        var user = await _currentUserService.GetRequiredUserAsync();
 44
 45        // Verify user has access
 46        if (!await HasAccessAsync(articleId, user.Id))
 47        {
 48            return NotFound(new { error = "Article not found or access denied" });
 49        }
 50
 51        _logger.LogDebug("Getting summary for article {ArticleId}", articleId);
 52
 53        var summary = await _summaryService.GetArticleSummaryAsync(articleId);
 54
 55        if (summary == null)
 56        {
 57            return NoContent();
 58        }
 59
 60        return Ok(summary);
 61    }
 62
 63    /// <summary>
 64    /// GET /api/articles/{articleId}/summary/preview - Get a lightweight summary preview for tooltip display.
 65    /// </summary>
 66    [HttpGet("preview")]
 67    public async Task<ActionResult<SummaryPreviewDto>> GetSummaryPreview(Guid articleId)
 68    {
 69        var user = await _currentUserService.GetRequiredUserAsync();
 70
 71        // Verify user has access
 72        if (!await HasAccessAsync(articleId, user.Id))
 73        {
 74            return NotFound(new { error = "Article not found or access denied" });
 75        }
 76
 77        _logger.LogDebug("Getting summary preview for article {ArticleId}", articleId);
 78
 79        var preview = await _summaryService.GetArticleSummaryPreviewAsync(articleId);
 80
 81        if (preview == null)
 82        {
 83            return NoContent();
 84        }
 85
 86        return Ok(preview);
 87    }
 88
 89    /// <summary>
 90    /// GET /api/articles/{articleId}/summary/estimate - Estimate the cost of generating a summary.
 91    /// </summary>
 92    [HttpGet("estimate")]
 93    public async Task<ActionResult<SummaryEstimateDto>> GetEstimate(Guid articleId)
 94    {
 95        var user = await _currentUserService.GetRequiredUserAsync();
 96
 97        // Verify user has access
 98        if (!await HasAccessAsync(articleId, user.Id))
 99        {
 100            return NotFound(new { error = "Article not found or access denied" });
 101        }
 102
 103        _logger.LogDebug("Getting summary estimate for article {ArticleId}", articleId);
 104
 105        var estimate = await _summaryService.EstimateArticleSummaryAsync(articleId);
 106        return Ok(estimate);
 107    }
 108
 109    /// <summary>
 110    /// POST /api/articles/{articleId}/summary/generate - Generate a summary for an article.
 111    /// </summary>
 112    [HttpPost("generate")]
 113    public async Task<ActionResult<SummaryGenerationDto>> GenerateSummary(
 114        Guid articleId,
 115        [FromBody] GenerateSummaryRequestDto? request)
 116    {
 117        var user = await _currentUserService.GetRequiredUserAsync();
 118
 119        // Verify user has access
 120        if (!await HasAccessAsync(articleId, user.Id))
 121        {
 122            return NotFound(new { error = "Article not found or access denied" });
 123        }
 124
 125        _logger.LogDebug("Generating summary for article {ArticleId}", articleId);
 126
 127        var result = await _summaryService.GenerateArticleSummaryAsync(articleId, request);
 128
 129        if (!result.Success)
 130        {
 131            return BadRequest(new { error = result.ErrorMessage });
 132        }
 133
 134        return Ok(result);
 135    }
 136
 137    /// <summary>
 138    /// DELETE /api/articles/{articleId}/summary - Clear the summary for an article.
 139    /// </summary>
 140    [HttpDelete]
 141    public async Task<IActionResult> ClearSummary(Guid articleId)
 142    {
 143        var user = await _currentUserService.GetRequiredUserAsync();
 144
 145        // Verify user has access
 146        if (!await HasAccessAsync(articleId, user.Id))
 147        {
 148            return NotFound(new { error = "Article not found or access denied" });
 149        }
 150
 151        _logger.LogDebug("Clearing summary for article {ArticleId}", articleId);
 152
 153        var success = await _summaryService.ClearArticleSummaryAsync(articleId);
 154
 155        if (!success)
 156        {
 157            return NotFound(new { error = "Article not found" });
 158        }
 159
 160        return NoContent();
 161    }
 162
 163    private async Task<bool> HasAccessAsync(Guid articleId, Guid userId)
 164    {
 165        return await _context.Articles
 166            .Where(a => a.Id == articleId)
 167            .Where(a => a.World != null && a.World.Members.Any(m => m.UserId == userId))
 168            .AnyAsync();
 169    }
 170}
 171
 172/// <summary>
 173/// API endpoints for Campaign Summary operations.
 174/// </summary>
 175[ApiController]
 176[Route("campaigns/{campaignId:guid}/summary")]
 177[Authorize]
 178public class CampaignSummaryController : ControllerBase
 179{
 180    private readonly ISummaryService _summaryService;
 181    private readonly ChronicisDbContext _context;
 182    private readonly ICurrentUserService _currentUserService;
 183    private readonly ILogger<CampaignSummaryController> _logger;
 184
 0185    public CampaignSummaryController(
 0186        ISummaryService summaryService,
 0187        ChronicisDbContext context,
 0188        ICurrentUserService currentUserService,
 0189        ILogger<CampaignSummaryController> logger)
 190    {
 0191        _summaryService = summaryService;
 0192        _context = context;
 0193        _currentUserService = currentUserService;
 0194        _logger = logger;
 0195    }
 196
 197    /// <summary>
 198    /// GET /api/campaigns/{campaignId}/summary - Get the current summary for a campaign.
 199    /// </summary>
 200    [HttpGet]
 201    public async Task<ActionResult<EntitySummaryDto>> GetSummary(Guid campaignId)
 202    {
 0203        var user = await _currentUserService.GetRequiredUserAsync();
 204
 0205        if (!await HasAccessAsync(campaignId, user.Id))
 206        {
 0207            return NotFound(new { error = "Campaign not found or access denied" });
 208        }
 209
 0210        _logger.LogDebug("Getting summary for campaign {CampaignId}", campaignId);
 211
 0212        var summary = await _summaryService.GetCampaignSummaryAsync(campaignId);
 213
 0214        if (summary == null)
 215        {
 0216            return NoContent();
 217        }
 218
 0219        return Ok(summary);
 0220    }
 221
 222    /// <summary>
 223    /// GET /api/campaigns/{campaignId}/summary/estimate - Estimate the cost of generating a summary.
 224    /// </summary>
 225    [HttpGet("estimate")]
 226    public async Task<ActionResult<SummaryEstimateDto>> GetEstimate(Guid campaignId)
 227    {
 0228        var user = await _currentUserService.GetRequiredUserAsync();
 229
 0230        if (!await HasAccessAsync(campaignId, user.Id))
 231        {
 0232            return NotFound(new { error = "Campaign not found or access denied" });
 233        }
 234
 0235        _logger.LogDebug("Getting summary estimate for campaign {CampaignId}", campaignId);
 236
 0237        var estimate = await _summaryService.EstimateCampaignSummaryAsync(campaignId);
 0238        return Ok(estimate);
 0239    }
 240
 241    /// <summary>
 242    /// POST /api/campaigns/{campaignId}/summary/generate - Generate a summary for a campaign.
 243    /// </summary>
 244    [HttpPost("generate")]
 245    public async Task<ActionResult<SummaryGenerationDto>> GenerateSummary(
 246        Guid campaignId,
 247        [FromBody] GenerateSummaryRequestDto? request)
 248    {
 0249        var user = await _currentUserService.GetRequiredUserAsync();
 250
 0251        if (!await HasAccessAsync(campaignId, user.Id))
 252        {
 0253            return NotFound(new { error = "Campaign not found or access denied" });
 254        }
 255
 0256        _logger.LogDebug("Generating summary for campaign {CampaignId}", campaignId);
 257
 0258        var result = await _summaryService.GenerateCampaignSummaryAsync(campaignId, request);
 259
 0260        if (!result.Success)
 261        {
 0262            return BadRequest(new { error = result.ErrorMessage });
 263        }
 264
 0265        return Ok(result);
 0266    }
 267
 268    /// <summary>
 269    /// DELETE /api/campaigns/{campaignId}/summary - Clear the summary for a campaign.
 270    /// </summary>
 271    [HttpDelete]
 272    public async Task<IActionResult> ClearSummary(Guid campaignId)
 273    {
 0274        var user = await _currentUserService.GetRequiredUserAsync();
 275
 0276        if (!await HasAccessAsync(campaignId, user.Id))
 277        {
 0278            return NotFound(new { error = "Campaign not found or access denied" });
 279        }
 280
 0281        _logger.LogDebug("Clearing summary for campaign {CampaignId}", campaignId);
 282
 0283        var success = await _summaryService.ClearCampaignSummaryAsync(campaignId);
 284
 0285        if (!success)
 286        {
 0287            return NotFound(new { error = "Campaign not found" });
 288        }
 289
 0290        return NoContent();
 0291    }
 292
 293    private async Task<bool> HasAccessAsync(Guid campaignId, Guid userId)
 294    {
 0295        return await _context.Campaigns
 0296            .Where(c => c.Id == campaignId)
 0297            .Where(c => c.World != null && c.World.Members.Any(m => m.UserId == userId))
 0298            .AnyAsync();
 0299    }
 300}
 301
 302/// <summary>
 303/// API endpoints for Arc Summary operations.
 304/// </summary>
 305[ApiController]
 306[Route("arcs/{arcId:guid}/summary")]
 307[Authorize]
 308public class ArcSummaryController : ControllerBase
 309{
 310    private readonly ISummaryService _summaryService;
 311    private readonly ChronicisDbContext _context;
 312    private readonly ICurrentUserService _currentUserService;
 313    private readonly ILogger<ArcSummaryController> _logger;
 314
 315    public ArcSummaryController(
 316        ISummaryService summaryService,
 317        ChronicisDbContext context,
 318        ICurrentUserService currentUserService,
 319        ILogger<ArcSummaryController> logger)
 320    {
 321        _summaryService = summaryService;
 322        _context = context;
 323        _currentUserService = currentUserService;
 324        _logger = logger;
 325    }
 326
 327    /// <summary>
 328    /// GET /api/arcs/{arcId}/summary - Get the current summary for an arc.
 329    /// </summary>
 330    [HttpGet]
 331    public async Task<ActionResult<EntitySummaryDto>> GetSummary(Guid arcId)
 332    {
 333        var user = await _currentUserService.GetRequiredUserAsync();
 334
 335        if (!await HasAccessAsync(arcId, user.Id))
 336        {
 337            return NotFound(new { error = "Arc not found or access denied" });
 338        }
 339
 340        _logger.LogDebug("Getting summary for arc {ArcId}", arcId);
 341
 342        var summary = await _summaryService.GetArcSummaryAsync(arcId);
 343
 344        if (summary == null)
 345        {
 346            return NoContent();
 347        }
 348
 349        return Ok(summary);
 350    }
 351
 352    /// <summary>
 353    /// GET /api/arcs/{arcId}/summary/estimate - Estimate the cost of generating a summary.
 354    /// </summary>
 355    [HttpGet("estimate")]
 356    public async Task<ActionResult<SummaryEstimateDto>> GetEstimate(Guid arcId)
 357    {
 358        var user = await _currentUserService.GetRequiredUserAsync();
 359
 360        if (!await HasAccessAsync(arcId, user.Id))
 361        {
 362            return NotFound(new { error = "Arc not found or access denied" });
 363        }
 364
 365        _logger.LogDebug("Getting summary estimate for arc {ArcId}", arcId);
 366
 367        var estimate = await _summaryService.EstimateArcSummaryAsync(arcId);
 368        return Ok(estimate);
 369    }
 370
 371    /// <summary>
 372    /// POST /api/arcs/{arcId}/summary/generate - Generate a summary for an arc.
 373    /// </summary>
 374    [HttpPost("generate")]
 375    public async Task<ActionResult<SummaryGenerationDto>> GenerateSummary(
 376        Guid arcId,
 377        [FromBody] GenerateSummaryRequestDto? request)
 378    {
 379        var user = await _currentUserService.GetRequiredUserAsync();
 380
 381        if (!await HasAccessAsync(arcId, user.Id))
 382        {
 383            return NotFound(new { error = "Arc not found or access denied" });
 384        }
 385
 386        _logger.LogDebug("Generating summary for arc {ArcId}", arcId);
 387
 388        var result = await _summaryService.GenerateArcSummaryAsync(arcId, request);
 389
 390        if (!result.Success)
 391        {
 392            return BadRequest(new { error = result.ErrorMessage });
 393        }
 394
 395        return Ok(result);
 396    }
 397
 398    /// <summary>
 399    /// DELETE /api/arcs/{arcId}/summary - Clear the summary for an arc.
 400    /// </summary>
 401    [HttpDelete]
 402    public async Task<IActionResult> ClearSummary(Guid arcId)
 403    {
 404        var user = await _currentUserService.GetRequiredUserAsync();
 405
 406        if (!await HasAccessAsync(arcId, user.Id))
 407        {
 408            return NotFound(new { error = "Arc not found or access denied" });
 409        }
 410
 411        _logger.LogDebug("Clearing summary for arc {ArcId}", arcId);
 412
 413        var success = await _summaryService.ClearArcSummaryAsync(arcId);
 414
 415        if (!success)
 416        {
 417            return NotFound(new { error = "Arc not found" });
 418        }
 419
 420        return NoContent();
 421    }
 422
 423    private async Task<bool> HasAccessAsync(Guid arcId, Guid userId)
 424    {
 425        return await _context.Arcs
 426            .Where(a => a.Id == arcId)
 427            .Where(a => a.Campaign != null && a.Campaign.World != null && a.Campaign.World.Members.Any(m => m.UserId == 
 428            .AnyAsync();
 429    }
 430}