public async Task <QComment> GetById(string id) { var commentId = XUtils.ParseId(id); if (commentId == null) { return(null); } var query = from p in Context.Comments.Where(r => r.Id == commentId) join q in Context.Users on p.SenderId equals q.Id select new { comment = p, user = q, myAtt = Context.Attitudes.Where(o => o.CommentId == p.Id && o.SenderId == AuthStore.UserId).FirstOrDefault() }; var data = await query.FirstOrDefaultAsync(); var user = QUser.NormalView(data.user); var commentQ = QComment.NormalView(data.comment, user, data.myAtt?.Agree); return(commentQ); }
public async Task <IActionResult> JoinTopic([FromBody] JoinTopicModel model) { var topicId = XUtils.ParseId(model.TopicId); if (topicId == null) { return(new ApiError(MyErrorCode.IdNotFound, "Id parse error").Wrap()); } // Check topic exist var topic = await Context.Topics.FirstOrDefaultAsync(p => p.Id == topicId); if (topic == null) { return(new ApiError(MyErrorCode.IdNotFound, "Topic id not found").Wrap()); } // Check if already in topic var member = await Context.TopicMembers .FirstOrDefaultAsync(p => p.TopicId == topicId.Value && p.UserId == AuthStore.UserId.Value); if (member != null) { return(new ApiError(MyErrorCode.UniqueConstraintConflict, "你已经加入过了").Wrap()); } // join topic member = new TopicMember(topicId.Value, AuthStore.UserId.Value, MemberRole.Normal); await Context.AddAsync(member); await Context.GoAsync(); return(Ok()); }
public async Task <IActionResult> SendReply([FromBody] SendReplyModel model) { // post exist var postId = XUtils.ParseId(model.PostId); var post = await Context.Posts.FirstOrDefaultAsync(p => p.Id == postId); if (post == null) { return(new ApiError(MyErrorCode.IdNotFound, "Post id not found").Wrap()); } // user is a member of post.topic var member = await Context.TopicMembers.FirstOrDefaultAsync(p => p.UserId == AuthStore.UserId && p.TopicId == post.TopicId); if (member == null) { return(new ApiError(MyErrorCode.NotAMember, "You are not a member of the topic").Wrap()); } // send reply var reply = new Reply(AuthStore.UserId.Value, post.Id, model.Text); await Context.AddAsync(reply); await Context.GoAsync(); return(Ok(new IdResponse(reply.Id))); }
public async Task <IActionResult> GetReplies(string postId, int page) { const int pageSize = 20; // post exist var pid = XUtils.ParseId(postId); var post = await Context.Posts.FirstOrDefaultAsync(p => p.Id == pid); if (post == null) { return(new ApiError(MyErrorCode.IdNotFound, "Post id not found").Wrap()); } // get var query = (from p in Context.Replies.Where(p => p.PostId == pid) join q in Context.Users on p.SenderId equals q.Id select new { reply = p, user = q }) .OrderBy(p => p.reply.CreatedAt).ThenBy(p => p.reply.Id); var data = await query.Skip(pageSize *page).Take(pageSize).ToListAsync(); var repliesV = data.Select(p => QReply.NormalView(p.reply, p.user)); return(Ok(repliesV)); }
public async Task <IActionResult> Report([FromBody] ReportModel model) { var commentId = XUtils.ParseId(model.CommentId); if (commentId == null) { return(new ApiError(MyErrorCode.IdNotFound, "CommentId parse error").Wrap()); } var report = await Context.Reports.FirstOrDefaultAsync(p => p.CommentId == commentId && p.SenderId == AuthStore.UserId); if (report != null) { return(new ApiError(MyErrorCode.UniqueConstraintConflict, "你已经举报过了").Wrap()); } var comment = await Context.Comments.FirstOrDefaultAsync(p => p.Id == commentId); if (comment == null) { return(new ApiError(MyErrorCode.IdNotFound, "评论id不存在").Wrap()); } // send report report = new Report((Guid)AuthStore.UserId, (Guid)commentId, model.Title, model.Text); await Context.AddAsync(report); await Context.GoAsync(); return(Ok()); }
public async Task <IActionResult> GetPostById(string id) { var postId = XUtils.ParseId(id); if (postId == null) { return(new ApiError(MyErrorCode.IdNotFound, "Id parse error").Wrap()); } var query = from p in Context.Posts where p.Id == postId join q in Context.Users on p.SenderId equals q.Id select new { post = p, user = q, replyCount = Context.Replies.Count(z => z.PostId == p.Id), lastReply = Context.Replies.Where(z => z.PostId == p.Id) .DefaultIfEmpty().Max(p => p == null ? -2 : p.CreatedAt) }; var data = await query.FirstOrDefaultAsync(); var qpost = QPost.NormalView(data.post, QUser.NormalView(data.user), data.replyCount, data.lastReply); return(Ok(qpost)); }
public async Task <IActionResult> CreateTopic([FromBody] CreateTopicModel model) { // check related work Guid?workId; if (model.RelatedWork == null) { workId = null; } else { workId = XUtils.ParseId(model.RelatedWork); var work = await Context.Works.FirstOrDefaultAsync(p => p.Id == workId); if (work == null) { return(new ApiError("ID_NOT_FOUND", "作品id无效").Wrap()); } } // create topic and set member=1 var topic = new Topic(model.IsGroup, model.Name, model.Description, workId, AuthStore.UserId.Value); topic.SetMemberCount(1); await Context.AddAsync(topic); await Context.GoAsync(); return(Ok(new IdResponse(topic.Id))); }
public async Task <IActionResult> SendPost([FromBody] SendPostModel model) { var topicId = XUtils.ParseId(model.TopicId); if (topicId == null) { return(new ApiError(MyErrorCode.IdNotFound, "TopicId parse error").Wrap()); } // Topic exist and is group var topic = await Context.Topics.FirstOrDefaultAsync(p => p.Id == topicId); if (topic?.IsGroup != true) { return(new ApiError(MyErrorCode.TypeMismatch, "Topic not exist or is not group").Wrap()); } // should be a member of the topic var member = await Context.TopicMembers.FirstOrDefaultAsync(p => p.TopicId == topicId && p.UserId == AuthStore.UserId.Value); if (member == null) { return(new ApiError(MyErrorCode.PermissionDenied, "你不是成员").Wrap()); } // send post var post = new Post(AuthStore.UserId.Value, topicId.Value, model.Text, model.Title); await Context.AddAsync(post); await Context.GoAsync(); return(Ok(new IdResponse(post.Id))); }
public async Task <IActionResult> GetUnhandledRequests(string topicId, int page, bool newest) { const int pageSize = 20; var tid = XUtils.ParseId(topicId); var query = from p in Context.AdminRequests where p.TopicId == tid && p.Status == RequestStatus.Unhandled join q in Context.Users on p.SenderId equals q.Id select new { request = p, user = q }; if (newest) { query = query.OrderByDescending(p => p.request.CreatedAt); } else { query = query.OrderBy(p => p.request.CreatedAt); } query = query.Skip(page * pageSize).Take(pageSize); var requests = await query.ToListAsync(); var data = requests.Select(p => QAdminRequest.NormalView(p.request, QUser.NormalView(p.user))).ToList(); return(Ok(data)); }
public async Task <IActionResult> CreateComment([FromBody] CreateCommentModel model) { var workId = XUtils.ParseId(model.WorkId); var work = await Context.Works.FirstOrDefaultAsync(p => p.Id == workId); if (work == null) { return(new ApiError(MyErrorCode.IdNotFound, "不存在对应id的作品").Wrap()); } var comment = await Context.Comments.FirstOrDefaultAsync(p => p.WorkId == workId && p.SenderId == AuthStore.UserId); if (comment != null) { return(new ApiError(MyErrorCode.UniqueConstraintConflict, "你已经评价过此作品").Wrap()); } comment = new Comment(AuthStore.UserId.Value, workId.Value, model.Title, model.Text, model.Rating); await Context.AddAsync(comment); await Context.GoAsync(); return(Ok(new IdResponse(comment.Id))); }
public async Task <IActionResult> GetTopicProfile(string topicId) { var id = XUtils.ParseId(topicId); var topic = await Context.Topics.FirstOrDefaultAsync(p => p.Id == id); var qtopic = QTopic.NormalView(topic); return(Ok(qtopic)); }
async Task SendAdminRequestAndHandle() { var a = await ClientSesion.RandomInstance(); var b = await ClientSesion.RandomInstance(); // a create group var topicId = (await a.Api <TopicApi>().CreateTopicAsync(new CreateTopicModel(true, "ssss", "DDDDD", null))).Id; // b join group await b.Api <TopicApi>().JoinTopicAsync(new JoinTopicModel(topicId.ToString())); // b send request var requestId = (await b.Api <GroupManageApi>().SendAdminRequestAsync(new SendAdminRequestModel(topicId.ToString(), "hello!!!"))).Id; // check var request = await a.Api <GroupManageApi>().GetRequestByIdAsync(requestId.ToString()); Assert.Equal(requestId, request.Id); Assert.Equal(b.UserId, request.SenderId); Assert.Equal(topicId, request.TopicId); var requests = await a.Api <GroupManageApi>().GetUnhandledRequestsAsync(topicId.ToString(), 0, true); Assert.Single(requests); // accept await a.Api <GroupManageApi>().HandleRequestAsync(new HandleRequestModel(requestId.ToString(), true)); // check request in two ways var q = await a.Api <GroupManageApi>().GetRequestByIdAsyncWithHttpInfo(requestId.ToString()); requests = await a.Api <GroupManageApi>().GetUnhandledRequestsAsync(topicId.ToString(), 0, true); Assert.Empty(requests); request = await a.Api <GroupManageApi>().GetRequestByIdAsync(requestId.ToString()); Assert.Equal(RequestStatus.Accepted, request.Status); // check membership var membership = await Context.TopicMembers .Where(p => p.TopicId == XUtils.ParseId(topicId.ToString()) && p.UserId == XUtils.ParseId(b.UserId.ToString())) .FirstOrDefaultAsync(); Assert.Equal(Leopard.Domain.TopicMemberAG.MemberRole.Admin, membership.Role); }
public async Task <IActionResult> GetByWork(string workId, OrderByType order, int page) { if (!Enum.IsDefined(typeof(OrderByType), order)) { return(new ApiError(MyErrorCode.ModelInvalid, "Invalid 'order'").Wrap()); } page = Math.Max(page, 0); const int pageSize = 20; var wid = XUtils.ParseId(workId); if (wid == null) { return(new ApiError(MyErrorCode.ModelInvalid, "wordId parse error").Wrap()); } var query = from p in Context.Comments where p.WorkId == wid join q in Context.Users on p.SenderId equals q.Id join o in Context.Attitudes.Where(z => z.SenderId == AuthStore.UserId) on p.Id equals o.CommentId into xx from x in xx.DefaultIfEmpty() select new { comment = p, user = q, myatt = x }; if (order == OrderByType.Hottest) { query = query.OrderByDescending(p => p.comment.AgreeCount); } else { query = query.OrderByDescending(p => p.comment.CreatedAt); } var ll = await query.Take(10).ToListAsync(); query = query.Skip(page * pageSize).Take(pageSize); var data = await query.ToListAsync(); var commentsQ = data.Select(p => QComment.NormalView(p.comment, QUser.NormalView(p.user), p.myatt?.Agree)).ToList(); return(Ok(commentsQ)); }
public async Task <IActionResult> GetRequestById(string id) { var requestId = XUtils.ParseId(id); var query = from p in Context.AdminRequests where p.Id == requestId join q in Context.Users on p.SenderId equals q.Id select new { request = p, user = q }; var data = await query.FirstOrDefaultAsync(); var requestV = QAdminRequest.NormalView(data.request, QUser.NormalView(data.user)); return(Ok(requestV)); }
public async Task <IActionResult> DoAdmin([FromBody] DoAdminModel model) { // post exist var postId = XUtils.ParseId(model.PostId); var post = await Context.Posts.FirstOrDefaultAsync(p => p.Id == postId); if (post == null) { return(new ApiError(MyErrorCode.IdNotFound, "Post id not found").Wrap()); } // user >= post.Topic.Admin var member = await Context.TopicMembers.FirstOrDefaultAsync(p => p.TopicId == post.TopicId && p.UserId == AuthStore.UserId); if (member == null) { return(new ApiError(MyErrorCode.NotAMember, "You are not a member").Wrap()); } if ((int)member.Role < (int)MemberRole.Admin) { return(new ApiError(MyErrorCode.PermissionDenied, "You should be at least admin").Wrap()); } // ok if (model.Action == AdminAction.IsPinned) { post.SetPinned(model.Status); } if (model.Action == AdminAction.IsEssence) { post.SetEssence(model.Status); } if (model.Action == AdminAction.Remove) { if (model.Status) { Context.Remove(post); } } await Context.GoAsync(); return(Ok()); }
public async Task <IActionResult> SendAdminRequest([FromBody] SendAdminRequestModel model) { var topicId = XUtils.ParseId(model.TopicId); // Topic is group topic var topic = await Context.Topics.FirstOrDefaultAsync(p => p.Id == topicId); if (topic == null) { return(new ApiError(MyErrorCode.IdNotFound, "Topic id not found").Wrap()); } if (topic.IsGroup == false) { return(new ApiError(MyErrorCode.TypeMismatch, "This topic is not group").Wrap()); } // should be normal member var member = await Context.TopicMembers.FirstOrDefaultAsync(p => p.TopicId == topicId && p.UserId == AuthStore.UserId); if (member?.Role != MemberRole.Normal) { return(new ApiError(MyErrorCode.RoleMismatch, "You are not normal row of the topic").Wrap()); } // unhandled request exist? var previous = await Context.AdminRequests.FirstOrDefaultAsync( p => p.TopicId == topicId && p.SenderId == AuthStore.UserId && p.Status == RequestStatus.Unhandled); if (previous != null) { return(new ApiError(MyErrorCode.ExistUnhandledReuqest, "你已经发送过请求,但未被处理").Wrap()); } // send request var request = new AdminRequest(topicId.Value, AuthStore.UserId.Value, model.Text); await Context.AddAsync(request); await Context.GoAsync(); return(Ok(new IdResponse(request.Id))); }
public async Task <IActionResult> HandleRequest([FromBody] HandleRequestModel model) { // request should be unhandled var requestId = XUtils.ParseId(model.RequestId); var request = await Context.AdminRequests.FirstOrDefaultAsync(p => p.Id == requestId); if (request == null) { return(new ApiError(MyErrorCode.IdNotFound, "Request id not found").Wrap()); } if (request.Status != RequestStatus.Unhandled) { return(new ApiError(MyErrorCode.TypeMismatch, "Request is not unhandled").Wrap()); } // should have super role var member = await Context.TopicMembers .FirstOrDefaultAsync(p => p.UserId == AuthStore.UserId && p.TopicId == request.TopicId); if (member.Role != MemberRole.Super) { return(new ApiError(MyErrorCode.PermissionDenied, "You are not super administrator of the group").Wrap()); } // handle request.Handle(model.Accept); if (model.Accept) { var membership2 = await Context.TopicMembers .FirstOrDefaultAsync(p => p.UserId == request.SenderId && p.TopicId == request.TopicId); membership2.SetRole(MemberRole.Admin); } await Context.GoAsync(); return(Ok()); }
public async Task <IActionResult> GetPosts(string topicId, int page) { const int pageSize = 20; page = Math.Max(0, page); var tid = XUtils.ParseId(topicId); if (tid == null) { return(new ApiError(MyErrorCode.IdNotFound, "topicId parse error").Wrap()); } var query = from p in Context.Posts where p.TopicId == tid join q in Context.Users on p.SenderId equals q.Id select new { post = p, user = q, replyCount = Context.Replies.Count(z => z.PostId == p.Id), lastReply = Context.Replies.Where(z => z.PostId == p.Id) .DefaultIfEmpty().Max(p => p == null ? -2 : p.CreatedAt) }; query = query.OrderByDescending(p => p.post.IsPinned) .ThenByDescending(p => p.lastReply) .Skip(page * pageSize) .Take(pageSize); var data = await query.ToListAsync(); var qposts = data.Select( p => QPost.NormalView(p.post, QUser.NormalView(p.user), p.replyCount, p.lastReply)).ToList(); return(Ok(qposts)); }
public async Task InvokeAsync(HttpContext context, RequestDelegate next) { string token = null; // If not provided AccessToken in header, go for cookie if (context.Request.Headers.TryGetValue("AccessToken", out StringValues sv)) { token = sv.ToArray()?.FirstOrDefault(); } token = token ?? context.Request.Cookies["AccessToken"]; if (token == null) { goto failure; } Claims claims; try { claims = JWT.Decode <Claims>(token, SecretStore.SecretKey); } catch (JoseException) { goto failure; } // Model validation (due to schema migration) if (claims.UserId == null || claims.Expire == null || claims.SecurityVersion == null) { goto failure; } var userId = XUtils.ParseId(claims.UserId); if (userId == null) { goto failure; } User user = null; // Test expire if (claims.Expire < DateTimeOffset.UtcNow.ToUnixTimeMilliseconds()) { // Test security version user = await Context.Users.FirstOrDefaultAsync(p => p.Id == userId); if (user.SecurityVersion == claims.SecurityVersion) { // Issue a new token var newClaims = new Claims { UserId = user.Id.ToString(), SecurityVersion = user.SecurityVersion, Expire = DateTimeOffset.UtcNow.AddMinutes(5).ToUnixTimeMilliseconds() }; var newToken = JWT.Encode(claims, SecretStore.SecretKey, JwsAlgorithm.HS256); var options = new CookieOptions { MaxAge = TimeSpan.FromDays(120), }; context.Response.Cookies.Append("AccessToken", token, options); } else { goto failure; } } // Success Store.UserId = userId; // TODO: Not this filter's responsibility. Do this in another filter Store.User = user ?? await Context.Users.FirstOrDefaultAsync(p => p.Id == userId); // Important! await next(context); return; failure: // Let Store.UserId remain null and delete AccessToken in cookie context.Response.Cookies.Delete("AccessToken"); await next(context); }
public async Task <IActionResult> ExpressAttitude(string commentId, bool?agree) { var cid = XUtils.ParseId(commentId); if (cid == null) { return(new ApiError(MyErrorCode.IdNotFound, "评论的id不存在(解析错误)").Wrap()); } var comment = await Context.Comments.FirstOrDefaultAsync(p => p.Id == cid); if (comment == null) { return(new ApiError(MyErrorCode.IdNotFound, "评论的id不存在").Wrap()); } var attitude = await Context.Attitudes .FirstOrDefaultAsync(p => p.SenderId == AuthStore.UserId && p.CommentId == cid); // Modify or update attitude if (attitude == null) // No attitude before { if (agree != null) // if agree==null do nothing { attitude = new Attitude((Guid)AuthStore.UserId, (Guid)cid, agree.Value); if (agree == true) { comment.SetAgreeCount(comment.AgreeCount + 1); } else if (agree == false) { comment.SetDisagreeCount(comment.DisagreeCount + 1); } await Context.AddAsync(attitude); } } else // Already exist attitude { if (attitude.Agree == agree) { return(Ok()); // Unchanged } if (agree == true) { comment.SetAgreeCount(comment.AgreeCount + 1); comment.SetDisagreeCount(comment.DisagreeCount - 1); attitude.SetAgree(true); } else if (agree == false) { comment.SetAgreeCount(comment.AgreeCount - 1); comment.SetDisagreeCount(comment.DisagreeCount + 1); attitude.SetAgree(false); } else { // Remove attitude Context.Remove(attitude); if (attitude.Agree) { comment.SetAgreeCount(comment.AgreeCount - 1); } else { comment.SetDisagreeCount(comment.DisagreeCount - 1); } } } Console.WriteLine($"AAAAA {comment.AgreeCount} {comment.DisagreeCount}"); await Context.GoAsync(); return(Ok()); }