From 85c5faf90f9b4f904c36e3a47fa80994d6231a5d Mon Sep 17 00:00:00 2001 From: Alper Ebicoglu Date: Thu, 20 Sep 2018 17:49:02 +0300 Subject: [PATCH] Refactored. And added tree tag helper. --- .../Docs/Documents/ContentWithDetailsDto.cs | 50 +++++++++++++++ .../Docs/Documents/DocumentWithDetailsDto.cs | 23 ------- .../Docs/Documents/IDocumentAppService.cs | 6 +- .../Docs/DocsApplicationAutoMapperProfile.cs | 5 +- .../Volo/Docs/Documents/DocumentAppService.cs | 26 ++++---- .../Docs/Documents/GithubDocumentStore.cs | 64 +++++++++++++------ .../Volo/Docs/Documents/IDocumentStore.cs | 3 +- .../docs/src/Volo.Docs.Web/DocsWebConsts.cs | 9 +++ .../Helpers/TagHelpers/TreeTagHelper.cs | 49 ++++++++++++++ .../Pages/Documents/Index.cshtml | 9 ++- .../Pages/Documents/Index.cshtml.cs | 7 +- .../Pages/Documents/Project/Index.cshtml | 36 +++++++++-- .../Pages/Documents/Project/Index.cshtml.cs | 62 +++++++++++++----- .../Pages/Documents/Project/VersionInfo.cs | 18 ++++++ .../Pages/Documents/_ViewImports.cshtml | 3 +- 15 files changed, 287 insertions(+), 83 deletions(-) create mode 100644 modules/docs/src/Volo.Docs.Application.Contracts/Volo/Docs/Documents/ContentWithDetailsDto.cs delete mode 100644 modules/docs/src/Volo.Docs.Application.Contracts/Volo/Docs/Documents/DocumentWithDetailsDto.cs create mode 100644 modules/docs/src/Volo.Docs.Web/DocsWebConsts.cs create mode 100644 modules/docs/src/Volo.Docs.Web/Helpers/TagHelpers/TreeTagHelper.cs create mode 100644 modules/docs/src/Volo.Docs.Web/Pages/Documents/Project/VersionInfo.cs diff --git a/modules/docs/src/Volo.Docs.Application.Contracts/Volo/Docs/Documents/ContentWithDetailsDto.cs b/modules/docs/src/Volo.Docs.Application.Contracts/Volo/Docs/Documents/ContentWithDetailsDto.cs new file mode 100644 index 0000000000..a96715d089 --- /dev/null +++ b/modules/docs/src/Volo.Docs.Application.Contracts/Volo/Docs/Documents/ContentWithDetailsDto.cs @@ -0,0 +1,50 @@ +using System.Collections.Generic; +using Newtonsoft.Json; +using Volo.Docs.Projects; + +namespace Volo.Docs.Documents +{ + public class DocumentWithDetailsDto + { + public string Title { get; set; } + + public string Content { get; set; } + + public string Format { get; set; } + + public string EditLink { get; set; } + + public string RootUrl { get; set; } + + public string RawRootUrl { get; set; } + + public string Version { get; set; } + + public ProjectDto Project { get; set; } + } + + public class NavigationNode + { + [JsonProperty("text")] + public string Text { get; set; } + + [JsonProperty("path")] + public string Path { get; set; } + + [JsonProperty("items")] + public List Items { get; set; } + } + + public class NavigationWithDetailsDto : DocumentWithDetailsDto + { + [JsonProperty("items")] + public NavigationNode RootItem { get; set; } + + public void ConvertItems() + { + RootItem = string.IsNullOrWhiteSpace(Content) ? + new NavigationNode() : + JsonConvert.DeserializeObject(Content); + } + } +} \ No newline at end of file diff --git a/modules/docs/src/Volo.Docs.Application.Contracts/Volo/Docs/Documents/DocumentWithDetailsDto.cs b/modules/docs/src/Volo.Docs.Application.Contracts/Volo/Docs/Documents/DocumentWithDetailsDto.cs deleted file mode 100644 index 0087efc19b..0000000000 --- a/modules/docs/src/Volo.Docs.Application.Contracts/Volo/Docs/Documents/DocumentWithDetailsDto.cs +++ /dev/null @@ -1,23 +0,0 @@ -using Volo.Docs.Projects; - -namespace Volo.Docs.Documents -{ - public class DocumentWithDetailsDto - { - public string Title { get; set; } - - public string Content { get; set; } - - public string Format { get; set; } - - public string EditLink { get; set; } - - public string RootUrl { get; set; } - - public string RawRootUrl { get; set; } - - public string Version { get; set; } - - public ProjectDto Project { get; set; } - } -} \ No newline at end of file diff --git a/modules/docs/src/Volo.Docs.Application.Contracts/Volo/Docs/Documents/IDocumentAppService.cs b/modules/docs/src/Volo.Docs.Application.Contracts/Volo/Docs/Documents/IDocumentAppService.cs index 23c5869d8b..cac27efac6 100644 --- a/modules/docs/src/Volo.Docs.Application.Contracts/Volo/Docs/Documents/IDocumentAppService.cs +++ b/modules/docs/src/Volo.Docs.Application.Contracts/Volo/Docs/Documents/IDocumentAppService.cs @@ -6,9 +6,11 @@ namespace Volo.Docs.Documents { public interface IDocumentAppService : IApplicationService { - Task GetByNameAsync(string projectShortName, string documentName, string version); + Task GetByNameAsync(string projectShortName, string documentName, string version, + bool normalize); - Task GetNavigationDocumentAsync(string projectShortName, string version); + Task GetNavigationDocumentAsync(string projectShortName, string version, + bool normalize); Task> GetVersions(string projectShortName, string documentName); } diff --git a/modules/docs/src/Volo.Docs.Application/Volo/Docs/DocsApplicationAutoMapperProfile.cs b/modules/docs/src/Volo.Docs.Application/Volo/Docs/DocsApplicationAutoMapperProfile.cs index b15a538ccb..c3f193d29e 100644 --- a/modules/docs/src/Volo.Docs.Application/Volo/Docs/DocsApplicationAutoMapperProfile.cs +++ b/modules/docs/src/Volo.Docs.Application/Volo/Docs/DocsApplicationAutoMapperProfile.cs @@ -11,7 +11,10 @@ namespace Volo.Docs { CreateMap(); CreateMap() - .Ignore(x => x.Project); + .Ignore(x => x.Project); + + CreateMap() + .Ignore(x => x.RootItem); } } } \ No newline at end of file diff --git a/modules/docs/src/Volo.Docs.Application/Volo/Docs/Documents/DocumentAppService.cs b/modules/docs/src/Volo.Docs.Application/Volo/Docs/Documents/DocumentAppService.cs index d174404b47..15595ab811 100644 --- a/modules/docs/src/Volo.Docs.Application/Volo/Docs/Documents/DocumentAppService.cs +++ b/modules/docs/src/Volo.Docs.Application/Volo/Docs/Documents/DocumentAppService.cs @@ -26,25 +26,26 @@ namespace Volo.Docs.Documents _documentStoreFactory = documentStoreFactory; } - public async Task GetByNameAsync(string projectShortName, string documentName, string version) + public async Task GetByNameAsync(string projectShortName, string documentName, string version, bool normalize) { var project = await _projectRepository.FindByShortNameAsync(projectShortName); - return await GetDocument(project, documentName, version); + return await GetDocument(project, documentName, version, normalize); } - public async Task GetNavigationDocumentAsync(string projectShortName, string version) + public async Task GetNavigationDocumentAsync(string projectShortName, string version, bool normalize) { var project = await _projectRepository.FindByShortNameAsync(projectShortName); - return await GetDocument(project, project.NavigationDocumentName, version); + return ObjectMapper.Map( + await GetDocument(project, project.NavigationDocumentName, version, normalize)); } - private async Task GetDocument(Project project, string documentName, string version) + private async Task GetDocument(Project project, string documentName, string version, bool normalize) { if (project == null) { - throw new EntityNotFoundException($"Project Not Found!"); + throw new EntityNotFoundException("Project Not Found!"); } if (string.IsNullOrWhiteSpace(documentName)) @@ -52,16 +53,19 @@ namespace Volo.Docs.Documents documentName = project.DefaultDocumentName; } - var documentStore = _documentStoreFactory.Create(project); + IDocumentStore documentStore = _documentStoreFactory.Create(project); var document = await documentStore.FindDocumentByNameAsync(project, documentName, version); var dto = ObjectMapper.Map(document); dto.Project = ObjectMapper.Map(project); - dto.Content = NormalizeLinks(dto.Content, project.ShortName, version); - dto.Content = NormalizeImages(dto.Content, dto.RawRootUrl); - + if (normalize) + { + dto.Content = NormalizeLinks(dto.Content, project.ShortName, version); + dto.Content = NormalizeImages(dto.Content, dto.RawRootUrl); + } + return dto; } @@ -99,7 +103,7 @@ namespace Volo.Docs.Documents private async Task SetVersionsToCache(string projectShortName, List versions) { - var options = new DistributedCacheEntryOptions(){SlidingExpiration = TimeSpan.FromDays(1)}; + var options = new DistributedCacheEntryOptions() { SlidingExpiration = TimeSpan.FromDays(1) }; await _distributedCache.SetAsync(projectShortName, versions, options); } diff --git a/modules/docs/src/Volo.Docs.Application/Volo/Docs/Documents/GithubDocumentStore.cs b/modules/docs/src/Volo.Docs.Application/Volo/Docs/Documents/GithubDocumentStore.cs index e9b520c191..53a8fbb861 100644 --- a/modules/docs/src/Volo.Docs.Application/Volo/Docs/Documents/GithubDocumentStore.cs +++ b/modules/docs/src/Volo.Docs.Application/Volo/Docs/Documents/GithubDocumentStore.cs @@ -3,48 +3,70 @@ using System.Collections.Generic; using System.Linq; using System.Net; using System.Threading.Tasks; +using Microsoft.Extensions.Logging; using Octokit; -using Volo.Abp.DependencyInjection; +using Volo.Abp.Domain.Services; using ProductHeaderValue = Octokit.ProductHeaderValue; using Project = Volo.Docs.Projects.Project; namespace Volo.Docs.Documents { - public class GithubDocumentStore : IDocumentStore, ITransientDependency + public class GithubDocumentStore : DomainService, IDocumentStore { - public const string Type = "Github"; //TODO: Conver to "github" + public const string Type = "Github"; //TODO: Convert to "github" public async Task FindDocumentByNameAsync(Project project, string documentName, string version) { - var rootUrl = project.ExtraProperties["GithubRootUrl"].ToString().Replace("_version_/", version + "/").Replace("www.",""); + var rootUrl = project.ExtraProperties["GithubRootUrl"].ToString().Replace("_version_/", version + "/").Replace("www.", ""); var token = project.ExtraProperties["GithubAccessToken"]?.ToString(); var rawRootUrl = rootUrl.Replace("github.com", token + "raw.githubusercontent.com").Replace("/tree/", "/"); - var rawUrl = rawRootUrl + $"{documentName}.md"; - var editLink = rootUrl.Replace("/tree/", "/blob/") + $"{documentName}.md"; + var rawUrl = rawRootUrl + documentName; + var editLink = rootUrl.Replace("/tree/", "/blob/") + documentName; - using (var webClient = new WebClient()) + var content = DownloadWebContent(documentName, rawUrl); + + return await Task.FromResult(new Document { - string content; + Title = documentName, + Content = content, + EditLink = editLink, + RootUrl = rootUrl, + RawRootUrl = rawRootUrl, + Format = project.Format + }); + } + private string DownloadWebContent(string documentName, string rawUrl) + { + using (var webClient = new WebClient()) + { try { - content = webClient.DownloadString(rawUrl); + return webClient.DownloadString(rawUrl); } - catch (Exception) + catch (WebException ex) { - content = "The Document doesn't exist."; - } + Logger.LogError(ex, ex.Message); + + if (ex.Status == WebExceptionStatus.ProtocolError) + { + if (ex.Response != null && ex.Response is HttpWebResponse response) + { + if (response.StatusCode == HttpStatusCode.NotFound) + { + return $"The document {documentName} not found in this version!"; + } + } + } - return new Document + return "An error occured while getting the document " + documentName; + } + catch (Exception ex) { - Title = documentName, - Content = content, - EditLink = editLink, - RootUrl = rootUrl, - RawRootUrl = rawRootUrl, - Format = project.Format - }; + Logger.LogError(ex, ex.Message); + return "An error occured while getting the document " + documentName; + } } } @@ -53,7 +75,7 @@ namespace Volo.Docs.Documents var gitHubClient = new GitHubClient(new ProductHeaderValue("AbpWebSite")); var url = project.ExtraProperties["GithubRootUrl"].ToString(); var releases = await gitHubClient.Repository.Release.GetAll(GetGithubOrganizationNameFromUrl(url), GetGithubRepositoryNameFromUrl(url)); - + return releases.OrderByDescending(r => r.PublishedAt).Select(r => r.TagName).ToList(); } diff --git a/modules/docs/src/Volo.Docs.Application/Volo/Docs/Documents/IDocumentStore.cs b/modules/docs/src/Volo.Docs.Application/Volo/Docs/Documents/IDocumentStore.cs index 1442fc8db0..4bc3993ac5 100644 --- a/modules/docs/src/Volo.Docs.Application/Volo/Docs/Documents/IDocumentStore.cs +++ b/modules/docs/src/Volo.Docs.Application/Volo/Docs/Documents/IDocumentStore.cs @@ -1,10 +1,11 @@ using System.Collections.Generic; using System.Threading.Tasks; +using Volo.Abp.Domain.Services; using Volo.Docs.Projects; namespace Volo.Docs.Documents { - public interface IDocumentStore + public interface IDocumentStore : IDomainService { Task FindDocumentByNameAsync(Project project, string documentName, string version); diff --git a/modules/docs/src/Volo.Docs.Web/DocsWebConsts.cs b/modules/docs/src/Volo.Docs.Web/DocsWebConsts.cs new file mode 100644 index 0000000000..8c34f15d5c --- /dev/null +++ b/modules/docs/src/Volo.Docs.Web/DocsWebConsts.cs @@ -0,0 +1,9 @@ +using Volo.Docs.Pages.Documents.Project; + +namespace Volo.Docs +{ + public class DocsWebConsts + { + public static VersionInfo DefaultVersion = new VersionInfo("Unstable", "master"); //can be *latest* as well. + } +} \ No newline at end of file diff --git a/modules/docs/src/Volo.Docs.Web/Helpers/TagHelpers/TreeTagHelper.cs b/modules/docs/src/Volo.Docs.Web/Helpers/TagHelpers/TreeTagHelper.cs new file mode 100644 index 0000000000..b339726698 --- /dev/null +++ b/modules/docs/src/Volo.Docs.Web/Helpers/TagHelpers/TreeTagHelper.cs @@ -0,0 +1,49 @@ +using System.Linq; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Razor.TagHelpers; +using Volo.Docs.Documents; + +namespace Volo.Docs.Helpers.TagHelpers +{ + [HtmlTargetElement("ul", Attributes = "navigation-items")] + public class TreeTagHelper : TagHelper + { + //private readonly IHttpContextAccessor _contextAccessor; + private const string LiItemTemplate = @"
  • {1}{2}
  • "; + private const string UlItemTemplate = @""; + + //public TreeTagHelper(IHttpContextAccessor contextAccessor) + //{ + // _contextAccessor = contextAccessor; + //} + + [HtmlAttributeName("navigation-items")] + public NavigationNode RootItem { get; set; } + + public override void Process(TagHelperContext context, TagHelperOutput output) + { + var rootUl = string.Format(UlItemTemplate, GetNodeHtml(RootItem)); + + output.Content.AppendHtml(rootUl); + //output.Attributes.SetAttribute("item-count", test); + } + + private static string GetNodeHtml(NavigationNode node) + { + var childContent = ""; + + if (node.Items != null && node.Items.Any()) + { + node.Items.ForEach(innerNode => + { + childContent += string.Format(UlItemTemplate, GetNodeHtml(innerNode)); + }); + } + + var li = string.Format(LiItemTemplate, string.IsNullOrWhiteSpace(node.Path) ? "#" : node.Path, node.Text, childContent); + + return li; + } + + } +} diff --git a/modules/docs/src/Volo.Docs.Web/Pages/Documents/Index.cshtml b/modules/docs/src/Volo.Docs.Web/Pages/Documents/Index.cshtml index 41097038c0..b2d88b2dcc 100644 --- a/modules/docs/src/Volo.Docs.Web/Pages/Documents/Index.cshtml +++ b/modules/docs/src/Volo.Docs.Web/Pages/Documents/Index.cshtml @@ -1,4 +1,5 @@ @page +@using Volo.Docs @using Volo.Docs.Pages.Documents @model IndexModel @{ @@ -10,7 +11,13 @@ } diff --git a/modules/docs/src/Volo.Docs.Web/Pages/Documents/Index.cshtml.cs b/modules/docs/src/Volo.Docs.Web/Pages/Documents/Index.cshtml.cs index 9b68051be9..86aead43ee 100644 --- a/modules/docs/src/Volo.Docs.Web/Pages/Documents/Index.cshtml.cs +++ b/modules/docs/src/Volo.Docs.Web/Pages/Documents/Index.cshtml.cs @@ -24,7 +24,12 @@ namespace Volo.Docs.Pages.Documents if (result.Items.Count == 1) { var project = result.Items[0]; - return RedirectToPage("./Project/Index", new { projectName = project.ShortName, version = "latest", documentName = project.DefaultDocumentName }); + return RedirectToPage("./Project/Index", new + { + projectName = project.ShortName, + version = DocsWebConsts.DefaultVersion.Version, + documentName = project.DefaultDocumentName + }); } Projects = result.Items; diff --git a/modules/docs/src/Volo.Docs.Web/Pages/Documents/Project/Index.cshtml b/modules/docs/src/Volo.Docs.Web/Pages/Documents/Project/Index.cshtml index 092dd8b037..e41ac64fa7 100644 --- a/modules/docs/src/Volo.Docs.Web/Pages/Documents/Project/Index.cshtml +++ b/modules/docs/src/Volo.Docs.Web/Pages/Documents/Project/Index.cshtml @@ -1,4 +1,5 @@ @page +@using Volo.Docs.Helpers.TagHelpers; @model Volo.Docs.Pages.Documents.Project.IndexModel @{ ViewBag.FluidLayout = true; @@ -13,7 +14,6 @@ - } @@ -57,7 +57,7 @@ { Text = v.DisplayText, Value = "/documents/" + Model.ProjectName + "/" + v.Version + "/" + Model.DocumentName, - Selected = (v.Version == Model.Version) + Selected = v.IsSelected }), new { @class = "form-control flat" })