< Summary

Information
Class: Services.LabelServices.DropboxToServerFileStorageMigrationJob
Assembly: Services
File(s): /home/runner/work/Studio2Prod/Studio2Prod/AppRepository/LabelServices/DropboxToServerFileStorageMigrationJob.cs
Line coverage
0%
Covered lines: 0
Uncovered lines: 34
Coverable lines: 34
Total lines: 70
Line coverage: 0%
Branch coverage
0%
Covered branches: 0
Total branches: 14
Branch coverage: 0%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
.cctor()100%210%
.ctor(...)100%210%
ExecuteAsync()0%210140%

File(s)

/home/runner/work/Studio2Prod/Studio2Prod/AppRepository/LabelServices/DropboxToServerFileStorageMigrationJob.cs

#LineLine coverage
 1using Services.ApiServices.DropBoxApi;
 2
 3namespace Services.LabelServices;
 4
 5/// <summary>
 6/// Разовый перенос существующих PDF-этикеток из Dropbox-папки в новое ServerFileStorage-хранилище.
 7/// Не recurring — запускается вручную один раз при переходе с Dropbox. Идемпотентна: уже
 8/// перенесённые файлы пропускаются, безопасно перезапускать при сбое на середине.
 9/// </summary>
 10public class DropboxToServerFileStorageMigrationJob
 11{
 12    private const string DropboxFolderPath = "/Приложения/Studio2/Этикетки";
 013    private static readonly TimeSpan DelayBetweenFiles = TimeSpan.FromMilliseconds(100);
 14
 15    private readonly DropboxApiClient _dropboxApiClient;
 16    private readonly ILabelFileStorage _labelFileStorage;
 17
 018    public DropboxToServerFileStorageMigrationJob(DropboxApiClient dropboxApiClient, ILabelFileStorage labelFileStorage)
 19    {
 020        _dropboxApiClient = dropboxApiClient;
 021        _labelFileStorage = labelFileStorage;
 022    }
 23
 24    public async Task<string> ExecuteAsync()
 25    {
 26        // GetPdfShipmentNumberIndexAsync обходит пагинацию Dropbox list_folder (HasMore/ListFolderContinueAsync),
 27        // в отличие от GetFilesListAsync — на большой папке тот молча вернул бы неполный список.
 028        var baseNames = await _dropboxApiClient.GetPdfShipmentNumberIndexAsync(DropboxFolderPath);
 29
 030        var migrated = 0;
 031        var skipped = 0;
 032        var failed = 0;
 033        var failures = new List<string>();
 34
 035        foreach (var baseName in baseNames)
 36        {
 037            var fileName = $"{baseName}.pdf";
 38            try
 39            {
 040                if (await _labelFileStorage.ExistsAsync(fileName))
 41                {
 042                    skipped++;
 043                    continue;
 44                }
 45
 046                var bytes = await _dropboxApiClient.DownloadFileAsync(DropboxFolderPath, fileName);
 047                if (bytes is not { Length: > 0 })
 48                {
 049                    failed++;
 050                    failures.Add($"{fileName}: пустой файл");
 051                    continue;
 52                }
 53
 054                await _labelFileStorage.UploadAsync(bytes, fileName, overwrite: false);
 055                migrated++;
 056                await Task.Delay(DelayBetweenFiles);
 057            }
 058            catch (Exception ex)
 59            {
 060                failed++;
 061                failures.Add($"{fileName}: {ex.Message}");
 062            }
 063        }
 64
 065        var summary = $"Migrated {migrated}, skipped {skipped} (already present), failed {failed}";
 066        return failures.Count > 0
 067            ? $"{summary}. Failures: {string.Join("; ", failures.Take(20))}"
 068            : summary;
 069    }
 70}