diff --git a/abp_io/AbpIoLocalization/AbpIoLocalization/Admin/Localization/Resources/en.json b/abp_io/AbpIoLocalization/AbpIoLocalization/Admin/Localization/Resources/en.json index f44096199a..1523a97c6d 100644 --- a/abp_io/AbpIoLocalization/AbpIoLocalization/Admin/Localization/Resources/en.json +++ b/abp_io/AbpIoLocalization/AbpIoLocalization/Admin/Localization/Resources/en.json @@ -247,6 +247,10 @@ "Address": "Address", "TaxNo": "Tax No", "Permission:InvoiceRequest": "Invoice Request", - "Permission:Question": "Question" + "Permission:Question": "Question", + "AddNoteSuccessMessage": "Note successfully added", + "NameSurname": "Name Surname", + "Note": "Note", + "Add": "Add" } } diff --git a/abp_io/AbpIoLocalization/AbpIoLocalization/Admin/Localization/Resources/tr.json b/abp_io/AbpIoLocalization/AbpIoLocalization/Admin/Localization/Resources/tr.json index fc32024bc0..750df02dc4 100644 --- a/abp_io/AbpIoLocalization/AbpIoLocalization/Admin/Localization/Resources/tr.json +++ b/abp_io/AbpIoLocalization/AbpIoLocalization/Admin/Localization/Resources/tr.json @@ -196,6 +196,10 @@ "Address": "Adres", "TaxNo": "Vergi no", "Permission:InvoiceRequest": "Fatura Talebi", - "Permission:Question": "Soru" + "Permission:Question": "Soru", + "AddNoteSuccessMessage": "Not başarıyla eklendi", + "NameSurname": "Adı Soyadı", + "Note": "Not", + "Add": "Ekle" } } \ No newline at end of file diff --git a/abp_io/AbpIoLocalization/AbpIoLocalization/Admin/Localization/Resources/zh-Hans.json b/abp_io/AbpIoLocalization/AbpIoLocalization/Admin/Localization/Resources/zh-Hans.json index ee0dbef838..9a269da0d4 100644 --- a/abp_io/AbpIoLocalization/AbpIoLocalization/Admin/Localization/Resources/zh-Hans.json +++ b/abp_io/AbpIoLocalization/AbpIoLocalization/Admin/Localization/Resources/zh-Hans.json @@ -231,7 +231,11 @@ "Address": "地址", "TaxNo": "税号", "Permission:InvoiceRequest": "发票请求", - "Permission:Question": "问题" + "Permission:Question": "问题", + "AddNoteSuccessMessage": "注释添加成功", + "NameSurname": "姓", + "Note": "注释", + "Add": "添加" } } \ No newline at end of file diff --git a/docs/en/Community-Articles/2021-03-12-Simple-SignalR-Notification/POST.md b/docs/en/Community-Articles/2021-03-12-Simple-SignalR-Notification/POST.md new file mode 100644 index 0000000000..519a09fa42 --- /dev/null +++ b/docs/en/Community-Articles/2021-03-12-Simple-SignalR-Notification/POST.md @@ -0,0 +1,98 @@ +# Send Real-time Notifications via SignalR in ABP Project + +SignalR is an open source library that adds real-time operation functionality to applications. Real-time web functionality enables server-side code to instantly send content to clients without refreshing the page. I'll show you how to add SignalR and use it to send notifications from backend. I'll implement this functionality in MVC template of ABP Framework. + +![signalr-architecture](signalr-architecture.png) + +## Implement Backend + +### Create Notification Hub + +Create a new folder named `SignalR` in your root directory of your Web project. + +![SignalR Folder](signalr-folder.jpg) + +Then add the following classes to the folder: + +1. [INotificationClient.cs](https://gist.github.com/ebicoglu/f7dc22cca2d353f8bf7f68a03e3395b8#file-inotificationclient-cs) +2. [UiNotificationClient.cs](https://gist.github.com/ebicoglu/f7dc22cca2d353f8bf7f68a03e3395b8#file-uinotificationclient-cs) +3. [UiNotificationHub.cs](https://gist.github.com/ebicoglu/f7dc22cca2d353f8bf7f68a03e3395b8#file-uinotificationhub-cs) + +### Configure Module + +These 3 steps will be done in your web module class. + +#### 1- Add SignalR + +Open `YourProjectWebModule.cs` class and add the following line to the `PreConfigureServices` method: + +```csharp + context.Services.AddSignalR(); +``` + + + +![PreConfigureServices](preconfigureservices.jpg) + + + +#### 2- Add Client Scripts + +2- In the `ConfigureServices` method of your web module add the following code to add the `signalr.js` and `notification-hub.js`. We'll add these packages in the next steps. + +![Script Bundles](add-script-bundles.jpg) + +#### 3- Add Hub Endpoint + +Add the following code to add the notification hub endpoint in `OnApplicationInitialization` method: + +```csharp +app.UseEndpoints(endpoints => +{ + endpoints.MapHub("/notification-hub"); +}); +``` + +![Add endpoint](add-endpoint.jpg) + +### Implement Frontend + +We'll write the client-side code to be able to handle the SignalR response. + +#### 1- Add Notification Hub + +Add the following JavaScript class into your `Pages` folder in your Web project. We already added this script to our global scripts. + +[notification-hub.js](https://gist.github.com/ebicoglu/f7dc22cca2d353f8bf7f68a03e3395b8#file-notification-hub-js) + +![notification-hub.js](notification-hub.jpg) + +#### 2- Add SignalR NPM package + +Add [Microsoft.SignalR](https://www.npmjs.com/package/@microsoft/signalr) JavaScript package to the `package.json` which is located in your root folder of the Web project. After you add it, run `yarn` command in your Web directory to be able to install this package. + +![Add SignalR package](signalr-package.jpg) + +#### 3- Add resource Mapping + +We added SignalR to the `package.json` but it comes into your `node_modules` folder. We need to copy the related files to `wwwroot/libs` folder. To do this copy the content of the following file to your `abp.resourcemappings.js` file. It's in your root directory of Web folder. After you do this, go to your web directory and run `gulp` command. By doing this, it'll copy the related files into your `wwwroot/libs` folder. + +[abp.resourcemappings.js](https://gist.github.com/ebicoglu/f7dc22cca2d353f8bf7f68a03e3395b8#file-abp-resourcemapping-js) + +![Resource mappings](resource-mappings.jpg) + +#### 4- Usage + +We have completed the implementation part. Let's check if it's running... + +To do this easily, open your `Index.cshtml` which is in the Pages folder of your Web project. And replace the content with the following. Also replace the `Index.cshtml.cs` as well. + +[Index.cshtml](https://gist.github.com/ebicoglu/f7dc22cca2d353f8bf7f68a03e3395b8#file-index-cshtml) + +[Index.cshtml.cs](https://gist.github.com/ebicoglu/f7dc22cca2d353f8bf7f68a03e3395b8#file-index-cshtml-cs) + +#### 5- See it in action + +Run your web project and in the Index page you'll see a button named as "Get Notification". Click the button and see the notification that comes from SignalR. This is a basic usage of SignalR notification system. You can implement it according to your own requirements. + +![Result](result.jpg) diff --git a/docs/en/Community-Articles/2021-03-12-Simple-SignalR-Notification/add-endpoint.jpg b/docs/en/Community-Articles/2021-03-12-Simple-SignalR-Notification/add-endpoint.jpg new file mode 100644 index 0000000000..706a860dd0 Binary files /dev/null and b/docs/en/Community-Articles/2021-03-12-Simple-SignalR-Notification/add-endpoint.jpg differ diff --git a/docs/en/Community-Articles/2021-03-12-Simple-SignalR-Notification/add-script-bundles.jpg b/docs/en/Community-Articles/2021-03-12-Simple-SignalR-Notification/add-script-bundles.jpg new file mode 100644 index 0000000000..0523d73e37 Binary files /dev/null and b/docs/en/Community-Articles/2021-03-12-Simple-SignalR-Notification/add-script-bundles.jpg differ diff --git a/docs/en/Community-Articles/2021-03-12-Simple-SignalR-Notification/article-signalr-banner.png b/docs/en/Community-Articles/2021-03-12-Simple-SignalR-Notification/article-signalr-banner.png new file mode 100644 index 0000000000..450d4e2339 Binary files /dev/null and b/docs/en/Community-Articles/2021-03-12-Simple-SignalR-Notification/article-signalr-banner.png differ diff --git a/docs/en/Community-Articles/2021-03-12-Simple-SignalR-Notification/notification-hub.jpg b/docs/en/Community-Articles/2021-03-12-Simple-SignalR-Notification/notification-hub.jpg new file mode 100644 index 0000000000..e762b2cc8d Binary files /dev/null and b/docs/en/Community-Articles/2021-03-12-Simple-SignalR-Notification/notification-hub.jpg differ diff --git a/docs/en/Community-Articles/2021-03-12-Simple-SignalR-Notification/preconfigureservices.jpg b/docs/en/Community-Articles/2021-03-12-Simple-SignalR-Notification/preconfigureservices.jpg new file mode 100644 index 0000000000..4421143aa3 Binary files /dev/null and b/docs/en/Community-Articles/2021-03-12-Simple-SignalR-Notification/preconfigureservices.jpg differ diff --git a/docs/en/Community-Articles/2021-03-12-Simple-SignalR-Notification/resource-mappings.jpg b/docs/en/Community-Articles/2021-03-12-Simple-SignalR-Notification/resource-mappings.jpg new file mode 100644 index 0000000000..7d6d0a3de8 Binary files /dev/null and b/docs/en/Community-Articles/2021-03-12-Simple-SignalR-Notification/resource-mappings.jpg differ diff --git a/docs/en/Community-Articles/2021-03-12-Simple-SignalR-Notification/result.jpg b/docs/en/Community-Articles/2021-03-12-Simple-SignalR-Notification/result.jpg new file mode 100644 index 0000000000..4c9ca0663b Binary files /dev/null and b/docs/en/Community-Articles/2021-03-12-Simple-SignalR-Notification/result.jpg differ diff --git a/docs/en/Community-Articles/2021-03-12-Simple-SignalR-Notification/signalr-architecture.png b/docs/en/Community-Articles/2021-03-12-Simple-SignalR-Notification/signalr-architecture.png new file mode 100644 index 0000000000..6f39568239 Binary files /dev/null and b/docs/en/Community-Articles/2021-03-12-Simple-SignalR-Notification/signalr-architecture.png differ diff --git a/docs/en/Community-Articles/2021-03-12-Simple-SignalR-Notification/signalr-folder.jpg b/docs/en/Community-Articles/2021-03-12-Simple-SignalR-Notification/signalr-folder.jpg new file mode 100644 index 0000000000..5c1dd351fb Binary files /dev/null and b/docs/en/Community-Articles/2021-03-12-Simple-SignalR-Notification/signalr-folder.jpg differ diff --git a/docs/en/Community-Articles/2021-03-12-Simple-SignalR-Notification/signalr-package.jpg b/docs/en/Community-Articles/2021-03-12-Simple-SignalR-Notification/signalr-package.jpg new file mode 100644 index 0000000000..be1e87d1b2 Binary files /dev/null and b/docs/en/Community-Articles/2021-03-12-Simple-SignalR-Notification/signalr-package.jpg differ diff --git a/docs/en/Migration-Guides/Abp-4_3-Angular.md b/docs/en/Migration-Guides/Abp-4_3-Angular.md new file mode 100644 index 0000000000..0b4a90fc72 --- /dev/null +++ b/docs/en/Migration-Guides/Abp-4_3-Angular.md @@ -0,0 +1,90 @@ +# Angular UI v4.3 Migration Guide + +## Breaking Changes + +### Manage Profile Page + +Before v4.3, the "Manage Your Profile" link in the current user dropdown on the top bar redirected the user to MVC's profile management page. As of v4.3, the same link will land on a page in the Angular UI account module instead. So you have to install and implement the account module to your Angular project when you update the ABP to v4.3. + +#### Account Module Implementation + +Install the `@abp/ng.account` NPM package by running the below command: + +```bash +npm install @abp/ng.account@next +``` + +> Make sure v4.3-rc or higher version is installed. + +Open the `app.module.ts` and add `AccountConfigModule.forRoot()` to the imports array as shown below: + +```js +// app.module.ts + +import { AccountConfigModule } from '@abp/ng.account/config'; +//... + +@NgModule({ + imports: [ + //... + AccountConfigModule.forRoot() + ], + //... +}) +export class AppModule {} +``` + +Open the `app-routing.module.ts` and add the `account` route to `routes` array as follows: + +```js +// app-routing.module.ts +const routes: Routes = [ + //... + { + path: 'account', + loadChildren: () => import('@abp/ng.account').then(m => m.AccountModule.forLazy()), + }, + //... +export class AppRoutingModule {} +``` + +#### Account Module Implementation for Commercial Templates + +The pro startup template comes with `@volo/abp.ng.account` package. You should update the package version to v4.3-rc or higher version. The package can be updated by running the following command: + +```bash +npm install @volo/abp.ng.account@next +``` +> Make sure v4.3-rc or higher version is installed. + +`AccountConfigModule` is already imported to `app.module.ts` in the startup template. So no need to import the module to the `AppModule`. If you removed the `AccountConfigModule` from the `AppModule`, you can import it as shown below: + +```js +// app.module.ts + +import { AccountConfigModule } from '@volo/abp.ng.account/config'; +//... + +@NgModule({ + imports: [ + //... + AccountConfigModule.forRoot() + ], + //... +}) +export class AppModule {} +``` + +Open the `app-routing.module.ts` and add the `account` route to `routes` array as follows: + +```js +// app-routing.module.ts +const routes: Routes = [ + //... + { + path: 'account', + loadChildren: () => import('@volo/abp.ng.account').then(m => m.AccountPublicModule.forLazy()), + }, + //... +export class AppRoutingModule {} +``` \ No newline at end of file diff --git a/docs/en/Migration-Guides/Abp-4_3.md b/docs/en/Migration-Guides/Abp-4_3.md new file mode 100644 index 0000000000..491143b0b0 --- /dev/null +++ b/docs/en/Migration-Guides/Abp-4_3.md @@ -0,0 +1,5 @@ +# ABP v4.3 Migration Guide + +## Angular UI + +See the [Angular UI Migration Guide](Abp-4_3-Angular.md). \ No newline at end of file diff --git a/docs/en/Migration-Guides/Index.md b/docs/en/Migration-Guides/Index.md index 26fe825f50..c7bee5a82a 100644 --- a/docs/en/Migration-Guides/Index.md +++ b/docs/en/Migration-Guides/Index.md @@ -1,5 +1,6 @@ # ABP Framework Migration Guides +* [4.2 to 4.3](Abp-4_3.md) * [4.x to 4.2](Abp-4_2.md) * [3.3.x to 4.0](Abp-4_0.md) * [2.9.x to 3.0](../UI/Angular/Migration-Guide-v3.md) diff --git a/docs/en/UI/AspNetCore/Navigation-Menu.md b/docs/en/UI/AspNetCore/Navigation-Menu.md index 7a8fe31e3e..8480590f50 100644 --- a/docs/en/UI/AspNetCore/Navigation-Menu.md +++ b/docs/en/UI/AspNetCore/Navigation-Menu.md @@ -104,6 +104,7 @@ There are more options of a menu item (the constructor of the `ApplicationMenuIt * `target` (`string`): Target of the menu item. Can be `null` (default), "\_*blank*", "\_*self*", "\_*parent*", "\_*top*" or a frame name for web applications. * `elementId` (`string`): Can be used to render the element with a specific HTML `id` attribute. * `cssClass` (`string`): Additional string classes for the menu item. +* `RequiredPermissionName` (`string`): The required permission name, this menu item will be removed if this permission is not granted. ### Authorization @@ -120,6 +121,25 @@ if (await context.IsGrantedAsync("MyPermissionName")) } ```` +For the authorization, you can use `RequiredPermissionName` as a shortcut. It is also more performant, ABP optimizes the permission check for all the items. + +````csharp +context.Menu.AddItem( + new ApplicationMenuItem("MyProject.Crm", l["Menu:CRM"]) + .AddItem(new ApplicationMenuItem( + name: "MyProject.Crm.Customers", + displayName: l["Menu:Customers"], + url: "/crm/customers", + requiredPermissionName: "MyProject.Crm.Customers") + ).AddItem(new ApplicationMenuItem( + name: "MyProject.Crm.Orders", + displayName: l["Menu:Orders"], + url: "/crm/orders", + requiredPermissionName: "MyProject.Crm.Orders") + ) +); +```` + > You can use `context.AuthorizationService` to directly access to the `IAuthorizationService`. ### Resolving Dependencies diff --git a/docs/en/UI/AspNetCore/Toolbars.md b/docs/en/UI/AspNetCore/Toolbars.md index 3f1185f61b..66ec7519b8 100644 --- a/docs/en/UI/AspNetCore/Toolbars.md +++ b/docs/en/UI/AspNetCore/Toolbars.md @@ -52,6 +52,21 @@ public class MyToolbarContributor : IToolbarContributor } ```` +You can use the [authorization](../../Authorization.md) to decide whether to add a `ToolbarItem`. + +````csharp +if (await context.IsGrantedAsync("MyPermissionName")) +{ + //...add Toolbar items +} +```` + +You can use `RequiredPermissionName` as a shortcut. It is also more performant, ABP optimizes the permission check for all the items. + +````csharp +context.Toolbar.Items.Insert(0, new ToolbarItem(typeof(NotificationViewComponent), requiredPermissionName: "MyPermissionName")); +```` + This class adds the `NotificationViewComponent` as the first item in the `Main` toolbar. Finally, you need to add this contributor to the `AbpToolbarOptions`, in the `ConfigureServices` of your [module](../../Module-Development-Basics.md): @@ -71,4 +86,4 @@ That's all, you will see the notification icon on the toolbar when you run the a ## IToolbarManager -`IToolbarManager` is used to render the toolbar. It returns the toolbar items by a toolbar name. This is generally used by the [themes](Theming.md) to render the toolbar on the layout. \ No newline at end of file +`IToolbarManager` is used to render the toolbar. It returns the toolbar items by a toolbar name. This is generally used by the [themes](Theming.md) to render the toolbar on the layout. diff --git a/framework/src/Volo.Abp.Authorization/Volo/Abp/Authorization/Localization/zh-Hant.json b/framework/src/Volo.Abp.Authorization/Volo/Abp/Authorization/Localization/zh-Hant.json new file mode 100644 index 0000000000..937299656c --- /dev/null +++ b/framework/src/Volo.Abp.Authorization/Volo/Abp/Authorization/Localization/zh-Hant.json @@ -0,0 +1,10 @@ +{ + "culture": "zh-Hant", + "texts": { + "Volo.Authorization:010001": "認證失敗! Given policy has not granted.", + "Volo.Authorization:010002": "認證失敗! Given policy has not granted: {PolicyName}", + "Volo.Authorization:010003": "認證失敗! Given policy has not granted for given resource: {ResourceName}", + "Volo.Authorization:010004": "認證失敗! Given requirement has not granted for given resource: {ResourceName}", + "Volo.Authorization:010005": "認證失敗! Given requirements has not granted for given resource: {ResourceName}" + } +} \ No newline at end of file diff --git a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectBuilding/Building/Steps/RemoveProjectFromPrometheusStep.cs b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectBuilding/Building/Steps/RemoveProjectFromPrometheusStep.cs new file mode 100644 index 0000000000..d2523fbc01 --- /dev/null +++ b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectBuilding/Building/Steps/RemoveProjectFromPrometheusStep.cs @@ -0,0 +1,54 @@ +using System; +using System.Collections.Generic; +using System.Linq; + +namespace Volo.Abp.Cli.ProjectBuilding.Building.Steps +{ + public class RemoveProjectFromPrometheusStep : ProjectBuildPipelineStep + { + private readonly string _name; + + public RemoveProjectFromPrometheusStep(string name) + { + _name = name; + } + + public override void Execute(ProjectBuildContext context) + { + var tyeFile = context.Files.FirstOrDefault(f => f.Name == "/etc/prometheus/prometheus.yml"); + + if (tyeFile == null) + { + return; + } + + var lines = tyeFile.GetLines(); + var newLines = new List(); + + var nameLine = $"- job_name:"; + var isOneOfTargetLines = false; + + foreach (var line in lines) + { + if (line.Trim().Equals($"{nameLine} '{_name}'")) + { + isOneOfTargetLines = true; + continue; + } + + if (line.Trim().StartsWith(nameLine)) + { + isOneOfTargetLines = false; + } + + if (!isOneOfTargetLines) + { + newLines.Add(line); + } + } + + tyeFile.SetContent(String.Join(Environment.NewLine, newLines)); + } + + } +} diff --git a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectBuilding/Building/Steps/RemoveProjectFromTyeStep.cs b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectBuilding/Building/Steps/RemoveProjectFromTyeStep.cs index 1c51e22bc9..8c84acf9e9 100644 --- a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectBuilding/Building/Steps/RemoveProjectFromTyeStep.cs +++ b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectBuilding/Building/Steps/RemoveProjectFromTyeStep.cs @@ -30,13 +30,13 @@ namespace Volo.Abp.Cli.ProjectBuilding.Building.Steps foreach (var line in lines) { - if (line.Equals($"{nameLine} {_name}")) + if (line.Trim().Equals($"{nameLine} {_name}")) { isOneOfTargetLines = true; continue; } - if (line.StartsWith(nameLine)) + if (line.Trim().StartsWith(nameLine)) { isOneOfTargetLines = false; } diff --git a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectBuilding/Templates/Microservice/MicroserviceTemplateBase.cs b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectBuilding/Templates/Microservice/MicroserviceTemplateBase.cs index 1efbe09ff1..909c9841d9 100644 --- a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectBuilding/Templates/Microservice/MicroserviceTemplateBase.cs +++ b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectBuilding/Templates/Microservice/MicroserviceTemplateBase.cs @@ -37,6 +37,7 @@ namespace Volo.Abp.Cli.ProjectBuilding.Templates.Microservice "/applications/web/src/MyCompanyName.MyProjectName.Web")); steps.Add(new RemoveFolderStep("/applications/web")); steps.Add(new RemoveProjectFromTyeStep("web")); + steps.Add(new RemoveProjectFromPrometheusStep("web")); steps.Add(new RemoveProjectFromSolutionStep("MyCompanyName.MyProjectName.Blazor",null, "/applications/blazor/src/MyCompanyName.MyProjectName.Blazor")); @@ -51,6 +52,7 @@ namespace Volo.Abp.Cli.ProjectBuilding.Templates.Microservice "/applications/web/src/MyCompanyName.MyProjectName.Web")); steps.Add(new RemoveFolderStep("/applications/web")); steps.Add(new RemoveProjectFromTyeStep("web")); + steps.Add(new RemoveProjectFromPrometheusStep("web")); steps.Add(new RemoveProjectFromSolutionStep("MyCompanyName.MyProjectName.Blazor",null, "/applications/blazor/src/MyCompanyName.MyProjectName.Blazor")); @@ -64,6 +66,7 @@ namespace Volo.Abp.Cli.ProjectBuilding.Templates.Microservice steps.Add(new RemoveFolderStep("/applications/web")); steps.Add(new RemoveFolderStep("/angular")); steps.Add(new RemoveProjectFromTyeStep("web")); + steps.Add(new RemoveProjectFromPrometheusStep("web")); break; case UiFramework.Mvc: diff --git a/framework/src/Volo.Abp.ExceptionHandling/Volo/Abp/ExceptionHandling/Localization/zh-Hant.json b/framework/src/Volo.Abp.ExceptionHandling/Volo/Abp/ExceptionHandling/Localization/zh-Hant.json index bf02b7f053..f934d77187 100644 --- a/framework/src/Volo.Abp.ExceptionHandling/Volo/Abp/ExceptionHandling/Localization/zh-Hant.json +++ b/framework/src/Volo.Abp.ExceptionHandling/Volo/Abp/ExceptionHandling/Localization/zh-Hant.json @@ -18,6 +18,8 @@ "401Message": "未授權", "403Message": "禁止訪問", "404Message": "網頁未找到", - "500Message": "內部伺服器錯誤" + "500Message": "內部伺服器錯誤", + "403MessageDetail": "你不被授權執行此操作", + "404MessageDetail": "對不起,地址是空的" } -} +} \ No newline at end of file diff --git a/framework/src/Volo.Abp.Features/Volo/Abp/Features/Localization/zh-Hant.json b/framework/src/Volo.Abp.Features/Volo/Abp/Features/Localization/zh-Hant.json new file mode 100644 index 0000000000..82b62dcab3 --- /dev/null +++ b/framework/src/Volo.Abp.Features/Volo/Abp/Features/Localization/zh-Hant.json @@ -0,0 +1,8 @@ +{ + "culture": "zh-Hant", + "texts": { + "Volo.Feature:010001": "功能尚未啟用: {FeatureName}", + "Volo.Feature:010002": "請求的功能尚未啟用。這些功能被須全部啟用: {FeatureNames}", + "Volo.Feature:010003": "請求的功能尚未啟用。這些功能至少需啟用一個: {FeatureNames}" + } +} \ No newline at end of file diff --git a/framework/test/Volo.Abp.Emailing.Tests/Volo/Abp/Emailing/Localization/zh-Hant.json b/framework/test/Volo.Abp.Emailing.Tests/Volo/Abp/Emailing/Localization/zh-Hant.json new file mode 100644 index 0000000000..3630ce5e70 --- /dev/null +++ b/framework/test/Volo.Abp.Emailing.Tests/Volo/Abp/Emailing/Localization/zh-Hant.json @@ -0,0 +1,6 @@ +{ + "culture": "zh-Hant", + "texts": { + "hello": "嗨" + } +} \ No newline at end of file diff --git a/framework/test/Volo.Abp.TextTemplating.Tests/Volo/Abp/TextTemplating/Localization/zh-Hant.json b/framework/test/Volo.Abp.TextTemplating.Tests/Volo/Abp/TextTemplating/Localization/zh-Hant.json new file mode 100644 index 0000000000..1c60908b66 --- /dev/null +++ b/framework/test/Volo.Abp.TextTemplating.Tests/Volo/Abp/TextTemplating/Localization/zh-Hant.json @@ -0,0 +1,7 @@ +{ + "culture": "zh-Hant", + "texts": { + "HelloText": "嗨 {0}", + "HowAreYou": "你好嗎?" + } +} \ No newline at end of file diff --git a/modules/account/src/Volo.Abp.Account.Application.Contracts/Volo/Abp/Account/Localization/Resources/zh-Hant.json b/modules/account/src/Volo.Abp.Account.Application.Contracts/Volo/Abp/Account/Localization/Resources/zh-Hant.json index 8a57429344..9517c2121f 100644 --- a/modules/account/src/Volo.Abp.Account.Application.Contracts/Volo/Abp/Account/Localization/Resources/zh-Hant.json +++ b/modules/account/src/Volo.Abp.Account.Application.Contracts/Volo/Abp/Account/Localization/Resources/zh-Hant.json @@ -44,6 +44,7 @@ "LoggedOutTitle": "註銷", "LoggedOutText": "你已成功註銷並將馬上返回.", "ReturnToText": "點擊此處返回到 {0}", + "OrLoginWith": "或是登入用:", "ForgotPassword": "忘記密碼?", "SendPasswordResetLink_Information": "密碼重置鏈接將發送到您的電子郵件以重置密碼. 如果您在幾分鐘內沒有收到電子郵件,請重試.", "PasswordResetMailSentMessage": "帳戶恢復電子郵件已發送到您的電子郵件地址. 如果您在15分鐘內未在收件箱中看到此電子郵件,請檢查垃圾郵件,並標記為非垃圾郵件.", @@ -62,4 +63,4 @@ "AccessDenied": "拒絕訪問!", "AccessDeniedMessage": "您無權訪問此資源." } -} +} \ No newline at end of file diff --git a/modules/cms-kit/host/Volo.CmsKit.Web.Unified/CmsKitWebUnifiedModule.cs b/modules/cms-kit/host/Volo.CmsKit.Web.Unified/CmsKitWebUnifiedModule.cs index adb915b832..482959dea3 100644 --- a/modules/cms-kit/host/Volo.CmsKit.Web.Unified/CmsKitWebUnifiedModule.cs +++ b/modules/cms-kit/host/Volo.CmsKit.Web.Unified/CmsKitWebUnifiedModule.cs @@ -44,6 +44,7 @@ using Volo.CmsKit.Tags; using Volo.CmsKit.Comments; using Volo.CmsKit.MediaDescriptors; using Volo.CmsKit.Reactions; +using Volo.CmsKit.Ratings; namespace Volo.CmsKit { @@ -165,6 +166,11 @@ namespace Volo.CmsKit new ReactionDefinition(StandardReactions.ThumbsDown), })); }); + + Configure(options => + { + options.EntityTypes.Add(new RatingEntityTypeDefinition("quote")); + }); } public override void OnApplicationInitialization(ApplicationInitializationContext context) diff --git a/modules/cms-kit/src/Volo.CmsKit.Admin.Application/Volo/CmsKit/Admin/MediaDescriptors/MediaDescriptorAdminAppService.cs b/modules/cms-kit/src/Volo.CmsKit.Admin.Application/Volo/CmsKit/Admin/MediaDescriptors/MediaDescriptorAdminAppService.cs index 8ea11bd3c8..b359d55244 100644 --- a/modules/cms-kit/src/Volo.CmsKit.Admin.Application/Volo/CmsKit/Admin/MediaDescriptors/MediaDescriptorAdminAppService.cs +++ b/modules/cms-kit/src/Volo.CmsKit.Admin.Application/Volo/CmsKit/Admin/MediaDescriptors/MediaDescriptorAdminAppService.cs @@ -31,7 +31,7 @@ namespace Volo.CmsKit.Admin.MediaDescriptors public virtual async Task CreateAsync(CreateMediaInputStream inputStream) { - var definition = await MediaDescriptorDefinitionStore.GetDefinitionAsync(inputStream.EntityType); + var definition = await MediaDescriptorDefinitionStore.GetAsync(inputStream.EntityType); /* TODO: Shouldn't CreatePolicies be a dictionary and we check for inputStream.EntityType? */ await CheckAnyOfPoliciesAsync(definition.CreatePolicies); @@ -51,7 +51,7 @@ namespace Volo.CmsKit.Admin.MediaDescriptors { var mediaDescriptor = await MediaDescriptorRepository.GetAsync(id); - var definition = await MediaDescriptorDefinitionStore.GetDefinitionAsync(mediaDescriptor.EntityType); + var definition = await MediaDescriptorDefinitionStore.GetAsync(mediaDescriptor.EntityType); /* TODO: Shouldn't DeletePolicies be a dictionary and we check for inputStream.EntityType? */ await CheckAnyOfPoliciesAsync(definition.DeletePolicies); diff --git a/modules/cms-kit/src/Volo.CmsKit.Admin.Application/Volo/CmsKit/Admin/Tags/EntityTagAdminAppService.cs b/modules/cms-kit/src/Volo.CmsKit.Admin.Application/Volo/CmsKit/Admin/Tags/EntityTagAdminAppService.cs index d118ddece7..0095063e2b 100644 --- a/modules/cms-kit/src/Volo.CmsKit.Admin.Application/Volo/CmsKit/Admin/Tags/EntityTagAdminAppService.cs +++ b/modules/cms-kit/src/Volo.CmsKit.Admin.Application/Volo/CmsKit/Admin/Tags/EntityTagAdminAppService.cs @@ -29,7 +29,7 @@ namespace Volo.CmsKit.Admin.Tags public virtual async Task AddTagToEntityAsync(EntityTagCreateDto input) { - var definition = await TagDefinitionStore.GetTagEntityTypeDefinitionAsync(input.EntityType); + var definition = await TagDefinitionStore.GetAsync(input.EntityType); await CheckAnyOfPoliciesAsync(definition.CreatePolicies); @@ -44,7 +44,7 @@ namespace Volo.CmsKit.Admin.Tags public virtual async Task RemoveTagFromEntityAsync(EntityTagRemoveDto input) { - var definition = await TagDefinitionStore.GetTagEntityTypeDefinitionAsync(input.EntityType); + var definition = await TagDefinitionStore.GetAsync(input.EntityType); await CheckAnyOfPoliciesAsync(definition.DeletePolicies); @@ -57,7 +57,7 @@ namespace Volo.CmsKit.Admin.Tags public virtual async Task SetEntityTagsAsync(EntityTagSetDto input) { - var definition = await TagDefinitionStore.GetTagEntityTypeDefinitionAsync(input.EntityType); + var definition = await TagDefinitionStore.GetAsync(input.EntityType); await CheckAnyOfPoliciesAsync(definition.UpdatePolicies); diff --git a/modules/cms-kit/src/Volo.CmsKit.Admin.Web/Pages/CmsKit/BlogPosts/Index.cshtml b/modules/cms-kit/src/Volo.CmsKit.Admin.Web/Pages/CmsKit/BlogPosts/Index.cshtml index 09f3f7f447..b819b0a161 100644 --- a/modules/cms-kit/src/Volo.CmsKit.Admin.Web/Pages/CmsKit/BlogPosts/Index.cshtml +++ b/modules/cms-kit/src/Volo.CmsKit.Admin.Web/Pages/CmsKit/BlogPosts/Index.cshtml @@ -25,16 +25,20 @@ @await Component.InvokeAsync(typeof(AbpPageToolbarViewComponent), new { pageName = typeof(IndexModel).FullName }) } -
- - + + +
@await Component.InvokeAsync(typeof(AbpPageSearchBoxViewComponent)) - - - - -
\ No newline at end of file +
+ + + + + + + + \ No newline at end of file diff --git a/modules/cms-kit/src/Volo.CmsKit.Admin.Web/Pages/CmsKit/Comments/Index.cshtml b/modules/cms-kit/src/Volo.CmsKit.Admin.Web/Pages/CmsKit/Comments/Index.cshtml index 8841d656b0..44fd02e9d8 100644 --- a/modules/cms-kit/src/Volo.CmsKit.Admin.Web/Pages/CmsKit/Comments/Index.cshtml +++ b/modules/cms-kit/src/Volo.CmsKit.Admin.Web/Pages/CmsKit/Comments/Index.cshtml @@ -15,14 +15,14 @@ PageLayout.Content.Title = L["Comments"].Value; PageLayout.Content.BreadCrumb.Add(L["Menu:CMS"].Value); PageLayout.Content.MenuItemName = CmsKitAdminMenus.Comments.CommentsMenu; - + var defaultStartDate = DateTime.Now.AddDays(-7).Date.ToShortDateString(); } @section styles{ - + } @section scripts { @@ -31,9 +31,9 @@ } -
- - + + +
@@ -47,13 +47,13 @@ - + - + - + @@ -64,8 +64,12 @@
- - - - -
\ No newline at end of file +
+ + + + + + + + diff --git a/modules/cms-kit/src/Volo.CmsKit.Admin.Web/Pages/CmsKit/Pages/Index.cshtml b/modules/cms-kit/src/Volo.CmsKit.Admin.Web/Pages/CmsKit/Pages/Index.cshtml index c85d4759ba..ffb1e156e0 100644 --- a/modules/cms-kit/src/Volo.CmsKit.Admin.Web/Pages/CmsKit/Pages/Index.cshtml +++ b/modules/cms-kit/src/Volo.CmsKit.Admin.Web/Pages/CmsKit/Pages/Index.cshtml @@ -1,6 +1,6 @@ @page @using Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared.Pages.Shared.Components.AbpPageToolbar -@using Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared.Pages.Shared.Components.AbpPageSearchBox +@using Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared.Pages.Shared.Components.AbpPageSearchBox @using Volo.CmsKit.Admin.Web.Pages @using Volo.CmsKit.Admin.Web.Menus @using Volo.CmsKit.Admin.Web.Pages.CmsKit.Pages @@ -16,23 +16,27 @@ } @section scripts { - + } @section content_toolbar { - @await Component.InvokeAsync(typeof(AbpPageToolbarViewComponent), new {pageName = typeof(IndexModel).FullName}) + @await Component.InvokeAsync(typeof(AbpPageToolbarViewComponent), new { pageName = typeof(IndexModel).FullName }) } -
- - + + +
@await Component.InvokeAsync(typeof(AbpPageSearchBoxViewComponent)) - - - - -
\ No newline at end of file +
+ + + + + + + + diff --git a/modules/cms-kit/src/Volo.CmsKit.Admin.Web/Pages/CmsKit/Tags/Index.cshtml b/modules/cms-kit/src/Volo.CmsKit.Admin.Web/Pages/CmsKit/Tags/Index.cshtml index b568c2737c..e76f0ad9f5 100644 --- a/modules/cms-kit/src/Volo.CmsKit.Admin.Web/Pages/CmsKit/Tags/Index.cshtml +++ b/modules/cms-kit/src/Volo.CmsKit.Admin.Web/Pages/CmsKit/Tags/Index.cshtml @@ -23,16 +23,20 @@ @await Component.InvokeAsync(typeof(AbpPageToolbarViewComponent), new { pageName = typeof(IndexModel).FullName }) } -
- - + + +
@await Component.InvokeAsync(typeof(AbpPageSearchBoxViewComponent)) - - - -
+
+ + + + + + + \ No newline at end of file diff --git a/modules/cms-kit/src/Volo.CmsKit.Domain.Shared/Volo/CmsKit/CmsKitErrorCodes.cs b/modules/cms-kit/src/Volo.CmsKit.Domain.Shared/Volo/CmsKit/CmsKitErrorCodes.cs index ad1af878a4..9ef2b9bb86 100644 --- a/modules/cms-kit/src/Volo.CmsKit.Domain.Shared/Volo/CmsKit/CmsKitErrorCodes.cs +++ b/modules/cms-kit/src/Volo.CmsKit.Domain.Shared/Volo/CmsKit/CmsKitErrorCodes.cs @@ -13,6 +13,11 @@ public const string SlugAlreadyExist = "CmsKit:Page:0001"; } + public static class Ratings + { + public const string EntityCantHaveRating = "CmsKit:Rating:0001"; + } + public static class Reactions { public const string EntityCantHaveReaction = "CmsKit:Reaction:0001"; diff --git a/modules/cms-kit/src/Volo.CmsKit.Domain.Shared/Volo/CmsKit/Localization/Resources/en.json b/modules/cms-kit/src/Volo.CmsKit.Domain.Shared/Volo/CmsKit/Localization/Resources/en.json index 5638d92fa8..a6d7fc0b57 100644 --- a/modules/cms-kit/src/Volo.CmsKit.Domain.Shared/Volo/CmsKit/Localization/Resources/en.json +++ b/modules/cms-kit/src/Volo.CmsKit.Domain.Shared/Volo/CmsKit/Localization/Resources/en.json @@ -21,6 +21,7 @@ "CmsKit:Media:0001": "'{Name}' is not a valid media name.", "CmsKit:Media:0002": "The entity can't have media.", "CmsKit:Page:0001": "The given url ({0}) already exists.", + "CmsKit:Rating:0001": "The entity {EntityType} can't be rated.", "CmsKit:Reaction:0001": "The entity {EntityType} can't have reactions.", "CmsKit:Tag:0002": "The entity is not taggable!", "CommentAuthorizationExceptionMessage": "Those comments are not allowed for public display.", @@ -45,6 +46,7 @@ "LastModification": "Last Modification", "LoginToAddComment": "Login to add comment", "LoginToRate": "Login to rate", + "LoginToReact": "Login to react", "LoginToReply": "Login to reply", "Menu:CMS": "CMS", "Message": "Message", @@ -82,7 +84,9 @@ "Permission:TagManagement.Delete": "Delete", "Permission:TagManagement.Update": "Update", "PickYourReaction": "Pick your reaction", + "Rating": "Rating", "RatingUndoMessage": "Your rating will be undo.", + "Reactions": "Reactions", "Read": "Read", "RepliesToThisComment": "Replies to this comment", "Reply": "Reply", diff --git a/modules/cms-kit/src/Volo.CmsKit.Domain.Shared/Volo/CmsKit/Localization/Resources/tr.json b/modules/cms-kit/src/Volo.CmsKit.Domain.Shared/Volo/CmsKit/Localization/Resources/tr.json index 73c02088ea..720399dc91 100644 --- a/modules/cms-kit/src/Volo.CmsKit.Domain.Shared/Volo/CmsKit/Localization/Resources/tr.json +++ b/modules/cms-kit/src/Volo.CmsKit.Domain.Shared/Volo/CmsKit/Localization/Resources/tr.json @@ -13,13 +13,14 @@ "CmsKit.Ratings": "Puanlama", "CmsKit.Reactions": "Tepkiler", "CmsKit.Tags": "Etiketler", - "CmsKit:Comments:0001": "{0} ögesi yorumlanabilir değil.", "CmsKit:0002": "İçerik zaten mevcut!", "CmsKit:0003": "{0} ögesi etiketlenebilir değil.", "CmsKit:BlogPost:0001": "Aynı url etiketi zaten mevcut.", + "CmsKit:Comments:0001": "{0} ögesi yorumlanabilir değil.", "CmsKit:Media:0002": "Bu öge için medya eklenemez.", - "CmsKit:Reaction:0001": "Bu ögeye tepki verilemez.", "CmsKit:Page:0001": "Girilen url ({0}) kullanımdadır.", + "CmsKit:Rating:0001": "{EntityType}, puanlanabilir değil.", + "CmsKit:Reaction:0001": "Bu ögeye tepki verilemez.", "CmsKit:Tag:0002": "Bu öge etiketlenebilir değil.", "CommentAuthorizationExceptionMessage": "Bu yorumları görebilmek için yetki gerekir.", "CommentDeletionConfirmationMessage": "Bu yorum ve buna yapılan tüm yorumlan silinecektir!", @@ -44,6 +45,7 @@ "LastModification": "Son Güncellenme", "LoginToAddComment": "Yorum yapmak için giriş yap", "LoginToRate": "Oylamak için giriş yapın", + "LoginToReact": "Reaksiyon vermek için giriş yap", "LoginToReply": "Cevap vermek için giriş yap", "Menu:CMS": "CMS", "Message": "Mesaj", @@ -72,7 +74,9 @@ "Permission:TagManagement.Delete": "Etiket Silme", "Permission:TagManagement.Update": "Etiket Güncelleme", "PickYourReaction": "Tepkinizi seçin", + "Rating": "Puan", "RatingUndoMessage": "Oylamanız geri alınacak.", + "Reactions": "Reaksiyonlar", "Read": "Oku", "RepliesToThisComment": "Bu yoruma yapılan yorumlar", "Reply": "Cevapla", diff --git a/modules/cms-kit/src/Volo.CmsKit.Domain.Shared/Volo/CmsKit/Localization/Resources/zh-Hant.json b/modules/cms-kit/src/Volo.CmsKit.Domain.Shared/Volo/CmsKit/Localization/Resources/zh-Hant.json new file mode 100644 index 0000000000..bf3ff196f0 --- /dev/null +++ b/modules/cms-kit/src/Volo.CmsKit.Domain.Shared/Volo/CmsKit/Localization/Resources/zh-Hant.json @@ -0,0 +1,125 @@ +{ + "culture": "zh-Hant", + "texts": { + "BlogDeletionConfirmationMessage": "部落格 '{0}' 將被刪除. 你確定嗎?", + "BlogFeatureNotAvailable": "目前此功能不可使用. 請用 `GlobalFeatureManager` 來啟用它.", + "BlogId": "部落格", + "BlogPostDeletionConfirmationMessage": "部落格貼文 '{0}' 將被刪除. 你確定嗎?", + "BlogPosts": "部落格貼文", + "Blogs": "部落格", + "ChoosePreference": "選擇 Preference...", + "Cms": "Cms", + "CmsKit.Comments": "評論", + "CmsKit.Ratings": "評分", + "CmsKit.Reactions": "反應", + "CmsKit.Tags": "標籤", + "CmsKit:0002": "內容已經存在!", + "CmsKit:0003": "實體 {0} 不可標記.", + "CmsKit:Blog:0001": "給定的slug ({Slug}) 已經存在!", + "CmsKit:BlogPost:0001": "給定的slug已經存在!", + "CmsKit:Comments:0001": "實體不可 {0} 不可評論.", + "CmsKit:Media:0001": "'{Name}' 不是有效的媒體名稱.", + "CmsKit:Media:0002": "實體不可以含有媒體", + "CmsKit:Page:0001": "給定的url ({0}) 已經存在.", + "CmsKit:Reaction:0001": "實體 {EntityType} 不能有反應", + "CmsKit:Tag:0002": "實體不可標記!", + "CommentAuthorizationExceptionMessage": "些評論不允許公開顯示", + "CommentDeletionConfirmationMessage": "此評論和所有回覆將被刪除!", + "Comments": "評論", + "ContentDeletionConfirmationMessage": "你確定要刪除這個內容嗎?", + "Contents": "內容", + "CoverImage": "封面圖片", + "CreateBlogPostPage": "新部落格貼文", + "CreationTime": "建立時間", + "Delete": "刪除", + "Detail": "詳情", + "Details": "詳情", + "DoYouPreferAdditionalEmails": "你是否更喜歡額外的郵件", + "Edit": "修改", + "EndDate": "結束時間", + "EntityId": "實體Id", + "EntityType": "實體類型", + "ExportCSV": "匯出 CSV", + "Features": "功能", + "GenericDeletionConfirmationMessage": "你確定刪除 '{0}' 嗎?", + "LastModification": "最後一次修改", + "LoginToAddComment": "登錄後添加評論", + "LoginToRate": "登錄後進行評分", + "LoginToReply": "登錄後進行回覆", + "Menu:CMS": "CMS", + "Message": "消息", + "MessageDeletionConfirmationMessage": "這條評論將被完全刪除", + "Name": "名稱", + "New": "新", + "OK": "好", + "PageDeletionConfirmationMessage": "你確定刪除這個頁面嗎?", + "PageSlugInformation": "Slug用於網址. 你的網址將是 '/pages/{{slug}}'.", + "Permission:BlogManagement": "部落格管理", + "Permission:BlogManagement.Create": "創建", + "Permission:BlogManagement.Delete": "刪除", + "Permission:BlogManagement.Features": "功能", + "Permission:BlogManagement.Update": "更新", + "Permission:BlogPostManagement": "部落格貼文管理", + "Permission:BlogPostManagement.Create": "創建", + "Permission:BlogPostManagement.Delete": "刪除", + "Permission:BlogPostManagement.Update": "更新", + "Permission:CmsKit": "Cms工具包", + "Permission:Comments": "評論管理", + "Permission:Comments.Delete": "刪除", + "Permission:Contents": "內容管理", + "Permission:Contents.Create": "創建內容", + "Permission:Contents.Delete": "刪除內容", + "Permission:Contents.Update": "更新內容", + "Permission:MediaDescriptorManagement": "媒體管理", + "Permission:MediaDescriptorManagement:Create": "創建", + "Permission:MediaDescriptorManagement:Delete": "刪除", + "Permission:PageManagement": "頁面管理", + "Permission:PageManagement:Create": "創建", + "Permission:PageManagement:Delete": "刪除", + "Permission:PageManagement:Update": "更新", + "Permission:TagManagement": "標籤管理", + "Permission:TagManagement.Create": "創建", + "Permission:TagManagement.Delete": "刪除", + "Permission:TagManagement.Update": "更新", + "PickYourReaction": "選擇你的回應", + "RatingUndoMessage": "您的評分將被收回", + "Read": "閱讀", + "RepliesToThisComment": "回覆此評論", + "Reply": "回覆", + "ReplyTo": "回覆給", + "SamplePageMessage": "Pro模組的展示頁面", + "SaveChanges": "保存更改", + "SelectAll": "選擇全部", + "Send": "發送", + "SendMessage": "發送消息", + "ShortDescription": "簡介", + "Slug": "Slug", + "Source": "來源", + "SourceUrl": "來源 Url", + "Star": "星", + "StartDate": "開始時間", + "Subject": "主題", + "SubjectPlaceholder": "請輸入主題", + "Submit": "提交", + "Subscribe": "訂閱", + "SuccessfullyDeleted": "刪除成功!", + "SuccessfullySaved": "保存成功!", + "TagDeletionConfirmationMessage": "你確定刪除 '{0}' 標籤嗎?", + "Tags": "標籤", + "Text": "文本", + "ThankYou": "謝謝你", + "Title": "標題", + "Undo": "復原", + "Update": "更新", + "UpdatePreferenceSuccessMessage": "您的 preferences 已經保存", + "UpdateYourEmailPreferences": "更新你的郵件preferences", + "UploadFailedMessage": "上傳失敗", + "UserId": "用戶Id", + "Username": "用戶名稱", + "YourComment": "你的評論", + "YourEmailAddress": "你的郵件地址", + "YourFullName": "你的全名", + "YourMessage": "你的消息", + "YourReply": "你的回覆" + } +} \ No newline at end of file diff --git a/modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/CmsKitDomainModule.cs b/modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/CmsKitDomainModule.cs index e8010d1b3b..53261fc8c2 100644 --- a/modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/CmsKitDomainModule.cs +++ b/modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/CmsKitDomainModule.cs @@ -1,19 +1,15 @@ using Volo.Abp.BlobStoring; -using Microsoft.Extensions.Options; -using System.Collections.Generic; -using Volo.Abp; using Volo.Abp.Domain; using Volo.Abp.GlobalFeatures; using Volo.Abp.Localization; using Volo.Abp.Modularity; using Volo.Abp.Users; +using Volo.CmsKit.Blogs; +using Volo.CmsKit.Comments; using Volo.CmsKit.GlobalFeatures; using Volo.CmsKit.Localization; -using Volo.CmsKit.Pages; +using Volo.CmsKit.Ratings; using Volo.CmsKit.Reactions; -using Volo.CmsKit.Tags; -using Volo.CmsKit.Blogs; -using Volo.CmsKit.Comments; namespace Volo.CmsKit { @@ -67,6 +63,19 @@ namespace Volo.CmsKit }); } + if (GlobalFeatureManager.Instance.IsEnabled()) + { + Configure(options => + { + if (GlobalFeatureManager.Instance.IsEnabled()) + { + options.EntityTypes.Add(new RatingEntityTypeDefinition(BlogPostConsts.EntityType)); + } + + // TODO: Define entity types here which can be rated. + }); + } + if (GlobalFeatureManager.Instance.IsEnabled()) { // TODO: Configure TagEntityTypes here... diff --git a/modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/Comments/CommentEntityTypeDefinition.cs b/modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/Comments/CommentEntityTypeDefinition.cs index fe0f8ebda3..cc235bda4d 100644 --- a/modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/Comments/CommentEntityTypeDefinition.cs +++ b/modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/Comments/CommentEntityTypeDefinition.cs @@ -4,18 +4,11 @@ using Volo.Abp; namespace Volo.CmsKit.Comments { - public class CommentEntityTypeDefinition : IEquatable + public class CommentEntityTypeDefinition : EntityTypeDefinition { - public CommentEntityTypeDefinition([NotNull] string entityType) + public CommentEntityTypeDefinition([NotNull] string entityType) : base(entityType) { EntityType = Check.NotNullOrEmpty(entityType, nameof(entityType)); } - - public string EntityType { get; } - - public bool Equals(CommentEntityTypeDefinition other) - { - return EntityType == other?.EntityType; - } } } diff --git a/modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/Comments/DefaultCommentEntityTypeDefinitionStore.cs b/modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/Comments/DefaultCommentEntityTypeDefinitionStore.cs index bbb1b19aee..ac5ebddb59 100644 --- a/modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/Comments/DefaultCommentEntityTypeDefinitionStore.cs +++ b/modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/Comments/DefaultCommentEntityTypeDefinitionStore.cs @@ -10,7 +10,7 @@ using Volo.Abp.DependencyInjection; namespace Volo.CmsKit.Comments { - public class DefaultCommentEntityTypeDefinitionStore : ICommentEntityTypeDefinitionStore, ITransientDependency + public class DefaultCommentEntityTypeDefinitionStore : ICommentEntityTypeDefinitionStore { protected CmsKitCommentOptions Options { get; } @@ -19,7 +19,7 @@ namespace Volo.CmsKit.Comments Options = options.Value; } - public virtual Task GetDefinitionAsync([NotNull] string entityType) + public virtual Task GetAsync([NotNull] string entityType) { Check.NotNullOrWhiteSpace(entityType, nameof(entityType)); diff --git a/modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/Comments/ICommentEntityTypeDefinitionStore.cs b/modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/Comments/ICommentEntityTypeDefinitionStore.cs index 315b7f878f..da4c56ce25 100644 --- a/modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/Comments/ICommentEntityTypeDefinitionStore.cs +++ b/modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/Comments/ICommentEntityTypeDefinitionStore.cs @@ -1,17 +1,7 @@ -using JetBrains.Annotations; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using Volo.CmsKit.Comments; - -namespace Volo.CmsKit.Comments +namespace Volo.CmsKit.Comments { - public interface ICommentEntityTypeDefinitionStore + public interface ICommentEntityTypeDefinitionStore : IEntityTypeDefinitionStore { - Task GetDefinitionAsync([NotNull] string entityType); - Task IsDefinedAsync([NotNull] string entityType); } } diff --git a/modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/EntityTypeDefinition.cs b/modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/EntityTypeDefinition.cs new file mode 100644 index 0000000000..aed0f040bb --- /dev/null +++ b/modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/EntityTypeDefinition.cs @@ -0,0 +1,22 @@ +using JetBrains.Annotations; +using System; +using Volo.Abp; + +namespace Volo.CmsKit +{ + public abstract class EntityTypeDefinition : IEquatable + { + public EntityTypeDefinition([NotNull] string entityType) + { + EntityType = Check.NotNullOrEmpty(entityType, nameof(entityType)); + } + + [NotNull] + public string EntityType { get; protected set; } + + public bool Equals(EntityTypeDefinition other) + { + return EntityType == other?.EntityType; + } + } +} diff --git a/modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/IEntityTypeDefinitionStore.cs b/modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/IEntityTypeDefinitionStore.cs new file mode 100644 index 0000000000..efe1974a4e --- /dev/null +++ b/modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/IEntityTypeDefinitionStore.cs @@ -0,0 +1,14 @@ +using JetBrains.Annotations; +using System.Threading.Tasks; +using Volo.Abp.DependencyInjection; + +namespace Volo.CmsKit +{ + public interface IEntityTypeDefinitionStore : ITransientDependency + where TPolicyDefinition : EntityTypeDefinition + { + Task GetAsync([NotNull] string entityType); + + Task IsDefinedAsync([NotNull] string entityType); + } +} diff --git a/modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/MediaDescriptors/DefaultMediaDescriptorDefinitionStore.cs b/modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/MediaDescriptors/DefaultMediaDescriptorDefinitionStore.cs index e3caed9904..de191f6014 100644 --- a/modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/MediaDescriptors/DefaultMediaDescriptorDefinitionStore.cs +++ b/modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/MediaDescriptors/DefaultMediaDescriptorDefinitionStore.cs @@ -10,7 +10,7 @@ using Volo.Abp.DependencyInjection; namespace Volo.CmsKit.MediaDescriptors { - public class DefaultMediaDescriptorDefinitionStore : IMediaDescriptorDefinitionStore, ITransientDependency + public class DefaultMediaDescriptorDefinitionStore : IMediaDescriptorDefinitionStore { protected CmsKitMediaOptions Options { get; } @@ -25,7 +25,7 @@ namespace Volo.CmsKit.MediaDescriptors /// EntityType to get definition. /// Thrown when EntityType is not configured as taggable. /// More than one element satisfies the condition in predicate. - public virtual Task GetDefinitionAsync([NotNull] string entityType) + public virtual Task GetAsync([NotNull] string entityType) { Check.NotNullOrWhiteSpace(entityType, nameof(entityType)); diff --git a/modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/MediaDescriptors/IMediaDescriptorDefinitionStore.cs b/modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/MediaDescriptors/IMediaDescriptorDefinitionStore.cs index 9cd5c5c40d..1c3dd2bd62 100644 --- a/modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/MediaDescriptors/IMediaDescriptorDefinitionStore.cs +++ b/modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/MediaDescriptors/IMediaDescriptorDefinitionStore.cs @@ -1,12 +1,7 @@ -using JetBrains.Annotations; -using System.Threading.Tasks; - -namespace Volo.CmsKit.MediaDescriptors +namespace Volo.CmsKit.MediaDescriptors { - public interface IMediaDescriptorDefinitionStore + public interface IMediaDescriptorDefinitionStore : IEntityTypeDefinitionStore { - Task IsDefinedAsync([NotNull] string entityType); - Task GetDefinitionAsync([NotNull] string entityType); } } diff --git a/modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/PolicySpecifiedDefinition.cs b/modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/PolicySpecifiedDefinition.cs index edfee13337..743b5c280a 100644 --- a/modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/PolicySpecifiedDefinition.cs +++ b/modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/PolicySpecifiedDefinition.cs @@ -6,20 +6,14 @@ using Volo.Abp; namespace Volo.CmsKit { - public abstract class PolicySpecifiedDefinition : IEquatable + public abstract class PolicySpecifiedDefinition : EntityTypeDefinition, IEquatable { - protected PolicySpecifiedDefinition() - { - } - public PolicySpecifiedDefinition( [NotNull] string entityType, IEnumerable createPolicies = null, IEnumerable updatePolicies = null, - IEnumerable deletePolicies = null) + IEnumerable deletePolicies = null) : base(entityType) { - EntityType = Check.NotNullOrEmpty(entityType, nameof(entityType)); - if (createPolicies != null) { CreatePolicies = CreatePolicies.Concat(createPolicies).ToList(); @@ -36,9 +30,6 @@ namespace Volo.CmsKit } } - [NotNull] - public string EntityType { get; set; } - [NotNull] public virtual ICollection CreatePolicies { get; } = new List(); diff --git a/modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/Ratings/CmsKitRatingOptions.cs b/modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/Ratings/CmsKitRatingOptions.cs new file mode 100644 index 0000000000..985e726b3c --- /dev/null +++ b/modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/Ratings/CmsKitRatingOptions.cs @@ -0,0 +1,11 @@ +using JetBrains.Annotations; +using System.Collections.Generic; + +namespace Volo.CmsKit.Ratings +{ + public class CmsKitRatingOptions + { + [NotNull] + public List EntityTypes { get; } = new (); + } +} diff --git a/modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/Ratings/DefaultRatingEntityTypeDefinitionStore.cs b/modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/Ratings/DefaultRatingEntityTypeDefinitionStore.cs new file mode 100644 index 0000000000..c0e8136986 --- /dev/null +++ b/modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/Ratings/DefaultRatingEntityTypeDefinitionStore.cs @@ -0,0 +1,38 @@ +using JetBrains.Annotations; +using Microsoft.Extensions.Options; +using System; +using System.Linq; +using System.Threading.Tasks; +using Volo.Abp; + +namespace Volo.CmsKit.Ratings +{ + public class DefaultRatingEntityTypeDefinitionStore : IRatingEntityTypeDefinitionStore + { + protected CmsKitRatingOptions Options { get; } + + public DefaultRatingEntityTypeDefinitionStore(IOptions options) + { + Options = options.Value; + } + + public virtual Task GetAsync([NotNull] string entityType) + { + Check.NotNullOrWhiteSpace(entityType, nameof(entityType)); + + var definition = Options.EntityTypes.SingleOrDefault(x => x.EntityType.Equals(entityType, StringComparison.InvariantCultureIgnoreCase)) ?? + throw new EntityCantHaveRatingException(entityType); + + return Task.FromResult(definition); + } + + public virtual Task IsDefinedAsync([NotNull] string entityType) + { + Check.NotNullOrWhiteSpace(entityType, nameof(entityType)); + + var isDefined = Options.EntityTypes.Any(x => x.EntityType.Equals(entityType, StringComparison.InvariantCultureIgnoreCase)); + + return Task.FromResult(isDefined); + } + } +} diff --git a/modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/Ratings/EntityCantHaveRatingException.cs b/modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/Ratings/EntityCantHaveRatingException.cs new file mode 100644 index 0000000000..82616482d7 --- /dev/null +++ b/modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/Ratings/EntityCantHaveRatingException.cs @@ -0,0 +1,22 @@ +using JetBrains.Annotations; +using System.Runtime.Serialization; +using Volo.Abp; + +namespace Volo.CmsKit.Ratings +{ + public class EntityCantHaveRatingException : BusinessException + { + public EntityCantHaveRatingException(SerializationInfo serializationInfo, StreamingContext context) : base(serializationInfo, context) + { + } + + public EntityCantHaveRatingException([NotNull] string entityType) + { + Code = CmsKitErrorCodes.Ratings.EntityCantHaveRating; + EntityType = Check.NotNullOrEmpty(entityType, nameof(entityType)); + WithData(nameof(EntityType), EntityType); + } + + public string EntityType { get; } + } +} diff --git a/modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/Ratings/IRatingEntityTypeDefinitionStore.cs b/modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/Ratings/IRatingEntityTypeDefinitionStore.cs new file mode 100644 index 0000000000..ad964b272b --- /dev/null +++ b/modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/Ratings/IRatingEntityTypeDefinitionStore.cs @@ -0,0 +1,9 @@ +using Volo.CmsKit.Ratings; + +namespace Volo.CmsKit.Ratings +{ + public interface IRatingEntityTypeDefinitionStore : IEntityTypeDefinitionStore + { + + } +} diff --git a/modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/Ratings/Rating.cs b/modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/Ratings/Rating.cs index a3575cf0b4..dd4b5510a1 100644 --- a/modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/Ratings/Rating.cs +++ b/modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/Ratings/Rating.cs @@ -25,7 +25,7 @@ namespace Volo.CmsKit.Ratings } - public Rating( + internal Rating( Guid id, [NotNull] string entityType, [NotNull] string entityId, diff --git a/modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/Ratings/RatingEntityTypeDefinition.cs b/modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/Ratings/RatingEntityTypeDefinition.cs new file mode 100644 index 0000000000..47534f98ab --- /dev/null +++ b/modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/Ratings/RatingEntityTypeDefinition.cs @@ -0,0 +1,12 @@ +using JetBrains.Annotations; + +namespace Volo.CmsKit.Ratings +{ + public class RatingEntityTypeDefinition : EntityTypeDefinition + { + public RatingEntityTypeDefinition( + [NotNull] string entityType) : base(entityType) + { + } + } +} diff --git a/modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/Ratings/RatingManager.cs b/modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/Ratings/RatingManager.cs new file mode 100644 index 0000000000..7186089deb --- /dev/null +++ b/modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/Ratings/RatingManager.cs @@ -0,0 +1,52 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Volo.Abp.Domain.Services; +using Volo.CmsKit.Users; + +namespace Volo.CmsKit.Ratings +{ + public class RatingManager : DomainService + { + protected IRatingRepository RatingRepository { get; } + protected IRatingEntityTypeDefinitionStore RatingDefinitionStore { get; } + + public RatingManager( + IRatingRepository ratingRepository, + IRatingEntityTypeDefinitionStore ratingDefinitionStore) + { + RatingRepository = ratingRepository; + RatingDefinitionStore = ratingDefinitionStore; + } + + public async Task SetStarAsync(CmsUser user, string entityType, string entityId, short starCount) + { + var currentUserRating = await RatingRepository.GetCurrentUserRatingAsync(entityType, entityId, user.Id); + + if (currentUserRating != null) + { + currentUserRating.SetStarCount(starCount); + + return await RatingRepository.UpdateAsync(currentUserRating); + } + + if (!await RatingDefinitionStore.IsDefinedAsync(entityType)) + { + throw new EntityCantHaveRatingException(entityType); + } + + return await RatingRepository.InsertAsync( + new Rating( + GuidGenerator.Create(), + entityType, + entityId, + starCount, + user.Id, + CurrentTenant.Id + ) + ); + } + } +} diff --git a/modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/Reactions/DefaultReactionDefinitionStore.cs b/modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/Reactions/DefaultReactionDefinitionStore.cs index 8af09e8946..5705a4c091 100644 --- a/modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/Reactions/DefaultReactionDefinitionStore.cs +++ b/modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/Reactions/DefaultReactionDefinitionStore.cs @@ -9,7 +9,7 @@ using Volo.Abp.DependencyInjection; namespace Volo.CmsKit.Reactions { - public class DefaultReactionDefinitionStore : IReactionDefinitionStore, ITransientDependency + public class DefaultReactionDefinitionStore : IReactionDefinitionStore { protected CmsKitReactionOptions Options { get; } @@ -46,6 +46,12 @@ namespace Volo.CmsKit.Reactions return Task.FromResult(isDefined); } + /// + /// Gets single by entityType. + /// + /// EntityType to get definition. + /// Thrown when EntityType is not configured as taggable. + /// More than one element satisfies the condition in predicate. public virtual Task GetAsync([NotNull] string entityType) { Check.NotNullOrWhiteSpace(entityType, nameof(entityType)); diff --git a/modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/Reactions/IReactionDefinitionStore.cs b/modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/Reactions/IReactionDefinitionStore.cs index 23c6d23ee7..ce0be47f23 100644 --- a/modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/Reactions/IReactionDefinitionStore.cs +++ b/modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/Reactions/IReactionDefinitionStore.cs @@ -4,12 +4,8 @@ using JetBrains.Annotations; namespace Volo.CmsKit.Reactions { - public interface IReactionDefinitionStore + public interface IReactionDefinitionStore : IEntityTypeDefinitionStore { - Task IsDefinedAsync([NotNull]string entityType); - - Task GetAsync([NotNull] string entityType); - Task> GetReactionsAsync([NotNull] string entityType); Task GetReactionOrNullAsync([NotNull] string reactionName, [NotNull] string entityType); diff --git a/modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/Tags/DefaultTagDefinitionStore.cs b/modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/Tags/DefaultTagDefinitionStore.cs index dc804d0417..830052fb15 100644 --- a/modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/Tags/DefaultTagDefinitionStore.cs +++ b/modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/Tags/DefaultTagDefinitionStore.cs @@ -9,7 +9,7 @@ using Volo.Abp.DependencyInjection; namespace Volo.CmsKit.Tags { - public class DefaultTagDefinitionStore : ITagDefinitionStore, ITransientDependency + public class DefaultTagDefinitionStore : ITagDefinitionStore { protected CmsKitTagOptions CmsKitTagOptions { get; } @@ -24,7 +24,7 @@ namespace Volo.CmsKit.Tags /// EntityType to get definition. /// Thrown when EntityType is not configured as taggable. /// More than one element satisfies the condition in predicate. - public virtual Task GetTagEntityTypeDefinitionAsync([NotNull] string entityType) + public virtual Task GetAsync([NotNull] string entityType) { Check.NotNullOrWhiteSpace(entityType, nameof(entityType)); diff --git a/modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/Tags/ITagDefinitionStore.cs b/modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/Tags/ITagDefinitionStore.cs index 906cb2b3e4..043b7a7e8a 100644 --- a/modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/Tags/ITagDefinitionStore.cs +++ b/modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/Tags/ITagDefinitionStore.cs @@ -4,12 +4,8 @@ using System.Threading.Tasks; namespace Volo.CmsKit.Tags { - public interface ITagDefinitionStore + public interface ITagDefinitionStore : IEntityTypeDefinitionStore { Task> GetTagEntityTypeDefinitionListAsync(); - - Task GetTagEntityTypeDefinitionAsync([NotNull] string entityType); - - Task IsDefinedAsync([NotNull] string entityType); } } diff --git a/modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/Tags/TagEntityTypeDefiniton.cs b/modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/Tags/TagEntityTypeDefiniton.cs index 6dedb1410e..37f9d16d39 100644 --- a/modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/Tags/TagEntityTypeDefiniton.cs +++ b/modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/Tags/TagEntityTypeDefiniton.cs @@ -11,10 +11,6 @@ namespace Volo.CmsKit.Tags [CanBeNull] public virtual ILocalizableString DisplayName { get; } - protected TagEntityTypeDefiniton() - { - } - public TagEntityTypeDefiniton( [NotNull] string entityType, [CanBeNull] ILocalizableString displayName = null, @@ -23,7 +19,6 @@ namespace Volo.CmsKit.Tags IEnumerable deletePolicies = null) : base(entityType, createPolicies, updatePolicies, deletePolicies) { DisplayName = displayName; - } public bool Equals(TagEntityTypeDefiniton other) diff --git a/modules/cms-kit/src/Volo.CmsKit.Public.Application/Volo/CmsKit/Public/Ratings/RatingPublicAppService.cs b/modules/cms-kit/src/Volo.CmsKit.Public.Application/Volo/CmsKit/Public/Ratings/RatingPublicAppService.cs index 4341157763..f3a9925d72 100644 --- a/modules/cms-kit/src/Volo.CmsKit.Public.Application/Volo/CmsKit/Public/Ratings/RatingPublicAppService.cs +++ b/modules/cms-kit/src/Volo.CmsKit.Public.Application/Volo/CmsKit/Public/Ratings/RatingPublicAppService.cs @@ -13,11 +13,16 @@ namespace Volo.CmsKit.Public.Ratings { protected IRatingRepository RatingRepository { get; } public ICmsUserLookupService CmsUserLookupService { get; } + protected RatingManager RatingManager { get; } - public RatingPublicAppService(IRatingRepository ratingRepository, ICmsUserLookupService cmsUserLookupService) + public RatingPublicAppService( + IRatingRepository ratingRepository, + ICmsUserLookupService cmsUserLookupService, + RatingManager ratingManager) { RatingRepository = ratingRepository; CmsUserLookupService = cmsUserLookupService; + RatingManager = ratingManager; } [Authorize] @@ -27,26 +32,7 @@ namespace Volo.CmsKit.Public.Ratings var userId = CurrentUser.GetId(); var user = await CmsUserLookupService.GetByIdAsync(userId); - var currentUserRating = await RatingRepository.GetCurrentUserRatingAsync(entityType, entityId, userId); - - if (currentUserRating != null) - { - currentUserRating.SetStarCount(input.StarCount); - var updatedRating = await RatingRepository.UpdateAsync(currentUserRating); - - return ObjectMapper.Map(updatedRating); - } - - var rating = await RatingRepository.InsertAsync( - new Rating( - GuidGenerator.Create(), - entityType, - entityId, - input.StarCount, - user.Id, - CurrentTenant.Id - ) - ); + var rating = await RatingManager.SetStarAsync(user, entityType, entityId, input.StarCount); return ObjectMapper.Map(rating); } diff --git a/modules/cms-kit/src/Volo.CmsKit.Public.Web/Pages/CmsKit/Shared/Components/Blogs/BlogPost/Default.cshtml b/modules/cms-kit/src/Volo.CmsKit.Public.Web/Pages/CmsKit/Shared/Components/Blogs/BlogPost/Default.cshtml deleted file mode 100644 index 46f7749d8b..0000000000 --- a/modules/cms-kit/src/Volo.CmsKit.Public.Web/Pages/CmsKit/Shared/Components/Blogs/BlogPost/Default.cshtml +++ /dev/null @@ -1,28 +0,0 @@ -@model Volo.CmsKit.Public.Blogs.BlogPostPublicDto -@using Volo.CmsKit.Localization -@using Microsoft.Extensions.Localization - -@inject IStringLocalizer L - -@{ - const string dummyImageSource = "https://dummyimage.com/300x200/a3a3a3/fff.png"; -} - - - - - @Model.Title - @Model.Author?.UserName - - @Html.Raw(Model.Content) - - - @Model.CreationTime - @if (Model.LastModificationTime != null) - { - @L["LastModification"].Value : @Model.LastModificationTime - } - - - - diff --git a/modules/cms-kit/src/Volo.CmsKit.Public.Web/Pages/CmsKit/Shared/Components/Blogs/BlogPost/DefaultBlogPostViewComponent.cs b/modules/cms-kit/src/Volo.CmsKit.Public.Web/Pages/CmsKit/Shared/Components/Blogs/BlogPost/DefaultBlogPostViewComponent.cs deleted file mode 100644 index 90dc2a6ab0..0000000000 --- a/modules/cms-kit/src/Volo.CmsKit.Public.Web/Pages/CmsKit/Shared/Components/Blogs/BlogPost/DefaultBlogPostViewComponent.cs +++ /dev/null @@ -1,29 +0,0 @@ -using Microsoft.AspNetCore.Mvc; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using Volo.Abp.AspNetCore.Mvc; -using Volo.CmsKit.Public.Blogs; - -namespace Volo.CmsKit.Public.Web.Pages.CmsKit.Shared.Components.Blogs.BlogPost -{ - [ViewComponent(Name = "CmsDefaultBlogPost")] - public class DefaultBlogPostViewComponent : AbpViewComponent - { - protected IBlogPostPublicAppService BlogPostPublicAppService { get; } - - public DefaultBlogPostViewComponent(IBlogPostPublicAppService blogPostPublicAppService) - { - BlogPostPublicAppService = blogPostPublicAppService; - } - - public virtual async Task InvokeAsync(string blogSlug, string blogPostSlug) - { - var blogPost = await BlogPostPublicAppService.GetAsync(blogSlug, blogPostSlug); - - return View("~/Pages/CmsKit/Shared/Components/Blogs/BlogPost/Default.cshtml", blogPost); - } - } -} diff --git a/modules/cms-kit/src/Volo.CmsKit.Public.Web/Pages/CmsKit/Shared/Components/Blogs/BlogPostComment/Default.cshtml b/modules/cms-kit/src/Volo.CmsKit.Public.Web/Pages/CmsKit/Shared/Components/Blogs/BlogPostComment/Default.cshtml index c34f64eb0c..aac65629f4 100644 --- a/modules/cms-kit/src/Volo.CmsKit.Public.Web/Pages/CmsKit/Shared/Components/Blogs/BlogPostComment/Default.cshtml +++ b/modules/cms-kit/src/Volo.CmsKit.Public.Web/Pages/CmsKit/Shared/Components/Blogs/BlogPostComment/Default.cshtml @@ -7,16 +7,9 @@ @model DefaultBlogPostCommentViewComponent.DefaultBlogPostCommentViewModel - - - - @L["Comments"] - - + @await Component.InvokeAsync(typeof(CommentingViewComponent), new { entityType = Model.EntityType, entityId = Model.EntityId - }) - - \ No newline at end of file + }) \ No newline at end of file diff --git a/modules/cms-kit/src/Volo.CmsKit.Public.Web/Pages/CmsKit/Shared/Components/Commenting/Default.cshtml b/modules/cms-kit/src/Volo.CmsKit.Public.Web/Pages/CmsKit/Shared/Components/Commenting/Default.cshtml index 1dc4ca37ff..062afddc4d 100644 --- a/modules/cms-kit/src/Volo.CmsKit.Public.Web/Pages/CmsKit/Shared/Components/Commenting/Default.cshtml +++ b/modules/cms-kit/src/Volo.CmsKit.Public.Web/Pages/CmsKit/Shared/Components/Commenting/Default.cshtml @@ -25,7 +25,7 @@ } @{ Func GetCommentArea(Guid? repliedCommentId, bool cancelButton = false) => - @
@@ -113,7 +113,7 @@
; } -
+
@if (CurrentUser.IsAuthenticated) {
@@ -129,28 +129,28 @@ @foreach (var comment in Model.Comments) {
-
+
@GetCommentTitle(comment.Author, comment.CreationTime).Invoke(null)
@GetCommentContentArea(comment.Id, comment.Text).Invoke(null) -
-
-
- @GetCommentActionArea(comment.Id, comment.Author.Id, false).Invoke(null) +
+
+
+ @GetCommentActionArea(comment.Id, comment.Author.Id, false).Invoke(null) +
-
-
-
- @if (cmsKitUiOptions.Value.CommentsOptions.IsReactionsEnabled && GlobalFeatureManager.Instance.IsEnabled()) - { - @await Component.InvokeAsync(typeof(ReactionSelectionViewComponent), new { entityType = "comment", entityId = comment.Id.ToString() }) - } +
+
+ @if (cmsKitUiOptions.Value.CommentsOptions.IsReactionsEnabled && GlobalFeatureManager.Instance.IsEnabled()) + { + @await Component.InvokeAsync(typeof(ReactionSelectionViewComponent), new { entityType = "comment", entityId = comment.Id.ToString() }) + } +
-
@GetEditArea(comment.Id, comment.Text).Invoke(null) @if (comment.Replies.Any()) @@ -165,21 +165,21 @@ @GetCommentContentArea(reply.Id, reply.Text).Invoke(null) -
-
-
- @GetCommentActionArea(reply.Id, reply.Author.Id, true).Invoke(null) +
+
+
+ @GetCommentActionArea(reply.Id, reply.Author.Id, true).Invoke(null) +
-
-
-
- @if (cmsKitUiOptions.Value.CommentsOptions.IsReactionsEnabled && GlobalFeatureManager.Instance.IsEnabled()) - { - @await Component.InvokeAsync(typeof(ReactionSelectionViewComponent), new { entityType = "comment", entityId = reply.Id.ToString() }) - } +
+
+ @if (cmsKitUiOptions.Value.CommentsOptions.IsReactionsEnabled && GlobalFeatureManager.Instance.IsEnabled()) + { + @await Component.InvokeAsync(typeof(ReactionSelectionViewComponent), new { entityType = "comment", entityId = reply.Id.ToString() }) + } +
-
@GetEditArea(reply.Id, reply.Text).Invoke(null)
@@ -190,7 +190,7 @@
@if (CurrentUser.IsAuthenticated) { - + @L["Reply"] } @@ -210,3 +210,4 @@
}
+ \ No newline at end of file diff --git a/modules/cms-kit/src/Volo.CmsKit.Public.Web/Pages/CmsKit/Shared/Components/Rating/Default.cshtml b/modules/cms-kit/src/Volo.CmsKit.Public.Web/Pages/CmsKit/Shared/Components/Rating/Default.cshtml index de6424d083..4a64c1c4a8 100644 --- a/modules/cms-kit/src/Volo.CmsKit.Public.Web/Pages/CmsKit/Shared/Components/Rating/Default.cshtml +++ b/modules/cms-kit/src/Volo.CmsKit.Public.Web/Pages/CmsKit/Shared/Components/Rating/Default.cshtml @@ -5,57 +5,68 @@ @model Volo.CmsKit.Public.Web.Pages.CmsKit.Shared.Components.Rating.RatingViewModel @inject IHtmlLocalizer L -
-
- @if (CurrentUser.IsAuthenticated) - { - - @(Model.CurrentRating != null ? Model.CurrentRating + " " : 0 + "") - @if (Model.CurrentRating != null) - { - - @L["Undo"] - - } - if (Model.Ratings != null) - { - - - +
+
+
+ + @L["Rating"] + +
+
+
+ @if (CurrentUser.IsAuthenticated) + { + @if (Model.CurrentRating != null) + { + + @L["Undo"] + + } + if (Model.Ratings != null) + { + + + -
\ No newline at end of file diff --git a/modules/cms-kit/src/Volo.CmsKit.Public.Web/Pages/CmsKit/Shared/Components/Rating/default.css b/modules/cms-kit/src/Volo.CmsKit.Public.Web/Pages/CmsKit/Shared/Components/Rating/default.css index eb46cf8f04..e8aa16162a 100644 --- a/modules/cms-kit/src/Volo.CmsKit.Public.Web/Pages/CmsKit/Shared/Components/Rating/default.css +++ b/modules/cms-kit/src/Volo.CmsKit.Public.Web/Pages/CmsKit/Shared/Components/Rating/default.css @@ -49,4 +49,22 @@ } .rating-undo-link:hover { text-decoration:none; +} +.reaction-in-comment span.area-title { + display: none; +} + +span.area-title { + font-weight: 600; + padding: 3px; + display: block; +} +.reaction-in-comment .card { + border: 0 !important; + padding: 0 !important; + margin: 0 !important; +} + +.popover { + min-width: 276px; } \ No newline at end of file diff --git a/modules/cms-kit/src/Volo.CmsKit.Public.Web/Pages/CmsKit/Shared/Components/ReactionSelection/Default.cshtml b/modules/cms-kit/src/Volo.CmsKit.Public.Web/Pages/CmsKit/Shared/Components/ReactionSelection/Default.cshtml index b95d679fda..8aaac7d8db 100644 --- a/modules/cms-kit/src/Volo.CmsKit.Public.Web/Pages/CmsKit/Shared/Components/ReactionSelection/Default.cshtml +++ b/modules/cms-kit/src/Volo.CmsKit.Public.Web/Pages/CmsKit/Shared/Components/ReactionSelection/Default.cshtml @@ -1,17 +1,32 @@ @inject ICurrentUser CurrentUser +@inject IHtmlLocalizer L @using Volo.Abp.Users +@using Volo.CmsKit.Localization +@using Microsoft.AspNetCore.Mvc.Localization @model Volo.CmsKit.Public.Web.Pages.CmsKit.Shared.Components.ReactionSelection.ReactionSelectionViewComponent.ReactionSelectionViewModel -@if (CurrentUser.IsAuthenticated || Model.Reactions.Count(r => r.Count > 0) > 0) -{ -
-
+ +
+
+
+ + @L["Reactions"] + +
+
+ @foreach (var reaction in Model.Reactions.Where(r => r.Count > 0)) + { + + + @(reaction.Count) + + } @if (CurrentUser.IsAuthenticated) { - - + + } - @foreach (var reaction in Model.Reactions.Where(r => r.Count > 0)) + else { - - - @(reaction.Count) +
"> + }
-} +
\ No newline at end of file diff --git a/modules/cms-kit/src/Volo.CmsKit.Public.Web/Pages/CmsKit/Shared/Components/ReactionSelection/ReactionSelectionViewComponent.cs b/modules/cms-kit/src/Volo.CmsKit.Public.Web/Pages/CmsKit/Shared/Components/ReactionSelection/ReactionSelectionViewComponent.cs index ff10ea662c..46869a3399 100644 --- a/modules/cms-kit/src/Volo.CmsKit.Public.Web/Pages/CmsKit/Shared/Components/ReactionSelection/ReactionSelectionViewComponent.cs +++ b/modules/cms-kit/src/Volo.CmsKit.Public.Web/Pages/CmsKit/Shared/Components/ReactionSelection/ReactionSelectionViewComponent.cs @@ -4,6 +4,7 @@ using JetBrains.Annotations; using Microsoft.AspNetCore.Mvc; using Microsoft.Extensions.Options; using Volo.Abp.AspNetCore.Mvc; +using Volo.Abp.AspNetCore.Mvc.UI; using Volo.Abp.AspNetCore.Mvc.UI.Widgets; using Volo.CmsKit.Public.Reactions; using Volo.CmsKit.Web; @@ -23,12 +24,16 @@ namespace Volo.CmsKit.Public.Web.Pages.CmsKit.Shared.Components.ReactionSelectio protected CmsKitUiOptions Options { get; } + public AbpMvcUiOptions AbpMvcUiOptions { get; } + public ReactionSelectionViewComponent( IReactionPublicAppService reactionPublicAppService, - IOptions options) + IOptions options, + IOptions abpMvcUiOptions) { ReactionPublicAppService = reactionPublicAppService; Options = options.Value; + AbpMvcUiOptions = abpMvcUiOptions.Value; } public virtual async Task InvokeAsync( @@ -37,11 +42,15 @@ namespace Volo.CmsKit.Public.Web.Pages.CmsKit.Shared.Components.ReactionSelectio { var result = await ReactionPublicAppService.GetForSelectionAsync(entityType, entityId); + var loginUrl = + $"{AbpMvcUiOptions.LoginUrl}?returnUrl={HttpContext.Request.Path.ToString()}&returnUrlHash=#cms-rating_{entityType}_{entityId}"; + var viewModel = new ReactionSelectionViewModel { EntityType = entityType, EntityId = entityId, - Reactions = new List() + Reactions = new List(), + LoginUrl = loginUrl }; foreach (var reactionDto in result.Items) @@ -67,6 +76,8 @@ namespace Volo.CmsKit.Public.Web.Pages.CmsKit.Shared.Components.ReactionSelectio public string EntityId { get; set; } public List Reactions { get; set; } + + public string LoginUrl { get; set; } } public class ReactionViewModel diff --git a/modules/cms-kit/src/Volo.CmsKit.Public.Web/Pages/CmsKit/Shared/Components/ReactionSelection/default.css b/modules/cms-kit/src/Volo.CmsKit.Public.Web/Pages/CmsKit/Shared/Components/ReactionSelection/default.css index 7ce8d0fc02..2bea61970d 100644 --- a/modules/cms-kit/src/Volo.CmsKit.Public.Web/Pages/CmsKit/Shared/Components/ReactionSelection/default.css +++ b/modules/cms-kit/src/Volo.CmsKit.Public.Web/Pages/CmsKit/Shared/Components/ReactionSelection/default.css @@ -5,4 +5,16 @@ width: 25%; display: inline-block; float: left; +} +.reaction-in-comment span.area-title { + display: none; +} + +span.area-title { + font-weight: 600; + padding: 3px; + display: block; +} +.popover { + min-width: 276px; } \ No newline at end of file diff --git a/modules/cms-kit/src/Volo.CmsKit.Public.Web/Pages/CmsKit/Shared/Components/Tags/Default.cshtml b/modules/cms-kit/src/Volo.CmsKit.Public.Web/Pages/CmsKit/Shared/Components/Tags/Default.cshtml index f7c61dbc81..bb7b95e08f 100644 --- a/modules/cms-kit/src/Volo.CmsKit.Public.Web/Pages/CmsKit/Shared/Components/Tags/Default.cshtml +++ b/modules/cms-kit/src/Volo.CmsKit.Public.Web/Pages/CmsKit/Shared/Components/Tags/Default.cshtml @@ -2,12 +2,16 @@ @model TagViewComponent.TagViewModel -@if (Model.Tags != null) -{ - foreach (var tag in Model.Tags) - { - - @tag.Name - - } -} \ No newline at end of file +
+
+ @if (Model.Tags != null) + { + foreach (var tag in Model.Tags) + { + + @tag.Name + + } + } +
+
\ No newline at end of file diff --git a/modules/cms-kit/src/Volo.CmsKit.Public.Web/Pages/CmsKit/Shared/Components/Tags/TagViewComponent.cs b/modules/cms-kit/src/Volo.CmsKit.Public.Web/Pages/CmsKit/Shared/Components/Tags/TagViewComponent.cs index c40408117a..33031c4c21 100644 --- a/modules/cms-kit/src/Volo.CmsKit.Public.Web/Pages/CmsKit/Shared/Components/Tags/TagViewComponent.cs +++ b/modules/cms-kit/src/Volo.CmsKit.Public.Web/Pages/CmsKit/Shared/Components/Tags/TagViewComponent.cs @@ -5,12 +5,17 @@ using System.Linq; using System.Text; using System.Threading.Tasks; using Volo.Abp.AspNetCore.Mvc; +using Volo.Abp.AspNetCore.Mvc.UI.Widgets; using Volo.CmsKit.Public.Tags; using Volo.CmsKit.Tags; namespace Volo.CmsKit.Public.Web.Pages.CmsKit.Shared.Components.Tags { - [ViewComponent(Name = "CmsTags")] + [Widget( + StyleFiles = new[] + { + "/Pages/CmsKit/Shared/Components/Tags/default.css" + })] public class TagViewComponent : AbpViewComponent { protected readonly ITagAppService TagAppService; diff --git a/modules/cms-kit/src/Volo.CmsKit.Public.Web/Pages/CmsKit/Shared/Components/Tags/default.css b/modules/cms-kit/src/Volo.CmsKit.Public.Web/Pages/CmsKit/Shared/Components/Tags/default.css new file mode 100644 index 0000000000..3465bb45be --- /dev/null +++ b/modules/cms-kit/src/Volo.CmsKit.Public.Web/Pages/CmsKit/Shared/Components/Tags/default.css @@ -0,0 +1,14 @@ + +.reaction-in-comment span.area-title { + display: none; +} + +span.area-title { + font-weight: 600; + padding: 3px; + display: block; +} + +.popover { + min-width: 276px; +} \ No newline at end of file diff --git a/modules/cms-kit/src/Volo.CmsKit.Public.Web/Pages/Public/CmsKit/Blogs/BlogPost.cshtml b/modules/cms-kit/src/Volo.CmsKit.Public.Web/Pages/Public/CmsKit/Blogs/BlogPost.cshtml index 8ad6dd9ca3..491ae75e8d 100644 --- a/modules/cms-kit/src/Volo.CmsKit.Public.Web/Pages/Public/CmsKit/Blogs/BlogPost.cshtml +++ b/modules/cms-kit/src/Volo.CmsKit.Public.Web/Pages/Public/CmsKit/Blogs/BlogPost.cshtml @@ -1,6 +1,5 @@ @page -@using Volo.CmsKit.Public.Web.Pages.CmsKit.Shared.Components.Blogs.BlogPost @using Volo.CmsKit.Public.Web.Pages.CmsKit.Shared.Components.Blogs.BlogPostComment @using Volo.CmsKit.Public.Web.Pages @using Volo.Abp.GlobalFeatures @@ -13,49 +12,82 @@ @model Volo.CmsKit.Public.Web.Pages.Public.CmsKit.Blogs.BlogPostModel -@await Component.InvokeAsync(typeof(DefaultBlogPostViewComponent), new -{ - Model.BlogSlug, - Model.BlogPostSlug -}) -@if (GlobalFeatureManager.Instance.IsEnabled()) -{ - if (Model.TagsFeature?.IsEnabled == true) - { - @await Component.InvokeAsync(typeof(TagViewComponent), new - { - entityType = Volo.CmsKit.Blogs.BlogPostConsts.EntityType, - entityId = Model.BlogPost.Id.ToString() - }) - } +@section styles{ + } -@if (GlobalFeatureManager.Instance.IsEnabled()) -{ - if (Model.ReactionsFeature?.IsEnabled == true) - { - @await Component.InvokeAsync(typeof(ReactionSelectionViewComponent), new - { - entityType = Volo.CmsKit.Blogs.BlogPostConsts.EntityType, - entityId = Model.BlogPost.Id.ToString() - }) - } +@{ + string dummyImageSource = "https://dummyimage.com/1280x720/a3a3a3/fff.png?text=" + Model.BlogPost.Title; } -@if (GlobalFeatureManager.Instance.IsEnabled()) -{ - if (Model.RatingsFeature?.IsEnabled == true) - { - @await Component.InvokeAsync(typeof(RatingViewComponent), new - { - entityType = Volo.CmsKit.Blogs.BlogPostConsts.EntityType, - entityId = Model.BlogPost.Id.ToString() - }) - } -} + + + + +
+

@Model.BlogPost.Title

+

+ @@@Model.BlogPost.Author?.UserName + @Model.BlogPost.CreationTime +

+ @Html.Raw(Model.BlogPost.Content) +

+ @if (Model.BlogPost.LastModificationTime != null) + { + @L["LastModification"].Value : @Model.BlogPost.LastModificationTime + } +

+
+ + @if (GlobalFeatureManager.Instance.IsEnabled()) + { + if (Model.TagsFeature?.IsEnabled == true) + { + @await Component.InvokeAsync(typeof(TagViewComponent), new + { + entityType = Volo.CmsKit.Blogs.BlogPostConsts.EntityType, + entityId = Model.BlogPost.Id.ToString() + }) + } + } +
+
+ + + + @if (GlobalFeatureManager.Instance.IsEnabled()) + { + if (Model.ReactionsFeature?.IsEnabled == true) + { + @await Component.InvokeAsync(typeof(ReactionSelectionViewComponent), new + { + entityType = Volo.CmsKit.Blogs.BlogPostConsts.EntityType, + entityId = Model.BlogPost.Id.ToString() + }) + } + } + + + + @if (GlobalFeatureManager.Instance.IsEnabled()) + { + if (Model.RatingsFeature?.IsEnabled == true) + { + @await Component.InvokeAsync(typeof(RatingViewComponent), new + { + entityType = Volo.CmsKit.Blogs.BlogPostConsts.EntityType, + entityId = Model.BlogPost.Id.ToString() + }) + } + } + + + +
+
+ -
@if (GlobalFeatureManager.Instance.IsEnabled()) { diff --git a/modules/cms-kit/src/Volo.CmsKit.Public.Web/Pages/Public/CmsKit/Blogs/Index.cshtml b/modules/cms-kit/src/Volo.CmsKit.Public.Web/Pages/Public/CmsKit/Blogs/Index.cshtml index b58e6d1543..c3cc22b91d 100644 --- a/modules/cms-kit/src/Volo.CmsKit.Public.Web/Pages/Public/CmsKit/Blogs/Index.cshtml +++ b/modules/cms-kit/src/Volo.CmsKit.Public.Web/Pages/Public/CmsKit/Blogs/Index.cshtml @@ -7,53 +7,45 @@ @model IndexModel +@section styles{ + +} @{ - const string dummyImageSource = "https://dummyimage.com/300x200/a3a3a3/fff.png"; + const string dummyImageSource = "https://dummyimage.com/320x180/a3a3a3/fff.png"; } @foreach (var blog in Model.Blogs.Items) { - + - - - @blog.Title - - - @@@blog.Author?.UserName - - - - @if (blog.CoverImageMediaId != null) - { - - } - else - { - - } - - @blog.ShortDescription - - - - - - + @if (blog.CoverImageMediaId != null) + { + + } + else + { + + } + +
@blog.Title
+

+ @@@blog.Author?.UserName + @blog.CreationTime +

+

@blog.ShortDescription

+ + @L["Read"] +
- - - @blog.CreationTime - -
}
- + + + diff --git a/modules/cms-kit/src/Volo.CmsKit.Public.Web/Pages/Public/CmsKit/Blogs/blogPost.css b/modules/cms-kit/src/Volo.CmsKit.Public.Web/Pages/Public/CmsKit/Blogs/blogPost.css new file mode 100644 index 0000000000..f4543f9870 --- /dev/null +++ b/modules/cms-kit/src/Volo.CmsKit.Public.Web/Pages/Public/CmsKit/Blogs/blogPost.css @@ -0,0 +1,23 @@ +.card-body img { + max-width: 100%; + border-radius: 4px; + margin: 20px 0; +} + +.badge.badge-light { + color: #757575; + background: #f2f2f2; +} + +.reaction-in-comment span.area-title { + display: none; +} + +span.area-title { + font-weight: 600; + padding: 3px; + display: block; +} +.popover { + min-width: 276px; +} \ No newline at end of file diff --git a/modules/cms-kit/src/Volo.CmsKit.Public.Web/Pages/Public/CmsKit/Blogs/index.css b/modules/cms-kit/src/Volo.CmsKit.Public.Web/Pages/Public/CmsKit/Blogs/index.css new file mode 100644 index 0000000000..48e71edcf9 --- /dev/null +++ b/modules/cms-kit/src/Volo.CmsKit.Public.Web/Pages/Public/CmsKit/Blogs/index.css @@ -0,0 +1,6 @@ +.card-img-top { +} + +.popover { + min-width: 276px; +} \ No newline at end of file diff --git a/modules/cms-kit/src/Volo.CmsKit.Public.Web/Pages/Public/CmsKit/Pages/Index.cshtml b/modules/cms-kit/src/Volo.CmsKit.Public.Web/Pages/Public/CmsKit/Pages/Index.cshtml index 426b5ebacf..7503bcfaa4 100644 --- a/modules/cms-kit/src/Volo.CmsKit.Public.Web/Pages/Public/CmsKit/Pages/Index.cshtml +++ b/modules/cms-kit/src/Volo.CmsKit.Public.Web/Pages/Public/CmsKit/Pages/Index.cshtml @@ -5,6 +5,9 @@ @model Volo.CmsKit.Public.Web.Pages.Public.CmsKit.Pages.IndexModel @inject IHtmlLocalizer L +@section styles{ + +} @await Component.InvokeAsync(typeof(DefaultPageViewComponent), new { diff --git a/modules/cms-kit/src/Volo.CmsKit.Public.Web/Pages/Public/CmsKit/Pages/index.css b/modules/cms-kit/src/Volo.CmsKit.Public.Web/Pages/Public/CmsKit/Pages/index.css new file mode 100644 index 0000000000..48e71edcf9 --- /dev/null +++ b/modules/cms-kit/src/Volo.CmsKit.Public.Web/Pages/Public/CmsKit/Pages/index.css @@ -0,0 +1,6 @@ +.card-img-top { +} + +.popover { + min-width: 276px; +} \ No newline at end of file diff --git a/modules/cms-kit/src/Volo.CmsKit.Public.Web/Properties/launchSettings.json b/modules/cms-kit/src/Volo.CmsKit.Public.Web/Properties/launchSettings.json deleted file mode 100644 index 60e2c66615..0000000000 --- a/modules/cms-kit/src/Volo.CmsKit.Public.Web/Properties/launchSettings.json +++ /dev/null @@ -1,27 +0,0 @@ -{ - "iisSettings": { - "windowsAuthentication": false, - "anonymousAuthentication": true, - "iisExpress": { - "applicationUrl": "http://localhost:60873/", - "sslPort": 44300 - } - }, - "profiles": { - "IIS Express": { - "commandName": "IISExpress", - "launchBrowser": true, - "environmentVariables": { - "ASPNETCORE_ENVIRONMENT": "Development" - } - }, - "Volo.CmsKit.Public.Web": { - "commandName": "Project", - "launchBrowser": true, - "environmentVariables": { - "ASPNETCORE_ENVIRONMENT": "Development" - }, - "applicationUrl": "https://localhost:5001;http://localhost:5000" - } - } -} \ No newline at end of file diff --git a/modules/cms-kit/src/Volo.CmsKit.Public.Web/Volo.CmsKit.Public.Web.csproj b/modules/cms-kit/src/Volo.CmsKit.Public.Web/Volo.CmsKit.Public.Web.csproj index 5f19bdd904..2003412559 100644 --- a/modules/cms-kit/src/Volo.CmsKit.Public.Web/Volo.CmsKit.Public.Web.csproj +++ b/modules/cms-kit/src/Volo.CmsKit.Public.Web/Volo.CmsKit.Public.Web.csproj @@ -29,4 +29,9 @@ + + + + + diff --git a/modules/cms-kit/test/Volo.CmsKit.Domain.Tests/Ratings/RatingManager_Test.cs b/modules/cms-kit/test/Volo.CmsKit.Domain.Tests/Ratings/RatingManager_Test.cs new file mode 100644 index 0000000000..35927fcb4b --- /dev/null +++ b/modules/cms-kit/test/Volo.CmsKit.Domain.Tests/Ratings/RatingManager_Test.cs @@ -0,0 +1,66 @@ +using Shouldly; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Volo.CmsKit.Blogs; +using Volo.CmsKit.Users; +using Xunit; + +namespace Volo.CmsKit.Ratings +{ + public class RatingManager_Test : CmsKitDomainTestBase + { + private readonly CmsKitTestData _cmsKitTestData; + private readonly RatingManager _ratingManager; + private readonly ICmsUserRepository _userRepository; + + public RatingManager_Test() + { + _cmsKitTestData = GetRequiredService(); + _ratingManager = GetRequiredService(); + _userRepository = GetRequiredService(); + } + + [Fact] + public async Task SetStarAsync_ShouldCreate_WhenFirstCall() + { + var user = await _userRepository.GetAsync(_cmsKitTestData.User1Id); + short starCount = 4; + + var rating = await _ratingManager.SetStarAsync(user, _cmsKitTestData.EntityType1, _cmsKitTestData.BlogPost_1_Id.ToString(), starCount); + + rating.ShouldNotBeNull(); + rating.Id.ShouldNotBe(Guid.Empty); + rating.StarCount.ShouldBe(starCount); + } + + [Fact] + public async Task SetStarAsync_ShouldUpdate_WithExistingRating() + { + var user = await _userRepository.GetAsync(_cmsKitTestData.User1Id); + short starCount = 2; + + var rating = await _ratingManager.SetStarAsync(user, _cmsKitTestData.EntityType1, _cmsKitTestData.EntityId1, starCount); + + rating.ShouldNotBeNull(); + rating.Id.ShouldNotBe(Guid.Empty); + rating.StarCount.ShouldBe(starCount); + } + + [Fact] + public async Task SetStarAsync_ShouldThrowException_WithNotConfiguredentityType() + { + var user = await _userRepository.GetAsync(_cmsKitTestData.User1Id); + var notConfiguredEntityType = "AnyOtherEntityType"; + short starCount = 3; + + var exception = await Should.ThrowAsync(async () => + await _ratingManager.SetStarAsync(user, notConfiguredEntityType, "1", starCount)); + + exception.ShouldNotBeNull(); + exception.EntityType.ShouldBe(notConfiguredEntityType); + } + } +} diff --git a/modules/cms-kit/test/Volo.CmsKit.TestBase/CmsKitDataSeedContributor.cs b/modules/cms-kit/test/Volo.CmsKit.TestBase/CmsKitDataSeedContributor.cs index 7971972227..02f10de384 100644 --- a/modules/cms-kit/test/Volo.CmsKit.TestBase/CmsKitDataSeedContributor.cs +++ b/modules/cms-kit/test/Volo.CmsKit.TestBase/CmsKitDataSeedContributor.cs @@ -46,6 +46,7 @@ namespace Volo.CmsKit private readonly BlogManager _blogManager; private readonly IOptions _mediaOptions; private readonly IOptions _commentsOptions; + private readonly IOptions _ratingOptions; public CmsKitDataSeedContributor( IGuidGenerator guidGenerator, @@ -70,7 +71,8 @@ namespace Volo.CmsKit IBlobContainer mediaBlobContainer, BlogManager blogManager, IOptions cmsMediaOptions, - IOptions commentsOptions) + IOptions commentsOptions, + IOptions ratingOptions) { _guidGenerator = guidGenerator; _cmsUserRepository = cmsUserRepository; @@ -95,6 +97,7 @@ namespace Volo.CmsKit _blogManager = blogManager; _mediaOptions = cmsMediaOptions; _commentsOptions = commentsOptions; + this._ratingOptions = ratingOptions; } public async Task SeedAsync(DataSeedContext context) @@ -159,6 +162,9 @@ namespace Volo.CmsKit _reactionOptions.Value.EntityTypes.Add(new ReactionEntityTypeDefinition(_cmsKitTestData.EntityType1, reactions)); _reactionOptions.Value.EntityTypes.Add(new ReactionEntityTypeDefinition(_cmsKitTestData.EntityType2, reactions)); + _ratingOptions.Value.EntityTypes.Add(new RatingEntityTypeDefinition(_cmsKitTestData.EntityType1)); + _ratingOptions.Value.EntityTypes.Add(new RatingEntityTypeDefinition(_cmsKitTestData.EntityType2)); + return Task.CompletedTask; } diff --git a/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Localization/Domain/zh-Hant.json b/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Localization/Domain/zh-Hant.json index dea171863c..2e2e168497 100644 --- a/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Localization/Domain/zh-Hant.json +++ b/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Localization/Domain/zh-Hant.json @@ -9,6 +9,7 @@ "Edit": "編輯", "LastEditTime": "上次編輯", "Delete": "刪除", + "ClearCacheConfirmationMessage": "你確定刪除此專案全部的快取 \"{0}\"", "InThisDocument": "在此文件中", "GoToTop": "到最上方", "Projects": "專案", @@ -20,6 +21,7 @@ "FilterTopics": "過濾主題", "FullSearch": "搜索文件", "Volo.Docs.Domain:010001": "Elastic search未啟用.", + "MultipleVersionDocumentInfo": "此份文件有多個版本。請選擇一個最適合的。", "New": "新文檔", "Upd": "更新", "NewExplanation": "在最近兩周內創建.", diff --git a/modules/setting-management/src/Volo.Abp.SettingManagement.Domain.Shared/Volo/Abp/SettingManagement/Localization/Resources/AbpSettingManagement/zh-Hant.json b/modules/setting-management/src/Volo.Abp.SettingManagement.Domain.Shared/Volo/Abp/SettingManagement/Localization/Resources/AbpSettingManagement/zh-Hant.json index f8f55c38cb..175cd47124 100644 --- a/modules/setting-management/src/Volo.Abp.SettingManagement.Domain.Shared/Volo/Abp/SettingManagement/Localization/Resources/AbpSettingManagement/zh-Hant.json +++ b/modules/setting-management/src/Volo.Abp.SettingManagement.Domain.Shared/Volo/Abp/SettingManagement/Localization/Resources/AbpSettingManagement/zh-Hant.json @@ -2,6 +2,18 @@ "culture": "zh-Hant", "texts": { "Settings": "設置", - "SuccessfullySaved": "保存成功" + "SuccessfullySaved": "保存成功", + "Permission:SettingManagement": "設定管理", + "Permission:Emailing": "信箱", + "Menu:Emailing": "信箱", + "SmtpHost": "主機", + "SmtpPort": "Port", + "SmtpUserName": "帳號", + "SmtpPassword": "密碼", + "SmtpDomain": "網域", + "SmtpEnableSsl": "啟用 SSL", + "SmtpUseDefaultCredentials": "使用預設Credentials", + "DefaultFromAddress": "預設發信信箱", + "DefaultFromDisplayName": "預設信件顯示名稱" } } \ No newline at end of file diff --git a/npm/ng-packs/packages/core/src/lib/strategies/auth-flow.strategy.ts b/npm/ng-packs/packages/core/src/lib/strategies/auth-flow.strategy.ts index 3b59c4d6ff..50e545ca1a 100644 --- a/npm/ng-packs/packages/core/src/lib/strategies/auth-flow.strategy.ts +++ b/npm/ng-packs/packages/core/src/lib/strategies/auth-flow.strategy.ts @@ -58,10 +58,14 @@ export abstract class AuthFlowStrategy { return Promise.resolve(); } - return this.oAuthService.refreshToken() as Promise; + return this.refreshToken(); }) .catch(this.catchError); } + + protected refreshToken() { + return this.oAuthService.refreshToken().catch(() => clearOAuthStorage()); + } } export class AuthCodeFlowStrategy extends AuthFlowStrategy { @@ -111,9 +115,10 @@ export class AuthPasswordFlowStrategy extends AuthFlowStrategy { ) .subscribe(() => { if (this.oAuthService.getRefreshToken()) { - this.oAuthService.refreshToken(); + this.refreshToken(); } else { this.oAuthService.logOut(); + this.removeRememberMe(); this.appConfigService.get().subscribe(res => { this.configState.setState(res); }); @@ -184,6 +189,13 @@ export class AuthPasswordFlowStrategy extends AuthFlowStrategy { }), ); } + + protected refreshToken() { + return this.oAuthService.refreshToken().catch(() => { + clearOAuthStorage(); + this.removeRememberMe(); + }); + } } export const AUTH_FLOW_STRATEGY = { diff --git a/templates/app/angular/package.json b/templates/app/angular/package.json index 70e09e2541..b3d96a7af3 100644 --- a/templates/app/angular/package.json +++ b/templates/app/angular/package.json @@ -12,6 +12,7 @@ }, "private": true, "dependencies": { + "@abp/ng.account": "~4.2.2", "@abp/ng.components": "~4.2.2", "@abp/ng.core": "~4.2.2", "@abp/ng.identity": "~4.2.2", diff --git a/templates/app/angular/src/app/app-routing.module.ts b/templates/app/angular/src/app/app-routing.module.ts index 570972c3fc..178c182324 100644 --- a/templates/app/angular/src/app/app-routing.module.ts +++ b/templates/app/angular/src/app/app-routing.module.ts @@ -7,6 +7,10 @@ const routes: Routes = [ pathMatch: 'full', loadChildren: () => import('./home/home.module').then(m => m.HomeModule), }, + { + path: 'account', + loadChildren: () => import('@abp/ng.account').then(m => m.AccountModule.forLazy()), + }, { path: 'identity', loadChildren: () => import('@abp/ng.identity').then(m => m.IdentityModule.forLazy()), diff --git a/templates/app/angular/src/app/app.module.ts b/templates/app/angular/src/app/app.module.ts index 8bd4876ffe..65ef51aea3 100644 --- a/templates/app/angular/src/app/app.module.ts +++ b/templates/app/angular/src/app/app.module.ts @@ -1,3 +1,4 @@ +import { AccountConfigModule } from '@abp/ng.account/config'; import { CoreModule } from '@abp/ng.core'; import { registerLocale } from '@abp/ng.core/locale'; import { IdentityConfigModule } from '@abp/ng.identity/config'; @@ -24,6 +25,7 @@ import { APP_ROUTE_PROVIDER } from './route.provider'; registerLocaleFn: registerLocale(), }), ThemeSharedModule.forRoot(), + AccountConfigModule.forRoot(), IdentityConfigModule.forRoot(), TenantManagementConfigModule.forRoot(), SettingManagementConfigModule.forRoot(), diff --git a/templates/module/angular/package.json b/templates/module/angular/package.json index a322e23558..6fd654ca94 100644 --- a/templates/module/angular/package.json +++ b/templates/module/angular/package.json @@ -15,6 +15,7 @@ }, "private": true, "dependencies": { + "@abp/ng.account": "~4.2.2", "@abp/ng.components": "~4.2.2", "@abp/ng.core": "~4.2.2", "@abp/ng.identity": "~4.2.2", diff --git a/templates/module/angular/projects/dev-app/src/app/app-routing.module.ts b/templates/module/angular/projects/dev-app/src/app/app-routing.module.ts index 9592b27d26..982cf8228b 100644 --- a/templates/module/angular/projects/dev-app/src/app/app-routing.module.ts +++ b/templates/module/angular/projects/dev-app/src/app/app-routing.module.ts @@ -7,6 +7,10 @@ const routes: Routes = [ pathMatch: 'full', loadChildren: () => import('./home/home.module').then(m => m.HomeModule), }, + { + path: 'account', + loadChildren: () => import('@abp/ng.account').then(m => m.AccountModule.forLazy()), + }, { path: 'identity', loadChildren: () => import('@abp/ng.identity').then(m => m.IdentityModule.forLazy()), diff --git a/templates/module/angular/projects/dev-app/src/app/app.module.ts b/templates/module/angular/projects/dev-app/src/app/app.module.ts index fe819f61ff..388f200daf 100644 --- a/templates/module/angular/projects/dev-app/src/app/app.module.ts +++ b/templates/module/angular/projects/dev-app/src/app/app.module.ts @@ -1,3 +1,4 @@ +import { AccountConfigModule } from '@abp/ng.account/config'; import { CoreModule } from '@abp/ng.core'; import { registerLocale } from '@abp/ng.core/locale'; import { IdentityConfigModule } from '@abp/ng.identity/config'; @@ -27,12 +28,13 @@ import { ThemeBasicModule } from '@abp/ng.theme.basic'; skipGetAppConfiguration: false, }), ThemeSharedModule.forRoot(), + AccountConfigModule.forRoot(), IdentityConfigModule.forRoot(), - MyProjectNameConfigModule.forRoot(), TenantManagementConfigModule.forRoot(), SettingManagementConfigModule.forRoot(), - NgxsModule.forRoot(), + MyProjectNameConfigModule.forRoot(), ThemeBasicModule.forRoot(), + NgxsModule.forRoot(), ], providers: [APP_ROUTE_PROVIDER], declarations: [AppComponent],