コード例 #1
0
        public async Task <IActionResult> Get([FromQuery] PostQueryFilter filter,
                                              [FromQuery] PostQuerySort sort,
                                              [FromQuery] PostQueryProjection projection,
                                              [FromQuery] PostQueryPaging paging,
                                              [FromQuery] PostQueryOptions options)
        {
            var validationResult = _service.ValidateGetPosts(
                User, filter, sort, projection, paging, options);

            if (!validationResult.Valid)
            {
                return(BadRequest(validationResult.Result));
            }
            var result = await _service.QueryPostDynamic(
                projection, options, filter, sort, paging);

            if (options.single_only)
            {
                if (result == null)
                {
                    return(NotFound(new AppResultBuilder().NotFound()));
                }
                return(Ok(new AppResultBuilder().Success(result.SingleResult)));
            }
            return(Ok(new AppResultBuilder().Success(result)));
        }
コード例 #2
0
 /// <summary>
 /// Refreshes the post content from the server.
 /// </summary>
 /// <param name="posts">The posts to be refreshed.</param>
 /// <param name="options">The options used to fetch the post.</param>
 /// <param name="cancellationToken">The token used to cancel the operation.</param>
 /// <remarks>
 /// This method will not fetch replies for the <paramref name="posts"/>. <see cref="Post.Replies"/> will remain unchanged after the invocation.
 /// </remarks>
 /// <seealso cref="Post.RefreshAsync(PostQueryOptions,CancellationToken)"/>
 public static Task RefreshAsync(this IEnumerable <Post> posts, PostQueryOptions options, CancellationToken cancellationToken)
 {
     if (posts == null)
     {
         throw new ArgumentNullException(nameof(posts));
     }
     return(RequestHelper.RefreshPostsAsync(posts, options, cancellationToken));
 }
コード例 #3
0
        public static async Task RefreshPostsAsync(IEnumerable <Post> posts,
                                                   PostQueryOptions options, CancellationToken cancellationToken)
        {
            Debug.Assert(posts != null);
            // Fetch comment content.
            // You can even fetch posts from different sites.
            foreach (var sitePosts in posts.GroupBy(p => p.Site))
            {
                var site       = sitePosts.Key;
                var titleLimit = site.AccountInfo.HasRight(UserRights.ApiHighLimits)
                    ? 500
                    : 50;
                foreach (var partition in sitePosts.Partition(titleLimit))
                {
                    using (site.BeginActionScope(partition, options))
                    {
                        var postsNeedFetchingId = partition.Where(p => p.Id == 0).ToList();
                        if (postsNeedFetchingId.Count > 0)
                        {
                            site.Logger.LogDebug("Fetching page ID for {Count} comments.", postsNeedFetchingId.Count);
                        }
                        // Fetch last revisions to determine content and last editor
                        var pages            = partition.Select(p => new WikiPage(site, p.Id)).ToList();
                        var lastRevisionTask = pages.RefreshAsync(postLastRevisionQueryProvider, cancellationToken);
                        // Fetch the first revisions, when needed, to determine author.
                        Dictionary <int, Revision> firstRevisionDict = null;
                        if (partition.Count == 1 ||
                            (options & PostQueryOptions.ExactAuthoringInformation) == PostQueryOptions.ExactAuthoringInformation)
                        {
                            // We can only fetch for 1 page at a time, with rvdir = "newer"
                            firstRevisionDict = new Dictionary <int, Revision>();
                            foreach (var post in partition)
                            {
                                var generator = new RevisionsGenerator(site, post.Id)
                                {
                                    TimeAscending    = true,
                                    PaginationSize   = 1,
                                    PropertyProvider = postRevisionWithContentProvider
                                };
                                var rev = await generator.EnumItemsAsync().FirstAsync(cancellationToken);

                                firstRevisionDict[post.Id] = rev;
                            }
                        }
                        await lastRevisionTask;
                        var   lastRevisions = pages.ToDictionary(p => p.Id, p => p.LastRevision);
                        foreach (var post in partition)
                        {
                            var      lastRev  = lastRevisions[post.Id];
                            Revision firstRev = null;
                            firstRevisionDict?.TryGetValue(post.Id, out firstRev);
                            post.SetRevisions(firstRev, lastRev);
                        }
                    }
                }
            }
        }
コード例 #4
0
ファイル: PostService.cs プロジェクト: war-man/SmartKiosk
 public ValidationResult ValidateGetPosts(
     ClaimsPrincipal principal,
     PostQueryFilter filter,
     PostQuerySort sort,
     PostQueryProjection projection,
     PostQueryPaging paging,
     PostQueryOptions options)
 {
     return(ValidationResult.Pass());
 }
コード例 #5
0
ファイル: PostService.cs プロジェクト: war-man/SmartKiosk
        public QueryResult <IDictionary <string, object> > GetPostDynamic(
            IEnumerable <PostQueryRow> rows, PostQueryProjection projection,
            PostQueryOptions options, int?totalCount = null)
        {
            var list = new List <IDictionary <string, object> >();

            foreach (var o in rows)
            {
                var obj = GetPostDynamic(o, projection, options);
                list.Add(obj);
            }
            var resp = new QueryResult <IDictionary <string, object> >();

            resp.Results = list;
            if (options.count_total)
            {
                resp.TotalCount = totalCount;
            }
            return(resp);
        }
コード例 #6
0
        public static async IAsyncEnumerable <Post> EnumArticleCommentsAsync(Board board, PostQueryOptions options,
                                                                             [EnumeratorCancellation] CancellationToken cancellationToken = default)
        {
            IList <Post> PostsFromJsonOutline(JObject commentList)
            {
                return(commentList.Properties().Select(p =>
                {
                    var post = new Post(board.Site, board.Page, Convert.ToInt32(p.Name));
                    var level2 = p.Value["level2"];
                    if (level2 != null && level2.HasValues)
                    {
                        post.Replies = new ReadOnlyCollection <Post>(((JObject)level2).Properties().Select(p2 =>
                                                                                                           new Post(board.Site, board.Page, Convert.ToInt32(p2.Name))).ToList());
                    }
                    return post;
                }).ToList());
            }

            IEnumerable <Post> PostsAndDescendants(IEnumerable <Post> posts)
            {
                foreach (var p in posts)
                {
                    yield return(p);

                    if (p.Replies.Count > 0)
                    {
                        foreach (var p2 in p.Replies)
                        {
                            yield return(p2);

                            // Wikia only supports level-2 comments for now.
                            Debug.Assert(p2.Replies.Count == 0);
                        }
                    }
                }
            }

            using (board.Site.BeginActionScope(board))
            {
                // Refresh to get the page id.
                if (!board.Page.HasId)
                {
                    await board.RefreshAsync(cancellationToken);
                }
                if (!board.Exists)
                {
                    yield break;
                }
                var pagesCount = 1;
                for (int page = 1; page <= pagesCount; page++)
                {
                    var jroot = await board.Site.InvokeNirvanaAsync(
                        new WikiaQueryRequestMessage(new
                    {
                        format = "json",
                        controller = "ArticleComments",
                        method = "Content",
                        articleId = board.Page.Id,
                        page = page
                    }), WikiaJsonResponseParser.Default, cancellationToken);

                    // Build comment structure.
                    var jcomments = jroot["commentListRaw"];
                    if (jcomments != null && jcomments.HasValues)
                    {
                        var comments = PostsFromJsonOutline((JObject)jcomments);
                        pagesCount = (int)jroot["pagesCount"];
                        await RefreshPostsAsync(PostsAndDescendants(comments), options, cancellationToken);

                        using (ExecutionContextStash.Capture())
                            foreach (var c in comments)
                            {
                                yield return(c);
                            }
                    }
                }
            }
        }
コード例 #7
0
 /// <summary>
 /// Asynchronously enumerates all the comments on the specified page.
 /// </summary>
 /// <param name="options">The options used to fetch the post.</param>
 public IAsyncEnumerable <Post> EnumPostsAsync(PostQueryOptions options)
 {
     return(RequestHelper.EnumArticleCommentsAsync(this, options));
 }
コード例 #8
0
ファイル: PostService.cs プロジェクト: war-man/SmartKiosk
        public IDictionary <string, object> GetPostDynamic(
            PostQueryRow row, PostQueryProjection projection,
            PostQueryOptions options)
        {
            var obj = new Dictionary <string, object>();

            foreach (var f in projection.GetFieldsArr())
            {
                switch (f)
                {
                case PostQueryProjection.INFO:
                {
                    var entity  = row.Post;
                    var content = row.Content;
                    obj["id"]        = entity.Id;
                    obj["owner_id"]  = entity.OwnerId;
                    obj["type"]      = entity.Type;
                    obj["archived"]  = entity.Archived;
                    obj["image_url"] = entity.ImageUrl;
                    var createdTime = entity.CreatedTime
                                      .ToTimeZone(options.time_zone, options.culture, content?.Lang);
                    var createdTimeStr = createdTime.ToString(options.date_format, options.culture, content?.Lang);
                    obj["created_time"] = new
                    {
                        display = createdTimeStr,
                        iso     = $"{createdTime.ToUniversalTime():s}Z"
                    };
                    var visibleTime = entity.VisibleTime?
                                      .ToTimeZone(options.time_zone, options.culture, content?.Lang);
                    var visibleTimeStr = visibleTime?.ToString(options.date_format, options.culture, content?.Lang);
                    if (visibleTimeStr != null)
                    {
                        obj["visible_time"] = new
                        {
                            display = visibleTimeStr,
                            iso     = $"{visibleTime?.ToUniversalTime():s}Z"
                        }
                    }
                    ;
                }
                break;

                case PostQueryProjection.CONTENT:
                {
                    var entity = row.Content;
                    if (entity != null)
                    {
                        obj["content_id"]  = entity.Id;
                        obj["lang"]        = entity.Lang;
                        obj["description"] = entity.Description;
                        obj["title"]       = entity.Title;
                    }
                }
                break;

                case PostQueryProjection.CONTENT_CONTENT:
                {
                    var entity = row.Content;
                    if (entity != null)
                    {
                        obj["content"] = entity.Content;
                    }
                }
                break;

                case PostQueryProjection.OWNER:
                {
                    var entity = row.Owner;
                    obj["owner"] = new
                    {
                        id   = entity.Id,
                        code = entity.Code,
                        name = entity.Name,
                    };
                }
                break;
                }
            }
            return(obj);
        }
コード例 #9
0
ファイル: PostService.cs プロジェクト: war-man/SmartKiosk
        public async Task <QueryResult <PostQueryRow> > QueryPost(
            PostQueryFilter filter         = null,
            PostQuerySort sort             = null,
            PostQueryProjection projection = null,
            PostQueryPaging paging         = null,
            PostQueryOptions options       = null)
        {
            var conn     = context.Database.GetDbConnection();
            var openConn = conn.OpenAsync();
            var query    = PostQuery.CreateDynamicSql();

            #region General
            if (filter != null)
            {
                query = query.SqlFilter(filter);
            }
            if (projection != null)
            {
                query = query.SqlJoin(projection, filter);
            }
            DynamicSql countQuery = null; int?totalCount = null; Task <int> countTask = null;
            if (options != null && options.count_total)
            {
                countQuery = query.SqlCount("*");
            }
            if (projection != null)
            {
                query = query.SqlProjectFields(projection);
            }
            #endregion
            await openConn;
            if (options != null && !options.single_only)
            {
                #region List query
                if (sort != null)
                {
                    query = query.SqlSort(sort);
                }
                if (paging != null && (!options.load_all || !PostQueryOptions.IsLoadAllAllowed))
                {
                    query = query.SqlSelectPage(paging.page, paging.limit);
                }
                #endregion
                #region Count query
                if (options.count_total)
                {
                    countTask = conn.ExecuteScalarAsync <int>(
                        sql: countQuery.PreparedForm,
                        param: countQuery.DynamicParameters);
                }
                #endregion
            }
            var queryResult = await conn.QueryAsync(
                sql : query.PreparedForm,
                types : query.GetTypesArr(),
                map : (objs) => ProcessMultiResults(query, objs),
                splitOn : string.Join(',', query.GetSplitOns()),
                param : query.DynamicParameters);

            if (options != null && options.single_only)
            {
                var single = queryResult.FirstOrDefault();
                return(new QueryResult <PostQueryRow>
                {
                    SingleResult = single
                });
            }
            if (options != null && options.count_total)
            {
                totalCount = await countTask;
            }
            return(new QueryResult <PostQueryRow>
            {
                Results = queryResult,
                TotalCount = totalCount
            });
        }
コード例 #10
0
ファイル: Post.cs プロジェクト: aquilla12/WikiClientLibrary
 /// <summary>
 /// Refreshes the post content from the server.
 /// </summary>
 /// <param name="options">The options used to fetch the post.</param>
 /// <param name="cancellationToken">The token used to cancel the operation.</param>
 /// <remarks>
 /// This method will not fetch replies. <see cref="Replies"/> will remain unchanged after the invocation.
 /// </remarks>
 /// <seealso cref="DiscussionsExtensions.RefreshAsync(IEnumerable{Post},PostQueryOptions,CancellationToken)"/>
 public Task RefreshAsync(PostQueryOptions options, CancellationToken cancellationToken)
 {
     return(RequestHelper.RefreshPostsAsync(new[] { this }, options, cancellationToken));
 }
コード例 #11
0
ファイル: Post.cs プロジェクト: aquilla12/WikiClientLibrary
 /// <inheritdoc cref="RefreshAsync(PostQueryOptions,CancellationToken)"/>
 /// <seealso cref="DiscussionsExtensions.RefreshAsync(IEnumerable{Post},PostQueryOptions)"/>
 public Task RefreshAsync(PostQueryOptions options)
 {
     return(RefreshAsync(options, CancellationToken.None));
 }
コード例 #12
0
 /// <inheritdoc cref="RefreshAsync(IEnumerable{Post},PostQueryOptions,CancellationToken)"/>
 /// <seealso cref="Post.RefreshAsync(PostQueryOptions)"/>
 public static Task RefreshAsync(this IEnumerable <Post> posts, PostQueryOptions options)
 {
     return(RefreshAsync(posts, options, new CancellationToken()));
 }