Browse Source

Merge branch 'dev' of https://github.com/abpframework/abp into 2294-Dynamic-CSharp-Api-Clients-net-standard20

pull/2867/head
Necati Meral 7 years ago
parent
commit
1702ea6156
  1. 1
      abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/en.json
  2. 4
      docs/en/Modules/Docs.md
  3. 4
      docs/zh-Hans/Modules/Docs.md
  4. 8
      framework/src/Volo.Abp.Auditing/Volo/Abp/Auditing/AbpAuditingOptions.cs
  5. 70
      framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/Auditing/AuditTestController.cs
  6. 130
      framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/Auditing/AuditTestController_Tests.cs
  7. 25
      modules/blogging/src/Volo.Blogging.Web/Pages/Blogs/BloggingPage.cs
  8. 8
      modules/docs/src/Volo.Docs.Web/DocsWebModule.cs
  9. 436
      modules/docs/src/Volo.Docs.Web/Pages/Documents/Project/Index.cshtml
  10. 17
      modules/docs/src/Volo.Docs.Web/Pages/Documents/Project/Index.cshtml.cs
  11. 53
      modules/docs/src/Volo.Docs.Web/Pages/Documents/Shared/DocumentNotFoundComponent/Default.cshtml
  12. 15
      modules/docs/src/Volo.Docs.Web/Pages/Documents/Shared/DocumentNotFoundComponent/DocumentNotFoundPageModel.cs
  13. 26
      modules/docs/src/Volo.Docs.Web/Pages/Documents/Shared/DocumentNotFoundComponent/DocumentNotFoundViewComponent.cs
  14. 1
      modules/docs/src/Volo.Docs.Web/Volo.Docs.Web.csproj
  15. 18
      npm/packs/jquery/src/abp.jquery.js
  16. 1
      samples/MicroserviceDemo/applications/AuthServer.Host/AuthServer.Host.csproj
  17. 4
      samples/MicroserviceDemo/applications/AuthServer.Host/AuthServerHostModule.cs

1
abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/en.json

@ -6,6 +6,7 @@
"Volo.AbpIo.Commercial:010003": "You are not owner of this organization!",
"OrganizationNotFoundMessage": "No organization found!",
"DeveloperCount": "Developer count",
"QuestionCount": "Question count",
"Owners": "Owners",
"AddMember": "Add member",
"AddOwner": "Add owner",

4
docs/en/Modules/Docs.md

@ -328,7 +328,7 @@ You can use [ABP Framework](https://github.com/abpframework/abp/) GitHub documen
For `SQL` databases, you can use the below `T-SQL` command to insert the specified sample into your `DocsProjects` table:
```mssql
INSERT [dbo].[DocsProjects] ([Id], [Name], [ShortName], [Format], [DefaultDocumentName], [NavigationDocumentName], [MinimumVersion], [DocumentStoreType], [ExtraProperties], [MainWebsiteUrl], [LatestVersionBranchName]) VALUES (N'12f21123-e08e-4f15-bedb-ae0b2d939658', N'ABP framework (GitHub)', N'abp', N'md', N'Index', N'docs-nav.json', NULL, N'GitHub', N'{"GitHubRootUrl":"https://github.com/abpframework/abp/tree/{version}/docs","GitHubAccessToken":"***"}', N'/', N'master')
INSERT [dbo].[DocsProjects] ([Id], [Name], [ShortName], [Format], [DefaultDocumentName], [NavigationDocumentName], [MinimumVersion], [DocumentStoreType], [ExtraProperties], [MainWebsiteUrl], [LatestVersionBranchName], [ParametersDocumentName]) VALUES (N'12f21123-e08e-4f15-bedb-ae0b2d939658', N'ABP framework (GitHub)', N'abp', N'md', N'Index', N'docs-nav.json', NULL, N'GitHub', N'{"GitHubRootUrl":"https://github.com/abpframework/abp/tree/{version}/docs","GitHubAccessToken":"***"}', N'/', N'master', N'')
```
Be aware that `GitHubAccessToken` is masked. It's a private token and you must get your own token and replace the `***` string.
@ -366,7 +366,7 @@ You can use [ABP Framework](https://github.com/abpframework/abp/) GitHub documen
For `SQL` databases, you can use the below `T-SQL` command to insert the specified sample into your `DocsProjects` table:
```mssql
INSERT [dbo].[DocsProjects] ([Id], [Name], [ShortName], [Format], [DefaultDocumentName], [NavigationDocumentName], [MinimumVersion], [DocumentStoreType], [ExtraProperties], [MainWebsiteUrl], [LatestVersionBranchName]) VALUES (N'12f21123-e08e-4f15-bedb-ae0b2d939659', N'ABP framework (FileSystem)', N'abp', N'md', N'Index', N'docs-nav.json', NULL, N'FileSystem', N'{"Path":"C:\\Github\\abp\\docs"}', N'/', NULL)
INSERT [dbo].[DocsProjects] ([Id], [Name], [ShortName], [Format], [DefaultDocumentName], [NavigationDocumentName], [MinimumVersion], [DocumentStoreType], [ExtraProperties], [MainWebsiteUrl], [LatestVersionBranchName], [ParametersDocumentName]) VALUES (N'12f21123-e08e-4f15-bedb-ae0b2d939659', N'ABP framework (FileSystem)', N'abp', N'md', N'Index', N'docs-nav.json', NULL, N'FileSystem', N'{"Path":"C:\\Github\\abp\\docs"}', N'/', NULL, N'')
```
Add one of the sample projects above and run the application. In the menu you will see `Documents` link, click the menu link to open the documents page.

4
docs/zh-Hans/Modules/Docs.md

@ -321,7 +321,7 @@ There are no projects yet!
对于 `SQL` 数据库,你可以使用下面的 `T-SQL` 命令将指定的示例插入到 `DocsProjects` 表中:
```mssql
INSERT [dbo].[DocsProjects] ([Id], [Name], [ShortName], [Format], [DefaultDocumentName], [NavigationDocumentName], [MinimumVersion], [DocumentStoreType], [ExtraProperties], [MainWebsiteUrl], [LatestVersionBranchName]) VALUES (N'12f21123-e08e-4f15-bedb-ae0b2d939658', N'ABP framework (GitHub)', N'abp', N'md', N'Index', N'docs-nav.json', NULL, N'GitHub', N'{"GitHubRootUrl":"https://github.com/abpframework/abp/tree/{version}/docs/zh-Hans/","GitHubAccessToken":"***"}', N'/', N'master')
INSERT [dbo].[DocsProjects] ([Id], [Name], [ShortName], [Format], [DefaultDocumentName], [NavigationDocumentName], [MinimumVersion], [DocumentStoreType], [ExtraProperties], [MainWebsiteUrl], [LatestVersionBranchName], [ParametersDocumentName]) VALUES (N'12f21123-e08e-4f15-bedb-ae0b2d939658', N'ABP framework (GitHub)', N'abp', N'md', N'Index', N'docs-nav.json', NULL, N'GitHub', N'{"GitHubRootUrl":"https://github.com/abpframework/abp/tree/{version}/docs","GitHubAccessToken":"***"}', N'/', N'master', N'')
```
请注意,`GitHubAccessToken` 被屏蔽了.它是一个私人令牌,你必须获得自己的令牌并替换 `***` 字符串.
@ -359,7 +359,7 @@ INSERT [dbo].[DocsProjects] ([Id], [Name], [ShortName], [Format], [DefaultDocume
对于 `SQL` 数据库,你可以使用下面的 `T-SQL` 命令将指定的示例插入到 `DocsProjects` 表中:
```mssql
INSERT [dbo].[DocsProjects] ([Id], [Name], [ShortName], [Format], [DefaultDocumentName], [NavigationDocumentName], [MinimumVersion], [DocumentStoreType], [ExtraProperties], [MainWebsiteUrl], [LatestVersionBranchName]) VALUES (N'12f21123-e08e-4f15-bedb-ae0b2d939659', N'ABP framework (FileSystem)', N'abp', N'md', N'Index', N'docs-nav.json', NULL, N'FileSystem', N'{"Path":"C:\\Github\\abp\\docs"}', N'/', NULL)
INSERT [dbo].[DocsProjects] ([Id], [Name], [ShortName], [Format], [DefaultDocumentName], [NavigationDocumentName], [MinimumVersion], [DocumentStoreType], [ExtraProperties], [MainWebsiteUrl], [LatestVersionBranchName], [ParametersDocumentName]) VALUES (N'12f21123-e08e-4f15-bedb-ae0b2d939659', N'ABP framework (FileSystem)', N'abp', N'md', N'Index', N'docs-nav.json', NULL, N'FileSystem', N'{"Path":"C:\\Github\\abp\\docs"}', N'/', NULL, N'')
```
添加上面的一个示例项目后运行该应用程序. 在菜单中你会看到`文档` 链接,点击菜单链接打开文档页面.

8
framework/src/Volo.Abp.Auditing/Volo/Abp/Auditing/AbpAuditingOptions.cs

@ -30,10 +30,10 @@ namespace Volo.Abp.Auditing
/// Default: true.
/// </summary>
public bool IsEnabledForAnonymousUsers { get; set; }
/// <summary>
/// Audit log on exceptions.
/// Default: true.
/// <summary>
/// Audit log on exceptions.
/// Default: true.
/// </summary>
public bool AlwaysLogOnException { get; set; }

70
framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/Auditing/AuditTestController.cs

@ -1,35 +1,35 @@
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Options;
using Volo.Abp.Auditing;
namespace Volo.Abp.AspNetCore.Mvc.Auditing
{
[Route("api/audit-test")]
[Audited]
public class AuditTestController : AbpController
{
private readonly AbpAuditingOptions _options;
public AuditTestController(IOptions<AbpAuditingOptions> options)
{
_options = options.Value;
}
[Route("audit-success")]
public IActionResult AuditSuccessForGetRequests()
{
return Ok();
}
[Route("audit-fail")]
public IActionResult AuditFailForGetRequests()
{
throw new UserFriendlyException("Exception occurred!");
}
[Route("audit-fail-object")]
public object AuditFailForGetRequestsReturningObject()
{
throw new UserFriendlyException("Exception occurred!");
}
}
}
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Options;
using Volo.Abp.Auditing;
namespace Volo.Abp.AspNetCore.Mvc.Auditing
{
[Route("api/audit-test")]
[Audited]
public class AuditTestController : AbpController
{
private readonly AbpAuditingOptions _options;
public AuditTestController(IOptions<AbpAuditingOptions> options)
{
_options = options.Value;
}
[Route("audit-success")]
public IActionResult AuditSuccessForGetRequests()
{
return Ok();
}
[Route("audit-fail")]
public IActionResult AuditFailForGetRequests()
{
throw new UserFriendlyException("Exception occurred!");
}
[Route("audit-fail-object")]
public object AuditFailForGetRequestsReturningObject()
{
throw new UserFriendlyException("Exception occurred!");
}
}
}

130
framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/Auditing/AuditTestController_Tests.cs

@ -1,65 +1,65 @@
using System;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.DependencyInjection.Extensions;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Options;
using NSubstitute;
using System.Threading.Tasks;
using Volo.Abp.Auditing;
using Xunit;
namespace Volo.Abp.AspNetCore.Mvc.Auditing
{
public class AuditTestController_Tests : AspNetCoreMvcTestBase
{
private readonly AbpAuditingOptions _options;
private IAuditingStore _auditingStore;
public AuditTestController_Tests()
{
_options = ServiceProvider.GetRequiredService<IOptions<AbpAuditingOptions>>().Value;
_auditingStore = ServiceProvider.GetRequiredService<IAuditingStore>();
}
protected override void ConfigureServices(HostBuilderContext context, IServiceCollection services)
{
_auditingStore = Substitute.For<IAuditingStore>();
services.Replace(ServiceDescriptor.Singleton(_auditingStore));
base.ConfigureServices(context, services);
}
[Fact]
public async Task Should_Trigger_Middleware_And_AuditLog_Success_For_GetRequests()
{
_options.IsEnabledForGetRequests = true;
_options.AlwaysLogOnException = false;
await GetResponseAsync("api/audit-test/audit-success");
await _auditingStore.Received().SaveAsync(Arg.Any<AuditLogInfo>());
}
[Fact]
public async Task Should_Trigger_Middleware_And_AuditLog_Exception_Always()
{
_options.IsEnabled = true;
_options.AlwaysLogOnException = true;
try
{
await GetResponseAsync("api/audit-test/audit-fail", System.Net.HttpStatusCode.Forbidden);
}
catch { }
await _auditingStore.Received().SaveAsync(Arg.Any<AuditLogInfo>());
}
[Fact]
public async Task Should_Trigger_Middleware_And_AuditLog_Exception_When_Returns_Object()
{
_options.IsEnabled = true;
_options.AlwaysLogOnException = true;
await GetResponseAsync("api/audit-test/audit-fail-object", System.Net.HttpStatusCode.Forbidden);
await _auditingStore.Received().SaveAsync(Arg.Any<AuditLogInfo>());
}
}
}
using System;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.DependencyInjection.Extensions;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Options;
using NSubstitute;
using System.Threading.Tasks;
using Volo.Abp.Auditing;
using Xunit;
namespace Volo.Abp.AspNetCore.Mvc.Auditing
{
public class AuditTestController_Tests : AspNetCoreMvcTestBase
{
private readonly AbpAuditingOptions _options;
private IAuditingStore _auditingStore;
public AuditTestController_Tests()
{
_options = ServiceProvider.GetRequiredService<IOptions<AbpAuditingOptions>>().Value;
_auditingStore = ServiceProvider.GetRequiredService<IAuditingStore>();
}
protected override void ConfigureServices(HostBuilderContext context, IServiceCollection services)
{
_auditingStore = Substitute.For<IAuditingStore>();
services.Replace(ServiceDescriptor.Singleton(_auditingStore));
base.ConfigureServices(context, services);
}
[Fact]
public async Task Should_Trigger_Middleware_And_AuditLog_Success_For_GetRequests()
{
_options.IsEnabledForGetRequests = true;
_options.AlwaysLogOnException = false;
await GetResponseAsync("api/audit-test/audit-success");
await _auditingStore.Received().SaveAsync(Arg.Any<AuditLogInfo>());
}
[Fact]
public async Task Should_Trigger_Middleware_And_AuditLog_Exception_Always()
{
_options.IsEnabled = true;
_options.AlwaysLogOnException = true;
try
{
await GetResponseAsync("api/audit-test/audit-fail", System.Net.HttpStatusCode.Forbidden);
}
catch { }
await _auditingStore.Received().SaveAsync(Arg.Any<AuditLogInfo>());
}
[Fact]
public async Task Should_Trigger_Middleware_And_AuditLog_Exception_When_Returns_Object()
{
_options.IsEnabled = true;
_options.AlwaysLogOnException = true;
await GetResponseAsync("api/audit-test/audit-fail-object", System.Net.HttpStatusCode.Forbidden);
await _auditingStore.Received().SaveAsync(Arg.Any<AuditLogInfo>());
}
}
}

25
modules/blogging/src/Volo.Blogging.Web/Pages/Blogs/BloggingPage.cs

@ -1,5 +1,7 @@
using System;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using CommonMark;
using Microsoft.AspNetCore.Html;
using Microsoft.AspNetCore.Mvc.Localization;
@ -30,30 +32,27 @@ namespace Volo.Blogging.Pages.Blog
public string GetShortContent(string content) //TODO: This should be moved to its own place!
{
var openingTag = "<p>";
var closingTag = "</p>";
var html = RenderMarkdownToString(content);
if (string.IsNullOrWhiteSpace(html))
var plainText = Regex.Replace(html, "/<[^>]*>/g", "");
if (string.IsNullOrWhiteSpace(plainText))
{
return "";
}
var splittedHtml = html.Split(closingTag);
if (splittedHtml.Length < 1)
var firsParag = plainText.Split(Environment.NewLine).FirstOrDefault(s => !string.IsNullOrWhiteSpace(s));
if (firsParag == null)
{
return "";
return plainText;
}
var firstHtmlPart = splittedHtml[0];
var paragraphStartIndex = firstHtmlPart.IndexOf(openingTag, StringComparison.Ordinal) + openingTag.Length;
if (firstHtmlPart.Length - paragraphStartIndex <= MaxShortContentLength)
if (firsParag.Length <= MaxShortContentLength)
{
return firstHtmlPart.Substring(paragraphStartIndex);
return firsParag;
}
return firstHtmlPart.Substring(paragraphStartIndex, MaxShortContentLength) + "...";
return firsParag.Substring(0, MaxShortContentLength) + "...";
}
public IHtmlContent RenderMarkdownToHtml(string content)

8
modules/docs/src/Volo.Docs.Web/DocsWebModule.cs

@ -5,7 +5,9 @@ using Microsoft.Extensions.Options;
using Volo.Abp.AspNetCore.Mvc.Localization;
using Volo.Abp.AspNetCore.Mvc.UI.Bootstrap;
using Volo.Abp.AspNetCore.Mvc.UI.Bundling;
using Volo.Abp.AspNetCore.Mvc.UI.Packages;
using Volo.Abp.AspNetCore.Mvc.UI.Packages.Prismjs;
using Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared;
using Volo.Abp.AutoMapper;
using Volo.Abp.Modularity;
using Volo.Abp.VirtualFileSystem;
@ -18,7 +20,11 @@ namespace Volo.Docs
{
[DependsOn(
typeof(DocsHttpApiModule),
typeof(AbpAspNetCoreMvcUiBootstrapModule)
typeof(AbpAutoMapperModule),
typeof(AbpAspNetCoreMvcUiBootstrapModule),
typeof(AbpAspNetCoreMvcUiThemeSharedModule),
typeof(AbpAspNetCoreMvcUiPackagesModule),
typeof(AbpAspNetCoreMvcUiBundlingModule)
)]
public class DocsWebModule : AbpModule
{

436
modules/docs/src/Volo.Docs.Web/Pages/Documents/Project/Index.cshtml

@ -5,6 +5,7 @@
@using Volo.Abp.AspNetCore.Mvc.UI.Packages.Clipboard
@using Volo.Abp.AspNetCore.Mvc.UI.Packages.MalihuCustomScrollbar
@using Volo.Abp.AspNetCore.Mvc.UI.Packages.Popper
@using Volo.Docs.Pages.Documents.Shared.DocumentNotFoundComponent
@using Volo.Abp.AspNetCore.Mvc.UI.Packages.Prismjs
@using Volo.Abp.AspNetCore.Mvc.UI.Theming
@using Volo.Docs
@ -39,269 +40,284 @@
<abp-script src="/Pages/Documents/Project/index.js" />
</abp-script-bundle>
}
<div class="docs-page" data-spy="scroll" data-target="#docs-sticky-index">
<div class="row justify-content-end">
<div class="col-md-3 docs-sidebar dark-sidebar">
<div class="docs-sidebar-wrapper">
<div class="docs-top">
<nav class="navbar navbar-logo">
@if (!Model.Project.Name.IsNullOrWhiteSpace())
{
<a class="navbar-brand w-100" href="@Model.CreateVersionLink(Model.LatestVersionInfo, Model.GetSpecificVersionOrLatest())">
<span id="ProjectName">@Model.Project.Name</span><br>
<strong class="display-block">
@L["Documents"]
</strong>
</a>
}
@if (Model.DocumentFound)
{
<div class="docs-page" data-spy="scroll" data-target="#docs-sticky-index">
<div class="row justify-content-end">
<div class="col-md-3 docs-sidebar dark-sidebar">
<div class="docs-sidebar-wrapper">
<div class="docs-top">
<nav class="navbar navbar-logo">
@if (!Model.Project.Name.IsNullOrWhiteSpace())
{
<a class="navbar-brand w-100" href="@Model.CreateVersionLink(Model.LatestVersionInfo, Model.GetSpecificVersionOrLatest())">
<span id="ProjectName">@Model.Project.Name</span><br>
<strong class="display-block">
@L["Documents"]
</strong>
</a>
}
@if (!Model.Document.Project.MainWebsiteUrl.IsNullOrWhiteSpace())
{
<a href="@Model.Document.Project.MainWebsiteUrl" class="go-back-site" id="GoToMainWebSite">
<i class="fa fa-chevron-left"></i>
@L["BackToWebsite"]
</a>
}
@if (!Model.Document.Project.MainWebsiteUrl.IsNullOrWhiteSpace())
{
<a href="@Model.Document.Project.MainWebsiteUrl" class="go-back-site" id="GoToMainWebSite">
<i class="fa fa-chevron-left"></i>
@L["BackToWebsite"]
</a>
}
<div class="for-mobile">
<div class="navbar-light">
<button type="button" class="open-dmenu navbar-toggler" aria-label="Close">
<span class="navbar-toggler-icon"></span>
</button>
<div class="for-mobile">
<div class="navbar-light">
<button type="button" class="open-dmenu navbar-toggler" aria-label="Close">
<span class="navbar-toggler-icon"></span>
</button>
</div>
</div>
</div>
</nav>
</div>
</nav>
</div>
<div class="docs-tree-list">
<div class="docs-tree-list">
@if (Model.ShowProjectsCombobox && Model.ProjectSelectItems.Count > 1)
{
<div class="docs-version">
<div class="version-select">
<div class="input-group">
<div class="input-group-prepend">
<label class="input-group-text">
<i class="fa fa-folder-open" aria-hidden="true" data-toggle="tooltip" title="@L["Project"]"></i>
</label>
</div>
@if (Model.ShowProjectsCombobox && Model.ProjectSelectItems.Count > 1)
{
<div class="docs-version">
<div class="version-select">
<div class="input-group">
<div class="input-group-prepend">
<label class="input-group-text">
<i class="fa fa-folder-open" aria-hidden="true" data-toggle="tooltip" title="@L["Project"]"></i>
</label>
</div>
<select asp-items="Model.ProjectSelectItems" class="form-control" onchange="window.location.pathname = this.value"></select>
<select asp-items="Model.ProjectSelectItems" class="form-control" onchange="window.location.pathname = this.value"></select>
</div>
</div>
</div>
</div>
}
}
<div class="row">
@if (Model.VersionSelectItems.Any())
{
<div class="col @(Model.LanguageSelectListItems.Count > 1?"pr-0":"")">
<div class="docs-version @(Model.LanguageSelectListItems.Count > 1?"pr-1":"")">
<div class="version-select">
<div class="input-group">
<div class="input-group-prepend">
<label class="input-group-text">
<i class="fa fa-check-square-o" aria-hidden="true" data-toggle="tooltip" title="@L["Version"]"></i>
</label>
</div>
<div class="row">
@if (Model.VersionSelectItems.Any())
{
<div class="col @(Model.LanguageSelectListItems.Count > 1?"pr-0":"")">
<div class="docs-version @(Model.LanguageSelectListItems.Count > 1?"pr-1":"")">
<div class="version-select">
<div class="input-group">
<div class="input-group-prepend">
<label class="input-group-text">
<i class="fa fa-check-square-o" aria-hidden="true" data-toggle="tooltip" title="@L["Version"]"></i>
</label>
</div>
<select asp-items="Model.VersionSelectItems" class="form-control" onchange="if (this.value) { window.location.replace(this.value) }"></select>
<select asp-items="Model.VersionSelectItems" class="form-control" onchange="if (this.value) { window.location.replace(this.value) }"></select>
</div>
</div>
</div>
</div>
</div>
}
}
@if (Model.LanguageSelectListItems.Count > 1)
{
<div class="col @(Model.VersionSelectItems.Any()?"pl-0":"")">
<div class="docs-version docs-language @(Model.VersionSelectItems.Any()?"pl-1":"")">
<div class="version-select">
<div class="input-group">
<div class="input-group-prepend">
<label class="input-group-text">
<i class="fa fa-globe" aria-hidden="true" data-toggle="tooltip" title="@L["Language"]"></i>
</label>
@if (Model.LanguageSelectListItems.Count > 1)
{
<div class="col @(Model.VersionSelectItems.Any()?"pl-0":"")">
<div class="docs-version docs-language @(Model.VersionSelectItems.Any()?"pl-1":"")">
<div class="version-select">
<div class="input-group">
<div class="input-group-prepend">
<label class="input-group-text">
<i class="fa fa-globe" aria-hidden="true" data-toggle="tooltip" title="@L["Language"]"></i>
</label>
</div>
<select asp-items="Model.LanguageSelectListItems" class="form-control" onchange="window.location.replace(this.value)"></select>
</div>
<select asp-items="Model.LanguageSelectListItems" class="form-control" onchange="window.location.replace(this.value)"></select>
</div>
</div>
</div>
</div>
}
</div>
}
</div>
<div class="docs-version mb-4">
<div class="version-select">
<div class="input-group">
<div class="input-group-prepend">
<label class="input-group-text"><i class="fa fa-filter"></i></label>
</div>
<div class="docs-version mb-4">
<div class="version-select">
<div class="input-group">
<div class="input-group-prepend">
<label class="input-group-text"><i class="fa fa-filter"></i></label>
</div>
<input class="form-control" type="search" placeholder="@L["FilterTopics"].Value" aria-label="Filter">
<input class="form-control" type="search" placeholder="@L["FilterTopics"].Value" aria-label="Filter">
</div>
</div>
</div>
</div>
@if (Model.Navigation == null || !Model.Navigation.HasChildItems)
{
<div class="text-muted p-3">
<i class="fa fa-warning"></i> @L["NavigationDocumentNotFound"]
</div>
}
else
{
<ul root-node="@Model.Navigation"
version="@(Model.LatestVersionInfo == null || Model.LatestVersionInfo.IsSelected ? DocsAppConsts.Latest : Model.Version)"
project-name="@Model.ProjectName"
project-format="@Model.Project.Format"
selected-document-name="@Model.DocumentNameWithExtension"
language="@Model.LanguageCode"
id="sidebar-scroll"
class="nav nav-list"></ul>
}
</div>
</div>
</div>
@if (Model.Document != null)
{
<div class="col-md-7 docs-content bg-white">
<div class="docs-link-btns">
<div class="float-left">
@(L["ShareOn"].Value + " :")
<a href="#" target="_blank" class="share-button twitter" id="TwitterShareLink" title="Twitter">
<i class="fa fa-twitter"></i>
</a>
<a href="#" target="_blank" class="share-button linkedin" id="LinkedinShareLink" title="LinkedIn">
<i class="fa fa-linkedin"></i>
</a>
<a href="#" target="_blank" class="share-button email" id="EmailShareLink" title="E-mail">
<i class="fa fa-envelope-square"></i>
</a>
</div>
<div class="float-right">
@if (!string.IsNullOrEmpty(Model.Document.EditLink))
@if (Model.Navigation == null || !Model.Navigation.HasChildItems)
{
<a href="@Model.Document.EditLink" target="_blank"> <i class="fa fa-edit"></i> @(L["Edit"]) (@L["LastEditTime"]: @Model.Document.LastUpdatedTime.ToShortDateString())</a>
<div class="text-muted p-3">
<i class="fa fa-warning"></i> @L["NavigationDocumentNotFound"]
</div>
}
</div>
<div class="float-right mr-3">
@if (Model.Document.Contributors != null && Model.Document.Contributors.Count > 0)
else
{
@(L["Contributors"].Value + " :")
@foreach (var contributor in Model.Document.Contributors)
{
<a href="@contributor.UserProfileUrl" target="_blank">
<img src="@contributor.AvatarUrl"
class="rounded-circle" height="21" width="21" title="@contributor.Username" />
</a>
}
<ul root-node="@Model.Navigation"
version="@(Model.LatestVersionInfo == null || Model.LatestVersionInfo.IsSelected ? DocsAppConsts.Latest : Model.Version)"
project-name="@Model.ProjectName"
project-format="@Model.Project.Format"
selected-document-name="@Model.DocumentNameWithExtension"
language="@Model.LanguageCode"
id="sidebar-scroll"
class="nav nav-list"></ul>
}
</div>
</div>
</div>
@if (Model.Document != null)
{
<div class="col-md-7 docs-content bg-white">
<div class="docs-link-btns">
<div class="float-left">
@(L["ShareOn"].Value + " :")
<a href="#" target="_blank" class="share-button twitter" id="TwitterShareLink" title="Twitter">
<i class="fa fa-twitter"></i>
</a>
<a href="#" target="_blank" class="share-button linkedin" id="LinkedinShareLink" title="LinkedIn">
<i class="fa fa-linkedin"></i>
</a>
<a href="#" target="_blank" class="share-button email" id="EmailShareLink" title="E-mail">
<i class="fa fa-envelope-square"></i>
</a>
</div>
<div class="docs-content-field">
<div class="docs-text-field">
<div class="position-relative">
@if (Model.DocumentPreferences != null && Model.DocumentPreferences.Parameters != null && Model.DocumentPreferences.Parameters.Any())
<div class="float-right">
@if (!string.IsNullOrEmpty(Model.Document.EditLink))
{
<div class="alert alert-primary alert-criteria">
<abp-row>
<abp-column>
<p class="alert-p mb-2">
<i class="fa fa-info-circle"></i>
@L["MultipleVersionDocumentInfo"]
</p>
</abp-column>
</abp-row>
<abp-form-row>
@foreach (var parameter in Model.DocumentPreferences.Parameters)
{
<abp-column size="_4">
<div class="input-group">
<div class="input-group-prepend">
<span class="input-group-text" id="@("Section" + parameter.Name + "ComboboxAddonId")">@(parameter.DisplayName)</span>
</div>
<select class="doc-section-combobox form-control"
aria-describedby="@("Section" + parameter.Name + "ComboboxAddonId")"
id="@("Section" + parameter.Name + "ComboboxId")" data-key="@parameter.Name">
@foreach (var value in parameter.Values)
{
@if (value.Key == (Model.UserPreferences.ContainsKey(parameter.Name) ? Model.UserPreferences[parameter.Name] : null))
{
<option value="@value.Key" selected="selected">@value.Value</option>
}
else
{
<option value="@value.Key">@value.Value</option>
}
}
</select>
</div>
</abp-column>
}
</abp-form-row>
</div>
<a href="@Model.Document.EditLink" target="_blank"> <i class="fa fa-edit"></i> @(L["Edit"]) (@L["LastEditTime"]: @Model.Document.LastUpdatedTime.ToShortDateString())</a>
}
</div>
<div data-spy="scroll" data-target="#docs-sticky-index" data-offset="0">
<article class="docs-body">
<div class="float-right mr-3">
@if (Model.Document.Contributors != null && Model.Document.Contributors.Count > 0)
{
@(L["Contributors"].Value + " :")
@foreach (var contributor in Model.Document.Contributors)
{
<a href="@contributor.UserProfileUrl" target="_blank">
<img src="@contributor.AvatarUrl"
class="rounded-circle" height="21" width="21" title="@contributor.Username" />
</a>
}
}
</div>
@if (Model.DocumentLanguageIsDifferent)
</div>
<div class="docs-content-field">
<div class="docs-text-field">
<div class="position-relative">
@if (Model.DocumentPreferences != null && Model.DocumentPreferences.Parameters != null && Model.DocumentPreferences.Parameters.Any())
{
<abp-alert alert-type="Warning" dismissible="true" class="mb-0">
@L["DocumentNotFoundInSelectedLanguage"]
</abp-alert>
<div class="alert alert-primary alert-criteria">
<abp-row>
<abp-column>
<p class="alert-p mb-2">
<i class="fa fa-info-circle"></i>
@L["MultipleVersionDocumentInfo"]
</p>
</abp-column>
</abp-row>
<abp-form-row>
@foreach (var parameter in Model.DocumentPreferences.Parameters)
{
<abp-column size="_4">
<div class="input-group">
<div class="input-group-prepend">
<span class="input-group-text" id="@("Section" + parameter.Name + "ComboboxAddonId")">@(parameter.DisplayName)</span>
</div>
<select class="doc-section-combobox form-control"
aria-describedby="@("Section" + parameter.Name + "ComboboxAddonId")"
id="@("Section" + parameter.Name + "ComboboxId")" data-key="@parameter.Name">
@foreach (var value in parameter.Values)
{
@if (value.Key == (Model.UserPreferences.ContainsKey(parameter.Name) ? Model.UserPreferences[parameter.Name] : null))
{
<option value="@value.Key" selected="selected">@value.Value</option>
}
else
{
<option value="@value.Key">@value.Value</option>
}
}
</select>
</div>
</abp-column>
}
</abp-form-row>
</div>
}
@Html.Raw(Model.Document.Content)
</article>
</div>
<div data-spy="scroll" data-target="#docs-sticky-index" data-offset="0">
<article class="docs-body">
<div id="crawler_link" style="display:none;">
@if (Model.DocumentLanguageIsDifferent)
{
<abp-alert alert-type="Warning" dismissible="true" class="mb-0">
@L["DocumentNotFoundInSelectedLanguage"]
</abp-alert>
}
@Html.Raw(Model.Document.Content)
</article>
<div id="crawler_link" style="display:none;">
</div>
</div>
</div>
</div>
</div>
</div>
<div class="col-md-2 docs-page-index position-relative bg-light">
<div class="col-md-2 docs-page-index position-relative bg-light">
<div id="scroll-index" class="docs-inner-anchors mt-2">
<div id="scroll-index" class="docs-inner-anchors mt-2">
<h5>@L["InThisDocument"]</h5>
<nav id="docs-sticky-index" class="navbar index-scroll">
</nav>
<h5>@L["InThisDocument"]</h5>
<nav id="docs-sticky-index" class="navbar index-scroll">
</nav>
<div class="row">
<div class="col p-0 py-3">
<a href="javascript:;" class="scroll-top-btn"><i class="fa fa-chevron-up"></i> @L["GoToTop"]</a>
<div class="row">
<div class="col p-0 py-3">
<a href="javascript:;" class="scroll-top-btn"><i class="fa fa-chevron-up"></i> @L["GoToTop"]</a>
</div>
</div>
</div>
</div>
</div>
</div>
}
else
{
<div class="col-md-9 p-5 bg-white">
<p>@L["DocumentNotFound"]</p>
}
else
{
<div class="col-md-9 p-5 bg-white">
<p>@L["DocumentNotFound"]</p>
<a href="/">
<i class="fa fa-chevron-left"></i>
@L["BackToWebsite"]
</a>
</div>
}
<a href="/">
<i class="fa fa-chevron-left"></i>
@L["BackToWebsite"]
</a>
</div>
}
</div>
</div>
</div>
}
else
{
@(await Component.InvokeAsync<DocumentNotFoundViewComponent>(new
{
model = new DocumentNotFoundPageModel
{
ProjectName = Model.ProjectName,
DocumentName = Model.DocumentName,
LanguageCode = Model.LanguageCode,
Version = Model.Version,
}
}))
}

17
modules/docs/src/Volo.Docs.Web/Pages/Documents/Project/Index.cshtml.cs

@ -33,6 +33,8 @@ namespace Volo.Docs.Pages.Documents.Project
[BindProperty(SupportsGet = true)]
public string LanguageCode { get; set; }
public bool DocumentFound { get; set; } = true;
public string DefaultLanguageCode { get; set; }
public ProjectDto Project { get; set; }
@ -86,6 +88,21 @@ namespace Volo.Docs.Pages.Documents.Project
}
public async Task<IActionResult> OnGetAsync()
{
try
{
return await SetPageAsync();
}
catch (DocumentNotFoundException exception)
{
Logger.LogWarning(exception.Message);
DocumentFound = false;
return Page();
}
}
private async Task<IActionResult> SetPageAsync()
{
DocumentsUrlPrefix = _uiOptions.RoutePrefix;
ShowProjectsCombobox = _uiOptions.ShowProjectsCombobox;

53
modules/docs/src/Volo.Docs.Web/Pages/Documents/Shared/DocumentNotFoundComponent/Default.cshtml

@ -0,0 +1,53 @@
@using Volo.Docs.Pages.Documents.Shared.DocumentNotFoundComponent
@model DocumentNotFoundPageModel
@{
}
<div class="row position-relative vh-100" style="background: #e8e8e8;">
<div class="center">
<span class="notfound-404">404</span>
<h1>
<strong>"@Model.DocumentName"</strong> not found in <strong>@Model.ProjectName</strong> documents, with <strong>@Model.Version</strong> version and <strong>@Model.LanguageCode</strong> language.
</h1>
<br />
<a href="@(Model.DocumentsUrlPrefix + Model.LanguageCode + "/" +Model.ProjectName + "/" + Model.Version)" class="btn btn-primary px-4">
Go Back
</a>
</div>
</div>
<style>
h1 {
font-size: 1.75em;
line-height: 1.75;
color: #777;
font-weight: normal;
}
h1 strong {
color: #222;
}
.center {
position: absolute;
left: 50%;
top: 50%;
-webkit-transform: translate(-50%, -50%);
-ms-transform: translate(-50%, -50%);
transform: translate(-50%, -50%);
text-align: center;
}
.notfound-404 {
font-size: 300px;
font-weight: 700;
line-height: 1.25;
margin: 0px;
color: #fff;
text-transform: uppercase;
display: block;
margin-bottom: -150px;
z-index: -1;
position: relative;
}
</style>

15
modules/docs/src/Volo.Docs.Web/Pages/Documents/Shared/DocumentNotFoundComponent/DocumentNotFoundPageModel.cs

@ -0,0 +1,15 @@
namespace Volo.Docs.Pages.Documents.Shared.DocumentNotFoundComponent
{
public class DocumentNotFoundPageModel
{
public string ProjectName { get; set; }
public string LanguageCode { get; set; }
public string Version { get; set; }
public string DocumentName { get; set; }
public string DocumentsUrlPrefix { get; set; }
}
}

26
modules/docs/src/Volo.Docs.Web/Pages/Documents/Shared/DocumentNotFoundComponent/DocumentNotFoundViewComponent.cs

@ -0,0 +1,26 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Options;
using Volo.Abp.AspNetCore.Mvc;
namespace Volo.Docs.Pages.Documents.Shared.DocumentNotFoundComponent
{
public class DocumentNotFoundViewComponent : AbpViewComponent
{
private readonly DocsUiOptions _options;
public DocumentNotFoundViewComponent(IOptions<DocsUiOptions> options)
{
_options = options.Value;
}
public IViewComponentResult Invoke(DocumentNotFoundPageModel model, string defaultErrorMessageKey)
{
model.DocumentsUrlPrefix = _options.RoutePrefix;
return View("~/Pages/Documents/Shared/DocumentNotFoundComponent/Default.cshtml", model);
}
}
}

1
modules/docs/src/Volo.Docs.Web/Volo.Docs.Web.csproj

@ -18,6 +18,7 @@
<ProjectReference Include="..\..\..\..\framework\src\Volo.Abp.AspNetCore.Mvc.UI.Bundling\Volo.Abp.AspNetCore.Mvc.UI.Bundling.csproj" />
<ProjectReference Include="..\..\..\..\framework\src\Volo.Abp.AspNetCore.Mvc.UI.Bootstrap\Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.csproj" />
<ProjectReference Include="..\..\..\..\framework\src\Volo.Abp.AspNetCore.Mvc.UI.Packages\Volo.Abp.AspNetCore.Mvc.UI.Packages.csproj" />
<ProjectReference Include="..\..\..\..\framework\src\Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared\Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared.csproj" />
<ProjectReference Include="..\Volo.Docs.HttpApi\Volo.Docs.HttpApi.csproj" />
<PackageReference Include="Markdig.Signed" Version="0.18.0" />
<PackageReference Include="Scriban" Version="2.1.1" />

18
npm/packs/jquery/src/abp.jquery.js

@ -359,13 +359,17 @@
var _loadScript = function (url, loadCallback, failCallback) {
_loadFromUrl(url, loadCallback, failCallback, function (urlInfo) {
$.getScript(url)
.done(function () {
urlInfo.succeed();
})
.fail(function () {
urlInfo.failed();
});
$.get({
url: url,
dataType: 'text'
})
.done(function (script) {
$.globalEval(script);
urlInfo.succeed();
})
.fail(function () {
urlInfo.failed();
});
});
};

1
samples/MicroserviceDemo/applications/AuthServer.Host/AuthServer.Host.csproj

@ -29,6 +29,7 @@
<ProjectReference Include="..\..\..\..\modules\identity\src\Volo.Abp.Identity.EntityFrameworkCore\Volo.Abp.Identity.EntityFrameworkCore.csproj" />
<ProjectReference Include="..\..\..\..\modules\identityserver\src\Volo.Abp.IdentityServer.EntityFrameworkCore\Volo.Abp.IdentityServer.EntityFrameworkCore.csproj" />
<ProjectReference Include="..\..\..\..\modules\account\src\Volo.Abp.Account.Web.IdentityServer\Volo.Abp.Account.Web.IdentityServer.csproj" />
<ProjectReference Include="..\..\..\..\modules\account\src\Volo.Abp.Account.Application\Volo.Abp.Account.Application.csproj" />
<ProjectReference Include="..\..\..\..\modules\audit-logging\src\Volo.Abp.AuditLogging.EntityFrameworkCore\Volo.Abp.AuditLogging.EntityFrameworkCore.csproj" />
<ProjectReference Include="..\..\..\..\modules\permission-management\src\Volo.Abp.PermissionManagement.EntityFrameworkCore\Volo.Abp.PermissionManagement.EntityFrameworkCore.csproj" />
<ProjectReference Include="..\..\..\..\modules\setting-management\src\Volo.Abp.SettingManagement.EntityFrameworkCore\Volo.Abp.SettingManagement.EntityFrameworkCore.csproj" />

4
samples/MicroserviceDemo/applications/AuthServer.Host/AuthServerHostModule.cs

@ -1,9 +1,10 @@
using AuthServer.Host.EntityFrameworkCore;
using AuthServer.Host.EntityFrameworkCore;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.DataProtection;
using Microsoft.Extensions.DependencyInjection;
using StackExchange.Redis;
using Volo.Abp;
using Volo.Abp.Account;
using Volo.Abp.Account.Web;
using Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic;
using Volo.Abp.Auditing;
@ -34,6 +35,7 @@ namespace AuthServer.Host
typeof(AbpSettingManagementEntityFrameworkCoreModule),
typeof(AbpIdentityEntityFrameworkCoreModule),
typeof(AbpIdentityApplicationContractsModule),
typeof(AbpAccountApplicationModule),
typeof(AbpIdentityServerEntityFrameworkCoreModule),
typeof(AbpEntityFrameworkCoreSqlServerModule),
typeof(AbpAccountWebIdentityServerModule),

Loading…
Cancel
Save