网站首页 网站源码
website
站点相关全部源代码,隐藏了一些关于服务器的信息
using AngleSharp;
using AngleSharp.Css.Dom;
using AngleSharp.Dom;
using Dpz.Core.Infrastructure;
using Dpz.Core.Public.ViewModel;
using Dpz.Core.Service.RepositoryService;
using HandlebarsDotNet;
using Hangfire;
using MailKit;
using MailKit.Net.Smtp;
using MailKit.Security;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Logging;
using MimeKit;
using IConfiguration = Microsoft.Extensions.Configuration.IConfiguration;

namespace Dpz.Core.Hangfire;

public class EmailSenderActivator(
    IConfiguration configuration,
    ICommentService commentService,
    IProtocolLogger protocolLogger,
    ILogger<EmailSenderActivator> logger)
    : JobActivator
{
    private readonly EmailConfiguration _smtpConfiguration =
        configuration.GetSection("EmailService").Get<EmailConfiguration>() ??
        throw new Exception("EmailService configuration is null");

    private readonly bool _openService = configuration.GetSection("MailServiceOpen").Get<bool?>() ?? false;


    private const string MasterEmail = "pengqian089@hotmail.com";

    [ProlongExpirationTime]
    public async Task SendMasterAsync(VmPublishComment comment)
    {
        if (!_openService)
        {
            logger.LogInformation("invoke {Method}", nameof(SendMasterAsync));
        }

        var message = new MimeMessage();
        message.To.Add(new MailboxAddress("", MasterEmail));
        message.From.Add(new MailboxAddress("叫我阿胖-邮件服务", _smtpConfiguration.Email));
        message.Subject = $"收到了来自 {comment.NickName} 新评论";
        var bodyBuilder = new BodyBuilder
        {
            HtmlBody = await MessageTemplate(comment)
        };
        message.Body = bodyBuilder.ToMessageBody();
        using var client = new SmtpClient(protocolLogger);
        client.ServerCertificateValidationCallback = (_, _, _, _) => true;
        try
        {
            await client.ConnectAsync(_smtpConfiguration.Smtp, _smtpConfiguration.Port, SecureSocketOptions.StartTls);
            await client.AuthenticateAsync(_smtpConfiguration.Email, _smtpConfiguration.Password);
            await client.SendAsync(message);
        }
        catch (Exception e)
        {
            logger.LogError(e, "邮件发送失败");
        }
        finally
        {
            await client.DisconnectAsync(true);
        }
    }

    [ProlongExpirationTime]
    public async Task SendCommenterAsync(VmPublishComment? reply)
    {
        if (!_openService)
        {
            logger.LogInformation("invoke {Method}", nameof(SendCommenterAsync));
        }

        if (!string.IsNullOrEmpty(reply?.ReplyId))
        {
            var comment = await commentService.GetComment(reply.ReplyId);
            if (comment is { Commenter: VmGuestCommenter guestCommenter } && guestCommenter.Email != reply.Email)
            {
                await SendEmailAsync(guestCommenter, comment, reply.NickName, reply.CommentText);
            }
        }
    }

    private async Task SendEmailAsync(
        VmGuestCommenter guestCommenter,
        CommentViewModel comment,
        string nickName,
        string commentText)
    {
        var message = new MimeMessage();
        message.To.Add(new MailboxAddress("", guestCommenter.Email));
        message.From.Add(new MailboxAddress("叫我阿胖-邮件服务", _smtpConfiguration.Email));
        message.Subject = "您的评论有新的回复了。";
        var bodyBuilder = new BodyBuilder
        {
            HtmlBody = await ReplyTemplate(comment, nickName, commentText)
        };
        message.Body = bodyBuilder.ToMessageBody();
        using var client = new SmtpClient(protocolLogger);
        client.ServerCertificateValidationCallback = (_, _, _, _) => true;
        try
        {
            await client.ConnectAsync(_smtpConfiguration.Smtp, _smtpConfiguration.Port, SecureSocketOptions.StartTls);
            await client.AuthenticateAsync(_smtpConfiguration.Email, _smtpConfiguration.Password);
            await client.SendAsync(message);
        }
        catch (Exception e)
        {
            logger.LogError(e, "邮件发送失败");
        }
        finally
        {
            await client.DisconnectAsync(true);
        }
    }

    [ProlongExpirationTime]
    public async Task SendCommenterAsync(MembleComment? reply)
    {
        if (!_openService)
        {
            logger.LogInformation("invoke {Method}", nameof(SendCommenterAsync));
        }

        if (!string.IsNullOrEmpty(reply?.ReplyId))
        {
            var comment = await commentService.GetComment(reply.ReplyId);
            if (comment is { Commenter: VmGuestCommenter guestCommenter })
            {
                await SendEmailAsync(guestCommenter, comment, reply.User.Name, reply.CommentText);
            }
        }
    }

    /// <summary>
    /// 评论回复通知模板
    /// </summary>
    private static string _replyTemplate = "";

    private async Task<string> ReplyTemplate(CommentViewModel comment, string nickName, string commentText)
    {
        if (string.IsNullOrEmpty(_replyTemplate))
        {
            var templatePath = Path.Combine(AppContext.BaseDirectory, "Template", "ReplyTemplate.html");
            if (!File.Exists(templatePath)) return "";
            using var reader = new StreamReader(templatePath);
            _replyTemplate = await reader.ReadToEndAsync();
        }

        if (comment.Commenter is VmGuestCommenter guestCommenter)
        {
            var handlebars = Handlebars.Create();
            handlebars.Configuration.TextEncoder = new IgnoreTextEncoder();
            var template = handlebars.Compile(_replyTemplate);
            return template(new Dictionary<string, string>
            {
                { nameof(VmGuestCommenter.NickName), guestCommenter.NickName },
                { nameof(nickName), nickName },
                { nameof(CommentViewModel.PublishTime), comment.PublishTime.ToString("yyyy-MM-dd HH:mm:ss") },
                { nameof(CommentViewModel.CommentText), await HandleContent(comment.CommentText) },
                { "replyTime", DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss") },
                { "replyText", await HandleContent(commentText) }
            });


            var context = BrowsingContext.New(Configuration.Default);
            var document = await context.OpenAsync(y => y.Content(_replyTemplate));
            var now = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss");

            document.QuerySelector("span.comment-nickname")?.SetInnerText(guestCommenter.NickName);
            document.QuerySelector("span.reply-nickname")?.SetInnerText(nickName);
            document.QuerySelector("p.send-time")?.SetInnerText(now);
            document.QuerySelector("span.head-nickname")?.SetInnerText(guestCommenter.NickName);
            document.QuerySelector("time.head-timeago")
                ?.SetInnerText(comment.PublishTime.ToString("yyyy-MM-dd HH:mm:ss"));
            var divCommentText = document.QuerySelector("div.comment-text");
            if (divCommentText != null)
            {
                divCommentText.InnerHtml = await HandleContent(comment.CommentText);
            }

            document.QuerySelector("span.head-reply-nickname")?.SetInnerText(nickName);
            document.QuerySelector("time.head-reply-timeago")?.SetInnerText(now);
            var divReplyText = document.QuerySelector("div.reply-text");
            if (divReplyText != null)
            {
                divReplyText.InnerHtml = await HandleContent(commentText);
            }

            return document.Body?.InnerHtml ?? "";
        }

        return "";
    }


    /// <summary>
    /// 原始模板内容
    /// </summary>
    private static string _templateContent = "";

    private async Task<string> MessageTemplate(VmPublishComment comment)
    {
        if (string.IsNullOrEmpty(_templateContent))
        {
            var templatePath = Path.Combine(AppContext.BaseDirectory, "Template", "MessageTemplate.html");
            if (!File.Exists(templatePath)) return "";
            using var reader = new StreamReader(templatePath);
            _templateContent = await reader.ReadToEndAsync();
        }

        var handlebars = Handlebars.Create();
        handlebars.Configuration.TextEncoder = new IgnoreTextEncoder();
        var template = handlebars.Compile(_templateContent);
        return template(new Dictionary<string, string>
        {
            { nameof(VmPublishComment.NickName), comment.NickName },
            { nameof(VmPublishComment.Email), comment.Email },
            { nameof(VmPublishComment.SendTime), comment.SendTime.ToString("yyyy-MM-dd HH:mm:ss") },
            { nameof(VmPublishComment.CommentText), await HandleContent(comment.CommentText) },
        });
    }

    private async Task<string> HandleContent(string? content)
    {
        if (string.IsNullOrEmpty(content))
            return "";
        var html = content.MarkdownToHtml();
        var context = BrowsingContext.New(Configuration.Default);
        var document = await context.OpenAsync(y => y.Content(html));

        var images = document.GetElementsByTagName("img");
        foreach (var image in images)
        {
            image.SetStyle("max-width:100%");
        }

        return document.Body?.InnerHtml ?? "";
    }


    internal class EmailConfiguration
    {
        public required string Email { get; set; }

        public required string Password { get; set; }

        public required string Smtp { get; set; }

        public required int Port { get; set; }
    }
}
loading