diff --git a/abp_io/AbpIoLocalization/AbpIoLocalization/Admin/Localization/Resources/en.json b/abp_io/AbpIoLocalization/AbpIoLocalization/Admin/Localization/Resources/en.json index c02e6e13de..51d818aad7 100644 --- a/abp_io/AbpIoLocalization/AbpIoLocalization/Admin/Localization/Resources/en.json +++ b/abp_io/AbpIoLocalization/AbpIoLocalization/Admin/Localization/Resources/en.json @@ -91,6 +91,7 @@ "UserNotFound": "User not found", "{0}WillBeRemovedFromDevelopers": "{0} Will be removed from developers, do you confirm?", "{0}WillBeRemovedFromOwners": "{0} Will be removed from owners, do you confirm?", + "{0}WillBeRemovedFromMembers": "{0} Will be removed from members, do you confirm?", "Computers": "Computers", "UniqueComputerId": "Unique computer id", "LastSeenDate": "Last seen date", @@ -213,7 +214,9 @@ "Currency": "Currency", "Gateway": "Gateway", "State": "State", - "FailReason": "Fail reason" - + "FailReason": "Fail reason", + "ReIndexAllPosts": "ReIndex All Posts", + "ReIndexAllPostsConfirmationMessage": "Are you sure to reindex all posts?", + "SuccessfullyReIndexAllPosts": "Successfully reindex for all posts" } } diff --git a/abp_io/AbpIoLocalization/AbpIoLocalization/Admin/Localization/Resources/tr.json b/abp_io/AbpIoLocalization/AbpIoLocalization/Admin/Localization/Resources/tr.json index 1884b0025f..34ee392140 100644 --- a/abp_io/AbpIoLocalization/AbpIoLocalization/Admin/Localization/Resources/tr.json +++ b/abp_io/AbpIoLocalization/AbpIoLocalization/Admin/Localization/Resources/tr.json @@ -163,6 +163,9 @@ "Enum:ContentSource:2": "Video İçerik", "DeleteCoverImage": "Kapak Fotoğrafını Sil", "DeleteCoverImageConfirmationMessage": "Kapak fotoğrafını \"{0}\" isimli makale için silmek istediğinize emin misiniz?", - "DeleteCoverImageSuccessMessage": "Kapak fotoğrafı başarılı bir şekilde silinmiştir" + "DeleteCoverImageSuccessMessage": "Kapak fotoğrafı başarılı bir şekilde silinmiştir", + "ReIndexAllPosts": "Yeniden indeksle", + "ReIndexAllPostsConfirmationMessage": "Tüm gönderileri yeniden indeksleyeceğinizden emin misiniz?", + "SuccessfullyReIndexAllPosts": "Tüm gönderiler başarıyla yeniden indekslendi" } } \ 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 71dc425dc6..eedfd4bccd 100644 --- a/abp_io/AbpIoLocalization/AbpIoLocalization/Base/Localization/Resources/en.json +++ b/abp_io/AbpIoLocalization/AbpIoLocalization/Base/Localization/Resources/en.json @@ -30,6 +30,8 @@ "Permission:License": "License", "Permission:UserInfo": "Usere info", "SeeDocuments": "See Documents", - "Samples": "Samples" + "Samples": "Samples", + "Framework": "Framework", + "Support": "Support" } } \ 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 f061408c98..01550612d4 100644 --- a/abp_io/AbpIoLocalization/AbpIoLocalization/Base/Localization/Resources/zh-Hans.json +++ b/abp_io/AbpIoLocalization/AbpIoLocalization/Base/Localization/Resources/zh-Hans.json @@ -30,6 +30,8 @@ "Permission:License": "许可", "Permission:UserInfo": "用户信息", "SeeDocuments": "查看文档", - "Samples": "示例" + "Samples": "示例", + "Framework": "框架", + "Support": "支持" } } \ 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 4de287778f..b03d57cee0 100644 --- a/abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/en.json +++ b/abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/en.json @@ -41,6 +41,250 @@ "Unsubscribe": "Unsubscribe", "NotOrganizationMember": "You are not member of any organization.", "UnsubscribeLicenseExpirationEmailSuccessTitle": "Successfully unsubscribed", - "UnsubscribeLicenseExpirationEmailSuccessMessage": "You will not receive license expiration date reminder emails anymore." - } + "UnsubscribeLicenseExpirationEmailSuccessMessage": "You will not receive license expiration date reminder emails anymore.", + "IndexPageHeroSection": "A complete web development platformbuilt-on framework", + "AbpCommercialShortDescription": "ABP Commercial provides pre-built application modules, rapid application development tooling, professional UI themes, premium support and more.", + "LiveDemo": "Live Demo", + "GetLicence" :"Get a Licence", + "Application": "Application", + "StartupTemplates": "Startup Templates", + "Startup": "Startup", + "Templates": "Templates", + "Developer": "Developer", + "Tools": "Tools", + "Premium": "Premium", + "PremiumSupport": "Premium Support", + "PremiumForumSupport": "Premium Forum Support", + "UI": "UI", + "Themes": "Themes", + "JoinOurNewsletter": "Join Our Newsletter", + "Send": "Send", + "Learn": "Learn", + "AdditionalServices": "Additional Services", + "WhatIsABPFramework": "WHAT IS THE ABP FRAMEWORK?", + "OpenSourceBaseFramework": "Open Source Base Framework", + "ABPFrameworkExplanation": "

ABP Commercial is based on the ABP Framework, an open source and community driven web application framework for ASP.NET Core.

ABP Framework provides an excellent infrastructure to write maintainable, extensible and testable code with best practices.

Built on and integrated to popular tools you already know. Low learning curve, easy adaptation, comfortable development.

", + "Modular": "Modular", + "MicroserviceCompatible": "Microservice compatible", + "DomainDrivenDesignInfrastructure": "Domain Driven Design Infrastructure", + "MultiTenancy": "Multi-Tenancy", + "DistributedMessaging": "Distributed Messaging", + "DynamicProxying": "Dynamic Proxying", + "BackgroundJobs": "Background Jobs", + "AuditLogging": "Audit Logging", + "BLOBStoring": "BLOB Storing", + "BundlingMinification": "Bundling & Minification", + "AdvancedLocalization": "Advanced Localization", + "ManyMore": "Many more", + "ExploreTheABPFramework": "Explore the ABP Framework", + "WhyUseTheABPCommercial": "Why Use The ABP Commercial?", + "WhyUseTheABPCommercialExplanation": "

Building enterprise-grade web applications can be complex and time-consuming.

ABP Commercial offers the perfect base infrastructure necessary for all modern enterprise-grade ASP.NET Core based solutions. Right from the design to deployment, the entire development cycle is empowered by ABP's built-in features & modules.

", + "StartupTemplatesShortDescription": "Startup templates make you jump-start to your project in a few seconds.", + "UIFrameworksOptions": "UI frameworks options;", + "DatabaseProviderOptions": "Database provider options;", + "PreBuiltApplicationModules": "Pre-Built Application Modules", + "PreBuiltApplicationModulesShortDescription": "Most common application requirements are already developed for you as reusable modules.", + "Account": "Account", + "Blogging": "Blogging", + "Identity": "Identity", + "IdentityServer": "Identity Server", + "Saas": "Saas", + "LanguageManagement": "Language Management", + "TextTemplateManagement": "Text Template Management", + "See All Modules": "SeeAllModules", + "ABPSuite": "ABP Suite", + "AbpSuiteShortDescription": "ABP Suite is a complementary tool to the ABP Commercial.", + "AbpSuiteExplanation": "It allows you to build web pages in a matter of minutes. It's a .NET Core Global tool which can be installed from the command line. It can create a new ABP solution, generate CRUD pages from the database to the front-end.", + "Details": "Details", + "LeptonTheme": "Lepton Theme", + "ProfessionalModernUIThemes": "Professional, modern UI themes", + "LeptonThemeExplanation": "Lepton provides a gamut of Bootstrap admin themes that serve as a solid foundation for any project requiring admin dashboard.", + "DefaultTheme": "Default Theme", + "MaterialTheme": "Material Theme", + "Default2Theme": "Default 2 Theme", + "DarkTheme": "Dark Theme", + "DarkBlueTheme": "Dark Blue Theme", + "LightTheme": "Light Theme", + "ProudToWorkWith": "Proud to Work With", + "OurConsumers": "Hundreds of enterprises and developers over 50 countries worldwide rely on ABP Commercial.", + "JoinOurConsumers": "Join them and build amazing products fast.", + "AdditionalServicesExplanation": "Do you need additional or custom services? We and our partners can provide;", + "CustomProjectDevelopment": "Custom Project Development", + "CustomProjectDevelopmentExplanation": "Dedicated developers for your custom projects.", + "PortingExistingProjects": "Porting Existing Projects", + "PortingExistingProjectsExplanation": "Migrating your legacy projects to the ABP platform.", + "LiveSupport": "Live Support", + "LiveSupportExplanation": "Live remote support option when you need it.", + "Training": "Training", + "TrainingExplanation": "Dedicated training for your developers.", + "OnBoarding": "Onboarding", + "OnBoardingExplanation": "Help to setup your development, CI & CD environments.", + "PrioritizedTechnicalSupport": "Prioritized Technical Support", + "PremiumSupportExplanation": "Beside the great community support of the ABP framework, our support team answers technical questions and problems of the commercial users with high priority.", + "SeeTheSupportOptions": "See the Support Options", + "Contact": "Contact", + "TellUsWhatYouNeed": "Tell us what you need.", + "YourMessage": "Your Message", + "YourFullName": "Your full name", + "EmailField": "E-mail Address", + "YourEmailAddress": "Your e-mail address", + "HowMayWeHelpYou": "How may we help you", + "SendMessage": "Send Message", + "Success": "Success", + "WeWillReplyYou.": "Your message is sent! We will reply you in a short time.", + "GoHome": "Go Home", + "CreateLiveDemo": "Create Live Demo", + "RegisterToTheNewsletter": "Register to the newsletter to get information on happenings about ABP.IO, like new releases.", + "EnterYourEmailOrLogin": "Enter your e-mail address to create your demo or Login using your existing account.", + "ApplicationTemplate": "Application Template", + "ApplicationTemplateExplanation": "Application startup template is used to create a new web application.", + "EfCoreProvider": "Entity Framework (Supports SQL Server, MySQL, PostgreSQL, Oracle and others)", + "AlreadyIncludedInTemplateModules": "Following modules are already included and configured in this template:", + "ApplicationTemplateArchitecture": "This application template also supports tiered architecture where UI layer, API layer and the authentication service are physically separated.", + "SeeTheGuideOrGoToTheLiveDemo": "See the developer guide for technical information about this template or go to the live demo.", + "DeveloperGuide": "Developer Guide", + "ModuleTemplate": "Module Template", + "ModuleTemplateExplanation1": "You want to create a module and reuse across different applications? This startup template prepares everything to start to create a reusable application module or a microservice.", + "ModuleTemplateExplanation2": "

You can support single or multiple UI frameworks, single or multiple database providers for a single module. The startup template is configured to run and test your module in a minimal application in addition to the unit and integration test infrastructure.

See the developer guide for technical information about this template.

", + "WithAllStyleOptions": "with all style options", + "Demo": "Demo", + "SeeAllModules": "See All Modules", + "ABPCLIExplanation": "ABP CLI (Command Line Interface) is a command line tool to perform some common operations for ABP based solutions.", + "ABPSuiteEasilyCURD": "ABP Suite is a tool which allows you to easily create CRUD pages", + "WeAreHereToHelp": "We are Here to Help", + "BrowseOrAskQuestion": "You can browse our help topics or search in frequently asked questions, or you can ask us a question by using the contact form.", + "SearchQuestionPlaceholder": "Search in frequently asked questions", + "WhatIsTheABPCommercial": "What is the ABP Commercial?", + "WhatAreDifferencesThanAbpFramework": "What are the differences between the open source ABP Framework and the ABP Commercial?", + "ABPCommercialExplanation": "ABP Commercial is a set of premium modules, tools, themes and services built on top of the open source ABP framework. ABP Commercial is being developed and supported by the same team behind the ABP framework.", + "WhatAreDifferencesThanABPFrameworkExplanation": "

ABP framework is a modular, themeable, micro-service compatible application development framework for ASP.NET Core. It provides a complete architecture and a strong infrastructure to make you focusing on your own business code rather than repeating yourself for every new project. It is based on software development best practices and popular tools you already know.

ABP framework is completely free, open source and community-driven. It also provides a free theme and some pre-built modules (e.g. identity management and tenant management).

", + "VisitTheFrameworkVSCommercialDocument": "Visit the following link, for more information {1} ", + "ABPCommercialFollowingBenefits": "ABP Commercial adds the following benefits on top of the ABP framework;", + "Professional": "Professional", + "UIThemes": "UI themes", + "EnterpriseModules": "Enterprise ready, feature rich, pre-built application modules (e.g. Identity Server management, SaaS management, language management)", + "ToolingToSupport": "Tooling to support your development productivity (e.g. ABP Suite)", + "PremiumSupportLink": "Premium support", + "WhatDoIDownloadABPCommercial": "What do I download when I purchase the ABP Commercial?", + "CreateUnlimitedSolutions": "Once you purchase an ABP Commercial license, you will be able to create unlimited solutions like described in the Getting Started document.", + "ABPCommercialSolutionExplanation": "When you create a new application, you get a Visual Studio solution (a startup template) based on your preferences. The downloaded solution has commercial modules and themes already installed and configured for you. You can remove a pre-installed module or add another module if you like. All modules and themes are used a NuGet/NPM packages by default.", + "StartDevelopWithTutorials": "The downloaded solution is well architected and documented. You can start to develop your own business code based on it following the tutorials", + "TryTheCommercialDemo": "You can try the demo to see a sample application created using the ABP Commercial startup template.", + "HowManyProducts": "How many different products/solutions can I build using the ABP Commercial?", + "HowManyProductsExplanation": "There is no limit to create an ABP project. You can create as many project as you want, develop and upload them to different servers.", + "HowManyDevelopers": "How many developers can work on the ABP Commercial?", + "HowManyDevelopersExplanation": "ABP Commercial licenses are per developer. Different license types have different developer limits. However, you can add more developers to any license type whenever you need. See the prices page for license types, developer limits and additional developer costs.", + "ChangingLicenseType": "Can I change my license type in the future?", + "ChangingLicenseTypeExplanation": "You can always add new developers in your same license type. See also \"How many developers can work on the ABP Commercial?\". You can also upgrade to a higher license by paying the calculated price difference. When you upgrade to a higher license plan, you get the benefits of the new plan, but the license upgrade does not change the license expiry date.", + "LicenseExtendUpgradeDiff": "What is the difference between license extend and upgrade?", + "LicenseExtendUpgradeDiffExplanation": "Extending: By extending/renewing your license, you will continue to get premium support and get major updates for the modules and themes. Besides, you will be able to continue creating new projects. And you will still be able to use ABP Suite which speeds up your development.
Upgrading: By upgrading your license, you will promote to a higher license plan which will allow you to get additional benefits. See the license comparison table to check the differences between the license plans.On the other hand, when you upgrade, your license expiry date will not change!To extend your license end date, you need to extend your license.", + "LicenseRenewalCost": "What is the license renewal cost after 1 year?", + "LicenseRenewalCostExplanation": "You can renew (extend) your license by paying %80 of the current license price. For example; Standard ABP Team License is ${0} and renewal price of the Team License is ${1}.", + "IsSourceCodeIncluded": "Does my license include the source code of the commercial modules and themes?", + "IsSourceCodeIncludedExplanation1": "Depends on the license type you've purchased:", + "IsSourceCodeIncludedExplanation2": "Team: Your solution uses the modules and the themes as NuGet and NPM packages. It doesn't include their source code. In this way, you can easily upgrade these modules and themes whenever a new version is available. However, you can not get the source code of the modules and the themes.", + "IsSourceCodeIncludedExplanation3": "Business/Enterprise: In addition to the Team license, you are able to download the source code of any module or theme you need. You can even remove the NuGet/NPM package references for a particular module and add its source code directly to your solution to fully change it.", + "IsSourceCodeIncludedExplanation4": "

Including the source code of a module to your solution gives you the maximum freedom to customize that module. However, then it will not be possible to automatically upgrade the module when a new version is released.

None of the licenses include the ABP Suite source code, which is an external tool that generates code for you and assist to your development.

See the pricing page for other differences between the license types.

", + "ChangingDevelopers": "Can I change the registered developers of my organization in the future?", + "ChangingDevelopersExplanation": "In addition to add new developers to your license, you can also change the existing developers (you can remove a developer and add a new one to the same seat) without any additional cost.", + "WhatHappensWhenLicenseEnds": "What happens when my license period ends?", + "WhatHappensWhenLicenseEndsExplanation1": "ABP Commercial has perpetual license type.After your license expires, you can continue developing your project. And you are not obliged to renew your license. After your license expires;", + "WhatHappensWhenLicenseEndsExplanation2": "You can not create new solutions using the ABP Commercial, but you can continue to develop your existing applications forever.", + "WhatHappensWhenLicenseEndsExplanation3": "You will be able to get updates for the modules and themes within your MAJOR version. For example; if you are using v3.2.0 of a module, you can still get updates for v3.x.x (v3.3.0, v3.5.2... etc.) of that module. But you cannot get updates for the next major version (like v4.x, v5.x)", + "WhatHappensWhenLicenseEndsExplanation4": "You can not install new modules and themes added to the ABP Commercial platform after your license ends.", + "WhatHappensWhenLicenseEndsExplanation5": "You can not use the ABP Suite.", + "WhatHappensWhenLicenseEndsExplanation6": "You can not get the premium support anymore.", + "WhatHappensWhenLicenseEndsExplanation7": "You can renew your subscription if you want to continue to get these benefits. There is a 20% discount when you renew your subscription.", + "WhenShouldIRenewMyLicense": "When should I renew my license?", + "WhenShouldIRenewMyLicenseExplanation1": "If you renew your license within 1 month after your license expires, %20 discount will be applied to total license price.", + "WhenShouldIRenewMyLicenseExplanation2": "If you renew your license after 1 month from your license expire date, the renew price will be same as license purchase price and there will be no discount for your renewal.", + "TrialPlan": "Do you have a trial plan?", + "TrialPlanExplanation": "For now, ABP Commercial doesn't have a trial plan. For the Team licenses we provide 30 days money back guarantee. You can just request a refund in the first 30 days. For the Business and Enterprise licenses, we provide 60% refund in 30 days. This is because Business and Enterprise licenses include the full source code of all the modules and the themes.", + "DoYouAcceptBankWireTransfer": "Do you accept bank wire transfer?", + "DoYouAcceptBankWireTransferExplanation": "Yes, we accept bank wire transfer.
After sending the license amount via bank wire transfer, send us your receipt and the requested license type via e-mail.
Our international bank account information:", + "HowToUpgrade": "How to upgrade existing applications when a new version is available?", + "HowToUpgradeExplanation1": "When you create a new application using ABP Commercial, all the modules and the theme are used as NuGet and NPM packages. So, you can easily upgrade the packages when a new version is available.", + "HowToUpgradeExplanation2": "In addition to the standard NuGet/NPM upgrades, ABP CLI provides an update command that automatically finds and upgrades all ABP related packages in your solution.", + "DatabaseSupport": "Which database systems are supported?", + "DatabaseSupportExplanation": "ABP Framework itself is database agnostic and can work with any database provider by its nature. See the data access document for a list of currently implemented providers.", + "UISupport": "Which UI frameworks are supported?", + "Supported": "Supported", + "UISupportExplanation": "ABP Framework itself is UI framework agnostic and can work with any UI framework. However, startup templates, module UIs and themes were not implemented for all UI frameworks. See the getting started document for the up-to-date list of UI options.", + "MicroserviceSupport": "Does it support the micro-service architecture?", + "MicroserviceSupportExplanation1": "One of the major goals of the ABP framework is to provide a convenient infrastructure to create micro-service solutions. See the micro-service architecture document to understand how it helps to create micro-service systems.", + "MicroserviceSupportExplanation2": "All the ABP Commercial modules are designed to support micro-service deployment scenarios (with its own API and database) by following the module development best practices document.", + "MicroserviceSupportExplanation3": "We provide a sample micro-service demo solutionthat demonstrates a micro-service architecture implementation to help you to create your own solution.", + "MicroserviceSupportExplanation4": "So, the short answer is \"yes, it supports micro-service architecture\".", + "MicroserviceSupportExplanation5": "However, a micro-service system is a solution and every solution will have different requirements, network topology, communication scenarios, authentication possibilities, database separation/sharing decisions, runtime configurations, 3rd party system integrations and many more.", + "MicroserviceSupportExplanation6": "The ABP Framework and the ABP Commercial provides infrastructure for micro-service scenarios, micro-service compatible modules, samples and documentation to help you to build your own solution. But don't expect to directly download your dream solution pre-built for you. You will need to understand it and bring some parts together based on your requirements.", + "WhereCanIDownloadSourceCode": "Where can I download source-code?", + "WhereCanIDownloadSourceCodeExplanation": "You can download the source code of all ABP modules, Angular packages and themes via ABP Suite or ABP CLI. See How to download source-code?", + "ComputerLimitation": "How many computers can a developer login when developing ABP?", + "ComputerLimitationExplanation": "We specifically permit {0} computers per individual/licensed developer. Whenever there is a need for a developer to develop ABP Commercial products on a third machine, an e-mail should be sent to license@abp.io explaining the situation and we will then make the appropriate allocation in our system.", + "RefundPolicy": "Do you have a refund policy?", + "RefundPolicyExplanation": "You can request a refund within 30 days of your license purchase. The Business and Enterprise license types have source-code download option, therefore refunds are not available for the Business and Enterprise (and any licenses that include a right to receive source-code). In addition, no refunds are made for renewals and second license purchases.", + "HowCanIRefundVat": "How can I refund VAT?", + "HowCanIRefundVatExplanation1": "If you made the payment using 2Checkout, you can refund VAT via your 2Checkout account:", + "HowCanIRefundVatExplanation2": "Log in into your 2Checkout account", + "HowCanIRefundVatExplanation3": "Find the appropriate order and press \"Refund Belated VAT\" (enter your VAT ID)", + "HowCanIGetMyInvoice": "How can I get my invoice?", + "HowCanIGetMyInvoiceExplanation": "There are 2 payment gateways for purchasing a license: PayU and 2Checkout. If you purchase your license through 2Checkout gateway, it sends the PDF invoice to your email address, see 2Checkout invoicing. If you purchase through the PayU gateway or via bank wire transfer, we will prepare and send your invoice. You can request your invoice from the organization management page.", + "Forum": "Forum", + "SupportExplanation": "ABP Commercial licenses provides a premium forum support by a team consists of the ABP Framework experts.", + "PrivateTicket": "Private Ticket", + "PrivateTicketExplanation": "Enterprise License also includes a private support with e-mail and ticket system.", + "AbpSuiteExplanation1": "ABP Suite allows you to build web pages in a matter of minutes. It's a .NET Core Global tool that can be installed from the command line.", + "AbpSuiteExplanation2": "It can create a new ABP solution, generate CRUD pages from the database to the front-end. For technical overview see the document", + "FastEasy": "Fast & Easy", + "AbpSuiteExplanation3": "ABP Suite allows you to easily create CRUD pages. You just need to define your entity and its properties, let the rest to ABP Suite for you! ABP Suite generates all the necessary code for your CRUD page in a few seconds. It supports Angular, MVC and Blazor user interfaces.", + "RichOptions": "Rich Options", + "AbpSuiteExplanation4": "ABP Suite supports multiple UI options like Razor Pages and Angular.It also supports multiple databases like MongoDB and all databases supported by EntityFramework Core (MS SQL Server, Oracle, MySql, PostgreSQL and more).", + "AbpSuiteExplanation5": "Good thing is that, you don't have to worry about those options. ABP Suite understands your project type and generates the code for your project and places the generated code in correct place in your project.", + "SourceCode": "Source Code", + "AbpSuiteExplanation6": "ABP Suite generates the source code for you! It doesn't generate magic files to generate the web page. ABP Suite generates the source code for Entity, Repository, Application Service, Code First Migration, JavaScript/TypeScript and CSHTML/HTML and necessary Interfaces as well. ABP Suite also generates the code according to Best Practices of software development, so you don't have to worry about generated code's quality.", + "AbpSuiteExplanation7": "Since you have the source code of building blocks of the generated CRUD page in correct application layers, you can easily modify the source code and inject your custom/bussiness logic to the generated code.", + "CrossPlatform": "Cross Platform", + "AbpSuiteExplanation8": "ABP Suite is built with .NET Core and it is cross platform. It runs as a web application on your local computer. You can run it on Windows, Mac and Linux", + "OtherFeatures": "Other Features", + "OtherFeatures1": "Updates NuGet and NPM packages on your solution easily.", + "OtherFeatures2": "Regenerates already generated pages from scratch.", + "OtherFeatures3": "Creates new solutions", + "ThanksForCreatingProject": "Thanks for Creating Your Project!", + "HotToRunSolution": "How to run your solution?", + "HotToRunSolutionExplanation": "See getting started document to learn how to configure and run your solution.", + "GettingStarted": "Getting Started", + "WebAppDevTutorial": "Web App Dev Tutorial", + "WebAppDevTutorialExplanation": "See web application development tutorial document for a step by step development sample.", + "Document": "Document", + "UsingABPSuiteToCURD": "Using ABP Suite for CRUD Page Generation & Tooling", + "SeeABPSuiteDocument": "See ABP Suite document to learn the usage of ABP Suite.", + "AskQuestionsOnSupport": "You can ask questions on ABP Commercial Support.", + "Documentation": "Documentation", + "SeeModulesDocument": "See modules document for a list of all commercial (pro) modules and their documents.", + "Pricing": "Pricing", + "PricingExplanation": "Choose the features and functionality your business needs today. Easily upgrade as your business grows.", + "Team": "Team", + "Business": "Business", + "Enterprise": "Enterprise", + "Custom": "Custom", + "IncludedDeveloperLicenses": "Included developer licenses", + "CustomLicenceOrAdditionalServices": "Need custom licence or additional services?", + "CustomOrVolumeLicense": "Custom or volume license", + "LiveTrainingSupport": "Live training & support", + "AndMore": "and more", + "AdditionalDeveloperLicense": "Additional developer license", + "ProjectCount": "Project count", + "AllProModules": "All pro modules", + "AllProThemes": "All pro themes", + "AllProStartupTemplates": "All pro startup templates", + "SourceCodeOfAllModules": "Source code of all modules", + "SourceCodeOfAllThemes": "Source code of all themes", + "PerpetualLicense": "Perpetual license", + "UnlimitedServerDeployment": "Unlimited server deployment", + "YearUpgrade": "1 year upgrade", + "YearPremiumForumSupport": "1 year premium forum support", + "ForumSupportIncidentCountYear": "Forum support incident count/year", + "PrivateTicketEmailSupport": "Private ticket & email support", + "BuyNow": "Buy Now" + } } \ 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 82c23450a0..0e1e61dba8 100644 --- a/abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/zh-Hans.json +++ b/abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/zh-Hans.json @@ -16,7 +16,7 @@ "Name": "名称", "EmailAddress": "电子邮件地址", "Developers": "开发者", - "LicenseType": "许可证类型", + "LicenseType": "许可类型", "Manage": "管理", "StartDate": "开始日期", "EndDate": "结束日期", @@ -33,7 +33,258 @@ "EmailNotValid": "请输入有效的电子邮件地址", "JoinOurMarketingNewsletter": "加入我们的营销简讯", "WouldLikeToReceiveMarketingMaterials": "我想收到市场营销资料,例如产品交易和特别优惠.", - "StartUsingYourLicenseNow": "立即开始使用你的许可证", - "WelcomePage": "欢迎页面" + "StartUsingYourLicenseNow": "立即开始使用你的许可", + "WelcomePage": "欢迎页面", + "UnsubscriptionExpireEmail": "退订许可到期提醒邮件", + "UnsubscribeLicenseExpireEmailReminderMessage": "此电子邮件订阅仅提醒你许可的到期日期.", + "UnsubscribeFromLicenseExpireEmails": "如果你不想收到关于许可到期邮件,你可以在任何时间取消订阅.", + "Unsubscribe": "取消订阅", + "NotOrganizationMember": "你不是任何组织的成员.", + "UnsubscribeLicenseExpirationEmailSuccessTitle": "退订成功", + "UnsubscribeLicenseExpirationEmailSuccessMessage": "你不会再收到任何许可到期提醒邮件.", + "IndexPageHeroSection": "一个完整的web开发平台基于 框架", + "AbpCommercialShortDescription": "ABP商业版提供了预构建的应用程序模块, 快速的应用程序开发工具, 专业的UI主题, 高级支持等.", + "LiveDemo": "在线演示", + "GetLicence" :"获得许可", + "Application": "应用程序", + "StartupTemplates": "启动模板", + "Startup": "启动", + "Templates": "模板", + "Developer": "开发人员", + "Tools": "工具", + "Premium": "高级", + "PremiumSupport": "高级支持", + "PremiumForumSupport": "高级论坛支持", + "UI": "UI", + "Themes": "主题", + "JoinOurNewsletter": "加入我们的时事通讯", + "Send": "发送", + "Learn": "学习", + "AdditionalServices": "额外的服务", + "WhatIsABPFramework": "什么是ABP框架?", + "OpenSourceBaseFramework": "开源的框架", + "ABPFrameworkExplanation": "

ABP商业版基于ABP框架, 这是一个开源和社区驱动的ASP.NET Core web应用程序开发框架.

ABP框架提供了出色的基础设施, 使用最佳实践编写可维护,可扩展,可测试的代码.

基于你已经知道的流行工具. 低学习曲线,容易适应,舒适的开发体检.

", + "Modular": "模块化", + "MicroserviceCompatible": "微服务兼容", + "DomainDrivenDesignInfrastructure": "领域驱动设计基础设施", + "MultiTenancy": "多租户", + "DistributedMessaging": "分布式消息", + "DynamicProxying": "动态代理", + "BackgroundJobs": "后台作业", + "AuditLogging": "审计日志", + "BLOBStoring": "BLOB存储", + "BundlingMinification": "捆绑 & 压缩", + "AdvancedLocalization": "高级本地化", + "ManyMore": "以及更多", + "ExploreTheABPFramework": "探索ABP框架", + "WhyUseTheABPCommercial": "为什么使用ABP商业版?", + "WhyUseTheABPCommercialExplanation": "

构建企业级的web应用程序可能复杂和耗时.

ABP商业版提供所有现代企业级基于ASP.NET Core的解决方案所需要的基础设施. 从设计到部署,整个开发生命周期都由ABP的内置功能和模块提供支持.

", + "StartupTemplatesShortDescription": "启动模板使你在几秒内快速启动项目.", + "UIFrameworksOptions": "UI框架选项;", + "DatabaseProviderOptions": "数据库提供程序选项;", + "PreBuiltApplicationModules": "预构建的应用程序模块", + "PreBuiltApplicationModulesShortDescription": "大多数常见的应用程序需求已经做为可重用的模块为你开发了.", + "Account": "账户", + "Blogging": "博客", + "Identity": "Identity", + "IdentityServer": "Identity Server", + "Saas": "Saas", + "LanguageManagement": "语言管理", + "TextTemplateManagement": "文本模板管理", + "See All Modules": "查看所有的模块", + "ABPSuite": "ABP Suite", + "AbpSuiteShortDescription": "ABP Suite是ABP商业版的辅助工具.", + "AbpSuiteExplanation": "它让你在几分钟内构建web页面. 它是一个.Net Core全局工具,可以使用命令行安装. 它可以创建一个新的ABP解决方案,从数据库生成前端CURD页面.", + "Details": "详情", + "LeptonTheme": "Lepton主题", + "ProfessionalModernUIThemes": "专业, 现代化的UI主题", + "LeptonThemeExplanation": "Lepton提供了一系列的Bootstrap管理主题,为任何需要管理仪表盘的项目提供了坚实的基础.", + "DefaultTheme": "默认主题", + "MaterialTheme": "Material主题", + "Default2Theme": "默认主题2", + "DarkTheme": "深色主题", + "DarkBlueTheme": "深蓝主题", + "LightTheme": "浅色主题", + "ProudToWorkWith": "荣幸与你合作", + "OurConsumers": "全球50多个国家的数百家企业和开发商使用ABP商业版.", + "JoinOurConsumers": "加它他们并快速构建令人惊叹的产品.", + "AdditionalServicesExplanation": "你是否需要额外或自定义的服务? 我们和我们的合作伙伴可以提供;", + "CustomProjectDevelopment": "自定义项目开发", + "CustomProjectDevelopmentExplanation": "专为你的自定义的开发人员.", + "PortingExistingProjects": "移植现有项目", + "PortingExistingProjectsExplanation": "将你的迁移传统项目迁移到ABP平台.", + "LiveSupport": "实时支持", + "LiveSupportExplanation": "在你需要时,可以实时提供远程支持选项.", + "Training": "培训", + "TrainingExplanation": "为你的开发人员提供专门培训.", + "OnBoarding": "管理", + "OnBoardingExplanation": "帮助设置你的开发,CI和CD环境.", + "PrioritizedTechnicalSupport": "优先的技术支持", + "PremiumSupportExplanation": "除了社区对ABP框架出色支持外,我们的支持团队会优先回答商业用户的技术问题.", + "SeeTheSupportOptions": "查看支持选项", + "Contact": "联系", + "TellUsWhatYouNeed": "告诉我们你需要什么.", + "YourMessage": "你的消息", + "YourFullName": "你的全名", + "EmailField": "E-mail地址", + "YourEmailAddress": "你的e-mail地址", + "HowMayWeHelpYou": "我们如何帮助你", + "SendMessage": "发送消息", + "Success": "成功", + "WeWillReplyYou.": "你的消息已经发送! 我们会在短时间内给你答复.", + "GoHome": "回到主页面", + "CreateLiveDemo": "创建在线演示", + "RegisterToTheNewsletter": "注册到时事简报以获取有关ABP.IO的消息,比如新发布的内容.", + "EnterYourEmailOrLogin": "输入你的e-mail地址来创建你的演示或者使用你的已有账号登录.", + "ApplicationTemplate": "应用程序模板", + "ApplicationTemplateExplanation": "应用程序启动模板用于创建新的web应用程序.", + "EfCoreProvider": "Entity Framework (支持 SQL Server, MySQL, PostgreSQL, Oracle 和其它)", + "AlreadyIncludedInTemplateModules": "以下模块已经包含并配置在此模板中:", + "ApplicationTemplateArchitecture": "应用程序模板还支持UI,API,身份验证服务器物理分离的分层架构.", + "SeeTheGuideOrGoToTheLiveDemo": "查看开发人员指南或者查看在线演示了解更多关于模板的信息.", + "DeveloperGuide": "开发人员指南", + "ModuleTemplate": "模块模块", + "ModuleTemplateExplanation1": "你是否想要创建可在不同应用程序之间重用的模块? 这个启动模板准备好了一切来创建可重用的应用程序模块或微服务.", + "ModuleTemplateExplanation2": "

你可以为一个模块支持单个或多个UI框架, 单个或多个数据库提供程序. 除了单元测试和集成测试基础架构外,启动模板被配置为在一个最小的应用程序中运行和测试你的模块.

查看开发人员指南了解有关此模板的技术信息.

", + "WithAllStyleOptions": "使用所有的样式选项", + "Demo": "演示", + "SeeAllModules": "查看所有的模块", + "ABPCLIExplanation": "ABP CLI(命令行页面)是一个执行基于ABP解决方案的一些常见操作的命令行工具.", + "ABPSuiteEasilyCURD": "ABP Suite是一个使你轻松创建CURD页面的工具", + "WeAreHereToHelp": "我们在这里为你提供帮助", + "BrowseOrAskQuestion": "你可以浏览我们的帮助主题或搜索常见的问题, 或者你可以使用联系表单向我们提问.", + "SearchQuestionPlaceholder": "搜索常见的问题", + "WhatIsTheABPCommercial": "什么是ABP商业版?", + "WhatAreDifferencesThanAbpFramework": "ABP框架与ABP商业版有什么不同?", + "ABPCommercialExplanation": "ABP商业版是一套基于开源ABP框架之上的高级模块,工具,主题和服务. ABP商业版由ABP框架背后的同一团队开发和支持.", + "WhatAreDifferencesThanABPFrameworkExplanation": "

ABP框架是模块化,主题化,微服务兼容的ASP.NET Core应用程序开发框架. 它提供了一个完整的架构和强大的基础设施,让你专注于自己的业务代码而不是重复自己的每一个项目. 它基于软件开发的最佳实践和你已经知道的流行工具

ABP框架是完全免费,开源和由社区驱动的. 它还提供了一个免费的主题和一些预构建的模块 (如 identity管理和租户管理).

", + "VisitTheFrameworkVSCommercialDocument": "访问以下链接,了解更多信息 {1} ", + "ABPCommercialFollowingBenefits": "ABP商业版在ABP框架之上添加了以下好处;", + "Professional": "专业的", + "UIThemes": "UI主题", + "EnterpriseModules": "企业就绪,功能丰富,预构建的应用程序模块 (如 Identity Server管理, SaaS管理, 语言管理)", + "ToolingToSupport": "支持你的生产力的工具(如. ABP Suite)", + "PremiumSupportLink": "高级支持", + "WhatDoIDownloadABPCommercial": "购买ABP商业版后我可以下载什么?", + "CreateUnlimitedSolutions": "一旦你购买了ABP商业许可, 你可以创建入门文档中描述的无限的解决方案.", + "ABPCommercialSolutionExplanation": "创建新应用程序时,将根据你的首选项获得Visual Studio解决方案(启动模板). 下载的解决方案已为你安装并配置了商业模块和主题. 你可以删除预装的模块,也可以根据需要添加其他模块. 默认情况下所有模块和主题都使用NuGet/NPM软件包.", + "StartDevelopWithTutorials": "下载的解决方案经过精心设计和记录, 你可以根据教程来开发自己的业务代码.", + "TryTheCommercialDemo": "你可以尝试示例来查看使用ABP商业模板创建的示例应用程序.", + "HowManyProducts": "使用ABP商业版,我可以构建多少不同的产品/解决方案?", + "HowManyProductsExplanation": "创建ABP项目没有限制. 你可以根据需要创建任意数量的项目,进行开发并将其部署到其他服务器.", + "HowManyDevelopers": "有多少开发者可以参与ABP商业版工作?", + "HowManyDevelopersExplanation": "ABP商业许可是针对每个开发人员的. 不同的许可类型具有不同的开发人员限制. 但是你可以在需要时将更多开发人员添加到任何许可类型. 查看许可类型,开发人员限制和额外的开发人员成本的价格页面.", + "ChangingLicenseType": "将来更改我的许可类型吗?", + "ChangingLicenseTypeExplanation": "你始终可以在同一许可中添加新的开发人员. 参阅 \"有多少开发者可以参与ABP商业版工作?\". 你还可以通过支付计算出的价格差来升级到更高的许可. 当你升级到更高的许可计划时,可以享受新计划的好处,但是许可升级不会更改许可的到期日期.", + "LicenseExtendUpgradeDiff": "许可扩展和升级有什么区别?", + "LicenseExtendUpgradeDiffExplanation": "扩展: 通过扩展/更新许可,你将继续获得高级支持,并获得有关模块和主题的重大更新. 此外你将能够继续创建新项目. 而且你仍然可以使用ABP Suite来加快开发速度.
升级: 通过升级许可,你将升级到更高的许可计划,这将使你获得更多好处. 查看 许可比较表来检查许可计划之间的差异. 另一方面,当你升级时你的许可到期日期不会改变!要延长你的许可终止日期,你需要延长你的许可.", + "LicenseRenewalCost": "一年后的许可续期费用是多少?", + "LicenseRenewalCostExplanation": "你可以通过支付当前许可价格的%80来续订(扩展)你的许可. 例如; 标准ABP团队许可为 ${0} 续订价格是 ${1}.", + "IsSourceCodeIncluded": "我的许可是否包括商业模块和主题的源代码?", + "IsSourceCodeIncludedExplanation1": "取决于你购买的许可类型:", + "IsSourceCodeIncludedExplanation2": "团队: 你的解决方案将这些模块和主题作为NuGet和NPM包使用. 它不包括其源代码. 这样,只要有新版本可用,你就可以轻松升级这些模块和主题. 但是,你无法获取模块和主题的源代码.", + "IsSourceCodeIncludedExplanation3": "商业/企业: 除了团队许可外,你还可以下载所需的任何模块或主题的源代码. 你甚至可以删除特定模块的NuGet/NPM软件包引用,并将其源代码直接添加到你的解决方案中以完全更改它.", + "IsSourceCodeIncludedExplanation4": "

将模块的源代码包含到解决方案中,可以最大程度地自定义该模块. 但是当新版本发布时,将无法自动升级模块.

这些许可均不包含ABP Suite源代码,该源代码是一个外部工具,可以为你生成代码并帮助你进行开发

有关许可类型之间的其它差异查看定价页面.

", + "ChangingDevelopers": "我将来可以更改我组织的注册开发人员吗?", + "ChangingDevelopersExplanation": "除了将新的开发人员添加到你的许可中之外,你还可以更改现有的开发人员(可以删除一个开发人员并将新的开发人员添加到同一位置),而无需任何额外费用.", + "WhatHappensWhenLicenseEnds": "我的许可期限结束后会怎样?", + "WhatHappensWhenLicenseEndsExplanation1": "ABP商业版具有永久许可类型.许可到期后, 你可以继续开发你的项目.并且你没有义务续订许可.许可到期后;", + "WhatHappensWhenLicenseEndsExplanation2": "你不能使用ABP商业版创建新的解决方案,但可以永远继续开发现有的应用程序.", + "WhatHappensWhenLicenseEndsExplanation3": "你能够在你的主版本中获得模块和主题的更新.例如;如果你使用的是模块的v3.2.0版本,你仍然可以获得v3.x.x版本的更新.(v3.3.0 v3.5.2…等等)的.但是你无法获得下一个主要版本(如v4.x,v5.x)的更新", + "WhatHappensWhenLicenseEndsExplanation4": "许可到期后,你无法安装添加到ABP商业平台的新模块和主题.", + "WhatHappensWhenLicenseEndsExplanation5": "你不能使用ABP Suite.", + "WhatHappensWhenLicenseEndsExplanation6": "你不再获得高级支持.", + "WhatHappensWhenLicenseEndsExplanation7": "如果你想继续获得这些好处,可以继续续订. 续订时有20%的折扣.", + "WhenShouldIRenewMyLicense": "我什么时候应该续订我的许可?", + "WhenShouldIRenewMyLicenseExplanation1": "如果你在许可到期后的 1个月内续订许可,则许可总价将享受%20的折扣.", + "WhenShouldIRenewMyLicenseExplanation2": "如果你在你的许可过期日期1个月后更新你的许可,更新价格将与许可购买价格相同,你的更新将没有折扣.", + "TrialPlan": "你们有试用计划吗?", + "TrialPlanExplanation": "目前,ABP商业版还没有试用计划.对于团队许可,我们提供30天的退款保证.你可以在30天内要求退款.对于企业营业执照,我们提供30天内60%的退款.这是因为商业和企业许可包含所有模块和主题的完整源代码.", + "DoYouAcceptBankWireTransfer": "你们接受银行电汇吗?", + "DoYouAcceptBankWireTransferExplanation": "是的,我们接受银行电汇.
通过银行电汇转账,通过电子邮件将收据和所要求的许可类型发送给我们.
我们的国际银行帐户信息:", + "HowToUpgrade": "可用新版本时如何升级现有应用程序?", + "HowToUpgradeExplanation1": "使用ABP商业版创建新应用程序时,所有模块和主题均用作NuGet和NPM软件包. 因此,当有新版本可用时,你可以轻松升级软件包.", + "HowToUpgradeExplanation2": "除了标准的NuGet/NPM升级之外, ABP CLI 还提供了一条更新命令,该命令可自动查找和升级解决方案中的所有与ABP相关的软件包.", + "DatabaseSupport": "支持哪些数据库系统?", + "DatabaseSupportExplanation": "ABP框架本身与数据库无关,并且就其性质而言,可以与任何数据库提供程序一起使用. 请参阅数据访问文档以获取当前实现的提供程序的列表.", + "UISupport": "支持哪些UI框架?", + "Supported": "支持的", + "UISupportExplanation": "ABP框架本身与UI框架无关,并且可以与任何UI框架一起使用. 但是,并非针对所有UI框架都实现了启动模板,模块UI和主题. 有关UI选项的最新列表,请参见入门文档.", + "MicroserviceSupport": "它是否支持微服务架构?", + "MicroserviceSupportExplanation1": "ABP框架的主要目标之一是为创建微服务解决方案提供便利的基础架构. 请参阅微服务体系结构文档,以了解它如何帮助创建微服务系统.", + "MicroserviceSupportExplanation2": "所有的ABP商业模块通过模块开发最佳实践文档被设计为支持微服务部署场景(使用自己的API和数据库).", + "MicroserviceSupportExplanation3": "我们提供了一个示例微服务演示解决方案,该示例演示了一种微服务架构实现,可帮助你创建自己的解决方案.", + "MicroserviceSupportExplanation4": "所以简短的答案是 \"是的, 它支持微服务体系结构\".", + "MicroserviceSupportExplanation5": "但是,微服务系统是一个解决方案,每个解决方案都有不同的要求,网络拓扑,通信场景,身份验证可能性,数据库分离/共享决策,运行时配置,第三方系统集成等等.", + "MicroserviceSupportExplanation6": "ABP框架和ABP商业版提供了微服务方案,微服务兼容模块,示例和文档的基础结构,以帮助你构建自己的解决方案. 但是不要期望直接下载为你预先构建的梦想解决方案. 你将需要了解它,并根据需要将某些部分组合在一起.", + "WhereCanIDownloadSourceCode": "在哪里可以下载源代码?", + "WhereCanIDownloadSourceCodeExplanation": "你可以通过ABP Suite或ABP CLI下载所有ABP模块,Angular软件包和主题的源代码. 请参见如何下载源代码?", + "ComputerLimitation": "开发人员在开发ABP时可以登录到多少台计算机?", + "ComputerLimitationExplanation": "我们特别允许每个个人/许可的开发人员使用 {0}台计算机. 每当需要开发人员在第三台计算机上开发ABP商业产品时,都应将电子邮件发送到license@abp.io,以说明情况,然后我们将在系统中进行适当分配.", + "RefundPolicy": "你们有退款政策吗?", + "RefundPolicyExplanation": "你可以在购买许可的30天内请求退款.商业和企业许可类型都有源代码下载选项,因此商业和企业(以及任何包含获得源代码的权利的许可)都不能退款.此外,续展和购买第二次许可也不退款.", + "HowCanIRefundVat": "我该如何退还增值税?", + "HowCanIRefundVatExplanation1": "如果你使用2Checkout付款,则可以通过2Checkout帐户退还增值税:", + "HowCanIRefundVatExplanation2": "登录到你的2Checkout账户", + "HowCanIRefundVatExplanation3": "找到适当的订单,然后按\"退还已延期的增值税\"(输入你的增值税ID", + "HowCanIGetMyInvoice": "我如何获得发票?", + "HowCanIGetMyInvoiceExplanation": "有两个用于购买许可的支付网关:PayU和2Checkout. 如果你通过2Checkout网关购买许可,则它将PDF发票发送到你的电子邮件地址,请参阅2Checkout发票.如果你是通过PayU网关或通过银行电汇购买的,我们将准备并发送你的发票. 你可以从组织管理页面索取发票.", + "Forum": "论坛", + "SupportExplanation": "ABP商业版许可包含由ABP框架专家组成的团队提供的高级论坛支持.", + "PrivateTicket": "私有票", + "PrivateTicketExplanation": "企业许可还包含带有电子邮件和票系统的私人支持.", + "AbpSuiteExplanation1": "ABP Suite使你在几分钟内构建web页面. 它是一个.NET Core Global工具,可以使用命令行安装.", + "AbpSuiteExplanation2": "它可以创建一个新的ABP解决方案, 从数据库生成前端CURD页面. 有关技术概述查看文档", + "FastEasy": "快速并且简单", + "AbpSuiteExplanation3": "ABP Suite允许你轻松的创建CURD页面. 你只需要定义你的实体和它的属性, 其它的让ABP Suite帮你完成! ABP Suite会在几秒内为你生成CURD页面和必要的代码. 它支持Angular, MVC和 Blazor用户界面.", + "RichOptions": "丰富的选项", + "AbpSuiteExplanation4": "ABP Suite支持多个UI选项,例如 Razor Pages和Angular.它还支持多个数据库, 如 MongoDB 和EntityFramework Core支持的所有数据库(MS SQL Server, Oracle, MySql, PostgreSQL 和 更多).", + "AbpSuiteExplanation5": "好消息是, 你不必担心这些选项. ABP Suite了解你的项目类型并且将生成的代码放到项目中正确的位置.", + "SourceCode": "源码", + "AbpSuiteExplanation6": "ABP Suite为你生成源代码! 它不会生成魔法文件来生成web页面. ABP Suite为实体, 仓储, 应用程序, Code First迁移, JavaScript/TypeScript 和 CSHTML/HTML以及必要的页面生成源代码. ABP Suite根据软件开发的最佳实践来生成代码, 所以你不必担心生成的代码的质量.", + "AbpSuiteExplanation7": "由于你有应用程序层中生成的CURD页面的构建块的源代码, 因此你可以轻松修改源码并将自定义/业务逻辑注入到所生成的代码中.", + "CrossPlatform": "跨平台", + "AbpSuiteExplanation8": "ABP Suite使用.NET Core构建并且它是跨平台的. 它在你的本地电脑中运行为web应用程序. 你可以在Windows, Mac和Linux上运行它", + "OtherFeatures": "其他功能", + "OtherFeatures1": "轻松更新你的解决方案的NuGet和NPM包.", + "OtherFeatures2": "重新生成已经生成的页面.", + "OtherFeatures3": "创建新的解决方案", + "ThanksForCreatingProject": "感谢你创建你的项目!", + "HotToRunSolution": "如何运行你的解决方案?", + "HotToRunSolutionExplanation": "查看入门文档来学习如何配置和运行你的解决方案.", + "GettingStarted": "入门", + "WebAppDevTutorial": "Web应用开发教程", + "WebAppDevTutorialExplanation": "查看web应用程序开发教程文档来一步一步的了解开发示例.", + "Document": "文档", + "UsingABPSuiteToCURD": "使用ABP Suite来生成CURD页面", + "SeeABPSuiteDocument": "查看ABP Suite文档学习如何使用ABP Suite.", + "AskQuestionsOnSupport": "你可以在ABP商业支持提出问题.", + "Documentation": "文档", + "SeeModulesDocument": "查看模块文档获取所有商业(专业)模块列表和它们的文档.", + "Pricing": "价格", + "PricingExplanation": "选择当前业务需要的特性和功能. 随着业务增长轻松升级.", + "Team": "团队", + "Business": "商业", + "Enterprise": "企业", + "Custom": "自定义", + "IncludedDeveloperLicenses": "包括开发人员许可", + "CustomLicenceOrAdditionalServices": "需要自定义许可与额外服务?", + "CustomOrVolumeLicense": "自定义或批量许可", + "LiveTrainingSupport": "现场培训和支持", + "AndMore": "和更多", + "AdditionalDeveloperLicense": "额外的开发人员许可", + "ProjectCount": "项目数量", + "AllProModules": "所有模块", + "AllProThemes": "所有主题", + "AllProStartupTemplates": "所有专业启动模板", + "SourceCodeOfAllModules": "所有模块的源码", + "SourceCodeOfAllThemes": "所有主题的源码", + "PerpetualLicense": "永久的许可", + "UnlimitedServerDeployment": "无限制的服务器部署", + "YearUpgrade": "1年升级", + "YearPremiumForumSupport": "1年高级论坛支持", + "ForumSupportIncidentCountYear": "论坛支持事件数量/年", + "PrivateTicketEmailSupport": "私有票和email支持", + "BuyNow": "现在购买" } } \ No newline at end of file diff --git a/abp_io/AbpIoLocalization/AbpIoLocalization/Community/Localization/Resources/en.json b/abp_io/AbpIoLocalization/AbpIoLocalization/Community/Localization/Resources/en.json index 9c1e434ac1..9c5ae26f89 100644 --- a/abp_io/AbpIoLocalization/AbpIoLocalization/Community/Localization/Resources/en.json +++ b/abp_io/AbpIoLocalization/AbpIoLocalization/Community/Localization/Resources/en.json @@ -136,6 +136,8 @@ "GitHubUserNameValidationMessage": "Your Github username can not include whitespace, please be sure your Github username is correct.", "PersonalSiteUrlValidationMessage": "Your personal site URL can not include whitespace, please be sure your personal site URL is correct.", "TwitterUserNameValidationMessage": "Your Twitter username can not include whitespace, please be sure your Twitter username is correct.", - "LinkedinUrlValidationMessage": "Your Linkedin URL can not include whitespace, please be sure your Linkedin URL is correct." + "LinkedinUrlValidationMessage": "Your Linkedin URL can not include whitespace, please be sure your Linkedin URL is correct.", + "NoPostsFound": "No posts found!", + "SearchInPosts": "Search in posts..." } } diff --git a/docs/en/Background-Jobs-RabbitMq.md b/docs/en/Background-Jobs-RabbitMq.md index 2ee478ed17..16b8b0981a 100644 --- a/docs/en/Background-Jobs-RabbitMq.md +++ b/docs/en/Background-Jobs-RabbitMq.md @@ -66,6 +66,26 @@ Defining multiple connections is allowed. In this case, you can use different co } ```` +If you need to connect to the RabbitMQ cluster, you can use the `;` character to separate the host names. + +**Example: Connect to the RabbitMQ cluster** + +```json +{ + "RabbitMQ": { + "Connections": { + "Default": { + "HostName": "123.123.123.123;234.234.234.234" + } + }, + "EventBus": { + "ClientName": "MyClientName", + "ExchangeName": "MyExchangeName" + } + } +} +``` + #### AbpRabbitMqOptions `AbpRabbitMqOptions` class can be used to configure the connection strings for the RabbitMQ. You can configure this options inside the `ConfigureServices` of your [module](Module-Development-Basics.md). diff --git a/docs/en/Distributed-Event-Bus-RabbitMQ-Integration.md b/docs/en/Distributed-Event-Bus-RabbitMQ-Integration.md index 9587a111bf..3d99e1e3cf 100644 --- a/docs/en/Distributed-Event-Bus-RabbitMQ-Integration.md +++ b/docs/en/Distributed-Event-Bus-RabbitMQ-Integration.md @@ -90,7 +90,7 @@ You can use any of the [ConnectionFactry](http://rabbitmq.github.io/rabbitmq-dot **Example: Specify the connection port** -````csharp +````json { "RabbitMQ": { "Connections": { @@ -103,6 +103,26 @@ You can use any of the [ConnectionFactry](http://rabbitmq.github.io/rabbitmq-dot } ```` +If you need to connect to the RabbitMQ cluster, you can use the `;` character to separate the host names. + +**Example: Connect to the RabbitMQ cluster** + +```json +{ + "RabbitMQ": { + "Connections": { + "Default": { + "HostName": "123.123.123.123;234.234.234.234" + } + }, + "EventBus": { + "ClientName": "MyClientName", + "ExchangeName": "MyExchangeName" + } + } +} +``` + ### The Options Classes `AbpRabbitMqOptions` and `AbpRabbitMqEventBusOptions` classes can be used to configure the connection strings and event bus options for the RabbitMQ. diff --git a/docs/en/UI/Angular/Router-Events.md b/docs/en/UI/Angular/Router-Events.md index 011d405b22..1d36c3a211 100644 --- a/docs/en/UI/Angular/Router-Events.md +++ b/docs/en/UI/Angular/Router-Events.md @@ -1,6 +1,6 @@ # Router Events Simplified -`RouterEvents` is a utility service to provide an easy implementation for one of the most frequent needs in Angular templates: `TrackByFunction`. Please see [this page in Angular docs](https://angular.io/guide/template-syntax#ngfor-with-trackby) for its purpose. +`RouterEvents` is a utility service for filtering specific router events and reacting to them. Please see [this page in Angular docs](https://angular.io/api/router/Event) for available router events. diff --git a/docs/en/UI/Angular/Service-Proxies.md b/docs/en/UI/Angular/Service-Proxies.md index 8f6b1c4d60..3a10f1b6e8 100644 --- a/docs/en/UI/Angular/Service-Proxies.md +++ b/docs/en/UI/Angular/Service-Proxies.md @@ -137,3 +137,7 @@ export class BookComponent implements OnInit { ``` > Please [see this article](https://github.com/abpframework/abp/blob/dev/docs/en/Blog-Posts/2020-09-07%20Angular-Service-Proxies/POST.md) to learn more about service proxies. + +### Known Limitations + +When you run a project on Visual Studio using IIS Express as the web server, there will be no remote access to your endpoints. This is the default behavior of IIS Express since it explicitly protects you from the security risks of running over the network. However, that will cause the proxy generator to fail because it needs a response from the `/api/abp/api-definition` endpoint. You may serve your endpoints via Kestrel to avoid this. Running `dotnet run` in your command line (at your project folder) will do that for you. diff --git a/docs/zh-Hans/Background-Jobs-RabbitMq.md b/docs/zh-Hans/Background-Jobs-RabbitMq.md index 979beec872..0f9fb21d8a 100644 --- a/docs/zh-Hans/Background-Jobs-RabbitMq.md +++ b/docs/zh-Hans/Background-Jobs-RabbitMq.md @@ -1,3 +1,153 @@ -# RabbitMQ Background Job Manager +# RabbitMQ 后台作业管理 -待添加 \ No newline at end of file +RabbitMQ 是一个标准的消息队列中间件,虽然它常用于消息传递/分布式事件,但也非常适合存储 FIFO(先进先出) 顺序的后台作业. + +ABP Framework 提供了 [Volo.Abp.BackgroundJobs.RabbitMQ](https://www.nuget.org/packages/Volo.Abp.BackgroundJobs.RabbitMQ) 包,将使用 RabbitMQ 来执行后台作业. + +> 参阅 [后台作业文档](Background-Jobs.md) 学习如何使用后台作业系统,本文只介绍了如何安装和配置 RabbitMQ 集成. + +## 安装 + +使用 ABP CLI 将 [Volo.Abp.BackgroundJobs.RabbitMQ](https://www.nuget.org/packages/Volo.Abp.BackgroundJobs.RabbitMQ) 包添加到你的项目: + +- 如果之前没有安装过 [ABP CLI](https://docs.abp.io/en/abp/latest/CLI),请先安装它. +- 跳转到待安装后台作业管理的项目目录中(包含 `.csproj` 文件的目录),打开终端管理器. +- 执行 `abp add-package Volo.Abp.BackgroundJobs.RabbitMQ` 命令. + +如果你想要手动安装,请先用 NuGet 包管理器安装 [Volo.Abp.BackgroundJobs.RabbitMQ](https://www.nuget.org/packages/Volo.Abp.BackgroundJobs.RabbitMQ) 包到指定项目,之后使在你的 [模块](Module-Development-Basics.md) 上面添加 `[DependsOn(typeof(AbpBackgroundJobsRabbitMqModule))]` 配置依赖. + +## 配置 + +### 默认配置 + +默认配置将会使用标准端口和主机名(localhost)连接到 RabbitMQ 服务,**你不需要进行额外配置**. + +### RabbitMQ 连接 + +你可以使用 ASP.NET Core 的 [标准配置系统](Configuration.md) 对 RabbitMQ 进行详细配置,比如 `appsettings.json` 或者是 [选项类](Options.md). + +#### 通过 `appsettings.json` 文件配置 + +这种方式是配置 RabbitMQ 连接最简单的方式,你可以使用其他的配置源(例如环境变量).这些强大的功能都是由 [ASP.NET Core](https://docs.microsoft.com/zh-cn/aspnet/core/fundamentals/configuration/) 提供的支持. + +**示例: 配置默认的 RabbitMQ 连接** + +```json +{ + "RabbitMQ": { + "Connections": { + "Default": { + "HostName": "123.123.123.123", + "Port": "5672" + } + } + } +} +``` + +你可以在配置文件使用所有 [ConnectionFactry](http://rabbitmq.github.io/rabbitmq-dotnet-client/api/RabbitMQ.Client.ConnectionFactory.html#properties) 的属性,关于这些属性的具体含义,可以查看 RabbitMQ 的 [官方文档](https://www.rabbitmq.com/dotnet-api-guide.html#exchanges-and-queues). + +目前我们允许定义多个连接,多连接的情况适用于不同的后台作业,具体配置信息可以参考下面的 RabbitMQ 后台作业配置说明. + +**示例: 定义两个 RabbitMQ 连接** + +```json +{ + "RabbitMQ": { + "Connections": { + "Default": { + "HostName": "123.123.123.123" + }, + "SecondConnection": { + "HostName": "321.321.321.321" + } + } + } +} +``` + +如果需要连接到 RabbitMQ 集群,你可以指定多个 HostName. + +**示例: 连接到 RabbitMQ 集群** + +```json +{ + "RabbitMQ": { + "Connections": { + "Default": { + "HostName": "123.123.123.123;234.234.234.234" + } + }, + "EventBus": { + "ClientName": "MyClientName", + "ExchangeName": "MyExchangeName" + } + } +} +``` + +#### 使用选项类 + +`AbpRabbitMqOptions` 类型用于配置 RabbitMQ 的连接字符串,你可以在 [模块](Module-Development-Basics.md) 的 `ConfigureService` 方法中进行配置. + +**示例: 配置 RabbitMQ 连接** + +```csharp +Configure(options => +{ + options.Connections.Default.UserName = "user"; + options.Connections.Default.Password = "pass"; + options.Connections.Default.HostName = "123.123.123.123"; + options.Connections.Default.Port = 5672; +}); +``` + +关于选项类,可以结合 `appsettings.json` 文件一起使用.针对同一个属性,在选项类里面对该值进行了设定,会覆盖掉 `appsettings.json` 的值. + +### RabbitMQ 后台作业配置说明 + +#### 后台作业队列的名称 + +默认情况下,每个后台作业都会使用一个单独的队列,结合标准前缀和作业名称来构造一个完整的队列名称.默认的前缀为 `AbpBackgroundJobs`,所以有一个作业的名称是 `EmailSending` 的话,在 RabbitMQ 的队列名称就是 `AbpBackgroundJobs.EmailSending`. + +> 在后台作业的参数类上,可以使用 `BackgroundJobName` 特性指定后台作业的名称.否则的话,后台作业的名称将会是后台作业类的全名(也包含命名空间). + +#### 后台作业使用的连接 + +默认情况下,后台作业都会使用 `Default` 作为默认连接. + +#### 自定义 + +`AbpRabbitMqBackgroundJobOptions` 可以自定义队列名和作业使用的 RabbitMQ 连接. + +**示例: ** + +```csharp +Configure(options => +{ + options.DefaultQueueNamePrefix = "my_app_jobs."; + options.JobQueues[typeof(EmailSendingArgs)] = + new JobQueueConfiguration( + typeof(EmailSendingArgs), + queueName: "my_app_jobs.emails", + connectionName: "SecondConnection" + ); +}); +``` + +- 这个示例将默认的队列名前缀设置为 `my_app_jobs.`,如果多个项目都使用的同一个 RabbitMQ 服务,设置不同的前缀可以避免执行其他项目的后台作业. +- 这里还设置了 `EmailSendingArgs` 绑定的 RabbitMQ 连接. + +`JobQueueConfiguration` 类的构造函数中,还有一些其他的可选参数. + +- `queueName`: 指定后台作业对应的队列名称(全名). +- `connectionName`: 后台作业对应的 RabbitMQ 连接名称,默认是 `Default`. +- `durable`: 可选参数,默认为 `true`. +- `exclusive`: 可选参数,默认为 `false`. +- `autoDelete`: 可选参数,默认为 `false`. + +如果你想要更多地了解 `durable`,`exclusive`,`autoDelete` 的用法,请阅读 RabbitMQ 提供的文档. + +## 另请参阅 + +- [后台作业](Background-Jobs.md) diff --git a/docs/zh-Hans/Distributed-Event-Bus-RabbitMQ-Integration.md b/docs/zh-Hans/Distributed-Event-Bus-RabbitMQ-Integration.md index 2a1810e309..ab7cb68bd7 100644 --- a/docs/zh-Hans/Distributed-Event-Bus-RabbitMQ-Integration.md +++ b/docs/zh-Hans/Distributed-Event-Bus-RabbitMQ-Integration.md @@ -103,6 +103,26 @@ } ```` +如果需要连接到 RabbitMQ 集群,你可以指定多个 HostName。 + +**示例: 连接到 RabbitMQ 集群** + +```json +{ + "RabbitMQ": { + "Connections": { + "Default": { + "HostName": "123.123.123.123;234.234.234.234" + } + }, + "EventBus": { + "ClientName": "MyClientName", + "ExchangeName": "MyExchangeName" + } + } +} +``` + ### 选项类 `AbpRabbitMqOptions` 和 `AbpRabbitMqEventBusOptions` 类用于配置RabbitMQ的连接字符串和事件总线选项. diff --git a/docs/zh-Hans/Repositories.md b/docs/zh-Hans/Repositories.md index 79186b79da..857df51439 100644 --- a/docs/zh-Hans/Repositories.md +++ b/docs/zh-Hans/Repositories.md @@ -150,7 +150,7 @@ var people = _personRepository * 这里异步方法**不是标准LINQ方法**,它们定义在[Microsoft.EntityFrameworkCore](https://www.nuget.org/packages/Microsoft.EntityFrameworkCore)Nuget包中. * 标准模板应用层与领域层**不引用**EF Core 包以实现数据库提供程序独立. -根据你的需求和开发模式,你可以根据以下选项使用异步方法.s +根据你的需求和开发模式,你可以根据以下选项使用异步方法. > 强烈建议使用异步方法! 在执行数据库查询时不要使用同步LINQ方法,以便能够开发可伸缩的应用程序. diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Packages/Volo/Abp/AspNetCore/Mvc/UI/Packages/TuiEditor/TuiEditorScriptContributor.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Packages/Volo/Abp/AspNetCore/Mvc/UI/Packages/TuiEditor/TuiEditorScriptContributor.cs index e788c612cf..e2e826445f 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Packages/Volo/Abp/AspNetCore/Mvc/UI/Packages/TuiEditor/TuiEditorScriptContributor.cs +++ b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Packages/Volo/Abp/AspNetCore/Mvc/UI/Packages/TuiEditor/TuiEditorScriptContributor.cs @@ -16,6 +16,7 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Packages.TuiEditor { public override void ConfigureBundle(BundleConfigurationContext context) { + context.Files.AddIfNotContains("/libs/tui-editor/tui-editor-jquery-patch.js"); context.Files.AddIfNotContains("/libs/to-mark/to-mark.min.js"); if (context.FileProvider.GetFileInfo("/libs/tui-code-snippet/tui-code-snippet.min.js").Exists) diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared/Toolbars/ToolbarItem.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared/Toolbars/ToolbarItem.cs index 9b6ef4becb..4676202c24 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared/Toolbars/ToolbarItem.cs +++ b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared/Toolbars/ToolbarItem.cs @@ -14,10 +14,14 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared.Toolbars public int Order { get; set; } - public ToolbarItem([NotNull] Type componentType, int order = 0) + [CanBeNull] + public string RequiredPermissionName { get; set; } + + public ToolbarItem([NotNull] Type componentType, int order = 0, string requiredPermissionName = null) { Order = order; ComponentType = Check.NotNull(componentType, nameof(componentType)); + RequiredPermissionName = requiredPermissionName; } } -} \ No newline at end of file +} diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared/Toolbars/ToolbarManager.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared/Toolbars/ToolbarManager.cs index f1ac30779a..2e97cebecb 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared/Toolbars/ToolbarManager.cs +++ b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared/Toolbars/ToolbarManager.cs @@ -1,8 +1,11 @@ using System; +using System.Collections.Generic; +using System.Linq; using System.Threading.Tasks; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Options; using Volo.Abp.AspNetCore.Mvc.UI.Theming; +using Volo.Abp.Authorization.Permissions; using Volo.Abp.DependencyInjection; namespace Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared.Toolbars @@ -14,7 +17,7 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared.Toolbars protected IServiceProvider ServiceProvider { get; } public ToolbarManager( - IOptions options, + IOptions options, IServiceProvider serviceProvider, IThemeManager themeManager) { @@ -35,9 +38,33 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared.Toolbars { await contributor.ConfigureToolbarAsync(context); } + + await CheckPermissionsAsync(scope.ServiceProvider, toolbar); } return toolbar; } + + protected virtual async Task CheckPermissionsAsync(IServiceProvider serviceProvider, Toolbar toolbar) + { + var requiredPermissionItems = toolbar.Items.Where(x => !x.RequiredPermissionName.IsNullOrWhiteSpace()).ToList(); + + if (requiredPermissionItems.Any()) + { + var permissionChecker = serviceProvider.GetRequiredService(); + var grantResult = await permissionChecker.IsGrantedAsync(requiredPermissionItems.Select(x => x.RequiredPermissionName).Distinct().ToArray()); + + var toBeDeleted = new HashSet(); + foreach (var item in requiredPermissionItems) + { + if (grantResult.Result[item.RequiredPermissionName!] != PermissionGrantResult.Granted) + { + toBeDeleted.Add(item); + } + } + + toolbar.Items.RemoveAll(toBeDeleted.Contains); + } + } } -} \ No newline at end of file +} diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ApiExploring/AbpRemoteServiceApiDescriptionProvider.cs b/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ApiExploring/AbpRemoteServiceApiDescriptionProvider.cs index ae09573d60..1a017e9925 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ApiExploring/AbpRemoteServiceApiDescriptionProvider.cs +++ b/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ApiExploring/AbpRemoteServiceApiDescriptionProvider.cs @@ -3,6 +3,7 @@ using System.Linq; using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc.Abstractions; using Microsoft.AspNetCore.Mvc.ApiExplorer; +using Microsoft.AspNetCore.Mvc.Controllers; using Microsoft.AspNetCore.Mvc.Formatters; using Microsoft.AspNetCore.Mvc.ModelBinding; using Microsoft.Extensions.Options; @@ -19,7 +20,7 @@ namespace Volo.Abp.AspNetCore.Mvc.ApiExploring public AbpRemoteServiceApiDescriptionProvider( IModelMetadataProvider modelMetadataProvider, - IOptions mvcOptionsAccessor, + IOptions mvcOptionsAccessor, IOptions optionsAccessor) { _modelMetadataProvider = modelMetadataProvider; @@ -41,7 +42,7 @@ namespace Volo.Abp.AspNetCore.Mvc.ApiExploring { foreach (var apiResponseType in GetApiResponseTypes()) { - foreach (var result in context.Results.Where(x => IsRemoteService(x.ActionDescriptor))) + foreach (var result in context.Results.Where(IsRemoteService)) { var actionProducesResponseTypeAttributes = ReflectionHelper.GetAttributesOfMemberOrDeclaringType( @@ -62,7 +63,7 @@ namespace Volo.Abp.AspNetCore.Mvc.ApiExploring foreach (var apiResponse in _options.SupportedResponseTypes) { apiResponse.ModelMetadata = _modelMetadataProvider.GetMetadataForType(apiResponse.Type); - + foreach (var responseTypeMetadataProvider in _mvcOptions.OutputFormatters.OfType()) { var formatterSupportedContentTypes = responseTypeMetadataProvider.GetSupportedContentTypes(null, apiResponse.Type); @@ -85,10 +86,29 @@ namespace Volo.Abp.AspNetCore.Mvc.ApiExploring return _options.SupportedResponseTypes; } - protected virtual bool IsRemoteService(ActionDescriptor actionDescriptor) + protected virtual bool IsRemoteService(ApiDescription actionDescriptor) { - var remoteServiceAttr = ReflectionHelper.GetSingleAttributeOfMemberOrDeclaringTypeOrDefault(actionDescriptor.GetMethodInfo()); - return remoteServiceAttr != null && remoteServiceAttr.IsEnabled; + if (actionDescriptor.ActionDescriptor is ControllerActionDescriptor controllerActionDescriptor) + { + var remoteServiceAttr = ReflectionHelper.GetSingleAttributeOfMemberOrDeclaringTypeOrDefault(controllerActionDescriptor.MethodInfo); + if (remoteServiceAttr != null && remoteServiceAttr.IsEnabled) + { + return true; + } + + remoteServiceAttr = ReflectionHelper.GetSingleAttributeOfMemberOrDeclaringTypeOrDefault(controllerActionDescriptor.ControllerTypeInfo); + if (remoteServiceAttr != null && remoteServiceAttr.IsEnabled) + { + return true; + } + + if (typeof(IRemoteService).IsAssignableFrom(controllerActionDescriptor.ControllerTypeInfo)) + { + return true; + } + } + + return false; } } -} \ No newline at end of file +} diff --git a/framework/src/Volo.Abp.Authorization/Microsoft/AspNetCore/Authorization/AbpAuthorizationServiceExtensions.cs b/framework/src/Volo.Abp.Authorization/Microsoft/AspNetCore/Authorization/AbpAuthorizationServiceExtensions.cs index bb820c3a83..133209f30a 100644 --- a/framework/src/Volo.Abp.Authorization/Microsoft/AspNetCore/Authorization/AbpAuthorizationServiceExtensions.cs +++ b/framework/src/Volo.Abp.Authorization/Microsoft/AspNetCore/Authorization/AbpAuthorizationServiceExtensions.cs @@ -65,6 +65,23 @@ namespace Microsoft.AspNetCore.Authorization { return (await authorizationService.AuthorizeAsync(policyName)).Succeeded; } + + public static async Task IsGrantedAnyAsync( + this IAuthorizationService authorizationService, + params string[] policyNames) + { + Check.NotNullOrEmpty(policyNames, nameof(policyNames)); + + foreach (var policyName in policyNames) + { + if ((await authorizationService.AuthorizeAsync(policyName)).Succeeded) + { + return true; + } + } + + return false; + } public static async Task IsGrantedAsync(this IAuthorizationService authorizationService, object resource, IAuthorizationRequirement requirement) { diff --git a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Commands/AddModuleCommand.cs b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Commands/AddModuleCommand.cs index 8129435266..a2c47af69b 100644 --- a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Commands/AddModuleCommand.cs +++ b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Commands/AddModuleCommand.cs @@ -59,7 +59,6 @@ namespace Volo.Abp.Cli.Commands await SolutionModuleAdder.AddAsync( solutionFile, commandLineArgs.Target, - commandLineArgs.Options.GetOrNull(Options.StartupProject.Short, Options.StartupProject.Long), version, skipDbMigrations, withSourceCode, @@ -167,12 +166,6 @@ namespace Volo.Abp.Cli.Commands public const string Skip = "skip-db-migrations"; } - public static class StartupProject - { - public const string Short = "sp"; - public const string Long = "startup-project"; - } - public static class SourceCode { public const string Long = "with-source-code"; diff --git a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Commands/CreateMigrationAndRunMigratorCommand.cs b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Commands/CreateMigrationAndRunMigratorCommand.cs index 68fae779ce..2a3c4652af 100644 --- a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Commands/CreateMigrationAndRunMigratorCommand.cs +++ b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Commands/CreateMigrationAndRunMigratorCommand.cs @@ -26,7 +26,9 @@ namespace Volo.Abp.Cli.Commands throw new CliUsageException("DbMigrations folder path is missing!"); } - var dbMigratorProjectPath = GetDbMigratorProjectPath(commandLineArgs.Target); + var dbMigrationsFolder = commandLineArgs.Target; + + var dbMigratorProjectPath = GetDbMigratorProjectPath(dbMigrationsFolder); if (dbMigratorProjectPath == null) { throw new Exception("DbMigrator is not found!"); @@ -37,13 +39,17 @@ namespace Volo.Abp.Cli.Commands InstallDotnetEfTool(); } - var addMigrationCmd = $"cd \"{commandLineArgs.Target}\" && " + - $"dotnet ef migrations add Initial -s \"{dbMigratorProjectPath}\""; + var tenantDbContextName = FindTenantDbContextName(dbMigrationsFolder); + var dbContextName = tenantDbContextName != null ? + FindDbContextName(dbMigrationsFolder) + : null; + + var migrationOutput = AddMigrationAndGetOutput(dbMigrationsFolder, dbContextName, "Migrations"); + var tenantMigrationOutput = tenantDbContextName != null ? + AddMigrationAndGetOutput(dbMigrationsFolder, tenantDbContextName, "TenantMigrations") + : null; - var output = CmdHelper.RunCmdAndGetOutput(addMigrationCmd); - if (output.Contains("Done.") && - output.Contains("To undo this action") && - output.Contains("ef migrations remove")) + if (CheckMigrationOutput(migrationOutput) && CheckMigrationOutput(tenantMigrationOutput)) { // Migration added successfully CmdHelper.RunCmd("cd \"" + Path.GetDirectoryName(dbMigratorProjectPath) + "\" && dotnet run"); @@ -51,22 +57,70 @@ namespace Volo.Abp.Cli.Commands } else { - var exceptionMsg = "Migrations failed! The following command didn't run successfully:" + + var exceptionMsg = "Migrations failed! A migration command didn't run successfully:" + Environment.NewLine + - addMigrationCmd + - Environment.NewLine + output; + Environment.NewLine + migrationOutput + + Environment.NewLine + + Environment.NewLine + tenantMigrationOutput; Logger.LogError(exceptionMsg); throw new Exception(exceptionMsg); } } + private string FindTenantDbContextName(string dbMigrationsFolder) + { + var tenantDbContext = Directory + .GetFiles(dbMigrationsFolder, "*TenantMigrationsDbContext.cs", SearchOption.AllDirectories) + .FirstOrDefault(); + + if (tenantDbContext == null) + { + return null; + } + + return Path.GetFileName(tenantDbContext).RemovePostFix(".cs"); + } + + private string FindDbContextName(string dbMigrationsFolder) + { + var dbContext = Directory + .GetFiles(dbMigrationsFolder, "*MigrationsDbContext.cs", SearchOption.AllDirectories) + .FirstOrDefault(fp => !fp.EndsWith("TenantMigrationsDbContext.cs")); + + if (dbContext == null) + { + return null; + } + + return Path.GetFileName(dbContext).RemovePostFix(".cs"); + } + + private static string AddMigrationAndGetOutput(string dbMigrationsFolder, string dbContext, string outputDirectory) + { + var dbContextOption = string.IsNullOrWhiteSpace(dbContext) + ? string.Empty + : $"--context {dbContext}"; + + var addMigrationCmd = $"cd \"{dbMigrationsFolder}\" && " + + $"dotnet ef migrations add Initial --output-dir {outputDirectory} {dbContextOption}"; + + return CmdHelper.RunCmdAndGetOutput(addMigrationCmd); + } + private static bool IsDotNetEfToolInstalled() { var output = CmdHelper.RunCmdAndGetOutput("dotnet tool list -g"); return output.Contains("dotnet-ef"); } + private static bool CheckMigrationOutput(string output) + { + return output == null || (output.Contains("Done.") && + output.Contains("To undo this action") && + output.Contains("ef migrations remove")); + } + private void InstallDotnetEfTool() { Logger.LogInformation("Installing dotnet-ef tool..."); @@ -95,4 +149,4 @@ namespace Volo.Abp.Cli.Commands return string.Empty; } } -} \ No newline at end of file +} diff --git a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectBuilding/Building/ModuleProjectBuildPipelineBuilder.cs b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectBuilding/Building/ModuleProjectBuildPipelineBuilder.cs index 9b66f17834..d4a74d9364 100644 --- a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectBuilding/Building/ModuleProjectBuildPipelineBuilder.cs +++ b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectBuilding/Building/ModuleProjectBuildPipelineBuilder.cs @@ -1,4 +1,5 @@ using Volo.Abp.Cli.ProjectBuilding.Building.Steps; +using Volo.Abp.Cli.ProjectBuilding.Templates; namespace Volo.Abp.Cli.ProjectBuilding.Building { @@ -12,6 +13,7 @@ namespace Volo.Abp.Cli.ProjectBuilding.Building pipeline.Steps.Add(new ProjectReferenceReplaceStep()); pipeline.Steps.Add(new ReplaceCommonPropsStep()); pipeline.Steps.Add(new ReplaceConfigureAwaitPropsStep()); + pipeline.Steps.Add(new UpdateNuGetConfigStep("/NuGet.Config")); pipeline.Steps.Add(new CreateProjectResultZipStep()); return pipeline; diff --git a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectBuilding/Building/Steps/DatabaseManagementSystemChangeStep.cs b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectBuilding/Building/Steps/DatabaseManagementSystemChangeStep.cs index 4286710899..605cc842f5 100644 --- a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectBuilding/Building/Steps/DatabaseManagementSystemChangeStep.cs +++ b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectBuilding/Building/Steps/DatabaseManagementSystemChangeStep.cs @@ -54,7 +54,8 @@ namespace Volo.Abp.Cli.ProjectBuilding.Building.Steps private void AdjustOracleDbContextOptionsBuilder(ProjectBuildContext context) { - var dbContextFactoryFile = context.Files.First(f => f.Name.EndsWith("MigrationsDbContextFactory.cs", StringComparison.OrdinalIgnoreCase)); + var dbContextFactoryFile = context.Files.FirstOrDefault(f => f.Name.EndsWith("MigrationsDbContextFactoryBase.cs", StringComparison.OrdinalIgnoreCase)) + ?? context.Files.First(f => f.Name.EndsWith("MigrationsDbContextFactory.cs", StringComparison.OrdinalIgnoreCase)); dbContextFactoryFile.ReplaceText("new DbContextOptionsBuilder", $"(DbContextOptionsBuilder<{context.BuildArgs.SolutionName.ProjectName}MigrationsDbContext>) new DbContextOptionsBuilder"); @@ -62,7 +63,8 @@ namespace Volo.Abp.Cli.ProjectBuilding.Building.Steps private void AddMySqlServerVersion(ProjectBuildContext context) { - var dbContextFactoryFile = context.Files.First(f => f.Name.EndsWith("MigrationsDbContextFactory.cs", StringComparison.OrdinalIgnoreCase)); + var dbContextFactoryFile = context.Files.FirstOrDefault(f => f.Name.EndsWith("MigrationsDbContextFactoryBase.cs", StringComparison.OrdinalIgnoreCase)) + ?? context.Files.First(f => f.Name.EndsWith("MigrationsDbContextFactory.cs", StringComparison.OrdinalIgnoreCase)); dbContextFactoryFile.ReplaceText("configuration.GetConnectionString(\"Default\")", "configuration.GetConnectionString(\"Default\"), MySqlServerVersion.LatestSupportedServerVersion"); @@ -90,7 +92,8 @@ namespace Volo.Abp.Cli.ProjectBuilding.Building.Steps var efCoreModuleClass = context.Files.First(f => f.Name.EndsWith("EntityFrameworkCoreModule.cs", StringComparison.OrdinalIgnoreCase)); efCoreModuleClass.ReplaceText(oldUseMethod, newUseMethodForEfModule); - var dbContextFactoryFile = context.Files.First(f => f.Name.EndsWith("MigrationsDbContextFactory.cs", StringComparison.OrdinalIgnoreCase)); + var dbContextFactoryFile = context.Files.FirstOrDefault(f => f.Name.EndsWith("MigrationsDbContextFactoryBase.cs", StringComparison.OrdinalIgnoreCase)) + ?? context.Files.First(f => f.Name.EndsWith("MigrationsDbContextFactory.cs", StringComparison.OrdinalIgnoreCase)); dbContextFactoryFile.ReplaceText(oldUseMethod, newUseMethodForDbContext); } } diff --git a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectBuilding/Building/Steps/MicroserviceServiceRandomPortStep.cs b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectBuilding/Building/Steps/MicroserviceServiceRandomPortStep.cs new file mode 100644 index 0000000000..88a19b43af --- /dev/null +++ b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectBuilding/Building/Steps/MicroserviceServiceRandomPortStep.cs @@ -0,0 +1,78 @@ +using System; +using System.IO; +using System.Linq; +using Volo.Abp.Cli.Commands; + +namespace Volo.Abp.Cli.ProjectBuilding.Building.Steps +{ + public class MicroserviceServiceRandomPortStep : ProjectBuildPipelineStep + { + private readonly string _defaultPort = string.Empty; + private string _tyeFileContent = null; + + public MicroserviceServiceRandomPortStep(string defaultPort) + { + _defaultPort = defaultPort; + } + + public override void Execute(ProjectBuildContext context) + { + var newPort = GetNewRandomPort(context); + + var targetFiles = context.Files.Where(f=> f.Name.EndsWith("launchSettings.json") || f.Name.EndsWith("appsettings.json")).ToList(); + + foreach (var file in targetFiles) + { + file.SetContent(file.Content.Replace(_defaultPort, newPort)); + } + } + + private string GetNewRandomPort(ProjectBuildContext context) + { + string newPort; + var rnd = new Random(); + var tryCount = 0; + + do + { + newPort = rnd.Next(44350, 45350).ToString(); + + if (tryCount++ > 2000) + { + break; + } + + } while (PortExistsForAnotherService(context, newPort)); + + return newPort; + } + + private bool PortExistsForAnotherService(ProjectBuildContext context, string newPort) + { + return ReadTyeFileContent(context).SplitToLines().Any(l => l.Contains("port") && l.Contains(newPort)); + } + + private string ReadTyeFileContent(ProjectBuildContext context) + { + if (_tyeFileContent != null) + { + return _tyeFileContent; + } + + var solutionFolderPath = context.BuildArgs.ExtraProperties[NewCommand.Options.OutputFolder.Short] ?? + context.BuildArgs.ExtraProperties[NewCommand.Options.OutputFolder.Long] ?? + Directory.GetCurrentDirectory(); + + var tyeFilePath = Path.Combine(solutionFolderPath, "tye.yaml"); + + if (!File.Exists(tyeFilePath)) + { + return String.Empty; + } + + _tyeFileContent = File.ReadAllText(tyeFilePath); + + return _tyeFileContent; + } + } +} diff --git a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectBuilding/Building/Steps/RemoveCmsKitStep.cs b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectBuilding/Building/Steps/RemoveCmsKitStep.cs index 4f63d377ea..a0778d5a4d 100644 --- a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectBuilding/Building/Steps/RemoveCmsKitStep.cs +++ b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectBuilding/Building/Steps/RemoveCmsKitStep.cs @@ -9,11 +9,9 @@ namespace Volo.Abp.Cli.ProjectBuilding.Building.Steps { var commonFiles = context.Files.Where(f => f.Name.EndsWith(".csproj") || - f.Name.EndsWith("Module.cs") || - f.Name.EndsWith("MyProjectNameMigrationsDbContext.cs") || - f.Name.EndsWith("MyProjectNameGlobalFeatureConfigurator.cs") || - (f.Name.EndsWith(".cshtml") && f.Name.Contains("MyCompanyName.MyProjectName.Web.Public")) - ); + f.Name.EndsWith(".cs") || + f.Name.EndsWith(".json") || + f.Name.EndsWith(".cshtml")); foreach (var file in commonFiles) { diff --git a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectBuilding/Building/Steps/RemoveEfCoreDependencyFromPublicStep.cs b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectBuilding/Building/Steps/RemoveEfCoreDependencyFromPublicStep.cs index f9e906c902..1f7b8f4e6f 100644 --- a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectBuilding/Building/Steps/RemoveEfCoreDependencyFromPublicStep.cs +++ b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectBuilding/Building/Steps/RemoveEfCoreDependencyFromPublicStep.cs @@ -7,8 +7,13 @@ namespace Volo.Abp.Cli.ProjectBuilding.Building.Steps { public override void Execute(ProjectBuildContext context) { - context.Files.FirstOrDefault(f => f.Name.EndsWith("MyCompanyName.MyProjectName.Web.Public.csproj"))?.RemoveTemplateCodeIfNot("EFCORE"); - context.Files.FirstOrDefault(f => f.Name.EndsWith("MyProjectNameWebPublicModule.cs"))?.RemoveTemplateCodeIfNot("EFCORE"); + foreach (var file in context.Files) + { + if (file.Name.EndsWith(".cs") || file.Name.EndsWith(".csproj") || file.Name.EndsWith(".json")) + { + file.RemoveTemplateCodeIfNot("EFCORE"); + } + } } } } diff --git a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectBuilding/Building/Steps/RemoveGlobalFeaturesPackageStep.cs b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectBuilding/Building/Steps/RemoveGlobalFeaturesPackageStep.cs index 06fd565353..15a84576c6 100644 --- a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectBuilding/Building/Steps/RemoveGlobalFeaturesPackageStep.cs +++ b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectBuilding/Building/Steps/RemoveGlobalFeaturesPackageStep.cs @@ -7,8 +7,15 @@ namespace Volo.Abp.Cli.ProjectBuilding.Building.Steps { public override void Execute(ProjectBuildContext context) { - context.Files.FirstOrDefault(f => f.Name.EndsWith("MyCompanyName.MyProjectName.Domain.Shared.csproj"))?.RemoveTemplateCodeIf("CMS-KIT"); - context.Files.FirstOrDefault(f => f.Name.EndsWith("MyProjectNameDomainSharedModule.cs"))?.RemoveTemplateCodeIf("CMS-KIT"); + var commonFiles = context.Files.Where(f => + f.Name.EndsWith(".csproj") || + f.Name.EndsWith(".cs") || + f.Name.EndsWith(".cshtml")); + + foreach (var file in commonFiles) + { + file.RemoveTemplateCodeIf("CMS-KIT"); + } } } } diff --git a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectBuilding/Building/Steps/RemoveProjectFromTyeStep.cs b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectBuilding/Building/Steps/RemoveProjectFromTyeStep.cs new file mode 100644 index 0000000000..1c51e22bc9 --- /dev/null +++ b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectBuilding/Building/Steps/RemoveProjectFromTyeStep.cs @@ -0,0 +1,54 @@ +using System; +using System.Collections.Generic; +using System.Linq; + +namespace Volo.Abp.Cli.ProjectBuilding.Building.Steps +{ + public class RemoveProjectFromTyeStep : ProjectBuildPipelineStep + { + private readonly string _name; + + public RemoveProjectFromTyeStep(string name) + { + _name = name; + } + + public override void Execute(ProjectBuildContext context) + { + var tyeFile = context.Files.FirstOrDefault(f => f.Name == "/tye.yaml"); + + if (tyeFile == null) + { + return; + } + + var lines = tyeFile.GetLines(); + var newLines = new List(); + + var nameLine = $"- name:"; + var isOneOfTargetLines = false; + + foreach (var line in lines) + { + if (line.Equals($"{nameLine} {_name}")) + { + isOneOfTargetLines = true; + continue; + } + + if (line.StartsWith(nameLine)) + { + isOneOfTargetLines = false; + } + + if (!isOneOfTargetLines) + { + newLines.Add(line); + } + } + + tyeFile.SetContent(String.Join(Environment.NewLine, newLines)); + } + + } +} diff --git a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectBuilding/Building/Steps/RemovePublicRedisStep.cs b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectBuilding/Building/Steps/RemovePublicRedisStep.cs index 1299f5b15d..eced4fd3e5 100644 --- a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectBuilding/Building/Steps/RemovePublicRedisStep.cs +++ b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectBuilding/Building/Steps/RemovePublicRedisStep.cs @@ -8,16 +8,12 @@ namespace Volo.Abp.Cli.ProjectBuilding.Building.Steps { public override void Execute(ProjectBuildContext context) { - context.Files.FirstOrDefault(f => f.Name.EndsWith("MyCompanyName.MyProjectName.Web.csproj"))?.RemoveTemplateCodeIfNot("PUBLIC-REDIS"); - context.Files.FirstOrDefault(f => f.Name.EndsWith("MyProjectNameWebModule.cs"))?.RemoveTemplateCodeIfNot("PUBLIC-REDIS"); - context.Files.FirstOrDefault(f => f.Name.EndsWith("MyCompanyName.MyProjectName.HttpApi.HostWithIds.csproj"))?.RemoveTemplateCodeIfNot("PUBLIC-REDIS"); - context.Files.FirstOrDefault(f => f.Name.EndsWith("MyCompanyName.MyProjectName.HttpApi.Host.csproj"))?.RemoveTemplateCodeIfNot("PUBLIC-REDIS"); - context.Files.FirstOrDefault(f => f.Name.EndsWith("MyProjectNameHttpApiHostModule.cs"))?.RemoveTemplateCodeIfNot("PUBLIC-REDIS"); - - var appSettingsFiles = context.Files.Where(f => f.Name.EndsWith("appSettings.json", StringComparison.InvariantCultureIgnoreCase)).ToList(); - foreach (var appSettings in appSettingsFiles) + foreach (var file in context.Files) { - appSettings.RemoveTemplateCodeIfNot("PUBLIC-REDIS"); + if (file.Name.EndsWith(".cs") || file.Name.EndsWith(".csproj") || file.Name.EndsWith(".json")) + { + file.RemoveTemplateCodeIfNot("PUBLIC-REDIS"); + } } } } diff --git a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectBuilding/Building/Steps/SolutionRenameStep.cs b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectBuilding/Building/Steps/SolutionRenameStep.cs index 27199f6ce4..1ea30fe783 100644 --- a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectBuilding/Building/Steps/SolutionRenameStep.cs +++ b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectBuilding/Building/Steps/SolutionRenameStep.cs @@ -18,6 +18,14 @@ namespace Volo.Abp.Cli.ProjectBuilding.Building.Steps context.BuildArgs.SolutionName.CompanyName, context.BuildArgs.SolutionName.ProjectName ).Run(); + + new SolutionRenamer( + context.Files, + null, + "MyProjectName", + null, + SolutionName.Parse(context.BuildArgs.SolutionName.CompanyName).ProjectName + ).Run(); } else { diff --git a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectBuilding/Files/FileEntryExtensions.cs b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectBuilding/Files/FileEntryExtensions.cs index 91180206bf..34200d41ac 100644 --- a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectBuilding/Files/FileEntryExtensions.cs +++ b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectBuilding/Files/FileEntryExtensions.cs @@ -28,6 +28,11 @@ namespace Volo.Abp.Cli.ProjectBuilding.Files public static void RemoveTemplateCodeMarkers(this FileEntry file) { + if (!file.Content.Contains("")) + { + return; + } + file.NormalizeLineEndings(); var lines = file.GetLines(); @@ -59,6 +64,11 @@ namespace Volo.Abp.Cli.ProjectBuilding.Files private static void RemoveMarkedTemplateCode(this FileEntry file, string beginMark) { + if (!file.Content.Contains("")) + { + return; + } + file.NormalizeLineEndings(); var lines = file.GetLines(); diff --git a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectBuilding/Templates/App/AppTemplateBase.cs b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectBuilding/Templates/App/AppTemplateBase.cs index 2a596b73a7..7541894181 100644 --- a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectBuilding/Templates/App/AppTemplateBase.cs +++ b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectBuilding/Templates/App/AppTemplateBase.cs @@ -24,6 +24,7 @@ namespace Volo.Abp.Cli.ProjectBuilding.Templates.App { var steps = new List(); + ConfigureTenantSchema(context, steps); SwitchDatabaseProvider(context, steps); DeleteUnrelatedProjects(context, steps); RemoveMigrations(context, steps); @@ -38,6 +39,19 @@ namespace Volo.Abp.Cli.ProjectBuilding.Templates.App return steps; } + private static void ConfigureTenantSchema(ProjectBuildContext context, List steps) + { + if (context.BuildArgs.ExtraProperties.ContainsKey("separate-tenant-schema")) + { + steps.Add(new RemoveProjectFromSolutionStep("MyCompanyName.MyProjectName.EntityFrameworkCore.DbMigrations")); + steps.Add(new AppTemplateProjectRenameStep("MyCompanyName.MyProjectName.EntityFrameworkCore.SeparateDbMigrations", "MyCompanyName.MyProjectName.EntityFrameworkCore.DbMigrations")); + } + else + { + steps.Add(new RemoveProjectFromSolutionStep("MyCompanyName.MyProjectName.EntityFrameworkCore.SeparateDbMigrations")); + } + } + private static void SwitchDatabaseProvider(ProjectBuildContext context, List steps) { if (context.BuildArgs.DatabaseProvider == DatabaseProvider.MongoDb) @@ -284,6 +298,7 @@ namespace Volo.Abp.Cli.ProjectBuilding.Templates.App SemanticVersion.Parse(context.BuildArgs.Version) > new SemanticVersion(4,1,99)) { steps.Add(new RemoveFolderStep("/aspnet-core/src/MyCompanyName.MyProjectName.EntityFrameworkCore.DbMigrations/Migrations")); + steps.Add(new RemoveFolderStep("/aspnet-core/src/MyCompanyName.MyProjectName.EntityFrameworkCore.DbMigrations/TenantMigrations")); } } diff --git a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectBuilding/Templates/Microservice/MicroserviceServiceTemplateBase.cs b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectBuilding/Templates/Microservice/MicroserviceServiceTemplateBase.cs index de589336b0..54ec4894b9 100644 --- a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectBuilding/Templates/Microservice/MicroserviceServiceTemplateBase.cs +++ b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectBuilding/Templates/Microservice/MicroserviceServiceTemplateBase.cs @@ -31,6 +31,7 @@ namespace Volo.Abp.Cli.ProjectBuilding.Templates.Microservice var steps = new List(); DeleteUnrelatedUiProject(context, steps); + SetRandomPortForHostProject(context, steps); RandomizeStringEncryption(context, steps); return steps; @@ -54,6 +55,11 @@ namespace Volo.Abp.Cli.ProjectBuilding.Templates.Microservice } } + private static void SetRandomPortForHostProject(ProjectBuildContext context, List steps) + { + steps.Add(new MicroserviceServiceRandomPortStep("44371")); + } + private static void RandomizeStringEncryption(ProjectBuildContext context, List steps) { steps.Add(new RandomizeStringEncryptionStep()); diff --git a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectBuilding/Templates/Microservice/MicroserviceTemplateBase.cs b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectBuilding/Templates/Microservice/MicroserviceTemplateBase.cs index 0a56f5272a..1efbe09ff1 100644 --- a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectBuilding/Templates/Microservice/MicroserviceTemplateBase.cs +++ b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectBuilding/Templates/Microservice/MicroserviceTemplateBase.cs @@ -36,9 +36,13 @@ namespace Volo.Abp.Cli.ProjectBuilding.Templates.Microservice steps.Add(new RemoveProjectFromSolutionStep("MyCompanyName.MyProjectName.Web",null, "/applications/web/src/MyCompanyName.MyProjectName.Web")); steps.Add(new RemoveFolderStep("/applications/web")); + steps.Add(new RemoveProjectFromTyeStep("web")); + steps.Add(new RemoveProjectFromSolutionStep("MyCompanyName.MyProjectName.Blazor",null, "/applications/blazor/src/MyCompanyName.MyProjectName.Blazor")); steps.Add(new RemoveFolderStep("/applications/blazor")); + steps.Add(new RemoveProjectFromTyeStep("blazor")); + steps.Add(new RemoveFolderStep("/angular")); break; @@ -46,9 +50,12 @@ namespace Volo.Abp.Cli.ProjectBuilding.Templates.Microservice steps.Add(new RemoveProjectFromSolutionStep("MyCompanyName.MyProjectName.Web",null, "/applications/web/src/MyCompanyName.MyProjectName.Web")); steps.Add(new RemoveFolderStep("/applications/web")); + steps.Add(new RemoveProjectFromTyeStep("web")); + steps.Add(new RemoveProjectFromSolutionStep("MyCompanyName.MyProjectName.Blazor",null, "/applications/blazor/src/MyCompanyName.MyProjectName.Blazor")); steps.Add(new RemoveFolderStep("/applications/blazor")); + steps.Add(new RemoveProjectFromTyeStep("blazor")); break; case UiFramework.Blazor: @@ -56,6 +63,7 @@ namespace Volo.Abp.Cli.ProjectBuilding.Templates.Microservice "/applications/web/src/MyCompanyName.MyProjectName.Web")); steps.Add(new RemoveFolderStep("/applications/web")); steps.Add(new RemoveFolderStep("/angular")); + steps.Add(new RemoveProjectFromTyeStep("web")); break; case UiFramework.Mvc: @@ -63,6 +71,8 @@ namespace Volo.Abp.Cli.ProjectBuilding.Templates.Microservice steps.Add(new RemoveProjectFromSolutionStep("MyCompanyName.MyProjectName.Blazor",null, "/applications/blazor/src/MyCompanyName.MyProjectName.Blazor")); steps.Add(new RemoveFolderStep("/applications/blazor")); + steps.Add(new RemoveProjectFromTyeStep("blazor")); + steps.Add(new RemoveFolderStep("/angular")); break; } diff --git a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectModification/EfCoreMigrationManager.cs b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectModification/EfCoreMigrationManager.cs index b15ffaa274..8143acf7b8 100644 --- a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectModification/EfCoreMigrationManager.cs +++ b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectModification/EfCoreMigrationManager.cs @@ -17,14 +17,38 @@ namespace Volo.Abp.Cli.ProjectModification Logger = NullLogger.Instance; } - public void AddMigration(string dbMigrationsCsprojFile, string module, string startupProject) + public void AddMigration(string dbMigrationsCsprojFile, string module) { + var dbMigrationsProjectFolder = Path.GetDirectoryName(dbMigrationsCsprojFile); var moduleName = ParseModuleName(module); var migrationName = "Added_" + moduleName + "_Module" + GetUniquePostFix(); - CmdHelper.RunCmd("cd \"" + Path.GetDirectoryName(dbMigrationsCsprojFile) + - "\" && dotnet ef migrations add " + migrationName + - GetStartupProjectOption(startupProject)); + var tenantDbContextName = FindTenantDbContextName(dbMigrationsProjectFolder); + var dbContextName = tenantDbContextName != null ? + FindDbContextName(dbMigrationsProjectFolder) + : null; + + if (!string.IsNullOrEmpty(tenantDbContextName)) + { + RunAddMigrationCommand(dbMigrationsProjectFolder, migrationName, tenantDbContextName, "TenantMigrations"); + } + + RunAddMigrationCommand(dbMigrationsProjectFolder, migrationName, dbContextName, "Migrations"); + } + + protected virtual void RunAddMigrationCommand( + string dbMigrationsProjectFolder, + string migrationName, + string dbContext, + string outputDirectory) + { + var dbContextOption = string.IsNullOrWhiteSpace(dbContext) + ? string.Empty + : $"--context {dbContext}"; + + CmdHelper.RunCmd($"cd \"{dbMigrationsProjectFolder}\" && dotnet ef migrations add {migrationName}" + + $" --output-dir {outputDirectory}" + + $" {dbContextOption}"); } protected virtual string ParseModuleName(string fullModuleName) @@ -43,9 +67,32 @@ namespace Volo.Abp.Cli.ProjectModification return "_" + new Random().Next(1, 99999); } - protected virtual string GetStartupProjectOption(string startupProject) + protected virtual string FindDbContextName(string dbMigrationsFolder) { - return startupProject.IsNullOrWhiteSpace() ? "" : $" -s {startupProject}"; + var dbContext = Directory + .GetFiles(dbMigrationsFolder, "*MigrationsDbContext.cs", SearchOption.AllDirectories) + .FirstOrDefault(fp => !fp.EndsWith("TenantMigrationsDbContext.cs")); + + if (dbContext == null) + { + return null; + } + + return Path.GetFileName(dbContext).RemovePostFix(".cs"); + } + + protected virtual string FindTenantDbContextName(string dbMigrationsFolder) + { + var tenantDbContext = Directory + .GetFiles(dbMigrationsFolder, "*TenantMigrationsDbContext.cs", SearchOption.AllDirectories) + .FirstOrDefault(); + + if (tenantDbContext == null) + { + return null; + } + + return Path.GetFileName(tenantDbContext).RemovePostFix(".cs"); } } } 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 c84713ffcb..d550912691 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 @@ -78,7 +78,6 @@ namespace Volo.Abp.Cli.ProjectModification public virtual async Task AddAsync( [NotNull] string solutionFile, [NotNull] string moduleName, - string startupProject, string version, bool skipDbMigrations = false, bool withSourceCode = false, @@ -128,7 +127,7 @@ namespace Volo.Abp.Cli.ProjectModification await RunBundleForBlazorAsync(projectFiles, module); - ModifyDbContext(projectFiles, module, startupProject, skipDbMigrations); + ModifyDbContext(projectFiles, module, skipDbMigrations); } private async Task RunBundleForBlazorAsync(string[] projectFiles, ModuleWithMastersInfo module) @@ -450,8 +449,7 @@ namespace Volo.Abp.Cli.ProjectModification } } - protected void ModifyDbContext(string[] projectFiles, ModuleInfo module, string startupProject, - bool skipDbMigrations = false) + protected void ModifyDbContext(string[] projectFiles, ModuleInfo module, bool skipDbMigrations = false) { if (string.IsNullOrWhiteSpace(module.EfCoreConfigureMethodName)) { @@ -463,11 +461,6 @@ namespace Volo.Abp.Cli.ProjectModification return; } - if (string.IsNullOrWhiteSpace(startupProject)) - { - startupProject = projectFiles.FirstOrDefault(p => p.EndsWith(".DbMigrator.csproj")); - } - var dbMigrationsProject = projectFiles.FirstOrDefault(p => p.EndsWith(".DbMigrations.csproj")); if (dbMigrationsProject == null) @@ -498,7 +491,7 @@ namespace Volo.Abp.Cli.ProjectModification { if (addedNewBuilder) { - EfCoreMigrationManager.AddMigration(dbMigrationsProject, module.Name, startupProject); + EfCoreMigrationManager.AddMigration(dbMigrationsProject, module.Name); } RunMigrator(projectFiles); diff --git a/framework/src/Volo.Abp.Core/Microsoft/Extensions/DependencyInjection/ServiceCollectionLoggingExtensions.cs b/framework/src/Volo.Abp.Core/Microsoft/Extensions/DependencyInjection/ServiceCollectionLoggingExtensions.cs new file mode 100644 index 0000000000..48921cb99b --- /dev/null +++ b/framework/src/Volo.Abp.Core/Microsoft/Extensions/DependencyInjection/ServiceCollectionLoggingExtensions.cs @@ -0,0 +1,12 @@ +using Volo.Abp.Logging; + +namespace Microsoft.Extensions.DependencyInjection +{ + public static class ServiceCollectionLoggingExtensions + { + public static IInitLogger GetInitLogger(this IServiceCollection services) + { + return services.GetSingletonInstance(); + } + } +} \ No newline at end of file diff --git a/framework/src/Volo.Abp.Core/System/AbpStringExtensions.cs b/framework/src/Volo.Abp.Core/System/AbpStringExtensions.cs index f272484611..5fe47112ba 100644 --- a/framework/src/Volo.Abp.Core/System/AbpStringExtensions.cs +++ b/framework/src/Volo.Abp.Core/System/AbpStringExtensions.cs @@ -260,8 +260,9 @@ namespace System /// /// String to convert /// set true to use current culture. Otherwise, invariant culture will be used. + /// set true to if you want to convert 'XYZ' to 'xyz'. /// camelCase of the string - public static string ToCamelCase(this string str, bool useCurrentCulture = false) + public static string ToCamelCase(this string str, bool useCurrentCulture = false, bool handleAbbreviations = false) { if (string.IsNullOrWhiteSpace(str)) { @@ -273,6 +274,11 @@ namespace System return useCurrentCulture ? str.ToLower() : str.ToLowerInvariant(); } + if (handleAbbreviations && IsAllUpperCase(str)) + { + return useCurrentCulture ? str.ToLower() : str.ToLowerInvariant(); + } + return (useCurrentCulture ? char.ToLower(str[0]) : char.ToLowerInvariant(str[0])) + str.Substring(1); } @@ -545,5 +551,18 @@ namespace System return encoding.GetBytes(str); } + + private static bool IsAllUpperCase(string input) + { + for (int i = 0; i < input.Length; i++) + { + if (Char.IsLetter(input[i]) && !Char.IsUpper(input[i])) + { + return false; + } + } + + return true; + } } } diff --git a/framework/src/Volo.Abp.Core/Volo/Abp/AbpApplicationBase.cs b/framework/src/Volo.Abp.Core/Volo/Abp/AbpApplicationBase.cs index 1e5b251ca0..256a1dd05d 100644 --- a/framework/src/Volo.Abp.Core/Volo/Abp/AbpApplicationBase.cs +++ b/framework/src/Volo.Abp.Core/Volo/Abp/AbpApplicationBase.cs @@ -3,8 +3,10 @@ using System.Collections.Generic; using System.Linq; using JetBrains.Annotations; using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Logging; using Volo.Abp.DependencyInjection; using Volo.Abp.Internal; +using Volo.Abp.Logging; using Volo.Abp.Modularity; namespace Volo.Abp @@ -71,11 +73,30 @@ namespace Volo.Abp { using (var scope = ServiceProvider.CreateScope()) { + WriteInitLogs(scope.ServiceProvider); scope.ServiceProvider .GetRequiredService() .InitializeModules(new ApplicationInitializationContext(scope.ServiceProvider)); } } + + protected virtual void WriteInitLogs(IServiceProvider serviceProvider) + { + var logger = serviceProvider.GetService>(); + if (logger == null) + { + return; + } + + var initLogger = serviceProvider.GetRequiredService(); + + foreach (var entry in initLogger.Entries) + { + logger.LogWithLevel(entry.Level, entry.Message, entry.Exception); + } + + initLogger.Entries.Clear(); + } protected virtual IReadOnlyList LoadModules(IServiceCollection services, AbpApplicationCreationOptions options) { diff --git a/framework/src/Volo.Abp.Core/Volo/Abp/Internal/InternalServiceCollectionExtensions.cs b/framework/src/Volo.Abp.Core/Volo/Abp/Internal/InternalServiceCollectionExtensions.cs index 83a7ec163e..c116a20080 100644 --- a/framework/src/Volo.Abp.Core/Volo/Abp/Internal/InternalServiceCollectionExtensions.cs +++ b/framework/src/Volo.Abp.Core/Volo/Abp/Internal/InternalServiceCollectionExtensions.cs @@ -1,6 +1,7 @@ using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection.Extensions; +using Volo.Abp.Logging; using Volo.Abp.Modularity; using Volo.Abp.Reflection; @@ -35,6 +36,7 @@ namespace Volo.Abp.Internal services.TryAddSingleton(moduleLoader); services.TryAddSingleton(assemblyFinder); services.TryAddSingleton(typeFinder); + services.TryAddSingleton(new DefaultInitLogger()); services.AddAssemblyOf(); diff --git a/framework/src/Volo.Abp.Core/Volo/Abp/Logging/AbpInitLogEntry.cs b/framework/src/Volo.Abp.Core/Volo/Abp/Logging/AbpInitLogEntry.cs new file mode 100644 index 0000000000..17a346fa1c --- /dev/null +++ b/framework/src/Volo.Abp.Core/Volo/Abp/Logging/AbpInitLogEntry.cs @@ -0,0 +1,26 @@ +using System; +using JetBrains.Annotations; +using Microsoft.Extensions.Logging; + +namespace Volo.Abp.Logging +{ + public class AbpInitLogEntry + { + public LogLevel Level { get; } + + public string Message { get; } + + [CanBeNull] + public Exception Exception { get; } + + public AbpInitLogEntry( + LogLevel level, + string message, + Exception exception) + { + Level = level; + Message = message; + Exception = exception; + } + } +} \ No newline at end of file diff --git a/framework/src/Volo.Abp.Core/Volo/Abp/Logging/DefaultInitLogger.cs b/framework/src/Volo.Abp.Core/Volo/Abp/Logging/DefaultInitLogger.cs new file mode 100644 index 0000000000..e1f7344f39 --- /dev/null +++ b/framework/src/Volo.Abp.Core/Volo/Abp/Logging/DefaultInitLogger.cs @@ -0,0 +1,24 @@ +using System; +using System.Collections.Generic; +using Microsoft.Extensions.Logging; + +namespace Volo.Abp.Logging +{ + public class DefaultInitLogger : IInitLogger + { + public List Entries { get; } + + public DefaultInitLogger() + { + Entries = new List(); + } + + public void Log( + LogLevel logLevel, + string message, + Exception exception = null) + { + Entries.Add(new AbpInitLogEntry(logLevel, message, exception)); + } + } +} \ No newline at end of file diff --git a/framework/src/Volo.Abp.Core/Volo/Abp/Logging/IInitLogger.cs b/framework/src/Volo.Abp.Core/Volo/Abp/Logging/IInitLogger.cs new file mode 100644 index 0000000000..5c549682e9 --- /dev/null +++ b/framework/src/Volo.Abp.Core/Volo/Abp/Logging/IInitLogger.cs @@ -0,0 +1,16 @@ +using System; +using System.Collections.Generic; +using Microsoft.Extensions.Logging; + +namespace Volo.Abp.Logging +{ + public interface IInitLogger + { + public List Entries { get; } + + void Log( + LogLevel logLevel, + string message, + Exception exception = null); + } +} \ No newline at end of file diff --git a/framework/src/Volo.Abp.Core/Volo/Abp/Modularity/AbpModuleHelper.cs b/framework/src/Volo.Abp.Core/Volo/Abp/Modularity/AbpModuleHelper.cs index d58483811b..9331014623 100644 --- a/framework/src/Volo.Abp.Core/Volo/Abp/Modularity/AbpModuleHelper.cs +++ b/framework/src/Volo.Abp.Core/Volo/Abp/Modularity/AbpModuleHelper.cs @@ -2,15 +2,18 @@ using System.Collections.Generic; using System.Linq; using System.Reflection; +using Microsoft.Extensions.Logging; +using Volo.Abp.Logging; namespace Volo.Abp.Modularity { internal static class AbpModuleHelper { - public static List FindAllModuleTypes(Type startupModuleType) + public static List FindAllModuleTypes(Type startupModuleType, IInitLogger logger) { var moduleTypes = new List(); - AddModuleAndDependenciesResursively(moduleTypes, startupModuleType); + logger.Log(LogLevel.Information, "Loaded ABP modules:"); + AddModuleAndDependenciesResursively(moduleTypes, startupModuleType, logger); return moduleTypes; } @@ -35,7 +38,11 @@ namespace Volo.Abp.Modularity return dependencies; } - private static void AddModuleAndDependenciesResursively(List moduleTypes, Type moduleType) + private static void AddModuleAndDependenciesResursively( + List moduleTypes, + Type moduleType, + IInitLogger logger, + int depth = 0) { AbpModule.CheckAbpModuleType(moduleType); @@ -45,10 +52,11 @@ namespace Volo.Abp.Modularity } moduleTypes.Add(moduleType); + logger.Log(LogLevel.Information, $"{new string(' ', depth * 2)}- {moduleType.FullName}"); foreach (var dependedModuleType in FindDependedModuleTypes(moduleType)) { - AddModuleAndDependenciesResursively(moduleTypes, dependedModuleType); + AddModuleAndDependenciesResursively(moduleTypes, dependedModuleType, logger, depth + 1); } } } diff --git a/framework/src/Volo.Abp.Core/Volo/Abp/Modularity/ModuleLoader.cs b/framework/src/Volo.Abp.Core/Volo/Abp/Modularity/ModuleLoader.cs index 7e7e69d457..56ee2f5d71 100644 --- a/framework/src/Volo.Abp.Core/Volo/Abp/Modularity/ModuleLoader.cs +++ b/framework/src/Volo.Abp.Core/Volo/Abp/Modularity/ModuleLoader.cs @@ -2,6 +2,7 @@ using System.Collections.Generic; using System.Linq; using Microsoft.Extensions.DependencyInjection; +using Volo.Abp.Logging; using Volo.Abp.Modularity.PlugIns; namespace Volo.Abp.Modularity @@ -43,14 +44,16 @@ namespace Volo.Abp.Modularity Type startupModuleType, PlugInSourceList plugInSources) { + var initLogger = services.GetInitLogger(); + //All modules starting from the startup module - foreach (var moduleType in AbpModuleHelper.FindAllModuleTypes(startupModuleType)) + foreach (var moduleType in AbpModuleHelper.FindAllModuleTypes(startupModuleType, initLogger)) { modules.Add(CreateModuleDescriptor(services, moduleType)); } //Plugin modules - foreach (var moduleType in plugInSources.GetAllModules()) + foreach (var moduleType in plugInSources.GetAllModules(initLogger)) { if (modules.Any(m => m.Type == moduleType)) { diff --git a/framework/src/Volo.Abp.Core/Volo/Abp/Modularity/ModuleManager.cs b/framework/src/Volo.Abp.Core/Volo/Abp/Modularity/ModuleManager.cs index 70b9036150..764acf1289 100644 --- a/framework/src/Volo.Abp.Core/Volo/Abp/Modularity/ModuleManager.cs +++ b/framework/src/Volo.Abp.Core/Volo/Abp/Modularity/ModuleManager.cs @@ -32,8 +32,6 @@ namespace Volo.Abp.Modularity public void InitializeModules(ApplicationInitializationContext context) { - LogListOfModules(); - foreach (var contributor in _lifecycleContributors) { foreach (var module in _moduleContainer.Modules) @@ -52,16 +50,6 @@ namespace Volo.Abp.Modularity _logger.LogInformation("Initialized all ABP modules."); } - private void LogListOfModules() - { - _logger.LogInformation("Loaded ABP modules:"); - - foreach (var module in _moduleContainer.Modules) - { - _logger.LogInformation("- " + module.Type.FullName); - } - } - public void ShutdownModules(ApplicationShutdownContext context) { var modules = _moduleContainer.Modules.Reverse().ToList(); diff --git a/framework/src/Volo.Abp.Core/Volo/Abp/Modularity/PlugIns/PlugInSourceExtensions.cs b/framework/src/Volo.Abp.Core/Volo/Abp/Modularity/PlugIns/PlugInSourceExtensions.cs index bf44f94605..b041cd160d 100644 --- a/framework/src/Volo.Abp.Core/Volo/Abp/Modularity/PlugIns/PlugInSourceExtensions.cs +++ b/framework/src/Volo.Abp.Core/Volo/Abp/Modularity/PlugIns/PlugInSourceExtensions.cs @@ -1,19 +1,20 @@ using System; using System.Linq; using JetBrains.Annotations; +using Volo.Abp.Logging; namespace Volo.Abp.Modularity.PlugIns { public static class PlugInSourceExtensions { [NotNull] - public static Type[] GetModulesWithAllDependencies([NotNull] this IPlugInSource plugInSource) + public static Type[] GetModulesWithAllDependencies([NotNull] this IPlugInSource plugInSource, IInitLogger logger) { Check.NotNull(plugInSource, nameof(plugInSource)); return plugInSource .GetModules() - .SelectMany(AbpModuleHelper.FindAllModuleTypes) + .SelectMany(type => AbpModuleHelper.FindAllModuleTypes(type, logger)) .Distinct() .ToArray(); } diff --git a/framework/src/Volo.Abp.Core/Volo/Abp/Modularity/PlugIns/PlugInSourceList.cs b/framework/src/Volo.Abp.Core/Volo/Abp/Modularity/PlugIns/PlugInSourceList.cs index 1e96e26e14..1d5509b359 100644 --- a/framework/src/Volo.Abp.Core/Volo/Abp/Modularity/PlugIns/PlugInSourceList.cs +++ b/framework/src/Volo.Abp.Core/Volo/Abp/Modularity/PlugIns/PlugInSourceList.cs @@ -2,16 +2,17 @@ using System.Collections.Generic; using System.Linq; using JetBrains.Annotations; +using Volo.Abp.Logging; namespace Volo.Abp.Modularity.PlugIns { public class PlugInSourceList : List { [NotNull] - internal Type[] GetAllModules() + internal Type[] GetAllModules(IInitLogger logger) { return this - .SelectMany(pluginSource => pluginSource.GetModulesWithAllDependencies()) + .SelectMany(pluginSource => pluginSource.GetModulesWithAllDependencies(logger)) .Distinct() .ToArray(); } diff --git a/framework/src/Volo.Abp.Data/Volo.Abp.Data.csproj b/framework/src/Volo.Abp.Data/Volo.Abp.Data.csproj index cde2718a56..b1077c82da 100644 --- a/framework/src/Volo.Abp.Data/Volo.Abp.Data.csproj +++ b/framework/src/Volo.Abp.Data/Volo.Abp.Data.csproj @@ -15,7 +15,7 @@ - + diff --git a/framework/src/Volo.Abp.Data/Volo/Abp/Data/AbpDataModule.cs b/framework/src/Volo.Abp.Data/Volo/Abp/Data/AbpDataModule.cs index bc3bc8e5dd..6690f855e4 100644 --- a/framework/src/Volo.Abp.Data/Volo/Abp/Data/AbpDataModule.cs +++ b/framework/src/Volo.Abp.Data/Volo/Abp/Data/AbpDataModule.cs @@ -2,6 +2,7 @@ using System.Collections.Generic; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Options; +using Volo.Abp.EventBus.Abstractions; using Volo.Abp.Modularity; using Volo.Abp.ObjectExtending; using Volo.Abp.Uow; @@ -10,7 +11,8 @@ namespace Volo.Abp.Data { [DependsOn( typeof(AbpObjectExtendingModule), - typeof(AbpUnitOfWorkModule) + typeof(AbpUnitOfWorkModule), + typeof(AbpEventBusAbstractionsModule) )] public class AbpDataModule : AbpModule { diff --git a/framework/src/Volo.Abp.Data/Volo/Abp/Data/AbpDatabaseInfo.cs b/framework/src/Volo.Abp.Data/Volo/Abp/Data/AbpDatabaseInfo.cs index 4f719a862a..bcd08718cb 100644 --- a/framework/src/Volo.Abp.Data/Volo/Abp/Data/AbpDatabaseInfo.cs +++ b/framework/src/Volo.Abp.Data/Volo/Abp/Data/AbpDatabaseInfo.cs @@ -4,7 +4,7 @@ namespace Volo.Abp.Data { public class AbpDatabaseInfo { - public string DatabaseName { get; set; } + public string DatabaseName { get; } /// /// List of connection names mapped to this database. @@ -12,8 +12,8 @@ namespace Volo.Abp.Data public HashSet MappedConnections { get; } /// - /// Is this database used by tenants. Set this to true if this database - /// can't owned by tenants. + /// Is this database used by tenants. Set this to false if this database + /// can not owned by tenants. /// /// Default: true. /// diff --git a/framework/src/Volo.Abp.Data/Volo/Abp/Data/ApplyDatabaseMigrationsEto.cs b/framework/src/Volo.Abp.Data/Volo/Abp/Data/ApplyDatabaseMigrationsEto.cs new file mode 100644 index 0000000000..86c2003aad --- /dev/null +++ b/framework/src/Volo.Abp.Data/Volo/Abp/Data/ApplyDatabaseMigrationsEto.cs @@ -0,0 +1,15 @@ +using System; +using Volo.Abp.Domain.Entities.Events.Distributed; +using Volo.Abp.EventBus; + +namespace Volo.Abp.Data +{ + [Serializable] + [EventName("abp.data.apply_database_migrations")] + public class ApplyDatabaseMigrationsEto : EtoBase + { + public Guid? TenantId { get; set; } + + public string DatabaseName { get; set; } + } +} \ No newline at end of file diff --git a/framework/src/Volo.Abp.Http/Volo/Abp/Http/Modeling/PropertyApiDescriptionModel.cs b/framework/src/Volo.Abp.Http/Volo/Abp/Http/Modeling/PropertyApiDescriptionModel.cs index 678798ae39..fc9f13edbc 100644 --- a/framework/src/Volo.Abp.Http/Volo/Abp/Http/Modeling/PropertyApiDescriptionModel.cs +++ b/framework/src/Volo.Abp.Http/Volo/Abp/Http/Modeling/PropertyApiDescriptionModel.cs @@ -24,7 +24,7 @@ namespace Volo.Abp.Http.Modeling return new PropertyApiDescriptionModel { Name = propertyInfo.Name, - JsonName = AbpApiProxyScriptingOptions.PropertyNameGenerator.Invoke(propertyInfo), + JsonName = AbpApiProxyScriptingConfiguration.PropertyNameGenerator.Invoke(propertyInfo), Type = ApiTypeNameHelper.GetTypeName(propertyInfo.PropertyType), TypeSimple = ApiTypeNameHelper.GetSimpleTypeName(propertyInfo.PropertyType), IsRequired = propertyInfo.IsDefined(typeof(RequiredAttribute), true) diff --git a/framework/src/Volo.Abp.Http/Volo/Abp/Http/ProxyScripting/Configuration/AbpApiProxyScriptingConfiguration.cs b/framework/src/Volo.Abp.Http/Volo/Abp/Http/ProxyScripting/Configuration/AbpApiProxyScriptingConfiguration.cs new file mode 100644 index 0000000000..1f17d0d2cf --- /dev/null +++ b/framework/src/Volo.Abp.Http/Volo/Abp/Http/ProxyScripting/Configuration/AbpApiProxyScriptingConfiguration.cs @@ -0,0 +1,32 @@ +using System; +using System.Reflection; + +namespace Volo.Abp.Http.ProxyScripting.Configuration +{ + public static class AbpApiProxyScriptingConfiguration + { + public static Func PropertyNameGenerator { get; set; } + + static AbpApiProxyScriptingConfiguration() + { + PropertyNameGenerator = propertyInfo => + { + var jsonPropertyNameAttribute = propertyInfo.GetSingleAttributeOrNull(true); + + if (jsonPropertyNameAttribute != null) + { + return jsonPropertyNameAttribute.Name; + } + + var jsonPropertyAttribute = propertyInfo.GetSingleAttributeOrNull(true); + + if (jsonPropertyAttribute != null) + { + return jsonPropertyAttribute.PropertyName; + } + + return null; + }; + } + } +} \ No newline at end of file diff --git a/framework/src/Volo.Abp.Http/Volo/Abp/Http/ProxyScripting/Configuration/AbpApiProxyScriptingOptions.cs b/framework/src/Volo.Abp.Http/Volo/Abp/Http/ProxyScripting/Configuration/AbpApiProxyScriptingOptions.cs index 21bc6783bb..e698d00416 100644 --- a/framework/src/Volo.Abp.Http/Volo/Abp/Http/ProxyScripting/Configuration/AbpApiProxyScriptingOptions.cs +++ b/framework/src/Volo.Abp.Http/Volo/Abp/Http/ProxyScripting/Configuration/AbpApiProxyScriptingOptions.cs @@ -1,6 +1,5 @@ using System; using System.Collections.Generic; -using System.Reflection; namespace Volo.Abp.Http.ProxyScripting.Configuration { @@ -8,30 +7,9 @@ namespace Volo.Abp.Http.ProxyScripting.Configuration { public IDictionary Generators { get; } - public static Func PropertyNameGenerator { get; set; } - public AbpApiProxyScriptingOptions() { Generators = new Dictionary(); - - PropertyNameGenerator = propertyInfo => - { - var jsonPropertyNameAttribute = propertyInfo.GetSingleAttributeOrNull(true); - - if (jsonPropertyNameAttribute != null) - { - return jsonPropertyNameAttribute.Name; - } - - var jsonPropertyAttribute = propertyInfo.GetSingleAttributeOrNull(true); - - if (jsonPropertyAttribute != null) - { - return jsonPropertyAttribute.PropertyName; - } - - return null; - }; } } } \ No newline at end of file diff --git a/framework/src/Volo.Abp.MongoDB/Volo/Abp/Domain/Repositories/MongoDbCoreRepositoryExtensions.cs b/framework/src/Volo.Abp.MongoDB/Volo/Abp/Domain/Repositories/MongoDbCoreRepositoryExtensions.cs index bcbdc00d9e..27e031fe58 100644 --- a/framework/src/Volo.Abp.MongoDB/Volo/Abp/Domain/Repositories/MongoDbCoreRepositoryExtensions.cs +++ b/framework/src/Volo.Abp.MongoDB/Volo/Abp/Domain/Repositories/MongoDbCoreRepositoryExtensions.cs @@ -11,60 +11,58 @@ namespace Volo.Abp.Domain.Repositories public static class MongoDbCoreRepositoryExtensions { [Obsolete("Use GetDatabaseAsync method.")] - public static IMongoDatabase GetDatabase(this IBasicRepository repository) - where TEntity : class, IEntity + public static IMongoDatabase GetDatabase(this IReadOnlyBasicRepository repository) + where TEntity : class, IEntity { return repository.ToMongoDbRepository().Database; } - public static Task GetDatabaseAsync(this IBasicRepository repository, CancellationToken cancellationToken = default) - where TEntity : class, IEntity + public static Task GetDatabaseAsync(this IReadOnlyBasicRepository repository, CancellationToken cancellationToken = default) + where TEntity : class, IEntity { return repository.ToMongoDbRepository().GetDatabaseAsync(cancellationToken); } [Obsolete("Use GetCollectionAsync method.")] - public static IMongoCollection GetCollection(this IBasicRepository repository) - where TEntity : class, IEntity + public static IMongoCollection GetCollection(this IReadOnlyBasicRepository repository) + where TEntity : class, IEntity { return repository.ToMongoDbRepository().Collection; } - public static Task> GetCollectionAsync(this IBasicRepository repository, CancellationToken cancellationToken = default) - where TEntity : class, IEntity + public static Task> GetCollectionAsync(this IReadOnlyBasicRepository repository, CancellationToken cancellationToken = default) + where TEntity : class, IEntity { return repository.ToMongoDbRepository().GetCollectionAsync(cancellationToken); } [Obsolete("Use GetMongoQueryableAsync method.")] - public static IMongoQueryable GetMongoQueryable(this IBasicRepository repository) - where TEntity : class, IEntity + public static IMongoQueryable GetMongoQueryable(this IReadOnlyBasicRepository repository) + where TEntity : class, IEntity { return repository.ToMongoDbRepository().GetMongoQueryable(); } - public static Task> GetMongoQueryableAsync(this IBasicRepository repository, CancellationToken cancellationToken = default) - where TEntity : class, IEntity + public static Task> GetMongoQueryableAsync(this IReadOnlyBasicRepository repository, CancellationToken cancellationToken = default) + where TEntity : class, IEntity { return repository.ToMongoDbRepository().GetMongoQueryableAsync(cancellationToken); } - public static Task> GetAggregateAsync(this IBasicRepository repository, CancellationToken cancellationToken = default) - where TEntity : class, IEntity + public static Task> GetAggregateAsync(this IReadOnlyBasicRepository repository, CancellationToken cancellationToken = default) + where TEntity : class, IEntity { return repository.ToMongoDbRepository().GetAggregateAsync(cancellationToken); } - public static IMongoDbRepository ToMongoDbRepository(this IBasicRepository repository) - where TEntity : class, IEntity + public static IMongoDbRepository ToMongoDbRepository(this IReadOnlyBasicRepository repository) + where TEntity : class, IEntity { - var mongoDbRepository = repository as IMongoDbRepository; - if (mongoDbRepository == null) + if (repository is IMongoDbRepository mongoDbRepository) { - throw new ArgumentException("Given repository does not implement " + typeof(IMongoDbRepository).AssemblyQualifiedName, nameof(repository)); - } - - return mongoDbRepository; + return mongoDbRepository; + } + throw new ArgumentException("Given repository does not implement " + typeof(IMongoDbRepository).AssemblyQualifiedName, nameof(repository)); } } } diff --git a/framework/src/Volo.Abp.RabbitMQ/Volo/Abp/RabbitMQ/ConnectionPool.cs b/framework/src/Volo.Abp.RabbitMQ/Volo/Abp/RabbitMQ/ConnectionPool.cs index 5856f7bb16..7ca8346d11 100644 --- a/framework/src/Volo.Abp.RabbitMQ/Volo/Abp/RabbitMQ/ConnectionPool.cs +++ b/framework/src/Volo.Abp.RabbitMQ/Volo/Abp/RabbitMQ/ConnectionPool.cs @@ -26,10 +26,13 @@ namespace Volo.Abp.RabbitMQ return Connections.GetOrAdd( connectionName, - () => Options - .Connections - .GetOrDefault(connectionName) - .CreateConnection() + () => + { + var connection = Options.Connections.GetOrDefault(connectionName); + var hostnames = connection.HostName.TrimEnd(';').Split(';'); + // Handle Rabbit MQ Cluster. + return hostnames.Length == 1 ? connection.CreateConnection() : connection.CreateConnection(hostnames); + } ); } diff --git a/framework/src/Volo.Abp.UI.Navigation/Volo/Abp/Ui/Navigation/ApplicationMenuItem.cs b/framework/src/Volo.Abp.UI.Navigation/Volo/Abp/Ui/Navigation/ApplicationMenuItem.cs index 1c41727f7b..63f4d7239d 100644 --- a/framework/src/Volo.Abp.UI.Navigation/Volo/Abp/Ui/Navigation/ApplicationMenuItem.cs +++ b/framework/src/Volo.Abp.UI.Navigation/Volo/Abp/Ui/Navigation/ApplicationMenuItem.cs @@ -71,6 +71,9 @@ namespace Volo.Abp.UI.Navigation [NotNull] public ApplicationMenuItemList Items { get; } + [CanBeNull] + public string RequiredPermissionName { get; set; } + /// /// Can be used to store a custom object related to this menu item. Optional. /// @@ -95,7 +98,8 @@ namespace Volo.Abp.UI.Navigation object customData = null, string target = null, string elementId = null, - string cssClass = null) + string cssClass = null, + string requiredPermissionName = null) { Check.NotNullOrWhiteSpace(name, nameof(name)); Check.NotNullOrWhiteSpace(displayName, nameof(displayName)); @@ -109,6 +113,7 @@ namespace Volo.Abp.UI.Navigation Target = target; ElementId = elementId ?? GetDefaultElementId(); CssClass = cssClass; + RequiredPermissionName = requiredPermissionName; Items = new ApplicationMenuItemList(); } 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 5c33866aa2..960389230e 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 @@ -2,7 +2,9 @@ using System; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; +using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Options; +using Volo.Abp.Authorization.Permissions; using Volo.Abp.DependencyInjection; namespace Volo.Abp.UI.Navigation @@ -13,7 +15,7 @@ namespace Volo.Abp.UI.Navigation protected IHybridServiceScopeFactory ServiceScopeFactory { get; } public MenuManager( - IOptions options, + IOptions options, IHybridServiceScopeFactory serviceScopeFactory) { ServiceScopeFactory = serviceScopeFactory; @@ -32,6 +34,8 @@ namespace Volo.Abp.UI.Navigation { await contributor.ConfigureMenuAsync(context); } + + await CheckPermissionsAsync(scope.ServiceProvider, menu); } NormalizeMenu(menu); @@ -39,14 +43,60 @@ namespace Volo.Abp.UI.Navigation return menu; } + protected virtual async Task CheckPermissionsAsync(IServiceProvider serviceProvider, IHasMenuItems menuWithItems) + { + var requiredPermissionItems = new List(); + GetRequiredPermissionNameMenus(menuWithItems, requiredPermissionItems); + + if (requiredPermissionItems.Any()) + { + var permissionChecker = serviceProvider.GetRequiredService(); + var grantResult = await permissionChecker.IsGrantedAsync(requiredPermissionItems.Select(x => x.RequiredPermissionName).Distinct().ToArray()); + + var toBeDeleted = new HashSet(); + foreach (var menu in requiredPermissionItems) + { + if (grantResult.Result[menu.RequiredPermissionName!] != PermissionGrantResult.Granted) + { + toBeDeleted.Add(menu); + } + } + + RemoveMenus(menuWithItems, toBeDeleted); + } + } + + protected virtual void GetRequiredPermissionNameMenus(IHasMenuItems menuWithItems, List output) + { + foreach (var item in menuWithItems.Items) + { + if (!item.RequiredPermissionName.IsNullOrWhiteSpace()) + { + output.Add(item); + } + + GetRequiredPermissionNameMenus(item, output); + } + } + + protected virtual void RemoveMenus(IHasMenuItems menuWithItems, HashSet toBeDeleted) + { + menuWithItems.Items.RemoveAll(toBeDeleted.Contains); + + foreach (var item in menuWithItems.Items) + { + RemoveMenus(item, toBeDeleted); + } + } + protected virtual void NormalizeMenu(IHasMenuItems menuWithItems) { - foreach (var menuItem in menuWithItems.Items) + foreach (var item in menuWithItems.Items) { - NormalizeMenu(menuItem); + NormalizeMenu(item); } menuWithItems.Items.Normalize(); } } -} \ No newline at end of file +} diff --git a/framework/test/Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared.Tests/Volo/Abp/AspNetCore/Mvc/UI/Theme/Shared/Permissions/FakePermissionStore.cs b/framework/test/Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared.Tests/Volo/Abp/AspNetCore/Mvc/UI/Theme/Shared/Permissions/FakePermissionStore.cs new file mode 100644 index 0000000000..f8f9d21b27 --- /dev/null +++ b/framework/test/Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared.Tests/Volo/Abp/AspNetCore/Mvc/UI/Theme/Shared/Permissions/FakePermissionStore.cs @@ -0,0 +1,28 @@ +using System.Threading.Tasks; +using Volo.Abp.Authorization.Permissions; +using Volo.Abp.DependencyInjection; + +namespace Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared.Tests.Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared.Permissions +{ + public class FakePermissionStore : IPermissionStore, ITransientDependency + { + public Task IsGrantedAsync(string name, string providerName, string providerKey) + { + var result = (name.Contains("MyComponent1") || name.Contains("MyComponent3")); + return Task.FromResult(result); + } + + public Task IsGrantedAsync(string[] names, string providerName, string providerKey) + { + var result = new MultiplePermissionGrantResult(); + foreach (var name in names) + { + result.Result.Add(name, (name.Contains("MyComponent1") || name.Contains("MyComponent3")) + ? PermissionGrantResult.Granted + : PermissionGrantResult.Prohibited); + } + + return Task.FromResult(result); + } + } +} diff --git a/framework/test/Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared.Tests/Volo/Abp/AspNetCore/Mvc/UI/Theme/Shared/Permissions/TestPermissionDefinitionProvider.cs b/framework/test/Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared.Tests/Volo/Abp/AspNetCore/Mvc/UI/Theme/Shared/Permissions/TestPermissionDefinitionProvider.cs new file mode 100644 index 0000000000..ef706a6c0a --- /dev/null +++ b/framework/test/Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared.Tests/Volo/Abp/AspNetCore/Mvc/UI/Theme/Shared/Permissions/TestPermissionDefinitionProvider.cs @@ -0,0 +1,16 @@ +using Volo.Abp.Authorization.Permissions; + +namespace Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared.Tests.Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared.Permissions +{ + public class TestPermissionDefinitionProvider : PermissionDefinitionProvider + { + public override void Define(IPermissionDefinitionContext context) + { + var group = context.AddGroup("TestGroup"); + + group.AddPermission("MyComponent1"); + group.AddPermission("MyComponent2"); + group.AddPermission("MyComponent3"); + } + } +} diff --git a/framework/test/Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared.Tests/Volo/Abp/AspNetCore/Mvc/UI/Theme/Shared/Toolbars/Toolbar_Tests.cs b/framework/test/Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared.Tests/Volo/Abp/AspNetCore/Mvc/UI/Theme/Shared/Toolbars/Toolbar_Tests.cs new file mode 100644 index 0000000000..70ca907fac --- /dev/null +++ b/framework/test/Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared.Tests/Volo/Abp/AspNetCore/Mvc/UI/Theme/Shared/Toolbars/Toolbar_Tests.cs @@ -0,0 +1,129 @@ +using System.Collections.Generic; +using System.Security.Claims; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Mvc; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.DependencyInjection.Extensions; +using Microsoft.Extensions.Hosting; +using Microsoft.Extensions.Options; +using NSubstitute; +using Shouldly; +using Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared.Toolbars; +using Volo.Abp.AspNetCore.Mvc.UI.Theming; +using Volo.Abp.Security.Claims; +using Xunit; + +namespace Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared.Tests.Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared.Toolbars +{ + public class Toolbar_Tests : AbpAspNetCoreMvcUiThemeSharedTestBase + { + protected override void ConfigureServices(HostBuilderContext context, IServiceCollection services) + { + services.Configure(options => + { + options.Contributors.Add(new MyToolbarContributor()); + options.Contributors.Add(new MyToolbarContributor2()); + }); + + var claims = new List() { + new Claim(AbpClaimTypes.UserId, "1fcf46b2-28c3-48d0-8bac-fa53268a2775"), + }; + + var identity = new ClaimsIdentity(claims); + var claimsPrincipal = new ClaimsPrincipal(identity); + var principalAccessor = Substitute.For(); + principalAccessor.Principal.Returns(ci => claimsPrincipal); + Thread.CurrentPrincipal = claimsPrincipal; + + var themeManager = Substitute.For(); + themeManager.CurrentTheme.Returns(x => null); + services.Replace(ServiceDescriptor.Singleton(themeManager)); + } + + [Fact] + public void AbpToolbarOptions_Should_Contain_Contributors() + { + var options = GetRequiredService>().Value; + options.Contributors.Count.ShouldBe(2); + options.Contributors.ShouldContain(x => x.GetType() == typeof(MyToolbarContributor)); + options.Contributors.ShouldContain(x => x.GetType() == typeof(MyToolbarContributor2)); + } + + [Fact] + public async Task ToolbarManager_Should_Return_Toolbar() + { + var toolbarManager = GetRequiredService(); + var toolbar = await toolbarManager.GetAsync(StandardToolbars.Main); + + toolbar.Items.Count.ShouldBe(3); + toolbar.Items[0].ComponentType.ShouldBe(typeof(MyComponent1)); + toolbar.Items[1].ComponentType.ShouldBe(typeof(MyComponent3)); + toolbar.Items[2].ComponentType.ShouldBe(typeof(MyComponent4)); + } + + public class MyToolbarContributor : IToolbarContributor + { + public Task ConfigureToolbarAsync(IToolbarConfigurationContext context) + { + if (context.Toolbar.Name != StandardToolbars.Main) + { + return Task.CompletedTask; + } + + context.Toolbar.Items.Add(new ToolbarItem(typeof(MyComponent1), requiredPermissionName: "MyComponent1")); + context.Toolbar.Items.Add(new ToolbarItem(typeof(MyComponent2), requiredPermissionName: "MyComponent2")); + + return Task.CompletedTask; + } + } + + public class MyToolbarContributor2 : IToolbarContributor + { + public Task ConfigureToolbarAsync(IToolbarConfigurationContext context) + { + if (context.Toolbar.Name != StandardToolbars.Main) + { + return Task.CompletedTask; + } + + context.Toolbar.Items.Add(new ToolbarItem(typeof(MyComponent3), requiredPermissionName: "MyComponent3")); + context.Toolbar.Items.Add(new ToolbarItem(typeof(MyComponent4))); + + return Task.CompletedTask; + } + } + + public class MyComponent1 : AbpViewComponent + { + public IViewComponentResult InvokeAsync() + { + return Content("MyComponent1"); + } + } + + public class MyComponent2 : AbpViewComponent + { + public IViewComponentResult InvokeAsync() + { + return Content("MyComponent2"); + } + } + + public class MyComponent3 : AbpViewComponent + { + public IViewComponentResult InvokeAsync() + { + return Content("MyComponent3"); + } + } + + public class MyComponent4 : AbpViewComponent + { + public IViewComponentResult InvokeAsync() + { + return Content("MyComponent4"); + } + } + } +} diff --git a/framework/test/Volo.Abp.Core.Tests/Volo/Abp/Modularity/ModuleLoader_Tests.cs b/framework/test/Volo.Abp.Core.Tests/Volo/Abp/Modularity/ModuleLoader_Tests.cs index 3541f9b78e..cc0117e184 100644 --- a/framework/test/Volo.Abp.Core.Tests/Volo/Abp/Modularity/ModuleLoader_Tests.cs +++ b/framework/test/Volo.Abp.Core.Tests/Volo/Abp/Modularity/ModuleLoader_Tests.cs @@ -1,5 +1,6 @@ using Microsoft.Extensions.DependencyInjection; using Shouldly; +using Volo.Abp.Logging; using Volo.Abp.Modularity.PlugIns; using Xunit; @@ -11,7 +12,12 @@ namespace Volo.Abp.Modularity public void Should_Load_Modules_By_Dependency_Order() { var moduleLoader = new ModuleLoader(); - var modules = moduleLoader.LoadModules(new ServiceCollection(), typeof(MyStartupModule), new PlugInSourceList()); + var modules = moduleLoader.LoadModules( + new ServiceCollection() + .AddSingleton(new DefaultInitLogger()), + typeof(MyStartupModule), + new PlugInSourceList() + ); modules.Length.ShouldBe(2); modules[0].Type.ShouldBe(typeof(IndependentEmptyModule)); modules[1].Type.ShouldBe(typeof(MyStartupModule)); diff --git a/framework/test/Volo.Abp.UI.Navigation.Tests/Volo.Abp.UI.Navigation.Tests.csproj b/framework/test/Volo.Abp.UI.Navigation.Tests/Volo.Abp.UI.Navigation.Tests.csproj index ecfd73c615..a59bb11e0f 100644 --- a/framework/test/Volo.Abp.UI.Navigation.Tests/Volo.Abp.UI.Navigation.Tests.csproj +++ b/framework/test/Volo.Abp.UI.Navigation.Tests/Volo.Abp.UI.Navigation.Tests.csproj @@ -9,6 +9,8 @@ + + diff --git a/framework/test/Volo.Abp.UI.Navigation.Tests/Volo/Abp/Ui/Navigation/AbpUiNavigationTestModule.cs b/framework/test/Volo.Abp.UI.Navigation.Tests/Volo/Abp/Ui/Navigation/AbpUiNavigationTestModule.cs new file mode 100644 index 0000000000..35b368cc1b --- /dev/null +++ b/framework/test/Volo.Abp.UI.Navigation.Tests/Volo/Abp/Ui/Navigation/AbpUiNavigationTestModule.cs @@ -0,0 +1,21 @@ +using Volo.Abp.Authorization; +using Volo.Abp.Autofac; +using Volo.Abp.Modularity; + +namespace Volo.Abp.UI.Navigation +{ + [DependsOn(typeof(AbpUiNavigationModule))] + [DependsOn(typeof(AbpAuthorizationModule))] + [DependsOn(typeof(AbpAutofacModule))] + public class AbpUiNavigationTestModule : AbpModule + { + public override void ConfigureServices(ServiceConfigurationContext context) + { + Configure(options => + { + options.MenuContributors.Add(new MenuManager_Tests.TestMenuContributor1()); + options.MenuContributors.Add(new MenuManager_Tests.TestMenuContributor2()); + }); + } + } +} diff --git a/framework/test/Volo.Abp.UI.Navigation.Tests/Volo/Abp/Ui/Navigation/FakePermissionStore.cs b/framework/test/Volo.Abp.UI.Navigation.Tests/Volo/Abp/Ui/Navigation/FakePermissionStore.cs new file mode 100644 index 0000000000..ac074220f5 --- /dev/null +++ b/framework/test/Volo.Abp.UI.Navigation.Tests/Volo/Abp/Ui/Navigation/FakePermissionStore.cs @@ -0,0 +1,28 @@ +using System.Threading.Tasks; +using Volo.Abp.Authorization.Permissions; +using Volo.Abp.DependencyInjection; + +namespace Volo.Abp.UI.Navigation +{ + public class FakePermissionStore : IPermissionStore, ITransientDependency + { + public Task IsGrantedAsync(string name, string providerName, string providerKey) + { + var result = (name.Contains("Administration") || name.Contains("Dashboard")) && !name.Contains("SubMenu1"); + return Task.FromResult(result); + } + + public Task IsGrantedAsync(string[] names, string providerName, string providerKey) + { + var result = new MultiplePermissionGrantResult(); + foreach (var name in names) + { + result.Result.Add(name, (name.Contains("Administration") || name.Contains("Dashboard")) && !name.Contains("SubMenu1") + ? PermissionGrantResult.Granted + : PermissionGrantResult.Prohibited); + } + + return Task.FromResult(result); + } + } +} diff --git a/framework/test/Volo.Abp.UI.Navigation.Tests/Volo/Abp/Ui/Navigation/MenuManager_Tests.cs b/framework/test/Volo.Abp.UI.Navigation.Tests/Volo/Abp/Ui/Navigation/MenuManager_Tests.cs index 96db1622b5..c72082945b 100644 --- a/framework/test/Volo.Abp.UI.Navigation.Tests/Volo/Abp/Ui/Navigation/MenuManager_Tests.cs +++ b/framework/test/Volo.Abp.UI.Navigation.Tests/Volo/Abp/Ui/Navigation/MenuManager_Tests.cs @@ -1,13 +1,17 @@ -using System.Threading.Tasks; +using System.Collections.Generic; +using System.Security.Claims; +using System.Threading; +using System.Threading.Tasks; using Microsoft.Extensions.DependencyInjection; +using NSubstitute; using Shouldly; -using Volo.Abp.Modularity; +using Volo.Abp.Security.Claims; using Volo.Abp.Testing; using Xunit; namespace Volo.Abp.UI.Navigation { - public class MenuManager_Tests : AbpIntegratedTest + public class MenuManager_Tests : AbpIntegratedTest { private readonly IMenuManager _menuManager; @@ -16,6 +20,24 @@ namespace Volo.Abp.UI.Navigation _menuManager = ServiceProvider.GetRequiredService(); } + protected override void SetAbpApplicationCreationOptions(AbpApplicationCreationOptions options) + { + options.UseAutofac(); + } + + protected override void AfterAddApplication(IServiceCollection services) + { + var claims = new List() { + new Claim(AbpClaimTypes.UserId, "1fcf46b2-28c3-48d0-8bac-fa53268a2775"), + }; + + var identity = new ClaimsIdentity(claims); + var claimsPrincipal = new ClaimsPrincipal(identity); + var principalAccessor = Substitute.For(); + principalAccessor.Principal.Returns(ci => claimsPrincipal); + Thread.CurrentPrincipal = claimsPrincipal; + } + [Fact] public async Task Should_Get_Menu() { @@ -29,22 +51,8 @@ namespace Volo.Abp.UI.Navigation mainMenu.Items[1].Items[0].Name.ShouldBe("Administration.UserManagement"); mainMenu.Items[1].Items[1].Name.ShouldBe("Administration.RoleManagement"); mainMenu.Items[1].Items[2].Name.ShouldBe("Administration.DashboardSettings"); - mainMenu.Items[1].Items[3].Name.ShouldBe("Administration.SubMenu1"); - mainMenu.Items[1].Items[3].Items[0].Name.ShouldBe("Administration.SubMenu1.1"); - mainMenu.Items[1].Items[3].Items[1].Name.ShouldBe("Administration.SubMenu1.2"); - } - - [DependsOn(typeof(AbpUiNavigationModule))] - public class TestModule : AbpModule - { - public override void ConfigureServices(ServiceConfigurationContext context) - { - Configure(options => - { - options.MenuContributors.Add(new TestMenuContributor1()); - options.MenuContributors.Add(new TestMenuContributor2()); - }); - } + mainMenu.Items[1].Items[3].Name.ShouldBe("Administration.SubMenu1"); //No need permission. + // Administration.SubMenu1.1 and Administration.SubMenu1.2 are removed because of don't have permissions. } /* Adds menu items: @@ -65,8 +73,8 @@ namespace Volo.Abp.UI.Navigation var administration = context.Menu.GetAdministration(); - administration.AddItem(new ApplicationMenuItem("Administration.UserManagement", "User Management", url: "/admin/users")); - administration.AddItem(new ApplicationMenuItem("Administration.RoleManagement", "Role Management", url: "/admin/roles")); + administration.AddItem(new ApplicationMenuItem("Administration.UserManagement", "User Management", url: "/admin/users", requiredPermissionName: "Administration.UserManagement")); + administration.AddItem(new ApplicationMenuItem("Administration.RoleManagement", "Role Management", url: "/admin/roles", requiredPermissionName: "Administration.RoleManagement")); return Task.CompletedTask; } @@ -86,16 +94,16 @@ namespace Volo.Abp.UI.Navigation return Task.CompletedTask; } - context.Menu.Items.Insert(0, new ApplicationMenuItem("Dashboard", "Dashboard", url: "/dashboard")); + context.Menu.Items.Insert(0, new ApplicationMenuItem("Dashboard", "Dashboard", url: "/dashboard", requiredPermissionName: "Dashboard")); var administration = context.Menu.GetAdministration(); - administration.AddItem(new ApplicationMenuItem("Administration.DashboardSettings", "Dashboard Settings", url: "/admin/settings/dashboard")); + administration.AddItem(new ApplicationMenuItem("Administration.DashboardSettings", "Dashboard Settings", url: "/admin/settings/dashboard", requiredPermissionName: "Administration.DashboardSettings")); administration.AddItem( - new ApplicationMenuItem("Administration.SubMenu1", "Sub menu 1") - .AddItem(new ApplicationMenuItem("Administration.SubMenu1.1", "Sub menu 1.1", url: "/submenu1/submenu1_1")) - .AddItem(new ApplicationMenuItem("Administration.SubMenu1.2", "Sub menu 1.2", url: "/submenu1/submenu1_2")) + new ApplicationMenuItem("Administration.SubMenu1", "Sub menu 1", url: "/submenu1") + .AddItem(new ApplicationMenuItem("Administration.SubMenu1.1", "Sub menu 1.1", url: "/submenu1/submenu1_1", requiredPermissionName: "Administration.SubMenu1.1")) + .AddItem(new ApplicationMenuItem("Administration.SubMenu1.2", "Sub menu 1.2", url: "/submenu1/submenu1_2", requiredPermissionName: "Administration.SubMenu1.2")) ); return Task.CompletedTask; diff --git a/framework/test/Volo.Abp.UI.Navigation.Tests/Volo/Abp/Ui/Navigation/TestPermissionDefinitionProvider.cs b/framework/test/Volo.Abp.UI.Navigation.Tests/Volo/Abp/Ui/Navigation/TestPermissionDefinitionProvider.cs new file mode 100644 index 0000000000..c9afe5a1f0 --- /dev/null +++ b/framework/test/Volo.Abp.UI.Navigation.Tests/Volo/Abp/Ui/Navigation/TestPermissionDefinitionProvider.cs @@ -0,0 +1,24 @@ +using Volo.Abp.Authorization.Permissions; + +namespace Volo.Abp.UI.Navigation +{ + public class TestPermissionDefinitionProvider : PermissionDefinitionProvider + { + public override void Define(IPermissionDefinitionContext context) + { + var group = context.AddGroup("TestGroup"); + + group.AddPermission("Dashboard"); + + group.AddPermission("Administration"); + group.AddPermission("Administration.UserManagement"); + group.AddPermission("Administration.RoleManagement"); + + group.AddPermission("Administration.DashboardSettings"); + + group.AddPermission("Administration.SubMenu1"); + group.AddPermission("Administration.SubMenu1.1"); + group.AddPermission("Administration.SubMenu1.2"); + } + } +} diff --git a/modules/blogging/src/Volo.Blogging.Admin.Web/BloggingAdminMenuContributor.cs b/modules/blogging/src/Volo.Blogging.Admin.Web/BloggingAdminMenuContributor.cs index 95a403678f..43e4bfca5b 100644 --- a/modules/blogging/src/Volo.Blogging.Admin.Web/BloggingAdminMenuContributor.cs +++ b/modules/blogging/src/Volo.Blogging.Admin.Web/BloggingAdminMenuContributor.cs @@ -14,22 +14,17 @@ namespace Volo.Blogging.Admin } } - private async Task ConfigureMainMenuAsync(MenuConfigurationContext context) + private Task ConfigureMainMenuAsync(MenuConfigurationContext context) { var l = context.GetLocalizer(); - if (await context.IsGrantedAsync(BloggingPermissions.Blogs.Management)) - { - var managementRootMenuItem = new ApplicationMenuItem("BlogManagement", l["Menu:BlogManagement"]); + var managementRootMenuItem = new ApplicationMenuItem("BlogManagement", l["Menu:BlogManagement"], requiredPermissionName: BloggingPermissions.Blogs.Management); - //TODO: Using the same permission. Reconsider. - if (await context.IsGrantedAsync(BloggingPermissions.Blogs.Management)) - { - managementRootMenuItem.AddItem(new ApplicationMenuItem("BlogManagement.Blogs", l["Menu:Blogs"], "~/Blogging/Admin/Blogs")); - } + managementRootMenuItem.AddItem(new ApplicationMenuItem("BlogManagement.Blogs", l["Menu:Blogs"], "~/Blogging/Admin/Blogs", requiredPermissionName: BloggingPermissions.Blogs.Management)); - context.Menu.GetAdministration().AddItem(managementRootMenuItem); - } + context.Menu.GetAdministration().AddItem(managementRootMenuItem); + + return Task.CompletedTask; } } } diff --git a/modules/blogging/src/Volo.Blogging.Application/Volo/Blogging/Posts/PostAppService.cs b/modules/blogging/src/Volo.Blogging.Application/Volo/Blogging/Posts/PostAppService.cs index 70007a0c56..07d22d3385 100644 --- a/modules/blogging/src/Volo.Blogging.Application/Volo/Blogging/Posts/PostAppService.cs +++ b/modules/blogging/src/Volo.Blogging.Application/Volo/Blogging/Posts/PostAppService.cs @@ -4,6 +4,8 @@ using System.Threading.Tasks; using Volo.Abp.Application.Dtos; using System.Collections.Generic; using Microsoft.AspNetCore.Authorization; +using Microsoft.Extensions.Caching.Distributed; +using Volo.Abp.Caching; using Volo.Blogging.Comments; using Volo.Blogging.Tagging; using Volo.Blogging.Tagging.Dtos; @@ -18,71 +20,41 @@ namespace Volo.Blogging.Posts private readonly IPostRepository _postRepository; private readonly ITagRepository _tagRepository; private readonly ICommentRepository _commentRepository; + private readonly IDistributedCache> _postsCache; - public PostAppService(IPostRepository postRepository, ITagRepository tagRepository, ICommentRepository commentRepository, IBlogUserLookupService userLookupService) + public PostAppService(IPostRepository postRepository, ITagRepository tagRepository, ICommentRepository commentRepository, IBlogUserLookupService userLookupService, IDistributedCache> postsCache) { UserLookupService = userLookupService; _postRepository = postRepository; _tagRepository = tagRepository; _commentRepository = commentRepository; + _postsCache = postsCache; } - + public async Task> GetListByBlogIdAndTagName(Guid id, string tagName) { - var posts = await _postRepository.GetPostsByBlogId(id); - var tag = tagName.IsNullOrWhiteSpace() ? null : await _tagRepository.FindByNameAsync(id, tagName); - var userDictionary = new Dictionary(); - var postDtos = new List(ObjectMapper.Map, List>(posts)); - - foreach (var postDto in postDtos) - { - postDto.Tags = await GetTagsOfPost(postDto.Id); - } - - if (tag != null) - { - postDtos = await FilterPostsByTag(postDtos, tag); - } - - foreach (var postDto in postDtos) - { - if (postDto.CreatorId.HasValue) + var cacheKey = id.ToString() + "-" + tagName; + + return await _postsCache.GetOrAddAsync( + cacheKey, + async () => await GetPostsByBlogIdAndTagName(id, tagName), + () => new DistributedCacheEntryOptions { - if (!userDictionary.ContainsKey(postDto.CreatorId.Value)) - { - var creatorUser = await UserLookupService.FindByIdAsync(postDto.CreatorId.Value); - if (creatorUser != null) - { - userDictionary[creatorUser.Id] = ObjectMapper.Map(creatorUser); - } - } - - if (userDictionary.ContainsKey(postDto.CreatorId.Value)) - { - postDto.Writer = userDictionary[(Guid)postDto.CreatorId]; - } + AbsoluteExpiration = DateTimeOffset.Now.AddHours(6) } - } - - return new ListResultDto(postDtos); + ); } - + public async Task> GetTimeOrderedListAsync(Guid blogId) { - var posts = await _postRepository.GetOrderedList(blogId); - - var postDtos = new List(ObjectMapper.Map, List>(posts)); - - foreach (var postDto in postDtos) - { - var creatorUser = await UserLookupService.FindByIdAsync(postDto.CreatorId.Value); - if (creatorUser != null) + return await _postsCache.GetOrAddAsync( + blogId.ToString(), + async () => await GetTimeOrderedPostsAsync(blogId), + () => new DistributedCacheEntryOptions { - postDto.Writer = ObjectMapper.Map(creatorUser); + AbsoluteExpiration = DateTimeOffset.Now.AddHours(6) } - } - - return new ListResultDto(postDtos); + ); } public async Task GetForReadingAsync(GetPostInput input) @@ -185,6 +157,64 @@ namespace Volo.Blogging.Posts return ObjectMapper.Map(post); } + private async Task> GetPostsByBlogIdAndTagName(Guid id, string tagName) + { + var posts = await _postRepository.GetPostsByBlogId(id); + var tag = tagName.IsNullOrWhiteSpace() ? null : await _tagRepository.FindByNameAsync(id, tagName); + var userDictionary = new Dictionary(); + var postDtos = new List(ObjectMapper.Map, List>(posts)); + + foreach (var postDto in postDtos) + { + postDto.Tags = await GetTagsOfPost(postDto.Id); + } + + if (tag != null) + { + postDtos = await FilterPostsByTag(postDtos, tag); + } + + foreach (var postDto in postDtos) + { + if (postDto.CreatorId.HasValue) + { + if (!userDictionary.ContainsKey(postDto.CreatorId.Value)) + { + var creatorUser = await UserLookupService.FindByIdAsync(postDto.CreatorId.Value); + if (creatorUser != null) + { + userDictionary[creatorUser.Id] = ObjectMapper.Map(creatorUser); + } + } + + if (userDictionary.ContainsKey(postDto.CreatorId.Value)) + { + postDto.Writer = userDictionary[(Guid)postDto.CreatorId]; + } + } + } + + return new ListResultDto(postDtos); + } + + private async Task> GetTimeOrderedPostsAsync(Guid blogId) + { + var posts = await _postRepository.GetOrderedList(blogId); + + var postDtos = new List(ObjectMapper.Map, List>(posts)); + + foreach (var postDto in postDtos) + { + var creatorUser = await UserLookupService.FindByIdAsync(postDto.CreatorId.Value); + if (creatorUser != null) + { + postDto.Writer = ObjectMapper.Map(creatorUser); + } + } + + return new ListResultDto(postDtos); + } + private async Task RenameUrlIfItAlreadyExistAsync(Guid blogId, string url, Post existingPost = null) { if (await _postRepository.IsPostUrlInUseAsync(blogId, url, existingPost?.Id)) diff --git a/modules/cms-kit/host/Volo.CmsKit.Web.Unified/Migrations/20210226112040_BlogPost_Author.Designer.cs b/modules/cms-kit/host/Volo.CmsKit.Web.Unified/Migrations/20210226112040_BlogPost_Author.Designer.cs new file mode 100644 index 0000000000..8ace403879 --- /dev/null +++ b/modules/cms-kit/host/Volo.CmsKit.Web.Unified/Migrations/20210226112040_BlogPost_Author.Designer.cs @@ -0,0 +1,2007 @@ +// +using System; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Metadata; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; +using Volo.Abp.EntityFrameworkCore; +using Volo.CmsKit.EntityFrameworkCore; + +namespace Volo.CmsKit.Migrations +{ + [DbContext(typeof(UnifiedDbContext))] + [Migration("20210226112040_BlogPost_Author")] + partial class BlogPost_Author + { + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("_Abp_DatabaseProvider", EfCoreDatabaseProvider.SqlServer) + .HasAnnotation("Relational:MaxIdentifierLength", 128) + .HasAnnotation("ProductVersion", "5.0.3") + .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); + + modelBuilder.Entity("Volo.Abp.AuditLogging.AuditLog", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("ApplicationName") + .HasMaxLength(96) + .HasColumnType("nvarchar(96)") + .HasColumnName("ApplicationName"); + + b.Property("BrowserInfo") + .HasMaxLength(512) + .HasColumnType("nvarchar(512)") + .HasColumnName("BrowserInfo"); + + b.Property("ClientId") + .HasMaxLength(64) + .HasColumnType("nvarchar(64)") + .HasColumnName("ClientId"); + + b.Property("ClientIpAddress") + .HasMaxLength(64) + .HasColumnType("nvarchar(64)") + .HasColumnName("ClientIpAddress"); + + b.Property("ClientName") + .HasMaxLength(128) + .HasColumnType("nvarchar(128)") + .HasColumnName("ClientName"); + + b.Property("Comments") + .HasMaxLength(256) + .HasColumnType("nvarchar(256)") + .HasColumnName("Comments"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .HasMaxLength(40) + .HasColumnType("nvarchar(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("CorrelationId") + .HasMaxLength(64) + .HasColumnType("nvarchar(64)") + .HasColumnName("CorrelationId"); + + b.Property("Exceptions") + .HasMaxLength(4000) + .HasColumnType("nvarchar(4000)") + .HasColumnName("Exceptions"); + + b.Property("ExecutionDuration") + .HasColumnType("int") + .HasColumnName("ExecutionDuration"); + + b.Property("ExecutionTime") + .HasColumnType("datetime2"); + + b.Property("ExtraProperties") + .HasColumnType("nvarchar(max)") + .HasColumnName("ExtraProperties"); + + b.Property("HttpMethod") + .HasMaxLength(16) + .HasColumnType("nvarchar(16)") + .HasColumnName("HttpMethod"); + + b.Property("HttpStatusCode") + .HasColumnType("int") + .HasColumnName("HttpStatusCode"); + + b.Property("ImpersonatorTenantId") + .HasColumnType("uniqueidentifier") + .HasColumnName("ImpersonatorTenantId"); + + b.Property("ImpersonatorUserId") + .HasColumnType("uniqueidentifier") + .HasColumnName("ImpersonatorUserId"); + + b.Property("TenantId") + .HasColumnType("uniqueidentifier") + .HasColumnName("TenantId"); + + b.Property("TenantName") + .HasColumnType("nvarchar(max)"); + + b.Property("Url") + .HasMaxLength(256) + .HasColumnType("nvarchar(256)") + .HasColumnName("Url"); + + b.Property("UserId") + .HasColumnType("uniqueidentifier") + .HasColumnName("UserId"); + + b.Property("UserName") + .HasMaxLength(256) + .HasColumnType("nvarchar(256)") + .HasColumnName("UserName"); + + b.HasKey("Id"); + + b.HasIndex("TenantId", "ExecutionTime"); + + b.HasIndex("TenantId", "UserId", "ExecutionTime"); + + b.ToTable("AbpAuditLogs"); + }); + + modelBuilder.Entity("Volo.Abp.AuditLogging.AuditLogAction", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("AuditLogId") + .HasColumnType("uniqueidentifier") + .HasColumnName("AuditLogId"); + + b.Property("ExecutionDuration") + .HasColumnType("int") + .HasColumnName("ExecutionDuration"); + + b.Property("ExecutionTime") + .HasColumnType("datetime2") + .HasColumnName("ExecutionTime"); + + b.Property("ExtraProperties") + .HasColumnType("nvarchar(max)") + .HasColumnName("ExtraProperties"); + + b.Property("MethodName") + .HasMaxLength(128) + .HasColumnType("nvarchar(128)") + .HasColumnName("MethodName"); + + b.Property("Parameters") + .HasMaxLength(2000) + .HasColumnType("nvarchar(2000)") + .HasColumnName("Parameters"); + + b.Property("ServiceName") + .HasMaxLength(256) + .HasColumnType("nvarchar(256)") + .HasColumnName("ServiceName"); + + b.Property("TenantId") + .HasColumnType("uniqueidentifier") + .HasColumnName("TenantId"); + + b.HasKey("Id"); + + b.HasIndex("AuditLogId"); + + b.HasIndex("TenantId", "ServiceName", "MethodName", "ExecutionTime"); + + b.ToTable("AbpAuditLogActions"); + }); + + modelBuilder.Entity("Volo.Abp.AuditLogging.EntityChange", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("AuditLogId") + .HasColumnType("uniqueidentifier") + .HasColumnName("AuditLogId"); + + b.Property("ChangeTime") + .HasColumnType("datetime2") + .HasColumnName("ChangeTime"); + + b.Property("ChangeType") + .HasColumnType("tinyint") + .HasColumnName("ChangeType"); + + b.Property("EntityId") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("nvarchar(128)") + .HasColumnName("EntityId"); + + b.Property("EntityTenantId") + .HasColumnType("uniqueidentifier"); + + b.Property("EntityTypeFullName") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("nvarchar(128)") + .HasColumnName("EntityTypeFullName"); + + b.Property("ExtraProperties") + .HasColumnType("nvarchar(max)") + .HasColumnName("ExtraProperties"); + + b.Property("TenantId") + .HasColumnType("uniqueidentifier") + .HasColumnName("TenantId"); + + b.HasKey("Id"); + + b.HasIndex("AuditLogId"); + + b.HasIndex("TenantId", "EntityTypeFullName", "EntityId"); + + b.ToTable("AbpEntityChanges"); + }); + + modelBuilder.Entity("Volo.Abp.AuditLogging.EntityPropertyChange", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("EntityChangeId") + .HasColumnType("uniqueidentifier"); + + b.Property("NewValue") + .HasMaxLength(512) + .HasColumnType("nvarchar(512)") + .HasColumnName("NewValue"); + + b.Property("OriginalValue") + .HasMaxLength(512) + .HasColumnType("nvarchar(512)") + .HasColumnName("OriginalValue"); + + b.Property("PropertyName") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("nvarchar(128)") + .HasColumnName("PropertyName"); + + b.Property("PropertyTypeFullName") + .IsRequired() + .HasMaxLength(64) + .HasColumnType("nvarchar(64)") + .HasColumnName("PropertyTypeFullName"); + + b.Property("TenantId") + .HasColumnType("uniqueidentifier") + .HasColumnName("TenantId"); + + b.HasKey("Id"); + + b.HasIndex("EntityChangeId"); + + b.ToTable("AbpEntityPropertyChanges"); + }); + + modelBuilder.Entity("Volo.Abp.BlobStoring.Database.DatabaseBlob", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .HasMaxLength(40) + .HasColumnType("nvarchar(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("ContainerId") + .HasColumnType("uniqueidentifier"); + + b.Property("Content") + .HasMaxLength(2147483647) + .HasColumnType("varbinary(max)"); + + b.Property("ExtraProperties") + .HasColumnType("nvarchar(max)") + .HasColumnName("ExtraProperties"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.Property("TenantId") + .HasColumnType("uniqueidentifier") + .HasColumnName("TenantId"); + + b.HasKey("Id"); + + b.HasIndex("ContainerId"); + + b.HasIndex("TenantId", "ContainerId", "Name"); + + b.ToTable("AbpBlobs"); + }); + + modelBuilder.Entity("Volo.Abp.BlobStoring.Database.DatabaseBlobContainer", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .HasMaxLength(40) + .HasColumnType("nvarchar(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("ExtraProperties") + .HasColumnType("nvarchar(max)") + .HasColumnName("ExtraProperties"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("nvarchar(128)"); + + b.Property("TenantId") + .HasColumnType("uniqueidentifier") + .HasColumnName("TenantId"); + + b.HasKey("Id"); + + b.HasIndex("TenantId", "Name"); + + b.ToTable("AbpBlobContainers"); + }); + + modelBuilder.Entity("Volo.Abp.FeatureManagement.FeatureValue", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("nvarchar(128)"); + + b.Property("ProviderKey") + .HasMaxLength(64) + .HasColumnType("nvarchar(64)"); + + b.Property("ProviderName") + .HasMaxLength(64) + .HasColumnType("nvarchar(64)"); + + b.Property("Value") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("nvarchar(128)"); + + b.HasKey("Id"); + + b.HasIndex("Name", "ProviderName", "ProviderKey"); + + b.ToTable("AbpFeatureValues"); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityClaimType", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .HasMaxLength(40) + .HasColumnType("nvarchar(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("Description") + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.Property("ExtraProperties") + .HasColumnType("nvarchar(max)") + .HasColumnName("ExtraProperties"); + + b.Property("IsStatic") + .HasColumnType("bit"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.Property("Regex") + .HasMaxLength(512) + .HasColumnType("nvarchar(512)"); + + b.Property("RegexDescription") + .HasMaxLength(128) + .HasColumnType("nvarchar(128)"); + + b.Property("Required") + .HasColumnType("bit"); + + b.Property("ValueType") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.ToTable("AbpClaimTypes"); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityLinkUser", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("SourceTenantId") + .HasColumnType("uniqueidentifier"); + + b.Property("SourceUserId") + .HasColumnType("uniqueidentifier"); + + b.Property("TargetTenantId") + .HasColumnType("uniqueidentifier"); + + b.Property("TargetUserId") + .HasColumnType("uniqueidentifier"); + + b.HasKey("Id"); + + b.HasIndex("SourceUserId", "SourceTenantId", "TargetUserId", "TargetTenantId") + .IsUnique() + .HasFilter("[SourceTenantId] IS NOT NULL AND [TargetTenantId] IS NOT NULL"); + + b.ToTable("AbpLinkUsers"); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityRole", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .HasMaxLength(40) + .HasColumnType("nvarchar(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("ExtraProperties") + .HasColumnType("nvarchar(max)") + .HasColumnName("ExtraProperties"); + + b.Property("IsDefault") + .HasColumnType("bit") + .HasColumnName("IsDefault"); + + b.Property("IsPublic") + .HasColumnType("bit") + .HasColumnName("IsPublic"); + + b.Property("IsStatic") + .HasColumnType("bit") + .HasColumnName("IsStatic"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.Property("NormalizedName") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.Property("TenantId") + .HasColumnType("uniqueidentifier") + .HasColumnName("TenantId"); + + b.HasKey("Id"); + + b.HasIndex("NormalizedName"); + + b.ToTable("AbpRoles"); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityRoleClaim", b => + { + b.Property("Id") + .HasColumnType("uniqueidentifier"); + + b.Property("ClaimType") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.Property("ClaimValue") + .HasMaxLength(1024) + .HasColumnType("nvarchar(1024)"); + + b.Property("RoleId") + .HasColumnType("uniqueidentifier"); + + b.Property("TenantId") + .HasColumnType("uniqueidentifier") + .HasColumnName("TenantId"); + + b.HasKey("Id"); + + b.HasIndex("RoleId"); + + b.ToTable("AbpRoleClaims"); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentitySecurityLog", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("Action") + .HasMaxLength(96) + .HasColumnType("nvarchar(96)"); + + b.Property("ApplicationName") + .HasMaxLength(96) + .HasColumnType("nvarchar(96)"); + + b.Property("BrowserInfo") + .HasMaxLength(512) + .HasColumnType("nvarchar(512)"); + + b.Property("ClientId") + .HasMaxLength(64) + .HasColumnType("nvarchar(64)"); + + b.Property("ClientIpAddress") + .HasMaxLength(64) + .HasColumnType("nvarchar(64)"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .HasMaxLength(40) + .HasColumnType("nvarchar(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("CorrelationId") + .HasMaxLength(64) + .HasColumnType("nvarchar(64)"); + + b.Property("CreationTime") + .HasColumnType("datetime2"); + + b.Property("ExtraProperties") + .HasColumnType("nvarchar(max)") + .HasColumnName("ExtraProperties"); + + b.Property("Identity") + .HasMaxLength(96) + .HasColumnType("nvarchar(96)"); + + b.Property("TenantId") + .HasColumnType("uniqueidentifier") + .HasColumnName("TenantId"); + + b.Property("TenantName") + .HasMaxLength(64) + .HasColumnType("nvarchar(64)"); + + b.Property("UserId") + .HasColumnType("uniqueidentifier"); + + b.Property("UserName") + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.HasKey("Id"); + + b.HasIndex("TenantId", "Action"); + + b.HasIndex("TenantId", "ApplicationName"); + + b.HasIndex("TenantId", "Identity"); + + b.HasIndex("TenantId", "UserId"); + + b.ToTable("AbpSecurityLogs"); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityUser", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("AccessFailedCount") + .ValueGeneratedOnAdd() + .HasColumnType("int") + .HasDefaultValue(0) + .HasColumnName("AccessFailedCount"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .HasMaxLength(40) + .HasColumnType("nvarchar(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("CreationTime") + .HasColumnType("datetime2") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uniqueidentifier") + .HasColumnName("CreatorId"); + + b.Property("DeleterId") + .HasColumnType("uniqueidentifier") + .HasColumnName("DeleterId"); + + b.Property("DeletionTime") + .HasColumnType("datetime2") + .HasColumnName("DeletionTime"); + + b.Property("Email") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("nvarchar(256)") + .HasColumnName("Email"); + + b.Property("EmailConfirmed") + .ValueGeneratedOnAdd() + .HasColumnType("bit") + .HasDefaultValue(false) + .HasColumnName("EmailConfirmed"); + + b.Property("ExtraProperties") + .HasColumnType("nvarchar(max)") + .HasColumnName("ExtraProperties"); + + b.Property("IsDeleted") + .ValueGeneratedOnAdd() + .HasColumnType("bit") + .HasDefaultValue(false) + .HasColumnName("IsDeleted"); + + b.Property("IsExternal") + .ValueGeneratedOnAdd() + .HasColumnType("bit") + .HasDefaultValue(false) + .HasColumnName("IsExternal"); + + b.Property("LastModificationTime") + .HasColumnType("datetime2") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uniqueidentifier") + .HasColumnName("LastModifierId"); + + b.Property("LockoutEnabled") + .ValueGeneratedOnAdd() + .HasColumnType("bit") + .HasDefaultValue(false) + .HasColumnName("LockoutEnabled"); + + b.Property("LockoutEnd") + .HasColumnType("datetimeoffset"); + + b.Property("Name") + .HasMaxLength(64) + .HasColumnType("nvarchar(64)") + .HasColumnName("Name"); + + b.Property("NormalizedEmail") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("nvarchar(256)") + .HasColumnName("NormalizedEmail"); + + b.Property("NormalizedUserName") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("nvarchar(256)") + .HasColumnName("NormalizedUserName"); + + b.Property("PasswordHash") + .HasMaxLength(256) + .HasColumnType("nvarchar(256)") + .HasColumnName("PasswordHash"); + + b.Property("PhoneNumber") + .HasMaxLength(16) + .HasColumnType("nvarchar(16)") + .HasColumnName("PhoneNumber"); + + b.Property("PhoneNumberConfirmed") + .ValueGeneratedOnAdd() + .HasColumnType("bit") + .HasDefaultValue(false) + .HasColumnName("PhoneNumberConfirmed"); + + b.Property("SecurityStamp") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("nvarchar(256)") + .HasColumnName("SecurityStamp"); + + b.Property("Surname") + .HasMaxLength(64) + .HasColumnType("nvarchar(64)") + .HasColumnName("Surname"); + + b.Property("TenantId") + .HasColumnType("uniqueidentifier") + .HasColumnName("TenantId"); + + b.Property("TwoFactorEnabled") + .ValueGeneratedOnAdd() + .HasColumnType("bit") + .HasDefaultValue(false) + .HasColumnName("TwoFactorEnabled"); + + b.Property("UserName") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("nvarchar(256)") + .HasColumnName("UserName"); + + b.HasKey("Id"); + + b.HasIndex("Email"); + + b.HasIndex("NormalizedEmail"); + + b.HasIndex("NormalizedUserName"); + + b.HasIndex("UserName"); + + b.ToTable("AbpUsers"); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityUserClaim", b => + { + b.Property("Id") + .HasColumnType("uniqueidentifier"); + + b.Property("ClaimType") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.Property("ClaimValue") + .HasMaxLength(1024) + .HasColumnType("nvarchar(1024)"); + + b.Property("TenantId") + .HasColumnType("uniqueidentifier") + .HasColumnName("TenantId"); + + b.Property("UserId") + .HasColumnType("uniqueidentifier"); + + b.HasKey("Id"); + + b.HasIndex("UserId"); + + b.ToTable("AbpUserClaims"); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityUserLogin", b => + { + b.Property("UserId") + .HasColumnType("uniqueidentifier"); + + b.Property("LoginProvider") + .HasMaxLength(64) + .HasColumnType("nvarchar(64)"); + + b.Property("ProviderDisplayName") + .HasMaxLength(128) + .HasColumnType("nvarchar(128)"); + + b.Property("ProviderKey") + .IsRequired() + .HasMaxLength(196) + .HasColumnType("nvarchar(196)"); + + b.Property("TenantId") + .HasColumnType("uniqueidentifier") + .HasColumnName("TenantId"); + + b.HasKey("UserId", "LoginProvider"); + + b.HasIndex("LoginProvider", "ProviderKey"); + + b.ToTable("AbpUserLogins"); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityUserOrganizationUnit", b => + { + b.Property("OrganizationUnitId") + .HasColumnType("uniqueidentifier"); + + b.Property("UserId") + .HasColumnType("uniqueidentifier"); + + b.Property("CreationTime") + .HasColumnType("datetime2") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uniqueidentifier") + .HasColumnName("CreatorId"); + + b.Property("TenantId") + .HasColumnType("uniqueidentifier") + .HasColumnName("TenantId"); + + b.HasKey("OrganizationUnitId", "UserId"); + + b.HasIndex("UserId", "OrganizationUnitId"); + + b.ToTable("AbpUserOrganizationUnits"); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityUserRole", b => + { + b.Property("UserId") + .HasColumnType("uniqueidentifier"); + + b.Property("RoleId") + .HasColumnType("uniqueidentifier"); + + b.Property("TenantId") + .HasColumnType("uniqueidentifier") + .HasColumnName("TenantId"); + + b.HasKey("UserId", "RoleId"); + + b.HasIndex("RoleId", "UserId"); + + b.ToTable("AbpUserRoles"); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityUserToken", b => + { + b.Property("UserId") + .HasColumnType("uniqueidentifier"); + + b.Property("LoginProvider") + .HasMaxLength(64) + .HasColumnType("nvarchar(64)"); + + b.Property("Name") + .HasMaxLength(128) + .HasColumnType("nvarchar(128)"); + + b.Property("TenantId") + .HasColumnType("uniqueidentifier") + .HasColumnName("TenantId"); + + b.Property("Value") + .HasColumnType("nvarchar(max)"); + + b.HasKey("UserId", "LoginProvider", "Name"); + + b.ToTable("AbpUserTokens"); + }); + + modelBuilder.Entity("Volo.Abp.Identity.OrganizationUnit", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("Code") + .IsRequired() + .HasMaxLength(95) + .HasColumnType("nvarchar(95)") + .HasColumnName("Code"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .HasMaxLength(40) + .HasColumnType("nvarchar(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("CreationTime") + .HasColumnType("datetime2") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uniqueidentifier") + .HasColumnName("CreatorId"); + + b.Property("DeleterId") + .HasColumnType("uniqueidentifier") + .HasColumnName("DeleterId"); + + b.Property("DeletionTime") + .HasColumnType("datetime2") + .HasColumnName("DeletionTime"); + + b.Property("DisplayName") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("nvarchar(128)") + .HasColumnName("DisplayName"); + + b.Property("ExtraProperties") + .HasColumnType("nvarchar(max)") + .HasColumnName("ExtraProperties"); + + b.Property("IsDeleted") + .ValueGeneratedOnAdd() + .HasColumnType("bit") + .HasDefaultValue(false) + .HasColumnName("IsDeleted"); + + b.Property("LastModificationTime") + .HasColumnType("datetime2") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uniqueidentifier") + .HasColumnName("LastModifierId"); + + b.Property("ParentId") + .HasColumnType("uniqueidentifier"); + + b.Property("TenantId") + .HasColumnType("uniqueidentifier") + .HasColumnName("TenantId"); + + b.HasKey("Id"); + + b.HasIndex("Code"); + + b.HasIndex("ParentId"); + + b.ToTable("AbpOrganizationUnits"); + }); + + modelBuilder.Entity("Volo.Abp.Identity.OrganizationUnitRole", b => + { + b.Property("OrganizationUnitId") + .HasColumnType("uniqueidentifier"); + + b.Property("RoleId") + .HasColumnType("uniqueidentifier"); + + b.Property("CreationTime") + .HasColumnType("datetime2") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uniqueidentifier") + .HasColumnName("CreatorId"); + + b.Property("TenantId") + .HasColumnType("uniqueidentifier") + .HasColumnName("TenantId"); + + b.HasKey("OrganizationUnitId", "RoleId"); + + b.HasIndex("RoleId", "OrganizationUnitId"); + + b.ToTable("AbpOrganizationUnitRoles"); + }); + + modelBuilder.Entity("Volo.Abp.PermissionManagement.PermissionGrant", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("nvarchar(128)"); + + b.Property("ProviderKey") + .IsRequired() + .HasMaxLength(64) + .HasColumnType("nvarchar(64)"); + + b.Property("ProviderName") + .IsRequired() + .HasMaxLength(64) + .HasColumnType("nvarchar(64)"); + + b.Property("TenantId") + .HasColumnType("uniqueidentifier") + .HasColumnName("TenantId"); + + b.HasKey("Id"); + + b.HasIndex("Name", "ProviderName", "ProviderKey"); + + b.ToTable("AbpPermissionGrants"); + }); + + modelBuilder.Entity("Volo.Abp.SettingManagement.Setting", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("nvarchar(128)"); + + b.Property("ProviderKey") + .HasMaxLength(64) + .HasColumnType("nvarchar(64)"); + + b.Property("ProviderName") + .HasMaxLength(64) + .HasColumnType("nvarchar(64)"); + + b.Property("Value") + .IsRequired() + .HasMaxLength(2048) + .HasColumnType("nvarchar(2048)"); + + b.HasKey("Id"); + + b.HasIndex("Name", "ProviderName", "ProviderKey"); + + b.ToTable("AbpSettings"); + }); + + modelBuilder.Entity("Volo.Abp.TenantManagement.Tenant", 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("CreatorId") + .HasColumnType("uniqueidentifier") + .HasColumnName("CreatorId"); + + b.Property("DeleterId") + .HasColumnType("uniqueidentifier") + .HasColumnName("DeleterId"); + + b.Property("DeletionTime") + .HasColumnType("datetime2") + .HasColumnName("DeletionTime"); + + b.Property("ExtraProperties") + .HasColumnType("nvarchar(max)") + .HasColumnName("ExtraProperties"); + + b.Property("IsDeleted") + .ValueGeneratedOnAdd() + .HasColumnType("bit") + .HasDefaultValue(false) + .HasColumnName("IsDeleted"); + + b.Property("LastModificationTime") + .HasColumnType("datetime2") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uniqueidentifier") + .HasColumnName("LastModifierId"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(64) + .HasColumnType("nvarchar(64)"); + + b.HasKey("Id"); + + b.HasIndex("Name"); + + b.ToTable("AbpTenants"); + }); + + modelBuilder.Entity("Volo.Abp.TenantManagement.TenantConnectionString", b => + { + b.Property("TenantId") + .HasColumnType("uniqueidentifier"); + + b.Property("Name") + .HasMaxLength(64) + .HasColumnType("nvarchar(64)"); + + b.Property("Value") + .IsRequired() + .HasMaxLength(1024) + .HasColumnType("nvarchar(1024)"); + + b.HasKey("TenantId", "Name"); + + b.ToTable("AbpTenantConnectionStrings"); + }); + + modelBuilder.Entity("Volo.CmsKit.Blogs.Blog", 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("CreatorId") + .HasColumnType("uniqueidentifier") + .HasColumnName("CreatorId"); + + b.Property("DeleterId") + .HasColumnType("uniqueidentifier") + .HasColumnName("DeleterId"); + + b.Property("DeletionTime") + .HasColumnType("datetime2") + .HasColumnName("DeletionTime"); + + b.Property("ExtraProperties") + .HasColumnType("nvarchar(max)") + .HasColumnName("ExtraProperties"); + + b.Property("IsDeleted") + .ValueGeneratedOnAdd() + .HasColumnType("bit") + .HasDefaultValue(false) + .HasColumnName("IsDeleted"); + + b.Property("LastModificationTime") + .HasColumnType("datetime2") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uniqueidentifier") + .HasColumnName("LastModifierId"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(64) + .HasColumnType("nvarchar(64)"); + + b.Property("Slug") + .IsRequired() + .HasMaxLength(64) + .HasColumnType("nvarchar(64)"); + + b.Property("TenantId") + .HasColumnType("uniqueidentifier") + .HasColumnName("TenantId"); + + b.HasKey("Id"); + + b.ToTable("CmsBlogs"); + }); + + modelBuilder.Entity("Volo.CmsKit.Blogs.BlogFeature", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("BlogId") + .HasColumnType("uniqueidentifier"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .HasMaxLength(40) + .HasColumnType("nvarchar(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("CreationTime") + .HasColumnType("datetime2") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uniqueidentifier") + .HasColumnName("CreatorId"); + + b.Property("DeleterId") + .HasColumnType("uniqueidentifier") + .HasColumnName("DeleterId"); + + b.Property("DeletionTime") + .HasColumnType("datetime2") + .HasColumnName("DeletionTime"); + + b.Property("ExtraProperties") + .HasColumnType("nvarchar(max)") + .HasColumnName("ExtraProperties"); + + b.Property("FeatureName") + .IsRequired() + .HasMaxLength(64) + .HasColumnType("nvarchar(64)"); + + b.Property("IsDeleted") + .ValueGeneratedOnAdd() + .HasColumnType("bit") + .HasDefaultValue(false) + .HasColumnName("IsDeleted"); + + b.Property("IsEnabled") + .HasColumnType("bit"); + + b.Property("LastModificationTime") + .HasColumnType("datetime2") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uniqueidentifier") + .HasColumnName("LastModifierId"); + + b.HasKey("Id"); + + b.ToTable("CmsBlogFeatures"); + }); + + modelBuilder.Entity("Volo.CmsKit.Blogs.BlogPost", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("AuthorId") + .HasColumnType("uniqueidentifier"); + + b.Property("BlogId") + .HasColumnType("uniqueidentifier"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .HasMaxLength(40) + .HasColumnType("nvarchar(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("CreationTime") + .HasColumnType("datetime2") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uniqueidentifier") + .HasColumnName("CreatorId"); + + b.Property("DeleterId") + .HasColumnType("uniqueidentifier") + .HasColumnName("DeleterId"); + + b.Property("DeletionTime") + .HasColumnType("datetime2") + .HasColumnName("DeletionTime"); + + b.Property("ExtraProperties") + .HasColumnType("nvarchar(max)") + .HasColumnName("ExtraProperties"); + + b.Property("IsDeleted") + .ValueGeneratedOnAdd() + .HasColumnType("bit") + .HasDefaultValue(false) + .HasColumnName("IsDeleted"); + + b.Property("LastModificationTime") + .HasColumnType("datetime2") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uniqueidentifier") + .HasColumnName("LastModifierId"); + + b.Property("ShortDescription") + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.Property("Slug") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.Property("TenantId") + .HasColumnType("uniqueidentifier") + .HasColumnName("TenantId"); + + b.Property("Title") + .IsRequired() + .HasMaxLength(64) + .HasColumnType("nvarchar(64)"); + + b.HasKey("Id"); + + b.HasIndex("AuthorId"); + + b.HasIndex("Slug", "BlogId"); + + b.ToTable("CmsBlogPosts"); + }); + + modelBuilder.Entity("Volo.CmsKit.Comments.Comment", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("CreationTime") + .HasColumnType("datetime2") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uniqueidentifier") + .HasColumnName("CreatorId"); + + b.Property("EntityId") + .IsRequired() + .HasMaxLength(64) + .HasColumnType("nvarchar(64)"); + + b.Property("EntityType") + .IsRequired() + .HasMaxLength(64) + .HasColumnType("nvarchar(64)"); + + b.Property("RepliedCommentId") + .HasColumnType("uniqueidentifier"); + + b.Property("TenantId") + .HasColumnType("uniqueidentifier") + .HasColumnName("TenantId"); + + b.Property("Text") + .IsRequired() + .HasMaxLength(512) + .HasColumnType("nvarchar(512)"); + + b.HasKey("Id"); + + b.HasIndex("TenantId", "RepliedCommentId"); + + b.HasIndex("TenantId", "EntityType", "EntityId"); + + b.ToTable("CmsComments"); + }); + + modelBuilder.Entity("Volo.CmsKit.Contents.Content", 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("CreatorId") + .HasColumnType("uniqueidentifier") + .HasColumnName("CreatorId"); + + b.Property("DeleterId") + .HasColumnType("uniqueidentifier") + .HasColumnName("DeleterId"); + + b.Property("DeletionTime") + .HasColumnType("datetime2") + .HasColumnName("DeletionTime"); + + b.Property("EntityId") + .IsRequired() + .HasMaxLength(64) + .HasColumnType("nvarchar(64)"); + + b.Property("EntityType") + .IsRequired() + .HasMaxLength(64) + .HasColumnType("nvarchar(64)"); + + b.Property("ExtraProperties") + .HasColumnType("nvarchar(max)") + .HasColumnName("ExtraProperties"); + + b.Property("IsDeleted") + .ValueGeneratedOnAdd() + .HasColumnType("bit") + .HasDefaultValue(false) + .HasColumnName("IsDeleted"); + + b.Property("LastModificationTime") + .HasColumnType("datetime2") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uniqueidentifier") + .HasColumnName("LastModifierId"); + + b.Property("TenantId") + .HasColumnType("uniqueidentifier") + .HasColumnName("TenantId"); + + b.Property("Value") + .IsRequired() + .HasMaxLength(2147483647) + .HasColumnType("nvarchar(max)"); + + b.HasKey("Id"); + + b.HasIndex("TenantId", "EntityType", "EntityId"); + + b.ToTable("CmsContents"); + }); + + modelBuilder.Entity("Volo.CmsKit.MediaDescriptors.MediaDescriptor", 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("CreatorId") + .HasColumnType("uniqueidentifier") + .HasColumnName("CreatorId"); + + b.Property("DeleterId") + .HasColumnType("uniqueidentifier") + .HasColumnName("DeleterId"); + + b.Property("DeletionTime") + .HasColumnType("datetime2") + .HasColumnName("DeletionTime"); + + b.Property("ExtraProperties") + .HasColumnType("nvarchar(max)") + .HasColumnName("ExtraProperties"); + + b.Property("IsDeleted") + .ValueGeneratedOnAdd() + .HasColumnType("bit") + .HasDefaultValue(false) + .HasColumnName("IsDeleted"); + + b.Property("LastModificationTime") + .HasColumnType("datetime2") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uniqueidentifier") + .HasColumnName("LastModifierId"); + + b.Property("MimeType") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("nvarchar(128)"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("nvarchar(255)"); + + b.Property("Size") + .HasMaxLength(2147483647) + .HasColumnType("bigint"); + + b.Property("TenantId") + .HasColumnType("uniqueidentifier") + .HasColumnName("TenantId"); + + b.HasKey("Id"); + + b.ToTable("CmsMediaDescriptors"); + }); + + modelBuilder.Entity("Volo.CmsKit.Pages.Page", 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("CreatorId") + .HasColumnType("uniqueidentifier") + .HasColumnName("CreatorId"); + + b.Property("DeleterId") + .HasColumnType("uniqueidentifier") + .HasColumnName("DeleterId"); + + b.Property("DeletionTime") + .HasColumnType("datetime2") + .HasColumnName("DeletionTime"); + + b.Property("ExtraProperties") + .HasColumnType("nvarchar(max)") + .HasColumnName("ExtraProperties"); + + b.Property("IsDeleted") + .ValueGeneratedOnAdd() + .HasColumnType("bit") + .HasDefaultValue(false) + .HasColumnName("IsDeleted"); + + b.Property("LastModificationTime") + .HasColumnType("datetime2") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uniqueidentifier") + .HasColumnName("LastModifierId"); + + b.Property("Slug") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.Property("TenantId") + .HasColumnType("uniqueidentifier") + .HasColumnName("TenantId"); + + b.Property("Title") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.HasKey("Id"); + + b.HasIndex("TenantId", "Slug"); + + b.ToTable("CmsPages"); + }); + + modelBuilder.Entity("Volo.CmsKit.Ratings.Rating", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("CreationTime") + .HasColumnType("datetime2") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uniqueidentifier") + .HasColumnName("CreatorId"); + + b.Property("EntityId") + .IsRequired() + .HasMaxLength(64) + .HasColumnType("nvarchar(64)"); + + b.Property("EntityType") + .IsRequired() + .HasMaxLength(64) + .HasColumnType("nvarchar(64)"); + + b.Property("StarCount") + .HasColumnType("smallint"); + + b.Property("TenantId") + .HasColumnType("uniqueidentifier"); + + b.HasKey("Id"); + + b.HasIndex("TenantId", "EntityType", "EntityId", "CreatorId"); + + b.ToTable("CmsRatings"); + }); + + modelBuilder.Entity("Volo.CmsKit.Reactions.UserReaction", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("CreationTime") + .HasColumnType("datetime2") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uniqueidentifier") + .HasColumnName("CreatorId"); + + b.Property("EntityId") + .IsRequired() + .HasMaxLength(64) + .HasColumnType("nvarchar(64)"); + + b.Property("EntityType") + .IsRequired() + .HasMaxLength(64) + .HasColumnType("nvarchar(64)"); + + b.Property("ReactionName") + .IsRequired() + .HasMaxLength(32) + .HasColumnType("nvarchar(32)"); + + b.Property("TenantId") + .HasColumnType("uniqueidentifier") + .HasColumnName("TenantId"); + + b.HasKey("Id"); + + b.HasIndex("TenantId", "EntityType", "EntityId", "ReactionName"); + + b.HasIndex("TenantId", "CreatorId", "EntityType", "EntityId", "ReactionName"); + + b.ToTable("CmsUserReactions"); + }); + + modelBuilder.Entity("Volo.CmsKit.Tags.EntityTag", b => + { + b.Property("EntityId") + .HasColumnType("nvarchar(450)"); + + b.Property("TagId") + .HasColumnType("uniqueidentifier"); + + b.Property("TenantId") + .HasColumnType("uniqueidentifier") + .HasColumnName("TenantId"); + + b.HasKey("EntityId", "TagId"); + + b.HasIndex("TenantId", "EntityId", "TagId"); + + b.ToTable("CmsEntityTags"); + }); + + modelBuilder.Entity("Volo.CmsKit.Tags.Tag", 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("CreatorId") + .HasColumnType("uniqueidentifier") + .HasColumnName("CreatorId"); + + b.Property("DeleterId") + .HasColumnType("uniqueidentifier") + .HasColumnName("DeleterId"); + + b.Property("DeletionTime") + .HasColumnType("datetime2") + .HasColumnName("DeletionTime"); + + b.Property("EntityType") + .IsRequired() + .HasMaxLength(64) + .HasColumnType("nvarchar(64)"); + + b.Property("ExtraProperties") + .HasColumnType("nvarchar(max)") + .HasColumnName("ExtraProperties"); + + b.Property("IsDeleted") + .ValueGeneratedOnAdd() + .HasColumnType("bit") + .HasDefaultValue(false) + .HasColumnName("IsDeleted"); + + b.Property("LastModificationTime") + .HasColumnType("datetime2") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uniqueidentifier") + .HasColumnName("LastModifierId"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(32) + .HasColumnType("nvarchar(32)"); + + b.Property("TenantId") + .HasColumnType("uniqueidentifier") + .HasColumnName("TenantId"); + + b.HasKey("Id"); + + b.HasIndex("TenantId", "Name"); + + b.ToTable("CmsTags"); + }); + + modelBuilder.Entity("Volo.CmsKit.Users.CmsUser", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .HasMaxLength(40) + .HasColumnType("nvarchar(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("Email") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("nvarchar(256)") + .HasColumnName("Email"); + + b.Property("EmailConfirmed") + .ValueGeneratedOnAdd() + .HasColumnType("bit") + .HasDefaultValue(false) + .HasColumnName("EmailConfirmed"); + + b.Property("ExtraProperties") + .HasColumnType("nvarchar(max)") + .HasColumnName("ExtraProperties"); + + b.Property("Name") + .HasMaxLength(64) + .HasColumnType("nvarchar(64)") + .HasColumnName("Name"); + + b.Property("PhoneNumber") + .HasMaxLength(16) + .HasColumnType("nvarchar(16)") + .HasColumnName("PhoneNumber"); + + b.Property("PhoneNumberConfirmed") + .ValueGeneratedOnAdd() + .HasColumnType("bit") + .HasDefaultValue(false) + .HasColumnName("PhoneNumberConfirmed"); + + b.Property("Surname") + .HasMaxLength(64) + .HasColumnType("nvarchar(64)") + .HasColumnName("Surname"); + + b.Property("TenantId") + .HasColumnType("uniqueidentifier") + .HasColumnName("TenantId"); + + b.Property("UserName") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("nvarchar(256)") + .HasColumnName("UserName"); + + b.HasKey("Id"); + + b.HasIndex("TenantId", "Email"); + + b.HasIndex("TenantId", "UserName"); + + b.ToTable("CmsUsers"); + }); + + modelBuilder.Entity("Volo.Abp.AuditLogging.AuditLogAction", b => + { + b.HasOne("Volo.Abp.AuditLogging.AuditLog", null) + .WithMany("Actions") + .HasForeignKey("AuditLogId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Volo.Abp.AuditLogging.EntityChange", b => + { + b.HasOne("Volo.Abp.AuditLogging.AuditLog", null) + .WithMany("EntityChanges") + .HasForeignKey("AuditLogId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Volo.Abp.AuditLogging.EntityPropertyChange", b => + { + b.HasOne("Volo.Abp.AuditLogging.EntityChange", null) + .WithMany("PropertyChanges") + .HasForeignKey("EntityChangeId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Volo.Abp.BlobStoring.Database.DatabaseBlob", b => + { + b.HasOne("Volo.Abp.BlobStoring.Database.DatabaseBlobContainer", null) + .WithMany() + .HasForeignKey("ContainerId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityRoleClaim", b => + { + b.HasOne("Volo.Abp.Identity.IdentityRole", null) + .WithMany("Claims") + .HasForeignKey("RoleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityUserClaim", b => + { + b.HasOne("Volo.Abp.Identity.IdentityUser", null) + .WithMany("Claims") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityUserLogin", b => + { + b.HasOne("Volo.Abp.Identity.IdentityUser", null) + .WithMany("Logins") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityUserOrganizationUnit", b => + { + b.HasOne("Volo.Abp.Identity.OrganizationUnit", null) + .WithMany() + .HasForeignKey("OrganizationUnitId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Volo.Abp.Identity.IdentityUser", null) + .WithMany("OrganizationUnits") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityUserRole", b => + { + b.HasOne("Volo.Abp.Identity.IdentityRole", null) + .WithMany() + .HasForeignKey("RoleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Volo.Abp.Identity.IdentityUser", null) + .WithMany("Roles") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityUserToken", b => + { + b.HasOne("Volo.Abp.Identity.IdentityUser", null) + .WithMany("Tokens") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Volo.Abp.Identity.OrganizationUnit", b => + { + b.HasOne("Volo.Abp.Identity.OrganizationUnit", null) + .WithMany() + .HasForeignKey("ParentId"); + }); + + modelBuilder.Entity("Volo.Abp.Identity.OrganizationUnitRole", b => + { + b.HasOne("Volo.Abp.Identity.OrganizationUnit", null) + .WithMany("Roles") + .HasForeignKey("OrganizationUnitId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Volo.Abp.Identity.IdentityRole", null) + .WithMany() + .HasForeignKey("RoleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Volo.Abp.TenantManagement.TenantConnectionString", b => + { + b.HasOne("Volo.Abp.TenantManagement.Tenant", null) + .WithMany("ConnectionStrings") + .HasForeignKey("TenantId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Volo.CmsKit.Blogs.BlogPost", b => + { + b.HasOne("Volo.CmsKit.Users.CmsUser", "Author") + .WithMany() + .HasForeignKey("AuthorId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Author"); + }); + + modelBuilder.Entity("Volo.Abp.AuditLogging.AuditLog", b => + { + b.Navigation("Actions"); + + b.Navigation("EntityChanges"); + }); + + modelBuilder.Entity("Volo.Abp.AuditLogging.EntityChange", b => + { + b.Navigation("PropertyChanges"); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityRole", b => + { + b.Navigation("Claims"); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityUser", b => + { + b.Navigation("Claims"); + + b.Navigation("Logins"); + + b.Navigation("OrganizationUnits"); + + b.Navigation("Roles"); + + b.Navigation("Tokens"); + }); + + modelBuilder.Entity("Volo.Abp.Identity.OrganizationUnit", b => + { + b.Navigation("Roles"); + }); + + modelBuilder.Entity("Volo.Abp.TenantManagement.Tenant", b => + { + b.Navigation("ConnectionStrings"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/modules/cms-kit/host/Volo.CmsKit.Web.Unified/Migrations/20210226112040_BlogPost_Author.cs b/modules/cms-kit/host/Volo.CmsKit.Web.Unified/Migrations/20210226112040_BlogPost_Author.cs new file mode 100644 index 0000000000..48186c4918 --- /dev/null +++ b/modules/cms-kit/host/Volo.CmsKit.Web.Unified/Migrations/20210226112040_BlogPost_Author.cs @@ -0,0 +1,109 @@ +using System; +using Microsoft.EntityFrameworkCore.Migrations; + +namespace Volo.CmsKit.Migrations +{ + public partial class BlogPost_Author : Migration + { + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropForeignKey( + name: "FK_CmsBlogPosts_CmsUsers_CreatorId", + table: "CmsBlogPosts"); + + migrationBuilder.DropForeignKey( + name: "FK_CmsBlogPosts_CmsUsers_DeleterId", + table: "CmsBlogPosts"); + + migrationBuilder.DropForeignKey( + name: "FK_CmsBlogPosts_CmsUsers_LastModifierId", + table: "CmsBlogPosts"); + + migrationBuilder.DropIndex( + name: "IX_CmsBlogPosts_CreatorId", + table: "CmsBlogPosts"); + + migrationBuilder.DropIndex( + name: "IX_CmsBlogPosts_DeleterId", + table: "CmsBlogPosts"); + + migrationBuilder.DropIndex( + name: "IX_CmsBlogPosts_LastModifierId", + table: "CmsBlogPosts"); + + migrationBuilder.AddColumn( + name: "AuthorId", + table: "CmsBlogPosts", + type: "uniqueidentifier", + nullable: false, + defaultValue: new Guid("00000000-0000-0000-0000-000000000000")); + + migrationBuilder.CreateIndex( + name: "IX_CmsBlogPosts_AuthorId", + table: "CmsBlogPosts", + column: "AuthorId"); + + migrationBuilder.AddForeignKey( + name: "FK_CmsBlogPosts_CmsUsers_AuthorId", + table: "CmsBlogPosts", + column: "AuthorId", + principalTable: "CmsUsers", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + } + + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropForeignKey( + name: "FK_CmsBlogPosts_CmsUsers_AuthorId", + table: "CmsBlogPosts"); + + migrationBuilder.DropIndex( + name: "IX_CmsBlogPosts_AuthorId", + table: "CmsBlogPosts"); + + migrationBuilder.DropColumn( + name: "AuthorId", + table: "CmsBlogPosts"); + + migrationBuilder.CreateIndex( + name: "IX_CmsBlogPosts_CreatorId", + table: "CmsBlogPosts", + column: "CreatorId"); + + migrationBuilder.CreateIndex( + name: "IX_CmsBlogPosts_DeleterId", + table: "CmsBlogPosts", + column: "DeleterId"); + + migrationBuilder.CreateIndex( + name: "IX_CmsBlogPosts_LastModifierId", + table: "CmsBlogPosts", + column: "LastModifierId"); + + migrationBuilder.AddForeignKey( + name: "FK_CmsBlogPosts_CmsUsers_CreatorId", + table: "CmsBlogPosts", + column: "CreatorId", + principalTable: "CmsUsers", + principalColumn: "Id", + onDelete: ReferentialAction.Restrict); + + migrationBuilder.AddForeignKey( + name: "FK_CmsBlogPosts_CmsUsers_DeleterId", + table: "CmsBlogPosts", + column: "DeleterId", + principalTable: "CmsUsers", + principalColumn: "Id", + onDelete: ReferentialAction.Restrict); + + migrationBuilder.AddForeignKey( + name: "FK_CmsBlogPosts_CmsUsers_LastModifierId", + table: "CmsBlogPosts", + column: "LastModifierId", + principalTable: "CmsUsers", + principalColumn: "Id", + onDelete: ReferentialAction.Restrict); + } + } +} diff --git a/modules/cms-kit/host/Volo.CmsKit.Web.Unified/Migrations/20210302064229_Added_EntityType_to_Media.Designer.cs b/modules/cms-kit/host/Volo.CmsKit.Web.Unified/Migrations/20210302064229_Added_EntityType_to_Media.Designer.cs new file mode 100644 index 0000000000..d291705365 --- /dev/null +++ b/modules/cms-kit/host/Volo.CmsKit.Web.Unified/Migrations/20210302064229_Added_EntityType_to_Media.Designer.cs @@ -0,0 +1,2012 @@ +// +using System; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Metadata; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; +using Volo.Abp.EntityFrameworkCore; +using Volo.CmsKit.EntityFrameworkCore; + +namespace Volo.CmsKit.Migrations +{ + [DbContext(typeof(UnifiedDbContext))] + [Migration("20210302064229_Added_EntityType_to_Media")] + partial class Added_EntityType_to_Media + { + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("_Abp_DatabaseProvider", EfCoreDatabaseProvider.SqlServer) + .HasAnnotation("Relational:MaxIdentifierLength", 128) + .HasAnnotation("ProductVersion", "5.0.3") + .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); + + modelBuilder.Entity("Volo.Abp.AuditLogging.AuditLog", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("ApplicationName") + .HasMaxLength(96) + .HasColumnType("nvarchar(96)") + .HasColumnName("ApplicationName"); + + b.Property("BrowserInfo") + .HasMaxLength(512) + .HasColumnType("nvarchar(512)") + .HasColumnName("BrowserInfo"); + + b.Property("ClientId") + .HasMaxLength(64) + .HasColumnType("nvarchar(64)") + .HasColumnName("ClientId"); + + b.Property("ClientIpAddress") + .HasMaxLength(64) + .HasColumnType("nvarchar(64)") + .HasColumnName("ClientIpAddress"); + + b.Property("ClientName") + .HasMaxLength(128) + .HasColumnType("nvarchar(128)") + .HasColumnName("ClientName"); + + b.Property("Comments") + .HasMaxLength(256) + .HasColumnType("nvarchar(256)") + .HasColumnName("Comments"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .HasMaxLength(40) + .HasColumnType("nvarchar(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("CorrelationId") + .HasMaxLength(64) + .HasColumnType("nvarchar(64)") + .HasColumnName("CorrelationId"); + + b.Property("Exceptions") + .HasMaxLength(4000) + .HasColumnType("nvarchar(4000)") + .HasColumnName("Exceptions"); + + b.Property("ExecutionDuration") + .HasColumnType("int") + .HasColumnName("ExecutionDuration"); + + b.Property("ExecutionTime") + .HasColumnType("datetime2"); + + b.Property("ExtraProperties") + .HasColumnType("nvarchar(max)") + .HasColumnName("ExtraProperties"); + + b.Property("HttpMethod") + .HasMaxLength(16) + .HasColumnType("nvarchar(16)") + .HasColumnName("HttpMethod"); + + b.Property("HttpStatusCode") + .HasColumnType("int") + .HasColumnName("HttpStatusCode"); + + b.Property("ImpersonatorTenantId") + .HasColumnType("uniqueidentifier") + .HasColumnName("ImpersonatorTenantId"); + + b.Property("ImpersonatorUserId") + .HasColumnType("uniqueidentifier") + .HasColumnName("ImpersonatorUserId"); + + b.Property("TenantId") + .HasColumnType("uniqueidentifier") + .HasColumnName("TenantId"); + + b.Property("TenantName") + .HasColumnType("nvarchar(max)"); + + b.Property("Url") + .HasMaxLength(256) + .HasColumnType("nvarchar(256)") + .HasColumnName("Url"); + + b.Property("UserId") + .HasColumnType("uniqueidentifier") + .HasColumnName("UserId"); + + b.Property("UserName") + .HasMaxLength(256) + .HasColumnType("nvarchar(256)") + .HasColumnName("UserName"); + + b.HasKey("Id"); + + b.HasIndex("TenantId", "ExecutionTime"); + + b.HasIndex("TenantId", "UserId", "ExecutionTime"); + + b.ToTable("AbpAuditLogs"); + }); + + modelBuilder.Entity("Volo.Abp.AuditLogging.AuditLogAction", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("AuditLogId") + .HasColumnType("uniqueidentifier") + .HasColumnName("AuditLogId"); + + b.Property("ExecutionDuration") + .HasColumnType("int") + .HasColumnName("ExecutionDuration"); + + b.Property("ExecutionTime") + .HasColumnType("datetime2") + .HasColumnName("ExecutionTime"); + + b.Property("ExtraProperties") + .HasColumnType("nvarchar(max)") + .HasColumnName("ExtraProperties"); + + b.Property("MethodName") + .HasMaxLength(128) + .HasColumnType("nvarchar(128)") + .HasColumnName("MethodName"); + + b.Property("Parameters") + .HasMaxLength(2000) + .HasColumnType("nvarchar(2000)") + .HasColumnName("Parameters"); + + b.Property("ServiceName") + .HasMaxLength(256) + .HasColumnType("nvarchar(256)") + .HasColumnName("ServiceName"); + + b.Property("TenantId") + .HasColumnType("uniqueidentifier") + .HasColumnName("TenantId"); + + b.HasKey("Id"); + + b.HasIndex("AuditLogId"); + + b.HasIndex("TenantId", "ServiceName", "MethodName", "ExecutionTime"); + + b.ToTable("AbpAuditLogActions"); + }); + + modelBuilder.Entity("Volo.Abp.AuditLogging.EntityChange", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("AuditLogId") + .HasColumnType("uniqueidentifier") + .HasColumnName("AuditLogId"); + + b.Property("ChangeTime") + .HasColumnType("datetime2") + .HasColumnName("ChangeTime"); + + b.Property("ChangeType") + .HasColumnType("tinyint") + .HasColumnName("ChangeType"); + + b.Property("EntityId") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("nvarchar(128)") + .HasColumnName("EntityId"); + + b.Property("EntityTenantId") + .HasColumnType("uniqueidentifier"); + + b.Property("EntityTypeFullName") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("nvarchar(128)") + .HasColumnName("EntityTypeFullName"); + + b.Property("ExtraProperties") + .HasColumnType("nvarchar(max)") + .HasColumnName("ExtraProperties"); + + b.Property("TenantId") + .HasColumnType("uniqueidentifier") + .HasColumnName("TenantId"); + + b.HasKey("Id"); + + b.HasIndex("AuditLogId"); + + b.HasIndex("TenantId", "EntityTypeFullName", "EntityId"); + + b.ToTable("AbpEntityChanges"); + }); + + modelBuilder.Entity("Volo.Abp.AuditLogging.EntityPropertyChange", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("EntityChangeId") + .HasColumnType("uniqueidentifier"); + + b.Property("NewValue") + .HasMaxLength(512) + .HasColumnType("nvarchar(512)") + .HasColumnName("NewValue"); + + b.Property("OriginalValue") + .HasMaxLength(512) + .HasColumnType("nvarchar(512)") + .HasColumnName("OriginalValue"); + + b.Property("PropertyName") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("nvarchar(128)") + .HasColumnName("PropertyName"); + + b.Property("PropertyTypeFullName") + .IsRequired() + .HasMaxLength(64) + .HasColumnType("nvarchar(64)") + .HasColumnName("PropertyTypeFullName"); + + b.Property("TenantId") + .HasColumnType("uniqueidentifier") + .HasColumnName("TenantId"); + + b.HasKey("Id"); + + b.HasIndex("EntityChangeId"); + + b.ToTable("AbpEntityPropertyChanges"); + }); + + modelBuilder.Entity("Volo.Abp.BlobStoring.Database.DatabaseBlob", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .HasMaxLength(40) + .HasColumnType("nvarchar(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("ContainerId") + .HasColumnType("uniqueidentifier"); + + b.Property("Content") + .HasMaxLength(2147483647) + .HasColumnType("varbinary(max)"); + + b.Property("ExtraProperties") + .HasColumnType("nvarchar(max)") + .HasColumnName("ExtraProperties"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.Property("TenantId") + .HasColumnType("uniqueidentifier") + .HasColumnName("TenantId"); + + b.HasKey("Id"); + + b.HasIndex("ContainerId"); + + b.HasIndex("TenantId", "ContainerId", "Name"); + + b.ToTable("AbpBlobs"); + }); + + modelBuilder.Entity("Volo.Abp.BlobStoring.Database.DatabaseBlobContainer", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .HasMaxLength(40) + .HasColumnType("nvarchar(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("ExtraProperties") + .HasColumnType("nvarchar(max)") + .HasColumnName("ExtraProperties"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("nvarchar(128)"); + + b.Property("TenantId") + .HasColumnType("uniqueidentifier") + .HasColumnName("TenantId"); + + b.HasKey("Id"); + + b.HasIndex("TenantId", "Name"); + + b.ToTable("AbpBlobContainers"); + }); + + modelBuilder.Entity("Volo.Abp.FeatureManagement.FeatureValue", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("nvarchar(128)"); + + b.Property("ProviderKey") + .HasMaxLength(64) + .HasColumnType("nvarchar(64)"); + + b.Property("ProviderName") + .HasMaxLength(64) + .HasColumnType("nvarchar(64)"); + + b.Property("Value") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("nvarchar(128)"); + + b.HasKey("Id"); + + b.HasIndex("Name", "ProviderName", "ProviderKey"); + + b.ToTable("AbpFeatureValues"); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityClaimType", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .HasMaxLength(40) + .HasColumnType("nvarchar(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("Description") + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.Property("ExtraProperties") + .HasColumnType("nvarchar(max)") + .HasColumnName("ExtraProperties"); + + b.Property("IsStatic") + .HasColumnType("bit"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.Property("Regex") + .HasMaxLength(512) + .HasColumnType("nvarchar(512)"); + + b.Property("RegexDescription") + .HasMaxLength(128) + .HasColumnType("nvarchar(128)"); + + b.Property("Required") + .HasColumnType("bit"); + + b.Property("ValueType") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.ToTable("AbpClaimTypes"); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityLinkUser", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("SourceTenantId") + .HasColumnType("uniqueidentifier"); + + b.Property("SourceUserId") + .HasColumnType("uniqueidentifier"); + + b.Property("TargetTenantId") + .HasColumnType("uniqueidentifier"); + + b.Property("TargetUserId") + .HasColumnType("uniqueidentifier"); + + b.HasKey("Id"); + + b.HasIndex("SourceUserId", "SourceTenantId", "TargetUserId", "TargetTenantId") + .IsUnique() + .HasFilter("[SourceTenantId] IS NOT NULL AND [TargetTenantId] IS NOT NULL"); + + b.ToTable("AbpLinkUsers"); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityRole", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .HasMaxLength(40) + .HasColumnType("nvarchar(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("ExtraProperties") + .HasColumnType("nvarchar(max)") + .HasColumnName("ExtraProperties"); + + b.Property("IsDefault") + .HasColumnType("bit") + .HasColumnName("IsDefault"); + + b.Property("IsPublic") + .HasColumnType("bit") + .HasColumnName("IsPublic"); + + b.Property("IsStatic") + .HasColumnType("bit") + .HasColumnName("IsStatic"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.Property("NormalizedName") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.Property("TenantId") + .HasColumnType("uniqueidentifier") + .HasColumnName("TenantId"); + + b.HasKey("Id"); + + b.HasIndex("NormalizedName"); + + b.ToTable("AbpRoles"); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityRoleClaim", b => + { + b.Property("Id") + .HasColumnType("uniqueidentifier"); + + b.Property("ClaimType") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.Property("ClaimValue") + .HasMaxLength(1024) + .HasColumnType("nvarchar(1024)"); + + b.Property("RoleId") + .HasColumnType("uniqueidentifier"); + + b.Property("TenantId") + .HasColumnType("uniqueidentifier") + .HasColumnName("TenantId"); + + b.HasKey("Id"); + + b.HasIndex("RoleId"); + + b.ToTable("AbpRoleClaims"); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentitySecurityLog", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("Action") + .HasMaxLength(96) + .HasColumnType("nvarchar(96)"); + + b.Property("ApplicationName") + .HasMaxLength(96) + .HasColumnType("nvarchar(96)"); + + b.Property("BrowserInfo") + .HasMaxLength(512) + .HasColumnType("nvarchar(512)"); + + b.Property("ClientId") + .HasMaxLength(64) + .HasColumnType("nvarchar(64)"); + + b.Property("ClientIpAddress") + .HasMaxLength(64) + .HasColumnType("nvarchar(64)"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .HasMaxLength(40) + .HasColumnType("nvarchar(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("CorrelationId") + .HasMaxLength(64) + .HasColumnType("nvarchar(64)"); + + b.Property("CreationTime") + .HasColumnType("datetime2"); + + b.Property("ExtraProperties") + .HasColumnType("nvarchar(max)") + .HasColumnName("ExtraProperties"); + + b.Property("Identity") + .HasMaxLength(96) + .HasColumnType("nvarchar(96)"); + + b.Property("TenantId") + .HasColumnType("uniqueidentifier") + .HasColumnName("TenantId"); + + b.Property("TenantName") + .HasMaxLength(64) + .HasColumnType("nvarchar(64)"); + + b.Property("UserId") + .HasColumnType("uniqueidentifier"); + + b.Property("UserName") + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.HasKey("Id"); + + b.HasIndex("TenantId", "Action"); + + b.HasIndex("TenantId", "ApplicationName"); + + b.HasIndex("TenantId", "Identity"); + + b.HasIndex("TenantId", "UserId"); + + b.ToTable("AbpSecurityLogs"); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityUser", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("AccessFailedCount") + .ValueGeneratedOnAdd() + .HasColumnType("int") + .HasDefaultValue(0) + .HasColumnName("AccessFailedCount"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .HasMaxLength(40) + .HasColumnType("nvarchar(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("CreationTime") + .HasColumnType("datetime2") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uniqueidentifier") + .HasColumnName("CreatorId"); + + b.Property("DeleterId") + .HasColumnType("uniqueidentifier") + .HasColumnName("DeleterId"); + + b.Property("DeletionTime") + .HasColumnType("datetime2") + .HasColumnName("DeletionTime"); + + b.Property("Email") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("nvarchar(256)") + .HasColumnName("Email"); + + b.Property("EmailConfirmed") + .ValueGeneratedOnAdd() + .HasColumnType("bit") + .HasDefaultValue(false) + .HasColumnName("EmailConfirmed"); + + b.Property("ExtraProperties") + .HasColumnType("nvarchar(max)") + .HasColumnName("ExtraProperties"); + + b.Property("IsDeleted") + .ValueGeneratedOnAdd() + .HasColumnType("bit") + .HasDefaultValue(false) + .HasColumnName("IsDeleted"); + + b.Property("IsExternal") + .ValueGeneratedOnAdd() + .HasColumnType("bit") + .HasDefaultValue(false) + .HasColumnName("IsExternal"); + + b.Property("LastModificationTime") + .HasColumnType("datetime2") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uniqueidentifier") + .HasColumnName("LastModifierId"); + + b.Property("LockoutEnabled") + .ValueGeneratedOnAdd() + .HasColumnType("bit") + .HasDefaultValue(false) + .HasColumnName("LockoutEnabled"); + + b.Property("LockoutEnd") + .HasColumnType("datetimeoffset"); + + b.Property("Name") + .HasMaxLength(64) + .HasColumnType("nvarchar(64)") + .HasColumnName("Name"); + + b.Property("NormalizedEmail") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("nvarchar(256)") + .HasColumnName("NormalizedEmail"); + + b.Property("NormalizedUserName") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("nvarchar(256)") + .HasColumnName("NormalizedUserName"); + + b.Property("PasswordHash") + .HasMaxLength(256) + .HasColumnType("nvarchar(256)") + .HasColumnName("PasswordHash"); + + b.Property("PhoneNumber") + .HasMaxLength(16) + .HasColumnType("nvarchar(16)") + .HasColumnName("PhoneNumber"); + + b.Property("PhoneNumberConfirmed") + .ValueGeneratedOnAdd() + .HasColumnType("bit") + .HasDefaultValue(false) + .HasColumnName("PhoneNumberConfirmed"); + + b.Property("SecurityStamp") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("nvarchar(256)") + .HasColumnName("SecurityStamp"); + + b.Property("Surname") + .HasMaxLength(64) + .HasColumnType("nvarchar(64)") + .HasColumnName("Surname"); + + b.Property("TenantId") + .HasColumnType("uniqueidentifier") + .HasColumnName("TenantId"); + + b.Property("TwoFactorEnabled") + .ValueGeneratedOnAdd() + .HasColumnType("bit") + .HasDefaultValue(false) + .HasColumnName("TwoFactorEnabled"); + + b.Property("UserName") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("nvarchar(256)") + .HasColumnName("UserName"); + + b.HasKey("Id"); + + b.HasIndex("Email"); + + b.HasIndex("NormalizedEmail"); + + b.HasIndex("NormalizedUserName"); + + b.HasIndex("UserName"); + + b.ToTable("AbpUsers"); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityUserClaim", b => + { + b.Property("Id") + .HasColumnType("uniqueidentifier"); + + b.Property("ClaimType") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.Property("ClaimValue") + .HasMaxLength(1024) + .HasColumnType("nvarchar(1024)"); + + b.Property("TenantId") + .HasColumnType("uniqueidentifier") + .HasColumnName("TenantId"); + + b.Property("UserId") + .HasColumnType("uniqueidentifier"); + + b.HasKey("Id"); + + b.HasIndex("UserId"); + + b.ToTable("AbpUserClaims"); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityUserLogin", b => + { + b.Property("UserId") + .HasColumnType("uniqueidentifier"); + + b.Property("LoginProvider") + .HasMaxLength(64) + .HasColumnType("nvarchar(64)"); + + b.Property("ProviderDisplayName") + .HasMaxLength(128) + .HasColumnType("nvarchar(128)"); + + b.Property("ProviderKey") + .IsRequired() + .HasMaxLength(196) + .HasColumnType("nvarchar(196)"); + + b.Property("TenantId") + .HasColumnType("uniqueidentifier") + .HasColumnName("TenantId"); + + b.HasKey("UserId", "LoginProvider"); + + b.HasIndex("LoginProvider", "ProviderKey"); + + b.ToTable("AbpUserLogins"); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityUserOrganizationUnit", b => + { + b.Property("OrganizationUnitId") + .HasColumnType("uniqueidentifier"); + + b.Property("UserId") + .HasColumnType("uniqueidentifier"); + + b.Property("CreationTime") + .HasColumnType("datetime2") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uniqueidentifier") + .HasColumnName("CreatorId"); + + b.Property("TenantId") + .HasColumnType("uniqueidentifier") + .HasColumnName("TenantId"); + + b.HasKey("OrganizationUnitId", "UserId"); + + b.HasIndex("UserId", "OrganizationUnitId"); + + b.ToTable("AbpUserOrganizationUnits"); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityUserRole", b => + { + b.Property("UserId") + .HasColumnType("uniqueidentifier"); + + b.Property("RoleId") + .HasColumnType("uniqueidentifier"); + + b.Property("TenantId") + .HasColumnType("uniqueidentifier") + .HasColumnName("TenantId"); + + b.HasKey("UserId", "RoleId"); + + b.HasIndex("RoleId", "UserId"); + + b.ToTable("AbpUserRoles"); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityUserToken", b => + { + b.Property("UserId") + .HasColumnType("uniqueidentifier"); + + b.Property("LoginProvider") + .HasMaxLength(64) + .HasColumnType("nvarchar(64)"); + + b.Property("Name") + .HasMaxLength(128) + .HasColumnType("nvarchar(128)"); + + b.Property("TenantId") + .HasColumnType("uniqueidentifier") + .HasColumnName("TenantId"); + + b.Property("Value") + .HasColumnType("nvarchar(max)"); + + b.HasKey("UserId", "LoginProvider", "Name"); + + b.ToTable("AbpUserTokens"); + }); + + modelBuilder.Entity("Volo.Abp.Identity.OrganizationUnit", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("Code") + .IsRequired() + .HasMaxLength(95) + .HasColumnType("nvarchar(95)") + .HasColumnName("Code"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .HasMaxLength(40) + .HasColumnType("nvarchar(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("CreationTime") + .HasColumnType("datetime2") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uniqueidentifier") + .HasColumnName("CreatorId"); + + b.Property("DeleterId") + .HasColumnType("uniqueidentifier") + .HasColumnName("DeleterId"); + + b.Property("DeletionTime") + .HasColumnType("datetime2") + .HasColumnName("DeletionTime"); + + b.Property("DisplayName") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("nvarchar(128)") + .HasColumnName("DisplayName"); + + b.Property("ExtraProperties") + .HasColumnType("nvarchar(max)") + .HasColumnName("ExtraProperties"); + + b.Property("IsDeleted") + .ValueGeneratedOnAdd() + .HasColumnType("bit") + .HasDefaultValue(false) + .HasColumnName("IsDeleted"); + + b.Property("LastModificationTime") + .HasColumnType("datetime2") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uniqueidentifier") + .HasColumnName("LastModifierId"); + + b.Property("ParentId") + .HasColumnType("uniqueidentifier"); + + b.Property("TenantId") + .HasColumnType("uniqueidentifier") + .HasColumnName("TenantId"); + + b.HasKey("Id"); + + b.HasIndex("Code"); + + b.HasIndex("ParentId"); + + b.ToTable("AbpOrganizationUnits"); + }); + + modelBuilder.Entity("Volo.Abp.Identity.OrganizationUnitRole", b => + { + b.Property("OrganizationUnitId") + .HasColumnType("uniqueidentifier"); + + b.Property("RoleId") + .HasColumnType("uniqueidentifier"); + + b.Property("CreationTime") + .HasColumnType("datetime2") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uniqueidentifier") + .HasColumnName("CreatorId"); + + b.Property("TenantId") + .HasColumnType("uniqueidentifier") + .HasColumnName("TenantId"); + + b.HasKey("OrganizationUnitId", "RoleId"); + + b.HasIndex("RoleId", "OrganizationUnitId"); + + b.ToTable("AbpOrganizationUnitRoles"); + }); + + modelBuilder.Entity("Volo.Abp.PermissionManagement.PermissionGrant", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("nvarchar(128)"); + + b.Property("ProviderKey") + .IsRequired() + .HasMaxLength(64) + .HasColumnType("nvarchar(64)"); + + b.Property("ProviderName") + .IsRequired() + .HasMaxLength(64) + .HasColumnType("nvarchar(64)"); + + b.Property("TenantId") + .HasColumnType("uniqueidentifier") + .HasColumnName("TenantId"); + + b.HasKey("Id"); + + b.HasIndex("Name", "ProviderName", "ProviderKey"); + + b.ToTable("AbpPermissionGrants"); + }); + + modelBuilder.Entity("Volo.Abp.SettingManagement.Setting", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("nvarchar(128)"); + + b.Property("ProviderKey") + .HasMaxLength(64) + .HasColumnType("nvarchar(64)"); + + b.Property("ProviderName") + .HasMaxLength(64) + .HasColumnType("nvarchar(64)"); + + b.Property("Value") + .IsRequired() + .HasMaxLength(2048) + .HasColumnType("nvarchar(2048)"); + + b.HasKey("Id"); + + b.HasIndex("Name", "ProviderName", "ProviderKey"); + + b.ToTable("AbpSettings"); + }); + + modelBuilder.Entity("Volo.Abp.TenantManagement.Tenant", 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("CreatorId") + .HasColumnType("uniqueidentifier") + .HasColumnName("CreatorId"); + + b.Property("DeleterId") + .HasColumnType("uniqueidentifier") + .HasColumnName("DeleterId"); + + b.Property("DeletionTime") + .HasColumnType("datetime2") + .HasColumnName("DeletionTime"); + + b.Property("ExtraProperties") + .HasColumnType("nvarchar(max)") + .HasColumnName("ExtraProperties"); + + b.Property("IsDeleted") + .ValueGeneratedOnAdd() + .HasColumnType("bit") + .HasDefaultValue(false) + .HasColumnName("IsDeleted"); + + b.Property("LastModificationTime") + .HasColumnType("datetime2") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uniqueidentifier") + .HasColumnName("LastModifierId"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(64) + .HasColumnType("nvarchar(64)"); + + b.HasKey("Id"); + + b.HasIndex("Name"); + + b.ToTable("AbpTenants"); + }); + + modelBuilder.Entity("Volo.Abp.TenantManagement.TenantConnectionString", b => + { + b.Property("TenantId") + .HasColumnType("uniqueidentifier"); + + b.Property("Name") + .HasMaxLength(64) + .HasColumnType("nvarchar(64)"); + + b.Property("Value") + .IsRequired() + .HasMaxLength(1024) + .HasColumnType("nvarchar(1024)"); + + b.HasKey("TenantId", "Name"); + + b.ToTable("AbpTenantConnectionStrings"); + }); + + modelBuilder.Entity("Volo.CmsKit.Blogs.Blog", 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("CreatorId") + .HasColumnType("uniqueidentifier") + .HasColumnName("CreatorId"); + + b.Property("DeleterId") + .HasColumnType("uniqueidentifier") + .HasColumnName("DeleterId"); + + b.Property("DeletionTime") + .HasColumnType("datetime2") + .HasColumnName("DeletionTime"); + + b.Property("ExtraProperties") + .HasColumnType("nvarchar(max)") + .HasColumnName("ExtraProperties"); + + b.Property("IsDeleted") + .ValueGeneratedOnAdd() + .HasColumnType("bit") + .HasDefaultValue(false) + .HasColumnName("IsDeleted"); + + b.Property("LastModificationTime") + .HasColumnType("datetime2") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uniqueidentifier") + .HasColumnName("LastModifierId"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(64) + .HasColumnType("nvarchar(64)"); + + b.Property("Slug") + .IsRequired() + .HasMaxLength(64) + .HasColumnType("nvarchar(64)"); + + b.Property("TenantId") + .HasColumnType("uniqueidentifier") + .HasColumnName("TenantId"); + + b.HasKey("Id"); + + b.ToTable("CmsBlogs"); + }); + + modelBuilder.Entity("Volo.CmsKit.Blogs.BlogFeature", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("BlogId") + .HasColumnType("uniqueidentifier"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .HasMaxLength(40) + .HasColumnType("nvarchar(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("CreationTime") + .HasColumnType("datetime2") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uniqueidentifier") + .HasColumnName("CreatorId"); + + b.Property("DeleterId") + .HasColumnType("uniqueidentifier") + .HasColumnName("DeleterId"); + + b.Property("DeletionTime") + .HasColumnType("datetime2") + .HasColumnName("DeletionTime"); + + b.Property("ExtraProperties") + .HasColumnType("nvarchar(max)") + .HasColumnName("ExtraProperties"); + + b.Property("FeatureName") + .IsRequired() + .HasMaxLength(64) + .HasColumnType("nvarchar(64)"); + + b.Property("IsDeleted") + .ValueGeneratedOnAdd() + .HasColumnType("bit") + .HasDefaultValue(false) + .HasColumnName("IsDeleted"); + + b.Property("IsEnabled") + .HasColumnType("bit"); + + b.Property("LastModificationTime") + .HasColumnType("datetime2") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uniqueidentifier") + .HasColumnName("LastModifierId"); + + b.HasKey("Id"); + + b.ToTable("CmsBlogFeatures"); + }); + + modelBuilder.Entity("Volo.CmsKit.Blogs.BlogPost", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("AuthorId") + .HasColumnType("uniqueidentifier"); + + b.Property("BlogId") + .HasColumnType("uniqueidentifier"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .HasMaxLength(40) + .HasColumnType("nvarchar(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("CreationTime") + .HasColumnType("datetime2") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uniqueidentifier") + .HasColumnName("CreatorId"); + + b.Property("DeleterId") + .HasColumnType("uniqueidentifier") + .HasColumnName("DeleterId"); + + b.Property("DeletionTime") + .HasColumnType("datetime2") + .HasColumnName("DeletionTime"); + + b.Property("ExtraProperties") + .HasColumnType("nvarchar(max)") + .HasColumnName("ExtraProperties"); + + b.Property("IsDeleted") + .ValueGeneratedOnAdd() + .HasColumnType("bit") + .HasDefaultValue(false) + .HasColumnName("IsDeleted"); + + b.Property("LastModificationTime") + .HasColumnType("datetime2") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uniqueidentifier") + .HasColumnName("LastModifierId"); + + b.Property("ShortDescription") + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.Property("Slug") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.Property("TenantId") + .HasColumnType("uniqueidentifier") + .HasColumnName("TenantId"); + + b.Property("Title") + .IsRequired() + .HasMaxLength(64) + .HasColumnType("nvarchar(64)"); + + b.HasKey("Id"); + + b.HasIndex("AuthorId"); + + b.HasIndex("Slug", "BlogId"); + + b.ToTable("CmsBlogPosts"); + }); + + modelBuilder.Entity("Volo.CmsKit.Comments.Comment", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("CreationTime") + .HasColumnType("datetime2") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uniqueidentifier") + .HasColumnName("CreatorId"); + + b.Property("EntityId") + .IsRequired() + .HasMaxLength(64) + .HasColumnType("nvarchar(64)"); + + b.Property("EntityType") + .IsRequired() + .HasMaxLength(64) + .HasColumnType("nvarchar(64)"); + + b.Property("RepliedCommentId") + .HasColumnType("uniqueidentifier"); + + b.Property("TenantId") + .HasColumnType("uniqueidentifier") + .HasColumnName("TenantId"); + + b.Property("Text") + .IsRequired() + .HasMaxLength(512) + .HasColumnType("nvarchar(512)"); + + b.HasKey("Id"); + + b.HasIndex("TenantId", "RepliedCommentId"); + + b.HasIndex("TenantId", "EntityType", "EntityId"); + + b.ToTable("CmsComments"); + }); + + modelBuilder.Entity("Volo.CmsKit.Contents.Content", 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("CreatorId") + .HasColumnType("uniqueidentifier") + .HasColumnName("CreatorId"); + + b.Property("DeleterId") + .HasColumnType("uniqueidentifier") + .HasColumnName("DeleterId"); + + b.Property("DeletionTime") + .HasColumnType("datetime2") + .HasColumnName("DeletionTime"); + + b.Property("EntityId") + .IsRequired() + .HasMaxLength(64) + .HasColumnType("nvarchar(64)"); + + b.Property("EntityType") + .IsRequired() + .HasMaxLength(64) + .HasColumnType("nvarchar(64)"); + + b.Property("ExtraProperties") + .HasColumnType("nvarchar(max)") + .HasColumnName("ExtraProperties"); + + b.Property("IsDeleted") + .ValueGeneratedOnAdd() + .HasColumnType("bit") + .HasDefaultValue(false) + .HasColumnName("IsDeleted"); + + b.Property("LastModificationTime") + .HasColumnType("datetime2") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uniqueidentifier") + .HasColumnName("LastModifierId"); + + b.Property("TenantId") + .HasColumnType("uniqueidentifier") + .HasColumnName("TenantId"); + + b.Property("Value") + .IsRequired() + .HasMaxLength(2147483647) + .HasColumnType("nvarchar(max)"); + + b.HasKey("Id"); + + b.HasIndex("TenantId", "EntityType", "EntityId"); + + b.ToTable("CmsContents"); + }); + + modelBuilder.Entity("Volo.CmsKit.MediaDescriptors.MediaDescriptor", 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("CreatorId") + .HasColumnType("uniqueidentifier") + .HasColumnName("CreatorId"); + + b.Property("DeleterId") + .HasColumnType("uniqueidentifier") + .HasColumnName("DeleterId"); + + b.Property("DeletionTime") + .HasColumnType("datetime2") + .HasColumnName("DeletionTime"); + + b.Property("EntityType") + .IsRequired() + .HasMaxLength(64) + .HasColumnType("nvarchar(64)"); + + b.Property("ExtraProperties") + .HasColumnType("nvarchar(max)") + .HasColumnName("ExtraProperties"); + + b.Property("IsDeleted") + .ValueGeneratedOnAdd() + .HasColumnType("bit") + .HasDefaultValue(false) + .HasColumnName("IsDeleted"); + + b.Property("LastModificationTime") + .HasColumnType("datetime2") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uniqueidentifier") + .HasColumnName("LastModifierId"); + + b.Property("MimeType") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("nvarchar(128)"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("nvarchar(255)"); + + b.Property("Size") + .HasMaxLength(2147483647) + .HasColumnType("bigint"); + + b.Property("TenantId") + .HasColumnType("uniqueidentifier") + .HasColumnName("TenantId"); + + b.HasKey("Id"); + + b.ToTable("CmsMediaDescriptors"); + }); + + modelBuilder.Entity("Volo.CmsKit.Pages.Page", 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("CreatorId") + .HasColumnType("uniqueidentifier") + .HasColumnName("CreatorId"); + + b.Property("DeleterId") + .HasColumnType("uniqueidentifier") + .HasColumnName("DeleterId"); + + b.Property("DeletionTime") + .HasColumnType("datetime2") + .HasColumnName("DeletionTime"); + + b.Property("ExtraProperties") + .HasColumnType("nvarchar(max)") + .HasColumnName("ExtraProperties"); + + b.Property("IsDeleted") + .ValueGeneratedOnAdd() + .HasColumnType("bit") + .HasDefaultValue(false) + .HasColumnName("IsDeleted"); + + b.Property("LastModificationTime") + .HasColumnType("datetime2") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uniqueidentifier") + .HasColumnName("LastModifierId"); + + b.Property("Slug") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.Property("TenantId") + .HasColumnType("uniqueidentifier") + .HasColumnName("TenantId"); + + b.Property("Title") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.HasKey("Id"); + + b.HasIndex("TenantId", "Slug"); + + b.ToTable("CmsPages"); + }); + + modelBuilder.Entity("Volo.CmsKit.Ratings.Rating", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("CreationTime") + .HasColumnType("datetime2") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uniqueidentifier") + .HasColumnName("CreatorId"); + + b.Property("EntityId") + .IsRequired() + .HasMaxLength(64) + .HasColumnType("nvarchar(64)"); + + b.Property("EntityType") + .IsRequired() + .HasMaxLength(64) + .HasColumnType("nvarchar(64)"); + + b.Property("StarCount") + .HasColumnType("smallint"); + + b.Property("TenantId") + .HasColumnType("uniqueidentifier"); + + b.HasKey("Id"); + + b.HasIndex("TenantId", "EntityType", "EntityId", "CreatorId"); + + b.ToTable("CmsRatings"); + }); + + modelBuilder.Entity("Volo.CmsKit.Reactions.UserReaction", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("CreationTime") + .HasColumnType("datetime2") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uniqueidentifier") + .HasColumnName("CreatorId"); + + b.Property("EntityId") + .IsRequired() + .HasMaxLength(64) + .HasColumnType("nvarchar(64)"); + + b.Property("EntityType") + .IsRequired() + .HasMaxLength(64) + .HasColumnType("nvarchar(64)"); + + b.Property("ReactionName") + .IsRequired() + .HasMaxLength(32) + .HasColumnType("nvarchar(32)"); + + b.Property("TenantId") + .HasColumnType("uniqueidentifier") + .HasColumnName("TenantId"); + + b.HasKey("Id"); + + b.HasIndex("TenantId", "EntityType", "EntityId", "ReactionName"); + + b.HasIndex("TenantId", "CreatorId", "EntityType", "EntityId", "ReactionName"); + + b.ToTable("CmsUserReactions"); + }); + + modelBuilder.Entity("Volo.CmsKit.Tags.EntityTag", b => + { + b.Property("EntityId") + .HasColumnType("nvarchar(450)"); + + b.Property("TagId") + .HasColumnType("uniqueidentifier"); + + b.Property("TenantId") + .HasColumnType("uniqueidentifier") + .HasColumnName("TenantId"); + + b.HasKey("EntityId", "TagId"); + + b.HasIndex("TenantId", "EntityId", "TagId"); + + b.ToTable("CmsEntityTags"); + }); + + modelBuilder.Entity("Volo.CmsKit.Tags.Tag", 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("CreatorId") + .HasColumnType("uniqueidentifier") + .HasColumnName("CreatorId"); + + b.Property("DeleterId") + .HasColumnType("uniqueidentifier") + .HasColumnName("DeleterId"); + + b.Property("DeletionTime") + .HasColumnType("datetime2") + .HasColumnName("DeletionTime"); + + b.Property("EntityType") + .IsRequired() + .HasMaxLength(64) + .HasColumnType("nvarchar(64)"); + + b.Property("ExtraProperties") + .HasColumnType("nvarchar(max)") + .HasColumnName("ExtraProperties"); + + b.Property("IsDeleted") + .ValueGeneratedOnAdd() + .HasColumnType("bit") + .HasDefaultValue(false) + .HasColumnName("IsDeleted"); + + b.Property("LastModificationTime") + .HasColumnType("datetime2") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uniqueidentifier") + .HasColumnName("LastModifierId"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(32) + .HasColumnType("nvarchar(32)"); + + b.Property("TenantId") + .HasColumnType("uniqueidentifier") + .HasColumnName("TenantId"); + + b.HasKey("Id"); + + b.HasIndex("TenantId", "Name"); + + b.ToTable("CmsTags"); + }); + + modelBuilder.Entity("Volo.CmsKit.Users.CmsUser", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .HasMaxLength(40) + .HasColumnType("nvarchar(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("Email") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("nvarchar(256)") + .HasColumnName("Email"); + + b.Property("EmailConfirmed") + .ValueGeneratedOnAdd() + .HasColumnType("bit") + .HasDefaultValue(false) + .HasColumnName("EmailConfirmed"); + + b.Property("ExtraProperties") + .HasColumnType("nvarchar(max)") + .HasColumnName("ExtraProperties"); + + b.Property("Name") + .HasMaxLength(64) + .HasColumnType("nvarchar(64)") + .HasColumnName("Name"); + + b.Property("PhoneNumber") + .HasMaxLength(16) + .HasColumnType("nvarchar(16)") + .HasColumnName("PhoneNumber"); + + b.Property("PhoneNumberConfirmed") + .ValueGeneratedOnAdd() + .HasColumnType("bit") + .HasDefaultValue(false) + .HasColumnName("PhoneNumberConfirmed"); + + b.Property("Surname") + .HasMaxLength(64) + .HasColumnType("nvarchar(64)") + .HasColumnName("Surname"); + + b.Property("TenantId") + .HasColumnType("uniqueidentifier") + .HasColumnName("TenantId"); + + b.Property("UserName") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("nvarchar(256)") + .HasColumnName("UserName"); + + b.HasKey("Id"); + + b.HasIndex("TenantId", "Email"); + + b.HasIndex("TenantId", "UserName"); + + b.ToTable("CmsUsers"); + }); + + modelBuilder.Entity("Volo.Abp.AuditLogging.AuditLogAction", b => + { + b.HasOne("Volo.Abp.AuditLogging.AuditLog", null) + .WithMany("Actions") + .HasForeignKey("AuditLogId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Volo.Abp.AuditLogging.EntityChange", b => + { + b.HasOne("Volo.Abp.AuditLogging.AuditLog", null) + .WithMany("EntityChanges") + .HasForeignKey("AuditLogId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Volo.Abp.AuditLogging.EntityPropertyChange", b => + { + b.HasOne("Volo.Abp.AuditLogging.EntityChange", null) + .WithMany("PropertyChanges") + .HasForeignKey("EntityChangeId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Volo.Abp.BlobStoring.Database.DatabaseBlob", b => + { + b.HasOne("Volo.Abp.BlobStoring.Database.DatabaseBlobContainer", null) + .WithMany() + .HasForeignKey("ContainerId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityRoleClaim", b => + { + b.HasOne("Volo.Abp.Identity.IdentityRole", null) + .WithMany("Claims") + .HasForeignKey("RoleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityUserClaim", b => + { + b.HasOne("Volo.Abp.Identity.IdentityUser", null) + .WithMany("Claims") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityUserLogin", b => + { + b.HasOne("Volo.Abp.Identity.IdentityUser", null) + .WithMany("Logins") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityUserOrganizationUnit", b => + { + b.HasOne("Volo.Abp.Identity.OrganizationUnit", null) + .WithMany() + .HasForeignKey("OrganizationUnitId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Volo.Abp.Identity.IdentityUser", null) + .WithMany("OrganizationUnits") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityUserRole", b => + { + b.HasOne("Volo.Abp.Identity.IdentityRole", null) + .WithMany() + .HasForeignKey("RoleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Volo.Abp.Identity.IdentityUser", null) + .WithMany("Roles") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityUserToken", b => + { + b.HasOne("Volo.Abp.Identity.IdentityUser", null) + .WithMany("Tokens") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Volo.Abp.Identity.OrganizationUnit", b => + { + b.HasOne("Volo.Abp.Identity.OrganizationUnit", null) + .WithMany() + .HasForeignKey("ParentId"); + }); + + modelBuilder.Entity("Volo.Abp.Identity.OrganizationUnitRole", b => + { + b.HasOne("Volo.Abp.Identity.OrganizationUnit", null) + .WithMany("Roles") + .HasForeignKey("OrganizationUnitId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Volo.Abp.Identity.IdentityRole", null) + .WithMany() + .HasForeignKey("RoleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Volo.Abp.TenantManagement.TenantConnectionString", b => + { + b.HasOne("Volo.Abp.TenantManagement.Tenant", null) + .WithMany("ConnectionStrings") + .HasForeignKey("TenantId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Volo.CmsKit.Blogs.BlogPost", b => + { + b.HasOne("Volo.CmsKit.Users.CmsUser", "Author") + .WithMany() + .HasForeignKey("AuthorId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Author"); + }); + + modelBuilder.Entity("Volo.Abp.AuditLogging.AuditLog", b => + { + b.Navigation("Actions"); + + b.Navigation("EntityChanges"); + }); + + modelBuilder.Entity("Volo.Abp.AuditLogging.EntityChange", b => + { + b.Navigation("PropertyChanges"); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityRole", b => + { + b.Navigation("Claims"); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityUser", b => + { + b.Navigation("Claims"); + + b.Navigation("Logins"); + + b.Navigation("OrganizationUnits"); + + b.Navigation("Roles"); + + b.Navigation("Tokens"); + }); + + modelBuilder.Entity("Volo.Abp.Identity.OrganizationUnit", b => + { + b.Navigation("Roles"); + }); + + modelBuilder.Entity("Volo.Abp.TenantManagement.Tenant", b => + { + b.Navigation("ConnectionStrings"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/modules/cms-kit/host/Volo.CmsKit.Web.Unified/Migrations/20210302064229_Added_EntityType_to_Media.cs b/modules/cms-kit/host/Volo.CmsKit.Web.Unified/Migrations/20210302064229_Added_EntityType_to_Media.cs new file mode 100644 index 0000000000..10a6abd994 --- /dev/null +++ b/modules/cms-kit/host/Volo.CmsKit.Web.Unified/Migrations/20210302064229_Added_EntityType_to_Media.cs @@ -0,0 +1,25 @@ +using Microsoft.EntityFrameworkCore.Migrations; + +namespace Volo.CmsKit.Migrations +{ + public partial class Added_EntityType_to_Media : Migration + { + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.AddColumn( + name: "EntityType", + table: "CmsMediaDescriptors", + type: "nvarchar(64)", + maxLength: 64, + nullable: false, + defaultValue: ""); + } + + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropColumn( + name: "EntityType", + table: "CmsMediaDescriptors"); + } + } +} diff --git a/modules/cms-kit/host/Volo.CmsKit.Web.Unified/Migrations/20210302075529_Added_Content_To_BlogPost.Designer.cs b/modules/cms-kit/host/Volo.CmsKit.Web.Unified/Migrations/20210302075529_Added_Content_To_BlogPost.Designer.cs new file mode 100644 index 0000000000..8f6bd9239d --- /dev/null +++ b/modules/cms-kit/host/Volo.CmsKit.Web.Unified/Migrations/20210302075529_Added_Content_To_BlogPost.Designer.cs @@ -0,0 +1,2016 @@ +// +using System; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Metadata; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; +using Volo.Abp.EntityFrameworkCore; +using Volo.CmsKit.EntityFrameworkCore; + +namespace Volo.CmsKit.Migrations +{ + [DbContext(typeof(UnifiedDbContext))] + [Migration("20210302075529_Added_Content_To_BlogPost")] + partial class Added_Content_To_BlogPost + { + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("_Abp_DatabaseProvider", EfCoreDatabaseProvider.SqlServer) + .HasAnnotation("Relational:MaxIdentifierLength", 128) + .HasAnnotation("ProductVersion", "5.0.3") + .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); + + modelBuilder.Entity("Volo.Abp.AuditLogging.AuditLog", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("ApplicationName") + .HasMaxLength(96) + .HasColumnType("nvarchar(96)") + .HasColumnName("ApplicationName"); + + b.Property("BrowserInfo") + .HasMaxLength(512) + .HasColumnType("nvarchar(512)") + .HasColumnName("BrowserInfo"); + + b.Property("ClientId") + .HasMaxLength(64) + .HasColumnType("nvarchar(64)") + .HasColumnName("ClientId"); + + b.Property("ClientIpAddress") + .HasMaxLength(64) + .HasColumnType("nvarchar(64)") + .HasColumnName("ClientIpAddress"); + + b.Property("ClientName") + .HasMaxLength(128) + .HasColumnType("nvarchar(128)") + .HasColumnName("ClientName"); + + b.Property("Comments") + .HasMaxLength(256) + .HasColumnType("nvarchar(256)") + .HasColumnName("Comments"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .HasMaxLength(40) + .HasColumnType("nvarchar(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("CorrelationId") + .HasMaxLength(64) + .HasColumnType("nvarchar(64)") + .HasColumnName("CorrelationId"); + + b.Property("Exceptions") + .HasMaxLength(4000) + .HasColumnType("nvarchar(4000)") + .HasColumnName("Exceptions"); + + b.Property("ExecutionDuration") + .HasColumnType("int") + .HasColumnName("ExecutionDuration"); + + b.Property("ExecutionTime") + .HasColumnType("datetime2"); + + b.Property("ExtraProperties") + .HasColumnType("nvarchar(max)") + .HasColumnName("ExtraProperties"); + + b.Property("HttpMethod") + .HasMaxLength(16) + .HasColumnType("nvarchar(16)") + .HasColumnName("HttpMethod"); + + b.Property("HttpStatusCode") + .HasColumnType("int") + .HasColumnName("HttpStatusCode"); + + b.Property("ImpersonatorTenantId") + .HasColumnType("uniqueidentifier") + .HasColumnName("ImpersonatorTenantId"); + + b.Property("ImpersonatorUserId") + .HasColumnType("uniqueidentifier") + .HasColumnName("ImpersonatorUserId"); + + b.Property("TenantId") + .HasColumnType("uniqueidentifier") + .HasColumnName("TenantId"); + + b.Property("TenantName") + .HasColumnType("nvarchar(max)"); + + b.Property("Url") + .HasMaxLength(256) + .HasColumnType("nvarchar(256)") + .HasColumnName("Url"); + + b.Property("UserId") + .HasColumnType("uniqueidentifier") + .HasColumnName("UserId"); + + b.Property("UserName") + .HasMaxLength(256) + .HasColumnType("nvarchar(256)") + .HasColumnName("UserName"); + + b.HasKey("Id"); + + b.HasIndex("TenantId", "ExecutionTime"); + + b.HasIndex("TenantId", "UserId", "ExecutionTime"); + + b.ToTable("AbpAuditLogs"); + }); + + modelBuilder.Entity("Volo.Abp.AuditLogging.AuditLogAction", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("AuditLogId") + .HasColumnType("uniqueidentifier") + .HasColumnName("AuditLogId"); + + b.Property("ExecutionDuration") + .HasColumnType("int") + .HasColumnName("ExecutionDuration"); + + b.Property("ExecutionTime") + .HasColumnType("datetime2") + .HasColumnName("ExecutionTime"); + + b.Property("ExtraProperties") + .HasColumnType("nvarchar(max)") + .HasColumnName("ExtraProperties"); + + b.Property("MethodName") + .HasMaxLength(128) + .HasColumnType("nvarchar(128)") + .HasColumnName("MethodName"); + + b.Property("Parameters") + .HasMaxLength(2000) + .HasColumnType("nvarchar(2000)") + .HasColumnName("Parameters"); + + b.Property("ServiceName") + .HasMaxLength(256) + .HasColumnType("nvarchar(256)") + .HasColumnName("ServiceName"); + + b.Property("TenantId") + .HasColumnType("uniqueidentifier") + .HasColumnName("TenantId"); + + b.HasKey("Id"); + + b.HasIndex("AuditLogId"); + + b.HasIndex("TenantId", "ServiceName", "MethodName", "ExecutionTime"); + + b.ToTable("AbpAuditLogActions"); + }); + + modelBuilder.Entity("Volo.Abp.AuditLogging.EntityChange", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("AuditLogId") + .HasColumnType("uniqueidentifier") + .HasColumnName("AuditLogId"); + + b.Property("ChangeTime") + .HasColumnType("datetime2") + .HasColumnName("ChangeTime"); + + b.Property("ChangeType") + .HasColumnType("tinyint") + .HasColumnName("ChangeType"); + + b.Property("EntityId") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("nvarchar(128)") + .HasColumnName("EntityId"); + + b.Property("EntityTenantId") + .HasColumnType("uniqueidentifier"); + + b.Property("EntityTypeFullName") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("nvarchar(128)") + .HasColumnName("EntityTypeFullName"); + + b.Property("ExtraProperties") + .HasColumnType("nvarchar(max)") + .HasColumnName("ExtraProperties"); + + b.Property("TenantId") + .HasColumnType("uniqueidentifier") + .HasColumnName("TenantId"); + + b.HasKey("Id"); + + b.HasIndex("AuditLogId"); + + b.HasIndex("TenantId", "EntityTypeFullName", "EntityId"); + + b.ToTable("AbpEntityChanges"); + }); + + modelBuilder.Entity("Volo.Abp.AuditLogging.EntityPropertyChange", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("EntityChangeId") + .HasColumnType("uniqueidentifier"); + + b.Property("NewValue") + .HasMaxLength(512) + .HasColumnType("nvarchar(512)") + .HasColumnName("NewValue"); + + b.Property("OriginalValue") + .HasMaxLength(512) + .HasColumnType("nvarchar(512)") + .HasColumnName("OriginalValue"); + + b.Property("PropertyName") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("nvarchar(128)") + .HasColumnName("PropertyName"); + + b.Property("PropertyTypeFullName") + .IsRequired() + .HasMaxLength(64) + .HasColumnType("nvarchar(64)") + .HasColumnName("PropertyTypeFullName"); + + b.Property("TenantId") + .HasColumnType("uniqueidentifier") + .HasColumnName("TenantId"); + + b.HasKey("Id"); + + b.HasIndex("EntityChangeId"); + + b.ToTable("AbpEntityPropertyChanges"); + }); + + modelBuilder.Entity("Volo.Abp.BlobStoring.Database.DatabaseBlob", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .HasMaxLength(40) + .HasColumnType("nvarchar(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("ContainerId") + .HasColumnType("uniqueidentifier"); + + b.Property("Content") + .HasMaxLength(2147483647) + .HasColumnType("varbinary(max)"); + + b.Property("ExtraProperties") + .HasColumnType("nvarchar(max)") + .HasColumnName("ExtraProperties"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.Property("TenantId") + .HasColumnType("uniqueidentifier") + .HasColumnName("TenantId"); + + b.HasKey("Id"); + + b.HasIndex("ContainerId"); + + b.HasIndex("TenantId", "ContainerId", "Name"); + + b.ToTable("AbpBlobs"); + }); + + modelBuilder.Entity("Volo.Abp.BlobStoring.Database.DatabaseBlobContainer", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .HasMaxLength(40) + .HasColumnType("nvarchar(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("ExtraProperties") + .HasColumnType("nvarchar(max)") + .HasColumnName("ExtraProperties"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("nvarchar(128)"); + + b.Property("TenantId") + .HasColumnType("uniqueidentifier") + .HasColumnName("TenantId"); + + b.HasKey("Id"); + + b.HasIndex("TenantId", "Name"); + + b.ToTable("AbpBlobContainers"); + }); + + modelBuilder.Entity("Volo.Abp.FeatureManagement.FeatureValue", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("nvarchar(128)"); + + b.Property("ProviderKey") + .HasMaxLength(64) + .HasColumnType("nvarchar(64)"); + + b.Property("ProviderName") + .HasMaxLength(64) + .HasColumnType("nvarchar(64)"); + + b.Property("Value") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("nvarchar(128)"); + + b.HasKey("Id"); + + b.HasIndex("Name", "ProviderName", "ProviderKey"); + + b.ToTable("AbpFeatureValues"); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityClaimType", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .HasMaxLength(40) + .HasColumnType("nvarchar(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("Description") + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.Property("ExtraProperties") + .HasColumnType("nvarchar(max)") + .HasColumnName("ExtraProperties"); + + b.Property("IsStatic") + .HasColumnType("bit"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.Property("Regex") + .HasMaxLength(512) + .HasColumnType("nvarchar(512)"); + + b.Property("RegexDescription") + .HasMaxLength(128) + .HasColumnType("nvarchar(128)"); + + b.Property("Required") + .HasColumnType("bit"); + + b.Property("ValueType") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.ToTable("AbpClaimTypes"); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityLinkUser", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("SourceTenantId") + .HasColumnType("uniqueidentifier"); + + b.Property("SourceUserId") + .HasColumnType("uniqueidentifier"); + + b.Property("TargetTenantId") + .HasColumnType("uniqueidentifier"); + + b.Property("TargetUserId") + .HasColumnType("uniqueidentifier"); + + b.HasKey("Id"); + + b.HasIndex("SourceUserId", "SourceTenantId", "TargetUserId", "TargetTenantId") + .IsUnique() + .HasFilter("[SourceTenantId] IS NOT NULL AND [TargetTenantId] IS NOT NULL"); + + b.ToTable("AbpLinkUsers"); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityRole", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .HasMaxLength(40) + .HasColumnType("nvarchar(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("ExtraProperties") + .HasColumnType("nvarchar(max)") + .HasColumnName("ExtraProperties"); + + b.Property("IsDefault") + .HasColumnType("bit") + .HasColumnName("IsDefault"); + + b.Property("IsPublic") + .HasColumnType("bit") + .HasColumnName("IsPublic"); + + b.Property("IsStatic") + .HasColumnType("bit") + .HasColumnName("IsStatic"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.Property("NormalizedName") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.Property("TenantId") + .HasColumnType("uniqueidentifier") + .HasColumnName("TenantId"); + + b.HasKey("Id"); + + b.HasIndex("NormalizedName"); + + b.ToTable("AbpRoles"); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityRoleClaim", b => + { + b.Property("Id") + .HasColumnType("uniqueidentifier"); + + b.Property("ClaimType") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.Property("ClaimValue") + .HasMaxLength(1024) + .HasColumnType("nvarchar(1024)"); + + b.Property("RoleId") + .HasColumnType("uniqueidentifier"); + + b.Property("TenantId") + .HasColumnType("uniqueidentifier") + .HasColumnName("TenantId"); + + b.HasKey("Id"); + + b.HasIndex("RoleId"); + + b.ToTable("AbpRoleClaims"); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentitySecurityLog", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("Action") + .HasMaxLength(96) + .HasColumnType("nvarchar(96)"); + + b.Property("ApplicationName") + .HasMaxLength(96) + .HasColumnType("nvarchar(96)"); + + b.Property("BrowserInfo") + .HasMaxLength(512) + .HasColumnType("nvarchar(512)"); + + b.Property("ClientId") + .HasMaxLength(64) + .HasColumnType("nvarchar(64)"); + + b.Property("ClientIpAddress") + .HasMaxLength(64) + .HasColumnType("nvarchar(64)"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .HasMaxLength(40) + .HasColumnType("nvarchar(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("CorrelationId") + .HasMaxLength(64) + .HasColumnType("nvarchar(64)"); + + b.Property("CreationTime") + .HasColumnType("datetime2"); + + b.Property("ExtraProperties") + .HasColumnType("nvarchar(max)") + .HasColumnName("ExtraProperties"); + + b.Property("Identity") + .HasMaxLength(96) + .HasColumnType("nvarchar(96)"); + + b.Property("TenantId") + .HasColumnType("uniqueidentifier") + .HasColumnName("TenantId"); + + b.Property("TenantName") + .HasMaxLength(64) + .HasColumnType("nvarchar(64)"); + + b.Property("UserId") + .HasColumnType("uniqueidentifier"); + + b.Property("UserName") + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.HasKey("Id"); + + b.HasIndex("TenantId", "Action"); + + b.HasIndex("TenantId", "ApplicationName"); + + b.HasIndex("TenantId", "Identity"); + + b.HasIndex("TenantId", "UserId"); + + b.ToTable("AbpSecurityLogs"); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityUser", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("AccessFailedCount") + .ValueGeneratedOnAdd() + .HasColumnType("int") + .HasDefaultValue(0) + .HasColumnName("AccessFailedCount"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .HasMaxLength(40) + .HasColumnType("nvarchar(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("CreationTime") + .HasColumnType("datetime2") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uniqueidentifier") + .HasColumnName("CreatorId"); + + b.Property("DeleterId") + .HasColumnType("uniqueidentifier") + .HasColumnName("DeleterId"); + + b.Property("DeletionTime") + .HasColumnType("datetime2") + .HasColumnName("DeletionTime"); + + b.Property("Email") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("nvarchar(256)") + .HasColumnName("Email"); + + b.Property("EmailConfirmed") + .ValueGeneratedOnAdd() + .HasColumnType("bit") + .HasDefaultValue(false) + .HasColumnName("EmailConfirmed"); + + b.Property("ExtraProperties") + .HasColumnType("nvarchar(max)") + .HasColumnName("ExtraProperties"); + + b.Property("IsDeleted") + .ValueGeneratedOnAdd() + .HasColumnType("bit") + .HasDefaultValue(false) + .HasColumnName("IsDeleted"); + + b.Property("IsExternal") + .ValueGeneratedOnAdd() + .HasColumnType("bit") + .HasDefaultValue(false) + .HasColumnName("IsExternal"); + + b.Property("LastModificationTime") + .HasColumnType("datetime2") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uniqueidentifier") + .HasColumnName("LastModifierId"); + + b.Property("LockoutEnabled") + .ValueGeneratedOnAdd() + .HasColumnType("bit") + .HasDefaultValue(false) + .HasColumnName("LockoutEnabled"); + + b.Property("LockoutEnd") + .HasColumnType("datetimeoffset"); + + b.Property("Name") + .HasMaxLength(64) + .HasColumnType("nvarchar(64)") + .HasColumnName("Name"); + + b.Property("NormalizedEmail") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("nvarchar(256)") + .HasColumnName("NormalizedEmail"); + + b.Property("NormalizedUserName") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("nvarchar(256)") + .HasColumnName("NormalizedUserName"); + + b.Property("PasswordHash") + .HasMaxLength(256) + .HasColumnType("nvarchar(256)") + .HasColumnName("PasswordHash"); + + b.Property("PhoneNumber") + .HasMaxLength(16) + .HasColumnType("nvarchar(16)") + .HasColumnName("PhoneNumber"); + + b.Property("PhoneNumberConfirmed") + .ValueGeneratedOnAdd() + .HasColumnType("bit") + .HasDefaultValue(false) + .HasColumnName("PhoneNumberConfirmed"); + + b.Property("SecurityStamp") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("nvarchar(256)") + .HasColumnName("SecurityStamp"); + + b.Property("Surname") + .HasMaxLength(64) + .HasColumnType("nvarchar(64)") + .HasColumnName("Surname"); + + b.Property("TenantId") + .HasColumnType("uniqueidentifier") + .HasColumnName("TenantId"); + + b.Property("TwoFactorEnabled") + .ValueGeneratedOnAdd() + .HasColumnType("bit") + .HasDefaultValue(false) + .HasColumnName("TwoFactorEnabled"); + + b.Property("UserName") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("nvarchar(256)") + .HasColumnName("UserName"); + + b.HasKey("Id"); + + b.HasIndex("Email"); + + b.HasIndex("NormalizedEmail"); + + b.HasIndex("NormalizedUserName"); + + b.HasIndex("UserName"); + + b.ToTable("AbpUsers"); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityUserClaim", b => + { + b.Property("Id") + .HasColumnType("uniqueidentifier"); + + b.Property("ClaimType") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.Property("ClaimValue") + .HasMaxLength(1024) + .HasColumnType("nvarchar(1024)"); + + b.Property("TenantId") + .HasColumnType("uniqueidentifier") + .HasColumnName("TenantId"); + + b.Property("UserId") + .HasColumnType("uniqueidentifier"); + + b.HasKey("Id"); + + b.HasIndex("UserId"); + + b.ToTable("AbpUserClaims"); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityUserLogin", b => + { + b.Property("UserId") + .HasColumnType("uniqueidentifier"); + + b.Property("LoginProvider") + .HasMaxLength(64) + .HasColumnType("nvarchar(64)"); + + b.Property("ProviderDisplayName") + .HasMaxLength(128) + .HasColumnType("nvarchar(128)"); + + b.Property("ProviderKey") + .IsRequired() + .HasMaxLength(196) + .HasColumnType("nvarchar(196)"); + + b.Property("TenantId") + .HasColumnType("uniqueidentifier") + .HasColumnName("TenantId"); + + b.HasKey("UserId", "LoginProvider"); + + b.HasIndex("LoginProvider", "ProviderKey"); + + b.ToTable("AbpUserLogins"); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityUserOrganizationUnit", b => + { + b.Property("OrganizationUnitId") + .HasColumnType("uniqueidentifier"); + + b.Property("UserId") + .HasColumnType("uniqueidentifier"); + + b.Property("CreationTime") + .HasColumnType("datetime2") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uniqueidentifier") + .HasColumnName("CreatorId"); + + b.Property("TenantId") + .HasColumnType("uniqueidentifier") + .HasColumnName("TenantId"); + + b.HasKey("OrganizationUnitId", "UserId"); + + b.HasIndex("UserId", "OrganizationUnitId"); + + b.ToTable("AbpUserOrganizationUnits"); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityUserRole", b => + { + b.Property("UserId") + .HasColumnType("uniqueidentifier"); + + b.Property("RoleId") + .HasColumnType("uniqueidentifier"); + + b.Property("TenantId") + .HasColumnType("uniqueidentifier") + .HasColumnName("TenantId"); + + b.HasKey("UserId", "RoleId"); + + b.HasIndex("RoleId", "UserId"); + + b.ToTable("AbpUserRoles"); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityUserToken", b => + { + b.Property("UserId") + .HasColumnType("uniqueidentifier"); + + b.Property("LoginProvider") + .HasMaxLength(64) + .HasColumnType("nvarchar(64)"); + + b.Property("Name") + .HasMaxLength(128) + .HasColumnType("nvarchar(128)"); + + b.Property("TenantId") + .HasColumnType("uniqueidentifier") + .HasColumnName("TenantId"); + + b.Property("Value") + .HasColumnType("nvarchar(max)"); + + b.HasKey("UserId", "LoginProvider", "Name"); + + b.ToTable("AbpUserTokens"); + }); + + modelBuilder.Entity("Volo.Abp.Identity.OrganizationUnit", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("Code") + .IsRequired() + .HasMaxLength(95) + .HasColumnType("nvarchar(95)") + .HasColumnName("Code"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .HasMaxLength(40) + .HasColumnType("nvarchar(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("CreationTime") + .HasColumnType("datetime2") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uniqueidentifier") + .HasColumnName("CreatorId"); + + b.Property("DeleterId") + .HasColumnType("uniqueidentifier") + .HasColumnName("DeleterId"); + + b.Property("DeletionTime") + .HasColumnType("datetime2") + .HasColumnName("DeletionTime"); + + b.Property("DisplayName") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("nvarchar(128)") + .HasColumnName("DisplayName"); + + b.Property("ExtraProperties") + .HasColumnType("nvarchar(max)") + .HasColumnName("ExtraProperties"); + + b.Property("IsDeleted") + .ValueGeneratedOnAdd() + .HasColumnType("bit") + .HasDefaultValue(false) + .HasColumnName("IsDeleted"); + + b.Property("LastModificationTime") + .HasColumnType("datetime2") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uniqueidentifier") + .HasColumnName("LastModifierId"); + + b.Property("ParentId") + .HasColumnType("uniqueidentifier"); + + b.Property("TenantId") + .HasColumnType("uniqueidentifier") + .HasColumnName("TenantId"); + + b.HasKey("Id"); + + b.HasIndex("Code"); + + b.HasIndex("ParentId"); + + b.ToTable("AbpOrganizationUnits"); + }); + + modelBuilder.Entity("Volo.Abp.Identity.OrganizationUnitRole", b => + { + b.Property("OrganizationUnitId") + .HasColumnType("uniqueidentifier"); + + b.Property("RoleId") + .HasColumnType("uniqueidentifier"); + + b.Property("CreationTime") + .HasColumnType("datetime2") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uniqueidentifier") + .HasColumnName("CreatorId"); + + b.Property("TenantId") + .HasColumnType("uniqueidentifier") + .HasColumnName("TenantId"); + + b.HasKey("OrganizationUnitId", "RoleId"); + + b.HasIndex("RoleId", "OrganizationUnitId"); + + b.ToTable("AbpOrganizationUnitRoles"); + }); + + modelBuilder.Entity("Volo.Abp.PermissionManagement.PermissionGrant", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("nvarchar(128)"); + + b.Property("ProviderKey") + .IsRequired() + .HasMaxLength(64) + .HasColumnType("nvarchar(64)"); + + b.Property("ProviderName") + .IsRequired() + .HasMaxLength(64) + .HasColumnType("nvarchar(64)"); + + b.Property("TenantId") + .HasColumnType("uniqueidentifier") + .HasColumnName("TenantId"); + + b.HasKey("Id"); + + b.HasIndex("Name", "ProviderName", "ProviderKey"); + + b.ToTable("AbpPermissionGrants"); + }); + + modelBuilder.Entity("Volo.Abp.SettingManagement.Setting", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("nvarchar(128)"); + + b.Property("ProviderKey") + .HasMaxLength(64) + .HasColumnType("nvarchar(64)"); + + b.Property("ProviderName") + .HasMaxLength(64) + .HasColumnType("nvarchar(64)"); + + b.Property("Value") + .IsRequired() + .HasMaxLength(2048) + .HasColumnType("nvarchar(2048)"); + + b.HasKey("Id"); + + b.HasIndex("Name", "ProviderName", "ProviderKey"); + + b.ToTable("AbpSettings"); + }); + + modelBuilder.Entity("Volo.Abp.TenantManagement.Tenant", 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("CreatorId") + .HasColumnType("uniqueidentifier") + .HasColumnName("CreatorId"); + + b.Property("DeleterId") + .HasColumnType("uniqueidentifier") + .HasColumnName("DeleterId"); + + b.Property("DeletionTime") + .HasColumnType("datetime2") + .HasColumnName("DeletionTime"); + + b.Property("ExtraProperties") + .HasColumnType("nvarchar(max)") + .HasColumnName("ExtraProperties"); + + b.Property("IsDeleted") + .ValueGeneratedOnAdd() + .HasColumnType("bit") + .HasDefaultValue(false) + .HasColumnName("IsDeleted"); + + b.Property("LastModificationTime") + .HasColumnType("datetime2") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uniqueidentifier") + .HasColumnName("LastModifierId"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(64) + .HasColumnType("nvarchar(64)"); + + b.HasKey("Id"); + + b.HasIndex("Name"); + + b.ToTable("AbpTenants"); + }); + + modelBuilder.Entity("Volo.Abp.TenantManagement.TenantConnectionString", b => + { + b.Property("TenantId") + .HasColumnType("uniqueidentifier"); + + b.Property("Name") + .HasMaxLength(64) + .HasColumnType("nvarchar(64)"); + + b.Property("Value") + .IsRequired() + .HasMaxLength(1024) + .HasColumnType("nvarchar(1024)"); + + b.HasKey("TenantId", "Name"); + + b.ToTable("AbpTenantConnectionStrings"); + }); + + modelBuilder.Entity("Volo.CmsKit.Blogs.Blog", 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("CreatorId") + .HasColumnType("uniqueidentifier") + .HasColumnName("CreatorId"); + + b.Property("DeleterId") + .HasColumnType("uniqueidentifier") + .HasColumnName("DeleterId"); + + b.Property("DeletionTime") + .HasColumnType("datetime2") + .HasColumnName("DeletionTime"); + + b.Property("ExtraProperties") + .HasColumnType("nvarchar(max)") + .HasColumnName("ExtraProperties"); + + b.Property("IsDeleted") + .ValueGeneratedOnAdd() + .HasColumnType("bit") + .HasDefaultValue(false) + .HasColumnName("IsDeleted"); + + b.Property("LastModificationTime") + .HasColumnType("datetime2") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uniqueidentifier") + .HasColumnName("LastModifierId"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(64) + .HasColumnType("nvarchar(64)"); + + b.Property("Slug") + .IsRequired() + .HasMaxLength(64) + .HasColumnType("nvarchar(64)"); + + b.Property("TenantId") + .HasColumnType("uniqueidentifier") + .HasColumnName("TenantId"); + + b.HasKey("Id"); + + b.ToTable("CmsBlogs"); + }); + + modelBuilder.Entity("Volo.CmsKit.Blogs.BlogFeature", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("BlogId") + .HasColumnType("uniqueidentifier"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .HasMaxLength(40) + .HasColumnType("nvarchar(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("CreationTime") + .HasColumnType("datetime2") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uniqueidentifier") + .HasColumnName("CreatorId"); + + b.Property("DeleterId") + .HasColumnType("uniqueidentifier") + .HasColumnName("DeleterId"); + + b.Property("DeletionTime") + .HasColumnType("datetime2") + .HasColumnName("DeletionTime"); + + b.Property("ExtraProperties") + .HasColumnType("nvarchar(max)") + .HasColumnName("ExtraProperties"); + + b.Property("FeatureName") + .IsRequired() + .HasMaxLength(64) + .HasColumnType("nvarchar(64)"); + + b.Property("IsDeleted") + .ValueGeneratedOnAdd() + .HasColumnType("bit") + .HasDefaultValue(false) + .HasColumnName("IsDeleted"); + + b.Property("IsEnabled") + .HasColumnType("bit"); + + b.Property("LastModificationTime") + .HasColumnType("datetime2") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uniqueidentifier") + .HasColumnName("LastModifierId"); + + b.HasKey("Id"); + + b.ToTable("CmsBlogFeatures"); + }); + + modelBuilder.Entity("Volo.CmsKit.Blogs.BlogPost", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("AuthorId") + .HasColumnType("uniqueidentifier"); + + b.Property("BlogId") + .HasColumnType("uniqueidentifier"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .HasMaxLength(40) + .HasColumnType("nvarchar(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("Content") + .HasMaxLength(2147483647) + .HasColumnType("nvarchar(max)"); + + b.Property("CreationTime") + .HasColumnType("datetime2") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uniqueidentifier") + .HasColumnName("CreatorId"); + + b.Property("DeleterId") + .HasColumnType("uniqueidentifier") + .HasColumnName("DeleterId"); + + b.Property("DeletionTime") + .HasColumnType("datetime2") + .HasColumnName("DeletionTime"); + + b.Property("ExtraProperties") + .HasColumnType("nvarchar(max)") + .HasColumnName("ExtraProperties"); + + b.Property("IsDeleted") + .ValueGeneratedOnAdd() + .HasColumnType("bit") + .HasDefaultValue(false) + .HasColumnName("IsDeleted"); + + b.Property("LastModificationTime") + .HasColumnType("datetime2") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uniqueidentifier") + .HasColumnName("LastModifierId"); + + b.Property("ShortDescription") + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.Property("Slug") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.Property("TenantId") + .HasColumnType("uniqueidentifier") + .HasColumnName("TenantId"); + + b.Property("Title") + .IsRequired() + .HasMaxLength(64) + .HasColumnType("nvarchar(64)"); + + b.HasKey("Id"); + + b.HasIndex("AuthorId"); + + b.HasIndex("Slug", "BlogId"); + + b.ToTable("CmsBlogPosts"); + }); + + modelBuilder.Entity("Volo.CmsKit.Comments.Comment", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("CreationTime") + .HasColumnType("datetime2") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uniqueidentifier") + .HasColumnName("CreatorId"); + + b.Property("EntityId") + .IsRequired() + .HasMaxLength(64) + .HasColumnType("nvarchar(64)"); + + b.Property("EntityType") + .IsRequired() + .HasMaxLength(64) + .HasColumnType("nvarchar(64)"); + + b.Property("RepliedCommentId") + .HasColumnType("uniqueidentifier"); + + b.Property("TenantId") + .HasColumnType("uniqueidentifier") + .HasColumnName("TenantId"); + + b.Property("Text") + .IsRequired() + .HasMaxLength(512) + .HasColumnType("nvarchar(512)"); + + b.HasKey("Id"); + + b.HasIndex("TenantId", "RepliedCommentId"); + + b.HasIndex("TenantId", "EntityType", "EntityId"); + + b.ToTable("CmsComments"); + }); + + modelBuilder.Entity("Volo.CmsKit.Contents.Content", 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("CreatorId") + .HasColumnType("uniqueidentifier") + .HasColumnName("CreatorId"); + + b.Property("DeleterId") + .HasColumnType("uniqueidentifier") + .HasColumnName("DeleterId"); + + b.Property("DeletionTime") + .HasColumnType("datetime2") + .HasColumnName("DeletionTime"); + + b.Property("EntityId") + .IsRequired() + .HasMaxLength(64) + .HasColumnType("nvarchar(64)"); + + b.Property("EntityType") + .IsRequired() + .HasMaxLength(64) + .HasColumnType("nvarchar(64)"); + + b.Property("ExtraProperties") + .HasColumnType("nvarchar(max)") + .HasColumnName("ExtraProperties"); + + b.Property("IsDeleted") + .ValueGeneratedOnAdd() + .HasColumnType("bit") + .HasDefaultValue(false) + .HasColumnName("IsDeleted"); + + b.Property("LastModificationTime") + .HasColumnType("datetime2") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uniqueidentifier") + .HasColumnName("LastModifierId"); + + b.Property("TenantId") + .HasColumnType("uniqueidentifier") + .HasColumnName("TenantId"); + + b.Property("Value") + .IsRequired() + .HasMaxLength(2147483647) + .HasColumnType("nvarchar(max)"); + + b.HasKey("Id"); + + b.HasIndex("TenantId", "EntityType", "EntityId"); + + b.ToTable("CmsContents"); + }); + + modelBuilder.Entity("Volo.CmsKit.MediaDescriptors.MediaDescriptor", 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("CreatorId") + .HasColumnType("uniqueidentifier") + .HasColumnName("CreatorId"); + + b.Property("DeleterId") + .HasColumnType("uniqueidentifier") + .HasColumnName("DeleterId"); + + b.Property("DeletionTime") + .HasColumnType("datetime2") + .HasColumnName("DeletionTime"); + + b.Property("EntityType") + .IsRequired() + .HasMaxLength(64) + .HasColumnType("nvarchar(64)"); + + b.Property("ExtraProperties") + .HasColumnType("nvarchar(max)") + .HasColumnName("ExtraProperties"); + + b.Property("IsDeleted") + .ValueGeneratedOnAdd() + .HasColumnType("bit") + .HasDefaultValue(false) + .HasColumnName("IsDeleted"); + + b.Property("LastModificationTime") + .HasColumnType("datetime2") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uniqueidentifier") + .HasColumnName("LastModifierId"); + + b.Property("MimeType") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("nvarchar(128)"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("nvarchar(255)"); + + b.Property("Size") + .HasMaxLength(2147483647) + .HasColumnType("bigint"); + + b.Property("TenantId") + .HasColumnType("uniqueidentifier") + .HasColumnName("TenantId"); + + b.HasKey("Id"); + + b.ToTable("CmsMediaDescriptors"); + }); + + modelBuilder.Entity("Volo.CmsKit.Pages.Page", 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("CreatorId") + .HasColumnType("uniqueidentifier") + .HasColumnName("CreatorId"); + + b.Property("DeleterId") + .HasColumnType("uniqueidentifier") + .HasColumnName("DeleterId"); + + b.Property("DeletionTime") + .HasColumnType("datetime2") + .HasColumnName("DeletionTime"); + + b.Property("ExtraProperties") + .HasColumnType("nvarchar(max)") + .HasColumnName("ExtraProperties"); + + b.Property("IsDeleted") + .ValueGeneratedOnAdd() + .HasColumnType("bit") + .HasDefaultValue(false) + .HasColumnName("IsDeleted"); + + b.Property("LastModificationTime") + .HasColumnType("datetime2") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uniqueidentifier") + .HasColumnName("LastModifierId"); + + b.Property("Slug") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.Property("TenantId") + .HasColumnType("uniqueidentifier") + .HasColumnName("TenantId"); + + b.Property("Title") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.HasKey("Id"); + + b.HasIndex("TenantId", "Slug"); + + b.ToTable("CmsPages"); + }); + + modelBuilder.Entity("Volo.CmsKit.Ratings.Rating", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("CreationTime") + .HasColumnType("datetime2") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uniqueidentifier") + .HasColumnName("CreatorId"); + + b.Property("EntityId") + .IsRequired() + .HasMaxLength(64) + .HasColumnType("nvarchar(64)"); + + b.Property("EntityType") + .IsRequired() + .HasMaxLength(64) + .HasColumnType("nvarchar(64)"); + + b.Property("StarCount") + .HasColumnType("smallint"); + + b.Property("TenantId") + .HasColumnType("uniqueidentifier"); + + b.HasKey("Id"); + + b.HasIndex("TenantId", "EntityType", "EntityId", "CreatorId"); + + b.ToTable("CmsRatings"); + }); + + modelBuilder.Entity("Volo.CmsKit.Reactions.UserReaction", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("CreationTime") + .HasColumnType("datetime2") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uniqueidentifier") + .HasColumnName("CreatorId"); + + b.Property("EntityId") + .IsRequired() + .HasMaxLength(64) + .HasColumnType("nvarchar(64)"); + + b.Property("EntityType") + .IsRequired() + .HasMaxLength(64) + .HasColumnType("nvarchar(64)"); + + b.Property("ReactionName") + .IsRequired() + .HasMaxLength(32) + .HasColumnType("nvarchar(32)"); + + b.Property("TenantId") + .HasColumnType("uniqueidentifier") + .HasColumnName("TenantId"); + + b.HasKey("Id"); + + b.HasIndex("TenantId", "EntityType", "EntityId", "ReactionName"); + + b.HasIndex("TenantId", "CreatorId", "EntityType", "EntityId", "ReactionName"); + + b.ToTable("CmsUserReactions"); + }); + + modelBuilder.Entity("Volo.CmsKit.Tags.EntityTag", b => + { + b.Property("EntityId") + .HasColumnType("nvarchar(450)"); + + b.Property("TagId") + .HasColumnType("uniqueidentifier"); + + b.Property("TenantId") + .HasColumnType("uniqueidentifier") + .HasColumnName("TenantId"); + + b.HasKey("EntityId", "TagId"); + + b.HasIndex("TenantId", "EntityId", "TagId"); + + b.ToTable("CmsEntityTags"); + }); + + modelBuilder.Entity("Volo.CmsKit.Tags.Tag", 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("CreatorId") + .HasColumnType("uniqueidentifier") + .HasColumnName("CreatorId"); + + b.Property("DeleterId") + .HasColumnType("uniqueidentifier") + .HasColumnName("DeleterId"); + + b.Property("DeletionTime") + .HasColumnType("datetime2") + .HasColumnName("DeletionTime"); + + b.Property("EntityType") + .IsRequired() + .HasMaxLength(64) + .HasColumnType("nvarchar(64)"); + + b.Property("ExtraProperties") + .HasColumnType("nvarchar(max)") + .HasColumnName("ExtraProperties"); + + b.Property("IsDeleted") + .ValueGeneratedOnAdd() + .HasColumnType("bit") + .HasDefaultValue(false) + .HasColumnName("IsDeleted"); + + b.Property("LastModificationTime") + .HasColumnType("datetime2") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uniqueidentifier") + .HasColumnName("LastModifierId"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(32) + .HasColumnType("nvarchar(32)"); + + b.Property("TenantId") + .HasColumnType("uniqueidentifier") + .HasColumnName("TenantId"); + + b.HasKey("Id"); + + b.HasIndex("TenantId", "Name"); + + b.ToTable("CmsTags"); + }); + + modelBuilder.Entity("Volo.CmsKit.Users.CmsUser", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .HasMaxLength(40) + .HasColumnType("nvarchar(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("Email") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("nvarchar(256)") + .HasColumnName("Email"); + + b.Property("EmailConfirmed") + .ValueGeneratedOnAdd() + .HasColumnType("bit") + .HasDefaultValue(false) + .HasColumnName("EmailConfirmed"); + + b.Property("ExtraProperties") + .HasColumnType("nvarchar(max)") + .HasColumnName("ExtraProperties"); + + b.Property("Name") + .HasMaxLength(64) + .HasColumnType("nvarchar(64)") + .HasColumnName("Name"); + + b.Property("PhoneNumber") + .HasMaxLength(16) + .HasColumnType("nvarchar(16)") + .HasColumnName("PhoneNumber"); + + b.Property("PhoneNumberConfirmed") + .ValueGeneratedOnAdd() + .HasColumnType("bit") + .HasDefaultValue(false) + .HasColumnName("PhoneNumberConfirmed"); + + b.Property("Surname") + .HasMaxLength(64) + .HasColumnType("nvarchar(64)") + .HasColumnName("Surname"); + + b.Property("TenantId") + .HasColumnType("uniqueidentifier") + .HasColumnName("TenantId"); + + b.Property("UserName") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("nvarchar(256)") + .HasColumnName("UserName"); + + b.HasKey("Id"); + + b.HasIndex("TenantId", "Email"); + + b.HasIndex("TenantId", "UserName"); + + b.ToTable("CmsUsers"); + }); + + modelBuilder.Entity("Volo.Abp.AuditLogging.AuditLogAction", b => + { + b.HasOne("Volo.Abp.AuditLogging.AuditLog", null) + .WithMany("Actions") + .HasForeignKey("AuditLogId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Volo.Abp.AuditLogging.EntityChange", b => + { + b.HasOne("Volo.Abp.AuditLogging.AuditLog", null) + .WithMany("EntityChanges") + .HasForeignKey("AuditLogId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Volo.Abp.AuditLogging.EntityPropertyChange", b => + { + b.HasOne("Volo.Abp.AuditLogging.EntityChange", null) + .WithMany("PropertyChanges") + .HasForeignKey("EntityChangeId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Volo.Abp.BlobStoring.Database.DatabaseBlob", b => + { + b.HasOne("Volo.Abp.BlobStoring.Database.DatabaseBlobContainer", null) + .WithMany() + .HasForeignKey("ContainerId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityRoleClaim", b => + { + b.HasOne("Volo.Abp.Identity.IdentityRole", null) + .WithMany("Claims") + .HasForeignKey("RoleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityUserClaim", b => + { + b.HasOne("Volo.Abp.Identity.IdentityUser", null) + .WithMany("Claims") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityUserLogin", b => + { + b.HasOne("Volo.Abp.Identity.IdentityUser", null) + .WithMany("Logins") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityUserOrganizationUnit", b => + { + b.HasOne("Volo.Abp.Identity.OrganizationUnit", null) + .WithMany() + .HasForeignKey("OrganizationUnitId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Volo.Abp.Identity.IdentityUser", null) + .WithMany("OrganizationUnits") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityUserRole", b => + { + b.HasOne("Volo.Abp.Identity.IdentityRole", null) + .WithMany() + .HasForeignKey("RoleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Volo.Abp.Identity.IdentityUser", null) + .WithMany("Roles") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityUserToken", b => + { + b.HasOne("Volo.Abp.Identity.IdentityUser", null) + .WithMany("Tokens") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Volo.Abp.Identity.OrganizationUnit", b => + { + b.HasOne("Volo.Abp.Identity.OrganizationUnit", null) + .WithMany() + .HasForeignKey("ParentId"); + }); + + modelBuilder.Entity("Volo.Abp.Identity.OrganizationUnitRole", b => + { + b.HasOne("Volo.Abp.Identity.OrganizationUnit", null) + .WithMany("Roles") + .HasForeignKey("OrganizationUnitId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Volo.Abp.Identity.IdentityRole", null) + .WithMany() + .HasForeignKey("RoleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Volo.Abp.TenantManagement.TenantConnectionString", b => + { + b.HasOne("Volo.Abp.TenantManagement.Tenant", null) + .WithMany("ConnectionStrings") + .HasForeignKey("TenantId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Volo.CmsKit.Blogs.BlogPost", b => + { + b.HasOne("Volo.CmsKit.Users.CmsUser", "Author") + .WithMany() + .HasForeignKey("AuthorId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Author"); + }); + + modelBuilder.Entity("Volo.Abp.AuditLogging.AuditLog", b => + { + b.Navigation("Actions"); + + b.Navigation("EntityChanges"); + }); + + modelBuilder.Entity("Volo.Abp.AuditLogging.EntityChange", b => + { + b.Navigation("PropertyChanges"); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityRole", b => + { + b.Navigation("Claims"); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityUser", b => + { + b.Navigation("Claims"); + + b.Navigation("Logins"); + + b.Navigation("OrganizationUnits"); + + b.Navigation("Roles"); + + b.Navigation("Tokens"); + }); + + modelBuilder.Entity("Volo.Abp.Identity.OrganizationUnit", b => + { + b.Navigation("Roles"); + }); + + modelBuilder.Entity("Volo.Abp.TenantManagement.Tenant", b => + { + b.Navigation("ConnectionStrings"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/modules/cms-kit/host/Volo.CmsKit.Web.Unified/Migrations/20210302075529_Added_Content_To_BlogPost.cs b/modules/cms-kit/host/Volo.CmsKit.Web.Unified/Migrations/20210302075529_Added_Content_To_BlogPost.cs new file mode 100644 index 0000000000..836507c222 --- /dev/null +++ b/modules/cms-kit/host/Volo.CmsKit.Web.Unified/Migrations/20210302075529_Added_Content_To_BlogPost.cs @@ -0,0 +1,24 @@ +using Microsoft.EntityFrameworkCore.Migrations; + +namespace Volo.CmsKit.Migrations +{ + public partial class Added_Content_To_BlogPost : Migration + { + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.AddColumn( + name: "Content", + table: "CmsBlogPosts", + type: "nvarchar(max)", + maxLength: 2147483647, + nullable: true); + } + + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropColumn( + name: "Content", + table: "CmsBlogPosts"); + } + } +} diff --git a/modules/cms-kit/host/Volo.CmsKit.Web.Unified/Migrations/20210302091451_Added_Content_To_Page.Designer.cs b/modules/cms-kit/host/Volo.CmsKit.Web.Unified/Migrations/20210302091451_Added_Content_To_Page.Designer.cs new file mode 100644 index 0000000000..6c89519250 --- /dev/null +++ b/modules/cms-kit/host/Volo.CmsKit.Web.Unified/Migrations/20210302091451_Added_Content_To_Page.Designer.cs @@ -0,0 +1,2020 @@ +// +using System; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Metadata; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; +using Volo.Abp.EntityFrameworkCore; +using Volo.CmsKit.EntityFrameworkCore; + +namespace Volo.CmsKit.Migrations +{ + [DbContext(typeof(UnifiedDbContext))] + [Migration("20210302091451_Added_Content_To_Page")] + partial class Added_Content_To_Page + { + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("_Abp_DatabaseProvider", EfCoreDatabaseProvider.SqlServer) + .HasAnnotation("Relational:MaxIdentifierLength", 128) + .HasAnnotation("ProductVersion", "5.0.3") + .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); + + modelBuilder.Entity("Volo.Abp.AuditLogging.AuditLog", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("ApplicationName") + .HasMaxLength(96) + .HasColumnType("nvarchar(96)") + .HasColumnName("ApplicationName"); + + b.Property("BrowserInfo") + .HasMaxLength(512) + .HasColumnType("nvarchar(512)") + .HasColumnName("BrowserInfo"); + + b.Property("ClientId") + .HasMaxLength(64) + .HasColumnType("nvarchar(64)") + .HasColumnName("ClientId"); + + b.Property("ClientIpAddress") + .HasMaxLength(64) + .HasColumnType("nvarchar(64)") + .HasColumnName("ClientIpAddress"); + + b.Property("ClientName") + .HasMaxLength(128) + .HasColumnType("nvarchar(128)") + .HasColumnName("ClientName"); + + b.Property("Comments") + .HasMaxLength(256) + .HasColumnType("nvarchar(256)") + .HasColumnName("Comments"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .HasMaxLength(40) + .HasColumnType("nvarchar(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("CorrelationId") + .HasMaxLength(64) + .HasColumnType("nvarchar(64)") + .HasColumnName("CorrelationId"); + + b.Property("Exceptions") + .HasMaxLength(4000) + .HasColumnType("nvarchar(4000)") + .HasColumnName("Exceptions"); + + b.Property("ExecutionDuration") + .HasColumnType("int") + .HasColumnName("ExecutionDuration"); + + b.Property("ExecutionTime") + .HasColumnType("datetime2"); + + b.Property("ExtraProperties") + .HasColumnType("nvarchar(max)") + .HasColumnName("ExtraProperties"); + + b.Property("HttpMethod") + .HasMaxLength(16) + .HasColumnType("nvarchar(16)") + .HasColumnName("HttpMethod"); + + b.Property("HttpStatusCode") + .HasColumnType("int") + .HasColumnName("HttpStatusCode"); + + b.Property("ImpersonatorTenantId") + .HasColumnType("uniqueidentifier") + .HasColumnName("ImpersonatorTenantId"); + + b.Property("ImpersonatorUserId") + .HasColumnType("uniqueidentifier") + .HasColumnName("ImpersonatorUserId"); + + b.Property("TenantId") + .HasColumnType("uniqueidentifier") + .HasColumnName("TenantId"); + + b.Property("TenantName") + .HasColumnType("nvarchar(max)"); + + b.Property("Url") + .HasMaxLength(256) + .HasColumnType("nvarchar(256)") + .HasColumnName("Url"); + + b.Property("UserId") + .HasColumnType("uniqueidentifier") + .HasColumnName("UserId"); + + b.Property("UserName") + .HasMaxLength(256) + .HasColumnType("nvarchar(256)") + .HasColumnName("UserName"); + + b.HasKey("Id"); + + b.HasIndex("TenantId", "ExecutionTime"); + + b.HasIndex("TenantId", "UserId", "ExecutionTime"); + + b.ToTable("AbpAuditLogs"); + }); + + modelBuilder.Entity("Volo.Abp.AuditLogging.AuditLogAction", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("AuditLogId") + .HasColumnType("uniqueidentifier") + .HasColumnName("AuditLogId"); + + b.Property("ExecutionDuration") + .HasColumnType("int") + .HasColumnName("ExecutionDuration"); + + b.Property("ExecutionTime") + .HasColumnType("datetime2") + .HasColumnName("ExecutionTime"); + + b.Property("ExtraProperties") + .HasColumnType("nvarchar(max)") + .HasColumnName("ExtraProperties"); + + b.Property("MethodName") + .HasMaxLength(128) + .HasColumnType("nvarchar(128)") + .HasColumnName("MethodName"); + + b.Property("Parameters") + .HasMaxLength(2000) + .HasColumnType("nvarchar(2000)") + .HasColumnName("Parameters"); + + b.Property("ServiceName") + .HasMaxLength(256) + .HasColumnType("nvarchar(256)") + .HasColumnName("ServiceName"); + + b.Property("TenantId") + .HasColumnType("uniqueidentifier") + .HasColumnName("TenantId"); + + b.HasKey("Id"); + + b.HasIndex("AuditLogId"); + + b.HasIndex("TenantId", "ServiceName", "MethodName", "ExecutionTime"); + + b.ToTable("AbpAuditLogActions"); + }); + + modelBuilder.Entity("Volo.Abp.AuditLogging.EntityChange", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("AuditLogId") + .HasColumnType("uniqueidentifier") + .HasColumnName("AuditLogId"); + + b.Property("ChangeTime") + .HasColumnType("datetime2") + .HasColumnName("ChangeTime"); + + b.Property("ChangeType") + .HasColumnType("tinyint") + .HasColumnName("ChangeType"); + + b.Property("EntityId") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("nvarchar(128)") + .HasColumnName("EntityId"); + + b.Property("EntityTenantId") + .HasColumnType("uniqueidentifier"); + + b.Property("EntityTypeFullName") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("nvarchar(128)") + .HasColumnName("EntityTypeFullName"); + + b.Property("ExtraProperties") + .HasColumnType("nvarchar(max)") + .HasColumnName("ExtraProperties"); + + b.Property("TenantId") + .HasColumnType("uniqueidentifier") + .HasColumnName("TenantId"); + + b.HasKey("Id"); + + b.HasIndex("AuditLogId"); + + b.HasIndex("TenantId", "EntityTypeFullName", "EntityId"); + + b.ToTable("AbpEntityChanges"); + }); + + modelBuilder.Entity("Volo.Abp.AuditLogging.EntityPropertyChange", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("EntityChangeId") + .HasColumnType("uniqueidentifier"); + + b.Property("NewValue") + .HasMaxLength(512) + .HasColumnType("nvarchar(512)") + .HasColumnName("NewValue"); + + b.Property("OriginalValue") + .HasMaxLength(512) + .HasColumnType("nvarchar(512)") + .HasColumnName("OriginalValue"); + + b.Property("PropertyName") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("nvarchar(128)") + .HasColumnName("PropertyName"); + + b.Property("PropertyTypeFullName") + .IsRequired() + .HasMaxLength(64) + .HasColumnType("nvarchar(64)") + .HasColumnName("PropertyTypeFullName"); + + b.Property("TenantId") + .HasColumnType("uniqueidentifier") + .HasColumnName("TenantId"); + + b.HasKey("Id"); + + b.HasIndex("EntityChangeId"); + + b.ToTable("AbpEntityPropertyChanges"); + }); + + modelBuilder.Entity("Volo.Abp.BlobStoring.Database.DatabaseBlob", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .HasMaxLength(40) + .HasColumnType("nvarchar(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("ContainerId") + .HasColumnType("uniqueidentifier"); + + b.Property("Content") + .HasMaxLength(2147483647) + .HasColumnType("varbinary(max)"); + + b.Property("ExtraProperties") + .HasColumnType("nvarchar(max)") + .HasColumnName("ExtraProperties"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.Property("TenantId") + .HasColumnType("uniqueidentifier") + .HasColumnName("TenantId"); + + b.HasKey("Id"); + + b.HasIndex("ContainerId"); + + b.HasIndex("TenantId", "ContainerId", "Name"); + + b.ToTable("AbpBlobs"); + }); + + modelBuilder.Entity("Volo.Abp.BlobStoring.Database.DatabaseBlobContainer", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .HasMaxLength(40) + .HasColumnType("nvarchar(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("ExtraProperties") + .HasColumnType("nvarchar(max)") + .HasColumnName("ExtraProperties"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("nvarchar(128)"); + + b.Property("TenantId") + .HasColumnType("uniqueidentifier") + .HasColumnName("TenantId"); + + b.HasKey("Id"); + + b.HasIndex("TenantId", "Name"); + + b.ToTable("AbpBlobContainers"); + }); + + modelBuilder.Entity("Volo.Abp.FeatureManagement.FeatureValue", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("nvarchar(128)"); + + b.Property("ProviderKey") + .HasMaxLength(64) + .HasColumnType("nvarchar(64)"); + + b.Property("ProviderName") + .HasMaxLength(64) + .HasColumnType("nvarchar(64)"); + + b.Property("Value") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("nvarchar(128)"); + + b.HasKey("Id"); + + b.HasIndex("Name", "ProviderName", "ProviderKey"); + + b.ToTable("AbpFeatureValues"); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityClaimType", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .HasMaxLength(40) + .HasColumnType("nvarchar(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("Description") + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.Property("ExtraProperties") + .HasColumnType("nvarchar(max)") + .HasColumnName("ExtraProperties"); + + b.Property("IsStatic") + .HasColumnType("bit"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.Property("Regex") + .HasMaxLength(512) + .HasColumnType("nvarchar(512)"); + + b.Property("RegexDescription") + .HasMaxLength(128) + .HasColumnType("nvarchar(128)"); + + b.Property("Required") + .HasColumnType("bit"); + + b.Property("ValueType") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.ToTable("AbpClaimTypes"); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityLinkUser", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("SourceTenantId") + .HasColumnType("uniqueidentifier"); + + b.Property("SourceUserId") + .HasColumnType("uniqueidentifier"); + + b.Property("TargetTenantId") + .HasColumnType("uniqueidentifier"); + + b.Property("TargetUserId") + .HasColumnType("uniqueidentifier"); + + b.HasKey("Id"); + + b.HasIndex("SourceUserId", "SourceTenantId", "TargetUserId", "TargetTenantId") + .IsUnique() + .HasFilter("[SourceTenantId] IS NOT NULL AND [TargetTenantId] IS NOT NULL"); + + b.ToTable("AbpLinkUsers"); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityRole", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .HasMaxLength(40) + .HasColumnType("nvarchar(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("ExtraProperties") + .HasColumnType("nvarchar(max)") + .HasColumnName("ExtraProperties"); + + b.Property("IsDefault") + .HasColumnType("bit") + .HasColumnName("IsDefault"); + + b.Property("IsPublic") + .HasColumnType("bit") + .HasColumnName("IsPublic"); + + b.Property("IsStatic") + .HasColumnType("bit") + .HasColumnName("IsStatic"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.Property("NormalizedName") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.Property("TenantId") + .HasColumnType("uniqueidentifier") + .HasColumnName("TenantId"); + + b.HasKey("Id"); + + b.HasIndex("NormalizedName"); + + b.ToTable("AbpRoles"); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityRoleClaim", b => + { + b.Property("Id") + .HasColumnType("uniqueidentifier"); + + b.Property("ClaimType") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.Property("ClaimValue") + .HasMaxLength(1024) + .HasColumnType("nvarchar(1024)"); + + b.Property("RoleId") + .HasColumnType("uniqueidentifier"); + + b.Property("TenantId") + .HasColumnType("uniqueidentifier") + .HasColumnName("TenantId"); + + b.HasKey("Id"); + + b.HasIndex("RoleId"); + + b.ToTable("AbpRoleClaims"); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentitySecurityLog", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("Action") + .HasMaxLength(96) + .HasColumnType("nvarchar(96)"); + + b.Property("ApplicationName") + .HasMaxLength(96) + .HasColumnType("nvarchar(96)"); + + b.Property("BrowserInfo") + .HasMaxLength(512) + .HasColumnType("nvarchar(512)"); + + b.Property("ClientId") + .HasMaxLength(64) + .HasColumnType("nvarchar(64)"); + + b.Property("ClientIpAddress") + .HasMaxLength(64) + .HasColumnType("nvarchar(64)"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .HasMaxLength(40) + .HasColumnType("nvarchar(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("CorrelationId") + .HasMaxLength(64) + .HasColumnType("nvarchar(64)"); + + b.Property("CreationTime") + .HasColumnType("datetime2"); + + b.Property("ExtraProperties") + .HasColumnType("nvarchar(max)") + .HasColumnName("ExtraProperties"); + + b.Property("Identity") + .HasMaxLength(96) + .HasColumnType("nvarchar(96)"); + + b.Property("TenantId") + .HasColumnType("uniqueidentifier") + .HasColumnName("TenantId"); + + b.Property("TenantName") + .HasMaxLength(64) + .HasColumnType("nvarchar(64)"); + + b.Property("UserId") + .HasColumnType("uniqueidentifier"); + + b.Property("UserName") + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.HasKey("Id"); + + b.HasIndex("TenantId", "Action"); + + b.HasIndex("TenantId", "ApplicationName"); + + b.HasIndex("TenantId", "Identity"); + + b.HasIndex("TenantId", "UserId"); + + b.ToTable("AbpSecurityLogs"); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityUser", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("AccessFailedCount") + .ValueGeneratedOnAdd() + .HasColumnType("int") + .HasDefaultValue(0) + .HasColumnName("AccessFailedCount"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .HasMaxLength(40) + .HasColumnType("nvarchar(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("CreationTime") + .HasColumnType("datetime2") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uniqueidentifier") + .HasColumnName("CreatorId"); + + b.Property("DeleterId") + .HasColumnType("uniqueidentifier") + .HasColumnName("DeleterId"); + + b.Property("DeletionTime") + .HasColumnType("datetime2") + .HasColumnName("DeletionTime"); + + b.Property("Email") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("nvarchar(256)") + .HasColumnName("Email"); + + b.Property("EmailConfirmed") + .ValueGeneratedOnAdd() + .HasColumnType("bit") + .HasDefaultValue(false) + .HasColumnName("EmailConfirmed"); + + b.Property("ExtraProperties") + .HasColumnType("nvarchar(max)") + .HasColumnName("ExtraProperties"); + + b.Property("IsDeleted") + .ValueGeneratedOnAdd() + .HasColumnType("bit") + .HasDefaultValue(false) + .HasColumnName("IsDeleted"); + + b.Property("IsExternal") + .ValueGeneratedOnAdd() + .HasColumnType("bit") + .HasDefaultValue(false) + .HasColumnName("IsExternal"); + + b.Property("LastModificationTime") + .HasColumnType("datetime2") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uniqueidentifier") + .HasColumnName("LastModifierId"); + + b.Property("LockoutEnabled") + .ValueGeneratedOnAdd() + .HasColumnType("bit") + .HasDefaultValue(false) + .HasColumnName("LockoutEnabled"); + + b.Property("LockoutEnd") + .HasColumnType("datetimeoffset"); + + b.Property("Name") + .HasMaxLength(64) + .HasColumnType("nvarchar(64)") + .HasColumnName("Name"); + + b.Property("NormalizedEmail") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("nvarchar(256)") + .HasColumnName("NormalizedEmail"); + + b.Property("NormalizedUserName") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("nvarchar(256)") + .HasColumnName("NormalizedUserName"); + + b.Property("PasswordHash") + .HasMaxLength(256) + .HasColumnType("nvarchar(256)") + .HasColumnName("PasswordHash"); + + b.Property("PhoneNumber") + .HasMaxLength(16) + .HasColumnType("nvarchar(16)") + .HasColumnName("PhoneNumber"); + + b.Property("PhoneNumberConfirmed") + .ValueGeneratedOnAdd() + .HasColumnType("bit") + .HasDefaultValue(false) + .HasColumnName("PhoneNumberConfirmed"); + + b.Property("SecurityStamp") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("nvarchar(256)") + .HasColumnName("SecurityStamp"); + + b.Property("Surname") + .HasMaxLength(64) + .HasColumnType("nvarchar(64)") + .HasColumnName("Surname"); + + b.Property("TenantId") + .HasColumnType("uniqueidentifier") + .HasColumnName("TenantId"); + + b.Property("TwoFactorEnabled") + .ValueGeneratedOnAdd() + .HasColumnType("bit") + .HasDefaultValue(false) + .HasColumnName("TwoFactorEnabled"); + + b.Property("UserName") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("nvarchar(256)") + .HasColumnName("UserName"); + + b.HasKey("Id"); + + b.HasIndex("Email"); + + b.HasIndex("NormalizedEmail"); + + b.HasIndex("NormalizedUserName"); + + b.HasIndex("UserName"); + + b.ToTable("AbpUsers"); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityUserClaim", b => + { + b.Property("Id") + .HasColumnType("uniqueidentifier"); + + b.Property("ClaimType") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.Property("ClaimValue") + .HasMaxLength(1024) + .HasColumnType("nvarchar(1024)"); + + b.Property("TenantId") + .HasColumnType("uniqueidentifier") + .HasColumnName("TenantId"); + + b.Property("UserId") + .HasColumnType("uniqueidentifier"); + + b.HasKey("Id"); + + b.HasIndex("UserId"); + + b.ToTable("AbpUserClaims"); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityUserLogin", b => + { + b.Property("UserId") + .HasColumnType("uniqueidentifier"); + + b.Property("LoginProvider") + .HasMaxLength(64) + .HasColumnType("nvarchar(64)"); + + b.Property("ProviderDisplayName") + .HasMaxLength(128) + .HasColumnType("nvarchar(128)"); + + b.Property("ProviderKey") + .IsRequired() + .HasMaxLength(196) + .HasColumnType("nvarchar(196)"); + + b.Property("TenantId") + .HasColumnType("uniqueidentifier") + .HasColumnName("TenantId"); + + b.HasKey("UserId", "LoginProvider"); + + b.HasIndex("LoginProvider", "ProviderKey"); + + b.ToTable("AbpUserLogins"); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityUserOrganizationUnit", b => + { + b.Property("OrganizationUnitId") + .HasColumnType("uniqueidentifier"); + + b.Property("UserId") + .HasColumnType("uniqueidentifier"); + + b.Property("CreationTime") + .HasColumnType("datetime2") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uniqueidentifier") + .HasColumnName("CreatorId"); + + b.Property("TenantId") + .HasColumnType("uniqueidentifier") + .HasColumnName("TenantId"); + + b.HasKey("OrganizationUnitId", "UserId"); + + b.HasIndex("UserId", "OrganizationUnitId"); + + b.ToTable("AbpUserOrganizationUnits"); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityUserRole", b => + { + b.Property("UserId") + .HasColumnType("uniqueidentifier"); + + b.Property("RoleId") + .HasColumnType("uniqueidentifier"); + + b.Property("TenantId") + .HasColumnType("uniqueidentifier") + .HasColumnName("TenantId"); + + b.HasKey("UserId", "RoleId"); + + b.HasIndex("RoleId", "UserId"); + + b.ToTable("AbpUserRoles"); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityUserToken", b => + { + b.Property("UserId") + .HasColumnType("uniqueidentifier"); + + b.Property("LoginProvider") + .HasMaxLength(64) + .HasColumnType("nvarchar(64)"); + + b.Property("Name") + .HasMaxLength(128) + .HasColumnType("nvarchar(128)"); + + b.Property("TenantId") + .HasColumnType("uniqueidentifier") + .HasColumnName("TenantId"); + + b.Property("Value") + .HasColumnType("nvarchar(max)"); + + b.HasKey("UserId", "LoginProvider", "Name"); + + b.ToTable("AbpUserTokens"); + }); + + modelBuilder.Entity("Volo.Abp.Identity.OrganizationUnit", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("Code") + .IsRequired() + .HasMaxLength(95) + .HasColumnType("nvarchar(95)") + .HasColumnName("Code"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .HasMaxLength(40) + .HasColumnType("nvarchar(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("CreationTime") + .HasColumnType("datetime2") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uniqueidentifier") + .HasColumnName("CreatorId"); + + b.Property("DeleterId") + .HasColumnType("uniqueidentifier") + .HasColumnName("DeleterId"); + + b.Property("DeletionTime") + .HasColumnType("datetime2") + .HasColumnName("DeletionTime"); + + b.Property("DisplayName") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("nvarchar(128)") + .HasColumnName("DisplayName"); + + b.Property("ExtraProperties") + .HasColumnType("nvarchar(max)") + .HasColumnName("ExtraProperties"); + + b.Property("IsDeleted") + .ValueGeneratedOnAdd() + .HasColumnType("bit") + .HasDefaultValue(false) + .HasColumnName("IsDeleted"); + + b.Property("LastModificationTime") + .HasColumnType("datetime2") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uniqueidentifier") + .HasColumnName("LastModifierId"); + + b.Property("ParentId") + .HasColumnType("uniqueidentifier"); + + b.Property("TenantId") + .HasColumnType("uniqueidentifier") + .HasColumnName("TenantId"); + + b.HasKey("Id"); + + b.HasIndex("Code"); + + b.HasIndex("ParentId"); + + b.ToTable("AbpOrganizationUnits"); + }); + + modelBuilder.Entity("Volo.Abp.Identity.OrganizationUnitRole", b => + { + b.Property("OrganizationUnitId") + .HasColumnType("uniqueidentifier"); + + b.Property("RoleId") + .HasColumnType("uniqueidentifier"); + + b.Property("CreationTime") + .HasColumnType("datetime2") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uniqueidentifier") + .HasColumnName("CreatorId"); + + b.Property("TenantId") + .HasColumnType("uniqueidentifier") + .HasColumnName("TenantId"); + + b.HasKey("OrganizationUnitId", "RoleId"); + + b.HasIndex("RoleId", "OrganizationUnitId"); + + b.ToTable("AbpOrganizationUnitRoles"); + }); + + modelBuilder.Entity("Volo.Abp.PermissionManagement.PermissionGrant", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("nvarchar(128)"); + + b.Property("ProviderKey") + .IsRequired() + .HasMaxLength(64) + .HasColumnType("nvarchar(64)"); + + b.Property("ProviderName") + .IsRequired() + .HasMaxLength(64) + .HasColumnType("nvarchar(64)"); + + b.Property("TenantId") + .HasColumnType("uniqueidentifier") + .HasColumnName("TenantId"); + + b.HasKey("Id"); + + b.HasIndex("Name", "ProviderName", "ProviderKey"); + + b.ToTable("AbpPermissionGrants"); + }); + + modelBuilder.Entity("Volo.Abp.SettingManagement.Setting", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("nvarchar(128)"); + + b.Property("ProviderKey") + .HasMaxLength(64) + .HasColumnType("nvarchar(64)"); + + b.Property("ProviderName") + .HasMaxLength(64) + .HasColumnType("nvarchar(64)"); + + b.Property("Value") + .IsRequired() + .HasMaxLength(2048) + .HasColumnType("nvarchar(2048)"); + + b.HasKey("Id"); + + b.HasIndex("Name", "ProviderName", "ProviderKey"); + + b.ToTable("AbpSettings"); + }); + + modelBuilder.Entity("Volo.Abp.TenantManagement.Tenant", 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("CreatorId") + .HasColumnType("uniqueidentifier") + .HasColumnName("CreatorId"); + + b.Property("DeleterId") + .HasColumnType("uniqueidentifier") + .HasColumnName("DeleterId"); + + b.Property("DeletionTime") + .HasColumnType("datetime2") + .HasColumnName("DeletionTime"); + + b.Property("ExtraProperties") + .HasColumnType("nvarchar(max)") + .HasColumnName("ExtraProperties"); + + b.Property("IsDeleted") + .ValueGeneratedOnAdd() + .HasColumnType("bit") + .HasDefaultValue(false) + .HasColumnName("IsDeleted"); + + b.Property("LastModificationTime") + .HasColumnType("datetime2") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uniqueidentifier") + .HasColumnName("LastModifierId"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(64) + .HasColumnType("nvarchar(64)"); + + b.HasKey("Id"); + + b.HasIndex("Name"); + + b.ToTable("AbpTenants"); + }); + + modelBuilder.Entity("Volo.Abp.TenantManagement.TenantConnectionString", b => + { + b.Property("TenantId") + .HasColumnType("uniqueidentifier"); + + b.Property("Name") + .HasMaxLength(64) + .HasColumnType("nvarchar(64)"); + + b.Property("Value") + .IsRequired() + .HasMaxLength(1024) + .HasColumnType("nvarchar(1024)"); + + b.HasKey("TenantId", "Name"); + + b.ToTable("AbpTenantConnectionStrings"); + }); + + modelBuilder.Entity("Volo.CmsKit.Blogs.Blog", 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("CreatorId") + .HasColumnType("uniqueidentifier") + .HasColumnName("CreatorId"); + + b.Property("DeleterId") + .HasColumnType("uniqueidentifier") + .HasColumnName("DeleterId"); + + b.Property("DeletionTime") + .HasColumnType("datetime2") + .HasColumnName("DeletionTime"); + + b.Property("ExtraProperties") + .HasColumnType("nvarchar(max)") + .HasColumnName("ExtraProperties"); + + b.Property("IsDeleted") + .ValueGeneratedOnAdd() + .HasColumnType("bit") + .HasDefaultValue(false) + .HasColumnName("IsDeleted"); + + b.Property("LastModificationTime") + .HasColumnType("datetime2") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uniqueidentifier") + .HasColumnName("LastModifierId"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(64) + .HasColumnType("nvarchar(64)"); + + b.Property("Slug") + .IsRequired() + .HasMaxLength(64) + .HasColumnType("nvarchar(64)"); + + b.Property("TenantId") + .HasColumnType("uniqueidentifier") + .HasColumnName("TenantId"); + + b.HasKey("Id"); + + b.ToTable("CmsBlogs"); + }); + + modelBuilder.Entity("Volo.CmsKit.Blogs.BlogFeature", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("BlogId") + .HasColumnType("uniqueidentifier"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .HasMaxLength(40) + .HasColumnType("nvarchar(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("CreationTime") + .HasColumnType("datetime2") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uniqueidentifier") + .HasColumnName("CreatorId"); + + b.Property("DeleterId") + .HasColumnType("uniqueidentifier") + .HasColumnName("DeleterId"); + + b.Property("DeletionTime") + .HasColumnType("datetime2") + .HasColumnName("DeletionTime"); + + b.Property("ExtraProperties") + .HasColumnType("nvarchar(max)") + .HasColumnName("ExtraProperties"); + + b.Property("FeatureName") + .IsRequired() + .HasMaxLength(64) + .HasColumnType("nvarchar(64)"); + + b.Property("IsDeleted") + .ValueGeneratedOnAdd() + .HasColumnType("bit") + .HasDefaultValue(false) + .HasColumnName("IsDeleted"); + + b.Property("IsEnabled") + .HasColumnType("bit"); + + b.Property("LastModificationTime") + .HasColumnType("datetime2") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uniqueidentifier") + .HasColumnName("LastModifierId"); + + b.HasKey("Id"); + + b.ToTable("CmsBlogFeatures"); + }); + + modelBuilder.Entity("Volo.CmsKit.Blogs.BlogPost", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("AuthorId") + .HasColumnType("uniqueidentifier"); + + b.Property("BlogId") + .HasColumnType("uniqueidentifier"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .HasMaxLength(40) + .HasColumnType("nvarchar(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("Content") + .HasMaxLength(2147483647) + .HasColumnType("nvarchar(max)"); + + b.Property("CreationTime") + .HasColumnType("datetime2") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uniqueidentifier") + .HasColumnName("CreatorId"); + + b.Property("DeleterId") + .HasColumnType("uniqueidentifier") + .HasColumnName("DeleterId"); + + b.Property("DeletionTime") + .HasColumnType("datetime2") + .HasColumnName("DeletionTime"); + + b.Property("ExtraProperties") + .HasColumnType("nvarchar(max)") + .HasColumnName("ExtraProperties"); + + b.Property("IsDeleted") + .ValueGeneratedOnAdd() + .HasColumnType("bit") + .HasDefaultValue(false) + .HasColumnName("IsDeleted"); + + b.Property("LastModificationTime") + .HasColumnType("datetime2") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uniqueidentifier") + .HasColumnName("LastModifierId"); + + b.Property("ShortDescription") + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.Property("Slug") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.Property("TenantId") + .HasColumnType("uniqueidentifier") + .HasColumnName("TenantId"); + + b.Property("Title") + .IsRequired() + .HasMaxLength(64) + .HasColumnType("nvarchar(64)"); + + b.HasKey("Id"); + + b.HasIndex("AuthorId"); + + b.HasIndex("Slug", "BlogId"); + + b.ToTable("CmsBlogPosts"); + }); + + modelBuilder.Entity("Volo.CmsKit.Comments.Comment", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("CreationTime") + .HasColumnType("datetime2") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uniqueidentifier") + .HasColumnName("CreatorId"); + + b.Property("EntityId") + .IsRequired() + .HasMaxLength(64) + .HasColumnType("nvarchar(64)"); + + b.Property("EntityType") + .IsRequired() + .HasMaxLength(64) + .HasColumnType("nvarchar(64)"); + + b.Property("RepliedCommentId") + .HasColumnType("uniqueidentifier"); + + b.Property("TenantId") + .HasColumnType("uniqueidentifier") + .HasColumnName("TenantId"); + + b.Property("Text") + .IsRequired() + .HasMaxLength(512) + .HasColumnType("nvarchar(512)"); + + b.HasKey("Id"); + + b.HasIndex("TenantId", "RepliedCommentId"); + + b.HasIndex("TenantId", "EntityType", "EntityId"); + + b.ToTable("CmsComments"); + }); + + modelBuilder.Entity("Volo.CmsKit.Contents.Content", 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("CreatorId") + .HasColumnType("uniqueidentifier") + .HasColumnName("CreatorId"); + + b.Property("DeleterId") + .HasColumnType("uniqueidentifier") + .HasColumnName("DeleterId"); + + b.Property("DeletionTime") + .HasColumnType("datetime2") + .HasColumnName("DeletionTime"); + + b.Property("EntityId") + .IsRequired() + .HasMaxLength(64) + .HasColumnType("nvarchar(64)"); + + b.Property("EntityType") + .IsRequired() + .HasMaxLength(64) + .HasColumnType("nvarchar(64)"); + + b.Property("ExtraProperties") + .HasColumnType("nvarchar(max)") + .HasColumnName("ExtraProperties"); + + b.Property("IsDeleted") + .ValueGeneratedOnAdd() + .HasColumnType("bit") + .HasDefaultValue(false) + .HasColumnName("IsDeleted"); + + b.Property("LastModificationTime") + .HasColumnType("datetime2") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uniqueidentifier") + .HasColumnName("LastModifierId"); + + b.Property("TenantId") + .HasColumnType("uniqueidentifier") + .HasColumnName("TenantId"); + + b.Property("Value") + .IsRequired() + .HasMaxLength(2147483647) + .HasColumnType("nvarchar(max)"); + + b.HasKey("Id"); + + b.HasIndex("TenantId", "EntityType", "EntityId"); + + b.ToTable("CmsContents"); + }); + + modelBuilder.Entity("Volo.CmsKit.MediaDescriptors.MediaDescriptor", 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("CreatorId") + .HasColumnType("uniqueidentifier") + .HasColumnName("CreatorId"); + + b.Property("DeleterId") + .HasColumnType("uniqueidentifier") + .HasColumnName("DeleterId"); + + b.Property("DeletionTime") + .HasColumnType("datetime2") + .HasColumnName("DeletionTime"); + + b.Property("EntityType") + .IsRequired() + .HasMaxLength(64) + .HasColumnType("nvarchar(64)"); + + b.Property("ExtraProperties") + .HasColumnType("nvarchar(max)") + .HasColumnName("ExtraProperties"); + + b.Property("IsDeleted") + .ValueGeneratedOnAdd() + .HasColumnType("bit") + .HasDefaultValue(false) + .HasColumnName("IsDeleted"); + + b.Property("LastModificationTime") + .HasColumnType("datetime2") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uniqueidentifier") + .HasColumnName("LastModifierId"); + + b.Property("MimeType") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("nvarchar(128)"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("nvarchar(255)"); + + b.Property("Size") + .HasMaxLength(2147483647) + .HasColumnType("bigint"); + + b.Property("TenantId") + .HasColumnType("uniqueidentifier") + .HasColumnName("TenantId"); + + b.HasKey("Id"); + + b.ToTable("CmsMediaDescriptors"); + }); + + modelBuilder.Entity("Volo.CmsKit.Pages.Page", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .HasMaxLength(40) + .HasColumnType("nvarchar(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("Content") + .HasMaxLength(2147483647) + .HasColumnType("nvarchar(max)"); + + b.Property("CreationTime") + .HasColumnType("datetime2") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uniqueidentifier") + .HasColumnName("CreatorId"); + + b.Property("DeleterId") + .HasColumnType("uniqueidentifier") + .HasColumnName("DeleterId"); + + b.Property("DeletionTime") + .HasColumnType("datetime2") + .HasColumnName("DeletionTime"); + + b.Property("ExtraProperties") + .HasColumnType("nvarchar(max)") + .HasColumnName("ExtraProperties"); + + b.Property("IsDeleted") + .ValueGeneratedOnAdd() + .HasColumnType("bit") + .HasDefaultValue(false) + .HasColumnName("IsDeleted"); + + b.Property("LastModificationTime") + .HasColumnType("datetime2") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uniqueidentifier") + .HasColumnName("LastModifierId"); + + b.Property("Slug") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.Property("TenantId") + .HasColumnType("uniqueidentifier") + .HasColumnName("TenantId"); + + b.Property("Title") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.HasKey("Id"); + + b.HasIndex("TenantId", "Slug"); + + b.ToTable("CmsPages"); + }); + + modelBuilder.Entity("Volo.CmsKit.Ratings.Rating", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("CreationTime") + .HasColumnType("datetime2") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uniqueidentifier") + .HasColumnName("CreatorId"); + + b.Property("EntityId") + .IsRequired() + .HasMaxLength(64) + .HasColumnType("nvarchar(64)"); + + b.Property("EntityType") + .IsRequired() + .HasMaxLength(64) + .HasColumnType("nvarchar(64)"); + + b.Property("StarCount") + .HasColumnType("smallint"); + + b.Property("TenantId") + .HasColumnType("uniqueidentifier"); + + b.HasKey("Id"); + + b.HasIndex("TenantId", "EntityType", "EntityId", "CreatorId"); + + b.ToTable("CmsRatings"); + }); + + modelBuilder.Entity("Volo.CmsKit.Reactions.UserReaction", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("CreationTime") + .HasColumnType("datetime2") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uniqueidentifier") + .HasColumnName("CreatorId"); + + b.Property("EntityId") + .IsRequired() + .HasMaxLength(64) + .HasColumnType("nvarchar(64)"); + + b.Property("EntityType") + .IsRequired() + .HasMaxLength(64) + .HasColumnType("nvarchar(64)"); + + b.Property("ReactionName") + .IsRequired() + .HasMaxLength(32) + .HasColumnType("nvarchar(32)"); + + b.Property("TenantId") + .HasColumnType("uniqueidentifier") + .HasColumnName("TenantId"); + + b.HasKey("Id"); + + b.HasIndex("TenantId", "EntityType", "EntityId", "ReactionName"); + + b.HasIndex("TenantId", "CreatorId", "EntityType", "EntityId", "ReactionName"); + + b.ToTable("CmsUserReactions"); + }); + + modelBuilder.Entity("Volo.CmsKit.Tags.EntityTag", b => + { + b.Property("EntityId") + .HasColumnType("nvarchar(450)"); + + b.Property("TagId") + .HasColumnType("uniqueidentifier"); + + b.Property("TenantId") + .HasColumnType("uniqueidentifier") + .HasColumnName("TenantId"); + + b.HasKey("EntityId", "TagId"); + + b.HasIndex("TenantId", "EntityId", "TagId"); + + b.ToTable("CmsEntityTags"); + }); + + modelBuilder.Entity("Volo.CmsKit.Tags.Tag", 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("CreatorId") + .HasColumnType("uniqueidentifier") + .HasColumnName("CreatorId"); + + b.Property("DeleterId") + .HasColumnType("uniqueidentifier") + .HasColumnName("DeleterId"); + + b.Property("DeletionTime") + .HasColumnType("datetime2") + .HasColumnName("DeletionTime"); + + b.Property("EntityType") + .IsRequired() + .HasMaxLength(64) + .HasColumnType("nvarchar(64)"); + + b.Property("ExtraProperties") + .HasColumnType("nvarchar(max)") + .HasColumnName("ExtraProperties"); + + b.Property("IsDeleted") + .ValueGeneratedOnAdd() + .HasColumnType("bit") + .HasDefaultValue(false) + .HasColumnName("IsDeleted"); + + b.Property("LastModificationTime") + .HasColumnType("datetime2") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uniqueidentifier") + .HasColumnName("LastModifierId"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(32) + .HasColumnType("nvarchar(32)"); + + b.Property("TenantId") + .HasColumnType("uniqueidentifier") + .HasColumnName("TenantId"); + + b.HasKey("Id"); + + b.HasIndex("TenantId", "Name"); + + b.ToTable("CmsTags"); + }); + + modelBuilder.Entity("Volo.CmsKit.Users.CmsUser", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .HasMaxLength(40) + .HasColumnType("nvarchar(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("Email") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("nvarchar(256)") + .HasColumnName("Email"); + + b.Property("EmailConfirmed") + .ValueGeneratedOnAdd() + .HasColumnType("bit") + .HasDefaultValue(false) + .HasColumnName("EmailConfirmed"); + + b.Property("ExtraProperties") + .HasColumnType("nvarchar(max)") + .HasColumnName("ExtraProperties"); + + b.Property("Name") + .HasMaxLength(64) + .HasColumnType("nvarchar(64)") + .HasColumnName("Name"); + + b.Property("PhoneNumber") + .HasMaxLength(16) + .HasColumnType("nvarchar(16)") + .HasColumnName("PhoneNumber"); + + b.Property("PhoneNumberConfirmed") + .ValueGeneratedOnAdd() + .HasColumnType("bit") + .HasDefaultValue(false) + .HasColumnName("PhoneNumberConfirmed"); + + b.Property("Surname") + .HasMaxLength(64) + .HasColumnType("nvarchar(64)") + .HasColumnName("Surname"); + + b.Property("TenantId") + .HasColumnType("uniqueidentifier") + .HasColumnName("TenantId"); + + b.Property("UserName") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("nvarchar(256)") + .HasColumnName("UserName"); + + b.HasKey("Id"); + + b.HasIndex("TenantId", "Email"); + + b.HasIndex("TenantId", "UserName"); + + b.ToTable("CmsUsers"); + }); + + modelBuilder.Entity("Volo.Abp.AuditLogging.AuditLogAction", b => + { + b.HasOne("Volo.Abp.AuditLogging.AuditLog", null) + .WithMany("Actions") + .HasForeignKey("AuditLogId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Volo.Abp.AuditLogging.EntityChange", b => + { + b.HasOne("Volo.Abp.AuditLogging.AuditLog", null) + .WithMany("EntityChanges") + .HasForeignKey("AuditLogId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Volo.Abp.AuditLogging.EntityPropertyChange", b => + { + b.HasOne("Volo.Abp.AuditLogging.EntityChange", null) + .WithMany("PropertyChanges") + .HasForeignKey("EntityChangeId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Volo.Abp.BlobStoring.Database.DatabaseBlob", b => + { + b.HasOne("Volo.Abp.BlobStoring.Database.DatabaseBlobContainer", null) + .WithMany() + .HasForeignKey("ContainerId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityRoleClaim", b => + { + b.HasOne("Volo.Abp.Identity.IdentityRole", null) + .WithMany("Claims") + .HasForeignKey("RoleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityUserClaim", b => + { + b.HasOne("Volo.Abp.Identity.IdentityUser", null) + .WithMany("Claims") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityUserLogin", b => + { + b.HasOne("Volo.Abp.Identity.IdentityUser", null) + .WithMany("Logins") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityUserOrganizationUnit", b => + { + b.HasOne("Volo.Abp.Identity.OrganizationUnit", null) + .WithMany() + .HasForeignKey("OrganizationUnitId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Volo.Abp.Identity.IdentityUser", null) + .WithMany("OrganizationUnits") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityUserRole", b => + { + b.HasOne("Volo.Abp.Identity.IdentityRole", null) + .WithMany() + .HasForeignKey("RoleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Volo.Abp.Identity.IdentityUser", null) + .WithMany("Roles") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityUserToken", b => + { + b.HasOne("Volo.Abp.Identity.IdentityUser", null) + .WithMany("Tokens") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Volo.Abp.Identity.OrganizationUnit", b => + { + b.HasOne("Volo.Abp.Identity.OrganizationUnit", null) + .WithMany() + .HasForeignKey("ParentId"); + }); + + modelBuilder.Entity("Volo.Abp.Identity.OrganizationUnitRole", b => + { + b.HasOne("Volo.Abp.Identity.OrganizationUnit", null) + .WithMany("Roles") + .HasForeignKey("OrganizationUnitId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Volo.Abp.Identity.IdentityRole", null) + .WithMany() + .HasForeignKey("RoleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Volo.Abp.TenantManagement.TenantConnectionString", b => + { + b.HasOne("Volo.Abp.TenantManagement.Tenant", null) + .WithMany("ConnectionStrings") + .HasForeignKey("TenantId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Volo.CmsKit.Blogs.BlogPost", b => + { + b.HasOne("Volo.CmsKit.Users.CmsUser", "Author") + .WithMany() + .HasForeignKey("AuthorId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Author"); + }); + + modelBuilder.Entity("Volo.Abp.AuditLogging.AuditLog", b => + { + b.Navigation("Actions"); + + b.Navigation("EntityChanges"); + }); + + modelBuilder.Entity("Volo.Abp.AuditLogging.EntityChange", b => + { + b.Navigation("PropertyChanges"); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityRole", b => + { + b.Navigation("Claims"); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityUser", b => + { + b.Navigation("Claims"); + + b.Navigation("Logins"); + + b.Navigation("OrganizationUnits"); + + b.Navigation("Roles"); + + b.Navigation("Tokens"); + }); + + modelBuilder.Entity("Volo.Abp.Identity.OrganizationUnit", b => + { + b.Navigation("Roles"); + }); + + modelBuilder.Entity("Volo.Abp.TenantManagement.Tenant", b => + { + b.Navigation("ConnectionStrings"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/modules/cms-kit/host/Volo.CmsKit.Web.Unified/Migrations/20210302091451_Added_Content_To_Page.cs b/modules/cms-kit/host/Volo.CmsKit.Web.Unified/Migrations/20210302091451_Added_Content_To_Page.cs new file mode 100644 index 0000000000..b7ae92ccc7 --- /dev/null +++ b/modules/cms-kit/host/Volo.CmsKit.Web.Unified/Migrations/20210302091451_Added_Content_To_Page.cs @@ -0,0 +1,24 @@ +using Microsoft.EntityFrameworkCore.Migrations; + +namespace Volo.CmsKit.Migrations +{ + public partial class Added_Content_To_Page : Migration + { + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.AddColumn( + name: "Content", + table: "CmsPages", + type: "nvarchar(max)", + maxLength: 2147483647, + nullable: true); + } + + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropColumn( + name: "Content", + table: "CmsPages"); + } + } +} diff --git a/modules/cms-kit/host/Volo.CmsKit.Web.Unified/Migrations/UnifiedDbContextModelSnapshot.cs b/modules/cms-kit/host/Volo.CmsKit.Web.Unified/Migrations/UnifiedDbContextModelSnapshot.cs index ed07831276..c14e469499 100644 --- a/modules/cms-kit/host/Volo.CmsKit.Web.Unified/Migrations/UnifiedDbContextModelSnapshot.cs +++ b/modules/cms-kit/host/Volo.CmsKit.Web.Unified/Migrations/UnifiedDbContextModelSnapshot.cs @@ -1257,6 +1257,9 @@ namespace Volo.CmsKit.Migrations .ValueGeneratedOnAdd() .HasColumnType("uniqueidentifier"); + b.Property("AuthorId") + .HasColumnType("uniqueidentifier"); + b.Property("BlogId") .HasColumnType("uniqueidentifier"); @@ -1266,6 +1269,10 @@ namespace Volo.CmsKit.Migrations .HasColumnType("nvarchar(40)") .HasColumnName("ConcurrencyStamp"); + b.Property("Content") + .HasMaxLength(2147483647) + .HasColumnType("nvarchar(max)"); + b.Property("CreationTime") .HasColumnType("datetime2") .HasColumnName("CreationTime"); @@ -1320,11 +1327,7 @@ namespace Volo.CmsKit.Migrations b.HasKey("Id"); - b.HasIndex("CreatorId"); - - b.HasIndex("DeleterId"); - - b.HasIndex("LastModifierId"); + b.HasIndex("AuthorId"); b.HasIndex("Slug", "BlogId"); @@ -1476,6 +1479,11 @@ namespace Volo.CmsKit.Migrations .HasColumnType("datetime2") .HasColumnName("DeletionTime"); + b.Property("EntityType") + .IsRequired() + .HasMaxLength(64) + .HasColumnType("nvarchar(64)"); + b.Property("ExtraProperties") .HasColumnType("nvarchar(max)") .HasColumnName("ExtraProperties"); @@ -1529,6 +1537,10 @@ namespace Volo.CmsKit.Migrations .HasColumnType("nvarchar(40)") .HasColumnName("ConcurrencyStamp"); + b.Property("Content") + .HasMaxLength(2147483647) + .HasColumnType("nvarchar(max)"); + b.Property("CreationTime") .HasColumnType("datetime2") .HasColumnName("CreationTime"); @@ -1952,23 +1964,13 @@ namespace Volo.CmsKit.Migrations modelBuilder.Entity("Volo.CmsKit.Blogs.BlogPost", b => { - b.HasOne("Volo.CmsKit.Users.CmsUser", "Creator") + b.HasOne("Volo.CmsKit.Users.CmsUser", "Author") .WithMany() - .HasForeignKey("CreatorId"); - - b.HasOne("Volo.CmsKit.Users.CmsUser", "Deleter") - .WithMany() - .HasForeignKey("DeleterId"); - - b.HasOne("Volo.CmsKit.Users.CmsUser", "LastModifier") - .WithMany() - .HasForeignKey("LastModifierId"); - - b.Navigation("Creator"); - - b.Navigation("Deleter"); + .HasForeignKey("AuthorId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); - b.Navigation("LastModifier"); + b.Navigation("Author"); }); modelBuilder.Entity("Volo.Abp.AuditLogging.AuditLog", b => diff --git a/modules/cms-kit/host/Volo.CmsKit.Web.Unified/Pages/Index.cshtml b/modules/cms-kit/host/Volo.CmsKit.Web.Unified/Pages/Index.cshtml index 885034b055..31267b61aa 100644 --- a/modules/cms-kit/host/Volo.CmsKit.Web.Unified/Pages/Index.cshtml +++ b/modules/cms-kit/host/Volo.CmsKit.Web.Unified/Pages/Index.cshtml @@ -8,7 +8,6 @@ @using Volo.CmsKit.GlobalFeatures @using Volo.CmsKit.Pages @using Volo.CmsKit.Public.Web.Pages.CmsKit.Shared.Components.Commenting -@using Volo.CmsKit.Public.Web.Pages.CmsKit.Shared.Components.Contents @using Volo.CmsKit.Public.Web.Pages.CmsKit.Shared.Components.Rating @using Volo.CmsKit.Public.Web.Pages.CmsKit.Shared.Components.ReactionSelection @using Volo.CmsKit.Public.Web.Pages.CmsKit.Shared.Components.Tags @@ -31,11 +30,6 @@ - @if (GlobalFeatureManager.Instance.IsEnabled()) - { - @await Component.InvokeAsync(typeof(ContentViewComponent), new {entityType = "quote", entityId = "1"}) - } - @if (GlobalFeatureManager.Instance.IsEnabled()) { @await Component.InvokeAsync(typeof(TagViewComponent), new diff --git a/modules/cms-kit/host/Volo.CmsKit.Web.Unified/package.json b/modules/cms-kit/host/Volo.CmsKit.Web.Unified/package.json index a373644dd2..09764bdd29 100644 --- a/modules/cms-kit/host/Volo.CmsKit.Web.Unified/package.json +++ b/modules/cms-kit/host/Volo.CmsKit.Web.Unified/package.json @@ -7,6 +7,7 @@ "@abp/cms-kit": "4.2.1", "@abp/tui-editor": "^4.2.1", "tui-code-snippet": "1.5.2", - "@abp/uppy": "^4.2.1" + "@abp/uppy": "^4.2.1", + "slugify": "1.4.6" } } \ No newline at end of file diff --git a/modules/cms-kit/host/Volo.CmsKit.Web.Unified/wwwroot/libs/slugify/LICENSE b/modules/cms-kit/host/Volo.CmsKit.Web.Unified/wwwroot/libs/slugify/LICENSE new file mode 100644 index 0000000000..ebbb2c2b97 --- /dev/null +++ b/modules/cms-kit/host/Volo.CmsKit.Web.Unified/wwwroot/libs/slugify/LICENSE @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) Simeon Velichkov + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/modules/cms-kit/host/Volo.CmsKit.Web.Unified/wwwroot/libs/slugify/README.md b/modules/cms-kit/host/Volo.CmsKit.Web.Unified/wwwroot/libs/slugify/README.md new file mode 100644 index 0000000000..cc5783b32e --- /dev/null +++ b/modules/cms-kit/host/Volo.CmsKit.Web.Unified/wwwroot/libs/slugify/README.md @@ -0,0 +1,90 @@ + +# slugify + +[![npm-version]][npm] [![travis-ci]][travis] [![coveralls-status]][coveralls] + +```js +var slugify = require('slugify') + +slugify('some string') // some-string + +// if you prefer something other than '-' as separator +slugify('some string', '_') // some_string +``` + +- Vanilla ES5 JavaScript +- No dependencies +- Coerces foreign symbols to their English equivalent (check out the [charMap][charmap] for more details) +- Works in the browser (window.slugify) and AMD/CommonJS-flavored module loaders + +## Options + +```js +slugify('some string', { + replacement: '-', // replace spaces with replacement character, defaults to `-` + remove: undefined, // remove characters that match regex, defaults to `undefined` + lower: false, // convert to lower case, defaults to `false` + strict: false, // strip special characters except replacement, defaults to `false` + locale: 'vi' // language code of the locale to use +}) +``` + +## Remove + +For example, to remove `*+~.()'"!:@` from the result slug, you can use `slugify('..', {remove: /[*+~.()'"!:@]/g})`. + +## Locales + +The main `charmap.json` file contains all known characters and their transliteration. All new characters should be added there first. In case you stumble upon a character already set in `charmap.json`, but not transliterated correctly according to your language, then you have to add those characters in `locales.json` to override the already existing transliteration in `charmap.json`, but for your locale only. + +You can get the correct language code of your language from [here](https://en.wikipedia.org/wiki/List_of_ISO_639-1_codes). + +## Extend + +Out of the box `slugify` comes with support for a handful of Unicode symbols. For example the `☢` (radioactive) symbol is not defined in the [`charMap`][charmap] and therefore it will be stripped by default: + +```js +slugify('unicode ♥ is ☢') // unicode-love-is +``` + +However you can extend the supported symbols, or override the existing ones with your own: + +```js +slugify.extend({'☢': 'radioactive'}) +slugify('unicode ♥ is ☢') // unicode-love-is-radioactive +``` + +Keep in mind that the `extend` method extends/overrides the default `charMap` for the entire process. In case you need a fresh instance of the slugify's `charMap` object you have to clean up the module cache first: + +```js +delete require.cache[require.resolve('slugify')] +var slugify = require('slugify') +``` + +## Contribute + +1. Add chars to `charmap.json` +2. Run tests `npm test` +3. The tests will build the charmap in `index.js` and will sort the `charmap.json` +4. Commit **all** modified files + +--- + +> This module was originally a vanilla javascript port of [node-slug][node-slug].
+> Note that the original [slug][slug] module has been ported to vanilla javascript too.
+> One major difference between the two modules is that `slugify` does not depend on the external [unicode][unicode] module. + + + [npm-version]: https://img.shields.io/npm/v/slugify.svg?style=flat-square (NPM Package Version) + [travis-ci]: https://img.shields.io/travis/simov/slugify/master.svg?style=flat-square (Build Status - Travis CI) + [coveralls-status]: https://img.shields.io/coveralls/simov/slugify.svg?style=flat-square (Test Coverage - Coveralls) + + [npm]: https://www.npmjs.com/package/slugify + [travis]: https://travis-ci.org/simov/slugify + [coveralls]: https://coveralls.io/r/simov/slugify?branch=master + + [node-slug]: https://github.com/dodo/node-slug + [slug]: https://www.npmjs.com/package/slug + [unicode]: https://www.npmjs.com/package/unicode + [index]: https://github.com/simov/slugify/blob/master/index.js + [charmap]: https://github.com/simov/slugify/blob/master/config/charmap.json diff --git a/modules/cms-kit/host/Volo.CmsKit.Web.Unified/wwwroot/libs/slugify/package.json b/modules/cms-kit/host/Volo.CmsKit.Web.Unified/wwwroot/libs/slugify/package.json new file mode 100644 index 0000000000..5f5ea9dd61 --- /dev/null +++ b/modules/cms-kit/host/Volo.CmsKit.Web.Unified/wwwroot/libs/slugify/package.json @@ -0,0 +1,40 @@ +{ + "name": "slugify", + "version": "1.4.6", + "description": "Slugifies a String", + "keywords": [ + "slugify", + "slug", + "url", + "urlify" + ], + "license": "MIT", + "homepage": "https://github.com/simov/slugify", + "author": "Simeon Velichkov (https://simov.github.io)", + "repository": { + "type": "git", + "url": "https://github.com/simov/slugify.git" + }, + "devDependencies": { + "coveralls": "^3.1.0", + "mocha": "^7.2.0", + "nyc": "^15.1.0" + }, + "main": "./slugify.js", + "files": [ + "LICENSE", + "README.md", + "slugify.d.ts", + "slugify.js" + ], + "types": "slugify.d.ts", + "scripts": { + "build": "node bin/build", + "test:ci": "npx mocha --recursive", + "test:cov": "npx nyc --reporter=lcov --reporter=text-summary mocha -- --recursive", + "test": "npm run build && npm run test:ci" + }, + "engines": { + "node": ">=8.0.0" + } +} diff --git a/modules/cms-kit/host/Volo.CmsKit.Web.Unified/wwwroot/libs/slugify/slugify.d.ts b/modules/cms-kit/host/Volo.CmsKit.Web.Unified/wwwroot/libs/slugify/slugify.d.ts new file mode 100644 index 0000000000..ade1592584 --- /dev/null +++ b/modules/cms-kit/host/Volo.CmsKit.Web.Unified/wwwroot/libs/slugify/slugify.d.ts @@ -0,0 +1,23 @@ +declare module slugify { + type ExtendArgs = { + [key: string]: any; + } + + export function extend (args: ExtendArgs): void; +} + +declare function slugify( + string: string, + options?: + | { + replacement?: string; + remove?: RegExp; + lower?: boolean; + strict?: boolean; + locale?: string; + } + | string, + +): string; + +export default slugify; diff --git a/modules/cms-kit/host/Volo.CmsKit.Web.Unified/wwwroot/libs/slugify/slugify.js b/modules/cms-kit/host/Volo.CmsKit.Web.Unified/wwwroot/libs/slugify/slugify.js new file mode 100644 index 0000000000..692c8e8d69 --- /dev/null +++ b/modules/cms-kit/host/Volo.CmsKit.Web.Unified/wwwroot/libs/slugify/slugify.js @@ -0,0 +1,66 @@ + +;(function (name, root, factory) { + if (typeof exports === 'object') { + module.exports = factory() + module.exports['default'] = factory() + } + /* istanbul ignore next */ + else if (typeof define === 'function' && define.amd) { + define(factory) + } + else { + root[name] = factory() + } +}('slugify', this, function () { + var charMap = JSON.parse('{"$":"dollar","%":"percent","&":"and","<":"less",">":"greater","|":"or","¢":"cent","£":"pound","¤":"currency","¥":"yen","©":"(c)","ª":"a","®":"(r)","º":"o","À":"A","Á":"A","Â":"A","Ã":"A","Ä":"A","Å":"A","Æ":"AE","Ç":"C","È":"E","É":"E","Ê":"E","Ë":"E","Ì":"I","Í":"I","Î":"I","Ï":"I","Ð":"D","Ñ":"N","Ò":"O","Ó":"O","Ô":"O","Õ":"O","Ö":"O","Ø":"O","Ù":"U","Ú":"U","Û":"U","Ü":"U","Ý":"Y","Þ":"TH","ß":"ss","à":"a","á":"a","â":"a","ã":"a","ä":"a","å":"a","æ":"ae","ç":"c","è":"e","é":"e","ê":"e","ë":"e","ì":"i","í":"i","î":"i","ï":"i","ð":"d","ñ":"n","ò":"o","ó":"o","ô":"o","õ":"o","ö":"o","ø":"o","ù":"u","ú":"u","û":"u","ü":"u","ý":"y","þ":"th","ÿ":"y","Ā":"A","ā":"a","Ă":"A","ă":"a","Ą":"A","ą":"a","Ć":"C","ć":"c","Č":"C","č":"c","Ď":"D","ď":"d","Đ":"DJ","đ":"dj","Ē":"E","ē":"e","Ė":"E","ė":"e","Ę":"e","ę":"e","Ě":"E","ě":"e","Ğ":"G","ğ":"g","Ģ":"G","ģ":"g","Ĩ":"I","ĩ":"i","Ī":"i","ī":"i","Į":"I","į":"i","İ":"I","ı":"i","Ķ":"k","ķ":"k","Ļ":"L","ļ":"l","Ľ":"L","ľ":"l","Ł":"L","ł":"l","Ń":"N","ń":"n","Ņ":"N","ņ":"n","Ň":"N","ň":"n","Ō":"O","ō":"o","Ő":"O","ő":"o","Œ":"OE","œ":"oe","Ŕ":"R","ŕ":"r","Ř":"R","ř":"r","Ś":"S","ś":"s","Ş":"S","ş":"s","Š":"S","š":"s","Ţ":"T","ţ":"t","Ť":"T","ť":"t","Ũ":"U","ũ":"u","Ū":"u","ū":"u","Ů":"U","ů":"u","Ű":"U","ű":"u","Ų":"U","ų":"u","Ŵ":"W","ŵ":"w","Ŷ":"Y","ŷ":"y","Ÿ":"Y","Ź":"Z","ź":"z","Ż":"Z","ż":"z","Ž":"Z","ž":"z","Ə":"E","ƒ":"f","Ơ":"O","ơ":"o","Ư":"U","ư":"u","Lj":"LJ","lj":"lj","Nj":"NJ","nj":"nj","Ș":"S","ș":"s","Ț":"T","ț":"t","ə":"e","˚":"o","Ά":"A","Έ":"E","Ή":"H","Ί":"I","Ό":"O","Ύ":"Y","Ώ":"W","ΐ":"i","Α":"A","Β":"B","Γ":"G","Δ":"D","Ε":"E","Ζ":"Z","Η":"H","Θ":"8","Ι":"I","Κ":"K","Λ":"L","Μ":"M","Ν":"N","Ξ":"3","Ο":"O","Π":"P","Ρ":"R","Σ":"S","Τ":"T","Υ":"Y","Φ":"F","Χ":"X","Ψ":"PS","Ω":"W","Ϊ":"I","Ϋ":"Y","ά":"a","έ":"e","ή":"h","ί":"i","ΰ":"y","α":"a","β":"b","γ":"g","δ":"d","ε":"e","ζ":"z","η":"h","θ":"8","ι":"i","κ":"k","λ":"l","μ":"m","ν":"n","ξ":"3","ο":"o","π":"p","ρ":"r","ς":"s","σ":"s","τ":"t","υ":"y","φ":"f","χ":"x","ψ":"ps","ω":"w","ϊ":"i","ϋ":"y","ό":"o","ύ":"y","ώ":"w","Ё":"Yo","Ђ":"DJ","Є":"Ye","І":"I","Ї":"Yi","Ј":"J","Љ":"LJ","Њ":"NJ","Ћ":"C","Џ":"DZ","А":"A","Б":"B","В":"V","Г":"G","Д":"D","Е":"E","Ж":"Zh","З":"Z","И":"I","Й":"J","К":"K","Л":"L","М":"M","Н":"N","О":"O","П":"P","Р":"R","С":"S","Т":"T","У":"U","Ф":"F","Х":"H","Ц":"C","Ч":"Ch","Ш":"Sh","Щ":"Sh","Ъ":"U","Ы":"Y","Ь":"","Э":"E","Ю":"Yu","Я":"Ya","а":"a","б":"b","в":"v","г":"g","д":"d","е":"e","ж":"zh","з":"z","и":"i","й":"j","к":"k","л":"l","м":"m","н":"n","о":"o","п":"p","р":"r","с":"s","т":"t","у":"u","ф":"f","х":"h","ц":"c","ч":"ch","ш":"sh","щ":"sh","ъ":"u","ы":"y","ь":"","э":"e","ю":"yu","я":"ya","ё":"yo","ђ":"dj","є":"ye","і":"i","ї":"yi","ј":"j","љ":"lj","њ":"nj","ћ":"c","ѝ":"u","џ":"dz","Ґ":"G","ґ":"g","Ғ":"GH","ғ":"gh","Қ":"KH","қ":"kh","Ң":"NG","ң":"ng","Ү":"UE","ү":"ue","Ұ":"U","ұ":"u","Һ":"H","һ":"h","Ә":"AE","ә":"ae","Ө":"OE","ө":"oe","฿":"baht","ა":"a","ბ":"b","გ":"g","დ":"d","ე":"e","ვ":"v","ზ":"z","თ":"t","ი":"i","კ":"k","ლ":"l","მ":"m","ნ":"n","ო":"o","პ":"p","ჟ":"zh","რ":"r","ს":"s","ტ":"t","უ":"u","ფ":"f","ქ":"k","ღ":"gh","ყ":"q","შ":"sh","ჩ":"ch","ც":"ts","ძ":"dz","წ":"ts","ჭ":"ch","ხ":"kh","ჯ":"j","ჰ":"h","Ẁ":"W","ẁ":"w","Ẃ":"W","ẃ":"w","Ẅ":"W","ẅ":"w","ẞ":"SS","Ạ":"A","ạ":"a","Ả":"A","ả":"a","Ấ":"A","ấ":"a","Ầ":"A","ầ":"a","Ẩ":"A","ẩ":"a","Ẫ":"A","ẫ":"a","Ậ":"A","ậ":"a","Ắ":"A","ắ":"a","Ằ":"A","ằ":"a","Ẳ":"A","ẳ":"a","Ẵ":"A","ẵ":"a","Ặ":"A","ặ":"a","Ẹ":"E","ẹ":"e","Ẻ":"E","ẻ":"e","Ẽ":"E","ẽ":"e","Ế":"E","ế":"e","Ề":"E","ề":"e","Ể":"E","ể":"e","Ễ":"E","ễ":"e","Ệ":"E","ệ":"e","Ỉ":"I","ỉ":"i","Ị":"I","ị":"i","Ọ":"O","ọ":"o","Ỏ":"O","ỏ":"o","Ố":"O","ố":"o","Ồ":"O","ồ":"o","Ổ":"O","ổ":"o","Ỗ":"O","ỗ":"o","Ộ":"O","ộ":"o","Ớ":"O","ớ":"o","Ờ":"O","ờ":"o","Ở":"O","ở":"o","Ỡ":"O","ỡ":"o","Ợ":"O","ợ":"o","Ụ":"U","ụ":"u","Ủ":"U","ủ":"u","Ứ":"U","ứ":"u","Ừ":"U","ừ":"u","Ử":"U","ử":"u","Ữ":"U","ữ":"u","Ự":"U","ự":"u","Ỳ":"Y","ỳ":"y","Ỵ":"Y","ỵ":"y","Ỷ":"Y","ỷ":"y","Ỹ":"Y","ỹ":"y","‘":"\'","’":"\'","“":"\\\"","”":"\\\"","†":"+","•":"*","…":"...","₠":"ecu","₢":"cruzeiro","₣":"french franc","₤":"lira","₥":"mill","₦":"naira","₧":"peseta","₨":"rupee","₩":"won","₪":"new shequel","₫":"dong","€":"euro","₭":"kip","₮":"tugrik","₯":"drachma","₰":"penny","₱":"peso","₲":"guarani","₳":"austral","₴":"hryvnia","₵":"cedi","₸":"kazakhstani tenge","₹":"indian rupee","₺":"turkish lira","₽":"russian ruble","₿":"bitcoin","℠":"sm","™":"tm","∂":"d","∆":"delta","∑":"sum","∞":"infinity","♥":"love","元":"yuan","円":"yen","﷼":"rial"}') + var locales = JSON.parse('{"de":{"Ä":"AE","ä":"ae","Ö":"OE","ö":"oe","Ü":"UE","ü":"ue"},"vi":{"Đ":"D","đ":"d"}}') + + function replace (string, options) { + if (typeof string !== 'string') { + throw new Error('slugify: string argument expected') + } + + options = (typeof options === 'string') + ? {replacement: options} + : options || {} + + var locale = locales[options.locale] || {} + + var replacement = options.replacement === undefined ? '-' : options.replacement + + var slug = string.split('') + // replace characters based on charMap + .reduce(function (result, ch) { + return result + (locale[ch] || charMap[ch] || ch) + // remove not allowed characters + .replace(options.remove || /[^\w\s$*_+~.()'"!\-:@]+/g, '') + }, '') + // trim leading/trailing spaces + .trim() + // convert spaces to replacement character + // also remove duplicates of the replacement character + .replace(new RegExp('[\\s' + replacement + ']+', 'g'), replacement) + + if (options.lower) { + slug = slug.toLowerCase() + } + + if (options.strict) { + // remove anything besides letters, numbers, and the replacement char + slug = slug + .replace(new RegExp('[^a-zA-Z0-9' + replacement + ']', 'g'), '') + // remove duplicates of the replacement character + .replace(new RegExp('[\\s' + replacement + ']+', 'g'), replacement) + } + + return slug + } + + replace.extend = function (customMap) { + for (var key in customMap) { + charMap[key] = customMap[key] + } + } + + return replace +})) diff --git a/modules/cms-kit/host/Volo.CmsKit.Web.Unified/yarn.lock b/modules/cms-kit/host/Volo.CmsKit.Web.Unified/yarn.lock index bf9985a470..6a5bf91700 100644 --- a/modules/cms-kit/host/Volo.CmsKit.Web.Unified/yarn.lock +++ b/modules/cms-kit/host/Volo.CmsKit.Web.Unified/yarn.lock @@ -3032,6 +3032,11 @@ signal-exit@^3.0.0: resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.2.tgz#b5fdc08f1287ea1178628e415e25132b73646c6d" integrity sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0= +slugify@1.4.6: + version "1.4.6" + resolved "https://registry.yarnpkg.com/slugify/-/slugify-1.4.6.tgz#ef288d920a47fb01c2be56b3487b6722f5e34ace" + integrity sha512-ZdJIgv9gdrYwhXqxsH9pv7nXxjUEyQ6nqhngRxoAAOlmMGA28FDq5O4/5US4G2/Nod7d1ovNcgURQJ7kHq50KQ== + snapdragon-node@^2.0.1: version "2.1.1" resolved "https://registry.yarnpkg.com/snapdragon-node/-/snapdragon-node-2.1.1.tgz#6c175f86ff14bdb0724563e8f3c1b021a286853b" diff --git a/modules/cms-kit/src/Volo.CmsKit.Admin.Application.Contracts/Volo/CmsKit/Admin/Blogs/BlogPostDto.cs b/modules/cms-kit/src/Volo.CmsKit.Admin.Application.Contracts/Volo/CmsKit/Admin/Blogs/BlogPostDto.cs index d12a2f2982..5222b50fe8 100644 --- a/modules/cms-kit/src/Volo.CmsKit.Admin.Application.Contracts/Volo/CmsKit/Admin/Blogs/BlogPostDto.cs +++ b/modules/cms-kit/src/Volo.CmsKit.Admin.Application.Contracts/Volo/CmsKit/Admin/Blogs/BlogPostDto.cs @@ -11,6 +11,9 @@ namespace Volo.CmsKit.Admin.Blogs public string Title { get; set; } public string Slug { get; set; } - public string ShortDescription { get; protected set; } + + public string ShortDescription { get; set; } + + public string Content { get; set; } } } diff --git a/modules/cms-kit/src/Volo.CmsKit.Admin.Application.Contracts/Volo/CmsKit/Admin/Blogs/CreateBlogPostDto.cs b/modules/cms-kit/src/Volo.CmsKit.Admin.Application.Contracts/Volo/CmsKit/Admin/Blogs/CreateBlogPostDto.cs index 7780a21669..3e339c738c 100644 --- a/modules/cms-kit/src/Volo.CmsKit.Admin.Application.Contracts/Volo/CmsKit/Admin/Blogs/CreateBlogPostDto.cs +++ b/modules/cms-kit/src/Volo.CmsKit.Admin.Application.Contracts/Volo/CmsKit/Admin/Blogs/CreateBlogPostDto.cs @@ -21,5 +21,8 @@ namespace Volo.CmsKit.Admin.Blogs [DynamicMaxLength(typeof(BlogPostConsts), nameof(BlogPostConsts.MaxShortDescriptionLength))] public string ShortDescription { get; set; } + + [DynamicMaxLength(typeof(BlogPostConsts), nameof(BlogPostConsts.MaxContentLength))] + public string Content { get; set; } } } diff --git a/modules/cms-kit/src/Volo.CmsKit.Admin.Application.Contracts/Volo/CmsKit/Admin/Blogs/UpdateBlogPostDto.cs b/modules/cms-kit/src/Volo.CmsKit.Admin.Application.Contracts/Volo/CmsKit/Admin/Blogs/UpdateBlogPostDto.cs index eeb4548c8e..7aaf775427 100644 --- a/modules/cms-kit/src/Volo.CmsKit.Admin.Application.Contracts/Volo/CmsKit/Admin/Blogs/UpdateBlogPostDto.cs +++ b/modules/cms-kit/src/Volo.CmsKit.Admin.Application.Contracts/Volo/CmsKit/Admin/Blogs/UpdateBlogPostDto.cs @@ -18,6 +18,8 @@ namespace Volo.CmsKit.Admin.Blogs [DynamicMaxLength(typeof(BlogPostConsts), nameof(BlogPostConsts.MaxShortDescriptionLength))] public string ShortDescription { get; set; } - + + [DynamicMaxLength(typeof(BlogPostConsts), nameof(BlogPostConsts.MaxContentLength))] + public string Content { get; set; } } } diff --git a/modules/cms-kit/src/Volo.CmsKit.Admin.Application.Contracts/Volo/CmsKit/Admin/Contents/ContentCreateDto.cs b/modules/cms-kit/src/Volo.CmsKit.Admin.Application.Contracts/Volo/CmsKit/Admin/Contents/ContentCreateDto.cs deleted file mode 100644 index 6832d26bd3..0000000000 --- a/modules/cms-kit/src/Volo.CmsKit.Admin.Application.Contracts/Volo/CmsKit/Admin/Contents/ContentCreateDto.cs +++ /dev/null @@ -1,23 +0,0 @@ -using System; -using System.ComponentModel.DataAnnotations; -using Volo.Abp.Validation; -using Volo.CmsKit.Contents; - -namespace Volo.CmsKit.Admin.Contents -{ - [Serializable] - public class ContentCreateDto - { - [Required] - [DynamicMaxLength(typeof(ContentConsts), nameof(ContentConsts.MaxEntityTypeLength))] - public string EntityType { get; set; } - - [Required] - [DynamicMaxLength(typeof(ContentConsts), nameof(ContentConsts.MaxEntityIdLength))] - public string EntityId { get; set; } - - [Required] - [DynamicMaxLength(typeof(ContentConsts), nameof(ContentConsts.MaxValueLength))] - public string Value { get; set; } - } -} diff --git a/modules/cms-kit/src/Volo.CmsKit.Admin.Application.Contracts/Volo/CmsKit/Admin/Contents/ContentDto.cs b/modules/cms-kit/src/Volo.CmsKit.Admin.Application.Contracts/Volo/CmsKit/Admin/Contents/ContentDto.cs deleted file mode 100644 index 8cfb2e2e7c..0000000000 --- a/modules/cms-kit/src/Volo.CmsKit.Admin.Application.Contracts/Volo/CmsKit/Admin/Contents/ContentDto.cs +++ /dev/null @@ -1,15 +0,0 @@ -using System; -using Volo.Abp.Application.Dtos; - -namespace Volo.CmsKit.Admin.Contents -{ - [Serializable] - public class ContentDto : EntityDto - { - public string EntityType { get; set; } - - public string EntityId { get; set; } - - public string Value { get; set; } - } -} diff --git a/modules/cms-kit/src/Volo.CmsKit.Admin.Application.Contracts/Volo/CmsKit/Admin/Contents/ContentGetListDto.cs b/modules/cms-kit/src/Volo.CmsKit.Admin.Application.Contracts/Volo/CmsKit/Admin/Contents/ContentGetListDto.cs deleted file mode 100644 index ba44253ae9..0000000000 --- a/modules/cms-kit/src/Volo.CmsKit.Admin.Application.Contracts/Volo/CmsKit/Admin/Contents/ContentGetListDto.cs +++ /dev/null @@ -1,13 +0,0 @@ -using System; -using Volo.Abp.Application.Dtos; - -namespace Volo.CmsKit.Admin.Contents -{ - [Serializable] - public class ContentGetListDto : EntityDto - { - public string EntityType { get; set; } - - public string EntityId { get; set; } - } -} diff --git a/modules/cms-kit/src/Volo.CmsKit.Admin.Application.Contracts/Volo/CmsKit/Admin/Contents/ContentGetListInput.cs b/modules/cms-kit/src/Volo.CmsKit.Admin.Application.Contracts/Volo/CmsKit/Admin/Contents/ContentGetListInput.cs deleted file mode 100644 index fbca53a7b9..0000000000 --- a/modules/cms-kit/src/Volo.CmsKit.Admin.Application.Contracts/Volo/CmsKit/Admin/Contents/ContentGetListInput.cs +++ /dev/null @@ -1,10 +0,0 @@ -using System; -using Volo.Abp.Application.Dtos; - -namespace Volo.CmsKit.Admin.Contents -{ - [Serializable] - public class ContentGetListInput : PagedAndSortedResultRequestDto - { - } -} diff --git a/modules/cms-kit/src/Volo.CmsKit.Admin.Application.Contracts/Volo/CmsKit/Admin/Contents/ContentUpdateDto.cs b/modules/cms-kit/src/Volo.CmsKit.Admin.Application.Contracts/Volo/CmsKit/Admin/Contents/ContentUpdateDto.cs deleted file mode 100644 index c59075cc8d..0000000000 --- a/modules/cms-kit/src/Volo.CmsKit.Admin.Application.Contracts/Volo/CmsKit/Admin/Contents/ContentUpdateDto.cs +++ /dev/null @@ -1,15 +0,0 @@ -using System; -using System.ComponentModel.DataAnnotations; -using Volo.Abp.Validation; -using Volo.CmsKit.Contents; - -namespace Volo.CmsKit.Admin.Contents -{ - [Serializable] - public class ContentUpdateDto - { - [Required] - [DynamicMaxLength(typeof(ContentConsts), nameof(ContentConsts.MaxValueLength))] - public string Value { get; set; } - } -} diff --git a/modules/cms-kit/src/Volo.CmsKit.Admin.Application.Contracts/Volo/CmsKit/Admin/Contents/IContentAdminAppService.cs b/modules/cms-kit/src/Volo.CmsKit.Admin.Application.Contracts/Volo/CmsKit/Admin/Contents/IContentAdminAppService.cs deleted file mode 100644 index 52bd07aa86..0000000000 --- a/modules/cms-kit/src/Volo.CmsKit.Admin.Application.Contracts/Volo/CmsKit/Admin/Contents/IContentAdminAppService.cs +++ /dev/null @@ -1,19 +0,0 @@ -using System; -using System.Threading.Tasks; -using Volo.Abp.Application.Services; -using Volo.CmsKit.Admin.Contents; - -namespace Volo.CmsKit.Admin.Contents -{ - public interface IContentAdminAppService - : ICrudAppService< - ContentDto, - ContentGetListDto, - Guid, - ContentGetListInput, - ContentCreateDto, - ContentUpdateDto> - { - Task GetAsync(string entityType, string entityId); - } -} diff --git a/modules/cms-kit/src/Volo.CmsKit.Admin.Application.Contracts/Volo/CmsKit/Admin/MediaDescriptors/CreateMediaInputStream.cs b/modules/cms-kit/src/Volo.CmsKit.Admin.Application.Contracts/Volo/CmsKit/Admin/MediaDescriptors/CreateMediaInputStream.cs index b61d50e124..0f66ab5fef 100644 --- a/modules/cms-kit/src/Volo.CmsKit.Admin.Application.Contracts/Volo/CmsKit/Admin/MediaDescriptors/CreateMediaInputStream.cs +++ b/modules/cms-kit/src/Volo.CmsKit.Admin.Application.Contracts/Volo/CmsKit/Admin/MediaDescriptors/CreateMediaInputStream.cs @@ -8,6 +8,10 @@ namespace Volo.CmsKit.Admin.MediaDescriptors { public class CreateMediaInputStream : RemoteStreamContent { + [Required] + [DynamicStringLength(typeof(MediaDescriptorConsts), nameof(MediaDescriptorConsts.MaxEntityTypeLength))] + public string EntityType { get; set; } + [Required] [DynamicStringLength(typeof(MediaDescriptorConsts), nameof(MediaDescriptorConsts.MaxNameLength))] public string Name { get; set; } diff --git a/modules/cms-kit/src/Volo.CmsKit.Admin.Application.Contracts/Volo/CmsKit/Admin/Pages/CreatePageInputDto.cs b/modules/cms-kit/src/Volo.CmsKit.Admin.Application.Contracts/Volo/CmsKit/Admin/Pages/CreatePageInputDto.cs index 465408a8bf..174278d829 100644 --- a/modules/cms-kit/src/Volo.CmsKit.Admin.Application.Contracts/Volo/CmsKit/Admin/Pages/CreatePageInputDto.cs +++ b/modules/cms-kit/src/Volo.CmsKit.Admin.Application.Contracts/Volo/CmsKit/Admin/Pages/CreatePageInputDto.cs @@ -16,5 +16,8 @@ namespace Volo.CmsKit.Admin.Pages [Required] [DynamicMaxLength(typeof(PageConsts), nameof(PageConsts.MaxSlugLength))] public string Slug { get; set; } + + [DynamicMaxLength(typeof(PageConsts), nameof(PageConsts.MaxContentLength))] + public string Content { get; set; } } } \ No newline at end of file diff --git a/modules/cms-kit/src/Volo.CmsKit.Admin.Application.Contracts/Volo/CmsKit/Admin/Pages/PageDto.cs b/modules/cms-kit/src/Volo.CmsKit.Admin.Application.Contracts/Volo/CmsKit/Admin/Pages/PageDto.cs index e8117ed7b1..5297e9b7d0 100644 --- a/modules/cms-kit/src/Volo.CmsKit.Admin.Application.Contracts/Volo/CmsKit/Admin/Pages/PageDto.cs +++ b/modules/cms-kit/src/Volo.CmsKit.Admin.Application.Contracts/Volo/CmsKit/Admin/Pages/PageDto.cs @@ -9,5 +9,7 @@ namespace Volo.CmsKit.Admin.Pages public string Title { get; set; } public string Slug { get; set; } + + public string Content { get; set; } } } \ No newline at end of file diff --git a/modules/cms-kit/src/Volo.CmsKit.Admin.Application.Contracts/Volo/CmsKit/Admin/Pages/UpdatePageInputDto.cs b/modules/cms-kit/src/Volo.CmsKit.Admin.Application.Contracts/Volo/CmsKit/Admin/Pages/UpdatePageInputDto.cs index f33c40be6a..eff3cb2919 100644 --- a/modules/cms-kit/src/Volo.CmsKit.Admin.Application.Contracts/Volo/CmsKit/Admin/Pages/UpdatePageInputDto.cs +++ b/modules/cms-kit/src/Volo.CmsKit.Admin.Application.Contracts/Volo/CmsKit/Admin/Pages/UpdatePageInputDto.cs @@ -16,5 +16,8 @@ namespace Volo.CmsKit.Admin.Pages [Required] [DynamicMaxLength(typeof(PageConsts), nameof(PageConsts.MaxSlugLength))] public string Slug { get; set; } + + [DynamicMaxLength(typeof(PageConsts), nameof(PageConsts.MaxContentLength))] + public string Content { get; set; } } } \ No newline at end of file diff --git a/modules/cms-kit/src/Volo.CmsKit.Admin.Application.Contracts/Volo/CmsKit/Permissions/CmsKitAdminPermissionDefinitionProvider.cs b/modules/cms-kit/src/Volo.CmsKit.Admin.Application.Contracts/Volo/CmsKit/Permissions/CmsKitAdminPermissionDefinitionProvider.cs index ccb4d1048b..284ce15827 100644 --- a/modules/cms-kit/src/Volo.CmsKit.Admin.Application.Contracts/Volo/CmsKit/Permissions/CmsKitAdminPermissionDefinitionProvider.cs +++ b/modules/cms-kit/src/Volo.CmsKit.Admin.Application.Contracts/Volo/CmsKit/Permissions/CmsKitAdminPermissionDefinitionProvider.cs @@ -52,16 +52,9 @@ namespace Volo.CmsKit.Permissions blogManagement.AddChild(CmsKitAdminPermissions.Blogs.Features, L("Permission:BlogManagement.Features")); var blogPostManagement = cmsGroup.AddPermission(CmsKitAdminPermissions.BlogPosts.Default, L("Permission:BlogPostManagement")); - blogManagement.AddChild(CmsKitAdminPermissions.BlogPosts.Create, L("Permission:BlogPostManagement.Create")); - blogManagement.AddChild(CmsKitAdminPermissions.BlogPosts.Update, L("Permission:BlogPostManagement.Update")); - blogManagement.AddChild(CmsKitAdminPermissions.BlogPosts.Delete, L("Permission:BlogPostManagement.Delete")); - } - - if (GlobalFeatureManager.Instance.IsEnabled()) - { - var mediaDescriptorManagement = cmsGroup.AddPermission(CmsKitAdminPermissions.MediaDescriptors.Default, L("Permission:MediaDescriptorManagement")); - mediaDescriptorManagement.AddChild(CmsKitAdminPermissions.MediaDescriptors.Create, L("Permission:MediaDescriptorManagement:Create")); - mediaDescriptorManagement.AddChild(CmsKitAdminPermissions.MediaDescriptors.Delete, L("Permission:MediaDescriptorManagement:Delete")); + blogPostManagement.AddChild(CmsKitAdminPermissions.BlogPosts.Create, L("Permission:BlogPostManagement.Create")); + blogPostManagement.AddChild(CmsKitAdminPermissions.BlogPosts.Update, L("Permission:BlogPostManagement.Update")); + blogPostManagement.AddChild(CmsKitAdminPermissions.BlogPosts.Delete, L("Permission:BlogPostManagement.Delete")); } } diff --git a/modules/cms-kit/src/Volo.CmsKit.Admin.Application.Contracts/Volo/CmsKit/Permissions/CmsKitAdminPermissions.cs b/modules/cms-kit/src/Volo.CmsKit.Admin.Application.Contracts/Volo/CmsKit/Permissions/CmsKitAdminPermissions.cs index 6de7bad5e4..c524e7e6b5 100644 --- a/modules/cms-kit/src/Volo.CmsKit.Admin.Application.Contracts/Volo/CmsKit/Permissions/CmsKitAdminPermissions.cs +++ b/modules/cms-kit/src/Volo.CmsKit.Admin.Application.Contracts/Volo/CmsKit/Permissions/CmsKitAdminPermissions.cs @@ -5,13 +5,13 @@ namespace Volo.CmsKit.Permissions public class CmsKitAdminPermissions { public const string GroupName = "CmsKit"; - + public static class Comments { public const string Default = GroupName + ".Comments"; public const string Delete = Default + ".Delete"; } - + public static class Tags { public const string Default = GroupName + ".Tags"; @@ -19,7 +19,7 @@ namespace Volo.CmsKit.Permissions public const string Update = Default + ".Update"; public const string Delete = Default + ".Delete"; } - + public static class Contents { public const string Default = GroupName + ".Contents"; @@ -52,12 +52,5 @@ namespace Volo.CmsKit.Permissions public const string Update = Default + ".Update"; public const string Delete = Default + ".Delete"; } - - public static class MediaDescriptors - { - public const string Default = GroupName + ".MediaDescriptors"; - public const string Create = Default + ".Create"; - public const string Delete = Default + ".Delete"; - } } } 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 4fbbf88675..a25aa07a09 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 @@ -54,7 +54,7 @@ namespace Volo.CmsKit.Admin.Blogs input.Title, input.Slug, input.ShortDescription, - CurrentTenant.Id); + input.Content); await BlogPostRepository.InsertAsync(blogPost); @@ -68,7 +68,8 @@ namespace Volo.CmsKit.Admin.Blogs blogPost.SetTitle(input.Title); blogPost.SetShortDescription(input.ShortDescription); - + blogPost.SetContent(input.Content); + if (blogPost.Slug != input.Slug) { await BlogPostManager.SetSlugUrlAsync(blogPost, input.Slug); diff --git a/modules/cms-kit/src/Volo.CmsKit.Admin.Application/Volo/CmsKit/Admin/CmsKitAdminAppServiceBase.cs b/modules/cms-kit/src/Volo.CmsKit.Admin.Application/Volo/CmsKit/Admin/CmsKitAdminAppServiceBase.cs index 3f4596f586..9d4c109698 100644 --- a/modules/cms-kit/src/Volo.CmsKit.Admin.Application/Volo/CmsKit/Admin/CmsKitAdminAppServiceBase.cs +++ b/modules/cms-kit/src/Volo.CmsKit.Admin.Application/Volo/CmsKit/Admin/CmsKitAdminAppServiceBase.cs @@ -1,4 +1,13 @@ -namespace Volo.CmsKit.Admin +using JetBrains.Annotations; +using Microsoft.AspNetCore.Authorization; +using System.Collections; +using System.Collections.Generic; +using System.Runtime.InteropServices.ComTypes; +using System.Threading.Tasks; +using Volo.Abp; +using Volo.Abp.Authorization; + +namespace Volo.CmsKit.Admin { public abstract class CmsKitAdminAppServiceBase : CmsKitAppServiceBase { @@ -6,5 +15,25 @@ { ObjectMapperContext = typeof(CmsKitAdminApplicationModule); } + + /// + /// Checks given policies until finding granted policy. If none of them is granted, throws + /// + /// Policies to be checked. + /// Thrown when none of policies is granted. + protected async Task CheckAnyOfPoliciesAsync([NotNull] IEnumerable policies) + { + Check.NotNull(policies, nameof(policies)); + + foreach (var policy in policies) + { + if (await AuthorizationService.IsGrantedAsync(policy)) + { + return; + } + } + + throw new AbpAuthorizationException(); + } } } diff --git a/modules/cms-kit/src/Volo.CmsKit.Admin.Application/Volo/CmsKit/Admin/CmsKitAdminApplicationAutoMapperProfile.cs b/modules/cms-kit/src/Volo.CmsKit.Admin.Application/Volo/CmsKit/Admin/CmsKitAdminApplicationAutoMapperProfile.cs index b78910ce01..a2615292f0 100644 --- a/modules/cms-kit/src/Volo.CmsKit.Admin.Application/Volo/CmsKit/Admin/CmsKitAdminApplicationAutoMapperProfile.cs +++ b/modules/cms-kit/src/Volo.CmsKit.Admin.Application/Volo/CmsKit/Admin/CmsKitAdminApplicationAutoMapperProfile.cs @@ -2,13 +2,11 @@ using Volo.Abp.AutoMapper; using Volo.CmsKit.Admin.Blogs; using Volo.CmsKit.Admin.Comments; -using Volo.CmsKit.Admin.Contents; using Volo.CmsKit.Admin.MediaDescriptors; using Volo.CmsKit.Admin.Pages; using Volo.CmsKit.Blogs; using Volo.CmsKit.Admin.Tags; using Volo.CmsKit.Comments; -using Volo.CmsKit.Contents; using Volo.CmsKit.MediaDescriptors; using Volo.CmsKit.Pages; using Volo.CmsKit.Tags; @@ -28,11 +26,6 @@ namespace Volo.CmsKit.Admin CreateMap(); - CreateMap(MemberList.Destination); - CreateMap(MemberList.Destination); - CreateMap(MemberList.Source); - CreateMap(MemberList.Source); - CreateMap(MemberList.Destination); CreateMap(MemberList.Source); CreateMap(MemberList.Source); diff --git a/modules/cms-kit/src/Volo.CmsKit.Admin.Application/Volo/CmsKit/Admin/CmsKitAdminApplicationModule.cs b/modules/cms-kit/src/Volo.CmsKit.Admin.Application/Volo/CmsKit/Admin/CmsKitAdminApplicationModule.cs index 2ad96af963..5eaf3dae28 100644 --- a/modules/cms-kit/src/Volo.CmsKit.Admin.Application/Volo/CmsKit/Admin/CmsKitAdminApplicationModule.cs +++ b/modules/cms-kit/src/Volo.CmsKit.Admin.Application/Volo/CmsKit/Admin/CmsKitAdminApplicationModule.cs @@ -5,8 +5,11 @@ using Volo.Abp.GlobalFeatures; using Volo.Abp.Localization; using Volo.Abp.Modularity; using Volo.CmsKit.Blogs; +using Volo.CmsKit.Comments; using Volo.CmsKit.GlobalFeatures; using Volo.CmsKit.Localization; +using Volo.CmsKit.MediaDescriptors; +using Volo.CmsKit.Pages; using Volo.CmsKit.Permissions; using Volo.CmsKit.Tags; @@ -19,15 +22,14 @@ namespace Volo.CmsKit.Admin )] public class CmsKitAdminApplicationModule : AbpModule { - public override void PreConfigureServices(ServiceConfigurationContext context) - { - ConfigureTagOptions(); - } - public override void ConfigureServices(ServiceConfigurationContext context) { context.Services.AddAutoMapperObjectMapper(); + ConfigureTagOptions(); + + ConfigureCommentOptions(); + Configure(options => { options.AddMaps(validate: true); @@ -44,11 +46,81 @@ namespace Volo.CmsKit.Admin new TagEntityTypeDefiniton( BlogPostConsts.EntityType, LocalizableString.Create("BlogPost"), - CmsKitAdminPermissions.BlogPosts.Update, - CmsKitAdminPermissions.BlogPosts.Update, - CmsKitAdminPermissions.BlogPosts.Update)); + createPolicies: new[] + { + CmsKitAdminPermissions.BlogPosts.Create, + CmsKitAdminPermissions.BlogPosts.Update + }, + updatePolicies: new[] + { + CmsKitAdminPermissions.BlogPosts.Create, + CmsKitAdminPermissions.BlogPosts.Update + }, + deletePolicies: new[] + { + CmsKitAdminPermissions.BlogPosts.Create, + CmsKitAdminPermissions.BlogPosts.Update + })); } }); + + if (GlobalFeatureManager.Instance.IsEnabled()) + { + Configure(options => + { + if (GlobalFeatureManager.Instance.IsEnabled()) + { + options.EntityTypes.AddIfNotContains( + new MediaDescriptorDefinition( + BlogPostConsts.EntityType, + createPolicies: new[] + { + CmsKitAdminPermissions.BlogPosts.Create, + CmsKitAdminPermissions.BlogPosts.Update + }, + deletePolicies: new[] + { + CmsKitAdminPermissions.BlogPosts.Create, + CmsKitAdminPermissions.BlogPosts.Update, + CmsKitAdminPermissions.BlogPosts.Delete + })); + } + + if (GlobalFeatureManager.Instance.IsEnabled()) + { + options.EntityTypes.AddIfNotContains( + new MediaDescriptorDefinition( + PageConsts.EntityType, + createPolicies: new[] + { + CmsKitAdminPermissions.Pages.Create, + CmsKitAdminPermissions.Pages.Update + }, + deletePolicies: new[] + { + CmsKitAdminPermissions.Pages.Create, + CmsKitAdminPermissions.Pages.Update, + CmsKitAdminPermissions.Pages.Delete + })); + } + }); + } + } + + private void ConfigureCommentOptions() + { + if (GlobalFeatureManager.Instance.IsEnabled()) + { + Configure(options => + { + if (GlobalFeatureManager.Instance.IsEnabled()) + { + options.EntityTypes.AddIfNotContains( + new CommentEntityTypeDefinition(BlogPostConsts.EntityType)); + + } + }); + } } } } diff --git a/modules/cms-kit/src/Volo.CmsKit.Admin.Application/Volo/CmsKit/Admin/Contents/ContentAdminAppService.cs b/modules/cms-kit/src/Volo.CmsKit.Admin.Application/Volo/CmsKit/Admin/Contents/ContentAdminAppService.cs deleted file mode 100644 index 1aa0bffcfa..0000000000 --- a/modules/cms-kit/src/Volo.CmsKit.Admin.Application/Volo/CmsKit/Admin/Contents/ContentAdminAppService.cs +++ /dev/null @@ -1,71 +0,0 @@ -using JetBrains.Annotations; -using Microsoft.AspNetCore.Authorization; -using System; -using System.Threading.Tasks; -using Volo.Abp; -using Volo.Abp.Application.Services; -using Volo.Abp.Domain.Repositories; -using Volo.CmsKit.Contents; -using Volo.CmsKit.Permissions; - -namespace Volo.CmsKit.Admin.Contents -{ - [Authorize(CmsKitAdminPermissions.Contents.Default)] - public class ContentAdminAppService : - CrudAppService< - Content, - ContentDto, - ContentGetListDto, - Guid, - ContentGetListInput, - ContentCreateDto, - ContentUpdateDto - >, IContentAdminAppService - { - protected IContentManager ContentManager { get; } - - protected IContentRepository ContentRepository { get; } - - public ContentAdminAppService( - IRepository repository, - IContentManager contentManager, - IContentRepository contentRepository) : base(repository) - { - ContentManager = contentManager; - ContentRepository = contentRepository; - - GetListPolicyName = CmsKitAdminPermissions.Contents.Default; - GetPolicyName = CmsKitAdminPermissions.Contents.Default; - CreatePolicyName = CmsKitAdminPermissions.Contents.Create; - UpdatePolicyName = CmsKitAdminPermissions.Contents.Update; - DeletePolicyName = CmsKitAdminPermissions.Contents.Delete; - } - - [Authorize(CmsKitAdminPermissions.Contents.Create)] - public override async Task CreateAsync(ContentCreateDto input) - { - var entity = new Content( - GuidGenerator.Create(), - input.EntityType, - input.EntityId, - input.Value, - CurrentTenant?.Id); - - await ContentManager.InsertAsync(entity); - - return await MapToGetOutputDtoAsync(entity); - } - - public virtual async Task GetAsync( - [NotNull] string entityType, - [NotNull] string entityId) - { - Check.NotNullOrWhiteSpace(entityType, nameof(entityType)); - Check.NotNullOrWhiteSpace(entityId, nameof(entityId)); - - var content = await ContentRepository.GetAsync(entityType, entityId, CurrentTenant?.Id); - - return ObjectMapper.Map(content); - } - } -} 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 17af6a9993..ab7d841cad 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 @@ -10,34 +10,50 @@ using Volo.CmsKit.Permissions; namespace Volo.CmsKit.Admin.MediaDescriptors { [RequiresGlobalFeature(typeof(MediaFeature))] - [Authorize(CmsKitAdminPermissions.MediaDescriptors.Default)] public class MediaDescriptorAdminAppService : CmsKitAdminAppServiceBase, IMediaDescriptorAdminAppService { - protected readonly IBlobContainer MediaContainer; - protected readonly IMediaDescriptorRepository MediaDescriptorRepository; - - public MediaDescriptorAdminAppService(IBlobContainer mediaContainer, IMediaDescriptorRepository mediaDescriptorRepository) + protected IBlobContainer MediaContainer { get; } + protected IMediaDescriptorRepository MediaDescriptorRepository { get; } + protected MediaDescriptorManager MediaDescriptorManager { get; } + protected IMediaDescriptorDefinitionStore MediaDescriptorDefinitionStore { get; } + + public MediaDescriptorAdminAppService( + IBlobContainer mediaContainer, + IMediaDescriptorRepository mediaDescriptorRepository, + MediaDescriptorManager mediaDescriptorManager, + IMediaDescriptorDefinitionStore mediaDescriptorDefinitionStore) { MediaContainer = mediaContainer; MediaDescriptorRepository = mediaDescriptorRepository; + MediaDescriptorManager = mediaDescriptorManager; + MediaDescriptorDefinitionStore = mediaDescriptorDefinitionStore; } - [Authorize(CmsKitAdminPermissions.MediaDescriptors.Create)] public virtual async Task CreateAsync(CreateMediaInputStream inputStream) { - var newId = GuidGenerator.Create(); - var stream = inputStream.GetStream(); - var newEntity = new MediaDescriptor(newId, inputStream.Name, inputStream.ContentType, stream.Length, CurrentTenant.Id); + var definition = await MediaDescriptorDefinitionStore.GetDefinitionAsync(inputStream.EntityType); + + await CheckAnyOfPoliciesAsync(definition.CreatePolicies); + + using (var stream = inputStream.GetStream()) + { + var newEntity = await MediaDescriptorManager.CreateAsync(inputStream.EntityType, inputStream.Name, inputStream.ContentType, inputStream.ContentLength ?? 0); - await MediaContainer.SaveAsync(newId.ToString(), stream); - await MediaDescriptorRepository.InsertAsync(newEntity); + await MediaContainer.SaveAsync(newEntity.Id.ToString(), stream); + await MediaDescriptorRepository.InsertAsync(newEntity); - return ObjectMapper.Map(newEntity); + return ObjectMapper.Map(newEntity); + } } - [Authorize(CmsKitAdminPermissions.MediaDescriptors.Delete)] public virtual async Task DeleteAsync(Guid id) { + var mediaDescriptor = await MediaDescriptorRepository.GetAsync(id); + + var definition = await MediaDescriptorDefinitionStore.GetDefinitionAsync(mediaDescriptor.EntityType); + + await CheckAnyOfPoliciesAsync(definition.DeletePolicies); + await MediaContainer.DeleteAsync(id.ToString()); await MediaDescriptorRepository.DeleteAsync(id); } 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 9016a620c8..102b2a6afd 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 @@ -50,7 +50,7 @@ namespace Volo.CmsKit.Admin.Pages { await CheckPageSlugAsync(input.Slug); - var page = new Page(GuidGenerator.Create(), input.Title, input.Slug, CurrentTenant.Id); + var page = new Page(GuidGenerator.Create(), input.Title, input.Slug, input.Content, CurrentTenant.Id); await PageRepository.InsertAsync(page); @@ -69,6 +69,7 @@ namespace Volo.CmsKit.Admin.Pages page.SetTitle(input.Title); page.SetSlug(input.Slug); + page.SetContent(input.Content); await PageRepository.UpdateAsync(page); 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 cf3de19933..d118ddece7 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 @@ -31,7 +31,7 @@ namespace Volo.CmsKit.Admin.Tags { var definition = await TagDefinitionStore.GetTagEntityTypeDefinitionAsync(input.EntityType); - await CheckPolicyAsync(definition.CreatePolicy); + await CheckAnyOfPoliciesAsync(definition.CreatePolicies); var tag = await TagManager.GetOrAddAsync(input.EntityType, input.TagName); @@ -46,7 +46,7 @@ namespace Volo.CmsKit.Admin.Tags { var definition = await TagDefinitionStore.GetTagEntityTypeDefinitionAsync(input.EntityType); - await CheckPolicyAsync(definition.DeletePolicy); + await CheckAnyOfPoliciesAsync(definition.DeletePolicies); await EntityTagManager.RemoveTagFromEntityAsync( input.TagId, @@ -59,7 +59,7 @@ namespace Volo.CmsKit.Admin.Tags { var definition = await TagDefinitionStore.GetTagEntityTypeDefinitionAsync(input.EntityType); - await CheckPolicyAsync(definition.UpdatePolicy); + await CheckAnyOfPoliciesAsync(definition.UpdatePolicies); await EntityTagManager.SetEntityTagsAsync(input.EntityType, input.EntityId, input.Tags); } diff --git a/modules/cms-kit/src/Volo.CmsKit.Admin.HttpApi/Volo/CmsKit/Admin/Contents/ContentAdminController.cs b/modules/cms-kit/src/Volo.CmsKit.Admin.HttpApi/Volo/CmsKit/Admin/Contents/ContentAdminController.cs deleted file mode 100644 index 4e3a56a8e2..0000000000 --- a/modules/cms-kit/src/Volo.CmsKit.Admin.HttpApi/Volo/CmsKit/Admin/Contents/ContentAdminController.cs +++ /dev/null @@ -1,71 +0,0 @@ -using Microsoft.AspNetCore.Authorization; -using Microsoft.AspNetCore.Mvc; -using System; -using System.Threading.Tasks; -using Volo.Abp; -using Volo.Abp.Application.Dtos; -using Volo.Abp.GlobalFeatures; -using Volo.CmsKit.Admin.Contents; -using Volo.CmsKit.GlobalFeatures; -using Volo.CmsKit.Permissions; - -namespace Volo.CmsKit.Admin.Contents -{ - [Authorize(CmsKitAdminPermissions.Contents.Default)] - [RequiresGlobalFeature(typeof(ContentsFeature))] - [RemoteService(Name = CmsKitCommonRemoteServiceConsts.RemoteServiceName)] - [Area("cms-kit")] - [Route("api/cms-kit-admin/contents")] - public class ContentAdminController : CmsKitAdminController, IContentAdminAppService - { - protected IContentAdminAppService ContentAdminAppService { get; } - - public ContentAdminController(IContentAdminAppService contentAdminAppService) - { - ContentAdminAppService = contentAdminAppService; - } - - [HttpPost] - [Authorize(CmsKitAdminPermissions.Contents.Create)] - public Task CreateAsync(ContentCreateDto input) - { - return ContentAdminAppService.CreateAsync(input); - } - - [HttpDelete("{id}")] - [Authorize(CmsKitAdminPermissions.Contents.Delete)] - public Task DeleteAsync(Guid id) - { - return ContentAdminAppService.DeleteAsync(id); - } - - [HttpGet("{id}")] - [Authorize(CmsKitAdminPermissions.Contents.Default)] - public Task GetAsync(Guid id) - { - return ContentAdminAppService.GetAsync(id); - } - - [HttpGet] - [Authorize(CmsKitAdminPermissions.Contents.Default)] - public Task> GetListAsync(ContentGetListInput input) - { - return ContentAdminAppService.GetListAsync(input); - } - - [HttpPut] - [Authorize(CmsKitAdminPermissions.Contents.Update)] - public Task UpdateAsync(Guid id, ContentUpdateDto input) - { - return ContentAdminAppService.UpdateAsync(id, input); - } - - [HttpGet] - [Route("{entityType}/{entityId}")] - [Authorize(CmsKitAdminPermissions.Contents.Default)] - public Task GetAsync(string entityType, string entityId) - { - return ContentAdminAppService.GetAsync(entityType, entityId); - } - } -} 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 4267f635b0..91cd5170a5 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 @@ -13,7 +13,6 @@ namespace Volo.CmsKit.Admin.MediaDescriptors { [RequiresGlobalFeature(typeof(MediaFeature))] [RemoteService(Name = CmsKitCommonRemoteServiceConsts.RemoteServiceName)] - [Authorize(CmsKitAdminPermissions.MediaDescriptors.Default)] [Area("cms-kit")] [Route("api/cms-kit-admin/media")] public class MediaDescriptorAdminController : CmsKitAdminController, IMediaDescriptorAdminAppService @@ -26,7 +25,6 @@ namespace Volo.CmsKit.Admin.MediaDescriptors } [HttpPost] - [Authorize(CmsKitAdminPermissions.MediaDescriptors.Create)] [NonAction] public virtual Task CreateAsync(CreateMediaInputStream inputStream) { @@ -35,15 +33,14 @@ namespace Volo.CmsKit.Admin.MediaDescriptors [HttpDelete] [Route("{id}")] - [Authorize(CmsKitAdminPermissions.MediaDescriptors.Delete)] public virtual Task DeleteAsync(Guid id) { return MediaDescriptorAdminAppService.DeleteAsync(id); } [HttpPost] - [Authorize(CmsKitAdminPermissions.MediaDescriptors.Create)] - public virtual async Task UploadAsync(IFormFile file) + [Route("{entityType}")] + public virtual async Task UploadAsync(string entityType, IFormFile file) { if (file == null) { @@ -52,6 +49,7 @@ namespace Volo.CmsKit.Admin.MediaDescriptors var inputStream = new CreateMediaInputStream(file.OpenReadStream()) { + EntityType = entityType, ContentType = file.ContentType, Name = file.FileName }; diff --git a/modules/cms-kit/src/Volo.CmsKit.Admin.Web/Bundles/SlugifyScriptContributor.cs b/modules/cms-kit/src/Volo.CmsKit.Admin.Web/Bundles/SlugifyScriptContributor.cs new file mode 100644 index 0000000000..942f484ebe --- /dev/null +++ b/modules/cms-kit/src/Volo.CmsKit.Admin.Web/Bundles/SlugifyScriptContributor.cs @@ -0,0 +1,17 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Volo.Abp.AspNetCore.Mvc.UI.Bundling; + +namespace Volo.CmsKit.Admin.Web.Bundles +{ + public class SlugifyScriptContributor : BundleContributor + { + public override void ConfigureBundle(BundleConfigurationContext context) + { + context.Files.Add("/libs/slugify/slugify.js"); + } + } +} diff --git a/modules/cms-kit/src/Volo.CmsKit.Admin.Web/CmsKitAdminWebModule.cs b/modules/cms-kit/src/Volo.CmsKit.Admin.Web/CmsKitAdminWebModule.cs index 075d700720..ed162cc360 100644 --- a/modules/cms-kit/src/Volo.CmsKit.Admin.Web/CmsKitAdminWebModule.cs +++ b/modules/cms-kit/src/Volo.CmsKit.Admin.Web/CmsKitAdminWebModule.cs @@ -7,6 +7,10 @@ using Volo.Abp.UI.Navigation; using Volo.Abp.VirtualFileSystem; using Volo.CmsKit.Localization; using Volo.CmsKit.Web; +using Volo.CmsKit.Permissions; +using Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared.PageToolbars; +using Volo.Abp.Localization; +using Volo.Abp.AutoMapper; namespace Volo.CmsKit.Admin.Web { @@ -46,9 +50,90 @@ namespace Volo.CmsKit.Admin.Web options.FileSets.AddEmbedded("Volo.CmsKit.Admin.Web"); }); + context.Services.AddAutoMapperObjectMapper(); + Configure(options => { options.AddMaps(validate: true); }); + Configure(options => { - //Configure authorization. + options.Conventions.AuthorizeFolder("/CmsKit/Tags/", CmsKitAdminPermissions.Tags.Default); + options.Conventions.AuthorizeFolder("/CmsKit/Tags/CreateModal", CmsKitAdminPermissions.Tags.Create); + options.Conventions.AuthorizeFolder("/CmsKit/Tags/UpdateModal", CmsKitAdminPermissions.Tags.Update); + options.Conventions.AuthorizeFolder("/CmsKit/Pages", CmsKitAdminPermissions.Pages.Default); + options.Conventions.AuthorizeFolder("/CmsKit/Pages/Create", CmsKitAdminPermissions.Pages.Create); + options.Conventions.AuthorizeFolder("/CmsKit/Pages/Update", CmsKitAdminPermissions.Pages.Update); + options.Conventions.AuthorizeFolder("/CmsKit/Blogs", CmsKitAdminPermissions.Blogs.Default); + options.Conventions.AuthorizeFolder("/CmsKit/Blogs/Create", CmsKitAdminPermissions.Blogs.Create); + options.Conventions.AuthorizeFolder("/CmsKit/Blogs/Update", CmsKitAdminPermissions.Blogs.Update); + options.Conventions.AuthorizeFolder("/CmsKit/BlogPosts", CmsKitAdminPermissions.BlogPosts.Default); + options.Conventions.AuthorizeFolder("/CmsKit/BlogPosts/Create", CmsKitAdminPermissions.BlogPosts.Create); + options.Conventions.AuthorizeFolder("/CmsKit/BlogPosts/Update", CmsKitAdminPermissions.BlogPosts.Update); + options.Conventions.AuthorizeFolder("/CmsKit/Comments/", CmsKitAdminPermissions.Comments.Default); + options.Conventions.AuthorizeFolder("/CmsKit/Comments/Details", CmsKitAdminPermissions.Comments.Default); + }); + + Configure(options => + { + options.Conventions.AddPageRoute("/CmsKit/Tags/Index", "/Cms/Tags"); + options.Conventions.AddPageRoute("/CmsKit/Pages/Index", "/Cms/Pages"); + options.Conventions.AddPageRoute("/CmsKit/Pages/Create", "/Cms/Pages/Create"); + options.Conventions.AddPageRoute("/CmsKit/Pages/Update", "/Cms/Pages/Update/{Id}"); + options.Conventions.AddPageRoute("/CmsKit/Blogs/Index", "/Cms/Blogs"); + options.Conventions.AddPageRoute("/CmsKit/BlogPosts/Index", "/Cms/BlogPosts"); + options.Conventions.AddPageRoute("/CmsKit/BlogPosts/Create", "/Cms/BlogPosts/Create"); + options.Conventions.AddPageRoute("/CmsKit/BlogPosts/Update", "/Cms/BlogPosts/Update/{Id}"); + options.Conventions.AddPageRoute("/CmsKit/Comments/Index", "/Cms/Comments"); + options.Conventions.AddPageRoute("/CmsKit/Comments/Details", "/Cms/Comments/{Id}"); + }); + + Configure(options => + { + + options.Configure( + toolbar => + { + toolbar.AddButton( + LocalizableString.Create("New"), + icon: "plus", + name: "NewButton", + requiredPolicyName: CmsKitAdminPermissions.Tags.Create + ); + } + ); + + options.Configure( + toolbar => + { + toolbar.AddButton( + LocalizableString.Create("New"), + icon: "plus", + name: "CreatePage", + requiredPolicyName: CmsKitAdminPermissions.Pages.Create + ); + }); + + options.Configure( + toolbar => + { + toolbar.AddButton( + LocalizableString.Create("New"), + icon: "plus", + name: "CreateBlog", + id: "CreateBlog", + requiredPolicyName: CmsKitAdminPermissions.Blogs.Create + ); + }); + + options.Configure( + toolbar => + { + toolbar.AddButton( + LocalizableString.Create("New"), + icon: "plus", + name: "CreateBlogPost", + id: "CreateBlogPost", + requiredPolicyName: CmsKitAdminPermissions.BlogPosts.Create + ); + }); }); } } 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 403715b1bf..e38a9e486b 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 @@ -1,5 +1,11 @@ -using System.Threading.Tasks; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using Volo.Abp.GlobalFeatures; using Volo.Abp.UI.Navigation; +using Volo.CmsKit.GlobalFeatures; +using Volo.CmsKit.Localization; +using Volo.CmsKit.Permissions; namespace Volo.CmsKit.Admin.Web.Menus { @@ -13,11 +19,92 @@ namespace Volo.CmsKit.Admin.Web.Menus } } - private Task ConfigureMainMenuAsync(MenuConfigurationContext context) + private async Task ConfigureMainMenuAsync(MenuConfigurationContext context) { - //Add main menu items. + await AddCmsMenuAsync(context); + } + + private async Task AddCmsMenuAsync(MenuConfigurationContext context) + { + var l = context.GetLocalizer(); + + var cmsMenus = new List(); + + if (GlobalFeatureManager.Instance.IsEnabled()) + { + if (await context.IsGrantedAsync(CmsKitAdminPermissions.Pages.Default)) + { + cmsMenus.Add(new ApplicationMenuItem( + CmsKitAdminMenus.Pages.PagesMenu, + l["Pages"].Value, + "/Cms/Pages")); + } + } + + if (GlobalFeatureManager.Instance.IsEnabled()) + { + if (await context.IsGrantedAsync(CmsKitAdminPermissions.Blogs.Default)) + { + cmsMenus.Add(new ApplicationMenuItem( + CmsKitAdminMenus.Blogs.BlogsMenu, + l["Blogs"], + "/Cms/Blogs" + )); + } + + if (await context.IsGrantedAsync(CmsKitAdminPermissions.BlogPosts.Default)) + { + cmsMenus.Add(new ApplicationMenuItem( + CmsKitAdminMenus.BlogPosts.BlogPostsMenu, + l["BlogPosts"], + "/Cms/BlogPosts" + )); + } + } + + if (GlobalFeatureManager.Instance.IsEnabled()) + { + if (await context.IsGrantedAsync(CmsKitAdminPermissions.Tags.Default)) + { + cmsMenus.Add(new ApplicationMenuItem( + CmsKitAdminMenus.Tags.TagsMenu, + l["Tags"].Value, + "/Cms/Tags")); + } + } + + if (GlobalFeatureManager.Instance.IsEnabled()) + { + if (await context.IsGrantedAsync(CmsKitAdminPermissions.Comments.Default)) + { + cmsMenus.Add(new ApplicationMenuItem( + CmsKitAdminMenus.Comments.CommentsMenu, + l["Comments"].Value, + "/Cms/Comments" + ) + ); + } + } - return Task.CompletedTask; + if (cmsMenus.Any()) + { + var cmsMenu = context.Menu.FindMenuItem(CmsKitAdminMenus.GroupName); + + if (cmsMenu == null) + { + cmsMenu = new ApplicationMenuItem( + CmsKitAdminMenus.GroupName, + l["Cms"], + icon: "far fa-newspaper"); + + context.Menu.AddItem(cmsMenu); + } + + foreach (var menu in cmsMenus) + { + cmsMenu.AddItem(menu); + } + } } } } \ No newline at end of file diff --git a/modules/cms-kit/src/Volo.CmsKit.Admin.Web/Menus/CmsKitAdminMenus.cs b/modules/cms-kit/src/Volo.CmsKit.Admin.Web/Menus/CmsKitAdminMenus.cs index e6a42db4fa..b9024692df 100644 --- a/modules/cms-kit/src/Volo.CmsKit.Admin.Web/Menus/CmsKitAdminMenus.cs +++ b/modules/cms-kit/src/Volo.CmsKit.Admin.Web/Menus/CmsKitAdminMenus.cs @@ -2,10 +2,32 @@ { public class CmsKitAdminMenus { - private const string Prefix = "CmsKit.Admin"; + public const string GroupName = "Cms"; - //Add your menu items here... - //public const string Home = Prefix + ".MyNewMenuItem"; + public static class Comments + { + public const string CommentsMenu = GroupName + ".Comments"; + } + + public static class Tags + { + public const string TagsMenu = GroupName + ".Tags"; + } + + public static class Pages + { + public const string PagesMenu = GroupName + ".Pages"; + } + + public static class Blogs + { + public const string BlogsMenu = GroupName + ".Blogs"; + } + + public static class BlogPosts + { + public const string BlogPostsMenu = GroupName + ".BlogPosts"; + } } } \ No newline at end of file diff --git a/modules/cms-kit/src/Volo.CmsKit.Admin.Web/Pages/CmsKit/BlogPosts/Create.cshtml b/modules/cms-kit/src/Volo.CmsKit.Admin.Web/Pages/CmsKit/BlogPosts/Create.cshtml new file mode 100644 index 0000000000..4659ca4198 --- /dev/null +++ b/modules/cms-kit/src/Volo.CmsKit.Admin.Web/Pages/CmsKit/BlogPosts/Create.cshtml @@ -0,0 +1,86 @@ +@page + +@using System.Globalization +@using Volo.Abp.AspNetCore.Mvc.UI.Packages.TuiEditor +@using Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared.Pages.Shared.Components.AbpPageToolbar +@using Volo.CmsKit.Admin.Web.Pages +@using Volo.CmsKit.Admin.Web.Menus +@using Volo.CmsKit.Admin.Web.Pages.CmsKit.BlogPosts +@using Volo.CmsKit.Admin.Web.Pages.CmsKit.Tags.Components.TagEditor +@using Volo.CmsKit.Blogs +@using Volo.Abp.AspNetCore.Mvc.UI.Packages.Uppy +@using Volo.CmsKit.Admin.Web.Bundles + +@inherits CmsKitAdminPageBase + +@model CreateModel + +@{ + PageLayout.Content.Title = L["BlogPosts"].Value; + PageLayout.Content.BreadCrumb.Add(L["Menu:CMS"].Value); + PageLayout.Content.MenuItemName = CmsKitAdminMenus.BlogPosts.BlogPostsMenu; +} + +@section scripts { + + + + + + +} + +@section styles { + + + +} + +@section content_toolbar { + @await Component.InvokeAsync(typeof(AbpPageToolbarViewComponent), new { pageName = typeof(CreateModel).FullName }) +} + + + + +
+ + +
+ + +
+ + + +
+ + + + + + + +
+
+
+ +
+ +
+ + @await Component.InvokeAsync(typeof(TagEditorViewComponent), new + { + entityType = BlogPostConsts.EntityType, + displaySubmitButton = false + }) +
+ +
+ + + +
diff --git a/modules/cms-kit/src/Volo.CmsKit.Admin.Web/Pages/CmsKit/BlogPosts/Create.cshtml.cs b/modules/cms-kit/src/Volo.CmsKit.Admin.Web/Pages/CmsKit/BlogPosts/Create.cshtml.cs new file mode 100644 index 0000000000..2d3c7d36ab --- /dev/null +++ b/modules/cms-kit/src/Volo.CmsKit.Admin.Web/Pages/CmsKit/BlogPosts/Create.cshtml.cs @@ -0,0 +1,67 @@ +using AutoMapper; +using Microsoft.AspNetCore.Mvc; +using Microsoft.AspNetCore.Mvc.Rendering; +using System; +using System.Collections.Generic; +using System.ComponentModel.DataAnnotations; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Form; +using Volo.Abp.Validation; +using Volo.CmsKit.Admin.Blogs; +using Volo.CmsKit.Blogs; + +namespace Volo.CmsKit.Admin.Web.Pages.CmsKit.BlogPosts +{ + public class CreateModel : CmsKitAdminPageModel + { + protected IBlogPostAdminAppService BlogPostAdminAppService { get; } + + [BindProperty] + public CreateBlogPostViewModel ViewModel { get; set; } + + public CreateModel( + IBlogPostAdminAppService blogPostAdminAppService) + { + BlogPostAdminAppService = blogPostAdminAppService; + } + + public async Task OnPostAsync() + { + var dto = ObjectMapper.Map(ViewModel); + + var created = await BlogPostAdminAppService.CreateAsync(dto); + + return new OkObjectResult(created); + } + + [AutoMap(typeof(CreateBlogPostDto), ReverseMap = true)] + public class CreateBlogPostViewModel + { + [Required] + [DynamicFormIgnore] + public Guid BlogId { get; set; } + + [Required] + [DynamicMaxLength(typeof(BlogPostConsts), nameof(BlogPostConsts.MaxTitleLength))] + [DynamicFormIgnore] + public string Title { get; set; } + + [Required] + [DynamicStringLength( + typeof(BlogPostConsts), + nameof(BlogPostConsts.MaxSlugLength), + nameof(BlogPostConsts.MinSlugLength))] + [DynamicFormIgnore] + public string Slug { get; set; } + + [DynamicMaxLength(typeof(BlogPostConsts), nameof(BlogPostConsts.MaxShortDescriptionLength))] + public string ShortDescription { get; set; } + + [HiddenInput] + [DynamicMaxLength(typeof(BlogPostConsts), nameof(BlogPostConsts.MaxContentLength))] + public string Content { get; set; } + } + } +} diff --git a/modules/cms-kit/src/Volo.CmsKit.Admin.Web/Pages/CmsKit/BlogPosts/Index.cshtml b/modules/cms-kit/src/Volo.CmsKit.Admin.Web/Pages/CmsKit/BlogPosts/Index.cshtml new file mode 100644 index 0000000000..caea6d3754 --- /dev/null +++ b/modules/cms-kit/src/Volo.CmsKit.Admin.Web/Pages/CmsKit/BlogPosts/Index.cshtml @@ -0,0 +1,33 @@ +@page + +@using Volo.CmsKit.Admin.Web.Pages.CmsKit.BlogPosts +@using Volo.CmsKit.Admin.Web.Pages +@using Volo.CmsKit.Admin.Web.Menus +@using Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared.Pages.Shared.Components.AbpPageToolbar + +@inherits CmsKitAdminPageBase + +@model IndexModel + +@{ + PageLayout.Content.Title = L["BlogPosts"].Value; + PageLayout.Content.BreadCrumb.Add(L["Menu:CMS"].Value); + PageLayout.Content.MenuItemName = CmsKitAdminMenus.BlogPosts.BlogPostsMenu; +} + +@section scripts { + +} + + +@section content_toolbar { + @await Component.InvokeAsync(typeof(AbpPageToolbarViewComponent), new { pageName = typeof(IndexModel).FullName }) +} + +
+ + + + + +
\ No newline at end of file diff --git a/modules/cms-kit/src/Volo.CmsKit.Admin.Web/Pages/CmsKit/BlogPosts/Index.cshtml.cs b/modules/cms-kit/src/Volo.CmsKit.Admin.Web/Pages/CmsKit/BlogPosts/Index.cshtml.cs new file mode 100644 index 0000000000..02afe21fc1 --- /dev/null +++ b/modules/cms-kit/src/Volo.CmsKit.Admin.Web/Pages/CmsKit/BlogPosts/Index.cshtml.cs @@ -0,0 +1,7 @@ +namespace Volo.CmsKit.Admin.Web.Pages.CmsKit.BlogPosts +{ + public class IndexModel : CmsKitAdminPageModel + { + + } +} diff --git a/modules/cms-kit/src/Volo.CmsKit.Admin.Web/Pages/CmsKit/BlogPosts/Update.cshtml b/modules/cms-kit/src/Volo.CmsKit.Admin.Web/Pages/CmsKit/BlogPosts/Update.cshtml new file mode 100644 index 0000000000..7c56152b8e --- /dev/null +++ b/modules/cms-kit/src/Volo.CmsKit.Admin.Web/Pages/CmsKit/BlogPosts/Update.cshtml @@ -0,0 +1,85 @@ +@page "{Id}" + +@using System.Globalization +@using Volo.Abp.AspNetCore.Mvc.UI.Packages.TuiEditor +@using Volo.CmsKit.Blogs +@using Volo.CmsKit.Admin.Web.Pages +@using Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared.Pages.Shared.Components.AbpPageToolbar +@using Volo.CmsKit.Admin.Web.Menus +@using Volo.CmsKit.Admin.Web.Pages.CmsKit.BlogPosts +@using Volo.CmsKit.Admin.Web.Pages.CmsKit.Tags.Components.TagEditor +@using Volo.Abp.AspNetCore.Mvc.UI.Packages.Uppy +@using Volo.CmsKit.Admin.Web.Bundles + +@inherits CmsKitAdminPageBase + +@model UpdateModel + +@{ + PageLayout.Content.Title = L["BlogPosts"].Value; + PageLayout.Content.BreadCrumb.Add(L["Menu:CMS"].Value); + PageLayout.Content.MenuItemName = CmsKitAdminMenus.BlogPosts.BlogPostsMenu; +} + +@section scripts { + + + + + + +} + +@section styles { + + + +} + +@section content_toolbar { + @await Component.InvokeAsync(typeof(AbpPageToolbarViewComponent), new { pageName = typeof(UpdateModel).FullName }) +} + + + + + +
+ + + +
+ + + + + + + + + + +
+
+ +
+ + @if (Model.TagsFeature?.IsEnabled == true) + { +
+ + @await Component.InvokeAsync(typeof(TagEditorViewComponent), new + { + entityType = BlogPostConsts.EntityType, + entityId = Model.Id.ToString(), + displaySubmitButton = false + }) + } +
+ + + +
\ No newline at end of file diff --git a/modules/cms-kit/src/Volo.CmsKit.Admin.Web/Pages/CmsKit/BlogPosts/Update.cshtml.cs b/modules/cms-kit/src/Volo.CmsKit.Admin.Web/Pages/CmsKit/BlogPosts/Update.cshtml.cs new file mode 100644 index 0000000000..5fef40f8a1 --- /dev/null +++ b/modules/cms-kit/src/Volo.CmsKit.Admin.Web/Pages/CmsKit/BlogPosts/Update.cshtml.cs @@ -0,0 +1,81 @@ +using AutoMapper; +using Microsoft.AspNetCore.Mvc; +using Microsoft.AspNetCore.Mvc.Rendering; +using System; +using System.Collections.Generic; +using System.ComponentModel.DataAnnotations; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Form; +using Volo.Abp.Validation; +using Volo.CmsKit.Admin.Blogs; +using Volo.CmsKit.Blogs; + +namespace Volo.CmsKit.Admin.Web.Pages.CmsKit.BlogPosts +{ + public class UpdateModel : CmsKitAdminPageModel + { + protected IBlogPostAdminAppService BlogPostAdminAppService { get; } + protected IBlogFeatureAppService BlogFeatureAppService { get; } + + [BindProperty] + public virtual UpdateBlogPostViewModel ViewModel { get; set; } + + [HiddenInput] + [BindProperty(SupportsGet = true)] + public virtual Guid Id { get; set; } + + public virtual BlogFeatureDto TagsFeature { get; protected set; } + + public UpdateModel( + IBlogPostAdminAppService blogPostAdminAppService, + IBlogFeatureAppService blogFeatureAppService) + { + BlogPostAdminAppService = blogPostAdminAppService; + BlogFeatureAppService = blogFeatureAppService; + } + + public virtual async Task OnGetAsync() + { + var blogPost = await BlogPostAdminAppService.GetAsync(Id); + + ViewModel = ObjectMapper.Map(blogPost); + + TagsFeature = await BlogFeatureAppService.GetOrDefaultAsync(blogPost.BlogId, GlobalFeatures.TagsFeature.Name); + } + + public virtual async Task OnPostAsync() + { + var dto = ObjectMapper.Map(ViewModel); + + await BlogPostAdminAppService.UpdateAsync(Id, dto); + + return NoContent(); + } + + [AutoMap(typeof(BlogPostDto))] + [AutoMap(typeof(UpdateBlogPostDto), ReverseMap = true)] + public class UpdateBlogPostViewModel + { + [DynamicMaxLength(typeof(BlogPostConsts), nameof(BlogPostConsts.MaxTitleLength))] + [Required] + [DynamicFormIgnore] + public string Title { get; set; } + + [DynamicStringLength(typeof(BlogPostConsts), nameof(BlogPostConsts.MaxSlugLength), nameof(BlogPostConsts.MinSlugLength))] + [Required] + [DisplayOrder(10000)] + [DynamicFormIgnore] + public string Slug { get; set; } + + [DynamicMaxLength(typeof(BlogPostConsts), nameof(BlogPostConsts.MaxShortDescriptionLength))] + [DisplayOrder(10001)] + public string ShortDescription { get; set; } + + [HiddenInput] + [DynamicMaxLength(typeof(BlogPostConsts), nameof(BlogPostConsts.MaxContentLength))] + public string Content { get; set; } + } + } +} 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 new file mode 100644 index 0000000000..977c90fde0 --- /dev/null +++ b/modules/cms-kit/src/Volo.CmsKit.Admin.Web/Pages/CmsKit/BlogPosts/create.js @@ -0,0 +1,277 @@ +$(function () { + + var l = abp.localization.getResource("CmsKit"); + + var $selectBlog = $('#BlogSelectionSelect'); + var $formCreate = $('#form-blog-post-create'); + var $title = $('#ViewModel_Title'); + var $shortDescription = $('#ViewModel_ShortDescription'); + var $url = $('#ViewModel_Slug'); + var $buttonSubmit = $('#button-blog-post-create'); + var $pageContentInput = $('#ViewModel_Content'); + var $tagsInput = $('.tag-editor-form input[name=tags]'); + var $fileInput = $('#BlogPostCoverImage'); + var $tagsWrapper = $('#blog-post-tags-wrapper'); + + var UPPY_UPLOAD_ENDPOINT = "/api/cms-kit-admin/blogs/blog-posts/{0}/cover-image"; + var UPPY_FILE_ID = "uppy-upload-file"; + + var isTagsEnabled = true; + + $formCreate.data('validator').settings.ignore = ":hidden, [contenteditable='true']:not([name]), .tui-popup-wrapper"; + + function initSelectBlog() { + $selectBlog.data('autocompleteApiUrl', '/api/cms-kit-admin/blogs'); + $selectBlog.data('autocompleteDisplayProperty', 'name'); + $selectBlog.data('autocompleteValueProperty', 'id'); + $selectBlog.data('autocompleteItemsProperty', 'items'); + $selectBlog.data('autocompleteFilterParamName', 'filter'); + + abp.dom.initializers.initializeAutocompleteSelects($selectBlog); + } + + initSelectBlog(); + + $formCreate.on('submit', function (e) { + e.preventDefault(); + + if ($formCreate.valid()) { + + abp.ui.setBusy(); + + $formCreate.ajaxSubmit({ + success: function (result) { + if (isTagsEnabled) { + submitEntityTags(result.id); + } + else { + submitCoverImage(result.id); + } + }, + error: function (result) { + abp.notify.error(result.responseJSON.error.message); + abp.ui.clearBusy(); + } + }); + } + }); + + $buttonSubmit.click(function (e) { + e.preventDefault(); + $formCreate.submit(); + }); + + function submitEntityTags(blogPostId) { + + var tags = $tagsInput.val().split(',').map(x => x.trim()).filter(x => x); + + if(tags.length === 0){ + submitCoverImage(blogPostId); + return; + } + + volo.cmsKit.admin.tags.entityTagAdmin + .setEntityTags({ + entityType: 'BlogPost', + entityId: blogPostId, + tags: tags + }) + .then(function (result) { + submitCoverImage(blogPostId); + }); + } + + function getUppyHeaders() { + var headers = {}; + headers[abp.security.antiForgery.tokenHeaderName] = abp.security.antiForgery.getToken(); + + return headers; + } + + function submitCoverImage(blogPostId) { + var UPPY_OPTIONS = { + endpoint: UPPY_UPLOAD_ENDPOINT.replace("{0}", blogPostId), + formData: true, + fieldName: "file", + method: "post", + headers: getUppyHeaders() + }; + + var UPPY = Uppy.Core().use(Uppy.XHRUpload, UPPY_OPTIONS); + + UPPY.reset(); + + var file = $fileInput[0].files[0]; + + if (file) { + + UPPY.addFile({ + id: UPPY_FILE_ID, + name: file.name, // file name + type: file.type, // file type + data: file, // file + }); + + UPPY.upload().then((result) => { + if (result.failed.length > 0) { + abp.message.error(l("UploadFailedMessage")); + } else { + finishSaving(); + } + }); + } + else { + finishSaving(); + } + } + + function finishSaving() { + abp.notify.success(l('SuccessfullySaved')); + abp.ui.clearBusy(); + location.href = "../BlogPosts"; + } + + var urlEdited = false; + var reflectedChange = false; + + $url.on('change', function () { + reflectUrlChanges(); + }); + + $title.on('keyup paste', function () { + reflectUrlChanges(); + }); + + function reflectUrlChanges() { + var title = $title.val().toLocaleLowerCase(); + + if (urlEdited) { + title = $url.val(); + } + + var slugified = slugify(title, { + lower: true + }); + + if (slugified != $url.val()) { + reflectedChange = true; + + $url.val(slugified); + + reflectedChange = false; + } + } + + $url.change(function () { + if (!reflectedChange) { + urlEdited = true; + } + }); + + var shorDescriptionEdited = false; + $pageContentInput.on('change', function () { + if (shorDescriptionEdited) { + return; + } + + var htmlValue = $pageContentInput.val(); + + var plainValue = jQuery('
').html(htmlValue).text().replace(/\n/g, ' ').substring(0, 120); + + $shortDescription.val(plainValue); + }); + + $shortDescription.on('change', function () { + shorDescriptionEdited = true; + }); + + $selectBlog.on('change', function () { + var blogId = $selectBlog.val(); + volo.cmsKit.blogs.blogFeature + .getOrDefault(blogId, 'CmsKit.Tags') + .then(function (result) { + if (result) { + isTagsEnabled = result.isEnabled == true + if (isTagsEnabled === true) { + $tagsWrapper.removeClass('d-none'); + } + else { + $tagsWrapper.addClass('d-none'); + } + } + }); + }); + + // ----------------------------------- + var fileUploadUri = "/api/cms-kit-admin/media/blogpost"; + var fileUriPrefix = "/api/cms-kit/media/"; + + var editorDataKey = "tuiEditor"; + + initAllEditors(); + + function initAllEditors() { + $('.content-editor').each(function (i, item) { + initEditor(item); + }); + } + + function initEditor(element) { + var $editorContainer = $(element); + var inputName = $editorContainer.data('input-id'); + var $editorInput = $('#' + inputName); + var initialValue = $editorInput.val(); + + var editor = $editorContainer.tuiEditor({ + usageStatistics: false, + useCommandShortcut: true, + initialValue: initialValue, + previewStyle: 'tab', + height: "25em", + minHeight: "25em", + initialEditType: initialValue ? 'wysiwyg' : 'markdown', + language: $editorContainer.data("language"), + hooks: { + addImageBlobHook: uploadFile, + }, + events: { + change: function (_val) { + $editorInput.val(editor.getHtml()); + $editorInput.trigger("change"); + } + } + }).data(editorDataKey); + } + + function uploadFile(blob, callback, source) { + var UPPY_OPTIONS = { + endpoint: fileUploadUri, + formData: true, + fieldName: "file", + method: "post", + headers: getUppyHeaders() + }; + + var UPPY = Uppy.Core().use(Uppy.XHRUpload, UPPY_OPTIONS); + + UPPY.reset(); + + UPPY.addFile({ + id: "content-file", + name: blob.name, + type: blob.type, + data: blob, + }); + + UPPY.upload().then((result) => { + if (result.failed.length > 0) { + abp.message.error("File upload failed"); + } else { + var mediaDto = result.successful[0].response.body; + var fileUrl = (fileUriPrefix + mediaDto.id); + + callback(fileUrl, mediaDto.name); + } + }); + } +}); \ No newline at end of file diff --git a/modules/cms-kit/src/Volo.CmsKit.Admin.Web/Pages/CmsKit/BlogPosts/index.js b/modules/cms-kit/src/Volo.CmsKit.Admin.Web/Pages/CmsKit/BlogPosts/index.js new file mode 100644 index 0000000000..e2f19079b7 --- /dev/null +++ b/modules/cms-kit/src/Volo.CmsKit.Admin.Web/Pages/CmsKit/BlogPosts/index.js @@ -0,0 +1,68 @@ + +$(function () { + var l = abp.localization.getResource("CmsKit"); + + var blogsService = volo.cmsKit.admin.blogs.blogPostAdmin; + + var $blogPostWrapper = $('#CmsKitBlogPostsWrapper'); + + var dataTable = $("#BlogPostsTable").DataTable(abp.libs.datatables.normalizeConfiguration({ + processing: true, + serverSide: true, + paging: true, + searching: false, + autoWidth: false, + scrollCollapse: true, + scrollX: true, + ordering: true, + order: [[1, "desc"]], + ajax: abp.libs.datatables.createAjax(blogsService.getList), + columnDefs: [ + { + title: l("Details"), + targets: 0, + rowAction: { + items: [ + { + text: l('Edit'), + visible: abp.auth.isGranted('CmsKit.Blogs.Update'), + action: function (data) { + location.href = "BlogPosts/Update/" + data.record.id + } + }, + { + text: l('Delete'), + visible: abp.auth.isGranted('CmsKit.Blogs.Delete'), + confirmMessage: function (data) { + return l("BlogPostDeletionConfirmationMessage", data.record.title) + }, + action: function (data) { + blogsService + .delete(data.record.id) + .then(function () { + abp.notify.info(l("SuccessfullyDeleted")); + dataTable.ajax.reload(); + }); + } + } + ] + } + }, + { + title: l("Title"), + orderable: true, + data: "title" + }, + { + title: l("Slug"), + orderable: true, + data: "slug" + } + ] + })); + + $('#AbpContentToolbar button[name=CreateBlogPost]').on('click', function (e) { + e.preventDefault(); + window.location.href = "BlogPosts/Create" + }); +}); \ No newline at end of file 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 new file mode 100644 index 0000000000..ee6da62f6a --- /dev/null +++ b/modules/cms-kit/src/Volo.CmsKit.Admin.Web/Pages/CmsKit/BlogPosts/update.js @@ -0,0 +1,226 @@ +$(function () { + + var l = abp.localization.getResource("CmsKit"); + + var $selectBlog = $('#BlogSelectionSelect'); + var $formUpdate = $('#form-blog-post-update'); + var $title = $('#ViewModel_Title'); + var $titleClone = $('#title-clone'); + var $slug = $('#ViewModel_Slug'); + var $buttonSubmit = $('#button-blog-post-update'); + var $blogPostIdInput = $('#Id'); + var $tagsInput = $('.tag-editor-form input[name=tags]'); + var $fileInput = $('#BlogPostCoverImage'); + + var UPPY_UPLOAD_ENDPOINT = "/api/cms-kit-admin/blogs/blog-posts/{0}/cover-image"; + var UPPY_FILE_ID = "uppy-upload-file"; + + var isTagsEnabled = true; + + $formUpdate.data('validator').settings.ignore = ":hidden, [contenteditable='true']:not([name]), .tui-popup-wrapper"; + + function initSelectBlog() { + $selectBlog.data('autocompleteApiUrl', '/api/cms-kit-admin/blogs/blogs'); + $selectBlog.data('autocompleteDisplayProperty', 'name'); + $selectBlog.data('autocompleteValueProperty', 'id'); + $selectBlog.data('autocompleteItemsProperty', 'items'); + $selectBlog.data('autocompleteFilterParamName', 'filter'); + + abp.dom.initializers.initializeAutocompleteSelects($selectBlog); + } + + initSelectBlog(); + + $formUpdate.on('submit', function (e) { + e.preventDefault(); + + if ($formUpdate.valid()) { + + abp.ui.setBusy(); + + $formUpdate.ajaxSubmit({ + success: function (result) { + if (isTagsEnabled) { + submitEntityTags($blogPostIdInput.val()); + } + else { + submitCoverImage($blogPostIdInput.val()); + } + }, + error: function (result) { + abp.ui.clearBusy(); abp.notify.error(result.responseJSON.error.message); + } + }); + } + }); + + $buttonSubmit.click(function (e) { + e.preventDefault(); + $formUpdate.submit(); + }); + + function submitEntityTags(blogPostId) { + + var tags = $tagsInput.val().split(',').map(x => x.trim()).filter(x => x); + + if(tags.length === 0){ + submitCoverImage(blogPostId); + return; + } + + volo.cmsKit.admin.tags.entityTagAdmin + .setEntityTags({ + entityType: 'BlogPost', + entityId: blogPostId, + tags: tags + }) + .then(function (result) { + submitCoverImage(blogPostId); + }); + } + + function getUppyHeaders() { + var headers = {}; + headers[abp.security.antiForgery.tokenHeaderName] = abp.security.antiForgery.getToken(); + + return headers; + } + + function submitCoverImage(blogPostId) { + var UPPY_OPTIONS = { + endpoint: UPPY_UPLOAD_ENDPOINT.replace("{0}", blogPostId), + formData: true, + fieldName: "file", + method: "post", + headers: getUppyHeaders() + }; + + var UPPY = Uppy.Core().use(Uppy.XHRUpload, UPPY_OPTIONS); + + UPPY.reset(); + + var file = $fileInput[0].files[0]; + + if (file) { + + UPPY.addFile({ + id: UPPY_FILE_ID, + name: file.name, // file name + type: file.type, // file type + data: file, // file + }); + + UPPY.upload().then((result) => { + if (result.failed.length > 0) { + abp.message.error(l("UploadFailedMessage")); + } else { + finishSaving(); + } + }); + } + else { + finishSaving(); + } + } + + function finishSaving(result) { + abp.notify.success(l('SuccessfullySaved')); + abp.ui.clearBusy(); + location.href = "../../BlogPosts"; + } + + $titleClone.on('change paste keyup', function () { + $title.val($titleClone.val()); + }); + + $slug.on('change', function () { + reflectUrlChanges(); + }); + + function reflectUrlChanges() { + + var title = $slug.val(); + + var slugified = slugify(title); + + if (slugified != title) { + $slug.val(slugified, { + lower: true + }); + } + } + + + // ----------------------------------- + var fileUploadUri = "/api/cms-kit-admin/media/blogpost"; + var fileUriPrefix = "/api/cms-kit/media/"; + + var editorDataKey = "tuiEditor"; + + initAllEditors(); + + function initAllEditors() { + $('.content-editor').each(function (i, item) { + initEditor(item); + }); + } + + function initEditor(element) { + var $editorContainer = $(element); + var inputName = $editorContainer.data('input-id'); + var $editorInput = $('#' + inputName); + var initialValue = $editorInput.val(); + + var editor = $editorContainer.tuiEditor({ + usageStatistics: false, + useCommandShortcut: true, + initialValue: initialValue, + previewStyle: 'tab', + height: "25em", + minHeight: "25em", + initialEditType: initialValue ? 'wysiwyg' : 'markdown', + language: $editorContainer.data("language"), + hooks: { + addImageBlobHook: uploadFile, + }, + events: { + change: function (_val) { + $editorInput.val(editor.getHtml()); + $editorInput.trigger("change"); + } + } + }).data(editorDataKey); + } + + function uploadFile(blob, callback, source) { + var UPPY_OPTIONS = { + endpoint: fileUploadUri, + formData: true, + fieldName: "file", + method: "post", + headers: getUppyHeaders() + }; + + var UPPY = Uppy.Core().use(Uppy.XHRUpload, UPPY_OPTIONS); + + UPPY.reset(); + + UPPY.addFile({ + id: "content-file", + name: blob.name, + type: blob.type, + data: blob, + }); + + UPPY.upload().then((result) => { + if (result.failed.length > 0) { + abp.message.error("File upload failed"); + } else { + var mediaDto = result.successful[0].response.body; + var fileUrl = (fileUriPrefix + mediaDto.id); + + callback(fileUrl, mediaDto.name); + } + }); + } +}); \ No newline at end of file diff --git a/modules/cms-kit/src/Volo.CmsKit.Admin.Web/Pages/CmsKit/Blogs/CreateModal.cshtml b/modules/cms-kit/src/Volo.CmsKit.Admin.Web/Pages/CmsKit/Blogs/CreateModal.cshtml new file mode 100644 index 0000000000..d6cd7c26f5 --- /dev/null +++ b/modules/cms-kit/src/Volo.CmsKit.Admin.Web/Pages/CmsKit/Blogs/CreateModal.cshtml @@ -0,0 +1,23 @@ +@page + +@using Volo.CmsKit.Admin.Web.Pages.CmsKit.Blogs +@using Volo.CmsKit.Admin.Web.Pages +@using Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Modal + +@inherits CmsKitAdminPageBase + +@model CreateModalModel + +@{ + Layout = null; +} + + + + + + + + + + \ No newline at end of file diff --git a/modules/cms-kit/src/Volo.CmsKit.Admin.Web/Pages/CmsKit/Blogs/CreateModal.cshtml.cs b/modules/cms-kit/src/Volo.CmsKit.Admin.Web/Pages/CmsKit/Blogs/CreateModal.cshtml.cs new file mode 100644 index 0000000000..05996b6f87 --- /dev/null +++ b/modules/cms-kit/src/Volo.CmsKit.Admin.Web/Pages/CmsKit/Blogs/CreateModal.cshtml.cs @@ -0,0 +1,44 @@ +using AutoMapper; +using Microsoft.AspNetCore.Mvc; +using System.ComponentModel.DataAnnotations; +using System.Threading.Tasks; +using Volo.Abp.Validation; +using Volo.CmsKit.Admin.Blogs; +using Volo.CmsKit.Blogs; + +namespace Volo.CmsKit.Admin.Web.Pages.CmsKit.Blogs +{ + public class CreateModalModel : CmsKitAdminPageModel + { + protected IBlogAdminAppService BlogAdminAppService { get; } + + [BindProperty] + public CreateBlogViewModel ViewModel { get; set; } + + public CreateModalModel(IBlogAdminAppService blogAdminAppService) + { + BlogAdminAppService = blogAdminAppService; + } + + public async Task OnPostAsync() + { + var dto = ObjectMapper.Map(ViewModel); + + await BlogAdminAppService.CreateAsync(dto); + + return NoContent(); + } + + [AutoMap(typeof(CreateBlogDto), ReverseMap = true)] + public class CreateBlogViewModel + { + [Required] + [DynamicMaxLength(typeof(BlogConsts), nameof(BlogConsts.MaxNameLength))] + public string Name { get; set; } + + [DynamicMaxLength(typeof(BlogConsts), nameof(BlogConsts.MaxSlugLength))] + [Required] + public string Slug { get; set; } + } + } +} diff --git a/modules/cms-kit/src/Volo.CmsKit.Admin.Web/Pages/CmsKit/Blogs/FeaturesModal.cshtml b/modules/cms-kit/src/Volo.CmsKit.Admin.Web/Pages/CmsKit/Blogs/FeaturesModal.cshtml new file mode 100644 index 0000000000..428131c596 --- /dev/null +++ b/modules/cms-kit/src/Volo.CmsKit.Admin.Web/Pages/CmsKit/Blogs/FeaturesModal.cshtml @@ -0,0 +1,44 @@ +@page + +@using Volo.CmsKit.Admin.Web.Pages.CmsKit.Blogs +@using Volo.CmsKit.Admin.Web.Pages +@using Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Modal + +@inherits CmsKitAdminPageBase + +@model FeaturesModalModel + +@{ + Layout = null; +} + +
+ + + + + @for (int i = 0; i < Model.Items.Count; i++) + { +
+ + @if (Model.Items[i].IsAvailable) + { + + } + else + { +
+ +
+ } + +
+ } + +
+ +
+
diff --git a/modules/cms-kit/src/Volo.CmsKit.Admin.Web/Pages/CmsKit/Blogs/FeaturesModal.cshtml.cs b/modules/cms-kit/src/Volo.CmsKit.Admin.Web/Pages/CmsKit/Blogs/FeaturesModal.cshtml.cs new file mode 100644 index 0000000000..c788e2cf4a --- /dev/null +++ b/modules/cms-kit/src/Volo.CmsKit.Admin.Web/Pages/CmsKit/Blogs/FeaturesModal.cshtml.cs @@ -0,0 +1,77 @@ +using AutoMapper; +using Microsoft.AspNetCore.Mvc; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Volo.Abp.GlobalFeatures; +using Volo.CmsKit.Admin.Blogs; +using Volo.CmsKit.Admin.Web.Pages; +using Volo.CmsKit.Blogs; + +namespace Volo.CmsKit.Admin.Web.Pages.CmsKit.Blogs +{ + public class FeaturesModalModel : CmsKitAdminPageModel + { + [BindProperty(SupportsGet = true)] + [HiddenInput] + public Guid BlogId { get; set; } + + [BindProperty] + public List Items { get; set; } + + protected IBlogFeatureAdminAppService BlogFeatureAdminAppService { get; } + + public FeaturesModalModel(IBlogFeatureAdminAppService blogFeatureAdminAppService) + { + BlogFeatureAdminAppService = blogFeatureAdminAppService; + } + + public async Task OnGetAsync() + { + var blogFeatureDtos = await BlogFeatureAdminAppService.GetListAsync(BlogId); + + Items = ObjectMapper.Map, List>(blogFeatureDtos); + } + + public async Task OnPostAsync() + { + var dtos = ObjectMapper.Map, List>(Items); + + foreach (var item in dtos) + { + await BlogFeatureAdminAppService.SetAsync(BlogId, item); + } + + return NoContent(); + } + + [AutoMap(typeof(BlogFeatureDto), ReverseMap = true)] + [AutoMap(typeof(BlogFeatureInputDto), ReverseMap = true)] + public class BlogFeatureViewModel + { + private string featureName; + [HiddenInput] + public string FeatureName { get => featureName; set => SetFeatureName(value); } + + public bool IsEnabled { get; set; } + + public bool IsAvailable { get; private set; } + + private void SetFeatureName(string value) + { + featureName = value; + + IsAvailable = GlobalFeatureManager.Instance.Modules.CmsKit().GetFeatures().Any(a => a.FeatureName == FeatureName) ? + GlobalFeatureManager.Instance.IsEnabled(FeatureName) : + true; + + if (!IsAvailable) + { + IsEnabled = false; + } + } + } + } +} diff --git a/modules/cms-kit/src/Volo.CmsKit.Admin.Web/Pages/CmsKit/Blogs/Index.cshtml b/modules/cms-kit/src/Volo.CmsKit.Admin.Web/Pages/CmsKit/Blogs/Index.cshtml new file mode 100644 index 0000000000..9e51d54421 --- /dev/null +++ b/modules/cms-kit/src/Volo.CmsKit.Admin.Web/Pages/CmsKit/Blogs/Index.cshtml @@ -0,0 +1,38 @@ +@page + +@using Volo.CmsKit.Admin.Web.Pages.CmsKit.Blogs +@using Volo.CmsKit.Admin.Web.Pages +@using Volo.CmsKit.Admin.Web.Menus +@using Volo.CmsKit.Admin.Web.Bundles +@using Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared.Pages.Shared.Components.AbpPageToolbar + +@inherits CmsKitAdminPageBase + +@model IndexModel + +@{ + PageLayout.Content.Title = L["Blogs"].Value; + PageLayout.Content.BreadCrumb.Add(L["Menu:CMS"].Value); + PageLayout.Content.MenuItemName = CmsKitAdminMenus.Blogs.BlogsMenu; +} + +@section scripts { + + + + + + +} + +@section content_toolbar { + @await Component.InvokeAsync(typeof(AbpPageToolbarViewComponent), new { pageName = typeof(IndexModel).FullName }) +} + +
+ + + + + +
\ No newline at end of file diff --git a/modules/cms-kit/src/Volo.CmsKit.Admin.Web/Pages/CmsKit/Blogs/Index.cshtml.cs b/modules/cms-kit/src/Volo.CmsKit.Admin.Web/Pages/CmsKit/Blogs/Index.cshtml.cs new file mode 100644 index 0000000000..77ca47493b --- /dev/null +++ b/modules/cms-kit/src/Volo.CmsKit.Admin.Web/Pages/CmsKit/Blogs/Index.cshtml.cs @@ -0,0 +1,7 @@ +namespace Volo.CmsKit.Admin.Web.Pages.CmsKit.Blogs +{ + public class IndexModel : CmsKitAdminPageModel + { + + } +} diff --git a/modules/cms-kit/src/Volo.CmsKit.Admin.Web/Pages/CmsKit/Blogs/UpdateModal.cshtml b/modules/cms-kit/src/Volo.CmsKit.Admin.Web/Pages/CmsKit/Blogs/UpdateModal.cshtml new file mode 100644 index 0000000000..5a23933a0a --- /dev/null +++ b/modules/cms-kit/src/Volo.CmsKit.Admin.Web/Pages/CmsKit/Blogs/UpdateModal.cshtml @@ -0,0 +1,23 @@ +@page +@using Volo.CmsKit.Admin.Web.Pages +@using Volo.CmsKit.Admin.Web.Pages.CmsKit.Blogs +@using Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Modal + +@inherits CmsKitAdminPageBase + +@model UpdateModalModel + +@{ + Layout = null; +} + + + + + + + + + + + \ No newline at end of file diff --git a/modules/cms-kit/src/Volo.CmsKit.Admin.Web/Pages/CmsKit/Blogs/UpdateModal.cshtml.cs b/modules/cms-kit/src/Volo.CmsKit.Admin.Web/Pages/CmsKit/Blogs/UpdateModal.cshtml.cs new file mode 100644 index 0000000000..75c15018d4 --- /dev/null +++ b/modules/cms-kit/src/Volo.CmsKit.Admin.Web/Pages/CmsKit/Blogs/UpdateModal.cshtml.cs @@ -0,0 +1,61 @@ +using AutoMapper; +using Microsoft.AspNetCore.Mvc; +using System; +using System.Collections.Generic; +using System.ComponentModel.DataAnnotations; +using System.Linq; +using System.Runtime.CompilerServices; +using System.Text; +using System.Threading.Tasks; +using Volo.Abp.Validation; +using Volo.CmsKit.Admin.Blogs; +using Volo.CmsKit.Blogs; + +namespace Volo.CmsKit.Admin.Web.Pages.CmsKit.Blogs +{ + public class UpdateModalModel : CmsKitAdminPageModel + { + protected IBlogAdminAppService BlogAdminAppService { get; } + + [HiddenInput] + [BindProperty(SupportsGet = true)] + public Guid Id { get; set; } + + [BindProperty] + public UpdateBlogViewModel ViewModel { get; set; } + + public UpdateModalModel(IBlogAdminAppService blogAdminAppService) + { + BlogAdminAppService = blogAdminAppService; + } + + public async Task OnGetAsync() + { + var blog = await BlogAdminAppService.GetAsync(Id); + + ViewModel = ObjectMapper.Map(blog); + } + + public async Task OnPostAsync() + { + var dto = ObjectMapper.Map(ViewModel); + + await BlogAdminAppService.UpdateAsync(Id, dto); + + return NoContent(); + } + + [AutoMap(typeof(BlogDto))] + [AutoMap(typeof(UpdateBlogDto), ReverseMap = true)] + public class UpdateBlogViewModel + { + [Required] + [DynamicMaxLength(typeof(BlogConsts), nameof(BlogConsts.MaxNameLength))] + public string Name { get; set; } + + [DynamicMaxLength(typeof(BlogConsts), nameof(BlogConsts.MaxSlugLength))] + [Required] + public string Slug { get; set; } + } + } +} diff --git a/modules/cms-kit/src/Volo.CmsKit.Admin.Web/Pages/CmsKit/Blogs/createModal.js b/modules/cms-kit/src/Volo.CmsKit.Admin.Web/Pages/CmsKit/Blogs/createModal.js new file mode 100644 index 0000000000..f42a96f500 --- /dev/null +++ b/modules/cms-kit/src/Volo.CmsKit.Admin.Web/Pages/CmsKit/Blogs/createModal.js @@ -0,0 +1,47 @@ +var abp = abp || {}; +$(function () { + abp.modals.createBlog = function () { + var initModal = function (publicApi, args) { + + var $name = $('#ViewModel_Name'); + var $slug = $('#ViewModel_Slug'); + + var urlEdited = false; + + $name.on('change paste keyup', function () { + reflectUrlChanges(); + }); + + $slug.on('change', function () { + reflectUrlChanges(); + }); + + function reflectUrlChanges() { + var title = $name.val(); + + if (urlEdited) { + title = $slug.val(); + } + + var slugified = slugify(title, { + lower: true + }); + + if (slugified != $slug.val()) { + reflectedChange = true; + + $slug.val(slugified); + + reflectedChange = false; + } + } + + $slug.change(function () { + urlEdited = true; + }); + } + return { + initModal: initModal + }; + }; +}); \ No newline at end of file diff --git a/modules/cms-kit/src/Volo.CmsKit.Admin.Web/Pages/CmsKit/Blogs/index.js b/modules/cms-kit/src/Volo.CmsKit.Admin.Web/Pages/CmsKit/Blogs/index.js new file mode 100644 index 0000000000..ac1a7ce484 --- /dev/null +++ b/modules/cms-kit/src/Volo.CmsKit.Admin.Web/Pages/CmsKit/Blogs/index.js @@ -0,0 +1,85 @@ + +$(function () { + var l = abp.localization.getResource("CmsKit"); + + var createModal = new abp.ModalManager({ viewUrl: abp.appPath + "CmsKit/Blogs/CreateModal", modalClass: 'createBlog' }); + var updateModal = new abp.ModalManager({ viewUrl: abp.appPath + "CmsKit/Blogs/UpdateModal", modalClass: 'updateBlog' }); + var featuresModal = new abp.ModalManager(abp.appPath + "CmsKit/Blogs/FeaturesModal"); + + var blogsService = volo.cmsKit.admin.blogs.blogAdmin; + + var dataTable = $("#BlogsTable").DataTable(abp.libs.datatables.normalizeConfiguration({ + processing: true, + serverSide: true, + paging: true, + searching: false, + autoWidth: false, + scrollCollapse: true, + scrollX: true, + ordering: true, + order: [[1, "desc"]], + ajax: abp.libs.datatables.createAjax(blogsService.getList), + columnDefs: [ + { + title: l("Details"), + targets: 0, + rowAction: { + items: [ + { + text: l('Features'), + visible: abp.auth.isGranted('CmsKit.Blogs.Features'), + action: function (data) { + featuresModal.open({ blogId: data.record.id }); + } + }, + { + text: l('Edit'), + visible: abp.auth.isGranted('CmsKit.Blogs.Update'), + action: function (data) { + updateModal.open({ id: data.record.id }); + } + }, + { + text: l('Delete'), + visible: abp.auth.isGranted('CmsKit.Blogs.Delete'), + confirmMessage: function (data) { + return l("BlogDeletionConfirmationMessage", data.record.name) + }, + action: function (data) { + blogsService + .delete(data.record.id) + .then(function () { + abp.notify.info(l("SuccessfullyDeleted")); + dataTable.ajax.reload(); + }); + } + } + ] + } + }, + { + title: l("Name"), + orderable: true, + data: "name" + }, + { + title: l("Slug"), + orderable: true, + data: "slug" + } + ] + })); + + $('#AbpContentToolbar button[name=CreateBlog]').on('click', function (e) { + e.preventDefault(); + createModal.open(); + }); + + createModal.onResult(function () { + dataTable.ajax.reload(); + }); + + updateModal.onResult(function () { + dataTable.ajax.reload(); + }); +}); \ No newline at end of file diff --git a/modules/cms-kit/src/Volo.CmsKit.Admin.Web/Pages/CmsKit/Blogs/updateModal.js b/modules/cms-kit/src/Volo.CmsKit.Admin.Web/Pages/CmsKit/Blogs/updateModal.js new file mode 100644 index 0000000000..669a25ee8c --- /dev/null +++ b/modules/cms-kit/src/Volo.CmsKit.Admin.Web/Pages/CmsKit/Blogs/updateModal.js @@ -0,0 +1,30 @@ +var abp = abp || {}; +$(function () { + abp.modals.updateBlog = function () { + var initModal = function (publicApi, args) { + debugger; + var $slug = $('#ViewModel_Slug'); + + $slug.on('change', function () { + reflectUrlChanges(); + }); + + function reflectUrlChanges() { + + var title = $slug.val(); + + var slugified = slugify(title); + + if (slugified != title) { + + $slug.val(slugified, { + lower: true + }); + } + } + } + return { + initModal: initModal + }; + }; +}); \ No newline at end of file diff --git a/modules/cms-kit/src/Volo.CmsKit.Admin.Web/Pages/CmsKit/Comments/Details.cshtml b/modules/cms-kit/src/Volo.CmsKit.Admin.Web/Pages/CmsKit/Comments/Details.cshtml new file mode 100644 index 0000000000..ae2e11713c --- /dev/null +++ b/modules/cms-kit/src/Volo.CmsKit.Admin.Web/Pages/CmsKit/Comments/Details.cshtml @@ -0,0 +1,108 @@ +@page "{id}" + +@using System.Globalization +@using Microsoft.AspNetCore.Mvc.Localization +@using Volo.Abp.AspNetCore.Mvc.UI.Layout +@using Volo.CmsKit.Admin.Web.Pages.CmsKit.Comments +@using Volo.CmsKit.Admin.Web.Menus +@using Volo.CmsKit.Localization + +@inject IPageLayout PageLayout +@inject IHtmlLocalizer L + +@model DetailsModel + +@{ + PageLayout.Content.Title = L["Details"].Value; + PageLayout.Content.BreadCrumb.Add(L["Menu:CMS"].Value); + PageLayout.Content.BreadCrumb.Add(L["Comments"].Value); + PageLayout.Content.MenuItemName = CmsKitAdminMenus.Comments.CommentsMenu; +} + +@section styles{ + + + +} + +@section scripts { + + + +} + +
+ + + + + + + + @L["EntityType"]: + @Model.CommentWithAuthorDto.EntityType + + + @L["EntityId"]: + @Model.CommentWithAuthorDto.EntityId + + + @L["CreationTime"]: + @Model.CommentWithAuthorDto.CreationTime.ToString(CultureInfo.CurrentUICulture) + + + @L["Username"]: + @Model.CommentWithAuthorDto.Author.Name + + @if (Model.CommentWithAuthorDto.RepliedCommentId.HasValue) + { + + @L["ReplyTo"]: + @Model.CommentWithAuthorDto.RepliedCommentId + + } + + @L["Text"]: + @Model.CommentWithAuthorDto.Text + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + +
+
+
+
+
+ +

@L["RepliesToThisComment"]

+ + +
\ No newline at end of file diff --git a/modules/cms-kit/src/Volo.CmsKit.Admin.Web/Pages/CmsKit/Comments/Details.cshtml.cs b/modules/cms-kit/src/Volo.CmsKit.Admin.Web/Pages/CmsKit/Comments/Details.cshtml.cs new file mode 100644 index 0000000000..7e8b757b1a --- /dev/null +++ b/modules/cms-kit/src/Volo.CmsKit.Admin.Web/Pages/CmsKit/Comments/Details.cshtml.cs @@ -0,0 +1,33 @@ +using System; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Mvc; +using Volo.CmsKit.Admin.Comments; + +namespace Volo.CmsKit.Admin.Web.Pages.CmsKit.Comments +{ + public class DetailsModel : CmsKitAdminPageModel + { + [BindProperty(SupportsGet = true)] + public Guid Id { get; set; } + + public string Author { get; set; } + + public DateTime? CreationStartDate { get; set; } + + public DateTime? CreationEndDate { get; set; } + + public CommentWithAuthorDto CommentWithAuthorDto { get; protected set; } + + protected readonly ICommentAdminAppService CommentAdminAppService; + + public DetailsModel(ICommentAdminAppService commentAdminAppService) + { + CommentAdminAppService = commentAdminAppService; + } + + public async Task OnGetAsync() + { + CommentWithAuthorDto = await CommentAdminAppService.GetAsync(Id); + } + } +} diff --git a/modules/cms-kit/src/Volo.CmsKit.Admin.Web/Pages/CmsKit/Comments/Index.cshtml b/modules/cms-kit/src/Volo.CmsKit.Admin.Web/Pages/CmsKit/Comments/Index.cshtml new file mode 100644 index 0000000000..8841d656b0 --- /dev/null +++ b/modules/cms-kit/src/Volo.CmsKit.Admin.Web/Pages/CmsKit/Comments/Index.cshtml @@ -0,0 +1,71 @@ +@page + +@using Microsoft.AspNetCore.Mvc.Localization +@using Volo.Abp.AspNetCore.Mvc.UI.Layout +@using Volo.CmsKit.Admin.Web.Pages.CmsKit.Comments +@using Volo.CmsKit.Admin.Web.Menus +@using Volo.CmsKit.Localization + +@inject IPageLayout PageLayout +@inject IHtmlLocalizer L + +@model IndexModel + +@{ + PageLayout.Content.Title = L["Comments"].Value; + PageLayout.Content.BreadCrumb.Add(L["Menu:CMS"].Value); + PageLayout.Content.MenuItemName = CmsKitAdminMenus.Comments.CommentsMenu; + + var defaultStartDate = DateTime.Now.AddDays(-7).Date.ToShortDateString(); +} + +@section styles{ + + + +} + +@section scripts { + + + +} + +
+ + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+
+ + +
\ No newline at end of file diff --git a/modules/cms-kit/src/Volo.CmsKit.Admin.Web/Pages/CmsKit/Comments/Index.cshtml.cs b/modules/cms-kit/src/Volo.CmsKit.Admin.Web/Pages/CmsKit/Comments/Index.cshtml.cs new file mode 100644 index 0000000000..4e8a03593b --- /dev/null +++ b/modules/cms-kit/src/Volo.CmsKit.Admin.Web/Pages/CmsKit/Comments/Index.cshtml.cs @@ -0,0 +1,17 @@ +using System; + +namespace Volo.CmsKit.Admin.Web.Pages.CmsKit.Comments +{ + public class IndexModel : CmsKitAdminPageModel + { + public string EntityType { get; set; } + + public string EntityId { get; set; } + + public string Author { get; set; } + + public DateTime? CreationStartDate { get; set; } + + public DateTime? CreationEndDate { get; set; } + } +} diff --git a/modules/cms-kit/src/Volo.CmsKit.Admin.Web/Pages/CmsKit/Comments/details.css b/modules/cms-kit/src/Volo.CmsKit.Admin.Web/Pages/CmsKit/Comments/details.css new file mode 100644 index 0000000000..80c815e1c5 --- /dev/null +++ b/modules/cms-kit/src/Volo.CmsKit.Admin.Web/Pages/CmsKit/Comments/details.css @@ -0,0 +1,3 @@ +.datatableCell{ + cursor: pointer; +} \ No newline at end of file diff --git a/modules/cms-kit/src/Volo.CmsKit.Admin.Web/Pages/CmsKit/Comments/details.js b/modules/cms-kit/src/Volo.CmsKit.Admin.Web/Pages/CmsKit/Comments/details.js new file mode 100644 index 0000000000..31e32d37e3 --- /dev/null +++ b/modules/cms-kit/src/Volo.CmsKit.Admin.Web/Pages/CmsKit/Comments/details.js @@ -0,0 +1,146 @@ +$(function (){ + var l = abp.localization.getResource("CmsKit"); + + var commentsService = volo.cmsKit.admin.comments.commentAdmin; + + var detailsModal = new abp.ModalManager(abp.appPath + "CmsKit/Comments/DetailsModal"); + + $(".input-daterange") + .datepicker({ + todayBtn: "linked", + autoclose: true, + language: abp.localization.currentCulture.cultureName, + }) + .on("hide", function (e) { + e.stopPropagation(); + }); + + var filterForm = $('#CmsKitCommentsFilterForm'); + + var getFilter = function () { + var filterObj = filterForm.serializeFormToObject(); + + var startDate = luxon.DateTime.fromFormat( + filterObj.creationStartDate, + abp.localization.currentCulture.dateTimeFormat.shortDatePattern, + { locale: abp.localization.currentCulture.cultureName } + ); + if (!startDate.invalid) { + filterObj.creationStartDate = startDate.toFormat("yyyy-MM-dd"); + } + + var endDate = luxon.DateTime.fromFormat( + filterObj.creationEndDate, + abp.localization.currentCulture.dateTimeFormat.shortDatePattern, + { locale: abp.localization.currentCulture.cultureName } + ); + if (!endDate.invalid) { + filterObj.creationEndDate = endDate.toFormat("yyyy-MM-dd"); + } + + return filterObj; + }; + + var _dataTable = $('#CommentsTable').DataTable(abp.libs.datatables.normalizeConfiguration({ + processing: true, + serverSide: true, + paging: true, + scrollX: true, + searching: false, + scrollCollapse: true, + ajax: abp.libs.datatables.createAjax(commentsService.getList, getFilter), + columnDefs: [ + { + width: "10%", + title: l("Actions"), + targets: 0, + orderable: false, + rowAction: { + items: [ + { + text: l('Details'), + action: function (data) { + window.location = abp.appPath + 'CmsKit/Comments/Details/' + data.record.id; + } + }, + { + text: l('Delete'), + visible: abp.auth.isGranted('CmsKit.Comments.Delete'), + confirmMessage: function (data) { + return l("CommentDeletionConfirmationMessage") + }, + action: function (data) { + commentsService + .delete(data.record.id) + .then(function () { + abp.notify.info(l("SuccessfullyDeleted")); + _dataTable.ajax.reload(); + }); + } + } + ] + } + }, + { + width: "10%", + title: l("Username"), + orderable: false, + data: "author.userName", + render: function (data) { + if (data !== null) { + return GetFilterableDatatableContent('#Author', data); + } + return ""; + } + }, + { + title: l("Text"), + data: "text", + orderable: false, + render: function (data) { + data = data || ""; + + var maxChars = 64; + + if (data.length > maxChars) { + return ( + '' + + data.substring(0, maxChars) + + "..." + + "" + ); + } else { + return data; + } + } + }, + { + width: "15%", + title: l("CreationTime"), + data: "creationTime", + orderable: true, + dataFormat: "datetime" + } + ] + })); + + function GetFilterableDatatableContent(filterSelector, data){ + return '' + data + ''; + } + + $(document).on('click', '.datatableCell', function () { + var inputSelector = $(this).attr('data-field'); + var value = $(this).attr('data-val'); + + $(inputSelector).val(value); + + _dataTable.ajax.reload(); + }); + + filterForm.submit(function (e){ + e.preventDefault(); + _dataTable.ajax.reload(); + }); +}); \ No newline at end of file diff --git a/modules/cms-kit/src/Volo.CmsKit.Admin.Web/Pages/CmsKit/Comments/index.css b/modules/cms-kit/src/Volo.CmsKit.Admin.Web/Pages/CmsKit/Comments/index.css new file mode 100644 index 0000000000..80c815e1c5 --- /dev/null +++ b/modules/cms-kit/src/Volo.CmsKit.Admin.Web/Pages/CmsKit/Comments/index.css @@ -0,0 +1,3 @@ +.datatableCell{ + cursor: pointer; +} \ No newline at end of file diff --git a/modules/cms-kit/src/Volo.CmsKit.Admin.Web/Pages/CmsKit/Comments/index.js b/modules/cms-kit/src/Volo.CmsKit.Admin.Web/Pages/CmsKit/Comments/index.js new file mode 100644 index 0000000000..c2a9c7d364 --- /dev/null +++ b/modules/cms-kit/src/Volo.CmsKit.Admin.Web/Pages/CmsKit/Comments/index.js @@ -0,0 +1,158 @@ +$(function (){ + var l = abp.localization.getResource("CmsKit"); + + var commentsService = volo.cmsKit.admin.comments.commentAdmin; + + var detailsModal = new abp.ModalManager(abp.appPath + "CmsKit/Comments/DetailsModal"); + + $(".input-daterange") + .datepicker({ + todayBtn: "linked", + autoclose: true, + language: abp.localization.currentCulture.cultureName, + }) + .on("hide", function (e) { + e.stopPropagation(); + }); + + var filterForm = $('#CmsKitCommentsFilterForm'); + + var getFilter = function () { + var filterObj = filterForm.serializeFormToObject(); + + var startDate = luxon.DateTime.fromFormat( + filterObj.creationStartDate, + abp.localization.currentCulture.dateTimeFormat.shortDatePattern, + { locale: abp.localization.currentCulture.cultureName } + ); + if (!startDate.invalid) { + filterObj.creationStartDate = startDate.toFormat("yyyy-MM-dd"); + } + + var endDate = luxon.DateTime.fromFormat( + filterObj.creationEndDate, + abp.localization.currentCulture.dateTimeFormat.shortDatePattern, + { locale: abp.localization.currentCulture.cultureName } + ); + if (!endDate.invalid) { + filterObj.creationEndDate = endDate.toFormat("yyyy-MM-dd"); + } + + return filterObj; + }; + + var _dataTable = $('#CommentsTable').DataTable(abp.libs.datatables.normalizeConfiguration({ + processing: true, + serverSide: true, + paging: true, + scrollX: true, + searching: false, + scrollCollapse: true, + ajax: abp.libs.datatables.createAjax(commentsService.getList, getFilter), + columnDefs: [ + { + width: "10%", + title: l("Actions"), + targets: 0, + orderable: false, + rowAction: { + items: [ + { + text: l('Details'), + action: function (data) { + location.href = 'Comments/' + data.record.id; + } + }, + { + text: l('Delete'), + visible: abp.auth.isGranted('CmsKit.Comments.Delete'), + confirmMessage: function (data) { + return l("CommentDeletionConfirmationMessage") + }, + action: function (data) { + commentsService + .delete(data.record.id) + .then(function () { + abp.notify.info(l("SuccessfullyDeleted")); + _dataTable.ajax.reload(); + }); + } + } + ] + } + }, + { + width: "10%", + title: l("Username"), + orderable: false, + data: "author.userName", + render: function (data) { + if (data !== null) { + return GetFilterableDatatableContent('#Author', data); + } + return ""; + } + }, + { + width: "15%", + title: l("EntityType"), + orderable: false, + data: "entityType", + render: function (data) { + if (data !== null) { + return GetFilterableDatatableContent('#EntityType', data); + } + return ""; + } + }, + { + title: l("Text"), + data: "text", + orderable: false, + render: function (data) { + data = data || ""; + + var maxChars = 64; + + if (data.length > maxChars) { + return ( + '' + + data.substring(0, maxChars) + + "..." + + "" + ); + } else { + return data; + } + } + }, + { + width: "15%", + title: l("CreationTime"), + data: "creationTime", + orderable: true, + dataFormat: "datetime" + } + ] + })); + + function GetFilterableDatatableContent(filterSelector, data){ + return '' + data + ''; + } + + $(document).on('click', '.datatableCell', function () { + var inputSelector = $(this).attr('data-field'); + var value = $(this).attr('data-val'); + + $(inputSelector).val(value); + + _dataTable.ajax.reload(); + }); + + filterForm.submit(function (e){ + e.preventDefault(); + _dataTable.ajax.reload(); + }); +}); \ No newline at end of file diff --git a/modules/cms-kit/src/Volo.CmsKit.Admin.Web/Pages/CmsKit/Pages/Create.cshtml b/modules/cms-kit/src/Volo.CmsKit.Admin.Web/Pages/CmsKit/Pages/Create.cshtml new file mode 100644 index 0000000000..b4896a7449 --- /dev/null +++ b/modules/cms-kit/src/Volo.CmsKit.Admin.Web/Pages/CmsKit/Pages/Create.cshtml @@ -0,0 +1,55 @@ +@page + +@using System.Globalization +@using Volo.Abp.AspNetCore.Mvc.UI.Packages.TuiEditor +@using Volo.Abp.AspNetCore.Mvc.UI.Packages.Uppy +@using Volo.CmsKit.Admin.Web.Pages +@using Volo.CmsKit.Admin.Web.Menus +@using Volo.CmsKit.Admin.Web.Bundles + +@inherits CmsKitAdminPageBase + +@model Volo.CmsKit.Admin.Web.Pages.CmsKit.Pages.CreateModel + +@{ + PageLayout.Content.Title = L["Pages"].Value; + PageLayout.Content.BreadCrumb.Add(L["Menu:CMS"].Value); + PageLayout.Content.MenuItemName = CmsKitAdminMenus.Pages.PagesMenu; +} + +@section scripts { + + + + + + +} + +@section styles { + + + +} + + + + +
+ + + + + + +
+
+ +
+ + + +
diff --git a/modules/cms-kit/src/Volo.CmsKit.Admin.Web/Pages/CmsKit/Pages/Create.cshtml.cs b/modules/cms-kit/src/Volo.CmsKit.Admin.Web/Pages/CmsKit/Pages/Create.cshtml.cs new file mode 100644 index 0000000000..430c516ce3 --- /dev/null +++ b/modules/cms-kit/src/Volo.CmsKit.Admin.Web/Pages/CmsKit/Pages/Create.cshtml.cs @@ -0,0 +1,48 @@ +using AutoMapper; +using Microsoft.AspNetCore.Mvc; +using System.ComponentModel.DataAnnotations; +using System.Threading.Tasks; +using Volo.Abp.Validation; +using Volo.CmsKit.Admin.Pages; +using Volo.CmsKit.Pages; + +namespace Volo.CmsKit.Admin.Web.Pages.CmsKit.Pages +{ + public class CreateModel : CmsKitAdminPageModel + { + protected readonly IPageAdminAppService pageAdminAppService; + + [BindProperty] + public CreatePageViewModel ViewModel { get; set; } + + public CreateModel(IPageAdminAppService pageAdminAppService) + { + this.pageAdminAppService = pageAdminAppService; + } + + public async Task OnPostAsync() + { + var createInput = ObjectMapper.Map(ViewModel); + + var created = await pageAdminAppService.CreateAsync(createInput); + + return new OkObjectResult(created); + } + + [AutoMap(typeof(CreatePageInputDto), ReverseMap = true)] + public class CreatePageViewModel + { + [Required] + [DynamicMaxLength(typeof(PageConsts), nameof(PageConsts.MaxTitleLength))] + public string Title { get; set; } + + [Required] + [DynamicMaxLength(typeof(PageConsts), nameof(PageConsts.MaxSlugLength))] + public string Slug { get; set; } + + [HiddenInput] + [DynamicMaxLength(typeof(PageConsts), nameof(PageConsts.MaxSlugLength))] + public string Content { get; set; } + } + } +} diff --git a/modules/cms-kit/src/Volo.CmsKit.Admin.Web/Pages/CmsKit/Pages/Index.cshtml b/modules/cms-kit/src/Volo.CmsKit.Admin.Web/Pages/CmsKit/Pages/Index.cshtml new file mode 100644 index 0000000000..c85d4759ba --- /dev/null +++ b/modules/cms-kit/src/Volo.CmsKit.Admin.Web/Pages/CmsKit/Pages/Index.cshtml @@ -0,0 +1,38 @@ +@page +@using Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared.Pages.Shared.Components.AbpPageToolbar +@using Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared.Pages.Shared.Components.AbpPageSearchBox +@using Volo.CmsKit.Admin.Web.Pages +@using Volo.CmsKit.Admin.Web.Menus +@using Volo.CmsKit.Admin.Web.Pages.CmsKit.Pages + +@inherits CmsKitAdminPageBase + +@model IndexModel + +@{ + PageLayout.Content.Title = L["Pages"].Value; + PageLayout.Content.BreadCrumb.Add(L["Menu:CMS"].Value); + PageLayout.Content.MenuItemName = CmsKitAdminMenus.Pages.PagesMenu; +} + +@section scripts { + +} + +@section content_toolbar { + @await Component.InvokeAsync(typeof(AbpPageToolbarViewComponent), new {pageName = typeof(IndexModel).FullName}) +} + +
+ + + + + @await Component.InvokeAsync(typeof(AbpPageSearchBoxViewComponent)) + + + + + + +
\ No newline at end of file diff --git a/modules/cms-kit/src/Volo.CmsKit.Admin.Web/Pages/CmsKit/Pages/Index.cshtml.cs b/modules/cms-kit/src/Volo.CmsKit.Admin.Web/Pages/CmsKit/Pages/Index.cshtml.cs new file mode 100644 index 0000000000..9c4eea078b --- /dev/null +++ b/modules/cms-kit/src/Volo.CmsKit.Admin.Web/Pages/CmsKit/Pages/Index.cshtml.cs @@ -0,0 +1,11 @@ + +namespace Volo.CmsKit.Admin.Web.Pages.CmsKit.Pages +{ + public class IndexModel : CmsKitAdminPageModel + { + public void OnGet() + { + + } + } +} \ No newline at end of file diff --git a/modules/cms-kit/src/Volo.CmsKit.Admin.Web/Pages/CmsKit/Pages/Update.cshtml b/modules/cms-kit/src/Volo.CmsKit.Admin.Web/Pages/CmsKit/Pages/Update.cshtml new file mode 100644 index 0000000000..1b35e6c913 --- /dev/null +++ b/modules/cms-kit/src/Volo.CmsKit.Admin.Web/Pages/CmsKit/Pages/Update.cshtml @@ -0,0 +1,58 @@ +@page "{Id}" + +@using System.Globalization +@using Volo.Abp.AspNetCore.Mvc.UI.Packages.TuiEditor +@using Volo.Abp.AspNetCore.Mvc.UI.Packages.Uppy +@using Volo.CmsKit.Admin.Web.Bundles +@using Volo.CmsKit.Admin.Web.Menus +@using Volo.CmsKit.Admin.Web.Pages + +@inherits CmsKitAdminPageBase + +@model Volo.CmsKit.Admin.Web.Pages.CmsKit.Pages.UpdateModel + +@{ + PageLayout.Content.Title = L["Pages"].Value; + PageLayout.Content.BreadCrumb.Add(L["Menu:CMS"].Value); + PageLayout.Content.MenuItemName = CmsKitAdminMenus.Pages.PagesMenu; +} + + +@section scripts { + + + + + + +} + +@section styles { + + + +} + + + + +
+ + + + + + + + +
+
+ +
+ + + +
diff --git a/modules/cms-kit/src/Volo.CmsKit.Admin.Web/Pages/CmsKit/Pages/Update.cshtml.cs b/modules/cms-kit/src/Volo.CmsKit.Admin.Web/Pages/CmsKit/Pages/Update.cshtml.cs new file mode 100644 index 0000000000..c21f8f587c --- /dev/null +++ b/modules/cms-kit/src/Volo.CmsKit.Admin.Web/Pages/CmsKit/Pages/Update.cshtml.cs @@ -0,0 +1,62 @@ +using AutoMapper; +using Microsoft.AspNetCore.Mvc; +using System; +using System.ComponentModel.DataAnnotations; +using System.Threading.Tasks; +using Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Form; +using Volo.Abp.Validation; +using Volo.CmsKit.Admin.Pages; +using Volo.CmsKit.Pages; + +namespace Volo.CmsKit.Admin.Web.Pages.CmsKit.Pages +{ + public class UpdateModel : CmsKitAdminPageModel + { + [BindProperty(SupportsGet = true)] + [HiddenInput] + public Guid Id { get; set; } + + [BindProperty] + public UpdatePageViewModel ViewModel { get; set; } + + protected readonly IPageAdminAppService pageAdminAppService; + + public UpdateModel(IPageAdminAppService pageAdminAppService) + { + this.pageAdminAppService = pageAdminAppService; + } + + public async Task OnGetAsync() + { + var dto = await pageAdminAppService.GetAsync(Id); + + ViewModel = ObjectMapper.Map(dto); + } + + public async Task OnPostAsync() + { + var updateInput = ObjectMapper.Map(ViewModel); + + await pageAdminAppService.UpdateAsync(Id, updateInput); + + return NoContent(); + } + + [AutoMap(typeof(PageDto))] + [AutoMap(typeof(UpdatePageInputDto), ReverseMap = true)] + public class UpdatePageViewModel + { + [Required] + [DynamicMaxLength(typeof(PageConsts), nameof(PageConsts.MaxTitleLength))] + public string Title { get; set; } + + [Required] + [DynamicMaxLength(typeof(PageConsts), nameof(PageConsts.MaxSlugLength))] + public string Slug { get; set; } + + [HiddenInput] + [DynamicMaxLength(typeof(PageConsts), nameof(PageConsts.MaxSlugLength))] + public string Content { get; set; } + } + } +} 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 new file mode 100644 index 0000000000..5872dad438 --- /dev/null +++ b/modules/cms-kit/src/Volo.CmsKit.Admin.Web/Pages/CmsKit/Pages/create.js @@ -0,0 +1,136 @@ +$(function () { + var l = abp.localization.getResource("CmsKit"); + + var $createForm = $('#form-page-create'); + var $title = $('#ViewModel_Title'); + var $slug = $('#ViewModel_Slug'); + var $buttonSubmit = $('#button-page-create'); + + $createForm.data('validator').settings.ignore = ":hidden, [contenteditable='true']:not([name]), .tui-popup-wrapper"; + + $createForm.on('submit', function (e) { + e.preventDefault(); + + if ($createForm.valid()) { + + abp.ui.setBusy(); + + $createForm.ajaxSubmit({ + success: function (result) { + abp.notify.success(l('SuccessfullySaved')); + abp.ui.clearBusy(); + location.href = "../Pages"; + } + }); + } + }); + + $buttonSubmit.click(function (e) { + e.preventDefault(); + $createForm.submit(); + }); + + var slugEdited = false; + + $title.on('change paste keyup', function () { + var title = $title.val(); + + if (slugEdited) { + title = $slug.val(); + } + + var slugified = slugify(title, { + lower: true + }); + + if (slugified != $slug.val()) { + reflectedChange = true; + $slug.val(slugified); + reflectedChange = false; + } + }); + + $slug.change(function () { + slugEdited = true; + }); + + // ----------------------------------- + function getUppyHeaders() { + var headers = {}; + headers[abp.security.antiForgery.tokenHeaderName] = abp.security.antiForgery.getToken(); + + return headers; + } + + var fileUploadUri = "/api/cms-kit-admin/media/page"; + var fileUriPrefix = "/api/cms-kit/media/"; + + var editorDataKey = "tuiEditor"; + + initAllEditors(); + + function initAllEditors() { + $('.content-editor').each(function (i, item) { + initEditor(item); + }); + } + + function initEditor(element) { + var $editorContainer = $(element); + var inputName = $editorContainer.data('input-id'); + var $editorInput = $('#' + inputName); + var initialValue = $editorInput.val(); + + var editor = $editorContainer.tuiEditor({ + usageStatistics: false, + useCommandShortcut: true, + initialValue: initialValue, + previewStyle: 'tab', + height: "25em", + minHeight: "25em", + initialEditType: initialValue ? 'wysiwyg' : 'markdown', + language: $editorContainer.data("language"), + hooks: { + addImageBlobHook: uploadFile, + }, + events: { + change: function (_val) { + $editorInput.val(editor.getHtml()); + $editorInput.trigger("change"); + } + } + }).data(editorDataKey); + } + + function uploadFile(blob, callback, source) { + var UPPY_OPTIONS = { + endpoint: fileUploadUri, + formData: true, + fieldName: "file", + method: "post", + headers: getUppyHeaders() + }; + + var UPPY = Uppy.Core().use(Uppy.XHRUpload, UPPY_OPTIONS); + + UPPY.reset(); + + UPPY.addFile({ + id: "content-file", + name: blob.name, + type: blob.type, + data: blob, + }); + + UPPY.upload().then((result) => { + if (result.failed.length > 0) { + abp.message.error("File upload failed"); + } else { + var mediaDto = result.successful[0].response.body; + var fileUrl = (fileUriPrefix + mediaDto.id); + + callback(fileUrl, mediaDto.name); + } + }); + } +}); \ No newline at end of file diff --git a/modules/cms-kit/src/Volo.CmsKit.Admin.Web/Pages/CmsKit/Pages/index.js b/modules/cms-kit/src/Volo.CmsKit.Admin.Web/Pages/CmsKit/Pages/index.js new file mode 100644 index 0000000000..828da9c55c --- /dev/null +++ b/modules/cms-kit/src/Volo.CmsKit.Admin.Web/Pages/CmsKit/Pages/index.js @@ -0,0 +1,81 @@ +$(function (){ + var l = abp.localization.getResource("CmsKit"); + + var pagesService = volo.cmsKit.admin.pages.pageAdmin; + + var getFilter = function () { + return { + filter: $('#CmsKitPagesWrapper input.page-search-filter-text').val() + }; + }; + + var _dataTable = $("#PagesTable").DataTable(abp.libs.datatables.normalizeConfiguration({ + processing: true, + serverSide: true, + paging: true, + searching: false, + autoWidth: false, + scrollCollapse: true, + scrollX: true, + ordering: true, + order: [[3, "desc"]], + ajax: abp.libs.datatables.createAjax(pagesService.getList, getFilter), + columnDefs: [ + { + title: l("Details"), + targets: 0, + rowAction: { + items: [ + { + text: l('Edit'), + visible: abp.auth.isGranted('CmsKit.Pages.Update'), + action: function (data) { + location.href = 'Pages/Update/' + data.record.id; + } + }, + { + text: l('Delete'), + visible: abp.auth.isGranted('CmsKit.Pages.Delete'), + confirmMessage: function (data) { + return l("PageDeletionConfirmationMessage") + }, + action: function (data) { + pagesService + .delete(data.record.id) + .then(function () { + abp.notify.info(l("SuccessfullyDeleted")); + _dataTable.ajax.reload(); + }); + } + } + ] + } + }, + { + title: l("Title"), + orderable: true, + data: "title" + }, + { + title: l("Slug"), + orderable: true, + data: "slug" + }, + { + title: l("CreationTime"), + orderable: true, + data: 'creationTime' + } + ] + })); + + $('#CmsKitPagesWrapper form.page-search-form').submit(function (e) { + e.preventDefault(); + _dataTable.ajax.reload(); + }); + + $('#AbpContentToolbar button[name=CreatePage]').on('click', function (e) { + e.preventDefault(); + window.location.href = "Pages/Create" + }); +}); \ No newline at end of file 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 new file mode 100644 index 0000000000..8e8ba3d85d --- /dev/null +++ b/modules/cms-kit/src/Volo.CmsKit.Admin.Web/Pages/CmsKit/Pages/update.js @@ -0,0 +1,111 @@ +$(function () { + + var l = abp.localization.getResource("CmsKit"); + + var $formUpdate = $('#form-page-update'); + var $buttonSubmit = $('#button-page-update'); + + $formUpdate.data('validator').settings.ignore = ":hidden, [contenteditable='true']:not([name]), .tui-popup-wrapper"; + + $formUpdate.on('submit', function (e) { + e.preventDefault(); + + if ($formUpdate.valid()) { + + abp.ui.setBusy(); + + $formUpdate.ajaxSubmit({ + success: function (result) { + abp.notify.success(l('SuccessfullySaved')); + abp.ui.clearBusy(); + location.href = "../../Pages"; + } + }); + } + }); + + $buttonSubmit.click(function (e) { + e.preventDefault(); + $formUpdate.submit(); + }); + + // ----------------------------------- + function getUppyHeaders() { + var headers = {}; + headers[abp.security.antiForgery.tokenHeaderName] = abp.security.antiForgery.getToken(); + + return headers; + } + + var fileUploadUri = "/api/cms-kit-admin/media/page"; + var fileUriPrefix = "/api/cms-kit/media/"; + + var editorDataKey = "tuiEditor"; + + initAllEditors(); + + function initAllEditors() { + $('.content-editor').each(function (i, item) { + initEditor(item); + }); + } + + function initEditor(element) { + var $editorContainer = $(element); + var inputName = $editorContainer.data('input-id'); + var $editorInput = $('#' + inputName); + var initialValue = $editorInput.val(); + + var editor = $editorContainer.tuiEditor({ + usageStatistics: false, + useCommandShortcut: true, + initialValue: initialValue, + previewStyle: 'tab', + height: "25em", + minHeight: "25em", + initialEditType: initialValue ? 'wysiwyg' : 'markdown', + language: $editorContainer.data("language"), + hooks: { + addImageBlobHook: uploadFile, + }, + events: { + change: function (_val) { + $editorInput.val(editor.getHtml()); + $editorInput.trigger("change"); + } + } + }).data(editorDataKey); + } + + function uploadFile(blob, callback, source) { + var UPPY_OPTIONS = { + endpoint: fileUploadUri, + formData: true, + fieldName: "file", + method: "post", + headers: getUppyHeaders() + }; + + var UPPY = Uppy.Core().use(Uppy.XHRUpload, UPPY_OPTIONS); + + UPPY.reset(); + + UPPY.addFile({ + id: "content-file", + name: blob.name, + type: blob.type, + data: blob, + }); + + UPPY.upload().then((result) => { + if (result.failed.length > 0) { + abp.message.error("File upload failed"); + } else { + var mediaDto = result.successful[0].response.body; + var fileUrl = (fileUriPrefix + mediaDto.id); + + callback(fileUrl, mediaDto.name); + } + }); + } +}); \ No newline at end of file diff --git a/modules/cms-kit/src/Volo.CmsKit.Admin.Web/Pages/CmsKit/Tags/Components/TagEditor/Default.cshtml b/modules/cms-kit/src/Volo.CmsKit.Admin.Web/Pages/CmsKit/Tags/Components/TagEditor/Default.cshtml new file mode 100644 index 0000000000..b647de10a8 --- /dev/null +++ b/modules/cms-kit/src/Volo.CmsKit.Admin.Web/Pages/CmsKit/Tags/Components/TagEditor/Default.cshtml @@ -0,0 +1,22 @@ +@model TagEditorViewComponent.TagEditorViewModel + +@using Volo.CmsKit.Admin.Web.Pages.CmsKit.Tags.Components.TagEditor +@using Volo.CmsKit.Localization +@using Microsoft.Extensions.Localization + +@inject IStringLocalizer L + +
+ +
+ + +
+ + @if (Model.DisplaySubmitButton) + { + + + + } +
\ No newline at end of file diff --git a/modules/cms-kit/src/Volo.CmsKit.Admin.Web/Pages/CmsKit/Tags/Components/TagEditor/TagEditorViewComponent.cs b/modules/cms-kit/src/Volo.CmsKit.Admin.Web/Pages/CmsKit/Tags/Components/TagEditor/TagEditorViewComponent.cs new file mode 100644 index 0000000000..3c77f8c0c2 --- /dev/null +++ b/modules/cms-kit/src/Volo.CmsKit.Admin.Web/Pages/CmsKit/Tags/Components/TagEditor/TagEditorViewComponent.cs @@ -0,0 +1,49 @@ +using Microsoft.AspNetCore.Mvc; +using System; +using System.Collections.Generic; +using System.Threading.Tasks; +using Volo.Abp.AspNetCore.Mvc; +using Volo.Abp.AspNetCore.Mvc.UI.Widgets; +using Volo.CmsKit.Tags; + +namespace Volo.CmsKit.Admin.Web.Pages.CmsKit.Tags.Components.TagEditor +{ + [Widget( + ScriptFiles = new[] + { + "/Pages/CmsKit/Tags/Components/TagEditor/default.js" + })] + public class TagEditorViewComponent : AbpViewComponent + { + protected ITagAppService TagAppService { get; } + + public TagEditorViewComponent(ITagAppService tagAppService) + { + TagAppService = tagAppService; + } + + public async Task InvokeAsync(string entityType, string entityId, bool displaySubmitButton = true) + { + var tags = + entityId.IsNullOrWhiteSpace() ? + new List() : + await TagAppService.GetAllRelatedTagsAsync(entityType, entityId); + + return View("~/Pages/CmsKit/Tags/Components/TagEditor/Default.cshtml", new TagEditorViewModel + { + EntityId = entityId, + EntityType = entityType, + Tags = tags, + DisplaySubmitButton = displaySubmitButton + }); + } + + public class TagEditorViewModel + { + public string EntityType { get; set; } + public string EntityId { get; set; } + public List Tags { get; set; } + public bool DisplaySubmitButton { get; set; } + } + } +} diff --git a/modules/cms-kit/src/Volo.CmsKit.Admin.Web/Pages/CmsKit/Tags/Components/TagEditor/default.js b/modules/cms-kit/src/Volo.CmsKit.Admin.Web/Pages/CmsKit/Tags/Components/TagEditor/default.js new file mode 100644 index 0000000000..debb0ed084 --- /dev/null +++ b/modules/cms-kit/src/Volo.CmsKit.Admin.Web/Pages/CmsKit/Tags/Components/TagEditor/default.js @@ -0,0 +1,26 @@ +$(function () { + + var $tagEditorForms = $('.tag-editor-form'); + + $tagEditorForms.on('submit', function (e) { + e.preventDefault(); + + var $form = $(e.currentTarget); + + if ($form.valid()) { + + abp.ui.setBusy(); + + var entityId = $form.data('entity-id'); + var entityType = $form.data('entity-type'); + var tags = $form.find('input').val().split(","); + + volo.cmsKit.admin.tags.entityTagAdmin + .setEntityTags({ + entityId: entityId, + entityType: entityType, + tags: tags + }) + } + }) +}) \ No newline at end of file diff --git a/modules/cms-kit/src/Volo.CmsKit.Admin.Web/Pages/CmsKit/Tags/CreateModal.cshtml b/modules/cms-kit/src/Volo.CmsKit.Admin.Web/Pages/CmsKit/Tags/CreateModal.cshtml new file mode 100644 index 0000000000..35ca3df9da --- /dev/null +++ b/modules/cms-kit/src/Volo.CmsKit.Admin.Web/Pages/CmsKit/Tags/CreateModal.cshtml @@ -0,0 +1,23 @@ +@page +@using Microsoft.AspNetCore.Mvc.Localization +@using Volo.CmsKit.Admin.Web.Pages.CmsKit.Tags +@using Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Modal +@using Volo.CmsKit.Localization + +@inject IHtmlLocalizer L + +@model CreateModalModel + +@{ + Layout = null; +} + + + + + + + + + + \ No newline at end of file diff --git a/modules/cms-kit/src/Volo.CmsKit.Admin.Web/Pages/CmsKit/Tags/CreateModal.cshtml.cs b/modules/cms-kit/src/Volo.CmsKit.Admin.Web/Pages/CmsKit/Tags/CreateModal.cshtml.cs new file mode 100644 index 0000000000..5ce3d0cb1f --- /dev/null +++ b/modules/cms-kit/src/Volo.CmsKit.Admin.Web/Pages/CmsKit/Tags/CreateModal.cshtml.cs @@ -0,0 +1,58 @@ +using AutoMapper; +using Microsoft.AspNetCore.Mvc; +using Microsoft.AspNetCore.Mvc.Rendering; +using System.Collections.Generic; +using System.ComponentModel.DataAnnotations; +using System.Linq; +using System.Threading.Tasks; +using Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Form; +using Volo.Abp.Validation; +using Volo.CmsKit.Admin.Tags; +using Volo.CmsKit.Tags; + +namespace Volo.CmsKit.Admin.Web.Pages.CmsKit.Tags +{ + public class CreateModalModel : CmsKitAdminPageModel + { + protected ITagAdminAppService TagAdminAppService { get; } + + [BindProperty] + public TagCreateViewModel ViewModel { get; set; } + + public List TagDefinitions { get; set; } + + public CreateModalModel(ITagAdminAppService tagAdminAppService) + { + TagAdminAppService = tagAdminAppService; + } + + public async Task OnGetAsync() + { + var definitions = await TagAdminAppService.GetTagDefinitionsAsync(); + + TagDefinitions = definitions.Select(s => new SelectListItem(s.DisplayName, s.EntityType)).ToList(); + } + + public async Task OnPostAsync() + { + var tagCreateDto = ObjectMapper.Map(ViewModel); + + await TagAdminAppService.CreateAsync(tagCreateDto); + + return NoContent(); + } + + [AutoMap(typeof(TagCreateDto), ReverseMap = true)] + public class TagCreateViewModel + { + [DynamicMaxLength(typeof(TagConsts), nameof(TagConsts.MaxEntityTypeLength))] + [Required] + [SelectItems(nameof(TagDefinitions))] + public string EntityType { get; set; } + + [DynamicMaxLength(typeof(TagConsts), nameof(TagConsts.MaxNameLength))] + [Required] + public string Name { get; set; } + } + } +} diff --git a/modules/cms-kit/src/Volo.CmsKit.Admin.Web/Pages/CmsKit/Tags/EditModal.cshtml b/modules/cms-kit/src/Volo.CmsKit.Admin.Web/Pages/CmsKit/Tags/EditModal.cshtml new file mode 100644 index 0000000000..3146915cef --- /dev/null +++ b/modules/cms-kit/src/Volo.CmsKit.Admin.Web/Pages/CmsKit/Tags/EditModal.cshtml @@ -0,0 +1,24 @@ +@page +@using Microsoft.AspNetCore.Mvc.Localization +@using Volo.CmsKit.Admin.Web.Pages +@using Volo.CmsKit.Admin.Web.Pages.CmsKit.Tags +@using Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Modal +@using Volo.CmsKit.Localization + +@inject IHtmlLocalizer L +@model EditModalModel + +@{ + Layout = null; +} + + + + + + + + + + + \ No newline at end of file diff --git a/modules/cms-kit/src/Volo.CmsKit.Admin.Web/Pages/CmsKit/Tags/EditModal.cshtml.cs b/modules/cms-kit/src/Volo.CmsKit.Admin.Web/Pages/CmsKit/Tags/EditModal.cshtml.cs new file mode 100644 index 0000000000..7845a1b474 --- /dev/null +++ b/modules/cms-kit/src/Volo.CmsKit.Admin.Web/Pages/CmsKit/Tags/EditModal.cshtml.cs @@ -0,0 +1,54 @@ +using AutoMapper; +using Microsoft.AspNetCore.Mvc; +using System; +using System.Collections.Generic; +using System.ComponentModel.DataAnnotations; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Volo.Abp.Validation; +using Volo.CmsKit.Admin.Tags; +using Volo.CmsKit.Tags; + +namespace Volo.CmsKit.Admin.Web.Pages.CmsKit.Tags +{ + public class EditModalModel : CmsKitAdminPageModel + { + protected ITagAdminAppService TagAdminAppService { get; } + + [HiddenInput] + [BindProperty(SupportsGet = true)] + public Guid Id { get; set; } + + [BindProperty] + public TagEditViewModel ViewModel { get; set; } + + public EditModalModel(ITagAdminAppService tagAdminAppService) + { + this.TagAdminAppService = tagAdminAppService; + } + + public async Task OnGetAsync() + { + var dto = await TagAdminAppService.GetAsync(Id); + + ViewModel = ObjectMapper.Map(dto); + } + + public async Task OnPostAsync() + { + var tagDto = ObjectMapper.Map(ViewModel); + await TagAdminAppService.UpdateAsync(Id, tagDto); + return NoContent(); + } + + [AutoMap(typeof(TagDto))] + [AutoMap(typeof(TagUpdateDto), ReverseMap = true)] + public class TagEditViewModel + { + [Required] + [DynamicMaxLength(typeof(TagConsts), nameof(TagConsts.MaxNameLength))] + public string Name { get; set; } + } + } +} diff --git a/modules/cms-kit/src/Volo.CmsKit.Admin.Web/Pages/CmsKit/Tags/Index.cshtml b/modules/cms-kit/src/Volo.CmsKit.Admin.Web/Pages/CmsKit/Tags/Index.cshtml new file mode 100644 index 0000000000..b568c2737c --- /dev/null +++ b/modules/cms-kit/src/Volo.CmsKit.Admin.Web/Pages/CmsKit/Tags/Index.cshtml @@ -0,0 +1,38 @@ +@page + +@using Volo.CmsKit.Admin.Web.Pages +@using Volo.CmsKit.Admin.Web.Pages.CmsKit.Tags +@using Volo.CmsKit.Admin.Web.Menus +@using Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared.Pages.Shared.Components.AbpPageToolbar +@using Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared.Pages.Shared.Components.AbpPageSearchBox + +@inherits CmsKitAdminPageBase + +@model IndexModel + +@{ + PageLayout.Content.Title = L["Tags"].Value; + PageLayout.Content.BreadCrumb.Add(L["Menu:CMS"].Value); + PageLayout.Content.MenuItemName = CmsKitAdminMenus.Tags.TagsMenu; +} +@section scripts { + +} + +@section content_toolbar { + @await Component.InvokeAsync(typeof(AbpPageToolbarViewComponent), new { pageName = typeof(IndexModel).FullName }) +} + +
+ + + + + @await Component.InvokeAsync(typeof(AbpPageSearchBoxViewComponent)) + + + + + +
+ diff --git a/modules/cms-kit/src/Volo.CmsKit.Admin.Web/Pages/CmsKit/Tags/Index.cshtml.cs b/modules/cms-kit/src/Volo.CmsKit.Admin.Web/Pages/CmsKit/Tags/Index.cshtml.cs new file mode 100644 index 0000000000..268e61ab0e --- /dev/null +++ b/modules/cms-kit/src/Volo.CmsKit.Admin.Web/Pages/CmsKit/Tags/Index.cshtml.cs @@ -0,0 +1,8 @@ +using Volo.Abp.AspNetCore.Mvc.UI.RazorPages; + +namespace Volo.CmsKit.Admin.Web.Pages.CmsKit.Tags +{ + public class IndexModel : CmsKitAdminPageModel + { + } +} diff --git a/modules/cms-kit/src/Volo.CmsKit.Admin.Web/Pages/CmsKit/Tags/Index.js b/modules/cms-kit/src/Volo.CmsKit.Admin.Web/Pages/CmsKit/Tags/Index.js new file mode 100644 index 0000000000..85e91908d6 --- /dev/null +++ b/modules/cms-kit/src/Volo.CmsKit.Admin.Web/Pages/CmsKit/Tags/Index.js @@ -0,0 +1,83 @@ +$(function () { + var l = abp.localization.getResource("CmsKit"); + + var createModal = new abp.ModalManager(abp.appPath + "CmsKit/Tags/CreateModal"); + var updateModal = new abp.ModalManager(abp.appPath + "CmsKit/Tags/EditModal"); + + var service = volo.cmsKit.admin.tags.tagAdmin; + + var getFilter = function () { + return { + filter: $('#CmsKitTagsWrapper input.page-search-filter-text').val() + }; + }; + + let dataTable = $("#TagsTable").DataTable(abp.libs.datatables.normalizeConfiguration({ + processing: true, + serverSide: true, + paging: true, + searching: false, + autoWidth: false, + scrollCollapse: true, + scrollX: true, + ordering: false, + ajax: abp.libs.datatables.createAjax(service.getList, getFilter), + columnDefs: [ + { + title: l("Actions"), + rowAction: { + items: [ + { + text: l("Edit"), + visible: abp.auth.isGranted('CmsKit.Tags.Update'), + action: function (data) { + updateModal.open({ id: data.record.id }); + } + }, + { + text: l("Delete"), + visible: abp.auth.isGranted('CmsKit.Tags.Delete'), + confirmMessage: function (data) { + return l("TagDeletionConfirmationMessage", data.record.name) + }, + action: function (data) { + service + .delete(data.record.id) + .then(function () { + abp.notify.info(l("SuccessfullyDeleted")); + dataTable.ajax.reload(null, false); + }); + } + } + ] + } + }, + { + title: l("EntityType"), + data: "entityType" + }, + { + title: l("Name"), + data: "name" + } + ] + })); + + $('#CmsKitTagsWrapper form.page-search-form').on('submit', function (e) { + e.preventDefault(); + dataTable.ajax.reload(); + }); + + $('#AbpContentToolbar button[name=NewButton]').on('click', function (e) { + e.preventDefault(); + createModal.open(); + }); + + createModal.onResult(function () { + dataTable.ajax.reload(); + }); + + updateModal.onResult(function () { + dataTable.ajax.reload(); + }); +}); \ No newline at end of file diff --git a/modules/cms-kit/src/Volo.CmsKit.Admin.Web/Pages/CmsKit/_ViewImports.cshtml b/modules/cms-kit/src/Volo.CmsKit.Admin.Web/Pages/CmsKit/_ViewImports.cshtml new file mode 100644 index 0000000000..c1da1f5f10 --- /dev/null +++ b/modules/cms-kit/src/Volo.CmsKit.Admin.Web/Pages/CmsKit/_ViewImports.cshtml @@ -0,0 +1,4 @@ +@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers +@addTagHelper *, Volo.Abp.AspNetCore.Mvc.UI +@addTagHelper *, Volo.Abp.AspNetCore.Mvc.UI.Bootstrap +@addTagHelper *, Volo.Abp.AspNetCore.Mvc.UI.Bundling \ No newline at end of file diff --git a/modules/cms-kit/src/Volo.CmsKit.Admin.Web/Pages/CmsKitAdminPageBase.cs b/modules/cms-kit/src/Volo.CmsKit.Admin.Web/Pages/CmsKitAdminPageBase.cs new file mode 100644 index 0000000000..b45176453a --- /dev/null +++ b/modules/cms-kit/src/Volo.CmsKit.Admin.Web/Pages/CmsKitAdminPageBase.cs @@ -0,0 +1,20 @@ +using Microsoft.AspNetCore.Mvc.Razor.Internal; +using Microsoft.Extensions.Localization; +using System.Threading.Tasks; +using Volo.Abp.AspNetCore.Mvc.UI.Layout; +using Volo.CmsKit.Localization; + +namespace Volo.CmsKit.Admin.Web.Pages +{ + public class CmsKitAdminPageBase : Microsoft.AspNetCore.Mvc.RazorPages.Page + { + [RazorInject] public IStringLocalizer L { get; set; } + + [RazorInject] public IPageLayout PageLayout { get; set; } + + public override Task ExecuteAsync() + { + return Task.CompletedTask; // Will be overriden by razor pages. (.cshtml) + } + } +} diff --git a/modules/cms-kit/src/Volo.CmsKit.Admin.Web/Volo.CmsKit.Admin.Web.csproj b/modules/cms-kit/src/Volo.CmsKit.Admin.Web/Volo.CmsKit.Admin.Web.csproj index d1d1f28fac..9ba777ace5 100644 --- a/modules/cms-kit/src/Volo.CmsKit.Admin.Web/Volo.CmsKit.Admin.Web.csproj +++ b/modules/cms-kit/src/Volo.CmsKit.Admin.Web/Volo.CmsKit.Admin.Web.csproj @@ -1,4 +1,4 @@ - + diff --git a/modules/cms-kit/src/Volo.CmsKit.Common.Application/Volo/CmsKit/CmsKitCommonApplicationModule.cs b/modules/cms-kit/src/Volo.CmsKit.Common.Application/Volo/CmsKit/CmsKitCommonApplicationModule.cs index 8fa08fa950..1778e7e234 100644 --- a/modules/cms-kit/src/Volo.CmsKit.Common.Application/Volo/CmsKit/CmsKitCommonApplicationModule.cs +++ b/modules/cms-kit/src/Volo.CmsKit.Common.Application/Volo/CmsKit/CmsKitCommonApplicationModule.cs @@ -1,6 +1,11 @@ using Volo.Abp.Application; using Volo.Abp.AutoMapper; +using Volo.Abp.GlobalFeatures; using Volo.Abp.Modularity; +using Volo.CmsKit.Blogs; +using Volo.CmsKit.GlobalFeatures; +using Volo.CmsKit.MediaDescriptors; +using Volo.CmsKit.Permissions; namespace Volo.CmsKit { diff --git a/modules/cms-kit/src/Volo.CmsKit.Domain.Shared/Volo/CmsKit/Blogs/BlogPostConsts.cs b/modules/cms-kit/src/Volo.CmsKit.Domain.Shared/Volo/CmsKit/Blogs/BlogPostConsts.cs index 7e1de6e7c0..91748dc1e3 100644 --- a/modules/cms-kit/src/Volo.CmsKit.Domain.Shared/Volo/CmsKit/Blogs/BlogPostConsts.cs +++ b/modules/cms-kit/src/Volo.CmsKit.Domain.Shared/Volo/CmsKit/Blogs/BlogPostConsts.cs @@ -11,6 +11,8 @@ namespace Volo.CmsKit.Blogs public static int MinSlugLength { get; set; } = 2; public static int MaxShortDescriptionLength { get; set; } = 256; + + public static int MaxContentLength { get; set; } = int.MaxValue; public const string EntityType = "BlogPost"; } diff --git a/modules/cms-kit/src/Volo.CmsKit.Domain.Shared/Volo/CmsKit/CmsKitErrorCodes.cs b/modules/cms-kit/src/Volo.CmsKit.Domain.Shared/Volo/CmsKit/CmsKitErrorCodes.cs index 64956b8683..064c504fb4 100644 --- a/modules/cms-kit/src/Volo.CmsKit.Domain.Shared/Volo/CmsKit/CmsKitErrorCodes.cs +++ b/modules/cms-kit/src/Volo.CmsKit.Domain.Shared/Volo/CmsKit/CmsKitErrorCodes.cs @@ -24,10 +24,16 @@ { public const string SlugAlreadyExist = "CmsKit:BlogPost:0001"; } + + public static class Comments + { + public const string EntityNotCommentable = "CmsKit:Comments:0001"; + } public static class MediaDescriptors { public const string InvalidName = "CmsKit:Media:0001"; + public const string EntityTypeDoesntExist = "CmsKit:Media:0002"; } } } 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 212d495459..5ae38566af 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 @@ -1,24 +1,67 @@ { "culture": "en", "texts": { + "BlogDeletionConfirmationMessage": "The blog '{0}' will be deleted. Are you sure?", + "BlogFeatureNotAvailable": "This feature is not available now. Enable with 'GlobalFeatureManager' to use it.", + "BlogId": "Blog", + "BlogPostDeletionConfirmationMessage": "The blog post '{0}' will be deleted. Are you sure?", + "BlogPosts": "Blog Posts", + "Blogs": "Blogs", + "ChoosePreference": "Choose Preference...", + "Cms": "Cms", + "CmsKit.Comments": "Comments", + "CmsKit.Ratings": "Ratings", + "CmsKit.Reactions": "Reactions", + "CmsKit.Tags": "Tags", "CmsKit:0002": "Content already exists!", "CmsKit:0003": "The entity {0} is not taggable.", "CmsKit:Blog:0001": "The given slug ({Slug}) already exists!", "CmsKit:BlogPost:0001": "The given slug already exists!", + "CmsKit:Comments:0001": "The entity {0} is not commentable.", "CmsKit:Media:0001": "'{Name}' is not a valid media name.", + "CmsKit:Media:0002": "The entity can't have media.", "CmsKit:Page:0001": "The given url ({0}) already exists.", "CmsKit:Tag:0002": "The entity is not taggable!", "CommentAuthorizationExceptionMessage": "Those comments are not allowed for public display.", + "CommentDeletionConfirmationMessage": "This comment and all replies will be deleted!", "Comments": "Comments", + "ContentDeletionConfirmationMessage": "Are you sure to delete this content?", + "Contents": "Contents", + "CoverImage": "Cover Image", + "CreateBlogPostPage": "New Blog Post", + "CreationTime": "Creation Time", "Delete": "Delete", + "Detail": "Detail", + "Details": "Details", + "DoYouPreferAdditionalEmails": "Do you prefer additional emails?", "Edit": "Edit", + "EndDate": "End Date", + "EntityId": "Entity Id", + "EntityType": "Entity Type", + "ExportCSV": "Export CSV", + "Features": "Features", + "GenericDeletionConfirmationMessage": "Are you sure to delete '{0}'?", "LastModification": "Last Modification", "LoginToAddComment": "Login to add comment", "LoginToRate": "Login to rate", "LoginToReply": "Login to reply", "Menu:CMS": "CMS", + "Message": "Message", "MessageDeletionConfirmationMessage": "This comment will be deleted completely.", + "Name": "Name", + "New": "New", + "OK": "OK", + "PageDeletionConfirmationMessage": "Are you sure to delete this page?", + "PageSlugInformation": "Slug is used on url. Your url will be '/pages/{{slug}}'.", + "Permission:BlogManagement": "Blog Management", + "Permission:BlogManagement.Create": "Create", + "Permission:BlogManagement.Delete": "Delete", "Permission:BlogManagement.Features": "Features", + "Permission:BlogManagement.Update": "Update", + "Permission:BlogPostManagement": "Blog Post Management", + "Permission:BlogPostManagement.Create": "Create", + "Permission:BlogPostManagement.Delete": "Delete", + "Permission:BlogPostManagement.Update": "Update", "Permission:CmsKit": "CmsKit", "Permission:Comments": "Comment Management", "Permission:Comments.Delete": "Delete", @@ -40,14 +83,42 @@ "PickYourReaction": "Pick your reaction", "RatingUndoMessage": "Your rating will be undo.", "Read": "Read", + "RepliesToThisComment": "Replies to this comment", "Reply": "Reply", + "ReplyTo": "Reply to", + "SamplePageMessage": "A sample page for the Pro module", + "SaveChanges": "Save Changes", + "SelectAll": "Select All", "Send": "Send", + "SendMessage": "Send Message", + "ShortDescription": "Short description", + "Slug": "Slug", + "Source": "Source", + "SourceUrl": "Source Url", "Star": "Star", + "StartDate": "Start Date", + "Subject": "Subject", + "SubjectPlaceholder": "Please type a subject", + "Submit": "Submit", + "Subscribe": "Subscribe", + "SuccessfullyDeleted": "Successfully deleted!", + "SuccessfullySaved": "Successfully saved!", "TagDeletionConfirmationMessage": "Are you sure to delete '{0}' tag?", "Tags": "Tags", + "Text": "Text", + "ThankYou": "Thank you", + "Title": "Title", "Undo": "Undo", "Update": "Update", + "UpdatePreferenceSuccessMessage": "Your preferences have been saved.", + "UpdateYourEmailPreferences": "Update your email preferences", + "UploadFailedMessage": "Upload failed.", + "UserId": "User Id", + "Username": "Username", "YourComment": "Your comment", + "YourEmailAddress": "Your e-mail address", + "YourFullName": "Your full name", + "YourMessage": "Your Message", "YourReply": "Your reply" } } diff --git a/modules/cms-kit/src/Volo.CmsKit.Domain.Shared/Volo/CmsKit/Localization/Resources/tr.json b/modules/cms-kit/src/Volo.CmsKit.Domain.Shared/Volo/CmsKit/Localization/Resources/tr.json index af032d5480..2571d7ad96 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 @@ -1,22 +1,66 @@ { "culture": "tr", "texts": { + "BlogDeletionConfirmationMessage": "'{0}' adlı blog silinecek. Emin misiniz?", + "BlogFeatureNotAvailable": "Bu özellik kullanılabilir değil. 'GlobalFeatureManager' ile aktif ederek kullanabilisiniz.", + "BlogId": "Blog", + "BlogPostDeletionConfirmationMessage": "'{0}' başlıklı blog yazısı silinecek. Emin misiniz?", + "BlogPosts": "Blog Yazıları", + "Blogs": "Bloglar", + "ChoosePreference": "Tercih seçiniz...", + "Cms": "Cms", + "CmsKit.Comments": "Yorumlar", + "CmsKit.Ratings": "Puanlama", + "CmsKit.Reactions": "Tepkiler", + "CmsKit.Tags": "Etiketler", + "CmsKit:Comments:0001": "{0} ögesi yorumlanabilir değil.", "CmsKit:0002": "İçerik zaten mevcut!", "CmsKit:0003": "{0} ögesi etiketlenebilir değil.", "CmsKit:BlogPost:0001": "Aynı url etiketi zaten mevcut.", + "CmsKit:Media:0002": "Bu öge için medya eklenemez.", "CmsKit:Page:0001": "Girilen url ({0}) kullanımdadır.", "CmsKit:Tag:0002": "Bu öge etiketlenebilir değil.", "CommentAuthorizationExceptionMessage": "Bu yorumları görebilmek için yetki gerekir.", + "CommentDeletionConfirmationMessage": "Bu yorum ve buna yapılan tüm yorumlan silinecektir!", "Comments": "Yorumlar", + "ContentDeletionConfirmationMessage": "Bu içeriği gerçekten silmek istediğinize emin misiniz?", + "Contents": "İçerikler", + "CoverImage": "Kapak Resmi", + "CreateBlogPostPage": "Yeni Blog Yazısı", + "CreationTime": "Oluşturulma Zamanı", "Delete": "Sil", + "DeleteSubscriptionSubject": "E-posta adresiniz silinmiştir.", + "Detail": "Detay", + "Details": "Detaylar", + "DoYouPreferAdditionalEmails": "Ek e-postaları tercih ediyor musunuz?", "Edit": "Düzenle", + "EndDate": "Bitiş Tarihi", + "EntityId": "Entity Id", + "EntityType": "Entity Tür", + "ExportCSV": "CSV olarak dışa aktar", + "Features": "Özellikler", + "GenericDeletionConfirmationMessage": "'{0}' kaydını silmek istediğinize emin misiniz?", "LastModification": "Son Güncellenme", "LoginToAddComment": "Yorum yapmak için giriş yap", "LoginToRate": "Oylamak için giriş yapın", "LoginToReply": "Cevap vermek için giriş yap", "Menu:CMS": "CMS", + "Message": "Mesaj", "MessageDeletionConfirmationMessage": "Bu yorum tamamen silinecektir", + "Name": "Ad", + "New": "Yeni", + "OK": "Tamam", + "PageDeletionConfirmationMessage": "Bu sayfayı silmek istediğinize emin misiniz?", + "PageSlugInformation": "Etiket URL'de kullanılır. Url şöyle görünür: '/pages/{{slug}}'.", + "Permission:BlogManagement": "Blog Yönetimi", + "Permission:BlogManagement.Create": "Oluşturma", + "Permission:BlogManagement.Delete": "Silme", "Permission:BlogManagement.Features": "Özellikler", + "Permission:BlogManagement.Update": "Güncelleme", + "Permission:BlogPostManagement": "Blog Yazıları Yönetimi", + "Permission:BlogPostManagement.Create": "Oluşturma", + "Permission:BlogPostManagement.Delete": "Silme", + "Permission:BlogPostManagement.Update": "Güncelleme", "Permission:CmsKit": "CmsKit", "Permission:Contents": "İçerik Yönetimi", "Permission:Contents.Create": "İçerik Oluşturma", @@ -29,14 +73,43 @@ "PickYourReaction": "Tepkinizi seçin", "RatingUndoMessage": "Oylamanız geri alınacak.", "Read": "Oku", + "RepliesToThisComment": "Bu yoruma yapılan yorumlar", "Reply": "Cevapla", + "ReplyTo": "Cevap", + "SamplePageMessage": "Pro modulünden örnek bir sayfa", + "SaveChanges": "Değişiklikleri Kaydet", + "SelectAll": "Hepsini seç", "Send": "Gönder", + "SendMessage": "Mesajı Gönder", + "ShortDescription": "Kısa açıklama", + "Slug": "Etiket", + "Source": "Kaynak", + "SourceUrl": "Kaynak Link", "Star": "Yıldız", + "StartDate": "Başlangıç Tarihi", + "Subject": "Konu", + "SubjectPlaceholder": "Lütfen bir konu yazınız", + "Submit": "Kaydet", + "Subscribe": "Abone ol", + "SuccessfullyDeleted": "Başarıyla silindi!", + "SuccessfullySaved": "Başarıyla kaydedildi!", "TagDeletionConfirmationMessage": "'{0}' etiketini silmek istediğinize emin misiniz?", "Tags": "Etiketler", + "Text": "Metin", + "ThankYou": "Teşekkürler", + "Title": "Başlık", "Undo": "Geri al", "Update": "Güncelle", + "UpdatePreference": "Tercihleri Güncelle", + "UpdatePreferenceSuccessMessage": "Tercihleriniz kaydedilmiştir.", + "UpdateYourEmailPreferences": "E-posta tercihlerinizi güncelleyin", + "UploadFailedMessage": "Karşıya yükleme işlemi başarısız oldu.", + "UserId": "Kullanıcı Id", + "Username": "Kullanıcı adı", "YourComment": "Yorumunuz", + "YourEmailAddress": "Email adresiniz", + "YourFullName": "Tam adınız", + "YourMessage": "Mesajınız", "YourReply": "Cevabınız" } } diff --git a/modules/cms-kit/src/Volo.CmsKit.Domain.Shared/Volo/CmsKit/MediaDescriptors/MediaDescriptorConsts.cs b/modules/cms-kit/src/Volo.CmsKit.Domain.Shared/Volo/CmsKit/MediaDescriptors/MediaDescriptorConsts.cs index 5f4741828e..31737fa9fe 100644 --- a/modules/cms-kit/src/Volo.CmsKit.Domain.Shared/Volo/CmsKit/MediaDescriptors/MediaDescriptorConsts.cs +++ b/modules/cms-kit/src/Volo.CmsKit.Domain.Shared/Volo/CmsKit/MediaDescriptors/MediaDescriptorConsts.cs @@ -1,7 +1,11 @@ -namespace Volo.CmsKit.MediaDescriptors +using Volo.CmsKit.Entities; + +namespace Volo.CmsKit.MediaDescriptors { public class MediaDescriptorConsts { + public static int MaxEntityTypeLength { get; set; } = CmsEntityConsts.MaxEntityTypeLength; + public static int MaxNameLength { get; set; } = 255; public static int MaxMimeTypeLength { get; set; } = 128; 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 47d82b5d07..7b9b8a1f5c 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,8 +2,12 @@ { public class PageConsts { + public const string EntityType = "Page"; + public static int MaxTitleLength { get; set; } = 256; public static int MaxSlugLength { get; set; } = 256; + + public static int MaxContentLength { get; set; } = int.MaxValue; } } \ No newline at end of file diff --git a/modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/AssemblyInfo.cs b/modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/AssemblyInfo.cs new file mode 100644 index 0000000000..f8d4fc09f3 --- /dev/null +++ b/modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/AssemblyInfo.cs @@ -0,0 +1,4 @@ +using System.Runtime.CompilerServices; + +[assembly: InternalsVisibleTo("Volo.CmsKit.Domain.Tests", AllInternalsVisible = true)] +[assembly: InternalsVisibleTo("Volo.CmsKit.TestBase", AllInternalsVisible = true)] \ No newline at end of file diff --git a/modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/Blogs/BlogPost.cs b/modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/Blogs/BlogPost.cs index dc10725359..251a9c2895 100644 --- a/modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/Blogs/BlogPost.cs +++ b/modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/Blogs/BlogPost.cs @@ -21,9 +21,10 @@ namespace Volo.CmsKit.Blogs [NotNull] public virtual string ShortDescription { get; protected set; } + public virtual string Content { get; protected set; } + public virtual Guid? TenantId { get; protected set; } - [NotNull] public Guid AuthorId { get; set; } public virtual CmsUser Author { get; set; } @@ -38,13 +39,17 @@ namespace Volo.CmsKit.Blogs Guid authorId, [NotNull] string title, [NotNull] string slug, - [CanBeNull] string shortDescription = null) : base(id) + [CanBeNull] string shortDescription = null, + [CanBeNull] string content = null, + [CanBeNull] Guid? tenantId = null) : base(id) { + TenantId = tenantId; BlogId = blogId; AuthorId = authorId; SetTitle(title); SetSlug(slug); - ShortDescription = shortDescription; + SetShortDescription(shortDescription); + SetContent(content); } public virtual void SetTitle(string title) @@ -63,5 +68,10 @@ namespace Volo.CmsKit.Blogs { ShortDescription = Check.Length(shortDescription, nameof(shortDescription), BlogPostConsts.MaxShortDescriptionLength); } + + public virtual void SetContent(string content) + { + Content = Check.Length(content, nameof(content), BlogPostConsts.MaxContentLength); + } } } diff --git a/modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/Blogs/BlogPostManager.cs b/modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/Blogs/BlogPostManager.cs index 4ee29608b4..3e15b91117 100644 --- a/modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/Blogs/BlogPostManager.cs +++ b/modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/Blogs/BlogPostManager.cs @@ -27,7 +27,7 @@ namespace Volo.CmsKit.Blogs [NotNull] string title, [NotNull] string slug, [CanBeNull] string shortDescription = null, - [CanBeNull] Guid? tenantId = null) + [CanBeNull] string content = null) { Check.NotNull(author, nameof(author)); Check.NotNull(blog, nameof(blog)); @@ -42,7 +42,9 @@ namespace Volo.CmsKit.Blogs author.Id, title, slug, - shortDescription + shortDescription, + content, + CurrentTenant.Id ); await CheckSlugExistenceAsync(blog.Id, blogPost.Slug); diff --git a/modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/Comments/CmsKitCommentOptions.cs b/modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/Comments/CmsKitCommentOptions.cs new file mode 100644 index 0000000000..7e1dcbc1dd --- /dev/null +++ b/modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/Comments/CmsKitCommentOptions.cs @@ -0,0 +1,11 @@ +using JetBrains.Annotations; +using System.Collections.Generic; + +namespace Volo.CmsKit.Comments +{ + public class CmsKitCommentOptions + { + [NotNull] + public List EntityTypes { get; } = new List(); + } +} diff --git a/modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/Comments/Comment.cs b/modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/Comments/Comment.cs index 0d2a7e7a18..ea37b5ebdc 100644 --- a/modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/Comments/Comment.cs +++ b/modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/Comments/Comment.cs @@ -28,7 +28,7 @@ namespace Volo.CmsKit.Comments } - public Comment( + internal Comment( Guid id, [NotNull] string entityType, [NotNull] string entityId, diff --git a/modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/Comments/CommentEntityTypeDefinition.cs b/modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/Comments/CommentEntityTypeDefinition.cs new file mode 100644 index 0000000000..fe0f8ebda3 --- /dev/null +++ b/modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/Comments/CommentEntityTypeDefinition.cs @@ -0,0 +1,21 @@ +using JetBrains.Annotations; +using System; +using Volo.Abp; + +namespace Volo.CmsKit.Comments +{ + public class CommentEntityTypeDefinition : IEquatable + { + public CommentEntityTypeDefinition([NotNull] string entityType) + { + EntityType = Check.NotNullOrEmpty(entityType, nameof(entityType)); + } + + public string EntityType { get; } + + public bool Equals(CommentEntityTypeDefinition other) + { + return EntityType == other?.EntityType; + } + } +} diff --git a/modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/Comments/CommentManager.cs b/modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/Comments/CommentManager.cs new file mode 100644 index 0000000000..bbc44c4d06 --- /dev/null +++ b/modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/Comments/CommentManager.cs @@ -0,0 +1,46 @@ + +using JetBrains.Annotations; +using System; +using System.Threading.Tasks; +using Volo.Abp; +using Volo.Abp.Domain.Services; +using Volo.CmsKit.Users; + +namespace Volo.CmsKit.Comments +{ + public class CommentManager : DomainService + { + protected ICommentEntityTypeDefinitionStore DefinitionStore { get; } + + public CommentManager(ICommentEntityTypeDefinitionStore definitionStore) + { + DefinitionStore = definitionStore; + } + + public virtual async Task CreateAsync([NotNull] CmsUser creator, + [NotNull] string entityType, + [NotNull] string entityId, + [NotNull] string text, + [CanBeNull] Guid? repliedCommentId = null) + { + Check.NotNull(creator, nameof(creator)); + Check.NotNullOrWhiteSpace(entityType, nameof(entityType), CommentConsts.MaxEntityTypeLength); + Check.NotNullOrWhiteSpace(entityId, nameof(entityId), CommentConsts.MaxEntityIdLength); + Check.NotNullOrWhiteSpace(text, nameof(text), CommentConsts.MaxTextLength); + + if (!await DefinitionStore.IsDefinedAsync(entityType)) + { + throw new EntityNotCommentableException(entityType); + } + + return new Comment( + GuidGenerator.Create(), + entityType, + entityId, + text, + repliedCommentId, + creator.Id, + CurrentTenant.Id); + } + } +} diff --git a/modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/Comments/DefaultCommentEntityTypeDefinitionStore.cs b/modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/Comments/DefaultCommentEntityTypeDefinitionStore.cs new file mode 100644 index 0000000000..bbb1b19aee --- /dev/null +++ b/modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/Comments/DefaultCommentEntityTypeDefinitionStore.cs @@ -0,0 +1,41 @@ +using JetBrains.Annotations; +using Microsoft.Extensions.Options; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Volo.Abp; +using Volo.Abp.DependencyInjection; + +namespace Volo.CmsKit.Comments +{ + public class DefaultCommentEntityTypeDefinitionStore : ICommentEntityTypeDefinitionStore, ITransientDependency + { + protected CmsKitCommentOptions Options { get; } + + public DefaultCommentEntityTypeDefinitionStore(IOptions options) + { + Options = options.Value; + } + + public virtual Task GetDefinitionAsync([NotNull] string entityType) + { + Check.NotNullOrWhiteSpace(entityType, nameof(entityType)); + + var result = Options.EntityTypes.SingleOrDefault(x => x.EntityType.Equals(entityType, StringComparison.InvariantCultureIgnoreCase)) ?? + throw new EntityNotCommentableException(entityType); + + return Task.FromResult(result); + } + + public virtual Task IsDefinedAsync([NotNull] string entityType) + { + Check.NotNullOrWhiteSpace(entityType, nameof(entityType)); + + var isDefined = Options.EntityTypes.Any(x => x.EntityType == entityType); + + return Task.FromResult(isDefined); + } + } +} diff --git a/modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/Comments/EntityNotCommentableException.cs b/modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/Comments/EntityNotCommentableException.cs new file mode 100644 index 0000000000..ee1a8621bb --- /dev/null +++ b/modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/Comments/EntityNotCommentableException.cs @@ -0,0 +1,27 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Runtime.Serialization; +using System.Text; +using System.Threading.Tasks; +using Volo.Abp; + +namespace Volo.CmsKit.Comments +{ + [Serializable] + public class EntityNotCommentableException : BusinessException + { + public EntityNotCommentableException(SerializationInfo serializationInfo, StreamingContext context) : base(serializationInfo, context) + { + } + + public EntityNotCommentableException(string entityType) + { + Code = CmsKitErrorCodes.Comments.EntityNotCommentable; + EntityType = entityType; + WithData(nameof(EntityType), EntityType); + } + + public string EntityType { get; } + } +} diff --git a/modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/Comments/ICommentEntityTypeDefinitionStore.cs b/modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/Comments/ICommentEntityTypeDefinitionStore.cs new file mode 100644 index 0000000000..315b7f878f --- /dev/null +++ b/modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/Comments/ICommentEntityTypeDefinitionStore.cs @@ -0,0 +1,17 @@ +using JetBrains.Annotations; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Volo.CmsKit.Comments; + +namespace Volo.CmsKit.Comments +{ + public interface ICommentEntityTypeDefinitionStore + { + Task GetDefinitionAsync([NotNull] string entityType); + + Task IsDefinedAsync([NotNull] string entityType); + } +} diff --git a/modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/Contents/Content.cs b/modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/Contents/Content.cs deleted file mode 100644 index 392abfbc6f..0000000000 --- a/modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/Contents/Content.cs +++ /dev/null @@ -1,44 +0,0 @@ -using System; -using JetBrains.Annotations; -using Volo.Abp; -using Volo.Abp.Domain.Entities.Auditing; -using Volo.Abp.MultiTenancy; - -namespace Volo.CmsKit.Contents -{ - public class Content : FullAuditedAggregateRoot, IMultiTenant - { - [CanBeNull] public virtual Guid? TenantId { get; protected set; } - - [NotNull] public virtual string EntityType { get; protected set; } - - [NotNull] public virtual string EntityId { get; protected set; } - - [NotNull] public virtual string Value { get; protected set; } - - protected Content() - { - } - - public Content(Guid id, [NotNull] string entityType, [NotNull] string entityId, [NotNull] string value, - Guid? tenantId = null) : base(id) - { - EntityId = Check.NotNullOrWhiteSpace(entityId, nameof(entityId), ContentConsts.MaxEntityIdLength); - EntityType = Check.NotNullOrEmpty(entityType, nameof(entityType), ContentConsts.MaxEntityTypeLength); - Value = Check.NotNullOrEmpty(value, nameof(value), ContentConsts.MaxValueLength); - - TenantId = tenantId; - } - - public virtual void SetValue([NotNull] string value) - { - Value = Check.NotNullOrEmpty(value, nameof(value), ContentConsts.MaxValueLength); - } - - public virtual void SetEntity([NotNull] string entityType, [NotNull] string entityId) - { - EntityType = Check.NotNullOrEmpty(entityType, nameof(entityType), ContentConsts.MaxEntityTypeLength); - EntityId = Check.NotNullOrWhiteSpace(entityId, nameof(entityId), ContentConsts.MaxEntityIdLength); - } - } -} \ No newline at end of file diff --git a/modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/Contents/ContentAlreadyExistException.cs b/modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/Contents/ContentAlreadyExistException.cs deleted file mode 100644 index 8ea4d4c54a..0000000000 --- a/modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/Contents/ContentAlreadyExistException.cs +++ /dev/null @@ -1,17 +0,0 @@ -using JetBrains.Annotations; -using System; -using Volo.Abp; - -namespace Volo.CmsKit.Contents -{ - [Serializable] - public class ContentAlreadyExistException : BusinessException - { - public ContentAlreadyExistException([NotNull] string entityType, [NotNull] string entityId) - { - Code = CmsKitErrorCodes.ContentAlreadyExist; - WithData(nameof(Content.EntityType), entityType); - WithData(nameof(Content.EntityId), entityId); - } - } -} diff --git a/modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/Contents/ContentManager.cs b/modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/Contents/ContentManager.cs deleted file mode 100644 index 707f15bbb9..0000000000 --- a/modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/Contents/ContentManager.cs +++ /dev/null @@ -1,32 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading; -using System.Threading.Tasks; -using Volo.Abp.Domain.Services; -using Volo.CmsKit.Contents; - -namespace Volo.CmsKit.Contents -{ - public class ContentManager : DomainService, IContentManager - { - protected IContentRepository ContentRepository { get; } - - public ContentManager(IContentRepository contentRepository) - { - ContentRepository = contentRepository; - } - - public virtual async Task InsertAsync(Content content, CancellationToken cancellationToken = default) - { - if (await ContentRepository.ExistsAsync(content.EntityType, content.EntityId, content.TenantId, - cancellationToken)) - { - throw new ContentAlreadyExistException(content.EntityType, content.EntityId); - } - - return await ContentRepository.InsertAsync(content, cancellationToken: cancellationToken); - } - } -} \ No newline at end of file diff --git a/modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/Contents/IContentManager.cs b/modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/Contents/IContentManager.cs deleted file mode 100644 index d64bd0effe..0000000000 --- a/modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/Contents/IContentManager.cs +++ /dev/null @@ -1,11 +0,0 @@ -using System.Threading; -using System.Threading.Tasks; -using Volo.CmsKit.Contents; - -namespace Volo.CmsKit.Contents -{ - public interface IContentManager - { - Task InsertAsync(Content content, CancellationToken cancellationToken = default); - } -} diff --git a/modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/Contents/IContentRepository.cs b/modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/Contents/IContentRepository.cs deleted file mode 100644 index 3b767b4722..0000000000 --- a/modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/Contents/IContentRepository.cs +++ /dev/null @@ -1,35 +0,0 @@ -using JetBrains.Annotations; -using System; -using System.Threading; -using System.Threading.Tasks; -using Volo.Abp.Domain.Repositories; - -namespace Volo.CmsKit.Contents -{ - public interface IContentRepository : IBasicRepository - { - Task GetAsync( - [NotNull] string entityType, - [NotNull] string entityId, - Guid? tenantId = null, - CancellationToken cancellationToken = default); - - Task FindAsync( - [NotNull] string entityType, - [NotNull] string entityId, - Guid? tenantId = null, - CancellationToken cancellationToken = default); - - Task DeleteAsync( - [NotNull] string entityType, - [NotNull] string entityId, - Guid? tenantId = null, - CancellationToken cancellationToken = default); - - Task ExistsAsync( - [NotNull] string entityType, - [NotNull] string entityId, - Guid? tenantId = null, - CancellationToken cancellationToken = default); - } -} \ No newline at end of file diff --git a/modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/MediaDescriptors/CmsKitMediaOptions.cs b/modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/MediaDescriptors/CmsKitMediaOptions.cs new file mode 100644 index 0000000000..89f5d0dca3 --- /dev/null +++ b/modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/MediaDescriptors/CmsKitMediaOptions.cs @@ -0,0 +1,15 @@ +using JetBrains.Annotations; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Volo.CmsKit.MediaDescriptors +{ + public class CmsKitMediaOptions + { + [NotNull] + public List EntityTypes { get; } = new(); + } +} diff --git a/modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/MediaDescriptors/DefaultMediaDescriptorDefinitionStore.cs b/modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/MediaDescriptors/DefaultMediaDescriptorDefinitionStore.cs new file mode 100644 index 0000000000..752f921da7 --- /dev/null +++ b/modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/MediaDescriptors/DefaultMediaDescriptorDefinitionStore.cs @@ -0,0 +1,47 @@ +using JetBrains.Annotations; +using Microsoft.Extensions.Options; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Volo.Abp; +using Volo.Abp.DependencyInjection; + +namespace Volo.CmsKit.MediaDescriptors +{ + public class DefaultMediaDescriptorDefinitionStore : IMediaDescriptorDefinitionStore, ITransientDependency + { + protected CmsKitMediaOptions Options { get; } + + public DefaultMediaDescriptorDefinitionStore(IOptions options) + { + Options = options.Value; + } + + /// + /// Gets single by entityType. + /// + /// EntityType to get definition. + /// Thrown when EntityType is not configured as taggable. + /// More than one element satisfies the condition in predicate. + public virtual Task GetDefinitionAsync([NotNull] string entityType) + { + Check.NotNullOrWhiteSpace(entityType, nameof(entityType)); + + var result = Options.EntityTypes.SingleOrDefault(x => x.EntityType.Equals(entityType, StringComparison.InvariantCultureIgnoreCase)) ?? + throw new EntityCantHaveMediaException(entityType); + + return Task.FromResult(result); + } + + public virtual Task IsDefinedAsync([NotNull] string entityType) + { + Check.NotNullOrEmpty(entityType, nameof(entityType)); + + var isDefined = Options.EntityTypes.Any(a => a.EntityType.Equals(entityType, StringComparison.InvariantCultureIgnoreCase)); + + return Task.FromResult(isDefined); + } + } +} diff --git a/modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/MediaDescriptors/EntityCantHaveMediaException.cs b/modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/MediaDescriptors/EntityCantHaveMediaException.cs new file mode 100644 index 0000000000..29d60126a1 --- /dev/null +++ b/modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/MediaDescriptors/EntityCantHaveMediaException.cs @@ -0,0 +1,21 @@ +using System.Runtime.Serialization; +using Volo.Abp; + +namespace Volo.CmsKit.MediaDescriptors +{ + public class EntityCantHaveMediaException : BusinessException + { + public EntityCantHaveMediaException(SerializationInfo serializationInfo, StreamingContext context) : base(serializationInfo, context) + { + } + + public EntityCantHaveMediaException(string entityType) + { + EntityType = entityType; + Code = CmsKitErrorCodes.MediaDescriptors.EntityTypeDoesntExist; + WithData(nameof(entityType), EntityType); + } + + public string EntityType { get; } + } +} diff --git a/modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/MediaDescriptors/IMediaDescriptorDefinitionStore.cs b/modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/MediaDescriptors/IMediaDescriptorDefinitionStore.cs new file mode 100644 index 0000000000..9cd5c5c40d --- /dev/null +++ b/modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/MediaDescriptors/IMediaDescriptorDefinitionStore.cs @@ -0,0 +1,12 @@ +using JetBrains.Annotations; +using System.Threading.Tasks; + +namespace Volo.CmsKit.MediaDescriptors +{ + public interface IMediaDescriptorDefinitionStore + { + Task IsDefinedAsync([NotNull] string entityType); + + Task GetDefinitionAsync([NotNull] string entityType); + } +} diff --git a/modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/MediaDescriptors/MediaDescriptor.cs b/modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/MediaDescriptors/MediaDescriptor.cs index 3829a3afef..ee0df74b59 100644 --- a/modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/MediaDescriptors/MediaDescriptor.cs +++ b/modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/MediaDescriptors/MediaDescriptor.cs @@ -2,13 +2,14 @@ using Volo.Abp; using Volo.Abp.Domain.Entities.Auditing; using Volo.Abp.MultiTenancy; -using Volo.CmsKit.MediaDescriptors.Extensions; namespace Volo.CmsKit.MediaDescriptors { public class MediaDescriptor : FullAuditedAggregateRoot, IMultiTenant { public Guid? TenantId { get; protected set; } + + public string EntityType { get; protected set; } public string Name { get; protected set; } @@ -21,10 +22,11 @@ namespace Volo.CmsKit.MediaDescriptors } - public MediaDescriptor(Guid id, string name, string mimeType, long size, Guid? tenantId = null) : base(id) + internal MediaDescriptor(Guid id, string entityType, string name, string mimeType, long size, Guid? tenantId = null) : base(id) { TenantId = tenantId; + EntityType = Check.NotNullOrEmpty(entityType, nameof(entityType), MediaDescriptorConsts.MaxEntityTypeLength); MimeType = Check.NotNullOrWhiteSpace(mimeType, nameof(name), MediaDescriptorConsts.MaxMimeTypeLength); Size = size; @@ -33,7 +35,7 @@ namespace Volo.CmsKit.MediaDescriptors public void SetName(string name) { - if (!MediaDescriptorCheck.IsValidMediaFileName(name)) + if (!MediaDescriptorChecks.IsValidMediaFileName(name)) { throw new InvalidMediaDescriptorNameException(name); } diff --git a/modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/MediaDescriptors/MediaDescriptorCheck.cs b/modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/MediaDescriptors/MediaDescriptorChecks.cs similarity index 77% rename from modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/MediaDescriptors/MediaDescriptorCheck.cs rename to modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/MediaDescriptors/MediaDescriptorChecks.cs index 5ef0c4497a..1881de83e3 100644 --- a/modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/MediaDescriptors/MediaDescriptorCheck.cs +++ b/modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/MediaDescriptors/MediaDescriptorChecks.cs @@ -1,9 +1,9 @@ using System.IO; using System.Linq; -namespace Volo.CmsKit.MediaDescriptors.Extensions +namespace Volo.CmsKit.MediaDescriptors { - public static class MediaDescriptorCheck + public static class MediaDescriptorChecks { public static bool IsValidMediaFileName(string name) { diff --git a/modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/MediaDescriptors/MediaDescriptorDefinition.cs b/modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/MediaDescriptors/MediaDescriptorDefinition.cs new file mode 100644 index 0000000000..95bfaacb61 --- /dev/null +++ b/modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/MediaDescriptors/MediaDescriptorDefinition.cs @@ -0,0 +1,20 @@ +using JetBrains.Annotations; +using System; +using System.Collections.Generic; + +namespace Volo.CmsKit.MediaDescriptors +{ + public class MediaDescriptorDefinition : PolicySpecifiedDefinition + { + public MediaDescriptorDefinition( + [NotNull] string entityType, + IEnumerable createPolicies = null, + IEnumerable updatePolicies = null, + IEnumerable deletePolicies = null) : base(entityType, + createPolicies, + updatePolicies, + deletePolicies) + { + } + } +} diff --git a/modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/MediaDescriptors/MediaDescriptorManager.cs b/modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/MediaDescriptors/MediaDescriptorManager.cs new file mode 100644 index 0000000000..730e4e3ccf --- /dev/null +++ b/modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/MediaDescriptors/MediaDescriptorManager.cs @@ -0,0 +1,31 @@ +using System.Threading.Tasks; +using Volo.Abp.Domain.Services; + +namespace Volo.CmsKit.MediaDescriptors +{ + public class MediaDescriptorManager : DomainService + { + protected IMediaDescriptorDefinitionStore MediaDescriptorDefinitionStore { get; } + + public MediaDescriptorManager(IMediaDescriptorDefinitionStore mediaDescriptorDefinitionStore) + { + MediaDescriptorDefinitionStore = mediaDescriptorDefinitionStore; + } + + public virtual async Task CreateAsync(string entityType, string name, string mimeType, long size) + { + if(!await MediaDescriptorDefinitionStore.IsDefinedAsync(entityType)) + { + throw new EntityCantHaveMediaException(entityType); + } + + return new MediaDescriptor( + GuidGenerator.Create(), + entityType, + name, + mimeType, + size, + CurrentTenant.Id); + } + } +} diff --git a/modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/Pages/Page.cs b/modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/Pages/Page.cs index 9c0ee2d6b9..dd759ebd08 100644 --- a/modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/Pages/Page.cs +++ b/modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/Pages/Page.cs @@ -8,22 +8,25 @@ namespace Volo.CmsKit.Pages { public class Page : FullAuditedAggregateRoot, IMultiTenant { - [CanBeNull] public virtual Guid? TenantId { get; protected set; } + public virtual Guid? TenantId { get; protected set; } - [NotNull] public virtual string Title { get; protected set; } + public virtual string Title { get; protected set; } - [NotNull] public virtual string Slug { get; protected set; } + public virtual string Slug { get; protected set; } + public virtual string Content { get; protected set; } + protected Page() { } - public Page(Guid id, [NotNull] string title, [NotNull] string slug, [CanBeNull]Guid? tenantId = null) : base(id) + public Page(Guid id, [NotNull] string title, [NotNull] string slug, string content = null, Guid? tenantId = null) : base(id) { - Title = Check.NotNullOrEmpty(title, nameof(title), PageConsts.MaxTitleLength); - Slug = Check.NotNullOrEmpty(slug, nameof(slug), PageConsts.MaxSlugLength); - TenantId = tenantId; + + SetTitle(title); + SetSlug(slug); + SetContent(content); } public virtual void SetTitle(string title) @@ -35,5 +38,10 @@ namespace Volo.CmsKit.Pages { Slug = Check.NotNullOrEmpty(slug, nameof(slug), PageConsts.MaxSlugLength); } + + public virtual void SetContent(string content) + { + Content = Check.Length(content, nameof(content), PageConsts.MaxContentLength); + } } } \ No newline at end of file diff --git a/modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/PolicySpecifiedDefinition.cs b/modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/PolicySpecifiedDefinition.cs index 54527621ec..edfee13337 100644 --- a/modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/PolicySpecifiedDefinition.cs +++ b/modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/PolicySpecifiedDefinition.cs @@ -1,30 +1,56 @@ using JetBrains.Annotations; +using System; +using System.Collections.Generic; +using System.Linq; +using Volo.Abp; namespace Volo.CmsKit { - public abstract class PolicySpecifiedDefinition + public abstract class PolicySpecifiedDefinition : IEquatable { protected PolicySpecifiedDefinition() { } public PolicySpecifiedDefinition( - [CanBeNull] string createPolicy = null, - [CanBeNull] string updatePolicy = null, - [CanBeNull] string deletePolicy = null) + [NotNull] string entityType, + IEnumerable createPolicies = null, + IEnumerable updatePolicies = null, + IEnumerable deletePolicies = null) { - CreatePolicy = createPolicy; - DeletePolicy = deletePolicy; - UpdatePolicy = updatePolicy; + EntityType = Check.NotNullOrEmpty(entityType, nameof(entityType)); + + if (createPolicies != null) + { + CreatePolicies = CreatePolicies.Concat(createPolicies).ToList(); + } + + if (updatePolicies != null) + { + UpdatePolicies = UpdatePolicies.Concat(updatePolicies).ToList(); + } + + if (deletePolicies != null) + { + DeletePolicies = DeletePolicies.Concat(deletePolicies).ToList(); + } } - [CanBeNull] - public virtual string CreatePolicy { get; set; } + [NotNull] + public string EntityType { get; set; } + + [NotNull] + public virtual ICollection CreatePolicies { get; } = new List(); - [CanBeNull] - public virtual string UpdatePolicy { get; set; } + [NotNull] + public virtual ICollection UpdatePolicies { get; } = new List(); - [CanBeNull] - public virtual string DeletePolicy { get; set; } + [NotNull] + public virtual ICollection DeletePolicies { get; } = new List(); + + public bool Equals(PolicySpecifiedDefinition other) + { + return other?.EntityType == EntityType; + } } } diff --git a/modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/Tags/TagEntityTypeDefiniton.cs b/modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/Tags/TagEntityTypeDefiniton.cs index e714d91c0b..6dedb1410e 100644 --- a/modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/Tags/TagEntityTypeDefiniton.cs +++ b/modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/Tags/TagEntityTypeDefiniton.cs @@ -1,5 +1,6 @@ using JetBrains.Annotations; using System; +using System.Collections.Generic; using Volo.Abp; using Volo.Abp.Localization; @@ -7,8 +8,6 @@ namespace Volo.CmsKit.Tags { public class TagEntityTypeDefiniton : PolicySpecifiedDefinition, IEquatable { - public string EntityType { get; } - [CanBeNull] public virtual ILocalizableString DisplayName { get; } @@ -19,12 +18,12 @@ namespace Volo.CmsKit.Tags public TagEntityTypeDefiniton( [NotNull] string entityType, [CanBeNull] ILocalizableString displayName = null, - [CanBeNull] string createPolicy = null, - [CanBeNull] string updatePolicy = null, - [CanBeNull] string deletePolicy = null) : base(createPolicy, updatePolicy, deletePolicy) + IEnumerable createPolicies = null, + IEnumerable updatePolicies = null, + IEnumerable deletePolicies = null) : base(entityType, createPolicies, updatePolicies, deletePolicies) { - EntityType = Check.NotNullOrWhiteSpace(entityType, nameof(entityType)); DisplayName = displayName; + } public bool Equals(TagEntityTypeDefiniton other) diff --git a/modules/cms-kit/src/Volo.CmsKit.EntityFrameworkCore/Volo/CmsKit/Contents/EfCoreContentRepository.cs b/modules/cms-kit/src/Volo.CmsKit.EntityFrameworkCore/Volo/CmsKit/Contents/EfCoreContentRepository.cs deleted file mode 100644 index 9a99bc5eca..0000000000 --- a/modules/cms-kit/src/Volo.CmsKit.EntityFrameworkCore/Volo/CmsKit/Contents/EfCoreContentRepository.cs +++ /dev/null @@ -1,86 +0,0 @@ -using JetBrains.Annotations; -using Microsoft.EntityFrameworkCore; -using System; -using System.Threading; -using System.Threading.Tasks; -using Volo.Abp; -using Volo.Abp.Domain.Repositories.EntityFrameworkCore; -using Volo.Abp.EntityFrameworkCore; -using Volo.CmsKit.EntityFrameworkCore; - -namespace Volo.CmsKit.Contents -{ - public class EfCoreContentRepository : EfCoreRepository, IContentRepository - { - public EfCoreContentRepository(IDbContextProvider dbContextProvider) : base(dbContextProvider) - { - } - - public virtual Task GetAsync( - string entityType, - string entityId, - Guid? tenantId = null, - CancellationToken cancellationToken = default) - { - Check.NotNullOrEmpty(entityType, nameof(entityType)); - Check.NotNullOrEmpty(entityId, nameof(entityId)); - - return GetAsync(x => - x.EntityType == entityType && - x.EntityId == entityId && - x.TenantId == tenantId, - cancellationToken: GetCancellationToken(cancellationToken) - ); - } - - public virtual Task FindAsync( - string entityType, - string entityId, - Guid? tenantId = null, - CancellationToken cancellationToken = default) - { - Check.NotNullOrEmpty(entityType, nameof(entityType)); - Check.NotNullOrEmpty(entityId, nameof(entityId)); - - return FindAsync(x => - x.EntityType == entityType && - x.EntityId == entityId && - x.TenantId == tenantId, - cancellationToken: GetCancellationToken(cancellationToken) - ); - } - - public virtual Task DeleteAsync( - string entityType, - string entityId, - Guid? tenantId = null, - CancellationToken cancellationToken = default) - { - Check.NotNullOrEmpty(entityType, nameof(entityType)); - Check.NotNullOrEmpty(entityId, nameof(entityId)); - - return DeleteAsync(x => - x.EntityType == entityType && - x.EntityId == entityId && - x.TenantId == tenantId, - cancellationToken: GetCancellationToken(cancellationToken)); - } - - public virtual async Task ExistsAsync( - [NotNull] string entityType, - [NotNull] string entityId, - Guid? tenantId = null, - CancellationToken cancellationToken = default) - { - Check.NotNullOrEmpty(entityType, nameof(entityType)); - Check.NotNullOrEmpty(entityId, nameof(entityId)); - - var dbSet = await GetDbSetAsync(); - return await dbSet.AnyAsync(x => - x.EntityType == entityType && - x.EntityId == entityId && - x.TenantId == tenantId, - cancellationToken: GetCancellationToken(cancellationToken)); - } - } -} \ No newline at end of file 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 749a0653f9..7fc05ea042 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 @@ -3,7 +3,6 @@ using Volo.Abp.Data; using Volo.Abp.EntityFrameworkCore; using Volo.CmsKit.Blogs; using Volo.CmsKit.Comments; -using Volo.CmsKit.Contents; using Volo.CmsKit.MediaDescriptors; using Volo.CmsKit.Pages; using Volo.CmsKit.Ratings; @@ -16,7 +15,6 @@ namespace Volo.CmsKit.EntityFrameworkCore [ConnectionStringName(CmsKitDbProperties.ConnectionStringName)] public class CmsKitDbContext : AbpDbContext, ICmsKitDbContext { - public DbSet Contents { get; set; } public DbSet Comments { get; set; } public DbSet User { get; set; } public DbSet Reactions { 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 2f7308be95..57a8e062fc 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 @@ -8,7 +8,6 @@ using Volo.CmsKit.Comments; using Volo.CmsKit.Reactions; using Volo.CmsKit.Users; using Volo.Abp.Users.EntityFrameworkCore; -using Volo.CmsKit.Contents; using Volo.CmsKit.GlobalFeatures; using Volo.CmsKit.Pages; using Volo.CmsKit.Ratings; @@ -111,26 +110,6 @@ namespace Volo.CmsKit.EntityFrameworkCore builder.Ignore(); } - if (GlobalFeatureManager.Instance.IsEnabled()) - { - builder.Entity(b => - { - b.ToTable(options.TablePrefix + "Contents", options.Schema); - - b.ConfigureByConvention(); - - b.Property(x => x.EntityType).IsRequired().HasMaxLength(ContentConsts.MaxEntityTypeLength); - b.Property(x => x.EntityId).IsRequired().HasMaxLength(ContentConsts.MaxEntityIdLength); - b.Property(x => x.Value).IsRequired().HasMaxLength(ContentConsts.MaxValueLength); - - b.HasIndex(x => new { x.TenantId, x.EntityType, x.EntityId }); - }); - } - else - { - builder.Ignore(); - } - if (GlobalFeatureManager.Instance.IsEnabled()) { builder.Entity(b => @@ -179,6 +158,7 @@ namespace Volo.CmsKit.EntityFrameworkCore b.Property(x => x.Title).IsRequired().HasMaxLength(PageConsts.MaxTitleLength); b.Property(x => x.Slug).IsRequired().HasMaxLength(PageConsts.MaxSlugLength); + b.Property(x => x.Content).HasMaxLength(PageConsts.MaxContentLength); b.HasIndex(x => new { x.TenantId, Url = x.Slug }); }); @@ -207,14 +187,12 @@ namespace Volo.CmsKit.EntityFrameworkCore b.ConfigureByConvention(); + b.Property(p => p.AuthorId).IsRequired(); b.Property(p => p.Title).IsRequired().HasMaxLength(BlogPostConsts.MaxTitleLength); - b.Property(p => p.Slug).IsRequired().HasMaxLength(BlogPostConsts.MaxSlugLength); - b.Property(p => p.ShortDescription).HasMaxLength(BlogPostConsts.MaxShortDescriptionLength); - - b.Property(p => p.AuthorId).IsRequired(); - + b.Property(p => p.Content).HasMaxLength(BlogPostConsts.MaxContentLength); + b.HasIndex(x => new { x.Slug, x.BlogId }); }); @@ -242,6 +220,7 @@ namespace Volo.CmsKit.EntityFrameworkCore b.ConfigureByConvention(); + b.Property(x => x.EntityType).IsRequired().HasMaxLength(MediaDescriptorConsts.MaxEntityTypeLength); b.Property(x => x.Name).IsRequired().HasMaxLength(MediaDescriptorConsts.MaxNameLength); b.Property(x => x.MimeType).IsRequired().HasMaxLength(MediaDescriptorConsts.MaxMimeTypeLength); b.Property(x => x.Size).HasMaxLength(MediaDescriptorConsts.MaxSizeLength); diff --git a/modules/cms-kit/src/Volo.CmsKit.EntityFrameworkCore/Volo/CmsKit/EntityFrameworkCore/CmsKitEntityFrameworkCoreModule.cs b/modules/cms-kit/src/Volo.CmsKit.EntityFrameworkCore/Volo/CmsKit/EntityFrameworkCore/CmsKitEntityFrameworkCoreModule.cs index 335bbb9f78..0bbb9ea58b 100644 --- a/modules/cms-kit/src/Volo.CmsKit.EntityFrameworkCore/Volo/CmsKit/EntityFrameworkCore/CmsKitEntityFrameworkCoreModule.cs +++ b/modules/cms-kit/src/Volo.CmsKit.EntityFrameworkCore/Volo/CmsKit/EntityFrameworkCore/CmsKitEntityFrameworkCoreModule.cs @@ -29,7 +29,6 @@ namespace Volo.CmsKit.EntityFrameworkCore options.AddRepository(); options.AddRepository(); options.AddRepository(); - options.AddRepository(); options.AddRepository(); options.AddRepository(); options.AddRepository(); 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 0299856341..0484676a94 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 @@ -3,7 +3,6 @@ using Volo.Abp.Data; using Volo.Abp.EntityFrameworkCore; using Volo.CmsKit.Blogs; using Volo.CmsKit.Comments; -using Volo.CmsKit.Contents; using Volo.CmsKit.MediaDescriptors; using Volo.CmsKit.Pages; using Volo.CmsKit.Ratings; @@ -16,7 +15,6 @@ namespace Volo.CmsKit.EntityFrameworkCore [ConnectionStringName(CmsKitDbProperties.ConnectionStringName)] public interface ICmsKitDbContext : IEfCoreDbContext { - DbSet Contents { get; } DbSet Comments { get; } DbSet User { get; } DbSet Reactions { get; } diff --git a/modules/cms-kit/src/Volo.CmsKit.HttpApi/Volo.CmsKit.HttpApi.csproj b/modules/cms-kit/src/Volo.CmsKit.HttpApi/Volo.CmsKit.HttpApi.csproj index 64a3dcef21..b23ef3ba0e 100644 --- a/modules/cms-kit/src/Volo.CmsKit.HttpApi/Volo.CmsKit.HttpApi.csproj +++ b/modules/cms-kit/src/Volo.CmsKit.HttpApi/Volo.CmsKit.HttpApi.csproj @@ -9,9 +9,9 @@ - + - + diff --git a/modules/cms-kit/src/Volo.CmsKit.HttpApi/Volo/CmsKit/CmsKitHttpApiModule.cs b/modules/cms-kit/src/Volo.CmsKit.HttpApi/Volo/CmsKit/CmsKitHttpApiModule.cs index c4a45bb8cf..219f2d9442 100644 --- a/modules/cms-kit/src/Volo.CmsKit.HttpApi/Volo/CmsKit/CmsKitHttpApiModule.cs +++ b/modules/cms-kit/src/Volo.CmsKit.HttpApi/Volo/CmsKit/CmsKitHttpApiModule.cs @@ -5,8 +5,8 @@ using Volo.CmsKit.Public; namespace Volo.CmsKit { [DependsOn( - typeof(CmsKitAdminApplicationModule), - typeof(CmsKitPublicApplicationModule), + typeof(CmsKitAdminHttpApiModule), + typeof(CmsKitPublicHttpApiModule), typeof(CmsKitApplicationContractsModule) )] public class CmsKitHttpApiModule : AbpModule 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 cd03531448..4d8f86b823 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 @@ -24,8 +24,6 @@ namespace Volo.CmsKit.MongoDB public IMongoCollection CmsUsers => Collection(); public IMongoCollection Ratings => Collection(); - - public IMongoCollection Contents => Collection(); public IMongoCollection Tags => 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 2a542472d2..8585f988f9 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 @@ -47,11 +47,6 @@ namespace Volo.CmsKit.MongoDB x.CollectionName = CmsKitDbProperties.DbTablePrefix + "Ratings"; }); - builder.Entity(x => - { - x.CollectionName = CmsKitDbProperties.DbTablePrefix + "Contents"; - }); - builder.Entity(x => { x.CollectionName = CmsKitDbProperties.DbTablePrefix + "Tags"; diff --git a/modules/cms-kit/src/Volo.CmsKit.MongoDB/Volo/CmsKit/MongoDB/CmsKitMongoDbModule.cs b/modules/cms-kit/src/Volo.CmsKit.MongoDB/Volo/CmsKit/MongoDB/CmsKitMongoDbModule.cs index 11e3a0eb86..f18e92e2ba 100644 --- a/modules/cms-kit/src/Volo.CmsKit.MongoDB/Volo/CmsKit/MongoDB/CmsKitMongoDbModule.cs +++ b/modules/cms-kit/src/Volo.CmsKit.MongoDB/Volo/CmsKit/MongoDB/CmsKitMongoDbModule.cs @@ -4,11 +4,9 @@ using Volo.Abp.MongoDB; using Volo.Abp.Users.MongoDB; using Volo.CmsKit.Blogs; using Volo.CmsKit.Comments; -using Volo.CmsKit.Contents; using Volo.CmsKit.MediaDescriptors; using Volo.CmsKit.MongoDB.Blogs; using Volo.CmsKit.MongoDB.Comments; -using Volo.CmsKit.MongoDB.Contents; using Volo.CmsKit.MongoDB.MediaDescriptors; using Volo.CmsKit.MongoDB.Pages; using Volo.CmsKit.MongoDB.Ratings; @@ -38,7 +36,6 @@ namespace Volo.CmsKit.MongoDB options.AddRepository(); options.AddRepository(); options.AddRepository(); - options.AddRepository(); options.AddRepository(); options.AddRepository(); options.AddRepository(); diff --git a/modules/cms-kit/src/Volo.CmsKit.MongoDB/Volo/CmsKit/MongoDB/Contents/MongoContentRepository.cs b/modules/cms-kit/src/Volo.CmsKit.MongoDB/Volo/CmsKit/MongoDB/Contents/MongoContentRepository.cs deleted file mode 100644 index fded228c16..0000000000 --- a/modules/cms-kit/src/Volo.CmsKit.MongoDB/Volo/CmsKit/MongoDB/Contents/MongoContentRepository.cs +++ /dev/null @@ -1,80 +0,0 @@ -using JetBrains.Annotations; -using MongoDB.Driver.Linq; -using System; -using System.Threading; -using System.Threading.Tasks; -using Volo.Abp; -using Volo.Abp.Domain.Repositories.MongoDB; -using Volo.Abp.MongoDB; -using Volo.CmsKit.Contents; - -namespace Volo.CmsKit.MongoDB.Contents -{ - public class MongoContentRepository : MongoDbRepository, IContentRepository - { - public MongoContentRepository(IMongoDbContextProvider dbContextProvider) : base( - dbContextProvider) - { - } - - public virtual Task GetAsync( - string entityType, - string entityId, - Guid? tenantId = null, - CancellationToken cancellationToken = default) - { - Check.NotNullOrEmpty(entityType, nameof(entityType)); - Check.NotNullOrEmpty(entityId, nameof(entityId)); - - return GetAsync(x => - x.EntityType == entityType && - x.EntityId == entityId && - x.TenantId == tenantId, - cancellationToken: GetCancellationToken(cancellationToken) - ); - } - - public virtual Task FindAsync( - string entityType, - string entityId, - Guid? tenantId = null, - CancellationToken cancellationToken = default) - { - Check.NotNullOrEmpty(entityType, nameof(entityType)); - Check.NotNullOrEmpty(entityId, nameof(entityId)); - - return FindAsync(x => - x.EntityType == entityType && - x.EntityId == entityId && - x.TenantId == tenantId, - cancellationToken: GetCancellationToken(cancellationToken) - ); - } - - public virtual Task DeleteAsync(string entityType, string entityId, Guid? tenantId = null, - CancellationToken cancellationToken = default) - { - Check.NotNullOrEmpty(entityType, nameof(entityType)); - Check.NotNullOrEmpty(entityId, nameof(entityId)); - - return DeleteAsync(x => - x.EntityType == entityType && - x.EntityId == entityId && - x.TenantId == tenantId, - cancellationToken: GetCancellationToken(cancellationToken)); - } - - public virtual async Task ExistsAsync([NotNull] string entityType, [NotNull] string entityId, - Guid? tenantId = null, CancellationToken cancellationToken = default) - { - Check.NotNullOrEmpty(entityType, nameof(entityType)); - Check.NotNullOrEmpty(entityId, nameof(entityId)); - - return await (await GetMongoQueryableAsync(cancellationToken)).AnyAsync(x => - x.EntityType == entityType && - x.EntityId == entityId && - x.TenantId == tenantId, - cancellationToken: GetCancellationToken(cancellationToken)); - } - } -} \ No newline at end of file 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 742d40dfc6..5110bca501 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 @@ -25,8 +25,6 @@ namespace Volo.CmsKit.MongoDB IMongoCollection Ratings { get; } - IMongoCollection Contents { get; } - IMongoCollection Tags { get; } IMongoCollection EntityTags { get; } 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.Public.Application.Contracts/Volo/CmsKit/Public/Blogs/BlogPostPublicDto.cs index ece2704513..a7358f176a 100644 --- a/modules/cms-kit/src/Volo.CmsKit.Public.Application.Contracts/Volo/CmsKit/Public/Blogs/BlogPostPublicDto.cs +++ b/modules/cms-kit/src/Volo.CmsKit.Public.Application.Contracts/Volo/CmsKit/Public/Blogs/BlogPostPublicDto.cs @@ -15,6 +15,8 @@ namespace Volo.CmsKit.Public.Blogs public string ShortDescription { get; set; } + public string Content { get; set; } + public CmsUserDto Author { get; set; } } } diff --git a/modules/cms-kit/src/Volo.CmsKit.Public.Application.Contracts/Volo/CmsKit/Public/Contents/ContentDto.cs b/modules/cms-kit/src/Volo.CmsKit.Public.Application.Contracts/Volo/CmsKit/Public/Contents/ContentDto.cs deleted file mode 100644 index f11b4c8681..0000000000 --- a/modules/cms-kit/src/Volo.CmsKit.Public.Application.Contracts/Volo/CmsKit/Public/Contents/ContentDto.cs +++ /dev/null @@ -1,11 +0,0 @@ -using System; -using Volo.Abp.Application.Dtos; - -namespace Volo.CmsKit.Public.Contents -{ - [Serializable] - public class ContentDto : EntityDto - { - public string Value { get; set; } - } -} diff --git a/modules/cms-kit/src/Volo.CmsKit.Public.Application.Contracts/Volo/CmsKit/Public/Contents/GetContentInput.cs b/modules/cms-kit/src/Volo.CmsKit.Public.Application.Contracts/Volo/CmsKit/Public/Contents/GetContentInput.cs deleted file mode 100644 index 26a127e105..0000000000 --- a/modules/cms-kit/src/Volo.CmsKit.Public.Application.Contracts/Volo/CmsKit/Public/Contents/GetContentInput.cs +++ /dev/null @@ -1,12 +0,0 @@ -using System; - -namespace Volo.CmsKit.Public.Contents -{ - [Serializable] - public class GetContentInput - { - public string EntityType { get; set; } - - public string EntityId { get; set; } - } -} diff --git a/modules/cms-kit/src/Volo.CmsKit.Public.Application.Contracts/Volo/CmsKit/Public/Contents/IContentPublicAppService.cs b/modules/cms-kit/src/Volo.CmsKit.Public.Application.Contracts/Volo/CmsKit/Public/Contents/IContentPublicAppService.cs deleted file mode 100644 index df8b07cfce..0000000000 --- a/modules/cms-kit/src/Volo.CmsKit.Public.Application.Contracts/Volo/CmsKit/Public/Contents/IContentPublicAppService.cs +++ /dev/null @@ -1,10 +0,0 @@ -using System.Threading.Tasks; -using Volo.CmsKit.Contents; - -namespace Volo.CmsKit.Public.Contents -{ - public interface IContentPublicAppService - { - Task GetAsync(GetContentInput input); - } -} \ No newline at end of file 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.Public.Application.Contracts/Volo/CmsKit/Public/Pages/PageDto.cs index 2add3c9d38..682c90b8c8 100644 --- a/modules/cms-kit/src/Volo.CmsKit.Public.Application.Contracts/Volo/CmsKit/Public/Pages/PageDto.cs +++ b/modules/cms-kit/src/Volo.CmsKit.Public.Application.Contracts/Volo/CmsKit/Public/Pages/PageDto.cs @@ -9,5 +9,7 @@ namespace Volo.CmsKit.Public.Pages public string Title { get; set; } public string Slug { get; set; } + + public string Content { get; set; } } } \ No newline at end of file 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 f283473f95..d5dd555b71 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 @@ -21,20 +21,20 @@ namespace Volo.CmsKit.Public.Comments protected ICommentRepository CommentRepository { get; } protected ICmsUserLookupService CmsUserLookupService { get; } public IDistributedEventBus DistributedEventBus { get; } - public IUnitOfWorkManager UnitOfWorkManager { get; } + protected CommentManager CommentManager { get; } public CommentPublicAppService( ICommentRepository commentRepository, ICmsUserLookupService cmsUserLookupService, IDistributedEventBus distributedEventBus, - IUnitOfWorkManager unitOfWorkManager, - IOptions cmsKitOptions) + IOptions cmsKitOptions, + CommentManager commentManager) { CmsKitOptions = cmsKitOptions.Value; CommentRepository = commentRepository; CmsUserLookupService = cmsUserLookupService; DistributedEventBus = distributedEventBus; - UnitOfWorkManager = unitOfWorkManager; + CommentManager = commentManager; } public virtual async Task> GetListAsync(string entityType, string entityId) @@ -58,14 +58,12 @@ namespace Volo.CmsKit.Public.Comments } var comment = await CommentRepository.InsertAsync( - new Comment( - GuidGenerator.Create(), + await CommentManager.CreateAsync( + user, entityType, entityId, input.Text, - input.RepliedCommentId, - user.Id, - CurrentTenant.Id + input.RepliedCommentId ) ); diff --git a/modules/cms-kit/src/Volo.CmsKit.Public.Application/Volo/CmsKit/Public/Contents/ContentPublicAppService.cs b/modules/cms-kit/src/Volo.CmsKit.Public.Application/Volo/CmsKit/Public/Contents/ContentPublicAppService.cs deleted file mode 100644 index 995c99c2ed..0000000000 --- a/modules/cms-kit/src/Volo.CmsKit.Public.Application/Volo/CmsKit/Public/Contents/ContentPublicAppService.cs +++ /dev/null @@ -1,25 +0,0 @@ -using System.Threading.Tasks; -using Volo.CmsKit.Contents; - -namespace Volo.CmsKit.Public.Contents -{ - public class ContentPublicAppService : CmsKitPublicAppServiceBase, IContentPublicAppService - { - protected IContentRepository ContentRepository { get; } - - public ContentPublicAppService(IContentRepository contentRepository) - { - ContentRepository = contentRepository; - } - - public virtual async Task GetAsync(GetContentInput input) - { - var entity = await ContentRepository.GetAsync( - input.EntityType, - input.EntityId, - CurrentTenant.Id); - - return ObjectMapper.Map(entity); - } - } -} 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 46dab5a9a1..b8684f2463 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,11 +2,9 @@ using Volo.Abp.AutoMapper; using Volo.CmsKit.Blogs; using Volo.CmsKit.Comments; -using Volo.CmsKit.Contents; using Volo.CmsKit.Pages; using Volo.CmsKit.Public.Blogs; using Volo.CmsKit.Public.Comments; -using Volo.CmsKit.Public.Contents; using Volo.CmsKit.Public.Pages; using Volo.CmsKit.Public.Ratings; using Volo.CmsKit.Ratings; @@ -29,8 +27,6 @@ namespace Volo.CmsKit.Public CreateMap(); - CreateMap(); - CreateMap(); CreateMap(MemberList.None); diff --git a/modules/cms-kit/src/Volo.CmsKit.Public.HttpApi/Volo/CmsKit/Public/Contents/ContentController.cs b/modules/cms-kit/src/Volo.CmsKit.Public.HttpApi/Volo/CmsKit/Public/Contents/ContentController.cs deleted file mode 100644 index 9ba368f03d..0000000000 --- a/modules/cms-kit/src/Volo.CmsKit.Public.HttpApi/Volo/CmsKit/Public/Contents/ContentController.cs +++ /dev/null @@ -1,29 +0,0 @@ -using System.Threading.Tasks; -using Microsoft.AspNetCore.Mvc; -using Volo.Abp; -using Volo.Abp.GlobalFeatures; -using Volo.CmsKit.Contents; -using Volo.CmsKit.GlobalFeatures; - -namespace Volo.CmsKit.Public.Contents -{ - [RequiresGlobalFeature(typeof(ContentsFeature))] - [RemoteService(Name = CmsKitCommonRemoteServiceConsts.RemoteServiceName)] - [Area("cms-kit")] - [Route("api/cms-kit-public/contents")] - public class ContentController : CmsKitControllerBase, IContentPublicAppService - { - protected IContentPublicAppService ContentAppService { get; } - - public ContentController(IContentPublicAppService contentAppService) - { - ContentAppService = contentAppService; - } - - [HttpGet] - public virtual Task GetAsync(GetContentInput input) - { - return ContentAppService.GetAsync(input); - } - } -} 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 fe30d70b50..c8519b33f0 100644 --- a/modules/cms-kit/src/Volo.CmsKit.Public.Web/CmsKitPublicWebModule.cs +++ b/modules/cms-kit/src/Volo.CmsKit.Public.Web/CmsKitPublicWebModule.cs @@ -63,7 +63,9 @@ namespace Volo.CmsKit.Public.Web { Configure(options => { - options.Conventions.AddPageRoute("/CmsKit/Pages/Index", @"/pages/{slug:minlength(1)}"); + options.Conventions.AddPageRoute("/Public/CmsKit/Pages/Index", @"/pages/{slug:minlength(1)}"); + options.Conventions.AddPageRoute("/Public/CmsKit/Blogs/Index", @"/blogs/{blogSlug:minlength(1)}"); + options.Conventions.AddPageRoute("/Public/CmsKit/Blogs/BlogPost", @"/blogs/{blogSlug}/{blogPostSlug:minlength(1)}"); }); } } diff --git a/modules/cms-kit/src/Volo.CmsKit.Public.Web/Pages/CmsKit/Shared/Components/Blogs/BlogPost/Default.cshtml b/modules/cms-kit/src/Volo.CmsKit.Public.Web/Pages/CmsKit/Shared/Components/Blogs/BlogPost/Default.cshtml index 39737ba8df..f5c1bdc3a5 100644 --- a/modules/cms-kit/src/Volo.CmsKit.Public.Web/Pages/CmsKit/Shared/Components/Blogs/BlogPost/Default.cshtml +++ b/modules/cms-kit/src/Volo.CmsKit.Public.Web/Pages/CmsKit/Shared/Components/Blogs/BlogPost/Default.cshtml @@ -1,24 +1,18 @@ @model Volo.CmsKit.Public.Blogs.BlogPostPublicDto -@using Volo.CmsKit.Public.Web.Pages.CmsKit.Shared.Components.Contents -@using Volo.Abp.AspNetCore.Mvc.UI.Layout @using Volo.CmsKit.Localization @using Microsoft.Extensions.Localization @inject IStringLocalizer L +

@Model.Title

- @Model.Title @Model.Author?.UserName - @await Component.InvokeAsync(typeof(ContentViewComponent), new - { - entityType = Volo.CmsKit.Blogs.BlogPostConsts.EntityType, - entityId = Model.Id.ToString() - }) + @Html.Raw(Model.Content) @Model.CreationTime diff --git a/modules/cms-kit/src/Volo.CmsKit.Public.Web/Pages/CmsKit/Shared/Components/Contents/ContentViewComponent.cs b/modules/cms-kit/src/Volo.CmsKit.Public.Web/Pages/CmsKit/Shared/Components/Contents/ContentViewComponent.cs deleted file mode 100644 index 70baaf4436..0000000000 --- a/modules/cms-kit/src/Volo.CmsKit.Public.Web/Pages/CmsKit/Shared/Components/Contents/ContentViewComponent.cs +++ /dev/null @@ -1,59 +0,0 @@ -using System; -using System.Threading.Tasks; -using Microsoft.AspNetCore.Mvc; -using Volo.Abp.AspNetCore.Mvc; -using Volo.Abp.Domain.Entities; -using Volo.CmsKit.Public.Contents; -using Volo.CmsKit.Web.Contents; - -namespace Volo.CmsKit.Public.Web.Pages.CmsKit.Shared.Components.Contents -{ - [ViewComponent(Name = "CmsContent")] - public class ContentViewComponent : AbpViewComponent - { - private readonly IContentRenderer contentRenderer; - private readonly IContentPublicAppService contentAppService; - - public ContentViewComponent( - IContentRenderer contentRenderer, - IContentPublicAppService contentAppService) - { - this.contentRenderer = contentRenderer; - this.contentAppService = contentAppService; - } - - public virtual async Task InvokeAsync( - string entityType, - string entityId) - { - var content = string.Empty; - - try - { - var contentDto = await contentAppService.GetAsync(new GetContentInput - { - EntityId = entityId, - EntityType = entityType - }); - - content = contentDto.Value; - } - catch (EntityNotFoundException e) - { - // ContentDto can be null, we will render empty content. - } - - var viewModel = new ContentViewModel - { - Value = await contentRenderer.RenderAsync(content) - }; - - return View("~/Pages/CmsKit/Shared/Components/Contents/Default.cshtml", viewModel); - } - - public class ContentViewModel - { - public string Value { get; set; } - } - } -} diff --git a/modules/cms-kit/src/Volo.CmsKit.Public.Web/Pages/CmsKit/Shared/Components/Contents/Default.cshtml b/modules/cms-kit/src/Volo.CmsKit.Public.Web/Pages/CmsKit/Shared/Components/Contents/Default.cshtml deleted file mode 100644 index 0f1ddedfe5..0000000000 --- a/modules/cms-kit/src/Volo.CmsKit.Public.Web/Pages/CmsKit/Shared/Components/Contents/Default.cshtml +++ /dev/null @@ -1,3 +0,0 @@ -@model Volo.CmsKit.Public.Web.Pages.CmsKit.Shared.Components.Contents.ContentViewComponent.ContentViewModel - -@Html.Raw(Model.Value) diff --git a/modules/cms-kit/src/Volo.CmsKit.Public.Web/Pages/CmsKit/Shared/Components/Pages/Default.cshtml b/modules/cms-kit/src/Volo.CmsKit.Public.Web/Pages/CmsKit/Shared/Components/Pages/Default.cshtml index e10fa0754a..99d743aed9 100644 --- a/modules/cms-kit/src/Volo.CmsKit.Public.Web/Pages/CmsKit/Shared/Components/Pages/Default.cshtml +++ b/modules/cms-kit/src/Volo.CmsKit.Public.Web/Pages/CmsKit/Shared/Components/Pages/Default.cshtml @@ -1,22 +1,12 @@ @addTagHelper *, Volo.Abp.AspNetCore.Mvc.UI.Bootstrap - -@using Microsoft.AspNetCore.Mvc.RazorPages @using Volo.Abp.AspNetCore.Mvc.UI.Layout -@using Volo.CmsKit.Public.Web.Pages.CmsKit.Shared.Components.Contents @model Volo.CmsKit.Public.Web.Pages.CmsKit.Shared.Components.Pages.PageViewModel @inject IPageLayout PageLayout -@{ - PageLayout.Content.Title = Model.Title; -} +

@Model.Title

- @await Component.InvokeAsync(typeof(ContentViewComponent), - new - { - entityType = nameof(Page), - entityId = Model.Id.ToString() - }) + @Html.Raw(Model.Content) diff --git a/modules/cms-kit/src/Volo.CmsKit.Public.Web/Pages/CmsKit/Shared/Components/Pages/DefaultPageViewComponent.cs b/modules/cms-kit/src/Volo.CmsKit.Public.Web/Pages/CmsKit/Shared/Components/Pages/DefaultPageViewComponent.cs index c972643359..3c8be1c2c3 100644 --- a/modules/cms-kit/src/Volo.CmsKit.Public.Web/Pages/CmsKit/Shared/Components/Pages/DefaultPageViewComponent.cs +++ b/modules/cms-kit/src/Volo.CmsKit.Public.Web/Pages/CmsKit/Shared/Components/Pages/DefaultPageViewComponent.cs @@ -16,12 +16,13 @@ namespace Volo.CmsKit.Public.Web.Pages.CmsKit.Shared.Components.Pages PagePublicAppService = pagePublicAppService; } - public virtual async Task InvokeAsync(Guid pageId, string title, string description) + public virtual async Task InvokeAsync(Guid pageId, string title, string content) { var model = new PageViewModel { Id = pageId, - Title = title + Title = title, + Content = content }; return View("~/Pages/CmsKit/Shared/Components/Pages/Default.cshtml", model); @@ -33,5 +34,7 @@ namespace Volo.CmsKit.Public.Web.Pages.CmsKit.Shared.Components.Pages public Guid Id { get; set; } public string Title { get; set; } + + public string Content { get; set; } } } \ No newline at end of file diff --git a/modules/cms-kit/src/Volo.CmsKit.Public.Web/Pages/CmsKit/Blogs/BlogPost.cshtml b/modules/cms-kit/src/Volo.CmsKit.Public.Web/Pages/Public/CmsKit/Blogs/BlogPost.cshtml similarity index 92% rename from modules/cms-kit/src/Volo.CmsKit.Public.Web/Pages/CmsKit/Blogs/BlogPost.cshtml rename to modules/cms-kit/src/Volo.CmsKit.Public.Web/Pages/Public/CmsKit/Blogs/BlogPost.cshtml index 4eb2fa0ccd..8ad6dd9ca3 100644 --- a/modules/cms-kit/src/Volo.CmsKit.Public.Web/Pages/CmsKit/Blogs/BlogPost.cshtml +++ b/modules/cms-kit/src/Volo.CmsKit.Public.Web/Pages/Public/CmsKit/Blogs/BlogPost.cshtml @@ -1,8 +1,7 @@ -@page "/blogs/{blogSlug}/{blogPostSlug}" +@page @using Volo.CmsKit.Public.Web.Pages.CmsKit.Shared.Components.Blogs.BlogPost @using Volo.CmsKit.Public.Web.Pages.CmsKit.Shared.Components.Blogs.BlogPostComment -@using Volo.CmsKit.Public.Web.Pages.CmsKit.Blogs @using Volo.CmsKit.Public.Web.Pages @using Volo.Abp.GlobalFeatures @using Volo.CmsKit.GlobalFeatures @@ -12,11 +11,7 @@ @inherits CmsKitPublicPageBase -@model BlogPostModel - -@{ - PageLayout.Content.Title = Model.BlogPost.Title; -} +@model Volo.CmsKit.Public.Web.Pages.Public.CmsKit.Blogs.BlogPostModel @await Component.InvokeAsync(typeof(DefaultBlogPostViewComponent), new { diff --git a/modules/cms-kit/src/Volo.CmsKit.Public.Web/Pages/CmsKit/Blogs/BlogPost.cshtml.cs b/modules/cms-kit/src/Volo.CmsKit.Public.Web/Pages/Public/CmsKit/Blogs/BlogPost.cshtml.cs similarity index 97% rename from modules/cms-kit/src/Volo.CmsKit.Public.Web/Pages/CmsKit/Blogs/BlogPost.cshtml.cs rename to modules/cms-kit/src/Volo.CmsKit.Public.Web/Pages/Public/CmsKit/Blogs/BlogPost.cshtml.cs index 896ca37d67..6683f02cc8 100644 --- a/modules/cms-kit/src/Volo.CmsKit.Public.Web/Pages/CmsKit/Blogs/BlogPost.cshtml.cs +++ b/modules/cms-kit/src/Volo.CmsKit.Public.Web/Pages/Public/CmsKit/Blogs/BlogPost.cshtml.cs @@ -10,7 +10,7 @@ using Volo.CmsKit.Blogs; using Volo.CmsKit.GlobalFeatures; using Volo.CmsKit.Public.Blogs; -namespace Volo.CmsKit.Public.Web.Pages.CmsKit.Blogs +namespace Volo.CmsKit.Public.Web.Pages.Public.CmsKit.Blogs { public class BlogPostModel : CmsKitPublicPageModelBase { diff --git a/modules/cms-kit/src/Volo.CmsKit.Public.Web/Pages/CmsKit/Blogs/Index.cshtml b/modules/cms-kit/src/Volo.CmsKit.Public.Web/Pages/Public/CmsKit/Blogs/Index.cshtml similarity index 94% rename from modules/cms-kit/src/Volo.CmsKit.Public.Web/Pages/CmsKit/Blogs/Index.cshtml rename to modules/cms-kit/src/Volo.CmsKit.Public.Web/Pages/Public/CmsKit/Blogs/Index.cshtml index a58648f382..34f6a456d5 100644 --- a/modules/cms-kit/src/Volo.CmsKit.Public.Web/Pages/CmsKit/Blogs/Index.cshtml +++ b/modules/cms-kit/src/Volo.CmsKit.Public.Web/Pages/Public/CmsKit/Blogs/Index.cshtml @@ -1,10 +1,11 @@ -@page "/blogs/{blogSlug}" +@page @using Volo.CmsKit.Public.Web.Pages +@using Volo.CmsKit.Public.Web.Pages.Public.CmsKit.Blogs @inherits CmsKitPublicPageBase -@model Volo.CmsKit.Public.Web.Pages.CmsKit.Blogs.IndexModel +@model IndexModel @foreach (var blog in Model.Blogs.Items) diff --git a/modules/cms-kit/src/Volo.CmsKit.Public.Web/Pages/CmsKit/Blogs/Index.cshtml.cs b/modules/cms-kit/src/Volo.CmsKit.Public.Web/Pages/Public/CmsKit/Blogs/Index.cshtml.cs similarity index 95% rename from modules/cms-kit/src/Volo.CmsKit.Public.Web/Pages/CmsKit/Blogs/Index.cshtml.cs rename to modules/cms-kit/src/Volo.CmsKit.Public.Web/Pages/Public/CmsKit/Blogs/Index.cshtml.cs index 9f44d9beaa..eca0917d85 100644 --- a/modules/cms-kit/src/Volo.CmsKit.Public.Web/Pages/CmsKit/Blogs/Index.cshtml.cs +++ b/modules/cms-kit/src/Volo.CmsKit.Public.Web/Pages/Public/CmsKit/Blogs/Index.cshtml.cs @@ -8,7 +8,7 @@ using Volo.Abp.Application.Dtos; using Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Pagination; using Volo.CmsKit.Public.Blogs; -namespace Volo.CmsKit.Public.Web.Pages.CmsKit.Blogs +namespace Volo.CmsKit.Public.Web.Pages.Public.CmsKit.Blogs { public class IndexModel : CmsKitPublicPageModelBase { diff --git a/modules/cms-kit/src/Volo.CmsKit.Public.Web/Pages/CmsKit/Pages/Index.cshtml b/modules/cms-kit/src/Volo.CmsKit.Public.Web/Pages/Public/CmsKit/Pages/Index.cshtml similarity index 67% rename from modules/cms-kit/src/Volo.CmsKit.Public.Web/Pages/CmsKit/Pages/Index.cshtml rename to modules/cms-kit/src/Volo.CmsKit.Public.Web/Pages/Public/CmsKit/Pages/Index.cshtml index 4f4129b6d7..426b5ebacf 100644 --- a/modules/cms-kit/src/Volo.CmsKit.Public.Web/Pages/CmsKit/Pages/Index.cshtml +++ b/modules/cms-kit/src/Volo.CmsKit.Public.Web/Pages/Public/CmsKit/Pages/Index.cshtml @@ -2,12 +2,13 @@ @using Microsoft.AspNetCore.Mvc.Localization @using Volo.CmsKit.Localization @using Volo.CmsKit.Public.Web.Pages.CmsKit.Shared.Components.Pages -@model Volo.CmsKit.Public.Web.Pages.CmsKit.Pages.IndexModel +@model Volo.CmsKit.Public.Web.Pages.Public.CmsKit.Pages.IndexModel @inject IHtmlLocalizer L @await Component.InvokeAsync(typeof(DefaultPageViewComponent), new { pageId = Model.Page.Id, - title = Model.Page.Title + title = Model.Page.Title, + content = Model.Page.Content }) \ No newline at end of file diff --git a/modules/cms-kit/src/Volo.CmsKit.Public.Web/Pages/CmsKit/Pages/Index.cshtml.cs b/modules/cms-kit/src/Volo.CmsKit.Public.Web/Pages/Public/CmsKit/Pages/Index.cshtml.cs similarity index 93% rename from modules/cms-kit/src/Volo.CmsKit.Public.Web/Pages/CmsKit/Pages/Index.cshtml.cs rename to modules/cms-kit/src/Volo.CmsKit.Public.Web/Pages/Public/CmsKit/Pages/Index.cshtml.cs index 155a85d94f..2a30af8ae7 100644 --- a/modules/cms-kit/src/Volo.CmsKit.Public.Web/Pages/CmsKit/Pages/Index.cshtml.cs +++ b/modules/cms-kit/src/Volo.CmsKit.Public.Web/Pages/Public/CmsKit/Pages/Index.cshtml.cs @@ -3,7 +3,7 @@ using Microsoft.AspNetCore.Mvc; using Volo.CmsKit.Public.Pages; using Volo.CmsKit.Web.Pages; -namespace Volo.CmsKit.Public.Web.Pages.CmsKit.Pages +namespace Volo.CmsKit.Public.Web.Pages.Public.CmsKit.Pages { public class IndexModel : CommonPageModel { diff --git a/modules/cms-kit/src/Volo.CmsKit.Public.Web/Pages/CmsKit/_ViewImports.cshtml b/modules/cms-kit/src/Volo.CmsKit.Public.Web/Pages/_ViewImports.cshtml similarity index 100% rename from modules/cms-kit/src/Volo.CmsKit.Public.Web/Pages/CmsKit/_ViewImports.cshtml rename to modules/cms-kit/src/Volo.CmsKit.Public.Web/Pages/_ViewImports.cshtml diff --git a/modules/cms-kit/test/Volo.CmsKit.Application.Tests/Blogs/BlogPostAdminAppService_Tests.cs b/modules/cms-kit/test/Volo.CmsKit.Application.Tests/Blogs/BlogPostAdminAppService_Tests.cs index 4fe6f2e23e..28e3daea8d 100644 --- a/modules/cms-kit/test/Volo.CmsKit.Application.Tests/Blogs/BlogPostAdminAppService_Tests.cs +++ b/modules/cms-kit/test/Volo.CmsKit.Application.Tests/Blogs/BlogPostAdminAppService_Tests.cs @@ -30,13 +30,15 @@ namespace Volo.CmsKit.Blogs var title = "My awesome new Post"; var slug = "my-awesome-new-post"; var shortDescription = "This blog is all about awesomeness 🤗!"; - + var content = "Another blog post shared on internet"; + var created = await blogPostAdminAppService.CreateAsync(new CreateBlogPostDto { BlogId = cmsKitTestData.Blog_Id, Title = title, Slug = slug, - ShortDescription = shortDescription + ShortDescription = shortDescription, + Content = content }); created.Id.ShouldNotBe(Guid.Empty); @@ -46,6 +48,7 @@ namespace Volo.CmsKit.Blogs blogPost.Title.ShouldBe(title); blogPost.Slug.ShouldBe(slug); blogPost.ShortDescription.ShouldBe(shortDescription); + blogPost.Content.ShouldBe(content); } [Fact] @@ -54,6 +57,7 @@ namespace Volo.CmsKit.Blogs var title = "Another My Awesome New Post"; var slug = "another-my-awesome-new-post"; var shortDescription = "This blog is all about awesomeness 🤗!"; + var content = "Another blog post shared on internet"; var dto = new CreateBlogPostDto { @@ -61,7 +65,8 @@ namespace Volo.CmsKit.Blogs BlogId = Guid.NewGuid(), Title = title, Slug = slug, - ShortDescription = shortDescription + ShortDescription = shortDescription, + Content = content }; var exception = await Should.ThrowAsync(async () => @@ -107,12 +112,14 @@ namespace Volo.CmsKit.Blogs var shortDescription = "Another short description"; var title = "[Solved] Another Blog Post"; var slug = "another-short-blog-post"; + var content = "Another blog post shared on internet"; await blogPostAdminAppService.UpdateAsync(cmsKitTestData.BlogPost_2_Id, new UpdateBlogPostDto { ShortDescription = shortDescription, Title = title, Slug = slug, + Content = content }); var blogPost = await blogPostRepository.GetAsync(cmsKitTestData.BlogPost_2_Id); @@ -120,6 +127,7 @@ namespace Volo.CmsKit.Blogs blogPost.Title.ShouldBe(title); blogPost.ShortDescription.ShouldBe(shortDescription); blogPost.Slug.ShouldBe(slug); + blogPost.Content.ShouldBe(content); } [Fact] diff --git a/modules/cms-kit/test/Volo.CmsKit.Application.Tests/Contents/ContentAdminAppService_Tests.cs b/modules/cms-kit/test/Volo.CmsKit.Application.Tests/Contents/ContentAdminAppService_Tests.cs deleted file mode 100644 index 5c7e5969f1..0000000000 --- a/modules/cms-kit/test/Volo.CmsKit.Application.Tests/Contents/ContentAdminAppService_Tests.cs +++ /dev/null @@ -1,142 +0,0 @@ -using Microsoft.Extensions.DependencyInjection; -using NSubstitute; -using Shouldly; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using Volo.Abp.Domain.Entities; -using Volo.Abp.Users; -using Volo.CmsKit.Admin.Contents; -using Xunit; - -namespace Volo.CmsKit.Contents -{ - public class ContentAdminAppService_Tests : CmsKitApplicationTestBase - { - private ICurrentUser _currentUser; - private readonly CmsKitTestData _data; - private readonly IContentAdminAppService _service; - public ContentAdminAppService_Tests() - { - _data = GetRequiredService(); - _service = GetRequiredService(); - } - - protected override void AfterAddApplication(IServiceCollection services) - { - _currentUser = Substitute.For(); - services.AddSingleton(_currentUser); - } - - [Fact] - public async Task ShouldGetListAsync() - { - var result = await _service.GetListAsync(new ContentGetListInput()); - - result.ShouldNotBeNull(); - result.Items.ShouldNotBeEmpty(); - result.Items.Count.ShouldBe(4); - result.Items.All(x => x.ShouldBeOfType() != null); - } - - [Fact] - public async Task ShouldGetAsync() - { - var result = await _service.GetAsync(_data.Content_1_Id); - - result.ShouldNotBeNull(); - result.ShouldBeOfType(); - result.ShouldNotBeNull(result.Value); - } - - [Fact] - public async Task ShouldCreateAsync() - { - var entityId = "1-2-3"; - var entityType = "My.Awesome.Blog"; - var value = "Some long content"; - - var created = await _service.CreateAsync(new ContentCreateDto - { - EntityId = entityId, - EntityType = entityType, - Value = value - }); - - created.Id.ShouldNotBe(Guid.Empty); - - var content = await _service.GetAsync(created.Id); - - content.ShouldNotBeNull(); - content.EntityType.ShouldBe(entityType); - } - - [Fact] - public async Task ShouldNotCreateWithSameParametersAsync() - { - var entityTtype = "My.Awesome.Book"; - var entityId = "1"; - - await _service.CreateAsync(new ContentCreateDto - { - EntityId = entityId, - EntityType = entityTtype, - Value = "Some long content" - }); - - await Should.ThrowAsync(async () => - await _service.CreateAsync(new ContentCreateDto - { - EntityId = entityId, - EntityType = entityTtype, - Value = "Yet another long content" - }) - ); - } - - [Fact] - public async Task ShouldUpdateAsync() - { - string newValue = "Newly created fresh value"; - var updateDto = new ContentUpdateDto - { - Value = newValue - }; - - await _service.UpdateAsync(_data.Content_1_Id, updateDto); - - var content = await _service.GetAsync(_data.Content_1_Id); - content.ShouldNotBeNull(); - content.Value.ShouldBe(newValue); - } - - [Fact] - public async Task ShouldDeleteAsync() - { - await _service.DeleteAsync(_data.Content_2_Id); - - await Should.ThrowAsync(async () => await _service.GetAsync(_data.Content_2_Id)); - } - - [Fact] - public async Task ShouldNotThrowEntityNotFoundExceptionWhileDeletingAlreadyDeletedAsync() - { - await _service.DeleteAsync(_data.Content_2_Id); - - await Should.NotThrowAsync(async () => - await _service.DeleteAsync(_data.Content_2_Id)); - } - - [Fact] - public async Task ShouldGetByEntityAsync() - { - var entity = await _service.GetAsync(_data.Content_1_EntityType, _data.Content_1_EntityId); - - entity.ShouldNotBeNull(); - entity.EntityId.ShouldBe(_data.Content_1_EntityId); - entity.EntityType.ShouldBe(_data.Content_1_EntityType); - } - } -} diff --git a/modules/cms-kit/test/Volo.CmsKit.Application.Tests/MediaDescriptors/MediaDescriptorAdminAppService_Tests.cs b/modules/cms-kit/test/Volo.CmsKit.Application.Tests/MediaDescriptors/MediaDescriptorAdminAppService_Tests.cs index 20bfaf2c12..52169eddbe 100644 --- a/modules/cms-kit/test/Volo.CmsKit.Application.Tests/MediaDescriptors/MediaDescriptorAdminAppService_Tests.cs +++ b/modules/cms-kit/test/Volo.CmsKit.Application.Tests/MediaDescriptors/MediaDescriptorAdminAppService_Tests.cs @@ -34,7 +34,8 @@ namespace Volo.CmsKit.MediaDescriptors var inputStream = new CreateMediaInputStream(stream) { ContentType = mediaType, - Name = mediaName + Name = mediaName, + EntityType = _cmsKitTestData.Media_1_EntityType }; var media = await _mediaDescriptorAdminAppService.CreateAsync(inputStream); diff --git a/modules/cms-kit/test/Volo.CmsKit.Application.Tests/Pages/PageAdminAppService_Tests.cs b/modules/cms-kit/test/Volo.CmsKit.Application.Tests/Pages/PageAdminAppService_Tests.cs index c3e82c58f1..766c482ddd 100644 --- a/modules/cms-kit/test/Volo.CmsKit.Application.Tests/Pages/PageAdminAppService_Tests.cs +++ b/modules/cms-kit/test/Volo.CmsKit.Application.Tests/Pages/PageAdminAppService_Tests.cs @@ -64,7 +64,8 @@ namespace Volo.CmsKit.Pages var dto = new CreatePageInputDto { Title = "test", - Slug = "test-url" + Slug = "test-url", + Content = "test*content" }; await Should.NotThrowAsync(async () => await _pageAdminAppService.CreateAsync(dto)); @@ -94,7 +95,8 @@ namespace Volo.CmsKit.Pages var dto = new UpdatePageInputDto { Title = _data.Page_1_Title + "++", - Slug = _data.Page_1_Slug+ "test" + Slug = _data.Page_1_Slug+ "test", + Content = "changed" }; await Should.NotThrowAsync(async () => await _pageAdminAppService.UpdateAsync(_data.Page_1_Id, dto)); @@ -106,6 +108,9 @@ namespace Volo.CmsKit.Pages updatedPage.Slug.ShouldNotBe(_data.Page_1_Slug); updatedPage.Slug.ShouldBe(dto.Slug); + + updatedPage.Content.ShouldNotBe(_data.Content_1); + updatedPage.Content.ShouldBe(dto.Content); } [Fact] diff --git a/modules/cms-kit/test/Volo.CmsKit.Domain.Tests/Comments/CommentManager_Test.cs b/modules/cms-kit/test/Volo.CmsKit.Domain.Tests/Comments/CommentManager_Test.cs new file mode 100644 index 0000000000..5065ec9c06 --- /dev/null +++ b/modules/cms-kit/test/Volo.CmsKit.Domain.Tests/Comments/CommentManager_Test.cs @@ -0,0 +1,59 @@ +using Shouldly; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Volo.CmsKit.Users; +using Xunit; + +namespace Volo.CmsKit.Comments +{ + public class CommentManager_Test : CmsKitDomainTestBase + { + private readonly CommentManager commentManager; + private readonly CmsKitTestData testData; + private readonly ICmsUserRepository userRepository; + + public CommentManager_Test() + { + commentManager = GetRequiredService(); + testData = GetRequiredService(); + userRepository = GetRequiredService(); + } + + [Fact] + public async Task CreateAsync_ShouldWorkProperly_WithCorrectData() + { + var creator = await userRepository.GetAsync(testData.User1Id); + + var text = "Thank you for the article. It's awesome"; + + var comment = await commentManager.CreateAsync(creator, testData.EntityType1, testData.EntityId1, text); + + comment.Id.ShouldNotBe(Guid.Empty); + comment.CreatorId.ShouldBe(creator.Id); + comment.EntityType.ShouldBe(testData.EntityType1); + comment.EntityId.ShouldBe(testData.EntityId1); + comment.Text.ShouldBe(text); + } + + [Fact] + public async Task CreateAsync_ShouldThrowException_WithNotConfiguredEntityType() + { + var creator = await userRepository.GetAsync(testData.User1Id); + var notConfiguredEntityType = "Some.New.Entity"; + var text = "Thank you for the article. It's awesome"; + + var exception = await Should.ThrowAsync(async () => + await commentManager.CreateAsync( + creator, + notConfiguredEntityType, + testData.EntityId1, + text)); + + exception.ShouldNotBeNull(); + exception.EntityType.ShouldBe(notConfiguredEntityType); + } + } +} diff --git a/modules/cms-kit/test/Volo.CmsKit.Domain.Tests/MediaDescriptors/MediaDescriptorManager_Test.cs b/modules/cms-kit/test/Volo.CmsKit.Domain.Tests/MediaDescriptors/MediaDescriptorManager_Test.cs new file mode 100644 index 0000000000..6bf183564e --- /dev/null +++ b/modules/cms-kit/test/Volo.CmsKit.Domain.Tests/MediaDescriptors/MediaDescriptorManager_Test.cs @@ -0,0 +1,44 @@ +using Shouldly; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Volo.CmsKit.Blogs; +using Xunit; + +namespace Volo.CmsKit.MediaDescriptors +{ + public class MediaDescriptorManager_Test : CmsKitDomainTestBase + { + private readonly MediaDescriptorManager manager; + private readonly CmsKitTestData testData; + + public MediaDescriptorManager_Test() + { + manager = GetRequiredService(); + testData = GetRequiredService(); + } + + [Fact] + public async Task CreateAsync_ShouldWorkProperly_WithDefinedEntityType() + { + var created = await manager.CreateAsync(testData.Media_1_EntityType, "MyAwesomeImage.png", "image/png", 128000); + + created.ShouldNotBeNull(); + created.Id.ShouldNotBe(Guid.Empty); + } + + [Fact] + public async Task CreateAsync_ShouldThrowException_WithUndefinedEntityType() + { + var undefinedEntityType = "My.Any.EntityType"; + + var exception = await Should.ThrowAsync(async () => + await manager.CreateAsync(undefinedEntityType, "import.json", "application/json", 256000)); + + exception.ShouldNotBeNull(); + exception.EntityType.ShouldBe(undefinedEntityType); + } + } +} diff --git a/modules/cms-kit/test/Volo.CmsKit.Domain.Tests/Tags/TagEntityTypeDefinitionDictionary_Tests.cs b/modules/cms-kit/test/Volo.CmsKit.Domain.Tests/Tags/TagEntityTypeDefinitionDictionary_Tests.cs index a405c27190..2f2013cd0b 100644 --- a/modules/cms-kit/test/Volo.CmsKit.Domain.Tests/Tags/TagEntityTypeDefinitionDictionary_Tests.cs +++ b/modules/cms-kit/test/Volo.CmsKit.Domain.Tests/Tags/TagEntityTypeDefinitionDictionary_Tests.cs @@ -42,11 +42,11 @@ namespace Volo.CmsKit.Tags { cmsKitTagOptions.EntityTypes.Add( new TagEntityTypeDefiniton( - "My.Entity.Type", + "My.Entity.Type", LocalizableString.Create("MyEntity"), - "SomeCreatePolicy", - "SomeUpdatePolicy", - "SomeDeletePolicy" + new[] { "SomeCreatePolicy" }, + new[] { "SomeUpdatePolicy" }, + new[] { "SomeDeletePolicy" } )); } diff --git a/modules/cms-kit/test/Volo.CmsKit.EntityFrameworkCore.Tests/EntityFrameworkCore/Contents/ContentRepository_Test.cs b/modules/cms-kit/test/Volo.CmsKit.EntityFrameworkCore.Tests/EntityFrameworkCore/Contents/ContentRepository_Test.cs deleted file mode 100644 index 72f0b47485..0000000000 --- a/modules/cms-kit/test/Volo.CmsKit.EntityFrameworkCore.Tests/EntityFrameworkCore/Contents/ContentRepository_Test.cs +++ /dev/null @@ -1,9 +0,0 @@ -using Volo.CmsKit.Contents; - -namespace Volo.CmsKit.EntityFrameworkCore.Contents -{ - public class ContentRepository_Test : ContentRepository_Tests - { - - } -} \ No newline at end of file diff --git a/modules/cms-kit/test/Volo.CmsKit.MongoDB.Tests/MongoDB/Contents/ContentRepository_Test.cs b/modules/cms-kit/test/Volo.CmsKit.MongoDB.Tests/MongoDB/Contents/ContentRepository_Test.cs deleted file mode 100644 index bb467a4844..0000000000 --- a/modules/cms-kit/test/Volo.CmsKit.MongoDB.Tests/MongoDB/Contents/ContentRepository_Test.cs +++ /dev/null @@ -1,11 +0,0 @@ -using Volo.CmsKit.Contents; -using Xunit; - -namespace Volo.CmsKit.MongoDB.Contents -{ - [Collection(MongoTestCollection.Name)] - public class ContentRepository_Test : ContentRepository_Tests - { - - } -} \ No newline at end of file diff --git a/modules/cms-kit/test/Volo.CmsKit.TestBase/CmsKitDataSeedContributor.cs b/modules/cms-kit/test/Volo.CmsKit.TestBase/CmsKitDataSeedContributor.cs index be28728596..c4fc8de603 100644 --- a/modules/cms-kit/test/Volo.CmsKit.TestBase/CmsKitDataSeedContributor.cs +++ b/modules/cms-kit/test/Volo.CmsKit.TestBase/CmsKitDataSeedContributor.cs @@ -2,19 +2,16 @@ using System; using System.Collections.Generic; using System.IO; -using System.Linq; using System.Text; using System.Threading.Tasks; using Volo.Abp.BlobStoring; using Volo.Abp.Data; using Volo.Abp.DependencyInjection; -using Volo.Abp.Domain.Repositories; using Volo.Abp.Guids; using Volo.Abp.MultiTenancy; using Volo.Abp.Users; using Volo.CmsKit.Blogs; using Volo.CmsKit.Comments; -using Volo.CmsKit.Contents; using Volo.CmsKit.MediaDescriptors; using Volo.CmsKit.Pages; using Volo.CmsKit.Ratings; @@ -33,7 +30,6 @@ namespace Volo.CmsKit private readonly ReactionManager _reactionManager; private readonly IRatingRepository _ratingRepository; private readonly ICurrentTenant _currentTenant; - private readonly IContentRepository _contentRepository; private readonly EntityTagManager _entityTagManager; private readonly TagManager _tagManager; private readonly ITagRepository _tagRepository; @@ -48,6 +44,8 @@ namespace Volo.CmsKit private readonly IMediaDescriptorRepository _mediaDescriptorRepository; private readonly IBlobContainer _mediaBlobContainer; private readonly BlogManager _blogManager; + private readonly IOptions _mediaOptions; + private readonly IOptions _commentsOptions; public CmsKitDataSeedContributor( IGuidGenerator guidGenerator, @@ -57,7 +55,6 @@ namespace Volo.CmsKit ReactionManager reactionManager, IRatingRepository ratingRepository, ICurrentTenant currentTenant, - IContentRepository contentRepository, TagManager tagManager, ITagRepository tagRepository, IEntityTagRepository entityTagRepository, @@ -68,10 +65,12 @@ namespace Volo.CmsKit IBlogFeatureRepository blogFeatureRepository, EntityTagManager entityTagManager, IOptions options, - IOptions tagOptions, - IMediaDescriptorRepository mediaDescriptorRepository, - IBlobContainer mediaBlobContainer, - BlogManager blogManager) + IOptions tagOptions, + IMediaDescriptorRepository mediaDescriptorRepository, + IBlobContainer mediaBlobContainer, + BlogManager blogManager, + IOptions cmsMediaOptions, + IOptions commentsOptions) { _guidGenerator = guidGenerator; _cmsUserRepository = cmsUserRepository; @@ -80,7 +79,6 @@ namespace Volo.CmsKit _reactionManager = reactionManager; _ratingRepository = ratingRepository; _currentTenant = currentTenant; - _contentRepository = contentRepository; _tagManager = tagManager; _tagRepository = tagRepository; _entityTagManager = entityTagManager; @@ -95,6 +93,8 @@ namespace Volo.CmsKit _mediaDescriptorRepository = mediaDescriptorRepository; _mediaBlobContainer = mediaBlobContainer; _blogManager = blogManager; + _mediaOptions = cmsMediaOptions; + _commentsOptions = commentsOptions; } public async Task SeedAsync(DataSeedContext context) @@ -111,8 +111,6 @@ namespace Volo.CmsKit await SeedRatingsAsync(); - await SeedContentsAsync(); - await SeedTagsAsync(); await SeedPagesAsync(); @@ -133,6 +131,15 @@ namespace Volo.CmsKit _tagOptions.Value.EntityTypes.AddIfNotContains(new TagEntityTypeDefiniton(_cmsKitTestData.Content_2_EntityType)); _tagOptions.Value.EntityTypes.AddIfNotContains(new TagEntityTypeDefiniton(_cmsKitTestData.TagDefinition_1_EntityType)); + _mediaOptions.Value.EntityTypes.AddIfNotContains( + new MediaDescriptorDefinition( + _cmsKitTestData.Media_1_EntityType, + createPolicies: new[] { "SomeCreatePolicy" }, + deletePolicies: new[] { "SomeDeletePolicy" })); + + _commentsOptions.Value.EntityTypes.Add( + new CommentEntityTypeDefinition(_cmsKitTestData.EntityType1)); + return Task.CompletedTask; } @@ -264,37 +271,6 @@ namespace Volo.CmsKit )); } - private async Task SeedContentsAsync() - { - var content1 = new Content( - _cmsKitTestData.Content_1_Id, - _cmsKitTestData.Content_1_EntityType, - _cmsKitTestData.Content_1_EntityId, - _cmsKitTestData.Content_1 - ); - - var content2 = new Content( - _cmsKitTestData.Content_2_Id, - _cmsKitTestData.Content_2_EntityType, - _cmsKitTestData.Content_2_EntityId, - _cmsKitTestData.Content_2 - ); - - var content3 = new Content( - Guid.NewGuid(), - "deleted_entity_type", - "deleted_entity_id", - "Content" - ) - { - IsDeleted = true, - }; - - await _contentRepository.InsertAsync(content1); - await _contentRepository.InsertAsync(content2); - await _contentRepository.InsertAsync(content3); - } - private async Task SeedTagsAsync() { var created1 = await _tagRepository.InsertAsync( @@ -338,17 +314,11 @@ namespace Volo.CmsKit private async Task SeedPagesAsync() { - var page1 = new Page(_cmsKitTestData.Page_1_Id, _cmsKitTestData.Page_1_Title, _cmsKitTestData.Page_1_Slug); - var page1Content = new Content(_guidGenerator.Create(), nameof(Page), page1.Id.ToString(), _cmsKitTestData.Page_1_Content); - + var page1 = new Page(_cmsKitTestData.Page_1_Id, _cmsKitTestData.Page_1_Title, _cmsKitTestData.Page_1_Slug, _cmsKitTestData.Content_1); await _pageRepository.InsertAsync(page1); - await _contentRepository.InsertAsync(page1Content); - - var page2 = new Page(_cmsKitTestData.Page_2_Id, _cmsKitTestData.Page_2_Title, _cmsKitTestData.Page_2_Slug); - var page2Content = new Content(_guidGenerator.Create(), nameof(Page), page2.Id.ToString(), _cmsKitTestData.Page_2_Content); + var page2 = new Page(_cmsKitTestData.Page_2_Id, _cmsKitTestData.Page_2_Title, _cmsKitTestData.Page_2_Slug, _cmsKitTestData.Content_2); await _pageRepository.InsertAsync(page2); - await _contentRepository.InsertAsync(page2Content); } private async Task SeedBlogsAsync() @@ -367,7 +337,8 @@ namespace Volo.CmsKit blog, _cmsKitTestData.BlogPost_1_Title, _cmsKitTestData.BlogPost_1_Slug, - "Short desc 1"))).Id; + "Short desc 1", + "Blog Post 1 Content"))).Id; _cmsKitTestData.BlogPost_2_Id = (await _blogPostRepository.InsertAsync( @@ -376,7 +347,8 @@ namespace Volo.CmsKit blog, _cmsKitTestData.BlogPost_2_Title, _cmsKitTestData.BlogPost_2_Slug, - "Short desc 2"))).Id; + "Short desc 2", + "Blog Post 2 Content"))).Id; } private async Task SeedBlogFeaturesAsync() @@ -402,7 +374,7 @@ namespace Volo.CmsKit { using (var stream = new MemoryStream(Encoding.UTF8.GetBytes(_cmsKitTestData.Media_1_Content))) { - var media = new MediaDescriptor(_cmsKitTestData.Media_1_Id, _cmsKitTestData.Media_1_Name, _cmsKitTestData.Media_1_ContentType, stream.Length); + var media = new MediaDescriptor(_cmsKitTestData.Media_1_Id, _cmsKitTestData.Media_1_EntityType, _cmsKitTestData.Media_1_Name, _cmsKitTestData.Media_1_ContentType, stream.Length); await _mediaDescriptorRepository.InsertAsync(media); diff --git a/modules/cms-kit/test/Volo.CmsKit.TestBase/CmsKitTestData.cs b/modules/cms-kit/test/Volo.CmsKit.TestBase/CmsKitTestData.cs index 3762b8b073..396ae5a013 100644 --- a/modules/cms-kit/test/Volo.CmsKit.TestBase/CmsKitTestData.cs +++ b/modules/cms-kit/test/Volo.CmsKit.TestBase/CmsKitTestData.cs @@ -1,6 +1,7 @@ using System; using JetBrains.Annotations; using Volo.Abp.DependencyInjection; +using Volo.CmsKit.Blogs; namespace Volo.CmsKit { @@ -100,11 +101,13 @@ namespace Volo.CmsKit public bool BlogFeature_2_Enabled => false; public Guid Media_1_Id { get; } = Guid.NewGuid(); - - public string Media_1_Content = "Hi, this is text file"; - public string Media_1_Name = "hello.txt"; + public string Media_1_EntityType => nameof(Blog); - public string Media_1_ContentType = "text/plain"; + public string Media_1_Content { get; } = "Hi, this is text file"; + + public string Media_1_Name { get; } = "hello.txt"; + + public string Media_1_ContentType { get; } = "text/plain"; } } diff --git a/modules/cms-kit/test/Volo.CmsKit.TestBase/Contents/ContentRepository_Tests.cs b/modules/cms-kit/test/Volo.CmsKit.TestBase/Contents/ContentRepository_Tests.cs deleted file mode 100644 index c5b166551e..0000000000 --- a/modules/cms-kit/test/Volo.CmsKit.TestBase/Contents/ContentRepository_Tests.cs +++ /dev/null @@ -1,63 +0,0 @@ -using System; -using System.Threading.Tasks; -using Shouldly; -using Volo.Abp.Domain.Entities; -using Volo.Abp.Modularity; -using Xunit; - -namespace Volo.CmsKit.Contents -{ - public abstract class ContentRepository_Tests : CmsKitTestBase - where TStartupModule : IAbpModule - { - private readonly CmsKitTestData _cmsKitTestData; - private readonly IContentRepository _contentRepository; - - protected ContentRepository_Tests() - { - _cmsKitTestData = GetRequiredService(); - _contentRepository = GetRequiredService(); - } - - [Theory] - [InlineData("Lyrics", "1", "First things first")] - [InlineData("LyricsAlso", "2", "Second thing second")] - public async Task ShouldGetAsync(string entityType, string entityId, string contentStartsWith = null) - { - var content = await _contentRepository.GetAsync(entityType, entityId); - - content.ShouldNotBeNull(); - - if (contentStartsWith != null) - { - content.Value.ShouldStartWith(contentStartsWith); - } - } - - [Fact] - public async Task ShouldNotGetAsync() - { - Should.Throw( - async () - => - await _contentRepository.GetAsync("not_exist_entity", Guid.NewGuid().ToString())); - } - - [Fact] - public async Task ShouldFindAsync() - { - var content = - await _contentRepository.FindAsync(_cmsKitTestData.Content_1_EntityType, _cmsKitTestData.Content_1_EntityId); - - content.ShouldNotBeNull(); - } - - [Fact] - public async Task ShouldNotFindAsync() - { - var content = await _contentRepository.FindAsync("not_exist_entity", Guid.NewGuid().ToString()); - - content.ShouldBeNull(); - } - } -} \ No newline at end of file diff --git a/modules/docs/src/Volo.Docs.Admin.Web/Navigation/DocsMenuContributor.cs b/modules/docs/src/Volo.Docs.Admin.Web/Navigation/DocsMenuContributor.cs index 9bc55d543f..644dd037c4 100644 --- a/modules/docs/src/Volo.Docs.Admin.Web/Navigation/DocsMenuContributor.cs +++ b/modules/docs/src/Volo.Docs.Admin.Web/Navigation/DocsMenuContributor.cs @@ -17,7 +17,7 @@ namespace Volo.Docs.Admin.Navigation } } - private async Task ConfigureMainMenuAsync(MenuConfigurationContext context) + private Task ConfigureMainMenuAsync(MenuConfigurationContext context) { var administrationMenu = context.Menu.GetAdministration(); @@ -27,15 +27,10 @@ namespace Volo.Docs.Admin.Navigation administrationMenu.AddItem(rootMenuItem); - if (await context.IsGrantedAsync(DocsAdminPermissions.Projects.Default)) - { - rootMenuItem.AddItem(new ApplicationMenuItem(DocsMenuNames.Projects, l["Menu:ProjectManagement"], "~/Docs/Admin/Projects")); - } + rootMenuItem.AddItem(new ApplicationMenuItem(DocsMenuNames.Projects, l["Menu:ProjectManagement"], "~/Docs/Admin/Projects", requiredPermissionName: DocsAdminPermissions.Projects.Default)); + rootMenuItem.AddItem(new ApplicationMenuItem(DocsMenuNames.Documents, l["Menu:DocumentManagement"], "~/Docs/Admin/Documents", requiredPermissionName: DocsAdminPermissions.Documents.Default)); - if (await context.IsGrantedAsync(DocsAdminPermissions.Documents.Default)) - { - rootMenuItem.AddItem(new ApplicationMenuItem(DocsMenuNames.Documents, l["Menu:DocumentManagement"], "~/Docs/Admin/Documents")); - } + return Task.CompletedTask; } } } diff --git a/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Documents/FullSearch/Elastic/ElasticDocumentFullSearch.cs b/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Documents/FullSearch/Elastic/ElasticDocumentFullSearch.cs index 8e0a51324a..7160ca405b 100644 --- a/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Documents/FullSearch/Elastic/ElasticDocumentFullSearch.cs +++ b/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Documents/FullSearch/Elastic/ElasticDocumentFullSearch.cs @@ -60,11 +60,6 @@ namespace Volo.Docs.Documents.FullSearch.Elastic var client = _clientProvider.GetClient(); - var existsResponse = await client.DocumentExistsAsync(DocumentPath.Id(document.Id), - x => x.Index(_options.IndexName), cancellationToken); - - HandleError(existsResponse); - var esDocument = new EsDocument { Id = NormalizeField(document.Id), @@ -76,17 +71,7 @@ namespace Volo.Docs.Documents.FullSearch.Elastic Version = NormalizeField(document.Version) }; - if (!existsResponse.Exists) - { - HandleError(await client.IndexAsync(esDocument, - x => x.Id(document.Id).Index(_options.IndexName), cancellationToken)); - } - else - { - HandleError(await client.UpdateAsync(DocumentPath.Id(document.Id), - x => x.Doc(esDocument).Index(_options.IndexName), cancellationToken)); - } - + await client.IndexAsync(esDocument , x=>x.Index(_options.IndexName), cancellationToken); } public virtual async Task DeleteAsync(Guid id, CancellationToken cancellationToken = default) @@ -94,7 +79,7 @@ namespace Volo.Docs.Documents.FullSearch.Elastic ValidateElasticSearchEnabled(); HandleError(await _clientProvider.GetClient() - .DeleteAsync(DocumentPath.Id(id), x => x.Index(_options.IndexName), cancellationToken)); + .DeleteAsync(DocumentPath.Id( NormalizeField(id)), x => x.Index(_options.IndexName), cancellationToken)); } public virtual async Task DeleteAllAsync(CancellationToken cancellationToken = default) diff --git a/modules/identity/src/Volo.Abp.Identity.Blazor/AbpIdentityWebMainMenuContributor.cs b/modules/identity/src/Volo.Abp.Identity.Blazor/AbpIdentityWebMainMenuContributor.cs index 5e5714a851..609da7e6a7 100644 --- a/modules/identity/src/Volo.Abp.Identity.Blazor/AbpIdentityWebMainMenuContributor.cs +++ b/modules/identity/src/Volo.Abp.Identity.Blazor/AbpIdentityWebMainMenuContributor.cs @@ -6,35 +6,35 @@ namespace Volo.Abp.Identity.Blazor { public class AbpIdentityWebMainMenuContributor : IMenuContributor { - public virtual async Task ConfigureMenuAsync(MenuConfigurationContext context) + public virtual Task ConfigureMenuAsync(MenuConfigurationContext context) { if (context.Menu.Name != StandardMenus.Main) { - return; + return Task.CompletedTask; } - var hasRolePermission = await context.IsGrantedAsync(IdentityPermissions.Roles.Default); - var hasUserPermission = await context.IsGrantedAsync(IdentityPermissions.Users.Default); + var administrationMenu = context.Menu.GetAdministration(); - if (hasRolePermission || hasUserPermission) - { - var administrationMenu = context.Menu.GetAdministration(); + var l = context.GetLocalizer(); - var l = context.GetLocalizer(); + var identityMenuItem = new ApplicationMenuItem(IdentityMenuNames.GroupName, l["Menu:IdentityManagement"], + icon: "far fa-id-card"); + administrationMenu.AddItem(identityMenuItem); - var identityMenuItem = new ApplicationMenuItem(IdentityMenuNames.GroupName, l["Menu:IdentityManagement"], icon: "far fa-id-card"); - administrationMenu.AddItem(identityMenuItem); + identityMenuItem.AddItem(new ApplicationMenuItem( + IdentityMenuNames.Roles, + l["Roles"], + url: "identity/roles", + requiredPermissionName: IdentityPermissions.Roles.Default)); - if (hasRolePermission) - { - identityMenuItem.AddItem(new ApplicationMenuItem(IdentityMenuNames.Roles, l["Roles"], url: "identity/roles")); - } - if (hasUserPermission) - { - identityMenuItem.AddItem(new ApplicationMenuItem(IdentityMenuNames.Users, l["Users"], url: "identity/users")); - } - } + identityMenuItem.AddItem(new ApplicationMenuItem( + IdentityMenuNames.Users, + l["Users"], + url: "identity/users", + requiredPermissionName: IdentityPermissions.Users.Default)); + + return Task.CompletedTask; } } } diff --git a/modules/identity/src/Volo.Abp.Identity.Domain.Shared/Volo/Abp/Identity/IdentityRoleNameChangedEto.cs b/modules/identity/src/Volo.Abp.Identity.Domain.Shared/Volo/Abp/Identity/IdentityRoleNameChangedEto.cs new file mode 100644 index 0000000000..b8ae9e537b --- /dev/null +++ b/modules/identity/src/Volo.Abp.Identity.Domain.Shared/Volo/Abp/Identity/IdentityRoleNameChangedEto.cs @@ -0,0 +1,16 @@ +using System; + +namespace Volo.Abp.Identity +{ + [Serializable] + public class IdentityRoleNameChangedEto + { + public Guid Id { get; set; } + + public Guid? TenantId { get; set; } + + public string Name { get; set; } + + public string OldName { get; set; } + } +} \ No newline at end of file diff --git a/modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/AbpIdentityDomainModule.cs b/modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/AbpIdentityDomainModule.cs index 4326d1aeb8..79f5fb647b 100644 --- a/modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/AbpIdentityDomainModule.cs +++ b/modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/AbpIdentityDomainModule.cs @@ -40,6 +40,9 @@ namespace Volo.Abp.Identity options.EtoMappings.Add(typeof(AbpIdentityDomainModule)); options.EtoMappings.Add(typeof(AbpIdentityDomainModule)); options.EtoMappings.Add(typeof(AbpIdentityDomainModule)); + + options.AutoEventSelectors.Add(); + options.AutoEventSelectors.Add(); }); var identityBuilder = context.Services.AddAbpIdentity(options => diff --git a/modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/IdentityRole.cs b/modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/IdentityRole.cs index dac173719a..f856ee2277 100644 --- a/modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/IdentityRole.cs +++ b/modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/IdentityRole.cs @@ -108,12 +108,24 @@ namespace Volo.Abp.Identity Name = name; AddLocalEvent( +#pragma warning disable 618 new IdentityRoleNameChangedEvent +#pragma warning restore 618 { IdentityRole = this, OldName = oldName } ); + + AddDistributedEvent( + new IdentityRoleNameChangedEto + { + Id = Id, + Name = Name, + OldName = oldName, + TenantId = TenantId + } + ); } public override string ToString() diff --git a/modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/IdentityRoleNameChangedEvent.cs b/modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/IdentityRoleNameChangedEvent.cs index f14f0a71ed..86fc5eab3e 100644 --- a/modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/IdentityRoleNameChangedEvent.cs +++ b/modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/IdentityRoleNameChangedEvent.cs @@ -1,5 +1,8 @@ -namespace Volo.Abp.Identity +using System; + +namespace Volo.Abp.Identity { + [Obsolete("Use the distributed event (IdentityRoleNameChangedEto) instead.")] public class IdentityRoleNameChangedEvent { public IdentityRole IdentityRole { get; set; } diff --git a/modules/identity/src/Volo.Abp.Identity.Web/Navigation/AbpIdentityWebMainMenuContributor.cs b/modules/identity/src/Volo.Abp.Identity.Web/Navigation/AbpIdentityWebMainMenuContributor.cs index 279ea16278..2f48318511 100644 --- a/modules/identity/src/Volo.Abp.Identity.Web/Navigation/AbpIdentityWebMainMenuContributor.cs +++ b/modules/identity/src/Volo.Abp.Identity.Web/Navigation/AbpIdentityWebMainMenuContributor.cs @@ -9,35 +9,22 @@ namespace Volo.Abp.Identity.Web.Navigation { public class AbpIdentityWebMainMenuContributor : IMenuContributor { - public virtual async Task ConfigureMenuAsync(MenuConfigurationContext context) + public virtual Task ConfigureMenuAsync(MenuConfigurationContext context) { if (context.Menu.Name != StandardMenus.Main) { - return; + return Task.CompletedTask; } - var hasRolePermission = await context.IsGrantedAsync(IdentityPermissions.Roles.Default); - var hasUserPermission = await context.IsGrantedAsync(IdentityPermissions.Users.Default); + var l = context.GetLocalizer(); - if (hasRolePermission || hasUserPermission) - { - var administrationMenu = context.Menu.GetAdministration(); - - var l = context.GetLocalizer(); + var identityMenuItem = new ApplicationMenuItem(IdentityMenuNames.GroupName, l["Menu:IdentityManagement"], icon: "fa fa-id-card-o"); + identityMenuItem.AddItem(new ApplicationMenuItem(IdentityMenuNames.Roles, l["Roles"], url: "~/Identity/Roles", requiredPermissionName: IdentityPermissions.Roles.Default)); + identityMenuItem.AddItem(new ApplicationMenuItem(IdentityMenuNames.Users, l["Users"], url: "~/Identity/Users", requiredPermissionName: IdentityPermissions.Users.Default)); - var identityMenuItem = new ApplicationMenuItem(IdentityMenuNames.GroupName, l["Menu:IdentityManagement"], icon: "fa fa-id-card-o"); - administrationMenu.AddItem(identityMenuItem); + context.Menu.GetAdministration().AddItem(identityMenuItem); - if (hasRolePermission) - { - identityMenuItem.AddItem(new ApplicationMenuItem(IdentityMenuNames.Roles, l["Roles"], url: "~/Identity/Roles")); - } - - if (hasUserPermission) - { - identityMenuItem.AddItem(new ApplicationMenuItem(IdentityMenuNames.Users, l["Users"], url: "~/Identity/Users")); - } - } + return Task.CompletedTask; } } } diff --git a/modules/identity/src/Volo.Abp.PermissionManagement.Domain.Identity/Volo/Abp/PermissionManagement/Identity/RoleDeletedEventHandler.cs b/modules/identity/src/Volo.Abp.PermissionManagement.Domain.Identity/Volo/Abp/PermissionManagement/Identity/RoleDeletedEventHandler.cs index b3fd565b24..4a25abea50 100644 --- a/modules/identity/src/Volo.Abp.PermissionManagement.Domain.Identity/Volo/Abp/PermissionManagement/Identity/RoleDeletedEventHandler.cs +++ b/modules/identity/src/Volo.Abp.PermissionManagement.Domain.Identity/Volo/Abp/PermissionManagement/Identity/RoleDeletedEventHandler.cs @@ -1,26 +1,27 @@ using System.Threading.Tasks; using Volo.Abp.Authorization.Permissions; using Volo.Abp.DependencyInjection; -using Volo.Abp.Domain.Entities.Events; +using Volo.Abp.Domain.Entities.Events.Distributed; using Volo.Abp.EventBus; +using Volo.Abp.EventBus.Distributed; using Volo.Abp.Identity; namespace Volo.Abp.PermissionManagement.Identity { - // public class RoleDeletedEventHandler : - // ILocalEventHandler>, - // ITransientDependency - // { - // protected IPermissionManager PermissionManager { get; } - // - // public RoleDeletedEventHandler(IPermissionManager permissionManager) - // { - // PermissionManager = permissionManager; - // } - // - // public virtual async Task HandleEventAsync(EntityDeletedEventData eventData) - // { - // await PermissionManager.DeleteAsync(RolePermissionValueProvider.ProviderName, eventData.Entity.Name); - // } - // } + public class RoleDeletedEventHandler : + IDistributedEventHandler>, + ITransientDependency + { + protected IPermissionManager PermissionManager { get; } + + public RoleDeletedEventHandler(IPermissionManager permissionManager) + { + PermissionManager = permissionManager; + } + + public async Task HandleEventAsync(EntityDeletedEto eventData) + { + await PermissionManager.DeleteAsync(RolePermissionValueProvider.ProviderName, eventData.Entity.Name); + } + } } diff --git a/modules/identity/src/Volo.Abp.PermissionManagement.Domain.Identity/Volo/Abp/PermissionManagement/Identity/RoleUpdateEventHandler.cs b/modules/identity/src/Volo.Abp.PermissionManagement.Domain.Identity/Volo/Abp/PermissionManagement/Identity/RoleUpdateEventHandler.cs index 18612bcfad..d2d25ec3e8 100644 --- a/modules/identity/src/Volo.Abp.PermissionManagement.Domain.Identity/Volo/Abp/PermissionManagement/Identity/RoleUpdateEventHandler.cs +++ b/modules/identity/src/Volo.Abp.PermissionManagement.Domain.Identity/Volo/Abp/PermissionManagement/Identity/RoleUpdateEventHandler.cs @@ -1,45 +1,33 @@ using System.Threading.Tasks; using Volo.Abp.Authorization.Permissions; using Volo.Abp.DependencyInjection; -using Volo.Abp.Domain.Entities.Events; -using Volo.Abp.EventBus; +using Volo.Abp.EventBus.Distributed; using Volo.Abp.Identity; namespace Volo.Abp.PermissionManagement.Identity { - //TODO: This code can not be here! + public class RoleUpdateEventHandler : + IDistributedEventHandler, + ITransientDependency + { + protected IPermissionManager PermissionManager { get; } + protected IPermissionGrantRepository PermissionGrantRepository { get; } + + public RoleUpdateEventHandler( + IPermissionManager permissionManager, + IPermissionGrantRepository permissionGrantRepository) + { + PermissionManager = permissionManager; + PermissionGrantRepository = permissionGrantRepository; + } - // public class RoleUpdateEventHandler : - // ILocalEventHandler, - // ITransientDependency - // { - // protected IIdentityRoleRepository RoleRepository { get; } - // protected IPermissionManager PermissionManager { get; } - // protected IPermissionGrantRepository PermissionGrantRepository { get; } - // - // public RoleUpdateEventHandler( - // IIdentityRoleRepository roleRepository, - // IPermissionManager permissionManager, - // IPermissionGrantRepository permissionGrantRepository) - // { - // RoleRepository = roleRepository; - // PermissionManager = permissionManager; - // PermissionGrantRepository = permissionGrantRepository; - // } - // - // public virtual async Task HandleEventAsync(IdentityRoleNameChangedEvent eventData) - // { - // var role = await RoleRepository.FindAsync(eventData.IdentityRole.Id, false); - // if (role == null) - // { - // return; - // } - // - // var permissionGrantsInRole = await PermissionGrantRepository.GetListAsync(RolePermissionValueProvider.ProviderName, eventData.OldName); - // foreach (var permissionGrant in permissionGrantsInRole) - // { - // await PermissionManager.UpdateProviderKeyAsync(permissionGrant, eventData.IdentityRole.Name); - // } - // } - // } + public async Task HandleEventAsync(IdentityRoleNameChangedEto eventData) + { + var permissionGrantsInRole = await PermissionGrantRepository.GetListAsync(RolePermissionValueProvider.ProviderName, eventData.OldName); + foreach (var permissionGrant in permissionGrantsInRole) + { + await PermissionManager.UpdateProviderKeyAsync(permissionGrant, eventData.Name); + } + } + } } diff --git a/modules/identity/test/Volo.Abp.Identity.Domain.Tests/Volo/Abp/Identity/Distributed_Role_Change_Events_Test.cs b/modules/identity/test/Volo.Abp.Identity.Domain.Tests/Volo/Abp/Identity/Distributed_Role_Change_Events_Test.cs new file mode 100644 index 0000000000..a57a8baf69 --- /dev/null +++ b/modules/identity/test/Volo.Abp.Identity.Domain.Tests/Volo/Abp/Identity/Distributed_Role_Change_Events_Test.cs @@ -0,0 +1,105 @@ +using System.Collections.Generic; +using System.Linq; +using Microsoft.AspNetCore.Identity; +using Shouldly; +using System.Threading.Tasks; +using Microsoft.Extensions.Options; +using Volo.Abp.Caching; +using Volo.Abp.Domain.Entities.Events.Distributed; +using Volo.Abp.EventBus.Distributed; +using Volo.Abp.PermissionManagement; +using Volo.Abp.PermissionManagement.Identity; +using Volo.Abp.Uow; +using Xunit; + +namespace Volo.Abp.Identity +{ + public class Distributed_Role_Change_Events_Test : AbpIdentityDomainTestBase + { + protected readonly IIdentityRoleRepository RoleRepository; + protected readonly IPermissionGrantRepository PermissionGrantRepository; + protected readonly IdentityRoleManager RoleManager; + protected readonly ILookupNormalizer LookupNormalizer; + protected readonly IUnitOfWorkManager UowManager; + protected readonly IDistributedCache Cache; + + public Distributed_Role_Change_Events_Test() + { + RoleRepository = GetRequiredService(); + ; + PermissionGrantRepository = GetRequiredService(); + ; + RoleManager = GetRequiredService(); + ; + LookupNormalizer = GetRequiredService(); + ; + UowManager = GetRequiredService(); + Cache = GetRequiredService>(); + } + + [Fact] + public void Should_Register_Handler() + { + var x = GetRequiredService>(); + GetRequiredService>() + .Value + .AutoEventSelectors + .ShouldContain(m => m.Name == "Entity:" + typeof(IdentityRole).FullName); + + GetRequiredService>() + .Value + .Handlers + .ShouldContain(h => h == typeof(RoleUpdateEventHandler) || h == typeof(RoleDeletedEventHandler)); + } + + [Fact] + public async Task Role_Updated_Distributed_Event_Test() + { + var role = await RoleRepository.FindByNormalizedNameAsync(LookupNormalizer.NormalizeName("moderator")); + + var permissionGrantsInRole = await PermissionGrantRepository.GetListAsync("R", role.Name); + permissionGrantsInRole.ShouldNotBeNull(); + permissionGrantsInRole.Count.ShouldBeGreaterThan(0); + var count = permissionGrantsInRole.Count; + + using (var uow = UowManager.Begin()) + { + var identityResult = await RoleManager.SetRoleNameAsync(role, "TestModerator"); + identityResult.Succeeded.ShouldBeTrue(); + await RoleRepository.UpdateAsync(role); + await uow.CompleteAsync(); + } + + role = await RoleRepository.GetAsync(role.Id); + role.Name.ShouldBe("TestModerator"); + + permissionGrantsInRole = await PermissionGrantRepository.GetListAsync("R", role.Name); + permissionGrantsInRole.Count.ShouldBe(count); + } + + [Fact] + public async Task Role_Deleted_Distributed_Event_Test() + { + var role = await RoleRepository.FindByNormalizedNameAsync(LookupNormalizer.NormalizeName("moderator")); + var permissionGrantsInRole = await PermissionGrantRepository.GetListAsync("R", role.Name); + + var caches = permissionGrantsInRole.Select(x => new KeyValuePair( + PermissionGrantCacheItem.CalculateCacheKey(x.Name, x.ProviderName, x.ProviderKey), + new PermissionGrantCacheItem(true))).ToList(); + await Cache.SetManyAsync(caches); + + + using (var uow = UowManager.Begin()) + { + await RoleRepository.DeleteAsync(role); + await uow.CompleteAsync(); + } + + var permissionGrantCaches = await Cache.GetManyAsync(caches.Select(x=>x.Key)); + foreach (var cache in permissionGrantCaches) + { + cache.Value.ShouldBeNull(); + } + } + } +} diff --git a/modules/identity/test/Volo.Abp.Identity.Domain.Tests/Volo/Abp/Identity/RoleChangingEvents_Test.cs b/modules/identity/test/Volo.Abp.Identity.Domain.Tests/Volo/Abp/Identity/RoleChangingEvents_Test.cs deleted file mode 100644 index a668b5ff4f..0000000000 --- a/modules/identity/test/Volo.Abp.Identity.Domain.Tests/Volo/Abp/Identity/RoleChangingEvents_Test.cs +++ /dev/null @@ -1,60 +0,0 @@ -using Microsoft.AspNetCore.Identity; -using Shouldly; -using System.Threading.Tasks; -using Volo.Abp.EventBus.Distributed; -using Volo.Abp.Guids; -using Volo.Abp.PermissionManagement; -using Volo.Abp.Uow; -using Xunit; - -namespace Volo.Abp.Identity -{ - //TODO: This code can not be here! - //https://github.com/abpframework/abp/commit/847f526041145b62376b760776829d5ce257da1c - // public class RoleChangingEvents_Test : AbpIdentityDomainTestBase - // { - // protected readonly IIdentityRoleRepository RoleRepository; - // protected readonly IPermissionGrantRepository PermissionGrantRepository; - // protected readonly IdentityRoleManager RoleManager; - // protected readonly ILookupNormalizer LookupNormalizer; - // protected readonly IGuidGenerator GuidGenerator; - // protected readonly IUnitOfWorkManager UowManager; - // - // public RoleChangingEvents_Test() - // { - // RoleRepository = GetRequiredService(); ; - // PermissionGrantRepository = GetRequiredService(); ; - // RoleManager = GetRequiredService(); ; - // LookupNormalizer = GetRequiredService(); ; - // GuidGenerator = GetRequiredService(); - // UowManager = GetRequiredService(); - // } - // - // [Fact(Skip = "https://github.com/abpframework/abp/actions/runs/454248191")] - // public async Task Role_Update_Event_Test() - // { - // var role = await RoleRepository - // .FindByNormalizedNameAsync(LookupNormalizer.NormalizeName("moderator")) - // ; - // - // var permissionGrantsInRole = await PermissionGrantRepository.GetListAsync("R", role.Name); - // permissionGrantsInRole.ShouldNotBeNull(); - // permissionGrantsInRole.Count.ShouldBeGreaterThan(0); - // var count = permissionGrantsInRole.Count; - // - // using (var uow = UowManager.Begin()) - // { - // var identityResult = await RoleManager.SetRoleNameAsync(role, "TestModerator"); - // identityResult.Succeeded.ShouldBeTrue(); - // var xx = await RoleRepository.UpdateAsync(role); - // await uow.CompleteAsync(); - // } - // - // role = await RoleRepository.GetAsync(role.Id); - // role.Name.ShouldBe("TestModerator"); - // - // permissionGrantsInRole = await PermissionGrantRepository.GetListAsync("R", role.Name); - // permissionGrantsInRole.Count.ShouldBe(count); - // } - // } -} diff --git a/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/PermissionGrantCacheItemInvalidator.cs b/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/PermissionGrantCacheItemInvalidator.cs index 9e73e59b79..585c0a0559 100644 --- a/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/PermissionGrantCacheItemInvalidator.cs +++ b/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/PermissionGrantCacheItemInvalidator.cs @@ -7,7 +7,9 @@ using Volo.Abp.MultiTenancy; namespace Volo.Abp.PermissionManagement { - public class PermissionGrantCacheItemInvalidator : ILocalEventHandler>, ITransientDependency + public class PermissionGrantCacheItemInvalidator : + ILocalEventHandler>, + ITransientDependency { protected ICurrentTenant CurrentTenant { get; } 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 fc8da0c6c5..1f1e28dfd4 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 @@ -5,6 +5,7 @@ using System.Threading.Tasks; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Options; using Volo.Abp.Authorization.Permissions; +using Volo.Abp.Caching; using Volo.Abp.DependencyInjection; using Volo.Abp.Guids; using Volo.Abp.MultiTenancy; @@ -24,6 +25,8 @@ namespace Volo.Abp.PermissionManagement protected IReadOnlyList ManagementProviders => _lazyProviders.Value; protected PermissionManagementOptions Options { get; } + + protected IDistributedCache Cache { get; } private readonly Lazy> _lazyProviders; @@ -33,10 +36,12 @@ namespace Volo.Abp.PermissionManagement IServiceProvider serviceProvider, IGuidGenerator guidGenerator, IOptions options, - ICurrentTenant currentTenant) + ICurrentTenant currentTenant, + IDistributedCache cache) { GuidGenerator = guidGenerator; CurrentTenant = currentTenant; + Cache = cache; PermissionGrantRepository = permissionGrantRepository; PermissionDefinitionManager = permissionDefinitionManager; Options = options.Value; @@ -104,9 +109,21 @@ namespace Volo.Abp.PermissionManagement await provider.SetAsync(permissionName, providerKey, isGranted); } - + public virtual async Task UpdateProviderKeyAsync(PermissionGrant permissionGrant, string providerKey) { + using (CurrentTenant.Change(permissionGrant.TenantId)) + { + //Invalidating the cache for the old key + await Cache.RemoveAsync( + PermissionGrantCacheItem.CalculateCacheKey( + permissionGrant.Name, + permissionGrant.ProviderName, + permissionGrant.ProviderKey + ) + ); + } + permissionGrant.ProviderKey = providerKey; return await PermissionGrantRepository.UpdateAsync(permissionGrant); } @@ -114,7 +131,6 @@ namespace Volo.Abp.PermissionManagement public virtual async Task DeleteAsync(string providerName, string providerKey) { var permissionGrants = await PermissionGrantRepository.GetListAsync(providerName, providerKey); - //TODO: Use DeleteManyAsync method foreach (var permissionGrant in permissionGrants) { await PermissionGrantRepository.DeleteAsync(permissionGrant); diff --git a/modules/tenant-management/src/Volo.Abp.TenantManagement.Blazor/Navigation/TenantManagementBlazorMenuContributor.cs b/modules/tenant-management/src/Volo.Abp.TenantManagement.Blazor/Navigation/TenantManagementBlazorMenuContributor.cs index 03bfd6b2d2..32cac00b2c 100644 --- a/modules/tenant-management/src/Volo.Abp.TenantManagement.Blazor/Navigation/TenantManagementBlazorMenuContributor.cs +++ b/modules/tenant-management/src/Volo.Abp.TenantManagement.Blazor/Navigation/TenantManagementBlazorMenuContributor.cs @@ -6,24 +6,28 @@ namespace Volo.Abp.TenantManagement.Blazor.Navigation { public class TenantManagementBlazorMenuContributor : IMenuContributor { - public virtual async Task ConfigureMenuAsync(MenuConfigurationContext context) + public virtual Task ConfigureMenuAsync(MenuConfigurationContext context) { if (context.Menu.Name != StandardMenus.Main) { - return; + return Task.CompletedTask; } var administrationMenu = context.Menu.GetAdministration(); var l = context.GetLocalizer(); - var tenantManagementMenuItem = new ApplicationMenuItem(TenantManagementMenuNames.GroupName, l["Menu:TenantManagement"], icon: "fa fa-users"); + var tenantManagementMenuItem = new ApplicationMenuItem(TenantManagementMenuNames.GroupName, + l["Menu:TenantManagement"], icon: "fa fa-users"); administrationMenu.AddItem(tenantManagementMenuItem); - if (await context.IsGrantedAsync(TenantManagementPermissions.Tenants.Default)) - { - tenantManagementMenuItem.AddItem(new ApplicationMenuItem(TenantManagementMenuNames.Tenants, l["Tenants"], url: "tenant-management/tenants")); - } + tenantManagementMenuItem.AddItem(new ApplicationMenuItem( + TenantManagementMenuNames.Tenants, + l["Tenants"], + url: "tenant-management/tenants", + requiredPermissionName: TenantManagementPermissions.Tenants.Default)); + + return Task.CompletedTask; } } } diff --git a/modules/tenant-management/src/Volo.Abp.TenantManagement.Web/Navigation/AbpTenantManagementWebMainMenuContributor.cs b/modules/tenant-management/src/Volo.Abp.TenantManagement.Web/Navigation/AbpTenantManagementWebMainMenuContributor.cs index 0a36e9d130..c3ebaa39b5 100644 --- a/modules/tenant-management/src/Volo.Abp.TenantManagement.Web/Navigation/AbpTenantManagementWebMainMenuContributor.cs +++ b/modules/tenant-management/src/Volo.Abp.TenantManagement.Web/Navigation/AbpTenantManagementWebMainMenuContributor.cs @@ -9,11 +9,11 @@ namespace Volo.Abp.TenantManagement.Web.Navigation { public class AbpTenantManagementWebMainMenuContributor : IMenuContributor { - public virtual async Task ConfigureMenuAsync(MenuConfigurationContext context) + public virtual Task ConfigureMenuAsync(MenuConfigurationContext context) { if (context.Menu.Name != StandardMenus.Main) { - return; + return Task.CompletedTask; } var administrationMenu = context.Menu.GetAdministration(); @@ -23,10 +23,9 @@ namespace Volo.Abp.TenantManagement.Web.Navigation var tenantManagementMenuItem = new ApplicationMenuItem(TenantManagementMenuNames.GroupName, l["Menu:TenantManagement"], icon: "fa fa-users"); administrationMenu.AddItem(tenantManagementMenuItem); - if (await context.IsGrantedAsync(TenantManagementPermissions.Tenants.Default)) - { - tenantManagementMenuItem.AddItem(new ApplicationMenuItem(TenantManagementMenuNames.Tenants, l["Tenants"], url: "~/TenantManagement/Tenants")); - } + tenantManagementMenuItem.AddItem(new ApplicationMenuItem(TenantManagementMenuNames.Tenants, l["Tenants"], url: "~/TenantManagement/Tenants", requiredPermissionName: TenantManagementPermissions.Tenants.Default)); + + return Task.CompletedTask; } } } diff --git a/npm/ng-packs/apps/dev-app/src/environments/environment.ts b/npm/ng-packs/apps/dev-app/src/environments/environment.ts index 87ca8d1447..771698e394 100644 --- a/npm/ng-packs/apps/dev-app/src/environments/environment.ts +++ b/npm/ng-packs/apps/dev-app/src/environments/environment.ts @@ -23,23 +23,18 @@ export const environment = { rootNamespace: 'MyCompanyName.MyProjectName', }, AbpFeatureManagement: { - url: 'https://localhost:44305', rootNamespace: 'Volo.Abp', }, AbpPermissionManagement: { - url: 'https://localhost:44305', rootNamespace: 'Volo.Abp.PermissionManagement', }, AbpTenantManagement: { - url: 'https://localhost:44305', rootNamespace: 'Volo.Abp.TenantManagement', }, AbpIdentity: { - url: 'https://localhost:44305', rootNamespace: 'Volo.Abp', }, AbpSettingManagement: { - url: 'https://localhost:44305', rootNamespace: 'Volo.Abp.SettingManagement', }, }, diff --git a/npm/ng-packs/packages/core/src/lib/models/environment.ts b/npm/ng-packs/packages/core/src/lib/models/environment.ts index b29f0d338d..46596685b0 100644 --- a/npm/ng-packs/packages/core/src/lib/models/environment.ts +++ b/npm/ng-packs/packages/core/src/lib/models/environment.ts @@ -18,15 +18,14 @@ export interface ApplicationInfo { logoUrl?: string; } -export type ApiConfig = { +export interface ApiConfig { [key: string]: string; url: string; -} & Partial<{ - rootNamespace: string; -}>; + rootNamespace?: string; +} export interface Apis { - [key: string]: ApiConfig; + [key: string]: Partial; default: ApiConfig; } diff --git a/npm/ng-packs/packages/core/src/lib/services/environment.service.ts b/npm/ng-packs/packages/core/src/lib/services/environment.service.ts index 2062294b7b..10d7664acb 100644 --- a/npm/ng-packs/packages/core/src/lib/services/environment.service.ts +++ b/npm/ng-packs/packages/core/src/lib/services/environment.service.ts @@ -4,6 +4,9 @@ import { map } from 'rxjs/operators'; import { Apis, Environment } from '../models/environment'; import { InternalStore } from '../utils/internal-store-utils'; +const mapToApiUrl = (key: string) => (apis: Apis) => + (apis[key] || apis.default).url || apis.default.url; + @Injectable({ providedIn: 'root' }) export class EnvironmentService { private readonly store = new InternalStore({} as Environment); @@ -21,13 +24,11 @@ export class EnvironmentService { } getApiUrl(key?: string) { - return (this.store.state.apis[key || 'default'] || this.store.state.apis.default).url; + return mapToApiUrl(key)(this.store.state.apis); } getApiUrl$(key?: string) { - return this.store - .sliceState(state => state.apis) - .pipe(map((apis: Apis) => (apis[key || 'default'] || apis.default).url)); + return this.store.sliceState(state => state.apis).pipe(map(mapToApiUrl(key))); } setState(environment: Environment) { diff --git a/npm/ng-packs/packages/core/src/lib/tests/environment.service.spec.ts b/npm/ng-packs/packages/core/src/lib/tests/environment.service.spec.ts index fe9f50a546..95c2b58a6c 100644 --- a/npm/ng-packs/packages/core/src/lib/tests/environment.service.spec.ts +++ b/npm/ng-packs/packages/core/src/lib/tests/environment.service.spec.ts @@ -1,3 +1,4 @@ +import { waitForAsync } from '@angular/core/testing'; import { createServiceFactory, SpectatorService } from '@ngneat/spectator/jest'; import { Environment } from '../models'; import { EnvironmentService } from '../services'; @@ -17,6 +18,7 @@ export const ENVIRONMENT_DATA = ({ other: { url: 'https://localhost:44306', }, + yetAnother: {}, }, localization: { defaultResourceName: 'MyProjectName', @@ -39,19 +41,28 @@ describe('ConfigState', () => { }); describe('#getEnvironment', () => { - it('should return ENVIRONMENT_DATA', () => { - expect(environment.getEnvironment()).toEqual(ENVIRONMENT_DATA); - environment.getEnvironment$().subscribe(data => expect(data).toEqual(ENVIRONMENT_DATA)); - }); + it( + 'should return ENVIRONMENT_DATA', + waitForAsync(() => { + expect(environment.getEnvironment()).toEqual(ENVIRONMENT_DATA); + environment.getEnvironment$().subscribe(data => expect(data).toEqual(ENVIRONMENT_DATA)); + }), + ); }); describe('#getApiUrl', () => { - it('should return api url', () => { - expect(environment.getApiUrl()).toEqual(ENVIRONMENT_DATA.apis.default.url); - environment - .getApiUrl$('other') - .subscribe(data => expect(data).toEqual(ENVIRONMENT_DATA.apis.other.url)); - }); + it( + 'should return api url', + waitForAsync(() => { + expect(environment.getApiUrl()).toEqual(ENVIRONMENT_DATA.apis.default.url); + environment + .getApiUrl$('other') + .subscribe(data => expect(data).toEqual(ENVIRONMENT_DATA.apis.other.url)); + environment + .getApiUrl$('yetAnother') + .subscribe(data => expect(data).toEqual(ENVIRONMENT_DATA.apis.default.url)); + }), + ); }); // TODO: create permission.service.spec.ts diff --git a/npm/ng-packs/packages/theme-shared/extensions/src/lib/models/internal/object-extensions.ts b/npm/ng-packs/packages/theme-shared/extensions/src/lib/models/internal/object-extensions.ts index 448183b8a0..ea8a9dad8f 100644 --- a/npm/ng-packs/packages/theme-shared/extensions/src/lib/models/internal/object-extensions.ts +++ b/npm/ng-packs/packages/theme-shared/extensions/src/lib/models/internal/object-extensions.ts @@ -106,146 +106,3 @@ export interface PropContributors { createForm: PropContributorCallbacks>; editForm: PropContributorCallbacks>; } - -/** - * @deprecated To be deleted in v4.2. - */ -export interface Config { - objectExtensions: Item; -} - -/** - * @deprecated Use ObjectExtensionsDto. To be deleted in v4.2. - */ -export interface Item { - modules: Modules; - enums: Enums; -} - -/** - * @deprecated Use Record. To be deleted in v4.2. - */ -export type Modules = Configuration; - -/** - * @deprecated Use ModuleExtensionDto. To be deleted in v4.2. - */ -export interface Module { - configuration: Configuration; - entities: Entities; -} - -/** - * @deprecated Use Record. To be deleted in v4.2. - */ -export type Entities = Configuration; - -/** - * @deprecated Use EntityExtensionDto. To be deleted in v4.2. - */ -export interface Entity { - configuration: Configuration; - properties: Properties; -} - -/** - * @deprecated Use Record. To be deleted in v4.2. - */ -export type Properties = Configuration; - -/** - * @deprecated Use ExtensionPropertyDto. To be deleted in v4.2. - */ -export interface Property { - type: string; - typeSimple: ePropType; - displayName: DisplayName | null; - api: Api; - ui: Ui; - attributes: Attribute[]; - configuration: Configuration; - defaultValue?: any; -} - -/** - * @deprecated Use LocalizableStringDto. To be deleted in v4.2. - */ -export interface DisplayName { - name: string; - resource: string; -} - -/** - * @deprecated Use ExtensionPropertyApiDto. To be deleted in v4.2. - */ -export interface Api { - onGet: ApiConfig; - onCreate: ApiConfig; - onUpdate: ApiConfig; -} - -/** - * @deprecated Use ExtensionPropertyApiCreateDto. To be deleted in v4.2. - */ -export interface ApiConfig { - isAvailable: boolean; -} - -/** - * @deprecated Use ExtensionPropertyUiDto. To be deleted in v4.2. - */ -export interface Ui { - onTable: UiPropConfig; - onCreateForm: UiFormConfig; - onEditForm: UiFormConfig; -} - -/** - * @deprecated Use ExtensionPropertyUiTableDto. To be deleted in v4.2. - */ -export interface UiPropConfig { - isSortable: boolean; - isVisible: boolean; -} - -/** - * @deprecated Use ExtensionPropertyUiFormDto. To be deleted in v4.2. - */ -export interface UiFormConfig { - isVisible: boolean; -} - -/** - * @deprecated Use ExtensionPropertyAttributeDto. To be deleted in v4.2. - */ -export interface Attribute { - typeSimple: string; - config: Configuration; -} - -/** - * @deprecated To be deleted in v4.2. - */ -export type Configuration = Record; - -/** - * @deprecated Use Record. To be deleted in v4.2. - */ -export type Enums = Record; - -/** - * @deprecated Use ExtensionEnumDto. To be deleted in v4.2. - */ -export interface Enum { - fields: EnumMember[]; - localizationResource?: string; - transformed?: any; -} - -/** - * @deprecated Use ExtensionEnumFieldDto. To be deleted in v4.2. - */ -export interface EnumMember { - name: string; - value: any; -} diff --git a/npm/packs/cms-kit/package.json b/npm/packs/cms-kit/package.json index 47f4efcc75..e539cf68c8 100644 --- a/npm/packs/cms-kit/package.json +++ b/npm/packs/cms-kit/package.json @@ -5,7 +5,9 @@ "access": "public" }, "dependencies": { - "@abp/star-rating-svg": "~4.2.1" + "@abp/star-rating-svg": "~4.2.1", + "@abp/tui-editor": "^4.2.1", + "slugify": "^1.4.7" }, "gitHead": "bb4ea17d5996f01889134c138d00b6c8f858a431" } diff --git a/npm/packs/tui-editor/abp.resourcemapping.js b/npm/packs/tui-editor/abp.resourcemapping.js index 53a3e493f7..a1d944d7f1 100644 --- a/npm/packs/tui-editor/abp.resourcemapping.js +++ b/npm/packs/tui-editor/abp.resourcemapping.js @@ -3,6 +3,7 @@ "@node_modules/to-mark/dist/to-mark.min.js": "@libs/to-mark/", "@node_modules/tui-code-snippet/dist/*.*": "@libs/tui-code-snippet/", "@node_modules/squire-rte/build/squire.js": "@libs/squire-rte/", - "@node_modules/tui-editor/dist/*.*": "@libs/tui-editor/" + "@node_modules/tui-editor/dist/*.*": "@libs/tui-editor/", + "@node_modules/@abp/tui-editor/src/*.*": "@libs/tui-editor/" } } \ No newline at end of file diff --git a/npm/packs/tui-editor/src/tui-editor-jquery-patch.js b/npm/packs/tui-editor/src/tui-editor-jquery-patch.js new file mode 100644 index 0000000000..1033d18992 --- /dev/null +++ b/npm/packs/tui-editor/src/tui-editor-jquery-patch.js @@ -0,0 +1,7 @@ +/* + https://jquery.com/upgrade-guide/3.5/#jquery-htmlprefilter-changes +*/ +var rxhtmlTag = /<(?!area|br|col|embed|hr|img|input|link|meta|param)(([a-z][^\/\0>\x20\t\r\n\f]*)[^>]*)\/>/gi; +jQuery.htmlPrefilter = function( html ) { + return html.replace( rxhtmlTag, "<$1>" ); +}; diff --git a/templates/wpf/src/MyCompanyName.MyProjectName/App.xaml.cs b/templates/wpf/src/MyCompanyName.MyProjectName/App.xaml.cs index 6ab1bd8c86..686cb5cba1 100644 --- a/templates/wpf/src/MyCompanyName.MyProjectName/App.xaml.cs +++ b/templates/wpf/src/MyCompanyName.MyProjectName/App.xaml.cs @@ -1,9 +1,4 @@ using System; -using System.Collections.Generic; -using System.Configuration; -using System.Data; -using System.Linq; -using System.Threading.Tasks; using System.Windows; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; @@ -22,19 +17,6 @@ namespace MyCompanyName.MyProjectName private readonly IAbpApplicationWithExternalServiceProvider _application; public App() - { - _host = Host - .CreateDefaultBuilder(null) - .UseAutofac() - .UseSerilog() - .ConfigureServices((hostContext, services) => - { - services.AddApplication(); - }).Build(); - _application = _host.Services.GetService(); - } - - protected async override void OnStartup(StartupEventArgs e) { Log.Logger = new LoggerConfiguration() #if DEBUG @@ -47,6 +29,12 @@ namespace MyCompanyName.MyProjectName .WriteTo.Async(c => c.File("Logs/logs.txt")) .CreateLogger(); + _host = CreateHostBuilder(); + _application = _host.Services.GetService(); + } + + protected override async void OnStartup(StartupEventArgs e) + { try { Log.Information("Starting WPF host."); @@ -60,22 +48,31 @@ namespace MyCompanyName.MyProjectName { Log.Fatal(ex, "Host terminated unexpectedly!"); } - finally - { - Log.CloseAndFlush(); - } } - protected async override void OnExit(ExitEventArgs e) + protected override async void OnExit(ExitEventArgs e) { _application.Shutdown(); await _host.StopAsync(); _host.Dispose(); + Log.CloseAndFlush(); } private void Initialize(IServiceProvider serviceProvider) { _application.Initialize(serviceProvider); } + + private IHost CreateHostBuilder() + { + return Host + .CreateDefaultBuilder(null) + .UseAutofac() + .UseSerilog() + .ConfigureServices((hostContext, services) => + { + services.AddApplication(); + }).Build(); + } } } diff --git a/templates/wpf/src/MyCompanyName.MyProjectName/MainWindow.xaml.cs b/templates/wpf/src/MyCompanyName.MyProjectName/MainWindow.xaml.cs index be1004415d..a8244aa270 100644 --- a/templates/wpf/src/MyCompanyName.MyProjectName/MainWindow.xaml.cs +++ b/templates/wpf/src/MyCompanyName.MyProjectName/MainWindow.xaml.cs @@ -1,17 +1,5 @@ using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; using System.Windows; -using System.Windows.Controls; -using System.Windows.Data; -using System.Windows.Documents; -using System.Windows.Input; -using System.Windows.Media; -using System.Windows.Media.Imaging; -using System.Windows.Navigation; -using System.Windows.Shapes; namespace MyCompanyName.MyProjectName { diff --git a/templates/wpf/src/MyCompanyName.MyProjectName/MyCompanyName.MyProjectName.csproj b/templates/wpf/src/MyCompanyName.MyProjectName/MyCompanyName.MyProjectName.csproj index c1a57201f4..75a7074db5 100644 --- a/templates/wpf/src/MyCompanyName.MyProjectName/MyCompanyName.MyProjectName.csproj +++ b/templates/wpf/src/MyCompanyName.MyProjectName/MyCompanyName.MyProjectName.csproj @@ -14,7 +14,7 @@ - +