using System.ComponentModel.DataAnnotations;
using System.Text.RegularExpressions;
using Dpz.Core.Public.ViewModel.Request;
using Dpz.Core.Public.ViewModel.Request.HandlerRequest;
using Dpz.Core.Public.ViewModel.RequestEvent;
using Dpz.Core.Service.ObjectStorage.Services;
using Dpz.Core.Web.Library.Api;
namespace Dpz.Core.Web.Controllers;
public partial class ArticleController(
IArticleService articleService,
IObjectStorageOperation objectStorageService,
IMediator mediator,
ILogger<ArticleController> logger
) : Controller
{
public async Task<IActionResult> Index(
[FromServices] IHomeCacheService cacheService,
string? tag = "",
[Range(10, 100)] int pageSize = 15,
int pageIndex = 1
)
{
if (!ModelState.IsValid)
{
return NotFound();
}
var tags = string.IsNullOrEmpty(tag) ? [] : new[] { tag };
this.SetTitle(string.IsNullOrEmpty(tag) ? "文章列表" : $"标签-{tag}-文章列表");
var list = await articleService.GetPagesAsync(pageIndex, pageSize, tags: tags);
if (Request.Headers["X-PJAX"] == "true" && Request.Query["_pjax"] == "#article-list")
{
return PartialView("_ArticleListPartial", list);
}
var model = new ArticleIndexModel
{
LikeArticle = await cacheService.GetRandomArticlesAsync(),
List = list,
News = await cacheService.GetLatestArticlesAsync(),
Tags = await cacheService.GetArticleTagsAsync(),
};
return View(model);
}
public async Task<IActionResult> Read(string id = "", string text = "")
{
var article = await mediator.Send(new ArticleReadRequest { Id = id, Text = text });
if (article == null)
{
return NotFound();
}
this.SetTitle(article.Title);
var pageMetaPage = new VmPageMetadata
{
Description = ClearIntroductionRegex().Replace(article.Introduction ?? "", ""),
Keywords = [article.Title],
Relations = ["Article", "Read", id],
};
ViewData["PageMetadata"] = pageMetaPage;
ViewData["Text"] = text;
return View(article);
}
[CheckAuthorize]
[HttpPost]
public async Task<IActionResult> Upload()
{
var file = Request.Form.Files.FirstOrDefault();
if (file is { Length: > 0 } && file.ContentType.Contains("image"))
{
//var userInfo = User.GetIdentity();
var path = new[] { "images", "article", DateTime.Now.ToString("yyyy-MM-dd") };
var fileName =
ObjectId.GenerateNewId() + file.FileName[file.FileName.LastIndexOf('.')..];
var result = await objectStorageService.UploadAsync(
file.OpenReadStream(),
path,
fileName
);
return Json(
new
{
success = 1,
message = "",
url = result.AccessUrl,
}
);
}
return Json(
new
{
success = 0,
message = "请选择一张图片!",
url = "",
}
);
}
[HttpPost, CheckAuthorize]
public async Task<IActionResult> Publish(EditArticleRequest model, string newTag = "")
{
var userInfo = User.RequiredUserInfo;
var checkResult = ModelState.CheckModelState();
if (checkResult.IsValid)
{
return Json(new ResultInfo(string.Join("\n", checkResult.ErrorMessages)));
}
if (!string.IsNullOrWhiteSpace(newTag))
{
var newTags = newTag.Split(',').Where(x => !string.IsNullOrWhiteSpace(x)).ToList();
model.Tags.AddRange(newTags);
}
// 编辑
if (!string.IsNullOrEmpty(model.Id))
{
var article = await articleService.GetArticleAsync(model.Id);
if (article == null)
{
return Json(new ResultInfo("文章不存在"));
}
if (userInfo.Id != article.Author?.Id)
{
return Json(new ResultInfo("不能修改别人发布的文章!"));
}
await articleService.EditArticleAsync(model, userInfo);
return Json(new ResultInfo(data: model.Id));
}
try
{
// 新增
var createdArticle = await articleService.CreateArticleAsync(model, userInfo);
await articleService.ClearCacheAsync();
return Json(new ResultInfo(data: createdArticle.Id));
}
catch (Exception ex)
{
logger.LogInformation(ex, "创建文章失败");
return Json(ResultInfo.ToFail(ex.Message));
}
}
[CheckAuthorize, HttpPost]
public async Task<IActionResult> Delete(string id)
{
var article = await articleService.GetArticleAsync(id);
if (article == null || User.RequiredUserId != article.Author?.Id)
{
return Json(new ResultInfo("未找到文章,或者不能删除别人发布的文章!"));
}
await articleService.DeleteAsync(id);
return Json(new ResultInfo(true));
}
[HttpGet]
public async Task<IActionResult> Search(string? keyword = "")
{
var request = new ArticleSearchRequest { Keyword = keyword };
var searchResult = await mediator.Send(request);
var tags = await articleService.GetAllTagsAsync();
var model = new ArticleSearchModel(keyword, searchResult, tags);
this.SetTitle($"搜索 - {keyword}");
return View(model);
}
[GeneratedRegex("<[^>]*>")]
private static partial Regex ClearIntroductionRegex();
}
⚠⚠ 以下内容为AI分析的结果,请根据实际情况进行判断。
这段代码是一个 ASP.NET Core MVC 控制器的实现,主要用于处理与文章相关的操作。以下是对代码中各个部分功能的详细解释:
1. 控制器定义
ArticleController 继承自 Controller,并通过构造函数注入了三个服务:
IArticleService:用于处理与文章相关的业务逻辑。IObjectStorageOperation:用于处理对象存储(如文件上传)的操作。ILogger<ArticleController>:用于记录日志。
2. 文章列表 (Index 方法)
- 功能:获取并显示文章列表。
- 参数:
tag:可选的标签,用于过滤文章。pageSize:每页显示的文章数量,范围在 10 到 100 之间。pageIndex:当前页码。
- 逻辑:
- 如果模型状态无效,返回 404。
- 根据标签设置页面标题。
- 调用
articleService.GetPagesAsync获取文章列表。 - 如果请求是 PJAX 请求,返回部分视图。
- 否则,构建模型并返回完整视图。
3. 文章阅读 (Read 方法)
- 功能:根据文章 ID 获取并显示文章内容。
- 逻辑:
- 调用
articleService.GetArticleAsync获取文章。 - 如果文章不存在,返回 404。
- 设置页面标题和元数据,然后返回文章视图。
- 调用
4. 上传图片 (Upload 方法)
- 功能:处理文章图片的上传。
- 逻辑:
- 检查请求中是否包含文件,并且文件类型是否为图片。
- 生成文件名并调用
objectStorageService.UploadAsync上传文件。 - 返回 JSON 响应,包含上传结果。
5. 发布文章 (Publish 方法)
- 功能:显示和处理文章的发布(创建或编辑)。
- 逻辑:
- GET 方法用于显示编辑页面。
- POST 方法用于处理表单提交,验证模型状态,创建或编辑文章。
- 如果是编辑,检查文章是否存在以及用户权限。
- 返回 JSON 响应,包含操作结果。
6. 删除文章 (Delete 方法)
- 功能:删除指定 ID 的文章。
- 逻辑:
- 检查文章是否存在以及用户权限。
- 调用
articleService.DeleteAsync删除文章,并返回操作结果。
7. 文章预览 (Preview 方法)
- 功能:预览指定 ID 的文章。
- 逻辑:
- 检查文章是否存在,返回文章视图。
8. 获取我的文章 (MyArticle 方法)
- 功能:获取当前用户的文章列表。
- 逻辑:
- 调用
articleService.GetPagesAsync获取用户的文章,并返回 JSON 响应。
- 调用
9. 文章详情 (Detail 方法)
- 功能:获取指定 ID 的文章详情。
- 逻辑:
- 检查文章是否存在,返回 JSON 响应。
10. 获取所有标签 (Tags 方法)
- 功能:获取所有文章标签。
- 逻辑:
- 调用
articleService.GetAllTagsAsync获取标签,并返回 JSON 响应。
- 调用
11. 搜索文章 (Search 方法)
- 功能:根据关键字搜索文章。
- 逻辑:
- 调用
articleService.SearchAsync获取搜索结果,并返回视图。
- 调用
12. 正则表达式 (ClearIntroductionRRegex)
- 功能:用于清除文章简介中的 HTML 标签。
总结
整体上,这个控制器提供了一个完整的文章管理功能,包括文章的创建、编辑、删除、查看、搜索和标签管理等。通过依赖注入的方式,控制器能够与服务层进行交互,处理业务逻辑,并返回相应的视图或 JSON 数据。
评论加载中...