< Summary

Information
Class: Api.Files.Mutations.UploadFileRecordContentPayload
Assembly: Api
File(s): /home/runner/work/ProjectRead.ing/ProjectRead.ing/Api/Files/Mutations/UploadFileRecordContentMutation.cs
Line coverage
100%
Covered lines: 1
Uncovered lines: 0
Coverable lines: 1
Total lines: 92
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/UploadFileRecordContentMutation.cs

#LineLine coverage
 1// SPDX-FileCopyrightText: 2026 Alper Çelik <[email protected]>
 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 HotChocolate.Types;
 16using Microsoft.EntityFrameworkCore;
 17using static Api.Utils.ValidatorUtils;
 18
 19namespace Api.Files.Mutations;
 20
 21[MutationType]
 22public static partial class UploadFileRecordContentMutations
 23{
 24    [PermissionCheckAuthorize(UserPermissionBits.FileWrite)]
 25    [Error(typeof(DomainError))]
 26    public static async Task<UploadFileRecordContentPayload> UploadFileRecordContentAsync(
 27        [Service] ICurrentUserId userId,
 28        [Service] IEFTransactionDIAccessorService txGetter,
 29        [Service] UserFileRouter router,
 30        [Service] IValidator<UploadFileRecordContentInput> validator,
 31        UploadFileRecordContentInput input,
 32        IFile file,
 33        CancellationToken ct
 34    )
 35    {
 36        await validator.ValidateOrThrowInputAsync(input, ct);
 37
 38        var tx = await txGetter.BeginOrGetTransactionAsync(ct);
 39
 40        var fileRecord = await router.SetFileAsync(
 41            userId.Id!.Value,
 42            input.Id,
 43            file.OpenReadStream(),
 44            ct
 45        );
 46
 47        if (fileRecord is null)
 48        {
 49            throw new DomainException(
 50                ErrorCodes.FILE_UPLOAD_FAILED,
 51                "File content did not match the declared size or SHA256"
 52            );
 53        }
 54
 55        await tx.CommitAsync(ct);
 56        return new UploadFileRecordContentPayload(FileRecordMapper.ToDto(fileRecord));
 57    }
 58}
 59
 160public record UploadFileRecordContentPayload(Queries.FileRecord FileRecord);
 61
 62public record UploadFileRecordContentInput
 63{
 64    public required Guid Id { get; init; }
 65
 66    public class UploadFileRecordContentInputValidator
 67        : AbstractValidator<UploadFileRecordContentInput>
 68    {
 69        public UploadFileRecordContentInputValidator(
 70            PGContext db,
 71            ICurrentUserId userId,
 72            IEFTransactionDIAccessorService tx
 73        )
 74        {
 75            RuleFor(w => w).BeginTransaction(tx);
 76
 77            RuleFor(w => w.Id).IdMustExist(db.FileRecords, userId.Id);
 78
 79            RuleFor(w => w.Id)
 80                .MustAsync(
 81                    async (id, ct) =>
 82                        !await db.FileRecords.AnyAsync(
 83                            f => f.OwnerId == userId.Id && f.Id == id && f.Uploaded,
 84                            ct
 85                        )
 86                )
 87                .WithMessage("File is already uploaded")
 88                .WithErrorCode(ErrorCodes.FILE_ALREADY_UPLOADED);
 89        }
 90    }
 91}
 92// Mostly Ai Generated - End