< Summary

Information
Class: Api.Works.DTOs.WorkUpdateDTOMapper
Assembly: Api
File(s): /home/runner/work/ProjectRead.ing/ProjectRead.ing/Api/Works/DTOs/WorkDTOs.cs
Line coverage
0%
Covered lines: 0
Uncovered lines: 29
Coverable lines: 29
Total lines: 272
Line coverage: 0%
Branch coverage
0%
Covered branches: 0
Total branches: 2
Branch coverage: 0%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
FromWorkUpdateDTO(...)0%620%

File(s)

/home/runner/work/ProjectRead.ing/ProjectRead.ing/Api/Works/DTOs/WorkDTOs.cs

#LineLine coverage
 1// SPDX-FileCopyrightText: 2026 Alper Çelik <[email protected]>
 2//
 3// SPDX-License-Identifier: AGPL-3.0-or-later
 4
 5using Api.Auth.Utils;
 6using Api.Database;
 7using Api.Database.Utils;
 8using Api.Works.Models;
 9
 10using FluentValidation;
 11using FluentValidation.Results;
 12
 13using Riok.Mapperly.Abstractions;
 14
 15namespace Api.Works.DTOs;
 16
 17#region WorkUpdateDTO
 18public record WorkUpdateDTO(
 19        Guid Id,
 20        int RowVersion,
 21
 22        string Title,
 23        string? Description,
 24
 25        NodaTime.ZonedDateTime? WorkPublishedAt,
 26        NodaTime.ZonedDateTime? WorkUpdatedAt,
 27
 28        Guid[] TagIds,
 29        Guid[] AuthorIds,
 30
 31        WorkIdentifierDTO[] WorkIdentifiers
 32        );
 33
 34[Mapper]
 35public static partial class WorkUpdateDTOMapper
 36{
 37
 38    public static Work FromWorkUpdateDTO(WorkUpdateDTO w)
 039    {
 040        var now = NodaTime.SystemClock.Instance.GetCurrentInstant();
 041        return new Work()
 042        {
 043            Id = w.Id,
 044            RowVersion = w.RowVersion,
 045
 046            Title = w.Title,
 047            Description = w.Description,
 048
 049            WorkPublishedAt = w.WorkPublishedAt,
 050            WorkUpdatedAt = w.WorkUpdatedAt,
 051
 052            WorkTag_Works = [.. w.TagIds.Select(wTagId => new WorkTag_Work(){
 053                    WorkId = w.Id,
 054                    WorkTagId =wTagId
 055                    })],
 056
 057            Work_Authors = [.. w.AuthorIds.Select(wAuthorId => new Work_Author(){
 058                    WorkId = w.Id,
 059                    AuthorId = wAuthorId
 060                    })],
 061
 062            WorkIdentifiers = [.. w.WorkIdentifiers.Select(wid =>
 063                    new WorkIdentifier(wid.WorkIdentifierType,wid.WorkIdentifierValue)
 064            )],
 065
 066        };
 067    }
 68}
 69
 70
 71public class WorkUpdateDTOValidator : AbstractValidator<WorkUpdateDTO>
 72{
 73    private readonly IEFTransactionDIAccessorService _tx;
 74
 75    public WorkUpdateDTOValidator(
 76            PGContext db,
 77            IEFTransactionDIAccessorService tx,
 78            ICurrentUserId userId)
 79    {
 80        RuleFor(w => w.TagIds)
 81            .Must(ids => ids.Length == ids.Distinct().Count())
 82            .WithMessage("Duplicate tagIds are forbidden");
 83
 84        RuleFor(w => w.TagIds)
 85            .MustAsync(async (ids, ct) =>
 86                    await Microsoft.EntityFrameworkCore.EntityFrameworkQueryableExtensions.CountAsync(
 87                     db.WorkTags
 88                    .Where(wt => wt.OwnerId == userId.Id
 89                        && ids.Contains(wt.Id)), ct)
 90                    == ids.Length
 91                    )
 92            .WithMessage("Some or all tagIds doesn't exist");
 93
 94
 95
 96        RuleFor(w => w.AuthorIds)
 97           .Must(ids => ids.Length == ids.Distinct().Count())
 98           .WithMessage("Duplicate AuthorIds are forbidden");
 99
 100        RuleFor(w => w.AuthorIds)
 101            .MustAsync(async (ids, ct) =>
 102                    await Microsoft.EntityFrameworkCore.EntityFrameworkQueryableExtensions.CountAsync(
 103                     db.WorkTags
 104                    .Where(wt => wt.OwnerId == userId.Id
 105                        && ids.Contains(wt.Id)), ct)
 106                    == ids.Length
 107                    )
 108            .WithMessage("Some or all AuthorIds doesn't exist");
 109        _tx = tx;
 110    }
 111
 112    public override async Task<ValidationResult> ValidateAsync(ValidationContext<WorkUpdateDTO> context, CancellationTok
 113    {
 114        await _tx.BeginOrGetTransactionAsync();
 115        return await base.ValidateAsync(context, cancellation);
 116    }
 117
 118    protected override bool PreValidate(ValidationContext<WorkUpdateDTO> context, ValidationResult result)
 119    {
 120        _tx.BeginOrGetTransaction();
 121        return base.PreValidate(context, result);
 122    }
 123}
 124#endregion
 125
 126
 127#region WorkGetDTO
 128public record WorkGetDTO(
 129        Guid Id,
 130        int RowVersion,
 131        NodaTime.Instant MetadataAddedAt,
 132        NodaTime.Instant MetadataUpdatedAt,
 133
 134        string Title,
 135        string? Description,
 136
 137        NodaTime.ZonedDateTime? WorkPublishedAt,
 138        NodaTime.ZonedDateTime? WorkUpdatedAt,
 139
 140        TagGetDTO[] Tags,
 141        AuthorGetDTO[] Authors,
 142
 143        WorkIdentifierDTO[] WorkIdentifiers
 144        ) : IEntityMetadata;
 145
 146[Mapper]
 147public static partial class WorkGetDTOMapper
 148{
 149    [MapProperty(nameof(Work.WorkTags), nameof(WorkGetDTO.Tags))]
 150    public static partial WorkGetDTO ToDto(Work w);
 151}
 152#endregion
 153
 154#region WorkAddDTO
 155public record WorkAddDTO(
 156        string Title,
 157        string? Description,
 158
 159        NodaTime.ZonedDateTime? WorkPublishedAt,
 160        NodaTime.ZonedDateTime? WorkUpdatedAt,
 161
 162        Guid[] TagIds,
 163        Guid[] AuthorIds,
 164
 165        WorkIdentifierDTO[] WorkIdentifiers
 166        );
 167
 168[Mapper]
 169public static partial class WorkAddDTOMapper
 170{
 171
 172    public static Work FromWorkAddDTO(WorkAddDTO w)
 173    {
 174        var id = Guid.CreateVersion7();
 175        var now = NodaTime.SystemClock.Instance.GetCurrentInstant();
 176        return new Work()
 177        {
 178            Id = id,
 179            Title = w.Title,
 180            Description = w.Description,
 181
 182            WorkPublishedAt = w.WorkPublishedAt,
 183            WorkUpdatedAt = w.WorkUpdatedAt,
 184
 185            MetadataAddedAt = now,
 186            MetadataUpdatedAt = now,
 187
 188            WorkTag_Works = [.. w.TagIds.Select(wTagId => new WorkTag_Work(){
 189                    WorkId = id,
 190                    WorkTagId =wTagId
 191                    })],
 192
 193            Work_Authors = [.. w.AuthorIds.Select(wAuthorId => new Work_Author(){
 194                    WorkId = id,
 195                    AuthorId = wAuthorId
 196                    })],
 197
 198            WorkIdentifiers = [.. w.WorkIdentifiers.Select(wid =>
 199                    new WorkIdentifier (wid.WorkIdentifierType,wid.WorkIdentifierValue)
 200                    )],
 201
 202        };
 203    }
 204}
 205
 206public class WorkAddDTOValidator : AbstractValidator<WorkAddDTO>
 207{
 208    public WorkAddDTOValidator(PGContext db, ICurrentUserId userId)
 209    {
 210        RuleFor(w => w.TagIds)
 211            .Must(ids => ids.Length == ids.Distinct().Count())
 212            .WithMessage("Duplicate tagIds are forbidden");
 213
 214        RuleFor(w => w.TagIds)
 215            .MustAsync(async (ids, ct) =>
 216                    await Microsoft.EntityFrameworkCore.EntityFrameworkQueryableExtensions.CountAsync(
 217                     db.WorkTags
 218                    .Where(wt => wt.OwnerId == userId.Id
 219                        && ids.Contains(wt.Id)), ct)
 220                    == ids.Length
 221                    )
 222            .WithMessage("Some or all tagIds doesn't exist");
 223
 224
 225
 226        RuleFor(w => w.AuthorIds)
 227           .Must(ids => ids.Length == ids.Distinct().Count())
 228           .WithMessage("Duplicate AuthorIds are forbidden");
 229
 230        RuleFor(w => w.AuthorIds)
 231            .MustAsync(async (ids, ct) =>
 232                    await Microsoft.EntityFrameworkCore.EntityFrameworkQueryableExtensions.CountAsync(
 233                     db.WorkTags
 234                    .Where(wt => wt.OwnerId == userId.Id
 235                        && ids.Contains(wt.Id)), ct)
 236                    == ids.Length
 237                    )
 238            .WithMessage("Some or all AuthorIds doesn't exist");
 239    }
 240}
 241#endregion
 242public record struct WorkIdentifierDTO(
 243        string WorkIdentifierType,
 244        string WorkIdentifierValue
 245        );
 246
 247
 248public record struct WorksGetDTO(
 249        AuthorGetDTO[] ReferencedAuthors,
 250        WorkSmallDTO[] Works
 251        );
 252
 253#region WorkSmallDto
 254public record struct WorkSmallDTO(
 255        Guid Id,
 256        string Title,
 257        Guid[] AuthorIds,
 258        Guid? CoverId = null
 259        );
 260
 261public static partial class WorkSmallDTOMapper
 262{
 263    public static IQueryable<WorkSmallDTO> ProjectToDTO(IQueryable<Work> q) => q.Select(w => new WorkSmallDTO(
 264
 265         w.Id,
 266         w.Title,
 267         w.Authors!.Select(a => a.Id).ToArray(),
 268         null
 269    ));
 270
 271}
 272#endregion