基于.NetCore开发博客项目 StarBlog - (28) 开发友情链接相关接口

2023-05-30 11:48:43 作者:admin

前言

之前介绍的友情链接功能,只实现了友情链接的展示和管理接口。

还缺失友情链接申请、审核管理、通知,现在把这块功能补全。

Model 什么的之前那篇文章都有,本文直接补全逻辑代码~

详见: 基于.NetCore开发博客项目 StarBlog - (13) 加入友情链接功能

先看效果

友情链接申请页面

邮件通知

实现一个简单的通知功能,申请通过之后,给申请友链的邮箱发通知。

使用 MimeKit 这个库可以很方便的实现发邮件功能

为了更方便使用,我封装了一个 EmailUtils 放在 StarBlog.Share.Utils 里面

public class EmailAccountConfig {  public string Host { get; set; }  public int Port { get; set; }  public string FromUsername { get; set; }  public string FromPassword { get; set; }  public string FromAddress { get; set; }}public static class EmailUtils {  public static async Task<MessageSentEventArgs> SendEmailAsync(    EmailAccountConfig config,    string subject,    string htmlBody,    string toName,    string toAddress,    string fromName = "StarBlog"  ) {    return await SendEmailAsync(      config,      new MimeMessage {        Subject = subject,        From = {new MailboxAddress(fromName, config.FromAddress)},        To = {new MailboxAddress(toName, toAddress)},        Body = new BodyBuilder {          HtmlBody = htmlBody        }.ToMessageBody()      }    );  }  public static async Task<MessageSentEventArgs> SendEmailAsync(EmailAccountConfig config, MimeMessage message,                                                                HttpProxyClient? proxyClient = null) {    MessageSentEventArgs result = null;    using var client = new SmtpClient {      ServerCertificateValidationCallback = (s, c, h, e) => true,    };    if (proxyClient != null) {      client.ProxyClient = proxyClient;    }    client.AuthenticationMechanisms.Remove("XOAUTH2");    client.MessageSent += (sender, args) => { result = args; };    await client.ConnectAsync(config.Host, config.Port, SecureSocketOptions.Auto);    await client.AuthenticateAsync(config.FromUsername, config.FromPassword);    await client.SendAsync(message);    await client.DisconnectAsync(true);    return result;  }}

使用比较简单,传入邮箱配置和邮件主题、内容、收件地址就行。

具体的可以接着看下面的代码。

友链申请管理

管理友情链接申请记录的逻辑,同样也是有增删改查,这部分代码跟上面的一样,省略了

构造方法通过依赖注入,从配置系统里读取了邮箱配置,读者可以自行将邮箱配置添加到 appsettings.json 中,这里给出一个outlook邮箱的配置

"EmailAccountConfig": {  "Host": "smtp-mail.outlook.com",  "Port": 587,  "FromUsername": "邮箱地址@outlook.com",  "FromPassword": "邮箱密码",  "FromAddress": "邮箱地址@outlook.com"}

下面开始是 service 的代码

这里只贴设置是否验证发邮件通知 的代码

public class LinkExchangeService {  private readonly IBaseRepository<LinkExchange> _repo;  private readonly LinkService _linkService;  private readonly EmailAccountConfig _emailAccountConfig;  public LinkExchangeService(IBaseRepository<LinkExchange> repo, LinkService linkService, IOptions<EmailAccountConfig> options) {    _repo = repo;    _linkService = linkService;    _emailAccountConfig = options.Value;  }  public async Task<LinkExchange?> SetVerifyStatus(int id, bool status, string? reason = null) {    var item = await GetById(id);    if (item == null) return null;    item.Verified = status;    item.Reason = reason;    await _repo.UpdateAsync(item);    var link = await _linkService.GetByName(item.Name);    if (status) {      await SendEmailOnAccept(item);      if (link == null) {        await _linkService.AddOrUpdate(new Link {          Name = item.Name,          Description = item.Description,          Url = item.Url,          Visible = true        });      }      else {        await _linkService.SetVisibility(link.Id, true);      }    }    else {      await SendEmailOnReject(item);      if (link != null) await _linkService.DeleteById(link.Id);    }    return await GetById(id);  }  // 本文仅贴上申请通过的代码,其他的也是类似的写法  public async Task SendEmailOnAccept(LinkExchange item) {    const string starblogLink = "<a href=\"https://deali.cn\">StarBlog</a>";    var sb = new StringBuilder();    sb.AppendLine($"<p>您好,友链申请已通过!感谢支持,欢迎互访哦~</p>");    sb.AppendLine($"<br>");    sb.AppendLine($"<p>以下是您申请的友链信息:</p>");    sb.AppendLine($"<p>网站名称:{item.Name}</p>");    sb.AppendLine($"<p>介绍:{item.Description}</p>");    sb.AppendLine($"<p>网址:{item.Url}</p>");    sb.AppendLine($"<p>站长:{item.WebMaster}</p>");    sb.AppendLine($"<p>补充信息:{item.Reason}</p>");    sb.AppendLine($"<br>");    sb.AppendLine($"<br>");    sb.AppendLine($"<br>");    sb.AppendLine($"<p>本消息由 {starblogLink} 自动发送,无需回复。</p>");    await EmailUtils.SendEmailAsync(      _emailAccountConfig,      "[StarBlog]友链申请结果反馈",      sb.ToString(),      item.WebMaster,      item.Email    );  }}

在设置是否验证的方法中,实现了:

  • 设置一个申请为已验证,自动将该申请的链接添加到友情链接中
  • 设置一个申请为未验证,则自动将对应的友情链接删除(如果存在的话)

其他地方就跟上面的友情链接一样了。

写完之后别忘了注册服务

builder.Services.AddScoped<LinkExchangeService>();builder.Services.AddScoped<LinkService>();

友链申请

展示功能做完了,还得接着做友链申请的功能,以方便路过的站长申请互换友链~

添加 StarBlog.Web/ViewModels/LinkExchange/LinkExchangeAddViewModel.cs 文件

我们使用 AspNetCore MVC 框架提供的表单验证功能

public class LinkExchangeAddViewModel {  /// <summary>  /// 网站名称  /// </summary>  [Display(Name = "网站名称")]  [Required(ErrorMessage = "必须填写网站名称")]  public string Name { get; set; }  /// <summary>  /// 介绍  /// </summary>  [Display(Name = "介绍")]  public string? Description { get; set; }  /// <summary>  /// 网址  /// </summary>  [Display(Name = "网址")]  [Required(ErrorMessage = "必须填写网址")]  [DataType(DataType.Url)]  public string Url { get; set; }  /// <summary>  /// 站长  /// </summary>  [Display(Name = "站长名称")]  [Required(ErrorMessage = "必须填写站长名称")]  public string WebMaster { get; set; }  /// <summary>  /// 联系邮箱  /// </summary>  [Display(Name = "联系邮箱")]  [Required(ErrorMessage = "必须填写联系邮箱")]  [DataType(DataType.EmailAddress)]  public string Email { get; set; }}

接着写一下页面 StarBlog.Web/Views/LinkExchange/Add.cshtml

@model StarBlog.Web.ViewModels.LinkExchange.LinkExchangeAddViewModel@{ViewData["Title"] = "申请友链";}<div class="container px-4 py-3">  <h2 class="d-flex w-100 justify-content-between pb-2 mb-3 border-bottom">    <div>申请友链</div>    <div>Link Exchange</div>  </h2>  <div class="card px-1 py-3">    <form enctype="multipart/form-data" class="card-body row" asp-controller="LinkExchange" asp-action="Add" method="post">      <div class="col-xl-6">        <div class="mb-4">          <h4 class="card-title">友链信息</h4>          <h6 class="card-subtitle mb-3 text-muted">请输入您的网站信息,方便后续联系</h6>        </div>        <div class="mb-3">          <label asp-for="Name" class="form-label"></label>          <input asp-for="Name" class="form-control">          <span asp-validation-for="Name" class="form-text text-danger"></span>        </div>        <div class="mb-3">          <label asp-for="Description" class="form-label"></label>          <input asp-for="Description" class="form-control">          <span asp-validation-for="Description" class="form-text text-danger"></span>        </div>        <div class="mb-3">          <label asp-for="Url" class="form-label"></label>          <input asp-for="Url" class="form-control">          <span asp-validation-for="Url" class="form-text text-danger"></span>        </div>        <div class="mb-3">          <label asp-for="WebMaster" class="form-label"></label>          <input asp-for="WebMaster" class="form-control">          <span asp-validation-for="WebMaster" class="form-text text-danger"></span>        </div>        <div class="mb-3">          <label asp-for="Email" class="form-label"></label>          <input asp-for="Email" class="form-control">          <span asp-validation-for="Email" class="form-text text-danger"></span>        </div>      </div>      <div class="col-xl-6">        <div class="ms-3 mb-4">          <h4 class="card-title">注意事项</h4>          <h6 class="card-subtitle mb-3 text-muted">申请友情链接需符合以下几点要求</h6>        </div>        <ul class="list-group list-group-flush list-group-numbered">          <li class="list-group-item d-flex justify-content-between align-items-start">            <div class="ms-2 me-auto">              <div class="fw-bold">相互性</div>              请先在您的网站添加本站链接,再进行友链申请            </div>          </li>          <li class="list-group-item d-flex justify-content-between align-items-start">            <div class="ms-2 me-auto">              <div class="fw-bold">内容类别</div>              本站优先招同类原创、内容相近的博客或网站            </div>          </li>          <li class="list-group-item d-flex justify-content-between align-items-start">            <div class="ms-2 me-auto">              <div class="fw-bold">SEO</div>              Baidu和Google有正常收录,有近期快照的网站优先            </div>          </li>          <li class="list-group-item d-flex justify-content-between align-items-start">            <div class="ms-2 me-auto">              <div class="fw-bold">合法性</div>              不含有违反相关国家法律内容的合法网站,不接受TB客等垃圾站的链接            </div>          </li>          <li class="list-group-item d-flex justify-content-between align-items-start">            <div class="ms-2 me-auto">              <div class="fw-bold">更新及时性</div>              不接受原创内容很少,且长期不更新的网站            </div>          </li>          <li class="list-group-item d-flex justify-content-between align-items-start">            <div class="ms-2 me-auto">              <div class="fw-bold">可访问性</div>              如您的网站无法访问,将会暂时撤销友情链接,如需恢复请联系站长处理            </div>          </li>        </ul>      </div>      <div class="form-group">        <button type="submit" class="btn btn-outline-primary">提交</button>        <button type="reset" class="btn btn-outline-warning">重置</button>      </div>    </form>  </div></div>

最后是Controller,添加 StarBlog.Web/Controllers/LinkExchangeController.cs 文件

代码如下

public class LinkExchangeController : Controller {  private readonly ILogger<LinkExchangeController> _logger;  private readonly LinkExchangeService _service;  private readonly IMapper _mapper;  private readonly Messages _messages;  public LinkExchangeController(    ILogger<LinkExchangeController> logger, LinkExchangeService service, IMapper mapper,    Messages messages) {    _logger = logger;    _service = service;    _mapper = mapper;    _messages = messages;  }  [HttpGet]  public IActionResult Add() {    return View();  }  [HttpPost]  public async Task<IActionResult> Add(LinkExchangeAddViewModel vm) {    if (!ModelState.IsValid) return View();    if (await _service.HasUrl(vm.Url)) {      _messages.Error("相同网址的友链申请已提交!");      return View();    }    var item = _mapper.Map<LinkExchange>(vm);    item = await _service.AddOrUpdate(item);    // 发送邮件通知    await _service.SendEmailOnAdd(item);    _messages.Info("友链申请已提交,正在处理中,请及时关注邮件通知~");    return RedirectToAction("Index", "Home");  }}

搞定~

一切就绪

欢迎各位站长大佬来交换友链~!

在线咨询 拨打电话