< Summary

Line coverage
89%
Covered lines: 131
Uncovered lines: 16
Coverable lines: 147
Total lines: 263
Line coverage: 89.1%
Branch coverage
87%
Covered branches: 7
Total branches: 8
Branch coverage: 87.5%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

File(s)

/home/runner/work/ProjectRead.ing/ProjectRead.ing/Api/Files/Mutations/UploadFileRecordContentMutation.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 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    )
 135    {
 136        await validator.ValidateOrThrowInputAsync(input, ct);
 37
 138        var tx = await txGetter.BeginOrGetTransactionAsync(ct);
 39
 140        var fileRecord = await router.SetFileAsync(
 141            userId.Id!.Value,
 142            input.Id,
 143            file.OpenReadStream(),
 144            ct
 145        );
 46
 147        if (fileRecord is null)
 048        {
 049            throw new DomainException(
 050                ErrorCodes.FILE_UPLOAD_FAILED,
 051                "File content did not match the declared size or SHA256"
 052            );
 53        }
 54
 155        await tx.CommitAsync(ct);
 156        return new UploadFileRecordContentPayload(FileRecordMapper.ToDto(fileRecord));
 157    }
 58}
 59
 60public 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

/home/runner/work/ProjectRead.ing/ProjectRead.ing/Api/obj/Debug/net10.0/generated/HotChocolate.Types.Analyzers/HotChocolate.Types.Analyzers.GraphQLServerGenerator/UploadFileRecordContentMutations.MuAeZK5uwlVFtMhs568cXw.hc.g.cs

#LineLine coverage
 1// <auto-generated/>
 2
 3#nullable enable
 4#pragma warning disable
 5
 6using System;
 7using System.Runtime.CompilerServices;
 8using HotChocolate;
 9using HotChocolate.Types;
 10using HotChocolate.Execution.Configuration;
 11using Microsoft.Extensions.DependencyInjection;
 12using HotChocolate.Internal;
 13
 14namespace Api.Files.Mutations
 15{
 16    public static partial class UploadFileRecordContentMutations
 17    {
 18        internal static void Initialize(global::HotChocolate.Types.IObjectTypeDescriptor descriptor)
 119        {
 120            var extension = descriptor.Extend();
 121            var configuration = extension.Configuration;
 122            var thisType = typeof(global::Api.Files.Mutations.UploadFileRecordContentMutations);
 123            var bindingResolver = extension.Context.ParameterBindingResolver;
 124            var resolvers = new __Resolvers(bindingResolver);
 25
 126            HotChocolate.Internal.ConfigurationHelper.ApplyConfiguration(
 127                extension.Context,
 128                descriptor,
 129                typeof(global::Api.Files.Mutations.UploadFileRecordContentMutations),
 130                new global::HotChocolate.Types.MutationTypeAttribute());
 131            configuration.ConfigurationsAreApplied = true;
 32
 133            var naming = descriptor.Extend().Context.Naming;
 34
 135            descriptor
 136                .Field(naming.GetMemberName("UploadFileRecordContent", global::HotChocolate.Types.MemberKind.ObjectField
 137                .ExtendWith(static (field, context) =>
 138                {
 139                    var configuration = field.Configuration;
 140                    var typeInspector = field.Context.TypeInspector;
 141                    var bindingResolver = field.Context.ParameterBindingResolver;
 142                    var naming = field.Context.Naming;
 143
 144                    configuration.Type = global::HotChocolate.Types.Descriptors.TypeReference.Create(
 145                        typeInspector.GetTypeRef(typeof(global::Api.Files.Mutations.UploadFileRecordContentPayload), Hot
 146                        new global::HotChocolate.Language.NonNullTypeNode(new global::HotChocolate.Language.NamedTypeNod
 147                    configuration.ResultType = typeof(global::Api.Files.Mutations.UploadFileRecordContentPayload);
 148                    configuration.DeclaringType = context.ThisType;
 149
 150                    configuration.SetSourceGeneratorFlags();
 151
 152                    var bindingInfo = field.Context.ParameterBindingResolver;
 153                    var parameter = context.Resolvers.CreateParameterDescriptor_UploadFileRecordContentAsync_input();
 154                    var parameterInfo = bindingInfo.GetBindingInfo(parameter);
 155
 156                    if(parameterInfo.Kind is global::HotChocolate.Internal.ArgumentKind.Argument)
 157                    {
 158                        var argumentConfiguration = new global::HotChocolate.Types.Descriptors.Configurations.ArgumentCo
 159                        {
 160                            Name = naming.GetMemberName("input", global::HotChocolate.Types.MemberKind.Argument),
 161                            Type = global::HotChocolate.Types.Descriptors.TypeReference.Create(
 162                                typeInspector.GetTypeRef(typeof(global::Api.Files.Mutations.UploadFileRecordContentInput
 163                                new global::HotChocolate.Language.NonNullTypeNode(new global::HotChocolate.Language.Name
 164                            RuntimeType = typeof(global::Api.Files.Mutations.UploadFileRecordContentInput)
 165                        };
 166
 167                        configuration.Arguments.Add(argumentConfiguration);
 168                    }
 169
 170                    parameter = context.Resolvers.CreateParameterDescriptor_UploadFileRecordContentAsync_file();
 171                    parameterInfo = bindingInfo.GetBindingInfo(parameter);
 172
 173                    if(parameterInfo.Kind is global::HotChocolate.Internal.ArgumentKind.Argument)
 174                    {
 175                        var argumentConfiguration = new global::HotChocolate.Types.Descriptors.Configurations.ArgumentCo
 176                        {
 177                            Name = naming.GetMemberName("file", global::HotChocolate.Types.MemberKind.Argument),
 178                            Type = global::HotChocolate.Types.Descriptors.TypeReference.Create(
 179                                typeInspector.GetTypeRef(typeof(global::HotChocolate.Types.IFile), HotChocolate.Types.Ty
 180                                new global::HotChocolate.Language.NonNullTypeNode(new global::HotChocolate.Language.Name
 181                            RuntimeType = typeof(global::HotChocolate.Types.IFile)
 182                        };
 183
 184                        configuration.Arguments.Add(argumentConfiguration);
 185                    }
 186
 187                    configuration.Member = context.ThisType.GetMethod(
 188                        "UploadFileRecordContentAsync",
 189                        global::HotChocolate.Utilities.ReflectionUtils.StaticMemberFlags,
 190                        new global::System.Type[]
 191                        {
 192                            typeof(global::Api.Auth.Utils.ICurrentUserId),
 193                            typeof(global::Api.Database.Utils.IEFTransactionDIAccessorService),
 194                            typeof(global::Api.Files.FileProviders.UserFileRouter),
 195                            typeof(global::FluentValidation.IValidator<global::Api.Files.Mutations.UploadFileRecordConte
 196                            typeof(global::Api.Files.Mutations.UploadFileRecordContentInput),
 197                            typeof(global::HotChocolate.Types.IFile),
 198                            typeof(global::System.Threading.CancellationToken)
 199                        })!;
 1100
 1101                    var fieldDescriptor = global::HotChocolate.Types.Descriptors.ObjectFieldDescriptor.From(field.Contex
 1102                    HotChocolate.Internal.ConfigurationHelper.ApplyConfiguration(
 1103                        field.Context,
 1104                        fieldDescriptor,
 1105                        configuration.Member,
 1106                        new global::Api.Auth.Handlers.PermissionCheckAuthorizeAttribute(global::Api.Auth.Models.UserPerm
 1107                        new global::HotChocolate.Types.ErrorAttribute(typeof(global::Api.Utils.DomainError)));
 1108
 1109                    bindingResolver.ApplyConfiguration(
 1110                        context.Resolvers.CreateParameterDescriptor_UploadFileRecordContentAsync_input(),
 1111                        fieldDescriptor);
 1112
 1113                    bindingResolver.ApplyConfiguration(
 1114                        context.Resolvers.CreateParameterDescriptor_UploadFileRecordContentAsync_file(),
 1115                        fieldDescriptor);
 1116
 1117                    configuration.ConfigurationsAreApplied = true;
 1118                    fieldDescriptor.CreateConfiguration();
 1119
 1120                    configuration.Resolvers = context.Resolvers.UploadFileRecordContentAsync();
 1121                },
 1122                (Resolvers: resolvers, ThisType: thisType));
 123
 124            Configure(descriptor);
 1125        }
 126
 127        static partial void Configure(global::HotChocolate.Types.IObjectTypeDescriptor descriptor);
 128
 129        private sealed class __Resolvers
 130        {
 131            private readonly global::HotChocolate.Internal.IParameterBinding _binding_UploadFileRecordContentAsync_input
 132            private readonly global::HotChocolate.Internal.IParameterBinding _binding_UploadFileRecordContentAsync_file;
 133
 1134            public __Resolvers(global::HotChocolate.Resolvers.ParameterBindingResolver bindingResolver)
 1135            {
 1136                _binding_UploadFileRecordContentAsync_input = bindingResolver.GetBinding(CreateParameterDescriptor_Uploa
 1137                _binding_UploadFileRecordContentAsync_file = bindingResolver.GetBinding(CreateParameterDescriptor_Upload
 1138            }
 139
 140            public global::HotChocolate.Internal.ParameterDescriptor CreateParameterDescriptor_UploadFileRecordContentAs
 1141                => new HotChocolate.Internal.ParameterDescriptor(
 1142                    "input",
 1143                    typeof(global::Api.Files.Mutations.UploadFileRecordContentInput),
 1144                    isNullable: false,
 1145                    []);
 146            public global::HotChocolate.Internal.ParameterDescriptor CreateParameterDescriptor_UploadFileRecordContentAs
 1147                => new HotChocolate.Internal.ParameterDescriptor(
 1148                    "file",
 1149                    typeof(global::HotChocolate.Types.IFile),
 1150                    isNullable: false,
 1151                    []);
 152
 153            public HotChocolate.Resolvers.FieldResolverDelegates UploadFileRecordContentAsync()
 1154                => new global::HotChocolate.Resolvers.FieldResolverDelegates(resolver: UploadFileRecordContentAsync);
 155
 156            private async global::System.Threading.Tasks.ValueTask<global::System.Object?> UploadFileRecordContentAsync(
 0157            {
 0158                var args0 = context.Service<global::Api.Auth.Utils.ICurrentUserId>();
 0159                var args1 = context.Service<global::Api.Database.Utils.IEFTransactionDIAccessorService>();
 0160                var args2 = context.Service<global::Api.Files.FileProviders.UserFileRouter>();
 0161                var args3 = context.Service<global::FluentValidation.IValidator<global::Api.Files.Mutations.UploadFileRe
 0162                var args4 = _binding_UploadFileRecordContentAsync_input.Execute<global::Api.Files.Mutations.UploadFileRe
 0163                var args5 = _binding_UploadFileRecordContentAsync_file.Execute<global::HotChocolate.Types.IFile>(context
 0164                var args6 = context.RequestAborted;
 0165                var result = await global::Api.Files.Mutations.UploadFileRecordContentMutations.UploadFileRecordContentA
 0166                return result;
 0167            }
 168        }
 169    }
 170}
 171