using Dpz.Core.Public.ViewModel.Response;

namespace Dpz.Core.WebApi.Controllers;

/// <summary>
/// 其他的
/// </summary>
[ApiController, Route("api/[controller]")]
public class CommunityController(
    IPictureRecordService pictureRecordService,
    IArticleService articleService,
    IAppOptionService appOptionService,
    IAppLogEntryService logEntryService,
    IFusionCache fusionCache,
    IConfiguration configuration
) : ControllerBase
{
    /// <summary>
    /// 获取banner
    /// </summary>
    /// <returns></returns>
    [HttpGet("getBanners")]
    [ProducesResponseType<List<PictureRecordResponse>>(StatusCodes.Status200OK)]
    public async Task<IActionResult> GetBanners()
    {
        var banners = await GetBannerAsync();
        return Ok(banners);
    }

    /// <summary>
    /// 获取汇总信息
    /// </summary>
    /// <returns></returns>
    [HttpGet("summary")]
    [Authorize(Policy = "System")]
    [ProducesResponseType<SummaryInformation>(StatusCodes.Status200OK)]
    [ProducesResponseType(StatusCodes.Status401Unauthorized)]
    public async Task<IActionResult> GetSummary()
    {
        const string summaryKey = "community-summary";
        var cache = await fusionCache.TryGetAsync<SummaryInformation>(summaryKey);
        if (cache.HasValue)
        {
            return Ok(cache.Value);
        }

        var banner = await GetBannerAsync();

        var summary = new SummaryInformation
        {
            ArticleTotalCount = await articleService.GetTotalCountAsync(),
            Banner = banner,
            LatestArticles = await articleService.GetLatestAsync(),
            TodayArticleCount = await articleService.GetTodayCountAsync(),
        };
        if (
            configuration["AgileConfig:env"]?.Equals("PROD", StringComparison.OrdinalIgnoreCase)
            == false
        )
        {
            SetRandomData(summary);
        }
        else
        {
            summary.LatestLogs = await GetTop100LogsAsync();
            summary.TodayAccessNumber = await logEntryService.GetLatestAccessNumberAsync();
            summary.WeekAccessNumber = await logEntryService.GetLatestAccessNumberAsync(-7);
        }

        await fusionCache.SetAsync(summaryKey, summary, TimeSpan.FromHours(3));
        return Ok(summary);
    }

    [NonAction]
    private static void SetRandomData(SummaryInformation summary)
    {
        summary.TodayAccessNumber = [];
        summary.WeekAccessNumber = [];
        summary.LatestLogs = $"[{DateTime.Now:HH:mm:ss} INF] this is test log";
        var random = new Random();
        for (var i = 0; i < 7; i++)
        {
            if (i == 0)
            {
                summary.TodayAccessNumber.Add(
                    new AccessSummary
                    {
                        Date = DateTime.Now.ToString("yyyy/MM/dd"),
                        Count = random.Next(100, 100000),
                    }
                );
            }
            summary.WeekAccessNumber.Add(
                new AccessSummary
                {
                    Date = DateTime.Now.AddDays(-(i + 1)).ToString("yyyy/MM/dd"),
                    Count = random.Next(100, 100000),
                }
            );
        }
    }

    private async Task<List<PictureRecordResponse>> GetBannerAsync()
    {
        var cache = await fusionCache.TryGetAsync<List<PictureRecordResponse>>(CacheKey.BannerKey);
        if (cache.HasValue)
        {
            return cache.Value;
        }

        var banner = await pictureRecordService.GetBannerAsync();

        await fusionCache.SetAsync(CacheKey.BannerKey, banner, TimeSpan.FromHours(12));
        return banner.ToList();
    }

    [NonAction]
    private async Task<string> GetTop100LogsAsync()
    {
        var logs = await logEntryService.GetPageAsync(pageSize: 100);
        return string.Join(
            "\n",
            logs?.Events.Select(x =>
            {
                var recordTime = Convert.ToDateTime(x.Timestamp);
                return $"[{recordTime:HH:mm:ss} {x.Level}] {x.RenderedMessage}";
            })
                ?? new List<string>()
        );
    }

    /// <summary>
    /// 获取壁纸
    /// </summary>
    /// <param name="bingWallpaper"></param>
    /// <returns></returns>
    [HttpGet("wallpaper")]
    public async Task<ActionResult<List<Wallpaper>>> Wallpaper(
        [FromServices] IBingWallpaper bingWallpaper
    )
    {
        var wallpapers = await bingWallpaper.GetTodayWallpapersAsync();
        return Ok(wallpapers);
    }

    /// <summary>
    /// 获取页脚内容
    /// </summary>
    /// <returns></returns>
    [HttpGet("footer")]
    [ProducesResponseType<string>(StatusCodes.Status200OK)]
    public async Task<IActionResult> GetFooter()
    {
        var content = await appOptionService.GetFooterContentAsync();
        return Ok(content);
    }

    /// <summary>
    /// 保存页脚内容
    /// </summary>
    /// <param name="footer"></param>
    /// <returns></returns>
    [HttpPost("footer"), Authorize(Policy = "System")]
    [ProducesResponseType(StatusCodes.Status204NoContent)]
    [ProducesResponseType(StatusCodes.Status401Unauthorized)]
    public async Task<IActionResult> SaveFooter([FromBody] SaveFooterDto footer)
    {
        await appOptionService.SaveFooterContentAsync(footer.Content);
        return NoContent();
    }

    /// <summary>
    /// 获取robots.txt
    /// </summary>
    /// <returns></returns>
    [HttpGet("robots.txt"), Authorize(Policy = "System")]
    [ProducesResponseType(StatusCodes.Status204NoContent)]
    [ProducesResponseType(StatusCodes.Status401Unauthorized)]
    public async Task<IActionResult> GetRobots()
    {
        var robots = await appOptionService.GetRobotsAsync();
        return Ok(robots);
    }

    /// <summary>
    /// 保存robots.txt
    /// </summary>
    /// <param name="request"></param>
    /// <returns></returns>
    [HttpPost("robots.txt"), Authorize(Policy = "System")]
    [ProducesResponseType(StatusCodes.Status204NoContent)]
    [ProducesResponseType(StatusCodes.Status401Unauthorized)]
    public async Task<IActionResult> SaveRobots([FromBody] SvaeRobotsRequest request)
    {
        await appOptionService.SaveRobotsAsync(request.Content);
        return NoContent();
    }

    /// <summary>
    /// 获取友链
    /// </summary>
    /// <returns></returns>
    [HttpGet("friends")]
    public async Task<ActionResult<List<VmFriends>>> GetFriends()
    {
        var friends = await appOptionService.GetFriendsAsync();
        return Ok(friends);
    }

#if DEBUG
    private static HubConnection? _connection;

    /// <summary>
    ///
    /// </summary>
    /// <param name="message"></param>
    /// <returns></returns>
    [HttpPost("send")]
    public async Task<IActionResult> SendMessage([FromBody] string message)
    {
        if (_connection == null || _connection.State == HubConnectionState.Disconnected)
        {
            _connection = new HubConnectionBuilder()
                .WithUrl("https://localhost:37701/notification")
                .WithAutomaticReconnect()
                .Build();
            await _connection.StartAsync();
        }

        await _connection.InvokeCoreAsync("SendSystemNotification", [message]);

        return NoContent();
    }
#endif
}
⚠⚠    以下内容为AI分析的结果,请根据实际情况进行判断。

这是一个ASP.NET Core Web API控制器类,名为CommunityController,主要提供社区相关的功能接口。让我详细解释一下这个代码:

类结构和依赖注入

public class CommunityController(
    IPictureRecordService pictureRecordService,
    IArticleService articleService,
    IAppOptionService appOptionService,
    IAppLogEntryService logEntryService,
    IFusionCache fusionCache,
    IConfiguration configuration
) : ControllerBase

使用了C# 12的主构造函数语法,通过依赖注入获取了多个服务:

  • IPictureRecordService: 图片记录服务
  • IArticleService: 文章服务
  • IAppOptionService: 应用配置选项服务
  • IAppLogEntryService: 日志条目服务
  • IFusionCache: 缓存服务
  • IConfiguration: 配置服务

主要功能接口

  • GetBanners(): 获取banner图片列表,使用缓存机制(12小时过期)

2. 汇总信息

  • GetSummary(): 获取系统汇总信息,需要"System"策略授权
    • 包含文章总数、今日文章数、最新文章、banner等信息
    • 根据环境(生产/非生产)显示不同数据
    • 非生产环境显示随机测试数据
    • 生产环境显示真实的访问统计和日志
    • 使用缓存(3小时过期)

3. 壁纸服务

  • Wallpaper(): 获取必应壁纸

4. 页脚管理

  • GetFooter(): 获取页脚内容
  • SaveFooter(): 保存页脚内容(需要系统授权)

5. SEO配置

  • GetRobots(): 获取robots.txt内容(需要系统授权)
  • SaveRobots(): 保存robots.txt内容(需要系统授权)

6. 友链管理

  • GetFriends(): 获取友情链接列表

辅助方法

SetRandomData()

为非生产环境生成随机测试数据,包括:

  • 随机的今日和本周访问数据
  • 模拟的日志信息

GetBannerAsync()

获取banner数据的私有方法,实现了缓存机制

GetTop100LogsAsync()

获取最新100条日志并格式化为字符串

特殊功能

调试模式下的SignalR功能

#if DEBUG
[HttpPost("send")]
public async Task<IActionResult> SendMessage([FromBody] string message)

仅在DEBUG模式下编译,用于测试SignalR消息推送功能。

技术特点

  1. 缓存策略: 大量使用FusionCache来提高性能
  2. 环境区分: 根据配置区分生产和开发环境
  3. 授权控制: 部分接口需要特定的授权策略
  4. 异步编程: 所有数据库操作都使用异步方法
  5. 依赖注入: 充分利用.NET Core的DI容器
  6. 条件编译: 使用#if DEBUG实现调试功能

这个控制器是一个典型的现代ASP.NET Core Web API实现,展现了良好的架构设计和最佳实践。

评论加载中...