< Summary

Information
Class: Services.PartnerServices.PartnerLoginMailer
Assembly: Services
File(s): /home/runner/work/Studio2Prod/Studio2Prod/AppRepository/PartnerServices/PartnerLoginMailer.cs
Line coverage
97%
Covered lines: 79
Uncovered lines: 2
Coverable lines: 81
Total lines: 110
Line coverage: 97.5%
Branch coverage
62%
Covered branches: 5
Total branches: 8
Branch coverage: 62.5%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
.ctor(...)100%11100%
SendLoginCodeAsync(...)50%2290%
SendInviteAsync(...)50%2290.9%
RenderEmail(...)75%44100%

File(s)

/home/runner/work/Studio2Prod/Studio2Prod/AppRepository/PartnerServices/PartnerLoginMailer.cs

#LineLine coverage
 1using System.Net;
 2using Microsoft.Extensions.Logging;
 3using Microsoft.Extensions.Options;
 4using SlqStudio.Application.Services.EmailService;
 5
 6namespace Services.PartnerServices;
 7
 8/// <summary>Письма партнёру: код входа и приглашение. Отправитель — тот, что задан в SmtpSettings.</summary>
 9public interface IPartnerLoginMailer
 10{
 11    Task<bool> SendLoginCodeAsync(string email, string partnerName, string code, CancellationToken ct = default);
 12
 13    Task<bool> SendInviteAsync(string email, string partnerName, string code, string link, CancellationToken ct = defaul
 14}
 15
 116public sealed class PartnerLoginMailer(
 117    IHtmlEmailSender sender,
 118    IOptions<PartnerOfficeOptions> options,
 119    ILogger<PartnerLoginMailer> logger) : IPartnerLoginMailer
 20{
 21    public Task<bool> SendLoginCodeAsync(string email, string partnerName, string code, CancellationToken ct = default)
 22    {
 123        if (options.Value.LogCodesToConsole)
 024            logger.LogWarning("[PartnerOffice dev] Код входа для {Email}: {Code}", email, code);
 125        var body = RenderEmail(
 126            "email-login-code.png",
 127            "Код для входа",
 128            $"Здравствуйте! Для входа в кабинет партнёра «{WebUtility.HtmlEncode(partnerName)}» используйте этот код:",
 129            code,
 130            "Код действует 10 минут. Если вы не запрашивали вход, просто проигнорируйте это письмо.",
 131            codeHint: "Ваш одноразовый код");
 132        return sender.SendAsync(email, "Код для входа в PartnerOffice", body, ct);
 33    }
 34
 35    public Task<bool> SendInviteAsync(string email, string partnerName, string code, string link, CancellationToken ct =
 36    {
 137        if (options.Value.LogCodesToConsole)
 038            logger.LogWarning("[PartnerOffice dev] Приглашение для {Email}: код {Code}, ссылка {Link}", email, code, lin
 139        var body = RenderEmail(
 140            "email-invite.png",
 141            "Добро пожаловать в PartnerOffice",
 142            $"Для «{WebUtility.HtmlEncode(partnerName)}» открыт доступ к кабинету партнёра. В нём видны ваши заказы Ozon
 143            code,
 144            "Ссылка действует 7 дней и срабатывает один раз. Позже запросите новый код на странице входа, указав эту поч
 145            link,
 146            "Код уже подставлен в ссылку. Если она не открылась, введите его вручную.");
 147        return sender.SendAsync(email, "Приглашение в PartnerOffice", body, ct);
 48    }
 49
 50    private string RenderEmail(string illustrationFile, string title, string lead, string code, string note, string? act
 51    {
 252        var illustrationUrl = WebUtility.HtmlEncode($"{options.Value.PublicUrl.TrimEnd('/')}/illustrations/{illustration
 253        var action = actionLink is null
 254            ? string.Empty
 255            : $"""
 256              <tr>
 257                <td style="padding:0 40px 28px;text-align:center">
 258                  <a href="{WebUtility.HtmlEncode(actionLink)}" style="background:#005bff;border-radius:12px;color:#ffff
 259                </td>
 260              </tr>
 261              """;
 262        var codeCaption = codeHint is null
 263            ? string.Empty
 264            : $"""
 265              <tr>
 266                <td style="color:#6b7c8f;font-family:Arial,sans-serif;font-size:14px;line-height:20px;padding:0 40px 8px
 267              </tr>
 268              """;
 69
 270        return $"""
 271            <!doctype html>
 272            <html lang="ru">
 273            <body style="background:#f5f7fa;margin:0;padding:0">
 274              <table role="presentation" width="100%" cellpadding="0" cellspacing="0" border="0" style="background:#f5f7
 275                <tr>
 276                  <td align="center" style="padding:32px 16px">
 277                    <table role="presentation" width="100%" cellpadding="0" cellspacing="0" border="0" style="background
 278                      <tr>
 279                        <td align="center" style="background:#e6f3fe;padding:28px 40px 12px">
 280                          <img src="{illustrationUrl}" width="144" height="144" alt="" style="border:0;display:block;hei
 281                        </td>
 282                      </tr>
 283                      <tr>
 284                        <td style="padding:28px 40px 16px">
 285                          <p style="color:#005bff;font-family:Arial,sans-serif;font-size:14px;font-weight:700;letter-spa
 286                          <h1 style="color:#001a34;font-family:Arial,sans-serif;font-size:26px;font-weight:700;line-heig
 287                        </td>
 288                      </tr>
 289                      <tr>
 290                        <td style="color:#26394d;font-family:Arial,sans-serif;font-size:16px;line-height:24px;padding:0 
 291                      </tr>
 292                      {codeCaption}
 293                      <tr>
 294                        <td style="padding:0 40px 28px">
 295                          <div style="background:#f4fafe;border-radius:16px;color:#001a34;font-family:Arial,sans-serif;f
 296                        </td>
 297                      </tr>
 298                      {action}
 299                      <tr>
 2100                        <td style="color:#6b7c8f;font-family:Arial,sans-serif;font-size:14px;line-height:20px;padding:0 
 2101                      </tr>
 2102                    </table>
 2103                  </td>
 2104                </tr>
 2105              </table>
 2106            </body>
 2107            </html>
 2108            """;
 109    }
 110}