网站首页 网站源码
website
站点相关全部源代码,隐藏了一些关于服务器的信息
using Dpz.Core.Public.Entity.Option;
using Dpz.Core.Public.ViewModel.Option;
using ZiggyCreatures.Caching.Fusion;

namespace Dpz.Core.Service.RepositoryServiceImpl;

public class AppOptionService(
    IRepository<AppOption> repository,
    IFusionCache fusionCache,
    IMapper mapper
) : AbstractCacheService(fusionCache), IAppOptionService
{
    /// <summary>
    /// 友情链接 Option name
    /// </summary>
    private const string FriendOptionName = "friends";

    /// <summary>
    /// 页脚内容 Option name
    /// </summary>
    private const string FooterContentOptionName = "footer";

    /// <summary>
    /// 账号锁定 Option name
    /// </summary>
    private const string AccountLockOptionName = "AccountLoginFailLock";

    public async Task<IList<VmFriends>> GetFriendsAsync()
    {
        return await GetOrSetCacheAsync<List<VmFriends>>(
            nameof(GetFriendsAsync),
            async (_, cancellationToken) =>
            {
                var friends = await repository
                    .SearchFor(x => x.OptionName == FriendOptionName)
                    .ToListAsync(cancellationToken);
                if (friends == null || friends.Count == 0)
                {
                    return [];
                }

                var list = friends.Cast<Friends>().ToList();
                return mapper.Map<List<VmFriends>>(list);
            }
        );
    }

    public async Task AddFriendAsync(VmFriends friend)
    {
        var entity = mapper.Map<Friends>(friend);
        entity.CreateTime = DateTime.Now;
        entity.LastUpdateTime = DateTime.Now;
        entity.OptionName = FriendOptionName;
        await repository.InsertAsync(entity);
        await RemoveByMethodAsync(nameof(GetFriendsAsync));
    }

    public async Task EditFriendAsync(VmFriends? friend)
    {
        if (string.IsNullOrEmpty(friend?.Id) || !ObjectId.TryParse(friend.Id, out var oid))
        {
            return;
        }

        var entity = await repository.FindAsync(oid);
        if (entity == null || entity is not Friends entityFriend)
        {
            return;
        }

        entityFriend.Avatar = friend.Avatar;
        entityFriend.Description = friend.Description;
        entityFriend.Link = friend.Link;
        entityFriend.Name = friend.Name;
        entityFriend.LastUpdateTime = DateTime.Now;
        var updateResult = await repository.UpdateAsync(entityFriend);
        if (updateResult is { IsAcknowledged: true, ModifiedCount: > 0 })
        {
            await RemoveByMethodAsync(nameof(GetFriendsAsync));
        }
    }

    public async Task<VmAppOption?> FindAsync(string id)
    {
        var entity = await repository.TryGetAsync(id);
        if (entity == null)
        {
            return null;
        }

        return mapper.Map<VmAppOption>(entity);
    }

    public async Task<VmSaltOption> GetSaltAsync(string account)
    {
        var entity = await repository
            .Collection.Aggregate()
            .Match(new BsonDocument { { "OptionName", "AccountSalt" } })
            .Match(new BsonDocument { { "Account", account } })
            .Match(
                new BsonDocument
                {
                    {
                        "Expire",
                        new BsonDocument { { "$gt", BsonDateTime.Create(DateTime.Now) } }
                    },
                }
            )
            .FirstOrDefaultAsync();
        if (entity is SaltOption saltOption)
        {
            return mapper.Map<VmSaltOption>(saltOption);
        }

        var salt = Guid.NewGuid().ToString("N");
        var saltEntity = new SaltOption
        {
            Account = account,
            CreateTime = DateTime.Now,
            Expire = DateTime.Now.AddDays(7),
            LastUpdateTime = DateTime.Now,
            OptionName = "AccountSalt",
            Salt = salt,
        };

        await repository.InsertAsync(saltEntity);
        return mapper.Map<VmSaltOption>(saltEntity);
    }

    public async Task SaveFooterContentAsync(string content)
    {
        var footer = await repository
            .SearchFor(x => x.OptionName == FooterContentOptionName)
            .FirstOrDefaultAsync();
        if (footer != null)
        {
            var set = new BsonDocument
            {
                {
                    "$set",
                    new BsonDocument
                    {
                        { "Content", new BsonString(content) },
                        { "LastUpdateTime", new BsonDateTime(DateTime.Now) },
                    }
                },
            };
            UpdateDefinition<AppOption> update = new BsonDocumentUpdateDefinition<AppOption>(set);
            var updateResult = await repository.UpdateAsync(x => x.Id == footer.Id, update);
            if (updateResult is { IsAcknowledged: true, ModifiedCount: > 0 })
            {
                await RemoveByMethodAsync(nameof(GetFooterContentAsync));
            }
            return;
        }

        var entity = new FooterContent
        {
            Content = content,
            CreateTime = DateTime.Now,
            LastUpdateTime = DateTime.Now,
            OptionName = FooterContentOptionName,
        };
        await repository.InsertAsync(entity);
        await RemoveByMethodAsync(nameof(GetFooterContentAsync));
    }

    public async Task<string> GetFooterContentAsync()
    {
        return await GetOrSetCacheAsync<string>(
            nameof(GetFooterContentAsync),
            async (_, cancellationToken) =>
            {
                var footer = await repository
                    .SearchFor(x => x.OptionName == FooterContentOptionName)
                    .FirstOrDefaultAsync(cancellationToken);
                return footer is FooterContent entity ? entity.Content : "";
            }
        );
    }

    public async Task LoginFailAsync(string account)
    {
        if (
            await repository
                .Collection.Aggregate()
                .Match(new BsonDocument { { "OptionName", AccountLockOptionName } })
                .Match(new BsonDocument { { "Account", account } })
                .FirstOrDefaultAsync()
            is AccountLock accountLock
        )
        {
            // 如果锁定时间过期,那么重置
            if (
                accountLock.Expired.HasValue
                && DateTime.Now > accountLock.Expired.Value.ToLocalTime()
            )
            {
                accountLock.Expired = null;
                accountLock.AttemptNumber = 1;
                accountLock.LastUpdateTime = DateTime.Now;
                await repository.UpdateAsync(accountLock);
                return;
            }

            // 上次操作超过间隔时间,那么重置尝试次数
            if (DateTime.Now > accountLock.LastUpdateTime.ToLocalTime().AddHours(1))
            {
                accountLock.AttemptNumber = 1;
            }
            // 没有超过间隔时间,尝试次数累加
            else
            {
                accountLock.AttemptNumber++;
            }

            accountLock.LastUpdateTime = DateTime.Now;
            // 超过尝试次数,则锁定,设定锁定时间
            if (accountLock.AttemptNumber > 3)
            {
                accountLock.Expired = DateTime.Now.AddDays(1);
            }

            await repository.UpdateAsync(accountLock);
            return;
        }

        var entity = new AccountLock
        {
            Account = account,
            AttemptNumber = 1,
            CreateTime = DateTime.Now,
            LastUpdateTime = DateTime.Now,
            OptionName = AccountLockOptionName,
        };
        await repository.InsertAsync(entity);
    }

    public async Task LoginSuccessfulAsync(string account)
    {
        if (
            await repository
                .Collection.Aggregate()
                .Match(new BsonDocument { { "OptionName", AccountLockOptionName } })
                .Match(new BsonDocument { { "Account", account } })
                .FirstOrDefaultAsync()
            is AccountLock accountLock
        )
        {
            accountLock.AttemptNumber = 0;
            accountLock.Expired = null;
            accountLock.LastUpdateTime = DateTime.Now;
            await repository.UpdateAsync(accountLock);
        }
    }

    public async Task<bool> IsAccountLockAsync(string account)
    {
        var entity = await repository
            .Collection.Aggregate()
            .Match(new BsonDocument { { "OptionName", AccountLockOptionName } })
            .Match(new BsonDocument { { "Account", account } })
            .FirstOrDefaultAsync();
        return entity is AccountLock { Expired: { } } accountLock
            && accountLock.Expired.Value.ToLocalTime() > DateTime.Now;
    }

    private const string SettingOptionName = "Application.Setting";

    public async Task<VmSetting?> GetSettingAsync()
    {
        var option = await repository
            .SearchFor(x => x.OptionName == SettingOptionName)
            .SingleOrDefaultAsync();
        if (option is Setting setting)
        {
            return mapper.Map<VmSetting>(setting);
        }

        return null;
    }

    public async Task SaveSettingAsync(VmSetting setting)
    {
        var option = await repository
            .SearchFor(x => x.OptionName == SettingOptionName)
            .SingleOrDefaultAsync();
        if (option is Setting entitySetting)
        {
            entitySetting.Api = setting.Api;
            entitySetting.Cdn = setting.Cdn;
            entitySetting.Core = setting.Core;
            entitySetting.Image = setting.Image;
            entitySetting.Job = setting.Job;
            entitySetting.Main = setting.Main;
            entitySetting.Message = setting.Message;
            entitySetting.Script = setting.Script;
            entitySetting.Static = setting.Static;
            entitySetting.LastUpdateTime = DateTime.Now;
            await repository.UpdateAsync(entitySetting);
            return;
        }

        var entity = mapper.Map<Setting>(setting);
        entity.OptionName = SettingOptionName;
        entity.CreateTime = DateTime.Now;
        entity.LastUpdateTime = DateTime.Now;

        await repository.InsertAsync(entity);
    }

    public async Task DeleteFriendAsync(string id)
    {
        if (ObjectId.TryParse(id, out var oid))
        {
            var deleteResult = await repository.DeleteAsync(x =>
                x.OptionName == "Friends" && x.Id == oid
            );
            if (deleteResult is { IsAcknowledged: true, DeletedCount: > 0 })
            {
                await RemoveCacheAsync(nameof(GetFriendsAsync));
            }
        }
    }

    protected override string CachePrefixKey =>
        "Dpz.Core.Service.RepositoryServiceImpl.AppOptionService";
    protected override TimeSpan CacheDefaultExpiration => TimeSpan.FromDays(30);
}
⚠⚠    以下内容为AI分析的结果,请根据实际情况进行判断。

上述代码定义了一个名为 AppOptionService 的服务类,主要用于管理应用程序的选项和配置。该类实现了 IAppOptionService 接口,并依赖于一个通用的 IRepository<AppOption> 接口来进行数据存取操作。以下是该类的主要功能和方法的详细解释:

主要功能

  1. 管理友情链接

    • GetFriendsAsync:异步获取所有的友情链接,返回一个 VmFriends 的列表。
    • AddFriendAsync:异步添加一个新的友情链接。
    • EditFriendAsync:异步编辑现有的友情链接。
  2. 管理应用程序设置

    • GetSettingAsync:异步获取应用程序的设置,返回一个 VmSetting 对象。
    • SaveSettingAsync:异步保存应用程序的设置。
  3. 管理页脚内容

    • GetFooterContentAsync:异步获取页脚内容。
    • SaveFooterContentAsync:异步保存页脚内容,并将其缓存。
  4. 账号锁定管理

    • LoginFailAsync:记录登录失败的尝试,并在超过最大尝试次数后锁定账号。
    • LoginSuccessfulAsync:在成功登录后重置账号的锁定状态。
    • IsAccountLockAsync:检查账号是否被锁定。
  5. 盐值管理

    • GetSaltAsync:获取与特定账号相关的盐值,如果不存在则生成一个新的盐值并保存。
  6. 删除操作

    • DeleteAsync:根据 ID 删除特定的选项。

代码结构

  • 构造函数:接收 IRepository<AppOption>IHybridCachingProviderIMapper 的实例,以便在类中使用。
  • 常量定义:定义了一些常量字符串,用于标识不同的选项名称(如友情链接、页脚内容、账号锁定等)。
  • 异步方法:大多数方法都是异步的,使用 asyncawait 关键字,以提高性能和响应性。

具体方法解析

  • GetFriendsAsync:从数据库中查找所有名称为 "friends" 的选项,并将其映射为 VmFriends 对象列表。
  • AddFriendAsync:将传入的 VmFriends 对象映射为 Friends 实体,并插入到数据库中。
  • EditFriendAsync:根据 ID 查找现有的 Friends 实体,并更新其属性。
  • FindAsync:根据 ID 查找特定的选项并返回映射后的 VmAppOption 对象。
  • GetSaltAsync:查找与账号相关的盐值,如果不存在则生成新的盐值并保存。
  • SaveFooterContentAsync:保存页脚内容到数据库,并设置缓存。
  • GetFooterContentAsync:获取页脚内容。
  • LoginFailAsync:记录登录失败的尝试,并在超过最大尝试次数后锁定账号。
  • LoginSuccessfulAsync:重置账号的锁定状态。
  • IsAccountLockAsync:检查账号是否被锁定。
  • GetSettingAsync:获取应用程序的设置。
  • SaveSettingAsync:保存应用程序的设置。
  • DeleteAsync:根据 ID 删除特定的选项。

总结

AppOptionService 类提供了一系列方法来管理应用程序的选项和配置,包括友情链接、页脚内容、账号锁定、盐值和应用程序设置等。通过使用异步编程模式,该类能够高效地处理数据库操作,并提供良好的用户体验。

loading