< Summary

Information
Class: Chronicis.Api.Controllers.ArticleSummaryController
Assembly: Chronicis.Api
File(s): /home/runner/work/chronicis/chronicis/src/Chronicis.Api/Controllers/EntitySummaryControllers.cs
Line coverage
0%
Covered lines: 0
Uncovered lines: 58
Coverable lines: 58
Total lines: 430
Line coverage: 0%
Branch coverage
0%
Covered branches: 0
Total branches: 18
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%
GetSummaryPreview()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
 025    public ArticleSummaryController(
 026        ISummaryService summaryService,
 027        ChronicisDbContext context,
 028        ICurrentUserService currentUserService,
 029        ILogger<ArticleSummaryController> logger)
 30    {
 031        _summaryService = summaryService;
 032        _context = context;
 033        _currentUserService = currentUserService;
 034        _logger = logger;
 035    }
 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    {
 043        var user = await _currentUserService.GetRequiredUserAsync();
 44
 45        // Verify user has access
 046        if (!await HasAccessAsync(articleId, user.Id))
 47        {
 048            return NotFound(new { error = "Article not found or access denied" });
 49        }
 50
 051        _logger.LogDebug("Getting summary for article {ArticleId}", articleId);
 52
 053        var summary = await _summaryService.GetArticleSummaryAsync(articleId);
 54
 055        if (summary == null)
 56        {
 057            return NoContent();
 58        }
 59
 060        return Ok(summary);
 061    }
 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    {
 069        var user = await _currentUserService.GetRequiredUserAsync();
 70
 71        // Verify user has access
 072        if (!await HasAccessAsync(articleId, user.Id))
 73        {
 074            return NotFound(new { error = "Article not found or access denied" });
 75        }
 76
 077        _logger.LogDebug("Getting summary preview for article {ArticleId}", articleId);
 78
 079        var preview = await _summaryService.GetArticleSummaryPreviewAsync(articleId);
 80
 081        if (preview == null)
 82        {
 083            return NoContent();
 84        }
 85
 086        return Ok(preview);
 087    }
 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    {
 095        var user = await _currentUserService.GetRequiredUserAsync();
 96
 97        // Verify user has access
 098        if (!await HasAccessAsync(articleId, user.Id))
 99        {
 0100            return NotFound(new { error = "Article not found or access denied" });
 101        }
 102
 0103        _logger.LogDebug("Getting summary estimate for article {ArticleId}", articleId);
 104
 0105        var estimate = await _summaryService.EstimateArticleSummaryAsync(articleId);
 0106        return Ok(estimate);
 0107    }
 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    {
 0117        var user = await _currentUserService.GetRequiredUserAsync();
 118
 119        // Verify user has access
 0120        if (!await HasAccessAsync(articleId, user.Id))
 121        {
 0122            return NotFound(new { error = "Article not found or access denied" });
 123        }
 124
 0125        _logger.LogDebug("Generating summary for article {ArticleId}", articleId);
 126
 0127        var result = await _summaryService.GenerateArticleSummaryAsync(articleId, request);
 128
 0129        if (!result.Success)
 130        {
 0131            return BadRequest(new { error = result.ErrorMessage });
 132        }
 133
 0134        return Ok(result);
 0135    }
 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    {
 0143        var user = await _currentUserService.GetRequiredUserAsync();
 144
 145        // Verify user has access
 0146        if (!await HasAccessAsync(articleId, user.Id))
 147        {
 0148            return NotFound(new { error = "Article not found or access denied" });
 149        }
 150
 0151        _logger.LogDebug("Clearing summary for article {ArticleId}", articleId);
 152
 0153        var success = await _summaryService.ClearArticleSummaryAsync(articleId);
 154
 0155        if (!success)
 156        {
 0157            return NotFound(new { error = "Article not found" });
 158        }
 159
 0160        return NoContent();
 0161    }
 162
 163    private async Task<bool> HasAccessAsync(Guid articleId, Guid userId)
 164    {
 0165        return await _context.Articles
 0166            .Where(a => a.Id == articleId)
 0167            .Where(a => a.World != null && a.World.Members.Any(m => m.UserId == userId))
 0168            .AnyAsync();
 0169    }
 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
 185    public CampaignSummaryController(
 186        ISummaryService summaryService,
 187        ChronicisDbContext context,
 188        ICurrentUserService currentUserService,
 189        ILogger<CampaignSummaryController> logger)
 190    {
 191        _summaryService = summaryService;
 192        _context = context;
 193        _currentUserService = currentUserService;
 194        _logger = logger;
 195    }
 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    {
 203        var user = await _currentUserService.GetRequiredUserAsync();
 204
 205        if (!await HasAccessAsync(campaignId, user.Id))
 206        {
 207            return NotFound(new { error = "Campaign not found or access denied" });
 208        }
 209
 210        _logger.LogDebug("Getting summary for campaign {CampaignId}", campaignId);
 211
 212        var summary = await _summaryService.GetCampaignSummaryAsync(campaignId);
 213
 214        if (summary == null)
 215        {
 216            return NoContent();
 217        }
 218
 219        return Ok(summary);
 220    }
 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    {
 228        var user = await _currentUserService.GetRequiredUserAsync();
 229
 230        if (!await HasAccessAsync(campaignId, user.Id))
 231        {
 232            return NotFound(new { error = "Campaign not found or access denied" });
 233        }
 234
 235        _logger.LogDebug("Getting summary estimate for campaign {CampaignId}", campaignId);
 236
 237        var estimate = await _summaryService.EstimateCampaignSummaryAsync(campaignId);
 238        return Ok(estimate);
 239    }
 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    {
 249        var user = await _currentUserService.GetRequiredUserAsync();
 250
 251        if (!await HasAccessAsync(campaignId, user.Id))
 252        {
 253            return NotFound(new { error = "Campaign not found or access denied" });
 254        }
 255
 256        _logger.LogDebug("Generating summary for campaign {CampaignId}", campaignId);
 257
 258        var result = await _summaryService.GenerateCampaignSummaryAsync(campaignId, request);
 259
 260        if (!result.Success)
 261        {
 262            return BadRequest(new { error = result.ErrorMessage });
 263        }
 264
 265        return Ok(result);
 266    }
 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    {
 274        var user = await _currentUserService.GetRequiredUserAsync();
 275
 276        if (!await HasAccessAsync(campaignId, user.Id))
 277        {
 278            return NotFound(new { error = "Campaign not found or access denied" });
 279        }
 280
 281        _logger.LogDebug("Clearing summary for campaign {CampaignId}", campaignId);
 282
 283        var success = await _summaryService.ClearCampaignSummaryAsync(campaignId);
 284
 285        if (!success)
 286        {
 287            return NotFound(new { error = "Campaign not found" });
 288        }
 289
 290        return NoContent();
 291    }
 292
 293    private async Task<bool> HasAccessAsync(Guid campaignId, Guid userId)
 294    {
 295        return await _context.Campaigns
 296            .Where(c => c.Id == campaignId)
 297            .Where(c => c.World != null && c.World.Members.Any(m => m.UserId == userId))
 298            .AnyAsync();
 299    }
 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}