public Task <BlogPostListing> GetPublishedAsync(string tag, int?offset, int?maxResults, CancellationToken cancellationToken)
        {
            _logger.LogInformation($"Processing files from filesystem (rootPath = {_settings.BlogFileSystemRootPath}) ...");

            var blogPosts = new List <BlogPost>();

            _logger.LogInformation("Reading blog.json ...");

            var content = File.ReadAllText(Path.Combine(_settings.BlogFileSystemRootPath, "Blog.json"));

            _logger.LogInformation($"Blog.json content was {content}");

            var blogPostList = JsonConvert.DeserializeObject <List <BlogJsonItem> >(content);

            _logger.LogInformation($"Enumerating through {blogPostList.Count} posts downloading the file contents ...");

            var posts = blogPostList.AsQueryable();

            if (offset.HasValue)
            {
                posts = posts.Skip(offset.Value);
            }

            if (maxResults.HasValue)
            {
                posts = posts.Take(maxResults.Value);
            }

            foreach (var blogPost in posts)
            {
                var postFile = File.ReadAllText(Path.Combine(_settings.BlogFileSystemRootPath, blogPost.Folder.TrimStart('/')));

                _logger.LogDebug($"Reading content for {blogPost.Folder} ...");

                var post = new BlogPost
                {
                    Id            = blogPost.Id,
                    Title         = blogPost.Title,
                    PublishDate   = DateTime.ParseExact(blogPost.PublishDate, "yyyy-MM-dd", new CultureInfo("en-GB")),
                    HtmlText      = _renderer.Render(postFile, blogPost.Folder),
                    HtmlShortText = _renderer.Render(_blogPostSummaryHelper.GetSummaryText(postFile), blogPost.Folder),
                    Route         = blogPost.Route,
                    Featured      = blogPost.Featured,
                    Published     = blogPost.Status.ToLower() == "published"
                };

                post.BlogPostTags = blogPost.Tags.Split('|').Select(x => new BlogPostTag(post, new Tag(x))).ToList();

                blogPosts.Add(post);
            }

            return(Task.FromResult(new BlogPostListing
            {
                Posts = blogPosts,
                TotalPosts = blogPostList.Count
            }));
        }
        public async Task <IEnumerable <BlogPost> > GetAllAsync(CursorContainer cursor, CancellationToken cancellationToken)
        {
            List <DropboxFileModel> dropboxFiles = null;

            if (cursor == null)
            {
                _logger.LogInformation("Processing files from Dropbox ...");
            }
            else
            {
                _logger.LogInformation("Processing updated files from Dropbox ...");

                dropboxFiles = await _dropboxHelper.GetFilesAsync("", cursor, cancellationToken);

                _logger.LogInformation("Files dropbox thinks has been updated:");

                foreach (var updatedFile in dropboxFiles)
                {
                    _logger.LogDebug($"  Name: \"{updatedFile.Name}\", PathLower: \"{updatedFile.PathLower}\"");
                }
            }

            var blogPosts = new List <BlogPost>();

            _logger.LogInformation("Reading blog.json ...");

            var blogMetaDataFile = await _dropboxHelper.GetFileContentAsync("/Blog.json", cancellationToken);

            var blogJson = Encoding.UTF8.GetString(blogMetaDataFile);

            _logger.LogTrace($"Blog.json content was {blogJson}");

            var blogPostList = JsonConvert.DeserializeObject <List <BlogJsonItem> >(blogJson);

            var blogPostsToUpdate = cursor == null
                ? blogPostList
                : blogPostList.Where(x => dropboxFiles.Any(y => y.PathLower == $"/blog{x.Folder}/post.md".ToLower())).ToList();

            _logger.LogInformation($"Enumerating through {blogPostsToUpdate.Count} posts downloading the file contents ...");

            foreach (var blogPost in blogPostsToUpdate)
            {
                var imagePath = $"{blogPost.Folder}/images/";

                //(todo) Refactor so that in the case of an incremental sync, I'm only getting images that have changed since the cursor.

                var images = (await _dropboxHelper.GetFilesAsync(imagePath, cancellationToken)).Where(ImageFileFilter)
                             .Select(x => $"{imagePath}{x.Name}")
                             .Select(i => new BlogImageData
                {
                    FileName      = Path.GetFileName(i),
                    PostFolder    = blogPost.Folder,
                    ImageDataTask = _dropboxHelper.GetFileContentAsync(i, cancellationToken),
                }).ToList();

                _logger.LogInformation($"Reading content for {blogPost.Folder} ...");

                var postFile = await _dropboxHelper.GetFileContentAsync($"{blogPost.Folder}/post.md", cancellationToken);

                var postFileText = Encoding.UTF8.GetString(postFile);

                var post = new BlogPost
                {
                    Id            = blogPost.Id,
                    Title         = blogPost.Title,
                    PublishDate   = string.IsNullOrWhiteSpace(blogPost.PublishDate) ? null : (DateTime?)DateTime.ParseExact(blogPost.PublishDate, "yyyy-MM-dd", new CultureInfo("en-GB")),
                    HtmlText      = _renderer.Render(postFileText, blogPost.Folder),
                    HtmlShortText = _renderer.Render(_blogPostSummaryHelper.GetSummaryText(postFileText), blogPost.Folder),
                    Route         = blogPost.Route,
                    Featured      = blogPost.Featured,
                    Published     = blogPost.Status.ToLower() == "published",
                    ImageData     = images
                };

                post.BlogPostTags = blogPost.Tags.Split(new[] { '|' }, StringSplitOptions.RemoveEmptyEntries).Select(x => new BlogPostTag(post, new Tag(x))).ToList();

                blogPosts.Add(post);
            }

            return(blogPosts);
        }