< Summary

Information
Class: Api.Files.Mutations.AddFileRecordPayload
Assembly: Api
File(s): /home/runner/work/ProjectRead.ing/ProjectRead.ing/Api/Files/Mutations/AddFileRecordMutation.cs
Line coverage
100%
Covered lines: 1
Uncovered lines: 0
Coverable lines: 1
Total lines: 89
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/ProjectRead.ing/ProjectRead.ing/Api/Files/Mutations/AddFileRecordMutation.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.Database;
 10using Api.Database.Utils;
 11using Api.Files.FileProviders;
 12using Api.Files.Queries;
 13using Api.Utils;
 14using FluentValidation;
 15using static Api.Utils.ValidatorUtils;
 16
 17namespace Api.Files.Mutations;
 18
 19[MutationType]
 20public static partial class AddFileRecordMutations
 21{
 22    [PermissionCheckAuthorize(UserPermissionBits.FileWrite)]
 23    [Error(typeof(DomainError))]
 24    public static async Task<AddFileRecordPayload> AddFileRecordAsync(
 25        [Service] ICurrentUserId userId,
 26        [Service] IEFTransactionDIAccessorService txGetter,
 27        [Service] UserFileRouter router,
 28        [Service] IValidator<AddFileRecordInput> validator,
 29        AddFileRecordInput input,
 30        CancellationToken ct
 31    )
 32    {
 33        await validator.ValidateOrThrowInputAsync(input, ct);
 34
 35        var tx = await txGetter.BeginOrGetTransactionAsync(ct);
 36
 37        var fileRecord = await router.CreateFileAsync(
 38            userId.Id!.Value,
 39            input.FileKind,
 40            input.ContentType,
 41            input.OriginalFileName,
 42            input.SizeBytes,
 43            Convert.FromHexString(input.Sha256),
 44            ct
 45        );
 46
 47        await tx.CommitAsync(ct);
 48        return new AddFileRecordPayload(FileRecordMapper.ToDto(fileRecord));
 49    }
 50}
 51
 152public record AddFileRecordPayload(Queries.FileRecord FileRecord);
 53
 54public record AddFileRecordInput
 55{
 56    public required FileKind FileKind { get; init; }
 57
 58    public required string ContentType { get; init; }
 59
 60    public string? OriginalFileName { get; init; }
 61
 62    public required long SizeBytes { get; init; }
 63
 64    public required string Sha256 { get; init; }
 65
 66    public class AddFileRecordInputValidator : AbstractValidator<AddFileRecordInput>
 67    {
 68        public AddFileRecordInputValidator(
 69            PGContext db,
 70            ICurrentUserId userId,
 71            IEFTransactionDIAccessorService tx
 72        )
 73        {
 74            RuleFor(w => w).BeginTransaction(tx);
 75
 76            RuleFor(w => w.ContentType).NotEmpty();
 77            RuleFor(w => w.OriginalFileName).MaximumLength(1000);
 78            RuleFor(w => w.SizeBytes).GreaterThan(0);
 79            RuleFor(w => w.Sha256)
 80                .Must(BeValidSha256)
 81                .WithMessage("SHA256 must be 64 hexadecimal characters")
 82                .WithErrorCode(ErrorCodes.INVALID_SHA256);
 83        }
 84
 85        static bool BeValidSha256(string sha256) =>
 86            sha256.Length == 64 && sha256.All(Uri.IsHexDigit);
 87    }
 88}
 89// Mostly Ai Generated - End