< Summary

Information
Class: Chronicis.Api.Controllers.ExternalLinksController
Assembly: Chronicis.Api
File(s): /home/runner/work/chronicis/chronicis/src/Chronicis.Api/Controllers/ExternalLinksController.cs
Line coverage
100%
Covered lines: 6
Uncovered lines: 0
Coverable lines: 6
Total lines: 103
Line coverage: 100%
Branch coverage
N/A
Covered branches: 0
Total branches: 0
Branch coverage: N/A
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
.ctor(...)100%11100%

File(s)

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

#LineLine coverage
 1using Chronicis.Api.Services.ExternalLinks;
 2using Chronicis.Shared.DTOs;
 3using Microsoft.AspNetCore.Mvc;
 4
 5namespace Chronicis.Api.Controllers;
 6
 7/// <summary>
 8/// API endpoints for External Link operations (SRD content, etc.)
 9/// </summary>
 10[ApiController]
 11[Route("external-links")]
 12// [Authorize] // Temporarily disabled for testing
 13public class ExternalLinksController : ControllerBase
 14{
 15    private readonly IExternalLinkService _externalLinkService;
 16    private readonly ILogger<ExternalLinksController> _logger;
 17
 718    public ExternalLinksController(
 719        IExternalLinkService externalLinkService,
 720        ILogger<ExternalLinksController> logger)
 21    {
 722        _externalLinkService = externalLinkService;
 723        _logger = logger;
 724    }
 25
 26    /// <summary>
 27    /// GET /api/external-links/suggestions?worldId={worldId}&amp;source={source}&amp;query={query}
 28    /// Get external link suggestions for autocomplete.
 29    /// Filters to only include providers enabled for the specified world.
 30    /// </summary>
 31    [HttpGet("suggestions")]
 32    public async Task<ActionResult<List<ExternalLinkSuggestionDto>>> GetSuggestions(
 33        [FromQuery] Guid? worldId,
 34        [FromQuery] string? source,
 35        [FromQuery] string? query,
 36        CancellationToken ct)
 37    {
 38        if (string.IsNullOrWhiteSpace(source))
 39        {
 40            return Ok(new List<ExternalLinkSuggestionDto>());
 41        }
 42
 43        _logger.LogTraceSanitized(
 44            "Getting external link suggestions for world {WorldId}, source '{Source}' with query '{Query}'",
 45            worldId, source, query);
 46
 47        var suggestions = await _externalLinkService.GetSuggestionsAsync(worldId, source, query ?? "", ct);
 48
 49        var dtos = suggestions.Select(s => new ExternalLinkSuggestionDto
 50        {
 51            Source = s.Source,
 52            Id = s.Id,
 53            Title = s.Title,
 54            Subtitle = s.Subtitle,
 55            Category = s.Category,
 56            Icon = s.Icon,
 57            Href = s.Href
 58        }).ToList();
 59
 60        return Ok(dtos);
 61    }
 62
 63    /// <summary>
 64    /// GET /api/external-links/content?source={source}&amp;id={id}
 65    /// Get external link content for display.
 66    /// </summary>
 67    [HttpGet("content")]
 68    public async Task<ActionResult<ExternalLinkContentDto>> GetContent(
 69        [FromQuery] string? source,
 70        [FromQuery] string? id,
 71        CancellationToken ct)
 72    {
 73        if (string.IsNullOrWhiteSpace(source) || string.IsNullOrWhiteSpace(id))
 74        {
 75            return BadRequest(new ExternalLinkErrorDto { Message = "Source and id are required" });
 76        }
 77
 78        _logger.LogTraceSanitized(
 79            "Getting external link content for source '{Source}' with id '{Id}'",
 80            source, id);
 81
 82        var content = await _externalLinkService.GetContentAsync(source, id, ct);
 83
 84        if (content == null)
 85        {
 86            return NotFound(new ExternalLinkErrorDto { Message = "Content not found" });
 87        }
 88
 89        var dto = new ExternalLinkContentDto
 90        {
 91            Source = content.Source,
 92            Id = content.Id,
 93            Title = content.Title,
 94            Kind = content.Kind,
 95            Markdown = content.Markdown,
 96            Attribution = content.Attribution,
 97            ExternalUrl = content.ExternalUrl,
 98            JsonData = content.JsonData
 99        };
 100
 101        return Ok(dto);
 102    }
 103}