Esempio n. 1
0
        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);
        }
Esempio n. 2
0
        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());
        }
Esempio n. 3
0
        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)));
        }
Esempio n. 4
0
        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));
        }
Esempio n. 5
0
        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());
        }
Esempio n. 6
0
        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));
        }
Esempio n. 7
0
        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)));
        }
Esempio n. 8
0
        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)));
        }
Esempio n. 9
0
        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));
        }
Esempio n. 10
0
        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)));
        }
Esempio n. 11
0
        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));
        }
Esempio n. 12
0
        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);
        }
Esempio n. 13
0
        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));
        }
Esempio n. 14
0
        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));
        }
Esempio n. 15
0
        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());
        }
Esempio n. 16
0
        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)));
        }
Esempio n. 17
0
        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());
        }
Esempio n. 18
0
        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));
        }
Esempio n. 19
0
        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);
        }
Esempio n. 20
0
        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());
        }