/// <summary> /// 设置配置项 /// </summary> /// <typeparam name="T"></typeparam> /// <param name="obj"></param> /// <returns></returns> public async Task <int> SetConfigAsync <T>(T obj, DbTransaction transaction = null) where T : class, new() { string keyName = typeof(T).Name; if (obj == null) { throw new ArgumentNullException(nameof(obj)); } string json = JsonHelper.ToJson <T>(obj); Config config = await this.GetConfigFormKeyAsync(keyName); if (config == null) { config = new Config { Id = GuidHelper.CreateSequential(), ConfigKey = keyName, ConfigValue = json }; return(await this.InsertAsync(config, transaction)); } else { config.ConfigValue = json; return(await this.UpdateAsync(config, transaction)); } }
/// <summary> /// 插入单个标签,如果该标签已存在,则抛出异常 /// </summary> public async Task <Tag> CreateAsync(TagEditModel model) { if (model == null) { throw new ArgumentNullException(nameof(model)); } if (string.IsNullOrWhiteSpace(model.Name)) { throw new ModelException(nameof(model.Name), "标签名称不能为空"); } model.Name = model.Name.Trim(); using (var work = this.dbFactory.StartWork()) { Tag oldTag = await work.Tag.GetByNameAsync(model.Name); if (oldTag != null) { throw new ModelException(nameof(model.Name), "该标签名称已存在"); } else { Tag tag = new Tag { Id = GuidHelper.CreateSequential(), Name = model.Name, IsBest = model.IsBest, IsSystem = true }; await work.Tag.InsertAsync(tag); return(tag); } } }
/// <summary> /// 创建话题 /// </summary> public async Task <Topic> CreateAsync(TopicEditModel model) { if (model == null) { throw new ArgumentNullException(nameof(model)); } if (string.IsNullOrWhiteSpace(model.Name)) { throw new ModelException(nameof(model.Name), "话题名称不能为空"); } using (var work = this.dbFactory.StartWork()) { Topic old = await work.Topic.GetByNameAsync(model.Name.Trim()); if (old != null) { throw new ModelException(nameof(model.Name), "该话题名称已存在"); } Topic topic = ObjectMapper.Map <TopicEditModel, Topic>(model); topic.IsAnnounce = false; topic.Id = GuidHelper.CreateSequential(); await work.Topic.InsertAsync(topic); return(topic); } }
/// <summary> /// 插入邀请码 /// </summary> public async Task <InviteCode> InsertAsync(InviteEditModel model, PersonView person) { if (model == null) { throw new ArgumentNullException(nameof(model)); } if (person == null) { throw new ArgumentNullException(nameof(person)); } using (var work = this.dbFactory.StartWork()) { if (await work.InviteCode.IsExistCodeAsync(model.Code)) { throw new ModelException(nameof(model.Code), "该邀请码已存在"); } else { InviteCode code = new InviteCode { Code = model.Code, Id = GuidHelper.CreateSequential(), PersonId = person.Id }; await work.InviteCode.InsertAsync(code); return(code); } } }
/// <summary> /// 设置数据库版本 /// </summary> public async Task <int> SetDbVersionAsync(Version version, DbTransaction transaction = null) { if (version == null) { throw new ArgumentNullException(nameof(version)); } Config config = new Config { Id = GuidHelper.CreateSequential(), ConfigKey = DBVERSION, ConfigValue = version.ToString() }; return(await this.InsertAsync(config, transaction)); }
/// <summary> /// 创建新的邀请码 /// </summary> public async Task <InviteCode> CreateNewCodeAsync(Person person, DbTransaction transaction) { if (person == null) { throw new ArgumentNullException(nameof(person)); } string code = RandomHelper.GetIntNumber(100000, 999999).ToString(); InviteCode inviteCode = new InviteCode { Id = GuidHelper.CreateSequential(), PersonId = person.Id, Code = code }; await this.InsertAsync(inviteCode, transaction); return(inviteCode); }
/// <summary> /// 当前用户对帖子点赞 /// </summary> public async Task ZanPostAsync(Guid postId) { Guid? personId = httpContextAccessor.HttpContext.User.GetUserId(); string sessionId = httpContextAccessor.HttpContext.Session.Id; Zan zan = null; DateTime now = DateTime.Now; using (var work = this.dbFactory.StartWork()) { Post post = await work.Post.SingleByIdAsync(postId); if (post == null || post.PostStatus != Enums.PostStatus.Publish) { throw new Exception("该帖子不存在或已被删除"); } // 如果是匿名用户 if (personId == null) { if (!(await work.Zan.IsZanAsync(sessionId, postId, Enums.ZanType.Post))) { //添加赞记录 zan = new Zan { Id = GuidHelper.CreateSequential(), SessionId = this.httpContextAccessor.HttpContext.Session.Id, CommentId = null, DoTime = now, PersonId = null, PostId = postId, ZanType = Enums.ZanType.Post }; } } else { // 如果是登录用户 if (!(await work.Zan.IsZanAsync(personId.Value, postId, Enums.ZanType.Post))) { zan = new Zan { Id = GuidHelper.CreateSequential(), SessionId = this.httpContextAccessor.HttpContext.Session.Id, CommentId = null, DoTime = now, PersonId = personId.Value, PostId = postId, ZanType = Enums.ZanType.Post }; } } if (zan != null) { using (var trans = work.BeginTransaction()) { try { await work.Zan.InsertAsync(zan, trans); // 累计帖子赞 await work.Connection.IncreaseAsync(nameof(Post), nameof(Post.LikeNum), nameof(Post.Id), postId, trans); // 累计作者赞 await work.Connection.IncreaseAsync(nameof(PersonData), nameof(PersonData.LikeNum), nameof(PersonData.PersonId), post.PersonId, trans); trans.Commit(); } catch (Exception) { trans.Rollback(); throw; } } } } }
/// <summary> /// 初始化数据库 /// </summary> public async Task InitAsync() { using (DbConnection conn = this.dbFactory.Create()) { conn.Open(); long count = await conn.ScalarAsync <long>("select count(*) from pg_tables where schemaname='public';"); if (count > 0) { this.logger.LogInformation("The data table already exists in the database, the initialization process will be skipped."); // 如果数据库存在数据表,则不跳过初始化 return; } else { // 创建数据表 this.logger.LogInformation("Start creating data table"); await conn.ExecuteNonQueryAsync(GAsk.Properties.Resources.CreateTables); await conn.ExecuteNonQueryAsync(Properties.Resources.createIndex); // 创建角色 Role superAdminRole = new Role() { Id = GuidHelper.CreateSequential(), Name = "网站管理员", RoleType = RoleType.SuperAdmin }; Role adminRole = new Role() { Id = GuidHelper.CreateSequential(), Name = "管理员", RoleType = RoleType.Admin }; Role masterRole = new Role() { Id = GuidHelper.CreateSequential(), Name = "话题版主", RoleType = RoleType.Master }; Role userRole = new Role() { Id = GuidHelper.CreateSequential(), Name = "注册用户", RoleType = RoleType.User }; DateTime now = DateTime.Now; Person superAdmin = new Person() { Id = GuidHelper.CreateSequential(), AccountName = "admin", RoleId = superAdminRole.Id, NickName = "admin", Password = this.encryptService.PasswordHash("12345678"), LastUpdated = now, CreateTime = now }; PersonData adminData = new PersonData { Id = GuidHelper.CreateSequential(), AnswerNum = 0, ArticleNum = 0, AskNum = 0, LikeNum = 0, PersonId = superAdmin.Id }; Topic topic = new Topic { Id = GuidHelper.CreateSequential(), OrderNum = 0, IsAnnounce = true, IsHide = false, Name = "公告" }; DbConfig dbConfig = new DbConfig { Version = new Version(1, 0, 0, 0) }; Config config = new Config { Id = GuidHelper.CreateSequential(), ConfigKey = nameof(DbConfig), ConfigValue = JsonHelper.ToJson <DbConfig>(dbConfig) }; using (DbTransaction trans = conn.BeginTransaction()) { try { this.logger.LogInformation("Start initializing data"); await conn.InsertAsync <Role>(superAdminRole, trans); await conn.InsertAsync(adminRole, trans); await conn.InsertAsync(masterRole, trans); await conn.InsertAsync(userRole, trans); await conn.InsertAsync(superAdmin, trans); await conn.InsertAsync(adminData, trans); await conn.InsertAsync(topic, trans); await conn.InsertAsync(config, trans); trans.Commit(); } catch (Exception ex) { this.logger.LogError(ex, "Initialization data error"); trans.Rollback(); throw; } } } } }
/// <summary> /// 插入评论 /// </summary> public async Task <CommentView> InsertAsync(CommentEditModel model, Guid loginUserId) { if (model == null) { throw new ArgumentNullException(nameof(model)); } string html = this.htmlService.ClearHtml(model.Content); if (string.IsNullOrWhiteSpace(html)) { throw new Exception("评论内容不能为空"); } DateTime now = DateTime.Now; using (var work = this.dbFactory.StartWork()) { Person person = await work.Person.SingleByIdAsync(loginUserId); if (person == null || person.IsDelete || person.IsMute) { throw new Exception("该用户没有发贴权限"); } Post post = await work.Post.SingleByIdAsync(model.PostId); if (post == null || post.PostStatus != Enums.PostStatus.Publish) { throw new Exception("该帖子不存在,或禁止评论"); } using (var trans = work.BeginTransaction()) { try { // 插入评论 Comment comment = new Comment { Id = GuidHelper.CreateSequential(), CreateTime = now, HtmlContent = html, IsDelete = false, LikeNum = 0, ModifyTime = null, ParentId = model.ParentId, PersonId = loginUserId, PostId = model.PostId, TextContent = this.htmlService.HtmlToText(html) }; await work.Comment.InsertAsync(comment, trans); // 插入活动 CommentInfo info = new CommentInfo { CommentId = comment.Id, PostId = post.Id, PostTitle = post.Title }; Activity activity = new Activity { Id = GuidHelper.CreateSequential(), ActivityType = Enums.ActivityType.Comment, DoTime = now, PersonId = loginUserId, PostId = post.Id }; await work.Activity.InsertAsync(activity, trans); // 递增用户回复数 await work.Connection.IncreaseAsync(nameof(PersonData), nameof(PersonData.AnswerNum), nameof(PersonData.PersonId), person.Id, trans); // 递增帖子回复数 await work.Connection.IncreaseAsync(nameof(Post), nameof(Post.CommentNum), nameof(Post.Id), post.Id, trans); trans.Commit(); return(await work.CommentView.SingleByIdAsync(comment.Id)); } catch { trans.Rollback(); throw; } } } }
/// <summary> /// 为当前用户添加收藏 /// </summary> public async Task <Favorite> InsertFavoriteAsync(Guid postId) { Guid?userId = this.httpContextAccessor.HttpContext.User.GetUserId(); if (userId == null) { throw new Exception("使用收藏必须先登录"); } else { using (var work = this.dbFactory.StartWork()) { Person person = await work.Person.SingleByIdAsync(userId.Value); if (person == null || person.IsDelete) { throw new Exception("该用户不存在或已被删除"); } Post post = await work.Post.SingleByIdAsync(postId); if (post == null || post.PostStatus != Enums.PostStatus.Publish) { throw new Exception("该帖子不存在或未公开"); } DateTime now = DateTime.Now; using (var trans = work.BeginTransaction()) { try { // 插入收藏 Favorite favorite = new Favorite { Id = GuidHelper.CreateSequential(), PersonId = person.Id, PostId = post.Id, DoTime = now }; await work.Favorite.InsertAsync(favorite, trans); // 插入活动 Activity activity = new Activity { Id = GuidHelper.CreateSequential(), ActivityType = Enums.ActivityType.Favorite, DoTime = now, PersonId = person.Id, PostId = postId }; await work.Activity.InsertAsync(activity); trans.Commit(); return(favorite); } catch (Exception) { trans.Rollback(); throw; } } } } }
/// <summary> /// 注册用户 /// </summary> public async Task <Person> Register(AccountRegisterModel model) { if (model == null) { throw new ArgumentNullException(nameof(model)); } using (UnitOfWork work = this.dbFactory.StartWork()) { RegisterConfig config = await work.Config.GetRegisterConfigAsync(); #region 检查邀请码 if (config.IsEnableInviteCode) { if (string.IsNullOrWhiteSpace(model.InviteCode)) { throw new ModelException(nameof(model.InviteCode), "请填写邀请码"); } else { string inputCode = model.InviteCode.Trim(); if (!(await work.InviteCode.IsExistCodeAsync(inputCode))) { throw new ModelException(nameof(model.InviteCode), "该邀请码不存在,请重新输入"); } } } #endregion #region 检查账户 if (model.UserName.ToLower().Contains("admin")) { throw new ModelException(nameof(model.UserName), "该账户被系统保留,禁止使用该名称"); } if (await work.Person.IsExistNameAsync(model.UserName)) { throw new ModelException(nameof(model.UserName), "该账户已被注册"); } #endregion Role role = await work.Role.GetSingleAsync(Enums.RoleType.User); DateTime now = DateTime.Now; using (var trans = work.BeginTransaction()) { try { Person person = new Person { Id = GuidHelper.CreateSequential(), AccountName = model.UserName.Trim(), CreateTime = now, LastUpdated = now, NickName = model.UserName.Trim(), RoleId = role.Id, Password = this.encryptService.PasswordHash(model.Password), Avatar = GlobalVariable.DefaultAvatar }; await work.Person.InsertAsync(person, trans); PersonData personData = new PersonData() { Id = GuidHelper.CreateSequential(), AnswerNum = 0, ArticleNum = 0, AskNum = 0, LikeNum = 0, PersonId = person.Id, Score = 0 }; await work.PersonData.InsertAsync(personData, trans); trans.Commit(); return(person); } catch (Exception) { trans.Rollback(); throw; } } } }
/// <summary> /// 修改帖子 /// </summary> public async Task ModifyAsync(PostEditModel model, Guid userId) { if (model == null) { throw new ArgumentNullException(nameof(model)); } if (model.Id == null) { throw new ArgumentNullException(nameof(model.Id)); } if (model.UseTags.Count > 5) { throw new ModelException(nameof(model.UseTags), "最多只能创建5个标签"); } string htmlContent = htmlService.ClearHtml(model.Content); string textContent = htmlService.HtmlToText(htmlContent); if (model.PostType == PostType.Article && string.IsNullOrWhiteSpace(htmlContent)) { throw new Exception("文章内容不能为空"); } string title = htmlService.HtmlToText(model.Title).Trim(); if (string.IsNullOrWhiteSpace(title)) { throw new ModelException(nameof(model.Title), "标题不能为空"); } using (var work = this.dbFactory.StartWork()) { Post post = await work.Post.SingleByIdAsync(model.Id.Value); if (post == null || post.PostStatus == PostStatus.Block) { throw new Exception("该帖子不存在或已被删除"); } if (userId != post.PersonId) { throw new Exception("仅本人拥有修改的权限"); } PostData postData = await work.PostData.GetPostDataAsync(post); using (var trans = work.BeginTransaction()) { try { await work.PostTag.DeleteAllAsync(post, trans); List <string> tags = work.Tag.RemoveDuplication(model.UseTags); foreach (var item in tags) { Tag tag = await work.Tag.GetByNameAsync(item); // 如果标签不存在,则重新创建 if (tag == null) { tag = new Tag { Id = GuidHelper.CreateSequential(), IsBest = false, IsSystem = false, Name = item.Trim() }; await work.Tag.InsertAsync(tag, trans); } // 记录帖子与标签之间的关联 PostTag postTag = new PostTag { Id = GuidHelper.CreateSequential(), PostId = post.Id, TagId = tag.Id }; await work.PostTag.InsertAsync(postTag, trans); } DateTime now = DateTime.Now; // 修改帖子基本信息 await work.Post.ModifyContent(post.Id, htmlService.HtmlToText(model.Title), model.TopicId.Value, now, trans); // 修改帖子内容 postData.HtmlContent = htmlContent; postData.TextContent = textContent; await work.PostData.UpdateAsync(postData); // 插入活动 Activity activity = new Activity { Id = GuidHelper.CreateSequential(), ActivityType = ActivityType.Modify, PersonId = userId, PostId = post.Id, DoTime = now }; await work.Activity.InsertAsync(activity, trans); trans.Commit(); } catch (Exception) { trans.Rollback(); throw; } } } }
/// <summary> /// 创建公告 /// </summary> public async Task <Post> CreateAnnounceAsync(AnnounceEditModel model, PersonView person) { if (model == null) { throw new ArgumentNullException(nameof(model)); } if (person == null) { throw new ArgumentNullException(nameof(person)); } string htmlContent = htmlService.ClearHtml(model.Content); string textContent = htmlService.HtmlToText(htmlContent); if (string.IsNullOrWhiteSpace(textContent)) { throw new Exception("公告内容不能为空"); } using (var work = this.dbFactory.StartWork()) { if (person.RoleType != RoleType.Admin && person.RoleType != RoleType.SuperAdmin) { throw new Exception("你没有发布公告权限"); } // 获取公告话题 Topic topic = await work.Topic.GetAnnounce(); DateTime now = DateTime.Now; Post post = new Post() { Id = GuidHelper.CreateSequential(), CreateTime = now, IsBest = false, IsTop = false, ModifyTime = null, PostStatus = PostStatus.Publish, PostType = PostType.Article, // 帖子类型 Title = htmlService.HtmlToText(model.Title), TopicId = topic.Id, PersonId = person.Id }; PostData postData = new PostData { Id = GuidHelper.CreateSequential(), HtmlContent = htmlContent, TextContent = textContent, PostId = post.Id }; using (var trans = work.BeginTransaction()) { try { await work.Post.InsertAsync(post, trans); // 插入文章 await work.PostData.InsertAsync(postData, trans); // 插入文章内容 await work.Connection.IncreaseAsync(nameof(PersonData), nameof(PersonData.ArticleNum), nameof(PersonData.PersonId), person.Id, trans); // 递增发文数 trans.Commit(); } catch (Exception) { trans.Rollback(); throw; } } return(post); } }
/// <summary> /// 插入帖子(问题、文章) /// </summary> public async Task <Post> InsertAsync(PostEditModel model, Guid userId) { if (model == null) { throw new ArgumentNullException(nameof(model)); } if (model.UseTags.Count > 5) { throw new ModelException(nameof(model.UseTags), "最多只能创建5个标签"); } string htmlContent = htmlService.ClearHtml(model.Content); string textContent = htmlService.HtmlToText(htmlContent); if (model.PostType == PostType.Article && string.IsNullOrWhiteSpace(htmlContent)) { throw new Exception("文章内容不能为空"); } PostStatus postStatus = PostStatus.Publish; DateTime now = DateTime.Now; Post post = new Post() { Id = GuidHelper.CreateSequential(), CreateTime = now, IsBest = false, IsTop = false, ModifyTime = null, PostStatus = postStatus, PostType = model.PostType, // 帖子类型 Title = htmlService.HtmlToText(model.Title), TopicId = model.TopicId.Value, PersonId = userId }; PostData postData = new PostData { Id = GuidHelper.CreateSequential(), HtmlContent = htmlContent, PostId = post.Id, TextContent = textContent }; Activity activity = new Activity { Id = GuidHelper.CreateSequential(), DoTime = now, PersonId = userId, ActivityType = ActivityType.Publish, PostId = post.Id }; using (var work = this.dbFactory.StartWork()) { Person person = await work.Person.SingleByIdAsync(userId); if (person == null || person.IsDelete || person.IsMute) { throw new Exception("你没有发帖权限"); } using (var trans = work.BeginTransaction()) { try { List <string> tags = work.Tag.RemoveDuplication(model.UseTags); foreach (var item in tags) { Tag tag = await work.Tag.GetByNameAsync(item); // 如果标签不存在,则重新创建 if (tag == null) { tag = new Tag { Id = GuidHelper.CreateSequential(), IsBest = false, IsSystem = false, Name = item.Trim() }; await work.Tag.InsertAsync(tag, trans); } // 记录帖子与标签之间的关联 PostTag postTag = new PostTag { Id = GuidHelper.CreateSequential(), PostId = post.Id, TagId = tag.Id }; await work.PostTag.InsertAsync(postTag, trans); } await work.Post.InsertAsync(post, trans); // 插入文章 await work.PostData.InsertAsync(postData, trans); // 插入文章内容 await work.Activity.InsertAsync(activity, trans); // 插入活动 if (post.PostType == PostType.Question) { await work.Connection.IncreaseAsync(nameof(PersonData), nameof(PersonData.AskNum), nameof(PersonData.PersonId), person.Id, trans); // 递增提问数 } else if (post.PostType == PostType.Article) { await work.Connection.IncreaseAsync(nameof(PersonData), nameof(PersonData.ArticleNum), nameof(PersonData.PersonId), person.Id, trans); // 递增发文数 } trans.Commit(); } catch (Exception) { trans.Rollback(); throw; } } } return(post); }