diff --git a/.github/workflows/labeler.yml b/.github/workflows/labeler.yml index f24ba57949..5c464400cc 100644 --- a/.github/workflows/labeler.yml +++ b/.github/workflows/labeler.yml @@ -2,8 +2,12 @@ name: Pull request labeler on: schedule: - cron: '0 12 */1 * *' +permissions: + contents: read jobs: labeler: + permissions: + pull-requests: write runs-on: ubuntu-latest steps: - uses: paulfantom/periodic-labeler@master diff --git a/abp_io/AbpIoLocalization/AbpIoLocalization/Admin/Localization/Resources/en.json b/abp_io/AbpIoLocalization/AbpIoLocalization/Admin/Localization/Resources/en.json index 22ef0df894..7a064a8ce7 100644 --- a/abp_io/AbpIoLocalization/AbpIoLocalization/Admin/Localization/Resources/en.json +++ b/abp_io/AbpIoLocalization/AbpIoLocalization/Admin/Localization/Resources/en.json @@ -397,6 +397,8 @@ "BookDiscountDeletionConfirmationMessage": "Are you sure you want to delete this book discount?", "CustomPaymentFlexSwitchDescription": "With license", "AllowFeatureUpgradeOnLicenseExpire": "Allow feature upgrade on license expire", - "Deleted{0}": "[Deleted {0}]" + "Deleted{0}": "[Deleted {0}]", + "Tags": "Tags", + "SetTagsInfo": "Tags should be comma-separated. Eg: CSharp, Entity Framework" } } diff --git a/abp_io/AbpIoLocalization/AbpIoLocalization/Admin/Localization/Resources/ro-RO.json b/abp_io/AbpIoLocalization/AbpIoLocalization/Admin/Localization/Resources/ro-RO.json index 44ac964263..409ab816a5 100644 --- a/abp_io/AbpIoLocalization/AbpIoLocalization/Admin/Localization/Resources/ro-RO.json +++ b/abp_io/AbpIoLocalization/AbpIoLocalization/Admin/Localization/Resources/ro-RO.json @@ -30,7 +30,7 @@ "NugetPackageDeletionWarningMessage": "Sunteţi sigur(ă) că doriţi să ştergeţi acest pachet de tip Nuget?", "ModuleDeletionWarningMessage": "Sunteţi sigur(ă) că doriţi să ştergeţi acest modul?", "Name": "Nume", - "DisplayName": "Nume de afişare", + "DisplayName": "Nume afişat", "ShortDescription": "Descriere scurtă", "NameFilter": "Nume", "CreationTime": "Data şi ora creării", @@ -317,7 +317,7 @@ "TrialLicenseStartDateFilter": "Data de început", "TrialLicenseEndDateFilter": "Data de încheiere", "FirsName": "Nume", - "LastName": "Nume", + "LastName": "Nume de familie", "StartDate": "Data de început", "EndDate": "Data de încheiere", "PurchasedDate": "Data achiziției", @@ -350,4 +350,4 @@ "Volo.AbpIo.Commercial:030010": "Pentru a achiziționa licența de probă, mai întâi trebuie să vă activați licența de probă!", "Volo.AbpIo.Commercial:030011": "Nu puteți șterge o licență de probă atunci când este achiziționată!" } -} \ No newline at end of file +} diff --git a/abp_io/AbpIoLocalization/AbpIoLocalization/Base/Localization/Resources/en.json b/abp_io/AbpIoLocalization/AbpIoLocalization/Base/Localization/Resources/en.json index 3a1b574d21..b0555bfe32 100644 --- a/abp_io/AbpIoLocalization/AbpIoLocalization/Base/Localization/Resources/en.json +++ b/abp_io/AbpIoLocalization/AbpIoLocalization/Base/Localization/Resources/en.json @@ -73,6 +73,7 @@ "DeveloperFocused": "Developer Focused", "ShareYourExperiences": "Share your experiences with the ABP Framework", "LatestPosts": "Latest Posts", + "LatestVideos": "Latest Videos", "Views": "Views", "LearnLatestNewsAboutABPFramework": "Get information about happenings in ABP like new releases, free sources, posts, and more.", "DeveloperTools": "Developer Tools", @@ -98,6 +99,7 @@ "Logout": "Logout", "Home": "Home", "Posts": "Posts", + "Videos": "Videos", "JoinTheABPCommunity": "Join the ABP Community", "SubmitYourPost": "Submit Your Post", "Modules": "Modules", @@ -164,6 +166,19 @@ "Books": "Books", "ABPDiscordServer": "ABP Discord Server", "ABPCommunityTalks": "ABP Community Talks", - "ABPCommunityPosts": "ABP Community Posts" + "ABPCommunityPosts": "ABP Community Posts", + "BuyAndGetMonths": "BUY 12 MONTHS, GET 14 MONTHS!", + "GetYourDeal": "Get Your Deal", + "BuyOrRenewLicense": "Buy or Renew License Now and Get 2 Extra Months!", + "BuyOrRenewLicenseToGetExtra2Months": "Buy or Renew License Now and Get 2 Extra Months! HURRY UP! ⏰ Last Day: {0}", + "HurryUp": "HURRY UP!", + "LastDay": "Last Day: {0}", + "BuyNewLicenseBetweenDatesToGetBenefit": "Buy a new license between {0} and {1} to get benefit for extra 2 months!", + "CheckAllCommunityTalks": "Check All Community Posts", + "ReadMore": "Read More", + "Post": "Post", + "ExploreTheContentsCreatedByTheCoreABPTeamAndTheABPCommunity": "Explore the contents created by the core ABP team and the ABP community.", + "WelcomeFallCampaign": "Welcome Fall Campaign!", + "GiveAwayForNewPurchases": "Application Development Classroom Training will be given away for the new purchases!" } } diff --git a/abp_io/AbpIoLocalization/AbpIoLocalization/Base/Localization/Resources/tr.json b/abp_io/AbpIoLocalization/AbpIoLocalization/Base/Localization/Resources/tr.json index 818b4cab5e..1eedb98c61 100644 --- a/abp_io/AbpIoLocalization/AbpIoLocalization/Base/Localization/Resources/tr.json +++ b/abp_io/AbpIoLocalization/AbpIoLocalization/Base/Localization/Resources/tr.json @@ -39,6 +39,8 @@ "TrialLicensePeriodHasExpired": "Deneme lisansınızın süresi {0} gün önce sona erdi.", "TrialLicensePeriodWillExpire": "Deneme lisansınızın süresi {0} gün içinde dolacak.", "TrialLicensePeriodExpireToday": "Deneme lisans süreniz bugün sona erecek.", - "PurchaseNow": "Şimdi satın al!" + "PurchaseNow": "Şimdi satın al!", + "WelcomeFallCampaign": "Hoş Geldin Sonbahar Kampanyası!", + "GiveAwayForNewPurchases": "Yeni alımlar için Uygulama Geliştirme Sınıfı Eğitimi hediye edilecektir!" } } \ No newline at end of file diff --git a/abp_io/AbpIoLocalization/AbpIoLocalization/Base/Localization/Resources/zh-Hans.json b/abp_io/AbpIoLocalization/AbpIoLocalization/Base/Localization/Resources/zh-Hans.json index 2ea126df0f..e1ad37704f 100644 --- a/abp_io/AbpIoLocalization/AbpIoLocalization/Base/Localization/Resources/zh-Hans.json +++ b/abp_io/AbpIoLocalization/AbpIoLocalization/Base/Localization/Resources/zh-Hans.json @@ -73,6 +73,7 @@ "DeveloperFocused": "以开发者为中心", "ShareYourExperiences": "分享您使用 ABP 框架的经验", "LatestPosts": "最新的帖子", + "LatestVideos": "最新的视频", "Views": "意见", "LearnLatestNewsAboutABPFramework": "获取有关 ABP 的最新相关信息,例如新版本、免费资源、帖子等。", "DeveloperTools": "开发者工具", @@ -98,6 +99,7 @@ "Logout": "登出", "Home": "主页", "Posts": "帖子", + "Videos": "视频", "JoinTheABPCommunity": "加入 ABP 社区", "SubmitYourPost": "提交您的帖子", "Modules": "模块", @@ -161,6 +163,19 @@ "Error_Page_500_Title": "好像出了什么问题!", "Error_Page_500_Description_1": "我们会自动跟踪这些错误,但如果问题仍然存在,请随时
联系我们。 与此同时,尝试刷新。", "Error_Page_500_Description_2": "通过 info@abp.io 与我们联系。", - "Books": "书籍" + "Books": "书籍", + "BuyAndGetMonths": "购买 12 个月,获得 14 个月!", + "GetYourDeal": "得到你的交易", + "BuyOrRenewLicense": "立即购买或续订许可证并额外获得 2 个月!", + "BuyOrRenewLicenseToGetExtra2Months": "立即购买或续订 ABP 商业许可证(适用于所有版本)并额外获得 2 个月!", + "HurryUp": "赶快下单!", + "LastDay": "活动截止日期: {0}", + "BuyNewLicenseBetweenDatesToGetBenefit": "在 {0} 和 {1} 之间购买一个新的许可证以获得额外 2 个月的收益!", + "CheckAllCommunityTalks": "检查所有社区帖子", + "ReadMore": "阅读更多", + "Post": "邮政", + "ExploreTheContentsCreatedByTheCoreABPTeamAndTheABPCommunity": "探索核心 ABP 团队和 ABP 社区创建的内容。", + "WelcomeFallCampaign": "欢迎秋季活动!", + "GiveAwayForNewPurchases": "新购买将赠送应用程序开发课堂培训!" } } \ No newline at end of file diff --git a/abp_io/AbpIoLocalization/AbpIoLocalization/Base/Localization/Resources/zh-Hant.json b/abp_io/AbpIoLocalization/AbpIoLocalization/Base/Localization/Resources/zh-Hant.json index dbf04ae25b..f55f4a7f85 100644 --- a/abp_io/AbpIoLocalization/AbpIoLocalization/Base/Localization/Resources/zh-Hant.json +++ b/abp_io/AbpIoLocalization/AbpIoLocalization/Base/Localization/Resources/zh-Hant.json @@ -39,6 +39,8 @@ "TrialLicensePeriodHasExpired": "您的試用許可期限已於 {0} 天前到期。", "TrialLicensePeriodWillExpire": "您的試用許可期限將在 {0} 天后到期。", "TrialLicensePeriodExpireToday": "您的試用許可期將於今天到期。", - "PurchaseNow": "現在買!" + "PurchaseNow": "現在買!", + "WelcomeFallCampaign": "欢迎秋季活动!", + "GiveAwayForNewPurchases": "新购买将赠送应用程序开发课堂培训!" } } \ No newline at end of file diff --git a/abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/ar.json b/abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/ar.json index 1a9aa7cba2..c7b91a99a0 100644 --- a/abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/ar.json +++ b/abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/ar.json @@ -89,7 +89,7 @@ "Blogging": "التدوين", "Identity": "هوية", "IdentityServer": "خادم الهوية", - "Saas": "ساس", + "Saas": "البرمجيات كخدمة", "LanguageManagement": "إدارة اللغة", "TextTemplateManagement": "إدارة قالب النص", "See All Modules": "انظر جميع الوحدات", @@ -382,4 +382,4 @@ "RenewLicenseEarly": "إذا قمت بتجديد رخصتي في وقت مبكر ، هل سأحصل على السنة كاملة؟", "RenewLicenseEarylExplanation": "عند تجديد الترخيص الخاص بك قبل تاريخ انتهاء الترخيص الخاص بك ، ستتم إضافة سنة واحدة إلى تاريخ انتهاء الترخيص الخاص بك. على سبيل المثال ، إذا انتهت صلاحية ترخيصك في {0} -06-06 وقمت بتجديده في {0} -01-01 ، فسيكون تاريخ انتهاء صلاحية الترخيص الجديد {1} -06-06." } -} \ No newline at end of file +} diff --git a/abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/en.json b/abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/en.json index caf4a9dbbe..64cefef9af 100644 --- a/abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/en.json +++ b/abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/en.json @@ -735,6 +735,14 @@ "ConfirmedEmailAddressRequiredToStartTrial": "You should have a confirmed email address in order to start a trial license.", "EmailVerificationMailNotSent": "Email verification mail couldn't send.", "GetConfirmationEmail": "Click here to get a confirmation email if you haven't got it before.", - "WhichLicenseTypeYouAreInterestedIn": "Which license type you are interested in?" + "WhichLicenseTypeYouAreInterestedIn": "Which license type you are interested in?", + "DontTakeOurWordForIt": "Don't take our word for it...", + "ReadAbpCommercialUsersWantYouToKnow": "Read what ABP Commercial users want you to know", + "Testimonial_ShortDescription_1": "The modularity of ABP made it possible for the team to deliver in time.", + "Testimonial_ShortDescription_2": "Build new features faster than before.", + "Testimonial_ShortDescription_3": "We start from out-of-the-box features and just focus on what we really need to write.", + "Testimonial_ShortDescription_4": "ABP Commercial was the best fit for our needs.", + "OnlineReviewersOnAbpCommercial": "Online Reviews on ABP Commercial", + "SeeWhatToldAboutAbpCommercial": "See what has been told about ABP Commercial and write your thoughts if you want." } } diff --git a/abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/ro-RO.json b/abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/ro-RO.json index 44b6f66037..be56afbb43 100644 --- a/abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/ro-RO.json +++ b/abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/ro-RO.json @@ -341,7 +341,7 @@ "SignIn": "Autentificare", "Or": "Sau", "TellUsAboutYourself": "Spuneţi-ne despre dumneavoastră", - "Surname": "Nume", + "Surname": "Nume de familie", "DoYouAgreePrivacyPolicy": "Sunt de acord cu Termenii şi condiţiile şi Politica de confidenţialitate.", "VolosoftMarketingInformationMessage": "Sunt de acord să primesc informaţii, sfaturi şi oferte despre soluţii pentru afaceri şi organizaţii şi alte produse şi servicii Volosoft.", "VolosoftSharingInformationMessage": "Sunt de acord ca Volosoft să partajeze informaţiile mele cu partenerii selectaţi astfel încât să primesc informaţii relevante despre produsele şi serviciile lor.", @@ -380,4 +380,4 @@ "TrialLicenseExpiredInfo": "Perioada de licență de probă a expirat!", "CommercialNewsletterConfirmationMessage": "Sunt de acord cu Termenii și condițiile și cu Politica de confidențialitate ." } -} \ No newline at end of file +} diff --git a/abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/zh-Hans.json b/abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/zh-Hans.json index 924306634e..0d67d9cca5 100644 --- a/abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/zh-Hans.json +++ b/abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/zh-Hans.json @@ -565,7 +565,7 @@ "PrePayment_IyzicoRedirectionInfo": "您将被重定向到 Iyzico 支付网关以安全地完成您的购买。", "PrePayment_IyzicoAcceptVisaAndMasterCard": "Iyzico 接受 Visa 和 MasterCard。", "Purchase": "购买", - "AcceptTermsAndConditions": "我已阅读、理解并接受隐私政策条款和条件 EULA。", + "AcceptTermsAndConditions": "我已阅读、理解并接受隐私政策条款和条件 EULA。", "AcceptTermsAndConditionsWarningMessage": "请接受隐私政策和条款和条件", "SelectGatewayToContinue": "请选择一个网关以继续!", "GatewaySelection_SelectGateway": "选择支付网关", diff --git a/abp_io/AbpIoLocalization/AbpIoLocalization/Community/Localization/Resources/en.json b/abp_io/AbpIoLocalization/AbpIoLocalization/Community/Localization/Resources/en.json index 0ed3eda832..c73da26137 100644 --- a/abp_io/AbpIoLocalization/AbpIoLocalization/Community/Localization/Resources/en.json +++ b/abp_io/AbpIoLocalization/AbpIoLocalization/Community/Localization/Resources/en.json @@ -150,7 +150,6 @@ "GetStarted": "Get Started", "SourceCode": "Source Code", "LeaveComment": "Leave Comment", - "ReadMore": "Read more", "ShowMore": "Show More", "NoPublishedPostsYet": "No published posts yet.", "Name": "Name", @@ -184,6 +183,7 @@ "Post_Index_Page_MetaDescription": "ABP Community's purpose is to create a contribution environment for developers who use the ABP framework.", "Layout_Title": "{0} | ABP Community", "Layout_MetaDescription": "ABP Community is an environment where people can share posts about ABP framework and follows the projects.", - "Index_Page_CommunityIntroduction": "This is a hub for ABP Framework, .NET and software development. You can read the articles, watch the video tutorials, get informed about ABP’s development progress and ABP-related events, help other developers and share your expertise with the ABP community." + "Index_Page_CommunityIntroduction": "This is a hub for ABP Framework, .NET and software development. You can read the articles, watch the video tutorials, get informed about ABP’s development progress and ABP-related events, help other developers and share your expertise with the ABP community.", + "TagsInArticle": "Tags in article" } } diff --git a/abp_io/AbpIoLocalization/AbpIoLocalization/Community/Localization/Resources/zh-Hans.json b/abp_io/AbpIoLocalization/AbpIoLocalization/Community/Localization/Resources/zh-Hans.json index 3513a37dde..8196d567a1 100644 --- a/abp_io/AbpIoLocalization/AbpIoLocalization/Community/Localization/Resources/zh-Hans.json +++ b/abp_io/AbpIoLocalization/AbpIoLocalization/Community/Localization/Resources/zh-Hans.json @@ -150,7 +150,6 @@ "GetStarted": "开始使用", "SourceCode": "源代码", "LeaveComment": "发表评论", - "ReadMore": "阅读更多", "ShowMore": "展示更多", "NoPublishedPostsYet": "还没有发布的帖子。", "Name": "名字", diff --git a/abp_io/AbpIoLocalization/AbpIoLocalization/Www/AbpIoWwwResource.cs b/abp_io/AbpIoLocalization/AbpIoLocalization/Www/AbpIoWwwResource.cs index 552b5949e1..f64552be30 100644 --- a/abp_io/AbpIoLocalization/AbpIoLocalization/Www/AbpIoWwwResource.cs +++ b/abp_io/AbpIoLocalization/AbpIoLocalization/Www/AbpIoWwwResource.cs @@ -1,5 +1,8 @@ -namespace AbpIoLocalization.Www +using Volo.Abp.Localization; + +namespace AbpIoLocalization.Www { + [LocalizationResourceName("AbpIoWww")] public class AbpIoWwwResource { diff --git a/abp_io/AbpIoLocalization/AbpIoLocalization/Www/Localization/Resources/en.json b/abp_io/AbpIoLocalization/AbpIoLocalization/Www/Localization/Resources/en.json index 41eda60de6..0b9dfab886 100644 --- a/abp_io/AbpIoLocalization/AbpIoLocalization/Www/Localization/Resources/en.json +++ b/abp_io/AbpIoLocalization/AbpIoLocalization/Www/Localization/Resources/en.json @@ -293,7 +293,6 @@ "ExploreDocumentationAndGuides": "Explore the comprehensive documentation and guides.", "Documentations": "Documentation", "Views": "Views", - "ReadMore": "Read More", "EnterYouEmailToGetNews": "Enter your email to get the latest news about the ABP Framework", "Tiered": "Tiered", "SeparateIdentityServer": "Separate Identity Server", @@ -372,6 +371,27 @@ "MasteringAbpFramework_Book_What_You_Will_Learn_8": "Write unit, integration, and UI tests using ABP Framework.", "MasteringAbpFramework_Book_WhoIsThisBookFor": "Who's this book for", "MasteringAbpFramework_Book_WhoIsThisBookFor_Description": "This book is for web developers who want to learn software architectures and best practices for building\n maintainable web-based solutions using Microsoft technologies and ABP Framework. Basic knowledge of C#\n and ASP.NET Core is necessary to get started with this book.", - "ComputersAndTechnology": "Computers & Technology" + "ComputersAndTechnology": "Computers & Technology", + "BuildingMicroserviceSolutions": "Building Microservice Solutions", + "MicroserviceBookPracticalGuide": "This book is a reference guide for developing and managing microservice-based applications using the ABP Framework. It references the .NET Microservice Sample Reference Application: eShopOnContainers and discusses the architectural design and implementation approaches using the ABP Framework. By the end of this book, you'll learn how ABP approaches the common microservice complexities such as authorization, distributed transactions, inter-microservice communications, deployment, etc.", + "IntroducingTheSolution": "Introducing the eShopOnAbp Solution", + "RunningTheSolution": "Running the Solution", + "UnderstandingTheAuthenticationSystem": "Understanding the Authentication System", + "ExploringTheApplications": "Exploring the Applications", + "UnderstandingTheAPIGateways": "Understanding the API Gateways", + "DevelopingTheMicroservices": "Developing the Microservices", + "UnderstandingTheInfrastructure": "Understanding the Infrastructure", + "DiggingInTheUseCases": "Digging in the Use Cases", + "DeployingTheSolution": "Deploying the Solution", + "ThisBookIsInDraftStageAndIsNotCompletedYet": "This book is in draft stage and is not completed yet.", + "Authors": "Authors", + "MicroserviceEBook": "Microservice E-Book", + "SelectUITheme": "Select UI Theme", + "LeptonXLiteTheme": "LeptonX Lite Theme", + "BasicTheme": "Basic Theme", + "LeptonXLiteThemeInfo": " A modern and stylish Bootstrap UI theme. Ideal if you want to have a production ready UI theme. This is the newest theme and is the default.", + "BasicThemeInfo": "Minimalist UI theme with plain Bootstrap colors and styles. Ideal if you will build your own UI theme.", + "SeeDocumentation": "See documentation.", + "SeeFullScreen": "🖼️ See the screenshot" } } diff --git a/abp_io/AbpIoLocalization/AbpIoLocalization/Www/Localization/Resources/ro-RO.json b/abp_io/AbpIoLocalization/AbpIoLocalization/Www/Localization/Resources/ro-RO.json index bd04ba7f49..a1ff5f58ad 100644 --- a/abp_io/AbpIoLocalization/AbpIoLocalization/Www/Localization/Resources/ro-RO.json +++ b/abp_io/AbpIoLocalization/AbpIoLocalization/Www/Localization/Resources/ro-RO.json @@ -253,18 +253,18 @@ "Or": "Sau", "TellUsAboutYourself": "Spuneţi-ne un pic despre dumneavoastră", "Name": "Nume", - "Surname": "Nume", + "Surname": "Nume de familie", "CompanyName": "Nume companie", "DoYouAgreePrivacyPolicy": "Sunt de acord cu Termenii & condiţiile şi Politica de confidenţialitate.", "Free": "Gratuit", "DDDEBook": "E-book DDD", "PracticalGuideForImplementingDDD": "Această carte este un ghid practic pentru implementarea Domain Driven Design în framework-ul ABP.", "IntroducingDDD": "Introducere în Domain Driven Design", - "DDDLayersAndCleanArchitecture": "Straturile DDD & Arhitectură curată", + "DDDLayersAndCleanArchitecture": "Straturile DDD şi Arhitectură curată", "LayeringOfADotnetSolution": "Stratificarea unei soluţii .NET", "ImplementingDDDBuildingBlocks": "Implementând DDD Building Blocks", "DomainVsApplicationLogic": "Domain Logic vs Application Logic", - "SamplesAndDiscussions": "Exemple & Discuţii", + "SamplesAndDiscussions": "Exemple şi Discuţii", "EmailNotValid": "Vă rugăm să introduceţi o adresa de email validă.", "WeWillSendYouADownloadLink": "Un link care conţine e-book-ul a fost trimis către {0}. Verificaţi-vă folderele de inbox, junk sau spam!", "GoHome": "Pagina principală", diff --git a/abp_io/AbpIoLocalization/AbpIoLocalization/Www/Localization/Resources/tr.json b/abp_io/AbpIoLocalization/AbpIoLocalization/Www/Localization/Resources/tr.json index 01fe9f8b7b..a4a6e142a9 100644 --- a/abp_io/AbpIoLocalization/AbpIoLocalization/Www/Localization/Resources/tr.json +++ b/abp_io/AbpIoLocalization/AbpIoLocalization/Www/Localization/Resources/tr.json @@ -279,6 +279,7 @@ "SubscribeToNewsletter": "ABP.IO Platform'u ile ilgili yeni haberler, makaleler, teklifler ve daha fazlası gibi gelişmeler hakkında bilgi almak için bültene abone olun.", "FirstEdition": "İlk Baskı", "ThankYou": "Teşekkürler!", - "CheckboxMandatory": "Devam etmek için bunu kontrol etmeniz gerekiyor!" + "CheckboxMandatory": "Devam etmek için bunu kontrol etmeniz gerekiyor!", + "ThisBookIsInDraftStageAndIsNotCompletedYet": "Bu kitap taslak aşamasındadır ve henüz tamamlanmamıştır." } } \ No newline at end of file diff --git a/abp_io/AbpIoLocalization/AbpIoLocalization/Www/Localization/Resources/zh-Hans.json b/abp_io/AbpIoLocalization/AbpIoLocalization/Www/Localization/Resources/zh-Hans.json index 9a1373f76b..7826f00ca2 100644 --- a/abp_io/AbpIoLocalization/AbpIoLocalization/Www/Localization/Resources/zh-Hans.json +++ b/abp_io/AbpIoLocalization/AbpIoLocalization/Www/Localization/Resources/zh-Hans.json @@ -293,7 +293,6 @@ "ExploreDocumentationAndGuides": "探索全面的文档和指南。", "Documentations": "文档", "Views": "意见", - "ReadMore": "阅读更多", "EnterYouEmailToGetNews": "输入您的电子邮件以获取有关 ABP 框架的最新消息", "Tiered": "分层", "SeparateIdentityServer": "独立的身份服务器", @@ -372,6 +371,7 @@ "MasteringAbpFramework_Book_What_You_Will_Learn_8": "使用 ABP 框架编写单元、集成和 UI 测试。", "MasteringAbpFramework_Book_WhoIsThisBookFor": "这本书是给谁看的", "MasteringAbpFramework_Book_WhoIsThisBookFor_Description": "本书适用于希望学习软件架构和最佳实践的 Web 开发人员,以使用 Microsoft 技术和 ABP 框架构建\n 可维护的基于 Web 的解决方案。 C#\n 和 ASP.NET Core 的基本知识是开始阅读本书所必需的。", - "ComputersAndTechnology": "计算机与技术" + "ComputersAndTechnology": "计算机与技术", + "ThisBookIsInDraftStageAndIsNotCompletedYet": "这本书正在草案阶段,还没有完成。" } } \ No newline at end of file diff --git a/common.DotSettings b/common.DotSettings index 5c1cda48fd..f2cc0339ae 100644 --- a/common.DotSettings +++ b/common.DotSettings @@ -38,5 +38,6 @@ False False False + True True \ No newline at end of file diff --git a/common.props b/common.props index 2adcbdab77..f8b7c620c2 100644 --- a/common.props +++ b/common.props @@ -1,7 +1,7 @@ latest - 6.0.0-rc.4 + 7.0.0 $(NoWarn);CS1591;CS0436 https://abp.io/assets/abp_nupkg.png https://abp.io/ diff --git a/docs/en/Background-Jobs-Hangfire.md b/docs/en/Background-Jobs-Hangfire.md index 4ee58d84ef..869a8075af 100644 --- a/docs/en/Background-Jobs-Hangfire.md +++ b/docs/en/Background-Jobs-Hangfire.md @@ -80,6 +80,41 @@ After you have installed these NuGet packages, you need to configure your projec } ```` +### Specifying Queue + +You can use the [`QueueAttribute`](https://docs.hangfire.io/en/latest/background-processing/configuring-queues.html) to specify the queue. + +````csharp +using System.Threading.Tasks; +using Volo.Abp.BackgroundJobs; +using Volo.Abp.DependencyInjection; +using Volo.Abp.Emailing; + +namespace MyProject +{ + [Queue("alpha")] + public class EmailSendingJob + : AsyncBackgroundJob, ITransientDependency + { + private readonly IEmailSender _emailSender; + + public EmailSendingJob(IEmailSender emailSender) + { + _emailSender = emailSender; + } + + public override async Task ExecuteAsync(EmailSendingArgs args) + { + await _emailSender.SendAsync( + args.EmailAddress, + args.Subject, + args.Body + ); + } + } +} +```` + ### Dashboard Authorization Hangfire Dashboard provides information about your background jobs, including method names and serialized arguments as well as gives you an opportunity to manage them by performing different actions – retry, delete, trigger, etc. So it is important to restrict access to the Dashboard. diff --git a/docs/en/Background-Jobs-RabbitMq.md b/docs/en/Background-Jobs-RabbitMq.md index 16b8b0981a..8eec3733fb 100644 --- a/docs/en/Background-Jobs-RabbitMq.md +++ b/docs/en/Background-Jobs-RabbitMq.md @@ -126,25 +126,31 @@ By default, all the job types use the `Default` RabbitMQ connection. Configure(options => { options.DefaultQueueNamePrefix = "my_app_jobs."; + options.DefaultDelayedQueueNamePrefix = "my_app_jobs.delayed" + options.PrefetchCount = 1; options.JobQueues[typeof(EmailSendingArgs)] = new JobQueueConfiguration( typeof(EmailSendingArgs), queueName: "my_app_jobs.emails", - connectionName: "SecondConnection" + connectionName: "SecondConnection", + delayedQueueName:"my_app_jobs.emails.delayed" ); }); ```` -* This example sets the default queue name prefix to `my_app_jobs.`. If different applications use the same RabbitMQ server, it would be important to use different prefixes for each application to not consume jobs of each other. +* This example sets the default queue name prefix to `my_app_jobs.` and default delayed queue name prefix to `my_app_jobs.delayed`. If different applications use the same RabbitMQ server, it would be important to use different prefixes for each application to not consume jobs of each other. +* Sets `PrefetchCount` for all queues. * Also specifies a different connection string for the `EmailSendingArgs`. `JobQueueConfiguration` class has some additional options in its constructor; * `queueName`: The queue name that is used for this job. The prefix is not added, so you need to specify the full name of the queue. +* `DelayedQueueName`: The delayed queue name that is used for delayed execution of job. The prefix is not added, so you need to specify the full name of the queue. * `connectionName`: The RabbitMQ connection name (see the connection configuration above). This is optional and the default value is `Default`. * `durable` (optional, default: `true`). * `exclusive` (optional, default: `false`). -* `autoDelete` (optional, default: `false`) +* `autoDelete` (optional, default: `false`). +* `PrefetchCount` (optional, default: null) See the RabbitMQ documentation if you want to understand the `durable`, `exclusive` and `autoDelete` options better, while most of the times the default configuration is what you want. diff --git a/docs/en/Community-Articles/15-08-2022-How-to-Design-Multi-Lingual-Entity/How-to-Design-Multi-Lingual-Entity.md b/docs/en/Community-Articles/15-08-2022-How-to-Design-Multi-Lingual-Entity/How-to-Design-Multi-Lingual-Entity.md new file mode 100644 index 0000000000..2c4b860c95 --- /dev/null +++ b/docs/en/Community-Articles/15-08-2022-How-to-Design-Multi-Lingual-Entity/How-to-Design-Multi-Lingual-Entity.md @@ -0,0 +1,690 @@ +# How to Design Multi-Lingual Entity + +## Introduction + +If you want to open up to the global market these days, end-to-end localization is a must. ABP provides an already established infrastructure for static texts. However, this may not be sufficient for many applications. You may need to fully customize your app for a particular language and region. + +Let's take a look at a few quotes from Christian Arno's article "[How Foreign-Language Internet Strategies Boost Sales](https://www.mediapost.com/publications/article/155250/how-foreign-language-internet-strategies-boost-sal.html)" to better understand the impact of this: + +- 82% of European consumers are less likely to buy online if the site is not in their native tongue ([Eurobarometer survey](http://europa.eu/rapid/pressReleasesAction.do?reference=IP/11/556)). +- 72.4% of global consumers are more likely to buy a product if the information is available in their own language ([Common Sense Advisory](http://www.commonsenseadvisory.com/)). +- The English language currently only accounts for 31% of all online use, and more than half of all searches are in languages other than English. +- Today, 42% of all Internet users are in Asia, while almost one-quarter are in Europe and just over 10% are in Latin America. + +- Foreign languages have experienced exponential growth in online usage in the past decade -- with Chinese now officially the [second-most-prominent-language](http://english.peopledaily.com.cn/90001/90776/90882/7438489.html) on the Web. [Arabic](http://www.internetworldstats.com/stats7.htm) has increased by a whopping 2500%, while English has only risen by 204% + +If you are looking for ways to expand your market share by fully customizing your application for a particular language and region, in this article I will explain how you can do it with ABP framework. + +### Source Code + +You can find the source code of the application at [abpframework/abp-samples](https://github.com/abpframework/abp-samples/tree/master/AcmeBookStoreMultiLingual). + +### Demo of the Final Application + +At the end of this article, we will have created an application same as in the gif below. + +![data-model](./result.gif) + +## Development + +In order to keep the article short and get rid of unrelated information in the article (like defining entities etc.), we'll be using the [BookStore](https://github.com/abpframework/abp-samples/tree/master/BookStore-Mvc-EfCore) example, which is used in the "[Web Application Development Tutorial](https://docs.abp.io/en/abp/latest/Tutorials/Part-1?UI=MVC&DB=EF)" documentation of ABP Framework and we will make the Book entity as multi-lingual. If you do not want to finish this tutorial, you can find the application [here](https://github.com/abpframework/abp-samples/tree/master/BookStore-Mvc-EfCore). + +### Determining the data model + +We need a robust, maintainable, and efficient data model to store content in multiple languages. + +> I read many articles to determine the data model correctly, and as a result, I decided to use one of the many approaches that suit us. +> However, as in everything, there is a trade-off here. If you are wondering about the advantages and disadvantages of the model we will implement compared to other models, I recommend you to read [this article](https://vertabelo.com/blog/data-modeling-for-multiple-languages-how-to-design-a-localization-ready-system/). + +![data-model](./data-model.png) + +As a result of the tutorial, we already have the `Book` and `Author` entities, as an extra, we will just add the `BookTranslation`. + +> In the article, we will make the Name property of the Book entity multi-lingual, but the article is independent of the Book entity, you can make the entity you want multi-lingual with similar codes according to your requirements. + +#### Acme.BookStore.Domain.Shared + +Create a folder named `MultiLingualObjects` and create the following interfaces in its contents. + +We will use the `IObjectTranslation` interface to mark the translation of a multi-lingual entity: + +```csharp +public interface IObjectTranslation +{ + string Language { get; set; } +} +``` + +We will use the `IMultiLingualObject` interface to mark multi-lingual entities: + +```csharp +public interface IMultiLingualObject + where TTranslation : class, IObjectTranslation +{ + ICollection Translations { get; set; } +} +``` + +#### Acme.BookStore.Domain + +In the `Books` folder, create the `BookTranslation` class as follows: + +```csharp +public class BookTranslation : Entity, IObjectTranslation +{ + public Guid BookId { get; set; } + + public string Name { get; set; } + + public string Language { get; set; } + + public override object[] GetKeys() + { + return new object[] {BookId, Language}; + } +} +``` + +`BookTranslation` contains the `Language` property, which contains a language code for translation and a reference to the multi-lingual entity. We also have the `BookId` foreign key to help us know which book is translated. + +Implement `IMultiLingualObject` in the `Book` class as follows: + +```csharp +public class Book : AuditedAggregateRoot, IMultiLingualObject +{ + public Guid AuthorId { get; set; } + + public string Name { get; set; } + + public BookType Type { get; set; } + + public DateTime PublishDate { get; set; } + + public float Price { get; set; } + + public ICollection Translations { get; set; } +} +``` + +Create a folder named `MultiLingualObjects` and add the following class inside of this folder: + +```csharp +public class MultiLingualObjectManager : ITransientDependency +{ + protected const int MaxCultureFallbackDepth = 5; + + public async Task FindTranslationAsync( + TMultiLingual multiLingual, + string culture = null, + bool fallbackToParentCultures = true) + where TMultiLingual : IMultiLingualObject + where TTranslation : class, IObjectTranslation + { + culture ??= CultureInfo.CurrentUICulture.Name; + + if (multiLingual.Translations.IsNullOrEmpty()) + { + return null; + } + + var translation = multiLingual.Translations.FirstOrDefault(pt => pt.Language == culture); + if (translation != null) + { + return translation; + } + + if (fallbackToParentCultures) + { + translation = GetTranslationBasedOnCulturalRecursive( + CultureInfo.CurrentUICulture.Parent, + multiLingual.Translations, + 0 + ); + + if (translation != null) + { + return translation; + } + } + + return null; + } + + protected TTranslation GetTranslationBasedOnCulturalRecursive( + CultureInfo culture, ICollection translations, int currentDepth) + where TTranslation : class, IObjectTranslation + { + if (culture == null || + culture.Name.IsNullOrWhiteSpace() || + translations.IsNullOrEmpty() || + currentDepth > MaxCultureFallbackDepth) + { + return null; + } + + var translation = translations.FirstOrDefault(pt => pt.Language.Equals(culture.Name, StringComparison.OrdinalIgnoreCase)); + return translation ?? GetTranslationBasedOnCulturalRecursive(culture.Parent, translations, currentDepth + 1); + } +} +``` + +With `MultiLingualObjectManager`'s `FindTranslationAsync` method, we get the translated version of the book according to `CurrentUICulture`. If no translation of culture is found, we return null. + +> Every thread in .NET has `CurrentCulture` and `CurrentUICulture` objects. + +#### Acme.BookStore.EntityFrameworkCore + +In the `OnModelCreating` method of the `BookStoreDbContext` class, configure the `BookTranslation` as follows: + +```csharp +builder.Entity(b => +{ + b.ToTable(BookStoreConsts.DbTablePrefix + "BookTranslations", + BookStoreConsts.DbSchema); + + b.ConfigureByConvention(); + + b.HasKey(x => new {x.BookId, x.Language}); +}); +``` + +> I haven't explicitly set up a one-to-many relationship between `Book` and `BookTranslation` here, but the entity framework will do it for us. + +After that, you can just run the following command in a command-line terminal to add a new database migration (in the directory of the `EntityFrameworkCore` project): + +```bash +dotnet ef migrations add Added_BookTranslation +``` + +This will add a new migration class to your project. You can then run the following command (or run the `.DbMigrator` application) to apply changes to the database: + +```bash +dotnet ef database update +``` + +Add the following code to the `ConfigureServices` method of the `BookStoreEntityFrameworkCoreModule`: + +```csharp + Configure(options => + { + options.Entity(bookOptions => + { + bookOptions.DefaultWithDetailsFunc = query => query.Include(o => o.Translations); + }); +}); +``` + +Now we can use `WithDetailsAsync` without any parameters on `BookAppService` knowing that `Translations` will be included. + +#### Acme.BookStore.Application.Contracts + +Implement `IObjectTranslation` in the `BookDto` class as follows: + +```csharp +public class BookDto : AuditedEntityDto, IObjectTranslation +{ + public Guid AuthorId { get; set; } + + public string AuthorName { get; set; } + + public string Name { get; set; } + + public BookType Type { get; set; } + + public DateTime PublishDate { get; set; } + + public float Price { get; set; } + + public string Language { get; set; } +} +``` + +`Language` property is required to understand which language the translated book name belongs to in the UI. + +Create the `AddBookTranslationDto` class in the `Books` folder as follows: + +```csharp +public class AddBookTranslationDto : IObjectTranslation +{ + [Required] + public string Language { get; set; } + + [Required] + public string Name { get; set; } +} +``` + +Add the `AddTranslationsAsync` method to the `IBookAppService` as follows: + +```csharp +public interface IBookAppService : + ICrudAppService< + BookDto, + Guid, + PagedAndSortedResultRequestDto, + CreateUpdateBookDto> +{ + Task> GetAuthorLookupAsync(); + + Task AddTranslationsAsync(Guid id, AddBookTranslationDto input); // added this line +} +``` + +#### Acme.BookStore.Application + +Now, we need to implement the `AddTranslationsAsync` method in `BookAppService` and include `Translations` in the `Book` entity, for this you can change the `BookAppService` as follows: + +```csharp +[Authorize(BookStorePermissions.Books.Default)] +public class BookAppService : + CrudAppService< + Book, //The Book entity + BookDto, //Used to show books + Guid, //Primary key of the book entity + PagedAndSortedResultRequestDto, //Used for paging/sorting + CreateUpdateBookDto>, //Used to create/update a book + IBookAppService //implement the IBookAppService +{ + private readonly IAuthorRepository _authorRepository; + + public BookAppService( + IRepository repository, + IAuthorRepository authorRepository) + : base(repository) + { + _authorRepository = authorRepository; + GetPolicyName = BookStorePermissions.Books.Default; + GetListPolicyName = BookStorePermissions.Books.Default; + CreatePolicyName = BookStorePermissions.Books.Create; + UpdatePolicyName = BookStorePermissions.Books.Edit; + DeletePolicyName = BookStorePermissions.Books.Create; + } + + public override async Task GetAsync(Guid id) + { + //Get the IQueryable from the repository + var queryable = await Repository.WithDetailsAsync(); // this line changed + + //Prepare a query to join books and authors + var query = from book in queryable + join author in await _authorRepository.GetQueryableAsync() on book.AuthorId equals author.Id + where book.Id == id + select new { book, author }; + + //Execute the query and get the book with author + var queryResult = await AsyncExecuter.FirstOrDefaultAsync(query); + if (queryResult == null) + { + throw new EntityNotFoundException(typeof(Book), id); + } + + var bookDto = ObjectMapper.Map(queryResult.book); + bookDto.AuthorName = queryResult.author.Name; + return bookDto; + } + + public override async Task> GetListAsync(PagedAndSortedResultRequestDto input) + { + //Get the IQueryable from the repository + var queryable = await Repository.WithDetailsAsync(); // this line changed + + //Prepare a query to join books and authors + var query = from book in queryable + join author in await _authorRepository.GetQueryableAsync() on book.AuthorId equals author.Id + select new {book, author}; + + //Paging + query = query + .OrderBy(NormalizeSorting(input.Sorting)) + .Skip(input.SkipCount) + .Take(input.MaxResultCount); + + //Execute the query and get a list + var queryResult = await AsyncExecuter.ToListAsync(query); + + //Convert the query result to a list of BookDto objects + var bookDtos = queryResult.Select(x => + { + var bookDto = ObjectMapper.Map(x.book); + bookDto.AuthorName = x.author.Name; + return bookDto; + }).ToList(); + + //Get the total count with another query + var totalCount = await Repository.GetCountAsync(); + + return new PagedResultDto( + totalCount, + bookDtos + ); + } + + public async Task> GetAuthorLookupAsync() + { + var authors = await _authorRepository.GetListAsync(); + + return new ListResultDto( + ObjectMapper.Map, List>(authors) + ); + } + + public async Task AddTranslationsAsync(Guid id, AddBookTranslationDto input) + { + var queryable = await Repository.WithDetailsAsync(); + + var book = await AsyncExecuter.FirstOrDefaultAsync(queryable, x => x.Id == id); + + if (book.Translations.Any(x => x.Language == input.Language)) + { + throw new UserFriendlyException($"Translation already available for {input.Language}"); + } + + book.Translations.Add(new BookTranslation + { + BookId = book.Id, + Name = input.Name, + Language = input.Language + }); + + await Repository.UpdateAsync(book); + } + + private static string NormalizeSorting(string sorting) + { + if (sorting.IsNullOrEmpty()) + { + return $"book.{nameof(Book.Name)}"; + } + + if (sorting.Contains("authorName", StringComparison.OrdinalIgnoreCase)) + { + return sorting.Replace( + "authorName", + "author.Name", + StringComparison.OrdinalIgnoreCase + ); + } + + return $"book.{sorting}"; + } +} +``` + +Create the `MultiLingualBookObjectMapper` class as follows: + +```csharp +public class MultiLingualBookObjectMapper : IObjectMapper, ITransientDependency +{ + private readonly MultiLingualObjectManager _multiLingualObjectManager; + + private readonly ISettingProvider _settingProvider; + + public MultiLingualBookObjectMapper( + MultiLingualObjectManager multiLingualObjectManager, + ISettingProvider settingProvider) + { + _multiLingualObjectManager = multiLingualObjectManager; + _settingProvider = settingProvider; + } + + public BookDto Map(Book source) + { + var translation = AsyncHelper.RunSync(() => + _multiLingualObjectManager.FindTranslationAsync(source)); + + return new BookDto + { + Id = source.Id, + AuthorId = source.AuthorId, + Type = source.Type, + Name = translation?.Name ?? source.Name, + PublishDate = source.PublishDate, + Price = source.Price, + Language = translation?.Language ?? AsyncHelper.RunSync(() => _settingProvider.GetOrNullAsync(LocalizationSettingNames.DefaultLanguage)), + CreationTime = source.CreationTime, + CreatorId = source.CreatorId, + LastModificationTime = source.LastModificationTime, + LastModifierId = source.LastModifierId + }; + } + + public BookDto Map(Book source, BookDto destination) + { + return default; + } +} +``` + +To map the multi-lingual `Book` entity to `BookDto`, we implement custom mapping using the `IObjectMapper` interface. If no translation is found, default values are returned. + +So far we have created the entire infrastructure. We don't need to change anything in the UI, if there is a translation according to the language chosen by the user, the list view will change. However, I want to create a simple modal where we can add new translations to an existing book in order to see what we have done. + +#### Acme.BookStore.Web + +Create a new razor page named `AddTranslationModal` in the `Books` folder as below. + +**View** + +```html +@page +@using Microsoft.AspNetCore.Mvc.TagHelpers +@using Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Modal +@model Acme.BookStore.Web.Pages.Books.AddTranslationModal + +@{ + Layout = null; +} + +
+ + Translations + + + + + + + + + +
+``` + +**Model** + +```csharp +public class AddTranslationModal : BookStorePageModel +{ + [HiddenInput] + [BindProperty(SupportsGet = true)] + public Guid Id { get; set; } + + public List Languages { get; set; } + + [BindProperty] + public BookTranslationViewModel TranslationViewModel { get; set; } + + private readonly IBookAppService _bookAppService; + private readonly ILanguageProvider _languageProvider; + + public AddTranslationModal( + IBookAppService bookAppService, + ILanguageProvider languageProvider) + { + _bookAppService = bookAppService; + _languageProvider = languageProvider; + } + + public async Task OnGetAsync() + { + Languages = await GetLanguagesSelectItem(); + + TranslationViewModel = new BookTranslationViewModel(); + } + + public async Task OnPostAsync() + { + await _bookAppService.AddTranslationsAsync(Id, ObjectMapper.Map(TranslationViewModel)); + + return NoContent(); + } + + private async Task> GetLanguagesSelectItem() + { + var result = await _languageProvider.GetLanguagesAsync(); + + return result.Select( + languageInfo => new SelectListItem + { + Value = languageInfo.CultureName, + Text = languageInfo.DisplayName + " (" + languageInfo.CultureName + ")" + } + ).ToList(); + } + + public class BookTranslationViewModel + { + [Required] + [SelectItems(nameof(Languages))] + public string Language { get; set; } + + [Required] + public string Name { get; set; } + + } +} +``` + +Then, we can open the `BookStoreWebAutoMapperProfile` class and define the required mapping as follows: + +```csharp +CreateMap(); +``` + +Finally, change the content of `index.js` in the `Books` folder as follows: + +```javascript +$(function () { + var l = abp.localization.getResource('BookStore'); + var createModal = new abp.ModalManager(abp.appPath + 'Books/CreateModal'); + var editModal = new abp.ModalManager(abp.appPath + 'Books/EditModal'); + var addTranslationModal = new abp.ModalManager(abp.appPath + 'Books/AddTranslationModal'); // added this line + + var dataTable = $('#BooksTable').DataTable( + abp.libs.datatables.normalizeConfiguration({ + serverSide: true, + paging: true, + order: [[1, "asc"]], + searching: false, + scrollX: true, + ajax: abp.libs.datatables.createAjax(acme.bookStore.books.book.getList), + columnDefs: [ + { + title: l('Actions'), + rowAction: { + items: + [ + { + text: l('Edit'), + visible: abp.auth.isGranted('BookStore.Books.Edit'), + action: function (data) { + editModal.open({ id: data.record.id }); + } + }, + { + text: l('Add Translation'), // added this action + visible: abp.auth.isGranted('BookStore.Books.Edit'), + action: function (data) { + addTranslationModal.open({ id: data.record.id }); + } + }, + { + text: l('Delete'), + visible: abp.auth.isGranted('BookStore.Books.Delete'), + confirmMessage: function (data) { + return l( + 'BookDeletionConfirmationMessage', + data.record.name + ); + }, + action: function (data) { + acme.bookStore.books.book + .delete(data.record.id) + .then(function() { + abp.notify.info( + l('SuccessfullyDeleted') + ); + dataTable.ajax.reload(); + }); + } + } + ] + } + }, + { + title: l('Name'), + data: "name" + }, + { + title: l('Author'), + data: "authorName" + }, + { + title: l('Type'), + data: "type", + render: function (data) { + return l('Enum:BookType:' + data); + } + }, + { + title: l('PublishDate'), + data: "publishDate", + render: function (data) { + return luxon + .DateTime + .fromISO(data, { + locale: abp.localization.currentCulture.name + }).toLocaleString(); + } + }, + { + title: l('Price'), + data: "price" + }, + { + title: l('CreationTime'), + data: "creationTime", + render: function (data) { + return luxon + .DateTime + .fromISO(data, { + locale: abp.localization.currentCulture.name + }).toLocaleString(luxon.DateTime.DATETIME_SHORT); + } + } + ] + }) + ); + + createModal.onResult(function () { + dataTable.ajax.reload(); + }); + + editModal.onResult(function () { + dataTable.ajax.reload(); + }); + + $('#NewBookButton').click(function (e) { + e.preventDefault(); + createModal.open(); + }); +}); +``` + +## Conclusion + +With a multi-lingual application, you can expand your market share, but if not designed well, may your application will be unusable. So, I've tried to explain how to design a sustainable multi-lingual entity in this article. + +### Source Code + +You can find source code of the example solution used in this article [here](https://github.com/abpframework/abp-samples/tree/master/AcmeBookStoreMultiLingual). diff --git a/docs/en/Community-Articles/15-08-2022-How-to-Design-Multi-Lingual-Entity/data-model.png b/docs/en/Community-Articles/15-08-2022-How-to-Design-Multi-Lingual-Entity/data-model.png new file mode 100644 index 0000000000..c7e02bc2cd Binary files /dev/null and b/docs/en/Community-Articles/15-08-2022-How-to-Design-Multi-Lingual-Entity/data-model.png differ diff --git a/docs/en/Community-Articles/15-08-2022-How-to-Design-Multi-Lingual-Entity/result.gif b/docs/en/Community-Articles/15-08-2022-How-to-Design-Multi-Lingual-Entity/result.gif new file mode 100644 index 0000000000..0bc41cb8f1 Binary files /dev/null and b/docs/en/Community-Articles/15-08-2022-How-to-Design-Multi-Lingual-Entity/result.gif differ diff --git a/docs/en/Community-Articles/2020-10-08-How-To-Add-Custom-Property-To-The-User-Entity/How-To-Add-Custom-Property-To-The-User-Entity.md b/docs/en/Community-Articles/2020-10-08-How-To-Add-Custom-Property-To-The-User-Entity/How-To-Add-Custom-Property-To-The-User-Entity.md index 308358bb67..8e46bd6944 100644 --- a/docs/en/Community-Articles/2020-10-08-How-To-Add-Custom-Property-To-The-User-Entity/How-To-Add-Custom-Property-To-The-User-Entity.md +++ b/docs/en/Community-Articles/2020-10-08-How-To-Add-Custom-Property-To-The-User-Entity/How-To-Add-Custom-Property-To-The-User-Entity.md @@ -1,9 +1,13 @@ # How to Add Custom Properties to the User Entity +> **Note:** If your application is greater than version 4.3.3, please follow [this article](../2022-07-19-How-To-Add-Custom-Property-To-The-User-Entity/How-To-Add-Custom-Property-To-The-User-Entity.md). + ## Introduction In this step-by-step article, I will explain how you can customize the user entity class, which is available in every web application you create using the ABP framework, according to your needs. When you read this article, you will learn how to override the services of built-in modules, extend the entities, extend data transfer objects and customize the user interface in the applications you develop using the ABP framework. +> **Note:** This article is not about customizing the `Login` page. If you have such a need, please follow [this article](../2020-05-09-Customize-the-Login-Page-for-MVC-Razor-Page-Applications/POST.md). + You can see the screenshots below which we will reach at the end of the article. ![custom-identity-user-list](./custom-identity-user-list.png) diff --git a/docs/en/Community-Articles/2022-07-19-How-To-Add-Custom-Property-To-The-User-Entity/How-To-Add-Custom-Property-To-The-User-Entity.md b/docs/en/Community-Articles/2022-07-19-How-To-Add-Custom-Property-To-The-User-Entity/How-To-Add-Custom-Property-To-The-User-Entity.md new file mode 100644 index 0000000000..7c119c6e66 --- /dev/null +++ b/docs/en/Community-Articles/2022-07-19-How-To-Add-Custom-Property-To-The-User-Entity/How-To-Add-Custom-Property-To-The-User-Entity.md @@ -0,0 +1,154 @@ +# How to Add Custom Properties to the User Entity + +> **Note:** If your application is less than version 4.4.x, please follow [this article](../2020-10-08-How-To-Add-Custom-Property-To-The-User-Entity/How-To-Add-Custom-Property-To-The-User-Entity.md). + +## Introduction + +In this step-by-step article, I will explain how you can customize the user entity class, which is available in every web application you create using the ABP framework, according to your needs. When you read this article, you will learn how to override the services of built-in modules, extend the entities, extend data transfer objects and customize the user interface in the applications you develop using the ABP framework. + +> **Note:** This article is not about customizing the `Login` page. If you have such a need, please follow [this article](../2020-05-09-Customize-the-Login-Page-for-MVC-Razor-Page-Applications/POST.md). + +You can see the screenshots below which we will reach at the end of the article. + +![custom-identity-user-list](./custom-identity-user-list.png) + +![new-user](./new-user.png) + +## Preparing the Project + +### Startup template and the initial run + +Abp Framework offers startup templates to get into the work faster. We can create a new startup template using Abp CLI: + +`abp new CustomizeUserDemo` + +> In this article, I will go through the MVC application, but it will work also in the [Angular](https://docs.abp.io/en/abp/latest/Getting-Started?UI=NG&DB=EF&Tiered=No), [Blazor Server](https://docs.abp.io/en/abp/latest/Getting-Started?UI=BlazorServer&DB=EF&Tiered=No), and [Blazor WebAssembly](https://docs.abp.io/en/abp/latest/Getting-Started?UI=Blazor&DB=EF&Tiered=No) application. + +After the download is finished, we can run **CustomizeUserDemo.DbMigrator** project to create the database migrations and seed the initial data (admin user, role, etc). Then we can run `CustomizeUserDemo.Web` to see that our application is working. + +> Default admin username is **admin** and password is **1q2w3E\*** + +![initial-project](./initial-project.png) + +In this article, we will go through a scenario together and find the solutions to our questions through this scenario. However, since the scenario is not a real-life scenario, it may be strange, please don't get too about this issue :) + +## Step-1 + +Create the Users folder in the **CustomizeUserDemo.Domain.Shared** project, create the class `UserConsts` inside the folder and update the class you created as below: + +```csharp +public static class UserConsts +{ + public const string TitlePropertyName = "Title"; + + public const string ReputationPropertyName = "Reputation"; + + public const int MaxTitleLength = 64; + + public const double MaxReputationValue = 1_000; + + public const double MinReputationValue = 1; +} +``` + +## Step-2 + +Update the `CustomizeUserDemoEfCoreEntityExtensionMappings` class in the **CustomizeUserDemo.EntityFramework** project in the EntityFrameworkCore folder as below: + +```csharp +public static class CustomizeUserDemoEfCoreEntityExtensionMappings +{ + private static readonly OneTimeRunner OneTimeRunner = new OneTimeRunner(); + + public static void Configure() + { + CustomizeUserDemoGlobalFeatureConfigurator.Configure(); + CustomizeUserDemoModuleExtensionConfigurator.Configure(); + + OneTimeRunner.Run(() => + { + ObjectExtensionManager.Instance + .MapEfCoreProperty( + UserConsts.TitlePropertyName, + (_, propertyBuilder) => + { + propertyBuilder.HasDefaultValue(""); + propertyBuilder.HasMaxLength(UserConsts.MaxTitleLength); + } + ).MapEfCoreProperty( + UserConsts.ReputationPropertyName, + (_, propertyBuilder) => + { + propertyBuilder.HasDefaultValue(UserConsts.MinReputationValue); + } + ); + }); + } +} +``` + +This class can be used to map these extra properties to table fields in the database. Please read [this](https://docs.abp.io/en/abp/latest/Customizing-Application-Modules-Extending-Entities) article to improve your understanding of what we are doing. + +So far, we have added our extra features to the `User` entity and matched these features with the `ef core`. + +Now we need to add migration to see what has changed in our database. This for, open the Package Manager Console (PMC) under the menu Tools > NuGet Package Manager. + +![nuget-package-manager](./nuget-package-manager.png) + +Select the **CustomizeUserDemo.EntityFramework** as the **default project** and execute the following command: + +```bash +Add-Migration "Updated-User-Entity" +``` + +![added-new-migration](./added-new-migration.png) + +This will create a new migration class inside the `Migrations` folder of the **CustomizeUserDemo.EntityFrameworkCore** project. + +> If you are using another IDE than the Visual Studio, you can use `dotnet-ef` tool as [documented here](https://docs.microsoft.com/en-us/ef/core/managing-schemas/migrations/?tabs=dotnet-core-cli#create-a-migration). + +Finally, run the **CustomizeUserDemo.DbMigrator** project to update the database. + +When we updated the database, you can see that the `Title` and `Reputation` columns are added to the `Users` table. + +![user-table](./user-table.png) + +## Step-3 +Open the `CustomizeUserDemoModuleExtensionConfigurator` in the **CustomizeUserDemo.Domain.Shared** project, and change the contents of the `ConfigureExtraProperties` method as shown below: +```csharp +private static void ConfigureExtraProperties() +{ + ObjectExtensionManager.Instance.Modules().ConfigureIdentity(identity => + { + identity.ConfigureUser(user => + { + user.AddOrUpdateProperty( + UserConsts.TitlePropertyName, + options => + { + options.Attributes.Add(new RequiredAttribute()); + options.Attributes.Add( + new StringLengthAttribute(UserConsts.MaxTitleLength) + ); + } + ); + user.AddOrUpdateProperty( + UserConsts.ReputationPropertyName, + options => + { + options.DefaultValue = UserConsts.MinReputationValue; + options.Attributes.Add( + new RangeAttribute(UserConsts.MinReputationValue, UserConsts.MaxReputationValue) + ); + } + ); + }); + }); +} +``` + +That's it. Now let's run the application and look at the Identity user page. You can also try to edit and recreate a record if you want, it will work even though we haven't done anything extra. Here is the magic code behind ABP framework. + +If there is a situation you want to add, you can click the contribute button or make a comment. Also, if you like the article, don't forget to share it :) + +Happy coding :) diff --git a/docs/en/Community-Articles/2022-07-19-How-To-Add-Custom-Property-To-The-User-Entity/added-new-migration.png b/docs/en/Community-Articles/2022-07-19-How-To-Add-Custom-Property-To-The-User-Entity/added-new-migration.png new file mode 100755 index 0000000000..d459fdeed2 Binary files /dev/null and b/docs/en/Community-Articles/2022-07-19-How-To-Add-Custom-Property-To-The-User-Entity/added-new-migration.png differ diff --git a/docs/en/Community-Articles/2022-07-19-How-To-Add-Custom-Property-To-The-User-Entity/custom-identity-user-list.png b/docs/en/Community-Articles/2022-07-19-How-To-Add-Custom-Property-To-The-User-Entity/custom-identity-user-list.png new file mode 100644 index 0000000000..896ed947aa Binary files /dev/null and b/docs/en/Community-Articles/2022-07-19-How-To-Add-Custom-Property-To-The-User-Entity/custom-identity-user-list.png differ diff --git a/docs/en/Community-Articles/2022-07-19-How-To-Add-Custom-Property-To-The-User-Entity/initial-project.png b/docs/en/Community-Articles/2022-07-19-How-To-Add-Custom-Property-To-The-User-Entity/initial-project.png new file mode 100755 index 0000000000..b64e93a99f Binary files /dev/null and b/docs/en/Community-Articles/2022-07-19-How-To-Add-Custom-Property-To-The-User-Entity/initial-project.png differ diff --git a/docs/en/Community-Articles/2022-07-19-How-To-Add-Custom-Property-To-The-User-Entity/new-user.png b/docs/en/Community-Articles/2022-07-19-How-To-Add-Custom-Property-To-The-User-Entity/new-user.png new file mode 100644 index 0000000000..d3a5c66198 Binary files /dev/null and b/docs/en/Community-Articles/2022-07-19-How-To-Add-Custom-Property-To-The-User-Entity/new-user.png differ diff --git a/docs/en/Community-Articles/2022-07-19-How-To-Add-Custom-Property-To-The-User-Entity/nuget-package-manager.png b/docs/en/Community-Articles/2022-07-19-How-To-Add-Custom-Property-To-The-User-Entity/nuget-package-manager.png new file mode 100755 index 0000000000..680bc9d2e7 Binary files /dev/null and b/docs/en/Community-Articles/2022-07-19-How-To-Add-Custom-Property-To-The-User-Entity/nuget-package-manager.png differ diff --git a/docs/en/Community-Articles/2022-07-19-How-To-Add-Custom-Property-To-The-User-Entity/user-table.png b/docs/en/Community-Articles/2022-07-19-How-To-Add-Custom-Property-To-The-User-Entity/user-table.png new file mode 100755 index 0000000000..5bb71b8325 Binary files /dev/null and b/docs/en/Community-Articles/2022-07-19-How-To-Add-Custom-Property-To-The-User-Entity/user-table.png differ diff --git a/docs/en/Dependency-Injection.md b/docs/en/Dependency-Injection.md index 668eac6644..a0ad342c4c 100644 --- a/docs/en/Dependency-Injection.md +++ b/docs/en/Dependency-Injection.md @@ -244,25 +244,35 @@ One restriction of property injection is that you cannot use the dependency in y Property injection is also useful when you want to design a base class that has some common services injected by default. If you're going to use constructor injection, all derived classes should also inject depended services into their own constructors which makes development harder. However, be very careful using property injection for non-optional services as it makes it harder to clearly see the requirements of a class. -### Resolve Service from IServiceProvider +#### DisablePropertyInjectionAttribute -You may want to resolve a service directly from ``IServiceProvider``. In that case, you can inject IServiceProvider into your class and use ``GetService`` method as shown below: +You can use `[DisablePropertyInjection]` attribute on class or properties to disable property injection for the whole class or some specific properties. ````C# +[DisablePropertyInjection] public class MyService : ITransientDependency { - private readonly IServiceProvider _serviceProvider; + public ITaxCalculator TaxCalculator { get; set; } +} - public MyService(IServiceProvider serviceProvider) - { - _serviceProvider = serviceProvider; - } +public class MyService : ITransientDependency +{ + public ILogger Logger { get; set; } - public void DoSomething() - { - var taxCalculator = _serviceProvider.GetService(); - //... - } + [DisablePropertyInjection] + public ITaxCalculator TaxCalculator { get; set; } +} + +```` + +### Resolve Service from IServiceProvider + +You may want to resolve a service directly from ``IServiceProvider``. In that case, you can inject IServiceProvider into your class and use ``GetService`` method as shown below: + +````C# +public class MyService : ITransientDependency +{ + public ILogger Logger { get; set; } } ```` diff --git a/docs/en/Deploy-azure-app-service.md b/docs/en/Deploy-azure-app-service.md new file mode 100644 index 0000000000..9e0309f3b9 --- /dev/null +++ b/docs/en/Deploy-azure-app-service.md @@ -0,0 +1,452 @@ +# Deploying ABP Project to Azure App Service + +In this document, you will learn how to create and deploy your first ABP web app to [Azure App Service](https://docs.microsoft.com/en-us/azure/app-service/overview). The App Service supports various versions of .NET apps, and provides a highly scalable, self-patching web hosting service. ABP web apps are cross-platform and can be hosted on Linux, Windows or MacOS. + +****Prerequisites**** + +- An Azure account with an active subscription. [Create an account for free](https://azure.microsoft.com/free/dotnet). +- A GitHub account [Create an account for free](http://github.com/). + + + +## Creating a new ABP application + +Create a repository on [GitHub.com](https://github.com/) (keep all settings as default). + +Open the command prompt and clone the repository into a folder on your computer + +```bash +git clone https://github.com/your-username/your-repository-name.git +``` + +Check your dotnet version. It should be at least 3.1.x + +```bash +dotnet --version +``` + +Install or update the [ABP CLI](https://docs.abp.io/en/abp/latest/cli) with the following command: + +```bash +dotnet tool install -g Volo.Abp.Cli || dotnet tool update -g Volo.Abp.Cli +``` + +Open the command prompt in the *GitHub repository folder* and create a new ABP Blazor solution with the command below: + +```bash +abp new YourAppName -u blazor +``` + + + +## Running the application + +Open the command prompt in the *[YourAppName].DbMigrator* project and enter the command below to apply the database migrations: + +```bash +dotnet run +``` + +Open the command prompt in the *[YourAppName].HttpApi.Host* project to run the API project: + +```bash +dotnet run +``` + +Navigate to the *applicationUrl* specified in *the launchSettings.json* file of the *[YourAppName].HttpApi.Host project*. You should get the *Swagger window* + +Open the command prompt in the *[YourAppName].Blazor* folder and enter the command below to run the Blazor project: + +```bash +dotnet run +``` + +Navigate to the *applicationUrl* specified in the *launchSettings.json* file of the *[YourAppName].Blazor* project and you should see the landing page. + +Stop both the *API* and the *Blazor* project by pressing **CTRL+C** + + + +## Committing to GitHub + +Before the GitHub commit, you have to delete the line "**/wwwroot/libs/*" at *.gitignore* file. + +![azdevops-23](images/azdevops-23.png) + +Open the command prompt in the root folder of your project and *add, commit and push* all your changes to your GitHub repository: + +```bash +git add . +git commit -m initialcommit +git push +``` + + + +## Configuring Azure database connection string + +Create a SQL database on Azure and change the connection string in all the *appsettings.json* files. + +* Login into [Azure Portal](https://portal.azure.com/) + +* Click **Create a resource** + +* Search for *SQL Database* + +* Click the **Create** button in the *SQL Database window* + +* Create a new resource group. Name it *rg[YourAppName]* + +* Enter *[YourAppName]Db* as database name + +* Create a new Server and name it *[yourappname]server* + +* Enter a serveradmin login and passwords. Click the **OK** button + +* Select your *Location* + +* Check *Allow Azure services to access server* + +* Click **Configure database**. Go to the *Basic* version and click the **Apply** button + +* Click the **Review + create** button. Click **Create** + +* Click **Go to resource** and click **SQL server** when the SQL Database is created + +* Click **Networking** under Security left side menu + +* Select **Selected networks** and click **Add your client IP$ address** at the Firewall rules + +* Select **Allow Azure and resources to access this seerver** and save + +* Go to your **SQL database**, click **Connection strings** and copy the connection string + +* Copy/paste the *appsettings.json* files of the *[YourAppName].HttpApi.Host* and the *[YourAppName].DbMigrator* project + +* Do not forget to replace {your_password} with the correct server password you entered in Azure SQL Database + + + +## Running DB Migrations + +Open the command prompt in the *[YourAppName].DbMigrator* project again and enter the command below to apply the database migrations: + +```bash +dotnet run +``` + +Open the command prompt in the *[YourAppName].HttpApi.Host* project and enter the command below to check your API is working: + +```bash +dotnet run +``` + +Stop the *[YourAppName].HttpApi.Host* by pressing CTRL+C. + + + +## Committing to GitHub + +Open the command prompt in the root folder of your project and add, commit and push all your changes to your GitHub repository + +```bash +git add . +git commit -m initialcommit +git push +``` + + + +## Setting up the Build pipeline in AzureDevops and publish the Build Artifacts + +* Sign in Azure DevOps + +* Click **New organization** and follow the steps to create a new organisation. Name it [YourAppName]org + +* Enter [YourAppName]Proj as project name in the ***Create a project to get started*** window + +* Select **Public visibility** and click the **Create project** button + +* Click the **Pipelines** button to continue + +* Click the **Create Pipeline** button + + Select GitHub in the Select your repository window + +![azdevops-1](images/azdevops-1.png) + +* Enter the Connection name. *[YourAppName]GitHubConnection* and click **Authorize using OAuth** + +* Select your **GitHub** [YourAppName]repo and click Continue + +* Search for **ASP.NET** in the ***Select a template*** window + +![azdevops-2](images/azdevops-2.png) + +* Select the ASP.NET Core template and click the **Apply** button + +* Add the below commands block as a first step in the pipeline + + ``` + - task: UseDotNet@2 + inputs: + packageType: 'sdk' + version: '6.0.106' + ``` + +![azdevops-18](images/azdevops-18.png) + +* Select **Settings** on the second task(Nugetcommand@2) in the pipeline + +* Select **Feeds in my Nuget.config** and type **Nuget.config** in the text box + +![azdevops-3](images/azdevops-3.png) + +* Add the below commands block to the end of the pipeline + + ``` + - task: PublishBuildArtifacts@1 + displayName: 'Publish Artifact' + inputs: + PathtoPublish: '$(build.artifactstagingdirectory)' + ArtifactName: '$(Parameters.ArtifactName)' + condition: succeededOrFailed() + ``` + + ![azdevops-4](images/azdevops-4.png) + +``` +# ASP.NET +# Build and test ASP.NET projects. +# Add steps that publish symbols, save build artifacts, deploy, and more: +# https://docs.microsoft.com/azure/devops/pipelines/apps/aspnet/build-aspnet-4 + +trigger: +- main + +pool: + vmImage: 'windows-latest' + +variables: + solution: '**/*.sln' + buildPlatform: 'Any CPU' + buildConfiguration: 'Release' + +steps: +- task: UseDotNet@2 + inputs: + packageType: 'sdk' + version: '6.0.106' + +- task: NuGetToolInstaller@1 + +- task: NuGetCommand@2 + inputs: + command: 'restore' + restoreSolution: '$(solution)' + feedsToUse: 'config' + nugetConfigPath: 'NuGet.config' + +- task: VSBuild@1 + inputs: + solution: '$(solution)' + msbuildArgs: '/p:DeployOnBuild=true /p:WebPublishMethod=Package /p:PackageAsSingleFile=true /p:SkipInvalidConfigurations=true /p:PackageLocation="$(build.artifactStagingDirectory)"' + platform: '$(buildPlatform)' + configuration: '$(buildConfiguration)' + +- task: VSTest@2 + inputs: + platform: '$(buildPlatform)' + configuration: '$(buildConfiguration)' + +- task: PublishBuildArtifacts@1 + displayName: 'Publish Artifact' + inputs: + PathtoPublish: '$(build.artifactstagingdirectory)' + ArtifactName: '$(Parameters.ArtifactName)' + publishLocation: 'Container' + condition: succeededOrFailed() +``` + +* Click **Save & queue** in the top menu. Click **Save & queue** again and click **Save and run** to run the Build pipeline + +* When the Build pipeline has finished. Click **1 published; 1 consumed** + + + +## Creating a Web App in the Azure Portal to deploy [YourAppName].HttpApi.Host project + +* Search for Web App in the *Search the Marketplace* field + +* Click the **Create** button in the Web App window + +* Select rg[YourAppName] in the *Resource Group* dropdown + +* Enter [YourAppName]API in the *Name input* field + +* Select code, .NET Core 3.1 (LTS) and windows as *Operating System* + +* Enter [YourAppName]API in the *Name input* field + +* Select .NET Core 3.1 (LTS) in the *Runtime stack* dropdown + +* Select Windows as *Operating System* + +* Select the same *Region* as in the SQL server you created in Part 3 + +![azdevops-5](images/azdevops-5.png) + +* Click **Create new** in the Windows Plan. Name it [YourAppName]ApiWinPlan + +* Click **Change size** in Sku and size. Go to the Dev/Test Free F1 version and click the **Apply** button + +![azdevops-6](images/azdevops-6.png) + +* Click the **Review + create** button. Click the **Create** button + +* Click **Go to resource** when the Web App has been created + + + +## Creating a release pipeline in the AzureDevops and deploy [YourAppName].HttpApi.Host project + +* Sign in into [Azure DevOps](https://azure.microsoft.com/en-us/services/devops/) + +* Click [YourAppName]Proj and click **Releases** in the *Pipelines* menu + +* Click the **New pipeline** button in the *No release pipelines found* window + +* Select *Azure App Service deployment* and click the **Apply** button + +![azdevops-7](images/azdevops-7.png) + +* Enter *[YourAppName]staging* in the *Stage name* field in the *Stage* window. And close the window + +* Click **+ Add an artifact** in the *Pipeline* tab + +* Select the **Build** icon as *Source type* in the *Add an artifact* window + +* Select Build pipeline in the *Source (build pipeline)* dropdown and click the **Add** button + +![azdevops-8](images/azdevops-8.png) + +* Click the **Continuous deployment trigger (thunderbolt icon)** + +* Set the toggle to **Enabled** in the the *Continuous deployment trigger* window + +* Click **+ Add** in *No filters added*. Select **Include** in the *Type* dropdown. Select your branch in the *Build branch* dropdown and close the window + +![azdevops-9](images/azdevops-9.png) + +* Click **the little red circle with the exclamation mark** in the *Tasks* tab menu + +* Select your subscription in the *Azure subscription* dropdown. + +![azdevops-10](images/azdevops-10.png) + +* Click **Authorize** and enter your credentials in the next screens + +* After Authorization, select the **[YourAppName]API** in the *App service name* dropdown + +* Click the **Deploy Azure App Service** task + +* Select **[YourAppName].HttpApi.Host.zip** in the *Package or folder* input field + +![azdevops-11](images/azdevops-11.png) + +* Click the **Save** icon in the top menu and click **OK** + +* Click **Create release** in the top menu. Click **Create** to create a release + +* Click the *Pipeline* tab and wait until the Deployment succeeds + +![azdevops-12](images/azdevops-12.png) + +* Open a browser and navigate to the URL of your Web App + +``` +https://[YourAppName]api.azurewebsites.net +``` + +![azdevops-13](images/azdevops-13.png) + + + +## Creating a Web App in Azure Portal to deploy [YourAppName].Blazor project + +* Login into [Azure Portal](https://portal.azure.com/) + +* Click **Create a resource** + +* Search for *Web App* in the *Search the Marketplace* field + +* Click the **Create** button in the *Web App* window + +* Select *rg[YourAppName]* in the *Resource Group* dropdown + +* Enter *[YourAppName]Blazor* in the *Name* input field + +* Select *.NET Core 3.1 (LTS)* in the *Runtime stack* dropdown + +* Select *Windows* as *Operating System* + +* Select the same region as the SQL server you created in Part 3 + +* Select the [YourAppName]ApiWinPlan in the *Windows Plan* dropdown + +![azdevops-14](images/azdevops-14.png) + +* Click the **Review + create** button. Click **Create** button + +* Click **Go to resource** when the Web App has been created + +* Copy the URL of the Blazor Web App for later use + +``` +https://[YourAppName]blazor.azurewebsites.net +``` + + +## Changing the Web App configuration for the Azure App Service + +Copy the URL of the Api Host and Blazor Web App. Change appsettings.json files in the Web App as follows images. + +![azdevops-19](images/azdevops-19.png) + +![azdevops-20](images/azdevops-20.png) + +![azdevops-21](images/azdevops-21.png) + + + +## Adding an extra Stage in the Release pipeline in the AzureDevops to deploy [YourAppName].Blazor project + +* Go to the *Release* pipeline in [Azure DevOps](https://azure.microsoft.com/en-us/services/devops/) and click **Edit** + +* Click the **+ Add** link and add a **New Stage** + +![azdevops-15](images/azdevops-15.png) + +* Select *Azure App Service deployment* and click the **Apply** button + +* Enter *BlazorDeployment* in the *Stage name* input field and close the *Stage* window + +* Click the **little red circle with the exclamation mark** in the BlazorDeployment stage + +* Select your subscription in the *Azure subscription* dropdown + +* Select your Blazor Web App in the *App service name* dropdown + +* Click the **Deploy Azure App Service task** + +* Select *[YourAppName].Blazor.zip* in the *Package or folder* input field + +![azdevops-16](images/azdevops-16.png) + +* Click **Save** in the top menu and click the **OK** button after + +* Click **Create release** in the top menu and click the **Create** button + +![azdevops-17](images/azdevops-17.png) + +![azdevops-22](images/azdevops-22.png) diff --git a/docs/en/Distributed-Event-Bus-RabbitMQ-Integration.md b/docs/en/Distributed-Event-Bus-RabbitMQ-Integration.md index 251a84510b..4823cbaae9 100644 --- a/docs/en/Distributed-Event-Bus-RabbitMQ-Integration.md +++ b/docs/en/Distributed-Event-Bus-RabbitMQ-Integration.md @@ -141,13 +141,14 @@ Configure(options => }); ```` -**Example: Configure the client and exchange names** +**Example: Configure the client, exchange names and prefetchCount** ````csharp Configure(options => { options.ClientName = "TestApp1"; options.ExchangeName = "TestMessages"; + options.PrefetchCount = 1; }); ```` diff --git a/docs/en/Entities.md b/docs/en/Entities.md index c57af27457..ef8f52a04f 100644 --- a/docs/en/Entities.md +++ b/docs/en/Entities.md @@ -112,6 +112,21 @@ For the example above, the composite key is composed of `UserId` and `RoleId`. F > Also note that Entities with Composite Primary Keys cannot utilize the `IRepository` interface since it requires a single Id property. However, you can always use `IRepository`. See [repositories documentation](Repositories.md) for more. +### EntityEquals + +`Entity.EntityEquals(...)` method is used to check if two Entity Objects are equals. + +Example: + +```csharp +Book book1 = ... +Book book2 = ... + +if (book1.EntityEquals(book2)) //Check equality +{ + ... +} +``` ## AggregateRoot Class diff --git a/docs/en/Multi-Tenancy.md b/docs/en/Multi-Tenancy.md index 569bfeb4ca..7dac3762aa 100644 --- a/docs/en/Multi-Tenancy.md +++ b/docs/en/Multi-Tenancy.md @@ -222,7 +222,6 @@ The following resolvers are provided and configured by default; * `CurrentUserTenantResolveContributor`: Gets the tenant id from claims of the current user, if the current user has logged in. **This should always be the first contributor for the security**. * `QueryStringTenantResolveContributor`: Tries to find current tenant id from query string parameters. The parameter name is `__tenant` by default. -* `FormTenantResolveContributor`:Tries to find current tenant id from form parameters. The parameter name is `__tenant` by default. * `RouteTenantResolveContributor`: Tries to find current tenant id from route (URL path). The variable name is `__tenant` by default. If you defined a route with this variable, then it can determine the current tenant from the route. * `HeaderTenantResolveContributor`: Tries to find current tenant id from HTTP headers. The header name is `__tenant` by default. * `CookieTenantResolveContributor`: Tries to find current tenant id from cookie values. The cookie name is `__tenant` by default. diff --git a/docs/en/Themes/LeptonXLite/AspNetCore.md b/docs/en/Themes/LeptonXLite/AspNetCore.md index eeaf55f545..f480141120 100644 --- a/docs/en/Themes/LeptonXLite/AspNetCore.md +++ b/docs/en/Themes/LeptonXLite/AspNetCore.md @@ -9,22 +9,22 @@ LeptonX Lite has implementation for the ABP Framework Razor Pages. It's a simpli This theme is **already installed** when you create a new solution using the startup templates. If you are using any other template, you can install this theme by following the steps below: -- Add **Volo.Abp.AspNetCore.Mvc.UI.Theme.LeptonXLite** package to your **Web** application. +- Add the **Volo.Abp.AspNetCore.Mvc.UI.Theme.LeptonXLite** package to your **Web** application. ```bash dotnet add package Volo.Abp.AspNetCore.Mvc.UI.Theme.LeptonXLite --prerelease ``` -- Remove **Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic** reference from the project since it's not necessary after switching to LeptonX Lite. +- Remove the **Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic** reference from the project since it's not necessary after switching to LeptonX Lite. - Make sure the old theme is removed and LeptonX is added in your Module class. ```diff [DependsOn( - // Remove BasicTheme module from DependsOn attribute + // Remove the BasicTheme module from DependsOn attribute - typeof(AbpAspNetCoreMvcUiBasicThemeModule), - // Add LeptonX Lite module to DependsOn attribute + // Add the LeptonX Lite module to DependsOn attribute + typeof(AbpAspNetCoreMvcUiLeptonXLiteThemeModule), )] ``` @@ -35,9 +35,9 @@ dotnet add package Volo.Abp.AspNetCore.Mvc.UI.Theme.LeptonXLite --prerelease Configure(options => { options.StyleBundles.Configure( - // Remove following line + // Remove the following line - BasicThemeBundles.Styles.Global, - // Add following line instead + // Add the following line instead + LeptonXLiteThemeBundles.Styles.Global bundle => { @@ -47,10 +47,24 @@ Configure(options => }); ``` ---- - ## Customization +### Layouts + +LeptonX Lite Mvc provides **layouts** for your **user interface** based [ABP Framework Theming](https://docs.abp.io/en/abp/latest/UI/AspNetCore/Theming). You can use **layouts** to **organize your user interface**. + +The main responsibility of a theme is to **provide** the layouts. There are **three pre-defined layouts that must be implemented by all the themes:** + +* **Application:** The **default** layout which is used by the **main** application pages. + +* **Account:** Mostly used by the **account module** for **login**, **register**, **forgot password**... pages. + +* **Empty:** The **Minimal** layout that **has no layout components** at all. + +**Layout names** are **constants** defined in the `LeptonXLiteTheme` class in the **Mvc** project **root**. + +> The layout pages define under the `Themes/LeptonXLite/Layouts` folder and you can **override it** by creating a file with the **same name** and **under** the **same folder**. + ### Toolbars LeptonX Lite includes separeted toolbars for desktop & mobile. You can manage toolbars independently. Toolbar names can be accessible in the **LeptonXLiteToolbars** class. @@ -74,3 +88,128 @@ public class MyProjectNameMainToolbarContributor : IToolbarContributor } } ``` +# LeptonX Lite Mvc Components + +Abp **helps** you make **highly customizable UI**. You can easily **customize** your themes to fit your needs. **The Virtual File System** makes it possible to **manage files** that **do not physically** exist on the **file system** (disk). It's mainly used to embed **(js, css, image..)** files into assemblies and **use them like** physical files at runtime. An application (or another module) can **override** a **virtual file of a module** just like placing a file with the **same name** and **extension** into the **same folder** of the **virtual file**. + +LeptonX Lite is built on the [Abp Framework](https://abp.io/), so you can **easily** customize your Asp.Net Core Mvc user interface by following [Abp Mvc UI Customization](https://docs.abp.io/en/abp/latest/UI/AspNetCore/Customization-xUser-Interface). + +## Brand Component + +The **brand component** is a simple component that can be used to display your brand. It contains a **logo** and a **company name**. + +![Brand component](../../images/leptonxlite-brand-component.png) + +### How to override the Brand Component in LeptonX Lite Mvc + +* The **brand component page (.cshtml file)** is defined in the `Themes/LeptonXLite/Components/Brand/Default.cshtml` file and you can **override it** by creating a file with the **same name** and **under** the **same folder**. + +* The **brand component (C# file)** is defined in the `Themes/LeptonXLite/Components/Brand/MainNavbarBrandViewComponent.cs` file and you can **override it** by creating a file with the **same name** and under the **same folder**. + +## Breadcrumb Component + +On websites that have a lot of pages, **breadcrumb navigation** can greatly **enhance the way users find their way** around. In terms of **usability**, breadcrumbs reduce the number of actions a website **visitor** needs to take in order to get to a **higher-level page**, and they **improve** the **findability** of **website sections** and **pages**. + +![Breadcrumb component](../../images/leptonxlite-breadcrumb-component.png) + +### How to override the Breadcrumb Component in LeptonX Lite Mvc + +* The **breadcrumb component page (.cshtml file)** is defined in the `Themes/LeptonXLite/Components/Breadcrumbs/Default.cshtml` file and you can **override it** by creating a file with the **same name** and **under** the **same folder**. + +* The **breadcrumb component (C# file)** is defined in the `Themes/LeptonXLite/Components/Breadcrumbs/BreadcrumbsViewComponent.cs` file and you can **override it** by creating a file with the **same name** and **under** the **same folder**. + +## Sidebar Menu Component + +Sidebar menus have been used as **a directory for Related Pages** to a **Service** offering, **Navigation** items to a **specific service** or topic and even just as **Links** the user may be interested in. + +![Sidebar menu component](../../images/leptonxlite-sidebar-menu-component.png) + +### How to override the Sidebar Menu Component in LeptonX Lite Mvc + +* **Sidebar menu page (.cshtml)** is defined in the `Themes/LeptonXLite/Components/Menu/Default.cshtml` file and you can **override it** by creating a file with the **same name** and **under** the **same folder**. + +* If you want to **override the menu component (C#)** you can override the `Themes/LeptonXLite/Components/Menu/MainMenuViewComponent.cs` file and you can **override it** by creating a file with the **same name** and **under** the **same folder**. + +> The **sidebar menu** renders menu items **dynamically**. The **menu item** is a **partial view** and is defined in the `Themes/LeptonXLite/Components/Menu/_MenuItem.cshtml` file and you can **override it** by creating a file with the **same name** and **under** the **same folder**. + +## Page Alerts Component + +Provides contextual **feedback messages** for typical user actions with the handful of **available** and **flexible** **alert messages**. Alerts are available for any length of text, as well as an **optional dismiss button**. + +![Page alerts component](../../images/leptonxlite-page-alerts-component.png) + +### How to override the Page Alerts Component in LeptonX Lite Mvc + +* The **page alerts component page (.cshtml file)** is defined in the `Themes/LeptonXLite/Components/PageAlerts/Default.cshtml` file and you can **override it** by creating a file with the **same name** and **under** the **same folder**. + +* The **page alerts component (C#)** is defined in the `Themes/LeptonXLite/Components/PageAlerts/PageAlertsViewComponent.cs` file and you can **override it** by creating a file with the **same name** and **under** the **same folder**. + +## Toolbar Component + +Toolbar items are used to add **extra functionality to the toolbar**. The toolbar is a **horizontal bar** that **contains** a group of **toolbar items**. + +### How to override the Toolbar Component in LeptonX Lite Mvc + +* The **toolbar component page (.cshtml file)** is defined in the `Themes/LeptonXLite/Components/Toolbar/Default.cshtml` file and you can **override it** by creating a file with the **same name** and **under** the **same folder**. + +* The **toolbar component (C#)** is defined in the `Themes/LeptonXLite/Components/Toolbar/ToolbarViewComponent.cs` file and you can **override it** by creating a file with the **same name** and **under** the **same folder**. + +## Toolbar Item Component + +The toolbar item is a **single item** that **contains** a **link**, an **icon**, a **label** etc.. + +### How to override the Toolbar Item Component in LeptonX Lite Mvc + +* The **toolbar item component page (.cshtml file)** is defined in the `Themes/LeptonXLite/Components/ToolbarItems/Default.cshtml` file and you can **override it** by creating a file with the **same name** and **under** the **same folder**. + +* The **toolbar item component (C#)** is defined in the `Themes/LeptonXLite/Components/ToolbarItems/ToolbarItemsViewComponent.cs` file and you can **override it** by creating a file with the **same name** and **under** the **same folder**. + +You can find the toolbar components below: + +## Language Switch Component + +Think about a **multi-lingual** website and the first thing that could **hit your mind** is **the language switch component**. A **navigation bar** is a **great place** to **embed a language switch**. By embedding the language switch in the navigation bar of your website, you would **make it simpler** for users to **find it** and **easily** switch the **language** **without trying to locate it across the website.** + +![Language switch component](../../images/leptonxlite-language-switch-component.png) + +### How to override the Language Switch Component in LeptonX Lite Mvc + +* The **language switch component page (.cshtml file)** is defined in the `Themes/LeptonXLite/Components/LanguageSwitch/Default.cshtml` file and you can **override it** by creating a file with the **same name** and **under** the **same folder**. + +* The **language switch component (C#)** is defined in the `Themes/LeptonXLite/Components/LanguageSwitch/LanguageSwitchViewComponent.cs` file and you can **override it** by creating a file with the **same name** and **under** the **same folder**. + +## Mobile Language Switch Component + +The **mobile** **language switch component** is used to switch the language of the website **on mobile devices**. The mobile language switch component is a **dropdown menu** that **contains all the languages** of the website. + +![Mobil language switch component](../../images/leptonxlite-mobile-language-switch-component.png) + +### How to override the Mobile Language Switch Component in LeptonX Lite Mvc + +* The **mobile language switch component page (.cshtml file)** is defined in the `Themes/LeptonXLite/Components/MobileLanguageSwitch/Default.cshtml` file and you can **override it** by creating a file with the **same name** and **under** the **same folder**. + +* The **mobile language switch component (C#)** is defined in the `Themes/LeptonXLite/Components/MobileLanguageSwitch/MobileLanguageSwitchViewComponent.cs` file and you can **override it** by creating a file with the **same name** and **under** the **same folder**. + +## User Menu Component + +The **User Menu** is the **menu** that **drops down** when you **click your name** or **profile picture** in the **upper right corner** of your page (**in the toolbar**). It drops down options such as **Settings**, **Logout**, etc. + +![User menu component](../../images/leptonxlite-user-menu-component.png) + +### How to override the User Menu Component in LeptonX Lite Mvc + +* The **user menu component page (.cshtml file)** is defined in the `Themes/LeptonXLite/Components/UserMenu/Default.cshtml` file and you can **override it** by creating a file with the **same name** and **under** the **same folder**. + +* The **user menu component (C#)** is defined in the `Themes/LeptonXLite/Components/UserMenu/UserMenuViewComponent.cs` file and you can **override it** by creating a file with the **same name** and **under** the **same folder**. + +## Mobile User Menu Component + +The **mobile user menu component** is used to display the **user menu on mobile devices**. The mobile user menu component is a **dropdown menu** that contains all the **options** of the **user menu**. + +![Mobile user menu component](../../images/leptonxlite-mobile-user-menu-component.png) + +### How to override the Mobile User Menu Component in LeptonX Lite Mvc + +* The **mobile user menu component page (.cshtml file)** is defined in the `Themes/LeptonXLite/Components/MobileUserMenu/Default.cshtml` file and you can **override it** by creating a file with the **same name** and **under** the **same folder**. + +* The **mobile user menu component (C#)** is defined in the `Themes/LeptonLite/Components/MobileUserMenu/MobileUserMenuViewComponent.cs` file and you can **override it** by creating a file with the **same name** and **under** the **same folder**. diff --git a/docs/en/images/leptonxlite-brand-component.png b/docs/en/images/leptonxlite-brand-component.png new file mode 100644 index 0000000000..c06a51612f Binary files /dev/null and b/docs/en/images/leptonxlite-brand-component.png differ diff --git a/docs/en/images/leptonxlite-breadcrumb-component.png b/docs/en/images/leptonxlite-breadcrumb-component.png new file mode 100644 index 0000000000..9026ca4c52 Binary files /dev/null and b/docs/en/images/leptonxlite-breadcrumb-component.png differ diff --git a/docs/en/images/leptonxlite-language-switch-component.png b/docs/en/images/leptonxlite-language-switch-component.png new file mode 100644 index 0000000000..027910c23b Binary files /dev/null and b/docs/en/images/leptonxlite-language-switch-component.png differ diff --git a/docs/en/images/leptonxlite-mobile-language-switch-component.png b/docs/en/images/leptonxlite-mobile-language-switch-component.png new file mode 100644 index 0000000000..a058820743 Binary files /dev/null and b/docs/en/images/leptonxlite-mobile-language-switch-component.png differ diff --git a/docs/en/images/leptonxlite-mobile-user-menu-component.png b/docs/en/images/leptonxlite-mobile-user-menu-component.png new file mode 100644 index 0000000000..1a51c341d7 Binary files /dev/null and b/docs/en/images/leptonxlite-mobile-user-menu-component.png differ diff --git a/docs/en/images/leptonxlite-page-alerts-component.png b/docs/en/images/leptonxlite-page-alerts-component.png new file mode 100644 index 0000000000..7976412fb2 Binary files /dev/null and b/docs/en/images/leptonxlite-page-alerts-component.png differ diff --git a/docs/en/images/leptonxlite-sidebar-menu-component.png b/docs/en/images/leptonxlite-sidebar-menu-component.png new file mode 100644 index 0000000000..6afe4029e8 Binary files /dev/null and b/docs/en/images/leptonxlite-sidebar-menu-component.png differ diff --git a/docs/en/images/leptonxlite-user-menu-component.png b/docs/en/images/leptonxlite-user-menu-component.png new file mode 100644 index 0000000000..a0039e996c Binary files /dev/null and b/docs/en/images/leptonxlite-user-menu-component.png differ diff --git a/docs/es/Getting-Started-AspNetCore-Application.md b/docs/es/Getting-Started-AspNetCore-Application.md new file mode 100644 index 0000000000..c4d124d827 --- /dev/null +++ b/docs/es/Getting-Started-AspNetCore-Application.md @@ -0,0 +1,140 @@ +# Empezando con ABP y una Aplicacion AspNet Core MVC Web + +Este tutorial explica como empezar una aplicacion ABP desde cero usando las dependencias minimas. Uno generalmente desea +empezar con la **[plantilla de inicio](Getting-Started-AspNetCore-MVC-Template.md)**. + +## Crea un Proyecto Nuevo + +1. Crea una Aplicacion Web AspNet Core nueva usando Visual Studio 2022 (17.0.0+): + +![](images/create-new-aspnet-core-application-v2.png) + +2. Configura el nuevo proyecto: + +![](images/select-empty-web-application-v2.png) + +3. Presione el boton Create: + +![create-aspnet-core-application](images/create-aspnet-core-application.png) + +## Instale el paquete Volo.Abp.AspNetCore.Mvc + +Volo.Abp.AspNetCore.Mvc es el paquete de integracion con AspNet Core MVC para ABP. Siendo asi, instalalo en su proyecto: + +```` +Install-Package Volo.Abp.AspNetCore.Mvc +```` + +## Crea el primer modulo ABP + +ABP es un marco de referencia modular y require una clase de **inicio (raíz) tipo modulo** derivada de ``AbpModule``: + +````C# +using Microsoft.AspNetCore.Builder; +using Microsoft.Extensions.Hosting; +using Volo.Abp; +using Volo.Abp.AspNetCore.Mvc; +using Volo.Abp.Modularity; + +namespace BasicAspNetCoreApplication +{ + [DependsOn(typeof(AbpAspNetCoreMvcModule))] + public class AppModule : AbpModule + { + public override void OnApplicationInitialization(ApplicationInitializationContext context) + { + var app = context.GetApplicationBuilder(); + var env = context.GetEnvironment(); + + // Configura la canalización de peticiones HTTP. + if (env.IsDevelopment()) + { + app.UseExceptionHandler("/Error"); + // El valor por defecto de HSTS es 30 dias. Debes cambiar esto en ambientes productivos. Referencia https://aka.ms/aspnetcore-hsts. + app.UseHsts(); + } + + app.UseHttpsRedirection(); + app.UseStaticFiles(); + app.UseRouting(); + app.UseConfiguredEndpoints(); + } + } +} +```` + +``AppModule`` es un buen nombre para el modulo de inicio de una aplicacion. + +Los paquetes de ABP definen clases de tipo modulo y cada modulo puede depender de otro. +En el codigo anterior, el ``AppModule`` depende de el modulo ``AbpAspNetCoreMvcModule`` (definido por el paquete [Volo.Abp.AspNetCore.Mvc](https://www.nuget.org/packages/Volo.Abp.AspNetCore.Mvc)). Es comun agregar el atributo ``DependsOn`` despues de instalar un paquete ABP nuevo. + +En vez de la clase de inicion Startup, estamos configurando una canalizacion de ASP.NET Core en este modulo. + +## La clase Program + +El proximo paso es modificar la clase Program para integrate el sistema de modulos ABP: + +````C# +using BasicAspNetCoreApplication; + +var builder = WebApplication.CreateBuilder(args); + +await builder.Services.AddApplicationAsync(); + +var app = builder.Build(); + +await app.InitializeApplicationAsync(); +await app.RunAsync(); +```` + +``builder.Services.AddApplicationAsync();`` Agrega todos los servicios definidos en todos los modulos empezando desde ``AppModule``. + +``app.InitializeApplicationAsync()`` inicializa y empieza la aplicacion. + +## Ejecutar la Aplicación + +Es todo! Ejecuta la aplicación, debe funcionar como esperado. + +## Uso de Autofac como Marco de Inyección de Dependencia + +Mientras el sistema de Inyección de Dependencia de ASP.NET Core es suficiente para requerimientos basico, [Autofac](https://autofac.org/) proporciona características avanzadas como Inyección de Propiedades e Intercepcion de Metodos, los cuales son necesarios para que ABP pueda llevar a cabo funciones avanzadas. + +El acto de remplazar el sistema DI de ASP.NET Core por Autofac e integrarlo con ABP es facil. + +1. Instala el paquete [Volo.Abp.Autofac](https://www.nuget.org/packages/Volo.Abp.Autofac) + +```` +Install-Package Volo.Abp.Autofac +```` + +2. Agrega la dependencia sobre el modulo ``AbpAutofacModule`` + +````C# +[DependsOn(typeof(AbpAspNetCoreMvcModule))] +[DependsOn(typeof(AbpAutofacModule))] //Agrega la dependencia sobre el modulo ABP Autofac +public class AppModule : AbpModule +{ + ... +} +```` + +3. Actualiza `Program.cs` para que use Autofac: + +````C# +using BasicAspNetCoreApplication; + +var builder = WebApplication.CreateBuilder(args); + +builder.Host.UseAutofac(); //Agrega esta linea + +await builder.Services.AddApplicationAsync(); + +var app = builder.Build(); + +await app.InitializeApplicationAsync(); +await app.RunAsync(); +```` + +## Codigo fuente + + Obten el codigo fuente del ejemplo creado en este tutorial de [aqui](https://github.com/abpframework/abp-samples/tree/master/BasicAspNetCoreApplication). diff --git a/docs/es/images/create-aspnet-core-application.png b/docs/es/images/create-aspnet-core-application.png new file mode 100644 index 0000000000..b8b98f5c32 Binary files /dev/null and b/docs/es/images/create-aspnet-core-application.png differ diff --git a/docs/es/images/create-new-aspnet-core-application-v2.png b/docs/es/images/create-new-aspnet-core-application-v2.png new file mode 100644 index 0000000000..f8274ae2a4 Binary files /dev/null and b/docs/es/images/create-new-aspnet-core-application-v2.png differ diff --git a/docs/es/images/select-empty-web-application-v2.png b/docs/es/images/select-empty-web-application-v2.png new file mode 100644 index 0000000000..da32f71857 Binary files /dev/null and b/docs/es/images/select-empty-web-application-v2.png differ diff --git a/docs/pt-BR/Validation.md b/docs/pt-BR/Validation.md index 5818566cdd..662235431a 100644 --- a/docs/pt-BR/Validation.md +++ b/docs/pt-BR/Validation.md @@ -1,3 +1,182 @@ -## Validation +# Validação -Façam \ No newline at end of file +O sistema de validação é utilizado para validar a entrada do usuário ou a requisição do cliente para uma ação de um controller ou por um serviço. + +O ABP é compatível com o sistema de Validação de Modelos do ASP.NET Core e tudo escrito na [sua documentação](https://docs.microsoft.com/en-us/aspnet/core/mvc/models/validation) é válido para aplicações baseadas no ABP. Logo, esse documento foca nas funcionalidades do ABP ao invés de repetir a documentação da Microsoft. + +Além disso, o ABP adiciona os seguintes benefícios: + +* Define `IValidationEnabled` para adicionar validação automática para uma classe qualquer. Como todos os [serviços de aplicação](Application-Services.md) já o implementam, eles também são validados automaticamente. +* Automaticamente traduz os erros de validação para os atributos de anotação de dados. +* Provê serviços extensíveis para validar a chamada de um método ou o estado de um objeto. +* Provê integração com o [FluentValidation](https://fluentvalidation.net/) + +## Validando DTOs + +Essa seção introduz brevemente o sistema de validação. Para mais detalhes, veja a [Documentação da Validação de Modelo em ASP.NET Core](https://docs.microsoft.com/en-us/aspnet/core/mvc/models/validation). + +### Atributos de anotação de dados + +Utilizar anotações de dados é uma maneira simples de implementar uma validação formal para um [DTO](Data-Transfer-Objects.md) de uma forma declarativa. Exemplo: + +````csharp +public class CreateBookDto +{ + [Required] + [StringLength(100)] + public string Name { get; set; } + + [Required] + [StringLength(1000)] + public string Description { get; set; } + + [Range(0, 999.99)] + public decimal Price { get; set; } +} +```` +Quando você utilizar essa classe como parâmetro para um [serviço da aplicação](Application-Services.md) ou um controller, ele será automaticamente validado e a validação traduzida será lançada ([e tratada](Exception-Handling.md) pelo ABP framework). + +### IValidatableObject + +`IValidatableObject` pode ser implementado por um DTO para executar uma lógica customizada de validação. O `CreateBookDto` no exemplo a seguir implementa essa interface e verifica se o `Name` é igual a `Description` e retorna um erro de validação nesse caso. + +````csharp +using System.Collections.Generic; +using System.ComponentModel.DataAnnotations; + +namespace Acme.BookStore +{ + public class CreateBookDto : IValidatableObject + { + [Required] + [StringLength(100)] + public string Name { get; set; } + + [Required] + [StringLength(1000)] + public string Description { get; set; } + + [Range(0, 999.99)] + public decimal Price { get; set; } + + public IEnumerable Validate( + ValidationContext validationContext) + { + if (Name == Description) + { + yield return new ValidationResult( + "Name and Description can not be the same!", + new[] { "Name", "Description" } + ); + } + } + } +} +```` + +#### Resolvendo um serviço. + +Se você precisar resolver um serviço do [sistema de injeção de dependências](Dependency-Injection.md), você pode utilizar o objeto `ValidationContext`. + +````csharp +var myService = validationContext.GetRequiredService(); +```` + +> Enquanto resolver os serviços no método `Validate` permite várias possibilidades, não é um boa prática implementar sua lógica de validação do domínio nos DTOs. Mantenha os DTOs simples. Seu propósito é transferir dados (DTO: Data Transfer Object, ou Objeto de Transferência de Dados). + +## Infraestrutura de Validação. + +Essa seção explica alguns serviços adicionais fornecidos pelo ABP Framework. + +### Interface IValidationEnabled + +`IValidationEnabled` é um marcador vazio de interface que pode ser implementado por qualquer classe (registrada e resolvida a partir do [DI](Dependency-Injection.md)) para permitir que o ABP framework realize o sistema de validação para os métodos da classe. Por exemplo: + +````csharp +using System.Threading.Tasks; +using Volo.Abp.DependencyInjection; +using Volo.Abp.Validation; + +namespace Acme.BookStore +{ + public class MyService : ITransientDependency, IValidationEnabled + { + public virtual async Task DoItAsync(MyInput input) + { + //... + } + } +} +```` + +> O ABP framework utiliza o sistema de [Proxying Dinâmico / Interceptadores](Dynamic-Proxying-Interceptors.md) para realizar a validação. Para fazê-lo funcionar, seu método deve ser **virtual** ou seu serviço deve ser injetado e utilizado através de uma **interface** (como `IMyService`). + +#### Habilitando e Desabilitando Validações + +Você pode utilizar o `[DisableValidation]` e desabilitar a validação para métodos, classes e propriedades. + +````csharp +[DisableValidation] +public Void MyMethod() +{ +} + +[DisableValidation] +public class InputClass +{ + public string MyProperty { get; set; } +} + +public class InputClass +{ + [DisableValidation] + public string MyProperty { get; set; } +} +```` + +### AbpValidationException + +Uma vez que o ABP determina um erro de validação, é lançada uma validação do tipo `AbpValidationException`. O código da sua aplicação poderá lançar o `AbpValidationException`, mas na maioria das vezes não será necessário. + +* A propriedade `ValidationErrors` do `AbpValidationException` contem a lista com os erros de validação. +* O nível de log do `AbpValidationException` é definido como `Warning`. Todos os erros de validação são logados no [Sistema de Logging](Logging.md). +* `AbpValidationException` é tratado automaticamente pelo ABP framework e é convertido em um erro utilizável com o código de status HTTP 400. Veja a documentação de [Manipulação de Exceção](Exception-Handling.md) para mais informações. + +## Tópicos Avançados + +### IObjectValidator + +Além da validação automática, você pode querer validar um objeto manualmente. Nesse caso, [injete](Dependency-Injection.md) e use o serviço `IObjectValidator`: + +* O método `ValidateAsync` valida o objeto informado baseado nas regras de validação e lança uma `AbpValidationException` se não estiver em um estado válido. + +* `GetErrorsAsync` não lança uma exceção, somente retorna os erros de validação. + +`IObjectValidator` é implementado pelo `ObjectValidator` por padrão. `ObjectValidator` é extensível; você pode implementar a interface `IObjectValidationContributor` para contribuir com uma lógica customizada. Exemplo: + +````csharp +public class MyObjectValidationContributor + : IObjectValidationContributor, ITransientDependency +{ + public Task AddErrorsAsync(ObjectValidationContext context) + { + //Get the validating object + var obj = context.ValidatingObject; + + //Add the validation errors if available + context.Errors.Add(...); + return Task.CompletedTask; + } +} +```` + +* Lembre-se de registrar sua classe no [DI](Dependency-Injection.md) (implementar `ITransientDependency` faz isso no exemplo anterior) +* ABP vai automaticamente descobrir sua classe e utilizá-la em qualquer tipo de validação de objetos (incluindo chamadas de métodos de validação automáticas). + +### IMethodInvocationValidator + +`IMethodInvocationValidator` é utilizado para validar a chamada de um método. Ele utiliza internamente o `IObjectValidator` para validar os objetos passados na chamada do método. Você normalmente não precisa deste serviço, já que ele é utilizado automaticamente pelo framework, mas você pode querer reutilizar ou substituir na sua aplicação em alguns casos raros. + +## Integração com FluentValidation + +O pacote Volo.Abp.FluentValidation integra a biblioteca FluentValidation com o sistema de validação (implementando o `IObjectValidationContributor`). Veja o [documento de Integração com o FluentValidation](FluentValidation.md) para mais informações. diff --git a/docs/zh-Hans/Background-Jobs-Hangfire.md b/docs/zh-Hans/Background-Jobs-Hangfire.md index b1bf7b8c79..fb899758cc 100644 --- a/docs/zh-Hans/Background-Jobs-Hangfire.md +++ b/docs/zh-Hans/Background-Jobs-Hangfire.md @@ -66,6 +66,41 @@ public class YourModule : AbpModule } ```` +### 指定队列 + +你可以使用 [`QueueAttribute`](https://docs.hangfire.io/en/latest/background-processing/configuring-queues.html) 来指定队列. + +````csharp +using System.Threading.Tasks; +using Volo.Abp.BackgroundJobs; +using Volo.Abp.DependencyInjection; +using Volo.Abp.Emailing; + +namespace MyProject +{ + [Queue("alpha")] + public class EmailSendingJob + : AsyncBackgroundJob, ITransientDependency + { + private readonly IEmailSender _emailSender; + + public EmailSendingJob(IEmailSender emailSender) + { + _emailSender = emailSender; + } + + public override async Task ExecuteAsync(EmailSendingArgs args) + { + await _emailSender.SendAsync( + args.EmailAddress, + args.Subject, + args.Body + ); + } + } +} +```` + 1. 如果你想要使用Hangfire的面板,你可以在 `Module` 类的 `OnApplicationInitialization` 方法添加: `UseHangfireDashboard` ````csharp diff --git a/docs/zh-Hans/Background-Jobs-RabbitMq.md b/docs/zh-Hans/Background-Jobs-RabbitMq.md index 0f9fb21d8a..8bf61846e7 100644 --- a/docs/zh-Hans/Background-Jobs-RabbitMq.md +++ b/docs/zh-Hans/Background-Jobs-RabbitMq.md @@ -126,25 +126,31 @@ Configure(options => Configure(options => { options.DefaultQueueNamePrefix = "my_app_jobs."; + options.DefaultDelayedQueueNamePrefix = "my_app_jobs.delayed" + options.PrefetchCount = 1; options.JobQueues[typeof(EmailSendingArgs)] = new JobQueueConfiguration( typeof(EmailSendingArgs), queueName: "my_app_jobs.emails", - connectionName: "SecondConnection" + connectionName: "SecondConnection", + delayedQueueName:"my_app_jobs.emails.delayed" ); }); ``` -- 这个示例将默认的队列名前缀设置为 `my_app_jobs.`,如果多个项目都使用的同一个 RabbitMQ 服务,设置不同的前缀可以避免执行其他项目的后台作业. +- 这个示例将默认的队列名前缀设置为 `my_app_jobs.`并且设置默认的延迟队列名为 `my_app_jobs.delayed`,如果多个项目都使用的同一个 RabbitMQ 服务,设置不同的前缀可以避免执行其他项目的后台作业. +- 设置了预取数量, 用于所有队列. - 这里还设置了 `EmailSendingArgs` 绑定的 RabbitMQ 连接. `JobQueueConfiguration` 类的构造函数中,还有一些其他的可选参数. - `queueName`: 指定后台作业对应的队列名称(全名). +* `DelayedQueueName`: 指定后台延迟执行的作业对于的队列名称(全名). - `connectionName`: 后台作业对应的 RabbitMQ 连接名称,默认是 `Default`. - `durable`: 可选参数,默认为 `true`. - `exclusive`: 可选参数,默认为 `false`. - `autoDelete`: 可选参数,默认为 `false`. +* `PrefetchCount` (可选参数, 默认为: null) 如果你想要更多地了解 `durable`,`exclusive`,`autoDelete` 的用法,请阅读 RabbitMQ 提供的文档. diff --git a/docs/zh-Hans/Distributed-Event-Bus-RabbitMQ-Integration.md b/docs/zh-Hans/Distributed-Event-Bus-RabbitMQ-Integration.md index 1cd6b5b9dd..f45d4d90bf 100644 --- a/docs/zh-Hans/Distributed-Event-Bus-RabbitMQ-Integration.md +++ b/docs/zh-Hans/Distributed-Event-Bus-RabbitMQ-Integration.md @@ -141,13 +141,14 @@ Configure(options => }); ```` -**示例: 配置客户端和交换机名称** +**示例: 配置客户端,交换机名称和预取数量** ````csharp Configure(options => { options.ClientName = "TestApp1"; options.ExchangeName = "TestMessages"; + options.PrefetchCount = 1; }); ```` diff --git a/docs/zh-Hans/Entities.md b/docs/zh-Hans/Entities.md index 8fbf16ddd3..b9c236e346 100644 --- a/docs/zh-Hans/Entities.md +++ b/docs/zh-Hans/Entities.md @@ -105,6 +105,22 @@ public class UserRole : Entity > 需要注意,复合主键实体不可以使用 `IRepository` 接口,因为它需要一个唯一的Id属性. 但你可以使用 `IRepository`.更多信息请参见[仓储](Repositories.md)的文档. +### EntityEquals + +`Entity.EntityEquals(...)` 方法用于检查两个实体对象是否相等. + +示例: + +```csharp +Book book1 = ... +Book book2 = ... + +if (book1.EntityEquals(book2)) //Check equality +{ + ... +} +``` + ## 聚合根 "*聚合是域驱动设计中的一种模式.DDD的聚合是一组可以作为一个单元处理的域对象.例如,订单及订单系列的商品,这些是独立的对象,但将订单(连同订单系列的商品)视为一个聚合通常是很有用的*"( [查看详细介绍](http://martinfowler.com/bliki/DDD_Aggregate.html)) diff --git a/docs/zh-Hans/Multi-Tenancy.md b/docs/zh-Hans/Multi-Tenancy.md index 472dde9eab..6db625e7d9 100644 --- a/docs/zh-Hans/Multi-Tenancy.md +++ b/docs/zh-Hans/Multi-Tenancy.md @@ -322,7 +322,6 @@ Volo.Abp.AspNetCore.MultiTenancy 添加了下面这些租户解析器,从当前W * **CurrentUserTenantResolveContributor**: 如果当前用户已登录,从当前用户的声明中获取租户Id. **出于安全考虑,应该始终将其做为第一个Contributor**. * **QueryStringTenantResolveContributor**: 尝试从query string参数中获取当前租户,默认参数名为"__tenant". -* **FormTenantResolveContributor**: 尝试从form参数中获取当前租户,默认参数名为"__tenant". * **RouteTenantResolveContributor**:尝试从当前路由中获取(URL路径),默认是变量名是"__tenant".所以,如果你的路由中定义了这个变量,就可以从路由中确定当前租户. * **HeaderTenantResolveContributor**: 尝试从HTTP header中获取当前租户,默认的header名称是"__tenant". * **CookieTenantResolveContributor**: 尝试从当前cookie中获取当前租户.默认的Cookie名称是"__tenant". diff --git a/framework/Volo.Abp.sln b/framework/Volo.Abp.sln index fadd40bcc5..4ce47bdbc8 100644 --- a/framework/Volo.Abp.sln +++ b/framework/Volo.Abp.sln @@ -409,6 +409,18 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Volo.Abp.RemoteServices", " EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Volo.Abp.AspNetCore.Mvc.PlugIn", "test\Volo.Abp.AspNetCore.Mvc.PlugIn\Volo.Abp.AspNetCore.Mvc.PlugIn.csproj", "{C6D6D878-208A-4FD2-822E-365545D8681B}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Volo.Abp.Dapr", "src\Volo.Abp.Dapr\Volo.Abp.Dapr.csproj", "{192A829F-D608-4E41-8DE0-058E943E453F}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Volo.Abp.EventBus.Dapr", "src\Volo.Abp.EventBus.Dapr\Volo.Abp.EventBus.Dapr.csproj", "{DCC41E99-EBC7-4F19-BA0D-A6F770D8E431}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Volo.Abp.Http.Client.Dapr", "src\Volo.Abp.Http.Client.Dapr\Volo.Abp.Http.Client.Dapr.csproj", "{18B796D2-D45D-41AE-9A42-75C9B14B20DF}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Volo.Abp.AspNetCore.Mvc.Dapr", "src\Volo.Abp.AspNetCore.Mvc.Dapr\Volo.Abp.AspNetCore.Mvc.Dapr.csproj", "{5EED625D-8D86-492A-BCB8-F6C8CD8D4AA1}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Volo.Abp.AspNetCore.Mvc.Dapr.EventBus", "src\Volo.Abp.AspNetCore.Mvc.Dapr.EventBus\Volo.Abp.AspNetCore.Mvc.Dapr.EventBus.csproj", "{B02EF042-C39E-45C4-A92D-BF7554E1889D}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Volo.Abp.DistributedLocking.Dapr", "src\Volo.Abp.DistributedLocking.Dapr\Volo.Abp.DistributedLocking.Dapr.csproj", "{CAE48068-233C-47A9-BEAB-DDF521730E7A}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -1219,6 +1231,30 @@ Global {C6D6D878-208A-4FD2-822E-365545D8681B}.Debug|Any CPU.Build.0 = Debug|Any CPU {C6D6D878-208A-4FD2-822E-365545D8681B}.Release|Any CPU.ActiveCfg = Release|Any CPU {C6D6D878-208A-4FD2-822E-365545D8681B}.Release|Any CPU.Build.0 = Release|Any CPU + {192A829F-D608-4E41-8DE0-058E943E453F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {192A829F-D608-4E41-8DE0-058E943E453F}.Debug|Any CPU.Build.0 = Debug|Any CPU + {192A829F-D608-4E41-8DE0-058E943E453F}.Release|Any CPU.ActiveCfg = Release|Any CPU + {192A829F-D608-4E41-8DE0-058E943E453F}.Release|Any CPU.Build.0 = Release|Any CPU + {DCC41E99-EBC7-4F19-BA0D-A6F770D8E431}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {DCC41E99-EBC7-4F19-BA0D-A6F770D8E431}.Debug|Any CPU.Build.0 = Debug|Any CPU + {DCC41E99-EBC7-4F19-BA0D-A6F770D8E431}.Release|Any CPU.ActiveCfg = Release|Any CPU + {DCC41E99-EBC7-4F19-BA0D-A6F770D8E431}.Release|Any CPU.Build.0 = Release|Any CPU + {18B796D2-D45D-41AE-9A42-75C9B14B20DF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {18B796D2-D45D-41AE-9A42-75C9B14B20DF}.Debug|Any CPU.Build.0 = Debug|Any CPU + {18B796D2-D45D-41AE-9A42-75C9B14B20DF}.Release|Any CPU.ActiveCfg = Release|Any CPU + {18B796D2-D45D-41AE-9A42-75C9B14B20DF}.Release|Any CPU.Build.0 = Release|Any CPU + {5EED625D-8D86-492A-BCB8-F6C8CD8D4AA1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {5EED625D-8D86-492A-BCB8-F6C8CD8D4AA1}.Debug|Any CPU.Build.0 = Debug|Any CPU + {5EED625D-8D86-492A-BCB8-F6C8CD8D4AA1}.Release|Any CPU.ActiveCfg = Release|Any CPU + {5EED625D-8D86-492A-BCB8-F6C8CD8D4AA1}.Release|Any CPU.Build.0 = Release|Any CPU + {B02EF042-C39E-45C4-A92D-BF7554E1889D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {B02EF042-C39E-45C4-A92D-BF7554E1889D}.Debug|Any CPU.Build.0 = Debug|Any CPU + {B02EF042-C39E-45C4-A92D-BF7554E1889D}.Release|Any CPU.ActiveCfg = Release|Any CPU + {B02EF042-C39E-45C4-A92D-BF7554E1889D}.Release|Any CPU.Build.0 = Release|Any CPU + {CAE48068-233C-47A9-BEAB-DDF521730E7A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {CAE48068-233C-47A9-BEAB-DDF521730E7A}.Debug|Any CPU.Build.0 = Debug|Any CPU + {CAE48068-233C-47A9-BEAB-DDF521730E7A}.Release|Any CPU.ActiveCfg = Release|Any CPU + {CAE48068-233C-47A9-BEAB-DDF521730E7A}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -1425,6 +1461,12 @@ Global {3683340D-92F5-4B14-B77B-34A163333309} = {5DF0E140-0513-4D0D-BE2E-3D4D85CD70E6} {EDFFDA74-090D-439C-A58D-06CCF86D4423} = {5DF0E140-0513-4D0D-BE2E-3D4D85CD70E6} {C6D6D878-208A-4FD2-822E-365545D8681B} = {447C8A77-E5F0-4538-8687-7383196D04EA} + {192A829F-D608-4E41-8DE0-058E943E453F} = {5DF0E140-0513-4D0D-BE2E-3D4D85CD70E6} + {DCC41E99-EBC7-4F19-BA0D-A6F770D8E431} = {5DF0E140-0513-4D0D-BE2E-3D4D85CD70E6} + {18B796D2-D45D-41AE-9A42-75C9B14B20DF} = {5DF0E140-0513-4D0D-BE2E-3D4D85CD70E6} + {5EED625D-8D86-492A-BCB8-F6C8CD8D4AA1} = {5DF0E140-0513-4D0D-BE2E-3D4D85CD70E6} + {B02EF042-C39E-45C4-A92D-BF7554E1889D} = {5DF0E140-0513-4D0D-BE2E-3D4D85CD70E6} + {CAE48068-233C-47A9-BEAB-DDF521730E7A} = {5DF0E140-0513-4D0D-BE2E-3D4D85CD70E6} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {BB97ECF4-9A84-433F-A80B-2A3285BDD1D5} diff --git a/framework/src/Volo.Abp.AspNetCore.Components.Web.Theming/Components/LayoutHooks/LayoutHook.razor b/framework/src/Volo.Abp.AspNetCore.Components.Web.Theming/Components/LayoutHooks/LayoutHook.razor new file mode 100644 index 0000000000..f512232b86 --- /dev/null +++ b/framework/src/Volo.Abp.AspNetCore.Components.Web.Theming/Components/LayoutHooks/LayoutHook.razor @@ -0,0 +1,7 @@ +@if (LayoutHookViewModel.Hooks.Any()) +{ + foreach (var hook in LayoutHookViewModel.Hooks) + { + + } +} \ No newline at end of file diff --git a/framework/src/Volo.Abp.AspNetCore.Components.Web.Theming/Components/LayoutHooks/LayoutHook.razor.cs b/framework/src/Volo.Abp.AspNetCore.Components.Web.Theming/Components/LayoutHooks/LayoutHook.razor.cs new file mode 100644 index 0000000000..18fbcd89c2 --- /dev/null +++ b/framework/src/Volo.Abp.AspNetCore.Components.Web.Theming/Components/LayoutHooks/LayoutHook.razor.cs @@ -0,0 +1,39 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Components; +using Microsoft.Extensions.Options; +using Volo.Abp.Ui.LayoutHooks; + +namespace Volo.Abp.AspNetCore.Components.Web.Theming.Components.LayoutHooks; + +public partial class LayoutHook : ComponentBase +{ + [Parameter] + public string Name { get; set; } + + [Parameter] + public string Layout { get; set; } + + [Inject] + protected IOptions LayoutHookOptions { get; set; } + + protected LayoutHookViewModel LayoutHookViewModel { get; private set; } + + protected override Task OnInitializedAsync() + { + if (LayoutHookOptions.Value.Hooks.TryGetValue(Name, out var layoutHooks)) + { + layoutHooks = layoutHooks + .WhereIf(string.IsNullOrWhiteSpace(Layout), x => x.Layout == Layout) + .ToList(); + } + + layoutHooks ??= new List(); + + LayoutHookViewModel = new LayoutHookViewModel(layoutHooks.ToArray(), Layout); + + return Task.CompletedTask; + } +} \ No newline at end of file diff --git a/framework/src/Volo.Abp.AspNetCore.Components.Web.Theming/Layout/StandardLayouts.cs b/framework/src/Volo.Abp.AspNetCore.Components.Web.Theming/Layout/StandardLayouts.cs new file mode 100644 index 0000000000..ea73a5673f --- /dev/null +++ b/framework/src/Volo.Abp.AspNetCore.Components.Web.Theming/Layout/StandardLayouts.cs @@ -0,0 +1,6 @@ +namespace Volo.Abp.AspNetCore.Components.Web.Theming.Layout; + +public static class StandardLayouts +{ + public const string Application = "Application"; +} \ No newline at end of file diff --git a/framework/src/Volo.Abp.AspNetCore.Components.Web.Theming/PageToolbars/PageToolbarManager.cs b/framework/src/Volo.Abp.AspNetCore.Components.Web.Theming/PageToolbars/PageToolbarManager.cs index 05531096d4..00f7f5da23 100644 --- a/framework/src/Volo.Abp.AspNetCore.Components.Web.Theming/PageToolbars/PageToolbarManager.cs +++ b/framework/src/Volo.Abp.AspNetCore.Components.Web.Theming/PageToolbars/PageToolbarManager.cs @@ -3,16 +3,17 @@ using System; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; +using Microsoft.Extensions.DependencyInjection; using Volo.Abp.DependencyInjection; namespace Volo.Abp.AspNetCore.Components.Web.Theming.PageToolbars; public class PageToolbarManager : IPageToolbarManager, ITransientDependency { - protected IHybridServiceScopeFactory ServiceScopeFactory { get; } + protected IServiceScopeFactory ServiceScopeFactory { get; } public PageToolbarManager( - IHybridServiceScopeFactory serviceScopeFactory) + IServiceScopeFactory serviceScopeFactory) { ServiceScopeFactory = serviceScopeFactory; } diff --git a/framework/src/Volo.Abp.AspNetCore.MultiTenancy/Volo/Abp/AspNetCore/MultiTenancy/AbpAspNetCoreMultiTenancyModule.cs b/framework/src/Volo.Abp.AspNetCore.MultiTenancy/Volo/Abp/AspNetCore/MultiTenancy/AbpAspNetCoreMultiTenancyModule.cs index ad36cf0f11..e0d8ecd806 100644 --- a/framework/src/Volo.Abp.AspNetCore.MultiTenancy/Volo/Abp/AspNetCore/MultiTenancy/AbpAspNetCoreMultiTenancyModule.cs +++ b/framework/src/Volo.Abp.AspNetCore.MultiTenancy/Volo/Abp/AspNetCore/MultiTenancy/AbpAspNetCoreMultiTenancyModule.cs @@ -15,7 +15,6 @@ public class AbpAspNetCoreMultiTenancyModule : AbpModule Configure(options => { options.TenantResolvers.Add(new QueryStringTenantResolveContributor()); - options.TenantResolvers.Add(new FormTenantResolveContributor()); options.TenantResolvers.Add(new RouteTenantResolveContributor()); options.TenantResolvers.Add(new HeaderTenantResolveContributor()); options.TenantResolvers.Add(new CookieTenantResolveContributor()); diff --git a/framework/src/Volo.Abp.AspNetCore.MultiTenancy/Volo/Abp/AspNetCore/MultiTenancy/FormTenantResolveContributor.cs b/framework/src/Volo.Abp.AspNetCore.MultiTenancy/Volo/Abp/AspNetCore/MultiTenancy/FormTenantResolveContributor.cs index 67ef0a4c2c..d55343c94c 100644 --- a/framework/src/Volo.Abp.AspNetCore.MultiTenancy/Volo/Abp/AspNetCore/MultiTenancy/FormTenantResolveContributor.cs +++ b/framework/src/Volo.Abp.AspNetCore.MultiTenancy/Volo/Abp/AspNetCore/MultiTenancy/FormTenantResolveContributor.cs @@ -1,10 +1,11 @@ -using System.Linq; +using System; using System.Threading.Tasks; using Microsoft.AspNetCore.Http; using Volo.Abp.MultiTenancy; namespace Volo.Abp.AspNetCore.MultiTenancy; +[Obsolete("This may make some features of ASP NET Core unavailable, Will be removed in future versions.")] public class FormTenantResolveContributor : HttpTenantResolveContributorBase { public const string ContributorName = "Form"; diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.Dapr.EventBus/FodyWeavers.xml b/framework/src/Volo.Abp.AspNetCore.Mvc.Dapr.EventBus/FodyWeavers.xml new file mode 100644 index 0000000000..be0de3a908 --- /dev/null +++ b/framework/src/Volo.Abp.AspNetCore.Mvc.Dapr.EventBus/FodyWeavers.xml @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.Dapr.EventBus/FodyWeavers.xsd b/framework/src/Volo.Abp.AspNetCore.Mvc.Dapr.EventBus/FodyWeavers.xsd new file mode 100644 index 0000000000..3f3946e282 --- /dev/null +++ b/framework/src/Volo.Abp.AspNetCore.Mvc.Dapr.EventBus/FodyWeavers.xsd @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + 'true' to run assembly verification (PEVerify) on the target assembly after all weavers have been executed. + + + + + A comma-separated list of error codes that can be safely ignored in assembly verification. + + + + + 'false' to turn off automatic generation of the XML Schema file. + + + + + \ No newline at end of file diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.Dapr.EventBus/Volo.Abp.AspNetCore.Mvc.Dapr.EventBus.csproj b/framework/src/Volo.Abp.AspNetCore.Mvc.Dapr.EventBus/Volo.Abp.AspNetCore.Mvc.Dapr.EventBus.csproj new file mode 100644 index 0000000000..78b46cad27 --- /dev/null +++ b/framework/src/Volo.Abp.AspNetCore.Mvc.Dapr.EventBus/Volo.Abp.AspNetCore.Mvc.Dapr.EventBus.csproj @@ -0,0 +1,18 @@ + + + + + + + net6.0 + enable + enable + + + + + + + + + diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.Dapr.EventBus/Volo/Abp/AspNetCore/Mvc/Dapr/EventBus/AbpAspNetCoreMvcDaprEventBusModule.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.Dapr.EventBus/Volo/Abp/AspNetCore/Mvc/Dapr/EventBus/AbpAspNetCoreMvcDaprEventBusModule.cs new file mode 100644 index 0000000000..333a5aae9a --- /dev/null +++ b/framework/src/Volo.Abp.AspNetCore.Mvc.Dapr.EventBus/Volo/Abp/AspNetCore/Mvc/Dapr/EventBus/AbpAspNetCoreMvcDaprEventBusModule.cs @@ -0,0 +1,29 @@ +using Microsoft.AspNetCore.Http.Json; +using Volo.Abp.AspNetCore.Mvc.Dapr.EventBus.SystemTextJson; +using Volo.Abp.EventBus.Dapr; +using Volo.Abp.Json.SystemTextJson; +using Volo.Abp.Modularity; + +namespace Volo.Abp.AspNetCore.Mvc.Dapr.EventBus; + +[DependsOn( + typeof(AbpAspNetCoreMvcDaprModule), + typeof(AbpEventBusDaprModule) +)] +public class AbpAspNetCoreMvcDaprEventBusModule : AbpModule +{ + public override void ConfigureServices(ServiceConfigurationContext context) + { + // TODO: Add NewtonsoftJson json converter. + + Configure(options => + { + options.SerializerOptions.Converters.Add(new AbpAspNetCoreMvcDaprSubscriptionDefinitionConverter()); + }); + + Configure(options => + { + options.JsonSerializerOptions.Converters.Add(new AbpAspNetCoreMvcDaprSubscriptionDefinitionConverter()); + }); + } +} diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.Dapr.EventBus/Volo/Abp/AspNetCore/Mvc/Dapr/EventBus/AbpAspNetCoreMvcDaprEventBusOptions.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.Dapr.EventBus/Volo/Abp/AspNetCore/Mvc/Dapr/EventBus/AbpAspNetCoreMvcDaprEventBusOptions.cs new file mode 100644 index 0000000000..02ca4c8e22 --- /dev/null +++ b/framework/src/Volo.Abp.AspNetCore.Mvc.Dapr.EventBus/Volo/Abp/AspNetCore/Mvc/Dapr/EventBus/AbpAspNetCoreMvcDaprEventBusOptions.cs @@ -0,0 +1,11 @@ +namespace Volo.Abp.AspNetCore.Mvc.Dapr.EventBus; + +public class AbpAspNetCoreMvcDaprEventBusOptions +{ + public List Contributors { get; } + + public AbpAspNetCoreMvcDaprEventBusOptions() + { + Contributors = new List(); + } +} diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.Dapr.EventBus/Volo/Abp/AspNetCore/Mvc/Dapr/EventBus/AbpAspNetCoreMvcDaprPubSubConsts.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.Dapr.EventBus/Volo/Abp/AspNetCore/Mvc/Dapr/EventBus/AbpAspNetCoreMvcDaprPubSubConsts.cs new file mode 100644 index 0000000000..e785f2e737 --- /dev/null +++ b/framework/src/Volo.Abp.AspNetCore.Mvc.Dapr.EventBus/Volo/Abp/AspNetCore/Mvc/Dapr/EventBus/AbpAspNetCoreMvcDaprPubSubConsts.cs @@ -0,0 +1,8 @@ +namespace Volo.Abp.AspNetCore.Mvc.Dapr.EventBus; + +public class AbpAspNetCoreMvcDaprPubSubConsts +{ + public const string DaprSubscribeUrl = "dapr/subscribe"; + + public const string DaprEventCallbackUrl = "api/abp/dapr/event"; +} diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.Dapr.EventBus/Volo/Abp/AspNetCore/Mvc/Dapr/EventBus/AbpAspNetCoreMvcDaprPubSubProvider.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.Dapr.EventBus/Volo/Abp/AspNetCore/Mvc/Dapr/EventBus/AbpAspNetCoreMvcDaprPubSubProvider.cs new file mode 100644 index 0000000000..e797bd2fc0 --- /dev/null +++ b/framework/src/Volo.Abp.AspNetCore.Mvc.Dapr.EventBus/Volo/Abp/AspNetCore/Mvc/Dapr/EventBus/AbpAspNetCoreMvcDaprPubSubProvider.cs @@ -0,0 +1,63 @@ +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Options; +using Volo.Abp.AspNetCore.Mvc.Dapr.EventBus.Models; +using Volo.Abp.DependencyInjection; +using Volo.Abp.EventBus; +using Volo.Abp.EventBus.Dapr; +using Volo.Abp.EventBus.Distributed; + +namespace Volo.Abp.AspNetCore.Mvc.Dapr.EventBus; + +public class AbpAspNetCoreMvcDaprPubSubProvider : ITransientDependency +{ + protected IServiceProvider ServiceProvider { get; } + protected AbpAspNetCoreMvcDaprEventBusOptions AspNetCoreMvcDaprEventBusOptions { get; } + protected AbpDaprEventBusOptions DaprEventBusOptions { get; } + protected AbpDistributedEventBusOptions DistributedEventBusOptions { get; } + + public AbpAspNetCoreMvcDaprPubSubProvider( + IServiceProvider serviceProvider, + IOptions aspNetCoreDaprEventBusOptions, + IOptions daprEventBusOptions, + IOptions distributedEventBusOptions) + { + ServiceProvider = serviceProvider; + AspNetCoreMvcDaprEventBusOptions = aspNetCoreDaprEventBusOptions.Value; + DaprEventBusOptions = daprEventBusOptions.Value; + DistributedEventBusOptions = distributedEventBusOptions.Value; + } + + public virtual async Task> GetSubscriptionsAsync() + { + var subscriptions = new List(); + foreach (var handler in DistributedEventBusOptions.Handlers) + { + foreach (var @interface in handler.GetInterfaces().Where(x => x.IsGenericType && x.GetGenericTypeDefinition() == typeof(IDistributedEventHandler<>))) + { + var eventType = @interface.GetGenericArguments()[0]; + var eventName = EventNameAttribute.GetNameOrDefault(eventType); + + subscriptions.Add(new AbpAspNetCoreMvcDaprSubscriptionDefinition() + { + PubSubName = DaprEventBusOptions.PubSubName, + Topic = eventName, + Route = AbpAspNetCoreMvcDaprPubSubConsts.DaprEventCallbackUrl + }); + } + } + + if (AspNetCoreMvcDaprEventBusOptions.Contributors.Any()) + { + using (var scope = ServiceProvider.CreateScope()) + { + var context = new AbpAspNetCoreMvcDaprPubSubProviderContributorContext(scope.ServiceProvider, subscriptions); + foreach (var contributor in AspNetCoreMvcDaprEventBusOptions.Contributors) + { + await contributor.ContributeAsync(context); + } + } + } + + return subscriptions; + } +} diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.Dapr.EventBus/Volo/Abp/AspNetCore/Mvc/Dapr/EventBus/AbpAspNetCoreMvcDaprPubSubProviderContributorContext.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.Dapr.EventBus/Volo/Abp/AspNetCore/Mvc/Dapr/EventBus/AbpAspNetCoreMvcDaprPubSubProviderContributorContext.cs new file mode 100644 index 0000000000..564b541dec --- /dev/null +++ b/framework/src/Volo.Abp.AspNetCore.Mvc.Dapr.EventBus/Volo/Abp/AspNetCore/Mvc/Dapr/EventBus/AbpAspNetCoreMvcDaprPubSubProviderContributorContext.cs @@ -0,0 +1,16 @@ +using Volo.Abp.AspNetCore.Mvc.Dapr.EventBus.Models; + +namespace Volo.Abp.AspNetCore.Mvc.Dapr.EventBus; + +public class AbpAspNetCoreMvcDaprPubSubProviderContributorContext +{ + public IServiceProvider ServiceProvider { get; } + + public List Subscriptions { get; } + + public AbpAspNetCoreMvcDaprPubSubProviderContributorContext(IServiceProvider serviceProvider, List daprSubscriptionModels) + { + ServiceProvider = serviceProvider; + Subscriptions = daprSubscriptionModels; + } +} diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.Dapr.EventBus/Volo/Abp/AspNetCore/Mvc/Dapr/EventBus/Controllers/AbpAspNetCoreMvcDaprPubSubController.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.Dapr.EventBus/Volo/Abp/AspNetCore/Mvc/Dapr/EventBus/Controllers/AbpAspNetCoreMvcDaprPubSubController.cs new file mode 100644 index 0000000000..c97e793b53 --- /dev/null +++ b/framework/src/Volo.Abp.AspNetCore.Mvc.Dapr.EventBus/Volo/Abp/AspNetCore/Mvc/Dapr/EventBus/Controllers/AbpAspNetCoreMvcDaprPubSubController.cs @@ -0,0 +1,36 @@ +using System.Text.Json; +using Microsoft.AspNetCore.Mvc; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Options; +using Volo.Abp.AspNetCore.Mvc.Dapr.EventBus.Models; +using Volo.Abp.Dapr; +using Volo.Abp.EventBus.Dapr; + +namespace Volo.Abp.AspNetCore.Mvc.Dapr.EventBus.Controllers; + +[Area("abp")] +[RemoteService(Name = "abp")] +public class AbpAspNetCoreMvcDaprPubSubController : AbpController +{ + [HttpGet(AbpAspNetCoreMvcDaprPubSubConsts.DaprSubscribeUrl)] + public virtual async Task> SubscribeAsync() + { + return await HttpContext.RequestServices.GetRequiredService().GetSubscriptionsAsync(); + } + + [HttpPost(AbpAspNetCoreMvcDaprPubSubConsts.DaprEventCallbackUrl)] + public virtual async Task EventsAsync() + { + var bodyJsonDocument = await JsonDocument.ParseAsync(HttpContext.Request.Body); + var request = JsonSerializer.Deserialize(bodyJsonDocument.RootElement.GetRawText(), + HttpContext.RequestServices.GetRequiredService>().Value.JsonSerializerOptions); + + var distributedEventBus = HttpContext.RequestServices.GetRequiredService(); + var daprSerializer = HttpContext.RequestServices.GetRequiredService(); + + var eventData = daprSerializer.Deserialize(bodyJsonDocument.RootElement.GetProperty("data").GetRawText(), distributedEventBus.GetEventType(request.Topic)); + await distributedEventBus.TriggerHandlersAsync(distributedEventBus.GetEventType(request.Topic), eventData); + + return Ok(); + } +} diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.Dapr.EventBus/Volo/Abp/AspNetCore/Mvc/Dapr/EventBus/IAbpAspNetCoreMvcDaprPubSubProviderContributor.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.Dapr.EventBus/Volo/Abp/AspNetCore/Mvc/Dapr/EventBus/IAbpAspNetCoreMvcDaprPubSubProviderContributor.cs new file mode 100644 index 0000000000..87047cd7ec --- /dev/null +++ b/framework/src/Volo.Abp.AspNetCore.Mvc.Dapr.EventBus/Volo/Abp/AspNetCore/Mvc/Dapr/EventBus/IAbpAspNetCoreMvcDaprPubSubProviderContributor.cs @@ -0,0 +1,6 @@ +namespace Volo.Abp.AspNetCore.Mvc.Dapr.EventBus; + +public interface IAbpAspNetCoreMvcDaprPubSubProviderContributor +{ + Task ContributeAsync(AbpAspNetCoreMvcDaprPubSubProviderContributorContext context); +} diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.Dapr.EventBus/Volo/Abp/AspNetCore/Mvc/Dapr/EventBus/Models/AbpAspNetCoreMvcDaprSubscriptionDefinition.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.Dapr.EventBus/Volo/Abp/AspNetCore/Mvc/Dapr/EventBus/Models/AbpAspNetCoreMvcDaprSubscriptionDefinition.cs new file mode 100644 index 0000000000..287e78e01a --- /dev/null +++ b/framework/src/Volo.Abp.AspNetCore.Mvc.Dapr.EventBus/Volo/Abp/AspNetCore/Mvc/Dapr/EventBus/Models/AbpAspNetCoreMvcDaprSubscriptionDefinition.cs @@ -0,0 +1,10 @@ +namespace Volo.Abp.AspNetCore.Mvc.Dapr.EventBus.Models; + +public class AbpAspNetCoreMvcDaprSubscriptionDefinition +{ + public string PubSubName { get; set; } + + public string Topic { get; set; } + + public string Route { get; set; } +} diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.Dapr.EventBus/Volo/Abp/AspNetCore/Mvc/Dapr/EventBus/Models/AbpAspNetCoreMvcDaprSubscriptionRequest.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.Dapr.EventBus/Volo/Abp/AspNetCore/Mvc/Dapr/EventBus/Models/AbpAspNetCoreMvcDaprSubscriptionRequest.cs new file mode 100644 index 0000000000..46c04b5a44 --- /dev/null +++ b/framework/src/Volo.Abp.AspNetCore.Mvc.Dapr.EventBus/Volo/Abp/AspNetCore/Mvc/Dapr/EventBus/Models/AbpAspNetCoreMvcDaprSubscriptionRequest.cs @@ -0,0 +1,8 @@ +namespace Volo.Abp.AspNetCore.Mvc.Dapr.EventBus.Models; + +public class AbpAspNetCoreMvcDaprSubscriptionRequest +{ + public string PubSubName { get; set; } + + public string Topic { get; set; } +} diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.Dapr.EventBus/Volo/Abp/AspNetCore/Mvc/Dapr/EventBus/SystemTextJson/AbpAspNetCoreMvcDaprPubSubJsonNamingPolicy.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.Dapr.EventBus/Volo/Abp/AspNetCore/Mvc/Dapr/EventBus/SystemTextJson/AbpAspNetCoreMvcDaprPubSubJsonNamingPolicy.cs new file mode 100644 index 0000000000..0aa6bd4f7c --- /dev/null +++ b/framework/src/Volo.Abp.AspNetCore.Mvc.Dapr.EventBus/Volo/Abp/AspNetCore/Mvc/Dapr/EventBus/SystemTextJson/AbpAspNetCoreMvcDaprPubSubJsonNamingPolicy.cs @@ -0,0 +1,11 @@ +using System.Text.Json; + +namespace Volo.Abp.AspNetCore.Mvc.Dapr.EventBus.SystemTextJson; + +public class AbpAspNetCoreMvcDaprPubSubJsonNamingPolicy : JsonNamingPolicy +{ + public override string ConvertName(string name) + { + return name.ToLower(); + } +} diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.Dapr.EventBus/Volo/Abp/AspNetCore/Mvc/Dapr/EventBus/SystemTextJson/AbpAspNetCoreMvcDaprSubscriptionDefinitionConverter.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.Dapr.EventBus/Volo/Abp/AspNetCore/Mvc/Dapr/EventBus/SystemTextJson/AbpAspNetCoreMvcDaprSubscriptionDefinitionConverter.cs new file mode 100644 index 0000000000..fa26d35ca6 --- /dev/null +++ b/framework/src/Volo.Abp.AspNetCore.Mvc.Dapr.EventBus/Volo/Abp/AspNetCore/Mvc/Dapr/EventBus/SystemTextJson/AbpAspNetCoreMvcDaprSubscriptionDefinitionConverter.cs @@ -0,0 +1,25 @@ +using System.Text.Json; +using System.Text.Json.Serialization; +using Volo.Abp.AspNetCore.Mvc.Dapr.EventBus.Models; + +namespace Volo.Abp.AspNetCore.Mvc.Dapr.EventBus.SystemTextJson; + +public class AbpAspNetCoreMvcDaprSubscriptionDefinitionConverter : JsonConverter +{ + private JsonSerializerOptions _writeJsonSerializerOptions; + + public override AbpAspNetCoreMvcDaprSubscriptionDefinition Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + { + throw new NotSupportedException(); + } + + public override void Write(Utf8JsonWriter writer, AbpAspNetCoreMvcDaprSubscriptionDefinition value, JsonSerializerOptions options) + { + _writeJsonSerializerOptions ??= JsonSerializerOptionsHelper.Create(new JsonSerializerOptions(options) + { + PropertyNamingPolicy = new AbpAspNetCoreMvcDaprPubSubJsonNamingPolicy() + }, x => x == this); + + JsonSerializer.Serialize(writer, value, _writeJsonSerializerOptions); + } +} diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.Dapr/FodyWeavers.xml b/framework/src/Volo.Abp.AspNetCore.Mvc.Dapr/FodyWeavers.xml new file mode 100644 index 0000000000..be0de3a908 --- /dev/null +++ b/framework/src/Volo.Abp.AspNetCore.Mvc.Dapr/FodyWeavers.xml @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.Dapr/FodyWeavers.xsd b/framework/src/Volo.Abp.AspNetCore.Mvc.Dapr/FodyWeavers.xsd new file mode 100644 index 0000000000..3f3946e282 --- /dev/null +++ b/framework/src/Volo.Abp.AspNetCore.Mvc.Dapr/FodyWeavers.xsd @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + 'true' to run assembly verification (PEVerify) on the target assembly after all weavers have been executed. + + + + + A comma-separated list of error codes that can be safely ignored in assembly verification. + + + + + 'false' to turn off automatic generation of the XML Schema file. + + + + + \ No newline at end of file diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.Dapr/Volo.Abp.AspNetCore.Mvc.Dapr.csproj b/framework/src/Volo.Abp.AspNetCore.Mvc.Dapr/Volo.Abp.AspNetCore.Mvc.Dapr.csproj new file mode 100644 index 0000000000..d792a30b24 --- /dev/null +++ b/framework/src/Volo.Abp.AspNetCore.Mvc.Dapr/Volo.Abp.AspNetCore.Mvc.Dapr.csproj @@ -0,0 +1,22 @@ + + + + + + + net6.0 + enable + enable + + + + + + + + + + + + + diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.Dapr/Volo/Abp/AspNetCore/Mvc/Dapr/AbpAspNetCoreMvcDaprModule.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.Dapr/Volo/Abp/AspNetCore/Mvc/Dapr/AbpAspNetCoreMvcDaprModule.cs new file mode 100644 index 0000000000..f8ba3fcfc2 --- /dev/null +++ b/framework/src/Volo.Abp.AspNetCore.Mvc.Dapr/Volo/Abp/AspNetCore/Mvc/Dapr/AbpAspNetCoreMvcDaprModule.cs @@ -0,0 +1,13 @@ +using Volo.Abp.Dapr; +using Volo.Abp.Modularity; + +namespace Volo.Abp.AspNetCore.Mvc.Dapr; + +[DependsOn( + typeof(AbpAspNetCoreMvcModule), + typeof(AbpDaprModule) +)] +public class AbpAspNetCoreMvcDaprModule : AbpModule +{ + +} diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Modal/AbpModalSize.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Modal/AbpModalSize.cs index f022dacce5..452a616365 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Modal/AbpModalSize.cs +++ b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Modal/AbpModalSize.cs @@ -5,5 +5,11 @@ public enum AbpModalSize Default, Small, Large, - ExtraLarge + ExtraLarge, + Fullscreen, + FullscreenSmDown, + FullscreenMdDown, + FullscreenLgDown, + FullscreenXlDown, + FullscreenXxlDown } diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Modal/AbpModalSizeExtensions.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Modal/AbpModalSizeExtensions.cs index 7b0de7a595..9477783557 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Modal/AbpModalSizeExtensions.cs +++ b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Modal/AbpModalSizeExtensions.cs @@ -14,6 +14,18 @@ public static class AbpModalSizeExtensions return "modal-xl"; case AbpModalSize.Default: return ""; + case AbpModalSize.Fullscreen: + return "modal-fullscreen"; + case AbpModalSize.FullscreenSmDown: + return "modal-fullscreen-sm-down"; + case AbpModalSize.FullscreenMdDown: + return "modal-fullscreen-md-down"; + case AbpModalSize.FullscreenLgDown: + return "modal-fullscreen-lg-down"; + case AbpModalSize.FullscreenXlDown: + return "modal-fullscreen-xl-down"; + case AbpModalSize.FullscreenXxlDown: + return "modal-fullscreen-xxl-down"; default: throw new AbpException($"Unknown {nameof(AbpModalSize)}: {size}"); } diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared/PageToolbars/PageToolbarManager.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared/PageToolbars/PageToolbarManager.cs index b795c62c39..ec27b8087c 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared/PageToolbars/PageToolbarManager.cs +++ b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared/PageToolbars/PageToolbarManager.cs @@ -2,6 +2,7 @@ using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; +using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Options; using Volo.Abp.DependencyInjection; @@ -10,11 +11,11 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared.PageToolbars; public class PageToolbarManager : IPageToolbarManager, ITransientDependency { protected AbpPageToolbarOptions Options { get; } - protected IHybridServiceScopeFactory ServiceScopeFactory { get; } + protected IServiceScopeFactory ServiceScopeFactory { get; } public PageToolbarManager( IOptions options, - IHybridServiceScopeFactory serviceScopeFactory) + IServiceScopeFactory serviceScopeFactory) { Options = options.Value; ServiceScopeFactory = serviceScopeFactory; diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI/Volo/Abp/AspNetCore/Mvc/UI/Components/LayoutHook/Default.cshtml b/framework/src/Volo.Abp.AspNetCore.Mvc.UI/Volo/Abp/AspNetCore/Mvc/UI/Components/LayoutHook/Default.cshtml index 61e9afbf6e..34536ec373 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc.UI/Volo/Abp/AspNetCore/Mvc/UI/Components/LayoutHook/Default.cshtml +++ b/framework/src/Volo.Abp.AspNetCore.Mvc.UI/Volo/Abp/AspNetCore/Mvc/UI/Components/LayoutHook/Default.cshtml @@ -1,5 +1,4 @@ -@using Volo.Abp.AspNetCore.Mvc.UI.Components.LayoutHook -@model LayoutHookViewModel +@model Volo.Abp.Ui.LayoutHooks.LayoutHookViewModel @if (Model.Hooks.Any()) { foreach (var hook in Model.Hooks) diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI/Volo/Abp/AspNetCore/Mvc/UI/Components/LayoutHook/LayoutHookViewComponent.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.UI/Volo/Abp/AspNetCore/Mvc/UI/Components/LayoutHook/LayoutHookViewComponent.cs index 45eaa2b6a3..5bd18e4c31 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc.UI/Volo/Abp/AspNetCore/Mvc/UI/Components/LayoutHook/LayoutHookViewComponent.cs +++ b/framework/src/Volo.Abp.AspNetCore.Mvc.UI/Volo/Abp/AspNetCore/Mvc/UI/Components/LayoutHook/LayoutHookViewComponent.cs @@ -2,6 +2,7 @@ using System.Collections.Generic; using Microsoft.AspNetCore.Mvc; using Microsoft.Extensions.Options; +using Volo.Abp.Ui.LayoutHooks; namespace Volo.Abp.AspNetCore.Mvc.UI.Components.LayoutHook; diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/AbpApplicationConfigurationAppService.cs b/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/AbpApplicationConfigurationAppService.cs index 528a04583d..7bcc0b3cd9 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/AbpApplicationConfigurationAppService.cs +++ b/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/AbpApplicationConfigurationAppService.cs @@ -171,7 +171,8 @@ public class AbpApplicationConfigurationAppService : ApplicationService, IAbpApp foreach (var policyName in policyNames) { - if (await _defaultAuthorizationPolicyProvider.GetPolicyAsync(policyName) == null && _permissionDefinitionManager.GetOrNull(policyName) != null) + if (await _defaultAuthorizationPolicyProvider.GetPolicyAsync(policyName) == null && + await _permissionDefinitionManager.GetOrNullAsync(policyName) != null) { abpPolicyNames.Add(policyName); } @@ -214,9 +215,9 @@ public class AbpApplicationConfigurationAppService : ApplicationService, IAbpApp { var dictionary = new Dictionary(); - var localizer = _serviceProvider.GetRequiredService( + var localizer = (IStringLocalizer) _serviceProvider.GetRequiredService( typeof(IStringLocalizer<>).MakeGenericType(resource.ResourceType) - ) as IStringLocalizer; + ); foreach (var localizedString in localizer.GetAllStrings()) { diff --git a/framework/src/Volo.Abp.AspNetCore/Microsoft/AspNetCore/Hosting/AbpHostingEnvironmentExtensions.cs b/framework/src/Volo.Abp.AspNetCore/Microsoft/AspNetCore/Hosting/AbpHostingEnvironmentExtensions.cs index a6569d001b..15c1d74ccb 100644 --- a/framework/src/Volo.Abp.AspNetCore/Microsoft/AspNetCore/Hosting/AbpHostingEnvironmentExtensions.cs +++ b/framework/src/Volo.Abp.AspNetCore/Microsoft/AspNetCore/Hosting/AbpHostingEnvironmentExtensions.cs @@ -9,7 +9,7 @@ public static class AbpHostingEnvironmentExtensions this IWebHostEnvironment env, AbpConfigurationBuilderOptions options = null) { - options = options ?? new AbpConfigurationBuilderOptions(); + options ??= new AbpConfigurationBuilderOptions(); if (options.BasePath.IsNullOrEmpty()) { diff --git a/framework/src/Volo.Abp.AspNetCore/Volo/Abp/AspNetCore/DependencyInjection/HttpContextServiceScopeFactory.cs b/framework/src/Volo.Abp.AspNetCore/Volo/Abp/AspNetCore/DependencyInjection/HttpContextServiceScopeFactory.cs deleted file mode 100644 index a7f00f7451..0000000000 --- a/framework/src/Volo.Abp.AspNetCore/Volo/Abp/AspNetCore/DependencyInjection/HttpContextServiceScopeFactory.cs +++ /dev/null @@ -1,52 +0,0 @@ -using System; -using Microsoft.AspNetCore.Http; -using Microsoft.Extensions.DependencyInjection; -using Volo.Abp.DependencyInjection; - -namespace Volo.Abp.AspNetCore.DependencyInjection; - -[ExposeServices( - typeof(IHybridServiceScopeFactory), - typeof(HttpContextServiceScopeFactory) - )] -[Dependency(ReplaceServices = true)] -public class HttpContextServiceScopeFactory : IHybridServiceScopeFactory, ITransientDependency -{ - protected IHttpContextAccessor HttpContextAccessor { get; } - - protected IServiceScopeFactory ServiceScopeFactory { get; } - - public HttpContextServiceScopeFactory( - IHttpContextAccessor httpContextAccessor, - IServiceScopeFactory serviceScopeFactory) - { - HttpContextAccessor = httpContextAccessor; - ServiceScopeFactory = serviceScopeFactory; - } - - public virtual IServiceScope CreateScope() - { - var httpContext = HttpContextAccessor.HttpContext; - if (httpContext == null) - { - return ServiceScopeFactory.CreateScope(); - } - - return new NonDisposedHttpContextServiceScope(httpContext.RequestServices); - } - - protected class NonDisposedHttpContextServiceScope : IServiceScope - { - public IServiceProvider ServiceProvider { get; } - - public NonDisposedHttpContextServiceScope(IServiceProvider serviceProvider) - { - ServiceProvider = serviceProvider; - } - - public void Dispose() - { - - } - } -} diff --git a/framework/src/Volo.Abp.Auditing.Contracts/Volo/Abp/Auditing/IDeletionAuditedObject.cs b/framework/src/Volo.Abp.Auditing.Contracts/Volo/Abp/Auditing/IDeletionAuditedObject.cs index be59ea0431..a7be0c29a1 100644 --- a/framework/src/Volo.Abp.Auditing.Contracts/Volo/Abp/Auditing/IDeletionAuditedObject.cs +++ b/framework/src/Volo.Abp.Auditing.Contracts/Volo/Abp/Auditing/IDeletionAuditedObject.cs @@ -10,7 +10,7 @@ public interface IDeletionAuditedObject : IHasDeletionTime /// /// Id of the deleter user. /// - Guid? DeleterId { get; set; } + Guid? DeleterId { get; } } /// @@ -22,5 +22,5 @@ public interface IDeletionAuditedObject : IDeletionAuditedObject /// /// Reference to the deleter user. /// - TUser Deleter { get; set; } + TUser Deleter { get; } } diff --git a/framework/src/Volo.Abp.Auditing.Contracts/Volo/Abp/Auditing/IHasDeletionTime.cs b/framework/src/Volo.Abp.Auditing.Contracts/Volo/Abp/Auditing/IHasDeletionTime.cs index a84fc78c41..ef45b1b057 100644 --- a/framework/src/Volo.Abp.Auditing.Contracts/Volo/Abp/Auditing/IHasDeletionTime.cs +++ b/framework/src/Volo.Abp.Auditing.Contracts/Volo/Abp/Auditing/IHasDeletionTime.cs @@ -11,5 +11,5 @@ public interface IHasDeletionTime : ISoftDelete /// /// Deletion time. /// - DateTime? DeletionTime { get; set; } + DateTime? DeletionTime { get; } } diff --git a/framework/src/Volo.Abp.Auditing.Contracts/Volo/Abp/Auditing/IHasModificationTime.cs b/framework/src/Volo.Abp.Auditing.Contracts/Volo/Abp/Auditing/IHasModificationTime.cs index b7b7494081..001d07d617 100644 --- a/framework/src/Volo.Abp.Auditing.Contracts/Volo/Abp/Auditing/IHasModificationTime.cs +++ b/framework/src/Volo.Abp.Auditing.Contracts/Volo/Abp/Auditing/IHasModificationTime.cs @@ -10,5 +10,5 @@ public interface IHasModificationTime /// /// The last modified time for this entity. /// - DateTime? LastModificationTime { get; set; } + DateTime? LastModificationTime { get; } } diff --git a/framework/src/Volo.Abp.Auditing.Contracts/Volo/Abp/Auditing/IModificationAuditedObject.cs b/framework/src/Volo.Abp.Auditing.Contracts/Volo/Abp/Auditing/IModificationAuditedObject.cs index 5ba4fd1e02..48f26b6299 100644 --- a/framework/src/Volo.Abp.Auditing.Contracts/Volo/Abp/Auditing/IModificationAuditedObject.cs +++ b/framework/src/Volo.Abp.Auditing.Contracts/Volo/Abp/Auditing/IModificationAuditedObject.cs @@ -10,7 +10,7 @@ public interface IModificationAuditedObject : IHasModificationTime /// /// Last modifier user for this entity. /// - Guid? LastModifierId { get; set; } + Guid? LastModifierId { get; } } /// @@ -22,5 +22,5 @@ public interface IModificationAuditedObject : IModificationAuditedObject /// /// Reference to the last modifier user of this entity. /// - TUser LastModifier { get; set; } + TUser LastModifier { get; } } diff --git a/framework/src/Volo.Abp.Auditing/Volo/Abp/Auditing/AbpAuditingModule.cs b/framework/src/Volo.Abp.Auditing/Volo/Abp/Auditing/AbpAuditingModule.cs index bb3f104ce4..b6527f10c8 100644 --- a/framework/src/Volo.Abp.Auditing/Volo/Abp/Auditing/AbpAuditingModule.cs +++ b/framework/src/Volo.Abp.Auditing/Volo/Abp/Auditing/AbpAuditingModule.cs @@ -1,4 +1,6 @@ -using Microsoft.Extensions.DependencyInjection; +using System; +using System.Threading.Tasks; +using Microsoft.Extensions.DependencyInjection; using Volo.Abp.Data; using Volo.Abp.Json; using Volo.Abp.Modularity; @@ -24,4 +26,17 @@ public class AbpAuditingModule : AbpModule { context.Services.OnRegistred(AuditingInterceptorRegistrar.RegisterIfNeeded); } + + public override void ConfigureServices(ServiceConfigurationContext context) + { + var applicationName = context.Services.GetApplicationName(); + + if (!applicationName.IsNullOrEmpty()) + { + Configure(options => + { + options.ApplicationName = applicationName; + }); + } + } } diff --git a/framework/src/Volo.Abp.Auditing/Volo/Abp/Auditing/AuditPropertySetter.cs b/framework/src/Volo.Abp.Auditing/Volo/Abp/Auditing/AuditPropertySetter.cs index d85bad82eb..16632420d7 100644 --- a/framework/src/Volo.Abp.Auditing/Volo/Abp/Auditing/AuditPropertySetter.cs +++ b/framework/src/Volo.Abp.Auditing/Volo/Abp/Auditing/AuditPropertySetter.cs @@ -99,7 +99,7 @@ public class AuditPropertySetter : IAuditPropertySetter, ITransientDependency { if (targetObject is IHasModificationTime objectWithModificationTime) { - objectWithModificationTime.LastModificationTime = Clock.Now; + ObjectHelper.TrySetProperty(objectWithModificationTime, x => x.LastModificationTime, () => Clock.Now); } } @@ -112,7 +112,7 @@ public class AuditPropertySetter : IAuditPropertySetter, ITransientDependency if (!CurrentUser.Id.HasValue) { - modificationAuditedObject.LastModifierId = null; + ObjectHelper.TrySetProperty(modificationAuditedObject, x => x.LastModifierId, () => null); return; } @@ -120,7 +120,7 @@ public class AuditPropertySetter : IAuditPropertySetter, ITransientDependency { if (multiTenantEntity.TenantId != CurrentUser.TenantId) { - modificationAuditedObject.LastModifierId = null; + ObjectHelper.TrySetProperty(modificationAuditedObject, x => x.LastModifierId, () => null); return; } } @@ -134,7 +134,7 @@ public class AuditPropertySetter : IAuditPropertySetter, ITransientDependency } */ - modificationAuditedObject.LastModifierId = CurrentUser.Id; + ObjectHelper.TrySetProperty(modificationAuditedObject, x => x.LastModifierId, () => CurrentUser.Id); } protected virtual void SetDeletionTime(object targetObject) @@ -143,7 +143,7 @@ public class AuditPropertySetter : IAuditPropertySetter, ITransientDependency { if (objectWithDeletionTime.DeletionTime == null) { - objectWithDeletionTime.DeletionTime = Clock.Now; + ObjectHelper.TrySetProperty(objectWithDeletionTime, x => x.DeletionTime, () => Clock.Now); } } } @@ -162,7 +162,7 @@ public class AuditPropertySetter : IAuditPropertySetter, ITransientDependency if (!CurrentUser.Id.HasValue) { - deletionAuditedObject.DeleterId = null; + ObjectHelper.TrySetProperty(deletionAuditedObject, x => x.DeleterId, () => null); return; } @@ -170,11 +170,11 @@ public class AuditPropertySetter : IAuditPropertySetter, ITransientDependency { if (multiTenantEntity.TenantId != CurrentUser.TenantId) { - deletionAuditedObject.DeleterId = null; + ObjectHelper.TrySetProperty(deletionAuditedObject, x => x.DeleterId, () => null); return; } } - deletionAuditedObject.DeleterId = CurrentUser.Id; + ObjectHelper.TrySetProperty(deletionAuditedObject, x => x.DeleterId, () => CurrentUser.Id); } } diff --git a/framework/src/Volo.Abp.Authorization.Abstractions/Volo/Abp/Authorization/Permissions/ICanAddChildPermission.cs b/framework/src/Volo.Abp.Authorization.Abstractions/Volo/Abp/Authorization/Permissions/ICanAddChildPermission.cs new file mode 100644 index 0000000000..57a224699f --- /dev/null +++ b/framework/src/Volo.Abp.Authorization.Abstractions/Volo/Abp/Authorization/Permissions/ICanAddChildPermission.cs @@ -0,0 +1,14 @@ +using JetBrains.Annotations; +using Volo.Abp.Localization; +using Volo.Abp.MultiTenancy; + +namespace Volo.Abp.Authorization.Permissions; + +public interface ICanAddChildPermission +{ + PermissionDefinition AddPermission( + [NotNull] string name, + ILocalizableString displayName = null, + MultiTenancySides multiTenancySide = MultiTenancySides.Both, + bool isEnabled = true); +} \ No newline at end of file diff --git a/framework/src/Volo.Abp.Authorization.Abstractions/Volo/Abp/Authorization/Permissions/IPermissionDefinitionContext.cs b/framework/src/Volo.Abp.Authorization.Abstractions/Volo/Abp/Authorization/Permissions/IPermissionDefinitionContext.cs index 6d1f9a31fd..411b030b6a 100644 --- a/framework/src/Volo.Abp.Authorization.Abstractions/Volo/Abp/Authorization/Permissions/IPermissionDefinitionContext.cs +++ b/framework/src/Volo.Abp.Authorization.Abstractions/Volo/Abp/Authorization/Permissions/IPermissionDefinitionContext.cs @@ -37,8 +37,7 @@ public interface IPermissionDefinitionContext /// PermissionGroupDefinition AddGroup( [NotNull] string name, - ILocalizableString displayName = null, - MultiTenancySides multiTenancySide = MultiTenancySides.Both); + ILocalizableString displayName = null); /// /// Tries to remove a permission group. diff --git a/framework/src/Volo.Abp.Authorization.Abstractions/Volo/Abp/Authorization/Permissions/IPermissionDefinitionManager.cs b/framework/src/Volo.Abp.Authorization.Abstractions/Volo/Abp/Authorization/Permissions/IPermissionDefinitionManager.cs index 553148671c..b4628a15bc 100644 --- a/framework/src/Volo.Abp.Authorization.Abstractions/Volo/Abp/Authorization/Permissions/IPermissionDefinitionManager.cs +++ b/framework/src/Volo.Abp.Authorization.Abstractions/Volo/Abp/Authorization/Permissions/IPermissionDefinitionManager.cs @@ -1,17 +1,18 @@ using System.Collections.Generic; +using System.Threading.Tasks; using JetBrains.Annotations; namespace Volo.Abp.Authorization.Permissions; public interface IPermissionDefinitionManager { - [NotNull] - PermissionDefinition Get([NotNull] string name); + [ItemNotNull] + Task GetAsync([NotNull] string name); - [CanBeNull] - PermissionDefinition GetOrNull([NotNull] string name); + [ItemCanBeNull] + Task GetOrNullAsync([NotNull] string name); - IReadOnlyList GetPermissions(); + Task> GetPermissionsAsync(); - IReadOnlyList GetGroups(); + Task> GetGroupsAsync(); } diff --git a/framework/src/Volo.Abp.Authorization.Abstractions/Volo/Abp/Authorization/Permissions/PermissionDefinition.cs b/framework/src/Volo.Abp.Authorization.Abstractions/Volo/Abp/Authorization/Permissions/PermissionDefinition.cs index 75d463f30f..fb6f07690c 100644 --- a/framework/src/Volo.Abp.Authorization.Abstractions/Volo/Abp/Authorization/Permissions/PermissionDefinition.cs +++ b/framework/src/Volo.Abp.Authorization.Abstractions/Volo/Abp/Authorization/Permissions/PermissionDefinition.cs @@ -7,7 +7,9 @@ using Volo.Abp.SimpleStateChecking; namespace Volo.Abp.Authorization.Permissions; -public class PermissionDefinition : IHasSimpleStateCheckers +public class PermissionDefinition : + IHasSimpleStateCheckers, + ICanAddChildPermission { /// /// Unique name of the permission. @@ -110,6 +112,16 @@ public class PermissionDefinition : IHasSimpleStateCheckers /// Sets a property in the dictionary. diff --git a/framework/src/Volo.Abp.Authorization.Abstractions/Volo/Abp/Authorization/Permissions/PermissionDefinitionContext.cs b/framework/src/Volo.Abp.Authorization.Abstractions/Volo/Abp/Authorization/Permissions/PermissionDefinitionContext.cs index 7a10fe4b5e..5b5543e868 100644 --- a/framework/src/Volo.Abp.Authorization.Abstractions/Volo/Abp/Authorization/Permissions/PermissionDefinitionContext.cs +++ b/framework/src/Volo.Abp.Authorization.Abstractions/Volo/Abp/Authorization/Permissions/PermissionDefinitionContext.cs @@ -20,8 +20,7 @@ public class PermissionDefinitionContext : IPermissionDefinitionContext public virtual PermissionGroupDefinition AddGroup( string name, - ILocalizableString displayName = null, - MultiTenancySides multiTenancySide = MultiTenancySides.Both) + ILocalizableString displayName = null) { Check.NotNull(name, nameof(name)); @@ -30,7 +29,7 @@ public class PermissionDefinitionContext : IPermissionDefinitionContext throw new AbpException($"There is already an existing permission group with name: {name}"); } - return Groups[name] = new PermissionGroupDefinition(name, displayName, multiTenancySide); + return Groups[name] = new PermissionGroupDefinition(name, displayName); } [NotNull] diff --git a/framework/src/Volo.Abp.Authorization.Abstractions/Volo/Abp/Authorization/Permissions/PermissionGroupDefinition.cs b/framework/src/Volo.Abp.Authorization.Abstractions/Volo/Abp/Authorization/Permissions/PermissionGroupDefinition.cs index d2efedc0d9..9fd904f54c 100644 --- a/framework/src/Volo.Abp.Authorization.Abstractions/Volo/Abp/Authorization/Permissions/PermissionGroupDefinition.cs +++ b/framework/src/Volo.Abp.Authorization.Abstractions/Volo/Abp/Authorization/Permissions/PermissionGroupDefinition.cs @@ -6,7 +6,7 @@ using Volo.Abp.MultiTenancy; namespace Volo.Abp.Authorization.Permissions; -public class PermissionGroupDefinition //TODO: Consider to make possible a group have sub groups +public class PermissionGroupDefinition : ICanAddChildPermission { /// /// Unique name of the group. @@ -21,12 +21,6 @@ public class PermissionGroupDefinition //TODO: Consider to make possible a group } private ILocalizableString _displayName; - /// - /// MultiTenancy side. - /// Default: - /// - public MultiTenancySides MultiTenancySide { get; set; } - public IReadOnlyList Permissions => _permissions.ToImmutableList(); private readonly List _permissions; @@ -45,19 +39,17 @@ public class PermissionGroupDefinition //TODO: Consider to make possible a group protected internal PermissionGroupDefinition( string name, - ILocalizableString displayName = null, - MultiTenancySides multiTenancySide = MultiTenancySides.Both) + ILocalizableString displayName = null) { Name = name; DisplayName = displayName ?? new FixedLocalizableString(Name); - MultiTenancySide = multiTenancySide; Properties = new Dictionary(); _permissions = new List(); } public virtual PermissionDefinition AddPermission( - string name, + [NotNull] string name, ILocalizableString displayName = null, MultiTenancySides multiTenancySide = MultiTenancySides.Both, bool isEnabled = true) diff --git a/framework/src/Volo.Abp.Authorization/Volo/Abp/Authorization/AbpAuthorizationPolicyProvider.cs b/framework/src/Volo.Abp.Authorization/Volo/Abp/Authorization/AbpAuthorizationPolicyProvider.cs index 01037f3e96..fb37427c48 100644 --- a/framework/src/Volo.Abp.Authorization/Volo/Abp/Authorization/AbpAuthorizationPolicyProvider.cs +++ b/framework/src/Volo.Abp.Authorization/Volo/Abp/Authorization/AbpAuthorizationPolicyProvider.cs @@ -31,7 +31,7 @@ public class AbpAuthorizationPolicyProvider : DefaultAuthorizationPolicyProvider return policy; } - var permission = _permissionDefinitionManager.GetOrNull(policyName); + var permission = await _permissionDefinitionManager.GetOrNullAsync(policyName); if (permission != null) { //TODO: Optimize & Cache! @@ -43,16 +43,14 @@ public class AbpAuthorizationPolicyProvider : DefaultAuthorizationPolicyProvider return null; } - public Task> GetPoliciesNamesAsync() + public async Task> GetPoliciesNamesAsync() { - return Task.FromResult( - _options.GetPoliciesNames() - .Union( - _permissionDefinitionManager - .GetPermissions() - .Select(p => p.Name) - ) - .ToList() - ); + return _options.GetPoliciesNames() + .Union( + (await _permissionDefinitionManager + .GetPermissionsAsync()) + .Select(p => p.Name) + ) + .ToList(); } } diff --git a/framework/src/Volo.Abp.Authorization/Volo/Abp/Authorization/Permissions/AuthenticatedSimpleStateCheckerSerializerContributor.cs b/framework/src/Volo.Abp.Authorization/Volo/Abp/Authorization/Permissions/AuthenticatedSimpleStateCheckerSerializerContributor.cs new file mode 100644 index 0000000000..2a23b5bfcd --- /dev/null +++ b/framework/src/Volo.Abp.Authorization/Volo/Abp/Authorization/Permissions/AuthenticatedSimpleStateCheckerSerializerContributor.cs @@ -0,0 +1,38 @@ +using System.Text.Json.Nodes; +using Volo.Abp.DependencyInjection; +using Volo.Abp.SimpleStateChecking; + +namespace Volo.Abp.Authorization.Permissions; + +public class AuthenticatedSimpleStateCheckerSerializerContributor : + ISimpleStateCheckerSerializerContributor, + ISingletonDependency +{ + public const string CheckerShortName = "A"; + + public string SerializeToJson(ISimpleStateChecker checker) + where TState : IHasSimpleStateCheckers + { + if (checker is not RequireAuthenticatedSimpleStateChecker) + { + return null; + } + + var jsonObject = new JsonObject { + ["T"] = CheckerShortName + }; + + return jsonObject.ToJsonString(); + } + + public ISimpleStateChecker Deserialize(JsonObject jsonObject, TState state) + where TState : IHasSimpleStateCheckers + { + if (jsonObject["T"]?.ToString() != CheckerShortName) + { + return null; + } + + return new RequireAuthenticatedSimpleStateChecker(); + } +} \ No newline at end of file diff --git a/framework/src/Volo.Abp.Authorization/Volo/Abp/Authorization/Permissions/IDynamicPermissionDefinitionStore.cs b/framework/src/Volo.Abp.Authorization/Volo/Abp/Authorization/Permissions/IDynamicPermissionDefinitionStore.cs new file mode 100644 index 0000000000..ad74dae46b --- /dev/null +++ b/framework/src/Volo.Abp.Authorization/Volo/Abp/Authorization/Permissions/IDynamicPermissionDefinitionStore.cs @@ -0,0 +1,13 @@ +using System.Collections.Generic; +using System.Threading.Tasks; + +namespace Volo.Abp.Authorization.Permissions; + +public interface IDynamicPermissionDefinitionStore +{ + Task GetOrNullAsync(string name); + + Task> GetPermissionsAsync(); + + Task> GetGroupsAsync(); +} \ No newline at end of file diff --git a/framework/src/Volo.Abp.Authorization/Volo/Abp/Authorization/Permissions/IStaticPermissionDefinitionStore.cs b/framework/src/Volo.Abp.Authorization/Volo/Abp/Authorization/Permissions/IStaticPermissionDefinitionStore.cs new file mode 100644 index 0000000000..719412e4db --- /dev/null +++ b/framework/src/Volo.Abp.Authorization/Volo/Abp/Authorization/Permissions/IStaticPermissionDefinitionStore.cs @@ -0,0 +1,13 @@ +using System.Collections.Generic; +using System.Threading.Tasks; + +namespace Volo.Abp.Authorization.Permissions; + +public interface IStaticPermissionDefinitionStore +{ + Task GetOrNullAsync(string name); + + Task> GetPermissionsAsync(); + + Task> GetGroupsAsync(); +} \ No newline at end of file diff --git a/framework/src/Volo.Abp.Authorization/Volo/Abp/Authorization/Permissions/NullDynamicPermissionDefinitionStore.cs b/framework/src/Volo.Abp.Authorization/Volo/Abp/Authorization/Permissions/NullDynamicPermissionDefinitionStore.cs new file mode 100644 index 0000000000..61e70b057c --- /dev/null +++ b/framework/src/Volo.Abp.Authorization/Volo/Abp/Authorization/Permissions/NullDynamicPermissionDefinitionStore.cs @@ -0,0 +1,33 @@ +using System; +using System.Collections.Generic; +using System.Collections.Immutable; +using System.Threading.Tasks; +using Volo.Abp.DependencyInjection; + +namespace Volo.Abp.Authorization.Permissions; + +public class NullDynamicPermissionDefinitionStore : IDynamicPermissionDefinitionStore, ISingletonDependency +{ + private readonly static Task CachedPermissionResult = Task.FromResult((PermissionDefinition)null); + + private readonly static Task> CachedPermissionsResult = + Task.FromResult((IReadOnlyList)Array.Empty().ToImmutableList()); + + private readonly static Task> CachedGroupsResult = + Task.FromResult((IReadOnlyList)Array.Empty().ToImmutableList()); + + public Task GetOrNullAsync(string name) + { + return CachedPermissionResult; + } + + public Task> GetPermissionsAsync() + { + return CachedPermissionsResult; + } + + public Task> GetGroupsAsync() + { + return CachedGroupsResult; + } +} \ No newline at end of file diff --git a/framework/src/Volo.Abp.Authorization/Volo/Abp/Authorization/Permissions/PermissionChecker.cs b/framework/src/Volo.Abp.Authorization/Volo/Abp/Authorization/Permissions/PermissionChecker.cs index fec8771afa..168eb3064b 100644 --- a/framework/src/Volo.Abp.Authorization/Volo/Abp/Authorization/Permissions/PermissionChecker.cs +++ b/framework/src/Volo.Abp.Authorization/Volo/Abp/Authorization/Permissions/PermissionChecker.cs @@ -43,8 +43,12 @@ public class PermissionChecker : IPermissionChecker, ITransientDependency { Check.NotNull(name, nameof(name)); - var permission = PermissionDefinitionManager.Get(name); - + var permission = await PermissionDefinitionManager.GetOrNullAsync(name); + if (permission == null) + { + return false; + } + if (!permission.IsEnabled) { return false; @@ -97,18 +101,24 @@ public class PermissionChecker : IPermissionChecker, ITransientDependency { Check.NotNull(names, nameof(names)); - var multiTenancySide = claimsPrincipal?.GetMultiTenancySide() ?? CurrentTenant.GetMultiTenancySide(); - var result = new MultiplePermissionGrantResult(); if (!names.Any()) { return result; } + var multiTenancySide = claimsPrincipal?.GetMultiTenancySide() ?? + CurrentTenant.GetMultiTenancySide(); + var permissionDefinitions = new List(); foreach (var name in names) { - var permission = PermissionDefinitionManager.Get(name); + var permission = await PermissionDefinitionManager.GetOrNullAsync(name); + if (permission == null) + { + result.Result.Add(name, PermissionGrantResult.Prohibited); + continue; + } result.Result.Add(name, PermissionGrantResult.Undefined); diff --git a/framework/src/Volo.Abp.Authorization/Volo/Abp/Authorization/Permissions/PermissionDefinitionManager.cs b/framework/src/Volo.Abp.Authorization/Volo/Abp/Authorization/Permissions/PermissionDefinitionManager.cs index 7f4de3c767..de24ff59c5 100644 --- a/framework/src/Volo.Abp.Authorization/Volo/Abp/Authorization/Permissions/PermissionDefinitionManager.cs +++ b/framework/src/Volo.Abp.Authorization/Volo/Abp/Authorization/Permissions/PermissionDefinitionManager.cs @@ -1,47 +1,27 @@ -using System; -using System.Collections.Generic; +using System.Collections.Generic; using System.Collections.Immutable; using System.Linq; -using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.Options; +using System.Threading.Tasks; using Volo.Abp.DependencyInjection; namespace Volo.Abp.Authorization.Permissions; -public class PermissionDefinitionManager : IPermissionDefinitionManager, ISingletonDependency +public class PermissionDefinitionManager : IPermissionDefinitionManager, ITransientDependency { - protected IDictionary PermissionGroupDefinitions => _lazyPermissionGroupDefinitions.Value; - private readonly Lazy> _lazyPermissionGroupDefinitions; - - protected IDictionary PermissionDefinitions => _lazyPermissionDefinitions.Value; - private readonly Lazy> _lazyPermissionDefinitions; - - protected AbpPermissionOptions Options { get; } - - private readonly IServiceProvider _serviceProvider; + private readonly IStaticPermissionDefinitionStore _staticStore; + private readonly IDynamicPermissionDefinitionStore _dynamicStore; public PermissionDefinitionManager( - IOptions options, - IServiceProvider serviceProvider) + IStaticPermissionDefinitionStore staticStore, + IDynamicPermissionDefinitionStore dynamicStore) { - _serviceProvider = serviceProvider; - Options = options.Value; - - _lazyPermissionDefinitions = new Lazy>( - CreatePermissionDefinitions, - isThreadSafe: true - ); - - _lazyPermissionGroupDefinitions = new Lazy>( - CreatePermissionGroupDefinitions, - isThreadSafe: true - ); + _staticStore = staticStore; + _dynamicStore = dynamicStore; } - public virtual PermissionDefinition Get(string name) + public virtual async Task GetAsync(string name) { - var permission = GetOrNull(name); - + var permission = await GetOrNullAsync(name); if (permission == null) { throw new AbpException("Undefined permission: " + name); @@ -50,82 +30,41 @@ public class PermissionDefinitionManager : IPermissionDefinitionManager, ISingle return permission; } - public virtual PermissionDefinition GetOrNull(string name) + public virtual async Task GetOrNullAsync(string name) { Check.NotNull(name, nameof(name)); - return PermissionDefinitions.GetOrDefault(name); - } - - public virtual IReadOnlyList GetPermissions() - { - return PermissionDefinitions.Values.ToImmutableList(); - } - - public IReadOnlyList GetGroups() - { - return PermissionGroupDefinitions.Values.ToImmutableList(); - } - - protected virtual Dictionary CreatePermissionDefinitions() - { - var permissions = new Dictionary(); - - foreach (var groupDefinition in PermissionGroupDefinitions.Values) - { - foreach (var permission in groupDefinition.Permissions) - { - AddPermissionToDictionaryRecursively(permissions, permission); - } - } - - return permissions; + return await _staticStore.GetOrNullAsync(name) ?? + await _dynamicStore.GetOrNullAsync(name); } - protected virtual void AddPermissionToDictionaryRecursively( - Dictionary permissions, - PermissionDefinition permission) + public virtual async Task> GetPermissionsAsync() { - if (permissions.ContainsKey(permission.Name)) - { - throw new AbpException("Duplicate permission name: " + permission.Name); - } - - permissions[permission.Name] = permission; - - foreach (var child in permission.Children) - { - AddPermissionToDictionaryRecursively(permissions, child); - } + var staticPermissions = await _staticStore.GetPermissionsAsync(); + var staticPermissionNames = staticPermissions + .Select(p => p.Name) + .ToImmutableHashSet(); + + var dynamicPermissions = await _dynamicStore.GetPermissionsAsync(); + + /* We prefer static permissions over dynamics */ + return staticPermissions.Concat( + dynamicPermissions.Where(d => !staticPermissionNames.Contains(d.Name)) + ).ToImmutableList(); } - protected virtual Dictionary CreatePermissionGroupDefinitions() + public async Task> GetGroupsAsync() { - using (var scope = _serviceProvider.CreateScope()) - { - var context = new PermissionDefinitionContext(scope.ServiceProvider); - - var providers = Options - .DefinitionProviders - .Select(p => scope.ServiceProvider.GetRequiredService(p) as IPermissionDefinitionProvider) - .ToList(); - - foreach (var provider in providers) - { - provider.PreDefine(context); - } - - foreach (var provider in providers) - { - provider.Define(context); - } - - foreach (var provider in providers) - { - provider.PostDefine(context); - } - - return context.Groups; - } + var staticGroups = await _staticStore.GetGroupsAsync(); + var staticGroupNames = staticGroups + .Select(p => p.Name) + .ToImmutableHashSet(); + + var dynamicGroups = await _dynamicStore.GetGroupsAsync(); + + /* We prefer static groups over dynamics */ + return staticGroups.Concat( + dynamicGroups.Where(d => !staticGroupNames.Contains(d.Name)) + ).ToImmutableList(); } -} +} \ No newline at end of file diff --git a/framework/src/Volo.Abp.Authorization/Volo/Abp/Authorization/Permissions/PermissionsSimpleStateCheckerSerializerContributor.cs b/framework/src/Volo.Abp.Authorization/Volo/Abp/Authorization/Permissions/PermissionsSimpleStateCheckerSerializerContributor.cs new file mode 100644 index 0000000000..3b890797f6 --- /dev/null +++ b/framework/src/Volo.Abp.Authorization/Volo/Abp/Authorization/Permissions/PermissionsSimpleStateCheckerSerializerContributor.cs @@ -0,0 +1,62 @@ +using System.Linq; +using System.Text.Json.Nodes; +using Volo.Abp.Authorization.Permissions; +using Volo.Abp.DependencyInjection; +using Volo.Abp.SimpleStateChecking; + +namespace Volo.Abp.GlobalFeatures; + +public class PermissionsSimpleStateCheckerSerializerContributor : + ISimpleStateCheckerSerializerContributor, + ISingletonDependency +{ + public const string CheckerShortName = "P"; + + public string SerializeToJson(ISimpleStateChecker checker) + where TState : IHasSimpleStateCheckers + { + if (checker is not RequirePermissionsSimpleStateChecker permissionsSimpleStateChecker) + { + return null; + } + + var jsonObject = new JsonObject { + ["T"] = CheckerShortName, + ["A"] = permissionsSimpleStateChecker.RequiresAll + }; + + var nameArray = new JsonArray(); + foreach (var permissionName in permissionsSimpleStateChecker.PermissionNames) + { + nameArray.Add(permissionName); + } + + jsonObject["N"] = nameArray; + return jsonObject.ToJsonString(); + } + + public ISimpleStateChecker Deserialize( + JsonObject jsonObject, + TState state) + where TState : IHasSimpleStateCheckers + { + if (jsonObject["T"]?.ToString() != CheckerShortName) + { + return null; + } + + var nameArray = jsonObject["N"] as JsonArray; + if (nameArray == null) + { + throw new AbpException("'N' is not an array in the serialized state checker! JsonObject: " + jsonObject.ToJsonString()); + } + + return new RequirePermissionsSimpleStateChecker( + new RequirePermissionsSimpleBatchStateCheckerModel( + state, + nameArray.Select(x => x.ToString()).ToArray(), + (bool?)jsonObject["A"] ?? false + ) + ); + } +} \ No newline at end of file diff --git a/framework/src/Volo.Abp.Authorization/Volo/Abp/Authorization/Permissions/RequirePermissionsSimpleStateChecker.cs b/framework/src/Volo.Abp.Authorization/Volo/Abp/Authorization/Permissions/RequirePermissionsSimpleStateChecker.cs index 3ae1809b55..fd8eef3791 100644 --- a/framework/src/Volo.Abp.Authorization/Volo/Abp/Authorization/Permissions/RequirePermissionsSimpleStateChecker.cs +++ b/framework/src/Volo.Abp.Authorization/Volo/Abp/Authorization/Permissions/RequirePermissionsSimpleStateChecker.cs @@ -8,6 +8,10 @@ namespace Volo.Abp.Authorization.Permissions; public class RequirePermissionsSimpleStateChecker : ISimpleStateChecker where TState : IHasSimpleStateCheckers { + public bool RequiresAll => _model.RequiresAll; + + public string[] PermissionNames => _model.Permissions; + private readonly RequirePermissionsSimpleBatchStateCheckerModel _model; public RequirePermissionsSimpleStateChecker(RequirePermissionsSimpleBatchStateCheckerModel model) diff --git a/framework/src/Volo.Abp.Authorization/Volo/Abp/Authorization/Permissions/StaticPermissionDefinitionStore.cs b/framework/src/Volo.Abp.Authorization/Volo/Abp/Authorization/Permissions/StaticPermissionDefinitionStore.cs new file mode 100644 index 0000000000..ee4803d61e --- /dev/null +++ b/framework/src/Volo.Abp.Authorization/Volo/Abp/Authorization/Permissions/StaticPermissionDefinitionStore.cs @@ -0,0 +1,122 @@ +using System; +using System.Collections.Generic; +using System.Collections.Immutable; +using System.Linq; +using System.Threading.Tasks; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Options; +using Volo.Abp.DependencyInjection; + +namespace Volo.Abp.Authorization.Permissions; + +public class StaticPermissionDefinitionStore : IStaticPermissionDefinitionStore, ISingletonDependency +{ + protected IDictionary PermissionGroupDefinitions => _lazyPermissionGroupDefinitions.Value; + private readonly Lazy> _lazyPermissionGroupDefinitions; + + protected IDictionary PermissionDefinitions => _lazyPermissionDefinitions.Value; + private readonly Lazy> _lazyPermissionDefinitions; + + protected AbpPermissionOptions Options { get; } + + private readonly IServiceProvider _serviceProvider; + + public StaticPermissionDefinitionStore( + IServiceProvider serviceProvider, + IOptions options) + { + _serviceProvider = serviceProvider; + Options = options.Value; + + _lazyPermissionDefinitions = new Lazy>( + CreatePermissionDefinitions, + isThreadSafe: true + ); + + _lazyPermissionGroupDefinitions = new Lazy>( + CreatePermissionGroupDefinitions, + isThreadSafe: true + ); + } + + protected virtual Dictionary CreatePermissionDefinitions() + { + var permissions = new Dictionary(); + + foreach (var groupDefinition in PermissionGroupDefinitions.Values) + { + foreach (var permission in groupDefinition.Permissions) + { + AddPermissionToDictionaryRecursively(permissions, permission); + } + } + + return permissions; + } + + protected virtual void AddPermissionToDictionaryRecursively( + Dictionary permissions, + PermissionDefinition permission) + { + if (permissions.ContainsKey(permission.Name)) + { + throw new AbpException("Duplicate permission name: " + permission.Name); + } + + permissions[permission.Name] = permission; + + foreach (var child in permission.Children) + { + AddPermissionToDictionaryRecursively(permissions, child); + } + } + + protected virtual Dictionary CreatePermissionGroupDefinitions() + { + using (var scope = _serviceProvider.CreateScope()) + { + var context = new PermissionDefinitionContext(scope.ServiceProvider); + + var providers = Options + .DefinitionProviders + .Select(p => scope.ServiceProvider.GetRequiredService(p) as IPermissionDefinitionProvider) + .ToList(); + + foreach (var provider in providers) + { + provider.PreDefine(context); + } + + foreach (var provider in providers) + { + provider.Define(context); + } + + foreach (var provider in providers) + { + provider.PostDefine(context); + } + + return context.Groups; + } + } + + public Task GetOrNullAsync(string name) + { + return Task.FromResult(PermissionDefinitions.GetOrDefault(name)); + } + + public virtual Task> GetPermissionsAsync() + { + return Task.FromResult>( + PermissionDefinitions.Values.ToImmutableList() + ); + } + + public Task> GetGroupsAsync() + { + return Task.FromResult>( + PermissionGroupDefinitions.Values.ToImmutableList() + ); + } +} \ No newline at end of file diff --git a/framework/src/Volo.Abp.Autofac/Autofac/Builder/AbpRegistrationBuilderExtensions.cs b/framework/src/Volo.Abp.Autofac/Autofac/Builder/AbpRegistrationBuilderExtensions.cs index 868ecb3fa5..03084d8351 100644 --- a/framework/src/Volo.Abp.Autofac/Autofac/Builder/AbpRegistrationBuilderExtensions.cs +++ b/framework/src/Volo.Abp.Autofac/Autofac/Builder/AbpRegistrationBuilderExtensions.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using System.Linq; using Autofac.Core; using Autofac.Extras.DynamicProxy; +using Volo.Abp.Autofac; using Volo.Abp.Castle.DynamicProxy; using Volo.Abp.DependencyInjection; using Volo.Abp.Modularity; @@ -67,10 +68,11 @@ public static class AbpRegistrationBuilderExtensions Type implementationType) where TActivatorData : ReflectionActivatorData { - //Enable Property Injection only for types in an assembly containing an AbpModule - if (moduleContainer.Modules.Any(m => m.Assembly == implementationType.Assembly)) + // Enable Property Injection only for types in an assembly containing an AbpModule and without a DisablePropertyInjection attribute on class or properties. + if (moduleContainer.Modules.Any(m => m.Assembly == implementationType.Assembly) && + implementationType.GetCustomAttributes(typeof(DisablePropertyInjectionAttribute), true).IsNullOrEmpty()) { - registrationBuilder = registrationBuilder.PropertiesAutowired(); + registrationBuilder = registrationBuilder.PropertiesAutowired(new AbpPropertySelector(false)); } return registrationBuilder; diff --git a/framework/src/Volo.Abp.Autofac/Volo/Abp/Autofac/AbpPropertySelector.cs b/framework/src/Volo.Abp.Autofac/Volo/Abp/Autofac/AbpPropertySelector.cs new file mode 100644 index 0000000000..00d20e9bca --- /dev/null +++ b/framework/src/Volo.Abp.Autofac/Volo/Abp/Autofac/AbpPropertySelector.cs @@ -0,0 +1,21 @@ +using System.Collections.Generic; +using System.Reflection; +using Autofac.Core; +using Volo.Abp.DependencyInjection; + +namespace Volo.Abp.Autofac; + +public class AbpPropertySelector : DefaultPropertySelector +{ + public AbpPropertySelector(bool preserveSetValues) + : base(preserveSetValues) + { + } + + public override bool InjectProperty(PropertyInfo propertyInfo, object instance) + { + return propertyInfo.GetCustomAttributes(typeof(DisablePropertyInjectionAttribute), true).IsNullOrEmpty() && + base.InjectProperty(propertyInfo, instance); + } + +} diff --git a/framework/src/Volo.Abp.BackgroundJobs.HangFire/Volo/Abp/BackgroundJobs/Hangfire/HangfireBackgroundJobManager.cs b/framework/src/Volo.Abp.BackgroundJobs.HangFire/Volo/Abp/BackgroundJobs/Hangfire/HangfireBackgroundJobManager.cs index 2ebad0797f..2583ada9fc 100644 --- a/framework/src/Volo.Abp.BackgroundJobs.HangFire/Volo/Abp/BackgroundJobs/Hangfire/HangfireBackgroundJobManager.cs +++ b/framework/src/Volo.Abp.BackgroundJobs.HangFire/Volo/Abp/BackgroundJobs/Hangfire/HangfireBackgroundJobManager.cs @@ -1,6 +1,9 @@ using System; +using System.Reflection; using System.Threading.Tasks; using Hangfire; +using Hangfire.States; +using Microsoft.Extensions.Options; using Volo.Abp.DependencyInjection; namespace Volo.Abp.BackgroundJobs.Hangfire; @@ -8,16 +11,35 @@ namespace Volo.Abp.BackgroundJobs.Hangfire; [Dependency(ReplaceServices = true)] public class HangfireBackgroundJobManager : IBackgroundJobManager, ITransientDependency { + protected AbpBackgroundJobOptions Options { get; } + + public HangfireBackgroundJobManager(IOptions options) + { + Options = options.Value; + } + public virtual Task EnqueueAsync(TArgs args, BackgroundJobPriority priority = BackgroundJobPriority.Normal, TimeSpan? delay = null) { return Task.FromResult(delay.HasValue ? BackgroundJob.Schedule>( - adapter => adapter.ExecuteAsync(args), + adapter => adapter.ExecuteAsync(GetQueueName(typeof(TArgs)),args), delay.Value ) : BackgroundJob.Enqueue>( - adapter => adapter.ExecuteAsync(args) + adapter => adapter.ExecuteAsync(GetQueueName(typeof(TArgs)) ,args) )); } + + protected virtual string GetQueueName(Type argsType) + { + var queueName = EnqueuedState.DefaultQueue; + var queueAttribute = Options.GetJob(argsType).JobType.GetCustomAttribute(); + if (queueAttribute != null) + { + queueName = queueAttribute.Queue; + } + + return queueName; + } } diff --git a/framework/src/Volo.Abp.BackgroundJobs.HangFire/Volo/Abp/BackgroundJobs/Hangfire/HangfireJobExecutionAdapter.cs b/framework/src/Volo.Abp.BackgroundJobs.HangFire/Volo/Abp/BackgroundJobs/Hangfire/HangfireJobExecutionAdapter.cs index a2ad7dc77d..7ba0cd7db4 100644 --- a/framework/src/Volo.Abp.BackgroundJobs.HangFire/Volo/Abp/BackgroundJobs/Hangfire/HangfireJobExecutionAdapter.cs +++ b/framework/src/Volo.Abp.BackgroundJobs.HangFire/Volo/Abp/BackgroundJobs/Hangfire/HangfireJobExecutionAdapter.cs @@ -1,4 +1,5 @@ using System.Threading.Tasks; +using Hangfire; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Options; @@ -20,7 +21,8 @@ public class HangfireJobExecutionAdapter Options = options.Value; } - public async Task ExecuteAsync(TArgs args) + [Queue("{0}")] + public async Task ExecuteAsync(string queue, TArgs args) { if (!Options.IsJobExecutionEnabled) { diff --git a/framework/src/Volo.Abp.BackgroundJobs.RabbitMQ/Volo/Abp/BackgroundJobs/RabbitMQ/AbpRabbitMqBackgroundJobOptions.cs b/framework/src/Volo.Abp.BackgroundJobs.RabbitMQ/Volo/Abp/BackgroundJobs/RabbitMQ/AbpRabbitMqBackgroundJobOptions.cs index 83efe8ff31..540d848412 100644 --- a/framework/src/Volo.Abp.BackgroundJobs.RabbitMQ/Volo/Abp/BackgroundJobs/RabbitMQ/AbpRabbitMqBackgroundJobOptions.cs +++ b/framework/src/Volo.Abp.BackgroundJobs.RabbitMQ/Volo/Abp/BackgroundJobs/RabbitMQ/AbpRabbitMqBackgroundJobOptions.cs @@ -19,6 +19,8 @@ public class AbpRabbitMqBackgroundJobOptions /// Default value: "AbpBackgroundJobsDelayed." /// public string DefaultDelayedQueueNamePrefix { get; set; } + + public ushort? PrefetchCount { get; set; } public AbpRabbitMqBackgroundJobOptions() { diff --git a/framework/src/Volo.Abp.BackgroundJobs.RabbitMQ/Volo/Abp/BackgroundJobs/RabbitMQ/JobQueue.cs b/framework/src/Volo.Abp.BackgroundJobs.RabbitMQ/Volo/Abp/BackgroundJobs/RabbitMQ/JobQueue.cs index 208d7ecd9f..9c3bf26e62 100644 --- a/framework/src/Volo.Abp.BackgroundJobs.RabbitMQ/Volo/Abp/BackgroundJobs/RabbitMQ/JobQueue.cs +++ b/framework/src/Volo.Abp.BackgroundJobs.RabbitMQ/Volo/Abp/BackgroundJobs/RabbitMQ/JobQueue.cs @@ -66,7 +66,8 @@ public class JobQueue : IJobQueue new JobQueueConfiguration( typeof(TArgs), AbpRabbitMqBackgroundJobOptions.DefaultQueueNamePrefix + JobConfiguration.JobName, - AbpRabbitMqBackgroundJobOptions.DefaultDelayedQueueNamePrefix + JobConfiguration.JobName + AbpRabbitMqBackgroundJobOptions.DefaultDelayedQueueNamePrefix + JobConfiguration.JobName, + prefetchCount: AbpRabbitMqBackgroundJobOptions.PrefetchCount ); } @@ -140,9 +141,14 @@ public class JobQueue : IJobQueue if (AbpBackgroundJobOptions.IsJobExecutionEnabled) { + if (QueueConfiguration.PrefetchCount.HasValue) + { + ChannelAccessor.Channel.BasicQos(0, QueueConfiguration.PrefetchCount.Value, false); + } + Consumer = new AsyncEventingBasicConsumer(ChannelAccessor.Channel); Consumer.Received += MessageReceived; - + //TODO: What BasicConsume returns? ChannelAccessor.Channel.BasicConsume( queue: QueueConfiguration.QueueName, diff --git a/framework/src/Volo.Abp.BackgroundJobs.RabbitMQ/Volo/Abp/BackgroundJobs/RabbitMQ/JobQueueConfiguration.cs b/framework/src/Volo.Abp.BackgroundJobs.RabbitMQ/Volo/Abp/BackgroundJobs/RabbitMQ/JobQueueConfiguration.cs index 792eb9815e..ee706ab864 100644 --- a/framework/src/Volo.Abp.BackgroundJobs.RabbitMQ/Volo/Abp/BackgroundJobs/RabbitMQ/JobQueueConfiguration.cs +++ b/framework/src/Volo.Abp.BackgroundJobs.RabbitMQ/Volo/Abp/BackgroundJobs/RabbitMQ/JobQueueConfiguration.cs @@ -20,12 +20,14 @@ public class JobQueueConfiguration : QueueDeclareConfiguration string connectionName = null, bool durable = true, bool exclusive = false, - bool autoDelete = false) + bool autoDelete = false, + ushort? prefetchCount = null) : base( queueName, durable, exclusive, - autoDelete) + autoDelete, + prefetchCount) { JobArgsType = jobArgsType; ConnectionName = connectionName; diff --git a/framework/src/Volo.Abp.Caching.StackExchangeRedis/Volo/Abp/Caching/StackExchangeRedis/AbpRedisCache.cs b/framework/src/Volo.Abp.Caching.StackExchangeRedis/Volo/Abp/Caching/StackExchangeRedis/AbpRedisCache.cs index d52a40e5b5..68a59aab2d 100644 --- a/framework/src/Volo.Abp.Caching.StackExchangeRedis/Volo/Abp/Caching/StackExchangeRedis/AbpRedisCache.cs +++ b/framework/src/Volo.Abp.Caching.StackExchangeRedis/Volo/Abp/Caching/StackExchangeRedis/AbpRedisCache.cs @@ -15,18 +15,18 @@ namespace Volo.Abp.Caching.StackExchangeRedis; [DisableConventionalRegistration] public class AbpRedisCache : RedisCache, ICacheSupportsMultipleItems { - protected static readonly string SetScript; protected static readonly string AbsoluteExpirationKey; protected static readonly string SlidingExpirationKey; protected static readonly string DataKey; protected static readonly long NotPresent; - private static readonly FieldInfo RedisDatabaseField; - private static readonly MethodInfo ConnectMethod; - private static readonly MethodInfo ConnectAsyncMethod; - private static readonly MethodInfo MapMetadataMethod; - private static readonly MethodInfo GetAbsoluteExpirationMethod; - private static readonly MethodInfo GetExpirationInSecondsMethod; + private readonly static FieldInfo SetScriptField; + private readonly static FieldInfo RedisDatabaseField; + private readonly static MethodInfo ConnectMethod; + private readonly static MethodInfo ConnectAsyncMethod; + private readonly static MethodInfo MapMetadataMethod; + private readonly static MethodInfo GetAbsoluteExpirationMethod; + private readonly static MethodInfo GetExpirationInSecondsMethod; protected IDatabase RedisDatabase => GetRedisDatabase(); private IDatabase _redisDatabase; @@ -36,9 +36,11 @@ public class AbpRedisCache : RedisCache, ICacheSupportsMultipleItems static AbpRedisCache() { var type = typeof(RedisCache); - + RedisDatabaseField = type.GetField("_cache", BindingFlags.Instance | BindingFlags.NonPublic); + SetScriptField = type.GetField("_setScript", BindingFlags.Instance | BindingFlags.NonPublic); + ConnectMethod = type.GetMethod("Connect", BindingFlags.Instance | BindingFlags.NonPublic); ConnectAsyncMethod = type.GetMethod("ConnectAsync", BindingFlags.Instance | BindingFlags.NonPublic); @@ -51,9 +53,6 @@ public class AbpRedisCache : RedisCache, ICacheSupportsMultipleItems GetExpirationInSecondsMethod = type.GetMethod("GetExpirationInSeconds", BindingFlags.Static | BindingFlags.NonPublic); - SetScript = type.GetField("SetScript", BindingFlags.Static | BindingFlags.NonPublic)?.GetValue(null) - .ToString(); - AbsoluteExpirationKey = type.GetField("AbsoluteExpirationKey", BindingFlags.Static | BindingFlags.NonPublic) ?.GetValue(null).ToString(); @@ -83,14 +82,14 @@ public class AbpRedisCache : RedisCache, ICacheSupportsMultipleItems ConnectMethod.Invoke(this, Array.Empty()); } - protected virtual Task ConnectAsync(CancellationToken token = default) + protected virtual async Task ConnectAsync(CancellationToken token = default) { if (GetRedisDatabase() != null) { - return Task.CompletedTask; + return; } - return (Task)ConnectAsyncMethod.Invoke(this, new object[] { token }); + await (Task)ConnectAsyncMethod.Invoke(this, new object[] { token }); } public byte[][] GetMany( @@ -283,7 +282,7 @@ public class AbpRedisCache : RedisCache, ICacheSupportsMultipleItems for (var i = 0; i < itemArray.Length; i++) { - tasks[i] = RedisDatabase.ScriptEvaluateAsync(SetScript, new RedisKey[] { Instance + itemArray[i].Key }, + tasks[i] = RedisDatabase.ScriptEvaluateAsync(GetSetScript(), new RedisKey[] { Instance + itemArray[i].Key }, new RedisValue[] { absoluteExpiration?.Ticks ?? NotPresent, @@ -333,4 +332,9 @@ public class AbpRedisCache : RedisCache, ICacheSupportsMultipleItems return _redisDatabase; } + + private string GetSetScript() + { + return SetScriptField?.GetValue(this).ToString(); + } } diff --git a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/AbpCliOptions.cs b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/AbpCliOptions.cs index 62a7e59d8e..3068016f33 100644 --- a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/AbpCliOptions.cs +++ b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/AbpCliOptions.cs @@ -16,6 +16,8 @@ public class AbpCliOptions /// Default value: "CLI". /// public string ToolName { get; set; } = "CLI"; + + public bool AlwaysHideExternalCommandOutput { get; set; } public AbpCliOptions() { diff --git a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Auth/AuthService.cs b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Auth/AuthService.cs index c3ce0afb54..cc198e877b 100644 --- a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Auth/AuthService.cs +++ b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Auth/AuthService.cs @@ -74,9 +74,9 @@ public class AuthService : IAuthService, ITransientDependency { var configuration = new IdentityClientConfiguration( CliUrls.AccountAbpIo, - "role email abpio abpio_www abpio_commercial offline_access", + "abpio offline_access", "abp-cli", - "1q2w3e*", + null, OidcConstants.GrantTypes.Password, userName, password @@ -96,9 +96,9 @@ public class AuthService : IAuthService, ITransientDependency { var configuration = new IdentityClientConfiguration( CliUrls.AccountAbpIo, - "role email abpio abpio_www abpio_commercial openid offline_access", + "abpio offline_access", "abp-cli", - "1q2w3e*", + null, OidcConstants.GrantTypes.DeviceCode ); diff --git a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Commands/GenerateProxyCommand.cs b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Commands/GenerateProxyCommand.cs index bf8e2e3028..7874fddb86 100644 --- a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Commands/GenerateProxyCommand.cs +++ b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Commands/GenerateProxyCommand.cs @@ -1,4 +1,5 @@ using System.Text; +using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Options; using Volo.Abp.Cli.ServiceProxying; using Volo.Abp.DependencyInjection; @@ -13,7 +14,7 @@ public class GenerateProxyCommand : ProxyCommandBase public GenerateProxyCommand( IOptions serviceProxyOptions, - IHybridServiceScopeFactory serviceScopeFactory) + IServiceScopeFactory serviceScopeFactory) : base(serviceProxyOptions, serviceScopeFactory) { } diff --git a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Commands/ProjectCreationCommandBase.cs b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Commands/ProjectCreationCommandBase.cs index 646d8d4c08..813900ba18 100644 --- a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Commands/ProjectCreationCommandBase.cs +++ b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Commands/ProjectCreationCommandBase.cs @@ -333,14 +333,14 @@ public abstract class ProjectCreationCommandBase var tieredYesNo = tiered ? "yes" : "no"; var url = $"https://{urlPrefix}.abp.io/project-created-success?ui={uiFramework:g}&db={databaseProvider:g}&tiered={tieredYesNo}"; - CmdHelper.OpenWebPage(url); + CmdHelper.Open(url); } protected void OpenMicroserviceDocumentPage() { var url = "https://docs.abp.io/en/commercial/latest/startup-templates/microservice/index"; - CmdHelper.OpenWebPage(url); + CmdHelper.Open(url); } protected bool GetCreateSolutionFolderPreference(CommandLineArgs commandLineArgs) diff --git a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Commands/ProxyCommandBase.cs b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Commands/ProxyCommandBase.cs index 22311bb986..67c61b2a28 100644 --- a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Commands/ProxyCommandBase.cs +++ b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Commands/ProxyCommandBase.cs @@ -2,6 +2,7 @@ using System.IO; using System.Text; using System.Threading.Tasks; +using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging.Abstractions; using Microsoft.Extensions.Options; @@ -19,11 +20,11 @@ public abstract class ProxyCommandBase : IConsoleCommand, ITransientDependenc protected AbpCliServiceProxyOptions ServiceProxyOptions { get; } - protected IHybridServiceScopeFactory ServiceScopeFactory { get; } + protected IServiceScopeFactory ServiceScopeFactory { get; } public ProxyCommandBase( IOptions serviceProxyOptions, - IHybridServiceScopeFactory serviceScopeFactory) + IServiceScopeFactory serviceScopeFactory) { ServiceScopeFactory = serviceScopeFactory; ServiceProxyOptions = serviceProxyOptions.Value; diff --git a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Commands/RemoveProxyCommand.cs b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Commands/RemoveProxyCommand.cs index d89c19c892..3372584f1a 100644 --- a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Commands/RemoveProxyCommand.cs +++ b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Commands/RemoveProxyCommand.cs @@ -1,4 +1,5 @@ using System.Text; +using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Options; using Volo.Abp.Cli.ServiceProxying; using Volo.Abp.DependencyInjection; @@ -13,7 +14,7 @@ public class RemoveProxyCommand : ProxyCommandBase public RemoveProxyCommand( IOptions serviceProxyOptions, - IHybridServiceScopeFactory serviceScopeFactory) + IServiceScopeFactory serviceScopeFactory) : base(serviceProxyOptions, serviceScopeFactory) { } diff --git a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectModification/SolutionModuleAdder.cs b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectModification/SolutionModuleAdder.cs index 7f2831351a..ed90d16cfd 100644 --- a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectModification/SolutionModuleAdder.cs +++ b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectModification/SolutionModuleAdder.cs @@ -153,7 +153,7 @@ public class SolutionModuleAdder : ITransientDependency var documentationLink = module.GetFirstDocumentationLinkOrNull(); if (documentationLink != null) { - CmdHelper.OpenWebPage(documentationLink); + CmdHelper.Open(documentationLink); } return module; diff --git a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Utils/CmdHelper.cs b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Utils/CmdHelper.cs index c6325a4681..32c1acf5be 100644 --- a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Utils/CmdHelper.cs +++ b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Utils/CmdHelper.cs @@ -2,6 +2,7 @@ using System.Diagnostics; using System.IO; using System.Runtime.InteropServices; +using Microsoft.Extensions.Options; using Volo.Abp.DependencyInjection; namespace Volo.Abp.Cli.Utils; @@ -10,27 +11,39 @@ public class CmdHelper : ICmdHelper, ITransientDependency { private const int SuccessfulExitCode = 0; - public void OpenWebPage(string url) + protected AbpCliOptions CliOptions { get; } + + public CmdHelper(IOptionsSnapshot cliOptions) + { + CliOptions = cliOptions.Value; + } + + public void Open(string pathOrUrl) { if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) { - url = url.Replace("&", "^&"); - Process.Start(new ProcessStartInfo("cmd", $"/c start {url}") { CreateNoWindow = true }); + pathOrUrl = pathOrUrl.Replace("&", "^&"); + Process.Start(new ProcessStartInfo("cmd", $"/c start {pathOrUrl}") { CreateNoWindow = true }); } else if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux)) { - Process.Start("xdg-open", url); + Process.Start("xdg-open", pathOrUrl); } else if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX)) { - Process.Start("open", url); + Process.Start("open", pathOrUrl); } } - public void Run(string file, string arguments) { var procStartInfo = new ProcessStartInfo(file, arguments); + + if (CliOptions.AlwaysHideExternalCommandOutput) + { + HideNewCommandWindow(procStartInfo); + } + Process.Start(procStartInfo)?.WaitForExit(); } @@ -46,6 +59,11 @@ public class CmdHelper : ICmdHelper, ITransientDependency GetArguments(command) ); + if (CliOptions.AlwaysHideExternalCommandOutput) + { + HideNewCommandWindow(procStartInfo); + } + if (!string.IsNullOrEmpty(workingDirectory)) { procStartInfo.WorkingDirectory = workingDirectory; @@ -66,10 +84,14 @@ public class CmdHelper : ICmdHelper, ITransientDependency GetArguments(command) ); + if (CliOptions.AlwaysHideExternalCommandOutput) + { + HideNewCommandWindow(procStartInfo); + } + if (!string.IsNullOrEmpty(workingDirectory)) { procStartInfo.WorkingDirectory = workingDirectory; - procStartInfo.CreateNoWindow = false; } return Process.Start(procStartInfo); @@ -98,6 +120,7 @@ public class CmdHelper : ICmdHelper, ITransientDependency Arguments = GetArguments(command), UseShellExecute = false, CreateNoWindow = true, + WindowStyle = ProcessWindowStyle.Hidden, RedirectStandardOutput = true, RedirectStandardError = true }; @@ -137,6 +160,11 @@ public class CmdHelper : ICmdHelper, ITransientDependency { procStartInfo.WorkingDirectory = workingDirectory; } + + if (CliOptions.AlwaysHideExternalCommandOutput) + { + HideNewCommandWindow(procStartInfo); + } Process.Start(procStartInfo); Environment.Exit(0); @@ -178,4 +206,10 @@ public class CmdHelper : ICmdHelper, ITransientDependency $"Framework: {System.Runtime.InteropServices.RuntimeInformation.FrameworkDescription} | " + $"Process Architecture{System.Runtime.InteropServices.RuntimeInformation.ProcessArchitecture}"); } + + private void HideNewCommandWindow(ProcessStartInfo procStartInfo) + { + procStartInfo.WindowStyle = ProcessWindowStyle.Hidden; + procStartInfo.CreateNoWindow = true; + } } diff --git a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Utils/ICmdHelper.cs b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Utils/ICmdHelper.cs index f96697b1cc..2f71bda7b5 100644 --- a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Utils/ICmdHelper.cs +++ b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Utils/ICmdHelper.cs @@ -4,7 +4,7 @@ namespace Volo.Abp.Cli.Utils; public interface ICmdHelper { - void OpenWebPage(string url); + void Open(string pathOrUrl); void Run(string file, string arguments); diff --git a/framework/src/Volo.Abp.Core/Microsoft/Extensions/Configuration/AbpConfigurationBuilderOptions.cs b/framework/src/Volo.Abp.Core/Microsoft/Extensions/Configuration/AbpConfigurationBuilderOptions.cs index f922f2b7da..f9f2ca23ad 100644 --- a/framework/src/Volo.Abp.Core/Microsoft/Extensions/Configuration/AbpConfigurationBuilderOptions.cs +++ b/framework/src/Volo.Abp.Core/Microsoft/Extensions/Configuration/AbpConfigurationBuilderOptions.cs @@ -21,6 +21,16 @@ public class AbpConfigurationBuilderOptions /// public string FileName { get; set; } = "appsettings"; + /// + /// Whether the file is optional, Default value: true. + /// + public bool Optional { get; set; } = true; + + /// + /// Whether the configuration should be reloaded if the file changes, Default value: true. + /// + public bool ReloadOnChange { get; set; } = true; + /// /// Environment name. Generally used "Development", "Staging" or "Production". /// diff --git a/framework/src/Volo.Abp.Core/Microsoft/Extensions/Configuration/ConfigurationHelper.cs b/framework/src/Volo.Abp.Core/Microsoft/Extensions/Configuration/ConfigurationHelper.cs index a4dfa48db8..28ea8326ac 100644 --- a/framework/src/Volo.Abp.Core/Microsoft/Extensions/Configuration/ConfigurationHelper.cs +++ b/framework/src/Volo.Abp.Core/Microsoft/Extensions/Configuration/ConfigurationHelper.cs @@ -9,7 +9,7 @@ public static class ConfigurationHelper AbpConfigurationBuilderOptions options = null, Action builderAction = null) { - options = options ?? new AbpConfigurationBuilderOptions(); + options ??= new AbpConfigurationBuilderOptions(); if (options.BasePath.IsNullOrEmpty()) { @@ -18,11 +18,11 @@ public static class ConfigurationHelper var builder = new ConfigurationBuilder() .SetBasePath(options.BasePath) - .AddJsonFile(options.FileName + ".json", optional: true, reloadOnChange: true); + .AddJsonFile(options.FileName + ".json", optional: options.Optional, reloadOnChange: options.ReloadOnChange); if (!options.EnvironmentName.IsNullOrEmpty()) { - builder = builder.AddJsonFile($"{options.FileName}.{options.EnvironmentName}.json", optional: true, reloadOnChange: true); + builder = builder.AddJsonFile($"{options.FileName}.{options.EnvironmentName}.json", optional: options.Optional, reloadOnChange: options.ReloadOnChange); } if (options.EnvironmentName == "Development") diff --git a/framework/src/Volo.Abp.Core/Microsoft/Extensions/DependencyInjection/ServiceCollectionApplicationExtensions.cs b/framework/src/Volo.Abp.Core/Microsoft/Extensions/DependencyInjection/ServiceCollectionApplicationExtensions.cs index ce4af2befa..72ce661ed5 100644 --- a/framework/src/Volo.Abp.Core/Microsoft/Extensions/DependencyInjection/ServiceCollectionApplicationExtensions.cs +++ b/framework/src/Volo.Abp.Core/Microsoft/Extensions/DependencyInjection/ServiceCollectionApplicationExtensions.cs @@ -39,4 +39,10 @@ public static class ServiceCollectionApplicationExtensions { return await AbpApplicationFactory.CreateAsync(startupModuleType, services, optionsAction); } + + [CanBeNull] + public static string GetApplicationName(this IServiceCollection services) + { + return services.GetSingletonInstance().ApplicationName; + } } diff --git a/framework/src/Volo.Abp.Core/Volo/Abp/AbpApplicationBase.cs b/framework/src/Volo.Abp.Core/Volo/Abp/AbpApplicationBase.cs index 741f6f0586..87ddf14c1b 100644 --- a/framework/src/Volo.Abp.Core/Volo/Abp/AbpApplicationBase.cs +++ b/framework/src/Volo.Abp.Core/Volo/Abp/AbpApplicationBase.cs @@ -23,6 +23,8 @@ public abstract class AbpApplicationBase : IAbpApplication public IServiceCollection Services { get; } public IReadOnlyList Modules { get; } + + public string ApplicationName { get; } private bool _configuredServices; @@ -41,8 +43,11 @@ public abstract class AbpApplicationBase : IAbpApplication var options = new AbpApplicationCreationOptions(services); optionsAction?.Invoke(options); + + ApplicationName = options.ApplicationName; services.AddSingleton(this); + services.AddSingleton(this); services.AddSingleton(this); services.AddCoreServices(); diff --git a/framework/src/Volo.Abp.Core/Volo/Abp/AbpApplicationCreationOptions.cs b/framework/src/Volo.Abp.Core/Volo/Abp/AbpApplicationCreationOptions.cs index d18e43275b..24a1bf8ee6 100644 --- a/framework/src/Volo.Abp.Core/Volo/Abp/AbpApplicationCreationOptions.cs +++ b/framework/src/Volo.Abp.Core/Volo/Abp/AbpApplicationCreationOptions.cs @@ -20,6 +20,9 @@ public class AbpApplicationCreationOptions public AbpConfigurationBuilderOptions Configuration { get; } public bool SkipConfigureServices { get; set; } + + [CanBeNull] + public string ApplicationName { get; set; } public AbpApplicationCreationOptions([NotNull] IServiceCollection services) { diff --git a/framework/src/Volo.Abp.Core/Volo/Abp/AbpApplicationWithInternalServiceProvider.cs b/framework/src/Volo.Abp.Core/Volo/Abp/AbpApplicationWithInternalServiceProvider.cs index 245ce6fb06..5f09157fcc 100644 --- a/framework/src/Volo.Abp.Core/Volo/Abp/AbpApplicationWithInternalServiceProvider.cs +++ b/framework/src/Volo.Abp.Core/Volo/Abp/AbpApplicationWithInternalServiceProvider.cs @@ -60,6 +60,6 @@ internal class AbpApplicationWithInternalServiceProvider : AbpApplicationBase, I public override void Dispose() { base.Dispose(); - ServiceScope.Dispose(); + ServiceScope?.Dispose(); } } diff --git a/framework/src/Volo.Abp.Core/Volo/Abp/DependencyInjection/DefaultServiceScopeFactory.cs b/framework/src/Volo.Abp.Core/Volo/Abp/DependencyInjection/DefaultServiceScopeFactory.cs deleted file mode 100644 index befcf7951e..0000000000 --- a/framework/src/Volo.Abp.Core/Volo/Abp/DependencyInjection/DefaultServiceScopeFactory.cs +++ /dev/null @@ -1,22 +0,0 @@ -using Microsoft.Extensions.DependencyInjection; - -namespace Volo.Abp.DependencyInjection; - -[ExposeServices( - typeof(IHybridServiceScopeFactory), - typeof(DefaultServiceScopeFactory) - )] -public class DefaultServiceScopeFactory : IHybridServiceScopeFactory, ITransientDependency -{ - protected IServiceScopeFactory Factory { get; } - - public DefaultServiceScopeFactory(IServiceScopeFactory factory) - { - Factory = factory; - } - - public IServiceScope CreateScope() - { - return Factory.CreateScope(); - } -} diff --git a/framework/src/Volo.Abp.Core/Volo/Abp/DependencyInjection/DisablePropertyInjectionAttribute.cs b/framework/src/Volo.Abp.Core/Volo/Abp/DependencyInjection/DisablePropertyInjectionAttribute.cs new file mode 100644 index 0000000000..fad0d7334a --- /dev/null +++ b/framework/src/Volo.Abp.Core/Volo/Abp/DependencyInjection/DisablePropertyInjectionAttribute.cs @@ -0,0 +1,9 @@ +using System; + +namespace Volo.Abp.DependencyInjection; + +[AttributeUsage(AttributeTargets.Class | AttributeTargets.Property)] +public class DisablePropertyInjectionAttribute : Attribute +{ + +} diff --git a/framework/src/Volo.Abp.Core/Volo/Abp/DependencyInjection/IHybridServiceScopeFactory.cs b/framework/src/Volo.Abp.Core/Volo/Abp/DependencyInjection/IHybridServiceScopeFactory.cs deleted file mode 100644 index 62c3707352..0000000000 --- a/framework/src/Volo.Abp.Core/Volo/Abp/DependencyInjection/IHybridServiceScopeFactory.cs +++ /dev/null @@ -1,8 +0,0 @@ -using Microsoft.Extensions.DependencyInjection; - -namespace Volo.Abp.DependencyInjection; - -public interface IHybridServiceScopeFactory : IServiceScopeFactory -{ - -} diff --git a/framework/src/Volo.Abp.Core/Volo/Abp/DependencyInjection/IRootServiceProviderAccessor.cs b/framework/src/Volo.Abp.Core/Volo/Abp/DependencyInjection/IRootServiceProviderAccessor.cs new file mode 100644 index 0000000000..8a3c1d09a5 --- /dev/null +++ b/framework/src/Volo.Abp.Core/Volo/Abp/DependencyInjection/IRootServiceProviderAccessor.cs @@ -0,0 +1,14 @@ +using System; + +namespace Volo.Abp.DependencyInjection; + +/// +/// The root service provider of the application. +/// Be careful to use the root service provider since there is no way +/// to release/dispose objects resolved from the root service provider. +/// So, always create a new scope if you need to resolve any service. +/// +public interface IRootServiceProvider : IServiceProvider +{ + +} \ No newline at end of file diff --git a/framework/src/Volo.Abp.Core/Volo/Abp/DependencyInjection/RootServiceProvider.cs b/framework/src/Volo.Abp.Core/Volo/Abp/DependencyInjection/RootServiceProvider.cs new file mode 100644 index 0000000000..cbb6fb8984 --- /dev/null +++ b/framework/src/Volo.Abp.Core/Volo/Abp/DependencyInjection/RootServiceProvider.cs @@ -0,0 +1,19 @@ +using System; + +namespace Volo.Abp.DependencyInjection; + +[ExposeServices(typeof(IRootServiceProvider))] +public class RootServiceProvider : IRootServiceProvider, ISingletonDependency +{ + protected IServiceProvider ServiceProvider { get; } + + public RootServiceProvider(IObjectAccessor objectAccessor) + { + ServiceProvider = objectAccessor.Value; + } + + public virtual object GetService(Type serviceType) + { + return ServiceProvider.GetService(serviceType); + } +} \ No newline at end of file diff --git a/framework/src/Volo.Abp.Core/Volo/Abp/IAbpApplication.cs b/framework/src/Volo.Abp.Core/Volo/Abp/IAbpApplication.cs index 2fb66b735f..35542ee91f 100644 --- a/framework/src/Volo.Abp.Core/Volo/Abp/IAbpApplication.cs +++ b/framework/src/Volo.Abp.Core/Volo/Abp/IAbpApplication.cs @@ -5,7 +5,10 @@ using Volo.Abp.Modularity; namespace Volo.Abp; -public interface IAbpApplication : IModuleContainer, IDisposable +public interface IAbpApplication : + IModuleContainer, + IApplicationNameAccessor, + IDisposable { /// /// Type of the startup (entrance) module of the application. @@ -23,7 +26,7 @@ public interface IAbpApplication : IModuleContainer, IDisposable /// This can not be used before initialize the application. /// IServiceProvider ServiceProvider { get; } - + /// /// Calls the Pre/Post/ConfigureServicesAsync methods of the modules. /// If you use this method, you must have set the @@ -40,4 +43,4 @@ public interface IAbpApplication : IModuleContainer, IDisposable /// Used to gracefully shutdown the application and all modules. /// void Shutdown(); -} +} \ No newline at end of file diff --git a/framework/src/Volo.Abp.Core/Volo/Abp/IApplicationNameAccessor.cs b/framework/src/Volo.Abp.Core/Volo/Abp/IApplicationNameAccessor.cs new file mode 100644 index 0000000000..0047fcbcdf --- /dev/null +++ b/framework/src/Volo.Abp.Core/Volo/Abp/IApplicationNameAccessor.cs @@ -0,0 +1,11 @@ +namespace Volo.Abp; + +public interface IApplicationNameAccessor +{ + /// + /// Name of the application. + /// This is useful for systems with multiple applications, to distinguish + /// resources of the applications located together. + /// + string ApplicationName { get; } +} \ No newline at end of file diff --git a/framework/src/Volo.Abp.Core/Volo/Abp/ISoftDelete.cs b/framework/src/Volo.Abp.Core/Volo/Abp/ISoftDelete.cs index 1d7ba66d81..704dd3ba11 100644 --- a/framework/src/Volo.Abp.Core/Volo/Abp/ISoftDelete.cs +++ b/framework/src/Volo.Abp.Core/Volo/Abp/ISoftDelete.cs @@ -9,7 +9,7 @@ public interface ISoftDelete { /// - /// Used to mark an Entity as 'Deleted'. + /// Used to mark an Entity as 'Deleted'. /// - bool IsDeleted { get; set; } + bool IsDeleted { get; } } diff --git a/framework/src/Volo.Abp.Core/Volo/Abp/SimpleStateChecking/ISimpleStateChecker.cs b/framework/src/Volo.Abp.Core/Volo/Abp/SimpleStateChecking/ISimpleStateChecker.cs index f1a2e40425..e919b981a6 100644 --- a/framework/src/Volo.Abp.Core/Volo/Abp/SimpleStateChecking/ISimpleStateChecker.cs +++ b/framework/src/Volo.Abp.Core/Volo/Abp/SimpleStateChecking/ISimpleStateChecker.cs @@ -6,4 +6,4 @@ public interface ISimpleStateChecker where TState : IHasSimpleStateCheckers { Task IsEnabledAsync(SimpleStateCheckerContext context); -} +} \ No newline at end of file diff --git a/framework/src/Volo.Abp.Core/Volo/Abp/SimpleStateChecking/ISimpleStateCheckerSerializer.cs b/framework/src/Volo.Abp.Core/Volo/Abp/SimpleStateChecking/ISimpleStateCheckerSerializer.cs new file mode 100644 index 0000000000..ffbed53cf7 --- /dev/null +++ b/framework/src/Volo.Abp.Core/Volo/Abp/SimpleStateChecking/ISimpleStateCheckerSerializer.cs @@ -0,0 +1,12 @@ +using System.Text.Json.Nodes; + +namespace Volo.Abp.SimpleStateChecking; + +public interface ISimpleStateCheckerSerializer +{ + public string Serialize(ISimpleStateChecker checker) + where TState : IHasSimpleStateCheckers; + + public ISimpleStateChecker Deserialize(JsonObject jsonObject, TState state) + where TState : IHasSimpleStateCheckers; +} \ No newline at end of file diff --git a/framework/src/Volo.Abp.Core/Volo/Abp/SimpleStateChecking/ISimpleStateCheckerSerializerContributor.cs b/framework/src/Volo.Abp.Core/Volo/Abp/SimpleStateChecking/ISimpleStateCheckerSerializerContributor.cs new file mode 100644 index 0000000000..d65c90eee6 --- /dev/null +++ b/framework/src/Volo.Abp.Core/Volo/Abp/SimpleStateChecking/ISimpleStateCheckerSerializerContributor.cs @@ -0,0 +1,15 @@ +using System.Text.Json.Nodes; +using JetBrains.Annotations; + +namespace Volo.Abp.SimpleStateChecking; + +public interface ISimpleStateCheckerSerializerContributor +{ + [CanBeNull] + public string SerializeToJson(ISimpleStateChecker checker) + where TState : IHasSimpleStateCheckers; + + [CanBeNull] + public ISimpleStateChecker Deserialize(JsonObject jsonObject, TState state) + where TState : IHasSimpleStateCheckers; +} \ No newline at end of file diff --git a/framework/src/Volo.Abp.Core/Volo/Abp/SimpleStateChecking/SimpleStateCheckerSerializer.cs b/framework/src/Volo.Abp.Core/Volo/Abp/SimpleStateChecking/SimpleStateCheckerSerializer.cs new file mode 100644 index 0000000000..d5d931ffae --- /dev/null +++ b/framework/src/Volo.Abp.Core/Volo/Abp/SimpleStateChecking/SimpleStateCheckerSerializer.cs @@ -0,0 +1,50 @@ +using System.Collections.Generic; +using System.Text.Json.Nodes; +using JetBrains.Annotations; +using Volo.Abp.DependencyInjection; + +namespace Volo.Abp.SimpleStateChecking; + +public class SimpleStateCheckerSerializer : + ISimpleStateCheckerSerializer, + ISingletonDependency +{ + private readonly IEnumerable _contributors; + + public SimpleStateCheckerSerializer(IEnumerable contributors) + { + _contributors = contributors; + } + + [CanBeNull] + public string Serialize(ISimpleStateChecker checker) + where TState : IHasSimpleStateCheckers + { + foreach (var contributor in _contributors) + { + var result = contributor.SerializeToJson(checker); + if (result != null) + { + return result; + } + } + + return null; + } + + [CanBeNull] + public ISimpleStateChecker Deserialize(JsonObject jsonObject, TState state) + where TState : IHasSimpleStateCheckers + { + foreach (var contributor in _contributors) + { + var result = contributor.Deserialize(jsonObject, state); + if (result != null) + { + return result; + } + } + + return null; + } +} \ No newline at end of file diff --git a/framework/src/Volo.Abp.Core/Volo/Abp/SimpleStateChecking/SimpleStateCheckerSerializerExtensions.cs b/framework/src/Volo.Abp.Core/Volo/Abp/SimpleStateChecking/SimpleStateCheckerSerializerExtensions.cs new file mode 100644 index 0000000000..3594261741 --- /dev/null +++ b/framework/src/Volo.Abp.Core/Volo/Abp/SimpleStateChecking/SimpleStateCheckerSerializerExtensions.cs @@ -0,0 +1,90 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text.Json.Nodes; + +namespace Volo.Abp.SimpleStateChecking; + +public static class SimpleStateCheckerSerializerExtensions +{ + public static string Serialize( + this ISimpleStateCheckerSerializer serializer, + IList> stateCheckers) + where TState : IHasSimpleStateCheckers + { + switch (stateCheckers.Count) + { + case 0: + return null; + case 1: + var serializedChecker = serializer.Serialize(stateCheckers.Single()); + return serializedChecker != null + ? $"[{serializedChecker}]" + : null; + default: + var serializedCheckers = new List(stateCheckers.Count); + + foreach (var stateChecker in stateCheckers) + { + var serialized = serializer.Serialize(stateChecker); + if (serialized != null) + { + serializedCheckers.Add(serialized); + } + } + + return serializedCheckers.Any() + ? $"[{serializedCheckers.JoinAsString(",")}]" + : null; + } + } + + public static ISimpleStateChecker[] DeserializeArray( + this ISimpleStateCheckerSerializer serializer, + string value, + TState state) + where TState : IHasSimpleStateCheckers + { + if (value.IsNullOrWhiteSpace()) + { + return Array.Empty>(); + } + + var array = JsonNode.Parse(value) as JsonArray; + if (array == null || array.Count == 0) + { + return Array.Empty>(); + } + + if (array.Count == 1) + { + var jsonObject = array[0] as JsonObject; + if (jsonObject == null) + { + throw new AbpException("JSON value is not an array of objects: " + value); + } + + var checker = serializer.Deserialize(jsonObject, state); + if (checker == null) + { + return Array.Empty>(); + } + + return new[] { checker }; + } + + var checkers = new List>(); + + for (var i = 0; i < array.Count; i++) + { + if (array[i] is not JsonObject jsonObject) + { + throw new AbpException("JSON value is not an array of objects: " + value); + } + + checkers.Add(serializer.Deserialize(jsonObject, state)); + } + + return checkers.Where(x => x != null).ToArray(); + } +} \ No newline at end of file diff --git a/framework/src/Volo.Abp.Dapr/FodyWeavers.xml b/framework/src/Volo.Abp.Dapr/FodyWeavers.xml new file mode 100644 index 0000000000..be0de3a908 --- /dev/null +++ b/framework/src/Volo.Abp.Dapr/FodyWeavers.xml @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/framework/src/Volo.Abp.Dapr/FodyWeavers.xsd b/framework/src/Volo.Abp.Dapr/FodyWeavers.xsd new file mode 100644 index 0000000000..3f3946e282 --- /dev/null +++ b/framework/src/Volo.Abp.Dapr/FodyWeavers.xsd @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + 'true' to run assembly verification (PEVerify) on the target assembly after all weavers have been executed. + + + + + A comma-separated list of error codes that can be safely ignored in assembly verification. + + + + + 'false' to turn off automatic generation of the XML Schema file. + + + + + \ No newline at end of file diff --git a/framework/src/Volo.Abp.Dapr/Volo.Abp.Dapr.csproj b/framework/src/Volo.Abp.Dapr/Volo.Abp.Dapr.csproj new file mode 100644 index 0000000000..d3a8651086 --- /dev/null +++ b/framework/src/Volo.Abp.Dapr/Volo.Abp.Dapr.csproj @@ -0,0 +1,21 @@ + + + + + + + net6.0 + enable + enable + + + + + + + + + + + + diff --git a/framework/src/Volo.Abp.Dapr/Volo/Abp/Dapr/AbpDaprClientFactory.cs b/framework/src/Volo.Abp.Dapr/Volo/Abp/Dapr/AbpDaprClientFactory.cs new file mode 100644 index 0000000000..faaf450ddc --- /dev/null +++ b/framework/src/Volo.Abp.Dapr/Volo/Abp/Dapr/AbpDaprClientFactory.cs @@ -0,0 +1,48 @@ +using System.Collections.Concurrent; +using System.Text.Json; +using Dapr.Client; +using Microsoft.Extensions.Options; +using Volo.Abp.DependencyInjection; +using Volo.Abp.Json.SystemTextJson; + +namespace Volo.Abp.Dapr; + +public class AbpDaprClientFactory : ITransientDependency +{ + protected AbpDaprOptions Options { get; } + protected AbpSystemTextJsonSerializerOptions SystemTextJsonSerializerOptions { get; } + + public AbpDaprClientFactory( + IOptions options, + IOptions systemTextJsonSerializerOptions) + { + Options = options.Value; + SystemTextJsonSerializerOptions = systemTextJsonSerializerOptions.Value; + } + + public virtual async Task CreateAsync() + { + var builder = new DaprClientBuilder() + .UseJsonSerializationOptions(await CreateJsonSerializerOptions()); + + if (!Options.HttpEndpoint.IsNullOrWhiteSpace()) + { + builder.UseHttpEndpoint(Options.HttpEndpoint); + } + + if (!Options.GrpcEndpoint.IsNullOrWhiteSpace()) + { + builder.UseGrpcEndpoint(Options.GrpcEndpoint); + } + + return builder.Build(); + } + + private readonly static ConcurrentDictionary JsonSerializerOptionsCache = new ConcurrentDictionary(); + + protected virtual Task CreateJsonSerializerOptions() + { + return Task.FromResult(JsonSerializerOptionsCache.GetOrAdd(nameof(AbpDaprClientFactory), + _ => new JsonSerializerOptions(SystemTextJsonSerializerOptions.JsonSerializerOptions))); + } +} diff --git a/framework/src/Volo.Abp.Dapr/Volo/Abp/Dapr/AbpDaprModule.cs b/framework/src/Volo.Abp.Dapr/Volo/Abp/Dapr/AbpDaprModule.cs new file mode 100644 index 0000000000..43d6d11033 --- /dev/null +++ b/framework/src/Volo.Abp.Dapr/Volo/Abp/Dapr/AbpDaprModule.cs @@ -0,0 +1,15 @@ +using Microsoft.Extensions.DependencyInjection; +using Volo.Abp.Json; +using Volo.Abp.Modularity; + +namespace Volo.Abp.Dapr; + +[DependsOn(typeof(AbpJsonModule))] +public class AbpDaprModule : AbpModule +{ + public override void ConfigureServices(ServiceConfigurationContext context) + { + var configuration = context.Services.GetConfiguration(); + Configure(configuration.GetSection("Dapr")); + } +} diff --git a/framework/src/Volo.Abp.Dapr/Volo/Abp/Dapr/AbpDaprOptions.cs b/framework/src/Volo.Abp.Dapr/Volo/Abp/Dapr/AbpDaprOptions.cs new file mode 100644 index 0000000000..9d743263c5 --- /dev/null +++ b/framework/src/Volo.Abp.Dapr/Volo/Abp/Dapr/AbpDaprOptions.cs @@ -0,0 +1,10 @@ +namespace Volo.Abp.Dapr; + +public class AbpDaprOptions +{ + public string AppId { get; set; } + + public string HttpEndpoint { get; set; } + + public string GrpcEndpoint { get; set; } +} diff --git a/framework/src/Volo.Abp.Dapr/Volo/Abp/Dapr/IDaprSerializer.cs b/framework/src/Volo.Abp.Dapr/Volo/Abp/Dapr/IDaprSerializer.cs new file mode 100644 index 0000000000..7eec2c5c1c --- /dev/null +++ b/framework/src/Volo.Abp.Dapr/Volo/Abp/Dapr/IDaprSerializer.cs @@ -0,0 +1,16 @@ +namespace Volo.Abp.Dapr; + +public interface IDaprSerializer +{ + byte[] Serialize(object obj); + + object Deserialize(byte[] value, Type type); + + T Deserialize(byte[] value); + + string SerializeToString(object obj); + + object Deserialize(string value, Type type); + + T Deserialize(string value); +} diff --git a/framework/src/Volo.Abp.Dapr/Volo/Abp/Dapr/Utf8JsonDaprSerializer.cs b/framework/src/Volo.Abp.Dapr/Volo/Abp/Dapr/Utf8JsonDaprSerializer.cs new file mode 100644 index 0000000000..ce9b4a8523 --- /dev/null +++ b/framework/src/Volo.Abp.Dapr/Volo/Abp/Dapr/Utf8JsonDaprSerializer.cs @@ -0,0 +1,45 @@ +using System.Text; +using Volo.Abp.DependencyInjection; +using Volo.Abp.Json; + +namespace Volo.Abp.Dapr; + +public class Utf8JsonDaprSerializer : IDaprSerializer, ITransientDependency +{ + private readonly IJsonSerializer _jsonSerializer; + + public Utf8JsonDaprSerializer(IJsonSerializer jsonSerializer) + { + _jsonSerializer = jsonSerializer; + } + + public byte[] Serialize(object obj) + { + return Encoding.UTF8.GetBytes(_jsonSerializer.Serialize(obj)); + } + + public object Deserialize(byte[] value, Type type) + { + return _jsonSerializer.Deserialize(type, Encoding.UTF8.GetString(value)); + } + + public T Deserialize(byte[] value) + { + return _jsonSerializer.Deserialize(Encoding.UTF8.GetString(value)); + } + + public string SerializeToString(object obj) + { + return _jsonSerializer.Serialize(obj); + } + + public object Deserialize(string value, Type type) + { + return _jsonSerializer.Deserialize(type, value); + } + + public T Deserialize(string value) + { + return _jsonSerializer.Deserialize(value); + } +} diff --git a/framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/Entities/Events/EntityChangeEventHelper.cs b/framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/Entities/Events/EntityChangeEventHelper.cs index 8f9be2318f..20556f16ff 100644 --- a/framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/Entities/Events/EntityChangeEventHelper.cs +++ b/framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/Entities/Events/EntityChangeEventHelper.cs @@ -42,18 +42,6 @@ public class EntityChangeEventHelper : IEntityChangeEventHelper, ITransientDepen Logger = NullLogger.Instance; } - public virtual void PublishEntityCreatingEvent(object entity) - { - TriggerEventWithEntity( - LocalEventBus, -#pragma warning disable 618 - typeof(EntityCreatingEventData<>), -#pragma warning restore 618 - entity, - entity - ); - } - public virtual void PublishEntityCreatedEvent(object entity) { TriggerEventWithEntity( @@ -89,18 +77,6 @@ public class EntityChangeEventHelper : IEntityChangeEventHelper, ITransientDepen ); } - public virtual void PublishEntityUpdatingEvent(object entity) - { - TriggerEventWithEntity( - LocalEventBus, -#pragma warning disable 618 - typeof(EntityUpdatingEventData<>), -#pragma warning restore 618 - entity, - entity - ); - } - public virtual void PublishEntityUpdatedEvent(object entity) { TriggerEventWithEntity( @@ -125,18 +101,6 @@ public class EntityChangeEventHelper : IEntityChangeEventHelper, ITransientDepen } } - public virtual void PublishEntityDeletingEvent(object entity) - { - TriggerEventWithEntity( - LocalEventBus, -#pragma warning disable 618 - typeof(EntityDeletingEventData<>), -#pragma warning restore 618 - entity, - entity - ); - } - public virtual void PublishEntityDeletedEvent(object entity) { TriggerEventWithEntity( diff --git a/framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/Entities/Events/EntityChangingEventData.cs b/framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/Entities/Events/EntityChangingEventData.cs deleted file mode 100644 index ae24163966..0000000000 --- a/framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/Entities/Events/EntityChangingEventData.cs +++ /dev/null @@ -1,23 +0,0 @@ -using System; - -namespace Volo.Abp.Domain.Entities.Events; - -/// -/// Used to pass data for an event when an entity () is being changed (creating, updating or deleting). -/// See , and classes. -/// -/// Entity type -[Serializable] -[Obsolete("This event is no longer needed and identical to EntityChangedEventData. Please use EntityChangedEventData instead.")] -public class EntityChangingEventData : EntityEventData -{ - /// - /// Constructor. - /// - /// Changing entity in this event - public EntityChangingEventData(TEntity entity) - : base(entity) - { - - } -} diff --git a/framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/Entities/Events/EntityCreatingEventData.cs b/framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/Entities/Events/EntityCreatingEventData.cs deleted file mode 100644 index 914c8ca7c7..0000000000 --- a/framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/Entities/Events/EntityCreatingEventData.cs +++ /dev/null @@ -1,22 +0,0 @@ -using System; - -namespace Volo.Abp.Domain.Entities.Events; - -/// -/// This type of event is used to notify just before creation of an Entity. -/// -/// Entity type -[Serializable] -[Obsolete("This event is no longer needed and identical to EntityCreatedEventData. Please use EntityCreatedEventData instead.")] -public class EntityCreatingEventData : EntityChangingEventData -{ - /// - /// Constructor. - /// - /// The entity which is being created - public EntityCreatingEventData(TEntity entity) - : base(entity) - { - - } -} diff --git a/framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/Entities/Events/EntityDeletingEventData.cs b/framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/Entities/Events/EntityDeletingEventData.cs deleted file mode 100644 index af0d1218f7..0000000000 --- a/framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/Entities/Events/EntityDeletingEventData.cs +++ /dev/null @@ -1,22 +0,0 @@ -using System; - -namespace Volo.Abp.Domain.Entities.Events; - -/// -/// This type of event is used to notify just before deletion of an Entity. -/// -/// Entity type -[Serializable] -[Obsolete("This event is no longer needed and identical to EntityDeletedEventData. Please use EntityDeletedEventData instead.")] -public class EntityDeletingEventData : EntityChangingEventData -{ - /// - /// Constructor. - /// - /// The entity which is being deleted - public EntityDeletingEventData(TEntity entity) - : base(entity) - { - - } -} diff --git a/framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/Entities/Events/EntityUpdatingEventData.cs b/framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/Entities/Events/EntityUpdatingEventData.cs deleted file mode 100644 index 703304fefb..0000000000 --- a/framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/Entities/Events/EntityUpdatingEventData.cs +++ /dev/null @@ -1,22 +0,0 @@ -using System; - -namespace Volo.Abp.Domain.Entities.Events; - -/// -/// This type of event is used to notify just before update of an Entity. -/// -/// Entity type -[Serializable] -[Obsolete("This event is no longer needed and identical to EntityUpdatedEventData. Please use EntityUpdatedEventData instead.")] -public class EntityUpdatingEventData : EntityChangingEventData -{ - /// - /// Constructor. - /// - /// The entity which is being updated - public EntityUpdatingEventData(TEntity entity) - : base(entity) - { - - } -} diff --git a/framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/Entities/Events/IEntityChangeEventHelper.cs b/framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/Entities/Events/IEntityChangeEventHelper.cs index db580a0682..aa63c7e3c9 100644 --- a/framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/Entities/Events/IEntityChangeEventHelper.cs +++ b/framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/Entities/Events/IEntityChangeEventHelper.cs @@ -5,12 +5,9 @@ namespace Volo.Abp.Domain.Entities.Events; /// public interface IEntityChangeEventHelper { - void PublishEntityCreatingEvent(object entity); void PublishEntityCreatedEvent(object entity); - void PublishEntityUpdatingEvent(object entity); void PublishEntityUpdatedEvent(object entity); - void PublishEntityDeletingEvent(object entity); void PublishEntityDeletedEvent(object entity); } diff --git a/framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/Entities/Events/NullEntityChangeEventHelper.cs b/framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/Entities/Events/NullEntityChangeEventHelper.cs index d428f84d6f..4d849f2f27 100644 --- a/framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/Entities/Events/NullEntityChangeEventHelper.cs +++ b/framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/Entities/Events/NullEntityChangeEventHelper.cs @@ -14,26 +14,14 @@ public class NullEntityChangeEventHelper : IEntityChangeEventHelper { } - public void PublishEntityCreatingEvent(object entity) - { - } - public void PublishEntityCreatedEvent(object entity) { } - public void PublishEntityUpdatingEvent(object entity) - { - } - public void PublishEntityUpdatedEvent(object entity) { } - public void PublishEntityDeletingEvent(object entity) - { - } - public void PublishEntityDeletedEvent(object entity) { } diff --git a/framework/src/Volo.Abp.DistributedLocking.Dapr/FodyWeavers.xml b/framework/src/Volo.Abp.DistributedLocking.Dapr/FodyWeavers.xml new file mode 100644 index 0000000000..be0de3a908 --- /dev/null +++ b/framework/src/Volo.Abp.DistributedLocking.Dapr/FodyWeavers.xml @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/framework/src/Volo.Abp.DistributedLocking.Dapr/FodyWeavers.xsd b/framework/src/Volo.Abp.DistributedLocking.Dapr/FodyWeavers.xsd new file mode 100644 index 0000000000..3f3946e282 --- /dev/null +++ b/framework/src/Volo.Abp.DistributedLocking.Dapr/FodyWeavers.xsd @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + 'true' to run assembly verification (PEVerify) on the target assembly after all weavers have been executed. + + + + + A comma-separated list of error codes that can be safely ignored in assembly verification. + + + + + 'false' to turn off automatic generation of the XML Schema file. + + + + + \ No newline at end of file diff --git a/framework/src/Volo.Abp.DistributedLocking.Dapr/Volo.Abp.DistributedLocking.Dapr.csproj b/framework/src/Volo.Abp.DistributedLocking.Dapr/Volo.Abp.DistributedLocking.Dapr.csproj new file mode 100644 index 0000000000..80cad677a3 --- /dev/null +++ b/framework/src/Volo.Abp.DistributedLocking.Dapr/Volo.Abp.DistributedLocking.Dapr.csproj @@ -0,0 +1,18 @@ + + + + + + + net6.0 + enable + enable + + + + + + + + + diff --git a/framework/src/Volo.Abp.DistributedLocking.Dapr/Volo/Abp/DistributedLocking/Dapr/AbpDistributedLockDaprOptions.cs b/framework/src/Volo.Abp.DistributedLocking.Dapr/Volo/Abp/DistributedLocking/Dapr/AbpDistributedLockDaprOptions.cs new file mode 100644 index 0000000000..43feba3c3b --- /dev/null +++ b/framework/src/Volo.Abp.DistributedLocking.Dapr/Volo/Abp/DistributedLocking/Dapr/AbpDistributedLockDaprOptions.cs @@ -0,0 +1,13 @@ +namespace Volo.Abp.DistributedLocking.Dapr; + +public class AbpDistributedLockDaprOptions +{ + public string StoreName { get; set; } + + public TimeSpan DefaultTimeout { get; set; } + + public AbpDistributedLockDaprOptions() + { + DefaultTimeout = TimeSpan.FromSeconds(30); + } +} \ No newline at end of file diff --git a/framework/src/Volo.Abp.DistributedLocking.Dapr/Volo/Abp/DistributedLocking/Dapr/AbpDistributedLockingDaprModule.cs b/framework/src/Volo.Abp.DistributedLocking.Dapr/Volo/Abp/DistributedLocking/Dapr/AbpDistributedLockingDaprModule.cs new file mode 100644 index 0000000000..c915cfe2f7 --- /dev/null +++ b/framework/src/Volo.Abp.DistributedLocking.Dapr/Volo/Abp/DistributedLocking/Dapr/AbpDistributedLockingDaprModule.cs @@ -0,0 +1,11 @@ +using Volo.Abp.Dapr; +using Volo.Abp.Modularity; + +namespace Volo.Abp.DistributedLocking.Dapr; + +[DependsOn( + typeof(AbpDistributedLockingAbstractionsModule), + typeof(AbpDaprModule))] +public class AbpDistributedLockingDaprModule : AbpModule +{ +} \ No newline at end of file diff --git a/framework/src/Volo.Abp.DistributedLocking.Dapr/Volo/Abp/DistributedLocking/Dapr/DaprAbpDistributedLock.cs b/framework/src/Volo.Abp.DistributedLocking.Dapr/Volo/Abp/DistributedLocking/Dapr/DaprAbpDistributedLock.cs new file mode 100644 index 0000000000..7f95a56542 --- /dev/null +++ b/framework/src/Volo.Abp.DistributedLocking.Dapr/Volo/Abp/DistributedLocking/Dapr/DaprAbpDistributedLock.cs @@ -0,0 +1,50 @@ +using Microsoft.Extensions.Options; +using Volo.Abp.Dapr; +using Volo.Abp.DependencyInjection; + +namespace Volo.Abp.DistributedLocking.Dapr; + +[Dependency(ReplaceServices = true)] +public class DaprAbpDistributedLock : IAbpDistributedLock, ITransientDependency +{ + protected AbpDaprClientFactory DaprClientFactory { get; } + protected AbpDistributedLockDaprOptions DistributedLockDaprOptions { get; } + protected AbpDaprOptions DaprOptions { get; } + + public DaprAbpDistributedLock( + AbpDaprClientFactory daprClientFactory, + IOptions distributedLockDaprOptions, + IOptions daprOptions) + { + DaprClientFactory = daprClientFactory; + DaprOptions = daprOptions.Value; + DistributedLockDaprOptions = distributedLockDaprOptions.Value; + } + + public async Task TryAcquireAsync( + string name, + TimeSpan timeout = default, + CancellationToken cancellationToken = default) + { + if (timeout == default) + { + timeout = DistributedLockDaprOptions.DefaultTimeout; + } + + var daprClient = await DaprClientFactory.CreateAsync(); + + var lockResponse = await daprClient.Lock( + DistributedLockDaprOptions.StoreName, + name, + DaprOptions.AppId, + (int)timeout.TotalSeconds, + cancellationToken); + + if (lockResponse == null || !lockResponse.Success) + { + return null; + } + + return new DaprAbpDistributedLockHandle(lockResponse); + } +} \ No newline at end of file diff --git a/framework/src/Volo.Abp.DistributedLocking.Dapr/Volo/Abp/DistributedLocking/Dapr/DaprAbpDistributedLockHandle.cs b/framework/src/Volo.Abp.DistributedLocking.Dapr/Volo/Abp/DistributedLocking/Dapr/DaprAbpDistributedLockHandle.cs new file mode 100644 index 0000000000..b10f0f3672 --- /dev/null +++ b/framework/src/Volo.Abp.DistributedLocking.Dapr/Volo/Abp/DistributedLocking/Dapr/DaprAbpDistributedLockHandle.cs @@ -0,0 +1,18 @@ +using Dapr.Client; + +namespace Volo.Abp.DistributedLocking.Dapr; + +public class DaprAbpDistributedLockHandle : IAbpDistributedLockHandle +{ + protected TryLockResponse LockResponse { get; } + + public DaprAbpDistributedLockHandle(TryLockResponse lockResponse) + { + LockResponse = lockResponse; + } + + public async ValueTask DisposeAsync() + { + await LockResponse.DisposeAsync(); + } +} \ No newline at end of file diff --git a/framework/src/Volo.Abp.DistributedLocking/Volo.Abp.DistributedLocking.csproj b/framework/src/Volo.Abp.DistributedLocking/Volo.Abp.DistributedLocking.csproj index fd9b992133..0abb5e699c 100644 --- a/framework/src/Volo.Abp.DistributedLocking/Volo.Abp.DistributedLocking.csproj +++ b/framework/src/Volo.Abp.DistributedLocking/Volo.Abp.DistributedLocking.csproj @@ -16,6 +16,7 @@ + diff --git a/framework/src/Volo.Abp.DistributedLocking/Volo/Abp/DistributedLocking/AbpDistributedLockingModule.cs b/framework/src/Volo.Abp.DistributedLocking/Volo/Abp/DistributedLocking/AbpDistributedLockingModule.cs index 4c4abd3f32..eef5b396a2 100644 --- a/framework/src/Volo.Abp.DistributedLocking/Volo/Abp/DistributedLocking/AbpDistributedLockingModule.cs +++ b/framework/src/Volo.Abp.DistributedLocking/Volo/Abp/DistributedLocking/AbpDistributedLockingModule.cs @@ -1,11 +1,12 @@ using Volo.Abp.Modularity; +using Volo.Abp.Threading; namespace Volo.Abp.DistributedLocking; [DependsOn( - typeof(AbpDistributedLockingAbstractionsModule) + typeof(AbpDistributedLockingAbstractionsModule), + typeof(AbpThreadingModule) )] public class AbpDistributedLockingModule : AbpModule { - } diff --git a/framework/src/Volo.Abp.DistributedLocking/Volo/Abp/DistributedLocking/MedallionAbpDistributedLock.cs b/framework/src/Volo.Abp.DistributedLocking/Volo/Abp/DistributedLocking/MedallionAbpDistributedLock.cs index e78f1934c1..769303a348 100644 --- a/framework/src/Volo.Abp.DistributedLocking/Volo/Abp/DistributedLocking/MedallionAbpDistributedLock.cs +++ b/framework/src/Volo.Abp.DistributedLocking/Volo/Abp/DistributedLocking/MedallionAbpDistributedLock.cs @@ -3,6 +3,7 @@ using System.Threading; using System.Threading.Tasks; using Medallion.Threading; using Volo.Abp.DependencyInjection; +using Volo.Abp.Threading; namespace Volo.Abp.DistributedLocking; @@ -10,10 +11,14 @@ namespace Volo.Abp.DistributedLocking; public class MedallionAbpDistributedLock : IAbpDistributedLock, ITransientDependency { protected IDistributedLockProvider DistributedLockProvider { get; } + protected ICancellationTokenProvider CancellationTokenProvider { get; } - public MedallionAbpDistributedLock(IDistributedLockProvider distributedLockProvider) + public MedallionAbpDistributedLock( + IDistributedLockProvider distributedLockProvider, + ICancellationTokenProvider cancellationTokenProvider) { DistributedLockProvider = distributedLockProvider; + CancellationTokenProvider = cancellationTokenProvider; } public async Task TryAcquireAsync( @@ -23,7 +28,14 @@ public class MedallionAbpDistributedLock : IAbpDistributedLock, ITransientDepend { Check.NotNullOrWhiteSpace(name, nameof(name)); - var handle = await DistributedLockProvider.TryAcquireLockAsync(name, timeout, cancellationToken); + CancellationTokenProvider.FallbackToProvider(cancellationToken); + + var handle = await DistributedLockProvider.TryAcquireLockAsync( + name, + timeout, + CancellationTokenProvider.FallbackToProvider(cancellationToken) + ); + if (handle == null) { return null; diff --git a/framework/src/Volo.Abp.Emailing/Volo/Abp/Emailing/Localization/pt-BR.json b/framework/src/Volo.Abp.Emailing/Volo/Abp/Emailing/Localization/pt-BR.json index b1f3878b88..c0d6227e48 100644 --- a/framework/src/Volo.Abp.Emailing/Volo/Abp/Emailing/Localization/pt-BR.json +++ b/framework/src/Volo.Abp.Emailing/Volo/Abp/Emailing/Localization/pt-BR.json @@ -9,7 +9,7 @@ "DisplayName:Abp.Mailing.Smtp.Password": "Senha", "DisplayName:Abp.Mailing.Smtp.Domain": "Domínio", "DisplayName:Abp.Mailing.Smtp.EnableSsl": "Habilitar SSL", - "DisplayName:Abp.Mailing.Smtp.UseDefaultCredentials": "Use credenciais padrão", + "DisplayName:Abp.Mailing.Smtp.UseDefaultCredentials": "Usar credenciais padrão", "Description:Abp.Mailing.DefaultFromAddress": "O endereço de origem padrão", "Description:Abp.Mailing.DefaultFromDisplayName": "O nome de exibição padrão", "Description:Abp.Mailing.Smtp.Host": "O nome ou endereço IP do host usado para transações SMTP.", diff --git a/framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/EntityFrameworkCore/AbpDbContext.cs b/framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/EntityFrameworkCore/AbpDbContext.cs index 1f55bce770..fd998510af 100644 --- a/framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/EntityFrameworkCore/AbpDbContext.cs +++ b/framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/EntityFrameworkCore/AbpDbContext.cs @@ -292,7 +292,6 @@ public abstract class AbpDbContext : DbContext, IAbpEfCoreDbContext, { case EntityState.Added: ApplyAbpConceptsForAddedEntity(entry); - EntityChangeEventHelper.PublishEntityCreatingEvent(entry.Entity); EntityChangeEventHelper.PublishEntityCreatedEvent(entry.Entity); break; case EntityState.Modified: @@ -301,12 +300,10 @@ public abstract class AbpDbContext : DbContext, IAbpEfCoreDbContext, { if (entry.Entity is ISoftDelete && entry.Entity.As().IsDeleted) { - EntityChangeEventHelper.PublishEntityDeletingEvent(entry.Entity); EntityChangeEventHelper.PublishEntityDeletedEvent(entry.Entity); } else { - EntityChangeEventHelper.PublishEntityUpdatingEvent(entry.Entity); EntityChangeEventHelper.PublishEntityUpdatedEvent(entry.Entity); } } @@ -314,7 +311,6 @@ public abstract class AbpDbContext : DbContext, IAbpEfCoreDbContext, break; case EntityState.Deleted: ApplyAbpConceptsForDeletedEntity(entry); - EntityChangeEventHelper.PublishEntityDeletingEvent(entry.Entity); EntityChangeEventHelper.PublishEntityDeletedEvent(entry.Entity); break; } @@ -485,7 +481,7 @@ public abstract class AbpDbContext : DbContext, IAbpEfCoreDbContext, } entry.Reload(); - entry.Entity.As().IsDeleted = true; + ObjectHelper.TrySetProperty(entry.Entity.As(), x => x.IsDeleted, () => true); SetDeletionAuditProperties(entry); } diff --git a/framework/src/Volo.Abp.EventBus.Dapr/FodyWeavers.xml b/framework/src/Volo.Abp.EventBus.Dapr/FodyWeavers.xml new file mode 100644 index 0000000000..be0de3a908 --- /dev/null +++ b/framework/src/Volo.Abp.EventBus.Dapr/FodyWeavers.xml @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/framework/src/Volo.Abp.EventBus.Dapr/FodyWeavers.xsd b/framework/src/Volo.Abp.EventBus.Dapr/FodyWeavers.xsd new file mode 100644 index 0000000000..3f3946e282 --- /dev/null +++ b/framework/src/Volo.Abp.EventBus.Dapr/FodyWeavers.xsd @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + 'true' to run assembly verification (PEVerify) on the target assembly after all weavers have been executed. + + + + + A comma-separated list of error codes that can be safely ignored in assembly verification. + + + + + 'false' to turn off automatic generation of the XML Schema file. + + + + + \ No newline at end of file diff --git a/framework/src/Volo.Abp.EventBus.Dapr/Volo.Abp.EventBus.Dapr.csproj b/framework/src/Volo.Abp.EventBus.Dapr/Volo.Abp.EventBus.Dapr.csproj new file mode 100644 index 0000000000..2bef3f9dc9 --- /dev/null +++ b/framework/src/Volo.Abp.EventBus.Dapr/Volo.Abp.EventBus.Dapr.csproj @@ -0,0 +1,18 @@ + + + + + + + net6.0 + enable + enable + + + + + + + + + diff --git a/framework/src/Volo.Abp.EventBus.Dapr/Volo/Abp/EventBus/Dapr/AbpDaprEventBusOptions.cs b/framework/src/Volo.Abp.EventBus.Dapr/Volo/Abp/EventBus/Dapr/AbpDaprEventBusOptions.cs new file mode 100644 index 0000000000..d3ced52ba2 --- /dev/null +++ b/framework/src/Volo.Abp.EventBus.Dapr/Volo/Abp/EventBus/Dapr/AbpDaprEventBusOptions.cs @@ -0,0 +1,11 @@ +namespace Volo.Abp.EventBus.Dapr; + +public class AbpDaprEventBusOptions +{ + public string PubSubName { get; set; } + + public AbpDaprEventBusOptions() + { + PubSubName = "pubsub"; + } +} diff --git a/framework/src/Volo.Abp.EventBus.Dapr/Volo/Abp/EventBus/Dapr/AbpEventBusDaprModule.cs b/framework/src/Volo.Abp.EventBus.Dapr/Volo/Abp/EventBus/Dapr/AbpEventBusDaprModule.cs new file mode 100644 index 0000000000..5f6329a4bc --- /dev/null +++ b/framework/src/Volo.Abp.EventBus.Dapr/Volo/Abp/EventBus/Dapr/AbpEventBusDaprModule.cs @@ -0,0 +1,20 @@ +using Microsoft.Extensions.DependencyInjection; +using Volo.Abp.Dapr; +using Volo.Abp.Modularity; + +namespace Volo.Abp.EventBus.Dapr; + +[DependsOn( + typeof(AbpEventBusModule), + typeof(AbpDaprModule) + )] +public class AbpEventBusDaprModule : AbpModule +{ + public override void OnApplicationInitialization(ApplicationInitializationContext context) + { + context + .ServiceProvider + .GetRequiredService() + .Initialize(); + } +} diff --git a/framework/src/Volo.Abp.EventBus.Dapr/Volo/Abp/EventBus/Dapr/DaprDistributedEventBus.cs b/framework/src/Volo.Abp.EventBus.Dapr/Volo/Abp/EventBus/Dapr/DaprDistributedEventBus.cs new file mode 100644 index 0000000000..1f241b9c6d --- /dev/null +++ b/framework/src/Volo.Abp.EventBus.Dapr/Volo/Abp/EventBus/Dapr/DaprDistributedEventBus.cs @@ -0,0 +1,221 @@ +using System.Collections.Concurrent; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Options; +using Volo.Abp.Dapr; +using Volo.Abp.DependencyInjection; +using Volo.Abp.EventBus.Distributed; +using Volo.Abp.Guids; +using Volo.Abp.MultiTenancy; +using Volo.Abp.Threading; +using Volo.Abp.Timing; +using Volo.Abp.Uow; + +namespace Volo.Abp.EventBus.Dapr; + +[Dependency(ReplaceServices = true)] +[ExposeServices(typeof(IDistributedEventBus), typeof(DaprDistributedEventBus))] +public class DaprDistributedEventBus : DistributedEventBusBase, ISingletonDependency +{ + protected IDaprSerializer Serializer { get; } + protected AbpDaprEventBusOptions DaprEventBusOptions { get; } + protected AbpDaprClientFactory DaprClientFactory { get; } + + protected ConcurrentDictionary> HandlerFactories { get; } + protected ConcurrentDictionary EventTypes { get; } + + public DaprDistributedEventBus( + IServiceScopeFactory serviceScopeFactory, + ICurrentTenant currentTenant, + IUnitOfWorkManager unitOfWorkManager, + IOptions abpDistributedEventBusOptions, + IGuidGenerator guidGenerator, + IClock clock, + IEventHandlerInvoker eventHandlerInvoker, + IDaprSerializer serializer, + IOptions daprEventBusOptions, + AbpDaprClientFactory daprClientFactory) + : base(serviceScopeFactory, currentTenant, unitOfWorkManager, abpDistributedEventBusOptions, guidGenerator, clock, eventHandlerInvoker) + { + Serializer = serializer; + DaprEventBusOptions = daprEventBusOptions.Value; + DaprClientFactory = daprClientFactory; + + HandlerFactories = new ConcurrentDictionary>(); + EventTypes = new ConcurrentDictionary(); + } + + public void Initialize() + { + SubscribeHandlers(AbpDistributedEventBusOptions.Handlers); + } + + public override IDisposable Subscribe(Type eventType, IEventHandlerFactory factory) + { + var handlerFactories = GetOrCreateHandlerFactories(eventType); + + if (factory.IsInFactories(handlerFactories)) + { + return NullDisposable.Instance; + } + + handlerFactories.Add(factory); + + return new EventHandlerFactoryUnregistrar(this, eventType, factory); + } + + public override void Unsubscribe(Func action) + { + Check.NotNull(action, nameof(action)); + + GetOrCreateHandlerFactories(typeof(TEvent)) + .Locking(factories => + { + factories.RemoveAll( + factory => + { + var singleInstanceFactory = factory as SingleInstanceHandlerFactory; + if (singleInstanceFactory == null) + { + return false; + } + + var actionHandler = singleInstanceFactory.HandlerInstance as ActionEventHandler; + if (actionHandler == null) + { + return false; + } + + return actionHandler.Action == action; + }); + }); + } + + public override void Unsubscribe(Type eventType, IEventHandler handler) + { + GetOrCreateHandlerFactories(eventType) + .Locking(factories => + { + factories.RemoveAll( + factory => + factory is SingleInstanceHandlerFactory && + (factory as SingleInstanceHandlerFactory).HandlerInstance == handler + ); + }); + } + + public override void Unsubscribe(Type eventType, IEventHandlerFactory factory) + { + GetOrCreateHandlerFactories(eventType).Locking(factories => factories.Remove(factory)); + } + + public override void UnsubscribeAll(Type eventType) + { + GetOrCreateHandlerFactories(eventType).Locking(factories => factories.Clear()); + } + + protected async override Task PublishToEventBusAsync(Type eventType, object eventData) + { + await PublishToDaprAsync(eventType, eventData); + } + + protected override void AddToUnitOfWork(IUnitOfWork unitOfWork, UnitOfWorkEventRecord eventRecord) + { + unitOfWork.AddOrReplaceDistributedEvent(eventRecord); + } + + protected override IEnumerable GetHandlerFactories(Type eventType) + { + var handlerFactoryList = new List(); + + foreach (var handlerFactory in HandlerFactories.Where(hf => ShouldTriggerEventForHandler(eventType, hf.Key))) + { + handlerFactoryList.Add(new EventTypeWithEventHandlerFactories(handlerFactory.Key, handlerFactory.Value)); + } + + return handlerFactoryList.ToArray(); + } + + public async override Task PublishFromOutboxAsync(OutgoingEventInfo outgoingEvent, OutboxConfig outboxConfig) + { + await PublishToDaprAsync(outgoingEvent.EventName, Serializer.Deserialize(outgoingEvent.EventData, GetEventType(outgoingEvent.EventName))); + } + + public async override Task PublishManyFromOutboxAsync(IEnumerable outgoingEvents, OutboxConfig outboxConfig) + { + var outgoingEventArray = outgoingEvents.ToArray(); + + foreach (var outgoingEvent in outgoingEventArray) + { + await PublishToDaprAsync(outgoingEvent.EventName, Serializer.Deserialize(outgoingEvent.EventData, GetEventType(outgoingEvent.EventName))); + } + } + + public async override Task ProcessFromInboxAsync(IncomingEventInfo incomingEvent, InboxConfig inboxConfig) + { + var eventType = EventTypes.GetOrDefault(incomingEvent.EventName); + if (eventType == null) + { + return; + } + + var eventData = Serializer.Deserialize(incomingEvent.EventData, eventType); + var exceptions = new List(); + await TriggerHandlersAsync(eventType, eventData, exceptions, inboxConfig); + if (exceptions.Any()) + { + ThrowOriginalExceptions(eventType, exceptions); + } + } + + protected override byte[] Serialize(object eventData) + { + return Serializer.Serialize(eventData); + } + + private List GetOrCreateHandlerFactories(Type eventType) + { + return HandlerFactories.GetOrAdd( + eventType, + type => + { + var eventName = EventNameAttribute.GetNameOrDefault(type); + EventTypes[eventName] = type; + return new List(); + } + ); + } + + public Type GetEventType(string eventName) + { + return EventTypes.GetOrDefault(eventName); + } + + protected virtual async Task PublishToDaprAsync(Type eventType, object eventData) + { + await PublishToDaprAsync(EventNameAttribute.GetNameOrDefault(eventType), eventData); + } + + protected virtual async Task PublishToDaprAsync(string eventName, object eventData) + { + var client = await DaprClientFactory.CreateAsync(); + await client.PublishEventAsync(pubsubName: DaprEventBusOptions.PubSubName, topicName: eventName, data: eventData); + } + + private static bool ShouldTriggerEventForHandler(Type targetEventType, Type handlerEventType) + { + //Should trigger same type + if (handlerEventType == targetEventType) + { + return true; + } + + //TODO: Support inheritance? But it does not support on subscription to RabbitMq! + //Should trigger for inherited types + if (handlerEventType.IsAssignableFrom(targetEventType)) + { + return true; + } + + return false; + } +} diff --git a/framework/src/Volo.Abp.EventBus.RabbitMQ/Volo/Abp/EventBus/RabbitMq/AbpRabbitMqEventBusOptions.cs b/framework/src/Volo.Abp.EventBus.RabbitMQ/Volo/Abp/EventBus/RabbitMq/AbpRabbitMqEventBusOptions.cs index addbc49171..bac9bdf0c9 100644 --- a/framework/src/Volo.Abp.EventBus.RabbitMQ/Volo/Abp/EventBus/RabbitMq/AbpRabbitMqEventBusOptions.cs +++ b/framework/src/Volo.Abp.EventBus.RabbitMQ/Volo/Abp/EventBus/RabbitMq/AbpRabbitMqEventBusOptions.cs @@ -13,6 +13,8 @@ public class AbpRabbitMqEventBusOptions public string ExchangeName { get; set; } public string ExchangeType { get; set; } + + public ushort? PrefetchCount { get; set; } public string GetExchangeTypeOrDefault() { diff --git a/framework/src/Volo.Abp.EventBus.RabbitMQ/Volo/Abp/EventBus/RabbitMq/RabbitMqDistributedEventBus.cs b/framework/src/Volo.Abp.EventBus.RabbitMQ/Volo/Abp/EventBus/RabbitMq/RabbitMqDistributedEventBus.cs index c9ec49bc7e..7e352ca530 100644 --- a/framework/src/Volo.Abp.EventBus.RabbitMQ/Volo/Abp/EventBus/RabbitMq/RabbitMqDistributedEventBus.cs +++ b/framework/src/Volo.Abp.EventBus.RabbitMQ/Volo/Abp/EventBus/RabbitMq/RabbitMqDistributedEventBus.cs @@ -78,7 +78,8 @@ public class RabbitMqDistributedEventBus : DistributedEventBusBase, ISingletonDe AbpRabbitMqEventBusOptions.ClientName, durable: true, exclusive: false, - autoDelete: false + autoDelete: false, + prefetchCount: AbpRabbitMqEventBusOptions.PrefetchCount ), AbpRabbitMqEventBusOptions.ConnectionName ); diff --git a/framework/src/Volo.Abp.Features/Volo/Abp/Features/FeaturesSimpleStateCheckerSerializerContributor.cs b/framework/src/Volo.Abp.Features/Volo/Abp/Features/FeaturesSimpleStateCheckerSerializerContributor.cs new file mode 100644 index 0000000000..58e2817139 --- /dev/null +++ b/framework/src/Volo.Abp.Features/Volo/Abp/Features/FeaturesSimpleStateCheckerSerializerContributor.cs @@ -0,0 +1,56 @@ +using System.Linq; +using System.Text.Json.Nodes; +using Volo.Abp.DependencyInjection; +using Volo.Abp.SimpleStateChecking; + +namespace Volo.Abp.Features; + +public class FeaturesSimpleStateCheckerSerializerContributor : + ISimpleStateCheckerSerializerContributor, + ISingletonDependency +{ + public const string CheckerShortName = "F"; + + public string SerializeToJson(ISimpleStateChecker checker) + where TState : IHasSimpleStateCheckers + { + if (checker is not RequireFeaturesSimpleStateChecker featuresSimpleStateChecker) + { + return null; + } + + var jsonObject = new JsonObject { + ["T"] = CheckerShortName, + ["A"] = featuresSimpleStateChecker.RequiresAll + }; + + var nameArray = new JsonArray(); + foreach (var featureName in featuresSimpleStateChecker.FeatureNames) + { + nameArray.Add(featureName); + } + + jsonObject["N"] = nameArray; + return jsonObject.ToJsonString(); + } + + public ISimpleStateChecker Deserialize(JsonObject jsonObject, TState state) + where TState : IHasSimpleStateCheckers + { + if (jsonObject["T"]?.ToString() != CheckerShortName) + { + return null; + } + + var nameArray = jsonObject["N"] as JsonArray; + if (nameArray == null) + { + throw new AbpException("'N' is not an array in the serialized state checker! JsonObject: " + jsonObject.ToJsonString()); + } + + return new RequireFeaturesSimpleStateChecker( + (bool?)jsonObject["A"] ?? false, + nameArray.Select(x => x.ToString()).ToArray() + ); + } +} \ No newline at end of file diff --git a/framework/src/Volo.Abp.Features/Volo/Abp/Features/RequireFeaturesSimpleStateChecker.cs b/framework/src/Volo.Abp.Features/Volo/Abp/Features/RequireFeaturesSimpleStateChecker.cs index 1b437e623a..625d097441 100644 --- a/framework/src/Volo.Abp.Features/Volo/Abp/Features/RequireFeaturesSimpleStateChecker.cs +++ b/framework/src/Volo.Abp.Features/Volo/Abp/Features/RequireFeaturesSimpleStateChecker.cs @@ -7,8 +7,8 @@ namespace Volo.Abp.Features; public class RequireFeaturesSimpleStateChecker : ISimpleStateChecker where TState : IHasSimpleStateCheckers { - private readonly string[] _featureNames; - private readonly bool _requiresAll; + public string[] FeatureNames { get; } + public bool RequiresAll { get; } public RequireFeaturesSimpleStateChecker(params string[] featureNames) : this(true, featureNames) @@ -19,13 +19,13 @@ public class RequireFeaturesSimpleStateChecker : ISimpleStateChecker IsEnabledAsync(SimpleStateCheckerContext context) { var featureChecker = context.ServiceProvider.GetRequiredService(); - return await featureChecker.IsEnabledAsync(_requiresAll, _featureNames); + return await featureChecker.IsEnabledAsync(RequiresAll, FeatureNames); } } diff --git a/framework/src/Volo.Abp.GlobalFeatures/Volo/Abp/GlobalFeatures/GlobalFeaturesSimpleStateCheckerSerializerContributor.cs b/framework/src/Volo.Abp.GlobalFeatures/Volo/Abp/GlobalFeatures/GlobalFeaturesSimpleStateCheckerSerializerContributor.cs new file mode 100644 index 0000000000..d4abc25403 --- /dev/null +++ b/framework/src/Volo.Abp.GlobalFeatures/Volo/Abp/GlobalFeatures/GlobalFeaturesSimpleStateCheckerSerializerContributor.cs @@ -0,0 +1,56 @@ +using System.Linq; +using System.Text.Json.Nodes; +using Volo.Abp.DependencyInjection; +using Volo.Abp.SimpleStateChecking; + +namespace Volo.Abp.GlobalFeatures; + +public class GlobalFeaturesSimpleStateCheckerSerializerContributor : + ISimpleStateCheckerSerializerContributor, + ISingletonDependency +{ + public const string CheckerShortName = "G"; + + public string SerializeToJson(ISimpleStateChecker checker) + where TState : IHasSimpleStateCheckers + { + if (checker is not RequireGlobalFeaturesSimpleStateChecker globalFeaturesSimpleStateChecker) + { + return null; + } + + var jsonObject = new JsonObject { + ["T"] = CheckerShortName, + ["A"] = globalFeaturesSimpleStateChecker.RequiresAll + }; + + var nameArray = new JsonArray(); + foreach (var globalFeatureName in globalFeaturesSimpleStateChecker.GlobalFeatureNames) + { + nameArray.Add(globalFeatureName); + } + + jsonObject["N"] = nameArray; + return jsonObject.ToJsonString(); + } + + public ISimpleStateChecker Deserialize(JsonObject jsonObject, TState state) + where TState : IHasSimpleStateCheckers + { + if (jsonObject["T"]?.ToString() != CheckerShortName) + { + return null; + } + + var nameArray = jsonObject["N"] as JsonArray; + if (nameArray == null) + { + throw new AbpException("'N' is not an array in the serialized state checker! JsonObject: " + jsonObject.ToJsonString()); + } + + return new RequireGlobalFeaturesSimpleStateChecker( + (bool?)jsonObject["A"] ?? false, + nameArray.Select(x => x.ToString()).ToArray() + ); + } +} \ No newline at end of file diff --git a/framework/src/Volo.Abp.GlobalFeatures/Volo/Abp/GlobalFeatures/RequireGlobalFeaturesSimpleStateChecker.cs b/framework/src/Volo.Abp.GlobalFeatures/Volo/Abp/GlobalFeatures/RequireGlobalFeaturesSimpleStateChecker.cs index 77fdaa0e1e..d37aba8397 100644 --- a/framework/src/Volo.Abp.GlobalFeatures/Volo/Abp/GlobalFeatures/RequireGlobalFeaturesSimpleStateChecker.cs +++ b/framework/src/Volo.Abp.GlobalFeatures/Volo/Abp/GlobalFeatures/RequireGlobalFeaturesSimpleStateChecker.cs @@ -8,8 +8,8 @@ namespace Volo.Abp.GlobalFeatures; public class RequireGlobalFeaturesSimpleStateChecker : ISimpleStateChecker where TState : IHasSimpleStateCheckers { - private readonly string[] _globalFeatureNames; - private readonly bool _requiresAll; + public string[] GlobalFeatureNames { get; } + public bool RequiresAll { get; } public RequireGlobalFeaturesSimpleStateChecker(params string[] globalFeatureNames) : this(true, globalFeatureNames) @@ -20,23 +20,23 @@ public class RequireGlobalFeaturesSimpleStateChecker : ISimpleStateCheck { Check.NotNullOrEmpty(globalFeatureNames, nameof(globalFeatureNames)); - _requiresAll = requiresAll; - _globalFeatureNames = globalFeatureNames; + RequiresAll = requiresAll; + GlobalFeatureNames = globalFeatureNames; } public RequireGlobalFeaturesSimpleStateChecker(bool requiresAll, params Type[] globalFeatureNames) { Check.NotNullOrEmpty(globalFeatureNames, nameof(globalFeatureNames)); - _requiresAll = requiresAll; - _globalFeatureNames = globalFeatureNames.Select(GlobalFeatureNameAttribute.GetName).ToArray(); + RequiresAll = requiresAll; + GlobalFeatureNames = globalFeatureNames.Select(GlobalFeatureNameAttribute.GetName).ToArray(); } public Task IsEnabledAsync(SimpleStateCheckerContext context) { - var isEnabled = _requiresAll - ? _globalFeatureNames.All(x => GlobalFeatureManager.Instance.IsEnabled(x)) - : _globalFeatureNames.Any(x => GlobalFeatureManager.Instance.IsEnabled(x)); + var isEnabled = RequiresAll + ? GlobalFeatureNames.All(x => GlobalFeatureManager.Instance.IsEnabled(x)) + : GlobalFeatureNames.Any(x => GlobalFeatureManager.Instance.IsEnabled(x)); return Task.FromResult(isEnabled); } diff --git a/framework/src/Volo.Abp.Http.Client.Dapr/FodyWeavers.xml b/framework/src/Volo.Abp.Http.Client.Dapr/FodyWeavers.xml new file mode 100644 index 0000000000..be0de3a908 --- /dev/null +++ b/framework/src/Volo.Abp.Http.Client.Dapr/FodyWeavers.xml @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/framework/src/Volo.Abp.Http.Client.Dapr/FodyWeavers.xsd b/framework/src/Volo.Abp.Http.Client.Dapr/FodyWeavers.xsd new file mode 100644 index 0000000000..3f3946e282 --- /dev/null +++ b/framework/src/Volo.Abp.Http.Client.Dapr/FodyWeavers.xsd @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + 'true' to run assembly verification (PEVerify) on the target assembly after all weavers have been executed. + + + + + A comma-separated list of error codes that can be safely ignored in assembly verification. + + + + + 'false' to turn off automatic generation of the XML Schema file. + + + + + \ No newline at end of file diff --git a/framework/src/Volo.Abp.Http.Client.Dapr/Volo.Abp.Http.Client.Dapr.csproj b/framework/src/Volo.Abp.Http.Client.Dapr/Volo.Abp.Http.Client.Dapr.csproj new file mode 100644 index 0000000000..909fb156c8 --- /dev/null +++ b/framework/src/Volo.Abp.Http.Client.Dapr/Volo.Abp.Http.Client.Dapr.csproj @@ -0,0 +1,18 @@ + + + + + + + net6.0 + enable + enable + + + + + + + + + diff --git a/framework/src/Volo.Abp.Http.Client.Dapr/Volo/Abp/Http/Client/Dapr/AbpHttpClientDaprModule.cs b/framework/src/Volo.Abp.Http.Client.Dapr/Volo/Abp/Http/Client/Dapr/AbpHttpClientDaprModule.cs new file mode 100644 index 0000000000..18a509d3ff --- /dev/null +++ b/framework/src/Volo.Abp.Http.Client.Dapr/Volo/Abp/Http/Client/Dapr/AbpHttpClientDaprModule.cs @@ -0,0 +1,23 @@ +using Microsoft.Extensions.DependencyInjection; +using Volo.Abp.Dapr; +using Volo.Abp.Modularity; + +namespace Volo.Abp.Http.Client.Dapr; + +[DependsOn( + typeof(AbpHttpClientModule), + typeof(AbpDaprModule) +)] +public class AbpHttpClientDaprModule : AbpModule +{ + public override void PreConfigureServices(ServiceConfigurationContext context) + { + PreConfigure(options => + { + options.ProxyClientBuildActions.Add((_, clientBuilder) => + { + clientBuilder.AddHttpMessageHandler(); + }); + }); + } +} \ No newline at end of file diff --git a/framework/src/Volo.Abp.Http.Client.Dapr/Volo/Abp/Http/Client/Dapr/AbpInvocationHandler.cs b/framework/src/Volo.Abp.Http.Client.Dapr/Volo/Abp/Http/Client/Dapr/AbpInvocationHandler.cs new file mode 100644 index 0000000000..a3397b55e4 --- /dev/null +++ b/framework/src/Volo.Abp.Http.Client.Dapr/Volo/Abp/Http/Client/Dapr/AbpInvocationHandler.cs @@ -0,0 +1,14 @@ +using Dapr.Client; +using Microsoft.Extensions.Options; +using Volo.Abp.Dapr; +using Volo.Abp.DependencyInjection; + +namespace Volo.Abp.Http.Client.Dapr; + +public class AbpInvocationHandler : InvocationHandler, ITransientDependency +{ + public AbpInvocationHandler(IOptions daprOptions) + { + DaprEndpoint = daprOptions.Value.HttpEndpoint; + } +} \ No newline at end of file diff --git a/framework/src/Volo.Abp.Http.Client/Microsoft/Extensions/DependencyInjection/ServiceCollectionHttpClientProxyExtensions.cs b/framework/src/Volo.Abp.Http.Client/Microsoft/Extensions/DependencyInjection/ServiceCollectionHttpClientProxyExtensions.cs index 4ccac104cd..7bc239813d 100644 --- a/framework/src/Volo.Abp.Http.Client/Microsoft/Extensions/DependencyInjection/ServiceCollectionHttpClientProxyExtensions.cs +++ b/framework/src/Volo.Abp.Http.Client/Microsoft/Extensions/DependencyInjection/ServiceCollectionHttpClientProxyExtensions.cs @@ -212,7 +212,7 @@ public static class ServiceCollectionHttpClientProxyExtensions } /// - /// Checks wether the type is suitable to use with the proxying. + /// Checks whether the type is suitable to use with the proxying. /// Currently the type is checked statically against some fixed conditions. /// /// Type to check diff --git a/framework/src/Volo.Abp.Localization.Abstractions/Volo/Abp/Localization/LocalizableString.cs b/framework/src/Volo.Abp.Localization.Abstractions/Volo/Abp/Localization/LocalizableString.cs index 61494d609e..88eb8a399d 100644 --- a/framework/src/Volo.Abp.Localization.Abstractions/Volo/Abp/Localization/LocalizableString.cs +++ b/framework/src/Volo.Abp.Localization.Abstractions/Volo/Abp/Localization/LocalizableString.cs @@ -12,7 +12,7 @@ public class LocalizableString : ILocalizableString [NotNull] public string Name { get; } - public LocalizableString(Type resourceType, [NotNull] string name) + public LocalizableString([CanBeNull] Type resourceType, [NotNull] string name) { Name = Check.NotNullOrEmpty(name, nameof(name)); ResourceType = resourceType; @@ -20,7 +20,28 @@ public class LocalizableString : ILocalizableString public LocalizedString Localize(IStringLocalizerFactory stringLocalizerFactory) { - return stringLocalizerFactory.Create(ResourceType)[Name]; + var localizer = ResourceType != null + ? stringLocalizerFactory.Create(ResourceType) + : stringLocalizerFactory.CreateDefaultOrNull(); + + if (localizer == null) + { + throw new AbpException($"Set {nameof(ResourceType)} or configure the default localization resource type (in the AbpLocalizationOptions)!"); + } + + var result = localizer[Name]; + + if (result.ResourceNotFound && ResourceType != null) + { + /* Search in the default resource if not found in the provided resource */ + localizer = stringLocalizerFactory.CreateDefaultOrNull(); + if (localizer != null) + { + result = localizer[Name]; + } + } + + return result; } public static LocalizableString Create([NotNull] string name) diff --git a/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/ILocalizableStringSerializer.cs b/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/ILocalizableStringSerializer.cs new file mode 100644 index 0000000000..6f7a487b6c --- /dev/null +++ b/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/ILocalizableStringSerializer.cs @@ -0,0 +1,8 @@ +namespace Volo.Abp.Localization; + +public interface ILocalizableStringSerializer +{ + string Serialize(ILocalizableString localizableString); + + ILocalizableString Deserialize(string value); +} \ No newline at end of file diff --git a/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/LocalizableStringSerializer.cs b/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/LocalizableStringSerializer.cs new file mode 100644 index 0000000000..4cfd6e2f32 --- /dev/null +++ b/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/LocalizableStringSerializer.cs @@ -0,0 +1,69 @@ +using System; +using Microsoft.Extensions.Options; +using Volo.Abp.DependencyInjection; + +namespace Volo.Abp.Localization; + +public class LocalizableStringSerializer : ILocalizableStringSerializer, ITransientDependency +{ + protected AbpLocalizationOptions LocalizationOptions { get; } + + public LocalizableStringSerializer(IOptions localizationOptions) + { + LocalizationOptions = localizationOptions.Value; + } + + public virtual string Serialize(ILocalizableString localizableString) + { + if (localizableString is LocalizableString realLocalizableString) + { + return $"L:{LocalizationResourceNameAttribute.GetName(realLocalizableString.ResourceType)},{realLocalizableString.Name}"; + } + + if (localizableString is FixedLocalizableString fixedLocalizableString) + { + return $"F:{fixedLocalizableString.Value}"; + } + + throw new AbpException($"Unknown {nameof(ILocalizableString)} type: {localizableString.GetType().FullName}"); + } + + public virtual ILocalizableString Deserialize(string value) + { + if (value.IsNullOrEmpty() || + value.Length < 3 || + value[1] != ':') + { + return new FixedLocalizableString(value); + } + + var type = value[0]; + switch (type) + { + case 'F': + return new FixedLocalizableString(value.Substring(2)); + case 'L': + var commaPosition = value.IndexOf(',', 2); + if (commaPosition == -1) + { + throw new AbpException("Invalid LocalizableString value: " + value); + } + + var resourceName = value.Substring(2, commaPosition - 2); + var name = value.Substring(commaPosition + 1); + if (name.IsNullOrWhiteSpace()) + { + throw new AbpException("Invalid LocalizableString value: " + value); + } + + var resourceType = LocalizationOptions.Resources.GetOrNull(resourceName)?.ResourceType; + + return new LocalizableString( + resourceType, + name + ); + default: + return new FixedLocalizableString(value); + } + } +} \ No newline at end of file diff --git a/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/LocalizationResourceDictionary.cs b/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/LocalizationResourceDictionary.cs index e394e01202..d672a2f17a 100644 --- a/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/LocalizationResourceDictionary.cs +++ b/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/LocalizationResourceDictionary.cs @@ -6,6 +6,8 @@ namespace Volo.Abp.Localization; public class LocalizationResourceDictionary : Dictionary { + private readonly Dictionary _resourcesByNames = new(); + public LocalizationResource Add([CanBeNull] string defaultCultureName = null) { return Add(typeof(TResouce), defaultCultureName); @@ -18,7 +20,12 @@ public class LocalizationResourceDictionary : Dictionary() @@ -33,4 +40,20 @@ public class LocalizationResourceDictionary : Dictionary : RepositoryBase : RepositoryBase x.IsDeleted, () => true); (await GetCollectionAsync()).Update(entity); } else diff --git a/framework/src/Volo.Abp.MongoDB/Volo/Abp/Domain/Repositories/MongoDB/MongoDbRepository.cs b/framework/src/Volo.Abp.MongoDB/Volo/Abp/Domain/Repositories/MongoDB/MongoDbRepository.cs index 0485dd74bc..e128c8dee8 100644 --- a/framework/src/Volo.Abp.MongoDB/Volo/Abp/Domain/Repositories/MongoDB/MongoDbRepository.cs +++ b/framework/src/Volo.Abp.MongoDB/Volo/Abp/Domain/Repositories/MongoDB/MongoDbRepository.cs @@ -294,7 +294,7 @@ public class MongoDbRepository if (typeof(ISoftDelete).IsAssignableFrom(typeof(TEntity)) && !IsHardDeleted(entity)) { - ((ISoftDelete)entity).IsDeleted = true; + ObjectHelper.TrySetProperty(((ISoftDelete)entity), x => x.IsDeleted, () => true); ApplyAbpConceptsForDeletedEntity(entity); ReplaceOneResult result; @@ -365,8 +365,7 @@ public class MongoDbRepository { if (typeof(ISoftDelete).IsAssignableFrom(typeof(TEntity)) && !IsHardDeleted(entity)) { - ((ISoftDelete)entity).IsDeleted = true; - + ObjectHelper.TrySetProperty(((ISoftDelete)entity), x => x.IsDeleted, () => true); softDeletedEntities.Add(entity, SetNewConcurrencyStamp(entity)); } else @@ -598,13 +597,11 @@ public class MongoDbRepository private void TriggerEntityCreateEvents(TEntity entity) { - EntityChangeEventHelper.PublishEntityCreatingEvent(entity); EntityChangeEventHelper.PublishEntityCreatedEvent(entity); } protected virtual void TriggerEntityUpdateEvents(TEntity entity) { - EntityChangeEventHelper.PublishEntityUpdatingEvent(entity); EntityChangeEventHelper.PublishEntityUpdatedEvent(entity); } @@ -617,7 +614,6 @@ public class MongoDbRepository protected virtual void TriggerEntityDeleteEvents(TEntity entity) { - EntityChangeEventHelper.PublishEntityDeletingEvent(entity); EntityChangeEventHelper.PublishEntityDeletedEvent(entity); } diff --git a/framework/src/Volo.Abp.MultiTenancy/Volo/Abp/MultiTenancy/MultiTenancySides.cs b/framework/src/Volo.Abp.MultiTenancy/Volo/Abp/MultiTenancy/MultiTenancySides.cs index bf094c6bc3..0b848554bb 100644 --- a/framework/src/Volo.Abp.MultiTenancy/Volo/Abp/MultiTenancy/MultiTenancySides.cs +++ b/framework/src/Volo.Abp.MultiTenancy/Volo/Abp/MultiTenancy/MultiTenancySides.cs @@ -6,7 +6,7 @@ namespace Volo.Abp.MultiTenancy; /// Represents sides in a multi tenancy application. /// [Flags] -public enum MultiTenancySides +public enum MultiTenancySides : byte { /// /// Tenant side. diff --git a/framework/src/Volo.Abp.ObjectExtending/Volo/Abp/Data/ExtraPropertyDictionaryExtensions.cs b/framework/src/Volo.Abp.ObjectExtending/Volo/Abp/Data/ExtraPropertyDictionaryExtensions.cs index b97b0056e9..d5de504afc 100644 --- a/framework/src/Volo.Abp.ObjectExtending/Volo/Abp/Data/ExtraPropertyDictionaryExtensions.cs +++ b/framework/src/Volo.Abp.ObjectExtending/Volo/Abp/Data/ExtraPropertyDictionaryExtensions.cs @@ -1,4 +1,5 @@ using System; +using JetBrains.Annotations; namespace Volo.Abp.Data; @@ -26,4 +27,28 @@ public static class ExtraPropertyDictionaryExtensions extraPropertyDictionary[key] = Enum.Parse(enumType, extraPropertyDictionary[key].ToString(), ignoreCase: true); return extraPropertyDictionary[key]; } -} + + public static bool HasSameItems( + [NotNull] this ExtraPropertyDictionary dictionary, + [NotNull] ExtraPropertyDictionary otherDictionary) + { + Check.NotNull(dictionary, nameof(dictionary)); + Check.NotNull(otherDictionary, nameof(otherDictionary)); + + if (dictionary.Count != otherDictionary.Count) + { + return false; + } + + foreach (var key in dictionary.Keys) + { + if (!otherDictionary.ContainsKey(key) || + dictionary[key]?.ToString() != otherDictionary[key]?.ToString()) + { + return false; + } + } + + return true; + } +} \ No newline at end of file diff --git a/framework/src/Volo.Abp.ObjectExtending/Volo/Abp/Data/HasExtraPropertiesExtensions.cs b/framework/src/Volo.Abp.ObjectExtending/Volo/Abp/Data/HasExtraPropertiesExtensions.cs index 0bd64d55f1..db543bb67f 100644 --- a/framework/src/Volo.Abp.ObjectExtending/Volo/Abp/Data/HasExtraPropertiesExtensions.cs +++ b/framework/src/Volo.Abp.ObjectExtending/Volo/Abp/Data/HasExtraPropertiesExtensions.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using System.ComponentModel; using System.Globalization; using System.Linq; +using JetBrains.Annotations; using Volo.Abp.ObjectExtending; using Volo.Abp.Reflection; @@ -121,4 +122,14 @@ public static class HasExtraPropertiesExtensions source.RemoveProperty(property.Name); } } + + public static bool HasSameExtraProperties( + [NotNull] this IHasExtraProperties source, + [NotNull] IHasExtraProperties other) + { + Check.NotNull(source, nameof(source)); + Check.NotNull(other, nameof(other)); + + return source.ExtraProperties.HasSameItems(other.ExtraProperties); + } } diff --git a/framework/src/Volo.Abp.RabbitMQ/Volo/Abp/RabbitMQ/QueueDeclareConfiguration.cs b/framework/src/Volo.Abp.RabbitMQ/Volo/Abp/RabbitMQ/QueueDeclareConfiguration.cs index 36f638668c..4b03c788c6 100644 --- a/framework/src/Volo.Abp.RabbitMQ/Volo/Abp/RabbitMQ/QueueDeclareConfiguration.cs +++ b/framework/src/Volo.Abp.RabbitMQ/Volo/Abp/RabbitMQ/QueueDeclareConfiguration.cs @@ -13,6 +13,8 @@ public class QueueDeclareConfiguration public bool Exclusive { get; set; } public bool AutoDelete { get; set; } + + public ushort? PrefetchCount { get; set; } public IDictionary Arguments { get; } @@ -20,13 +22,15 @@ public class QueueDeclareConfiguration [NotNull] string queueName, bool durable = true, bool exclusive = false, - bool autoDelete = false) + bool autoDelete = false, + ushort? prefetchCount = null) { QueueName = queueName; Durable = durable; Exclusive = exclusive; AutoDelete = autoDelete; Arguments = new Dictionary(); + PrefetchCount = prefetchCount; } public virtual QueueDeclareOk Declare(IModel channel) diff --git a/framework/src/Volo.Abp.RabbitMQ/Volo/Abp/RabbitMQ/RabbitMqMessageConsumer.cs b/framework/src/Volo.Abp.RabbitMQ/Volo/Abp/RabbitMQ/RabbitMqMessageConsumer.cs index 8ce184295a..5c45b6aefc 100644 --- a/framework/src/Volo.Abp.RabbitMQ/Volo/Abp/RabbitMQ/RabbitMqMessageConsumer.cs +++ b/framework/src/Volo.Abp.RabbitMQ/Volo/Abp/RabbitMQ/RabbitMqMessageConsumer.cs @@ -165,9 +165,14 @@ public class RabbitMqMessageConsumer : IRabbitMqMessageConsumer, ITransientDepen arguments: Queue.Arguments ); + if (Queue.PrefetchCount.HasValue) + { + Channel.BasicQos(0, Queue.PrefetchCount.Value, false); + } + var consumer = new AsyncEventingBasicConsumer(Channel); consumer.Received += HandleIncomingMessageAsync; - + Channel.BasicConsume( queue: Queue.QueueName, autoAck: false, diff --git a/framework/src/Volo.Abp.Threading/Volo/Abp/Threading/NullCancellationTokenProvider.cs b/framework/src/Volo.Abp.Threading/Volo/Abp/Threading/NullCancellationTokenProvider.cs index 8f8113ba0d..2da06632cd 100644 --- a/framework/src/Volo.Abp.Threading/Volo/Abp/Threading/NullCancellationTokenProvider.cs +++ b/framework/src/Volo.Abp.Threading/Volo/Abp/Threading/NullCancellationTokenProvider.cs @@ -4,7 +4,7 @@ namespace Volo.Abp.Threading; public class NullCancellationTokenProvider : CancellationTokenProviderBase { - public static NullCancellationTokenProvider Instance { get; } = new NullCancellationTokenProvider(); + public static NullCancellationTokenProvider Instance { get; } = new(); public override CancellationToken Token => OverrideValue?.CancellationToken ?? CancellationToken.None; diff --git a/framework/src/Volo.Abp.UI.Navigation/Volo/Abp/Ui/Navigation/MenuManager.cs b/framework/src/Volo.Abp.UI.Navigation/Volo/Abp/Ui/Navigation/MenuManager.cs index d325708175..aa933c6e09 100644 --- a/framework/src/Volo.Abp.UI.Navigation/Volo/Abp/Ui/Navigation/MenuManager.cs +++ b/framework/src/Volo.Abp.UI.Navigation/Volo/Abp/Ui/Navigation/MenuManager.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using System.Diagnostics; using System.Linq; using System.Threading.Tasks; +using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Options; using Volo.Abp.Authorization.Permissions; using Volo.Abp.DependencyInjection; @@ -13,11 +14,11 @@ namespace Volo.Abp.UI.Navigation; public class MenuManager : IMenuManager, ITransientDependency { protected AbpNavigationOptions Options { get; } - protected IHybridServiceScopeFactory ServiceScopeFactory { get; } + protected IServiceScopeFactory ServiceScopeFactory { get; } protected ISimpleStateCheckerManager SimpleStateCheckerManager { get; } public MenuManager( IOptions options, - IHybridServiceScopeFactory serviceScopeFactory, + IServiceScopeFactory serviceScopeFactory, ISimpleStateCheckerManager simpleStateCheckerManager) { Options = options.Value; diff --git a/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/ar.json b/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/ar.json index 7e667c1bbc..4717b1fe9b 100644 --- a/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/ar.json +++ b/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/ar.json @@ -11,7 +11,7 @@ "Close": "أغلق", "Save": "حفظ", "SavingWithThreeDot": "حفظ...", - "Actions": "أجراءات", + "Actions": "الإجراءات", "Delete": "حذف", "SuccessfullyDeleted": "تم الحذف بنجاح", "Edit": "تعديل", @@ -50,4 +50,4 @@ "ItemWillBeDeletedMessage": "سوف يتم حذف هذا البند!", "ManageYourAccount": "إدارة حسابك" } -} \ No newline at end of file +} diff --git a/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/pt-BR.json b/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/pt-BR.json index aa915a704f..03855ec698 100644 --- a/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/pt-BR.json +++ b/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/pt-BR.json @@ -1,10 +1,10 @@ { "culture": "pt-BR", "texts": { - "Languages": "línguas", + "Languages": "Idiomas", "AreYouSure": "Você tem certeza?", "Cancel": "Cancelar", - "Clear": "Claro", + "Clear": "Limpar", "Yes": "Sim", "No": "Não", "Ok": "OK", @@ -16,7 +16,7 @@ "SuccessfullyDeleted": "Excluído com sucesso", "Edit": "Editar", "Refresh": "Atualizar", - "Language": "Língua", + "Language": "Idioma", "LoadMore": "Carregar mais", "ProcessingWithThreeDot": "Processando...", "LoadingWithThreeDot": "Carregando...", diff --git a/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/ro-RO.json b/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/ro-RO.json index 94e56a66f3..7064064671 100644 --- a/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/ro-RO.json +++ b/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/ro-RO.json @@ -31,14 +31,14 @@ "PagerPrevious": "Anterior", "PagerFirst": "Primul", "PagerLast": "Ultimul", - "PagerInfo": "Afişate _START_ to _END_ of _TOTAL_ înregistrări", - "PagerInfo{0}{1}{2}": "Afişate {0} to {1} of {2} înregistrări", - "PagerInfoEmpty": "Afişate 0 to 0 of 0 înregistrări", + "PagerInfo": "Afişate de la _START_ la _END_ din _TOTAL_ înregistrări", + "PagerInfo{0}{1}{2}": "Afişate de la {0} la {1} din {2} înregistrări", + "PagerInfoEmpty": "Afişate 0 din 0 înregistrări", "PagerInfoFiltered": "(filtrate de la _MAX_ înregistrări totale)", "NoDataAvailableInDatatable": "Nicio informaţie disponibilă", "Total": "total", "Selected": "selectate", - "PagerShowMenuEntries": "Arată _MENU_ intrări", + "PagerShowMenuEntries": "Afişează _MENU_ intrări", "DatatableActionDropdownDefaultText": "Acţiuni", "ChangePassword": "Schimbă parola", "PersonalInfo": "Profilul meu", @@ -50,4 +50,4 @@ "ItemWillBeDeletedMessage": "Acest articol va fi şters!", "ManageYourAccount": "Administraţi-vă contul" } -} \ No newline at end of file +} diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI/Volo/Abp/AspNetCore/Mvc/UI/Components/LayoutHook/AbpLayoutHookOptions.cs b/framework/src/Volo.Abp.UI/Volo/Abp/Ui/LayoutHooks/AbpLayoutHookOptions.cs similarity index 89% rename from framework/src/Volo.Abp.AspNetCore.Mvc.UI/Volo/Abp/AspNetCore/Mvc/UI/Components/LayoutHook/AbpLayoutHookOptions.cs rename to framework/src/Volo.Abp.UI/Volo/Abp/Ui/LayoutHooks/AbpLayoutHookOptions.cs index 68851c1860..d5ba4aa239 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc.UI/Volo/Abp/AspNetCore/Mvc/UI/Components/LayoutHook/AbpLayoutHookOptions.cs +++ b/framework/src/Volo.Abp.UI/Volo/Abp/Ui/LayoutHooks/AbpLayoutHookOptions.cs @@ -1,7 +1,7 @@ using System; using System.Collections.Generic; -namespace Volo.Abp.AspNetCore.Mvc.UI.Components.LayoutHook; +namespace Volo.Abp.Ui.LayoutHooks; public class AbpLayoutHookOptions { diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI/Volo/Abp/AspNetCore/Mvc/UI/Components/LayoutHook/LayoutHookInfo.cs b/framework/src/Volo.Abp.UI/Volo/Abp/Ui/LayoutHooks/LayoutHookInfo.cs similarity index 84% rename from framework/src/Volo.Abp.AspNetCore.Mvc.UI/Volo/Abp/AspNetCore/Mvc/UI/Components/LayoutHook/LayoutHookInfo.cs rename to framework/src/Volo.Abp.UI/Volo/Abp/Ui/LayoutHooks/LayoutHookInfo.cs index e2bb26dac5..db4ca39466 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc.UI/Volo/Abp/AspNetCore/Mvc/UI/Components/LayoutHook/LayoutHookInfo.cs +++ b/framework/src/Volo.Abp.UI/Volo/Abp/Ui/LayoutHooks/LayoutHookInfo.cs @@ -1,11 +1,11 @@ using System; -namespace Volo.Abp.AspNetCore.Mvc.UI.Components.LayoutHook; +namespace Volo.Abp.Ui.LayoutHooks; public class LayoutHookInfo { /// - /// ViewComponent type. + /// Component type. /// public Type ComponentType { get; } diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI/Volo/Abp/AspNetCore/Mvc/UI/Components/LayoutHook/LayoutHookViewModel.cs b/framework/src/Volo.Abp.UI/Volo/Abp/Ui/LayoutHooks/LayoutHookViewModel.cs similarity index 79% rename from framework/src/Volo.Abp.AspNetCore.Mvc.UI/Volo/Abp/AspNetCore/Mvc/UI/Components/LayoutHook/LayoutHookViewModel.cs rename to framework/src/Volo.Abp.UI/Volo/Abp/Ui/LayoutHooks/LayoutHookViewModel.cs index fbc73d8dad..107ad6990a 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc.UI/Volo/Abp/AspNetCore/Mvc/UI/Components/LayoutHook/LayoutHookViewModel.cs +++ b/framework/src/Volo.Abp.UI/Volo/Abp/Ui/LayoutHooks/LayoutHookViewModel.cs @@ -1,4 +1,4 @@ -namespace Volo.Abp.AspNetCore.Mvc.UI.Components.LayoutHook; +namespace Volo.Abp.Ui.LayoutHooks; public class LayoutHookViewModel { diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI/Volo/Abp/AspNetCore/Mvc/UI/Components/LayoutHook/LayoutHooks.cs b/framework/src/Volo.Abp.UI/Volo/Abp/Ui/LayoutHooks/LayoutHooks.cs similarity index 88% rename from framework/src/Volo.Abp.AspNetCore.Mvc.UI/Volo/Abp/AspNetCore/Mvc/UI/Components/LayoutHook/LayoutHooks.cs rename to framework/src/Volo.Abp.UI/Volo/Abp/Ui/LayoutHooks/LayoutHooks.cs index 588872c46b..fafab40161 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc.UI/Volo/Abp/AspNetCore/Mvc/UI/Components/LayoutHook/LayoutHooks.cs +++ b/framework/src/Volo.Abp.UI/Volo/Abp/Ui/LayoutHooks/LayoutHooks.cs @@ -1,4 +1,4 @@ -namespace Volo.Abp.AspNetCore.Mvc.UI.Components.LayoutHook; +namespace Volo.Abp.Ui.LayoutHooks; public static class LayoutHooks { diff --git a/framework/src/Volo.Abp.Validation/Volo/Abp/Validation/Localization/pt-BR.json b/framework/src/Volo.Abp.Validation/Volo/Abp/Validation/Localization/pt-BR.json index 4adbd81e80..1168a19317 100644 --- a/framework/src/Volo.Abp.Validation/Volo/Abp/Validation/Localization/pt-BR.json +++ b/framework/src/Volo.Abp.Validation/Volo/Abp/Validation/Localization/pt-BR.json @@ -24,6 +24,8 @@ "ThisFieldMustBeAStringOrArrayTypeWithAMinimumLengthOf{0}": "Este campo deve ser do tipo palavra ou matriz com comprimento mínimo de '{0}'.", "ThisFieldIsNotAValidPhoneNumber.": "Número de telefone inválido.", "ThisFieldMustBeBetween{0}And{1}": "Este campo deve estar entre {0} e {1}.", + "ThisFieldMustBeGreaterThanOrEqual{0}": "Este campo deve ser maior ou igual a {0}.", + "ThisFieldMustBeLessOrEqual{0}": "Este campo deve ser menor ou igual a {0}.", "ThisFieldMustMatchTheRegularExpression{0}": "Este campo deve ser compatível com a expressão regular: '{0}'.", "ThisFieldIsRequired.": "Campo Obrigatório.", "ThisFieldMustBeAStringWithAMaximumLengthOf{0}": "Campo com no máximo {0} caracteres.", diff --git a/framework/test/Volo.Abp.AspNetCore.Mvc.PlugIn/Volo.Abp.AspNetCore.Mvc.PlugIn.csproj b/framework/test/Volo.Abp.AspNetCore.Mvc.PlugIn/Volo.Abp.AspNetCore.Mvc.PlugIn.csproj index 91ca2b1312..d917afa97f 100644 --- a/framework/test/Volo.Abp.AspNetCore.Mvc.PlugIn/Volo.Abp.AspNetCore.Mvc.PlugIn.csproj +++ b/framework/test/Volo.Abp.AspNetCore.Mvc.PlugIn/Volo.Abp.AspNetCore.Mvc.PlugIn.csproj @@ -4,6 +4,7 @@ net6.0 Library true + true diff --git a/framework/test/Volo.Abp.Auditing.Tests/Volo/Abp/Auditing/AbpAuditingOptions_Tests.cs b/framework/test/Volo.Abp.Auditing.Tests/Volo/Abp/Auditing/AbpAuditingOptions_Tests.cs new file mode 100644 index 0000000000..6853046241 --- /dev/null +++ b/framework/test/Volo.Abp.Auditing.Tests/Volo/Abp/Auditing/AbpAuditingOptions_Tests.cs @@ -0,0 +1,23 @@ +using Microsoft.Extensions.Options; +using Shouldly; +using Xunit; + +namespace Volo.Abp.Auditing; + +public class AbpAuditingOptions_Tests : AbpAuditingTestBase +{ + private const string ApplicationName = "TEST_APP_NAME"; + + protected override void SetAbpApplicationCreationOptions(AbpApplicationCreationOptions options) + { + base.SetAbpApplicationCreationOptions(options); + options.ApplicationName = ApplicationName; + } + + [Fact] + public void Should_Set_Application_Name_From_Global_Application_Name_By_Default() + { + var options = GetRequiredService>().Value; + options.ApplicationName.ShouldBe(ApplicationName); + } +} \ No newline at end of file diff --git a/framework/test/Volo.Abp.Authorization.Tests/Volo/Abp/Authorization/AuthenticatedSimpleStateCheckerSerializerContributor_Tests.cs b/framework/test/Volo.Abp.Authorization.Tests/Volo/Abp/Authorization/AuthenticatedSimpleStateCheckerSerializerContributor_Tests.cs new file mode 100644 index 0000000000..0d84d167de --- /dev/null +++ b/framework/test/Volo.Abp.Authorization.Tests/Volo/Abp/Authorization/AuthenticatedSimpleStateCheckerSerializerContributor_Tests.cs @@ -0,0 +1,41 @@ +using System.Collections.Generic; +using System.Text.Json.Nodes; +using Shouldly; +using Volo.Abp.Authorization.Permissions; +using Volo.Abp.SimpleStateChecking; +using Xunit; + +namespace Volo.Abp.Authorization; + +public class AuthenticatedSimpleStateCheckerSerializerContributor_Tests +{ + [Fact] + public void Should_Serialize_RequireGlobalFeaturesSimpleStateChecker() + { + var serializer = new AuthenticatedSimpleStateCheckerSerializerContributor(); + + var result = serializer.SerializeToJson( + new RequireAuthenticatedSimpleStateChecker() + ); + + result.ShouldBe("{\"T\":\"A\"}"); + } + + [Fact] + public void Should_Deserialize_RequireGlobalFeaturesSimpleStateChecker() + { + var serializer = new AuthenticatedSimpleStateCheckerSerializerContributor(); + + var jsonObject = (JsonObject)JsonNode.Parse("{\"T\":\"A\"}"); + var checker = serializer.Deserialize(jsonObject, new MyState()); + + checker.ShouldBeOfType>(); + var globalFeaturesSimpleStateChecker = checker as RequireAuthenticatedSimpleStateChecker; + globalFeaturesSimpleStateChecker.ShouldNotBeNull(); + } + + private class MyState : IHasSimpleStateCheckers + { + public List> StateCheckers { get; } = new(); + } +} \ No newline at end of file diff --git a/framework/test/Volo.Abp.Authorization.Tests/Volo/Abp/Authorization/Authorization_Tests.cs b/framework/test/Volo.Abp.Authorization.Tests/Volo/Abp/Authorization/Authorization_Tests.cs index 42f6d3ce4a..a32939fa53 100644 --- a/framework/test/Volo.Abp.Authorization.Tests/Volo/Abp/Authorization/Authorization_Tests.cs +++ b/framework/test/Volo.Abp.Authorization.Tests/Volo/Abp/Authorization/Authorization_Tests.cs @@ -67,9 +67,9 @@ public class Authorization_Tests : AuthorizationTestBase } [Fact] - public void Should_Permission_Definition_GetGroup() + public async Task Should_Permission_Definition_GetGroup() { - _permissionDefinitionManager.GetGroups().Count.ShouldBe(1); + (await _permissionDefinitionManager.GetGroupsAsync()).Count.ShouldBe(1); } [Fact] diff --git a/framework/test/Volo.Abp.Authorization.Tests/Volo/Abp/Authorization/PermissionStateProvider_Tests.cs b/framework/test/Volo.Abp.Authorization.Tests/Volo/Abp/Authorization/PermissionStateProvider_Tests.cs index b0be00fe01..50805d4b58 100644 --- a/framework/test/Volo.Abp.Authorization.Tests/Volo/Abp/Authorization/PermissionStateProvider_Tests.cs +++ b/framework/test/Volo.Abp.Authorization.Tests/Volo/Abp/Authorization/PermissionStateProvider_Tests.cs @@ -29,7 +29,8 @@ public class SpecifyPermissionStateProvider : PermissionStateProvider_Tests [Fact] public async Task PermissionState_Test() { - var myPermission1 = PermissionDefinitionManager.Get("MyPermission1"); + var myPermission1 = await PermissionDefinitionManager.GetOrNullAsync("MyPermission1"); + myPermission1.ShouldNotBeNull(); myPermission1.StateCheckers.ShouldContain(x => x.GetType() == typeof(TestRequireEditionPermissionSimpleStateChecker)); (await StateCheckerManager.IsEnabledAsync(myPermission1)).ShouldBeFalse(); @@ -54,7 +55,8 @@ public class GlobalPermissionStateProvider : PermissionStateProvider_Tests [Fact] public async Task Global_PermissionState_Test() { - var myPermission2 = PermissionDefinitionManager.Get("MyPermission2"); + var myPermission2 = await PermissionDefinitionManager.GetOrNullAsync("MyPermission2"); + myPermission2.ShouldNotBeNull(); (await StateCheckerManager.IsEnabledAsync(myPermission2)).ShouldBeFalse(); diff --git a/framework/test/Volo.Abp.Core.Tests/Microsoft/Extensions/DependencyInjection/DependencyInjection_Tests.cs b/framework/test/Volo.Abp.Core.Tests/Microsoft/Extensions/DependencyInjection/DependencyInjection_Tests.cs index 5d77c6a00e..52f07620fb 100644 --- a/framework/test/Volo.Abp.Core.Tests/Microsoft/Extensions/DependencyInjection/DependencyInjection_Tests.cs +++ b/framework/test/Volo.Abp.Core.Tests/Microsoft/Extensions/DependencyInjection/DependencyInjection_Tests.cs @@ -47,19 +47,36 @@ public abstract class DependencyInjection_Standard_Tests : AbpIntegratedTest().ProperyInjectedService.ShouldNotBeNull(); + GetRequiredService().PropertyInjectedService.ShouldNotBeNull(); } [Fact] public void Should_Inject_Services_As_Properties_For_Generic_Classes() { - GetRequiredService>().ProperyInjectedService.ShouldNotBeNull(); + GetRequiredService>().PropertyInjectedService.ShouldNotBeNull(); } [Fact] public void Should_Inject_Services_As_Properties_For_Generic_Concrete_Classes() { - GetRequiredService().ProperyInjectedService.ShouldNotBeNull(); + GetRequiredService().PropertyInjectedService.ShouldNotBeNull(); + } + + [Fact] + public void Should_Not_Inject_Services_As_Properties_When_Class_With_DisablePropertyInjection() + { + GetRequiredService().PropertyInjectedService.ShouldBeNull(); + GetRequiredService>().PropertyInjectedService.ShouldBeNull(); + } + + [Fact] + public void Should_Not_Inject_Services_As_Properties_When_Property_With_DisablePropertyInjection() + { + GetRequiredService().PropertyInjectedService.ShouldNotBeNull(); + GetRequiredService().DisablePropertyInjectionService.ShouldBeNull(); + + GetRequiredService>().PropertyInjectedService.ShouldNotBeNull(); + GetRequiredService>().DisablePropertyInjectionService.ShouldBeNull(); } [Fact] @@ -145,18 +162,19 @@ public abstract class DependencyInjection_Standard_Tests : AbpIntegratedTest(); context.Services.AddType(); context.Services.AddTransient(typeof(GenericServiceWithPropertyInject<>)); - context.Services.AddTransient(typeof(ConcreteGenericServiceWithPropertyInject)); + context.Services.AddTransient(typeof(GenericServiceWithDisablePropertyInjectionOnClass<>)); + context.Services.AddTransient(typeof(GenericServiceWithDisablePropertyInjectionOnProperty<>)); } } public class ServiceWithPropertyInject : ITransientDependency { - public MyEmptyTransientService ProperyInjectedService { get; set; } + public MyEmptyTransientService PropertyInjectedService { get; set; } } public class GenericServiceWithPropertyInject : ITransientDependency { - public MyEmptyTransientService ProperyInjectedService { get; set; } + public MyEmptyTransientService PropertyInjectedService { get; set; } public T Value { get; set; } } @@ -165,4 +183,36 @@ public abstract class DependencyInjection_Standard_Tests : AbpIntegratedTest : ITransientDependency + { + public MyEmptyTransientService PropertyInjectedService { get; set; } + + public T Value { get; set; } + } + + public class GenericServiceWithDisablePropertyInjectionOnProperty : ITransientDependency + { + public MyEmptyTransientService PropertyInjectedService { get; set; } + + [DisablePropertyInjection] + public MyEmptyTransientService DisablePropertyInjectionService { get; set; } + + public T Value { get; set; } + } } diff --git a/framework/test/Volo.Abp.Core.Tests/Volo/Abp/AbpApplication_Initialize_Tests.cs b/framework/test/Volo.Abp.Core.Tests/Volo/Abp/AbpApplication_Initialize_Tests.cs index f69d94ce61..9eff208198 100644 --- a/framework/test/Volo.Abp.Core.Tests/Volo/Abp/AbpApplication_Initialize_Tests.cs +++ b/framework/test/Volo.Abp.Core.Tests/Volo/Abp/AbpApplication_Initialize_Tests.cs @@ -1,6 +1,7 @@ using System.Threading.Tasks; using Microsoft.Extensions.DependencyInjection; using Shouldly; +using Volo.Abp.DependencyInjection; using Volo.Abp.Modularity; using Volo.Abp.Modularity.PlugIns; using Xunit; @@ -142,4 +143,40 @@ public class AbpApplication_Initialize_Tests plugInModule.OnApplicationShutdownIsCalled.ShouldBeTrue(); } } + + [Fact] + public void Should_Set_And_Get_ApplicationName() + { + const string applicationName = "MyApplication"; + + using (var application = AbpApplicationFactory.Create(options => + { + options.ApplicationName = applicationName; + })) + { + application.ApplicationName.ShouldBe(applicationName); + application.Services.GetApplicationName().ShouldBe(applicationName); + + application.Initialize(); + + application.ServiceProvider + .GetRequiredService() + .ApplicationName + .ShouldBe(applicationName); + } + } + + [Fact] + public async Task Should_Resolve_Root_Service_Provider() + { + using (var application = await AbpApplicationFactory.CreateAsync()) + { + await application.InitializeAsync(); + + application + .ServiceProvider + .GetRequiredService() + .ShouldNotBeNull(); + } + } } diff --git a/framework/test/Volo.Abp.Core.Tests/Volo/Abp/DependencyInjection/HybridServiceScopeFactory_Tests.cs b/framework/test/Volo.Abp.Core.Tests/Volo/Abp/DependencyInjection/HybridServiceScopeFactory_Tests.cs deleted file mode 100644 index 6a3f059ba8..0000000000 --- a/framework/test/Volo.Abp.Core.Tests/Volo/Abp/DependencyInjection/HybridServiceScopeFactory_Tests.cs +++ /dev/null @@ -1,71 +0,0 @@ -using System; -using System.Threading.Tasks; -using Microsoft.Extensions.DependencyInjection; -using Shouldly; -using Volo.Abp.Modularity; -using Xunit; - -namespace Volo.Abp.DependencyInjection; - -public class HybridServiceScopeFactory_Tests -{ - [Fact] - public async Task Should_Use_Default_ServiceScopeFactory_By_Default_Async() - { - using (var application = await AbpApplicationFactory.CreateAsync()) - { - application.Services.AddType(typeof(MyServiceAsync)); - - await application.InitializeAsync(); - - var serviceScopeFactory = application.ServiceProvider.GetRequiredService(); - - using (var scope = serviceScopeFactory.CreateScope()) - { - scope.ServiceProvider.GetRequiredService(); - } - - MyServiceAsync.DisposeCount.ShouldBe(1); - } - } - - [Fact] - public void Should_Use_Default_ServiceScopeFactory_By_Default() - { - using (var application = AbpApplicationFactory.Create()) - { - application.Services.AddType(typeof(MyService)); - - application.Initialize(); - - var serviceScopeFactory = application.ServiceProvider.GetRequiredService(); - - using (var scope = serviceScopeFactory.CreateScope()) - { - scope.ServiceProvider.GetRequiredService(); - } - - MyService.DisposeCount.ShouldBe(1); - } - } - - private class MyServiceAsync : ITransientDependency, IDisposable - { - public static int DisposeCount { get; private set; } - - public void Dispose() - { - ++DisposeCount; - } - } - - private class MyService : ITransientDependency, IDisposable - { - public static int DisposeCount { get; private set; } - - public void Dispose() - { - ++DisposeCount; - } - } -} diff --git a/framework/test/Volo.Abp.Features.Tests/Volo/Abp/Features/FeaturesSimpleStateCheckerSerializerContributor_Tests.cs b/framework/test/Volo.Abp.Features.Tests/Volo/Abp/Features/FeaturesSimpleStateCheckerSerializerContributor_Tests.cs new file mode 100644 index 0000000000..9791ac44bc --- /dev/null +++ b/framework/test/Volo.Abp.Features.Tests/Volo/Abp/Features/FeaturesSimpleStateCheckerSerializerContributor_Tests.cs @@ -0,0 +1,46 @@ +using System.Collections.Generic; +using System.Text.Json.Nodes; +using Shouldly; +using Volo.Abp.SimpleStateChecking; +using Xunit; + +namespace Volo.Abp.Features; + +public class FeaturesSimpleStateCheckerSerializerContributor_Tests +{ + [Fact] + public void Should_Serialize_RequireGlobalFeaturesSimpleStateChecker() + { + var serializer = new FeaturesSimpleStateCheckerSerializerContributor(); + + var result = serializer.SerializeToJson( + new RequireFeaturesSimpleStateChecker( + "FeatureA", + "FeatureB" + ) + ); + + result.ShouldBe("{\"T\":\"F\",\"A\":true,\"N\":[\"FeatureA\",\"FeatureB\"]}"); + } + + [Fact] + public void Should_Deserialize_RequireGlobalFeaturesSimpleStateChecker() + { + var serializer = new FeaturesSimpleStateCheckerSerializerContributor(); + + var jsonObject = (JsonObject)JsonNode.Parse("{\"T\":\"F\",\"A\":true,\"N\":[\"FeatureA\",\"FeatureB\"]}"); + var checker = serializer.Deserialize(jsonObject, new MyState()); + + checker.ShouldBeOfType>(); + var globalFeaturesSimpleStateChecker = checker as RequireFeaturesSimpleStateChecker; + globalFeaturesSimpleStateChecker.ShouldNotBeNull(); + globalFeaturesSimpleStateChecker.RequiresAll.ShouldBeTrue(); + globalFeaturesSimpleStateChecker.FeatureNames[0].ShouldBe("FeatureA"); + globalFeaturesSimpleStateChecker.FeatureNames[1].ShouldBe("FeatureB"); + } + + private class MyState : IHasSimpleStateCheckers + { + public List> StateCheckers { get; } = new(); + } +} \ No newline at end of file diff --git a/framework/test/Volo.Abp.GlobalFeatures.Tests/Volo/Abp/GlobalFeatures/GlobalFeaturesSimpleStateCheckerSerializerContributor_Tests.cs b/framework/test/Volo.Abp.GlobalFeatures.Tests/Volo/Abp/GlobalFeatures/GlobalFeaturesSimpleStateCheckerSerializerContributor_Tests.cs new file mode 100644 index 0000000000..e0425775dc --- /dev/null +++ b/framework/test/Volo.Abp.GlobalFeatures.Tests/Volo/Abp/GlobalFeatures/GlobalFeaturesSimpleStateCheckerSerializerContributor_Tests.cs @@ -0,0 +1,46 @@ +using System.Collections.Generic; +using System.Text.Json.Nodes; +using Shouldly; +using Volo.Abp.SimpleStateChecking; +using Xunit; + +namespace Volo.Abp.GlobalFeatures; + +public class GlobalFeaturesSimpleStateCheckerSerializerContributor_Tests +{ + [Fact] + public void Should_Serialize_RequireGlobalFeaturesSimpleStateChecker() + { + var serializer = new GlobalFeaturesSimpleStateCheckerSerializerContributor(); + + var result = serializer.SerializeToJson( + new RequireGlobalFeaturesSimpleStateChecker( + "FeatureA", + "FeatureB" + ) + ); + + result.ShouldBe("{\"T\":\"G\",\"A\":true,\"N\":[\"FeatureA\",\"FeatureB\"]}"); + } + + [Fact] + public void Should_Deserialize_RequireGlobalFeaturesSimpleStateChecker() + { + var serializer = new GlobalFeaturesSimpleStateCheckerSerializerContributor(); + + var jsonObject = (JsonObject)JsonNode.Parse("{\"T\":\"G\",\"A\":true,\"N\":[\"FeatureA\",\"FeatureB\"]}"); + var checker = serializer.Deserialize(jsonObject, new MyState()); + + checker.ShouldBeOfType>(); + var globalFeaturesSimpleStateChecker = checker as RequireGlobalFeaturesSimpleStateChecker; + globalFeaturesSimpleStateChecker.ShouldNotBeNull(); + globalFeaturesSimpleStateChecker.RequiresAll.ShouldBeTrue(); + globalFeaturesSimpleStateChecker.GlobalFeatureNames[0].ShouldBe("FeatureA"); + globalFeaturesSimpleStateChecker.GlobalFeatureNames[1].ShouldBe("FeatureB"); + } + + private class MyState : IHasSimpleStateCheckers + { + public List> StateCheckers { get; } = new(); + } +} \ No newline at end of file diff --git a/framework/test/Volo.Abp.Localization.Tests/Volo/Abp/Localization/AbpLocalizationTestModule.cs b/framework/test/Volo.Abp.Localization.Tests/Volo/Abp/Localization/AbpLocalizationTestModule.cs new file mode 100644 index 0000000000..340d091330 --- /dev/null +++ b/framework/test/Volo.Abp.Localization.Tests/Volo/Abp/Localization/AbpLocalizationTestModule.cs @@ -0,0 +1,39 @@ +using Volo.Abp.Localization.TestResources.Base.CountryNames; +using Volo.Abp.Localization.TestResources.Base.Validation; +using Volo.Abp.Localization.TestResources.Source; +using Volo.Abp.Modularity; +using Volo.Abp.VirtualFileSystem; + +namespace Volo.Abp.Localization; + +[DependsOn(typeof(AbpTestBaseModule))] +[DependsOn(typeof(AbpLocalizationModule))] +public class AbpLocalizationTestModule : AbpModule +{ + public override void ConfigureServices(ServiceConfigurationContext context) + { + Configure(options => + { + options.FileSets.AddEmbedded(); + }); + + Configure(options => + { + options.Resources + .Add("en") + .AddVirtualJson("/Volo/Abp/Localization/TestResources/Base/Validation"); + + options.Resources + .Add("en") + .AddVirtualJson("/Volo/Abp/Localization/TestResources/Base/CountryNames"); + + options.Resources + .Add("en") + .AddVirtualJson("/Volo/Abp/Localization/TestResources/Source"); + + options.Resources + .Get() + .AddVirtualJson("/Volo/Abp/Localization/TestResources/SourceExt"); + }); + } +} \ No newline at end of file diff --git a/framework/test/Volo.Abp.Localization.Tests/Volo/Abp/Localization/AbpLocalization_Tests.cs b/framework/test/Volo.Abp.Localization.Tests/Volo/Abp/Localization/AbpLocalization_Tests.cs index 6c4bdfff08..d643f163b9 100644 --- a/framework/test/Volo.Abp.Localization.Tests/Volo/Abp/Localization/AbpLocalization_Tests.cs +++ b/framework/test/Volo.Abp.Localization.Tests/Volo/Abp/Localization/AbpLocalization_Tests.cs @@ -2,17 +2,13 @@ using System.Globalization; using System.Linq; using Microsoft.Extensions.Localization; using Shouldly; -using Volo.Abp.Localization.TestResources.Base.CountryNames; -using Volo.Abp.Localization.TestResources.Base.Validation; using Volo.Abp.Localization.TestResources.Source; -using Volo.Abp.Modularity; using Volo.Abp.Testing; -using Volo.Abp.VirtualFileSystem; using Xunit; namespace Volo.Abp.Localization; -public class AbpLocalization_Tests : AbpIntegratedTest +public class AbpLocalization_Tests : AbpIntegratedTest { private readonly IStringLocalizer _localizer; private readonly IStringLocalizerFactory _localizerFactory; @@ -76,7 +72,6 @@ public class AbpLocalization_Tests : AbpIntegratedTest ls.Name == "USA"); } - } [Fact] @@ -275,7 +268,6 @@ public class AbpLocalization_Tests : AbpIntegratedTest(options => - { - options.FileSets.AddEmbedded(); - }); - - Configure(options => - { - options.Resources - .Add("en") - .AddVirtualJson("/Volo/Abp/Localization/TestResources/Base/Validation"); - - options.Resources - .Add("en") - .AddVirtualJson("/Volo/Abp/Localization/TestResources/Base/CountryNames"); - - options.Resources - .Add("en") - .AddVirtualJson("/Volo/Abp/Localization/TestResources/Source"); - - options.Resources - .Get() - .AddVirtualJson("/Volo/Abp/Localization/TestResources/SourceExt"); - }); - } - } -} +} \ No newline at end of file diff --git a/framework/test/Volo.Abp.Localization.Tests/Volo/Abp/Localization/LocalizableStringSerializer_Tests.cs b/framework/test/Volo.Abp.Localization.Tests/Volo/Abp/Localization/LocalizableStringSerializer_Tests.cs new file mode 100644 index 0000000000..d8fc1717d2 --- /dev/null +++ b/framework/test/Volo.Abp.Localization.Tests/Volo/Abp/Localization/LocalizableStringSerializer_Tests.cs @@ -0,0 +1,75 @@ +using Shouldly; +using Volo.Abp.Localization.TestResources.Source; +using Volo.Abp.Testing; +using Xunit; + +namespace Volo.Abp.Localization; + +public class LocalizableStringSerializer_Tests : AbpIntegratedTest +{ + private readonly ILocalizableStringSerializer _serializer; + + public LocalizableStringSerializer_Tests() + { + _serializer = GetRequiredService(); + } + + [Fact] + public void Serialize_FixedLocalizableString() + { + _serializer + .Serialize(new FixedLocalizableString("")) + .ShouldBe("F:"); + + _serializer + .Serialize(new FixedLocalizableString("Hello World")) + .ShouldBe("F:Hello World"); + } + + [Fact] + public void Serialize_LocalizableString() + { + _serializer + .Serialize(new LocalizableString(typeof(LocalizationTestResource),"Car")) + .ShouldBe("L:Test,Car"); + } + + [Fact] + public void Deserialize_FixedLocalizableString() + { + _serializer + .Deserialize("") + .ShouldBeOfType() + .Value.ShouldBe(""); + + _serializer + .Deserialize("Hello") + .ShouldBeOfType() + .Value.ShouldBe("Hello"); + + _serializer + .Deserialize("F:Hello") + .ShouldBeOfType() + .Value.ShouldBe("Hello"); + } + + [Fact] + public void Deserialize_LocalizableString() + { + var localizableString = _serializer + .Deserialize("L:Test,Car") + .ShouldBeOfType(); + localizableString.ResourceType.ShouldBe(typeof(LocalizationTestResource)); + localizableString.Name.ShouldBe("Car"); + + Assert.Throws(() => + { + _serializer.Deserialize("L:Test"); + }); + + Assert.Throws(() => + { + _serializer.Deserialize("L:Test, "); + }); + } +} \ No newline at end of file diff --git a/framework/test/Volo.Abp.Localization.Tests/Volo/Abp/Localization/TestResources/Source/LocalizationTestResource.cs b/framework/test/Volo.Abp.Localization.Tests/Volo/Abp/Localization/TestResources/Source/LocalizationTestResource.cs index 772acd78d3..bc32e98bcc 100644 --- a/framework/test/Volo.Abp.Localization.Tests/Volo/Abp/Localization/TestResources/Source/LocalizationTestResource.cs +++ b/framework/test/Volo.Abp.Localization.Tests/Volo/Abp/Localization/TestResources/Source/LocalizationTestResource.cs @@ -7,6 +7,7 @@ namespace Volo.Abp.Localization.TestResources.Source; typeof(LocalizationTestValidationResource), typeof(LocalizationTestCountryNamesResource) )] +[LocalizationResourceName("Test")] public sealed class LocalizationTestResource { diff --git a/framework/test/Volo.Abp.TestApp/Volo.Abp.TestApp.csproj b/framework/test/Volo.Abp.TestApp/Volo.Abp.TestApp.csproj index 0664ad2b7b..5a6382eb80 100644 --- a/framework/test/Volo.Abp.TestApp/Volo.Abp.TestApp.csproj +++ b/framework/test/Volo.Abp.TestApp/Volo.Abp.TestApp.csproj @@ -5,6 +5,7 @@ net6.0 + true diff --git a/framework/test/Volo.Abp.TestApp/Volo/Abp/TestApp/Testing/EntityChangeEvents_Tests.cs b/framework/test/Volo.Abp.TestApp/Volo/Abp/TestApp/Testing/EntityChangeEvents_Tests.cs index a94c722faf..12b3fa01c0 100644 --- a/framework/test/Volo.Abp.TestApp/Volo/Abp/TestApp/Testing/EntityChangeEvents_Tests.cs +++ b/framework/test/Volo.Abp.TestApp/Volo/Abp/TestApp/Testing/EntityChangeEvents_Tests.cs @@ -32,37 +32,18 @@ public abstract class EntityChangeEvents_Tests : TestAppTestBase { var personName = Guid.NewGuid().ToString("N"); - var creatingEventTriggered = false; var createdEventTriggered = false; var createdEtoTriggered = false; using (var uow = GetRequiredService().Begin()) { -#pragma warning disable 618 - LocalEventBus.Subscribe>(data => -#pragma warning restore 618 - { - creatingEventTriggered.ShouldBeFalse(); - createdEventTriggered.ShouldBeFalse(); - - creatingEventTriggered = true; - - data.Entity.Name.ShouldBe(personName); - - /* Want to change age from 15 to 18 */ - data.Entity.Age.ShouldBe(15); - data.Entity.Age = 18; - return Task.CompletedTask; - }); - LocalEventBus.Subscribe>(data => { - creatingEventTriggered.ShouldBeTrue(); createdEventTriggered.ShouldBeFalse(); createdEventTriggered = true; - data.Entity.Age.ShouldBe(18); + data.Entity.Age.ShouldBe(15); data.Entity.Name.ShouldBe(personName); return Task.CompletedTask; @@ -81,8 +62,7 @@ public abstract class EntityChangeEvents_Tests : TestAppTestBase await uow.CompleteAsync(); } - - creatingEventTriggered.ShouldBeTrue(); + createdEventTriggered.ShouldBeTrue(); createdEtoTriggered.ShouldBeTrue(); } diff --git a/framework/test/Volo.Abp.TestApp/Volo/Abp/TestApp/Testing/HasExtraPropertiesExtensions_Tests.cs b/framework/test/Volo.Abp.TestApp/Volo/Abp/TestApp/Testing/HasExtraPropertiesExtensions_Tests.cs index 95e222e2c7..4ad99fee1e 100644 --- a/framework/test/Volo.Abp.TestApp/Volo/Abp/TestApp/Testing/HasExtraPropertiesExtensions_Tests.cs +++ b/framework/test/Volo.Abp.TestApp/Volo/Abp/TestApp/Testing/HasExtraPropertiesExtensions_Tests.cs @@ -45,4 +45,25 @@ public class HasExtraPropertiesExtensions_Tests city.SetProperty("DateTime?", DateTime.MinValue); city.GetProperty("DateTime?").ShouldBe(DateTime.MinValue); } + + [Fact] + public void HasSameExtraProperties_Tests() + { + var adana = new City(Guid.NewGuid(), "Adana"); + adana.SetProperty("IsHot", true); + + var antalya = new City(Guid.NewGuid(), "Antalya"); + antalya.SetProperty("IsHot", true); + + adana.HasSameExtraProperties(antalya).ShouldBeTrue(); + + adana.SetProperty("IsHot", false); + adana.HasSameExtraProperties(antalya).ShouldBeFalse(); + + adana.SetProperty("IsHot", true); + adana.HasSameExtraProperties(antalya).ShouldBeTrue(); + + adana.SetProperty("Population", 3_000_000); + adana.HasSameExtraProperties(antalya).ShouldBeFalse(); + } } diff --git a/modules/account/src/Volo.Abp.Account.Application.Contracts/Volo/Abp/Account/Localization/Resources/ro-RO.json b/modules/account/src/Volo.Abp.Account.Application.Contracts/Volo/Abp/Account/Localization/Resources/ro-RO.json index c753009bb0..149ad71d95 100644 --- a/modules/account/src/Volo.Abp.Account.Application.Contracts/Volo/Abp/Account/Localization/Resources/ro-RO.json +++ b/modules/account/src/Volo.Abp.Account.Application.Contracts/Volo/Abp/Account/Localization/Resources/ro-RO.json @@ -27,7 +27,7 @@ "DisplayName:UserName": "Nume de utilizator", "DisplayName:Email": "Email", "DisplayName:Name": "Nume", - "DisplayName:Surname": "Surname", + "DisplayName:Surname": "Nume de familie", "DisplayName:Password": "Parolă", "DisplayName:EmailAddress": "Adresa de email", "DisplayName:PhoneNumber": "Număr de telefon", diff --git a/modules/background-jobs/src/Volo.Abp.BackgroundJobs.Domain/Volo/Abp/BackgroundJobs/BackgroundJobsDbProperties.cs b/modules/background-jobs/src/Volo.Abp.BackgroundJobs.Domain/Volo/Abp/BackgroundJobs/AbpBackgroundJobsDbProperties.cs similarity index 86% rename from modules/background-jobs/src/Volo.Abp.BackgroundJobs.Domain/Volo/Abp/BackgroundJobs/BackgroundJobsDbProperties.cs rename to modules/background-jobs/src/Volo.Abp.BackgroundJobs.Domain/Volo/Abp/BackgroundJobs/AbpBackgroundJobsDbProperties.cs index 401aa379a7..85e44815a2 100644 --- a/modules/background-jobs/src/Volo.Abp.BackgroundJobs.Domain/Volo/Abp/BackgroundJobs/BackgroundJobsDbProperties.cs +++ b/modules/background-jobs/src/Volo.Abp.BackgroundJobs.Domain/Volo/Abp/BackgroundJobs/AbpBackgroundJobsDbProperties.cs @@ -2,7 +2,7 @@ namespace Volo.Abp.BackgroundJobs; -public static class BackgroundJobsDbProperties +public static class AbpBackgroundJobsDbProperties { public static string DbTablePrefix { get; set; } = AbpCommonDbProperties.DbTablePrefix; diff --git a/modules/background-jobs/src/Volo.Abp.BackgroundJobs.EntityFrameworkCore/Volo/Abp/BackgroundJobs/EntityFrameworkCore/BackgroundJobsDbContext.cs b/modules/background-jobs/src/Volo.Abp.BackgroundJobs.EntityFrameworkCore/Volo/Abp/BackgroundJobs/EntityFrameworkCore/BackgroundJobsDbContext.cs index fb01736cfa..0beef8d3ea 100644 --- a/modules/background-jobs/src/Volo.Abp.BackgroundJobs.EntityFrameworkCore/Volo/Abp/BackgroundJobs/EntityFrameworkCore/BackgroundJobsDbContext.cs +++ b/modules/background-jobs/src/Volo.Abp.BackgroundJobs.EntityFrameworkCore/Volo/Abp/BackgroundJobs/EntityFrameworkCore/BackgroundJobsDbContext.cs @@ -6,7 +6,7 @@ using Volo.Abp.MultiTenancy; namespace Volo.Abp.BackgroundJobs.EntityFrameworkCore; [IgnoreMultiTenancy] -[ConnectionStringName(BackgroundJobsDbProperties.ConnectionStringName)] +[ConnectionStringName(AbpBackgroundJobsDbProperties.ConnectionStringName)] public class BackgroundJobsDbContext : AbpDbContext, IBackgroundJobsDbContext { public DbSet BackgroundJobs { get; set; } diff --git a/modules/background-jobs/src/Volo.Abp.BackgroundJobs.EntityFrameworkCore/Volo/Abp/BackgroundJobs/EntityFrameworkCore/BackgroundJobsDbContextModelCreatingExtensions.cs b/modules/background-jobs/src/Volo.Abp.BackgroundJobs.EntityFrameworkCore/Volo/Abp/BackgroundJobs/EntityFrameworkCore/BackgroundJobsDbContextModelCreatingExtensions.cs index bf9f8d5ea3..849ac3c5d5 100644 --- a/modules/background-jobs/src/Volo.Abp.BackgroundJobs.EntityFrameworkCore/Volo/Abp/BackgroundJobs/EntityFrameworkCore/BackgroundJobsDbContextModelCreatingExtensions.cs +++ b/modules/background-jobs/src/Volo.Abp.BackgroundJobs.EntityFrameworkCore/Volo/Abp/BackgroundJobs/EntityFrameworkCore/BackgroundJobsDbContextModelCreatingExtensions.cs @@ -18,7 +18,7 @@ public static class BackgroundJobsDbContextModelCreatingExtensions builder.Entity(b => { - b.ToTable(BackgroundJobsDbProperties.DbTablePrefix + "BackgroundJobs", BackgroundJobsDbProperties.DbSchema); + b.ToTable(AbpBackgroundJobsDbProperties.DbTablePrefix + "BackgroundJobs", AbpBackgroundJobsDbProperties.DbSchema); b.ConfigureByConvention(); diff --git a/modules/background-jobs/src/Volo.Abp.BackgroundJobs.EntityFrameworkCore/Volo/Abp/BackgroundJobs/EntityFrameworkCore/IBackgroundJobsDbContext.cs b/modules/background-jobs/src/Volo.Abp.BackgroundJobs.EntityFrameworkCore/Volo/Abp/BackgroundJobs/EntityFrameworkCore/IBackgroundJobsDbContext.cs index b091ac126a..a6276e37f8 100644 --- a/modules/background-jobs/src/Volo.Abp.BackgroundJobs.EntityFrameworkCore/Volo/Abp/BackgroundJobs/EntityFrameworkCore/IBackgroundJobsDbContext.cs +++ b/modules/background-jobs/src/Volo.Abp.BackgroundJobs.EntityFrameworkCore/Volo/Abp/BackgroundJobs/EntityFrameworkCore/IBackgroundJobsDbContext.cs @@ -6,7 +6,7 @@ using Volo.Abp.MultiTenancy; namespace Volo.Abp.BackgroundJobs.EntityFrameworkCore; [IgnoreMultiTenancy] -[ConnectionStringName(BackgroundJobsDbProperties.ConnectionStringName)] +[ConnectionStringName(AbpBackgroundJobsDbProperties.ConnectionStringName)] public interface IBackgroundJobsDbContext : IEfCoreDbContext { DbSet BackgroundJobs { get; } diff --git a/modules/background-jobs/src/Volo.Abp.BackgroundJobs.MongoDB/Volo/Abp/BackgroundJobs/MongoDB/BackgroundJobsMongoDbContext.cs b/modules/background-jobs/src/Volo.Abp.BackgroundJobs.MongoDB/Volo/Abp/BackgroundJobs/MongoDB/BackgroundJobsMongoDbContext.cs index 42b8a44f0d..8a94e26650 100644 --- a/modules/background-jobs/src/Volo.Abp.BackgroundJobs.MongoDB/Volo/Abp/BackgroundJobs/MongoDB/BackgroundJobsMongoDbContext.cs +++ b/modules/background-jobs/src/Volo.Abp.BackgroundJobs.MongoDB/Volo/Abp/BackgroundJobs/MongoDB/BackgroundJobsMongoDbContext.cs @@ -6,7 +6,7 @@ using Volo.Abp.MultiTenancy; namespace Volo.Abp.BackgroundJobs.MongoDB; [IgnoreMultiTenancy] -[ConnectionStringName(BackgroundJobsDbProperties.ConnectionStringName)] +[ConnectionStringName(AbpBackgroundJobsDbProperties.ConnectionStringName)] public class BackgroundJobsMongoDbContext : AbpMongoDbContext, IBackgroundJobsMongoDbContext { public IMongoCollection BackgroundJobs { get; set; } diff --git a/modules/background-jobs/src/Volo.Abp.BackgroundJobs.MongoDB/Volo/Abp/BackgroundJobs/MongoDB/BackgroundJobsMongoDbContextExtensions.cs b/modules/background-jobs/src/Volo.Abp.BackgroundJobs.MongoDB/Volo/Abp/BackgroundJobs/MongoDB/BackgroundJobsMongoDbContextExtensions.cs index b687bf8f90..a4f255c724 100644 --- a/modules/background-jobs/src/Volo.Abp.BackgroundJobs.MongoDB/Volo/Abp/BackgroundJobs/MongoDB/BackgroundJobsMongoDbContextExtensions.cs +++ b/modules/background-jobs/src/Volo.Abp.BackgroundJobs.MongoDB/Volo/Abp/BackgroundJobs/MongoDB/BackgroundJobsMongoDbContextExtensions.cs @@ -11,7 +11,7 @@ public static class BackgroundJobsMongoDbContextExtensions builder.Entity(b => { - b.CollectionName = BackgroundJobsDbProperties.DbTablePrefix + "BackgroundJobs"; + b.CollectionName = AbpBackgroundJobsDbProperties.DbTablePrefix + "BackgroundJobs"; }); } } diff --git a/modules/background-jobs/src/Volo.Abp.BackgroundJobs.MongoDB/Volo/Abp/BackgroundJobs/MongoDB/IBackgroundJobsMongoDbContext.cs b/modules/background-jobs/src/Volo.Abp.BackgroundJobs.MongoDB/Volo/Abp/BackgroundJobs/MongoDB/IBackgroundJobsMongoDbContext.cs index 4f93e1cbe5..d8a94b740d 100644 --- a/modules/background-jobs/src/Volo.Abp.BackgroundJobs.MongoDB/Volo/Abp/BackgroundJobs/MongoDB/IBackgroundJobsMongoDbContext.cs +++ b/modules/background-jobs/src/Volo.Abp.BackgroundJobs.MongoDB/Volo/Abp/BackgroundJobs/MongoDB/IBackgroundJobsMongoDbContext.cs @@ -6,7 +6,7 @@ using Volo.Abp.MultiTenancy; namespace Volo.Abp.BackgroundJobs.MongoDB; [IgnoreMultiTenancy] -[ConnectionStringName(BackgroundJobsDbProperties.ConnectionStringName)] +[ConnectionStringName(AbpBackgroundJobsDbProperties.ConnectionStringName)] public interface IBackgroundJobsMongoDbContext : IAbpMongoDbContext { IMongoCollection BackgroundJobs { get; } diff --git a/modules/basic-theme/src/Volo.Abp.AspNetCore.Components.Web.BasicTheme/Themes/Basic/MainLayout.razor b/modules/basic-theme/src/Volo.Abp.AspNetCore.Components.Web.BasicTheme/Themes/Basic/MainLayout.razor index 01500c8801..3565d6add5 100644 --- a/modules/basic-theme/src/Volo.Abp.AspNetCore.Components.Web.BasicTheme/Themes/Basic/MainLayout.razor +++ b/modules/basic-theme/src/Volo.Abp.AspNetCore.Components.Web.BasicTheme/Themes/Basic/MainLayout.razor @@ -1,4 +1,5 @@ -@using Volo.Abp.AspNetCore.Components.Web.Theming.Components; +@using Volo.Abp.Ui.LayoutHooks +@using Volo.Abp.AspNetCore.Components.Web.Theming.Layout @inherits LayoutComponentBase
+ @Body + diff --git a/modules/basic-theme/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic/Themes/Basic/Layouts/Account.cshtml b/modules/basic-theme/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic/Themes/Basic/Layouts/Account.cshtml index f71171912c..5e2ca98ba7 100644 --- a/modules/basic-theme/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic/Themes/Basic/Layouts/Account.cshtml +++ b/modules/basic-theme/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic/Themes/Basic/Layouts/Account.cshtml @@ -12,6 +12,7 @@ @using Volo.Abp.MultiTenancy @using Volo.Abp.Localization @using Volo.Abp.Ui.Branding +@using Volo.Abp.Ui.LayoutHooks @inject IBrandingProvider BrandingProvider @inject IOptions MultiTenancyOptions @inject ICurrentTenant CurrentTenant diff --git a/modules/basic-theme/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic/Themes/Basic/Layouts/Application.cshtml b/modules/basic-theme/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic/Themes/Basic/Layouts/Application.cshtml index 23c19c077d..42f2b2ead2 100644 --- a/modules/basic-theme/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic/Themes/Basic/Layouts/Application.cshtml +++ b/modules/basic-theme/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic/Themes/Basic/Layouts/Application.cshtml @@ -8,6 +8,7 @@ @using Volo.Abp.AspNetCore.Mvc.UI.Widgets.Components.WidgetStyles @using Volo.Abp.Localization @using Volo.Abp.Ui.Branding +@using Volo.Abp.Ui.LayoutHooks @inject IBrandingProvider BrandingProvider @inject IPageLayout PageLayout @{ diff --git a/modules/basic-theme/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic/Themes/Basic/Layouts/Empty.cshtml b/modules/basic-theme/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic/Themes/Basic/Layouts/Empty.cshtml index 70c7d5e1e8..6d3461be43 100644 --- a/modules/basic-theme/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic/Themes/Basic/Layouts/Empty.cshtml +++ b/modules/basic-theme/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic/Themes/Basic/Layouts/Empty.cshtml @@ -7,6 +7,7 @@ @using Volo.Abp.AspNetCore.Mvc.UI.Widgets.Components.WidgetStyles @using Volo.Abp.Localization @using Volo.Abp.Ui.Branding +@using Volo.Abp.Ui.LayoutHooks @inject IBrandingProvider BrandingProvider @inject IPageLayout PageLayout @{ diff --git a/modules/blob-storing-database/src/Volo.Abp.BlobStoring.Database.Domain/Volo/Abp/BlobStoring/Database/BlobStoringDatabaseDbProperties.cs b/modules/blob-storing-database/src/Volo.Abp.BlobStoring.Database.Domain/Volo/Abp/BlobStoring/Database/AbpBlobStoringDatabaseDbProperties.cs similarity index 85% rename from modules/blob-storing-database/src/Volo.Abp.BlobStoring.Database.Domain/Volo/Abp/BlobStoring/Database/BlobStoringDatabaseDbProperties.cs rename to modules/blob-storing-database/src/Volo.Abp.BlobStoring.Database.Domain/Volo/Abp/BlobStoring/Database/AbpBlobStoringDatabaseDbProperties.cs index a9689eb9fd..19985351de 100644 --- a/modules/blob-storing-database/src/Volo.Abp.BlobStoring.Database.Domain/Volo/Abp/BlobStoring/Database/BlobStoringDatabaseDbProperties.cs +++ b/modules/blob-storing-database/src/Volo.Abp.BlobStoring.Database.Domain/Volo/Abp/BlobStoring/Database/AbpBlobStoringDatabaseDbProperties.cs @@ -2,7 +2,7 @@ namespace Volo.Abp.BlobStoring.Database; -public static class BlobStoringDatabaseDbProperties +public static class AbpBlobStoringDatabaseDbProperties { public static string DbTablePrefix { get; set; } = AbpCommonDbProperties.DbTablePrefix; diff --git a/modules/blob-storing-database/src/Volo.Abp.BlobStoring.Database.EntityFrameworkCore/Volo/Abp/BlobStoring/Database/EntityFrameworkCore/BlobStoringDbContext.cs b/modules/blob-storing-database/src/Volo.Abp.BlobStoring.Database.EntityFrameworkCore/Volo/Abp/BlobStoring/Database/EntityFrameworkCore/BlobStoringDbContext.cs index b20f5190c4..f3e7661366 100644 --- a/modules/blob-storing-database/src/Volo.Abp.BlobStoring.Database.EntityFrameworkCore/Volo/Abp/BlobStoring/Database/EntityFrameworkCore/BlobStoringDbContext.cs +++ b/modules/blob-storing-database/src/Volo.Abp.BlobStoring.Database.EntityFrameworkCore/Volo/Abp/BlobStoring/Database/EntityFrameworkCore/BlobStoringDbContext.cs @@ -4,7 +4,7 @@ using Volo.Abp.EntityFrameworkCore; namespace Volo.Abp.BlobStoring.Database.EntityFrameworkCore; -[ConnectionStringName(BlobStoringDatabaseDbProperties.ConnectionStringName)] +[ConnectionStringName(AbpBlobStoringDatabaseDbProperties.ConnectionStringName)] public class BlobStoringDbContext : AbpDbContext, IBlobStoringDbContext { public DbSet BlobContainers { get; set; } diff --git a/modules/blob-storing-database/src/Volo.Abp.BlobStoring.Database.EntityFrameworkCore/Volo/Abp/BlobStoring/Database/EntityFrameworkCore/BlobStoringDbContextModelCreatingExtensions.cs b/modules/blob-storing-database/src/Volo.Abp.BlobStoring.Database.EntityFrameworkCore/Volo/Abp/BlobStoring/Database/EntityFrameworkCore/BlobStoringDbContextModelCreatingExtensions.cs index e4fad62e37..6be009f3ec 100644 --- a/modules/blob-storing-database/src/Volo.Abp.BlobStoring.Database.EntityFrameworkCore/Volo/Abp/BlobStoring/Database/EntityFrameworkCore/BlobStoringDbContextModelCreatingExtensions.cs +++ b/modules/blob-storing-database/src/Volo.Abp.BlobStoring.Database.EntityFrameworkCore/Volo/Abp/BlobStoring/Database/EntityFrameworkCore/BlobStoringDbContextModelCreatingExtensions.cs @@ -12,7 +12,7 @@ public static class BlobStoringDbContextModelCreatingExtensions builder.Entity(b => { - b.ToTable(BlobStoringDatabaseDbProperties.DbTablePrefix + "BlobContainers", BlobStoringDatabaseDbProperties.DbSchema); + b.ToTable(AbpBlobStoringDatabaseDbProperties.DbTablePrefix + "BlobContainers", AbpBlobStoringDatabaseDbProperties.DbSchema); b.ConfigureByConvention(); @@ -27,7 +27,7 @@ public static class BlobStoringDbContextModelCreatingExtensions builder.Entity(b => { - b.ToTable(BlobStoringDatabaseDbProperties.DbTablePrefix + "Blobs", BlobStoringDatabaseDbProperties.DbSchema); + b.ToTable(AbpBlobStoringDatabaseDbProperties.DbTablePrefix + "Blobs", AbpBlobStoringDatabaseDbProperties.DbSchema); b.ConfigureByConvention(); diff --git a/modules/blob-storing-database/src/Volo.Abp.BlobStoring.Database.EntityFrameworkCore/Volo/Abp/BlobStoring/Database/EntityFrameworkCore/IBlobStoringDbContext.cs b/modules/blob-storing-database/src/Volo.Abp.BlobStoring.Database.EntityFrameworkCore/Volo/Abp/BlobStoring/Database/EntityFrameworkCore/IBlobStoringDbContext.cs index b36c0753d3..b139d8473b 100644 --- a/modules/blob-storing-database/src/Volo.Abp.BlobStoring.Database.EntityFrameworkCore/Volo/Abp/BlobStoring/Database/EntityFrameworkCore/IBlobStoringDbContext.cs +++ b/modules/blob-storing-database/src/Volo.Abp.BlobStoring.Database.EntityFrameworkCore/Volo/Abp/BlobStoring/Database/EntityFrameworkCore/IBlobStoringDbContext.cs @@ -4,7 +4,7 @@ using Volo.Abp.EntityFrameworkCore; namespace Volo.Abp.BlobStoring.Database.EntityFrameworkCore; -[ConnectionStringName(BlobStoringDatabaseDbProperties.ConnectionStringName)] +[ConnectionStringName(AbpBlobStoringDatabaseDbProperties.ConnectionStringName)] public interface IBlobStoringDbContext : IEfCoreDbContext { DbSet BlobContainers { get; } diff --git a/modules/blob-storing-database/src/Volo.Abp.BlobStoring.Database.MongoDB/Volo/Abp/BlobStoring/Database/MongoDB/BlobStoringMongoDbContext.cs b/modules/blob-storing-database/src/Volo.Abp.BlobStoring.Database.MongoDB/Volo/Abp/BlobStoring/Database/MongoDB/BlobStoringMongoDbContext.cs index d0be5f4973..108804fbb9 100644 --- a/modules/blob-storing-database/src/Volo.Abp.BlobStoring.Database.MongoDB/Volo/Abp/BlobStoring/Database/MongoDB/BlobStoringMongoDbContext.cs +++ b/modules/blob-storing-database/src/Volo.Abp.BlobStoring.Database.MongoDB/Volo/Abp/BlobStoring/Database/MongoDB/BlobStoringMongoDbContext.cs @@ -4,7 +4,7 @@ using Volo.Abp.MongoDB; namespace Volo.Abp.BlobStoring.Database.MongoDB; -[ConnectionStringName(BlobStoringDatabaseDbProperties.ConnectionStringName)] +[ConnectionStringName(AbpBlobStoringDatabaseDbProperties.ConnectionStringName)] public class BlobStoringMongoDbContext : AbpMongoDbContext, IBlobStoringMongoDbContext { public IMongoCollection BlobContainers => Collection(); diff --git a/modules/blob-storing-database/src/Volo.Abp.BlobStoring.Database.MongoDB/Volo/Abp/BlobStoring/Database/MongoDB/BlobStoringMongoDbContextExtensions.cs b/modules/blob-storing-database/src/Volo.Abp.BlobStoring.Database.MongoDB/Volo/Abp/BlobStoring/Database/MongoDB/BlobStoringMongoDbContextExtensions.cs index 7943215534..28c3bdde7f 100644 --- a/modules/blob-storing-database/src/Volo.Abp.BlobStoring.Database.MongoDB/Volo/Abp/BlobStoring/Database/MongoDB/BlobStoringMongoDbContextExtensions.cs +++ b/modules/blob-storing-database/src/Volo.Abp.BlobStoring.Database.MongoDB/Volo/Abp/BlobStoring/Database/MongoDB/BlobStoringMongoDbContextExtensions.cs @@ -11,12 +11,12 @@ public static class BlobStoringMongoDbContextExtensions builder.Entity(b => { - b.CollectionName = BlobStoringDatabaseDbProperties.DbTablePrefix + "BlobContainers"; + b.CollectionName = AbpBlobStoringDatabaseDbProperties.DbTablePrefix + "BlobContainers"; }); builder.Entity(b => { - b.CollectionName = BlobStoringDatabaseDbProperties.DbTablePrefix + "Blobs"; + b.CollectionName = AbpBlobStoringDatabaseDbProperties.DbTablePrefix + "Blobs"; }); } } diff --git a/modules/blob-storing-database/src/Volo.Abp.BlobStoring.Database.MongoDB/Volo/Abp/BlobStoring/Database/MongoDB/IBlobStoringMongoDbContext.cs b/modules/blob-storing-database/src/Volo.Abp.BlobStoring.Database.MongoDB/Volo/Abp/BlobStoring/Database/MongoDB/IBlobStoringMongoDbContext.cs index 1fcf61b146..803ed5171d 100644 --- a/modules/blob-storing-database/src/Volo.Abp.BlobStoring.Database.MongoDB/Volo/Abp/BlobStoring/Database/MongoDB/IBlobStoringMongoDbContext.cs +++ b/modules/blob-storing-database/src/Volo.Abp.BlobStoring.Database.MongoDB/Volo/Abp/BlobStoring/Database/MongoDB/IBlobStoringMongoDbContext.cs @@ -4,7 +4,7 @@ using Volo.Abp.MongoDB; namespace Volo.Abp.BlobStoring.Database.MongoDB; -[ConnectionStringName(BlobStoringDatabaseDbProperties.ConnectionStringName)] +[ConnectionStringName(AbpBlobStoringDatabaseDbProperties.ConnectionStringName)] public interface IBlobStoringMongoDbContext : IAbpMongoDbContext { IMongoCollection BlobContainers { get; } diff --git a/modules/blogging/src/Volo.Blogging.Domain.Shared/Volo/Blogging/Localization/Resources/pt-BR.json b/modules/blogging/src/Volo.Blogging.Domain.Shared/Volo/Blogging/Localization/Resources/pt-BR.json index f26b339d71..bb19760972 100644 --- a/modules/blogging/src/Volo.Blogging.Domain.Shared/Volo/Blogging/Localization/Resources/pt-BR.json +++ b/modules/blogging/src/Volo.Blogging.Domain.Shared/Volo/Blogging/Localization/Resources/pt-BR.json @@ -37,7 +37,7 @@ "Edit": "Editar", "BLOG": "BLOG", "CommentDeletionWarningMessage": "O comentário será excluído.", - "PostDeletionWarningMessage": "O post será excluído.", + "PostDeletionWarningMessage": "A postagem será excluída.", "BlogDeletionWarningMessage": "O Blog será excluído.", "AreYouSure": "Você tem certeza?", "CommentWithCount": "{0} comentários", @@ -54,8 +54,10 @@ "Blogs": "Blogs", "Tags": "Etiquetas", "ShareOn": "Compartilhar no", - "TitleLengthWarning": "Mantenha o tamanho do título abaixo de 60 caracteres para ser SEO amigável!", + "TitleLengthWarning": "Mantenha o tamanho do título abaixo de 60 caracteres para ser amigável ao SEO!", "ClearCache": "Limpar cache", - "ClearCacheConfirmationMessage": "Tem certeza de que deseja limpar o cache?" + "ClearCacheConfirmationMessage": "Tem certeza de que deseja limpar o cache?", + "MarkdownSupported": "Markdown é suportado", + "FileUploadInfo": "Arrastar, soltar, ou colar uma imagem copiada." } } \ No newline at end of file diff --git a/modules/blogging/src/Volo.Blogging.Domain/Volo/Blogging/BloggingDbProperties.cs b/modules/blogging/src/Volo.Blogging.Domain/Volo/Blogging/AbpBloggingDbProperties.cs similarity index 90% rename from modules/blogging/src/Volo.Blogging.Domain/Volo/Blogging/BloggingDbProperties.cs rename to modules/blogging/src/Volo.Blogging.Domain/Volo/Blogging/AbpBloggingDbProperties.cs index 6f57d5f404..464ea2c348 100644 --- a/modules/blogging/src/Volo.Blogging.Domain/Volo/Blogging/BloggingDbProperties.cs +++ b/modules/blogging/src/Volo.Blogging.Domain/Volo/Blogging/AbpBloggingDbProperties.cs @@ -1,6 +1,6 @@ namespace Volo.Blogging { - public static class BloggingDbProperties + public static class AbpBloggingDbProperties { /// /// Default value: "Blg". diff --git a/modules/blogging/src/Volo.Blogging.EntityFrameworkCore/Volo/Blogging/EntityFrameworkCore/BloggingDbContext.cs b/modules/blogging/src/Volo.Blogging.EntityFrameworkCore/Volo/Blogging/EntityFrameworkCore/BloggingDbContext.cs index 85c34aa996..9ccbe3aa3b 100644 --- a/modules/blogging/src/Volo.Blogging.EntityFrameworkCore/Volo/Blogging/EntityFrameworkCore/BloggingDbContext.cs +++ b/modules/blogging/src/Volo.Blogging.EntityFrameworkCore/Volo/Blogging/EntityFrameworkCore/BloggingDbContext.cs @@ -11,7 +11,7 @@ using Volo.Blogging.Users; namespace Volo.Blogging.EntityFrameworkCore { [IgnoreMultiTenancy] - [ConnectionStringName(BloggingDbProperties.ConnectionStringName)] + [ConnectionStringName(AbpBloggingDbProperties.ConnectionStringName)] public class BloggingDbContext : AbpDbContext, IBloggingDbContext { public DbSet Users { get; set; } diff --git a/modules/blogging/src/Volo.Blogging.EntityFrameworkCore/Volo/Blogging/EntityFrameworkCore/BloggingDbContextModelBuilderExtensions.cs b/modules/blogging/src/Volo.Blogging.EntityFrameworkCore/Volo/Blogging/EntityFrameworkCore/BloggingDbContextModelBuilderExtensions.cs index 3386da25a5..abf96ebcef 100644 --- a/modules/blogging/src/Volo.Blogging.EntityFrameworkCore/Volo/Blogging/EntityFrameworkCore/BloggingDbContextModelBuilderExtensions.cs +++ b/modules/blogging/src/Volo.Blogging.EntityFrameworkCore/Volo/Blogging/EntityFrameworkCore/BloggingDbContextModelBuilderExtensions.cs @@ -25,7 +25,7 @@ namespace Volo.Blogging.EntityFrameworkCore builder.Entity(b => { - b.ToTable(BloggingDbProperties.DbTablePrefix + "Users", BloggingDbProperties.DbSchema); + b.ToTable(AbpBloggingDbProperties.DbTablePrefix + "Users", AbpBloggingDbProperties.DbSchema); b.ConfigureByConvention(); b.ConfigureAbpUser(); @@ -35,7 +35,7 @@ namespace Volo.Blogging.EntityFrameworkCore builder.Entity(b => { - b.ToTable(BloggingDbProperties.DbTablePrefix + "Blogs", BloggingDbProperties.DbSchema); + b.ToTable(AbpBloggingDbProperties.DbTablePrefix + "Blogs", AbpBloggingDbProperties.DbSchema); b.ConfigureByConvention(); @@ -48,7 +48,7 @@ namespace Volo.Blogging.EntityFrameworkCore builder.Entity(b => { - b.ToTable(BloggingDbProperties.DbTablePrefix + "Posts", BloggingDbProperties.DbSchema); + b.ToTable(AbpBloggingDbProperties.DbTablePrefix + "Posts", AbpBloggingDbProperties.DbSchema); b.ConfigureByConvention(); @@ -68,7 +68,7 @@ namespace Volo.Blogging.EntityFrameworkCore builder.Entity(b => { - b.ToTable(BloggingDbProperties.DbTablePrefix + "Comments", BloggingDbProperties.DbSchema); + b.ToTable(AbpBloggingDbProperties.DbTablePrefix + "Comments", AbpBloggingDbProperties.DbSchema); b.ConfigureByConvention(); @@ -84,7 +84,7 @@ namespace Volo.Blogging.EntityFrameworkCore builder.Entity(b => { - b.ToTable(BloggingDbProperties.DbTablePrefix + "Tags", BloggingDbProperties.DbSchema); + b.ToTable(AbpBloggingDbProperties.DbTablePrefix + "Tags", AbpBloggingDbProperties.DbSchema); b.ConfigureByConvention(); @@ -99,7 +99,7 @@ namespace Volo.Blogging.EntityFrameworkCore builder.Entity(b => { - b.ToTable(BloggingDbProperties.DbTablePrefix + "PostTags", BloggingDbProperties.DbSchema); + b.ToTable(AbpBloggingDbProperties.DbTablePrefix + "PostTags", AbpBloggingDbProperties.DbSchema); b.ConfigureByConvention(); diff --git a/modules/blogging/src/Volo.Blogging.EntityFrameworkCore/Volo/Blogging/EntityFrameworkCore/IBloggingDbContext.cs b/modules/blogging/src/Volo.Blogging.EntityFrameworkCore/Volo/Blogging/EntityFrameworkCore/IBloggingDbContext.cs index 4eb8f35c03..ce63597029 100644 --- a/modules/blogging/src/Volo.Blogging.EntityFrameworkCore/Volo/Blogging/EntityFrameworkCore/IBloggingDbContext.cs +++ b/modules/blogging/src/Volo.Blogging.EntityFrameworkCore/Volo/Blogging/EntityFrameworkCore/IBloggingDbContext.cs @@ -11,7 +11,7 @@ using Volo.Blogging.Users; namespace Volo.Blogging.EntityFrameworkCore { [IgnoreMultiTenancy] - [ConnectionStringName(BloggingDbProperties.ConnectionStringName)] + [ConnectionStringName(AbpBloggingDbProperties.ConnectionStringName)] public interface IBloggingDbContext : IEfCoreDbContext { DbSet Users { get; } diff --git a/modules/blogging/src/Volo.Blogging.MongoDB/Volo/Blogging/MongoDB/BloggingMongoDbContext.cs b/modules/blogging/src/Volo.Blogging.MongoDB/Volo/Blogging/MongoDB/BloggingMongoDbContext.cs index 1f20ff1744..d782f0fb1b 100644 --- a/modules/blogging/src/Volo.Blogging.MongoDB/Volo/Blogging/MongoDB/BloggingMongoDbContext.cs +++ b/modules/blogging/src/Volo.Blogging.MongoDB/Volo/Blogging/MongoDB/BloggingMongoDbContext.cs @@ -10,7 +10,7 @@ using Volo.Blogging.Users; namespace Volo.Blogging.MongoDB { [IgnoreMultiTenancy] - [ConnectionStringName(BloggingDbProperties.ConnectionStringName)] + [ConnectionStringName(AbpBloggingDbProperties.ConnectionStringName)] public class BloggingMongoDbContext : AbpMongoDbContext, IBloggingMongoDbContext { public IMongoCollection Users => Collection(); diff --git a/modules/blogging/src/Volo.Blogging.MongoDB/Volo/Blogging/MongoDB/BloggingMongoDbContextExtensions.cs b/modules/blogging/src/Volo.Blogging.MongoDB/Volo/Blogging/MongoDB/BloggingMongoDbContextExtensions.cs index b04f0a74fc..1083169761 100644 --- a/modules/blogging/src/Volo.Blogging.MongoDB/Volo/Blogging/MongoDB/BloggingMongoDbContextExtensions.cs +++ b/modules/blogging/src/Volo.Blogging.MongoDB/Volo/Blogging/MongoDB/BloggingMongoDbContextExtensions.cs @@ -16,27 +16,27 @@ namespace Volo.Blogging.MongoDB builder.Entity(b => { - b.CollectionName = BloggingDbProperties.DbTablePrefix + "Users"; + b.CollectionName = AbpBloggingDbProperties.DbTablePrefix + "Users"; }); builder.Entity(b => { - b.CollectionName = BloggingDbProperties.DbTablePrefix + "Blogs"; + b.CollectionName = AbpBloggingDbProperties.DbTablePrefix + "Blogs"; }); builder.Entity(b => { - b.CollectionName = BloggingDbProperties.DbTablePrefix + "Posts"; + b.CollectionName = AbpBloggingDbProperties.DbTablePrefix + "Posts"; }); builder.Entity(b => { - b.CollectionName = BloggingDbProperties.DbTablePrefix + "Tags"; + b.CollectionName = AbpBloggingDbProperties.DbTablePrefix + "Tags"; }); builder.Entity(b => { - b.CollectionName = BloggingDbProperties.DbTablePrefix + "Comments"; + b.CollectionName = AbpBloggingDbProperties.DbTablePrefix + "Comments"; }); } } diff --git a/modules/blogging/src/Volo.Blogging.MongoDB/Volo/Blogging/MongoDB/IBloggingMongoDbContext.cs b/modules/blogging/src/Volo.Blogging.MongoDB/Volo/Blogging/MongoDB/IBloggingMongoDbContext.cs index 1dbf5eee92..d3c898a14d 100644 --- a/modules/blogging/src/Volo.Blogging.MongoDB/Volo/Blogging/MongoDB/IBloggingMongoDbContext.cs +++ b/modules/blogging/src/Volo.Blogging.MongoDB/Volo/Blogging/MongoDB/IBloggingMongoDbContext.cs @@ -10,7 +10,7 @@ using Volo.Blogging.Users; namespace Volo.Blogging.MongoDB { [IgnoreMultiTenancy] - [ConnectionStringName(BloggingDbProperties.ConnectionStringName)] + [ConnectionStringName(AbpBloggingDbProperties.ConnectionStringName)] public interface IBloggingMongoDbContext : IAbpMongoDbContext { IMongoCollection Users { get; } diff --git a/modules/cms-kit/src/Volo.CmsKit.Admin.Application.Contracts/Volo/CmsKit/Admin/Tags/EntityTagSetDto.cs b/modules/cms-kit/src/Volo.CmsKit.Admin.Application.Contracts/Volo/CmsKit/Admin/Tags/EntityTagSetDto.cs index 245526cfc2..11466463f8 100644 --- a/modules/cms-kit/src/Volo.CmsKit.Admin.Application.Contracts/Volo/CmsKit/Admin/Tags/EntityTagSetDto.cs +++ b/modules/cms-kit/src/Volo.CmsKit.Admin.Application.Contracts/Volo/CmsKit/Admin/Tags/EntityTagSetDto.cs @@ -1,15 +1,40 @@ using System; using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; +using System.ComponentModel.DataAnnotations; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Localization; +using Volo.Abp.Validation.Localization; +using Volo.CmsKit.Localization; +using Volo.CmsKit.Tags; namespace Volo.CmsKit.Admin.Tags; [Serializable] -public class EntityTagSetDto +public class EntityTagSetDto : IValidatableObject { public string EntityId { get; set; } + public string EntityType { get; set; } + + [Required] public List Tags { get; set; } + + public IEnumerable Validate(ValidationContext validationContext) + { + var l = validationContext.GetRequiredService>(); + + foreach (var tag in Tags) + { + if (tag.Length > TagConsts.MaxNameLength) + { + yield return new ValidationResult( + l[ + "ThisFieldMustBeAStringWithAMaximumLengthOf{0}", + TagConsts.MaxNameLength + ], + new[] { nameof(Tags) } + ); + } + } + } } diff --git a/modules/cms-kit/src/Volo.CmsKit.Admin.Application/Volo/CmsKit/Admin/Blogs/BlogAdminAppService.cs b/modules/cms-kit/src/Volo.CmsKit.Admin.Application/Volo/CmsKit/Admin/Blogs/BlogAdminAppService.cs index 7cd17b7696..5736048076 100644 --- a/modules/cms-kit/src/Volo.CmsKit.Admin.Application/Volo/CmsKit/Admin/Blogs/BlogAdminAppService.cs +++ b/modules/cms-kit/src/Volo.CmsKit.Admin.Application/Volo/CmsKit/Admin/Blogs/BlogAdminAppService.cs @@ -1,16 +1,19 @@ -using Microsoft.AspNetCore.Authorization; -using System; +using System; using System.Collections.Generic; using System.Threading.Tasks; +using Microsoft.AspNetCore.Authorization; using Volo.Abp.Application.Dtos; using Volo.Abp.Data; +using Volo.Abp.Features; using Volo.Abp.GlobalFeatures; using Volo.CmsKit.Blogs; +using Volo.CmsKit.Features; using Volo.CmsKit.GlobalFeatures; using Volo.CmsKit.Permissions; namespace Volo.CmsKit.Admin.Blogs; +[RequiresFeature(CmsKitFeatures.BlogEnable)] [RequiresGlobalFeature(typeof(BlogsFeature))] [Authorize(CmsKitAdminPermissions.Blogs.Default)] public class BlogAdminAppService : CmsKitAdminAppServiceBase, IBlogAdminAppService diff --git a/modules/cms-kit/src/Volo.CmsKit.Admin.Application/Volo/CmsKit/Admin/Blogs/BlogFeatureAdminAppService.cs b/modules/cms-kit/src/Volo.CmsKit.Admin.Application/Volo/CmsKit/Admin/Blogs/BlogFeatureAdminAppService.cs index 823f569bed..774f28634d 100644 --- a/modules/cms-kit/src/Volo.CmsKit.Admin.Application/Volo/CmsKit/Admin/Blogs/BlogFeatureAdminAppService.cs +++ b/modules/cms-kit/src/Volo.CmsKit.Admin.Application/Volo/CmsKit/Admin/Blogs/BlogFeatureAdminAppService.cs @@ -1,15 +1,18 @@ -using Microsoft.AspNetCore.Authorization; -using System; +using System; using System.Collections.Generic; using System.Threading.Tasks; +using Microsoft.AspNetCore.Authorization; using Volo.Abp.EventBus.Distributed; +using Volo.Abp.Features; using Volo.Abp.GlobalFeatures; using Volo.CmsKit.Blogs; +using Volo.CmsKit.Features; using Volo.CmsKit.GlobalFeatures; using Volo.CmsKit.Permissions; namespace Volo.CmsKit.Admin.Blogs; +[RequiresFeature(CmsKitFeatures.BlogEnable)] [RequiresGlobalFeature(typeof(BlogsFeature))] [Authorize(CmsKitAdminPermissions.Blogs.Features)] public class BlogFeatureAdminAppService : CmsKitAdminAppServiceBase, IBlogFeatureAdminAppService diff --git a/modules/cms-kit/src/Volo.CmsKit.Admin.Application/Volo/CmsKit/Admin/Blogs/BlogPostAdminAppService.cs b/modules/cms-kit/src/Volo.CmsKit.Admin.Application/Volo/CmsKit/Admin/Blogs/BlogPostAdminAppService.cs index 9d8fcfd917..297e70344f 100644 --- a/modules/cms-kit/src/Volo.CmsKit.Admin.Application/Volo/CmsKit/Admin/Blogs/BlogPostAdminAppService.cs +++ b/modules/cms-kit/src/Volo.CmsKit.Admin.Application/Volo/CmsKit/Admin/Blogs/BlogPostAdminAppService.cs @@ -1,19 +1,22 @@ -using Microsoft.AspNetCore.Authorization; -using System; +using System; using System.Linq; using System.Threading.Tasks; +using Microsoft.AspNetCore.Authorization; using Volo.Abp.Application.Dtos; using Volo.Abp.Data; +using Volo.Abp.Features; using Volo.Abp.GlobalFeatures; using Volo.Abp.Users; using Volo.CmsKit.Admin.MediaDescriptors; using Volo.CmsKit.Blogs; +using Volo.CmsKit.Features; using Volo.CmsKit.GlobalFeatures; using Volo.CmsKit.Permissions; using Volo.CmsKit.Users; namespace Volo.CmsKit.Admin.Blogs; +[RequiresFeature(CmsKitFeatures.BlogEnable)] [RequiresGlobalFeature(typeof(BlogsFeature))] [Authorize(CmsKitAdminPermissions.BlogPosts.Default)] public class BlogPostAdminAppService : CmsKitAppServiceBase, IBlogPostAdminAppService @@ -66,18 +69,18 @@ public class BlogPostAdminAppService : CmsKitAppServiceBase, IBlogPostAdminAppSe public virtual async Task UpdateAsync(Guid id, UpdateBlogPostDto input) { var blogPost = await BlogPostRepository.GetAsync(id); - + blogPost.SetTitle(input.Title); blogPost.SetShortDescription(input.ShortDescription); blogPost.SetContent(input.Content); blogPost.SetConcurrencyStampIfNotNull(input.ConcurrencyStamp); - + if (blogPost.CoverImageMediaId != null && input.CoverImageMediaId == null) { await MediaDescriptorAdminAppService.DeleteAsync(blogPost.CoverImageMediaId.Value); } blogPost.CoverImageMediaId = input.CoverImageMediaId; - + if (blogPost.Slug != input.Slug) { await BlogPostManager.SetSlugUrlAsync(blogPost, input.Slug); @@ -146,12 +149,12 @@ public class BlogPostAdminAppService : CmsKitAppServiceBase, IBlogPostAdminAppSe { var blogPost = await CreateAsync(input); await CurrentUnitOfWork.SaveChangesAsync(); - + await PublishAsync(blogPost.Id); blogPost.Status = BlogPostStatus.Published; return blogPost; } - + [Authorize(CmsKitAdminPermissions.BlogPosts.Create)] public virtual async Task SendToReviewAsync(Guid id) { @@ -159,13 +162,13 @@ public class BlogPostAdminAppService : CmsKitAppServiceBase, IBlogPostAdminAppSe blogPost.SetWaitingForReview(); await BlogPostRepository.UpdateAsync(blogPost); } - + [Authorize(CmsKitAdminPermissions.BlogPosts.Create)] public virtual async Task CreateAndSendToReviewAsync(CreateBlogPostDto input) { var blogPost = await CreateAsync(input); await CurrentUnitOfWork.SaveChangesAsync(); - + await SendToReviewAsync(blogPost.Id); blogPost.Status = BlogPostStatus.WaitingForReview; return blogPost; diff --git a/modules/cms-kit/src/Volo.CmsKit.Admin.Application/Volo/CmsKit/Admin/Comments/CommentAdminAppService.cs b/modules/cms-kit/src/Volo.CmsKit.Admin.Application/Volo/CmsKit/Admin/Comments/CommentAdminAppService.cs index 5295557860..973a74b58e 100644 --- a/modules/cms-kit/src/Volo.CmsKit.Admin.Application/Volo/CmsKit/Admin/Comments/CommentAdminAppService.cs +++ b/modules/cms-kit/src/Volo.CmsKit.Admin.Application/Volo/CmsKit/Admin/Comments/CommentAdminAppService.cs @@ -3,14 +3,17 @@ using System.Linq; using System.Threading.Tasks; using Microsoft.AspNetCore.Authorization; using Volo.Abp.Application.Dtos; +using Volo.Abp.Features; using Volo.Abp.GlobalFeatures; using Volo.CmsKit.Comments; +using Volo.CmsKit.Features; using Volo.CmsKit.GlobalFeatures; using Volo.CmsKit.Permissions; using Volo.CmsKit.Users; namespace Volo.CmsKit.Admin.Comments; +[RequiresFeature(CmsKitFeatures.CommentEnable)] [RequiresGlobalFeature(typeof(CommentsFeature))] [Authorize(CmsKitAdminPermissions.Comments.Default)] public class CommentAdminAppService : CmsKitAdminAppServiceBase, ICommentAdminAppService diff --git a/modules/cms-kit/src/Volo.CmsKit.Admin.Application/Volo/CmsKit/Admin/GlobalResources/GlobalResourceAdminAppService.cs b/modules/cms-kit/src/Volo.CmsKit.Admin.Application/Volo/CmsKit/Admin/GlobalResources/GlobalResourceAdminAppService.cs index a78a21de41..c5b63db6c3 100644 --- a/modules/cms-kit/src/Volo.CmsKit.Admin.Application/Volo/CmsKit/Admin/GlobalResources/GlobalResourceAdminAppService.cs +++ b/modules/cms-kit/src/Volo.CmsKit.Admin.Application/Volo/CmsKit/Admin/GlobalResources/GlobalResourceAdminAppService.cs @@ -1,13 +1,16 @@ using System.Threading.Tasks; using Microsoft.AspNetCore.Authorization; using Volo.Abp.Application.Services; +using Volo.Abp.Features; using Volo.Abp.GlobalFeatures; +using Volo.CmsKit.Features; using Volo.CmsKit.GlobalFeatures; using Volo.CmsKit.GlobalResources; using Volo.CmsKit.Permissions; namespace Volo.CmsKit.Admin.GlobalResources; +[RequiresFeature(CmsKitFeatures.GlobalResourceEnable)] [RequiresGlobalFeature(typeof(GlobalResourcesFeature))] [Authorize(CmsKitAdminPermissions.GlobalResources.Default)] public class GlobalResourceAdminAppService : ApplicationService, IGlobalResourceAdminAppService @@ -18,10 +21,11 @@ public class GlobalResourceAdminAppService : ApplicationService, IGlobalResource { GlobalResourceManager = globalResourceManager; } - + public async Task GetAsync() { - return new GlobalResourcesDto { + return new GlobalResourcesDto + { StyleContent = (await GlobalResourceManager.GetGlobalStyleAsync()).Value, ScriptContent = (await GlobalResourceManager.GetGlobalScriptAsync()).Value }; 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 cc785adac0..af347bcc55 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 @@ -1,12 +1,15 @@ using System; using System.Threading.Tasks; using Volo.Abp.BlobStoring; +using Volo.Abp.Features; using Volo.Abp.GlobalFeatures; +using Volo.CmsKit.Features; using Volo.CmsKit.GlobalFeatures; using Volo.CmsKit.MediaDescriptors; namespace Volo.CmsKit.Admin.MediaDescriptors; +[RequiresFeature(CmsKitFeatures.MediaEnable)] [RequiresGlobalFeature(typeof(MediaFeature))] public class MediaDescriptorAdminAppService : CmsKitAdminAppServiceBase, IMediaDescriptorAdminAppService { diff --git a/modules/cms-kit/src/Volo.CmsKit.Admin.Application/Volo/CmsKit/Admin/Menus/MenuItemAdminAppService.cs b/modules/cms-kit/src/Volo.CmsKit.Admin.Application/Volo/CmsKit/Admin/Menus/MenuItemAdminAppService.cs index 8ef6ce0346..3ba2a4b5b9 100644 --- a/modules/cms-kit/src/Volo.CmsKit.Admin.Application/Volo/CmsKit/Admin/Menus/MenuItemAdminAppService.cs +++ b/modules/cms-kit/src/Volo.CmsKit.Admin.Application/Volo/CmsKit/Admin/Menus/MenuItemAdminAppService.cs @@ -1,12 +1,12 @@ -using Microsoft.AspNetCore.Authorization; -using System; +using System; using System.Collections.Generic; -using System.Linq; -using System.Text; using System.Threading.Tasks; +using Microsoft.AspNetCore.Authorization; using Volo.Abp.Application.Dtos; using Volo.Abp.Data; +using Volo.Abp.Features; using Volo.Abp.GlobalFeatures; +using Volo.CmsKit.Features; using Volo.CmsKit.GlobalFeatures; using Volo.CmsKit.Menus; using Volo.CmsKit.Pages; @@ -14,6 +14,7 @@ using Volo.CmsKit.Permissions; namespace Volo.CmsKit.Admin.Menus; +[RequiresFeature(CmsKitFeatures.MenuEnable)] [RequiresGlobalFeature(typeof(MenuFeature))] [Authorize(CmsKitAdminPermissions.Menus.Default)] public class MenuItemAdminAppService : CmsKitAdminAppServiceBase, IMenuItemAdminAppService diff --git a/modules/cms-kit/src/Volo.CmsKit.Admin.Application/Volo/CmsKit/Admin/Pages/PageAdminAppService.cs b/modules/cms-kit/src/Volo.CmsKit.Admin.Application/Volo/CmsKit/Admin/Pages/PageAdminAppService.cs index 68f0690555..647568e561 100644 --- a/modules/cms-kit/src/Volo.CmsKit.Admin.Application/Volo/CmsKit/Admin/Pages/PageAdminAppService.cs +++ b/modules/cms-kit/src/Volo.CmsKit.Admin.Application/Volo/CmsKit/Admin/Pages/PageAdminAppService.cs @@ -1,18 +1,19 @@ using System; using System.Collections.Generic; using System.Threading.Tasks; -using AutoMapper; using Microsoft.AspNetCore.Authorization; using Volo.Abp.Application.Dtos; using Volo.Abp.Data; +using Volo.Abp.Features; using Volo.Abp.GlobalFeatures; -using Volo.CmsKit.Admin.Menus; +using Volo.CmsKit.Features; using Volo.CmsKit.GlobalFeatures; using Volo.CmsKit.Pages; using Volo.CmsKit.Permissions; namespace Volo.CmsKit.Admin.Pages; +[RequiresFeature(CmsKitFeatures.PageEnable)] [RequiresGlobalFeature(typeof(PagesFeature))] [Authorize(CmsKitAdminPermissions.Pages.Default)] public class PageAdminAppService : CmsKitAdminAppServiceBase, IPageAdminAppService 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 8d106b70e0..3cdc4dc093 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 @@ -1,10 +1,13 @@ using System.Threading.Tasks; +using Volo.Abp.Features; using Volo.Abp.GlobalFeatures; +using Volo.CmsKit.Features; using Volo.CmsKit.GlobalFeatures; using Volo.CmsKit.Tags; namespace Volo.CmsKit.Admin.Tags; +[RequiresFeature(CmsKitFeatures.TagEnable)] [RequiresGlobalFeature(typeof(TagsFeature))] public class EntityTagAdminAppService : CmsKitAdminAppServiceBase, IEntityTagAdminAppService { diff --git a/modules/cms-kit/src/Volo.CmsKit.Admin.Application/Volo/CmsKit/Admin/Tags/TagAdminAppService.cs b/modules/cms-kit/src/Volo.CmsKit.Admin.Application/Volo/CmsKit/Admin/Tags/TagAdminAppService.cs index f6de1ac5b9..46324937cc 100644 --- a/modules/cms-kit/src/Volo.CmsKit.Admin.Application/Volo/CmsKit/Admin/Tags/TagAdminAppService.cs +++ b/modules/cms-kit/src/Volo.CmsKit.Admin.Application/Volo/CmsKit/Admin/Tags/TagAdminAppService.cs @@ -1,18 +1,21 @@ -using Microsoft.AspNetCore.Authorization; -using Microsoft.Extensions.Localization; -using System; +using System; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; +using Microsoft.AspNetCore.Authorization; +using Microsoft.Extensions.Localization; using Volo.Abp.Application.Dtos; using Volo.Abp.Data; +using Volo.Abp.Features; using Volo.Abp.GlobalFeatures; +using Volo.CmsKit.Features; using Volo.CmsKit.GlobalFeatures; using Volo.CmsKit.Permissions; using Volo.CmsKit.Tags; namespace Volo.CmsKit.Admin.Tags; +[RequiresFeature(CmsKitFeatures.TagEnable)] [Authorize(CmsKitAdminPermissions.Tags.Default)] [RequiresGlobalFeature(typeof(TagsFeature))] public class TagAdminAppService : CmsKitAppServiceBase, ITagAdminAppService diff --git a/modules/cms-kit/src/Volo.CmsKit.Admin.HttpApi/Volo/CmsKit/Admin/Blogs/BlogAdminController.cs b/modules/cms-kit/src/Volo.CmsKit.Admin.HttpApi/Volo/CmsKit/Admin/Blogs/BlogAdminController.cs index 094c1b1b5a..e7d59ddbcd 100644 --- a/modules/cms-kit/src/Volo.CmsKit.Admin.HttpApi/Volo/CmsKit/Admin/Blogs/BlogAdminController.cs +++ b/modules/cms-kit/src/Volo.CmsKit.Admin.HttpApi/Volo/CmsKit/Admin/Blogs/BlogAdminController.cs @@ -1,15 +1,18 @@ -using Microsoft.AspNetCore.Authorization; -using Microsoft.AspNetCore.Mvc; -using System; +using System; using System.Threading.Tasks; +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Mvc; using Volo.Abp; using Volo.Abp.Application.Dtos; +using Volo.Abp.Features; using Volo.Abp.GlobalFeatures; +using Volo.CmsKit.Features; using Volo.CmsKit.GlobalFeatures; using Volo.CmsKit.Permissions; namespace Volo.CmsKit.Admin.Blogs; +[RequiresFeature(CmsKitFeatures.BlogEnable)] [RequiresGlobalFeature(typeof(BlogsFeature))] [RemoteService(Name = CmsKitAdminRemoteServiceConsts.RemoteServiceName)] [Area(CmsKitAdminRemoteServiceConsts.ModuleName)] diff --git a/modules/cms-kit/src/Volo.CmsKit.Admin.HttpApi/Volo/CmsKit/Admin/Blogs/BlogFeatureAdminController.cs b/modules/cms-kit/src/Volo.CmsKit.Admin.HttpApi/Volo/CmsKit/Admin/Blogs/BlogFeatureAdminController.cs index e3cc3c5e73..93bdced888 100644 --- a/modules/cms-kit/src/Volo.CmsKit.Admin.HttpApi/Volo/CmsKit/Admin/Blogs/BlogFeatureAdminController.cs +++ b/modules/cms-kit/src/Volo.CmsKit.Admin.HttpApi/Volo/CmsKit/Admin/Blogs/BlogFeatureAdminController.cs @@ -1,16 +1,19 @@ -using Microsoft.AspNetCore.Authorization; -using Microsoft.AspNetCore.Mvc; -using System; +using System; using System.Collections.Generic; using System.Threading.Tasks; +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Mvc; using Volo.Abp; +using Volo.Abp.Features; using Volo.Abp.GlobalFeatures; using Volo.CmsKit.Blogs; +using Volo.CmsKit.Features; using Volo.CmsKit.GlobalFeatures; using Volo.CmsKit.Permissions; namespace Volo.CmsKit.Admin.Blogs; +[RequiresFeature(CmsKitFeatures.BlogEnable)] [RequiresGlobalFeature(typeof(BlogsFeature))] [RemoteService(Name = CmsKitAdminRemoteServiceConsts.RemoteServiceName)] [Area(CmsKitAdminRemoteServiceConsts.ModuleName)] diff --git a/modules/cms-kit/src/Volo.CmsKit.Admin.HttpApi/Volo/CmsKit/Admin/Blogs/BlogPostAdminController.cs b/modules/cms-kit/src/Volo.CmsKit.Admin.HttpApi/Volo/CmsKit/Admin/Blogs/BlogPostAdminController.cs index 563d90c254..923f9a4036 100644 --- a/modules/cms-kit/src/Volo.CmsKit.Admin.HttpApi/Volo/CmsKit/Admin/Blogs/BlogPostAdminController.cs +++ b/modules/cms-kit/src/Volo.CmsKit.Admin.HttpApi/Volo/CmsKit/Admin/Blogs/BlogPostAdminController.cs @@ -1,15 +1,18 @@ -using Microsoft.AspNetCore.Authorization; -using Microsoft.AspNetCore.Mvc; -using System; +using System; using System.Threading.Tasks; +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Mvc; using Volo.Abp; using Volo.Abp.Application.Dtos; +using Volo.Abp.Features; using Volo.Abp.GlobalFeatures; +using Volo.CmsKit.Features; using Volo.CmsKit.GlobalFeatures; using Volo.CmsKit.Permissions; namespace Volo.CmsKit.Admin.Blogs; +[RequiresFeature(CmsKitFeatures.BlogEnable)] [RequiresGlobalFeature(typeof(BlogsFeature))] [RemoteService(Name = CmsKitAdminRemoteServiceConsts.RemoteServiceName)] [Area(CmsKitAdminRemoteServiceConsts.ModuleName)] @@ -61,7 +64,7 @@ public class BlogPostAdminController : CmsKitAdminController, IBlogPostAdminAppS { return BlogPostAdminAppService.UpdateAsync(id, input); } - + [HttpPost] [Route("{id}/publish")] [Authorize(CmsKitAdminPermissions.BlogPosts.Publish)] @@ -69,7 +72,7 @@ public class BlogPostAdminController : CmsKitAdminController, IBlogPostAdminAppS { return BlogPostAdminAppService.PublishAsync(id); } - + [HttpPost] [Route("{id}/draft")] [Authorize(CmsKitAdminPermissions.BlogPosts.Update)] @@ -86,7 +89,7 @@ public class BlogPostAdminController : CmsKitAdminController, IBlogPostAdminAppS { return BlogPostAdminAppService.CreateAndPublishAsync(input); } - + [HttpPost] [Route("{id}/send-to-review")] [Authorize(CmsKitAdminPermissions.BlogPosts.Create)] @@ -94,7 +97,7 @@ public class BlogPostAdminController : CmsKitAdminController, IBlogPostAdminAppS { return BlogPostAdminAppService.SendToReviewAsync(id); } - + [HttpPost] [Route("create-and-send-to-review")] [Authorize(CmsKitAdminPermissions.BlogPosts.Create)] @@ -102,7 +105,7 @@ public class BlogPostAdminController : CmsKitAdminController, IBlogPostAdminAppS { return BlogPostAdminAppService.CreateAndSendToReviewAsync(input); } - + [HttpGet] [Route("has-blogpost-waiting-for-review")] [Authorize(CmsKitAdminPermissions.BlogPosts.Publish)] diff --git a/modules/cms-kit/src/Volo.CmsKit.Admin.HttpApi/Volo/CmsKit/Admin/Comments/CommentAdminController.cs b/modules/cms-kit/src/Volo.CmsKit.Admin.HttpApi/Volo/CmsKit/Admin/Comments/CommentAdminController.cs index 6082ad3794..f4813f61ad 100644 --- a/modules/cms-kit/src/Volo.CmsKit.Admin.HttpApi/Volo/CmsKit/Admin/Comments/CommentAdminController.cs +++ b/modules/cms-kit/src/Volo.CmsKit.Admin.HttpApi/Volo/CmsKit/Admin/Comments/CommentAdminController.cs @@ -4,12 +4,15 @@ using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; using Volo.Abp; using Volo.Abp.Application.Dtos; +using Volo.Abp.Features; using Volo.Abp.GlobalFeatures; +using Volo.CmsKit.Features; using Volo.CmsKit.GlobalFeatures; using Volo.CmsKit.Permissions; namespace Volo.CmsKit.Admin.Comments; +[RequiresFeature(CmsKitFeatures.CommentEnable)] [Authorize(CmsKitAdminPermissions.Comments.Default)] [RequiresGlobalFeature(typeof(CommentsFeature))] [RemoteService(Name = CmsKitAdminRemoteServiceConsts.RemoteServiceName)] diff --git a/modules/cms-kit/src/Volo.CmsKit.Admin.HttpApi/Volo/CmsKit/Admin/GlobalResources/GlobalResourceAdminController.cs b/modules/cms-kit/src/Volo.CmsKit.Admin.HttpApi/Volo/CmsKit/Admin/GlobalResources/GlobalResourceAdminController.cs index 3bfe51a600..b1ae9b3f2e 100644 --- a/modules/cms-kit/src/Volo.CmsKit.Admin.HttpApi/Volo/CmsKit/Admin/GlobalResources/GlobalResourceAdminController.cs +++ b/modules/cms-kit/src/Volo.CmsKit.Admin.HttpApi/Volo/CmsKit/Admin/GlobalResources/GlobalResourceAdminController.cs @@ -2,18 +2,21 @@ using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; using Volo.Abp; +using Volo.Abp.Features; using Volo.Abp.GlobalFeatures; +using Volo.CmsKit.Features; using Volo.CmsKit.GlobalFeatures; using Volo.CmsKit.Permissions; namespace Volo.CmsKit.Admin.GlobalResources; +[RequiresFeature(CmsKitFeatures.GlobalResourceEnable)] [RequiresGlobalFeature(typeof(GlobalResourcesFeature))] [RemoteService(Name = CmsKitAdminRemoteServiceConsts.RemoteServiceName)] [Area(CmsKitAdminRemoteServiceConsts.ModuleName)] [Authorize(CmsKitAdminPermissions.Menus.Default)] [Route("api/cms-kit-admin/global-resources")] -public class GlobalResourceAdminController: CmsKitAdminController, IGlobalResourceAdminAppService +public class GlobalResourceAdminController : CmsKitAdminController, IGlobalResourceAdminAppService { private readonly IGlobalResourceAdminAppService _globalResourceAdminAppService; @@ -21,7 +24,7 @@ public class GlobalResourceAdminController: CmsKitAdminController, IGlobalResour { _globalResourceAdminAppService = globalResourceAdminAppService; } - + [HttpGet] public Task GetAsync() { diff --git a/modules/cms-kit/src/Volo.CmsKit.Admin.HttpApi/Volo/CmsKit/Admin/MediaDescriptors/MediaDescriptorAdminController.cs b/modules/cms-kit/src/Volo.CmsKit.Admin.HttpApi/Volo/CmsKit/Admin/MediaDescriptors/MediaDescriptorAdminController.cs index f95d2a86b2..c304c5c684 100644 --- a/modules/cms-kit/src/Volo.CmsKit.Admin.HttpApi/Volo/CmsKit/Admin/MediaDescriptors/MediaDescriptorAdminController.cs +++ b/modules/cms-kit/src/Volo.CmsKit.Admin.HttpApi/Volo/CmsKit/Admin/MediaDescriptors/MediaDescriptorAdminController.cs @@ -1,16 +1,15 @@ using System; -using System.Net; using System.Threading.Tasks; -using Microsoft.AspNetCore.Authorization; -using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; using Volo.Abp; +using Volo.Abp.Features; using Volo.Abp.GlobalFeatures; +using Volo.CmsKit.Features; using Volo.CmsKit.GlobalFeatures; -using Volo.CmsKit.Permissions; namespace Volo.CmsKit.Admin.MediaDescriptors; +[RequiresFeature(CmsKitFeatures.MediaEnable)] [RequiresGlobalFeature(typeof(MediaFeature))] [RemoteService(Name = CmsKitAdminRemoteServiceConsts.RemoteServiceName)] [Area(CmsKitAdminRemoteServiceConsts.ModuleName)] diff --git a/modules/cms-kit/src/Volo.CmsKit.Admin.HttpApi/Volo/CmsKit/Admin/Menus/MenuItemAdminController.cs b/modules/cms-kit/src/Volo.CmsKit.Admin.HttpApi/Volo/CmsKit/Admin/Menus/MenuItemAdminController.cs index de36883ff7..a0325f4f27 100644 --- a/modules/cms-kit/src/Volo.CmsKit.Admin.HttpApi/Volo/CmsKit/Admin/Menus/MenuItemAdminController.cs +++ b/modules/cms-kit/src/Volo.CmsKit.Admin.HttpApi/Volo/CmsKit/Admin/Menus/MenuItemAdminController.cs @@ -1,16 +1,19 @@ -using Microsoft.AspNetCore.Authorization; -using Microsoft.AspNetCore.Mvc; -using System; +using System; using System.Threading.Tasks; +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Mvc; using Volo.Abp; using Volo.Abp.Application.Dtos; +using Volo.Abp.Features; using Volo.Abp.GlobalFeatures; +using Volo.CmsKit.Features; using Volo.CmsKit.GlobalFeatures; using Volo.CmsKit.Menus; using Volo.CmsKit.Permissions; namespace Volo.CmsKit.Admin.Menus; +[RequiresFeature(CmsKitFeatures.MenuEnable)] [RequiresGlobalFeature(typeof(MenuFeature))] [RemoteService(Name = CmsKitAdminRemoteServiceConsts.RemoteServiceName)] [Area(CmsKitAdminRemoteServiceConsts.ModuleName)] diff --git a/modules/cms-kit/src/Volo.CmsKit.Admin.HttpApi/Volo/CmsKit/Admin/Pages/PageAdminController.cs b/modules/cms-kit/src/Volo.CmsKit.Admin.HttpApi/Volo/CmsKit/Admin/Pages/PageAdminController.cs index 7936b206e6..5acccb07aa 100644 --- a/modules/cms-kit/src/Volo.CmsKit.Admin.HttpApi/Volo/CmsKit/Admin/Pages/PageAdminController.cs +++ b/modules/cms-kit/src/Volo.CmsKit.Admin.HttpApi/Volo/CmsKit/Admin/Pages/PageAdminController.cs @@ -4,13 +4,15 @@ using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; using Volo.Abp; using Volo.Abp.Application.Dtos; +using Volo.Abp.Features; using Volo.Abp.GlobalFeatures; -using Volo.CmsKit.Admin.Menus; +using Volo.CmsKit.Features; using Volo.CmsKit.GlobalFeatures; using Volo.CmsKit.Permissions; namespace Volo.CmsKit.Admin.Pages; +[RequiresFeature(CmsKitFeatures.PageEnable)] [RequiresGlobalFeature(typeof(PagesFeature))] [RemoteService(Name = CmsKitAdminRemoteServiceConsts.RemoteServiceName)] [Area(CmsKitAdminRemoteServiceConsts.ModuleName)] diff --git a/modules/cms-kit/src/Volo.CmsKit.Admin.HttpApi/Volo/CmsKit/Admin/Tags/EntityTagAdminController.cs b/modules/cms-kit/src/Volo.CmsKit.Admin.HttpApi/Volo/CmsKit/Admin/Tags/EntityTagAdminController.cs index 9df9394fdd..c57e7bb0a7 100644 --- a/modules/cms-kit/src/Volo.CmsKit.Admin.HttpApi/Volo/CmsKit/Admin/Tags/EntityTagAdminController.cs +++ b/modules/cms-kit/src/Volo.CmsKit.Admin.HttpApi/Volo/CmsKit/Admin/Tags/EntityTagAdminController.cs @@ -1,13 +1,14 @@ -using Microsoft.AspNetCore.Authorization; +using System.Threading.Tasks; using Microsoft.AspNetCore.Mvc; -using System.Threading.Tasks; using Volo.Abp; +using Volo.Abp.Features; using Volo.Abp.GlobalFeatures; +using Volo.CmsKit.Features; using Volo.CmsKit.GlobalFeatures; -using Volo.CmsKit.Permissions; namespace Volo.CmsKit.Admin.Tags; +[RequiresFeature(CmsKitFeatures.TagEnable)] [RequiresGlobalFeature(typeof(TagsFeature))] [RemoteService(Name = CmsKitAdminRemoteServiceConsts.RemoteServiceName)] [Area(CmsKitAdminRemoteServiceConsts.ModuleName)] diff --git a/modules/cms-kit/src/Volo.CmsKit.Admin.HttpApi/Volo/CmsKit/Admin/Tags/TagAdminController.cs b/modules/cms-kit/src/Volo.CmsKit.Admin.HttpApi/Volo/CmsKit/Admin/Tags/TagAdminController.cs index c34107b742..db0131ba2f 100644 --- a/modules/cms-kit/src/Volo.CmsKit.Admin.HttpApi/Volo/CmsKit/Admin/Tags/TagAdminController.cs +++ b/modules/cms-kit/src/Volo.CmsKit.Admin.HttpApi/Volo/CmsKit/Admin/Tags/TagAdminController.cs @@ -1,18 +1,20 @@ -using Microsoft.AspNetCore.Authorization; -using Microsoft.AspNetCore.Mvc; -using System; +using System; using System.Collections.Generic; using System.Threading.Tasks; +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Mvc; using Volo.Abp; using Volo.Abp.Application.Dtos; +using Volo.Abp.Features; using Volo.Abp.GlobalFeatures; -using Volo.CmsKit.Admin.Tags; +using Volo.CmsKit.Features; using Volo.CmsKit.GlobalFeatures; using Volo.CmsKit.Permissions; using Volo.CmsKit.Tags; namespace Volo.CmsKit.Admin.Tags; +[RequiresFeature(CmsKitFeatures.TagEnable)] [RequiresGlobalFeature(typeof(TagsFeature))] [RemoteService(Name = CmsKitAdminRemoteServiceConsts.RemoteServiceName)] [Area(CmsKitAdminRemoteServiceConsts.ModuleName)] diff --git a/modules/cms-kit/src/Volo.CmsKit.Admin.Web/Menus/CmsKitAdminMenuContributor.cs b/modules/cms-kit/src/Volo.CmsKit.Admin.Web/Menus/CmsKitAdminMenuContributor.cs index bc9bbfb310..9cc76c080c 100644 --- a/modules/cms-kit/src/Volo.CmsKit.Admin.Web/Menus/CmsKitAdminMenuContributor.cs +++ b/modules/cms-kit/src/Volo.CmsKit.Admin.Web/Menus/CmsKitAdminMenuContributor.cs @@ -2,8 +2,10 @@ using System.Linq; using System.Threading.Tasks; using Volo.Abp.Authorization.Permissions; +using Volo.Abp.Features; using Volo.Abp.GlobalFeatures; using Volo.Abp.UI.Navigation; +using Volo.CmsKit.Features; using Volo.CmsKit.GlobalFeatures; using Volo.CmsKit.Localization; using Volo.CmsKit.Permissions; @@ -36,6 +38,7 @@ public class CmsKitAdminMenuContributor : IMenuContributor l["Pages"].Value, "/Cms/Pages", "fa fa-file-alt") + .RequireFeatures(CmsKitFeatures.PageEnable) .RequireGlobalFeatures(typeof(PagesFeature)) .RequirePermissions(CmsKitAdminPermissions.Pages.Default)); @@ -44,6 +47,7 @@ public class CmsKitAdminMenuContributor : IMenuContributor l["Blogs"], "/Cms/Blogs", "fa fa-blog") + .RequireFeatures(CmsKitFeatures.BlogEnable) .RequireGlobalFeatures(typeof(BlogsFeature)) .RequirePermissions(CmsKitAdminPermissions.Blogs.Default)); @@ -52,6 +56,7 @@ public class CmsKitAdminMenuContributor : IMenuContributor l["BlogPosts"], "/Cms/BlogPosts", "fa fa-file-signature") + .RequireFeatures(CmsKitFeatures.BlogEnable) .RequireGlobalFeatures(typeof(BlogsFeature)) .RequirePermissions(CmsKitAdminPermissions.BlogPosts.Default)); @@ -60,6 +65,7 @@ public class CmsKitAdminMenuContributor : IMenuContributor l["Tags"].Value, "/Cms/Tags", "fa fa-tags") + .RequireFeatures(CmsKitFeatures.TagEnable) .RequireGlobalFeatures(typeof(TagsFeature)) .RequirePermissions(CmsKitAdminPermissions.Tags.Default)); @@ -68,6 +74,7 @@ public class CmsKitAdminMenuContributor : IMenuContributor l["Comments"].Value, "/Cms/Comments", "fa fa-comments") + .RequireFeatures(CmsKitFeatures.CommentEnable) .RequireGlobalFeatures(typeof(CommentsFeature)) .RequirePermissions(CmsKitAdminPermissions.Comments.Default)); @@ -76,6 +83,7 @@ public class CmsKitAdminMenuContributor : IMenuContributor l["Menus"], "/Cms/Menus/Items", "fa fa-stream") + .RequireFeatures(CmsKitFeatures.MenuEnable) .RequireGlobalFeatures(typeof(MenuFeature)) .RequirePermissions(CmsKitAdminPermissions.Menus.Default)); @@ -84,6 +92,7 @@ public class CmsKitAdminMenuContributor : IMenuContributor l["GlobalResources"], "/Cms/GlobalResources", "fa fa-newspaper") + .RequireFeatures(CmsKitFeatures.GlobalResourceEnable) .RequireGlobalFeatures(typeof(GlobalResourcesFeature)) .RequirePermissions(CmsKitAdminPermissions.GlobalResources.Default)); diff --git a/modules/cms-kit/src/Volo.CmsKit.Admin.Web/Pages/CmsKit/BlogPosts/create.js b/modules/cms-kit/src/Volo.CmsKit.Admin.Web/Pages/CmsKit/BlogPosts/create.js index 375b7ad41b..a101635d73 100644 --- a/modules/cms-kit/src/Volo.CmsKit.Admin.Web/Pages/CmsKit/BlogPosts/create.js +++ b/modules/cms-kit/src/Volo.CmsKit.Admin.Web/Pages/CmsKit/BlogPosts/create.js @@ -334,6 +334,25 @@ $(function () { editor.insertText(txt); }); + $('.tab-item').on('click', function () { + if ($(this).attr("aria-label") == 'Preview' && editor.isMarkdownMode()) { + + let content = editor.getMarkdown(); + localStorage.setItem('content', content); + + $.post("/CmsKitCommonWidgets/ContentPreview", { content: content }, function (result) { + editor.setHTML(result); + + var highllightedText = $('#ContentEditor').find('.toastui-editor-md-preview-highlight'); + highllightedText.removeClass('toastui-editor-md-preview-highlight'); + }); + } + else if ($(this).attr("aria-label") == 'Write') { + var retrievedObject = localStorage.getItem('content'); + editor.setMarkdown(retrievedObject); + } + }); + function createAddWidgetButton() { const button = document.createElement('button'); diff --git a/modules/cms-kit/src/Volo.CmsKit.Admin.Web/Pages/CmsKit/BlogPosts/update.js b/modules/cms-kit/src/Volo.CmsKit.Admin.Web/Pages/CmsKit/BlogPosts/update.js index 51e3eda96c..d14194ecb5 100644 --- a/modules/cms-kit/src/Volo.CmsKit.Admin.Web/Pages/CmsKit/BlogPosts/update.js +++ b/modules/cms-kit/src/Volo.CmsKit.Admin.Web/Pages/CmsKit/BlogPosts/update.js @@ -255,6 +255,25 @@ $(function () { editor.insertText(txt); }); + $('.tab-item').on('click', function () { + if ($(this).attr("aria-label") == 'Preview' && editor.isMarkdownMode()) { + + let content = editor.getMarkdown(); + localStorage.setItem('content', content); + + $.post("/CmsKitCommonWidgets/ContentPreview", { content: content }, function (result) { + editor.setHTML(result); + + var highllightedText = $('#ContentEditor').find('.toastui-editor-md-preview-highlight'); + highllightedText.removeClass('toastui-editor-md-preview-highlight'); + }); + } + else if ($(this).attr("aria-label") == 'Write') { + var retrievedObject = localStorage.getItem('content'); + editor.setMarkdown(retrievedObject); + } + }); + function createAddWidgetButton() { const button = document.createElement('button'); diff --git a/modules/cms-kit/src/Volo.CmsKit.Admin.Web/Pages/CmsKit/Pages/create.js b/modules/cms-kit/src/Volo.CmsKit.Admin.Web/Pages/CmsKit/Pages/create.js index 49a482bf33..ee6c7b7f9f 100644 --- a/modules/cms-kit/src/Volo.CmsKit.Admin.Web/Pages/CmsKit/Pages/create.js +++ b/modules/cms-kit/src/Volo.CmsKit.Admin.Web/Pages/CmsKit/Pages/create.js @@ -1,6 +1,6 @@ $(function () { var l = abp.localization.getResource("CmsKit"); - + var $createForm = $('#form-page-create'); var $title = $('#ViewModel_Title'); var $slug = $('#ViewModel_Slug'); @@ -90,7 +90,7 @@ $(function () { var fileUriPrefix = "/api/cms-kit/media/"; initEditor(); - + var editor; function initEditor() { var $editorContainer = $("#ContentEditor"); @@ -133,7 +133,7 @@ $(function () { } }); } - + function uploadFile(blob, callback, source) { var UPPY_OPTIONS = { endpoint: fileUploadUri, @@ -166,11 +166,37 @@ $(function () { }); } - $('#GeneratedWidgetText').on('change',function () { + $('#GeneratedWidgetText').on('change', function () { var txt = $('#GeneratedWidgetText').val(); editor.insertText(txt); }); - + + $('.tab-item').on('click', function () { + if ($(this).attr("aria-label") == 'Preview' && editor.isMarkdownMode()) { + + let content = editor.getMarkdown(); + localStorage.setItem('content', content); + + $.post("/CmsKitCommonWidgets/ContentPreview", { content: content }, function (result) { + + let style = styleEditor.getValue(); + + $('#editor-preview-style').remove(); + + $('head').append(''); + + editor.setHTML(result); + + var highllightedText = $('#ContentEditor').find('.toastui-editor-md-preview-highlight'); + highllightedText.removeClass('toastui-editor-md-preview-highlight'); + }); + } + else if ($(this).attr("aria-label") == 'Write'){ + var retrievedObject = localStorage.getItem('content'); + editor.setMarkdown(retrievedObject); + } + }); + function createAddWidgetButton() { const button = document.createElement('button'); diff --git a/modules/cms-kit/src/Volo.CmsKit.Admin.Web/Pages/CmsKit/Pages/update.js b/modules/cms-kit/src/Volo.CmsKit.Admin.Web/Pages/CmsKit/Pages/update.js index 565f758552..c46f1c274c 100644 --- a/modules/cms-kit/src/Volo.CmsKit.Admin.Web/Pages/CmsKit/Pages/update.js +++ b/modules/cms-kit/src/Volo.CmsKit.Admin.Web/Pages/CmsKit/Pages/update.js @@ -140,7 +140,33 @@ $(function () { var txt = $('#GeneratedWidgetText').val(); editor.insertText(txt); }); - + + $('.tab-item').on('click', function () { + if ($(this).attr("aria-label") == 'Preview' && editor.isMarkdownMode()) { + + let content = editor.getMarkdown(); + localStorage.setItem('content', content); + + $.post("/CmsKitCommonWidgets/ContentPreview", { content: content }, function (result) { + + let style = styleEditor.getValue(); + + $('#editor-preview-style').remove(); + + $('head').append(''); + + editor.setHTML(result); + + var highllightedText = $('#ContentEditor').find('.toastui-editor-md-preview-highlight'); + highllightedText.removeClass('toastui-editor-md-preview-highlight'); + }); + } + else if ($(this).attr("aria-label") == 'Write') { + var retrievedObject = localStorage.getItem('content'); + editor.setMarkdown(retrievedObject); + } + }); + function createAddWidgetButton() { const button = document.createElement('button'); diff --git a/modules/cms-kit/src/Volo.CmsKit.Public.Application.Contracts/Volo/CmsKit/Public/Blogs/BlogPostPublicDto.cs b/modules/cms-kit/src/Volo.CmsKit.Common.Application.Contracts/Volo/CmsKit/Contents/BlogPostCommonDto.cs similarity index 80% rename from modules/cms-kit/src/Volo.CmsKit.Public.Application.Contracts/Volo/CmsKit/Public/Blogs/BlogPostPublicDto.cs rename to modules/cms-kit/src/Volo.CmsKit.Common.Application.Contracts/Volo/CmsKit/Contents/BlogPostCommonDto.cs index 8c6a6a01e9..a7bc27d713 100644 --- a/modules/cms-kit/src/Volo.CmsKit.Public.Application.Contracts/Volo/CmsKit/Public/Blogs/BlogPostPublicDto.cs +++ b/modules/cms-kit/src/Volo.CmsKit.Common.Application.Contracts/Volo/CmsKit/Contents/BlogPostCommonDto.cs @@ -2,10 +2,10 @@ using Volo.Abp.Application.Dtos; using Volo.CmsKit.Users; -namespace Volo.CmsKit.Public.Blogs; +namespace Volo.CmsKit.Contents; [Serializable] -public class BlogPostPublicDto : AuditedEntityDto +public class BlogPostCommonDto : AuditedEntityDto { public Guid BlogId { get; set; } @@ -20,4 +20,4 @@ public class BlogPostPublicDto : AuditedEntityDto public Guid? CoverImageMediaId { get; set; } public CmsUserDto Author { get; set; } -} +} \ No newline at end of file diff --git a/modules/cms-kit/src/Volo.CmsKit.Common.Application.Contracts/Volo/CmsKit/Contents/DefaultContentDto.cs b/modules/cms-kit/src/Volo.CmsKit.Common.Application.Contracts/Volo/CmsKit/Contents/DefaultContentDto.cs new file mode 100644 index 0000000000..731e346df4 --- /dev/null +++ b/modules/cms-kit/src/Volo.CmsKit.Common.Application.Contracts/Volo/CmsKit/Contents/DefaultContentDto.cs @@ -0,0 +1,8 @@ +using System.Collections.Generic; + +namespace Volo.CmsKit.Contents; + +public class DefaultContentDto : IContent +{ + public List ContentFragments { get; set; } +} diff --git a/modules/cms-kit/src/Volo.CmsKit.Common.Application.Contracts/Volo/CmsKit/Contents/IContent.cs b/modules/cms-kit/src/Volo.CmsKit.Common.Application.Contracts/Volo/CmsKit/Contents/IContent.cs new file mode 100644 index 0000000000..2a393e0a14 --- /dev/null +++ b/modules/cms-kit/src/Volo.CmsKit.Common.Application.Contracts/Volo/CmsKit/Contents/IContent.cs @@ -0,0 +1,7 @@ +using System.Collections.Generic; + +namespace Volo.CmsKit.Contents; +public interface IContent +{ + public List ContentFragments { get; set; } +} diff --git a/modules/cms-kit/src/Volo.CmsKit.Public.Application.Contracts/Volo/CmsKit/Public/Pages/PageDto.cs b/modules/cms-kit/src/Volo.CmsKit.Common.Application.Contracts/Volo/CmsKit/Contents/PageDto.cs similarity index 71% rename from modules/cms-kit/src/Volo.CmsKit.Public.Application.Contracts/Volo/CmsKit/Public/Pages/PageDto.cs rename to modules/cms-kit/src/Volo.CmsKit.Common.Application.Contracts/Volo/CmsKit/Contents/PageDto.cs index 6f18787a44..d495c5de20 100644 --- a/modules/cms-kit/src/Volo.CmsKit.Public.Application.Contracts/Volo/CmsKit/Public/Pages/PageDto.cs +++ b/modules/cms-kit/src/Volo.CmsKit.Common.Application.Contracts/Volo/CmsKit/Contents/PageDto.cs @@ -1,9 +1,8 @@ -using System; -using System.Collections.Generic; +using System.Collections.Generic; +using System; using Volo.Abp.Application.Dtos; -using Volo.CmsKit.Contents; -namespace Volo.CmsKit.Public.Pages; +namespace Volo.CmsKit.Contents; [Serializable] public class PageDto : EntityDto @@ -17,4 +16,4 @@ public class PageDto : EntityDto public string Script { get; set; } public string Style { get; set; } -} +} \ No newline at end of file diff --git a/modules/cms-kit/src/Volo.CmsKit.Common.Web/Controllers/CmsKitCommonWidgetsController.cs b/modules/cms-kit/src/Volo.CmsKit.Common.Web/Controllers/CmsKitCommonWidgetsController.cs new file mode 100644 index 0000000000..8e226a31f2 --- /dev/null +++ b/modules/cms-kit/src/Volo.CmsKit.Common.Web/Controllers/CmsKitCommonWidgetsController.cs @@ -0,0 +1,14 @@ +using Microsoft.AspNetCore.Mvc; +using Volo.Abp.AspNetCore.Mvc; +using Volo.CmsKit.Web.Pages.CmsKit.Components.ContentPreview; + +namespace Volo.CmsKit.Web.Controllers; + +public class CmsKitCommonWidgetsController : AbpController +{ + [HttpPost] + public IActionResult ContentPreview(ContentPreviewDto dto) + { + return ViewComponent(typeof(ContentPreviewViewComponent), new { content = dto.Content }); + } +} diff --git a/modules/cms-kit/src/Volo.CmsKit.Common.Web/Pages/CmsKit/Components/ContentPreview/ContentPreviewDto.cs b/modules/cms-kit/src/Volo.CmsKit.Common.Web/Pages/CmsKit/Components/ContentPreview/ContentPreviewDto.cs new file mode 100644 index 0000000000..9c01a325bf --- /dev/null +++ b/modules/cms-kit/src/Volo.CmsKit.Common.Web/Pages/CmsKit/Components/ContentPreview/ContentPreviewDto.cs @@ -0,0 +1,9 @@ +using System; + +namespace Volo.CmsKit.Web.Pages.CmsKit.Components.ContentPreview; + +[Serializable] +public class ContentPreviewDto +{ + public string Content { get; set; } +} diff --git a/modules/cms-kit/src/Volo.CmsKit.Common.Web/Pages/CmsKit/Components/ContentPreview/ContentPreviewViewComponent.cs b/modules/cms-kit/src/Volo.CmsKit.Common.Web/Pages/CmsKit/Components/ContentPreview/ContentPreviewViewComponent.cs new file mode 100644 index 0000000000..2251f6d0cd --- /dev/null +++ b/modules/cms-kit/src/Volo.CmsKit.Common.Web/Pages/CmsKit/Components/ContentPreview/ContentPreviewViewComponent.cs @@ -0,0 +1,31 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Mvc; +using Volo.Abp.AspNetCore.Mvc; +using Volo.CmsKit.Contents; +using Volo.CmsKit.Web.Contents; + +namespace Volo.CmsKit.Web.Pages.CmsKit.Components.ContentPreview; + +public class ContentPreviewViewComponent : AbpViewComponent +{ + protected ContentParser ContentParser { get; } + + public ContentPreviewViewComponent(ContentParser contentParser) + { + ContentParser = contentParser; + } + + public virtual async Task InvokeAsync(string content) + { + var fragments = await ContentParser.ParseAsync(content); + + return View("~/Pages/CmsKit/Components/ContentPreview/Default.cshtml", new DefaultContentDto + { + ContentFragments = fragments + }); + } +} diff --git a/modules/cms-kit/src/Volo.CmsKit.Common.Web/Pages/CmsKit/Components/ContentPreview/Default.cshtml b/modules/cms-kit/src/Volo.CmsKit.Common.Web/Pages/CmsKit/Components/ContentPreview/Default.cshtml new file mode 100644 index 0000000000..6baf41716e --- /dev/null +++ b/modules/cms-kit/src/Volo.CmsKit.Common.Web/Pages/CmsKit/Components/ContentPreview/Default.cshtml @@ -0,0 +1,10 @@ +@using Volo.CmsKit.Contents +@using Volo.CmsKit.Web.Pages.CmsKit.Components.Contents + +@model DefaultContentDto + +
+ + @await Component.InvokeAsync(typeof(ContentFragmentViewComponent), Model) + +
\ No newline at end of file diff --git a/modules/cms-kit/src/Volo.CmsKit.Common.Web/Contents/CmsKitContentWidgetOptions.cs b/modules/cms-kit/src/Volo.CmsKit.Common.Web/Pages/CmsKit/Components/Contents/CmsKitContentWidgetOptions.cs similarity index 100% rename from modules/cms-kit/src/Volo.CmsKit.Common.Web/Contents/CmsKitContentWidgetOptions.cs rename to modules/cms-kit/src/Volo.CmsKit.Common.Web/Pages/CmsKit/Components/Contents/CmsKitContentWidgetOptions.cs diff --git a/modules/cms-kit/src/Volo.CmsKit.Common.Web/Pages/CmsKit/Components/Contents/ContentFragment.cshtml b/modules/cms-kit/src/Volo.CmsKit.Common.Web/Pages/CmsKit/Components/Contents/ContentFragment.cshtml new file mode 100644 index 0000000000..0fa7d59064 --- /dev/null +++ b/modules/cms-kit/src/Volo.CmsKit.Common.Web/Pages/CmsKit/Components/Contents/ContentFragment.cshtml @@ -0,0 +1,20 @@ +@using System.Dynamic +@using Volo.Abp.Data +@using Volo.CmsKit.Web.Renderers; +@using Volo.CmsKit.Web.Pages.CmsKit.Components.Contents; + +@model ContentFragmentViewComponent + +@inject IMarkdownToHtmlRenderer MarkdownRenderer + +@foreach (var contentFragment in Model.ContentDto.ContentFragments) +{ + if (contentFragment.Type == "Markdown") + { + @Html.Raw(await MarkdownRenderer.RenderAsync(contentFragment.GetProperty("Content"))) + } + else if (contentFragment.Type == "Widget") + { + @await Component.InvokeAsync(contentFragment.GetProperty("Type"), contentFragment.ExtraProperties.ConvertToDynamicObject()) + } +} \ No newline at end of file diff --git a/modules/cms-kit/src/Volo.CmsKit.Common.Web/Pages/CmsKit/Components/Contents/ContentFragmentViewComponent.cs b/modules/cms-kit/src/Volo.CmsKit.Common.Web/Pages/CmsKit/Components/Contents/ContentFragmentViewComponent.cs new file mode 100644 index 0000000000..d276165982 --- /dev/null +++ b/modules/cms-kit/src/Volo.CmsKit.Common.Web/Pages/CmsKit/Components/Contents/ContentFragmentViewComponent.cs @@ -0,0 +1,21 @@ +using System.Threading.Tasks; +using Microsoft.AspNetCore.Mvc; +using Volo.Abp.AspNetCore.Mvc; +using Volo.Abp.AspNetCore.Mvc.UI.Widgets; +using Volo.CmsKit.Contents; + +namespace Volo.CmsKit.Web.Pages.CmsKit.Components.Contents; + +[ViewComponent(Name = "ContentFragment")] +[Widget( + AutoInitialize = true +)] +public class ContentFragmentViewComponent : AbpViewComponent +{ + public IContent ContentDto { get; set; } + + public virtual async Task InvokeAsync(IContent contentDto) + { + return View("~/Pages/CmsKit/Components/Contents/ContentFragment.cshtml", new ContentFragmentViewComponent() { ContentDto = contentDto }); + } +} \ No newline at end of file diff --git a/modules/cms-kit/src/Volo.CmsKit.Common.Web/Contents/ContentParser.cs b/modules/cms-kit/src/Volo.CmsKit.Common.Web/Pages/CmsKit/Components/Contents/ContentParser.cs similarity index 100% rename from modules/cms-kit/src/Volo.CmsKit.Common.Web/Contents/ContentParser.cs rename to modules/cms-kit/src/Volo.CmsKit.Common.Web/Pages/CmsKit/Components/Contents/ContentParser.cs diff --git a/modules/cms-kit/src/Volo.CmsKit.Common.Web/Contents/ContentWidgetConfig.cs b/modules/cms-kit/src/Volo.CmsKit.Common.Web/Pages/CmsKit/Components/Contents/ContentWidgetConfig.cs similarity index 100% rename from modules/cms-kit/src/Volo.CmsKit.Common.Web/Contents/ContentWidgetConfig.cs rename to modules/cms-kit/src/Volo.CmsKit.Common.Web/Pages/CmsKit/Components/Contents/ContentWidgetConfig.cs diff --git a/modules/cms-kit/src/Volo.CmsKit.Common.Web/Contents/IContentRenderer.cs b/modules/cms-kit/src/Volo.CmsKit.Common.Web/Pages/CmsKit/Components/Contents/IContentRenderer.cs similarity index 66% rename from modules/cms-kit/src/Volo.CmsKit.Common.Web/Contents/IContentRenderer.cs rename to modules/cms-kit/src/Volo.CmsKit.Common.Web/Pages/CmsKit/Components/Contents/IContentRenderer.cs index 879b27cda7..b33c044392 100644 --- a/modules/cms-kit/src/Volo.CmsKit.Common.Web/Contents/IContentRenderer.cs +++ b/modules/cms-kit/src/Volo.CmsKit.Common.Web/Pages/CmsKit/Components/Contents/IContentRenderer.cs @@ -1,6 +1,6 @@ using System.Threading.Tasks; -namespace Volo.CmsKit.Web.Contents; +namespace Volo.CmsKit.Web.Pages.CmsKit.Components.Contents; public interface IContentRenderer { diff --git a/modules/cms-kit/src/Volo.CmsKit.Common.Web/Contents/PlainTextContentRenderer.cs b/modules/cms-kit/src/Volo.CmsKit.Common.Web/Pages/CmsKit/Components/Contents/PlainTextContentRenderer.cs similarity index 80% rename from modules/cms-kit/src/Volo.CmsKit.Common.Web/Contents/PlainTextContentRenderer.cs rename to modules/cms-kit/src/Volo.CmsKit.Common.Web/Pages/CmsKit/Components/Contents/PlainTextContentRenderer.cs index cf68e25e15..3fcc78f658 100644 --- a/modules/cms-kit/src/Volo.CmsKit.Common.Web/Contents/PlainTextContentRenderer.cs +++ b/modules/cms-kit/src/Volo.CmsKit.Common.Web/Pages/CmsKit/Components/Contents/PlainTextContentRenderer.cs @@ -1,7 +1,7 @@ using System.Threading.Tasks; using Volo.Abp.DependencyInjection; -namespace Volo.CmsKit.Web.Contents; +namespace Volo.CmsKit.Web.Pages.CmsKit.Components.Contents; public class PlainTextContentRenderer : IContentRenderer, ITransientDependency { diff --git a/modules/cms-kit/src/Volo.CmsKit.Public.Web/Renderers/IMarkdownToHtmlRenderer.cs b/modules/cms-kit/src/Volo.CmsKit.Common.Web/Renderers/IMarkdownToHtmlRenderer.cs similarity index 80% rename from modules/cms-kit/src/Volo.CmsKit.Public.Web/Renderers/IMarkdownToHtmlRenderer.cs rename to modules/cms-kit/src/Volo.CmsKit.Common.Web/Renderers/IMarkdownToHtmlRenderer.cs index 0dd60f34c5..565437af7e 100644 --- a/modules/cms-kit/src/Volo.CmsKit.Public.Web/Renderers/IMarkdownToHtmlRenderer.cs +++ b/modules/cms-kit/src/Volo.CmsKit.Common.Web/Renderers/IMarkdownToHtmlRenderer.cs @@ -1,6 +1,6 @@ using System.Threading.Tasks; -namespace Volo.CmsKit.Public.Web.Renderers; +namespace Volo.CmsKit.Web.Renderers; public interface IMarkdownToHtmlRenderer { diff --git a/modules/cms-kit/src/Volo.CmsKit.Public.Web/Renderers/MarkdownToHtmlRenderer.cs b/modules/cms-kit/src/Volo.CmsKit.Common.Web/Renderers/MarkdownToHtmlRenderer.cs similarity index 98% rename from modules/cms-kit/src/Volo.CmsKit.Public.Web/Renderers/MarkdownToHtmlRenderer.cs rename to modules/cms-kit/src/Volo.CmsKit.Common.Web/Renderers/MarkdownToHtmlRenderer.cs index 4ef7c82c0d..83317c2111 100644 --- a/modules/cms-kit/src/Volo.CmsKit.Public.Web/Renderers/MarkdownToHtmlRenderer.cs +++ b/modules/cms-kit/src/Volo.CmsKit.Common.Web/Renderers/MarkdownToHtmlRenderer.cs @@ -7,7 +7,7 @@ using Ganss.XSS; using Markdig; using Volo.Abp.DependencyInjection; -namespace Volo.CmsKit.Public.Web.Renderers; +namespace Volo.CmsKit.Web.Renderers; public class MarkdownToHtmlRenderer : IMarkdownToHtmlRenderer, ITransientDependency { diff --git a/modules/cms-kit/src/Volo.CmsKit.Common.Web/Volo.CmsKit.Common.Web.csproj b/modules/cms-kit/src/Volo.CmsKit.Common.Web/Volo.CmsKit.Common.Web.csproj index 1ca9a78b27..e717f49be5 100644 --- a/modules/cms-kit/src/Volo.CmsKit.Common.Web/Volo.CmsKit.Common.Web.csproj +++ b/modules/cms-kit/src/Volo.CmsKit.Common.Web/Volo.CmsKit.Common.Web.csproj @@ -1,38 +1,40 @@ - - + + - - net6.0 - $(AssetTargetFallback);portable-net45+win8+wp8+wpa81; - true - Library - Volo.CmsKit.Web - true - + + net6.0 + $(AssetTargetFallback);portable-net45+win8+wp8+wpa81; + true + Library + Volo.CmsKit.Web + true + - - - - - + + + + + - - - + + + + + - - - - - - - - - - - - + + + + + + + + + + + + diff --git a/modules/cms-kit/src/Volo.CmsKit.Domain.Shared/Volo.CmsKit.Domain.Shared.csproj b/modules/cms-kit/src/Volo.CmsKit.Domain.Shared/Volo.CmsKit.Domain.Shared.csproj index 22160272fd..550a704a75 100644 --- a/modules/cms-kit/src/Volo.CmsKit.Domain.Shared/Volo.CmsKit.Domain.Shared.csproj +++ b/modules/cms-kit/src/Volo.CmsKit.Domain.Shared/Volo.CmsKit.Domain.Shared.csproj @@ -12,6 +12,7 @@ + diff --git a/modules/cms-kit/src/Volo.CmsKit.Domain.Shared/Volo/CmsKit/Features/CmsKitFeatureDefinitionProvider.cs b/modules/cms-kit/src/Volo.CmsKit.Domain.Shared/Volo/CmsKit/Features/CmsKitFeatureDefinitionProvider.cs new file mode 100644 index 0000000000..597e5240e8 --- /dev/null +++ b/modules/cms-kit/src/Volo.CmsKit.Domain.Shared/Volo/CmsKit/Features/CmsKitFeatureDefinitionProvider.cs @@ -0,0 +1,73 @@ +using Volo.Abp.Features; +using Volo.Abp.Localization; +using Volo.Abp.Validation.StringValues; +using Volo.CmsKit.Localization; + +namespace Volo.CmsKit.Features; +public class CmsKitFeatureDefinitionProvider : FeatureDefinitionProvider +{ + public override void Define(IFeatureDefinitionContext context) + { + var group = context.AddGroup(CmsKitFeatures.GroupName, + L("Feature:CmsKitGroup")); + + group.AddFeature(CmsKitFeatures.BlogEnable, + "true", + L("Feature:BlogEnable"), + L("Feature:BlogEnableDescription"), + new ToggleStringValueType()); + + group.AddFeature(CmsKitFeatures.CommentEnable, + "true", + L("Feature:CommentEnable"), + L("Feature:CommentEnableDescription"), + new ToggleStringValueType()); + + group.AddFeature(CmsKitFeatures.GlobalResourceEnable, + "true", + L("Feature:GlobalResourceEnable"), + L("Feature:GlobalResourceEnableDescription"), + new ToggleStringValueType()); + + group.AddFeature(CmsKitFeatures.MediaEnable, + "true", + L("Feature:MediaEnable"), + L("Feature:MediaEnableDescription"), + new ToggleStringValueType()); + + group.AddFeature(CmsKitFeatures.MenuEnable, + "true", + L("Feature:MenuEnable"), + L("Feature:MenuEnableDescription"), + new ToggleStringValueType()); + + group.AddFeature(CmsKitFeatures.PageEnable, + "true", + L("Feature:PageEnable"), + L("Feature:PageEnableDescription"), + new ToggleStringValueType()); + + group.AddFeature(CmsKitFeatures.RatingEnable, + "true", + L("Feature:RatingEnable"), + L("Feature:RatingEnableDescription"), + new ToggleStringValueType()); + + group.AddFeature(CmsKitFeatures.ReactionEnable, + "true", + L("Feature:ReactionEnable"), + L("Feature:ReactionEnableDescription"), + new ToggleStringValueType()); + + group.AddFeature(CmsKitFeatures.TagEnable, + "true", + L("Feature:TagEnable"), + L("Feature:TagEnableDescription"), + new ToggleStringValueType()); + } + + private static LocalizableString L(string name) + { + return LocalizableString.Create(name); + } +} diff --git a/modules/cms-kit/src/Volo.CmsKit.Domain.Shared/Volo/CmsKit/Features/CmsKitFeatures.cs b/modules/cms-kit/src/Volo.CmsKit.Domain.Shared/Volo/CmsKit/Features/CmsKitFeatures.cs new file mode 100644 index 0000000000..1dbf642755 --- /dev/null +++ b/modules/cms-kit/src/Volo.CmsKit.Domain.Shared/Volo/CmsKit/Features/CmsKitFeatures.cs @@ -0,0 +1,15 @@ +namespace Volo.CmsKit.Features; +public static class CmsKitFeatures +{ + public const string GroupName = "CmsKit"; + + public const string BlogEnable = GroupName + ".BlogEnable"; + public const string CommentEnable = GroupName + ".CommentEnable"; + public const string GlobalResourceEnable = GroupName + ".GlobalResourceEnable"; + public const string MediaEnable = GroupName + ".MediaEnable"; + public const string MenuEnable = GroupName + ".MenuEnable"; + public const string PageEnable = GroupName + ".PageEnable"; + public const string RatingEnable = GroupName + ".RatingEnable"; + public const string ReactionEnable = GroupName + ".ReactionEnable"; + public const string TagEnable = GroupName + ".TagEnable"; +} diff --git a/modules/cms-kit/src/Volo.CmsKit.Domain.Shared/Volo/CmsKit/GlobalFeatures/ContentsFeature.cs b/modules/cms-kit/src/Volo.CmsKit.Domain.Shared/Volo/CmsKit/GlobalFeatures/ContentsFeature.cs new file mode 100644 index 0000000000..ac752a68c4 --- /dev/null +++ b/modules/cms-kit/src/Volo.CmsKit.Domain.Shared/Volo/CmsKit/GlobalFeatures/ContentsFeature.cs @@ -0,0 +1,28 @@ +using JetBrains.Annotations; +using Volo.Abp.GlobalFeatures; + +namespace Volo.CmsKit.GlobalFeatures; + +[GlobalFeatureName(Name)] +public class ContentsFeature : GlobalFeature +{ + public const string Name = "CmsKit.Contents"; + + internal ContentsFeature( + [NotNull] GlobalCmsKitFeatures cmsKit + ) : base(cmsKit) + { + + } + + public override void Enable() + { + var userFeature = FeatureManager.Modules.CmsKit().User; + if (!userFeature.IsEnabled) + { + userFeature.Enable(); + } + + base.Enable(); + } +} diff --git a/modules/cms-kit/src/Volo.CmsKit.Domain.Shared/Volo/CmsKit/Localization/Resources/ar.json b/modules/cms-kit/src/Volo.CmsKit.Domain.Shared/Volo/CmsKit/Localization/Resources/ar.json index 922059463f..3119bf618c 100644 --- a/modules/cms-kit/src/Volo.CmsKit.Domain.Shared/Volo/CmsKit/Localization/Resources/ar.json +++ b/modules/cms-kit/src/Volo.CmsKit.Domain.Shared/Volo/CmsKit/Localization/Resources/ar.json @@ -75,7 +75,7 @@ "PageDeletionConfirmationMessage": "هل أنت متأكد من حذف هذه الصفحة؟", "PageId": "صفحة", "Pages": "الصفحات", - "PageSlugInformation": "سبيكة تستخدم على url. سيكون عنوان url الخاص بك هو \"/pages/{{slug}}\".", + "PageSlugInformation": "سبيكة تستخدم على url. سيكون عنوان url الخاص بك هو \"/{slug}}\".", "Permission:BlogManagement": "إدارة المدونة", "Permission:BlogManagement.Create": "إنشاء", "Permission:BlogManagement.Delete": "حذف", diff --git a/modules/cms-kit/src/Volo.CmsKit.Domain.Shared/Volo/CmsKit/Localization/Resources/cs.json b/modules/cms-kit/src/Volo.CmsKit.Domain.Shared/Volo/CmsKit/Localization/Resources/cs.json index 9192b48abe..8ae9479b06 100644 --- a/modules/cms-kit/src/Volo.CmsKit.Domain.Shared/Volo/CmsKit/Localization/Resources/cs.json +++ b/modules/cms-kit/src/Volo.CmsKit.Domain.Shared/Volo/CmsKit/Localization/Resources/cs.json @@ -75,7 +75,7 @@ "PageDeletionConfirmationMessage": "Opravdu chcete smazat tuto stránku?", "PageId": "Strana", "Pages": "stránky", - "PageSlugInformation": "Na adrese URL je použit Slug. Vaše adresa URL bude '/pages/{{slug}}'.", + "PageSlugInformation": "Na adrese URL je použit Slug. Vaše adresa URL bude '/{{slug}}'.", "Permission:BlogManagement": "Správa blogu", "Permission:BlogManagement.Create": "Vytvořit", "Permission:BlogManagement.Delete": "Vymazat", diff --git a/modules/cms-kit/src/Volo.CmsKit.Domain.Shared/Volo/CmsKit/Localization/Resources/de-DE.json b/modules/cms-kit/src/Volo.CmsKit.Domain.Shared/Volo/CmsKit/Localization/Resources/de-DE.json index 903a7e3d0a..857f7f1e1a 100644 --- a/modules/cms-kit/src/Volo.CmsKit.Domain.Shared/Volo/CmsKit/Localization/Resources/de-DE.json +++ b/modules/cms-kit/src/Volo.CmsKit.Domain.Shared/Volo/CmsKit/Localization/Resources/de-DE.json @@ -75,7 +75,7 @@ "PageDeletionConfirmationMessage": "Möchten Sie diese Seite wirklich löschen?", "PageId": "Buchseite", "Pages": "Seiten", - "PageSlugInformation": "Slug wird auf URL verwendet. Ihre URL lautet '/pages/{{slug}}'.", + "PageSlugInformation": "Slug wird auf URL verwendet. Ihre URL lautet '/{{slug}}'.", "Permission:BlogManagement": "Blog-Verwaltung", "Permission:BlogManagement.Create": "Schaffen", "Permission:BlogManagement.Delete": "Löschen", diff --git a/modules/cms-kit/src/Volo.CmsKit.Domain.Shared/Volo/CmsKit/Localization/Resources/el.json b/modules/cms-kit/src/Volo.CmsKit.Domain.Shared/Volo/CmsKit/Localization/Resources/el.json index 222cbe0fbd..7a838b120a 100644 --- a/modules/cms-kit/src/Volo.CmsKit.Domain.Shared/Volo/CmsKit/Localization/Resources/el.json +++ b/modules/cms-kit/src/Volo.CmsKit.Domain.Shared/Volo/CmsKit/Localization/Resources/el.json @@ -75,7 +75,7 @@ "PageDeletionConfirmationMessage": "Είστε βέβαιοι ότι θα διαγράψετε αυτήν τη σελίδα;", "PageId": "Σελίδα", "Pages": "Σελίδες", - "PageSlugInformation": "Το Slug χρησιμοποιείται στο url. Το url σας θα είναι '/pages/{{slug}}'.", + "PageSlugInformation": "Το Slug χρησιμοποιείται στο url. Το url σας θα είναι '/{{slug}}'.", "Permission:BlogManagement": "Διαχείριση ιστολογίου", "Permission:BlogManagement.Create": "Δημιουργώ", "Permission:BlogManagement.Delete": "Διαγράφω", 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 8da6be8bd5..0faaf04e81 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 @@ -75,7 +75,7 @@ "PageDeletionConfirmationMessage": "Are you sure to delete this page?", "PageId": "Page", "Pages": "Pages", - "PageSlugInformation": "Slug is used on url. Your url will be '/pages/{{slug}}'.", + "PageSlugInformation": "Slug is used on url. Your url will be '/{{slug}}'.", "Permission:BlogManagement": "Blog Management", "Permission:BlogManagement.Create": "Create", "Permission:BlogManagement.Delete": "Delete", @@ -185,8 +185,27 @@ "Add": "Add", "AddWidget": "Add Widget", "PleaseConfigureWidgets": "Please configure widgets", - "SelectAnAuthor":"Select an Author", - "InThisDocument":"In This Document", - "GoToTop":"Go To Top" + "SelectAnAuthor": "Select an Author", + "InThisDocument": "In This Document", + "GoToTop": "Go To Top", + "Feature:CmsKitGroup": "Cms Kit", + "Feature:BlogEnable": "Enabled blog page", + "Feature:BlogEnableDescription": "Enable blog page in the application.", + "Feature:CommentEnable": "Enabled commenting", + "Feature:CommentEnableDescription": "Enable comment in the application.", + "Feature:GlobalResourceEnable": "Enabled global resourcing", + "Feature:GlobalResourceEnableDescription": "Enable global resource in the application.", + "Feature:MediaEnable": "Enabled media", + "Feature:MediaEnableDescription": "Enable media in the application.", + "Feature:MenuEnable": "Enabled menu", + "Feature:MenuEnableDescription": "Enable menu in the application.", + "Feature:PageEnable": "Enabled paging page", + "Feature:PageEnableDescription": "Enable paging page in the application.", + "Feature:RatingEnable": "Enabled rating", + "Feature:RatingEnableDescription": "Enable rating in the application.", + "Feature:ReactionEnable": "Enabled reaction", + "Feature:ReactionEnableDescription": "Enable reaction in the application.", + "Feature:TagEnable": "Enabled taging", + "Feature:TagEnableDescription": "Enable taging in the application." } } \ No newline at end of file diff --git a/modules/cms-kit/src/Volo.CmsKit.Domain.Shared/Volo/CmsKit/Localization/Resources/es.json b/modules/cms-kit/src/Volo.CmsKit.Domain.Shared/Volo/CmsKit/Localization/Resources/es.json index 19df2c45a2..8e8750e530 100644 --- a/modules/cms-kit/src/Volo.CmsKit.Domain.Shared/Volo/CmsKit/Localization/Resources/es.json +++ b/modules/cms-kit/src/Volo.CmsKit.Domain.Shared/Volo/CmsKit/Localization/Resources/es.json @@ -75,7 +75,7 @@ "PageDeletionConfirmationMessage": "¿Está seguro de eliminar esta página?", "PageId": "Página", "Pages": "Paginas", - "PageSlugInformation": "Slug se usa en la URL. Su URL será '/pages/{{slug}}'.", + "PageSlugInformation": "Slug se usa en la URL. Su URL será '/{{slug}}'.", "Permission:BlogManagement": "Gestión de blogs", "Permission:BlogManagement.Create": "Crear", "Permission:BlogManagement.Delete": "Borrar", diff --git a/modules/cms-kit/src/Volo.CmsKit.Domain.Shared/Volo/CmsKit/Localization/Resources/fa.json b/modules/cms-kit/src/Volo.CmsKit.Domain.Shared/Volo/CmsKit/Localization/Resources/fa.json index 3ac961feef..855b6d091d 100644 --- a/modules/cms-kit/src/Volo.CmsKit.Domain.Shared/Volo/CmsKit/Localization/Resources/fa.json +++ b/modules/cms-kit/src/Volo.CmsKit.Domain.Shared/Volo/CmsKit/Localization/Resources/fa.json @@ -75,7 +75,7 @@ "PageDeletionConfirmationMessage": "آیا مطمئن هستید که این صفحه را حذف می کنید؟", "PageId": "صفحه", "Pages": "صفحات", - "PageSlugInformation": "Slug در url استفاده می شود. آدرس اینترنتی شما '/pages/{{slug}}' خواهد بود.", + "PageSlugInformation": "Slug در url استفاده می شود. آدرس اینترنتی شما '/{{slug}}' خواهد بود.", "Permission:BlogManagement": "مدیریت وبلاگ", "Permission:BlogManagement.Create": "ایجاد", "Permission:BlogManagement.Delete": "حذف", diff --git a/modules/cms-kit/src/Volo.CmsKit.Domain.Shared/Volo/CmsKit/Localization/Resources/fi.json b/modules/cms-kit/src/Volo.CmsKit.Domain.Shared/Volo/CmsKit/Localization/Resources/fi.json index 30a56fa9c0..438818cdfb 100644 --- a/modules/cms-kit/src/Volo.CmsKit.Domain.Shared/Volo/CmsKit/Localization/Resources/fi.json +++ b/modules/cms-kit/src/Volo.CmsKit.Domain.Shared/Volo/CmsKit/Localization/Resources/fi.json @@ -75,7 +75,7 @@ "PageDeletionConfirmationMessage": "Haluatko varmasti poistaa tämän sivun?", "PageId": "Sivu", "Pages": "Sivut", - "PageSlugInformation": "Etanaa käytetään URL-osoitteessa. URL-osoitteesi on '/pages/{{slug}}'.", + "PageSlugInformation": "Etanaa käytetään URL-osoitteessa. URL-osoitteesi on '/{{slug}}'.", "Permission:BlogManagement": "Blogin hallinta", "Permission:BlogManagement.Create": "Luoda", "Permission:BlogManagement.Delete": "Poistaa", diff --git a/modules/cms-kit/src/Volo.CmsKit.Domain.Shared/Volo/CmsKit/Localization/Resources/fr.json b/modules/cms-kit/src/Volo.CmsKit.Domain.Shared/Volo/CmsKit/Localization/Resources/fr.json index 6d4e8f4cf5..5c789e996e 100644 --- a/modules/cms-kit/src/Volo.CmsKit.Domain.Shared/Volo/CmsKit/Localization/Resources/fr.json +++ b/modules/cms-kit/src/Volo.CmsKit.Domain.Shared/Volo/CmsKit/Localization/Resources/fr.json @@ -75,7 +75,7 @@ "PageDeletionConfirmationMessage": "Êtes-vous sûr de vouloir supprimer cette page?", "PageId": "Page", "Pages": "Pages", - "PageSlugInformation": "Slug est utilisé sur l'url. Votre URL sera '/pages/{{slug}}'.", + "PageSlugInformation": "Slug est utilisé sur l'url. Votre URL sera '/{{slug}}'.", "Permission:BlogManagement": "Gestion de blog", "Permission:BlogManagement.Create": "Créer", "Permission:BlogManagement.Delete": "Effacer", diff --git a/modules/cms-kit/src/Volo.CmsKit.Domain.Shared/Volo/CmsKit/Localization/Resources/hi.json b/modules/cms-kit/src/Volo.CmsKit.Domain.Shared/Volo/CmsKit/Localization/Resources/hi.json index 732ca3d2de..8f69f2e25f 100644 --- a/modules/cms-kit/src/Volo.CmsKit.Domain.Shared/Volo/CmsKit/Localization/Resources/hi.json +++ b/modules/cms-kit/src/Volo.CmsKit.Domain.Shared/Volo/CmsKit/Localization/Resources/hi.json @@ -75,7 +75,7 @@ "PageDeletionConfirmationMessage": "क्या आप इस पृष्ठ को हटाना सुनिश्चित कर रहे हैं?", "PageId": "पृष्ठ", "Pages": "पृष्ठों", - "PageSlugInformation": "स्लग का उपयोग url पर किया जाता है। आपका url '/pages/{{slug}}' होगा।", + "PageSlugInformation": "स्लग का उपयोग url पर किया जाता है। आपका url '/{{slug}}' होगा।", "Permission:BlogManagement": "ब्लॉग प्रबंधन", "Permission:BlogManagement.Create": "सृजन करना", "Permission:BlogManagement.Delete": "हटाएं", diff --git a/modules/cms-kit/src/Volo.CmsKit.Domain.Shared/Volo/CmsKit/Localization/Resources/hu.json b/modules/cms-kit/src/Volo.CmsKit.Domain.Shared/Volo/CmsKit/Localization/Resources/hu.json index 49b7d5f828..ebeb5dad25 100644 --- a/modules/cms-kit/src/Volo.CmsKit.Domain.Shared/Volo/CmsKit/Localization/Resources/hu.json +++ b/modules/cms-kit/src/Volo.CmsKit.Domain.Shared/Volo/CmsKit/Localization/Resources/hu.json @@ -75,7 +75,7 @@ "PageDeletionConfirmationMessage": "Biztosan törlöd ezt az oldalt?", "PageId": "oldal", "Pages": "Oldalak", - "PageSlugInformation": "A Slug az url-en használatos. Az Ön URL-je a következő lesz: „/pages/{{slug}}”.", + "PageSlugInformation": "A Slug az url-en használatos. Az Ön URL-je a következő lesz: „/{{slug}}”.", "Permission:BlogManagement": "Blogkezelés", "Permission:BlogManagement.Create": "Teremt", "Permission:BlogManagement.Delete": "Töröl", diff --git a/modules/cms-kit/src/Volo.CmsKit.Domain.Shared/Volo/CmsKit/Localization/Resources/it.json b/modules/cms-kit/src/Volo.CmsKit.Domain.Shared/Volo/CmsKit/Localization/Resources/it.json index f5bb342dc6..60c8d13744 100644 --- a/modules/cms-kit/src/Volo.CmsKit.Domain.Shared/Volo/CmsKit/Localization/Resources/it.json +++ b/modules/cms-kit/src/Volo.CmsKit.Domain.Shared/Volo/CmsKit/Localization/Resources/it.json @@ -75,7 +75,7 @@ "PageDeletionConfirmationMessage": "Sei sicuro di cancellare questa pagina?", "PageId": "Pagina", "Pages": "Pagine", - "PageSlugInformation": "Lo slug viene utilizzato sull'URL. Il tuo URL sarà '/pages/{{slug}}'.", + "PageSlugInformation": "Lo slug viene utilizzato sull'URL. Il tuo URL sarà '/{{slug}}'.", "Permission:BlogManagement": "Gestione del blog", "Permission:BlogManagement.Create": "Crea", "Permission:BlogManagement.Delete": "Elimina", diff --git a/modules/cms-kit/src/Volo.CmsKit.Domain.Shared/Volo/CmsKit/Localization/Resources/nl.json b/modules/cms-kit/src/Volo.CmsKit.Domain.Shared/Volo/CmsKit/Localization/Resources/nl.json index b8adbbd5bb..39779d1d57 100644 --- a/modules/cms-kit/src/Volo.CmsKit.Domain.Shared/Volo/CmsKit/Localization/Resources/nl.json +++ b/modules/cms-kit/src/Volo.CmsKit.Domain.Shared/Volo/CmsKit/Localization/Resources/nl.json @@ -75,7 +75,7 @@ "PageDeletionConfirmationMessage": "Weet u zeker dat u deze pagina wilt verwijderen?", "PageId": "Bladzijde", "Pages": "Pagina's", - "PageSlugInformation": "Slug wordt gebruikt voor de url. Uw url wordt '/pages/{{slug}}'.", + "PageSlugInformation": "Slug wordt gebruikt voor de url. Uw url wordt '/{{slug}}'.", "Permission:BlogManagement": "Blogbeheer", "Permission:BlogManagement.Create": "Toevoegen", "Permission:BlogManagement.Delete": "Verwijderen", diff --git a/modules/cms-kit/src/Volo.CmsKit.Domain.Shared/Volo/CmsKit/Localization/Resources/pl-PL.json b/modules/cms-kit/src/Volo.CmsKit.Domain.Shared/Volo/CmsKit/Localization/Resources/pl-PL.json index 6c5e77a7d3..5a2ed06a5d 100644 --- a/modules/cms-kit/src/Volo.CmsKit.Domain.Shared/Volo/CmsKit/Localization/Resources/pl-PL.json +++ b/modules/cms-kit/src/Volo.CmsKit.Domain.Shared/Volo/CmsKit/Localization/Resources/pl-PL.json @@ -75,7 +75,7 @@ "PageDeletionConfirmationMessage": "Czy na pewno chcesz usunąć tę stronę?", "PageId": "Strona", "Pages": "Strony", - "PageSlugInformation": "Slug jest używany na adresie URL. Twój adres URL to „/pages/{{slug}}”.", + "PageSlugInformation": "Slug jest używany na adresie URL. Twój adres URL to „/{{slug}}”.", "Permission:BlogManagement": "Zarządzanie blogiem", "Permission:BlogManagement.Create": "Tworzyć", "Permission:BlogManagement.Delete": "Kasować", diff --git a/modules/cms-kit/src/Volo.CmsKit.Domain.Shared/Volo/CmsKit/Localization/Resources/pt-BR.json b/modules/cms-kit/src/Volo.CmsKit.Domain.Shared/Volo/CmsKit/Localization/Resources/pt-BR.json index 5ec2a64799..fff05fefdd 100644 --- a/modules/cms-kit/src/Volo.CmsKit.Domain.Shared/Volo/CmsKit/Localization/Resources/pt-BR.json +++ b/modules/cms-kit/src/Volo.CmsKit.Domain.Shared/Volo/CmsKit/Localization/Resources/pt-BR.json @@ -75,7 +75,7 @@ "PageDeletionConfirmationMessage": "Tem certeza que deseja deletar esta página?", "PageId": "Página", "Pages": "Páginas", - "PageSlugInformation": "Slug é usado na url. Sua url será '/pages/{{slug}}'.", + "PageSlugInformation": "Slug é usado na url. Sua url será '/{{slug}}'.", "Permission:BlogManagement": "Gerenciamento de blogs", "Permission:BlogManagement.Create": "Criar", "Permission:BlogManagement.Delete": "Excluir", @@ -181,6 +181,31 @@ "HasBlogPostWaitingForReviewMessage": "Você tem uma postagem para revisão. Clique para listar.", "SelectAStatus": "Selecione um status", "Status": "Status", - "CmsKit.BlogPost.ScrollIndex": "Barra de navegação rápida em postagens" + "CmsKit.BlogPost.ScrollIndex": "Barra de navegação rápida em postagens", + "Add": "Adicionar", + "AddWidget": "Adicionar Widget", + "PleaseConfigureWidgets": "Por favor, configure os widgets", + "SelectAnAuthor": "Selecione um Autor", + "InThisDocument": "Neste Documento", + "GoToTop": "Ir para o Topo", + "Feature:CmsKitGroup": "Cms Kit", + "Feature:BlogEnable": "Habilitar página de blog", + "Feature:BlogEnableDescription": "Habilitar página de blog no aplicativo.", + "Feature:CommentEnable": "Habilitar comentários", + "Feature:CommentEnableDescription": "Habilitar comentários no aplicativo.", + "Feature:GlobalResourceEnable": "Recursos globais ativados", + "Feature:GlobalResourceEnableDescription": "Habilitar recurso global no aplicativo.", + "Feature:MediaEnable": "Mídia ativada", + "Feature:MediaEnableDescription": "Mídia ativada no aplicativo.", + "Feature:MenuEnable": "Menu habilitado", + "Feature:MenuEnableDescription": "Menu habilitado no aplicativo.", + "Feature:PageEnable": "Página de paginação ativada", + "Feature:PageEnableDescription": "Página de paginação ativada no aplicativo.", + "Feature:RatingEnable": "Classificação ativada", + "Feature:RatingEnableDescription": "Classificação ativada no aplicativo.", + "Feature:ReactionEnable": "Reações habilitadas", + "Feature:ReactionEnableDescription": "Reações habilitadas no aplicativo.", + "Feature:TagEnable": "Habilitar tag", + "Feature:TagEnableDescription": "Habilitar tag no aplicativo." } } \ No newline at end of file diff --git a/modules/cms-kit/src/Volo.CmsKit.Domain.Shared/Volo/CmsKit/Localization/Resources/ro-RO.json b/modules/cms-kit/src/Volo.CmsKit.Domain.Shared/Volo/CmsKit/Localization/Resources/ro-RO.json index 3e7e1caaa9..9cd519bb53 100644 --- a/modules/cms-kit/src/Volo.CmsKit.Domain.Shared/Volo/CmsKit/Localization/Resources/ro-RO.json +++ b/modules/cms-kit/src/Volo.CmsKit.Domain.Shared/Volo/CmsKit/Localization/Resources/ro-RO.json @@ -75,7 +75,7 @@ "PageDeletionConfirmationMessage": "Sunteţi sigur(ă) că vreţi să ştergeţi această pagină?", "PageId": "Pagina", "Pages": "Pagini", - "PageSlugInformation": "Slug este folosit pe url. Url-ul dumneavoastră va fi '/pages/{{slug}}'.", + "PageSlugInformation": "Slug este folosit pe url. Url-ul dumneavoastră va fi '/{{slug}}'.", "Permission:BlogManagement": "Administrare Blog", "Permission:BlogManagement.Create": "Creează", "Permission:BlogManagement.Delete": "Şterge", diff --git a/modules/cms-kit/src/Volo.CmsKit.Domain.Shared/Volo/CmsKit/Localization/Resources/ru.json b/modules/cms-kit/src/Volo.CmsKit.Domain.Shared/Volo/CmsKit/Localization/Resources/ru.json index 289b952e1b..f95ee910e4 100644 --- a/modules/cms-kit/src/Volo.CmsKit.Domain.Shared/Volo/CmsKit/Localization/Resources/ru.json +++ b/modules/cms-kit/src/Volo.CmsKit.Domain.Shared/Volo/CmsKit/Localization/Resources/ru.json @@ -75,7 +75,7 @@ "PageDeletionConfirmationMessage": "Вы уверены, что хотите удалить эту страницу?", "PageId": "Страница", "Pages": "Страницы", - "PageSlugInformation": "Слаг используется для URL. Ваш URL-адрес будет '/pages/{{slug}}'.", + "PageSlugInformation": "Слаг используется для URL. Ваш URL-адрес будет '/{{slug}}'.", "Permission:BlogManagement": "Управление блогом", "Permission:BlogManagement.Create": "Создавать", "Permission:BlogManagement.Delete": "Удалить", diff --git a/modules/cms-kit/src/Volo.CmsKit.Domain.Shared/Volo/CmsKit/Localization/Resources/sk.json b/modules/cms-kit/src/Volo.CmsKit.Domain.Shared/Volo/CmsKit/Localization/Resources/sk.json index d5873f42e1..2cf9410ca9 100644 --- a/modules/cms-kit/src/Volo.CmsKit.Domain.Shared/Volo/CmsKit/Localization/Resources/sk.json +++ b/modules/cms-kit/src/Volo.CmsKit.Domain.Shared/Volo/CmsKit/Localization/Resources/sk.json @@ -75,7 +75,7 @@ "PageDeletionConfirmationMessage": "Určite chcete túto stránku vymazať?", "PageId": "Stránka", "Pages": "Stránky", - "PageSlugInformation": "Slug sa používa v URL. Vaša URL bude '/pages/{{slug}}'.", + "PageSlugInformation": "Slug sa používa v URL. Vaša URL bude '/{{slug}}'.", "Permission:BlogManagement": "Správa blogov", "Permission:BlogManagement.Create": "Vytvoriť", "Permission:BlogManagement.Delete": "Zmazať", diff --git a/modules/cms-kit/src/Volo.CmsKit.Domain.Shared/Volo/CmsKit/Localization/Resources/sl.json b/modules/cms-kit/src/Volo.CmsKit.Domain.Shared/Volo/CmsKit/Localization/Resources/sl.json index 0a79428aac..22f252ea51 100644 --- a/modules/cms-kit/src/Volo.CmsKit.Domain.Shared/Volo/CmsKit/Localization/Resources/sl.json +++ b/modules/cms-kit/src/Volo.CmsKit.Domain.Shared/Volo/CmsKit/Localization/Resources/sl.json @@ -75,7 +75,7 @@ "PageDeletionConfirmationMessage": "Ali ste prepričani, da želite izbrisati to stran?", "PageId": "stran", "Pages": "strani", - "PageSlugInformation": "Slug se uporablja na url-ju. Vaš url bo '/pages/{{slug}}'.", + "PageSlugInformation": "Slug se uporablja na url-ju. Vaš url bo '/{{slug}}'.", "Permission:BlogManagement": "Upravljanje blogov", "Permission:BlogManagement.Create": "Ustvari", "Permission:BlogManagement.Delete": "Izbriši", 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 431c50596c..78fb34087b 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 @@ -75,7 +75,7 @@ "PageDeletionConfirmationMessage": "Bu sayfayı silmek istediğinize emin misiniz?", "PageId": "Sayfa", "Pages": "Sayfalar", - "PageSlugInformation": "Etiket URL'de kullanılır. Url şöyle görünür: '/pages/{{slug}}'.", + "PageSlugInformation": "Etiket URL'de kullanılır. Url şöyle görünür: '/{{slug}}'.", "Permission:BlogManagement": "Blog Yönetimi", "Permission:BlogManagement.Create": "Oluşturma", "Permission:BlogManagement.Delete": "Silme", @@ -190,6 +190,25 @@ "CmsKit.BlogPost.ScrollIndex": "Blog yazılarında hızlı gezinme çubuğu", "Add": "Ekle", "AddWidget": "Widget Ekle", - "PleaseConfigureWidgets": "Lütfen widget'leri yapılandırın" + "PleaseConfigureWidgets": "Lütfen widget'leri yapılandırın", + "Feature:CmsKitGroup": "Cms Kit", + "Feature:BlogEnable": "Blog sayfasını etkinleştirin", + "Feature:BlogEnableDescription": "Uygulamınızdaki blog sayfasını etkinleştirir.", + "Feature:CommentEnable": "Yorum özelliğini etkinleştirin", + "Feature:CommentEnableDescription": "Uygulamınızdaki yorum özelliğini etkinleştirir.", + "Feature:GlobalResourceEnable": "Blog global kaynakları etkinleştirin", + "Feature:GlobalResourceEnableDescription": "Uygulamınızdaki global kaynakları etkinleştirir.", + "Feature:MediaEnable": "Medyayı etkinleştirin", + "Feature:MediaEnableDescription": "Uygulamınızdaki medyayı etkinleştirir.", + "Feature:MenuEnable": "Menüyü etkinleştirin", + "Feature:MenuEnableDescription": "Uygulamınızdaki menüyü etkinleştirir.", + "Feature:PageEnable": "Sayfa özelliğini etkinleştirin", + "Feature:PageEnableDescription": "Uygulamınızdaki sayfa özelliğini etkinleştirir.", + "Feature:RatingEnable": "Oylamayı etkinleştirin", + "Feature:RatingEnableDescription": "Uygulamınızdaki oylamayı etkinleştirir.", + "Feature:ReactionEnable": "Reaksiyonları etkinleştirin", + "Feature:ReactionEnableDescription": "Uygulamınızdaki reaksiyonları etkinleştirir.", + "Feature:TagEnable": "Etkiketleri etkinleştirin", + "Feature:TagEnableDescription": "Uygulamınızdaki etiketleri etkinleştirir." } } diff --git a/modules/cms-kit/src/Volo.CmsKit.Domain.Shared/Volo/CmsKit/Localization/Resources/vi.json b/modules/cms-kit/src/Volo.CmsKit.Domain.Shared/Volo/CmsKit/Localization/Resources/vi.json index b0ed51a5d6..a581da6362 100644 --- a/modules/cms-kit/src/Volo.CmsKit.Domain.Shared/Volo/CmsKit/Localization/Resources/vi.json +++ b/modules/cms-kit/src/Volo.CmsKit.Domain.Shared/Volo/CmsKit/Localization/Resources/vi.json @@ -75,7 +75,7 @@ "PageDeletionConfirmationMessage": "Bạn có chắc chắn xóa trang này không?", "PageId": "Trang", "Pages": "Các trang", - "PageSlugInformation": "Slug được sử dụng trên url. Url của bạn sẽ là '/pages/{{slug}}'.", + "PageSlugInformation": "Slug được sử dụng trên url. Url của bạn sẽ là '/{{slug}}'.", "Permission:BlogManagement": "Quản lý blog", "Permission:BlogManagement.Create": "Tạo ra", "Permission:BlogManagement.Delete": "Xóa bỏ", diff --git a/modules/cms-kit/src/Volo.CmsKit.Domain.Shared/Volo/CmsKit/Localization/Resources/zh-Hans.json b/modules/cms-kit/src/Volo.CmsKit.Domain.Shared/Volo/CmsKit/Localization/Resources/zh-Hans.json index b312349ef4..bba6fff938 100644 --- a/modules/cms-kit/src/Volo.CmsKit.Domain.Shared/Volo/CmsKit/Localization/Resources/zh-Hans.json +++ b/modules/cms-kit/src/Volo.CmsKit.Domain.Shared/Volo/CmsKit/Localization/Resources/zh-Hans.json @@ -75,7 +75,7 @@ "PageDeletionConfirmationMessage": "你确定删除这个页面吗?", "PageId": "页", "Pages": "页面", - "PageSlugInformation": "Slug用于url. 你的url将是 '/pages/{{slug}}'.", + "PageSlugInformation": "Slug用于url. 你的url将是 '/{{slug}}'.", "Permission:BlogManagement": "博客管理", "Permission:BlogManagement.Create": "创建", "Permission:BlogManagement.Delete": "删除", 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 index 49584e5af0..91a742deba 100644 --- 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 @@ -75,7 +75,7 @@ "PageDeletionConfirmationMessage": "你確定刪除這個頁面嗎?", "PageId": "頁", "Pages": "頁面", - "PageSlugInformation": "Slug用於網址. 你的網址將是 '/pages/{{slug}}'.", + "PageSlugInformation": "Slug用於網址. 你的網址將是 '/{{slug}}'.", "Permission:BlogManagement": "部落格管理", "Permission:BlogManagement.Create": "創建", "Permission:BlogManagement.Delete": "刪除", diff --git a/modules/cms-kit/src/Volo.CmsKit.Domain.Shared/Volo/CmsKit/Pages/PageConsts.cs b/modules/cms-kit/src/Volo.CmsKit.Domain.Shared/Volo/CmsKit/Pages/PageConsts.cs index 9f03dc809f..ff07df87a1 100644 --- a/modules/cms-kit/src/Volo.CmsKit.Domain.Shared/Volo/CmsKit/Pages/PageConsts.cs +++ b/modules/cms-kit/src/Volo.CmsKit.Domain.Shared/Volo/CmsKit/Pages/PageConsts.cs @@ -2,7 +2,7 @@ namespace Volo.CmsKit.Pages; -public class PageConsts +public static class PageConsts { public const string EntityType = "Page"; @@ -16,7 +16,7 @@ public class PageConsts public static int MaxStyleLength { get; set; } = int.MaxValue; - private static string _urlPrefix = "/pages/"; + private static string _urlPrefix = "/"; public static string UrlPrefix { get => _urlPrefix; set => _urlPrefix = value.EnsureEndsWith('/').EnsureStartsWith('/'); diff --git a/modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/CmsKitDbProperties.cs b/modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/AbpCmsKitDbProperties.cs similarity index 83% rename from modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/CmsKitDbProperties.cs rename to modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/AbpCmsKitDbProperties.cs index 6a29834233..1ce1fd8413 100644 --- a/modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/CmsKitDbProperties.cs +++ b/modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/AbpCmsKitDbProperties.cs @@ -1,6 +1,6 @@ namespace Volo.CmsKit; -public static class CmsKitDbProperties +public static class AbpCmsKitDbProperties { public static string DbTablePrefix { get; set; } = "Cms"; diff --git a/modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/Tags/EntityTagManager.cs b/modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/Tags/EntityTagManager.cs index 2707b8854c..98a401af17 100644 --- a/modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/Tags/EntityTagManager.cs +++ b/modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/Tags/EntityTagManager.cs @@ -1,9 +1,9 @@ -using JetBrains.Annotations; -using System; +using System; using System.Collections.Generic; using System.Linq; using System.Threading; using System.Threading.Tasks; +using JetBrains.Annotations; using Volo.Abp.Domain.Services; namespace Volo.CmsKit.Tags; @@ -62,7 +62,7 @@ public class EntityTagManager : DomainService var deletedTags = existingTags.Where(x => !tags.Contains(x.Name)).ToList(); var addedTags = tags.Where(x => !existingTags.Any(a => a.Name == x)); - await EntityTagRepository.DeleteManyAsync(deletedTags.Select(s => s.Id).ToArray()); + await EntityTagRepository.DeleteManyAsync(deletedTags.Select(s => s.Id).ToArray(), entityId); foreach (var addedTag in addedTags) { @@ -85,6 +85,6 @@ public class EntityTagManager : DomainService [CanBeNull] Guid? tenantId, CancellationToken cancellationToken = default) { - return await EntityTagRepository.GetEntityIdsFilteredByTagNameAsync(tagName, entityType,tenantId, cancellationToken); + return await EntityTagRepository.GetEntityIdsFilteredByTagNameAsync(tagName, entityType, tenantId, cancellationToken); } } \ No newline at end of file diff --git a/modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/Tags/IEntityTagRepository.cs b/modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/Tags/IEntityTagRepository.cs index 5105635c82..098ac8e46c 100644 --- a/modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/Tags/IEntityTagRepository.cs +++ b/modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/Tags/IEntityTagRepository.cs @@ -1,8 +1,8 @@ -using JetBrains.Annotations; -using System; +using System; using System.Collections.Generic; using System.Threading; using System.Threading.Tasks; +using JetBrains.Annotations; using Volo.Abp.Domain.Repositories; namespace Volo.CmsKit.Tags; @@ -15,7 +15,7 @@ public interface IEntityTagRepository : IBasicRepository [CanBeNull] Guid? tenantId, CancellationToken cancellationToken = default); - Task DeleteManyAsync(Guid[] tagIds, CancellationToken cancellationToken = default); + Task DeleteManyAsync(Guid[] tagIds, string entityId, CancellationToken cancellationToken = default); Task> GetEntityIdsFilteredByTagAsync( [NotNull] Guid tagId, @@ -25,6 +25,6 @@ public interface IEntityTagRepository : IBasicRepository Task> GetEntityIdsFilteredByTagNameAsync( [NotNull] string tagName, [NotNull] string entityType, - [CanBeNull] Guid? tenantId=null, - CancellationToken cancellationToken=default); + [CanBeNull] Guid? tenantId = null, + CancellationToken cancellationToken = default); } diff --git a/modules/cms-kit/src/Volo.CmsKit.EntityFrameworkCore/Volo/CmsKit/EntityFrameworkCore/CmsKitDbContext.cs b/modules/cms-kit/src/Volo.CmsKit.EntityFrameworkCore/Volo/CmsKit/EntityFrameworkCore/CmsKitDbContext.cs index 8f501f4c98..265495f5bf 100644 --- a/modules/cms-kit/src/Volo.CmsKit.EntityFrameworkCore/Volo/CmsKit/EntityFrameworkCore/CmsKitDbContext.cs +++ b/modules/cms-kit/src/Volo.CmsKit.EntityFrameworkCore/Volo/CmsKit/EntityFrameworkCore/CmsKitDbContext.cs @@ -14,7 +14,7 @@ using Volo.CmsKit.Users; namespace Volo.CmsKit.EntityFrameworkCore; -[ConnectionStringName(CmsKitDbProperties.ConnectionStringName)] +[ConnectionStringName(AbpCmsKitDbProperties.ConnectionStringName)] public class CmsKitDbContext : AbpDbContext, ICmsKitDbContext { public DbSet Comments { get; set; } diff --git a/modules/cms-kit/src/Volo.CmsKit.EntityFrameworkCore/Volo/CmsKit/EntityFrameworkCore/CmsKitDbContextModelCreatingExtensions.cs b/modules/cms-kit/src/Volo.CmsKit.EntityFrameworkCore/Volo/CmsKit/EntityFrameworkCore/CmsKitDbContextModelCreatingExtensions.cs index 9ab103fefc..9a42f6c4b0 100644 --- a/modules/cms-kit/src/Volo.CmsKit.EntityFrameworkCore/Volo/CmsKit/EntityFrameworkCore/CmsKitDbContextModelCreatingExtensions.cs +++ b/modules/cms-kit/src/Volo.CmsKit.EntityFrameworkCore/Volo/CmsKit/EntityFrameworkCore/CmsKitDbContextModelCreatingExtensions.cs @@ -28,7 +28,7 @@ public static class CmsKitDbContextModelCreatingExtensions { builder.Entity(b => { - b.ToTable(CmsKitDbProperties.DbTablePrefix + "Users", CmsKitDbProperties.DbSchema); + b.ToTable(AbpCmsKitDbProperties.DbTablePrefix + "Users", AbpCmsKitDbProperties.DbSchema); b.ConfigureByConvention(); b.ConfigureAbpUser(); @@ -48,7 +48,7 @@ public static class CmsKitDbContextModelCreatingExtensions { builder.Entity(b => { - b.ToTable(CmsKitDbProperties.DbTablePrefix + "UserReactions", CmsKitDbProperties.DbSchema); + b.ToTable(AbpCmsKitDbProperties.DbTablePrefix + "UserReactions", AbpCmsKitDbProperties.DbSchema); b.ConfigureByConvention(); @@ -71,7 +71,7 @@ public static class CmsKitDbContextModelCreatingExtensions { builder.Entity(b => { - b.ToTable(CmsKitDbProperties.DbTablePrefix + "Comments", CmsKitDbProperties.DbSchema); + b.ToTable(AbpCmsKitDbProperties.DbTablePrefix + "Comments", AbpCmsKitDbProperties.DbSchema); b.ConfigureByConvention(); @@ -95,7 +95,7 @@ public static class CmsKitDbContextModelCreatingExtensions { builder.Entity(r => { - r.ToTable(CmsKitDbProperties.DbTablePrefix + "Ratings", CmsKitDbProperties.DbSchema); + r.ToTable(AbpCmsKitDbProperties.DbTablePrefix + "Ratings", AbpCmsKitDbProperties.DbSchema); r.ConfigureByConvention(); @@ -117,7 +117,7 @@ public static class CmsKitDbContextModelCreatingExtensions { builder.Entity(b => { - b.ToTable(CmsKitDbProperties.DbTablePrefix + "Tags", CmsKitDbProperties.DbSchema); + b.ToTable(AbpCmsKitDbProperties.DbTablePrefix + "Tags", AbpCmsKitDbProperties.DbSchema); b.ConfigureByConvention(); @@ -134,7 +134,7 @@ public static class CmsKitDbContextModelCreatingExtensions builder.Entity(b => { - b.ToTable(CmsKitDbProperties.DbTablePrefix + "EntityTags", CmsKitDbProperties.DbSchema); + b.ToTable(AbpCmsKitDbProperties.DbTablePrefix + "EntityTags", AbpCmsKitDbProperties.DbSchema); b.ConfigureByConvention(); @@ -158,7 +158,7 @@ public static class CmsKitDbContextModelCreatingExtensions { builder.Entity(b => { - b.ToTable(CmsKitDbProperties.DbTablePrefix + "Pages", CmsKitDbProperties.DbSchema); + b.ToTable(AbpCmsKitDbProperties.DbTablePrefix + "Pages", AbpCmsKitDbProperties.DbSchema); b.ConfigureByConvention(); @@ -180,7 +180,7 @@ public static class CmsKitDbContextModelCreatingExtensions { builder.Entity(b => { - b.ToTable(CmsKitDbProperties.DbTablePrefix + "Blogs", CmsKitDbProperties.DbSchema); + b.ToTable(AbpCmsKitDbProperties.DbTablePrefix + "Blogs", AbpCmsKitDbProperties.DbSchema); b.ConfigureByConvention(); @@ -193,7 +193,7 @@ public static class CmsKitDbContextModelCreatingExtensions builder.Entity(b => { - b.ToTable(CmsKitDbProperties.DbTablePrefix + "BlogPosts", CmsKitDbProperties.DbSchema); + b.ToTable(AbpCmsKitDbProperties.DbTablePrefix + "BlogPosts", AbpCmsKitDbProperties.DbSchema); b.ConfigureByConvention(); @@ -210,7 +210,7 @@ public static class CmsKitDbContextModelCreatingExtensions builder.Entity(b => { - b.ToTable(CmsKitDbProperties.DbTablePrefix + "BlogFeatures", CmsKitDbProperties.DbSchema); + b.ToTable(AbpCmsKitDbProperties.DbTablePrefix + "BlogFeatures", AbpCmsKitDbProperties.DbSchema); b.ConfigureByConvention(); @@ -230,7 +230,7 @@ public static class CmsKitDbContextModelCreatingExtensions { builder.Entity(b => { - b.ToTable(CmsKitDbProperties.DbTablePrefix + "MediaDescriptors", CmsKitDbProperties.DbSchema); + b.ToTable(AbpCmsKitDbProperties.DbTablePrefix + "MediaDescriptors", AbpCmsKitDbProperties.DbSchema); b.ConfigureByConvention(); @@ -251,7 +251,7 @@ public static class CmsKitDbContextModelCreatingExtensions { builder.Entity(b => { - b.ToTable(CmsKitDbProperties.DbTablePrefix + "MenuItems", CmsKitDbProperties.DbSchema); + b.ToTable(AbpCmsKitDbProperties.DbTablePrefix + "MenuItems", AbpCmsKitDbProperties.DbSchema); b.ConfigureByConvention(); @@ -269,7 +269,7 @@ public static class CmsKitDbContextModelCreatingExtensions { builder.Entity(b => { - b.ToTable(CmsKitDbProperties.DbTablePrefix + "GlobalResources", CmsKitDbProperties.DbSchema); + b.ToTable(AbpCmsKitDbProperties.DbTablePrefix + "GlobalResources", AbpCmsKitDbProperties.DbSchema); b.ConfigureByConvention(); diff --git a/modules/cms-kit/src/Volo.CmsKit.EntityFrameworkCore/Volo/CmsKit/EntityFrameworkCore/ICmsKitDbContext.cs b/modules/cms-kit/src/Volo.CmsKit.EntityFrameworkCore/Volo/CmsKit/EntityFrameworkCore/ICmsKitDbContext.cs index fca31f2d73..8b6edc1cbe 100644 --- a/modules/cms-kit/src/Volo.CmsKit.EntityFrameworkCore/Volo/CmsKit/EntityFrameworkCore/ICmsKitDbContext.cs +++ b/modules/cms-kit/src/Volo.CmsKit.EntityFrameworkCore/Volo/CmsKit/EntityFrameworkCore/ICmsKitDbContext.cs @@ -14,7 +14,7 @@ using Volo.CmsKit.Users; namespace Volo.CmsKit.EntityFrameworkCore; -[ConnectionStringName(CmsKitDbProperties.ConnectionStringName)] +[ConnectionStringName(AbpCmsKitDbProperties.ConnectionStringName)] public interface ICmsKitDbContext : IEfCoreDbContext { DbSet Comments { get; } diff --git a/modules/cms-kit/src/Volo.CmsKit.EntityFrameworkCore/Volo/CmsKit/Tags/EfCoreEntityTagRepository.cs b/modules/cms-kit/src/Volo.CmsKit.EntityFrameworkCore/Volo/CmsKit/Tags/EfCoreEntityTagRepository.cs index c9e501edc0..8dfeacfc36 100644 --- a/modules/cms-kit/src/Volo.CmsKit.EntityFrameworkCore/Volo/CmsKit/Tags/EfCoreEntityTagRepository.cs +++ b/modules/cms-kit/src/Volo.CmsKit.EntityFrameworkCore/Volo/CmsKit/Tags/EfCoreEntityTagRepository.cs @@ -1,9 +1,9 @@ -using JetBrains.Annotations; -using System; +using System; using System.Collections.Generic; using System.Linq; using System.Threading; using System.Threading.Tasks; +using JetBrains.Annotations; using Microsoft.EntityFrameworkCore; using Volo.Abp; using Volo.Abp.Domain.Repositories.EntityFrameworkCore; @@ -19,11 +19,11 @@ public class EfCoreEntityTagRepository : EfCoreRepository(); - dbSet.RemoveRange(dbSet.Where(x => tagIds.Contains(x.TagId))); + dbSet.RemoveRange(dbSet.Where(x => tagIds.Contains(x.TagId) && x.EntityId == entityId)); await dbContext.SaveChangesAsync(GetCancellationToken(cancellationToken)); } @@ -56,18 +56,18 @@ public class EfCoreEntityTagRepository : EfCoreRepository> GetEntityIdsFilteredByTagNameAsync( [NotNull] string tagName, [NotNull] string entityType, - [CanBeNull] Guid? tenantId=null, - CancellationToken cancellationToken=default) + [CanBeNull] Guid? tenantId = null, + CancellationToken cancellationToken = default) { var dbContext = await GetDbContextAsync(); var result = from et in dbContext.Set() join t in dbContext.Set() on et.TagId equals t.Id - where t.Name == tagName - && t.EntityType == entityType - && et.TenantId == tenantId + where t.Name == tagName + && t.EntityType == entityType + && et.TenantId == tenantId && t.TenantId == tenantId && !t.IsDeleted - select et.EntityId; - return await result.ToListAsync(cancellationToken:GetCancellationToken(cancellationToken)); + select et.EntityId; + return await result.ToListAsync(cancellationToken: GetCancellationToken(cancellationToken)); } } \ No newline at end of file diff --git a/modules/cms-kit/src/Volo.CmsKit.MongoDB/Volo/CmsKit/MongoDB/CmsKitMongoDbContext.cs b/modules/cms-kit/src/Volo.CmsKit.MongoDB/Volo/CmsKit/MongoDB/CmsKitMongoDbContext.cs index 36c9cf882c..c6a97dfbef 100644 --- a/modules/cms-kit/src/Volo.CmsKit.MongoDB/Volo/CmsKit/MongoDB/CmsKitMongoDbContext.cs +++ b/modules/cms-kit/src/Volo.CmsKit.MongoDB/Volo/CmsKit/MongoDB/CmsKitMongoDbContext.cs @@ -15,7 +15,7 @@ using Tag = Volo.CmsKit.Tags.Tag; namespace Volo.CmsKit.MongoDB; -[ConnectionStringName(CmsKitDbProperties.ConnectionStringName)] +[ConnectionStringName(AbpCmsKitDbProperties.ConnectionStringName)] public class CmsKitMongoDbContext : AbpMongoDbContext, ICmsKitMongoDbContext { public IMongoCollection Comments => Collection(); diff --git a/modules/cms-kit/src/Volo.CmsKit.MongoDB/Volo/CmsKit/MongoDB/CmsKitMongoDbContextExtensions.cs b/modules/cms-kit/src/Volo.CmsKit.MongoDB/Volo/CmsKit/MongoDB/CmsKitMongoDbContextExtensions.cs index 7b7edcce0d..b6127ab125 100644 --- a/modules/cms-kit/src/Volo.CmsKit.MongoDB/Volo/CmsKit/MongoDB/CmsKitMongoDbContextExtensions.cs +++ b/modules/cms-kit/src/Volo.CmsKit.MongoDB/Volo/CmsKit/MongoDB/CmsKitMongoDbContextExtensions.cs @@ -22,67 +22,67 @@ public static class CmsKitMongoDbContextExtensions builder.Entity(x => { - x.CollectionName = CmsKitDbProperties.DbTablePrefix + "Users"; + x.CollectionName = AbpCmsKitDbProperties.DbTablePrefix + "Users"; }); builder.Entity(x => { - x.CollectionName = CmsKitDbProperties.DbTablePrefix + "UserReactions"; + x.CollectionName = AbpCmsKitDbProperties.DbTablePrefix + "UserReactions"; }); builder.Entity(x => { - x.CollectionName = CmsKitDbProperties.DbTablePrefix + "Comments"; + x.CollectionName = AbpCmsKitDbProperties.DbTablePrefix + "Comments"; }); builder.Entity(x => { - x.CollectionName = CmsKitDbProperties.DbTablePrefix + "Ratings"; + x.CollectionName = AbpCmsKitDbProperties.DbTablePrefix + "Ratings"; }); builder.Entity(x => { - x.CollectionName = CmsKitDbProperties.DbTablePrefix + "Tags"; + x.CollectionName = AbpCmsKitDbProperties.DbTablePrefix + "Tags"; }); builder.Entity(x => { - x.CollectionName = CmsKitDbProperties.DbTablePrefix + "EntityTags"; + x.CollectionName = AbpCmsKitDbProperties.DbTablePrefix + "EntityTags"; }); builder.Entity(x => { - x.CollectionName = CmsKitDbProperties.DbTablePrefix + "Pages"; + x.CollectionName = AbpCmsKitDbProperties.DbTablePrefix + "Pages"; }); builder.Entity(x => { - x.CollectionName = CmsKitDbProperties.DbTablePrefix + "Blogs"; + x.CollectionName = AbpCmsKitDbProperties.DbTablePrefix + "Blogs"; }); builder.Entity(x => { - x.CollectionName = CmsKitDbProperties.DbTablePrefix + "BlogPosts"; + x.CollectionName = AbpCmsKitDbProperties.DbTablePrefix + "BlogPosts"; }); builder.Entity(x => { - x.CollectionName = CmsKitDbProperties.DbTablePrefix + "BlogFeatures"; + x.CollectionName = AbpCmsKitDbProperties.DbTablePrefix + "BlogFeatures"; }); builder.Entity(x => { - x.CollectionName = CmsKitDbProperties.DbTablePrefix + "MediaDescriptors"; + x.CollectionName = AbpCmsKitDbProperties.DbTablePrefix + "MediaDescriptors"; }); builder.Entity(x => { - x.CollectionName = CmsKitDbProperties.DbTablePrefix + "MenuItems"; + x.CollectionName = AbpCmsKitDbProperties.DbTablePrefix + "MenuItems"; }); builder.Entity(x => { - x.CollectionName = CmsKitDbProperties.DbTablePrefix + "GlobalResources"; + x.CollectionName = AbpCmsKitDbProperties.DbTablePrefix + "GlobalResources"; }); } } diff --git a/modules/cms-kit/src/Volo.CmsKit.MongoDB/Volo/CmsKit/MongoDB/ICmsKitMongoDbContext.cs b/modules/cms-kit/src/Volo.CmsKit.MongoDB/Volo/CmsKit/MongoDB/ICmsKitMongoDbContext.cs index a2dff419e2..e220aff46e 100644 --- a/modules/cms-kit/src/Volo.CmsKit.MongoDB/Volo/CmsKit/MongoDB/ICmsKitMongoDbContext.cs +++ b/modules/cms-kit/src/Volo.CmsKit.MongoDB/Volo/CmsKit/MongoDB/ICmsKitMongoDbContext.cs @@ -15,7 +15,7 @@ using Tag = Volo.CmsKit.Tags.Tag; namespace Volo.CmsKit.MongoDB; -[ConnectionStringName(CmsKitDbProperties.ConnectionStringName)] +[ConnectionStringName(AbpCmsKitDbProperties.ConnectionStringName)] public interface ICmsKitMongoDbContext : IAbpMongoDbContext { IMongoCollection UserReactions { get; } diff --git a/modules/cms-kit/src/Volo.CmsKit.MongoDB/Volo/CmsKit/MongoDB/Tags/MongoEntityTagRepository.cs b/modules/cms-kit/src/Volo.CmsKit.MongoDB/Volo/CmsKit/MongoDB/Tags/MongoEntityTagRepository.cs index e3835bfe42..b270255900 100644 --- a/modules/cms-kit/src/Volo.CmsKit.MongoDB/Volo/CmsKit/MongoDB/Tags/MongoEntityTagRepository.cs +++ b/modules/cms-kit/src/Volo.CmsKit.MongoDB/Volo/CmsKit/MongoDB/Tags/MongoEntityTagRepository.cs @@ -1,15 +1,14 @@ -using JetBrains.Annotations; -using MongoDB.Driver; -using System; +using System; using System.Collections.Generic; using System.Linq; using System.Threading; using System.Threading.Tasks; +using JetBrains.Annotations; +using MongoDB.Driver; using Volo.Abp; using Volo.Abp.Domain.Repositories.MongoDB; using Volo.Abp.MongoDB; using Volo.CmsKit.Tags; -using Tag = Volo.CmsKit.Tags.Tag; namespace Volo.CmsKit.MongoDB.Tags; @@ -20,12 +19,19 @@ public class MongoEntityTagRepository : MongoDbRepository.Filter.In(x => x.TagId, tagIds), token); + + var builder = Builders.Filter; + var filter = builder.And( + builder.In(x => x.TagId, tagIds), + builder.Eq(x => x.EntityId, entityId) + ); + + await collection.DeleteManyAsync(filter, token); } public virtual Task FindAsync( @@ -57,7 +63,7 @@ public class MongoEntityTagRepository : MongoDbRepository> GetEntityIdsFilteredByTagNameAsync( [NotNull] string tagName, [NotNull] string entityType, - [CanBeNull] Guid? tenantId=null, + [CanBeNull] Guid? tenantId = null, CancellationToken cancellationToken = default) { var dbContext = await GetDbContextAsync(); @@ -76,7 +82,7 @@ public class MongoEntityTagRepository : MongoDbRepository s.entityTag.EntityId); - + return await AsyncExecuter.ToListAsync(resultQueryable, GetCancellationToken(cancellationToken)); } } diff --git a/modules/cms-kit/src/Volo.CmsKit.Public.Application.Contracts/Volo/CmsKit/Public/Blogs/IBlogPostPublicAppService.cs b/modules/cms-kit/src/Volo.CmsKit.Public.Application.Contracts/Volo/CmsKit/Public/Blogs/IBlogPostPublicAppService.cs index 42161f884c..a6462d937c 100644 --- a/modules/cms-kit/src/Volo.CmsKit.Public.Application.Contracts/Volo/CmsKit/Public/Blogs/IBlogPostPublicAppService.cs +++ b/modules/cms-kit/src/Volo.CmsKit.Public.Application.Contracts/Volo/CmsKit/Public/Blogs/IBlogPostPublicAppService.cs @@ -1,18 +1,18 @@ -using System.Collections.Generic; -using JetBrains.Annotations; +using System; using System.Threading.Tasks; +using JetBrains.Annotations; using Volo.Abp.Application.Dtos; using Volo.Abp.Application.Services; +using Volo.CmsKit.Contents; using Volo.CmsKit.Users; -using System; namespace Volo.CmsKit.Public.Blogs; public interface IBlogPostPublicAppService : IApplicationService { - Task> GetListAsync([NotNull] string blogSlug, BlogPostGetListInput input); + Task> GetListAsync([NotNull] string blogSlug, BlogPostGetListInput input); - Task GetAsync([NotNull] string blogSlug, [NotNull] string blogPostSlug); + Task GetAsync([NotNull] string blogSlug, [NotNull] string blogPostSlug); Task> GetAuthorsHasBlogPostsAsync(BlogPostFilteredPagedAndSortedResultRequestDto input); diff --git a/modules/cms-kit/src/Volo.CmsKit.Public.Application.Contracts/Volo/CmsKit/Public/Pages/IPagePublicAppService.cs b/modules/cms-kit/src/Volo.CmsKit.Public.Application.Contracts/Volo/CmsKit/Public/Pages/IPagePublicAppService.cs index 0b33a91236..230b8ded97 100644 --- a/modules/cms-kit/src/Volo.CmsKit.Public.Application.Contracts/Volo/CmsKit/Public/Pages/IPagePublicAppService.cs +++ b/modules/cms-kit/src/Volo.CmsKit.Public.Application.Contracts/Volo/CmsKit/Public/Pages/IPagePublicAppService.cs @@ -1,6 +1,7 @@ using JetBrains.Annotations; using System.Threading.Tasks; using Volo.Abp.Application.Services; +using Volo.CmsKit.Contents; namespace Volo.CmsKit.Public.Pages; diff --git a/modules/cms-kit/src/Volo.CmsKit.Public.Application/Volo/CmsKit/Public/Blogs/BlogPostPublicAppService.cs b/modules/cms-kit/src/Volo.CmsKit.Public.Application/Volo/CmsKit/Public/Blogs/BlogPostPublicAppService.cs index 5b16e41f4f..5041406bd0 100644 --- a/modules/cms-kit/src/Volo.CmsKit.Public.Application/Volo/CmsKit/Public/Blogs/BlogPostPublicAppService.cs +++ b/modules/cms-kit/src/Volo.CmsKit.Public.Application/Volo/CmsKit/Public/Blogs/BlogPostPublicAppService.cs @@ -3,13 +3,18 @@ using System.Collections.Generic; using System.Threading.Tasks; using JetBrains.Annotations; using Volo.Abp.Application.Dtos; +using Volo.Abp.Features; using Volo.Abp.GlobalFeatures; using Volo.CmsKit.Blogs; + +using Volo.CmsKit.Contents; +using Volo.CmsKit.Features; using Volo.CmsKit.GlobalFeatures; using Volo.CmsKit.Users; namespace Volo.CmsKit.Public.Blogs; +[RequiresFeature(CmsKitFeatures.BlogEnable)] [RequiresGlobalFeature(typeof(BlogsFeature))] public class BlogPostPublicAppService : CmsKitPublicAppServiceBase, IBlogPostPublicAppService { @@ -25,17 +30,17 @@ public class BlogPostPublicAppService : CmsKitPublicAppServiceBase, IBlogPostPub BlogPostRepository = blogPostRepository; } - public virtual async Task GetAsync( + public virtual async Task GetAsync( [NotNull] string blogSlug, [NotNull] string blogPostSlug) { var blog = await BlogRepository.GetBySlugAsync(blogSlug); var blogPost = await BlogPostRepository.GetBySlugAsync(blog.Id, blogPostSlug); - return ObjectMapper.Map(blogPost); + return ObjectMapper.Map(blogPost); } - public virtual async Task> GetListAsync([NotNull] string blogSlug, BlogPostGetListInput input) + public virtual async Task> GetListAsync([NotNull] string blogSlug, BlogPostGetListInput input) { var blog = await BlogRepository.GetBySlugAsync(blogSlug); @@ -43,10 +48,10 @@ public class BlogPostPublicAppService : CmsKitPublicAppServiceBase, IBlogPostPub BlogPostStatus.Published, input.MaxResultCount, input.SkipCount, input.Sorting); - return new PagedResultDto( + return new PagedResultDto( await BlogPostRepository.GetCountAsync(blogId: blog.Id, tagId: input.TagId, statusFilter: BlogPostStatus.Published, authorId: input.AuthorId), - ObjectMapper.Map, List>(blogPosts)); + ObjectMapper.Map, List>(blogPosts)); } public virtual async Task> GetAuthorsHasBlogPostsAsync(BlogPostFilteredPagedAndSortedResultRequestDto input) diff --git a/modules/cms-kit/src/Volo.CmsKit.Public.Application/Volo/CmsKit/Public/Comments/CommentPublicAppService.cs b/modules/cms-kit/src/Volo.CmsKit.Public.Application/Volo/CmsKit/Public/Comments/CommentPublicAppService.cs index b1fae564d2..ef7e6be9fd 100644 --- a/modules/cms-kit/src/Volo.CmsKit.Public.Application/Volo/CmsKit/Public/Comments/CommentPublicAppService.cs +++ b/modules/cms-kit/src/Volo.CmsKit.Public.Application/Volo/CmsKit/Public/Comments/CommentPublicAppService.cs @@ -1,20 +1,23 @@ -using Microsoft.AspNetCore.Authorization; -using System; +using System; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; +using Microsoft.AspNetCore.Authorization; using Volo.Abp.Application.Dtos; using Volo.Abp.Authorization; using Volo.Abp.Data; using Volo.Abp.EventBus.Distributed; +using Volo.Abp.Features; using Volo.Abp.GlobalFeatures; using Volo.Abp.Users; using Volo.CmsKit.Comments; +using Volo.CmsKit.Features; using Volo.CmsKit.GlobalFeatures; using Volo.CmsKit.Users; namespace Volo.CmsKit.Public.Comments; +[RequiresFeature(CmsKitFeatures.CommentEnable)] [RequiresGlobalFeature(typeof(CommentsFeature))] public class CommentPublicAppService : CmsKitPublicAppServiceBase, ICommentPublicAppService { diff --git a/modules/cms-kit/src/Volo.CmsKit.Public.Application/Volo/CmsKit/Public/GlobalResources/GlobalResourcePublicAppService.cs b/modules/cms-kit/src/Volo.CmsKit.Public.Application/Volo/CmsKit/Public/GlobalResources/GlobalResourcePublicAppService.cs index 2debf10ed5..af0d1fbf39 100644 --- a/modules/cms-kit/src/Volo.CmsKit.Public.Application/Volo/CmsKit/Public/GlobalResources/GlobalResourcePublicAppService.cs +++ b/modules/cms-kit/src/Volo.CmsKit.Public.Application/Volo/CmsKit/Public/GlobalResources/GlobalResourcePublicAppService.cs @@ -1,11 +1,14 @@ using System.Threading.Tasks; using Volo.Abp.Application.Services; +using Volo.Abp.Features; using Volo.Abp.GlobalFeatures; +using Volo.CmsKit.Features; using Volo.CmsKit.GlobalFeatures; using Volo.CmsKit.GlobalResources; namespace Volo.CmsKit.Public.GlobalResources; +[RequiresFeature(CmsKitFeatures.GlobalResourceEnable)] [RequiresGlobalFeature(typeof(GlobalResourcesFeature))] public class GlobalResourcePublicAppService : ApplicationService, IGlobalResourcePublicAppService { @@ -15,18 +18,18 @@ public class GlobalResourcePublicAppService : ApplicationService, IGlobalResourc { GlobalResourceManager = globalResourceManager; } - + public async Task GetGlobalScriptAsync() { var globalScript = await GlobalResourceManager.GetGlobalScriptAsync(); - + return ObjectMapper.Map(globalScript); } - + public async Task GetGlobalStyleAsync() { var globalStyle = await GlobalResourceManager.GetGlobalStyleAsync(); - + return ObjectMapper.Map(globalStyle); } } \ No newline at end of file diff --git a/modules/cms-kit/src/Volo.CmsKit.Public.Application/Volo/CmsKit/Public/Menus/MenuItemPublicAppService.cs b/modules/cms-kit/src/Volo.CmsKit.Public.Application/Volo/CmsKit/Public/Menus/MenuItemPublicAppService.cs index 11a58d5935..0e9062d9af 100644 --- a/modules/cms-kit/src/Volo.CmsKit.Public.Application/Volo/CmsKit/Public/Menus/MenuItemPublicAppService.cs +++ b/modules/cms-kit/src/Volo.CmsKit.Public.Application/Volo/CmsKit/Public/Menus/MenuItemPublicAppService.cs @@ -1,12 +1,15 @@ using System.Collections.Generic; using System.Threading.Tasks; using Volo.Abp.Caching; +using Volo.Abp.Features; using Volo.Abp.GlobalFeatures; +using Volo.CmsKit.Features; using Volo.CmsKit.GlobalFeatures; using Volo.CmsKit.Menus; namespace Volo.CmsKit.Public.Menus; +[RequiresFeature(CmsKitFeatures.MenuEnable)] [RequiresGlobalFeature(typeof(MenuFeature))] public class MenuItemPublicAppService : CmsKitPublicAppServiceBase, IMenuItemPublicAppService { diff --git a/modules/cms-kit/src/Volo.CmsKit.Public.Application/Volo/CmsKit/Public/Pages/PagePublicAppService.cs b/modules/cms-kit/src/Volo.CmsKit.Public.Application/Volo/CmsKit/Public/Pages/PagePublicAppService.cs index 258ef935ed..c93adcd5a7 100644 --- a/modules/cms-kit/src/Volo.CmsKit.Public.Application/Volo/CmsKit/Public/Pages/PagePublicAppService.cs +++ b/modules/cms-kit/src/Volo.CmsKit.Public.Application/Volo/CmsKit/Public/Pages/PagePublicAppService.cs @@ -1,10 +1,14 @@ using System.Threading.Tasks; +using Volo.Abp.Features; using Volo.Abp.GlobalFeatures; +using Volo.CmsKit.Contents; +using Volo.CmsKit.Features; using Volo.CmsKit.GlobalFeatures; using Volo.CmsKit.Pages; namespace Volo.CmsKit.Public.Pages; +[RequiresFeature(CmsKitFeatures.PageEnable)] [RequiresGlobalFeature(typeof(PagesFeature))] public class PagePublicAppService : CmsKitPublicAppServiceBase, IPagePublicAppService { diff --git a/modules/cms-kit/src/Volo.CmsKit.Public.Application/Volo/CmsKit/Public/PublicApplicationAutoMapperProfile.cs b/modules/cms-kit/src/Volo.CmsKit.Public.Application/Volo/CmsKit/Public/PublicApplicationAutoMapperProfile.cs index d5a1b58445..92620743ff 100644 --- a/modules/cms-kit/src/Volo.CmsKit.Public.Application/Volo/CmsKit/Public/PublicApplicationAutoMapperProfile.cs +++ b/modules/cms-kit/src/Volo.CmsKit.Public.Application/Volo/CmsKit/Public/PublicApplicationAutoMapperProfile.cs @@ -2,13 +2,13 @@ using Volo.Abp.AutoMapper; using Volo.CmsKit.Blogs; using Volo.CmsKit.Comments; +using Volo.CmsKit.Contents; using Volo.CmsKit.GlobalResources; using Volo.CmsKit.Menus; using Volo.CmsKit.Pages; using Volo.CmsKit.Public.Blogs; using Volo.CmsKit.Public.Comments; using Volo.CmsKit.Public.GlobalResources; -using Volo.CmsKit.Public.Pages; using Volo.CmsKit.Public.Ratings; using Volo.CmsKit.Ratings; using Volo.CmsKit.Users; @@ -31,8 +31,8 @@ public class PublicApplicationAutoMapperProfile : Profile CreateMap(); CreateMap(); - - CreateMap(); + + CreateMap(); CreateMap(); 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 87ea0531db..f3b46c518b 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 @@ -1,15 +1,18 @@ -using Microsoft.AspNetCore.Authorization; -using System.Collections.Generic; +using System.Collections.Generic; using System.Threading.Tasks; +using Microsoft.AspNetCore.Authorization; using Volo.Abp.Authorization; +using Volo.Abp.Features; using Volo.Abp.GlobalFeatures; using Volo.Abp.Users; +using Volo.CmsKit.Features; using Volo.CmsKit.GlobalFeatures; using Volo.CmsKit.Ratings; using Volo.CmsKit.Users; namespace Volo.CmsKit.Public.Ratings; +[RequiresFeature(CmsKitFeatures.RatingEnable)] [RequiresGlobalFeature(typeof(RatingsFeature))] public class RatingPublicAppService : CmsKitPublicAppServiceBase, IRatingPublicAppService { diff --git a/modules/cms-kit/src/Volo.CmsKit.Public.Application/Volo/CmsKit/Public/Reactions/ReactionPublicAppService.cs b/modules/cms-kit/src/Volo.CmsKit.Public.Application/Volo/CmsKit/Public/Reactions/ReactionPublicAppService.cs index b12f659d23..1151578d57 100644 --- a/modules/cms-kit/src/Volo.CmsKit.Public.Application/Volo/CmsKit/Public/Reactions/ReactionPublicAppService.cs +++ b/modules/cms-kit/src/Volo.CmsKit.Public.Application/Volo/CmsKit/Public/Reactions/ReactionPublicAppService.cs @@ -1,17 +1,19 @@ -using Microsoft.AspNetCore.Authorization; -using System.Collections.Generic; +using System.Collections.Generic; using System.Linq; using System.Linq.Dynamic.Core; -using System.Security.Cryptography.X509Certificates; using System.Threading.Tasks; +using Microsoft.AspNetCore.Authorization; using Volo.Abp.Application.Dtos; +using Volo.Abp.Features; using Volo.Abp.GlobalFeatures; using Volo.Abp.Users; +using Volo.CmsKit.Features; using Volo.CmsKit.GlobalFeatures; using Volo.CmsKit.Reactions; namespace Volo.CmsKit.Public.Reactions; +[RequiresFeature(CmsKitFeatures.ReactionEnable)] [RequiresGlobalFeature(typeof(ReactionsFeature))] public class ReactionPublicAppService : CmsKitPublicAppServiceBase, IReactionPublicAppService { diff --git a/modules/cms-kit/src/Volo.CmsKit.Public.HttpApi.Client/ClientProxies/BlogPostPublicClientProxy.Generated.cs b/modules/cms-kit/src/Volo.CmsKit.Public.HttpApi.Client/ClientProxies/BlogPostPublicClientProxy.Generated.cs index b1bbf6be07..f26816e88d 100644 --- a/modules/cms-kit/src/Volo.CmsKit.Public.HttpApi.Client/ClientProxies/BlogPostPublicClientProxy.Generated.cs +++ b/modules/cms-kit/src/Volo.CmsKit.Public.HttpApi.Client/ClientProxies/BlogPostPublicClientProxy.Generated.cs @@ -2,11 +2,9 @@ using System; using System.Threading.Tasks; using Volo.Abp.Application.Dtos; -using Volo.Abp.Http.Client; -using Volo.Abp.Http.Modeling; using Volo.Abp.DependencyInjection; using Volo.Abp.Http.Client.ClientProxying; -using Volo.CmsKit.Public.Blogs; +using Volo.CmsKit.Contents; using Volo.CmsKit.Users; // ReSharper disable once CheckNamespace @@ -16,18 +14,18 @@ namespace Volo.CmsKit.Public.Blogs.ClientProxies; [ExposeServices(typeof(IBlogPostPublicAppService), typeof(BlogPostPublicClientProxy))] public partial class BlogPostPublicClientProxy : ClientProxyBase, IBlogPostPublicAppService { - public virtual async Task GetAsync(string blogSlug, string blogPostSlug) + public virtual async Task GetAsync(string blogSlug, string blogPostSlug) { - return await RequestAsync(nameof(GetAsync), new ClientProxyRequestTypeValue + return await RequestAsync(nameof(GetAsync), new ClientProxyRequestTypeValue { { typeof(string), blogSlug }, { typeof(string), blogPostSlug } }); } - public virtual async Task> GetListAsync(string blogSlug, BlogPostGetListInput input) + public virtual async Task> GetListAsync(string blogSlug, BlogPostGetListInput input) { - return await RequestAsync>(nameof(GetListAsync), new ClientProxyRequestTypeValue + return await RequestAsync>(nameof(GetListAsync), new ClientProxyRequestTypeValue { { typeof(string), blogSlug }, { typeof(BlogPostGetListInput), input } diff --git a/modules/cms-kit/src/Volo.CmsKit.Public.HttpApi.Client/ClientProxies/PagesPublicClientProxy.Generated.cs b/modules/cms-kit/src/Volo.CmsKit.Public.HttpApi.Client/ClientProxies/PagesPublicClientProxy.Generated.cs index 9ecf6cb387..f992bb3dbf 100644 --- a/modules/cms-kit/src/Volo.CmsKit.Public.HttpApi.Client/ClientProxies/PagesPublicClientProxy.Generated.cs +++ b/modules/cms-kit/src/Volo.CmsKit.Public.HttpApi.Client/ClientProxies/PagesPublicClientProxy.Generated.cs @@ -1,12 +1,8 @@ // This file is automatically generated by ABP framework to use MVC Controllers from CSharp -using System; using System.Threading.Tasks; -using Volo.Abp.Application.Dtos; -using Volo.Abp.Http.Client; -using Volo.Abp.Http.Modeling; using Volo.Abp.DependencyInjection; using Volo.Abp.Http.Client.ClientProxying; -using Volo.CmsKit.Public.Pages; +using Volo.CmsKit.Contents; // ReSharper disable once CheckNamespace namespace Volo.CmsKit.Public.Pages.ClientProxies; diff --git a/modules/cms-kit/src/Volo.CmsKit.Public.HttpApi.Client/ClientProxies/cms-kit-generate-proxy.json b/modules/cms-kit/src/Volo.CmsKit.Public.HttpApi.Client/ClientProxies/cms-kit-generate-proxy.json index 626dce7ff2..e3b3802ee9 100644 --- a/modules/cms-kit/src/Volo.CmsKit.Public.HttpApi.Client/ClientProxies/cms-kit-generate-proxy.json +++ b/modules/cms-kit/src/Volo.CmsKit.Public.HttpApi.Client/ClientProxies/cms-kit-generate-proxy.json @@ -505,57 +505,6 @@ } } }, - "Volo.CmsKit.Public.Polls.PollViewComponentController": { - "controllerName": "PollViewComponent", - "controllerGroupName": "PollViewComponent", - "isRemoteService": true, - "apiVersion": null, - "type": "Volo.CmsKit.Public.Polls.PollViewComponentController", - "interfaces": [ - { - "type": "Volo.CmsKit.Public.Polls.IPollViewComponentAppService" - } - ], - "actions": { - "ParseAsyncByContent": { - "uniqueName": "ParseAsyncByContent", - "name": "ParseAsync", - "httpMethod": "GET", - "url": "api/cms-kit-public/polls/{content}", - "supportedVersions": [], - "parametersOnMethod": [ - { - "name": "content", - "typeAsString": "System.String, System.Private.CoreLib", - "type": "System.String", - "typeSimple": "string", - "isOptional": false, - "defaultValue": null - } - ], - "parameters": [ - { - "nameOnMethod": "content", - "name": "content", - "jsonName": null, - "type": "System.String", - "typeSimple": "string", - "isOptional": false, - "defaultValue": null, - "constraintTypes": [], - "bindingSourceId": "Path", - "descriptorName": "" - } - ], - "returnValue": { - "type": "System.Collections.Generic.List", - "typeSimple": "[Volo.CmsKit.Polls.ContentFragment]" - }, - "allowAnonymous": null, - "implementFrom": "Volo.CmsKit.Public.Polls.IPollViewComponentAppService" - } - } - }, "Volo.CmsKit.Public.Pages.PagesPublicController": { "controllerName": "PagesPublic", "controllerGroupName": "PagesPublic", @@ -599,8 +548,8 @@ } ], "returnValue": { - "type": "Volo.CmsKit.Public.Pages.PageDto", - "typeSimple": "Volo.CmsKit.Public.Pages.PageDto" + "type": "Volo.CmsKit.Contents.PageDto", + "typeSimple": "Volo.CmsKit.Contents.PageDto" }, "allowAnonymous": null, "implementFrom": "Volo.CmsKit.Public.Pages.IPagePublicAppService" @@ -985,8 +934,8 @@ } ], "returnValue": { - "type": "Volo.CmsKit.Public.Blogs.BlogPostPublicDto", - "typeSimple": "Volo.CmsKit.Public.Blogs.BlogPostPublicDto" + "type": "Volo.CmsKit.Contents.BlogPostCommonDto", + "typeSimple": "Volo.CmsKit.Contents.BlogPostCommonDto" }, "allowAnonymous": null, "implementFrom": "Volo.CmsKit.Public.Blogs.IBlogPostPublicAppService" @@ -1090,8 +1039,8 @@ } ], "returnValue": { - "type": "Volo.Abp.Application.Dtos.PagedResultDto", - "typeSimple": "Volo.Abp.Application.Dtos.PagedResultDto" + "type": "Volo.Abp.Application.Dtos.PagedResultDto", + "typeSimple": "Volo.Abp.Application.Dtos.PagedResultDto" }, "allowAnonymous": null, "implementFrom": "Volo.CmsKit.Public.Blogs.IBlogPostPublicAppService" diff --git a/modules/cms-kit/src/Volo.CmsKit.Public.HttpApi/Volo/CmsKit/Public/Blogs/BlogPostPublicController.cs b/modules/cms-kit/src/Volo.CmsKit.Public.HttpApi/Volo/CmsKit/Public/Blogs/BlogPostPublicController.cs index 9f43d65766..e5d2570e21 100644 --- a/modules/cms-kit/src/Volo.CmsKit.Public.HttpApi/Volo/CmsKit/Public/Blogs/BlogPostPublicController.cs +++ b/modules/cms-kit/src/Volo.CmsKit.Public.HttpApi/Volo/CmsKit/Public/Blogs/BlogPostPublicController.cs @@ -1,16 +1,18 @@ -using Microsoft.AspNetCore.Mvc; -using System; -using System.Collections.Generic; +using System; using System.Threading.Tasks; +using Microsoft.AspNetCore.Mvc; using Volo.Abp; using Volo.Abp.Application.Dtos; -using Volo.Abp.Content; +using Volo.Abp.Features; using Volo.Abp.GlobalFeatures; +using Volo.CmsKit.Contents; +using Volo.CmsKit.Features; using Volo.CmsKit.GlobalFeatures; using Volo.CmsKit.Users; namespace Volo.CmsKit.Public.Blogs; +[RequiresFeature(CmsKitFeatures.BlogEnable)] [RequiresGlobalFeature(typeof(BlogsFeature))] [RemoteService(Name = CmsKitPublicRemoteServiceConsts.RemoteServiceName)] [Area(CmsKitPublicRemoteServiceConsts.ModuleName)] @@ -26,14 +28,14 @@ public class BlogPostPublicController : CmsKitPublicControllerBase, IBlogPostPub [HttpGet] [Route("{blogSlug}/{blogPostSlug}")] - public virtual Task GetAsync(string blogSlug, string blogPostSlug) + public virtual Task GetAsync(string blogSlug, string blogPostSlug) { return BlogPostPublicAppService.GetAsync(blogSlug, blogPostSlug); } [HttpGet] [Route("{blogSlug}")] - public virtual Task> GetListAsync(string blogSlug, BlogPostGetListInput input) + public virtual Task> GetListAsync(string blogSlug, BlogPostGetListInput input) { return BlogPostPublicAppService.GetListAsync(blogSlug, input); } diff --git a/modules/cms-kit/src/Volo.CmsKit.Public.HttpApi/Volo/CmsKit/Public/Comments/CommentPublicController.cs b/modules/cms-kit/src/Volo.CmsKit.Public.HttpApi/Volo/CmsKit/Public/Comments/CommentPublicController.cs index afbf11e843..f77444431e 100644 --- a/modules/cms-kit/src/Volo.CmsKit.Public.HttpApi/Volo/CmsKit/Public/Comments/CommentPublicController.cs +++ b/modules/cms-kit/src/Volo.CmsKit.Public.HttpApi/Volo/CmsKit/Public/Comments/CommentPublicController.cs @@ -3,11 +3,14 @@ using System.Threading.Tasks; using Microsoft.AspNetCore.Mvc; using Volo.Abp; using Volo.Abp.Application.Dtos; +using Volo.Abp.Features; using Volo.Abp.GlobalFeatures; +using Volo.CmsKit.Features; using Volo.CmsKit.GlobalFeatures; namespace Volo.CmsKit.Public.Comments; +[RequiresFeature(CmsKitFeatures.CommentEnable)] [RequiresGlobalFeature(typeof(CommentsFeature))] [RemoteService(Name = CmsKitPublicRemoteServiceConsts.RemoteServiceName)] [Area(CmsKitPublicRemoteServiceConsts.ModuleName)] diff --git a/modules/cms-kit/src/Volo.CmsKit.Public.HttpApi/Volo/CmsKit/Public/GlobalResources/GlobalResourcePublicController.cs b/modules/cms-kit/src/Volo.CmsKit.Public.HttpApi/Volo/CmsKit/Public/GlobalResources/GlobalResourcePublicController.cs index 8b58a00f9a..635e228e0b 100644 --- a/modules/cms-kit/src/Volo.CmsKit.Public.HttpApi/Volo/CmsKit/Public/GlobalResources/GlobalResourcePublicController.cs +++ b/modules/cms-kit/src/Volo.CmsKit.Public.HttpApi/Volo/CmsKit/Public/GlobalResources/GlobalResourcePublicController.cs @@ -1,16 +1,19 @@ using System.Threading.Tasks; using Microsoft.AspNetCore.Mvc; using Volo.Abp; +using Volo.Abp.Features; using Volo.Abp.GlobalFeatures; +using Volo.CmsKit.Features; using Volo.CmsKit.GlobalFeatures; namespace Volo.CmsKit.Public.GlobalResources; +[RequiresFeature(CmsKitFeatures.GlobalResourceEnable)] [RequiresGlobalFeature(typeof(GlobalResourcesFeature))] [RemoteService(Name = CmsKitPublicRemoteServiceConsts.RemoteServiceName)] [Area(CmsKitPublicRemoteServiceConsts.ModuleName)] [Route("api/cms-kit-public/global-resources")] -public class GlobalResourcePublicController: CmsKitPublicControllerBase, IGlobalResourcePublicAppService +public class GlobalResourcePublicController : CmsKitPublicControllerBase, IGlobalResourcePublicAppService { private readonly IGlobalResourcePublicAppService _globalResourcePublicAppService; @@ -18,14 +21,14 @@ public class GlobalResourcePublicController: CmsKitPublicControllerBase, IGlobal { _globalResourcePublicAppService = globalResourcePublicAppService; } - + [HttpGet] [Route("script")] public Task GetGlobalScriptAsync() { return _globalResourcePublicAppService.GetGlobalScriptAsync(); } - + [HttpGet] [Route("style")] public Task GetGlobalStyleAsync() diff --git a/modules/cms-kit/src/Volo.CmsKit.Public.HttpApi/Volo/CmsKit/Public/Menus/MenuItemPublicController.cs b/modules/cms-kit/src/Volo.CmsKit.Public.HttpApi/Volo/CmsKit/Public/Menus/MenuItemPublicController.cs index fc8820c1b2..3eb00439fb 100644 --- a/modules/cms-kit/src/Volo.CmsKit.Public.HttpApi/Volo/CmsKit/Public/Menus/MenuItemPublicController.cs +++ b/modules/cms-kit/src/Volo.CmsKit.Public.HttpApi/Volo/CmsKit/Public/Menus/MenuItemPublicController.cs @@ -2,13 +2,16 @@ using System.Collections.Generic; using System.Threading.Tasks; using Microsoft.AspNetCore.Mvc; using Volo.Abp; +using Volo.Abp.Features; using Volo.Abp.GlobalFeatures; +using Volo.CmsKit.Features; using Volo.CmsKit.GlobalFeatures; using Volo.CmsKit.Menus; namespace Volo.CmsKit.Public.Menus; -[RequiresGlobalFeature(typeof(BlogsFeature))] +[RequiresFeature(CmsKitFeatures.MenuEnable)] +[RequiresGlobalFeature(typeof(MenuFeature))] [RemoteService(Name = CmsKitPublicRemoteServiceConsts.RemoteServiceName)] [Area(CmsKitPublicRemoteServiceConsts.ModuleName)] [Route("api/cms-kit-public/menu-items")] diff --git a/modules/cms-kit/src/Volo.CmsKit.Public.HttpApi/Volo/CmsKit/Public/Pages/PagesPublicController.cs b/modules/cms-kit/src/Volo.CmsKit.Public.HttpApi/Volo/CmsKit/Public/Pages/PagesPublicController.cs index 763fe7522d..22f2bd75bd 100644 --- a/modules/cms-kit/src/Volo.CmsKit.Public.HttpApi/Volo/CmsKit/Public/Pages/PagesPublicController.cs +++ b/modules/cms-kit/src/Volo.CmsKit.Public.HttpApi/Volo/CmsKit/Public/Pages/PagesPublicController.cs @@ -1,11 +1,15 @@ using System.Threading.Tasks; using Microsoft.AspNetCore.Mvc; using Volo.Abp; +using Volo.Abp.Features; using Volo.Abp.GlobalFeatures; +using Volo.CmsKit.Contents; +using Volo.CmsKit.Features; using Volo.CmsKit.GlobalFeatures; namespace Volo.CmsKit.Public.Pages; +[RequiresFeature(CmsKitFeatures.PageEnable)] [RequiresGlobalFeature(typeof(PagesFeature))] [RemoteService(Name = CmsKitPublicRemoteServiceConsts.RemoteServiceName)] [Area(CmsKitPublicRemoteServiceConsts.ModuleName)] diff --git a/modules/cms-kit/src/Volo.CmsKit.Public.HttpApi/Volo/CmsKit/Public/Ratings/RatingPublicController.cs b/modules/cms-kit/src/Volo.CmsKit.Public.HttpApi/Volo/CmsKit/Public/Ratings/RatingPublicController.cs index 11e8d22a69..f793aaefc4 100644 --- a/modules/cms-kit/src/Volo.CmsKit.Public.HttpApi/Volo/CmsKit/Public/Ratings/RatingPublicController.cs +++ b/modules/cms-kit/src/Volo.CmsKit.Public.HttpApi/Volo/CmsKit/Public/Ratings/RatingPublicController.cs @@ -2,11 +2,14 @@ using System.Threading.Tasks; using Microsoft.AspNetCore.Mvc; using Volo.Abp; +using Volo.Abp.Features; using Volo.Abp.GlobalFeatures; +using Volo.CmsKit.Features; using Volo.CmsKit.GlobalFeatures; namespace Volo.CmsKit.Public.Ratings; +[RequiresFeature(CmsKitFeatures.RatingEnable)] [RequiresGlobalFeature(typeof(RatingsFeature))] [RemoteService(Name = CmsKitPublicRemoteServiceConsts.RemoteServiceName)] [Area(CmsKitPublicRemoteServiceConsts.ModuleName)] diff --git a/modules/cms-kit/src/Volo.CmsKit.Public.HttpApi/Volo/CmsKit/Public/Reactions/ReactionPublicController.cs b/modules/cms-kit/src/Volo.CmsKit.Public.HttpApi/Volo/CmsKit/Public/Reactions/ReactionPublicController.cs index 4a9df74df7..6242e253a2 100644 --- a/modules/cms-kit/src/Volo.CmsKit.Public.HttpApi/Volo/CmsKit/Public/Reactions/ReactionPublicController.cs +++ b/modules/cms-kit/src/Volo.CmsKit.Public.HttpApi/Volo/CmsKit/Public/Reactions/ReactionPublicController.cs @@ -2,11 +2,14 @@ using Microsoft.AspNetCore.Mvc; using Volo.Abp; using Volo.Abp.Application.Dtos; +using Volo.Abp.Features; using Volo.Abp.GlobalFeatures; +using Volo.CmsKit.Features; using Volo.CmsKit.GlobalFeatures; namespace Volo.CmsKit.Public.Reactions; +[RequiresFeature(CmsKitFeatures.ReactionEnable)] [RequiresGlobalFeature(typeof(ReactionsFeature))] [RemoteService(Name = CmsKitPublicRemoteServiceConsts.RemoteServiceName)] [Area(CmsKitPublicRemoteServiceConsts.ModuleName)] diff --git a/modules/cms-kit/src/Volo.CmsKit.Public.HttpApi/Volo/CmsKit/Public/Tags/TagPublicController.cs b/modules/cms-kit/src/Volo.CmsKit.Public.HttpApi/Volo/CmsKit/Public/Tags/TagPublicController.cs index ec45901118..1620f136da 100644 --- a/modules/cms-kit/src/Volo.CmsKit.Public.HttpApi/Volo/CmsKit/Public/Tags/TagPublicController.cs +++ b/modules/cms-kit/src/Volo.CmsKit.Public.HttpApi/Volo/CmsKit/Public/Tags/TagPublicController.cs @@ -1,13 +1,16 @@ -using Microsoft.AspNetCore.Mvc; -using System.Collections.Generic; +using System.Collections.Generic; using System.Threading.Tasks; +using Microsoft.AspNetCore.Mvc; using Volo.Abp; +using Volo.Abp.Features; using Volo.Abp.GlobalFeatures; +using Volo.CmsKit.Features; using Volo.CmsKit.GlobalFeatures; using Volo.CmsKit.Tags; namespace Volo.CmsKit.Public.Tags; +[RequiresFeature(CmsKitFeatures.TagEnable)] [RequiresGlobalFeature(typeof(TagsFeature))] [RemoteService(Name = CmsKitPublicRemoteServiceConsts.RemoteServiceName)] [Area(CmsKitPublicRemoteServiceConsts.ModuleName)] diff --git a/modules/cms-kit/src/Volo.CmsKit.Public.Web/CmsKitPublicWebModule.cs b/modules/cms-kit/src/Volo.CmsKit.Public.Web/CmsKitPublicWebModule.cs index 88b01c8ae9..3ce96f1a86 100644 --- a/modules/cms-kit/src/Volo.CmsKit.Public.Web/CmsKitPublicWebModule.cs +++ b/modules/cms-kit/src/Volo.CmsKit.Public.Web/CmsKitPublicWebModule.cs @@ -2,7 +2,7 @@ using Microsoft.AspNetCore.Mvc.RazorPages; using Microsoft.Extensions.DependencyInjection; using Volo.Abp.AspNetCore.Mvc.Localization; -using Volo.Abp.AspNetCore.Mvc.UI.Components.LayoutHook; +using Volo.Abp.Ui.LayoutHooks; using Volo.Abp.AutoMapper; using Volo.Abp.GlobalFeatures; using Volo.Abp.Http.ProxyScripting.Generators.JQuery; diff --git a/modules/cms-kit/src/Volo.CmsKit.Public.Web/Pages/CmsKit/Shared/Components/Commenting/CommentingViewComponent.cs b/modules/cms-kit/src/Volo.CmsKit.Public.Web/Pages/CmsKit/Shared/Components/Commenting/CommentingViewComponent.cs index 8c307e390e..81fd94406d 100644 --- a/modules/cms-kit/src/Volo.CmsKit.Public.Web/Pages/CmsKit/Shared/Components/Commenting/CommentingViewComponent.cs +++ b/modules/cms-kit/src/Volo.CmsKit.Public.Web/Pages/CmsKit/Shared/Components/Commenting/CommentingViewComponent.cs @@ -8,7 +8,7 @@ using Volo.Abp.AspNetCore.Mvc; using Volo.Abp.AspNetCore.Mvc.UI; using Volo.Abp.AspNetCore.Mvc.UI.Widgets; using Volo.CmsKit.Public.Comments; -using Volo.CmsKit.Public.Web.Renderers; +using Volo.CmsKit.Web.Renderers; namespace Volo.CmsKit.Public.Web.Pages.CmsKit.Shared.Components.Commenting; 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 88d7398fcf..d5dc5a0be8 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 @@ -9,7 +9,7 @@ @using Volo.CmsKit.Public.Web.Pages.CmsKit.Shared.Components.ReactionSelection @using Volo.CmsKit.Public.Web.Pages.CmsKit.Shared.Components.Rating @using Volo.CmsKit.Public.Web.Pages.CmsKit.Shared.Components.Tags -@using Volo.CmsKit.Public.Web.Renderers +@using Volo.CmsKit.Web.Renderers @using Volo.Abp.AspNetCore.Mvc.UI.Packages.HighlightJs @using Volo.CmsKit.Contents diff --git a/modules/cms-kit/src/Volo.CmsKit.Public.Web/Pages/Public/CmsKit/Blogs/BlogPost.cshtml.cs b/modules/cms-kit/src/Volo.CmsKit.Public.Web/Pages/Public/CmsKit/Blogs/BlogPost.cshtml.cs index 268528c4bc..87630f9bd0 100644 --- a/modules/cms-kit/src/Volo.CmsKit.Public.Web/Pages/Public/CmsKit/Blogs/BlogPost.cshtml.cs +++ b/modules/cms-kit/src/Volo.CmsKit.Public.Web/Pages/Public/CmsKit/Blogs/BlogPost.cshtml.cs @@ -3,6 +3,7 @@ using Microsoft.AspNetCore.Mvc; using Volo.Abp.GlobalFeatures; using Volo.Abp.ObjectMapping; using Volo.CmsKit.Blogs; +using Volo.CmsKit.Contents; using Volo.CmsKit.GlobalFeatures; using Volo.CmsKit.Public.Blogs; using Volo.CmsKit.Web.Contents; @@ -48,7 +49,7 @@ public class BlogPostModel : CmsKitPublicPageModelBase public virtual async Task OnGetAsync() { var blogPostPublicDto = await BlogPostPublicAppService.GetAsync(BlogSlug, BlogPostSlug); - ViewModel = ObjectMapper.Map(blogPostPublicDto); + ViewModel = ObjectMapper.Map(blogPostPublicDto); if (ViewModel == null) { return NotFound(); diff --git a/modules/cms-kit/src/Volo.CmsKit.Public.Web/Pages/Public/CmsKit/Blogs/BlogPostViewModel.cs b/modules/cms-kit/src/Volo.CmsKit.Public.Web/Pages/Public/CmsKit/Blogs/BlogPostViewModel.cs index ff154b6a7b..789d2687fc 100644 --- a/modules/cms-kit/src/Volo.CmsKit.Public.Web/Pages/Public/CmsKit/Blogs/BlogPostViewModel.cs +++ b/modules/cms-kit/src/Volo.CmsKit.Public.Web/Pages/Public/CmsKit/Blogs/BlogPostViewModel.cs @@ -3,12 +3,11 @@ using System.Collections.Generic; using AutoMapper; using Volo.Abp.Application.Dtos; using Volo.CmsKit.Contents; -using Volo.CmsKit.Public.Blogs; using Volo.CmsKit.Users; namespace Volo.CmsKit.Public.Web.Pages.Public.CmsKit.Blogs; -[AutoMap(typeof(BlogPostPublicDto), ReverseMap = true)] +[AutoMap(typeof(BlogPostCommonDto), ReverseMap = true)] public class BlogPostViewModel : AuditedEntityDto { public Guid BlogId { get; set; } diff --git a/modules/cms-kit/src/Volo.CmsKit.Public.Web/Pages/Public/CmsKit/Blogs/Index.cshtml.cs b/modules/cms-kit/src/Volo.CmsKit.Public.Web/Pages/Public/CmsKit/Blogs/Index.cshtml.cs index f5f2cc2f7a..736fba5e9e 100644 --- a/modules/cms-kit/src/Volo.CmsKit.Public.Web/Pages/Public/CmsKit/Blogs/Index.cshtml.cs +++ b/modules/cms-kit/src/Volo.CmsKit.Public.Web/Pages/Public/CmsKit/Blogs/Index.cshtml.cs @@ -1,11 +1,9 @@ -using Microsoft.AspNetCore.Mvc; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; +using System; using System.Threading.Tasks; +using Microsoft.AspNetCore.Mvc; using Volo.Abp.Application.Dtos; using Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Pagination; +using Volo.CmsKit.Contents; using Volo.CmsKit.Public.Blogs; using Volo.CmsKit.Users; @@ -27,7 +25,7 @@ public class IndexModel : CmsKitPublicPageModelBase [BindProperty(SupportsGet = true)] public Guid? TagId { get; set; } - public PagedResultDto Blogs { get; private set; } + public PagedResultDto Blogs { get; private set; } public PagerModel PagerModel => new PagerModel(Blogs.TotalCount, Blogs.Items.Count, CurrentPage, PageSize, Request.Path.ToString()); 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 6a8b7a6742..e14733695a 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 @@ -2,16 +2,13 @@ @addTagHelper *, Volo.Abp.AspNetCore.Mvc.UI.Bootstrap @using Volo.CmsKit.Contents @using System.Dynamic -@using Volo.CmsKit.Public.Web.Renderers @using Volo.Abp.Data @using Volo.Abp.AspNetCore.Mvc.UI.Packages.HighlightJs; @using Volo.Abp.AspNetCore.Mvc.UI.Widgets; - -@inject IMarkdownToHtmlRenderer MarkdownRenderer - - +@using Volo.CmsKit.Web.Renderers @model Volo.CmsKit.Public.Web.Pages.Public.CmsKit.Pages.IndexModel +@inject IMarkdownToHtmlRenderer MarkdownRenderer @section styles{ diff --git a/modules/cms-kit/src/Volo.CmsKit.Public.Web/Pages/Public/CmsKit/Pages/Index.cshtml.cs b/modules/cms-kit/src/Volo.CmsKit.Public.Web/Pages/Public/CmsKit/Pages/Index.cshtml.cs index 98f1fb70c4..18eb184742 100644 --- a/modules/cms-kit/src/Volo.CmsKit.Public.Web/Pages/Public/CmsKit/Pages/Index.cshtml.cs +++ b/modules/cms-kit/src/Volo.CmsKit.Public.Web/Pages/Public/CmsKit/Pages/Index.cshtml.cs @@ -1,5 +1,6 @@ using System.Threading.Tasks; using Microsoft.AspNetCore.Mvc; +using Volo.CmsKit.Contents; using Volo.CmsKit.Public.Pages; using Volo.CmsKit.Web.Contents; using Volo.CmsKit.Web.Pages; diff --git a/modules/cms-kit/test/Volo.CmsKit.TestBase/Tags/EntityTagRepository_Test.cs b/modules/cms-kit/test/Volo.CmsKit.TestBase/Tags/EntityTagRepository_Test.cs index c200fd01f3..a895f4a949 100644 --- a/modules/cms-kit/test/Volo.CmsKit.TestBase/Tags/EntityTagRepository_Test.cs +++ b/modules/cms-kit/test/Volo.CmsKit.TestBase/Tags/EntityTagRepository_Test.cs @@ -9,11 +9,11 @@ namespace Volo.CmsKit.Tags; public abstract class EntityTagRepository_Test : CmsKitTestBase where TStartupModule : IAbpModule { - private CmsKitTestData _cmsKitTestData; - private IEntityTagRepository _entityTagRepository; - private ITagRepository _tagRepository; + private readonly CmsKitTestData _cmsKitTestData; + private readonly IEntityTagRepository _entityTagRepository; + private readonly ITagRepository _tagRepository; - public EntityTagRepository_Test() + protected EntityTagRepository_Test() { _cmsKitTestData = GetRequiredService(); _entityTagRepository = GetRequiredService(); @@ -25,7 +25,7 @@ public abstract class EntityTagRepository_Test : CmsKitTestBase< { var relatedTags = await _tagRepository.GetAllRelatedTagsAsync(_cmsKitTestData.Content_1_EntityType, _cmsKitTestData.Content_1_EntityId); - await _entityTagRepository.DeleteManyAsync(relatedTags.Select(s => s.Id).ToArray()); + await _entityTagRepository.DeleteManyAsync(relatedTags.Select(s => s.Id).ToArray(), _cmsKitTestData.Content_1_EntityId); relatedTags = await _tagRepository.GetAllRelatedTagsAsync(_cmsKitTestData.Content_1_EntityType, _cmsKitTestData.Content_1_EntityId); @@ -35,7 +35,7 @@ public abstract class EntityTagRepository_Test : CmsKitTestBase< [Fact] public async Task GetEntityIdsFilteredByTagNameAsync_ShouldWorkProperly() { - var entityIds = await _entityTagRepository.GetEntityIdsFilteredByTagNameAsync(_cmsKitTestData.TagName_1, _cmsKitTestData.EntityType1); + var entityIds = await _entityTagRepository.GetEntityIdsFilteredByTagNameAsync(_cmsKitTestData.TagName_1, _cmsKitTestData.EntityType1); entityIds.ShouldNotBeNull(); entityIds.ShouldNotBeEmpty(); diff --git a/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Documents/DocumentDto.cs b/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Documents/DocumentDto.cs index c415efa860..b574870fd8 100644 --- a/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Documents/DocumentDto.cs +++ b/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Documents/DocumentDto.cs @@ -8,6 +8,8 @@ namespace Volo.Docs.Admin.Documents public class DocumentDto : EntityDto { public virtual Guid ProjectId { get; set; } + + public virtual string ProjectName { get; set; } public virtual string Name { get; set; } diff --git a/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Documents/DocumentInfoDto.cs b/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Documents/DocumentInfoDto.cs new file mode 100644 index 0000000000..545e665869 --- /dev/null +++ b/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Documents/DocumentInfoDto.cs @@ -0,0 +1,11 @@ +using System; + +namespace Volo.Docs.Admin.Documents; + +public class DocumentInfoDto +{ + public string Version { get; set; } + public string Format { get; set; } + public string LanguageCode { get; set; } + public Guid ProjectId { get; set; } +} \ No newline at end of file diff --git a/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Documents/IDocumentAdminAppService.cs b/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Documents/IDocumentAdminAppService.cs index 0770ec5d72..12bdbc87be 100644 --- a/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Documents/IDocumentAdminAppService.cs +++ b/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Documents/IDocumentAdminAppService.cs @@ -19,5 +19,7 @@ namespace Volo.Docs.Admin.Documents Task RemoveFromCacheAsync(Guid documentId); Task ReindexAsync(Guid documentId); + + Task> GetFilterItemsAsync(); } } diff --git a/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/ar.json b/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/ar.json index 4849da66e5..ada739b4d7 100644 --- a/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/ar.json +++ b/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/ar.json @@ -54,6 +54,7 @@ "Version": "إصدار", "LanguageCode": "رمز اللغة", "FileName": "اسم الملف", - "LastCachedTime": "وقت ذاكرة التخزين" + "LastCachedTime": "وقت ذاكرة التخزين", + "Project": "مشروع " } } diff --git a/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/cs.json b/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/cs.json index 57dd3c75d5..c593147804 100644 --- a/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/cs.json +++ b/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/cs.json @@ -54,6 +54,7 @@ "Version": "Verze", "LanguageCode": "Kód jazyka", "FileName": "Název souboru", - "LastCachedTime": "Čas uložení v mezipaměti" + "LastCachedTime": "Čas uložení v mezipaměti", + "Project": "Projekt" } } diff --git a/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/de-DE.json b/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/de-DE.json index 28d5f53f47..4d92840132 100644 --- a/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/de-DE.json +++ b/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/de-DE.json @@ -54,6 +54,7 @@ "Version": "Version", "LanguageCode": "Sprachcode", "FileName": "Dateiname", - "LastCachedTime": "Cache-Zeit" + "LastCachedTime": "Cache-Zeit", + "Project": "Projekt" } } \ No newline at end of file diff --git a/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/de.json b/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/de.json index 2eccecb715..7939e4a8f1 100644 --- a/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/de.json +++ b/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/de.json @@ -32,6 +32,7 @@ "DisplayName:GitHubUserAgent": "GitHub-Benutzer-Agent", "DisplayName:All": "Pull all", "DisplayName:LanguageCode": "Sprachcode", - "DisplayName:Version": "Version" + "DisplayName:Version": "Version", + "Project": "Projekt" } } \ No newline at end of file diff --git a/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/el.json b/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/el.json index d44ba001db..bacdfd56de 100644 --- a/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/el.json +++ b/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/el.json @@ -54,6 +54,7 @@ "Version": "Εκδοχή", "LanguageCode": "Κωδικός γλώσσας", "FileName": "Όνομα αρχείου", - "LastCachedTime": "Χρόνος προσωρινής αποθήκευσης" + "LastCachedTime": "Χρόνος προσωρινής αποθήκευσης", + "Project": "Εργο" } } \ No newline at end of file diff --git a/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/en-GB.json b/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/en-GB.json index 1e3339963a..d72c523ef5 100644 --- a/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/en-GB.json +++ b/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/en-GB.json @@ -54,6 +54,8 @@ "Version": "Version", "LanguageCode": "Language code", "FileName": "File name", - "LastCachedTime": "Cache time" + "LastCachedTime": "Cache time", + "Project": "Project", + "AdvancedFilters": "Advanced Filters" } } \ No newline at end of file diff --git a/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/en.json b/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/en.json index d19bef7adf..86142ceb44 100644 --- a/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/en.json +++ b/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/en.json @@ -54,6 +54,8 @@ "Version": "Version", "LanguageCode": "Language code", "FileName": "File name", - "LastCachedTime": "Cache time" + "LastCachedTime": "Cache time", + "Project": "Project", + "AdvancedFilters": "Advanced Filters" } } \ No newline at end of file diff --git a/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/es.json b/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/es.json index f09eb5386b..9858f9d94a 100644 --- a/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/es.json +++ b/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/es.json @@ -54,6 +54,7 @@ "Version": "Versión", "LanguageCode": "Código de idioma", "FileName": "Nombre de fichero", - "LastCachedTime": "Última actualización de caché" + "LastCachedTime": "Última actualización de caché", + "Project": "Proyecto" } } \ No newline at end of file diff --git a/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/fi.json b/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/fi.json index 0d0f7de507..58befd658c 100644 --- a/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/fi.json +++ b/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/fi.json @@ -54,6 +54,7 @@ "Version": "Versio", "LanguageCode": "Kielikoodi", "FileName": "Tiedoston nimi", - "LastCachedTime": "Välimuistin aika" + "LastCachedTime": "Välimuistin aika", + "Project": "Projekti" } } \ No newline at end of file diff --git a/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/fr.json b/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/fr.json index f00ce0a5c9..7a6d6a89cf 100644 --- a/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/fr.json +++ b/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/fr.json @@ -54,6 +54,7 @@ "Version": "Version", "LanguageCode": "Code de langue", "FileName": "Nom de fichier", - "LastCachedTime": "Temps de cache" + "LastCachedTime": "Temps de cache", + "Project": "Projet" } } \ No newline at end of file diff --git a/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/hi.json b/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/hi.json index d2a0e11876..a7d357e83e 100644 --- a/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/hi.json +++ b/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/hi.json @@ -54,6 +54,7 @@ "Version": "संस्करण", "LanguageCode": "भाषा कोड", "FileName": "फ़ाइल का नाम", - "LastCachedTime": "कैश समय" + "LastCachedTime": "कैश समय", + "Project": "परियोजना" } } \ No newline at end of file diff --git a/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/hu.json b/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/hu.json index 10d1611838..b10e721550 100644 --- a/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/hu.json +++ b/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/hu.json @@ -1,61 +1,61 @@ { - "culture": "hu", - "texts": { - "Permission:DocumentManagement": "Dokumentum kezelés", - "Permission:Projects": "Projektek", - "Permission:Edit": "Szerkesztés", - "Permission:Delete": "Törlés", - "Permission:Create": "Létrehozás", - "Permission:Documents": "Dokumentumok", - "Menu:Documents": "Dokumentumok", - "Menu:DocumentManagement": "Dokumentumok", - "Menu:ProjectManagement": "Projektek", - "CreateANewProject": "Új projekt létrehozása", - "Edit": "Szerkesztés", - "Create": "Létrehozás", - "Pull": "Pull", - "Projects": "Projektek", - "Name": "Név", - "ShortName": "Rövid név", - "DocumentStoreType": "Dokumentumtároló típus", - "Format": "Formátum", - "ShortNameInfoText": "Használjon egyedi URL-t.", - "DisplayName:Name": "Név", - "DisplayName:ShortName": "Rövid név", - "DisplayName:Format": "Formátum", - "DisplayName:DefaultDocumentName": "Alapértlemezett dokumentum név", - "DisplayName:NavigationDocumentName": "Navigációs dokumentum neve", - "DisplayName:MinimumVersion": "Minimális verzió", - "DisplayName:MainWebsiteUrl": "A fő webhely URL-je", - "DisplayName:LatestVersionBranchName": "Az utolsó verzió branch neve", - "DisplayName:GitHubRootUrl": "GitHub root URL", - "DisplayName:GitHubAccessToken": "GitHub access token", - "DisplayName:GitHubUserAgent": "GitHub user agent", - "DisplayName:GithubVersionProviderSource": "GitHub version provider source", - "DisplayName:VersionBranchPrefix": "Version branch prefix", - "DisplayName:All": "Pull all", - "DisplayName:LanguageCode": "Nyelv kódja", - "DisplayName:Version": "Verzió", - "Documents": "Dokumentumok", - "RemoveFromCache": "Távolítsa el a gyorsítótárból", - "Reindex": "Újraindexálás", - "ReindexCompleted": "Újraindexálás teljes.", - "RemovedFromCache": "Távolítsa el a gyorsítótárból", - "RemoveFromCacheConfirmation": "Biztosan eltávolítja ezt az elemet a gyorsítótárból?", - "ReIndexDocumentConfirmation": "Biztosan újraindexeli ezt az elemet?", - "DeleteDocumentFromDbConfirmation": "Biztosan törli ezt az elemet az adatbázisból?", - "DeleteFromDatabase": "Törlés az adatbázisból", - "Deleted": "Törölt", - "Search": "Keresés", - "StartDate": "Indulási dátum", - "EndDate": "Befejezés dátuma", - "CreationTime": "Létrehozás ideje", - "LastUpdateTime": "Utolsó módosítás ideje", - "LastSignificantUpdateTime": "Utolsó jelentős frissítés", - "Version": "Verzió", - "LanguageCode": "Nyelv kódja", - "FileName": "Filenév", - "LastCachedTime": "Cache idő" - } + "culture": "hu", + "texts": { + "Permission:DocumentManagement": "Dokumentum kezelés", + "Permission:Projects": "Projektek", + "Permission:Edit": "Szerkesztés", + "Permission:Delete": "Törlés", + "Permission:Create": "Létrehozás", + "Permission:Documents": "Dokumentumok", + "Menu:Documents": "Dokumentumok", + "Menu:DocumentManagement": "Dokumentumok", + "Menu:ProjectManagement": "Projektek", + "CreateANewProject": "Új projekt létrehozása", + "Edit": "Szerkesztés", + "Create": "Létrehozás", + "Pull": "Pull", + "Projects": "Projektek", + "Name": "Név", + "ShortName": "Rövid név", + "DocumentStoreType": "Dokumentumtároló típus", + "Format": "Formátum", + "ShortNameInfoText": "Használjon egyedi URL-t.", + "DisplayName:Name": "Név", + "DisplayName:ShortName": "Rövid név", + "DisplayName:Format": "Formátum", + "DisplayName:DefaultDocumentName": "Alapértlemezett dokumentum név", + "DisplayName:NavigationDocumentName": "Navigációs dokumentum neve", + "DisplayName:MinimumVersion": "Minimális verzió", + "DisplayName:MainWebsiteUrl": "A fő webhely URL-je", + "DisplayName:LatestVersionBranchName": "Az utolsó verzió branch neve", + "DisplayName:GitHubRootUrl": "GitHub root URL", + "DisplayName:GitHubAccessToken": "GitHub access token", + "DisplayName:GitHubUserAgent": "GitHub user agent", + "DisplayName:GithubVersionProviderSource": "GitHub version provider source", + "DisplayName:VersionBranchPrefix": "Version branch prefix", + "DisplayName:All": "Pull all", + "DisplayName:LanguageCode": "Nyelv kódja", + "DisplayName:Version": "Verzió", + "Documents": "Dokumentumok", + "RemoveFromCache": "Távolítsa el a gyorsítótárból", + "Reindex": "Újraindexálás", + "ReindexCompleted": "Újraindexálás teljes.", + "RemovedFromCache": "Távolítsa el a gyorsítótárból", + "RemoveFromCacheConfirmation": "Biztosan eltávolítja ezt az elemet a gyorsítótárból?", + "ReIndexDocumentConfirmation": "Biztosan újraindexeli ezt az elemet?", + "DeleteDocumentFromDbConfirmation": "Biztosan törli ezt az elemet az adatbázisból?", + "DeleteFromDatabase": "Törlés az adatbázisból", + "Deleted": "Törölt", + "Search": "Keresés", + "StartDate": "Indulási dátum", + "EndDate": "Befejezés dátuma", + "CreationTime": "Létrehozás ideje", + "LastUpdateTime": "Utolsó módosítás ideje", + "LastSignificantUpdateTime": "Utolsó jelentős frissítés", + "Version": "Verzió", + "LanguageCode": "Nyelv kódja", + "FileName": "File név", + "LastCachedTime": "Cache idő", + "Project": "Projekt" } - \ No newline at end of file +} diff --git a/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/is.json b/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/is.json index 101aab8182..c7d13791d0 100644 --- a/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/is.json +++ b/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/is.json @@ -54,6 +54,7 @@ "Version": "Útgáfa", "LanguageCode": "Túngumála kóði", "FileName": "Skráar nafn", - "LastCachedTime": "Tími geymt í skyndiminni" + "LastCachedTime": "Tími geymt í skyndiminni", + "Project": "Verkefni" } } \ No newline at end of file diff --git a/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/it.json b/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/it.json index 1a4d8e3f4c..b6c95e5b58 100644 --- a/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/it.json +++ b/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/it.json @@ -54,6 +54,7 @@ "Version": "Versione", "LanguageCode": "Codice della lingua", "FileName": "Nome del file", - "LastCachedTime": "Tempo di cache" + "LastCachedTime": "Tempo di cache", + "Project": "Progetto" } } \ No newline at end of file diff --git a/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/nl.json b/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/nl.json index 6451eed41e..e8cd5d730a 100644 --- a/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/nl.json +++ b/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/nl.json @@ -54,6 +54,7 @@ "Version": "Versie", "LanguageCode": "Taalcode", "FileName": "Bestandsnaam", - "LastCachedTime": "Cache tijd" + "LastCachedTime": "Cache tijd", + "Project": "Project" } } \ No newline at end of file diff --git a/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/pl-PL.json b/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/pl-PL.json index 26e4b8bc7f..5f1025a9a6 100644 --- a/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/pl-PL.json +++ b/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/pl-PL.json @@ -54,6 +54,7 @@ "Version": "Wersja", "LanguageCode": "Kod języka", "FileName": "Nazwa pliku", - "LastCachedTime": "Czas w pamięci podręcznej" + "LastCachedTime": "Czas w pamięci podręcznej", + "Project": "Projekt" } } \ No newline at end of file diff --git a/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/pt-BR.json b/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/pt-BR.json index 7daa4964b3..d926dfada9 100644 --- a/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/pt-BR.json +++ b/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/pt-BR.json @@ -32,7 +32,7 @@ "DisplayName:GitHubAccessToken": "Token de acesso do GitHub", "DisplayName:GitHubUserAgent": "Usuário agente do GitHub", "DisplayName:GithubVersionProviderSource": "Fonte do provedor de versão do GitHub", - "DisplayName:VersionBranchPrefix": "Prefixo da ramificação da versão", + "DisplayName:VersionBranchPrefix": "Prefixo da Branch da versão", "DisplayName:All": "Puxe tudo", "DisplayName:LanguageCode": "Código de idioma", "DisplayName:Version": "Versão", @@ -54,6 +54,8 @@ "Version": "Versão", "LanguageCode": "Código de idioma", "FileName": "Nome do arquivo", - "LastCachedTime": "Tempo de cache" + "LastCachedTime": "Tempo de cache", + "Project": "Projeto", + "AdvancedFilters": "Filtros Avançados" } } \ No newline at end of file diff --git a/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/ro-RO.json b/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/ro-RO.json index 02198cb96c..b236915665 100644 --- a/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/ro-RO.json +++ b/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/ro-RO.json @@ -54,6 +54,7 @@ "Version": "Versiune", "LanguageCode": "Codul limbii", "FileName": "Nume fişier", - "LastCachedTime": "Durată cache" + "LastCachedTime": "Durată cache", + "Project": "Proiect" } } \ No newline at end of file diff --git a/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/ru.json b/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/ru.json index 1b7082d189..16102717c2 100644 --- a/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/ru.json +++ b/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/ru.json @@ -54,6 +54,7 @@ "Version": "Версия", "LanguageCode": "Код языка", "FileName": "Имя файла", - "LastCachedTime": "Время кеширования" + "LastCachedTime": "Время кеширования", + "Project": "Проект" } } \ No newline at end of file diff --git a/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/sk.json b/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/sk.json index ab0bc3e008..8041e796f0 100644 --- a/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/sk.json +++ b/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/sk.json @@ -54,6 +54,7 @@ "Version": "Verzia", "LanguageCode": "Kód jazyka", "FileName": "Názov súboru", - "LastCachedTime": "Čas vyrovnávacej pamäte" + "LastCachedTime": "Čas vyrovnávacej pamäte", + "Project": "Projekt" } } \ No newline at end of file diff --git a/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/sl.json b/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/sl.json index f2061a9fd5..a3445dc87b 100644 --- a/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/sl.json +++ b/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/sl.json @@ -54,6 +54,7 @@ "Version": "Različica", "LanguageCode": "Jezikovna koda", "FileName": "Ime datoteke", - "LastCachedTime": "Čas predpomnilnika" + "LastCachedTime": "Čas pred pomnilnika", + "Project": "Projekt" } } \ No newline at end of file diff --git a/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/tr.json b/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/tr.json index 57c72b6db5..dade32b970 100644 --- a/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/tr.json +++ b/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/tr.json @@ -48,12 +48,14 @@ "Search": "Arama", "StartDate": "Başlangıç tarihi", "EndDate": "Bitiş tarihi", - "CreationTime": "oluşturma zamanı", + "CreationTime": "Oluşturma Zamanı", "LastUpdateTime": "Son Güncelleme", "LastSignificantUpdateTime": "Son önemli güncelleme", - "Version": "sürüm", + "Version": "Sürüm", "LanguageCode": "Dil kodu", "FileName": "Dosya adı", - "LastCachedTime": "Önbellek süresi" + "LastCachedTime": "Önbellek süresi", + "Project": "Proje", + "AdvancedFilters": "Gelişmiş Filtre" } } \ No newline at end of file diff --git a/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/vi.json b/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/vi.json index 350d995cfe..c44d2feb8f 100644 --- a/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/vi.json +++ b/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/vi.json @@ -54,6 +54,7 @@ "Version": "Phiên bản", "LanguageCode": "Mật ngữ", "FileName": "Tên tệp", - "LastCachedTime": "Thời gian lưu vào bộ nhớ đệm" + "LastCachedTime": "Thời gian lưu vào bộ nhớ đệm", + "Project": "Dự án" } } \ No newline at end of file diff --git a/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/zh-Hans.json b/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/zh-Hans.json index c0985f956a..f81333d38e 100644 --- a/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/zh-Hans.json +++ b/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/zh-Hans.json @@ -54,6 +54,7 @@ "Version": "版本", "LanguageCode": "语言代码", "FileName": "文件名称", - "LastCachedTime": "缓存项" + "LastCachedTime": "缓存项", + "Project": "项目" } } \ No newline at end of file diff --git a/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/zh-Hant.json b/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/zh-Hant.json index cc76f54510..54d86eca33 100644 --- a/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/zh-Hant.json +++ b/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Localization/Resources/Docs/ApplicationContracts/zh-Hant.json @@ -54,6 +54,7 @@ "Version": "版本", "LanguageCode": "語言代碼", "FileName": "文檔名稱", - "LastCachedTime": "緩存時間" + "LastCachedTime": "緩存時間", + "Project": "项目" } } \ No newline at end of file diff --git a/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Projects/IProjectAdminAppService.cs b/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Projects/IProjectAdminAppService.cs index 9b832165d1..6f3d503f44 100644 --- a/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Projects/IProjectAdminAppService.cs +++ b/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Projects/IProjectAdminAppService.cs @@ -1,4 +1,5 @@ using System; +using System.Collections.Generic; using System.Threading.Tasks; using Volo.Abp.Application.Dtos; using Volo.Abp.Application.Services; @@ -20,5 +21,6 @@ namespace Volo.Docs.Admin.Projects Task ReindexAsync(ReindexInput input); Task ReindexAllAsync(); + Task> GetListWithoutDetailsAsync(); } } diff --git a/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Projects/ProjectWithoutDetailsDto.cs b/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Projects/ProjectWithoutDetailsDto.cs new file mode 100644 index 0000000000..b6e6a301cb --- /dev/null +++ b/modules/docs/src/Volo.Docs.Admin.Application.Contracts/Volo/Docs/Admin/Projects/ProjectWithoutDetailsDto.cs @@ -0,0 +1,9 @@ +using System; + +namespace Volo.Docs.Admin.Projects; + +public class ProjectWithoutDetailsDto +{ + public Guid Id { get; set; } + public string Name { get; set; } +} \ No newline at end of file diff --git a/modules/docs/src/Volo.Docs.Admin.Application/Volo/Docs/Admin/DocsAdminApplicationAutoMapperProfile.cs b/modules/docs/src/Volo.Docs.Admin.Application/Volo/Docs/Admin/DocsAdminApplicationAutoMapperProfile.cs index 86e6d46e0c..01a7250ce5 100644 --- a/modules/docs/src/Volo.Docs.Admin.Application/Volo/Docs/Admin/DocsAdminApplicationAutoMapperProfile.cs +++ b/modules/docs/src/Volo.Docs.Admin.Application/Volo/Docs/Admin/DocsAdminApplicationAutoMapperProfile.cs @@ -1,4 +1,5 @@ using AutoMapper; +using Volo.Abp.AutoMapper; using Volo.Docs.Admin.Documents; using Volo.Docs.Admin.Projects; using Volo.Docs.Documents; @@ -11,8 +12,10 @@ namespace Volo.Docs.Admin public DocsAdminApplicationAutoMapperProfile() { CreateMap(); - CreateMap(); + CreateMap().Ignore(x => x.ProjectName); CreateMap(); + CreateMap(); + CreateMap(); } } } \ No newline at end of file diff --git a/modules/docs/src/Volo.Docs.Admin.Application/Volo/Docs/Admin/Documents/DocumentAdminAppService.cs b/modules/docs/src/Volo.Docs.Admin.Application/Volo/Docs/Admin/Documents/DocumentAdminAppService.cs index af515b4be7..7d68681b1d 100644 --- a/modules/docs/src/Volo.Docs.Admin.Application/Volo/Docs/Admin/Documents/DocumentAdminAppService.cs +++ b/modules/docs/src/Volo.Docs.Admin.Application/Volo/Docs/Admin/Documents/DocumentAdminAppService.cs @@ -5,7 +5,6 @@ using System.Threading.Tasks; using Microsoft.AspNetCore.Authorization; using Microsoft.Extensions.Logging; using Volo.Abp; -using Volo.Abp.Uow; using Volo.Abp.Application.Dtos; using Volo.Abp.Application.Services; using Volo.Abp.Caching; @@ -217,6 +216,13 @@ namespace Volo.Docs.Admin.Documents await _elasticSearchService.AddOrUpdateAsync(document); } + public async Task> GetFilterItemsAsync() + { + var documents = await _documentRepository.GetUniqueListDocumentInfoAsync(); + return ObjectMapper.Map, List>(documents); + } + + private async Task UpdateDocumentUpdateInfoCache(Document document) { var cacheKey = $"DocumentUpdateInfo{document.ProjectId}#{document.Name}#{document.LanguageCode}#{document.Version}"; diff --git a/modules/docs/src/Volo.Docs.Admin.Application/Volo/Docs/Admin/Projects/ProjectAdminAppService.cs b/modules/docs/src/Volo.Docs.Admin.Application/Volo/Docs/Admin/Projects/ProjectAdminAppService.cs index 14833cd3e4..540ecfe275 100644 --- a/modules/docs/src/Volo.Docs.Admin.Application/Volo/Docs/Admin/Projects/ProjectAdminAppService.cs +++ b/modules/docs/src/Volo.Docs.Admin.Application/Volo/Docs/Admin/Projects/ProjectAdminAppService.cs @@ -156,5 +156,11 @@ namespace Volo.Docs.Admin.Projects await ReindexProjectAsync(project.Id); } } + + public async Task> GetListWithoutDetailsAsync() + { + var projects = await _projectRepository.GetListWithoutDetailsAsync(); + return ObjectMapper.Map, List>(projects); + } } } diff --git a/modules/docs/src/Volo.Docs.Admin.HttpApi.Client/ClientProxies/DocumentsAdminClientProxy.Generated.cs b/modules/docs/src/Volo.Docs.Admin.HttpApi.Client/ClientProxies/DocumentsAdminClientProxy.Generated.cs index 7bb1ef0e87..e2b9fa2783 100644 --- a/modules/docs/src/Volo.Docs.Admin.HttpApi.Client/ClientProxies/DocumentsAdminClientProxy.Generated.cs +++ b/modules/docs/src/Volo.Docs.Admin.HttpApi.Client/ClientProxies/DocumentsAdminClientProxy.Generated.cs @@ -7,6 +7,7 @@ using Volo.Abp.Http.Modeling; using Volo.Abp.DependencyInjection; using Volo.Abp.Http.Client.ClientProxying; using Volo.Docs.Admin.Documents; +using System.Collections.Generic; // ReSharper disable once CheckNamespace namespace Volo.Docs.Admin.ClientProxies; @@ -62,4 +63,9 @@ public partial class DocumentsAdminClientProxy : ClientProxyBase> GetFilterItemsAsync() + { + return await RequestAsync>(nameof(GetFilterItemsAsync)); + } } diff --git a/modules/docs/src/Volo.Docs.Admin.HttpApi.Client/ClientProxies/ProjectsAdminClientProxy.Generated.cs b/modules/docs/src/Volo.Docs.Admin.HttpApi.Client/ClientProxies/ProjectsAdminClientProxy.Generated.cs index cb8d5c3947..072106df0e 100644 --- a/modules/docs/src/Volo.Docs.Admin.HttpApi.Client/ClientProxies/ProjectsAdminClientProxy.Generated.cs +++ b/modules/docs/src/Volo.Docs.Admin.HttpApi.Client/ClientProxies/ProjectsAdminClientProxy.Generated.cs @@ -7,6 +7,7 @@ using Volo.Abp.Http.Modeling; using Volo.Abp.DependencyInjection; using Volo.Abp.Http.Client.ClientProxying; using Volo.Docs.Admin.Projects; +using System.Collections.Generic; // ReSharper disable once CheckNamespace namespace Volo.Docs.Admin.ClientProxies; @@ -61,6 +62,11 @@ public partial class ProjectsAdminClientProxy : ClientProxyBase> GetListWithoutDetailsAsync() + { + return await RequestAsync>(nameof(GetListWithoutDetailsAsync)); + } + public virtual async Task ReindexAsync(ReindexInput input) { await RequestAsync(nameof(ReindexAsync), new ClientProxyRequestTypeValue diff --git a/modules/docs/src/Volo.Docs.Admin.HttpApi.Client/ClientProxies/docs-admin-generate-proxy.json b/modules/docs/src/Volo.Docs.Admin.HttpApi.Client/ClientProxies/docs-admin-generate-proxy.json index e85e6fbb43..c6cf885b09 100644 --- a/modules/docs/src/Volo.Docs.Admin.HttpApi.Client/ClientProxies/docs-admin-generate-proxy.json +++ b/modules/docs/src/Volo.Docs.Admin.HttpApi.Client/ClientProxies/docs-admin-generate-proxy.json @@ -7,6 +7,8 @@ "Volo.Docs.Admin.DocumentsAdminController": { "controllerName": "DocumentsAdmin", "controllerGroupName": "DocumentsAdmin", + "isRemoteService": true, + "apiVersion": null, "type": "Volo.Docs.Admin.DocumentsAdminController", "interfaces": [ { @@ -427,12 +429,29 @@ }, "allowAnonymous": null, "implementFrom": "Volo.Docs.Admin.Documents.IDocumentAdminAppService" + }, + "GetFilterItemsAsync": { + "uniqueName": "GetFilterItemsAsync", + "name": "GetFilterItemsAsync", + "httpMethod": "GET", + "url": "api/docs/admin/documents/GetFilterItems", + "supportedVersions": [], + "parametersOnMethod": [], + "parameters": [], + "returnValue": { + "type": "System.Collections.Generic.List", + "typeSimple": "[Volo.Docs.Admin.Documents.DocumentInfoDto]" + }, + "allowAnonymous": null, + "implementFrom": "Volo.Docs.Admin.Documents.IDocumentAdminAppService" } } }, "Volo.Docs.Admin.ProjectsAdminController": { "controllerName": "ProjectsAdmin", "controllerGroupName": "ProjectsAdmin", + "isRemoteService": true, + "apiVersion": null, "type": "Volo.Docs.Admin.ProjectsAdminController", "interfaces": [ { @@ -684,6 +703,21 @@ "allowAnonymous": null, "implementFrom": "Volo.Docs.Admin.Projects.IProjectAdminAppService" }, + "GetListWithoutDetailsAsync": { + "uniqueName": "GetListWithoutDetailsAsync", + "name": "GetListWithoutDetailsAsync", + "httpMethod": "GET", + "url": "api/docs/admin/projects/GetListProjectWithoutDetailsAsync", + "supportedVersions": [], + "parametersOnMethod": [], + "parameters": [], + "returnValue": { + "type": "System.Collections.Generic.List", + "typeSimple": "[Volo.Docs.Admin.Projects.ProjectWithoutDetailsDto]" + }, + "allowAnonymous": null, + "implementFrom": "Volo.Docs.Admin.Projects.IProjectAdminAppService" + }, "ReindexAsyncByInput": { "uniqueName": "ReindexAsyncByInput", "name": "ReindexAsync", diff --git a/modules/docs/src/Volo.Docs.Admin.HttpApi/Volo/Docs/Admin/DocumentsAdminController.cs b/modules/docs/src/Volo.Docs.Admin.HttpApi/Volo/Docs/Admin/DocumentsAdminController.cs index 9404ac0bde..c0586ed699 100644 --- a/modules/docs/src/Volo.Docs.Admin.HttpApi/Volo/Docs/Admin/DocumentsAdminController.cs +++ b/modules/docs/src/Volo.Docs.Admin.HttpApi/Volo/Docs/Admin/DocumentsAdminController.cs @@ -63,5 +63,12 @@ namespace Volo.Docs.Admin { await _documentAdminAppService.ReindexAsync(documentId); } + + [HttpGet] + [Route("GetFilterItems")] + public async Task> GetFilterItemsAsync() + { + return await _documentAdminAppService.GetFilterItemsAsync(); + } } } diff --git a/modules/docs/src/Volo.Docs.Admin.HttpApi/Volo/Docs/Admin/ProjectsAdminController.cs b/modules/docs/src/Volo.Docs.Admin.HttpApi/Volo/Docs/Admin/ProjectsAdminController.cs index 1696229bf8..ea0c7f1afd 100644 --- a/modules/docs/src/Volo.Docs.Admin.HttpApi/Volo/Docs/Admin/ProjectsAdminController.cs +++ b/modules/docs/src/Volo.Docs.Admin.HttpApi/Volo/Docs/Admin/ProjectsAdminController.cs @@ -1,4 +1,5 @@ using System; +using System.Collections.Generic; using System.Threading.Tasks; using Microsoft.AspNetCore.Mvc; using Volo.Abp; @@ -61,6 +62,13 @@ namespace Volo.Docs.Admin return _projectAppService.ReindexAllAsync(); } + [HttpGet] + [Route("GetListProjectWithoutDetailsAsync")] + public Task> GetListWithoutDetailsAsync() + { + return _projectAppService.GetListWithoutDetailsAsync(); + } + [HttpPost] [Route("Reindex")] public Task ReindexAsync(ReindexInput input) diff --git a/modules/docs/src/Volo.Docs.Admin.Web/Pages/Docs/Admin/Documents/Index.cshtml b/modules/docs/src/Volo.Docs.Admin.Web/Pages/Docs/Admin/Documents/Index.cshtml index 5873afc279..9e846f24a9 100644 --- a/modules/docs/src/Volo.Docs.Admin.Web/Pages/Docs/Admin/Documents/Index.cshtml +++ b/modules/docs/src/Volo.Docs.Admin.Web/Pages/Docs/Admin/Documents/Index.cshtml @@ -32,147 +32,156 @@
-
-
-
-
@L["Name"].Value
- - -
-
+ -
+
-
@L["Version"].Value
- - +
@L["Project"].Value
+ +
-
+ -
+
-
@L["LanguageCode"].Value
+
@L["Version"].Value
- +
-
- - -
+ + +
-
@L["FileName"].Value
+
@L["Name"].Value
+ id="Name" + name="Name" + class="form-control">
-
+ -
+
-
@L["Format"].Value
+
@L["LanguageCode"].Value
- +
-
- - -
-
-
@L["CreationTime"].Value
- - - + + + + + + @L["AdvancedFilters"] + + +
+
+ -
-
-
@L["LastUpdateTime"].Value
- - +
+
@L["LastUpdateTime"].Value
+ - - - - -
-
- -
-
-
@L["LastSignificantUpdateTime"].Value
- - - - - - - -
-
+
+ -
-
-
@L["LastCachedTime"].Value
+ +
+
@L["LastCachedTime"].Value
- - - - - - -
-
- -
- -
-
+
+ + + +
+
@L["Format"].Value
+ + +
+
+ + + + + +
+
@L["LastSignificantUpdateTime"].Value
+ + + + +
+
+ + +
@@ -180,13 +189,14 @@ @L["Actions"] + @L["ProjectName"] @L["Name"] @L["Version"] @L["LanguageCode"] @L["FileName"] @L["Format"] @L["CreationTime"] - @L["LastUpdatedTime"] + @L["LastUpdateTime"] @L["LastSignificantUpdateTime"] @L["LastCachedTime"] diff --git a/modules/docs/src/Volo.Docs.Admin.Web/Pages/Docs/Admin/Documents/Index.cshtml.cs b/modules/docs/src/Volo.Docs.Admin.Web/Pages/Docs/Admin/Documents/Index.cshtml.cs index 559eaab5eb..194ad6780f 100644 --- a/modules/docs/src/Volo.Docs.Admin.Web/Pages/Docs/Admin/Documents/Index.cshtml.cs +++ b/modules/docs/src/Volo.Docs.Admin.Web/Pages/Docs/Admin/Documents/Index.cshtml.cs @@ -1,18 +1,24 @@ -using System; -using System.ComponentModel.DataAnnotations; +using System.Collections.Generic; using System.Threading.Tasks; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; -using Volo.Docs.Documents; +using Volo.Docs.Admin.Projects; -namespace Volo.Docs.Admin.Pages.Docs.Admin.Documents +namespace Volo.Docs.Admin.Pages.Docs.Admin.Documents; + +[Authorize(DocsAdminPermissions.Projects.Default)] +public class IndexModel : DocsAdminPageModel { - [Authorize(DocsAdminPermissions.Projects.Default)] - public class IndexModel : DocsAdminPageModel + private readonly IProjectAdminAppService _projectAdminAppService; + public List Projects { get; set; } + + public IndexModel(IProjectAdminAppService projectAdminAppService) + { + _projectAdminAppService = projectAdminAppService; + } + public virtual async Task OnGet() { - public virtual Task OnGet() - { - return Task.FromResult(Page()); - } + Projects = await _projectAdminAppService.GetListWithoutDetailsAsync(); + return Page(); } -} \ No newline at end of file +} diff --git a/modules/docs/src/Volo.Docs.Admin.Web/Pages/Docs/Admin/Documents/index.js b/modules/docs/src/Volo.Docs.Admin.Web/Pages/Docs/Admin/Documents/index.js index 928990e160..85c1ebc7be 100644 --- a/modules/docs/src/Volo.Docs.Admin.Web/Pages/Docs/Admin/Documents/index.js +++ b/modules/docs/src/Volo.Docs.Admin.Web/Pages/Docs/Admin/Documents/index.js @@ -6,13 +6,112 @@ $(function () { return $datePicker.data().datepicker.getFormattedDate('yyyy-mm-dd'); }; + var comboboxItems = []; + + service.getFilterItems() + .then(function (result) { + comboboxItems = result; + fillOptions(); + }).catch(function (error) { + abp.message.error(error); + }); + + + var $projectId = $('#ProjectId'); + + $projectId.on('change', function () { + fillOptions(); + }); + + var comboboxs = { + version: $('#Version'), + languageCode: $('#LanguageCode'), + format: $('#Format') + }; + + for (var key in comboboxs) { + comboboxs[key].on('change', function () { + fillOptions(); + }); + } + + + var selectedItem = getSelectedItem(); + + function emptyComboboxs() { + for (var key in comboboxs) { + comboboxs[key].empty(); + } + } + + function getSelectedItem() { + var item = {}; + for (var key in comboboxs) { + item[key] = comboboxs[key].val(); + } + return item; + } + + function SetComboboxsValues(item) { + for (var key in comboboxs) { + comboboxs[key].val(item[key]); + } + } + + function addComboboxsEmptyItem() { + for (var key in comboboxs) { + comboboxs[key].append($('
public bool AddDeveloperSigningCredential { get; set; } = true; + + /// + /// Adds the default cookie handlers and corresponding configuration + /// Default: true, Set false to suppress AddCookieAuthentication() call on the IIdentityServerBuilder. + /// + public bool AddIdentityServerCookieAuthentication { get; set; } = true; } diff --git a/modules/identityserver/src/Volo.Abp.IdentityServer.Domain/Volo/Abp/IdentityServer/AbpIdentityServerDomainModule.cs b/modules/identityserver/src/Volo.Abp.IdentityServer.Domain/Volo/Abp/IdentityServer/AbpIdentityServerDomainModule.cs index 96ab4abd89..9b9dde5c96 100644 --- a/modules/identityserver/src/Volo.Abp.IdentityServer.Domain/Volo/Abp/IdentityServer/AbpIdentityServerDomainModule.cs +++ b/modules/identityserver/src/Volo.Abp.IdentityServer.Domain/Volo/Abp/IdentityServer/AbpIdentityServerDomainModule.cs @@ -1,4 +1,5 @@ using System.Threading.Tasks; +using IdentityServer4.Configuration; using IdentityServer4.Services; using IdentityServer4.Stores; using Microsoft.Extensions.DependencyInjection; @@ -71,13 +72,7 @@ public class AbpIdentityServerDomainModule : AbpModule var configuration = services.GetConfiguration(); var builderOptions = services.ExecutePreConfiguredActions(); - var identityServerBuilder = services.AddIdentityServer(options => - { - options.Events.RaiseErrorEvents = true; - options.Events.RaiseInformationEvents = true; - options.Events.RaiseFailureEvents = true; - options.Events.RaiseSuccessEvents = true; - }); + var identityServerBuilder = AddIdentityServer(services, builderOptions); if (builderOptions.AddDeveloperSigningCredential) { @@ -110,6 +105,37 @@ public class AbpIdentityServerDomainModule : AbpModule } } + private static IIdentityServerBuilder AddIdentityServer(IServiceCollection services, AbpIdentityServerBuilderOptions abpIdentityServerBuilderOptions) + { + services.Configure(options => + { + options.Events.RaiseErrorEvents = true; + options.Events.RaiseInformationEvents = true; + options.Events.RaiseFailureEvents = true; + options.Events.RaiseSuccessEvents = true; + }); + + var identityServerBuilder = services.AddIdentityServerBuilder() + .AddRequiredPlatformServices() + .AddCoreServices() + .AddDefaultEndpoints() + .AddPluggableServices() + .AddValidators() + .AddResponseGenerators() + .AddDefaultSecretParsers() + .AddDefaultSecretValidators(); + + if (abpIdentityServerBuilderOptions.AddIdentityServerCookieAuthentication) + { + identityServerBuilder.AddCookieAuthentication(); + } + + // provide default in-memory implementation, not suitable for most production scenarios + identityServerBuilder.AddInMemoryPersistedGrants(); + + return identityServerBuilder; + } + public override void PostConfigureServices(ServiceConfigurationContext context) { OneTimeRunner.Run(() => diff --git a/modules/identityserver/src/Volo.Abp.IdentityServer.Domain/Volo/Abp/IdentityServer/AbpWildcardSubdomainCorsPolicyService.cs b/modules/identityserver/src/Volo.Abp.IdentityServer.Domain/Volo/Abp/IdentityServer/AbpWildcardSubdomainCorsPolicyService.cs index 82658ceccd..32d2d1eb73 100644 --- a/modules/identityserver/src/Volo.Abp.IdentityServer.Domain/Volo/Abp/IdentityServer/AbpWildcardSubdomainCorsPolicyService.cs +++ b/modules/identityserver/src/Volo.Abp.IdentityServer.Domain/Volo/Abp/IdentityServer/AbpWildcardSubdomainCorsPolicyService.cs @@ -3,6 +3,7 @@ using System.Linq; using System.Threading.Tasks; using IdentityServer4.Configuration; using Microsoft.Extensions.Options; +using Microsoft.Extensions.DependencyInjection; using Volo.Abp.Caching; using Volo.Abp.DependencyInjection; using Volo.Abp.Text.Formatting; @@ -13,7 +14,7 @@ public class AbpWildcardSubdomainCorsPolicyService : AbpCorsPolicyService { public AbpWildcardSubdomainCorsPolicyService( IDistributedCache cache, - IHybridServiceScopeFactory hybridServiceScopeFactory, + IServiceScopeFactory hybridServiceScopeFactory, IOptions options) : base(cache, hybridServiceScopeFactory, options) { diff --git a/modules/identityserver/src/Volo.Abp.IdentityServer.Domain/Volo/Abp/IdentityServer/AspNetIdentity/AbpResourceOwnerPasswordValidator.cs b/modules/identityserver/src/Volo.Abp.IdentityServer.Domain/Volo/Abp/IdentityServer/AspNetIdentity/AbpResourceOwnerPasswordValidator.cs index 77181a8b8b..cf69fda91a 100644 --- a/modules/identityserver/src/Volo.Abp.IdentityServer.Domain/Volo/Abp/IdentityServer/AspNetIdentity/AbpResourceOwnerPasswordValidator.cs +++ b/modules/identityserver/src/Volo.Abp.IdentityServer.Domain/Volo/Abp/IdentityServer/AspNetIdentity/AbpResourceOwnerPasswordValidator.cs @@ -32,7 +32,7 @@ public class AbpResourceOwnerPasswordValidator : IResourceOwnerPasswordValidator protected IdentitySecurityLogManager IdentitySecurityLogManager { get; } protected ILogger> Logger { get; } protected IStringLocalizer Localizer { get; } - protected IHybridServiceScopeFactory ServiceScopeFactory { get; } + protected IServiceScopeFactory ServiceScopeFactory { get; } protected AbpIdentityOptions AbpIdentityOptions { get; } protected IOptions IdentityOptions { get; } @@ -43,7 +43,7 @@ public class AbpResourceOwnerPasswordValidator : IResourceOwnerPasswordValidator ILogger> logger, IStringLocalizer localizer, IOptions abpIdentityOptions, - IHybridServiceScopeFactory serviceScopeFactory, + IServiceScopeFactory serviceScopeFactory, IOptions identityOptions) { UserManager = userManager; diff --git a/modules/openiddict/src/Volo.Abp.OpenIddict.AspNetCore/Volo/Abp/OpenIddict/Controllers/TokenController.Password.cs b/modules/openiddict/src/Volo.Abp.OpenIddict.AspNetCore/Volo/Abp/OpenIddict/Controllers/TokenController.Password.cs index 49d415c927..1484ea4b52 100644 --- a/modules/openiddict/src/Volo.Abp.OpenIddict.AspNetCore/Volo/Abp/OpenIddict/Controllers/TokenController.Password.cs +++ b/modules/openiddict/src/Volo.Abp.OpenIddict.AspNetCore/Volo/Abp/OpenIddict/Controllers/TokenController.Password.cs @@ -22,7 +22,7 @@ namespace Volo.Abp.OpenIddict.Controllers; public partial class TokenController { - protected IHybridServiceScopeFactory ServiceScopeFactory => LazyServiceProvider.LazyGetRequiredService(); + protected IServiceScopeFactory ServiceScopeFactory => LazyServiceProvider.LazyGetRequiredService(); protected ITenantConfigurationProvider TenantConfigurationProvider=> LazyServiceProvider.LazyGetRequiredService(); protected IOptions AbpIdentityOptions => LazyServiceProvider.LazyGetRequiredService>(); protected IOptions IdentityOptions => LazyServiceProvider.LazyGetRequiredService>(); diff --git a/modules/openiddict/src/Volo.Abp.OpenIddict.Domain.Shared/Volo/Abp/OpenIddict/Localization/OpenIddict/pt-BR.json b/modules/openiddict/src/Volo.Abp.OpenIddict.Domain.Shared/Volo/Abp/OpenIddict/Localization/OpenIddict/pt-BR.json index 2952a0352c..6962ebcc4c 100644 --- a/modules/openiddict/src/Volo.Abp.OpenIddict.Domain.Shared/Volo/Abp/OpenIddict/Localization/OpenIddict/pt-BR.json +++ b/modules/openiddict/src/Volo.Abp.OpenIddict.Domain.Shared/Volo/Abp/OpenIddict/Localization/OpenIddict/pt-BR.json @@ -4,10 +4,10 @@ "TheOpenIDConnectRequestCannotBeRetrieved": "Não foi possivel recuperar a requisição do OpenID Connect.", "TheUserDetailsCannotBbeRetrieved": "Não foi possivel recuperar os detalhes do usuário.", "TheApplicationDetailsCannotBeFound": "Os detalhes da aplicação não foram encontrados.", - "DetailsConcerningTheCallingClientApplicationCannotBeFound": "Os detalhes relativos ao aplicativo cliente requisitante não firam encontrados.", + "DetailsConcerningTheCallingClientApplicationCannotBeFound": "Os detalhes relativos ao aplicativo cliente requisitante não foram encontrados.", "TheSpecifiedGrantTypeIsNotImplemented.": "O tipo de permissão {0} não está implementando.", "Authorization": "Autorização", - "DoYouWantToGrantAccessToYourData": "Deseja permitir {0} acesse seus dados?", + "DoYouWantToGrantAccessToYourData": "Deseja permitir {0} acessar seus dados?", "ScopesRequested": "Escopo solicitado", "Accept": "Aceitar", "Deny": "Negar" diff --git a/modules/permission-management/src/Volo.Abp.PermissionManagement.Application.Contracts/Volo/Abp/PermissionManagement/PermissionGrantInfoDto.cs b/modules/permission-management/src/Volo.Abp.PermissionManagement.Application.Contracts/Volo/Abp/PermissionManagement/PermissionGrantInfoDto.cs index b608a69b54..12e4010f99 100644 --- a/modules/permission-management/src/Volo.Abp.PermissionManagement.Application.Contracts/Volo/Abp/PermissionManagement/PermissionGrantInfoDto.cs +++ b/modules/permission-management/src/Volo.Abp.PermissionManagement.Application.Contracts/Volo/Abp/PermissionManagement/PermissionGrantInfoDto.cs @@ -7,6 +7,10 @@ public class PermissionGrantInfoDto public string Name { get; set; } public string DisplayName { get; set; } + + public string DisplayNameKey { get; set; } + + public string DisplayNameResource { get; set; } public string ParentName { get; set; } diff --git a/modules/permission-management/src/Volo.Abp.PermissionManagement.Application.Contracts/Volo/Abp/PermissionManagement/PermissionGroupDto.cs b/modules/permission-management/src/Volo.Abp.PermissionManagement.Application.Contracts/Volo/Abp/PermissionManagement/PermissionGroupDto.cs index a138cd0451..b9cc6d5f90 100644 --- a/modules/permission-management/src/Volo.Abp.PermissionManagement.Application.Contracts/Volo/Abp/PermissionManagement/PermissionGroupDto.cs +++ b/modules/permission-management/src/Volo.Abp.PermissionManagement.Application.Contracts/Volo/Abp/PermissionManagement/PermissionGroupDto.cs @@ -7,6 +7,10 @@ public class PermissionGroupDto public string Name { get; set; } public string DisplayName { get; set; } + + public string DisplayNameKey { get; set; } + + public string DisplayNameResource { get; set; } public List Permissions { get; set; } } diff --git a/modules/permission-management/src/Volo.Abp.PermissionManagement.Application/Volo/Abp/PermissionManagement/PermissionAppService.cs b/modules/permission-management/src/Volo.Abp.PermissionManagement.Application/Volo/Abp/PermissionManagement/PermissionAppService.cs index d7d7f28820..fd0ccf0246 100644 --- a/modules/permission-management/src/Volo.Abp.PermissionManagement.Application/Volo/Abp/PermissionManagement/PermissionAppService.cs +++ b/modules/permission-management/src/Volo.Abp.PermissionManagement.Application/Volo/Abp/PermissionManagement/PermissionAppService.cs @@ -6,6 +6,7 @@ using Microsoft.AspNetCore.Authorization; using Microsoft.Extensions.Options; using Volo.Abp.Application.Services; using Volo.Abp.Authorization.Permissions; +using Volo.Abp.Localization; using Volo.Abp.MultiTenancy; using Volo.Abp.SimpleStateChecking; @@ -43,14 +44,9 @@ public class PermissionAppService : ApplicationService, IPermissionAppService var multiTenancySide = CurrentTenant.GetMultiTenancySide(); - foreach (var group in PermissionDefinitionManager.GetGroups()) + foreach (var group in await PermissionDefinitionManager.GetGroupsAsync()) { - var groupDto = new PermissionGroupDto - { - Name = group.Name, - DisplayName = group.DisplayName.Localize(StringLocalizerFactory), - Permissions = new List() - }; + var groupDto = CreatePermissionGroupDto(group); var neededCheckPermissions = new List(); @@ -70,14 +66,9 @@ public class PermissionAppService : ApplicationService, IPermissionAppService continue; } - var grantInfoDtos = neededCheckPermissions.Select(x => new PermissionGrantInfoDto - { - Name = x.Name, - DisplayName = x.DisplayName.Localize(StringLocalizerFactory), - ParentName = x.Parent?.Name, - AllowedProviders = x.Providers, - GrantedProviders = new List() - }).ToList(); + var grantInfoDtos = neededCheckPermissions + .Select(CreatePermissionGrantInfoDto) + .ToList(); var multipleGrantInfo = await PermissionManager.GetAsync(neededCheckPermissions.Select(x => x.Name).ToArray(), providerName, providerKey); @@ -108,6 +99,39 @@ public class PermissionAppService : ApplicationService, IPermissionAppService return result; } + private PermissionGrantInfoDto CreatePermissionGrantInfoDto(PermissionDefinition permission) + { + var localizableDisplayName = permission.DisplayName as LocalizableString; + + return new PermissionGrantInfoDto { + Name = permission.Name, + DisplayName = permission.DisplayName.Localize(StringLocalizerFactory), + DisplayNameKey = localizableDisplayName?.Name, + DisplayNameResource = localizableDisplayName?.ResourceType != null + ? LocalizationResourceNameAttribute.GetName(localizableDisplayName.ResourceType) + : null, + ParentName = permission.Parent?.Name, + AllowedProviders = permission.Providers, + GrantedProviders = new List() + }; + } + + private PermissionGroupDto CreatePermissionGroupDto(PermissionGroupDefinition group) + { + var localizableDisplayName = group.DisplayName as LocalizableString; + + return new PermissionGroupDto + { + Name = group.Name, + DisplayName = group.DisplayName.Localize(StringLocalizerFactory), + DisplayNameKey = localizableDisplayName?.Name, + DisplayNameResource = localizableDisplayName?.ResourceType != null + ? LocalizationResourceNameAttribute.GetName(localizableDisplayName.ResourceType) + : null, + Permissions = new List() + }; + } + public virtual async Task UpdateAsync(string providerName, string providerKey, UpdatePermissionsDto input) { await CheckProviderPolicy(providerName); diff --git a/modules/permission-management/src/Volo.Abp.PermissionManagement.Blazor/Components/PermissionManagementModal.razor.cs b/modules/permission-management/src/Volo.Abp.PermissionManagement.Blazor/Components/PermissionManagementModal.razor.cs index b477de008d..36358c1b95 100644 --- a/modules/permission-management/src/Volo.Abp.PermissionManagement.Blazor/Components/PermissionManagementModal.razor.cs +++ b/modules/permission-management/src/Volo.Abp.PermissionManagement.Blazor/Components/PermissionManagementModal.razor.cs @@ -4,7 +4,9 @@ using System.Linq; using System.Threading.Tasks; using Blazorise; using Microsoft.AspNetCore.Components; +using Microsoft.Extensions.Options; using Volo.Abp.AspNetCore.Components.Web.Configuration; +using Volo.Abp.Localization; using Volo.Abp.PermissionManagement.Localization; namespace Volo.Abp.PermissionManagement.Blazor.Components; @@ -14,6 +16,8 @@ public partial class PermissionManagementModal [Inject] protected IPermissionAppService PermissionAppService { get; set; } [Inject] protected ICurrentApplicationConfigurationCacheResetService CurrentApplicationConfigurationCacheResetService { get; set; } + [Inject] protected IOptions LocalizationOptions { get; set; } + protected Modal _modal; protected string _providerName; @@ -80,6 +84,8 @@ public partial class PermissionManagementModal var result = await PermissionAppService.GetAsync(_providerName, _providerKey); + UpdateLocalizations(result); + _entityDisplayName = entityDisplayName ?? result.EntityDisplayName; _groups = result.Groups; @@ -246,4 +252,47 @@ public partial class PermissionManagementModal eventArgs.Cancel = eventArgs.CloseReason == CloseReason.FocusLostClosing; return Task.CompletedTask; } + + protected virtual void UpdateLocalizations(GetPermissionListResultDto result) + { + foreach (var group in result.Groups) + { + group.DisplayName = Localize( + group.DisplayNameKey, + group.DisplayNameResource, + group.DisplayName + ); + + foreach (var permission in group.Permissions) + { + permission.DisplayName = Localize( + permission.DisplayNameKey, + permission.DisplayNameResource, + permission.DisplayName + ); + } + } + } + + protected virtual string Localize(string key, string resourceName, string fallbackValue) + { + if (key.IsNullOrEmpty() || resourceName.IsNullOrEmpty()) + { + return fallbackValue; + } + + var resource = LocalizationOptions.Value.Resources.GetOrNull(resourceName); + if (resource == null) + { + return fallbackValue; + } + + var result = new LocalizableString(resource.ResourceType, key).Localize(StringLocalizerFactory); + if (result.ResourceNotFound) + { + return fallbackValue; + } + + return result.Value; + } } diff --git a/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain.Shared/Volo/Abp/PermissionManagement/PermissionDefinitionRecordConsts.cs b/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain.Shared/Volo/Abp/PermissionManagement/PermissionDefinitionRecordConsts.cs new file mode 100644 index 0000000000..93b1b465c6 --- /dev/null +++ b/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain.Shared/Volo/Abp/PermissionManagement/PermissionDefinitionRecordConsts.cs @@ -0,0 +1,15 @@ +namespace Volo.Abp.PermissionManagement; + +public class PermissionDefinitionRecordConsts +{ + /// + /// Default value: 128 + /// + public static int MaxNameLength { get; set; } = 128; + + public static int MaxDisplayNameLength { get; set; } = 256; + + public static int MaxProvidersLength { get; set; } = 128; + + public static int MaxStateCheckersLength { get; set; } = 256; +} \ No newline at end of file diff --git a/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain.Shared/Volo/Abp/PermissionManagement/PermissionGrantConsts.cs b/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain.Shared/Volo/Abp/PermissionManagement/PermissionGrantConsts.cs index 38a17340c5..630f5dc72e 100644 --- a/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain.Shared/Volo/Abp/PermissionManagement/PermissionGrantConsts.cs +++ b/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain.Shared/Volo/Abp/PermissionManagement/PermissionGrantConsts.cs @@ -2,11 +2,6 @@ public static class PermissionGrantConsts { - /// - /// Default value: 128 - /// - public static int MaxNameLength { get; set; } = 128; - /// /// Default value: 64 /// diff --git a/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain.Shared/Volo/Abp/PermissionManagement/PermissionGroupDefinitionRecordConsts.cs b/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain.Shared/Volo/Abp/PermissionManagement/PermissionGroupDefinitionRecordConsts.cs new file mode 100644 index 0000000000..fb26c075b8 --- /dev/null +++ b/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain.Shared/Volo/Abp/PermissionManagement/PermissionGroupDefinitionRecordConsts.cs @@ -0,0 +1,11 @@ +namespace Volo.Abp.PermissionManagement; + +public class PermissionGroupDefinitionRecordConsts +{ + /// + /// Default value: 128 + /// + public static int MaxNameLength { get; set; } = 128; + + public static int MaxDisplayNameLength { get; set; } = 256; +} \ No newline at end of file diff --git a/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo.Abp.PermissionManagement.Domain.csproj b/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo.Abp.PermissionManagement.Domain.csproj index d9cc5a058f..f9eb16d965 100644 --- a/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo.Abp.PermissionManagement.Domain.csproj +++ b/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo.Abp.PermissionManagement.Domain.csproj @@ -23,4 +23,8 @@ + + + + diff --git a/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/AbpPermissionManagementDomainModule.cs b/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/AbpPermissionManagementDomainModule.cs index 6dff7bf663..1e05590176 100644 --- a/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/AbpPermissionManagementDomainModule.cs +++ b/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/AbpPermissionManagementDomainModule.cs @@ -1,11 +1,19 @@ -using System.Collections.Generic; +using System; +using System.Threading; +using System.Threading.Tasks; using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Hosting; +using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; +using Polly; using Volo.Abp.Authorization; +using Volo.Abp.Authorization.Permissions; using Volo.Abp.Caching; +using Volo.Abp.DependencyInjection; using Volo.Abp.Domain; using Volo.Abp.Json; using Volo.Abp.Modularity; +using Volo.Abp.Threading; namespace Volo.Abp.PermissionManagement; @@ -16,5 +24,124 @@ namespace Volo.Abp.PermissionManagement; [DependsOn(typeof(AbpJsonModule))] public class AbpPermissionManagementDomainModule : AbpModule { + private readonly CancellationTokenSource _cancellationTokenSource = new(); + + public override Task OnApplicationInitializationAsync(ApplicationInitializationContext context) + { + InitializeDynamicPermissions(context); + return Task.CompletedTask; + } -} + public override Task OnApplicationShutdownAsync(ApplicationShutdownContext context) + { + _cancellationTokenSource.Cancel(); + return Task.CompletedTask; + } + + private void InitializeDynamicPermissions(ApplicationInitializationContext context) + { + var options = context + .ServiceProvider + .GetRequiredService>() + .Value; + + if (!options.SaveStaticPermissionsToDatabase && !options.IsDynamicPermissionStoreEnabled) + { + return; + } + + var rootServiceProvider = context.ServiceProvider.GetRequiredService(); + + Task.Run(async () => + { + using var scope = rootServiceProvider.CreateScope(); + var applicationLifetime = scope.ServiceProvider.GetService(); + var cancellationTokenProvider = scope.ServiceProvider.GetRequiredService(); + var cancellationToken = applicationLifetime?.ApplicationStopping ?? _cancellationTokenSource.Token; + + try + { + using (cancellationTokenProvider.Use(cancellationToken)) + { + if (cancellationTokenProvider.Token.IsCancellationRequested) + { + return; + } + + await SaveStaticPermissionsToDatabaseAsync(options, scope, cancellationTokenProvider); + + if (cancellationTokenProvider.Token.IsCancellationRequested) + { + return; + } + + await PreCacheDynamicPermissionsAsync(options, scope); + } + } + // ReSharper disable once EmptyGeneralCatchClause (No need to log since it is logged above) + catch { } + }); + } + + private async static Task SaveStaticPermissionsToDatabaseAsync( + PermissionManagementOptions options, + IServiceScope scope, + ICancellationTokenProvider cancellationTokenProvider) + { + if (!options.SaveStaticPermissionsToDatabase) + { + return; + } + + await Policy + .Handle() + .WaitAndRetryAsync(8, retryAttempt => TimeSpan.FromSeconds(Math.Pow(2, retryAttempt) * 10)) + .ExecuteAsync(async _ => + { + try + { + // ReSharper disable once AccessToDisposedClosure + await scope + .ServiceProvider + .GetRequiredService() + .SaveAsync(); + } + catch (Exception ex) + { + // ReSharper disable once AccessToDisposedClosure + scope.ServiceProvider + .GetService>()? + .LogException(ex); + + throw; // Polly will catch it + } + }, cancellationTokenProvider.Token); + } + + private async static Task PreCacheDynamicPermissionsAsync(PermissionManagementOptions options, IServiceScope scope) + { + if (!options.IsDynamicPermissionStoreEnabled) + { + return; + } + + try + { + // Pre-cache permissions, so first request doesn't wait + await scope + .ServiceProvider + .GetRequiredService() + .GetGroupsAsync(); + } + catch (Exception ex) + { + // ReSharper disable once AccessToDisposedClosure + scope + .ServiceProvider + .GetService>()? + .LogException(ex); + + throw; // It will be cached in InitializeDynamicPermissions + } + } +} \ No newline at end of file diff --git a/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/DynamicPermissionDefinitionStore.cs b/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/DynamicPermissionDefinitionStore.cs new file mode 100644 index 0000000000..f2e73cefc0 --- /dev/null +++ b/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/DynamicPermissionDefinitionStore.cs @@ -0,0 +1,171 @@ +using System; +using System.Collections.Generic; +using System.Collections.Immutable; +using System.Threading.Tasks; +using Microsoft.Extensions.Caching.Distributed; +using Microsoft.Extensions.Options; +using Volo.Abp.Authorization.Permissions; +using Volo.Abp.Caching; +using Volo.Abp.DependencyInjection; +using Volo.Abp.DistributedLocking; +using Volo.Abp.Threading; + +namespace Volo.Abp.PermissionManagement; + +[Dependency(ReplaceServices = true)] +public class DynamicPermissionDefinitionStore : IDynamicPermissionDefinitionStore, ITransientDependency +{ + protected IPermissionGroupDefinitionRecordRepository PermissionGroupRepository { get; } + protected IPermissionDefinitionRecordRepository PermissionRepository { get; } + protected IPermissionDefinitionSerializer PermissionDefinitionSerializer { get; } + protected IDynamicPermissionDefinitionStoreInMemoryCache StoreCache { get; } + protected IDistributedCache DistributedCache { get; } + protected IAbpDistributedLock DistributedLock { get; } + public PermissionManagementOptions PermissionManagementOptions { get; } + protected AbpDistributedCacheOptions CacheOptions { get; } + + public DynamicPermissionDefinitionStore( + IPermissionGroupDefinitionRecordRepository permissionGroupRepository, + IPermissionDefinitionRecordRepository permissionRepository, + IPermissionDefinitionSerializer permissionDefinitionSerializer, + IDynamicPermissionDefinitionStoreInMemoryCache storeCache, + IDistributedCache distributedCache, + IOptions cacheOptions, + IOptions permissionManagementOptions, + IAbpDistributedLock distributedLock) + { + PermissionGroupRepository = permissionGroupRepository; + PermissionRepository = permissionRepository; + PermissionDefinitionSerializer = permissionDefinitionSerializer; + StoreCache = storeCache; + DistributedCache = distributedCache; + DistributedLock = distributedLock; + PermissionManagementOptions = permissionManagementOptions.Value; + CacheOptions = cacheOptions.Value; + } + + public virtual async Task GetOrNullAsync(string name) + { + if (!PermissionManagementOptions.IsDynamicPermissionStoreEnabled) + { + return null; + } + + using (await StoreCache.SyncSemaphore.LockAsync()) + { + await EnsureCacheIsUptoDateAsync(); + return StoreCache.GetPermissionOrNull(name); + } + } + + public virtual async Task> GetPermissionsAsync() + { + if (!PermissionManagementOptions.IsDynamicPermissionStoreEnabled) + { + return Array.Empty(); + } + + using (await StoreCache.SyncSemaphore.LockAsync()) + { + await EnsureCacheIsUptoDateAsync(); + return StoreCache.GetPermissions().ToImmutableList(); + } + } + + public virtual async Task> GetGroupsAsync() + { + if (!PermissionManagementOptions.IsDynamicPermissionStoreEnabled) + { + return Array.Empty(); + } + + using (await StoreCache.SyncSemaphore.LockAsync()) + { + await EnsureCacheIsUptoDateAsync(); + return StoreCache.GetGroups().ToImmutableList(); + } + } + + protected virtual async Task EnsureCacheIsUptoDateAsync() + { + if (StoreCache.LastCheckTime.HasValue && + DateTime.Now.Subtract(StoreCache.LastCheckTime.Value).TotalSeconds < 30) + { + /* We get the latest permission with a small delay for optimization */ + return; + } + + var stampInDistributedCache = await GetOrSetStampInDistributedCache(); + + if (stampInDistributedCache == StoreCache.CacheStamp) + { + StoreCache.LastCheckTime = DateTime.Now; + return; + } + + await UpdateInMemoryStoreCache(); + + StoreCache.CacheStamp = stampInDistributedCache; + StoreCache.LastCheckTime = DateTime.Now; + } + + protected virtual async Task UpdateInMemoryStoreCache() + { + var permissionGroupRecords = await PermissionGroupRepository.GetListAsync(); + var permissionRecords = await PermissionRepository.GetListAsync(); + + await StoreCache.FillAsync(permissionGroupRecords, permissionRecords); + } + + protected virtual async Task GetOrSetStampInDistributedCache() + { + var cacheKey = GetCommonStampCacheKey(); + + var stampInDistributedCache = await DistributedCache.GetStringAsync(cacheKey); + if (stampInDistributedCache != null) + { + return stampInDistributedCache; + } + + await using (var commonLockHandle = await DistributedLock + .TryAcquireAsync(GetCommonDistributedLockKey(), TimeSpan.FromMinutes(2))) + { + if (commonLockHandle == null) + { + /* This request will fail */ + throw new AbpException( + "Could not acquire distributed lock for permission definition common stamp check!" + ); + } + + stampInDistributedCache = await DistributedCache.GetStringAsync(cacheKey); + if (stampInDistributedCache != null) + { + return stampInDistributedCache; + } + + stampInDistributedCache = Guid.NewGuid().ToString(); + + await DistributedCache.SetStringAsync( + cacheKey, + stampInDistributedCache, + new DistributedCacheEntryOptions + { + SlidingExpiration = TimeSpan.FromDays(30) //TODO: Make it configurable? + } + ); + } + + return stampInDistributedCache; + } + + protected virtual string GetCommonStampCacheKey() + { + return $"{CacheOptions.KeyPrefix}_AbpInMemoryPermissionCacheStamp"; + } + + protected virtual string GetCommonDistributedLockKey() + { + return $"{CacheOptions.KeyPrefix}_Common_AbpPermissionUpdateLock"; + } +} \ No newline at end of file diff --git a/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/DynamicPermissionDefinitionStoreInMemoryCache.cs b/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/DynamicPermissionDefinitionStoreInMemoryCache.cs new file mode 100644 index 0000000000..3b09c922dc --- /dev/null +++ b/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/DynamicPermissionDefinitionStoreInMemoryCache.cs @@ -0,0 +1,127 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading; +using System.Threading.Tasks; +using Volo.Abp.Authorization.Permissions; +using Volo.Abp.DependencyInjection; +using Volo.Abp.Localization; +using Volo.Abp.SimpleStateChecking; + +namespace Volo.Abp.PermissionManagement; + +public class DynamicPermissionDefinitionStoreInMemoryCache : + IDynamicPermissionDefinitionStoreInMemoryCache, + ISingletonDependency +{ + public string CacheStamp { get; set; } + + protected IDictionary PermissionGroupDefinitions { get; } + protected IDictionary PermissionDefinitions { get; } + protected ISimpleStateCheckerSerializer StateCheckerSerializer { get; } + protected ILocalizableStringSerializer LocalizableStringSerializer { get; } + + public SemaphoreSlim SyncSemaphore { get; } = new(1, 1); + + public DateTime? LastCheckTime { get; set; } + + public DynamicPermissionDefinitionStoreInMemoryCache( + ISimpleStateCheckerSerializer stateCheckerSerializer, + ILocalizableStringSerializer localizableStringSerializer) + { + StateCheckerSerializer = stateCheckerSerializer; + LocalizableStringSerializer = localizableStringSerializer; + + PermissionGroupDefinitions = new Dictionary(); + PermissionDefinitions = new Dictionary(); + } + + public Task FillAsync( + List permissionGroupRecords, + List permissionRecords) + { + PermissionGroupDefinitions.Clear(); + PermissionDefinitions.Clear(); + + var context = new PermissionDefinitionContext(null); + + foreach (var permissionGroupRecord in permissionGroupRecords) + { + var permissionGroup = context.AddGroup( + permissionGroupRecord.Name, + LocalizableStringSerializer.Deserialize(permissionGroupRecord.DisplayName) + ); + + PermissionGroupDefinitions[permissionGroup.Name] = permissionGroup; + + foreach (var property in permissionGroupRecord.ExtraProperties) + { + permissionGroup[property.Key] = property.Value; + } + + var permissionRecordsInThisGroup = permissionRecords + .Where(p => p.GroupName == permissionGroup.Name); + + foreach (var permissionRecord in permissionRecordsInThisGroup.Where(x => x.ParentName == null)) + { + AddPermissionRecursively(permissionGroup, permissionRecord, permissionRecords); + } + } + + return Task.CompletedTask; + } + + public PermissionDefinition GetPermissionOrNull(string name) + { + return PermissionDefinitions.GetOrDefault(name); + } + + public IReadOnlyList GetPermissions() + { + return PermissionDefinitions.Values.ToList(); + } + + public IReadOnlyList GetGroups() + { + return PermissionGroupDefinitions.Values.ToList(); + } + + private void AddPermissionRecursively(ICanAddChildPermission permissionContainer, + PermissionDefinitionRecord permissionRecord, + List allPermissionRecords) + { + var permission = permissionContainer.AddPermission( + permissionRecord.Name, + LocalizableStringSerializer.Deserialize(permissionRecord.DisplayName), + permissionRecord.MultiTenancySide, + permissionRecord.IsEnabled + ); + + PermissionDefinitions[permission.Name] = permission; + + if (!permissionRecord.Providers.IsNullOrWhiteSpace()) + { + permission.Providers.AddRange(permissionRecord.Providers.Split(',')); + } + + if (!permissionRecord.StateCheckers.IsNullOrWhiteSpace()) + { + var checkers = StateCheckerSerializer + .DeserializeArray( + permissionRecord.StateCheckers, + permission + ); + permission.StateCheckers.AddRange(checkers); + } + + foreach (var property in permissionRecord.ExtraProperties) + { + permission[property.Key] = property.Value; + } + + foreach (var subPermission in allPermissionRecords.Where(p => p.ParentName == permissionRecord.Name)) + { + AddPermissionRecursively(permission, subPermission, allPermissionRecords); + } + } +} \ No newline at end of file diff --git a/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/IDynamicPermissionDefinitionStoreInMemoryCache.cs b/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/IDynamicPermissionDefinitionStoreInMemoryCache.cs new file mode 100644 index 0000000000..2dab588ebd --- /dev/null +++ b/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/IDynamicPermissionDefinitionStoreInMemoryCache.cs @@ -0,0 +1,26 @@ +using System; +using System.Collections.Generic; +using System.Threading; +using System.Threading.Tasks; +using Volo.Abp.Authorization.Permissions; + +namespace Volo.Abp.PermissionManagement; + +public interface IDynamicPermissionDefinitionStoreInMemoryCache +{ + string CacheStamp { get; set; } + + SemaphoreSlim SyncSemaphore { get; } + + DateTime? LastCheckTime { get; set; } + + Task FillAsync( + List permissionGroupRecords, + List permissionRecords); + + PermissionDefinition GetPermissionOrNull(string name); + + IReadOnlyList GetPermissions(); + + IReadOnlyList GetGroups(); +} \ No newline at end of file diff --git a/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/IPermissionDefinitionRecordRepository.cs b/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/IPermissionDefinitionRecordRepository.cs new file mode 100644 index 0000000000..e332d8483d --- /dev/null +++ b/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/IPermissionDefinitionRecordRepository.cs @@ -0,0 +1,13 @@ +using System; +using System.Threading; +using System.Threading.Tasks; +using Volo.Abp.Domain.Repositories; + +namespace Volo.Abp.PermissionManagement; + +public interface IPermissionDefinitionRecordRepository : IBasicRepository +{ + Task FindByNameAsync( + string name, + CancellationToken cancellationToken = default); +} \ No newline at end of file diff --git a/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/IPermissionDefinitionSerializer.cs b/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/IPermissionDefinitionSerializer.cs new file mode 100644 index 0000000000..8ed09a4380 --- /dev/null +++ b/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/IPermissionDefinitionSerializer.cs @@ -0,0 +1,19 @@ +using System.Collections.Generic; +using System.Threading.Tasks; +using JetBrains.Annotations; +using Volo.Abp.Authorization.Permissions; + +namespace Volo.Abp.PermissionManagement; + +public interface IPermissionDefinitionSerializer +{ + Task<(PermissionGroupDefinitionRecord[], PermissionDefinitionRecord[])> + SerializeAsync(IEnumerable permissionGroups); + + Task SerializeAsync( + PermissionGroupDefinition permissionGroup); + + Task SerializeAsync( + PermissionDefinition permission, + [CanBeNull] PermissionGroupDefinition permissionGroup); +} \ No newline at end of file diff --git a/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/IPermissionGroupDefinitionRecordRepository.cs b/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/IPermissionGroupDefinitionRecordRepository.cs new file mode 100644 index 0000000000..984adbe72d --- /dev/null +++ b/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/IPermissionGroupDefinitionRecordRepository.cs @@ -0,0 +1,9 @@ +using System; +using Volo.Abp.Domain.Repositories; + +namespace Volo.Abp.PermissionManagement; + +public interface IPermissionGroupDefinitionRecordRepository : IBasicRepository +{ + +} \ No newline at end of file diff --git a/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/IStaticPermissionSaver.cs b/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/IStaticPermissionSaver.cs new file mode 100644 index 0000000000..5c91636c3d --- /dev/null +++ b/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/IStaticPermissionSaver.cs @@ -0,0 +1,8 @@ +using System.Threading.Tasks; + +namespace Volo.Abp.PermissionManagement; + +public interface IStaticPermissionSaver +{ + Task SaveAsync(); +} \ No newline at end of file diff --git a/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/PermissionDataSeedContributor.cs b/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/PermissionDataSeedContributor.cs index d0a98eb593..71570aafce 100644 --- a/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/PermissionDataSeedContributor.cs +++ b/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/PermissionDataSeedContributor.cs @@ -23,17 +23,16 @@ public class PermissionDataSeedContributor : IDataSeedContributor, ITransientDep CurrentTenant = currentTenant; } - public virtual Task SeedAsync(DataSeedContext context) + public virtual async Task SeedAsync(DataSeedContext context) { var multiTenancySide = CurrentTenant.GetMultiTenancySide(); - var permissionNames = PermissionDefinitionManager - .GetPermissions() + var permissionNames = (await PermissionDefinitionManager.GetPermissionsAsync()) .Where(p => p.MultiTenancySide.HasFlag(multiTenancySide)) .Where(p => !p.Providers.Any() || p.Providers.Contains(RolePermissionValueProvider.ProviderName)) .Select(p => p.Name) .ToArray(); - return PermissionDataSeeder.SeedAsync( + await PermissionDataSeeder.SeedAsync( RolePermissionValueProvider.ProviderName, "admin", permissionNames, diff --git a/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/PermissionDefinitionRecord.cs b/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/PermissionDefinitionRecord.cs new file mode 100644 index 0000000000..2ba9ffa26a --- /dev/null +++ b/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/PermissionDefinitionRecord.cs @@ -0,0 +1,175 @@ +using System; +using System.Text.Json.Serialization; +using Volo.Abp.Data; +using Volo.Abp.Domain.Entities; +using Volo.Abp.MultiTenancy; + +namespace Volo.Abp.PermissionManagement; + +public class PermissionDefinitionRecord : BasicAggregateRoot, IHasExtraProperties +{ + /* Ignoring Id because it is different whenever we create an instance of + * this class, and we are using Json Serialize, than Hash to understand + * if permission definitions have changed (in StaticPermissionSaver.CalculateHash()). + */ + [JsonIgnore] + public override Guid Id { get; protected set; } + + public string GroupName { get; set; } + + public string Name { get; set; } + + public string ParentName { get; set; } + + public string DisplayName { get; set; } + + public bool IsEnabled { get; set; } + + public MultiTenancySides MultiTenancySide { get; set; } + + /// + /// Comma separated list of provider names. + /// + public string Providers { get; set; } + + /// + /// Serialized string to store info about the state checkers. + /// + public string StateCheckers { get; set; } + + public ExtraPropertyDictionary ExtraProperties { get; protected set; } + + public PermissionDefinitionRecord() + { + ExtraProperties = new ExtraPropertyDictionary(); + this.SetDefaultsForExtraProperties(); + } + + public PermissionDefinitionRecord( + Guid id, + string groupName, + string name, + string parentName, + string displayName, + bool isEnabled = true, + MultiTenancySides multiTenancySide = MultiTenancySides.Both, + string providers = null, + string stateCheckers = null) + : base(id) + { + GroupName = Check.NotNullOrWhiteSpace(groupName, nameof(groupName), PermissionGroupDefinitionRecordConsts.MaxNameLength); + Name = Check.NotNullOrWhiteSpace(name, nameof(name), PermissionDefinitionRecordConsts.MaxNameLength); + ParentName = Check.Length(parentName, nameof(parentName), PermissionDefinitionRecordConsts.MaxNameLength); + DisplayName = Check.NotNullOrWhiteSpace(displayName, nameof(displayName), PermissionDefinitionRecordConsts.MaxDisplayNameLength); + IsEnabled = isEnabled; + MultiTenancySide = multiTenancySide; + Providers = providers; + StateCheckers = stateCheckers; + + ExtraProperties = new ExtraPropertyDictionary(); + this.SetDefaultsForExtraProperties(); + } + + public bool HasSameData(PermissionDefinitionRecord otherRecord) + { + if (Name != otherRecord.Name) + { + return false; + } + + if (GroupName != otherRecord.GroupName) + { + return false; + } + + if (ParentName != otherRecord.ParentName) + { + return false; + } + + if (DisplayName != otherRecord.DisplayName) + { + return false; + } + + if (IsEnabled != otherRecord.IsEnabled) + { + return false; + } + + if (MultiTenancySide != otherRecord.MultiTenancySide) + { + return false; + } + + if (Providers != otherRecord.Providers) + { + return false; + } + + if (StateCheckers != otherRecord.StateCheckers) + { + return false; + } + + if (!this.HasSameExtraProperties(otherRecord)) + { + return false; + } + + return true; + } + + public void Patch(PermissionDefinitionRecord otherRecord) + { + if (Name != otherRecord.Name) + { + Name = otherRecord.Name; + } + + if (GroupName != otherRecord.GroupName) + { + GroupName = otherRecord.GroupName; + } + + if (ParentName != otherRecord.ParentName) + { + ParentName = otherRecord.ParentName; + } + + if (DisplayName != otherRecord.DisplayName) + { + DisplayName = otherRecord.DisplayName; + } + + if (IsEnabled != otherRecord.IsEnabled) + { + IsEnabled = otherRecord.IsEnabled; + } + + if (MultiTenancySide != otherRecord.MultiTenancySide) + { + MultiTenancySide = otherRecord.MultiTenancySide; + } + + if (Providers != otherRecord.Providers) + { + Providers = otherRecord.Providers; + } + + if (StateCheckers != otherRecord.StateCheckers) + { + StateCheckers = otherRecord.StateCheckers; + } + + if (!this.HasSameExtraProperties(otherRecord)) + { + this.ExtraProperties.Clear(); + + foreach (var property in otherRecord.ExtraProperties) + { + this.ExtraProperties.Add(property.Key, property.Value); + } + } + } +} \ No newline at end of file diff --git a/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/PermissionDefinitionSerializer.cs b/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/PermissionDefinitionSerializer.cs new file mode 100644 index 0000000000..8e63342502 --- /dev/null +++ b/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/PermissionDefinitionSerializer.cs @@ -0,0 +1,106 @@ +using System.Collections.Generic; +using System.Globalization; +using System.Linq; +using System.Threading.Tasks; +using Volo.Abp.Authorization.Permissions; +using Volo.Abp.Data; +using Volo.Abp.DependencyInjection; +using Volo.Abp.Guids; +using Volo.Abp.Localization; +using Volo.Abp.SimpleStateChecking; + +namespace Volo.Abp.PermissionManagement; + +public class PermissionDefinitionSerializer : IPermissionDefinitionSerializer, ITransientDependency +{ + protected ISimpleStateCheckerSerializer StateCheckerSerializer { get; } + protected IGuidGenerator GuidGenerator { get; } + protected ILocalizableStringSerializer LocalizableStringSerializer { get; } + + public PermissionDefinitionSerializer( + IGuidGenerator guidGenerator, + ISimpleStateCheckerSerializer stateCheckerSerializer, + ILocalizableStringSerializer localizableStringSerializer) + { + StateCheckerSerializer = stateCheckerSerializer; + LocalizableStringSerializer = localizableStringSerializer; + GuidGenerator = guidGenerator; + } + + public async Task<(PermissionGroupDefinitionRecord[], PermissionDefinitionRecord[])> + SerializeAsync(IEnumerable permissionGroups) + { + var permissionGroupRecords = new List(); + var permissionRecords = new List(); + + foreach (var permissionGroup in permissionGroups) + { + permissionGroupRecords.Add(await SerializeAsync(permissionGroup)); + + foreach (var permission in permissionGroup.GetPermissionsWithChildren()) + { + permissionRecords.Add(await SerializeAsync(permission, permissionGroup)); + } + } + + return (permissionGroupRecords.ToArray(), permissionRecords.ToArray()); + } + + public Task SerializeAsync(PermissionGroupDefinition permissionGroup) + { + using (CultureHelper.Use(CultureInfo.InvariantCulture)) + { + var permissionGroupRecord = new PermissionGroupDefinitionRecord( + GuidGenerator.Create(), + permissionGroup.Name, + LocalizableStringSerializer.Serialize(permissionGroup.DisplayName) + ); + + foreach (var property in permissionGroup.Properties) + { + permissionGroupRecord.SetProperty(property.Key, property.Value); + } + + return Task.FromResult(permissionGroupRecord); + } + } + + public Task SerializeAsync( + PermissionDefinition permission, + PermissionGroupDefinition permissionGroup) + { + using (CultureHelper.Use(CultureInfo.InvariantCulture)) + { + var permissionRecord = new PermissionDefinitionRecord( + GuidGenerator.Create(), + permissionGroup?.Name, + permission.Name, + permission.Parent?.Name, + LocalizableStringSerializer.Serialize(permission.DisplayName), + permission.IsEnabled, + permission.MultiTenancySide, + SerializeProviders(permission.Providers), + SerializeStateCheckers(permission.StateCheckers) + ); + + foreach (var property in permission.Properties) + { + permissionRecord.SetProperty(property.Key, property.Value); + } + + return Task.FromResult(permissionRecord); + } + } + + protected virtual string SerializeProviders(ICollection providers) + { + return providers.Any() + ? providers.JoinAsString(",") + : null; + } + + protected virtual string SerializeStateCheckers(List> stateCheckers) + { + return StateCheckerSerializer.Serialize(stateCheckers); + } +} \ No newline at end of file diff --git a/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/PermissionGroupDefinitionRecord.cs b/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/PermissionGroupDefinitionRecord.cs new file mode 100644 index 0000000000..f93bf57e21 --- /dev/null +++ b/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/PermissionGroupDefinitionRecord.cs @@ -0,0 +1,84 @@ +using System; +using System.Text.Json.Serialization; +using Volo.Abp.Data; +using Volo.Abp.Domain.Entities; + +namespace Volo.Abp.PermissionManagement; + +public class PermissionGroupDefinitionRecord : BasicAggregateRoot, IHasExtraProperties +{ + /* Ignoring Id because it is different whenever we create an instance of + * this class, and we are using Json Serialize, than Hash to understand + * if permission definitions have changed (in StaticPermissionSaver.CalculateHash()). + */ + [JsonIgnore] + public override Guid Id { get; protected set; } + + public string Name { get; set; } + + public string DisplayName { get; set; } + + public ExtraPropertyDictionary ExtraProperties { get; protected set; } + + public PermissionGroupDefinitionRecord() + { + ExtraProperties = new ExtraPropertyDictionary(); + this.SetDefaultsForExtraProperties(); + } + + public PermissionGroupDefinitionRecord( + Guid id, + string name, + string displayName) + : base(id) + { + Name = Check.NotNullOrWhiteSpace(name, nameof(name), PermissionGroupDefinitionRecordConsts.MaxNameLength); + DisplayName = Check.NotNullOrWhiteSpace(displayName, nameof(displayName), PermissionGroupDefinitionRecordConsts.MaxDisplayNameLength);; + + ExtraProperties = new ExtraPropertyDictionary(); + this.SetDefaultsForExtraProperties(); + } + + public bool HasSameData(PermissionGroupDefinitionRecord otherRecord) + { + if (Name != otherRecord.Name) + { + return false; + } + + if (DisplayName != otherRecord.DisplayName) + { + return false; + } + + if (!this.HasSameExtraProperties(otherRecord)) + { + return false; + } + + return true; + } + + public void Patch(PermissionGroupDefinitionRecord otherRecord) + { + if (Name != otherRecord.Name) + { + Name = otherRecord.Name; + } + + if (DisplayName != otherRecord.DisplayName) + { + DisplayName = otherRecord.DisplayName; + } + + if (!this.HasSameExtraProperties(otherRecord)) + { + this.ExtraProperties.Clear(); + + foreach (var property in otherRecord.ExtraProperties) + { + this.ExtraProperties.Add(property.Key, property.Value); + } + } + } +} \ No newline at end of file diff --git a/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/PermissionManagementOptions.cs b/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/PermissionManagementOptions.cs index 15da755a33..2109941a27 100644 --- a/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/PermissionManagementOptions.cs +++ b/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/PermissionManagementOptions.cs @@ -8,10 +8,27 @@ public class PermissionManagementOptions public ITypeList ManagementProviders { get; } public Dictionary ProviderPolicies { get; } + + public HashSet DeletedPermissions { get; } + + public HashSet DeletedPermissionGroups { get; } + + /// + /// Default: true. + /// + public bool SaveStaticPermissionsToDatabase { get; set; } = true; + + /// + /// Default: false. + /// + public bool IsDynamicPermissionStoreEnabled { get; set; } public PermissionManagementOptions() { ManagementProviders = new TypeList(); ProviderPolicies = new Dictionary(); + + DeletedPermissions = new HashSet(); + DeletedPermissionGroups = new HashSet(); } } diff --git a/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/PermissionManager.cs b/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/PermissionManager.cs index 2e709c49c2..b664e5c92d 100644 --- a/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/PermissionManager.cs +++ b/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/PermissionManager.cs @@ -62,18 +62,62 @@ public class PermissionManager : IPermissionManager, ISingletonDependency public virtual async Task GetAsync(string permissionName, string providerName, string providerKey) { - return await GetInternalAsync(PermissionDefinitionManager.Get(permissionName), providerName, providerKey); + var permission = await PermissionDefinitionManager.GetOrNullAsync(permissionName); + if (permission == null) + { + return new PermissionWithGrantedProviders(permissionName, false); + } + + return await GetInternalAsync( + permission, + providerName, + providerKey + ); } - public virtual async Task GetAsync(string[] permissionNames, string providerName, string providerKey) + public virtual async Task GetAsync( + string[] permissionNames, + string providerName, + string providerKey) { - var permissionDefinitions = permissionNames.Select(x => PermissionDefinitionManager.Get(x)).ToArray(); - return await GetInternalAsync(permissionDefinitions, providerName, providerKey); + var permissions = new List(); + var undefinedPermissions = new List(); + + foreach (var permissionName in permissionNames) + { + var permission = await PermissionDefinitionManager.GetOrNullAsync(permissionName); + if (permission != null) + { + permissions.Add(permission); + } + else + { + undefinedPermissions.Add(permissionName); + } + } + + if (!permissions.Any()) + { + return new MultiplePermissionWithGrantedProviders(undefinedPermissions.ToArray()); + } + + var result = await GetInternalAsync( + permissions.ToArray(), + providerName, + providerKey + ); + + foreach (var undefinedPermission in undefinedPermissions) + { + result.Result.Add(new PermissionWithGrantedProviders(undefinedPermission, false)); + } + + return result; } public virtual async Task> GetAllAsync(string providerName, string providerKey) { - var permissionDefinitions = PermissionDefinitionManager.GetPermissions().ToArray(); + var permissionDefinitions = (await PermissionDefinitionManager.GetPermissionsAsync()).ToArray(); var multiplePermissionWithGrantedProviders = await GetInternalAsync(permissionDefinitions, providerName, providerKey); @@ -83,7 +127,13 @@ public class PermissionManager : IPermissionManager, ISingletonDependency public virtual async Task SetAsync(string permissionName, string providerName, string providerKey, bool isGranted) { - var permission = PermissionDefinitionManager.Get(permissionName); + var permission = await PermissionDefinitionManager.GetOrNullAsync(permissionName); + if (permission == null) + { + /* Silently ignore undefined permissions, + maybe they were removed from dynamic permission definition store */ + return; + } if (!permission.IsEnabled || !await SimpleStateCheckerManager.IsEnabledAsync(permission)) { @@ -146,14 +196,24 @@ public class PermissionManager : IPermissionManager, ISingletonDependency } } - protected virtual async Task GetInternalAsync(PermissionDefinition permission, string providerName, string providerKey) + protected virtual async Task GetInternalAsync( + PermissionDefinition permission, + string providerName, + string providerKey) { - var multiplePermissionWithGrantedProviders = await GetInternalAsync(new PermissionDefinition[] { permission }, providerName, providerKey); + var multiplePermissionWithGrantedProviders = await GetInternalAsync( + new[] { permission }, + providerName, + providerKey + ); return multiplePermissionWithGrantedProviders.Result.First(); } - protected virtual async Task GetInternalAsync(PermissionDefinition[] permissions, string providerName, string providerKey) + protected virtual async Task GetInternalAsync( + PermissionDefinition[] permissions, + string providerName, + string providerKey) { var permissionNames = permissions.Select(x => x.Name).ToArray(); var multiplePermissionWithGrantedProviders = new MultiplePermissionWithGrantedProviders(permissionNames); diff --git a/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/PermissionStore.cs b/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/PermissionStore.cs index 5dd4e14ed0..6eed394a31 100644 --- a/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/PermissionStore.cs +++ b/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/PermissionStore.cs @@ -67,7 +67,7 @@ public class PermissionStore : IPermissionStore, ITransientDependency string currentName, PermissionGrantCacheItem currentCacheItem) { - var permissions = PermissionDefinitionManager.GetPermissions(); + var permissions = await PermissionDefinitionManager.GetPermissionsAsync(); Logger.LogDebug($"Getting all granted permissions from the repository for this provider name,key: {providerName},{providerKey}"); @@ -169,7 +169,8 @@ public class PermissionStore : IPermissionStore, ITransientDependency string providerKey, List notCacheKeys) { - var permissions = PermissionDefinitionManager.GetPermissions().Where(x => notCacheKeys.Any(k => GetPermissionNameFormCacheKeyOrNull(k) == x.Name)).ToList(); + var permissions = (await PermissionDefinitionManager.GetPermissionsAsync()) + .Where(x => notCacheKeys.Any(k => GetPermissionNameFormCacheKeyOrNull(k) == x.Name)).ToList(); Logger.LogDebug($"Getting not cache granted permissions from the repository for this provider name,key: {providerName},{providerKey}"); diff --git a/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/StaticPermissionSaver.cs b/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/StaticPermissionSaver.cs new file mode 100644 index 0000000000..5754031509 --- /dev/null +++ b/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/StaticPermissionSaver.cs @@ -0,0 +1,294 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Text.Json; +using System.Threading.Tasks; +using Microsoft.Extensions.Caching.Distributed; +using Microsoft.Extensions.Options; +using Volo.Abp.Authorization.Permissions; +using Volo.Abp.Caching; +using Volo.Abp.DependencyInjection; +using Volo.Abp.DistributedLocking; +using Volo.Abp.Threading; +using Volo.Abp.Uow; + +namespace Volo.Abp.PermissionManagement; + +public class StaticPermissionSaver : IStaticPermissionSaver, ITransientDependency +{ + protected IStaticPermissionDefinitionStore StaticStore { get; } + protected IPermissionGroupDefinitionRecordRepository PermissionGroupRepository { get; } + protected IPermissionDefinitionRecordRepository PermissionRepository { get; } + protected IPermissionDefinitionSerializer PermissionSerializer { get; } + protected IDistributedCache Cache { get; } + protected IApplicationNameAccessor ApplicationNameAccessor { get; } + protected IAbpDistributedLock DistributedLock { get; } + protected PermissionManagementOptions PermissionManagementOptions { get; } + protected ICancellationTokenProvider CancellationTokenProvider { get; } + protected AbpDistributedCacheOptions CacheOptions { get; } + + public StaticPermissionSaver( + IStaticPermissionDefinitionStore staticStore, + IPermissionGroupDefinitionRecordRepository permissionGroupRepository, + IPermissionDefinitionRecordRepository permissionRepository, + IPermissionDefinitionSerializer permissionSerializer, + IDistributedCache cache, + IOptions cacheOptions, + IApplicationNameAccessor applicationNameAccessor, + IAbpDistributedLock distributedLock, + IOptions permissionManagementOptions, + ICancellationTokenProvider cancellationTokenProvider) + { + StaticStore = staticStore; + PermissionGroupRepository = permissionGroupRepository; + PermissionRepository = permissionRepository; + PermissionSerializer = permissionSerializer; + Cache = cache; + ApplicationNameAccessor = applicationNameAccessor; + DistributedLock = distributedLock; + CancellationTokenProvider = cancellationTokenProvider; + PermissionManagementOptions = permissionManagementOptions.Value; + CacheOptions = cacheOptions.Value; + } + + [UnitOfWork] + public virtual async Task SaveAsync() + { + await using var applicationLockHandle = await DistributedLock.TryAcquireAsync( + GetApplicationDistributedLockKey() + ); + + if (applicationLockHandle == null) + { + /* Another application instance is already doing it */ + return; + } + + /* NOTE: This can be further optimized by using 4 cache values for: + * Groups, permissions, deleted groups and deleted permissions. + * But the code would be more complex. This is enough for now. + */ + + var cacheKey = GetApplicationHashCacheKey(); + var cachedHash = await Cache.GetStringAsync(cacheKey, CancellationTokenProvider.Token); + + var (permissionGroupRecords, permissionRecords) = await PermissionSerializer.SerializeAsync( + await StaticStore.GetGroupsAsync() + ); + + var currentHash = CalculateHash( + permissionGroupRecords, + permissionRecords, + PermissionManagementOptions.DeletedPermissionGroups, + PermissionManagementOptions.DeletedPermissions + ); + + if (cachedHash == currentHash) + { + return; + } + + await using (var commonLockHandle = await DistributedLock.TryAcquireAsync( + GetCommonDistributedLockKey(), + TimeSpan.FromMinutes(5))) + { + if (commonLockHandle == null) + { + /* It will re-try */ + throw new AbpException("Could not acquire distributed lock for saving static permissions!"); + } + + var hasChangesInGroups = await UpdateChangedPermissionGroupsAsync(permissionGroupRecords); + var hasChangesInPermissions = await UpdateChangedPermissionsAsync(permissionRecords); + + if (hasChangesInGroups ||hasChangesInPermissions) + { + await Cache.SetStringAsync( + GetCommonStampCacheKey(), + Guid.NewGuid().ToString(), + new DistributedCacheEntryOptions { + SlidingExpiration = TimeSpan.FromDays(30) //TODO: Make it configurable? + }, + CancellationTokenProvider.Token + ); + } + } + + await Cache.SetStringAsync( + cacheKey, + currentHash, + new DistributedCacheEntryOptions { + SlidingExpiration = TimeSpan.FromDays(30) //TODO: Make it configurable? + }, + CancellationTokenProvider.Token + ); + } + + private async Task UpdateChangedPermissionGroupsAsync( + IEnumerable permissionGroupRecords) + { + var newRecords = new List(); + var changedRecords = new List(); + + var permissionGroupRecordsInDatabase = (await PermissionGroupRepository.GetListAsync()) + .ToDictionary(x => x.Name); + + foreach (var permissionGroupRecord in permissionGroupRecords) + { + var permissionGroupRecordInDatabase = permissionGroupRecordsInDatabase.GetOrDefault(permissionGroupRecord.Name); + if (permissionGroupRecordInDatabase == null) + { + /* New group */ + newRecords.Add(permissionGroupRecord); + continue; + } + + if (permissionGroupRecord.HasSameData(permissionGroupRecordInDatabase)) + { + /* Not changed */ + continue; + } + + /* Changed */ + permissionGroupRecordInDatabase.Patch(permissionGroupRecord); + changedRecords.Add(permissionGroupRecordInDatabase); + } + + /* Deleted */ + var deletedRecords = PermissionManagementOptions.DeletedPermissionGroups.Any() + ? permissionGroupRecordsInDatabase.Values + .Where(x => PermissionManagementOptions.DeletedPermissionGroups.Contains(x.Name)) + .ToArray() + : Array.Empty(); + + if (newRecords.Any()) + { + await PermissionGroupRepository.InsertManyAsync(newRecords); + } + + if (changedRecords.Any()) + { + await PermissionGroupRepository.UpdateManyAsync(changedRecords); + } + + if (deletedRecords.Any()) + { + await PermissionGroupRepository.DeleteManyAsync(deletedRecords); + } + + return newRecords.Any() || changedRecords.Any() || deletedRecords.Any(); + } + + private async Task UpdateChangedPermissionsAsync( + IEnumerable permissionRecords) + { + var newRecords = new List(); + var changedRecords = new List(); + + var permissionRecordsInDatabase = (await PermissionRepository.GetListAsync()) + .ToDictionary(x => x.Name); + + foreach (var permissionRecord in permissionRecords) + { + var permissionRecordInDatabase = permissionRecordsInDatabase.GetOrDefault(permissionRecord.Name); + if (permissionRecordInDatabase == null) + { + /* New group */ + newRecords.Add(permissionRecord); + continue; + } + + if (permissionRecord.HasSameData(permissionRecordInDatabase)) + { + /* Not changed */ + continue; + } + + /* Changed */ + permissionRecordInDatabase.Patch(permissionRecord); + changedRecords.Add(permissionRecordInDatabase); + } + + /* Deleted */ + var deletedRecords = new List(); + + if (PermissionManagementOptions.DeletedPermissions.Any()) + { + deletedRecords.AddRange( + permissionRecordsInDatabase.Values + .Where(x => PermissionManagementOptions.DeletedPermissions.Contains(x.Name)) + ); + } + + if (PermissionManagementOptions.DeletedPermissionGroups.Any()) + { + deletedRecords.AddIfNotContains( + permissionRecordsInDatabase.Values + .Where(x => PermissionManagementOptions.DeletedPermissionGroups.Contains(x.GroupName)) + ); + } + + if (newRecords.Any()) + { + await PermissionRepository.InsertManyAsync(newRecords); + } + + if (changedRecords.Any()) + { + await PermissionRepository.UpdateManyAsync(changedRecords); + } + + if (deletedRecords.Any()) + { + await PermissionRepository.DeleteManyAsync(deletedRecords); + } + + return newRecords.Any() || changedRecords.Any() || deletedRecords.Any(); + } + + private string GetApplicationDistributedLockKey() + { + return $"{CacheOptions.KeyPrefix}_{ApplicationNameAccessor.ApplicationName}_AbpPermissionUpdateLock"; + } + + private string GetCommonDistributedLockKey() + { + return $"{CacheOptions.KeyPrefix}_Common_AbpPermissionUpdateLock"; + } + + private string GetApplicationHashCacheKey() + { + return $"{CacheOptions.KeyPrefix}_{ApplicationNameAccessor.ApplicationName}_AbpPermissionsHash"; + } + + private string GetCommonStampCacheKey() + { + return $"{CacheOptions.KeyPrefix}_AbpInMemoryPermissionCacheStamp"; + } + + private static string CalculateHash( + PermissionGroupDefinitionRecord[] permissionGroupRecords, + PermissionDefinitionRecord[] permissionRecords, + IEnumerable deletedPermissionGroups, + IEnumerable deletedPermissions) + { + var stringBuilder = new StringBuilder(); + + stringBuilder.Append("PermissionGroupRecords:"); + stringBuilder.AppendLine(JsonSerializer.Serialize(permissionGroupRecords)); + + stringBuilder.Append("PermissionRecords:"); + stringBuilder.AppendLine(JsonSerializer.Serialize(permissionRecords)); + + stringBuilder.Append("DeletedPermissionGroups:"); + stringBuilder.AppendLine(deletedPermissionGroups.JoinAsString(",")); + + stringBuilder.Append("DeletedPermission:"); + stringBuilder.Append(deletedPermissions.JoinAsString(",")); + + return stringBuilder + .ToString() + .ToMd5(); + } +} \ No newline at end of file diff --git a/modules/permission-management/src/Volo.Abp.PermissionManagement.EntityFrameworkCore/Volo/Abp/PermissionManagement/EntityFrameworkCore/AbpPermissionManagementDbContextModelBuilderExtensions.cs b/modules/permission-management/src/Volo.Abp.PermissionManagement.EntityFrameworkCore/Volo/Abp/PermissionManagement/EntityFrameworkCore/AbpPermissionManagementDbContextModelBuilderExtensions.cs index bf9aa570a7..c901cbeb7f 100644 --- a/modules/permission-management/src/Volo.Abp.PermissionManagement.EntityFrameworkCore/Volo/Abp/PermissionManagement/EntityFrameworkCore/AbpPermissionManagementDbContextModelBuilderExtensions.cs +++ b/modules/permission-management/src/Volo.Abp.PermissionManagement.EntityFrameworkCore/Volo/Abp/PermissionManagement/EntityFrameworkCore/AbpPermissionManagementDbContextModelBuilderExtensions.cs @@ -1,5 +1,6 @@ using JetBrains.Annotations; using Microsoft.EntityFrameworkCore; +using Volo.Abp.Authorization.Permissions; using Volo.Abp.EntityFrameworkCore.Modeling; namespace Volo.Abp.PermissionManagement.EntityFrameworkCore; @@ -17,11 +18,44 @@ public static class AbpPermissionManagementDbContextModelBuilderExtensions b.ConfigureByConvention(); - b.Property(x => x.Name).HasMaxLength(PermissionGrantConsts.MaxNameLength).IsRequired(); + b.Property(x => x.Name).HasMaxLength(PermissionDefinitionRecordConsts.MaxNameLength).IsRequired(); b.Property(x => x.ProviderName).HasMaxLength(PermissionGrantConsts.MaxProviderNameLength).IsRequired(); b.Property(x => x.ProviderKey).HasMaxLength(PermissionGrantConsts.MaxProviderKeyLength).IsRequired(); - b.HasIndex(x => new { x.TenantId, x.Name, x.ProviderName, x.ProviderKey }).IsUnique(true); + b.HasIndex(x => new { x.TenantId, x.Name, x.ProviderName, x.ProviderKey }).IsUnique(); + + b.ApplyObjectExtensionMappings(); + }); + + builder.Entity(b => + { + b.ToTable(AbpPermissionManagementDbProperties.DbTablePrefix + "PermissionGroups", AbpPermissionManagementDbProperties.DbSchema); + + b.ConfigureByConvention(); + + b.Property(x => x.Name).HasMaxLength(PermissionGroupDefinitionRecordConsts.MaxNameLength).IsRequired(); + b.Property(x => x.DisplayName).HasMaxLength(PermissionGroupDefinitionRecordConsts.MaxDisplayNameLength).IsRequired(); + + b.HasIndex(x => new { x.Name }).IsUnique(); + + b.ApplyObjectExtensionMappings(); + }); + + builder.Entity(b => + { + b.ToTable(AbpPermissionManagementDbProperties.DbTablePrefix + "Permissions", AbpPermissionManagementDbProperties.DbSchema); + + b.ConfigureByConvention(); + + b.Property(x => x.GroupName).HasMaxLength(PermissionGroupDefinitionRecordConsts.MaxNameLength).IsRequired(); + b.Property(x => x.Name).HasMaxLength(PermissionDefinitionRecordConsts.MaxNameLength).IsRequired(); + b.Property(x => x.ParentName).HasMaxLength(PermissionDefinitionRecordConsts.MaxNameLength); + b.Property(x => x.DisplayName).HasMaxLength(PermissionDefinitionRecordConsts.MaxDisplayNameLength).IsRequired(); + b.Property(x => x.Providers).HasMaxLength(PermissionDefinitionRecordConsts.MaxProvidersLength); + b.Property(x => x.StateCheckers).HasMaxLength(PermissionDefinitionRecordConsts.MaxStateCheckersLength); + + b.HasIndex(x => new { x.Name }).IsUnique(); + b.HasIndex(x => new { x.GroupName }); b.ApplyObjectExtensionMappings(); }); diff --git a/modules/permission-management/src/Volo.Abp.PermissionManagement.EntityFrameworkCore/Volo/Abp/PermissionManagement/EntityFrameworkCore/AbpPermissionManagementEntityFrameworkCoreModule.cs b/modules/permission-management/src/Volo.Abp.PermissionManagement.EntityFrameworkCore/Volo/Abp/PermissionManagement/EntityFrameworkCore/AbpPermissionManagementEntityFrameworkCoreModule.cs index 6d7451c5e9..ebcc8527c1 100644 --- a/modules/permission-management/src/Volo.Abp.PermissionManagement.EntityFrameworkCore/Volo/Abp/PermissionManagement/EntityFrameworkCore/AbpPermissionManagementEntityFrameworkCoreModule.cs +++ b/modules/permission-management/src/Volo.Abp.PermissionManagement.EntityFrameworkCore/Volo/Abp/PermissionManagement/EntityFrameworkCore/AbpPermissionManagementEntityFrameworkCoreModule.cs @@ -14,6 +14,8 @@ public class AbpPermissionManagementEntityFrameworkCoreModule : AbpModule { options.AddDefaultRepositories(); + options.AddRepository(); + options.AddRepository(); options.AddRepository(); }); } diff --git a/modules/permission-management/src/Volo.Abp.PermissionManagement.EntityFrameworkCore/Volo/Abp/PermissionManagement/EntityFrameworkCore/EfCorePermissionDefinitionRecordRepository.cs b/modules/permission-management/src/Volo.Abp.PermissionManagement.EntityFrameworkCore/Volo/Abp/PermissionManagement/EntityFrameworkCore/EfCorePermissionDefinitionRecordRepository.cs new file mode 100644 index 0000000000..09cf408f7d --- /dev/null +++ b/modules/permission-management/src/Volo.Abp.PermissionManagement.EntityFrameworkCore/Volo/Abp/PermissionManagement/EntityFrameworkCore/EfCorePermissionDefinitionRecordRepository.cs @@ -0,0 +1,29 @@ +using System; +using System.Linq; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.EntityFrameworkCore; +using Volo.Abp.Domain.Repositories.EntityFrameworkCore; +using Volo.Abp.EntityFrameworkCore; + +namespace Volo.Abp.PermissionManagement.EntityFrameworkCore; + +public class EfCorePermissionDefinitionRecordRepository : + EfCoreRepository, + IPermissionDefinitionRecordRepository +{ + public EfCorePermissionDefinitionRecordRepository( + IDbContextProvider dbContextProvider) + : base(dbContextProvider) + { + } + + public async Task FindByNameAsync( + string name, + CancellationToken cancellationToken = default) + { + return await (await GetDbSetAsync()) + .OrderBy(x => x.Id) + .FirstOrDefaultAsync(r => r.Name == name, cancellationToken); + } +} \ No newline at end of file diff --git a/modules/permission-management/src/Volo.Abp.PermissionManagement.EntityFrameworkCore/Volo/Abp/PermissionManagement/EntityFrameworkCore/EfCorePermissionGrantRepository.cs b/modules/permission-management/src/Volo.Abp.PermissionManagement.EntityFrameworkCore/Volo/Abp/PermissionManagement/EntityFrameworkCore/EfCorePermissionGrantRepository.cs index 6345f69735..a080d39d87 100644 --- a/modules/permission-management/src/Volo.Abp.PermissionManagement.EntityFrameworkCore/Volo/Abp/PermissionManagement/EntityFrameworkCore/EfCorePermissionGrantRepository.cs +++ b/modules/permission-management/src/Volo.Abp.PermissionManagement.EntityFrameworkCore/Volo/Abp/PermissionManagement/EntityFrameworkCore/EfCorePermissionGrantRepository.cs @@ -9,7 +9,8 @@ using Volo.Abp.EntityFrameworkCore; namespace Volo.Abp.PermissionManagement.EntityFrameworkCore; -public class EfCorePermissionGrantRepository : EfCoreRepository, +public class EfCorePermissionGrantRepository : + EfCoreRepository, IPermissionGrantRepository { public EfCorePermissionGrantRepository(IDbContextProvider dbContextProvider) diff --git a/modules/permission-management/src/Volo.Abp.PermissionManagement.EntityFrameworkCore/Volo/Abp/PermissionManagement/EntityFrameworkCore/EfCorePermissionGroupDefinitionRecordRepository.cs b/modules/permission-management/src/Volo.Abp.PermissionManagement.EntityFrameworkCore/Volo/Abp/PermissionManagement/EntityFrameworkCore/EfCorePermissionGroupDefinitionRecordRepository.cs new file mode 100644 index 0000000000..923d238761 --- /dev/null +++ b/modules/permission-management/src/Volo.Abp.PermissionManagement.EntityFrameworkCore/Volo/Abp/PermissionManagement/EntityFrameworkCore/EfCorePermissionGroupDefinitionRecordRepository.cs @@ -0,0 +1,16 @@ +using System; +using Volo.Abp.Domain.Repositories.EntityFrameworkCore; +using Volo.Abp.EntityFrameworkCore; + +namespace Volo.Abp.PermissionManagement.EntityFrameworkCore; + +public class EfCorePermissionGroupDefinitionRecordRepository : + EfCoreRepository, + IPermissionGroupDefinitionRecordRepository +{ + public EfCorePermissionGroupDefinitionRecordRepository( + IDbContextProvider dbContextProvider) + : base(dbContextProvider) + { + } +} \ No newline at end of file diff --git a/modules/permission-management/src/Volo.Abp.PermissionManagement.EntityFrameworkCore/Volo/Abp/PermissionManagement/EntityFrameworkCore/IPermissionManagementDbContext.cs b/modules/permission-management/src/Volo.Abp.PermissionManagement.EntityFrameworkCore/Volo/Abp/PermissionManagement/EntityFrameworkCore/IPermissionManagementDbContext.cs index 174ba1762a..c294c1b248 100644 --- a/modules/permission-management/src/Volo.Abp.PermissionManagement.EntityFrameworkCore/Volo/Abp/PermissionManagement/EntityFrameworkCore/IPermissionManagementDbContext.cs +++ b/modules/permission-management/src/Volo.Abp.PermissionManagement.EntityFrameworkCore/Volo/Abp/PermissionManagement/EntityFrameworkCore/IPermissionManagementDbContext.cs @@ -7,5 +7,9 @@ namespace Volo.Abp.PermissionManagement.EntityFrameworkCore; [ConnectionStringName(AbpPermissionManagementDbProperties.ConnectionStringName)] public interface IPermissionManagementDbContext : IEfCoreDbContext { + DbSet PermissionGroups { get; } + + DbSet Permissions { get; } + DbSet PermissionGrants { get; } } diff --git a/modules/permission-management/src/Volo.Abp.PermissionManagement.EntityFrameworkCore/Volo/Abp/PermissionManagement/EntityFrameworkCore/PermissionManagementDbContext.cs b/modules/permission-management/src/Volo.Abp.PermissionManagement.EntityFrameworkCore/Volo/Abp/PermissionManagement/EntityFrameworkCore/PermissionManagementDbContext.cs index f1183eec16..fe143fa8ae 100644 --- a/modules/permission-management/src/Volo.Abp.PermissionManagement.EntityFrameworkCore/Volo/Abp/PermissionManagement/EntityFrameworkCore/PermissionManagementDbContext.cs +++ b/modules/permission-management/src/Volo.Abp.PermissionManagement.EntityFrameworkCore/Volo/Abp/PermissionManagement/EntityFrameworkCore/PermissionManagementDbContext.cs @@ -7,6 +7,8 @@ namespace Volo.Abp.PermissionManagement.EntityFrameworkCore; [ConnectionStringName(AbpPermissionManagementDbProperties.ConnectionStringName)] public class PermissionManagementDbContext : AbpDbContext, IPermissionManagementDbContext { + public DbSet PermissionGroups { get; set; } + public DbSet Permissions { get; set; } public DbSet PermissionGrants { get; set; } public PermissionManagementDbContext(DbContextOptions options) diff --git a/modules/permission-management/src/Volo.Abp.PermissionManagement.MongoDB/Volo/Abp/PermissionManagement/MongoDb/AbpPermissionManagementMongoDbContextExtensions.cs b/modules/permission-management/src/Volo.Abp.PermissionManagement.MongoDB/Volo/Abp/PermissionManagement/MongoDb/AbpPermissionManagementMongoDbContextExtensions.cs index a3d1461e58..9c7c90af58 100644 --- a/modules/permission-management/src/Volo.Abp.PermissionManagement.MongoDB/Volo/Abp/PermissionManagement/MongoDb/AbpPermissionManagementMongoDbContextExtensions.cs +++ b/modules/permission-management/src/Volo.Abp.PermissionManagement.MongoDB/Volo/Abp/PermissionManagement/MongoDb/AbpPermissionManagementMongoDbContextExtensions.cs @@ -9,6 +9,16 @@ public static class AbpPermissionManagementMongoDbContextExtensions { Check.NotNull(builder, nameof(builder)); + builder.Entity(b => + { + b.CollectionName = AbpPermissionManagementDbProperties.DbTablePrefix + "PermissionGroups"; + }); + + builder.Entity(b => + { + b.CollectionName = AbpPermissionManagementDbProperties.DbTablePrefix + "Permissions"; + }); + builder.Entity(b => { b.CollectionName = AbpPermissionManagementDbProperties.DbTablePrefix + "PermissionGrants"; diff --git a/modules/permission-management/src/Volo.Abp.PermissionManagement.MongoDB/Volo/Abp/PermissionManagement/MongoDb/AbpPermissionManagementMongoDbModule.cs b/modules/permission-management/src/Volo.Abp.PermissionManagement.MongoDB/Volo/Abp/PermissionManagement/MongoDb/AbpPermissionManagementMongoDbModule.cs index b62d651bf1..80831660f8 100644 --- a/modules/permission-management/src/Volo.Abp.PermissionManagement.MongoDB/Volo/Abp/PermissionManagement/MongoDb/AbpPermissionManagementMongoDbModule.cs +++ b/modules/permission-management/src/Volo.Abp.PermissionManagement.MongoDB/Volo/Abp/PermissionManagement/MongoDb/AbpPermissionManagementMongoDbModule.cs @@ -16,6 +16,8 @@ public class AbpPermissionManagementMongoDbModule : AbpModule { options.AddDefaultRepositories(); + options.AddRepository(); + options.AddRepository(); options.AddRepository(); }); } diff --git a/modules/permission-management/src/Volo.Abp.PermissionManagement.MongoDB/Volo/Abp/PermissionManagement/MongoDb/IPermissionManagementMongoDbContext.cs b/modules/permission-management/src/Volo.Abp.PermissionManagement.MongoDB/Volo/Abp/PermissionManagement/MongoDb/IPermissionManagementMongoDbContext.cs index 0826003628..98015484fb 100644 --- a/modules/permission-management/src/Volo.Abp.PermissionManagement.MongoDB/Volo/Abp/PermissionManagement/MongoDb/IPermissionManagementMongoDbContext.cs +++ b/modules/permission-management/src/Volo.Abp.PermissionManagement.MongoDB/Volo/Abp/PermissionManagement/MongoDb/IPermissionManagementMongoDbContext.cs @@ -7,5 +7,9 @@ namespace Volo.Abp.PermissionManagement.MongoDB; [ConnectionStringName(AbpPermissionManagementDbProperties.ConnectionStringName)] public interface IPermissionManagementMongoDbContext : IAbpMongoDbContext { + IMongoCollection PermissionGroups { get; } + + IMongoCollection Permissions { get; } + IMongoCollection PermissionGrants { get; } } diff --git a/modules/permission-management/src/Volo.Abp.PermissionManagement.MongoDB/Volo/Abp/PermissionManagement/MongoDb/MongoPermissionDefinitionRecordRepository.cs b/modules/permission-management/src/Volo.Abp.PermissionManagement.MongoDB/Volo/Abp/PermissionManagement/MongoDb/MongoPermissionDefinitionRecordRepository.cs new file mode 100644 index 0000000000..e4894a1442 --- /dev/null +++ b/modules/permission-management/src/Volo.Abp.PermissionManagement.MongoDB/Volo/Abp/PermissionManagement/MongoDb/MongoPermissionDefinitionRecordRepository.cs @@ -0,0 +1,32 @@ +using System; +using System.Threading; +using System.Threading.Tasks; +using MongoDB.Driver.Linq; +using Volo.Abp.Domain.Repositories.MongoDB; +using Volo.Abp.MongoDB; + +namespace Volo.Abp.PermissionManagement.MongoDB; + +public class MongoPermissionDefinitionRecordRepository : + MongoDbRepository, + IPermissionDefinitionRecordRepository +{ + public MongoPermissionDefinitionRecordRepository( + IMongoDbContextProvider dbContextProvider) + : base(dbContextProvider) + { + } + + public async Task FindByNameAsync( + string name, + CancellationToken cancellationToken = default) + { + cancellationToken = GetCancellationToken(cancellationToken); + return await (await GetMongoQueryableAsync(cancellationToken)) + .OrderBy(x => x.Id) + .FirstOrDefaultAsync( + s => s.Name == name, + cancellationToken + ); + } +} \ No newline at end of file diff --git a/modules/permission-management/src/Volo.Abp.PermissionManagement.MongoDB/Volo/Abp/PermissionManagement/MongoDb/MongoPermissionGrantRepository.cs b/modules/permission-management/src/Volo.Abp.PermissionManagement.MongoDB/Volo/Abp/PermissionManagement/MongoDb/MongoPermissionGrantRepository.cs index 908f258a47..aa7694b7d5 100644 --- a/modules/permission-management/src/Volo.Abp.PermissionManagement.MongoDB/Volo/Abp/PermissionManagement/MongoDb/MongoPermissionGrantRepository.cs +++ b/modules/permission-management/src/Volo.Abp.PermissionManagement.MongoDB/Volo/Abp/PermissionManagement/MongoDb/MongoPermissionGrantRepository.cs @@ -10,7 +10,9 @@ using Volo.Abp.MongoDB; namespace Volo.Abp.PermissionManagement.MongoDB; -public class MongoPermissionGrantRepository : MongoDbRepository, IPermissionGrantRepository +public class MongoPermissionGrantRepository : + MongoDbRepository, + IPermissionGrantRepository { public MongoPermissionGrantRepository(IMongoDbContextProvider dbContextProvider) : base(dbContextProvider) diff --git a/modules/permission-management/src/Volo.Abp.PermissionManagement.MongoDB/Volo/Abp/PermissionManagement/MongoDb/MongoPermissionGroupDefinitionRecordRepository.cs b/modules/permission-management/src/Volo.Abp.PermissionManagement.MongoDB/Volo/Abp/PermissionManagement/MongoDb/MongoPermissionGroupDefinitionRecordRepository.cs new file mode 100644 index 0000000000..0b6b5550b9 --- /dev/null +++ b/modules/permission-management/src/Volo.Abp.PermissionManagement.MongoDB/Volo/Abp/PermissionManagement/MongoDb/MongoPermissionGroupDefinitionRecordRepository.cs @@ -0,0 +1,16 @@ +using System; +using Volo.Abp.Domain.Repositories.MongoDB; +using Volo.Abp.MongoDB; + +namespace Volo.Abp.PermissionManagement.MongoDB; + +public class MongoPermissionGroupDefinitionRecordRepository : + MongoDbRepository, + IPermissionGroupDefinitionRecordRepository +{ + public MongoPermissionGroupDefinitionRecordRepository( + IMongoDbContextProvider dbContextProvider) + : base(dbContextProvider) + { + } +} \ No newline at end of file diff --git a/modules/permission-management/src/Volo.Abp.PermissionManagement.MongoDB/Volo/Abp/PermissionManagement/MongoDb/PermissionManagementMongoDbContext.cs b/modules/permission-management/src/Volo.Abp.PermissionManagement.MongoDB/Volo/Abp/PermissionManagement/MongoDb/PermissionManagementMongoDbContext.cs index e8ef18f162..c62db52c11 100644 --- a/modules/permission-management/src/Volo.Abp.PermissionManagement.MongoDB/Volo/Abp/PermissionManagement/MongoDb/PermissionManagementMongoDbContext.cs +++ b/modules/permission-management/src/Volo.Abp.PermissionManagement.MongoDB/Volo/Abp/PermissionManagement/MongoDb/PermissionManagementMongoDbContext.cs @@ -7,6 +7,8 @@ namespace Volo.Abp.PermissionManagement.MongoDB; [ConnectionStringName(AbpPermissionManagementDbProperties.ConnectionStringName)] public class PermissionManagementMongoDbContext : AbpMongoDbContext, IPermissionManagementMongoDbContext { + public IMongoCollection PermissionGroups => Collection(); + public IMongoCollection Permissions => Collection(); public IMongoCollection PermissionGrants => Collection(); protected override void CreateModel(IMongoModelBuilder modelBuilder) diff --git a/modules/permission-management/src/Volo.Abp.PermissionManagement.Web/Pages/AbpPermissionManagement/PermissionManagementModal.cshtml.cs b/modules/permission-management/src/Volo.Abp.PermissionManagement.Web/Pages/AbpPermissionManagement/PermissionManagementModal.cshtml.cs index 5f1ca18fc0..30057eea82 100644 --- a/modules/permission-management/src/Volo.Abp.PermissionManagement.Web/Pages/AbpPermissionManagement/PermissionManagementModal.cshtml.cs +++ b/modules/permission-management/src/Volo.Abp.PermissionManagement.Web/Pages/AbpPermissionManagement/PermissionManagementModal.cshtml.cs @@ -1,11 +1,14 @@ +using System; using System.Collections.Generic; using System.ComponentModel.DataAnnotations; using System.Linq; using System.Threading.Tasks; using Microsoft.AspNetCore.Mvc; +using Microsoft.Extensions.Options; using Volo.Abp.AspNetCore.Mvc.ApplicationConfigurations; using Volo.Abp.AspNetCore.Mvc.UI.RazorPages; using Volo.Abp.EventBus.Local; +using Volo.Abp.Localization; using Volo.Abp.PermissionManagement.Web.Utils; namespace Volo.Abp.PermissionManagement.Web.Pages.AbpPermissionManagement; @@ -37,15 +40,18 @@ public class PermissionManagementModal : AbpPageModel protected IPermissionAppService PermissionAppService { get; } protected ILocalEventBus LocalEventBus { get; } + public AbpLocalizationOptions LocalizationOptions { get; } public PermissionManagementModal( - IPermissionAppService permissionAppService, - ILocalEventBus localEventBus) + IPermissionAppService permissionAppService, + ILocalEventBus localEventBus, + IOptions localizationOptions) { ObjectMapperContext = typeof(AbpPermissionManagementWebModule); PermissionAppService = permissionAppService; LocalEventBus = localEventBus; + LocalizationOptions = localizationOptions.Value; } public virtual async Task OnGetAsync() @@ -54,6 +60,8 @@ public class PermissionManagementModal : AbpPageModel var result = await PermissionAppService.GetAsync(ProviderName, ProviderKey); + UpdateLocalizations(result); + EntityDisplayName = !string.IsNullOrWhiteSpace(ProviderKeyDisplayName) ? ProviderKeyDisplayName : result.EntityDisplayName; @@ -78,6 +86,49 @@ public class PermissionManagementModal : AbpPageModel return Page(); } + private void UpdateLocalizations(GetPermissionListResultDto result) + { + foreach (var group in result.Groups) + { + group.DisplayName = Localize( + group.DisplayNameKey, + group.DisplayNameResource, + group.DisplayName + ); + + foreach (var permission in group.Permissions) + { + permission.DisplayName = Localize( + permission.DisplayNameKey, + permission.DisplayNameResource, + permission.DisplayName + ); + } + } + } + + private string Localize(string key, string resourceName, string fallbackValue) + { + if (key.IsNullOrEmpty() || resourceName.IsNullOrEmpty()) + { + return fallbackValue; + } + + var resource = LocalizationOptions.Resources.GetOrNull(resourceName); + if (resource == null) + { + return fallbackValue; + } + + var result = new LocalizableString(resource.ResourceType, key).Localize(StringLocalizerFactory); + if (result.ResourceNotFound) + { + return fallbackValue; + } + + return result.Value; + } + public virtual async Task OnPostAsync() { ValidateModel(); diff --git a/modules/permission-management/test/Volo.Abp.PermissionManagement.Domain.Tests/Volo.Abp.PermissionManagement.Domain.Tests.csproj b/modules/permission-management/test/Volo.Abp.PermissionManagement.Domain.Tests/Volo.Abp.PermissionManagement.Domain.Tests.csproj index 9b0cd2f1c0..8e77b2d56c 100644 --- a/modules/permission-management/test/Volo.Abp.PermissionManagement.Domain.Tests/Volo.Abp.PermissionManagement.Domain.Tests.csproj +++ b/modules/permission-management/test/Volo.Abp.PermissionManagement.Domain.Tests/Volo.Abp.PermissionManagement.Domain.Tests.csproj @@ -12,6 +12,8 @@ + + diff --git a/modules/permission-management/test/Volo.Abp.PermissionManagement.Domain.Tests/Volo/Abp/PermissionManagement/AbpPermissionManagementTestModule.cs b/modules/permission-management/test/Volo.Abp.PermissionManagement.Domain.Tests/Volo/Abp/PermissionManagement/AbpPermissionManagementTestModule.cs index 24945f83b0..bf32af126d 100644 --- a/modules/permission-management/test/Volo.Abp.PermissionManagement.Domain.Tests/Volo/Abp/PermissionManagement/AbpPermissionManagementTestModule.cs +++ b/modules/permission-management/test/Volo.Abp.PermissionManagement.Domain.Tests/Volo/Abp/PermissionManagement/AbpPermissionManagementTestModule.cs @@ -2,6 +2,8 @@ using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.DependencyInjection; using Volo.Abp.EntityFrameworkCore; +using Volo.Abp.Features; +using Volo.Abp.GlobalFeatures; using Volo.Abp.Modularity; using Volo.Abp.PermissionManagement.EntityFrameworkCore; using Volo.Abp.Uow; @@ -10,7 +12,10 @@ namespace Volo.Abp.PermissionManagement; [DependsOn( typeof(AbpPermissionManagementEntityFrameworkCoreModule), - typeof(AbpPermissionManagementTestBaseModule))] + typeof(AbpPermissionManagementTestBaseModule), + typeof(AbpFeaturesModule), + typeof(AbpGlobalFeaturesModule) + )] public class AbpPermissionManagementTestModule : AbpModule { public override void ConfigureServices(ServiceConfigurationContext context) diff --git a/modules/permission-management/test/Volo.Abp.PermissionManagement.Domain.Tests/Volo/Abp/PermissionManagement/PermissionChecker_Basic_Tests.cs b/modules/permission-management/test/Volo.Abp.PermissionManagement.Domain.Tests/Volo/Abp/PermissionManagement/PermissionChecker_Basic_Tests.cs index aa9e7ecca9..78ab5d0af9 100644 --- a/modules/permission-management/test/Volo.Abp.PermissionManagement.Domain.Tests/Volo/Abp/PermissionManagement/PermissionChecker_Basic_Tests.cs +++ b/modules/permission-management/test/Volo.Abp.PermissionManagement.Domain.Tests/Volo/Abp/PermissionManagement/PermissionChecker_Basic_Tests.cs @@ -15,11 +15,9 @@ public class PermissionChecker_Basic_Tests : PermissionTestBase } [Fact] - public async Task Should_Throw_Exception_If_Permission_Is_Not_Defined() + public async Task Should_Return_Prohibited_If_Permission_Is_Not_Defined() { - await Assert.ThrowsAsync(async () => - await _permissionChecker.IsGrantedAsync("UndefinedPermissionName") - ); + (await _permissionChecker.IsGrantedAsync("UndefinedPermissionName")).ShouldBeFalse(); } [Fact] diff --git a/modules/permission-management/test/Volo.Abp.PermissionManagement.Domain.Tests/Volo/Abp/PermissionManagement/PermissionDefinitionSerializer_Tests.cs b/modules/permission-management/test/Volo.Abp.PermissionManagement.Domain.Tests/Volo/Abp/PermissionManagement/PermissionDefinitionSerializer_Tests.cs new file mode 100644 index 0000000000..1e7c04580c --- /dev/null +++ b/modules/permission-management/test/Volo.Abp.PermissionManagement.Domain.Tests/Volo/Abp/PermissionManagement/PermissionDefinitionSerializer_Tests.cs @@ -0,0 +1,93 @@ +using System; +using System.Linq; +using System.Threading.Tasks; +using Shouldly; +using Volo.Abp.Authorization.Permissions; +using Volo.Abp.Data; +using Volo.Abp.Features; +using Volo.Abp.GlobalFeatures; +using Volo.Abp.Localization; +using Volo.Abp.MultiTenancy; +using Volo.Abp.PermissionManagement.Localization; +using Xunit; + +namespace Volo.Abp.PermissionManagement; + +public class PermissionDefinitionSerializer_Tests : PermissionTestBase +{ + private readonly IPermissionDefinitionSerializer _serializer; + + public PermissionDefinitionSerializer_Tests() + { + _serializer = GetRequiredService(); + } + + [Fact] + public async Task Serialize_Permission_Group_Definition() + { + // Arrange + + var context = new PermissionDefinitionContext(null); + var group1 = CreatePermissionGroup1(context); + + // Act + + var permissionGroupRecord = await _serializer.SerializeAsync(group1); + + //Assert + + permissionGroupRecord.Name.ShouldBe("Group1"); + permissionGroupRecord.DisplayName.ShouldBe("F:Group one"); + permissionGroupRecord.GetProperty("CustomProperty1").ShouldBe("CustomValue1"); + } + + [Fact] + public async Task Serialize_Complex_Permission_Definition() + { + // Arrange + + var context = new PermissionDefinitionContext(null); + var group1 = CreatePermissionGroup1(context); + var permission1 = group1.AddPermission( + "Permission1", + new LocalizableString(typeof(AbpPermissionManagementResource), "Permission1"), + MultiTenancySides.Tenant + ) + .WithProviders("ProviderA", "ProviderB") + .WithProperty("CustomProperty2", "CustomValue2") + .RequireAuthenticated() //For for testing, not so meaningful + .RequireGlobalFeatures("GlobalFeature1", "GlobalFeature2") + .RequireFeatures("Feature1", "Feature2") + .RequirePermissions(requiresAll: false, batchCheck: false,"Permission2", "Permission3"); + + // Act + + var permissionRecord = await _serializer.SerializeAsync( + permission1, + group1 + ); + + //Assert + + permissionRecord.Name.ShouldBe("Permission1"); + permissionRecord.GroupName.ShouldBe("Group1"); + permissionRecord.DisplayName.ShouldBe("L:AbpPermissionManagement,Permission1"); + permissionRecord.GetProperty("CustomProperty2").ShouldBe("CustomValue2"); + permissionRecord.Providers.ShouldBe("ProviderA,ProviderB"); + permissionRecord.MultiTenancySide.ShouldBe(MultiTenancySides.Tenant); + permissionRecord.StateCheckers.ShouldBe("[{\"T\":\"A\"},{\"T\":\"G\",\"A\":true,\"N\":[\"GlobalFeature1\",\"GlobalFeature2\"]},{\"T\":\"F\",\"A\":true,\"N\":[\"Feature1\",\"Feature2\"]},{\"T\":\"P\",\"A\":false,\"N\":[\"Permission2\",\"Permission3\"]}]"); + } + + private static PermissionGroupDefinition CreatePermissionGroup1( + IPermissionDefinitionContext context) + { + var group = context.AddGroup( + "Group1", + displayName: new FixedLocalizableString("Group one") + ); + + group["CustomProperty1"] = "CustomValue1"; + + return group; + } +} \ No newline at end of file diff --git a/modules/permission-management/test/Volo.Abp.PermissionManagement.Domain.Tests/Volo/Abp/PermissionManagement/PermissionManager_Tests.cs b/modules/permission-management/test/Volo.Abp.PermissionManagement.Domain.Tests/Volo/Abp/PermissionManagement/PermissionManager_Tests.cs index 06e245046c..1f771bdb3b 100644 --- a/modules/permission-management/test/Volo.Abp.PermissionManagement.Domain.Tests/Volo/Abp/PermissionManagement/PermissionManager_Tests.cs +++ b/modules/permission-management/test/Volo.Abp.PermissionManagement.Domain.Tests/Volo/Abp/PermissionManagement/PermissionManager_Tests.cs @@ -72,12 +72,12 @@ public class PermissionManager_Tests : PermissionTestBase } [Fact] - public async Task Get_Should_Exception_When_Permission_Undefined() + public async Task Get_Should_Return_Not_Granted_When_Permission_Undefined() { - await Assert.ThrowsAsync(async () => await _permissionManager.GetAsync( - "MyPermission1NotExist", - "Test", - "Test")); + var result = await _permissionManager.GetAsync("MyPermission1NotExist", "Test", "Test"); + result.Name.ShouldBe("MyPermission1NotExist"); + result.Providers.ShouldBeEmpty(); + result.IsGranted.ShouldBeFalse(); } [Fact] @@ -126,13 +126,13 @@ public class PermissionManager_Tests : PermissionTestBase } [Fact] - public async Task Set_Should_Exception_When_Permission_Undefined() + public async Task Set_Should_Silently_Ignore_When_Permission_Undefined() { - await Assert.ThrowsAsync(async () => await _permissionManager.SetAsync( + await _permissionManager.SetAsync( "MyPermission1NotExist", "Test", "Test", - true)); + true); } [Fact] diff --git a/modules/setting-management/src/Volo.Abp.SettingManagement.Domain/Volo/Abp/SettingManagement/SettingManager.cs b/modules/setting-management/src/Volo.Abp.SettingManagement.Domain/Volo/Abp/SettingManagement/SettingManager.cs index 14629b988e..570c99925b 100644 --- a/modules/setting-management/src/Volo.Abp.SettingManagement.Domain/Volo/Abp/SettingManagement/SettingManager.cs +++ b/modules/setting-management/src/Volo.Abp.SettingManagement.Domain/Volo/Abp/SettingManagement/SettingManager.cs @@ -27,7 +27,7 @@ public class SettingManager : ISettingManager, ISingletonDependency SettingEncryptionService = settingEncryptionService; Options = options.Value; - //TODO: Instead, use IHybridServiceScopeFactory and create a scope..? + //TODO: Instead, use IServiceScopeFactory and create a scope..? _lazyProviders = new Lazy>( () => Options diff --git a/modules/tenant-management/src/Volo.Abp.TenantManagement.Blazor/Pages/TenantManagement/TenantManagement.razor.cs b/modules/tenant-management/src/Volo.Abp.TenantManagement.Blazor/Pages/TenantManagement/TenantManagement.razor.cs index 11daa3fb4a..5969237a21 100644 --- a/modules/tenant-management/src/Volo.Abp.TenantManagement.Blazor/Pages/TenantManagement/TenantManagement.razor.cs +++ b/modules/tenant-management/src/Volo.Abp.TenantManagement.Blazor/Pages/TenantManagement/TenantManagement.razor.cs @@ -61,11 +61,6 @@ public partial class TenantManagement protected override ValueTask SetToolbarItemsAsync() { - Toolbar.AddButton(L["ManageHostFeatures"], - async () => await FeatureManagementModal.OpenAsync(FeatureProviderName), - "fa fa-cog", - requiredPolicyName: FeatureManagementPermissions.ManageHostFeatures); - Toolbar.AddButton(L["NewTenant"], OpenCreateModalAsync, IconName.Add, diff --git a/modules/tenant-management/src/Volo.Abp.TenantManagement.Domain.Shared/Volo/Abp/TenantManagement/Localization/Resources/ar.json b/modules/tenant-management/src/Volo.Abp.TenantManagement.Domain.Shared/Volo/Abp/TenantManagement/Localization/Resources/ar.json index 829a326d24..8146974400 100644 --- a/modules/tenant-management/src/Volo.Abp.TenantManagement.Domain.Shared/Volo/Abp/TenantManagement/Localization/Resources/ar.json +++ b/modules/tenant-management/src/Volo.Abp.TenantManagement.Domain.Shared/Volo/Abp/TenantManagement/Localization/Resources/ar.json @@ -11,7 +11,6 @@ "ConnectionStrings": "Connection Strings", "DisplayName:DefaultConnectionString": "Default Connection String", "DisplayName:UseSharedDatabase": "استخدام قاعدة البيانات المشتركة", - "ManageHostFeatures": "إدارة ميزات المضيف", "Permission:TenantManagement": "إدارة المستأجر", "Permission:Create": "إنشاء", "Permission:Edit": "تحرير", diff --git a/modules/tenant-management/src/Volo.Abp.TenantManagement.Domain.Shared/Volo/Abp/TenantManagement/Localization/Resources/cs.json b/modules/tenant-management/src/Volo.Abp.TenantManagement.Domain.Shared/Volo/Abp/TenantManagement/Localization/Resources/cs.json index 754b66d081..001d5d71fb 100644 --- a/modules/tenant-management/src/Volo.Abp.TenantManagement.Domain.Shared/Volo/Abp/TenantManagement/Localization/Resources/cs.json +++ b/modules/tenant-management/src/Volo.Abp.TenantManagement.Domain.Shared/Volo/Abp/TenantManagement/Localization/Resources/cs.json @@ -10,7 +10,6 @@ "ConnectionStrings": "Connection stringy", "DisplayName:DefaultConnectionString": "Výchozí connection string", "DisplayName:UseSharedDatabase": "Použít sdílenou databázi", - "ManageHostFeatures": "Správa funkcí hostitele", "Permission:TenantManagement": "Správa tenantů", "Permission:Create": "Vytvořit", "Permission:Edit": "Upravit", diff --git a/modules/tenant-management/src/Volo.Abp.TenantManagement.Domain.Shared/Volo/Abp/TenantManagement/Localization/Resources/de-DE.json b/modules/tenant-management/src/Volo.Abp.TenantManagement.Domain.Shared/Volo/Abp/TenantManagement/Localization/Resources/de-DE.json index 2033fdf1ed..58d71c9252 100644 --- a/modules/tenant-management/src/Volo.Abp.TenantManagement.Domain.Shared/Volo/Abp/TenantManagement/Localization/Resources/de-DE.json +++ b/modules/tenant-management/src/Volo.Abp.TenantManagement.Domain.Shared/Volo/Abp/TenantManagement/Localization/Resources/de-DE.json @@ -11,7 +11,6 @@ "ConnectionStrings": "Connection Strings", "DisplayName:DefaultConnectionString": "Standard-Connection String", "DisplayName:UseSharedDatabase": "Verwenden Sie die freigegebene Datenbank", - "ManageHostFeatures": "Host-Features verwalten", "Permission:TenantManagement": "Mandantenverwaltung", "Permission:Create": "Erstellen", "Permission:Edit": "Bearbeiten", diff --git a/modules/tenant-management/src/Volo.Abp.TenantManagement.Domain.Shared/Volo/Abp/TenantManagement/Localization/Resources/el.json b/modules/tenant-management/src/Volo.Abp.TenantManagement.Domain.Shared/Volo/Abp/TenantManagement/Localization/Resources/el.json index 026bcb0b76..bc75c34e03 100644 --- a/modules/tenant-management/src/Volo.Abp.TenantManagement.Domain.Shared/Volo/Abp/TenantManagement/Localization/Resources/el.json +++ b/modules/tenant-management/src/Volo.Abp.TenantManagement.Domain.Shared/Volo/Abp/TenantManagement/Localization/Resources/el.json @@ -10,7 +10,6 @@ "ConnectionStrings": "Συμβολοσειρές σύνδεσης", "DisplayName:DefaultConnectionString": "Προεπιλεγμένη συμβολοσειρά σύνδεσης", "DisplayName:UseSharedDatabase": "Χρησιμοποιήστε την Κοινόχρηστη βάση δεδομένων", - "ManageHostFeatures": "Διαχείριση δυνατοτήτων του Οικοδεσπότη", "Permission:TenantManagement": "Διαχείριση ενοικιαστών", "Permission:Create": "Δημιουργία", "Permission:Edit": "Επεξεργασία", diff --git a/modules/tenant-management/src/Volo.Abp.TenantManagement.Domain.Shared/Volo/Abp/TenantManagement/Localization/Resources/en-GB.json b/modules/tenant-management/src/Volo.Abp.TenantManagement.Domain.Shared/Volo/Abp/TenantManagement/Localization/Resources/en-GB.json index 4d6075ff74..8b4e4c185b 100644 --- a/modules/tenant-management/src/Volo.Abp.TenantManagement.Domain.Shared/Volo/Abp/TenantManagement/Localization/Resources/en-GB.json +++ b/modules/tenant-management/src/Volo.Abp.TenantManagement.Domain.Shared/Volo/Abp/TenantManagement/Localization/Resources/en-GB.json @@ -10,7 +10,6 @@ "ConnectionStrings": "Connection Strings", "DisplayName:DefaultConnectionString": "Default Connection String", "DisplayName:UseSharedDatabase": "Use the Shared Database", - "ManageHostFeatures": "Manage Host features", "Permission:TenantManagement": "Tenant management", "Permission:Create": "Create", "Permission:Edit": "Edit", diff --git a/modules/tenant-management/src/Volo.Abp.TenantManagement.Domain.Shared/Volo/Abp/TenantManagement/Localization/Resources/en.json b/modules/tenant-management/src/Volo.Abp.TenantManagement.Domain.Shared/Volo/Abp/TenantManagement/Localization/Resources/en.json index 1a10c5b77a..e639feb5f3 100644 --- a/modules/tenant-management/src/Volo.Abp.TenantManagement.Domain.Shared/Volo/Abp/TenantManagement/Localization/Resources/en.json +++ b/modules/tenant-management/src/Volo.Abp.TenantManagement.Domain.Shared/Volo/Abp/TenantManagement/Localization/Resources/en.json @@ -11,7 +11,6 @@ "ConnectionStrings": "Connection Strings", "DisplayName:DefaultConnectionString": "Default Connection String", "DisplayName:UseSharedDatabase": "Use the Shared Database", - "ManageHostFeatures": "Manage Host features", "Permission:TenantManagement": "Tenant management", "Permission:Create": "Create", "Permission:Edit": "Edit", diff --git a/modules/tenant-management/src/Volo.Abp.TenantManagement.Domain.Shared/Volo/Abp/TenantManagement/Localization/Resources/es.json b/modules/tenant-management/src/Volo.Abp.TenantManagement.Domain.Shared/Volo/Abp/TenantManagement/Localization/Resources/es.json index 774201178b..bcbfc98852 100644 --- a/modules/tenant-management/src/Volo.Abp.TenantManagement.Domain.Shared/Volo/Abp/TenantManagement/Localization/Resources/es.json +++ b/modules/tenant-management/src/Volo.Abp.TenantManagement.Domain.Shared/Volo/Abp/TenantManagement/Localization/Resources/es.json @@ -11,7 +11,6 @@ "ConnectionStrings": "Connection Strings", "DisplayName:DefaultConnectionString": "Connection String predeterminado", "DisplayName:UseSharedDatabase": "Usar la base de datos compartida", - "ManageHostFeatures": "Administrar funciones de host", "Permission:TenantManagement": "Gestión de tenants", "Permission:Create": "Crear", "Permission:Edit": "Editar", diff --git a/modules/tenant-management/src/Volo.Abp.TenantManagement.Domain.Shared/Volo/Abp/TenantManagement/Localization/Resources/fa.json b/modules/tenant-management/src/Volo.Abp.TenantManagement.Domain.Shared/Volo/Abp/TenantManagement/Localization/Resources/fa.json index f0a804c073..c67a9c070b 100644 --- a/modules/tenant-management/src/Volo.Abp.TenantManagement.Domain.Shared/Volo/Abp/TenantManagement/Localization/Resources/fa.json +++ b/modules/tenant-management/src/Volo.Abp.TenantManagement.Domain.Shared/Volo/Abp/TenantManagement/Localization/Resources/fa.json @@ -10,7 +10,6 @@ "ConnectionStrings": "کانکشن استرینگها", "DisplayName:DefaultConnectionString": "کانکشن استرینگ پیش فرض", "DisplayName:UseSharedDatabase": "استفاده از پایگاه داده مشترک", - "ManageHostFeatures": "مدیریت ویژگی های میزبان", "Permission:TenantManagement": "مدیریت تننت", "Permission:Create": "ایجاد", "Permission:Edit": "ویرایش", diff --git a/modules/tenant-management/src/Volo.Abp.TenantManagement.Domain.Shared/Volo/Abp/TenantManagement/Localization/Resources/fi.json b/modules/tenant-management/src/Volo.Abp.TenantManagement.Domain.Shared/Volo/Abp/TenantManagement/Localization/Resources/fi.json index b24d67135e..179ec3c1d6 100644 --- a/modules/tenant-management/src/Volo.Abp.TenantManagement.Domain.Shared/Volo/Abp/TenantManagement/Localization/Resources/fi.json +++ b/modules/tenant-management/src/Volo.Abp.TenantManagement.Domain.Shared/Volo/Abp/TenantManagement/Localization/Resources/fi.json @@ -11,7 +11,6 @@ "ConnectionStrings": "Yhteysjonot", "DisplayName:DefaultConnectionString": "Oletusyhteysmerkkijono", "DisplayName:UseSharedDatabase": "Käytä jaettua tietokantaa", - "ManageHostFeatures": "Hallinnoi isäntäominaisuuksia", "Permission:TenantManagement": "Vuokralaisten hallinta", "Permission:Create": "Luoda", "Permission:Edit": "Muokata", diff --git a/modules/tenant-management/src/Volo.Abp.TenantManagement.Domain.Shared/Volo/Abp/TenantManagement/Localization/Resources/fr.json b/modules/tenant-management/src/Volo.Abp.TenantManagement.Domain.Shared/Volo/Abp/TenantManagement/Localization/Resources/fr.json index 4d6ccd76b0..3537ca8ca6 100644 --- a/modules/tenant-management/src/Volo.Abp.TenantManagement.Domain.Shared/Volo/Abp/TenantManagement/Localization/Resources/fr.json +++ b/modules/tenant-management/src/Volo.Abp.TenantManagement.Domain.Shared/Volo/Abp/TenantManagement/Localization/Resources/fr.json @@ -11,7 +11,6 @@ "ConnectionStrings": "Chaînes de connexion", "DisplayName:DefaultConnectionString": "Chaîne de connexion par défaut", "DisplayName:UseSharedDatabase": "Utiliser la base de données partagée", - "ManageHostFeatures": "Gérer les fonctionnalités de l’hôte", "Permission:TenantManagement": "Gestion des locataires", "Permission:Create": "Créer", "Permission:Edit": "Modifier", diff --git a/modules/tenant-management/src/Volo.Abp.TenantManagement.Domain.Shared/Volo/Abp/TenantManagement/Localization/Resources/hi.json b/modules/tenant-management/src/Volo.Abp.TenantManagement.Domain.Shared/Volo/Abp/TenantManagement/Localization/Resources/hi.json index 93f4a1a1ad..70367305a9 100644 --- a/modules/tenant-management/src/Volo.Abp.TenantManagement.Domain.Shared/Volo/Abp/TenantManagement/Localization/Resources/hi.json +++ b/modules/tenant-management/src/Volo.Abp.TenantManagement.Domain.Shared/Volo/Abp/TenantManagement/Localization/Resources/hi.json @@ -11,7 +11,6 @@ "ConnectionStrings": "कनेक्शन स्ट्रिंग्स", "DisplayName:DefaultConnectionString": "डिफ़ॉल्ट कनेक्शन स्ट्रिंग", "DisplayName:UseSharedDatabase": "साझा डेटाबेस का उपयोग करें", - "ManageHostFeatures": "होस्ट सुविधाएँ प्रबंधित करें", "Permission:TenantManagement": "किरायेदार प्रबंधन", "Permission:Create": "सृजन करना", "Permission:Edit": "संपादित करें", diff --git a/modules/tenant-management/src/Volo.Abp.TenantManagement.Domain.Shared/Volo/Abp/TenantManagement/Localization/Resources/hu.json b/modules/tenant-management/src/Volo.Abp.TenantManagement.Domain.Shared/Volo/Abp/TenantManagement/Localization/Resources/hu.json index 60c61c15cf..f4ccb64b0a 100644 --- a/modules/tenant-management/src/Volo.Abp.TenantManagement.Domain.Shared/Volo/Abp/TenantManagement/Localization/Resources/hu.json +++ b/modules/tenant-management/src/Volo.Abp.TenantManagement.Domain.Shared/Volo/Abp/TenantManagement/Localization/Resources/hu.json @@ -10,7 +10,6 @@ "ConnectionStrings": "Kapcsolat beállítás", "DisplayName:DefaultConnectionString": "Alapértelmezettt kapcsolati beállítás", "DisplayName:UseSharedDatabase": "Használjon megosztott adatbázist", - "ManageHostFeatures": "Host funkciók kezelése", "Permission:TenantManagement": "Bérlő menedzsment", "Permission:Create": "Létrehozás", "Permission:Edit": "Szerkesztés", diff --git a/modules/tenant-management/src/Volo.Abp.TenantManagement.Domain.Shared/Volo/Abp/TenantManagement/Localization/Resources/is.json b/modules/tenant-management/src/Volo.Abp.TenantManagement.Domain.Shared/Volo/Abp/TenantManagement/Localization/Resources/is.json index 25c6a86ca3..ca2a8cb7a9 100644 --- a/modules/tenant-management/src/Volo.Abp.TenantManagement.Domain.Shared/Volo/Abp/TenantManagement/Localization/Resources/is.json +++ b/modules/tenant-management/src/Volo.Abp.TenantManagement.Domain.Shared/Volo/Abp/TenantManagement/Localization/Resources/is.json @@ -10,7 +10,6 @@ "ConnectionStrings": "Tengi strengir", "DisplayName:DefaultConnectionString": "Sjálfgefin tengistrengur", "DisplayName:UseSharedDatabase": "Notaðu samnýttan gagnagrunn", - "ManageHostFeatures": "Stjórna Gestgjafa Eiginleikum", "Permission:TenantManagement": "Tenant umsjá", "Permission:Create": "Búa til", "Permission:Edit": "Breyta", diff --git a/modules/tenant-management/src/Volo.Abp.TenantManagement.Domain.Shared/Volo/Abp/TenantManagement/Localization/Resources/it.json b/modules/tenant-management/src/Volo.Abp.TenantManagement.Domain.Shared/Volo/Abp/TenantManagement/Localization/Resources/it.json index 6deff1bd54..5d95e2039c 100644 --- a/modules/tenant-management/src/Volo.Abp.TenantManagement.Domain.Shared/Volo/Abp/TenantManagement/Localization/Resources/it.json +++ b/modules/tenant-management/src/Volo.Abp.TenantManagement.Domain.Shared/Volo/Abp/TenantManagement/Localization/Resources/it.json @@ -11,7 +11,6 @@ "ConnectionStrings": "Stringhe di connessione", "DisplayName:DefaultConnectionString": "Stringa di connessione predefinita", "DisplayName:UseSharedDatabase": "Usa il database condiviso", - "ManageHostFeatures": "Gestisci le funzionalità dell'host", "Permission:TenantManagement": "Gestione Tenant", "Permission:Create": "Crea", "Permission:Edit": "Modifica", diff --git a/modules/tenant-management/src/Volo.Abp.TenantManagement.Domain.Shared/Volo/Abp/TenantManagement/Localization/Resources/nl.json b/modules/tenant-management/src/Volo.Abp.TenantManagement.Domain.Shared/Volo/Abp/TenantManagement/Localization/Resources/nl.json index d4c45b8aad..1aeb208560 100644 --- a/modules/tenant-management/src/Volo.Abp.TenantManagement.Domain.Shared/Volo/Abp/TenantManagement/Localization/Resources/nl.json +++ b/modules/tenant-management/src/Volo.Abp.TenantManagement.Domain.Shared/Volo/Abp/TenantManagement/Localization/Resources/nl.json @@ -10,7 +10,6 @@ "ConnectionStrings": "Connection Strings", "DisplayName:DefaultConnectionString": "Standaard Connection String", "DisplayName:UseSharedDatabase": "Gebruik de gedeelde database", - "ManageHostFeatures": "Beheer host functies", "Permission:TenantManagement": "Klanten beheer", "Permission:Create": "Maak aan", "Permission:Edit": "Bewerk", diff --git a/modules/tenant-management/src/Volo.Abp.TenantManagement.Domain.Shared/Volo/Abp/TenantManagement/Localization/Resources/pl-PL.json b/modules/tenant-management/src/Volo.Abp.TenantManagement.Domain.Shared/Volo/Abp/TenantManagement/Localization/Resources/pl-PL.json index c62c67123e..6ec40c7310 100644 --- a/modules/tenant-management/src/Volo.Abp.TenantManagement.Domain.Shared/Volo/Abp/TenantManagement/Localization/Resources/pl-PL.json +++ b/modules/tenant-management/src/Volo.Abp.TenantManagement.Domain.Shared/Volo/Abp/TenantManagement/Localization/Resources/pl-PL.json @@ -10,7 +10,6 @@ "ConnectionStrings": "Connection Strings", "DisplayName:DefaultConnectionString": "Domyślny Connection String", "DisplayName:UseSharedDatabase": "Użyj współdzielonej bazy danych", - "ManageHostFeatures": "Zarządzaj funkcjami hosta", "Permission:TenantManagement": "Zarządzanie tenantami", "Permission:Create": "Utwórz", "Permission:Edit": "Edytuj", diff --git a/modules/tenant-management/src/Volo.Abp.TenantManagement.Domain.Shared/Volo/Abp/TenantManagement/Localization/Resources/pt-BR.json b/modules/tenant-management/src/Volo.Abp.TenantManagement.Domain.Shared/Volo/Abp/TenantManagement/Localization/Resources/pt-BR.json index d2c3ceecf1..d9f6b14a69 100644 --- a/modules/tenant-management/src/Volo.Abp.TenantManagement.Domain.Shared/Volo/Abp/TenantManagement/Localization/Resources/pt-BR.json +++ b/modules/tenant-management/src/Volo.Abp.TenantManagement.Domain.Shared/Volo/Abp/TenantManagement/Localization/Resources/pt-BR.json @@ -11,7 +11,6 @@ "ConnectionStrings": "Cadeia de Conexão", "DisplayName:DefaultConnectionString": "Cadeia de Conexão Padrão", "DisplayName:UseSharedDatabase": "Use o banco de dados compartilhado", - "ManageHostFeatures": "Gerenciar recursos do Host", "Permission:TenantManagement": "Inquilinos", "Permission:Create": "Criar", "Permission:Edit": "Editar", diff --git a/modules/tenant-management/src/Volo.Abp.TenantManagement.Domain.Shared/Volo/Abp/TenantManagement/Localization/Resources/ro-RO.json b/modules/tenant-management/src/Volo.Abp.TenantManagement.Domain.Shared/Volo/Abp/TenantManagement/Localization/Resources/ro-RO.json index 70147d9921..18bf9fb74e 100644 --- a/modules/tenant-management/src/Volo.Abp.TenantManagement.Domain.Shared/Volo/Abp/TenantManagement/Localization/Resources/ro-RO.json +++ b/modules/tenant-management/src/Volo.Abp.TenantManagement.Domain.Shared/Volo/Abp/TenantManagement/Localization/Resources/ro-RO.json @@ -10,7 +10,6 @@ "ConnectionStrings": "Connection Strings", "DisplayName:DefaultConnectionString": "Connection String implicit", "DisplayName:UseSharedDatabase": "Folosiţi baza de date partajată", - "ManageHostFeatures": "Administraţi caracteristicile de host", "Permission:TenantManagement": "Administrarea clienţilor", "Permission:Create": "Creează", "Permission:Edit": "Editează", diff --git a/modules/tenant-management/src/Volo.Abp.TenantManagement.Domain.Shared/Volo/Abp/TenantManagement/Localization/Resources/ru.json b/modules/tenant-management/src/Volo.Abp.TenantManagement.Domain.Shared/Volo/Abp/TenantManagement/Localization/Resources/ru.json index b3585c20a4..2204cf35cf 100644 --- a/modules/tenant-management/src/Volo.Abp.TenantManagement.Domain.Shared/Volo/Abp/TenantManagement/Localization/Resources/ru.json +++ b/modules/tenant-management/src/Volo.Abp.TenantManagement.Domain.Shared/Volo/Abp/TenantManagement/Localization/Resources/ru.json @@ -11,7 +11,6 @@ "ConnectionStrings": "Строки подключения", "DisplayName:DefaultConnectionString": "Строка подключения по умолчанию", "DisplayName:UseSharedDatabase": "Использование общей базы данных", - "ManageHostFeatures": "Управление функциями хоста", "Permission:TenantManagement": "Управление арендаторами", "Permission:Create": "Создать", "Permission:Edit": "Редактировать", diff --git a/modules/tenant-management/src/Volo.Abp.TenantManagement.Domain.Shared/Volo/Abp/TenantManagement/Localization/Resources/sk.json b/modules/tenant-management/src/Volo.Abp.TenantManagement.Domain.Shared/Volo/Abp/TenantManagement/Localization/Resources/sk.json index e37d605d16..1aff65e71c 100644 --- a/modules/tenant-management/src/Volo.Abp.TenantManagement.Domain.Shared/Volo/Abp/TenantManagement/Localization/Resources/sk.json +++ b/modules/tenant-management/src/Volo.Abp.TenantManagement.Domain.Shared/Volo/Abp/TenantManagement/Localization/Resources/sk.json @@ -11,7 +11,6 @@ "ConnectionStrings": "Connection stringy", "DisplayName:DefaultConnectionString": "Predvolený connection string", "DisplayName:UseSharedDatabase": "Použiť zdieľanú databázu", - "ManageHostFeatures": "Spravovať funkcie poskytovateľa", "Permission:TenantManagement": "Správa tenantov", "Permission:Create": "Vytvoriť", "Permission:Edit": "Upraviť", diff --git a/modules/tenant-management/src/Volo.Abp.TenantManagement.Domain.Shared/Volo/Abp/TenantManagement/Localization/Resources/sl.json b/modules/tenant-management/src/Volo.Abp.TenantManagement.Domain.Shared/Volo/Abp/TenantManagement/Localization/Resources/sl.json index 9e5d1c215a..a21cfa702a 100644 --- a/modules/tenant-management/src/Volo.Abp.TenantManagement.Domain.Shared/Volo/Abp/TenantManagement/Localization/Resources/sl.json +++ b/modules/tenant-management/src/Volo.Abp.TenantManagement.Domain.Shared/Volo/Abp/TenantManagement/Localization/Resources/sl.json @@ -11,7 +11,6 @@ "ConnectionStrings": "Connection Strings", "DisplayName:DefaultConnectionString": "Privzeti Connection String", "DisplayName:UseSharedDatabase": "Uporabi skupno bazo", - "ManageHostFeatures": "Upravljajte funkcije gostitelja", "Permission:TenantManagement": "Upravljanje najemnikov", "Permission:Create": "Ustvarjanje", "Permission:Edit": "Urejanje", diff --git a/modules/tenant-management/src/Volo.Abp.TenantManagement.Domain.Shared/Volo/Abp/TenantManagement/Localization/Resources/tr.json b/modules/tenant-management/src/Volo.Abp.TenantManagement.Domain.Shared/Volo/Abp/TenantManagement/Localization/Resources/tr.json index ffbab818f2..409aa40795 100644 --- a/modules/tenant-management/src/Volo.Abp.TenantManagement.Domain.Shared/Volo/Abp/TenantManagement/Localization/Resources/tr.json +++ b/modules/tenant-management/src/Volo.Abp.TenantManagement.Domain.Shared/Volo/Abp/TenantManagement/Localization/Resources/tr.json @@ -11,7 +11,6 @@ "ConnectionStrings": "Bağlantı cümlesi", "DisplayName:DefaultConnectionString": "Varsayılan bağlantı cümlesi", "DisplayName:UseSharedDatabase": "Paylaşılan veritabanını kullan", - "ManageHostFeatures": "Host özelliklerini yönetin", "Permission:TenantManagement": "Müşteri yönetimi", "Permission:Create": "Oluşturma", "Permission:Edit": "Düzenleme", diff --git a/modules/tenant-management/src/Volo.Abp.TenantManagement.Domain.Shared/Volo/Abp/TenantManagement/Localization/Resources/vi.json b/modules/tenant-management/src/Volo.Abp.TenantManagement.Domain.Shared/Volo/Abp/TenantManagement/Localization/Resources/vi.json index 025ec04eb6..4fafa9cc72 100644 --- a/modules/tenant-management/src/Volo.Abp.TenantManagement.Domain.Shared/Volo/Abp/TenantManagement/Localization/Resources/vi.json +++ b/modules/tenant-management/src/Volo.Abp.TenantManagement.Domain.Shared/Volo/Abp/TenantManagement/Localization/Resources/vi.json @@ -10,7 +10,6 @@ "ConnectionStrings": "Chuỗi kết nối", "DisplayName:DefaultConnectionString": "Chuỗi kết nối mặc định", "DisplayName:UseSharedDatabase": "Sử dụng cơ sở dữ liệu dùng chung", - "ManageHostFeatures": "Quản lý các tính năng của Máy chủ lưu trữ", "Permission:TenantManagement": "Quản lý khách thuê", "Permission:Create": "Tạo", "Permission:Edit": "Sửa", diff --git a/modules/tenant-management/src/Volo.Abp.TenantManagement.Domain.Shared/Volo/Abp/TenantManagement/Localization/Resources/zh-Hans.json b/modules/tenant-management/src/Volo.Abp.TenantManagement.Domain.Shared/Volo/Abp/TenantManagement/Localization/Resources/zh-Hans.json index 94ef8abba1..0367489a5a 100644 --- a/modules/tenant-management/src/Volo.Abp.TenantManagement.Domain.Shared/Volo/Abp/TenantManagement/Localization/Resources/zh-Hans.json +++ b/modules/tenant-management/src/Volo.Abp.TenantManagement.Domain.Shared/Volo/Abp/TenantManagement/Localization/Resources/zh-Hans.json @@ -11,7 +11,6 @@ "ConnectionStrings": "连接字符串", "DisplayName:DefaultConnectionString": "默认连接字符串", "DisplayName:UseSharedDatabase": "使用共享数据库", - "ManageHostFeatures": "管理Host特性", "Permission:TenantManagement": "租户管理", "Permission:Create": "创建", "Permission:Edit": "编辑", diff --git a/modules/tenant-management/src/Volo.Abp.TenantManagement.Domain.Shared/Volo/Abp/TenantManagement/Localization/Resources/zh-Hant.json b/modules/tenant-management/src/Volo.Abp.TenantManagement.Domain.Shared/Volo/Abp/TenantManagement/Localization/Resources/zh-Hant.json index 1403cb79d5..59519aff67 100644 --- a/modules/tenant-management/src/Volo.Abp.TenantManagement.Domain.Shared/Volo/Abp/TenantManagement/Localization/Resources/zh-Hant.json +++ b/modules/tenant-management/src/Volo.Abp.TenantManagement.Domain.Shared/Volo/Abp/TenantManagement/Localization/Resources/zh-Hant.json @@ -11,7 +11,6 @@ "ConnectionStrings": "資料庫連線字串", "DisplayName:DefaultConnectionString": "預設資料庫連線字串", "DisplayName:UseSharedDatabase": "使用共用資料庫", - "ManageHostFeatures": "管理Host功能", "Permission:TenantManagement": "租戶管理", "Permission:Create": "新增", "Permission:Edit": "編輯", diff --git a/modules/tenant-management/src/Volo.Abp.TenantManagement.Web/AbpTenantManagementWebModule.cs b/modules/tenant-management/src/Volo.Abp.TenantManagement.Web/AbpTenantManagementWebModule.cs index 1ac62db5e2..b3a63fb8ae 100644 --- a/modules/tenant-management/src/Volo.Abp.TenantManagement.Web/AbpTenantManagementWebModule.cs +++ b/modules/tenant-management/src/Volo.Abp.TenantManagement.Web/AbpTenantManagementWebModule.cs @@ -69,13 +69,6 @@ public class AbpTenantManagementWebModule : AbpModule options.Configure( toolbar => { - toolbar.AddButton( - LocalizableString.Create("ManageHostFeatures"), - icon: "cog", - name: "ManageHostFeatures", - requiredPolicyName: FeatureManagementPermissions.ManageHostFeatures - ); - toolbar.AddButton( LocalizableString.Create("NewTenant"), icon: "plus", diff --git a/modules/tenant-management/src/Volo.Abp.TenantManagement.Web/Pages/TenantManagement/Tenants/Index.js b/modules/tenant-management/src/Volo.Abp.TenantManagement.Web/Pages/TenantManagement/Tenants/Index.js index e990b8fc37..a9cf094c6c 100644 --- a/modules/tenant-management/src/Volo.Abp.TenantManagement.Web/Pages/TenantManagement/Tenants/Index.js +++ b/modules/tenant-management/src/Volo.Abp.TenantManagement.Web/Pages/TenantManagement/Tenants/Index.js @@ -113,12 +113,5 @@ e.preventDefault(); _createModal.open(); }); - - _$wrapper.find('button[name=ManageHostFeatures]').click(function (e) { - e.preventDefault(); - _featuresModal.open({ - providerName: 'T' - }); - }); }); })(); diff --git a/modules/virtual-file-explorer/src/Volo.Abp.VirtualFileExplorer.Web/Localization/Resources/pt-BR.json b/modules/virtual-file-explorer/src/Volo.Abp.VirtualFileExplorer.Web/Localization/Resources/pt-BR.json index d6fb96ed4e..f4b0675210 100644 --- a/modules/virtual-file-explorer/src/Volo.Abp.VirtualFileExplorer.Web/Localization/Resources/pt-BR.json +++ b/modules/virtual-file-explorer/src/Volo.Abp.VirtualFileExplorer.Web/Localization/Resources/pt-BR.json @@ -8,7 +8,7 @@ "VirtualFileName": "Nome do arquivo virtual", "FileContent": "Conteúdo do arquivo", "Size": "Tamanho", - "BackToRoot": "De volta à raiz", + "BackToRoot": "Voltar à raiz", "EmptyFileInfoList": "Não há arquivos virtuais" } } \ No newline at end of file diff --git a/npm/scripts/yarn.lock b/npm/scripts/yarn.lock index bae2201646..2feefc9b8a 100644 --- a/npm/scripts/yarn.lock +++ b/npm/scripts/yarn.lock @@ -1144,9 +1144,9 @@ locate-path@^6.0.0: p-locate "^5.0.0" lodash@^4.17.20: - version "4.17.20" - resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.20.tgz#b44a9b6297bcb698f1c51a3545a2b3b368d59c52" - integrity sha512-PlhdFcillOINfeV7Ni6oF1TAEayyZBoZ8bcshTHqOYJYlrqzRK5hagpagky5o4HfCzzd1TRkXPMFq6cKk9rGmA== + version "4.17.21" + resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c" + integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg== lowercase-keys@^1.0.0, lowercase-keys@^1.0.1: version "1.0.1" diff --git a/nupkg/common.ps1 b/nupkg/common.ps1 index bb434880de..002df803bd 100644 --- a/nupkg/common.ps1 +++ b/nupkg/common.ps1 @@ -99,6 +99,8 @@ $projects = ( "framework/src/Volo.Abp.AspNetCore.Authentication.OAuth", "framework/src/Volo.Abp.AspNetCore.Authentication.OpenIdConnect", "framework/src/Volo.Abp.AspNetCore", + "framework/src/Volo.Abp.AspNetCore.Mvc.Dapr", + "framework/src/Volo.Abp.AspNetCore.Mvc.Dapr.EventBus", "framework/src/Volo.Abp.AspNetCore.Components", "framework/src/Volo.Abp.AspNetCore.Components.Server", "framework/src/Volo.Abp.AspNetCore.Components.Web", @@ -155,12 +157,14 @@ $projects = ( "framework/src/Volo.Abp.Core", "framework/src/Volo.Abp", "framework/src/Volo.Abp.Dapper", + "framework/src/Volo.Abp.Dapr", "framework/src/Volo.Abp.Data", "framework/src/Volo.Abp.Ddd.Application", "framework/src/Volo.Abp.Ddd.Application.Contracts", "framework/src/Volo.Abp.Ddd.Domain", "framework/src/Volo.Abp.DistributedLocking.Abstractions", "framework/src/Volo.Abp.DistributedLocking", + "framework/src/Volo.Abp.DistributedLocking.Dapr", "framework/src/Volo.Abp.Emailing", "framework/src/Volo.Abp.EntityFrameworkCore", "framework/src/Volo.Abp.EntityFrameworkCore.MySQL", @@ -175,6 +179,7 @@ $projects = ( "framework/src/Volo.Abp.EventBus.Kafka", "framework/src/Volo.Abp.EventBus.Rebus", "framework/src/Volo.Abp.EventBus.Azure", + "framework/src/Volo.Abp.EventBus.Dapr", "framework/src/Volo.Abp.ExceptionHandling", "framework/src/Volo.Abp.Features", "framework/src/Volo.Abp.FluentValidation", @@ -184,7 +189,8 @@ $projects = ( "framework/src/Volo.Abp.HangFire", "framework/src/Volo.Abp.Http.Abstractions", "framework/src/Volo.Abp.Http.Client", - "framework/src/Volo.Abp.Http.Client.Web", + "framework/src/Volo.Abp.Http.Client.Dapr", + "framework/src/Volo.Abp.Http.Client.Web", "framework/src/Volo.Abp.Http.Client.IdentityModel", "framework/src/Volo.Abp.Http.Client.IdentityModel.Web", "framework/src/Volo.Abp.Http.Client.IdentityModel.WebAssembly", diff --git a/templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Blazor.Server.Mongo/Localization/MyProjectName/ar.json b/templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Blazor.Server.Mongo/Localization/MyProjectName/ar.json index 1ee94530fb..153f571276 100644 --- a/templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Blazor.Server.Mongo/Localization/MyProjectName/ar.json +++ b/templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Blazor.Server.Mongo/Localization/MyProjectName/ar.json @@ -3,6 +3,6 @@ "texts": { "Welcome_Title": "مرحبا", "Welcome_Text": "هذا هو قالب بدء تشغيل تطبيق ذو طبقة واحدة مبسط لإطار عمل ABP.", - "Menu:Home": "الرئيسية" + "Menu:Home": "الصفحة الرئيسية" } } diff --git a/templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Blazor.Server/Localization/MyProjectName/ar.json b/templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Blazor.Server/Localization/MyProjectName/ar.json index 1ee94530fb..153f571276 100644 --- a/templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Blazor.Server/Localization/MyProjectName/ar.json +++ b/templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Blazor.Server/Localization/MyProjectName/ar.json @@ -3,6 +3,6 @@ "texts": { "Welcome_Title": "مرحبا", "Welcome_Text": "هذا هو قالب بدء تشغيل تطبيق ذو طبقة واحدة مبسط لإطار عمل ABP.", - "Menu:Home": "الرئيسية" + "Menu:Home": "الصفحة الرئيسية" } } diff --git a/templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Blazor.Server/Migrations/20220617083820_Initial.Designer.cs b/templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Blazor.Server/Migrations/20220825012458_Initial.Designer.cs similarity index 95% rename from templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Blazor.Server/Migrations/20220617083820_Initial.Designer.cs rename to templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Blazor.Server/Migrations/20220825012458_Initial.Designer.cs index 9e1a8f9cd8..5347dc149d 100644 --- a/templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Blazor.Server/Migrations/20220617083820_Initial.Designer.cs +++ b/templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Blazor.Server/Migrations/20220825012458_Initial.Designer.cs @@ -13,7 +13,7 @@ using Volo.Abp.EntityFrameworkCore; namespace MyCompanyName.MyProjectName.Blazor.Server.Migrations { [DbContext(typeof(MyProjectNameDbContext))] - [Migration("20220617083820_Initial")] + [Migration("20220825012458_Initial")] partial class Initial { protected override void BuildTargetModel(ModelBuilder modelBuilder) @@ -1273,6 +1273,59 @@ namespace MyCompanyName.MyProjectName.Blazor.Server.Migrations b.ToTable("OpenIddictTokens", (string)null); }); + modelBuilder.Entity("Volo.Abp.PermissionManagement.PermissionDefinitionRecord", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("DisplayName") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.Property("ExtraProperties") + .HasColumnType("nvarchar(max)") + .HasColumnName("ExtraProperties"); + + b.Property("GroupName") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("nvarchar(128)"); + + b.Property("IsEnabled") + .HasColumnType("bit"); + + b.Property("MultiTenancySide") + .HasColumnType("tinyint"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("nvarchar(128)"); + + b.Property("ParentName") + .HasMaxLength(128) + .HasColumnType("nvarchar(128)"); + + b.Property("Providers") + .HasMaxLength(128) + .HasColumnType("nvarchar(128)"); + + b.Property("StateCheckers") + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.HasKey("Id"); + + b.HasIndex("GroupName"); + + b.HasIndex("Name") + .IsUnique(); + + b.ToTable("AbpPermissions", (string)null); + }); + modelBuilder.Entity("Volo.Abp.PermissionManagement.PermissionGrant", b => { b.Property("Id") @@ -1307,6 +1360,34 @@ namespace MyCompanyName.MyProjectName.Blazor.Server.Migrations b.ToTable("AbpPermissionGrants", (string)null); }); + modelBuilder.Entity("Volo.Abp.PermissionManagement.PermissionGroupDefinitionRecord", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("DisplayName") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.Property("ExtraProperties") + .HasColumnType("nvarchar(max)") + .HasColumnName("ExtraProperties"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("nvarchar(128)"); + + b.HasKey("Id"); + + b.HasIndex("Name") + .IsUnique(); + + b.ToTable("AbpPermissionGroups", (string)null); + }); + modelBuilder.Entity("Volo.Abp.SettingManagement.Setting", b => { b.Property("Id") diff --git a/templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Blazor.Server/Migrations/20220617083820_Initial.cs b/templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Blazor.Server/Migrations/20220825012458_Initial.cs similarity index 94% rename from templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Blazor.Server/Migrations/20220617083820_Initial.cs rename to templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Blazor.Server/Migrations/20220825012458_Initial.cs index 85d36d8b57..13ecbb5be7 100644 --- a/templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Blazor.Server/Migrations/20220617083820_Initial.cs +++ b/templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Blazor.Server/Migrations/20220825012458_Initial.cs @@ -137,6 +137,40 @@ namespace MyCompanyName.MyProjectName.Blazor.Server.Migrations table.PrimaryKey("PK_AbpPermissionGrants", x => x.Id); }); + migrationBuilder.CreateTable( + name: "AbpPermissionGroups", + columns: table => new + { + Id = table.Column(type: "uniqueidentifier", nullable: false), + Name = table.Column(type: "nvarchar(128)", maxLength: 128, nullable: false), + DisplayName = table.Column(type: "nvarchar(256)", maxLength: 256, nullable: false), + ExtraProperties = table.Column(type: "nvarchar(max)", nullable: true) + }, + constraints: table => + { + table.PrimaryKey("PK_AbpPermissionGroups", x => x.Id); + }); + + migrationBuilder.CreateTable( + name: "AbpPermissions", + columns: table => new + { + Id = table.Column(type: "uniqueidentifier", nullable: false), + GroupName = table.Column(type: "nvarchar(128)", maxLength: 128, nullable: false), + Name = table.Column(type: "nvarchar(128)", maxLength: 128, nullable: false), + ParentName = table.Column(type: "nvarchar(128)", maxLength: 128, nullable: true), + DisplayName = table.Column(type: "nvarchar(256)", maxLength: 256, nullable: false), + IsEnabled = table.Column(type: "bit", nullable: false), + MultiTenancySide = table.Column(type: "tinyint", nullable: false), + Providers = table.Column(type: "nvarchar(128)", maxLength: 128, nullable: true), + StateCheckers = table.Column(type: "nvarchar(256)", maxLength: 256, nullable: true), + ExtraProperties = table.Column(type: "nvarchar(max)", nullable: true) + }, + constraints: table => + { + table.PrimaryKey("PK_AbpPermissions", x => x.Id); + }); + migrationBuilder.CreateTable( name: "AbpRoles", columns: table => new @@ -714,6 +748,23 @@ namespace MyCompanyName.MyProjectName.Blazor.Server.Migrations unique: true, filter: "[TenantId] IS NOT NULL"); + migrationBuilder.CreateIndex( + name: "IX_AbpPermissionGroups_Name", + table: "AbpPermissionGroups", + column: "Name", + unique: true); + + migrationBuilder.CreateIndex( + name: "IX_AbpPermissions_GroupName", + table: "AbpPermissions", + column: "GroupName"); + + migrationBuilder.CreateIndex( + name: "IX_AbpPermissions_Name", + table: "AbpPermissions", + column: "Name", + unique: true); + migrationBuilder.CreateIndex( name: "IX_AbpRoleClaims_RoleId", table: "AbpRoleClaims", @@ -850,6 +901,12 @@ namespace MyCompanyName.MyProjectName.Blazor.Server.Migrations migrationBuilder.DropTable( name: "AbpPermissionGrants"); + migrationBuilder.DropTable( + name: "AbpPermissionGroups"); + + migrationBuilder.DropTable( + name: "AbpPermissions"); + migrationBuilder.DropTable( name: "AbpRoleClaims"); diff --git a/templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Blazor.Server/Migrations/MyProjectNameDbContextModelSnapshot.cs b/templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Blazor.Server/Migrations/MyProjectNameDbContextModelSnapshot.cs index 0a32c8664e..d6c92decad 100644 --- a/templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Blazor.Server/Migrations/MyProjectNameDbContextModelSnapshot.cs +++ b/templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Blazor.Server/Migrations/MyProjectNameDbContextModelSnapshot.cs @@ -1271,6 +1271,59 @@ namespace MyCompanyName.MyProjectName.Blazor.Server.Migrations b.ToTable("OpenIddictTokens", (string)null); }); + modelBuilder.Entity("Volo.Abp.PermissionManagement.PermissionDefinitionRecord", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("DisplayName") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.Property("ExtraProperties") + .HasColumnType("nvarchar(max)") + .HasColumnName("ExtraProperties"); + + b.Property("GroupName") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("nvarchar(128)"); + + b.Property("IsEnabled") + .HasColumnType("bit"); + + b.Property("MultiTenancySide") + .HasColumnType("tinyint"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("nvarchar(128)"); + + b.Property("ParentName") + .HasMaxLength(128) + .HasColumnType("nvarchar(128)"); + + b.Property("Providers") + .HasMaxLength(128) + .HasColumnType("nvarchar(128)"); + + b.Property("StateCheckers") + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.HasKey("Id"); + + b.HasIndex("GroupName"); + + b.HasIndex("Name") + .IsUnique(); + + b.ToTable("AbpPermissions", (string)null); + }); + modelBuilder.Entity("Volo.Abp.PermissionManagement.PermissionGrant", b => { b.Property("Id") @@ -1305,6 +1358,34 @@ namespace MyCompanyName.MyProjectName.Blazor.Server.Migrations b.ToTable("AbpPermissionGrants", (string)null); }); + modelBuilder.Entity("Volo.Abp.PermissionManagement.PermissionGroupDefinitionRecord", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("DisplayName") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.Property("ExtraProperties") + .HasColumnType("nvarchar(max)") + .HasColumnName("ExtraProperties"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("nvarchar(128)"); + + b.HasKey("Id"); + + b.HasIndex("Name") + .IsUnique(); + + b.ToTable("AbpPermissionGroups", (string)null); + }); + modelBuilder.Entity("Volo.Abp.SettingManagement.Setting", b => { b.Property("Id") diff --git a/templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Host.Mongo/Localization/MyProjectName/ar.json b/templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Host.Mongo/Localization/MyProjectName/ar.json index 1ee94530fb..153f571276 100644 --- a/templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Host.Mongo/Localization/MyProjectName/ar.json +++ b/templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Host.Mongo/Localization/MyProjectName/ar.json @@ -3,6 +3,6 @@ "texts": { "Welcome_Title": "مرحبا", "Welcome_Text": "هذا هو قالب بدء تشغيل تطبيق ذو طبقة واحدة مبسط لإطار عمل ABP.", - "Menu:Home": "الرئيسية" + "Menu:Home": "الصفحة الرئيسية" } } diff --git a/templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Host/Localization/MyProjectName/ar.json b/templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Host/Localization/MyProjectName/ar.json index 1ee94530fb..153f571276 100644 --- a/templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Host/Localization/MyProjectName/ar.json +++ b/templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Host/Localization/MyProjectName/ar.json @@ -3,6 +3,6 @@ "texts": { "Welcome_Title": "مرحبا", "Welcome_Text": "هذا هو قالب بدء تشغيل تطبيق ذو طبقة واحدة مبسط لإطار عمل ABP.", - "Menu:Home": "الرئيسية" + "Menu:Home": "الصفحة الرئيسية" } } diff --git a/templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Host/Migrations/20220617083539_Initial.Designer.cs b/templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Host/Migrations/20220825012635_Initial.Designer.cs similarity index 95% rename from templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Host/Migrations/20220617083539_Initial.Designer.cs rename to templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Host/Migrations/20220825012635_Initial.Designer.cs index 5b55ca75a9..0c525e8471 100644 --- a/templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Host/Migrations/20220617083539_Initial.Designer.cs +++ b/templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Host/Migrations/20220825012635_Initial.Designer.cs @@ -13,7 +13,7 @@ using Volo.Abp.EntityFrameworkCore; namespace MyCompanyName.MyProjectName.Host.Migrations { [DbContext(typeof(MyProjectNameDbContext))] - [Migration("20220617083539_Initial")] + [Migration("20220825012635_Initial")] partial class Initial { protected override void BuildTargetModel(ModelBuilder modelBuilder) @@ -1273,6 +1273,59 @@ namespace MyCompanyName.MyProjectName.Host.Migrations b.ToTable("OpenIddictTokens", (string)null); }); + modelBuilder.Entity("Volo.Abp.PermissionManagement.PermissionDefinitionRecord", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("DisplayName") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.Property("ExtraProperties") + .HasColumnType("nvarchar(max)") + .HasColumnName("ExtraProperties"); + + b.Property("GroupName") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("nvarchar(128)"); + + b.Property("IsEnabled") + .HasColumnType("bit"); + + b.Property("MultiTenancySide") + .HasColumnType("tinyint"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("nvarchar(128)"); + + b.Property("ParentName") + .HasMaxLength(128) + .HasColumnType("nvarchar(128)"); + + b.Property("Providers") + .HasMaxLength(128) + .HasColumnType("nvarchar(128)"); + + b.Property("StateCheckers") + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.HasKey("Id"); + + b.HasIndex("GroupName"); + + b.HasIndex("Name") + .IsUnique(); + + b.ToTable("AbpPermissions", (string)null); + }); + modelBuilder.Entity("Volo.Abp.PermissionManagement.PermissionGrant", b => { b.Property("Id") @@ -1307,6 +1360,34 @@ namespace MyCompanyName.MyProjectName.Host.Migrations b.ToTable("AbpPermissionGrants", (string)null); }); + modelBuilder.Entity("Volo.Abp.PermissionManagement.PermissionGroupDefinitionRecord", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("DisplayName") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.Property("ExtraProperties") + .HasColumnType("nvarchar(max)") + .HasColumnName("ExtraProperties"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("nvarchar(128)"); + + b.HasKey("Id"); + + b.HasIndex("Name") + .IsUnique(); + + b.ToTable("AbpPermissionGroups", (string)null); + }); + modelBuilder.Entity("Volo.Abp.SettingManagement.Setting", b => { b.Property("Id") diff --git a/templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Host/Migrations/20220617083539_Initial.cs b/templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Host/Migrations/20220825012635_Initial.cs similarity index 94% rename from templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Host/Migrations/20220617083539_Initial.cs rename to templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Host/Migrations/20220825012635_Initial.cs index 29cc53b046..8342507d18 100644 --- a/templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Host/Migrations/20220617083539_Initial.cs +++ b/templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Host/Migrations/20220825012635_Initial.cs @@ -137,6 +137,40 @@ namespace MyCompanyName.MyProjectName.Host.Migrations table.PrimaryKey("PK_AbpPermissionGrants", x => x.Id); }); + migrationBuilder.CreateTable( + name: "AbpPermissionGroups", + columns: table => new + { + Id = table.Column(type: "uniqueidentifier", nullable: false), + Name = table.Column(type: "nvarchar(128)", maxLength: 128, nullable: false), + DisplayName = table.Column(type: "nvarchar(256)", maxLength: 256, nullable: false), + ExtraProperties = table.Column(type: "nvarchar(max)", nullable: true) + }, + constraints: table => + { + table.PrimaryKey("PK_AbpPermissionGroups", x => x.Id); + }); + + migrationBuilder.CreateTable( + name: "AbpPermissions", + columns: table => new + { + Id = table.Column(type: "uniqueidentifier", nullable: false), + GroupName = table.Column(type: "nvarchar(128)", maxLength: 128, nullable: false), + Name = table.Column(type: "nvarchar(128)", maxLength: 128, nullable: false), + ParentName = table.Column(type: "nvarchar(128)", maxLength: 128, nullable: true), + DisplayName = table.Column(type: "nvarchar(256)", maxLength: 256, nullable: false), + IsEnabled = table.Column(type: "bit", nullable: false), + MultiTenancySide = table.Column(type: "tinyint", nullable: false), + Providers = table.Column(type: "nvarchar(128)", maxLength: 128, nullable: true), + StateCheckers = table.Column(type: "nvarchar(256)", maxLength: 256, nullable: true), + ExtraProperties = table.Column(type: "nvarchar(max)", nullable: true) + }, + constraints: table => + { + table.PrimaryKey("PK_AbpPermissions", x => x.Id); + }); + migrationBuilder.CreateTable( name: "AbpRoles", columns: table => new @@ -714,6 +748,23 @@ namespace MyCompanyName.MyProjectName.Host.Migrations unique: true, filter: "[TenantId] IS NOT NULL"); + migrationBuilder.CreateIndex( + name: "IX_AbpPermissionGroups_Name", + table: "AbpPermissionGroups", + column: "Name", + unique: true); + + migrationBuilder.CreateIndex( + name: "IX_AbpPermissions_GroupName", + table: "AbpPermissions", + column: "GroupName"); + + migrationBuilder.CreateIndex( + name: "IX_AbpPermissions_Name", + table: "AbpPermissions", + column: "Name", + unique: true); + migrationBuilder.CreateIndex( name: "IX_AbpRoleClaims_RoleId", table: "AbpRoleClaims", @@ -850,6 +901,12 @@ namespace MyCompanyName.MyProjectName.Host.Migrations migrationBuilder.DropTable( name: "AbpPermissionGrants"); + migrationBuilder.DropTable( + name: "AbpPermissionGroups"); + + migrationBuilder.DropTable( + name: "AbpPermissions"); + migrationBuilder.DropTable( name: "AbpRoleClaims"); diff --git a/templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Host/Migrations/MyProjectNameDbContextModelSnapshot.cs b/templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Host/Migrations/MyProjectNameDbContextModelSnapshot.cs index 2597920679..7360423342 100644 --- a/templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Host/Migrations/MyProjectNameDbContextModelSnapshot.cs +++ b/templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Host/Migrations/MyProjectNameDbContextModelSnapshot.cs @@ -1271,6 +1271,59 @@ namespace MyCompanyName.MyProjectName.Host.Migrations b.ToTable("OpenIddictTokens", (string)null); }); + modelBuilder.Entity("Volo.Abp.PermissionManagement.PermissionDefinitionRecord", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("DisplayName") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.Property("ExtraProperties") + .HasColumnType("nvarchar(max)") + .HasColumnName("ExtraProperties"); + + b.Property("GroupName") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("nvarchar(128)"); + + b.Property("IsEnabled") + .HasColumnType("bit"); + + b.Property("MultiTenancySide") + .HasColumnType("tinyint"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("nvarchar(128)"); + + b.Property("ParentName") + .HasMaxLength(128) + .HasColumnType("nvarchar(128)"); + + b.Property("Providers") + .HasMaxLength(128) + .HasColumnType("nvarchar(128)"); + + b.Property("StateCheckers") + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.HasKey("Id"); + + b.HasIndex("GroupName"); + + b.HasIndex("Name") + .IsUnique(); + + b.ToTable("AbpPermissions", (string)null); + }); + modelBuilder.Entity("Volo.Abp.PermissionManagement.PermissionGrant", b => { b.Property("Id") @@ -1305,6 +1358,34 @@ namespace MyCompanyName.MyProjectName.Host.Migrations b.ToTable("AbpPermissionGrants", (string)null); }); + modelBuilder.Entity("Volo.Abp.PermissionManagement.PermissionGroupDefinitionRecord", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("DisplayName") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.Property("ExtraProperties") + .HasColumnType("nvarchar(max)") + .HasColumnName("ExtraProperties"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("nvarchar(128)"); + + b.HasKey("Id"); + + b.HasIndex("Name") + .IsUnique(); + + b.ToTable("AbpPermissionGroups", (string)null); + }); + modelBuilder.Entity("Volo.Abp.SettingManagement.Setting", b => { b.Property("Id") diff --git a/templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Mvc.Mongo/Localization/MyProjectName/ar.json b/templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Mvc.Mongo/Localization/MyProjectName/ar.json index 1ee94530fb..153f571276 100644 --- a/templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Mvc.Mongo/Localization/MyProjectName/ar.json +++ b/templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Mvc.Mongo/Localization/MyProjectName/ar.json @@ -3,6 +3,6 @@ "texts": { "Welcome_Title": "مرحبا", "Welcome_Text": "هذا هو قالب بدء تشغيل تطبيق ذو طبقة واحدة مبسط لإطار عمل ABP.", - "Menu:Home": "الرئيسية" + "Menu:Home": "الصفحة الرئيسية" } } diff --git a/templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Mvc/Localization/MyProjectName/ar.json b/templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Mvc/Localization/MyProjectName/ar.json index 1ee94530fb..153f571276 100644 --- a/templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Mvc/Localization/MyProjectName/ar.json +++ b/templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Mvc/Localization/MyProjectName/ar.json @@ -3,6 +3,6 @@ "texts": { "Welcome_Title": "مرحبا", "Welcome_Text": "هذا هو قالب بدء تشغيل تطبيق ذو طبقة واحدة مبسط لإطار عمل ABP.", - "Menu:Home": "الرئيسية" + "Menu:Home": "الصفحة الرئيسية" } } diff --git a/templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Mvc/Migrations/20220617083649_Initial.Designer.cs b/templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Mvc/Migrations/20220825012450_Initial.Designer.cs similarity index 95% rename from templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Mvc/Migrations/20220617083649_Initial.Designer.cs rename to templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Mvc/Migrations/20220825012450_Initial.Designer.cs index 213ce02572..94f77b9938 100644 --- a/templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Mvc/Migrations/20220617083649_Initial.Designer.cs +++ b/templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Mvc/Migrations/20220825012450_Initial.Designer.cs @@ -13,7 +13,7 @@ using Volo.Abp.EntityFrameworkCore; namespace MyCompanyName.MyProjectName.Mvc.Migrations { [DbContext(typeof(MyProjectNameDbContext))] - [Migration("20220617083649_Initial")] + [Migration("20220825012450_Initial")] partial class Initial { protected override void BuildTargetModel(ModelBuilder modelBuilder) @@ -1273,6 +1273,59 @@ namespace MyCompanyName.MyProjectName.Mvc.Migrations b.ToTable("OpenIddictTokens", (string)null); }); + modelBuilder.Entity("Volo.Abp.PermissionManagement.PermissionDefinitionRecord", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("DisplayName") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.Property("ExtraProperties") + .HasColumnType("nvarchar(max)") + .HasColumnName("ExtraProperties"); + + b.Property("GroupName") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("nvarchar(128)"); + + b.Property("IsEnabled") + .HasColumnType("bit"); + + b.Property("MultiTenancySide") + .HasColumnType("tinyint"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("nvarchar(128)"); + + b.Property("ParentName") + .HasMaxLength(128) + .HasColumnType("nvarchar(128)"); + + b.Property("Providers") + .HasMaxLength(128) + .HasColumnType("nvarchar(128)"); + + b.Property("StateCheckers") + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.HasKey("Id"); + + b.HasIndex("GroupName"); + + b.HasIndex("Name") + .IsUnique(); + + b.ToTable("AbpPermissions", (string)null); + }); + modelBuilder.Entity("Volo.Abp.PermissionManagement.PermissionGrant", b => { b.Property("Id") @@ -1307,6 +1360,34 @@ namespace MyCompanyName.MyProjectName.Mvc.Migrations b.ToTable("AbpPermissionGrants", (string)null); }); + modelBuilder.Entity("Volo.Abp.PermissionManagement.PermissionGroupDefinitionRecord", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("DisplayName") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.Property("ExtraProperties") + .HasColumnType("nvarchar(max)") + .HasColumnName("ExtraProperties"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("nvarchar(128)"); + + b.HasKey("Id"); + + b.HasIndex("Name") + .IsUnique(); + + b.ToTable("AbpPermissionGroups", (string)null); + }); + modelBuilder.Entity("Volo.Abp.SettingManagement.Setting", b => { b.Property("Id") diff --git a/templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Mvc/Migrations/20220617083649_Initial.cs b/templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Mvc/Migrations/20220825012450_Initial.cs similarity index 94% rename from templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Mvc/Migrations/20220617083649_Initial.cs rename to templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Mvc/Migrations/20220825012450_Initial.cs index 2a30fba759..df71202963 100644 --- a/templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Mvc/Migrations/20220617083649_Initial.cs +++ b/templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Mvc/Migrations/20220825012450_Initial.cs @@ -137,6 +137,40 @@ namespace MyCompanyName.MyProjectName.Mvc.Migrations table.PrimaryKey("PK_AbpPermissionGrants", x => x.Id); }); + migrationBuilder.CreateTable( + name: "AbpPermissionGroups", + columns: table => new + { + Id = table.Column(type: "uniqueidentifier", nullable: false), + Name = table.Column(type: "nvarchar(128)", maxLength: 128, nullable: false), + DisplayName = table.Column(type: "nvarchar(256)", maxLength: 256, nullable: false), + ExtraProperties = table.Column(type: "nvarchar(max)", nullable: true) + }, + constraints: table => + { + table.PrimaryKey("PK_AbpPermissionGroups", x => x.Id); + }); + + migrationBuilder.CreateTable( + name: "AbpPermissions", + columns: table => new + { + Id = table.Column(type: "uniqueidentifier", nullable: false), + GroupName = table.Column(type: "nvarchar(128)", maxLength: 128, nullable: false), + Name = table.Column(type: "nvarchar(128)", maxLength: 128, nullable: false), + ParentName = table.Column(type: "nvarchar(128)", maxLength: 128, nullable: true), + DisplayName = table.Column(type: "nvarchar(256)", maxLength: 256, nullable: false), + IsEnabled = table.Column(type: "bit", nullable: false), + MultiTenancySide = table.Column(type: "tinyint", nullable: false), + Providers = table.Column(type: "nvarchar(128)", maxLength: 128, nullable: true), + StateCheckers = table.Column(type: "nvarchar(256)", maxLength: 256, nullable: true), + ExtraProperties = table.Column(type: "nvarchar(max)", nullable: true) + }, + constraints: table => + { + table.PrimaryKey("PK_AbpPermissions", x => x.Id); + }); + migrationBuilder.CreateTable( name: "AbpRoles", columns: table => new @@ -714,6 +748,23 @@ namespace MyCompanyName.MyProjectName.Mvc.Migrations unique: true, filter: "[TenantId] IS NOT NULL"); + migrationBuilder.CreateIndex( + name: "IX_AbpPermissionGroups_Name", + table: "AbpPermissionGroups", + column: "Name", + unique: true); + + migrationBuilder.CreateIndex( + name: "IX_AbpPermissions_GroupName", + table: "AbpPermissions", + column: "GroupName"); + + migrationBuilder.CreateIndex( + name: "IX_AbpPermissions_Name", + table: "AbpPermissions", + column: "Name", + unique: true); + migrationBuilder.CreateIndex( name: "IX_AbpRoleClaims_RoleId", table: "AbpRoleClaims", @@ -850,6 +901,12 @@ namespace MyCompanyName.MyProjectName.Mvc.Migrations migrationBuilder.DropTable( name: "AbpPermissionGrants"); + migrationBuilder.DropTable( + name: "AbpPermissionGroups"); + + migrationBuilder.DropTable( + name: "AbpPermissions"); + migrationBuilder.DropTable( name: "AbpRoleClaims"); diff --git a/templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Mvc/Migrations/MyProjectNameDbContextModelSnapshot.cs b/templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Mvc/Migrations/MyProjectNameDbContextModelSnapshot.cs index 350f086968..80d24ed8d2 100644 --- a/templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Mvc/Migrations/MyProjectNameDbContextModelSnapshot.cs +++ b/templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Mvc/Migrations/MyProjectNameDbContextModelSnapshot.cs @@ -1271,6 +1271,59 @@ namespace MyCompanyName.MyProjectName.Mvc.Migrations b.ToTable("OpenIddictTokens", (string)null); }); + modelBuilder.Entity("Volo.Abp.PermissionManagement.PermissionDefinitionRecord", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("DisplayName") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.Property("ExtraProperties") + .HasColumnType("nvarchar(max)") + .HasColumnName("ExtraProperties"); + + b.Property("GroupName") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("nvarchar(128)"); + + b.Property("IsEnabled") + .HasColumnType("bit"); + + b.Property("MultiTenancySide") + .HasColumnType("tinyint"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("nvarchar(128)"); + + b.Property("ParentName") + .HasMaxLength(128) + .HasColumnType("nvarchar(128)"); + + b.Property("Providers") + .HasMaxLength(128) + .HasColumnType("nvarchar(128)"); + + b.Property("StateCheckers") + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.HasKey("Id"); + + b.HasIndex("GroupName"); + + b.HasIndex("Name") + .IsUnique(); + + b.ToTable("AbpPermissions", (string)null); + }); + modelBuilder.Entity("Volo.Abp.PermissionManagement.PermissionGrant", b => { b.Property("Id") @@ -1305,6 +1358,34 @@ namespace MyCompanyName.MyProjectName.Mvc.Migrations b.ToTable("AbpPermissionGrants", (string)null); }); + modelBuilder.Entity("Volo.Abp.PermissionManagement.PermissionGroupDefinitionRecord", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("DisplayName") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.Property("ExtraProperties") + .HasColumnType("nvarchar(max)") + .HasColumnName("ExtraProperties"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("nvarchar(128)"); + + b.HasKey("Id"); + + b.HasIndex("Name") + .IsUnique(); + + b.ToTable("AbpPermissionGroups", (string)null); + }); + modelBuilder.Entity("Volo.Abp.SettingManagement.Setting", b => { b.Property("Id") diff --git a/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.Domain.Shared/Localization/MyProjectName/ar.json b/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.Domain.Shared/Localization/MyProjectName/ar.json index 3e5227a915..96bbf80b40 100644 --- a/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.Domain.Shared/Localization/MyProjectName/ar.json +++ b/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.Domain.Shared/Localization/MyProjectName/ar.json @@ -2,7 +2,7 @@ "culture": "ar", "texts": { "Menu:Home": "الرئيسية", - "Welcome": "مرحبا", + "Menu:Home": "الصفحة الرئيسية", "LongWelcomeMessage": "مرحبا بكم في التطبيق. هذا مشروع بدء تشغيل يعتمد على إطار عمل ABP. لمزيد من المعلومات ، يرجى زيارة abp.io." } -} \ No newline at end of file +} diff --git a/templates/module/aspnet-core/host/MyCompanyName.MyProjectName.AuthServer/Migrations/20220617083652_Initial.Designer.cs b/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.EntityFrameworkCore/Migrations/20220825012254_Initial.Designer.cs similarity index 92% rename from templates/module/aspnet-core/host/MyCompanyName.MyProjectName.AuthServer/Migrations/20220617083652_Initial.Designer.cs rename to templates/app/aspnet-core/src/MyCompanyName.MyProjectName.EntityFrameworkCore/Migrations/20220825012254_Initial.Designer.cs index ae32d5daa9..41c49a2e4d 100644 --- a/templates/module/aspnet-core/host/MyCompanyName.MyProjectName.AuthServer/Migrations/20220617083652_Initial.Designer.cs +++ b/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.EntityFrameworkCore/Migrations/20220825012254_Initial.Designer.cs @@ -12,8 +12,8 @@ using Volo.Abp.EntityFrameworkCore; namespace MyCompanyName.MyProjectName.Migrations { - [DbContext(typeof(AuthServerDbContext))] - [Migration("20220617083652_Initial")] + [DbContext(typeof(MyProjectNameDbContext))] + [Migration("20220825012254_Initial")] partial class Initial { protected override void BuildTargetModel(ModelBuilder modelBuilder) @@ -288,6 +288,64 @@ namespace MyCompanyName.MyProjectName.Migrations b.ToTable("AbpEntityPropertyChanges", (string)null); }); + modelBuilder.Entity("Volo.Abp.BackgroundJobs.BackgroundJobRecord", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .HasMaxLength(40) + .HasColumnType("nvarchar(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("CreationTime") + .HasColumnType("datetime2") + .HasColumnName("CreationTime"); + + b.Property("ExtraProperties") + .HasColumnType("nvarchar(max)") + .HasColumnName("ExtraProperties"); + + b.Property("IsAbandoned") + .ValueGeneratedOnAdd() + .HasColumnType("bit") + .HasDefaultValue(false); + + b.Property("JobArgs") + .IsRequired() + .HasMaxLength(1048576) + .HasColumnType("nvarchar(max)"); + + b.Property("JobName") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("nvarchar(128)"); + + b.Property("LastTryTime") + .HasColumnType("datetime2"); + + b.Property("NextTryTime") + .HasColumnType("datetime2"); + + b.Property("Priority") + .ValueGeneratedOnAdd() + .HasColumnType("tinyint") + .HasDefaultValue((byte)15); + + b.Property("TryCount") + .ValueGeneratedOnAdd() + .HasColumnType("smallint") + .HasDefaultValue((short)0); + + b.HasKey("Id"); + + b.HasIndex("IsAbandoned", "NextTryTime"); + + b.ToTable("AbpBackgroundJobs", (string)null); + }); + modelBuilder.Entity("Volo.Abp.FeatureManagement.FeatureValue", b => { b.Property("Id") @@ -324,7 +382,6 @@ namespace MyCompanyName.MyProjectName.Migrations modelBuilder.Entity("Volo.Abp.Identity.IdentityClaimType", b => { b.Property("Id") - .ValueGeneratedOnAdd() .HasColumnType("uniqueidentifier"); b.Property("ConcurrencyStamp") @@ -371,7 +428,6 @@ namespace MyCompanyName.MyProjectName.Migrations modelBuilder.Entity("Volo.Abp.Identity.IdentityLinkUser", b => { b.Property("Id") - .ValueGeneratedOnAdd() .HasColumnType("uniqueidentifier"); b.Property("SourceTenantId") @@ -398,7 +454,6 @@ namespace MyCompanyName.MyProjectName.Migrations modelBuilder.Entity("Volo.Abp.Identity.IdentityRole", b => { b.Property("Id") - .ValueGeneratedOnAdd() .HasColumnType("uniqueidentifier"); b.Property("ConcurrencyStamp") @@ -475,7 +530,6 @@ namespace MyCompanyName.MyProjectName.Migrations modelBuilder.Entity("Volo.Abp.Identity.IdentitySecurityLog", b => { b.Property("Id") - .ValueGeneratedOnAdd() .HasColumnType("uniqueidentifier"); b.Property("Action") @@ -550,7 +604,6 @@ namespace MyCompanyName.MyProjectName.Migrations modelBuilder.Entity("Volo.Abp.Identity.IdentityUser", b => { b.Property("Id") - .ValueGeneratedOnAdd() .HasColumnType("uniqueidentifier"); b.Property("AccessFailedCount") @@ -834,7 +887,6 @@ namespace MyCompanyName.MyProjectName.Migrations modelBuilder.Entity("Volo.Abp.Identity.OrganizationUnit", b => { b.Property("Id") - .ValueGeneratedOnAdd() .HasColumnType("uniqueidentifier"); b.Property("Code") @@ -1273,6 +1325,59 @@ namespace MyCompanyName.MyProjectName.Migrations b.ToTable("OpenIddictTokens", (string)null); }); + modelBuilder.Entity("Volo.Abp.PermissionManagement.PermissionDefinitionRecord", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("DisplayName") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.Property("ExtraProperties") + .HasColumnType("nvarchar(max)") + .HasColumnName("ExtraProperties"); + + b.Property("GroupName") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("nvarchar(128)"); + + b.Property("IsEnabled") + .HasColumnType("bit"); + + b.Property("MultiTenancySide") + .HasColumnType("tinyint"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("nvarchar(128)"); + + b.Property("ParentName") + .HasMaxLength(128) + .HasColumnType("nvarchar(128)"); + + b.Property("Providers") + .HasMaxLength(128) + .HasColumnType("nvarchar(128)"); + + b.Property("StateCheckers") + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.HasKey("Id"); + + b.HasIndex("GroupName"); + + b.HasIndex("Name") + .IsUnique(); + + b.ToTable("AbpPermissions", (string)null); + }); + modelBuilder.Entity("Volo.Abp.PermissionManagement.PermissionGrant", b => { b.Property("Id") @@ -1307,6 +1412,34 @@ namespace MyCompanyName.MyProjectName.Migrations b.ToTable("AbpPermissionGrants", (string)null); }); + modelBuilder.Entity("Volo.Abp.PermissionManagement.PermissionGroupDefinitionRecord", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("DisplayName") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.Property("ExtraProperties") + .HasColumnType("nvarchar(max)") + .HasColumnName("ExtraProperties"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("nvarchar(128)"); + + b.HasKey("Id"); + + b.HasIndex("Name") + .IsUnique(); + + b.ToTable("AbpPermissionGroups", (string)null); + }); + modelBuilder.Entity("Volo.Abp.SettingManagement.Setting", b => { b.Property("Id") @@ -1343,7 +1476,6 @@ namespace MyCompanyName.MyProjectName.Migrations modelBuilder.Entity("Volo.Abp.TenantManagement.Tenant", b => { b.Property("Id") - .ValueGeneratedOnAdd() .HasColumnType("uniqueidentifier"); b.Property("ConcurrencyStamp") diff --git a/templates/module/aspnet-core/host/MyCompanyName.MyProjectName.AuthServer/Migrations/20220617083652_Initial.cs b/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.EntityFrameworkCore/Migrations/20220825012254_Initial.cs similarity index 91% rename from templates/module/aspnet-core/host/MyCompanyName.MyProjectName.AuthServer/Migrations/20220617083652_Initial.cs rename to templates/app/aspnet-core/src/MyCompanyName.MyProjectName.EntityFrameworkCore/Migrations/20220825012254_Initial.cs index cbc01e3dfe..8ddcfae69e 100644 --- a/templates/module/aspnet-core/host/MyCompanyName.MyProjectName.AuthServer/Migrations/20220617083652_Initial.cs +++ b/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.EntityFrameworkCore/Migrations/20220825012254_Initial.cs @@ -43,6 +43,27 @@ namespace MyCompanyName.MyProjectName.Migrations table.PrimaryKey("PK_AbpAuditLogs", x => x.Id); }); + migrationBuilder.CreateTable( + name: "AbpBackgroundJobs", + columns: table => new + { + Id = table.Column(type: "uniqueidentifier", nullable: false), + JobName = table.Column(type: "nvarchar(128)", maxLength: 128, nullable: false), + JobArgs = table.Column(type: "nvarchar(max)", maxLength: 1048576, nullable: false), + TryCount = table.Column(type: "smallint", nullable: false, defaultValue: (short)0), + CreationTime = table.Column(type: "datetime2", nullable: false), + NextTryTime = table.Column(type: "datetime2", nullable: false), + LastTryTime = table.Column(type: "datetime2", nullable: true), + IsAbandoned = table.Column(type: "bit", nullable: false, defaultValue: false), + Priority = table.Column(type: "tinyint", nullable: false, defaultValue: (byte)15), + ExtraProperties = table.Column(type: "nvarchar(max)", nullable: true), + ConcurrencyStamp = table.Column(type: "nvarchar(40)", maxLength: 40, nullable: true) + }, + constraints: table => + { + table.PrimaryKey("PK_AbpBackgroundJobs", x => x.Id); + }); + migrationBuilder.CreateTable( name: "AbpClaimTypes", columns: table => new @@ -137,6 +158,40 @@ namespace MyCompanyName.MyProjectName.Migrations table.PrimaryKey("PK_AbpPermissionGrants", x => x.Id); }); + migrationBuilder.CreateTable( + name: "AbpPermissionGroups", + columns: table => new + { + Id = table.Column(type: "uniqueidentifier", nullable: false), + Name = table.Column(type: "nvarchar(128)", maxLength: 128, nullable: false), + DisplayName = table.Column(type: "nvarchar(256)", maxLength: 256, nullable: false), + ExtraProperties = table.Column(type: "nvarchar(max)", nullable: true) + }, + constraints: table => + { + table.PrimaryKey("PK_AbpPermissionGroups", x => x.Id); + }); + + migrationBuilder.CreateTable( + name: "AbpPermissions", + columns: table => new + { + Id = table.Column(type: "uniqueidentifier", nullable: false), + GroupName = table.Column(type: "nvarchar(128)", maxLength: 128, nullable: false), + Name = table.Column(type: "nvarchar(128)", maxLength: 128, nullable: false), + ParentName = table.Column(type: "nvarchar(128)", maxLength: 128, nullable: true), + DisplayName = table.Column(type: "nvarchar(256)", maxLength: 256, nullable: false), + IsEnabled = table.Column(type: "bit", nullable: false), + MultiTenancySide = table.Column(type: "tinyint", nullable: false), + Providers = table.Column(type: "nvarchar(128)", maxLength: 128, nullable: true), + StateCheckers = table.Column(type: "nvarchar(256)", maxLength: 256, nullable: true), + ExtraProperties = table.Column(type: "nvarchar(max)", nullable: true) + }, + constraints: table => + { + table.PrimaryKey("PK_AbpPermissions", x => x.Id); + }); + migrationBuilder.CreateTable( name: "AbpRoles", columns: table => new @@ -663,6 +718,11 @@ namespace MyCompanyName.MyProjectName.Migrations table: "AbpAuditLogs", columns: new[] { "TenantId", "UserId", "ExecutionTime" }); + migrationBuilder.CreateIndex( + name: "IX_AbpBackgroundJobs_IsAbandoned_NextTryTime", + table: "AbpBackgroundJobs", + columns: new[] { "IsAbandoned", "NextTryTime" }); + migrationBuilder.CreateIndex( name: "IX_AbpEntityChanges_AuditLogId", table: "AbpEntityChanges", @@ -714,6 +774,23 @@ namespace MyCompanyName.MyProjectName.Migrations unique: true, filter: "[TenantId] IS NOT NULL"); + migrationBuilder.CreateIndex( + name: "IX_AbpPermissionGroups_Name", + table: "AbpPermissionGroups", + column: "Name", + unique: true); + + migrationBuilder.CreateIndex( + name: "IX_AbpPermissions_GroupName", + table: "AbpPermissions", + column: "GroupName"); + + migrationBuilder.CreateIndex( + name: "IX_AbpPermissions_Name", + table: "AbpPermissions", + column: "Name", + unique: true); + migrationBuilder.CreateIndex( name: "IX_AbpRoleClaims_RoleId", table: "AbpRoleClaims", @@ -832,6 +909,9 @@ namespace MyCompanyName.MyProjectName.Migrations migrationBuilder.DropTable( name: "AbpAuditLogActions"); + migrationBuilder.DropTable( + name: "AbpBackgroundJobs"); + migrationBuilder.DropTable( name: "AbpClaimTypes"); @@ -850,6 +930,12 @@ namespace MyCompanyName.MyProjectName.Migrations migrationBuilder.DropTable( name: "AbpPermissionGrants"); + migrationBuilder.DropTable( + name: "AbpPermissionGroups"); + + migrationBuilder.DropTable( + name: "AbpPermissions"); + migrationBuilder.DropTable( name: "AbpRoleClaims"); diff --git a/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.EntityFrameworkCore/Migrations/MyProjectNameDbContextModelSnapshot.cs b/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.EntityFrameworkCore/Migrations/MyProjectNameDbContextModelSnapshot.cs index 781691a3d2..ce8d020786 100644 --- a/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.EntityFrameworkCore/Migrations/MyProjectNameDbContextModelSnapshot.cs +++ b/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.EntityFrameworkCore/Migrations/MyProjectNameDbContextModelSnapshot.cs @@ -1323,6 +1323,59 @@ namespace MyCompanyName.MyProjectName.Migrations b.ToTable("OpenIddictTokens", (string)null); }); + modelBuilder.Entity("Volo.Abp.PermissionManagement.PermissionDefinitionRecord", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("DisplayName") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.Property("ExtraProperties") + .HasColumnType("nvarchar(max)") + .HasColumnName("ExtraProperties"); + + b.Property("GroupName") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("nvarchar(128)"); + + b.Property("IsEnabled") + .HasColumnType("bit"); + + b.Property("MultiTenancySide") + .HasColumnType("tinyint"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("nvarchar(128)"); + + b.Property("ParentName") + .HasMaxLength(128) + .HasColumnType("nvarchar(128)"); + + b.Property("Providers") + .HasMaxLength(128) + .HasColumnType("nvarchar(128)"); + + b.Property("StateCheckers") + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.HasKey("Id"); + + b.HasIndex("GroupName"); + + b.HasIndex("Name") + .IsUnique(); + + b.ToTable("AbpPermissions", (string)null); + }); + modelBuilder.Entity("Volo.Abp.PermissionManagement.PermissionGrant", b => { b.Property("Id") @@ -1357,6 +1410,34 @@ namespace MyCompanyName.MyProjectName.Migrations b.ToTable("AbpPermissionGrants", (string)null); }); + modelBuilder.Entity("Volo.Abp.PermissionManagement.PermissionGroupDefinitionRecord", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("DisplayName") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.Property("ExtraProperties") + .HasColumnType("nvarchar(max)") + .HasColumnName("ExtraProperties"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("nvarchar(128)"); + + b.HasKey("Id"); + + b.HasIndex("Name") + .IsUnique(); + + b.ToTable("AbpPermissionGroups", (string)null); + }); + modelBuilder.Entity("Volo.Abp.SettingManagement.Setting", b => { b.Property("Id") diff --git a/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.EntityFrameworkCore/Migrations/20220617083228_Initial.Designer.cs b/templates/module/aspnet-core/host/MyCompanyName.MyProjectName.AuthServer/Migrations/20220825012920_Initial.Designer.cs similarity index 95% rename from templates/app/aspnet-core/src/MyCompanyName.MyProjectName.EntityFrameworkCore/Migrations/20220617083228_Initial.Designer.cs rename to templates/module/aspnet-core/host/MyCompanyName.MyProjectName.AuthServer/Migrations/20220825012920_Initial.Designer.cs index 1ea724aa5b..6f31dccc25 100644 --- a/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.EntityFrameworkCore/Migrations/20220617083228_Initial.Designer.cs +++ b/templates/module/aspnet-core/host/MyCompanyName.MyProjectName.AuthServer/Migrations/20220825012920_Initial.Designer.cs @@ -12,8 +12,8 @@ using Volo.Abp.EntityFrameworkCore; namespace MyCompanyName.MyProjectName.Migrations { - [DbContext(typeof(MyProjectNameDbContext))] - [Migration("20220617083228_Initial")] + [DbContext(typeof(AuthServerDbContext))] + [Migration("20220825012920_Initial")] partial class Initial { protected override void BuildTargetModel(ModelBuilder modelBuilder) @@ -288,64 +288,6 @@ namespace MyCompanyName.MyProjectName.Migrations b.ToTable("AbpEntityPropertyChanges", (string)null); }); - modelBuilder.Entity("Volo.Abp.BackgroundJobs.BackgroundJobRecord", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("uniqueidentifier"); - - b.Property("ConcurrencyStamp") - .IsConcurrencyToken() - .HasMaxLength(40) - .HasColumnType("nvarchar(40)") - .HasColumnName("ConcurrencyStamp"); - - b.Property("CreationTime") - .HasColumnType("datetime2") - .HasColumnName("CreationTime"); - - b.Property("ExtraProperties") - .HasColumnType("nvarchar(max)") - .HasColumnName("ExtraProperties"); - - b.Property("IsAbandoned") - .ValueGeneratedOnAdd() - .HasColumnType("bit") - .HasDefaultValue(false); - - b.Property("JobArgs") - .IsRequired() - .HasMaxLength(1048576) - .HasColumnType("nvarchar(max)"); - - b.Property("JobName") - .IsRequired() - .HasMaxLength(128) - .HasColumnType("nvarchar(128)"); - - b.Property("LastTryTime") - .HasColumnType("datetime2"); - - b.Property("NextTryTime") - .HasColumnType("datetime2"); - - b.Property("Priority") - .ValueGeneratedOnAdd() - .HasColumnType("tinyint") - .HasDefaultValue((byte)15); - - b.Property("TryCount") - .ValueGeneratedOnAdd() - .HasColumnType("smallint") - .HasDefaultValue((short)0); - - b.HasKey("Id"); - - b.HasIndex("IsAbandoned", "NextTryTime"); - - b.ToTable("AbpBackgroundJobs", (string)null); - }); - modelBuilder.Entity("Volo.Abp.FeatureManagement.FeatureValue", b => { b.Property("Id") @@ -382,6 +324,7 @@ namespace MyCompanyName.MyProjectName.Migrations modelBuilder.Entity("Volo.Abp.Identity.IdentityClaimType", b => { b.Property("Id") + .ValueGeneratedOnAdd() .HasColumnType("uniqueidentifier"); b.Property("ConcurrencyStamp") @@ -428,6 +371,7 @@ namespace MyCompanyName.MyProjectName.Migrations modelBuilder.Entity("Volo.Abp.Identity.IdentityLinkUser", b => { b.Property("Id") + .ValueGeneratedOnAdd() .HasColumnType("uniqueidentifier"); b.Property("SourceTenantId") @@ -454,6 +398,7 @@ namespace MyCompanyName.MyProjectName.Migrations modelBuilder.Entity("Volo.Abp.Identity.IdentityRole", b => { b.Property("Id") + .ValueGeneratedOnAdd() .HasColumnType("uniqueidentifier"); b.Property("ConcurrencyStamp") @@ -530,6 +475,7 @@ namespace MyCompanyName.MyProjectName.Migrations modelBuilder.Entity("Volo.Abp.Identity.IdentitySecurityLog", b => { b.Property("Id") + .ValueGeneratedOnAdd() .HasColumnType("uniqueidentifier"); b.Property("Action") @@ -604,6 +550,7 @@ namespace MyCompanyName.MyProjectName.Migrations modelBuilder.Entity("Volo.Abp.Identity.IdentityUser", b => { b.Property("Id") + .ValueGeneratedOnAdd() .HasColumnType("uniqueidentifier"); b.Property("AccessFailedCount") @@ -887,6 +834,7 @@ namespace MyCompanyName.MyProjectName.Migrations modelBuilder.Entity("Volo.Abp.Identity.OrganizationUnit", b => { b.Property("Id") + .ValueGeneratedOnAdd() .HasColumnType("uniqueidentifier"); b.Property("Code") @@ -1325,6 +1273,59 @@ namespace MyCompanyName.MyProjectName.Migrations b.ToTable("OpenIddictTokens", (string)null); }); + modelBuilder.Entity("Volo.Abp.PermissionManagement.PermissionDefinitionRecord", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("DisplayName") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.Property("ExtraProperties") + .HasColumnType("nvarchar(max)") + .HasColumnName("ExtraProperties"); + + b.Property("GroupName") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("nvarchar(128)"); + + b.Property("IsEnabled") + .HasColumnType("bit"); + + b.Property("MultiTenancySide") + .HasColumnType("tinyint"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("nvarchar(128)"); + + b.Property("ParentName") + .HasMaxLength(128) + .HasColumnType("nvarchar(128)"); + + b.Property("Providers") + .HasMaxLength(128) + .HasColumnType("nvarchar(128)"); + + b.Property("StateCheckers") + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.HasKey("Id"); + + b.HasIndex("GroupName"); + + b.HasIndex("Name") + .IsUnique(); + + b.ToTable("AbpPermissions", (string)null); + }); + modelBuilder.Entity("Volo.Abp.PermissionManagement.PermissionGrant", b => { b.Property("Id") @@ -1359,6 +1360,34 @@ namespace MyCompanyName.MyProjectName.Migrations b.ToTable("AbpPermissionGrants", (string)null); }); + modelBuilder.Entity("Volo.Abp.PermissionManagement.PermissionGroupDefinitionRecord", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("DisplayName") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.Property("ExtraProperties") + .HasColumnType("nvarchar(max)") + .HasColumnName("ExtraProperties"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("nvarchar(128)"); + + b.HasKey("Id"); + + b.HasIndex("Name") + .IsUnique(); + + b.ToTable("AbpPermissionGroups", (string)null); + }); + modelBuilder.Entity("Volo.Abp.SettingManagement.Setting", b => { b.Property("Id") @@ -1395,6 +1424,7 @@ namespace MyCompanyName.MyProjectName.Migrations modelBuilder.Entity("Volo.Abp.TenantManagement.Tenant", b => { b.Property("Id") + .ValueGeneratedOnAdd() .HasColumnType("uniqueidentifier"); b.Property("ConcurrencyStamp") diff --git a/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.EntityFrameworkCore/Migrations/20220617083228_Initial.cs b/templates/module/aspnet-core/host/MyCompanyName.MyProjectName.AuthServer/Migrations/20220825012920_Initial.cs similarity index 95% rename from templates/app/aspnet-core/src/MyCompanyName.MyProjectName.EntityFrameworkCore/Migrations/20220617083228_Initial.cs rename to templates/module/aspnet-core/host/MyCompanyName.MyProjectName.AuthServer/Migrations/20220825012920_Initial.cs index 55ae609199..e2dfaa2f6f 100644 --- a/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.EntityFrameworkCore/Migrations/20220617083228_Initial.cs +++ b/templates/module/aspnet-core/host/MyCompanyName.MyProjectName.AuthServer/Migrations/20220825012920_Initial.cs @@ -43,27 +43,6 @@ namespace MyCompanyName.MyProjectName.Migrations table.PrimaryKey("PK_AbpAuditLogs", x => x.Id); }); - migrationBuilder.CreateTable( - name: "AbpBackgroundJobs", - columns: table => new - { - Id = table.Column(type: "uniqueidentifier", nullable: false), - JobName = table.Column(type: "nvarchar(128)", maxLength: 128, nullable: false), - JobArgs = table.Column(type: "nvarchar(max)", maxLength: 1048576, nullable: false), - TryCount = table.Column(type: "smallint", nullable: false, defaultValue: (short)0), - CreationTime = table.Column(type: "datetime2", nullable: false), - NextTryTime = table.Column(type: "datetime2", nullable: false), - LastTryTime = table.Column(type: "datetime2", nullable: true), - IsAbandoned = table.Column(type: "bit", nullable: false, defaultValue: false), - Priority = table.Column(type: "tinyint", nullable: false, defaultValue: (byte)15), - ExtraProperties = table.Column(type: "nvarchar(max)", nullable: true), - ConcurrencyStamp = table.Column(type: "nvarchar(40)", maxLength: 40, nullable: true) - }, - constraints: table => - { - table.PrimaryKey("PK_AbpBackgroundJobs", x => x.Id); - }); - migrationBuilder.CreateTable( name: "AbpClaimTypes", columns: table => new @@ -158,6 +137,40 @@ namespace MyCompanyName.MyProjectName.Migrations table.PrimaryKey("PK_AbpPermissionGrants", x => x.Id); }); + migrationBuilder.CreateTable( + name: "AbpPermissionGroups", + columns: table => new + { + Id = table.Column(type: "uniqueidentifier", nullable: false), + Name = table.Column(type: "nvarchar(128)", maxLength: 128, nullable: false), + DisplayName = table.Column(type: "nvarchar(256)", maxLength: 256, nullable: false), + ExtraProperties = table.Column(type: "nvarchar(max)", nullable: true) + }, + constraints: table => + { + table.PrimaryKey("PK_AbpPermissionGroups", x => x.Id); + }); + + migrationBuilder.CreateTable( + name: "AbpPermissions", + columns: table => new + { + Id = table.Column(type: "uniqueidentifier", nullable: false), + GroupName = table.Column(type: "nvarchar(128)", maxLength: 128, nullable: false), + Name = table.Column(type: "nvarchar(128)", maxLength: 128, nullable: false), + ParentName = table.Column(type: "nvarchar(128)", maxLength: 128, nullable: true), + DisplayName = table.Column(type: "nvarchar(256)", maxLength: 256, nullable: false), + IsEnabled = table.Column(type: "bit", nullable: false), + MultiTenancySide = table.Column(type: "tinyint", nullable: false), + Providers = table.Column(type: "nvarchar(128)", maxLength: 128, nullable: true), + StateCheckers = table.Column(type: "nvarchar(256)", maxLength: 256, nullable: true), + ExtraProperties = table.Column(type: "nvarchar(max)", nullable: true) + }, + constraints: table => + { + table.PrimaryKey("PK_AbpPermissions", x => x.Id); + }); + migrationBuilder.CreateTable( name: "AbpRoles", columns: table => new @@ -684,11 +697,6 @@ namespace MyCompanyName.MyProjectName.Migrations table: "AbpAuditLogs", columns: new[] { "TenantId", "UserId", "ExecutionTime" }); - migrationBuilder.CreateIndex( - name: "IX_AbpBackgroundJobs_IsAbandoned_NextTryTime", - table: "AbpBackgroundJobs", - columns: new[] { "IsAbandoned", "NextTryTime" }); - migrationBuilder.CreateIndex( name: "IX_AbpEntityChanges_AuditLogId", table: "AbpEntityChanges", @@ -740,6 +748,23 @@ namespace MyCompanyName.MyProjectName.Migrations unique: true, filter: "[TenantId] IS NOT NULL"); + migrationBuilder.CreateIndex( + name: "IX_AbpPermissionGroups_Name", + table: "AbpPermissionGroups", + column: "Name", + unique: true); + + migrationBuilder.CreateIndex( + name: "IX_AbpPermissions_GroupName", + table: "AbpPermissions", + column: "GroupName"); + + migrationBuilder.CreateIndex( + name: "IX_AbpPermissions_Name", + table: "AbpPermissions", + column: "Name", + unique: true); + migrationBuilder.CreateIndex( name: "IX_AbpRoleClaims_RoleId", table: "AbpRoleClaims", @@ -858,9 +883,6 @@ namespace MyCompanyName.MyProjectName.Migrations migrationBuilder.DropTable( name: "AbpAuditLogActions"); - migrationBuilder.DropTable( - name: "AbpBackgroundJobs"); - migrationBuilder.DropTable( name: "AbpClaimTypes"); @@ -879,6 +901,12 @@ namespace MyCompanyName.MyProjectName.Migrations migrationBuilder.DropTable( name: "AbpPermissionGrants"); + migrationBuilder.DropTable( + name: "AbpPermissionGroups"); + + migrationBuilder.DropTable( + name: "AbpPermissions"); + migrationBuilder.DropTable( name: "AbpRoleClaims"); diff --git a/templates/module/aspnet-core/host/MyCompanyName.MyProjectName.AuthServer/Migrations/AuthServerDbContextModelSnapshot.cs b/templates/module/aspnet-core/host/MyCompanyName.MyProjectName.AuthServer/Migrations/AuthServerDbContextModelSnapshot.cs index e483e20a49..4ba9b7daaa 100644 --- a/templates/module/aspnet-core/host/MyCompanyName.MyProjectName.AuthServer/Migrations/AuthServerDbContextModelSnapshot.cs +++ b/templates/module/aspnet-core/host/MyCompanyName.MyProjectName.AuthServer/Migrations/AuthServerDbContextModelSnapshot.cs @@ -1271,6 +1271,59 @@ namespace MyCompanyName.MyProjectName.Migrations b.ToTable("OpenIddictTokens", (string)null); }); + modelBuilder.Entity("Volo.Abp.PermissionManagement.PermissionDefinitionRecord", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("DisplayName") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.Property("ExtraProperties") + .HasColumnType("nvarchar(max)") + .HasColumnName("ExtraProperties"); + + b.Property("GroupName") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("nvarchar(128)"); + + b.Property("IsEnabled") + .HasColumnType("bit"); + + b.Property("MultiTenancySide") + .HasColumnType("tinyint"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("nvarchar(128)"); + + b.Property("ParentName") + .HasMaxLength(128) + .HasColumnType("nvarchar(128)"); + + b.Property("Providers") + .HasMaxLength(128) + .HasColumnType("nvarchar(128)"); + + b.Property("StateCheckers") + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.HasKey("Id"); + + b.HasIndex("GroupName"); + + b.HasIndex("Name") + .IsUnique(); + + b.ToTable("AbpPermissions", (string)null); + }); + modelBuilder.Entity("Volo.Abp.PermissionManagement.PermissionGrant", b => { b.Property("Id") @@ -1305,6 +1358,34 @@ namespace MyCompanyName.MyProjectName.Migrations b.ToTable("AbpPermissionGrants", (string)null); }); + modelBuilder.Entity("Volo.Abp.PermissionManagement.PermissionGroupDefinitionRecord", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("DisplayName") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.Property("ExtraProperties") + .HasColumnType("nvarchar(max)") + .HasColumnName("ExtraProperties"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("nvarchar(128)"); + + b.HasKey("Id"); + + b.HasIndex("Name") + .IsUnique(); + + b.ToTable("AbpPermissionGroups", (string)null); + }); + modelBuilder.Entity("Volo.Abp.SettingManagement.Setting", b => { b.Property("Id") diff --git a/templates/module/aspnet-core/host/MyCompanyName.MyProjectName.Blazor.Server.Host/Migrations/20220617083658_Initial.Designer.cs b/templates/module/aspnet-core/host/MyCompanyName.MyProjectName.Blazor.Server.Host/Migrations/20220825013015_Initial.Designer.cs similarity index 94% rename from templates/module/aspnet-core/host/MyCompanyName.MyProjectName.Blazor.Server.Host/Migrations/20220617083658_Initial.Designer.cs rename to templates/module/aspnet-core/host/MyCompanyName.MyProjectName.Blazor.Server.Host/Migrations/20220825013015_Initial.Designer.cs index da5ce77b3f..4a13126215 100644 --- a/templates/module/aspnet-core/host/MyCompanyName.MyProjectName.Blazor.Server.Host/Migrations/20220617083658_Initial.Designer.cs +++ b/templates/module/aspnet-core/host/MyCompanyName.MyProjectName.Blazor.Server.Host/Migrations/20220825013015_Initial.Designer.cs @@ -13,7 +13,7 @@ using Volo.Abp.EntityFrameworkCore; namespace MyCompanyName.MyProjectName.Blazor.Server.Host.Migrations { [DbContext(typeof(UnifiedDbContext))] - [Migration("20220617083658_Initial")] + [Migration("20220825013015_Initial")] partial class Initial { protected override void BuildTargetModel(ModelBuilder modelBuilder) @@ -932,6 +932,59 @@ namespace MyCompanyName.MyProjectName.Blazor.Server.Host.Migrations b.ToTable("AbpOrganizationUnitRoles", (string)null); }); + modelBuilder.Entity("Volo.Abp.PermissionManagement.PermissionDefinitionRecord", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("DisplayName") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.Property("ExtraProperties") + .HasColumnType("nvarchar(max)") + .HasColumnName("ExtraProperties"); + + b.Property("GroupName") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("nvarchar(128)"); + + b.Property("IsEnabled") + .HasColumnType("bit"); + + b.Property("MultiTenancySide") + .HasColumnType("tinyint"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("nvarchar(128)"); + + b.Property("ParentName") + .HasMaxLength(128) + .HasColumnType("nvarchar(128)"); + + b.Property("Providers") + .HasMaxLength(128) + .HasColumnType("nvarchar(128)"); + + b.Property("StateCheckers") + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.HasKey("Id"); + + b.HasIndex("GroupName"); + + b.HasIndex("Name") + .IsUnique(); + + b.ToTable("AbpPermissions", (string)null); + }); + modelBuilder.Entity("Volo.Abp.PermissionManagement.PermissionGrant", b => { b.Property("Id") @@ -966,6 +1019,34 @@ namespace MyCompanyName.MyProjectName.Blazor.Server.Host.Migrations b.ToTable("AbpPermissionGrants", (string)null); }); + modelBuilder.Entity("Volo.Abp.PermissionManagement.PermissionGroupDefinitionRecord", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("DisplayName") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.Property("ExtraProperties") + .HasColumnType("nvarchar(max)") + .HasColumnName("ExtraProperties"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("nvarchar(128)"); + + b.HasKey("Id"); + + b.HasIndex("Name") + .IsUnique(); + + b.ToTable("AbpPermissionGroups", (string)null); + }); + modelBuilder.Entity("Volo.Abp.SettingManagement.Setting", b => { b.Property("Id") diff --git a/templates/module/aspnet-core/host/MyCompanyName.MyProjectName.Blazor.Server.Host/Migrations/20220617083658_Initial.cs b/templates/module/aspnet-core/host/MyCompanyName.MyProjectName.Blazor.Server.Host/Migrations/20220825013015_Initial.cs similarity index 93% rename from templates/module/aspnet-core/host/MyCompanyName.MyProjectName.Blazor.Server.Host/Migrations/20220617083658_Initial.cs rename to templates/module/aspnet-core/host/MyCompanyName.MyProjectName.Blazor.Server.Host/Migrations/20220825013015_Initial.cs index f575db2142..be6fee4b31 100644 --- a/templates/module/aspnet-core/host/MyCompanyName.MyProjectName.Blazor.Server.Host/Migrations/20220617083658_Initial.cs +++ b/templates/module/aspnet-core/host/MyCompanyName.MyProjectName.Blazor.Server.Host/Migrations/20220825013015_Initial.cs @@ -137,6 +137,40 @@ namespace MyCompanyName.MyProjectName.Blazor.Server.Host.Migrations table.PrimaryKey("PK_AbpPermissionGrants", x => x.Id); }); + migrationBuilder.CreateTable( + name: "AbpPermissionGroups", + columns: table => new + { + Id = table.Column(type: "uniqueidentifier", nullable: false), + Name = table.Column(type: "nvarchar(128)", maxLength: 128, nullable: false), + DisplayName = table.Column(type: "nvarchar(256)", maxLength: 256, nullable: false), + ExtraProperties = table.Column(type: "nvarchar(max)", nullable: true) + }, + constraints: table => + { + table.PrimaryKey("PK_AbpPermissionGroups", x => x.Id); + }); + + migrationBuilder.CreateTable( + name: "AbpPermissions", + columns: table => new + { + Id = table.Column(type: "uniqueidentifier", nullable: false), + GroupName = table.Column(type: "nvarchar(128)", maxLength: 128, nullable: false), + Name = table.Column(type: "nvarchar(128)", maxLength: 128, nullable: false), + ParentName = table.Column(type: "nvarchar(128)", maxLength: 128, nullable: true), + DisplayName = table.Column(type: "nvarchar(256)", maxLength: 256, nullable: false), + IsEnabled = table.Column(type: "bit", nullable: false), + MultiTenancySide = table.Column(type: "tinyint", nullable: false), + Providers = table.Column(type: "nvarchar(128)", maxLength: 128, nullable: true), + StateCheckers = table.Column(type: "nvarchar(256)", maxLength: 256, nullable: true), + ExtraProperties = table.Column(type: "nvarchar(max)", nullable: true) + }, + constraints: table => + { + table.PrimaryKey("PK_AbpPermissions", x => x.Id); + }); + migrationBuilder.CreateTable( name: "AbpRoles", columns: table => new @@ -581,6 +615,23 @@ namespace MyCompanyName.MyProjectName.Blazor.Server.Host.Migrations unique: true, filter: "[TenantId] IS NOT NULL"); + migrationBuilder.CreateIndex( + name: "IX_AbpPermissionGroups_Name", + table: "AbpPermissionGroups", + column: "Name", + unique: true); + + migrationBuilder.CreateIndex( + name: "IX_AbpPermissions_GroupName", + table: "AbpPermissions", + column: "GroupName"); + + migrationBuilder.CreateIndex( + name: "IX_AbpPermissions_Name", + table: "AbpPermissions", + column: "Name", + unique: true); + migrationBuilder.CreateIndex( name: "IX_AbpRoleClaims_RoleId", table: "AbpRoleClaims", @@ -687,6 +738,12 @@ namespace MyCompanyName.MyProjectName.Blazor.Server.Host.Migrations migrationBuilder.DropTable( name: "AbpPermissionGrants"); + migrationBuilder.DropTable( + name: "AbpPermissionGroups"); + + migrationBuilder.DropTable( + name: "AbpPermissions"); + migrationBuilder.DropTable( name: "AbpRoleClaims"); diff --git a/templates/module/aspnet-core/host/MyCompanyName.MyProjectName.Blazor.Server.Host/Migrations/UnifiedDbContextModelSnapshot.cs b/templates/module/aspnet-core/host/MyCompanyName.MyProjectName.Blazor.Server.Host/Migrations/UnifiedDbContextModelSnapshot.cs index 7ef4a80da0..0ba27152ac 100644 --- a/templates/module/aspnet-core/host/MyCompanyName.MyProjectName.Blazor.Server.Host/Migrations/UnifiedDbContextModelSnapshot.cs +++ b/templates/module/aspnet-core/host/MyCompanyName.MyProjectName.Blazor.Server.Host/Migrations/UnifiedDbContextModelSnapshot.cs @@ -930,6 +930,59 @@ namespace MyCompanyName.MyProjectName.Blazor.Server.Host.Migrations b.ToTable("AbpOrganizationUnitRoles", (string)null); }); + modelBuilder.Entity("Volo.Abp.PermissionManagement.PermissionDefinitionRecord", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("DisplayName") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.Property("ExtraProperties") + .HasColumnType("nvarchar(max)") + .HasColumnName("ExtraProperties"); + + b.Property("GroupName") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("nvarchar(128)"); + + b.Property("IsEnabled") + .HasColumnType("bit"); + + b.Property("MultiTenancySide") + .HasColumnType("tinyint"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("nvarchar(128)"); + + b.Property("ParentName") + .HasMaxLength(128) + .HasColumnType("nvarchar(128)"); + + b.Property("Providers") + .HasMaxLength(128) + .HasColumnType("nvarchar(128)"); + + b.Property("StateCheckers") + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.HasKey("Id"); + + b.HasIndex("GroupName"); + + b.HasIndex("Name") + .IsUnique(); + + b.ToTable("AbpPermissions", (string)null); + }); + modelBuilder.Entity("Volo.Abp.PermissionManagement.PermissionGrant", b => { b.Property("Id") @@ -964,6 +1017,34 @@ namespace MyCompanyName.MyProjectName.Blazor.Server.Host.Migrations b.ToTable("AbpPermissionGrants", (string)null); }); + modelBuilder.Entity("Volo.Abp.PermissionManagement.PermissionGroupDefinitionRecord", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("DisplayName") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.Property("ExtraProperties") + .HasColumnType("nvarchar(max)") + .HasColumnName("ExtraProperties"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("nvarchar(128)"); + + b.HasKey("Id"); + + b.HasIndex("Name") + .IsUnique(); + + b.ToTable("AbpPermissionGroups", (string)null); + }); + modelBuilder.Entity("Volo.Abp.SettingManagement.Setting", b => { b.Property("Id") diff --git a/templates/module/aspnet-core/host/MyCompanyName.MyProjectName.Web.Unified/Migrations/20220617083659_Initial.Designer.cs b/templates/module/aspnet-core/host/MyCompanyName.MyProjectName.Web.Unified/Migrations/20220825013032_Initial.Designer.cs similarity index 94% rename from templates/module/aspnet-core/host/MyCompanyName.MyProjectName.Web.Unified/Migrations/20220617083659_Initial.Designer.cs rename to templates/module/aspnet-core/host/MyCompanyName.MyProjectName.Web.Unified/Migrations/20220825013032_Initial.Designer.cs index e9f1df7c94..68cf3fe47f 100644 --- a/templates/module/aspnet-core/host/MyCompanyName.MyProjectName.Web.Unified/Migrations/20220617083659_Initial.Designer.cs +++ b/templates/module/aspnet-core/host/MyCompanyName.MyProjectName.Web.Unified/Migrations/20220825013032_Initial.Designer.cs @@ -13,7 +13,7 @@ using Volo.Abp.EntityFrameworkCore; namespace MyCompanyName.MyProjectName.Migrations { [DbContext(typeof(UnifiedDbContext))] - [Migration("20220617083659_Initial")] + [Migration("20220825013032_Initial")] partial class Initial { protected override void BuildTargetModel(ModelBuilder modelBuilder) @@ -932,6 +932,59 @@ namespace MyCompanyName.MyProjectName.Migrations b.ToTable("AbpOrganizationUnitRoles", (string)null); }); + modelBuilder.Entity("Volo.Abp.PermissionManagement.PermissionDefinitionRecord", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("DisplayName") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.Property("ExtraProperties") + .HasColumnType("nvarchar(max)") + .HasColumnName("ExtraProperties"); + + b.Property("GroupName") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("nvarchar(128)"); + + b.Property("IsEnabled") + .HasColumnType("bit"); + + b.Property("MultiTenancySide") + .HasColumnType("tinyint"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("nvarchar(128)"); + + b.Property("ParentName") + .HasMaxLength(128) + .HasColumnType("nvarchar(128)"); + + b.Property("Providers") + .HasMaxLength(128) + .HasColumnType("nvarchar(128)"); + + b.Property("StateCheckers") + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.HasKey("Id"); + + b.HasIndex("GroupName"); + + b.HasIndex("Name") + .IsUnique(); + + b.ToTable("AbpPermissions", (string)null); + }); + modelBuilder.Entity("Volo.Abp.PermissionManagement.PermissionGrant", b => { b.Property("Id") @@ -966,6 +1019,34 @@ namespace MyCompanyName.MyProjectName.Migrations b.ToTable("AbpPermissionGrants", (string)null); }); + modelBuilder.Entity("Volo.Abp.PermissionManagement.PermissionGroupDefinitionRecord", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("DisplayName") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.Property("ExtraProperties") + .HasColumnType("nvarchar(max)") + .HasColumnName("ExtraProperties"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("nvarchar(128)"); + + b.HasKey("Id"); + + b.HasIndex("Name") + .IsUnique(); + + b.ToTable("AbpPermissionGroups", (string)null); + }); + modelBuilder.Entity("Volo.Abp.SettingManagement.Setting", b => { b.Property("Id") diff --git a/templates/module/aspnet-core/host/MyCompanyName.MyProjectName.Web.Unified/Migrations/20220617083659_Initial.cs b/templates/module/aspnet-core/host/MyCompanyName.MyProjectName.Web.Unified/Migrations/20220825013032_Initial.cs similarity index 93% rename from templates/module/aspnet-core/host/MyCompanyName.MyProjectName.Web.Unified/Migrations/20220617083659_Initial.cs rename to templates/module/aspnet-core/host/MyCompanyName.MyProjectName.Web.Unified/Migrations/20220825013032_Initial.cs index b02029a8cd..7c0caa1baa 100644 --- a/templates/module/aspnet-core/host/MyCompanyName.MyProjectName.Web.Unified/Migrations/20220617083659_Initial.cs +++ b/templates/module/aspnet-core/host/MyCompanyName.MyProjectName.Web.Unified/Migrations/20220825013032_Initial.cs @@ -137,6 +137,40 @@ namespace MyCompanyName.MyProjectName.Migrations table.PrimaryKey("PK_AbpPermissionGrants", x => x.Id); }); + migrationBuilder.CreateTable( + name: "AbpPermissionGroups", + columns: table => new + { + Id = table.Column(type: "uniqueidentifier", nullable: false), + Name = table.Column(type: "nvarchar(128)", maxLength: 128, nullable: false), + DisplayName = table.Column(type: "nvarchar(256)", maxLength: 256, nullable: false), + ExtraProperties = table.Column(type: "nvarchar(max)", nullable: true) + }, + constraints: table => + { + table.PrimaryKey("PK_AbpPermissionGroups", x => x.Id); + }); + + migrationBuilder.CreateTable( + name: "AbpPermissions", + columns: table => new + { + Id = table.Column(type: "uniqueidentifier", nullable: false), + GroupName = table.Column(type: "nvarchar(128)", maxLength: 128, nullable: false), + Name = table.Column(type: "nvarchar(128)", maxLength: 128, nullable: false), + ParentName = table.Column(type: "nvarchar(128)", maxLength: 128, nullable: true), + DisplayName = table.Column(type: "nvarchar(256)", maxLength: 256, nullable: false), + IsEnabled = table.Column(type: "bit", nullable: false), + MultiTenancySide = table.Column(type: "tinyint", nullable: false), + Providers = table.Column(type: "nvarchar(128)", maxLength: 128, nullable: true), + StateCheckers = table.Column(type: "nvarchar(256)", maxLength: 256, nullable: true), + ExtraProperties = table.Column(type: "nvarchar(max)", nullable: true) + }, + constraints: table => + { + table.PrimaryKey("PK_AbpPermissions", x => x.Id); + }); + migrationBuilder.CreateTable( name: "AbpRoles", columns: table => new @@ -581,6 +615,23 @@ namespace MyCompanyName.MyProjectName.Migrations unique: true, filter: "[TenantId] IS NOT NULL"); + migrationBuilder.CreateIndex( + name: "IX_AbpPermissionGroups_Name", + table: "AbpPermissionGroups", + column: "Name", + unique: true); + + migrationBuilder.CreateIndex( + name: "IX_AbpPermissions_GroupName", + table: "AbpPermissions", + column: "GroupName"); + + migrationBuilder.CreateIndex( + name: "IX_AbpPermissions_Name", + table: "AbpPermissions", + column: "Name", + unique: true); + migrationBuilder.CreateIndex( name: "IX_AbpRoleClaims_RoleId", table: "AbpRoleClaims", @@ -687,6 +738,12 @@ namespace MyCompanyName.MyProjectName.Migrations migrationBuilder.DropTable( name: "AbpPermissionGrants"); + migrationBuilder.DropTable( + name: "AbpPermissionGroups"); + + migrationBuilder.DropTable( + name: "AbpPermissions"); + migrationBuilder.DropTable( name: "AbpRoleClaims"); diff --git a/templates/module/aspnet-core/host/MyCompanyName.MyProjectName.Web.Unified/Migrations/UnifiedDbContextModelSnapshot.cs b/templates/module/aspnet-core/host/MyCompanyName.MyProjectName.Web.Unified/Migrations/UnifiedDbContextModelSnapshot.cs index 39b8871ef6..cb1236c39b 100644 --- a/templates/module/aspnet-core/host/MyCompanyName.MyProjectName.Web.Unified/Migrations/UnifiedDbContextModelSnapshot.cs +++ b/templates/module/aspnet-core/host/MyCompanyName.MyProjectName.Web.Unified/Migrations/UnifiedDbContextModelSnapshot.cs @@ -930,6 +930,59 @@ namespace MyCompanyName.MyProjectName.Migrations b.ToTable("AbpOrganizationUnitRoles", (string)null); }); + modelBuilder.Entity("Volo.Abp.PermissionManagement.PermissionDefinitionRecord", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("DisplayName") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.Property("ExtraProperties") + .HasColumnType("nvarchar(max)") + .HasColumnName("ExtraProperties"); + + b.Property("GroupName") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("nvarchar(128)"); + + b.Property("IsEnabled") + .HasColumnType("bit"); + + b.Property("MultiTenancySide") + .HasColumnType("tinyint"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("nvarchar(128)"); + + b.Property("ParentName") + .HasMaxLength(128) + .HasColumnType("nvarchar(128)"); + + b.Property("Providers") + .HasMaxLength(128) + .HasColumnType("nvarchar(128)"); + + b.Property("StateCheckers") + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.HasKey("Id"); + + b.HasIndex("GroupName"); + + b.HasIndex("Name") + .IsUnique(); + + b.ToTable("AbpPermissions", (string)null); + }); + modelBuilder.Entity("Volo.Abp.PermissionManagement.PermissionGrant", b => { b.Property("Id") @@ -964,6 +1017,34 @@ namespace MyCompanyName.MyProjectName.Migrations b.ToTable("AbpPermissionGrants", (string)null); }); + modelBuilder.Entity("Volo.Abp.PermissionManagement.PermissionGroupDefinitionRecord", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("DisplayName") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.Property("ExtraProperties") + .HasColumnType("nvarchar(max)") + .HasColumnName("ExtraProperties"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("nvarchar(128)"); + + b.HasKey("Id"); + + b.HasIndex("Name") + .IsUnique(); + + b.ToTable("AbpPermissionGroups", (string)null); + }); + modelBuilder.Entity("Volo.Abp.SettingManagement.Setting", b => { b.Property("Id")