< Summary

Information
Class: Api.Files.Endpoints.GetFileEndpoint
Assembly: Api
File(s): /home/runner/work/ProjectRead.ing/ProjectRead.ing/Api/Files/Endpoints/GetFileEndpoint.cs
Line coverage
100%
Covered lines: 23
Uncovered lines: 0
Coverable lines: 23
Total lines: 55
Line coverage: 100%
Branch coverage
100%
Covered branches: 6
Total branches: 6
Branch coverage: 100%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
.cctor()100%11100%
GetFileAsync()100%66100%

File(s)

/home/runner/work/ProjectRead.ing/ProjectRead.ing/Api/Files/Endpoints/GetFileEndpoint.cs

#LineLine coverage
 1// SPDX-FileCopyrightText: 2026 Alper Çelik <alper@alper-celik.dev>
 2//
 3// SPDX-License-Identifier: AGPL-3.0-or-later
 4
 5// Mostly Ai Generated - Start
 6using Api.Auth.Handlers;
 7using Api.Auth.Models;
 8using Api.Auth.Utils;
 9using Api.Files.FileProviders;
 10using Microsoft.AspNetCore.Http.HttpResults;
 11using Microsoft.AspNetCore.Mvc;
 12using Microsoft.Net.Http.Headers;
 13
 14namespace Api.Files.Endpoints;
 15
 16public static class GetFileEndpoint
 17{
 118    static readonly string[] s_inlineContentTypes =
 119    [
 120        "image/avif",
 121        "image/jpeg",
 122        "application/epub+zip",
 123    ];
 24
 25    [PermissionCheckAuthorize(UserPermissionBits.FileRead)]
 26    public static async Task<Results<FileStreamHttpResult, NotFound>> GetFileAsync(
 27        Guid id,
 28        [FromServices] ICurrentUserId userId,
 29        [FromServices] UserFileRouter router,
 30        HttpContext httpContext,
 31        CancellationToken ct
 32    )
 133    {
 134        if (await router.GetFileAsync(userId.Id!.Value, id, ct) is not { } content)
 135        {
 136            return TypedResults.NotFound();
 37        }
 38
 139        httpContext.Response.Headers["Cache-Control"] =
 140            "private, max-age=31536000, immutable";
 141        httpContext.Response.Headers["X-Content-Type-Options"] = "nosniff";
 42
 143        var inline = s_inlineContentTypes.Contains(content.ContentType);
 44
 145        return TypedResults.File(
 146            content.Stream,
 147            inline ? content.ContentType : "application/octet-stream",
 148            inline ? null : content.OriginalFileName ?? id.ToString(),
 149            content.MetadataAddedAt.ToDateTimeOffset(),
 150            new EntityTagHeaderValue($"\"{Convert.ToHexStringLower(content.SHA256)}\""),
 151            enableRangeProcessing: true
 152        );
 153    }
 54}
 55// Mostly Ai Generated - End

Methods/Properties

.cctor()
GetFileAsync()