< Summary

Information
Class: OzonOrdersWeb.Areas.Studio2.Controllers.EmailRoutingSchedulerController
Assembly: OzonOrdersWeb
File(s): /home/runner/work/Studio2Prod/Studio2Prod/OzonOrdersWeb/Areas/Studio2/Controllers/EmailRoutingSchedulerController.cs
Line coverage
0%
Covered lines: 0
Uncovered lines: 92
Coverable lines: 92
Total lines: 161
Line coverage: 0%
Branch coverage
0%
Covered branches: 0
Total branches: 16
Branch coverage: 0%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
.ctor(...)100%210%
Index()100%210%
Save()0%620%
Save()100%210%
RunNow()100%210%
Disable()100%210%
BuildModel(...)0%4260%
MapSettings(...)100%210%
ToExecutionOptions(...)100%210%
ParseMinutesFromCron(...)0%7280%

File(s)

/home/runner/work/Studio2Prod/Studio2Prod/OzonOrdersWeb/Areas/Studio2/Controllers/EmailRoutingSchedulerController.cs

#LineLine coverage
 1using Hangfire;
 2using Hangfire.Storage;
 3using Microsoft.AspNetCore.Authorization;
 4using Microsoft.AspNetCore.Mvc;
 5using OzonOrdersWeb.Areas.Studio2.ViewModels.EmailRouting;
 6using Services.EmailRoutingServices;
 7using Services.HangfireService;
 8
 9namespace OzonOrdersWeb.Areas.Studio2.Controllers;
 10
 11[Area("Studio2")]
 12[Authorize(Roles = "Admin")]
 13public class EmailRoutingSchedulerController : Controller
 14{
 15    private readonly IEmailRoutingSchedulerStore _schedulerStore;
 16    private readonly IEmailRoutingJobRunService _jobRunService;
 17
 018    public EmailRoutingSchedulerController(
 019        IEmailRoutingSchedulerStore schedulerStore,
 020        IEmailRoutingJobRunService jobRunService)
 21    {
 022        _schedulerStore = schedulerStore;
 023        _jobRunService = jobRunService;
 024    }
 25
 26    [HttpGet]
 27    public async Task<IActionResult> Index()
 28    {
 029        var vm = BuildModel();
 030        vm.RecentExecutions = await _jobRunService.GetRecentAsync(15);
 031        return View(vm);
 032    }
 33
 34    [HttpPost]
 35    [ValidateAntiForgeryToken]
 36    public async Task<IActionResult> Save([Bind(Prefix = "Settings")] EmailRoutingSchedulerSettingsInput model)
 37    {
 038        if (!ModelState.IsValid)
 39        {
 040            var vm = BuildModel(model);
 041            vm.RecentExecutions = await _jobRunService.GetRecentAsync(15);
 042            return View(nameof(Index), vm);
 43        }
 44
 045        var settings = MapSettings(model, recurringJobEnabled: true);
 046        await _schedulerStore.SaveSettingsAsync(settings);
 047        EmailRoutingRecurringJobRegistrar.RegisterIfEnabled(ToExecutionOptions(settings));
 48
 049        TempData["TransactionResult"] =
 050            $"Настройки сохранены. Расписание: каждые {settings.IntervalMinutes} мин (MSK), " +
 051            $"до {settings.MaxBatchesPerRun * settings.FetchLimit} писем за запуск.";
 052        return RedirectToAction(nameof(Index));
 053    }
 54
 55    [HttpGet]
 56    public IActionResult Save()
 57    {
 058        TempData["TransactionResult"] = "Откройте страницу настроек и сохраните изменения через форму.";
 059        return RedirectToAction(nameof(Index));
 60    }
 61
 62    [HttpPost]
 63    [ValidateAntiForgeryToken]
 64    public IActionResult RunNow()
 65    {
 066        HangfireJobClientExtensions.EnqueueMain<EmailAttachmentRoutingJob>(x => x.ExecuteManualAsync());
 067        TempData["TransactionResult"] = "Задача поставлена в очередь на немедленное выполнение.";
 068        return RedirectToAction(nameof(Index));
 69    }
 70
 71    [HttpPost]
 72    [ValidateAntiForgeryToken]
 73    public async Task<IActionResult> Disable()
 74    {
 075        await _schedulerStore.DisableAsync();
 076        RecurringJob.RemoveIfExists(EmailAttachmentRoutingJob.JobId);
 077        TempData["TransactionResult"] = "Периодическая задача отключена.";
 078        return RedirectToAction(nameof(Index));
 079    }
 80
 81    private EmailRoutingSchedulerViewModel BuildModel(EmailRoutingSchedulerSettingsInput? submitted = null)
 82    {
 083        var current = _schedulerStore.GetCurrent();
 084        using var connection = JobStorage.Current.GetConnection();
 085        var recurring = connection.GetRecurringJobs()
 086            .FirstOrDefault(x => x.Id == EmailAttachmentRoutingJob.JobId);
 87
 088        var settings = submitted ?? new EmailRoutingSchedulerSettingsInput
 089        {
 090            IntervalMinutes = current.IntervalMinutes,
 091            MaxBatchesPerRun = current.MaxBatchesPerRun,
 092            AllowMultiMatch = current.AllowMultiMatch,
 093            FetchLimit = current.FetchLimit,
 094            FetchScanLimit = current.FetchScanLimit,
 095            FetchWindowDays = current.FetchWindowDays
 096        };
 97
 098        if (recurring == null)
 99        {
 0100            return new EmailRoutingSchedulerViewModel
 0101            {
 0102                IsScheduled = false,
 0103                RecurringJobEnabled = current.RecurringJobEnabled,
 0104                RecurringJobId = EmailAttachmentRoutingJob.JobId,
 0105                Settings = settings
 0106            };
 107        }
 108
 0109        var cronMinutes = ParseMinutesFromCron(recurring.Cron);
 0110        if (cronMinutes.HasValue)
 0111            settings.IntervalMinutes = cronMinutes.Value;
 112
 0113        return new EmailRoutingSchedulerViewModel
 0114        {
 0115            IsScheduled = current.RecurringJobEnabled,
 0116            RecurringJobEnabled = current.RecurringJobEnabled,
 0117            RecurringJobId = recurring.Id,
 0118            CronExpression = recurring.Cron,
 0119            LastExecution = recurring.LastExecution,
 0120            NextExecution = recurring.NextExecution,
 0121            LastJobState = recurring.LastJobState,
 0122            Settings = settings
 0123        };
 0124    }
 125
 126    private static EmailRoutingSchedulerSettings MapSettings(
 127        EmailRoutingSchedulerSettingsInput model,
 128        bool recurringJobEnabled) =>
 0129        new()
 0130        {
 0131            IntervalMinutes = model.IntervalMinutes,
 0132            MaxBatchesPerRun = model.MaxBatchesPerRun,
 0133            AllowMultiMatch = model.AllowMultiMatch,
 0134            RecurringJobEnabled = recurringJobEnabled,
 0135            FetchLimit = model.FetchLimit,
 0136            FetchScanLimit = model.FetchScanLimit,
 0137            FetchWindowDays = model.FetchWindowDays
 0138        };
 139
 140    private static EmailRoutingExecutionOptions ToExecutionOptions(EmailRoutingSchedulerSettings settings) =>
 0141        new()
 0142        {
 0143            AllowMultiMatch = settings.AllowMultiMatch,
 0144            RecurringJobEnabled = settings.RecurringJobEnabled,
 0145            IntervalMinutes = settings.IntervalMinutes,
 0146            MaxBatchesPerRun = settings.MaxBatchesPerRun
 0147        };
 148
 149    private static int? ParseMinutesFromCron(string? cron)
 150    {
 0151        if (string.IsNullOrWhiteSpace(cron) || !cron.StartsWith("*/", StringComparison.Ordinal))
 0152            return null;
 153
 0154        var spaceIdx = cron.IndexOf(' ');
 0155        if (spaceIdx < 0)
 0156            return null;
 157
 0158        var minutePart = cron.Substring(2, spaceIdx - 2);
 0159        return int.TryParse(minutePart, out var value) ? value : null;
 160    }
 161}