├── .github ├── FUNDING.yml └── workflows │ └── build.yml ├── .gitignore ├── .gitmodules ├── Directory.Build.props ├── Directory.Packages.props ├── LICENSE ├── OrchardCoreContrib.Modules.sln ├── README.md ├── images ├── OCC.png └── icon.png ├── src ├── OrchardCoreContrib.Apis.Swagger │ ├── Manifest.cs │ ├── OrchardCoreContrib.Apis.Swagger.csproj │ ├── README.md │ ├── Startup.cs │ ├── SwaggerApiDefinition.cs │ └── SwaggerUIStratup.cs ├── OrchardCoreContrib.ContentLocalization │ ├── AdminMenu.cs │ ├── Controllers │ │ └── AdminController.cs │ ├── DefaultContentLocalizationManager.cs │ ├── Liquid │ │ ├── ArabToLatFilter.cs │ │ └── CyrToLatFilter.cs │ ├── Manifest.cs │ ├── OrchardCoreContrib.ContentLocalization.csproj │ ├── README.md │ ├── Services │ │ ├── ITransliterationService.cs │ │ └── TransliterationService.cs │ ├── Startup.cs │ ├── ViewModels │ │ └── LocalizationMatrixViewModel.cs │ └── Views │ │ ├── Admin │ │ └── LocalizationMatrix.cshtml │ │ └── _ViewImports.cshtml ├── OrchardCoreContrib.ContentPermissions │ ├── Constants.cs │ ├── Drivers │ │ ├── ContentPermissionsPartDisplayDriver.cs │ │ └── ContentPermissionsPartSettingsDisplayDriver.cs │ ├── Extensions │ │ └── HttpReponseExtensions.cs │ ├── Manifest.cs │ ├── Migrations │ │ └── ContentPermissionsPartMigration.cs │ ├── Models │ │ ├── ContentPermissionsPart.cs │ │ └── ContentPermissionsPartSettings.cs │ ├── OrchardCoreContrib.ContentPermissions.csproj │ ├── README.md │ ├── Services │ │ ├── ContentPermissionsServices.cs │ │ └── IContentPermissionsService.cs │ ├── Startup.cs │ ├── ViewModels │ │ ├── ContentPermissionsPartSettingsViewModel.cs │ │ └── ContentPermissionsPartViewModel.cs │ ├── Views │ │ ├── ContentPermissionsPart.Edit.cshtml │ │ ├── ContentPermissionsPartSettings.Edit.cshtml │ │ └── _ViewImports.cshtml │ └── placement.json ├── OrchardCoreContrib.ContentPreview │ ├── Constants.cs │ ├── Controllers │ │ └── PreviewController.cs │ ├── Extensions │ │ └── PagePreviewOrchardCoreExtensions.cs │ ├── Manifest.cs │ ├── OrchardCoreContrib.ContentPreview.csproj │ ├── PagePreviewMiddleware.cs │ ├── README.md │ ├── RequestDestination.cs │ ├── ResourceManagementOptionsConfiguration.cs │ ├── Startup.cs │ ├── Views │ │ ├── Preview │ │ │ ├── Index.cshtml │ │ │ └── _PagePreviewBar.cshtml │ │ └── _ViewImports.cshtml │ └── wwwroot │ │ ├── Scripts │ │ └── PagePreviewBar.js │ │ └── Styles │ │ └── PagePreviewBar.css ├── OrchardCoreContrib.DataLocalization │ ├── AdminMenu.cs │ ├── Controllers │ │ └── AdminController.cs │ ├── DataTranslationProvider.cs │ ├── Manifest.cs │ ├── Models │ │ ├── Translation.cs │ │ └── TranslationsDocument.cs │ ├── OrchardCoreContrib.DataLocalization.csproj │ ├── README.md │ ├── Services │ │ ├── ContentFieldResourceStringProvider.cs │ │ ├── ContentTypeResourceStringProvider.cs │ │ └── TranslationsManager.cs │ ├── Startup.cs │ ├── ViewModels │ │ ├── ContentFieldResourcesViewModel.cs │ │ └── ContentTypeResourcesViewModel.cs │ └── Views │ │ ├── Admin │ │ ├── ManageContentFieldResources.cshtml │ │ └── ManageContentTypeResources.cshtml │ │ └── _ViewImports.cshtml ├── OrchardCoreContrib.Diagnostics.Elm │ ├── Manifest.cs │ ├── OrchardCoreContrib.Diagnostics.Elm.csproj │ ├── README.md │ └── Startup.cs ├── OrchardCoreContrib.Email.Gmail │ ├── AdminMenu.cs │ ├── Controllers │ │ └── AdminController.cs │ ├── Drivers │ │ └── GmailSettingsDisplayDriver.cs │ ├── GmailDefaults.cs │ ├── GmailSettings.cs │ ├── Manifest.cs │ ├── OrchardCoreContrib.Email.Gmail.csproj │ ├── Permissions.cs │ ├── README.md │ ├── Services │ │ ├── GmailService.cs │ │ └── GmailSettingsConfiguration.cs │ ├── Startup.cs │ ├── ViewModels │ │ └── GmailSettingsViewModel.cs │ └── Views │ │ ├── Admin │ │ └── Index.cshtml │ │ ├── GmailSettings.Edit.cshtml │ │ ├── GmailSettings.TestButton.cshtml │ │ ├── NavigationItemText-gmail.Id.cshtml │ │ └── _ViewImports.cshtml ├── OrchardCoreContrib.Email.Hotmail │ ├── AdminMenu.cs │ ├── Controllers │ │ └── AdminController.cs │ ├── Drivers │ │ └── HotmailSettingsDisplayDriver.cs │ ├── HotmailDefaults.cs │ ├── HotmailSettings.cs │ ├── Manifest.cs │ ├── OrchardCoreContrib.Email.Hotmail.csproj │ ├── Permissions.cs │ ├── README.md │ ├── Services │ │ ├── HotmailService.cs │ │ └── HotmailSettingsConfiguration.cs │ ├── Startup.cs │ ├── ViewModels │ │ └── HotmailSettingsViewModel.cs │ └── Views │ │ ├── Admin │ │ └── Index.cshtml │ │ ├── HotmailSettings.Edit.cshtml │ │ ├── HotmailSettings.TestButton.cshtml │ │ ├── NavigationItemText-hotmail.Id.cshtml │ │ └── _ViewImports.cshtml ├── OrchardCoreContrib.Email.SendGrid │ ├── AdminMenu.cs │ ├── Controllers │ │ └── AdminController.cs │ ├── Drivers │ │ └── SendGridSettingsDisplayDriver.cs │ ├── HealthChecks │ │ ├── Extensions │ │ │ └── SendGridHealthCheckExtensions.cs │ │ ├── SendGridHealthCheck.cs │ │ └── Startup.cs │ ├── Manifest.cs │ ├── OrchardCoreContrib.Email.SendGrid.csproj │ ├── Permissions.cs │ ├── README.md │ ├── SendGridSettings.cs │ ├── Services │ │ ├── SendGridService.cs │ │ └── SendGridSettingsConfiguration.cs │ ├── Startup.cs │ ├── ViewModels │ │ └── SendGridSettingsViewModel.cs │ └── Views │ │ ├── Admin │ │ └── Index.cshtml │ │ ├── NavigationItemText-sendgrid.Id.cshtml │ │ ├── SendGridSettings.Edit.cshtml │ │ ├── SendGridSettings.TestButton.cshtml │ │ └── _ViewImports.cshtml ├── OrchardCoreContrib.Email.Yahoo │ ├── AdminMenu.cs │ ├── Controllers │ │ └── AdminController.cs │ ├── Drivers │ │ └── YahooSettingsDisplayDriver.cs │ ├── Manifest.cs │ ├── OrchardCoreContrib.Email.Yahoo.csproj │ ├── Permissions.cs │ ├── README.md │ ├── Services │ │ ├── YahooService.cs │ │ └── YahooSettingsConfiguration.cs │ ├── Startup.cs │ ├── ViewModels │ │ └── YahooSettingsViewModel.cs │ ├── Views │ │ ├── Admin │ │ │ └── Index.cshtml │ │ ├── NavigationItemText-yahoo.Id.cshtml │ │ ├── YahooSettings.Edit.cshtml │ │ ├── YahooSettings.TestButton.cshtml │ │ └── _ViewImports.cshtml │ ├── YahooDefaults.cs │ └── YahooSettings.cs ├── OrchardCoreContrib.Garnet │ ├── Constants.cs │ ├── Extensions │ │ └── GarnetClientExtensions.cs │ ├── GarnetCache.cs │ ├── GarnetClientFactory.cs │ ├── GarnetKeyManagementOptionsSetup.cs │ ├── GarnetTagCache.cs │ ├── GarnetXmlRepository.cs │ ├── HealthChecks │ │ ├── Extensions │ │ │ └── GarnetHealthCheckExtensions.cs │ │ ├── GarnetHealthCheck.cs │ │ └── Startup.cs │ ├── Manifest.cs │ ├── OrchardCoreContrib.Garnet.csproj │ ├── README.md │ ├── Services │ │ ├── GarnetBus.cs │ │ └── GarnetService.cs │ └── Startups │ │ ├── GarnetBusStartup.cs │ │ ├── GarnetCacheStartup.cs │ │ ├── GarnetDataProtectionStartup.cs │ │ └── Startup.cs ├── OrchardCoreContrib.Gdpr │ ├── AdminMenu.cs │ ├── Controllers │ │ └── HomeController.cs │ ├── CookieConsentFilter.cs │ ├── Drivers │ │ └── GdprSettingsDisplayDriver.cs │ ├── GdprSettings.cs │ ├── Manifest.cs │ ├── OrchardCoreContrib.Gdpr.csproj │ ├── Permissions.cs │ ├── Startup.cs │ └── Views │ │ ├── CookieConsent.cshtml │ │ ├── GdprSettings.Edit.cshtml │ │ ├── Home │ │ └── Privacy.cshtml │ │ ├── NavigationItemText-gdpr.Id.cshtml │ │ └── _ViewImports.cshtml ├── OrchardCoreContrib.GoogleMaps │ ├── AdminMenu.cs │ ├── Drivers │ │ ├── GoogleMapPartDisplayDriver.cs │ │ └── GoogleMapsSettingsDisplayDriver.cs │ ├── GoogleMapsDefaults.cs │ ├── GoogleMapsSettings.cs │ ├── Manifest.cs │ ├── Migrations │ │ └── 0001_CreateGoogleMapPart.cs │ ├── Models │ │ └── GoogleMapPart.cs │ ├── OrchardCoreContrib.GoogleMaps.csproj │ ├── Permissions.cs │ ├── README.md │ ├── Startup.cs │ ├── ViewModels │ │ ├── GoogleMapPartViewModel.cs │ │ └── GoogleMapsSettingsViewModel.cs │ └── Views │ │ ├── GoogleMapPart.Edit.cshtml │ │ ├── GoogleMapPart.cshtml │ │ ├── GoogleMapsSettings.Edit.cshtml │ │ ├── NavigationItemText-googlemaps.Id.cshtml │ │ └── _ViewImports.cshtml ├── OrchardCoreContrib.Gravatar │ ├── GravatarConstants.cs │ ├── GravatarOptions.cs │ ├── GravatarRating.cs │ ├── Liquid │ │ └── GravatarFilter.cs │ ├── Manifest.cs │ ├── OrchardCoreContrib.Gravatar.csproj │ ├── README.md │ ├── Services │ │ ├── GravatarService.cs │ │ └── IGravatarService.cs │ ├── Startup.cs │ ├── TagHelpers │ │ └── GravatarTagHelper.cs │ └── Views │ │ ├── UserMenu.cshtml │ │ └── _ViewImports.cshtml ├── OrchardCoreContrib.HealthChecks │ ├── Manifest.cs │ ├── OrchardCoreContrib.HealthChecks.csproj │ ├── README.md │ └── Startup.cs ├── OrchardCoreContrib.Html │ ├── Controllers │ │ └── AdminController.cs │ ├── Manifest.cs │ ├── OrchardCoreContrib.Html.csproj │ ├── README.md │ ├── Startup.cs │ ├── Views │ │ ├── Admin │ │ │ └── Index.cshtml │ │ ├── HtmlBodyPart-GrapeJS.Edit.cshtml │ │ ├── HtmlBodyPart-GrapeJS.Option.cshtml │ │ └── _ViewImports.cshtml │ └── wwwroot │ │ ├── Scripts │ │ ├── grapes-editor.js │ │ ├── grapes.min.js │ │ └── grapesjs-preset-webpage.min.js │ │ ├── Styles │ │ ├── grapes-editor.css │ │ ├── grapes.min.css │ │ └── grapesjs-preset-webpage.min.css │ │ └── fonts │ │ └── main-fonts.woff ├── OrchardCoreContrib.Liquid │ ├── Environment.cs │ ├── Manifest.cs │ ├── OrchardCoreContrib.Liquid.csproj │ ├── README.md │ └── Startup.cs ├── OrchardCoreContrib.Modules.Web │ ├── MigrationUpdater.cs │ ├── OrchardCoreContrib.Modules.Web.csproj │ ├── Program.cs │ ├── Properties │ │ └── launchSettings.json │ ├── Recipes │ │ └── OCC.recipe.json │ ├── Startup.cs │ ├── Views │ │ └── Content-BlogPost.liquid │ ├── appsettings.Development.json │ ├── appsettings.json │ └── wwwroot │ │ └── .placeholder ├── OrchardCoreContrib.ReverseProxy.Yarp │ ├── Manifest.cs │ ├── OrchardCoreContrib.ReverseProxy.Yarp.csproj │ ├── README.md │ └── Startup.cs ├── OrchardCoreContrib.Sms.Azure │ ├── AdminMenu.cs │ ├── AzureSmsPermissionProvider.cs │ ├── AzureSmsPermissions.cs │ ├── AzureSmsSettings.cs │ ├── Controllers │ │ └── AdminController.cs │ ├── Drivers │ │ └── AzureSmsSettingsDisplayDriver.cs │ ├── Manifest.cs │ ├── OrchardCoreContrib.Sms.Azure.csproj │ ├── README.md │ ├── Services │ │ └── AzureSmsService.cs │ ├── Startup.cs │ ├── ViewModels │ │ └── AzureSmsSettingsViewModel.cs │ └── Views │ │ ├── Admin │ │ └── Index.cshtml │ │ ├── AzureSmsSettings.Edit.cshtml │ │ ├── AzureSmsSettings.TestButton.cshtml │ │ ├── NavigationItemText-azuresms.Id.cshtml │ │ └── _ViewImports.cshtml ├── OrchardCoreContrib.System │ ├── AdminMenu.cs │ ├── Controllers │ │ └── AdminController.cs │ ├── Drivers │ │ └── SystemSettingsDisplayDriver.cs │ ├── Extensions │ │ └── ApplicationBuilderExtensions.cs │ ├── HealthChecks │ │ ├── Extensions │ │ │ └── SystemUpdatesHealthCheckExtensions.cs │ │ └── SystemUpdatesHealthCheck.cs │ ├── MaintenanceAdminMenu.cs │ ├── Manifest.cs │ ├── Models │ │ └── SystemUpdate.cs │ ├── OrchardCoreContrib.System.csproj │ ├── Permissions.cs │ ├── README.md │ ├── Services │ │ ├── ISystemUpdateService.cs │ │ ├── MaintenanceRedirectMiddleware.cs │ │ ├── SystemInformation.cs │ │ └── SystemUpdateService.cs │ ├── Startup.cs │ ├── SystemMaintenanceConstants.cs │ ├── SystemSettings.cs │ ├── SystemUpdatesConstants.cs │ ├── UpdatesAdminMenu.cs │ ├── ViewModels │ │ ├── AboutViewModel.cs │ │ └── UpdatesViewModel.cs │ └── Views │ │ ├── Admin │ │ ├── About.cshtml │ │ └── Updates.cshtml │ │ ├── NavigationItemText-info.Id.cshtml │ │ ├── NavigationItemText-system.Id.cshtml │ │ ├── NavigationItemText-updates.Id.cshtml │ │ ├── SystemSettings.Edit.cshtml │ │ └── _ViewImports.cshtml ├── OrchardCoreContrib.Tenants │ ├── HealthChecks │ │ ├── Extensions │ │ │ └── TenantsHealthCheckExtensions.cs │ │ ├── Startup.cs │ │ └── TenantsHealthCheck.cs │ ├── Manifest.cs │ ├── OrchardCoreContrib.Tenants.csproj │ └── README.md ├── OrchardCoreContrib.Themes.Admin │ ├── Assets.json │ ├── Assets │ │ ├── js │ │ │ ├── Sortable.js │ │ │ ├── admin.js │ │ │ ├── darkmode.js │ │ │ ├── header │ │ │ │ └── userPreferencesLoader.js │ │ │ ├── menu.js │ │ │ ├── removeDiacritics.js │ │ │ ├── resizeDetector.js │ │ │ └── userPreferencesPersistor.js │ │ └── scss │ │ │ ├── admin.scss │ │ │ ├── mixins │ │ │ ├── _cursors.scss │ │ │ ├── _grid.scss │ │ │ ├── _sizes.scss │ │ │ └── _word-wrap.scss │ │ │ └── modules │ │ │ ├── _layout.scss │ │ │ ├── admin │ │ │ ├── _bootstrap-select.scss │ │ │ ├── _codemirror.scss │ │ │ ├── _forms.scss │ │ │ ├── _grid.scss │ │ │ ├── _jquery-ui.scss │ │ │ ├── _list.scss │ │ │ ├── _login.scss │ │ │ ├── _messages.scss │ │ │ ├── _monaco.scss │ │ │ ├── _navbar.scss │ │ │ ├── _nouislider.scss │ │ │ ├── _pager.scss │ │ │ ├── _root.scss │ │ │ ├── _sidebar-menu.scss │ │ │ ├── _tabs.scss │ │ │ ├── _trumbowyg.scss │ │ │ └── _validations.scss │ │ │ └── theme │ │ │ ├── darkmode │ │ │ ├── _admin-variables.scss │ │ │ ├── _bootswatch.scss │ │ │ ├── _forms.scss │ │ │ └── _variables.scss │ │ │ └── default │ │ │ ├── _admin-variables.scss │ │ │ ├── _bootswatch.scss │ │ │ ├── _forms.scss │ │ │ └── _variables.scss │ ├── Manifest.cs │ ├── OrchardCoreContrib.Themes.Admin.csproj │ ├── Recipes │ │ ├── blank.recipe.json │ │ └── headless.recipe.json │ ├── ResourceManifestOptionsConfiguration.cs │ ├── Startup.cs │ ├── Views │ │ ├── Layout-Login.cshtml │ │ ├── Layout.cshtml │ │ ├── Message.cshtml │ │ ├── Navigation-admin.cshtml │ │ ├── NavigationItem-admin.cshtml │ │ ├── NavigationItemLink-admin.cshtml │ │ ├── NavigationItemText.cshtml │ │ ├── OrchardCore.Users │ │ │ └── Account │ │ │ │ └── Login.cshtml │ │ └── _ViewImports.cshtml │ ├── package-lock.json │ ├── package.json │ └── wwwroot │ │ ├── Theme.png │ │ ├── css │ │ ├── TheAdmin.css │ │ └── TheAdmin.min.css │ │ ├── favicon.ico │ │ ├── fonts │ │ └── material-icons │ │ │ ├── material-icons-outlined.woff │ │ │ ├── material-icons-outlined.woff2 │ │ │ ├── material-icons-round.woff │ │ │ ├── material-icons-round.woff2 │ │ │ ├── material-icons-sharp.woff │ │ │ ├── material-icons-sharp.woff2 │ │ │ ├── material-icons-two-tone.woff │ │ │ ├── material-icons-two-tone.woff2 │ │ │ ├── material-icons.css │ │ │ ├── material-icons.min.css │ │ │ ├── material-icons.woff │ │ │ └── material-icons.woff2 │ │ ├── js │ │ ├── TheAdmin-header.js │ │ ├── TheAdmin-header.min.js │ │ ├── TheAdmin.js │ │ └── TheAdmin.min.js │ │ ├── logo-white.png │ │ └── logo.png ├── OrchardCoreContrib.UserGroups │ ├── AdminMenu.cs │ ├── Controllers │ │ └── AdminController.cs │ ├── Drivers │ │ ├── UserGroupsDisplayDriver.cs │ │ └── UserGroupsListPartDisplayDriver.cs │ ├── Extensions │ │ ├── UserExtensions.cs │ │ └── UserGroupsManagerExtensions.cs │ ├── Indexes │ │ ├── UserByGroupNameIndex.cs │ │ └── UserByUserGroupNameIndexProvider.cs │ ├── Manifest.cs │ ├── Migrations.cs │ ├── Models │ │ ├── UserGroup.cs │ │ ├── UserGroupDocument.cs │ │ └── UserGroupsListPart.cs │ ├── OrchardCoreContrib.UserGroups.csproj │ ├── Permissions.cs │ ├── README.md │ ├── Services │ │ └── UserGroupsManager.cs │ ├── Startup.cs │ ├── UserGroupsPermissions.cs │ ├── ViewModels │ │ ├── CreateUserGroupViewModel.cs │ │ ├── EditUserGroupViewModel.cs │ │ ├── UserGroupsEditViewModel.cs │ │ ├── UserGroupsIndexViewModel.cs │ │ ├── UserGroupsListPartEditViewModel.cs │ │ ├── UserGroupsListPartViewModel.cs │ │ └── UserGroupsViewModel.cs │ └── Views │ │ ├── Admin │ │ ├── Create.cshtml │ │ ├── Edit.cshtml │ │ └── Index.cshtml │ │ ├── NavigationItemText-usergroups.Id.cshtml │ │ ├── UserGroups.Edit.cshtml │ │ ├── UserGroups.cshtml │ │ ├── UserGroupsListPart.Edit.cshtml │ │ ├── UserGroupsListPart.cshtml │ │ └── _ViewImports.cshtml ├── OrchardCoreContrib.Users │ ├── AdminMenu.cs │ ├── AvatarOptions.cs │ ├── ClaimTypesExtended.cs │ ├── Controllers │ │ └── ImpersonationController.cs │ ├── Drivers │ │ └── ImpersonationDisplayDriver.cs │ ├── Manifest.cs │ ├── OrchardCoreContrib.Users.csproj │ ├── Permissions.cs │ ├── README.md │ ├── Services │ │ ├── AvatarService.cs │ │ ├── IAvatarService.cs │ │ └── NullAvatarService.cs │ ├── Startup.cs │ └── Views │ │ ├── ImpersonationButton.cshtml │ │ ├── NavigationItemText-endImpersonation.Id.cshtml │ │ ├── UserMenu.cshtml │ │ └── _ViewImports.cshtml └── OrchardCoreContrib.ViewCount │ ├── Drivers │ └── ViewCountPartDisplayDriver.cs │ ├── Handlers │ ├── IViewCountContentHandler.cs │ ├── ViewCountContentContext.cs │ └── ViewCountContentHandlerBase.cs │ ├── Manifest.cs │ ├── Migrations.cs │ ├── Models │ └── ViewCountPart.cs │ ├── OrchardCoreContrib.ViewCount.csproj │ ├── Services │ ├── IViewCountService.cs │ └── ViewCountService.cs │ ├── Startup.cs │ ├── ViewModels │ └── ViewCountPartViewModel.cs │ └── Views │ ├── ViewCountPart.cshtml │ └── _ViewImports.cshtml └── test ├── OrchardCoreContrib.ContentPermissions.Tests ├── OrchardCoreContrib.ContentPermissions.Tests.csproj └── Services │ └── ContentPermissionsServicesTests.cs ├── OrchardCoreContrib.Garnet.Tests ├── Extensions │ └── GarnetClientExtensionsTests.cs ├── GarnetCacheTests.cs ├── GarnetTagCacheTests.cs ├── GarnetXmlRepositoryTests.cs ├── OrchardCoreContrib.Garnet.Tests.csproj ├── Services │ └── GarnetBusTests.cs ├── TestBase.cs └── Utilities.cs ├── OrchardCoreContrib.Modules.Tests ├── ContentLocalization │ └── TransliterationServiceTests.cs ├── Email │ ├── Gmail │ │ └── GmailServiceTests.cs │ ├── Hotmail │ │ └── HotmailServiceTests.cs │ ├── SendGrid │ │ └── SendGridServiceTests.cs │ └── Yahoo │ │ └── YahooServiceTests.cs ├── OrchardCoreContrib.Modules.Tests.csproj └── appsettings.json └── OrchardCoreContrib.UserGroups.Tests ├── Extensions └── UserGroupsManagerExtensionsTests.cs ├── Helpers └── UserGroupsManagerHelper.cs ├── OrchardCoreContrib.UserGroups.Tests.csproj └── Services └── UserGroupsManagerTests.cs /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | github: [hishamco] 2 | open_collective: occ 3 | custom: ["https://paypal.me/hbinateya"] 4 | -------------------------------------------------------------------------------- /.github/workflows/build.yml: -------------------------------------------------------------------------------- 1 | name: Orchard Core Contrib Modules 2 | 3 | on: 4 | pull_request: 5 | branches: [ main ] 6 | 7 | env: 8 | DOTNET_SKIP_FIRST_TIME_EXPERIENCE: true 9 | DOTNET_CLI_TELEMETRY_OPTOUT: true 10 | 11 | jobs: 12 | build: 13 | name: Build windows-latest 14 | runs-on: windows-latest 15 | steps: 16 | - uses: actions/checkout@v3 17 | - name: Setup .NET Core 18 | uses: actions/setup-dotnet@v3.2.0 19 | with: 20 | dotnet-version: 8.0.* 21 | - name: Install Dependencies 22 | run: dotnet restore 23 | - name: Build 24 | run: dotnet build --configuration Release --no-restore 25 | - name: Test 26 | run: dotnet test --no-restore --verbosity normal 27 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OrchardCoreContrib/OrchardCoreContrib.Modules/3a124143f9e750c2d34535492c353f555dbe1d4b/.gitmodules -------------------------------------------------------------------------------- /Directory.Build.props: -------------------------------------------------------------------------------- 1 |  2 | 3 | net8.0 4 | latest 5 | enable 6 | disable 7 | false 8 | true 9 | 10 | 11 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | BSD 3-Clause License 2 | 3 | Copyright (c) 2023, Orchard Core Contrib 4 | 5 | Redistribution and use in source and binary forms, with or without 6 | modification, are permitted provided that the following conditions are met: 7 | 8 | 1. Redistributions of source code must retain the above copyright notice, this 9 | list of conditions and the following disclaimer. 10 | 11 | 2. Redistributions in binary form must reproduce the above copyright notice, 12 | this list of conditions and the following disclaimer in the documentation 13 | and/or other materials provided with the distribution. 14 | 15 | 3. Neither the name of the copyright holder nor the names of its 16 | contributors may be used to endorse or promote products derived from 17 | this software without specific prior written permission. 18 | 19 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 20 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 22 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 23 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 25 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 26 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 27 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 28 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 | -------------------------------------------------------------------------------- /images/OCC.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OrchardCoreContrib/OrchardCoreContrib.Modules/3a124143f9e750c2d34535492c353f555dbe1d4b/images/OCC.png -------------------------------------------------------------------------------- /images/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OrchardCoreContrib/OrchardCoreContrib.Modules/3a124143f9e750c2d34535492c353f555dbe1d4b/images/icon.png -------------------------------------------------------------------------------- /src/OrchardCoreContrib.Apis.Swagger/Manifest.cs: -------------------------------------------------------------------------------- 1 | using OrchardCore.Modules.Manifest; 2 | using ManifestConstants = OrchardCoreContrib.Modules.Manifest.ManifestConstants; 3 | 4 | [assembly: Module( 5 | Author = ManifestConstants.Author, 6 | Website = ManifestConstants.Website, 7 | Version = "1.4.1", 8 | Category = "Api" 9 | )] 10 | 11 | [assembly: Feature( 12 | Id = "OrchardCoreContrib.Apis.Swagger", 13 | Name = "Swagger", 14 | Description = "Enables Swagger for OrchardCore APIs." 15 | )] 16 | 17 | [assembly: Feature( 18 | Id = "OrchardCoreContrib.Apis.Swagger.UI", 19 | Name = "Swagger UI", 20 | Description = "Enables Swagger UI for OrchardCore APIs.", 21 | Dependencies = new[] { "OrchardCoreContrib.Apis.Swagger" } 22 | )] 23 | -------------------------------------------------------------------------------- /src/OrchardCoreContrib.Apis.Swagger/Startup.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.AspNetCore.Builder; 2 | using Microsoft.AspNetCore.Routing; 3 | using Microsoft.Extensions.DependencyInjection; 4 | using OrchardCore.Modules; 5 | using OrchardCoreContrib.OpenApi.Abstractions; 6 | using System; 7 | 8 | namespace OrchardCoreContrib.Apis.Swagger 9 | { 10 | /// 11 | /// Represensts a startup point to register the required services by Swagger module. 12 | /// 13 | public class Startup : StartupBase 14 | { 15 | /// 16 | public override void ConfigureServices(IServiceCollection services) 17 | { 18 | var swaggerApiDefinition = new SwaggerApiDefinition(); 19 | 20 | services.AddTransient(sp => swaggerApiDefinition); 21 | 22 | services.AddSwaggerGen(options => 23 | { 24 | options.SwaggerDoc(swaggerApiDefinition.Version, swaggerApiDefinition.Info); 25 | }); 26 | } 27 | 28 | /// 29 | public override void Configure(IApplicationBuilder builder, IEndpointRouteBuilder routes, IServiceProvider serviceProvider) 30 | => builder.UseSwagger(); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/OrchardCoreContrib.Apis.Swagger/SwaggerApiDefinition.cs: -------------------------------------------------------------------------------- 1 | using OrchardCoreContrib.OpenApi.Abstractions; 2 | 3 | namespace OrchardCoreContrib.Apis.Swagger 4 | { 5 | /// 6 | /// Respresents a swagger API definition for Orchard Core. 7 | /// 8 | public class SwaggerApiDefinition : OpenApiDefinition 9 | { 10 | /// 11 | public override string Name => "Orchard Core APIs Docs"; 12 | 13 | /// 14 | public override string Version => "v1.0.0"; 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/OrchardCoreContrib.Apis.Swagger/SwaggerUIStratup.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.AspNetCore.Builder; 2 | using Microsoft.AspNetCore.Routing; 3 | using Microsoft.Extensions.DependencyInjection; 4 | using OrchardCore.Environment.Shell; 5 | using OrchardCore.Modules; 6 | using OrchardCoreContrib.OpenApi.Abstractions; 7 | using System; 8 | 9 | namespace OrchardCoreContrib.Apis.Swagger 10 | { 11 | /// 12 | /// Represensts a startup point to register the required services by Swagger UI feature. 13 | /// 14 | [Feature("OrchardCoreContrib.Apis.Swagger.UI")] 15 | public class SwaggerUIStratup : StartupBase 16 | { 17 | /// 18 | public override void Configure(IApplicationBuilder builder, IEndpointRouteBuilder routes, IServiceProvider serviceProvider) 19 | { 20 | builder.UseSwaggerUI(options => 21 | { 22 | var swaggerApiDefinition = serviceProvider.GetService(); 23 | var shellSettings = serviceProvider.GetService(); 24 | var tenantUrlPrefix = String.IsNullOrEmpty(shellSettings.RequestUrlPrefix) 25 | ? shellSettings.RequestUrlPrefix 26 | : shellSettings.RequestUrlPrefix + "/"; 27 | 28 | options.SwaggerEndpoint($"/{tenantUrlPrefix}swagger/{swaggerApiDefinition.Version}/swagger.json", $"{swaggerApiDefinition.Name} {swaggerApiDefinition.Version}"); 29 | }); 30 | } 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/OrchardCoreContrib.ContentLocalization/AdminMenu.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.Extensions.Localization; 2 | using OrchardCore.Modules; 3 | using OrchardCore.Navigation; 4 | 5 | namespace OrchardCoreContrib.ContentLocalization 6 | { 7 | using OrchardCoreContrib.Navigation; 8 | 9 | [Feature("OrchardCoreContrib.ContentLocalization.LocalizationMatrix")] 10 | public class AdminMenu : AdminNavigationProvider 11 | { 12 | private readonly IStringLocalizer S; 13 | 14 | public AdminMenu(IStringLocalizer localizer) 15 | { 16 | S = localizer; 17 | } 18 | 19 | public override void BuildNavigation(NavigationBuilder builder) 20 | { 21 | builder 22 | .Add(S["Configuration"], c => c 23 | .Add(S["Settings"], s => s 24 | .Add(S["Localization"], l => l 25 | .AddClass("localization").Id("localization") 26 | .Add(S["Localization Matrix"], S["Localization Matrix"].PrefixPosition(), lm => lm 27 | .Action("LocalizationMatrix", "Admin", new { area = "OrchardCoreContrib.ContentLocalization" }) 28 | .LocalNav() 29 | ) 30 | ) 31 | ) 32 | ); 33 | } 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/OrchardCoreContrib.ContentLocalization/Controllers/AdminController.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.AspNetCore.Mvc; 2 | using OrchardCore.Localization; 3 | using OrchardCore.Modules; 4 | using OrchardCoreContrib.ContentLocalization.ViewModels; 5 | using System.Threading.Tasks; 6 | 7 | namespace OrchardCoreContrib.ContentLocalization.Controllers 8 | { 9 | [Feature("OrchardCoreContrib.ContentLocalization.LocalizationMatrix")] 10 | public class AdminController : Controller 11 | { 12 | private readonly IContentLocalizationManager _contentLocalizationManager; 13 | private readonly ILocalizationService _localizationService; 14 | 15 | public AdminController(IContentLocalizationManager contentLocalizationManager, ILocalizationService localizationService) 16 | { 17 | _contentLocalizationManager = contentLocalizationManager; 18 | _localizationService = localizationService; 19 | } 20 | 21 | public async Task LocalizationMatrix() 22 | { 23 | var supportedCultures = await _localizationService.GetSupportedCulturesAsync(); 24 | 25 | var localizationSets = await _contentLocalizationManager.GetSetsAsync(); 26 | 27 | return View(new LocalizationMatrixViewModel 28 | { 29 | Cultures = supportedCultures, 30 | LocalizationSets = localizationSets 31 | }); 32 | } 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/OrchardCoreContrib.ContentLocalization/Liquid/ArabToLatFilter.cs: -------------------------------------------------------------------------------- 1 | using System.Threading.Tasks; 2 | using Fluid; 3 | using Fluid.Values; 4 | using OrchardCore.Liquid; 5 | using OrchardCoreContrib.ContentLocalization.Services; 6 | using OrchardCoreContrib.ContentLocalization.Transliteration; 7 | 8 | namespace OrchardCoreContrib.ContentLocalization.Liquid; 9 | 10 | public class ArabToLatFilter(ITransliterationService transliterationService) : ILiquidFilter 11 | { 12 | public ValueTask ProcessAsync(FluidValue input, FilterArguments arguments, LiquidTemplateContext context) 13 | { 14 | var text = input.ToStringValue(); 15 | 16 | return new StringValue(transliterationService.Transliterate(TransliterateScript.Arabic, text)); 17 | } 18 | } -------------------------------------------------------------------------------- /src/OrchardCoreContrib.ContentLocalization/Liquid/CyrToLatFilter.cs: -------------------------------------------------------------------------------- 1 | using System.Threading.Tasks; 2 | using Fluid; 3 | using Fluid.Values; 4 | using OrchardCore.Liquid; 5 | using OrchardCoreContrib.ContentLocalization.Services; 6 | using OrchardCoreContrib.ContentLocalization.Transliteration; 7 | 8 | namespace OrchardCoreContrib.ContentLocalization.Liquid; 9 | 10 | public class CyrToLatFilter(ITransliterationService transliterationService) : ILiquidFilter 11 | { 12 | public ValueTask ProcessAsync(FluidValue input, FilterArguments arguments, LiquidTemplateContext context) 13 | { 14 | var text = input.ToStringValue(); 15 | 16 | return new StringValue(transliterationService.Transliterate(TransliterateScript.Cyrillic, text)); 17 | } 18 | } -------------------------------------------------------------------------------- /src/OrchardCoreContrib.ContentLocalization/Manifest.cs: -------------------------------------------------------------------------------- 1 | using OrchardCore.Modules.Manifest; 2 | using ManifestConstants = OrchardCoreContrib.Modules.Manifest.ManifestConstants; 3 | 4 | [assembly: Module( 5 | Name = "Content Localization", 6 | Author = ManifestConstants.Author, 7 | Website = ManifestConstants.Website, 8 | Version = "1.3.1", 9 | Category = "Internationalization" 10 | )] 11 | 12 | [assembly: Feature( 13 | Id = "OrchardCoreContrib.ContentLocalization.LocalizationMatrix", 14 | Name = "Localization Matrix", 15 | Description = "Provides a matrix shows the localized content per culture.", 16 | Dependencies = new[] { "OrchardCoreContrib.ContentLocalization", "OrchardCore.ContentLocalization" }, 17 | Category = "Internationalization" 18 | )] 19 | 20 | [assembly: Feature( 21 | Id = "OrchardCoreContrib.ContentLocalization.Transliteration", 22 | Name = "Transliteration", 23 | Description = "Provides a type of conversion of a text from one script to another that involves swapping letters.", 24 | Dependencies = new[] { "OrchardCoreContrib.ContentLocalization" }, 25 | Category = "Internationalization" 26 | )] -------------------------------------------------------------------------------- /src/OrchardCoreContrib.ContentLocalization/Services/ITransliterationService.cs: -------------------------------------------------------------------------------- 1 | using OrchardCoreContrib.ContentLocalization.Transliteration; 2 | 3 | namespace OrchardCoreContrib.ContentLocalization.Services; 4 | 5 | public interface ITransliterationService 6 | { 7 | string Transliterate(TransliterateScript script, string text); 8 | } 9 | -------------------------------------------------------------------------------- /src/OrchardCoreContrib.ContentLocalization/Services/TransliterationService.cs: -------------------------------------------------------------------------------- 1 | using OrchardCoreContrib.ContentLocalization.Transliteration; 2 | using System; 3 | 4 | namespace OrchardCoreContrib.ContentLocalization.Services; 5 | 6 | public class TransliterationService : ITransliterationService 7 | { 8 | private readonly ITransliterateRuleProvider _transliterateRuleProvider; 9 | 10 | public TransliterationService(ITransliterateRuleProvider transliterateRuleProvider) 11 | { 12 | _transliterateRuleProvider = transliterateRuleProvider; 13 | } 14 | 15 | public string Transliterate(TransliterateScript script, string text) 16 | { 17 | if (string.IsNullOrEmpty(text)) 18 | { 19 | throw new ArgumentException($"'{nameof(text)}' cannot be null or empty.", nameof(text)); 20 | } 21 | 22 | if (_transliterateRuleProvider.TryGetRule(script, out var rule)) 23 | { 24 | var mappings = rule.Invoke(); 25 | 26 | var result = String.Empty; 27 | foreach (var c in text) 28 | { 29 | var key = c.ToString(); 30 | if (!mappings.TryGetValue(key, out var value)) 31 | { 32 | value = key; 33 | } 34 | 35 | result += value; 36 | } 37 | 38 | return result; 39 | } 40 | 41 | return text; 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /src/OrchardCoreContrib.ContentLocalization/ViewModels/LocalizationMatrixViewModel.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | 3 | namespace OrchardCoreContrib.ContentLocalization.ViewModels 4 | { 5 | public class LocalizationMatrixViewModel 6 | { 7 | public IEnumerable Cultures { get; set; } 8 | 9 | public IEnumerable LocalizationSets { get; set; } 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /src/OrchardCoreContrib.ContentLocalization/Views/_ViewImports.cshtml: -------------------------------------------------------------------------------- 1 | @inherits OrchardCore.DisplayManagement.Razor.RazorPage 2 | @addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers 3 | @addTagHelper *, OrchardCore.Contents.TagHelpers 4 | @addTagHelper *, OrchardCore.DisplayManagement 5 | @addTagHelper *, OrchardCore.ResourceManagement 6 | 7 | @using Microsoft.Extensions.Localization 8 | @using Microsoft.AspNetCore.Mvc.Localization -------------------------------------------------------------------------------- /src/OrchardCoreContrib.ContentPermissions/Constants.cs: -------------------------------------------------------------------------------- 1 | namespace OrchardCoreContrib.ContentPermissions; 2 | 3 | /// 4 | /// Represents a class that contains constants. 5 | /// 6 | public sealed class Constants 7 | { 8 | /// 9 | /// Represents the name of the content permissions part. 10 | /// 11 | public const string ContentPermissionsPartName = "ContentPermissionsPart"; 12 | } 13 | -------------------------------------------------------------------------------- /src/OrchardCoreContrib.ContentPermissions/Extensions/HttpReponseExtensions.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.AspNetCore.Authentication.Cookies; 2 | using Microsoft.AspNetCore.Identity; 3 | using Microsoft.Extensions.DependencyInjection; 4 | using Microsoft.Extensions.Options; 5 | 6 | namespace Microsoft.AspNetCore.Http; 7 | 8 | // TODO: Move this to OCC.Infrastructure.Abstractions 9 | internal static class HttpReponseExtensions 10 | { 11 | public static void RedirectToAccessDeniedPage(this HttpResponse httpResponse) 12 | { 13 | var cookieAuthenticationOptions = httpResponse.HttpContext.RequestServices 14 | .GetService>() 15 | .Get(IdentityConstants.ApplicationScheme); 16 | 17 | httpResponse.StatusCode = StatusCodes.Status403Forbidden; 18 | httpResponse.Redirect(cookieAuthenticationOptions.AccessDeniedPath); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/OrchardCoreContrib.ContentPermissions/Manifest.cs: -------------------------------------------------------------------------------- 1 | using OrchardCore.Modules.Manifest; 2 | using ManifestConstants = OrchardCoreContrib.Modules.Manifest.ManifestConstants; 3 | 4 | [assembly: Module( 5 | Name = "Content Permissions", 6 | Author = ManifestConstants.Author, 7 | Website = ManifestConstants.Website, 8 | Version = "1.0.0", 9 | Description = "Provides a control to access the contents via permission(s).", 10 | Category = "Content Management" 11 | )] 12 | -------------------------------------------------------------------------------- /src/OrchardCoreContrib.ContentPermissions/Migrations/ContentPermissionsPartMigration.cs: -------------------------------------------------------------------------------- 1 | using OrchardCore.ContentManagement.Metadata; 2 | using OrchardCore.ContentManagement.Metadata.Settings; 3 | using OrchardCore.Data.Migration; 4 | 5 | namespace OrchardCoreContrib.ContentPermissions.Migrations; 6 | 7 | public class ContentPermissionsPartMigration(IContentDefinitionManager contentDefinitionManager) : DataMigration 8 | { 9 | public async Task CreateAsync() 10 | { 11 | await contentDefinitionManager.AlterPartDefinitionAsync(Constants.ContentPermissionsPartName, builder => builder 12 | .WithDisplayName("Content Permissions") 13 | .WithDescription("Controls the accessibilty for the content item by providing certain permission(s).") 14 | .Attachable() 15 | ); 16 | 17 | return 1; 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/OrchardCoreContrib.ContentPermissions/Models/ContentPermissionsPart.cs: -------------------------------------------------------------------------------- 1 | using OrchardCore.ContentManagement; 2 | 3 | namespace OrchardCoreContrib.ContentPermissions.Models; 4 | 5 | public class ContentPermissionsPart : ContentPart 6 | { 7 | public string[] Roles { get; set; } = []; 8 | 9 | public string[] Users { get; set; } = []; 10 | } 11 | -------------------------------------------------------------------------------- /src/OrchardCoreContrib.ContentPermissions/Models/ContentPermissionsPartSettings.cs: -------------------------------------------------------------------------------- 1 | namespace OrchardCoreContrib.ContentPermissions.Models; 2 | 3 | public class ContentPermissionsPartSettings 4 | { 5 | public bool EnableRoles { get; set; } 6 | 7 | public bool EnableUsers { get; set; } 8 | } 9 | -------------------------------------------------------------------------------- /src/OrchardCoreContrib.ContentPermissions/Services/IContentPermissionsService.cs: -------------------------------------------------------------------------------- 1 | using OrchardCore.ContentManagement; 2 | 3 | namespace OrchardCoreContrib.ContentPermissions.Services; 4 | 5 | /// 6 | /// Represents a contract for a service that provides content permissions. 7 | /// 8 | public interface IContentPermissionsService 9 | { 10 | /// 11 | /// Authorizes the specified content item. 12 | /// 13 | /// The content item to be checked. 14 | Task AuthorizeAsync(ContentItem contentItem); 15 | } 16 | -------------------------------------------------------------------------------- /src/OrchardCoreContrib.ContentPermissions/Startup.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.Extensions.DependencyInjection; 2 | using OrchardCore.ContentManagement; 3 | using OrchardCore.ContentManagement.Display.ContentDisplay; 4 | using OrchardCore.ContentTypes.Editors; 5 | using OrchardCore.Data.Migration; 6 | using OrchardCore.Modules; 7 | using OrchardCoreContrib.ContentPermissions.Drivers; 8 | using OrchardCoreContrib.ContentPermissions.Migrations; 9 | using OrchardCoreContrib.ContentPermissions.Models; 10 | using OrchardCoreContrib.ContentPermissions.Services; 11 | 12 | namespace OrchardCoreContrib.ContentPermissions; 13 | 14 | public sealed class Startup : StartupBase 15 | { 16 | public override void ConfigureServices(IServiceCollection services) 17 | { 18 | services.AddDataMigration(); 19 | 20 | services.AddContentPart() 21 | .UseDisplayDriver(); 22 | 23 | services.AddScoped(); 24 | services.AddScoped(); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/OrchardCoreContrib.ContentPermissions/ViewModels/ContentPermissionsPartSettingsViewModel.cs: -------------------------------------------------------------------------------- 1 | namespace OrchardCoreContrib.ContentPermissions.ViewModels; 2 | 3 | public class ContentPermissionsPartSettingsViewModel 4 | { 5 | public bool EnableRoles { get; set; } 6 | 7 | public bool EnableUsers { get; set; } 8 | } 9 | -------------------------------------------------------------------------------- /src/OrchardCoreContrib.ContentPermissions/ViewModels/ContentPermissionsPartViewModel.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.AspNetCore.Mvc.ModelBinding; 2 | 3 | namespace OrchardCoreContrib.ContentPermissions.ViewModels; 4 | 5 | public class ContentPermissionsPartViewModel 6 | { 7 | [BindNever] 8 | public IEnumerable Roles { get; set; } 9 | 10 | public string[] SelectedRoles { get; set; } 11 | 12 | [BindNever] 13 | public IEnumerable Users { get; set; } 14 | 15 | public string[] SelectedUsers { get; set; } 16 | 17 | public bool EnableRoles => Roles.Any(); 18 | 19 | public bool EnableUsers => Users.Any(); 20 | } 21 | -------------------------------------------------------------------------------- /src/OrchardCoreContrib.ContentPermissions/Views/ContentPermissionsPartSettings.Edit.cshtml: -------------------------------------------------------------------------------- 1 | @using OrchardCore.Security.Services 2 | @using OrchardCoreContrib.ContentPermissions.ViewModels 3 | @model ContentPermissionsPartSettingsViewModel 4 | 5 |
6 |
7 |
8 |
9 | 10 | 11 |
12 |
13 |
14 |
15 |
16 |
17 | 18 | 19 |
20 |
21 |
22 |
23 | -------------------------------------------------------------------------------- /src/OrchardCoreContrib.ContentPermissions/Views/_ViewImports.cshtml: -------------------------------------------------------------------------------- 1 | @inherits OrchardCore.DisplayManagement.Razor.RazorPage 2 | @addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers 3 | -------------------------------------------------------------------------------- /src/OrchardCoreContrib.ContentPermissions/placement.json: -------------------------------------------------------------------------------- 1 | { 2 | "ContentPermissionsPart_Edit": [ 3 | { 4 | "place": "Parts#Permissions:15" 5 | } 6 | ] 7 | } 8 | -------------------------------------------------------------------------------- /src/OrchardCoreContrib.ContentPreview/Constants.cs: -------------------------------------------------------------------------------- 1 | namespace OrchardCoreContrib.ContentPreview 2 | { 3 | internal class Constants 4 | { 5 | public const string PreviewSlug = "preview"; 6 | 7 | public const string PagePreviewBarFeatureId = "OrchardCoreContrib.ContentPreview.PagePreviewBar"; 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /src/OrchardCoreContrib.ContentPreview/Controllers/PreviewController.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.AspNetCore.Mvc; 2 | using OrchardCore.Modules; 3 | 4 | namespace OrchardCoreContrib.ContentPreview.Controllers 5 | { 6 | [Feature("OrchardCoreContrib.ContentPreview.PagePreviewBar")] 7 | public class PreviewController : Controller 8 | { 9 | public IActionResult Index() => View(); 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /src/OrchardCoreContrib.ContentPreview/Extensions/PagePreviewOrchardCoreExtensions.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.Extensions.DependencyInjection; 2 | using Microsoft.Extensions.Options; 3 | using OrchardCore.Admin; 4 | using OrchardCore.Environment.Shell; 5 | using OrchardCore.Users; 6 | using OrchardCoreContrib.ContentPreview; 7 | using System; 8 | 9 | namespace Microsoft.AspNetCore.Builder 10 | { 11 | /// 12 | /// Provides an extension methods for to enable page preview. 13 | /// 14 | public static class PagePreviewOrchardCoreExtensions 15 | { 16 | /// 17 | /// Uses the page preview middleware. 18 | /// 19 | /// The . 20 | public static IApplicationBuilder UsePagePreview(this IApplicationBuilder app) 21 | { 22 | if (app is null) 23 | { 24 | throw new ArgumentNullException(nameof(app)); 25 | } 26 | 27 | var adminOptions = app.ApplicationServices.GetService>(); 28 | var userOptions = app.ApplicationServices.GetService>(); 29 | var shellFeaturesManager = app.ApplicationServices.CreateScope().ServiceProvider.GetService(); 30 | 31 | app.UseMiddleware(adminOptions, userOptions, shellFeaturesManager); 32 | 33 | return app; 34 | } 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/OrchardCoreContrib.ContentPreview/Manifest.cs: -------------------------------------------------------------------------------- 1 | using OrchardCore.Modules.Manifest; 2 | using OrchardCoreContrib.ContentPreview; 3 | using ManifestConstants = OrchardCoreContrib.Modules.Manifest.ManifestConstants; 4 | 5 | [assembly: Module( 6 | Name = "Content Preview", 7 | Author = ManifestConstants.Author, 8 | Website = ManifestConstants.Website, 9 | Version = "1.3.1", 10 | Category = "Content Management" 11 | )] 12 | 13 | [assembly: Feature( 14 | Id = Constants.PagePreviewBarFeatureId, 15 | Name = "Page Preview Bar", 16 | Description = "Shows a top bar that allows you to preview the current page in desktop, tablet and mobile.", 17 | Dependencies = new[] { "OrchardCore.Resources" } 18 | )] 19 | -------------------------------------------------------------------------------- /src/OrchardCoreContrib.ContentPreview/RequestDestination.cs: -------------------------------------------------------------------------------- 1 | namespace OrchardCoreContrib.ContentPreview 2 | { 3 | /// 4 | /// Represents an enum like for request destination. 5 | /// 6 | public class RequestDestination 7 | { 8 | /// 9 | /// Request comes from document aka page. 10 | /// 11 | public readonly static string Document = "document"; 12 | 13 | /// 14 | /// Request comes from IFrame. 15 | /// 16 | public readonly static string Iframe = "iframe"; 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/OrchardCoreContrib.ContentPreview/ResourceManagementOptionsConfiguration.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.Extensions.Options; 2 | using OrchardCore.ResourceManagement; 3 | 4 | namespace OrchardCoreContrib.ContentPreview 5 | { 6 | /// 7 | /// Configure the resources that will be used in the module. 8 | /// 9 | public class ResourceManagementOptionsConfiguration : IConfigureOptions 10 | { 11 | private static readonly ResourceManifest _manifest; 12 | 13 | static ResourceManagementOptionsConfiguration() 14 | { 15 | _manifest = new ResourceManifest(); 16 | 17 | _manifest 18 | .DefineScript("page-preview-bar") 19 | .SetUrl("~/OrchardCoreContrib.ContentPreview/Scripts/PagePreviewBar.js") 20 | .SetVersion("1.0.0"); 21 | 22 | _manifest 23 | .DefineStyle("page-preview-bar") 24 | .SetUrl("~/OrchardCoreContrib.ContentPreview/Styles/PagePreviewBar.css") 25 | .SetVersion("1.0.0"); 26 | } 27 | 28 | /// 29 | public void Configure(ResourceManagementOptions options) 30 | { 31 | options.ResourceManifests.Add(_manifest); 32 | } 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/OrchardCoreContrib.ContentPreview/Startup.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.AspNetCore.Builder; 2 | using Microsoft.AspNetCore.Routing; 3 | using Microsoft.Extensions.DependencyInjection; 4 | using Microsoft.Extensions.Options; 5 | using OrchardCore.Modules; 6 | using OrchardCore.Mvc.Core.Utilities; 7 | using OrchardCore.ResourceManagement; 8 | using OrchardCoreContrib.ContentPreview.Controllers; 9 | using System; 10 | 11 | namespace OrchardCoreContrib.ContentPreview 12 | { 13 | /// 14 | /// Represents an entry point to register the page preview bar required services. 15 | /// 16 | [Feature("OrchardCoreContrib.ContentPreview.PagePreviewBar")] 17 | public class Startup : StartupBase 18 | { 19 | /// 20 | public override void ConfigureServices(IServiceCollection services) 21 | { 22 | services.AddTransient, ResourceManagementOptionsConfiguration>(); 23 | } 24 | 25 | /// 26 | public override void Configure(IApplicationBuilder app, IEndpointRouteBuilder routes, IServiceProvider serviceProvider) 27 | { 28 | routes.MapAreaControllerRoute( 29 | name: "PreviewContent", 30 | areaName: "OrchardCoreContrib.ContentPreview", 31 | pattern: "/Preview/{*page}", 32 | defaults: new { controller = typeof(PreviewController).ControllerName(), action = nameof(PreviewController.Index) } 33 | ); 34 | 35 | app.UsePagePreview(); 36 | } 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/OrchardCoreContrib.ContentPreview/Views/Preview/Index.cshtml: -------------------------------------------------------------------------------- 1 | @{ 2 | Layout = null; 3 | } 4 | 5 | @functions 6 | { 7 | public string PreviewPagePath 8 | { 9 | get 10 | { 11 | var requestPath = Context.Request.Path.Value; 12 | var previewPage = requestPath.Substring(requestPath.IndexOf($"/{Constants.PreviewSlug}") + Constants.PreviewSlug.Length + 1); 13 | var path = String.Concat(Context.Request.PathBase.Value, previewPage); 14 | 15 | return path; 16 | } 17 | } 18 | } 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | -------------------------------------------------------------------------------- /src/OrchardCoreContrib.ContentPreview/Views/Preview/_PagePreviewBar.cshtml: -------------------------------------------------------------------------------- 1 | @functions { 2 | public bool IframeRequest => Context.Request.Headers["sec-fetch-dest"] == RequestDestination.Iframe; 3 | } 4 | 5 | @if (!IframeRequest) 6 | { 7 | 21 | } 22 | -------------------------------------------------------------------------------- /src/OrchardCoreContrib.ContentPreview/Views/_ViewImports.cshtml: -------------------------------------------------------------------------------- 1 | @inherits OrchardCore.DisplayManagement.Razor.RazorPage 2 | @addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers 3 | @addTagHelper *, OrchardCore.DisplayManagement 4 | @addTagHelper *, OrchardCore.ResourceManagement 5 | @addTagHelper *, OrchardCoreContrib.ContentPreview 6 | 7 | @using Microsoft.Extensions.Localization 8 | @using Microsoft.AspNetCore.Mvc.Localization 9 | @using OrchardCoreContrib.ContentPreview -------------------------------------------------------------------------------- /src/OrchardCoreContrib.ContentPreview/wwwroot/Scripts/PagePreviewBar.js: -------------------------------------------------------------------------------- 1 | $(function () { 2 | $('[data-bs-toggle="tooltip"]').tooltip(); 3 | 4 | $('#btnDesktopPreview').change(function () { 5 | if (this.checked) { 6 | $('iframe').removeClass(); 7 | } 8 | }); 9 | $('#btnTabletPreview').change(function () { 10 | if (this.checked) { 11 | $('iframe').removeClass(); 12 | $('iframe').addClass('tablet-preview'); 13 | } 14 | }); 15 | $('#btnMobilePreview').change(function () { 16 | if (this.checked) { 17 | $('iframe').removeClass(); 18 | $('iframe').addClass('mobile-preview'); 19 | } 20 | }); 21 | }); -------------------------------------------------------------------------------- /src/OrchardCoreContrib.ContentPreview/wwwroot/Styles/PagePreviewBar.css: -------------------------------------------------------------------------------- 1 | nav { 2 | border-bottom-style: solid; 3 | padding-left: calc(50% - 88px); 4 | } 5 | 6 | label { 7 | width: 44px; 8 | } 9 | 10 | iframe { 11 | position: absolute; 12 | width: 100%; 13 | height: 94%; 14 | border: none; 15 | } 16 | 17 | .tablet-preview { 18 | width: 768px; 19 | left: 50%; 20 | transform: translate(-50%); 21 | } 22 | 23 | .mobile-preview { 24 | width: 375px; 25 | left: 50%; 26 | transform: translate(-50%); 27 | } 28 | -------------------------------------------------------------------------------- /src/OrchardCoreContrib.DataLocalization/Manifest.cs: -------------------------------------------------------------------------------- 1 | using OrchardCore.Modules.Manifest; 2 | using ManifestConstants = OrchardCoreContrib.Modules.Manifest.ManifestConstants; 3 | 4 | [assembly: Module( 5 | Name = "Data Localization", 6 | Author = ManifestConstants.Author, 7 | Website = ManifestConstants.Website, 8 | Version = "1.1.1", 9 | Category = "Internationalization", 10 | Dependencies = new[] { "OrchardCore.Localization" } 11 | )] 12 | 13 | -------------------------------------------------------------------------------- /src/OrchardCoreContrib.DataLocalization/Models/Translation.cs: -------------------------------------------------------------------------------- 1 | namespace OrchardCoreContrib.DataLocalization.Models 2 | { 3 | /// 4 | /// Represents a translation. 5 | /// 6 | public class Translation 7 | { 8 | /// 9 | /// Gets the translation context. 10 | /// 11 | public string Context { get; set; } 12 | 13 | /// 14 | /// Gets the translation key. 15 | /// 16 | public string Key { get; set; } 17 | 18 | /// 19 | /// Gets the translation value. 20 | /// 21 | public string Value { get; set; } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/OrchardCoreContrib.DataLocalization/Models/TranslationsDocument.cs: -------------------------------------------------------------------------------- 1 | using OrchardCore.Data.Documents; 2 | using System; 3 | using System.Collections.Generic; 4 | 5 | namespace OrchardCoreContrib.DataLocalization.Models 6 | { 7 | /// 8 | /// Represents a documents that contains a list of . 9 | /// 10 | public class TranslationsDocument : Document 11 | { 12 | /// 13 | /// Creates a new instance of . 14 | /// 15 | public TranslationsDocument() 16 | { 17 | Translations = new Dictionary>(StringComparer.OrdinalIgnoreCase); 18 | } 19 | 20 | /// 21 | /// Gets the list of the translations associated with a culture. 22 | /// 23 | public Dictionary> Translations { get; } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/OrchardCoreContrib.DataLocalization/ViewModels/ContentFieldResourcesViewModel.cs: -------------------------------------------------------------------------------- 1 | using OrchardCoreContrib.DataLocalization.Models; 2 | using System; 3 | using System.Collections.Generic; 4 | 5 | namespace OrchardCoreContrib.DataLocalization.ViewModels 6 | { 7 | public class ContentFieldResourcesViewModel 8 | { 9 | public IEnumerable ContentTypes { get; set; } 10 | 11 | public IEnumerable ResourcesNames { get; set; } 12 | 13 | public IEnumerable Translations { get; set; } 14 | 15 | public string SelectedContentType { get; set; } 16 | 17 | public string SelectedCulture { get; set; } 18 | 19 | public bool HasCulture => !String.IsNullOrEmpty(SelectedCulture); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/OrchardCoreContrib.DataLocalization/ViewModels/ContentTypeResourcesViewModel.cs: -------------------------------------------------------------------------------- 1 | using OrchardCoreContrib.DataLocalization.Models; 2 | using System; 3 | using System.Collections.Generic; 4 | 5 | namespace OrchardCoreContrib.DataLocalization.ViewModels 6 | { 7 | public class ContentTypeResourcesViewModel 8 | { 9 | public IEnumerable ResourcesNames { get; set; } 10 | 11 | public IEnumerable Translations { get; set; } 12 | 13 | public string SelectedCulture { get; set; } 14 | 15 | public bool HasCulture => !String.IsNullOrEmpty(SelectedCulture); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/OrchardCoreContrib.DataLocalization/Views/_ViewImports.cshtml: -------------------------------------------------------------------------------- 1 | @inherits OrchardCore.DisplayManagement.Razor.RazorPage 2 | @addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers 3 | @addTagHelper *, OrchardCore.DisplayManagement 4 | @addTagHelper *, OrchardCore.ResourceManagement 5 | 6 | @using Microsoft.Extensions.Localization 7 | @using Microsoft.AspNetCore.Mvc.Localization -------------------------------------------------------------------------------- /src/OrchardCoreContrib.Diagnostics.Elm/Manifest.cs: -------------------------------------------------------------------------------- 1 | using OrchardCore.Modules.Manifest; 2 | using ManifestConstants = OrchardCoreContrib.Modules.Manifest.ManifestConstants; 3 | 4 | [assembly: Module( 5 | Name = "Elm Diagnostics", 6 | Author = ManifestConstants.Author, 7 | Website = ManifestConstants.Website, 8 | Version = "1.4.1", 9 | Description = "Provides services to handle errors using Elm.", 10 | Category = "Infrastructure" 11 | )] 12 | -------------------------------------------------------------------------------- /src/OrchardCoreContrib.Diagnostics.Elm/Startup.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.AspNetCore.Builder; 2 | using Microsoft.AspNetCore.Http; 3 | using Microsoft.AspNetCore.Routing; 4 | using Microsoft.Extensions.DependencyInjection; 5 | using OrchardCore.Modules; 6 | using System; 7 | 8 | namespace OrchardCoreContrib.Diagnostics.Elm 9 | { 10 | /// 11 | /// Represensts a startup point to register the required services by Elm diagnostics module. 12 | /// 13 | public class Startup : StartupBase 14 | { 15 | /// 16 | public override void ConfigureServices(IServiceCollection services) 17 | { 18 | services.AddElm(options => options.Path = new PathString("/elm")); 19 | } 20 | 21 | /// 22 | public override void Configure(IApplicationBuilder builder, IEndpointRouteBuilder routes, IServiceProvider serviceProvider) 23 | { 24 | builder.UseElmCapture(); 25 | builder.UseElmPage(); 26 | } 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/OrchardCoreContrib.Email.Gmail/GmailDefaults.cs: -------------------------------------------------------------------------------- 1 | namespace OrchardCoreContrib.Email.Gmail 2 | { 3 | /// 4 | /// Respresents a default settings for Gmail. 5 | /// 6 | public static class GmailDefaults 7 | { 8 | /// 9 | /// Gets the server name. 10 | /// 11 | public const string Host = "smtp.gmail.com"; 12 | 13 | /// 14 | /// Gets the port number. 15 | /// 16 | public const int Port = 587; 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/OrchardCoreContrib.Email.Gmail/GmailSettings.cs: -------------------------------------------------------------------------------- 1 | namespace OrchardCoreContrib.Email.Gmail 2 | { 3 | /// 4 | /// Represents a settings for Gmail. 5 | /// 6 | public class GmailSettings : SmtpSettings 7 | { 8 | /// 9 | /// Initializes a new instance of . 10 | /// 11 | public GmailSettings() 12 | { 13 | Host = GmailDefaults.Host; 14 | Port = GmailDefaults.Port; 15 | } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/OrchardCoreContrib.Email.Gmail/Manifest.cs: -------------------------------------------------------------------------------- 1 | using OrchardCore.Modules.Manifest; 2 | using ManifestConstants = OrchardCoreContrib.Modules.Manifest.ManifestConstants; 3 | 4 | [assembly: Module( 5 | Name = "GMail", 6 | Author = ManifestConstants.Author, 7 | Website = ManifestConstants.Website, 8 | Version = "1.4.1", 9 | Description = "Provides email settings configuration for GMail service.", 10 | Category = "Messaging" 11 | )] 12 | -------------------------------------------------------------------------------- /src/OrchardCoreContrib.Email.Gmail/Permissions.cs: -------------------------------------------------------------------------------- 1 | using OrchardCore.Security.Permissions; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Threading.Tasks; 5 | 6 | namespace OrchardCoreContrib.Email.Gmail 7 | { 8 | /// 9 | /// Represents a permissions that will be applied into Gmail mailing module. 10 | /// 11 | public class Permissions : IPermissionProvider 12 | { 13 | /// 14 | /// Gets a permission for managing a Gmail settings. 15 | /// 16 | public static readonly Permission ManageGmailSettings = new Permission("ManageGmailSettings", "Manage Gmail Settings"); 17 | 18 | /// 19 | public Task> GetPermissionsAsync() 20 | { 21 | return Task.FromResult(new[] 22 | { 23 | ManageGmailSettings 24 | } 25 | .AsEnumerable()); 26 | } 27 | 28 | /// 29 | public IEnumerable GetDefaultStereotypes() 30 | { 31 | return new[] 32 | { 33 | new PermissionStereotype 34 | { 35 | Name = "Administrator", 36 | Permissions = new[] { ManageGmailSettings } 37 | }, 38 | }; 39 | } 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /src/OrchardCoreContrib.Email.Gmail/Views/GmailSettings.Edit.cshtml: -------------------------------------------------------------------------------- 1 | @using OrchardCore.Email 2 | @using OrchardCoreContrib.Email.Gmail 3 | @model GmailSettings 4 | 5 |

@T["The current tenant will be reloaded when the settings are saved."]

6 | 7 |
8 | 9 | 10 | 11 | @T["The default email address to use as a sender, unless the email sender is set."] 12 |
13 | 14 | 15 | 16 |
17 | 18 | 19 | 20 | @T["The username for authentication."] 21 |
22 | 23 |
24 | 25 | 26 | 27 | @T["The password for authentication."] 28 |
29 | -------------------------------------------------------------------------------- /src/OrchardCoreContrib.Email.Gmail/Views/GmailSettings.TestButton.cshtml: -------------------------------------------------------------------------------- 1 | @T["Test settings"] 2 | -------------------------------------------------------------------------------- /src/OrchardCoreContrib.Email.Gmail/Views/NavigationItemText-gmail.Id.cshtml: -------------------------------------------------------------------------------- 1 | @T["Gmail"] 2 | -------------------------------------------------------------------------------- /src/OrchardCoreContrib.Email.Gmail/Views/_ViewImports.cshtml: -------------------------------------------------------------------------------- 1 | @inherits OrchardCore.DisplayManagement.Razor.RazorPage 2 | 3 | @addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers 4 | @addTagHelper *, OrchardCore.DisplayManagement 5 | @addTagHelper *, OrchardCore.ResourceManagement -------------------------------------------------------------------------------- /src/OrchardCoreContrib.Email.Hotmail/HotmailDefaults.cs: -------------------------------------------------------------------------------- 1 | namespace OrchardCoreContrib.Email.Hotmail 2 | { 3 | /// 4 | /// Respresents a default settings for Hotmail. 5 | /// 6 | public static class HotmailDefaults 7 | { 8 | /// 9 | /// Gets the server name. 10 | /// 11 | public const string Host = "smtp.live.com"; 12 | 13 | /// 14 | /// Gets the port number. 15 | /// 16 | public const int Port = 587; 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/OrchardCoreContrib.Email.Hotmail/HotmailSettings.cs: -------------------------------------------------------------------------------- 1 | namespace OrchardCoreContrib.Email.Hotmail 2 | { 3 | /// 4 | /// Represents a settings for Hotmail. 5 | /// 6 | public class HotmailSettings : SmtpSettings 7 | { 8 | /// 9 | /// Initializes a new instance of . 10 | /// 11 | public HotmailSettings() 12 | { 13 | Host = HotmailDefaults.Host; 14 | Port = HotmailDefaults.Port; 15 | } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/OrchardCoreContrib.Email.Hotmail/Manifest.cs: -------------------------------------------------------------------------------- 1 | using OrchardCore.Modules.Manifest; 2 | using ManifestConstants = OrchardCoreContrib.Modules.Manifest.ManifestConstants; 3 | 4 | [assembly: Module( 5 | Name = "Hotmail", 6 | Author = ManifestConstants.Author, 7 | Website = ManifestConstants.Website, 8 | Version = "1.4.1", 9 | Description = "Provides email settings configuration for Hotmail service.", 10 | Category = "Messaging" 11 | )] 12 | 13 | -------------------------------------------------------------------------------- /src/OrchardCoreContrib.Email.Hotmail/Permissions.cs: -------------------------------------------------------------------------------- 1 | using OrchardCore.Security.Permissions; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Threading.Tasks; 5 | 6 | namespace OrchardCoreContrib.Email.Hotmail 7 | { 8 | /// 9 | /// Represents a permissions that will be applied into Hotmail mailing module. 10 | /// 11 | public class Permissions : IPermissionProvider 12 | { 13 | /// 14 | /// Gets a permission for managing a Hotmail settings. 15 | /// 16 | public static readonly Permission ManageHotmailSettings = new Permission("ManageHotmailSettings", "Manage Hotmail Settings"); 17 | 18 | /// 19 | public Task> GetPermissionsAsync() 20 | { 21 | return Task.FromResult(new[] 22 | { 23 | ManageHotmailSettings 24 | } 25 | .AsEnumerable()); 26 | } 27 | 28 | /// 29 | public IEnumerable GetDefaultStereotypes() 30 | { 31 | return new[] 32 | { 33 | new PermissionStereotype 34 | { 35 | Name = "Administrator", 36 | Permissions = new[] { ManageHotmailSettings } 37 | }, 38 | }; 39 | } 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /src/OrchardCoreContrib.Email.Hotmail/Views/HotmailSettings.Edit.cshtml: -------------------------------------------------------------------------------- 1 | @using OrchardCore.Email 2 | @using OrchardCoreContrib.Email.Hotmail 3 | @model HotmailSettings 4 | 5 |

@T["The current tenant will be reloaded when the settings are saved."]

6 | 7 |
8 | 9 | 10 | 11 | @T["The default email address to use as a sender, unless the email sender is set."] 12 |
13 | 14 | 15 | 16 |
17 | 18 | 19 | 20 | @T["The username for authentication."] 21 |
22 | 23 |
24 | 25 | 26 | 27 | @T["The password for authentication."] 28 |
29 | -------------------------------------------------------------------------------- /src/OrchardCoreContrib.Email.Hotmail/Views/HotmailSettings.TestButton.cshtml: -------------------------------------------------------------------------------- 1 | @T["Test settings"] 2 | -------------------------------------------------------------------------------- /src/OrchardCoreContrib.Email.Hotmail/Views/NavigationItemText-hotmail.Id.cshtml: -------------------------------------------------------------------------------- 1 | @T["Hotmail"] 2 | -------------------------------------------------------------------------------- /src/OrchardCoreContrib.Email.Hotmail/Views/_ViewImports.cshtml: -------------------------------------------------------------------------------- 1 | @inherits OrchardCore.DisplayManagement.Razor.RazorPage 2 | 3 | @addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers 4 | @addTagHelper *, OrchardCore.DisplayManagement 5 | @addTagHelper *, OrchardCore.ResourceManagement -------------------------------------------------------------------------------- /src/OrchardCoreContrib.Email.SendGrid/HealthChecks/Extensions/SendGridHealthCheckExtensions.cs: -------------------------------------------------------------------------------- 1 | using OrchardCoreContrib.Email.SendGrid.HealthChecks; 2 | 3 | namespace Microsoft.Extensions.DependencyInjection; 4 | 5 | public static class SendGridHealthCheckExtensions 6 | { 7 | public static IHealthChecksBuilder AddSendGridCheck(this IHealthChecksBuilder healthChecksBuilder) 8 | => healthChecksBuilder.AddCheck(SendGridHealthCheck.Name); 9 | } 10 | -------------------------------------------------------------------------------- /src/OrchardCoreContrib.Email.SendGrid/HealthChecks/Startup.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.AspNetCore.Builder; 2 | using Microsoft.AspNetCore.Diagnostics.HealthChecks; 3 | using Microsoft.AspNetCore.Routing; 4 | using Microsoft.Extensions.DependencyInjection; 5 | using Microsoft.Extensions.Options; 6 | using OrchardCore.Modules; 7 | using OrchardCoreContrib.HealthChecks; 8 | using System; 9 | 10 | namespace OrchardCoreContrib.Email.SendGrid.HealthChecks; 11 | 12 | [RequireFeatures("OrchardCoreContrib.HealthChecks")] 13 | public class Startup : StartupBase 14 | { 15 | public override void ConfigureServices(IServiceCollection services) 16 | { 17 | services.AddHttpClient(); 18 | 19 | services.AddHealthChecks() 20 | .AddSendGridCheck(); 21 | } 22 | 23 | public override void Configure(IApplicationBuilder app, IEndpointRouteBuilder routes, IServiceProvider serviceProvider) 24 | { 25 | var healthChecksOptions = serviceProvider.GetService>().Value; 26 | 27 | routes.MapHealthChecks($"{healthChecksOptions.Url}/sendgrid", new HealthCheckOptions 28 | { 29 | Predicate = r => r.Name == SendGridHealthCheck.Name 30 | }); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/OrchardCoreContrib.Email.SendGrid/Manifest.cs: -------------------------------------------------------------------------------- 1 | using OrchardCore.Modules.Manifest; 2 | using ManifestConstants = OrchardCoreContrib.Modules.Manifest.ManifestConstants; 3 | 4 | [assembly: Module( 5 | Name = "SendGrid", 6 | Author = ManifestConstants.Author, 7 | Website = ManifestConstants.Website, 8 | Version = "1.5.1", 9 | Description = "Provides email settings configuration for SendGrid service.", 10 | Category = "Messaging" 11 | )] 12 | -------------------------------------------------------------------------------- /src/OrchardCoreContrib.Email.SendGrid/Permissions.cs: -------------------------------------------------------------------------------- 1 | using OrchardCore.Security.Permissions; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Threading.Tasks; 5 | 6 | namespace OrchardCoreContrib.Email.SendGrid 7 | { 8 | /// 9 | /// Represents a permissions that will be applied into SendGrid mailing module. 10 | /// 11 | public class Permissions : IPermissionProvider 12 | { 13 | /// 14 | /// Gets a permission for managing a SendGrid settings. 15 | /// 16 | public static readonly Permission ManageSendGridSettings = new Permission("ManageSendGridSettings", "Manage SendGrid Settings"); 17 | 18 | /// 19 | public Task> GetPermissionsAsync() 20 | { 21 | return Task.FromResult(new[] 22 | { 23 | ManageSendGridSettings 24 | } 25 | .AsEnumerable()); 26 | } 27 | 28 | /// 29 | public IEnumerable GetDefaultStereotypes() 30 | { 31 | return new[] 32 | { 33 | new PermissionStereotype 34 | { 35 | Name = "Administrator", 36 | Permissions = new[] { ManageSendGridSettings } 37 | }, 38 | }; 39 | } 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /src/OrchardCoreContrib.Email.SendGrid/SendGridSettings.cs: -------------------------------------------------------------------------------- 1 | using OrchardCore.Email; 2 | using EmailAddress = OrchardCore.Email.EmailAddressAttribute; 3 | using System.ComponentModel.DataAnnotations; 4 | 5 | namespace OrchardCoreContrib.Email.SendGrid 6 | { 7 | /// 8 | /// Represents a settings for SendGrid. 9 | /// 10 | public class SendGridSettings 11 | { 12 | /// 13 | /// Gets or sets the default sender mail. 14 | /// 15 | [Required(AllowEmptyStrings = false), EmailAddress] 16 | public string DefaultSender { get; set; } 17 | 18 | /// 19 | /// Gets or sets the API key. 20 | /// 21 | public string ApiKey { get; set; } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/OrchardCoreContrib.Email.SendGrid/Views/NavigationItemText-sendgrid.Id.cshtml: -------------------------------------------------------------------------------- 1 | @T["SendGrid"] 2 | -------------------------------------------------------------------------------- /src/OrchardCoreContrib.Email.SendGrid/Views/SendGridSettings.Edit.cshtml: -------------------------------------------------------------------------------- 1 | @using OrchardCore.Email 2 | @using OrchardCoreContrib.Email.SendGrid 3 | @model SendGridSettings 4 | 5 |

@T["The current tenant will be reloaded when the settings are saved."]

6 | 7 |
8 | 9 | 10 | 11 | @T["The default email address to use as a sender, unless the email sender is set."] 12 |
13 | 14 |
15 | 16 | 17 | 18 | @T["The API key for authentication."] 19 |
20 | -------------------------------------------------------------------------------- /src/OrchardCoreContrib.Email.SendGrid/Views/SendGridSettings.TestButton.cshtml: -------------------------------------------------------------------------------- 1 | @T["Test settings"] 2 | -------------------------------------------------------------------------------- /src/OrchardCoreContrib.Email.SendGrid/Views/_ViewImports.cshtml: -------------------------------------------------------------------------------- 1 | @inherits OrchardCore.DisplayManagement.Razor.RazorPage 2 | 3 | @addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers 4 | @addTagHelper *, OrchardCore.DisplayManagement 5 | @addTagHelper *, OrchardCore.ResourceManagement -------------------------------------------------------------------------------- /src/OrchardCoreContrib.Email.Yahoo/Manifest.cs: -------------------------------------------------------------------------------- 1 | using OrchardCore.Modules.Manifest; 2 | using ManifestConstants = OrchardCoreContrib.Modules.Manifest.ManifestConstants; 3 | 4 | [assembly: Module( 5 | Name = "Yahoo", 6 | Author = ManifestConstants.Author, 7 | Website = ManifestConstants.Website, 8 | Version = "1.4.1", 9 | Description = "Provides email settings configuration for Yahoo service.", 10 | Category = "Messaging" 11 | )] 12 | -------------------------------------------------------------------------------- /src/OrchardCoreContrib.Email.Yahoo/Permissions.cs: -------------------------------------------------------------------------------- 1 | using OrchardCore.Security.Permissions; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Threading.Tasks; 5 | 6 | namespace OrchardCoreContrib.Email.Yahoo 7 | { 8 | /// 9 | /// Represents a permissions that will be applied into Yahoo mailing module. 10 | /// 11 | public class Permissions : IPermissionProvider 12 | { 13 | /// 14 | /// Gets a permission for managing a Yahoo settings. 15 | /// 16 | public static readonly Permission ManageYahooSettings = new Permission("ManageYahooSettings", "Manage Yahoo Settings"); 17 | 18 | /// 19 | public Task> GetPermissionsAsync() 20 | { 21 | return Task.FromResult(new[] 22 | { 23 | ManageYahooSettings 24 | } 25 | .AsEnumerable()); 26 | } 27 | 28 | /// 29 | public IEnumerable GetDefaultStereotypes() 30 | { 31 | return new[] 32 | { 33 | new PermissionStereotype 34 | { 35 | Name = "Administrator", 36 | Permissions = new[] { ManageYahooSettings } 37 | }, 38 | }; 39 | } 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /src/OrchardCoreContrib.Email.Yahoo/Views/NavigationItemText-yahoo.Id.cshtml: -------------------------------------------------------------------------------- 1 | @T["Yahoo"] 2 | -------------------------------------------------------------------------------- /src/OrchardCoreContrib.Email.Yahoo/Views/YahooSettings.Edit.cshtml: -------------------------------------------------------------------------------- 1 | @using OrchardCore.Email 2 | @using OrchardCoreContrib.Email.Yahoo 3 | @model YahooSettings 4 | 5 |

@T["The current tenant will be reloaded when the settings are saved."]

6 | 7 |
8 | 9 | 10 | 11 | @T["The default email address to use as a sender, unless the email sender is set."] 12 |
13 | 14 | 15 | 16 |
17 | 18 | 19 | 20 | @T["The username for authentication."] 21 |
22 | 23 |
24 | 25 | 26 | 27 | @T["The password for authentication."] 28 |
29 | -------------------------------------------------------------------------------- /src/OrchardCoreContrib.Email.Yahoo/Views/YahooSettings.TestButton.cshtml: -------------------------------------------------------------------------------- 1 | @T["Test settings"] 2 | -------------------------------------------------------------------------------- /src/OrchardCoreContrib.Email.Yahoo/Views/_ViewImports.cshtml: -------------------------------------------------------------------------------- 1 | @inherits OrchardCore.DisplayManagement.Razor.RazorPage 2 | 3 | @addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers 4 | @addTagHelper *, OrchardCore.DisplayManagement 5 | @addTagHelper *, OrchardCore.ResourceManagement -------------------------------------------------------------------------------- /src/OrchardCoreContrib.Email.Yahoo/YahooDefaults.cs: -------------------------------------------------------------------------------- 1 | namespace OrchardCoreContrib.Email.Yahoo 2 | { 3 | /// 4 | /// Respresents a default settings for Yahoo. 5 | /// 6 | public static class YahooDefaults 7 | { 8 | /// 9 | /// Gets the server name. 10 | /// 11 | public const string Host = "smtp.mail.yahoo.com"; 12 | 13 | /// 14 | /// Gets the port number. 15 | /// 16 | public const int Port = 465; 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/OrchardCoreContrib.Email.Yahoo/YahooSettings.cs: -------------------------------------------------------------------------------- 1 | namespace OrchardCoreContrib.Email.Yahoo 2 | { 3 | /// 4 | /// Represents a settings for Yahoo. 5 | /// 6 | public class YahooSettings : SmtpSettings 7 | { 8 | /// 9 | /// Initializes a new instance of . 10 | /// 11 | public YahooSettings() 12 | { 13 | Host = YahooDefaults.Host; 14 | Port = YahooDefaults.Port; 15 | } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/OrchardCoreContrib.Garnet/Constants.cs: -------------------------------------------------------------------------------- 1 | namespace OrchardCoreContrib.Garnet; 2 | 3 | /// 4 | /// Contains a set of constants for the Garnet module. 5 | /// 6 | public class Constants 7 | { 8 | /// 9 | /// Gets the configuration section name for the Garnet module. 10 | /// 11 | public const string ConfigurationSectionName = "OrchardCoreContrib_Garnet"; 12 | 13 | /// 14 | /// Gets the health check name for the Garnet module. 15 | /// 16 | public const string HealthCheckName = "Garnet Health Check"; 17 | } 18 | -------------------------------------------------------------------------------- /src/OrchardCoreContrib.Garnet/GarnetKeyManagementOptionsSetup.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.AspNetCore.DataProtection.KeyManagement; 2 | using Microsoft.Extensions.Options; 3 | using OrchardCore.Environment.Shell; 4 | using OrchardCoreContrib.Garnet.Services; 5 | 6 | namespace OrchardCoreContrib.Garnet; 7 | 8 | /// 9 | /// Represents a setup to configure the for Garnet data protection feature. 10 | /// 11 | /// The . 12 | /// The . 13 | public class GarnetKeyManagementOptionsSetup(IGarnetService garnetService, ShellSettings shellSettings) 14 | : IConfigureOptions 15 | { 16 | private readonly string _tenant = shellSettings.Name; 17 | 18 | /// 19 | public void Configure(KeyManagementOptions options) 20 | { 21 | options.XmlRepository = new GarnetXmlRepository(() => 22 | { 23 | if (garnetService.Client == null) 24 | { 25 | garnetService.ConnectAsync().GetAwaiter().GetResult(); 26 | } 27 | 28 | return garnetService.Client; 29 | }, $"({garnetService.InstancePrefix}{_tenant}:DataProtection-Keys"); 30 | } 31 | } -------------------------------------------------------------------------------- /src/OrchardCoreContrib.Garnet/GarnetXmlRepository.cs: -------------------------------------------------------------------------------- 1 | using Garnet.client; 2 | using Microsoft.AspNetCore.DataProtection.Repositories; 3 | using System.Xml.Linq; 4 | 5 | namespace OrchardCoreContrib.Garnet; 6 | 7 | /// 8 | /// Represents a repository to store data protection keys in Garnet. 9 | /// 10 | /// The factory. 11 | /// The key. 12 | public class GarnetXmlRepository(Func garnetClientFactory, string key) : IXmlRepository 13 | { 14 | /// 15 | public IReadOnlyCollection GetAllElements() => GetAllElementsCore().ToList().AsReadOnly(); 16 | 17 | /// 18 | public void StoreElement(XElement element, string friendlyName) => garnetClientFactory() 19 | .ListRightPushAsync(key, element.ToString(SaveOptions.DisableFormatting)) 20 | .GetAwaiter() 21 | .GetResult(); 22 | 23 | private IEnumerable GetAllElementsCore() 24 | { 25 | var elements = garnetClientFactory() 26 | .ListRangeAsync(key, 0, -1) 27 | .GetAwaiter() 28 | .GetResult(); 29 | 30 | foreach (var element in elements) 31 | { 32 | yield return XElement.Parse(element); 33 | } 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/OrchardCoreContrib.Garnet/HealthChecks/Extensions/GarnetHealthCheckExtensions.cs: -------------------------------------------------------------------------------- 1 | using OrchardCoreContrib.Garnet; 2 | using OrchardCoreContrib.Garnet.HealthChecks; 3 | 4 | namespace Microsoft.Extensions.DependencyInjection; 5 | 6 | /// 7 | /// Provides a set of extensions for to add Garnet health checks. 8 | /// 9 | public static class GarnetHealthCheckExtensions 10 | { 11 | /// 12 | /// Adds a Garnet health check. 13 | /// 14 | /// The . 15 | public static IHealthChecksBuilder AddGarnetCheck(this IHealthChecksBuilder healthChecksBuilder) 16 | => healthChecksBuilder.AddCheck(Constants.HealthCheckName); 17 | } 18 | -------------------------------------------------------------------------------- /src/OrchardCoreContrib.Garnet/HealthChecks/Startup.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.AspNetCore.Builder; 2 | using Microsoft.AspNetCore.Diagnostics.HealthChecks; 3 | using Microsoft.AspNetCore.Routing; 4 | using Microsoft.Extensions.DependencyInjection; 5 | using Microsoft.Extensions.Options; 6 | using OrchardCore.Modules; 7 | using OrchardCoreContrib.HealthChecks; 8 | 9 | namespace OrchardCoreContrib.Garnet.HealthChecks; 10 | 11 | /// 12 | /// Represensts a startup point to register the health checks for Garnet module. 13 | /// 14 | [RequireFeatures("OrchardCoreContrib.HealthChecks")] 15 | public class Startup : StartupBase 16 | { 17 | /// 18 | public override void ConfigureServices(IServiceCollection services) 19 | { 20 | services.AddHttpClient(); 21 | 22 | services.AddHealthChecks() 23 | .AddGarnetCheck(); 24 | } 25 | 26 | /// 27 | public override void Configure(IApplicationBuilder app, IEndpointRouteBuilder routes, IServiceProvider serviceProvider) 28 | { 29 | var healthChecksOptions = serviceProvider.GetService>().Value; 30 | 31 | routes.MapHealthChecks($"{healthChecksOptions.Url}/garnet", new HealthCheckOptions 32 | { 33 | Predicate = r => r.Name == Constants.HealthCheckName 34 | }); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/OrchardCoreContrib.Garnet/Manifest.cs: -------------------------------------------------------------------------------- 1 | using OrchardCore.Modules.Manifest; 2 | using ManifestConstants = OrchardCoreContrib.Modules.Manifest.ManifestConstants; 3 | 4 | [assembly: Module( 5 | Name = "Garnet", 6 | Author = ManifestConstants.Author, 7 | Website = ManifestConstants.Website, 8 | Version = "1.3.0" 9 | )] 10 | 11 | [assembly: Feature( 12 | Id = "OrchardCoreContrib.Garnet", 13 | Name = "Garnet", 14 | Description = "Garnet configuration support.", 15 | Category = "Distributed Caching" 16 | )] 17 | 18 | [assembly: Feature( 19 | Id = "OrchardCoreContrib.Garnet.Cache", 20 | Name = "Garnet Cache", 21 | Description = "Distributed cache using Garnet.", 22 | Dependencies = ["OrchardCoreContrib.Garnet"], 23 | Category = "Distributed Caching" 24 | )] 25 | 26 | [assembly: Feature( 27 | Id = "OrchardCoreContrib.Garnet.Bus", 28 | Name = "Garnet Bus", 29 | Description = "Makes the Signal service distributed though Garnet.", 30 | Dependencies = ["OrchardCoreContrib.Garnet"], 31 | Category = "Distributed Caching" 32 | )] 33 | 34 | [assembly: Feature( 35 | Id = "OrchardCoreContrib.Garnet.DataProtection", 36 | Name = "Garnet DataProtection", 37 | Description = "Distributed DataProtection using Garnet.", 38 | Dependencies = ["OrchardCoreContrib.Garnet"], 39 | Category = "Distributed Caching" 40 | )] 41 | -------------------------------------------------------------------------------- /src/OrchardCoreContrib.Garnet/Services/GarnetService.cs: -------------------------------------------------------------------------------- 1 | using Garnet.client; 2 | using Microsoft.Extensions.Options; 3 | using OrchardCore.Modules; 4 | 5 | namespace OrchardCoreContrib.Garnet.Services; 6 | 7 | /// 8 | /// Represents the Garnet service. 9 | /// 10 | /// The . 11 | /// The . 12 | public class GarnetService(IGarnetClientFactory factory, IOptions options) : ModularTenantEvents, IGarnetService 13 | { 14 | private readonly GarnetOptions _garnetOptions = options.Value; 15 | 16 | /// 17 | public GarnetClient Client { get; private set; } 18 | 19 | /// 20 | public string InstancePrefix => _garnetOptions.InstancePrefix; 21 | 22 | /// 23 | public async Task ConnectAsync() => Client ??= await factory.CreateAsync(_garnetOptions); 24 | 25 | /// 26 | public override async Task ActivatingAsync() => await ConnectAsync(); 27 | } 28 | -------------------------------------------------------------------------------- /src/OrchardCoreContrib.Garnet/Startups/GarnetBusStartup.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.Extensions.DependencyInjection; 2 | using OrchardCore.Caching.Distributed; 3 | using OrchardCore.Modules; 4 | using OrchardCoreContrib.Garnet.Services; 5 | 6 | namespace OrchardCoreContrib.Garnet; 7 | 8 | /// 9 | /// Represensts a startup point to register the required services by Garnet bus feature. 10 | /// 11 | [Feature("OrchardCoreContrib.Garnet.Bus")] 12 | public class GarnetBusStartup : StartupBase 13 | { 14 | /// 15 | public override void ConfigureServices(IServiceCollection services) 16 | { 17 | if (services.Any(d => d.ServiceType == typeof(IGarnetService))) 18 | { 19 | services.AddSingleton(); 20 | } 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/OrchardCoreContrib.Garnet/Startups/GarnetCacheStartup.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.Extensions.Caching.Distributed; 2 | using Microsoft.Extensions.DependencyInjection; 3 | using OrchardCore.Environment.Cache; 4 | using OrchardCore.Modules; 5 | using OrchardCoreContrib.Garnet.Services; 6 | 7 | namespace OrchardCoreContrib.Garnet; 8 | 9 | /// 10 | /// Represensts a startup point to register the required services by Garnet cache feature. 11 | /// 12 | [Feature("OrchardCoreContrib.Garnet.Cache")] 13 | public class GarnetCacheStartup : StartupBase 14 | { 15 | /// 16 | public override void ConfigureServices(IServiceCollection services) 17 | { 18 | if (services.Any(d => d.ServiceType == typeof(IGarnetService))) 19 | { 20 | services.AddSingleton(); 21 | services.AddScoped(); 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/OrchardCoreContrib.Garnet/Startups/GarnetDataProtectionStartup.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.AspNetCore.DataProtection.KeyManagement; 2 | using Microsoft.Extensions.DependencyInjection; 3 | using Microsoft.Extensions.Options; 4 | using OrchardCore.Modules; 5 | using OrchardCoreContrib.Garnet.Services; 6 | 7 | namespace OrchardCoreContrib.Garnet; 8 | 9 | /// 10 | /// Represensts a startup point to register the required services by Garnet data protection feature. 11 | /// 12 | [Feature("OrchardCoreContrib.Garnet.DataProtection")] 13 | public class GarnetDataProtectionStartup : StartupBase 14 | { 15 | /// 16 | public override void ConfigureServices(IServiceCollection services) 17 | { 18 | if (services.Any(d => d.ServiceType == typeof(IGarnetService))) 19 | { 20 | services.AddTransient, GarnetKeyManagementOptionsSetup>(); 21 | } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/OrchardCoreContrib.Garnet/Startups/Startup.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.Extensions.DependencyInjection; 2 | using OrchardCore.Environment.Shell.Configuration; 3 | using OrchardCore.Modules; 4 | using OrchardCoreContrib.Garnet.Services; 5 | 6 | namespace OrchardCoreContrib.Garnet; 7 | 8 | /// 9 | /// Represensts a startup point to register the required services by Garnet module. 10 | /// 11 | public class Startup(IShellConfiguration configuration) : StartupBase 12 | { 13 | /// 14 | public override void ConfigureServices(IServiceCollection services) 15 | { 16 | services.AddSingleton(); 17 | services.AddSingleton(sp => sp.GetRequiredService()); 18 | services.AddSingleton(); 19 | 20 | services.Configure(configuration.GetSection(Constants.ConfigurationSectionName)); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/OrchardCoreContrib.Gdpr/AdminMenu.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.Extensions.Localization; 2 | using OrchardCore.Navigation; 3 | using OrchardCoreContrib.Gdpr.Drivers; 4 | using System; 5 | using System.Threading.Tasks; 6 | 7 | namespace OrchardCoreContrib.Gdpr 8 | { 9 | using OrchardCoreContrib.Navigation; 10 | 11 | /// 12 | /// Represents an admin menu for GDPR module. 13 | /// 14 | public class AdminMenu : AdminNavigationProvider 15 | { 16 | private readonly IStringLocalizer S; 17 | 18 | /// 19 | /// Initializes a new instance of . 20 | /// 21 | /// The . 22 | public AdminMenu(IStringLocalizer stringLocalizer) 23 | { 24 | S = stringLocalizer; 25 | } 26 | 27 | /// 28 | public override void BuildNavigation(NavigationBuilder builder) 29 | { 30 | builder 31 | .Add(S["Configuration"], configuration => configuration 32 | .Add(S["Settings"], settings => settings 33 | .Add(S["GDPR"], S["GDPR"].PrefixPosition(), entry => entry 34 | .AddClass("gdpr").Id("gdpr") 35 | .Action("Index", "Admin", new { area = "OrchardCore.Settings", groupId = GdprSettingsDisplayDriver.GroupId }) 36 | .Permission(Permissions.ManageGdprSettings) 37 | .LocalNav() 38 | ))); 39 | } 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /src/OrchardCoreContrib.Gdpr/Controllers/HomeController.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.AspNetCore.Mvc; 2 | using OrchardCore.Entities; 3 | using OrchardCore.Settings; 4 | 5 | namespace OrchardCoreContrib.Gdpr.Controllers 6 | { 7 | public class HomeController : Controller 8 | { 9 | private readonly GdprSettings _gdprSettings; 10 | 11 | public HomeController(ISiteService site) 12 | { 13 | _gdprSettings = site.GetSiteSettingsAsync() 14 | .GetAwaiter().GetResult() 15 | .As(); 16 | } 17 | 18 | [HttpGet] 19 | public IActionResult Privacy() => View(_gdprSettings); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/OrchardCoreContrib.Gdpr/GdprSettings.cs: -------------------------------------------------------------------------------- 1 | namespace OrchardCoreContrib.Gdpr 2 | { 3 | /// 4 | /// Represents a GDPR settings 5 | /// 6 | public class GdprSettings 7 | { 8 | private static readonly string DefaultSummary = "Use this page to summarize your privacy and cookie use policy."; 9 | 10 | private static readonly string DefaultDetail = "Use this page to detail your site's privacy policy."; 11 | 12 | /// 13 | /// Gets or sets a summary that will be used in the cookie consent UI. 14 | /// 15 | public string Summary { get; set; } = DefaultSummary; 16 | 17 | /// 18 | /// Gets or sets a detail that will be used in the privacy policy page. 19 | /// 20 | public string Detail { get; set; } = DefaultDetail; 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/OrchardCoreContrib.Gdpr/Manifest.cs: -------------------------------------------------------------------------------- 1 | using OrchardCore.Modules.Manifest; 2 | using ManifestConstants = OrchardCoreContrib.Modules.Manifest.ManifestConstants; 3 | 4 | [assembly: Module( 5 | Name = "GDPR", 6 | Author = ManifestConstants.Author, 7 | Website = ManifestConstants.Website, 8 | Version = "1.0.0", 9 | Description = "Supports EU General Data Protection Regulation (GDPR).", 10 | Dependencies = new string[] { "OrchardCore.Gdpr" }, 11 | Category = "Security" 12 | )] 13 | 14 | [assembly: Feature( 15 | Id = "OrchardCoreContrib.Gdpr", 16 | Name = "GDPR", 17 | Description = "Supports EU General Data Protection Regulation (GDPR).", 18 | Category = "Security" 19 | )] 20 | -------------------------------------------------------------------------------- /src/OrchardCoreContrib.Gdpr/Permissions.cs: -------------------------------------------------------------------------------- 1 | using OrchardCore.Security.Permissions; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Threading.Tasks; 5 | 6 | namespace OrchardCoreContrib.Gdpr 7 | { 8 | /// 9 | /// Represents a permissions that will be applied into GDPR module. 10 | /// 11 | public class Permissions : IPermissionProvider 12 | { 13 | /// 14 | /// Gets a permission for managing a GDPR settings. 15 | /// 16 | public static readonly Permission ManageGdprSettings = new Permission("ManageGdprSettings", "Manage GDPR Settings"); 17 | 18 | /// 19 | public Task> GetPermissionsAsync() 20 | { 21 | return Task.FromResult(new[] 22 | { 23 | ManageGdprSettings 24 | } 25 | .AsEnumerable()); 26 | } 27 | 28 | /// 29 | public IEnumerable GetDefaultStereotypes() 30 | { 31 | return new[] 32 | { 33 | new PermissionStereotype 34 | { 35 | Name = "Administrator", 36 | Permissions = new[] { ManageGdprSettings } 37 | }, 38 | }; 39 | } 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /src/OrchardCoreContrib.Gdpr/Views/CookieConsent.cshtml: -------------------------------------------------------------------------------- 1 | @using Microsoft.AspNetCore.Http.Features 2 | @using OrchardCore.Entities 3 | @using OrchardCore.Settings 4 | @using OrchardCoreContrib.Gdpr 5 | @inject ISiteService Site 6 | 7 | @{ 8 | var consentFeature = Context.Features.Get(); 9 | var cookieString = consentFeature?.CreateConsentCookie(); 10 | var gdprSettings = Site.GetSiteSettingsAsync() 11 | .GetAwaiter().GetResult() 12 | .As(); 13 | } 14 | 15 | 29 | 30 | 36 | -------------------------------------------------------------------------------- /src/OrchardCoreContrib.Gdpr/Views/GdprSettings.Edit.cshtml: -------------------------------------------------------------------------------- 1 | @using OrchardCoreContrib.Gdpr 2 | @model GdprSettings 3 | 4 |

@T["The current tenant will be reloaded when the settings are saved."]

5 | 6 |
7 | 8 | 9 | 10 | @T["The message to summarize your privacy and cookie use policy."] 11 |
12 | 13 |
14 | 15 | 16 | 17 | @T["The content to detail your site's privacy policy."] 18 |
-------------------------------------------------------------------------------- /src/OrchardCoreContrib.Gdpr/Views/Home/Privacy.cshtml: -------------------------------------------------------------------------------- 1 | @using OrchardCoreContrib.Gdpr 2 | @model GdprSettings 3 | 4 |

Privacy Policy

5 |

@Model.Detail

-------------------------------------------------------------------------------- /src/OrchardCoreContrib.Gdpr/Views/NavigationItemText-gdpr.Id.cshtml: -------------------------------------------------------------------------------- 1 | @T["GDPR"] 2 | -------------------------------------------------------------------------------- /src/OrchardCoreContrib.Gdpr/Views/_ViewImports.cshtml: -------------------------------------------------------------------------------- 1 | @inherits OrchardCore.DisplayManagement.Razor.RazorPage 2 | 3 | @addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers 4 | @addTagHelper *, OrchardCore.DisplayManagement 5 | @addTagHelper *, OrchardCore.ResourceManagement -------------------------------------------------------------------------------- /src/OrchardCoreContrib.GoogleMaps/GoogleMapsDefaults.cs: -------------------------------------------------------------------------------- 1 | namespace OrchardCoreContrib.GoogleMaps 2 | { 3 | public class GoogleMapsDefaults 4 | { 5 | public static readonly double Latitude = 15.5539; 6 | 7 | public static readonly double Longitude = 48.1748; 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /src/OrchardCoreContrib.GoogleMaps/GoogleMapsSettings.cs: -------------------------------------------------------------------------------- 1 | namespace OrchardCoreContrib.GoogleMaps 2 | { 3 | public class GoogleMapsSettings 4 | { 5 | public string ApiKey { get; set; } 6 | 7 | public double Latitude { get; set; } = GoogleMapsDefaults.Latitude; 8 | 9 | public double Longitude { get; set; } = GoogleMapsDefaults.Longitude; 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /src/OrchardCoreContrib.GoogleMaps/Manifest.cs: -------------------------------------------------------------------------------- 1 | using OrchardCore.Modules.Manifest; 2 | using ManifestConstants = OrchardCoreContrib.Modules.Manifest.ManifestConstants; 3 | 4 | [assembly: Module( 5 | Name = "Google Maps", 6 | Author = ManifestConstants.Author, 7 | Website = ManifestConstants.Website, 8 | Version = "1.3.1", 9 | Description = "Displays Google maps.", 10 | Dependencies = new[] { "OrchardCore.Contents" }, 11 | Category = "Content Management" 12 | )] 13 | -------------------------------------------------------------------------------- /src/OrchardCoreContrib.GoogleMaps/Migrations/0001_CreateGoogleMapPart.cs: -------------------------------------------------------------------------------- 1 | using OrchardCore.ContentManagement.Metadata; 2 | using OrchardCore.ContentManagement.Metadata.Settings; 3 | using OrchardCoreContrib.Data.Migrations; 4 | 5 | namespace OrchardCoreContrib.GoogleMaps.Migrations; 6 | 7 | [Migration(1)] 8 | public class CreateGoogleMapPart : Migration 9 | { 10 | private readonly IContentDefinitionManager _contentDefinitionManager; 11 | 12 | public CreateGoogleMapPart(IContentDefinitionManager contentDefinitionManager) 13 | { 14 | _contentDefinitionManager = contentDefinitionManager; 15 | } 16 | 17 | public override void Up() 18 | { 19 | _contentDefinitionManager.AlterPartDefinitionAsync("GoogleMapPart", builder => builder 20 | .Attachable() 21 | .WithDescription("Provides a Google Map that you can use for your content item.")); 22 | } 23 | 24 | public override void Down() 25 | { 26 | _contentDefinitionManager.DeletePartDefinitionAsync("GoogleMapPart").GetAwaiter().GetResult(); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/OrchardCoreContrib.GoogleMaps/Models/GoogleMapPart.cs: -------------------------------------------------------------------------------- 1 | using OrchardCore.ContentManagement; 2 | 3 | namespace OrchardCoreContrib.GoogleMaps.Models 4 | { 5 | public class GoogleMapPart : ContentPart 6 | { 7 | public double Latitude { get; set; } 8 | 9 | public double Longitude { get; set; } 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /src/OrchardCoreContrib.GoogleMaps/Permissions.cs: -------------------------------------------------------------------------------- 1 | using OrchardCore.Security.Permissions; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Threading.Tasks; 5 | 6 | namespace OrchardCoreContrib.GoogleMaps 7 | { 8 | /// 9 | /// Represents a permissions that will be applied into GoogleMaps module. 10 | /// 11 | public class Permissions : IPermissionProvider 12 | { 13 | /// 14 | /// Gets a permission for managing a Gmail settings. 15 | /// 16 | public static readonly Permission ManageGoogleMapsSettings = new Permission("ManageGoogleMapsSettings", "Manage Google Maps Settings"); 17 | 18 | /// 19 | public Task> GetPermissionsAsync() 20 | { 21 | return Task.FromResult(new[] 22 | { 23 | ManageGoogleMapsSettings 24 | } 25 | .AsEnumerable()); 26 | } 27 | 28 | /// 29 | public IEnumerable GetDefaultStereotypes() 30 | { 31 | return new[] 32 | { 33 | new PermissionStereotype 34 | { 35 | Name = "Administrator", 36 | Permissions = new[] { ManageGoogleMapsSettings } 37 | }, 38 | }; 39 | } 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /src/OrchardCoreContrib.GoogleMaps/Startup.cs: -------------------------------------------------------------------------------- 1 | using Fluid; 2 | using Microsoft.Extensions.DependencyInjection; 3 | using OrchardCore.ContentManagement; 4 | using OrchardCore.ContentManagement.Display.ContentDisplay; 5 | using OrchardCore.DisplayManagement.Handlers; 6 | using OrchardCore.Modules; 7 | using OrchardCore.Navigation; 8 | using OrchardCore.Security.Permissions; 9 | using OrchardCore.Settings; 10 | using OrchardCoreContrib.Data.Migrations; 11 | using OrchardCoreContrib.GoogleMaps.Drivers; 12 | using OrchardCoreContrib.GoogleMaps.Migrations; 13 | using OrchardCoreContrib.GoogleMaps.Models; 14 | using OrchardCoreContrib.GoogleMaps.ViewModels; 15 | 16 | namespace OrchardCoreContrib.GoogleMaps 17 | { 18 | public class Startup : StartupBase 19 | { 20 | public override void ConfigureServices(IServiceCollection services) 21 | { 22 | services.Configure(o => 23 | { 24 | o.MemberAccessStrategy.Register(); 25 | o.MemberAccessStrategy.Register(); 26 | }); 27 | 28 | services.AddScoped(); 29 | services.AddScoped(); 30 | 31 | services.AddTransient(); 32 | services.AddScoped, GoogleMapsSettingsDisplayDriver>(); 33 | 34 | services.AddContentPart() 35 | .UseDisplayDriver(); 36 | } 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/OrchardCoreContrib.GoogleMaps/ViewModels/GoogleMapPartViewModel.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.AspNetCore.Mvc.ModelBinding; 2 | using OrchardCore.ContentManagement; 3 | using OrchardCoreContrib.GoogleMaps.Models; 4 | using System; 5 | 6 | namespace OrchardCoreContrib.GoogleMaps.ViewModels 7 | { 8 | public class GoogleMapPartViewModel 9 | { 10 | public double Latitude { get; set; } 11 | 12 | public double Longitude { get; set; } 13 | 14 | [BindNever] 15 | public ContentItem ContentItem { get; set; } 16 | 17 | [BindNever] 18 | public GoogleMapPart GoogleMapPart { get; set; } 19 | 20 | [BindNever] 21 | public GoogleMapsSettings Settings { get; set; } 22 | 23 | public bool DevelopmentMode => String.IsNullOrEmpty(Settings.ApiKey); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/OrchardCoreContrib.GoogleMaps/ViewModels/GoogleMapsSettingsViewModel.cs: -------------------------------------------------------------------------------- 1 | using System.ComponentModel.DataAnnotations; 2 | 3 | namespace OrchardCoreContrib.GoogleMaps.ViewModels 4 | { 5 | public class GoogleMapsSettingsViewModel 6 | { 7 | public string ApiKey { get; set; } 8 | 9 | [Required] 10 | public double Latitude { get; set; } 11 | 12 | [Required] 13 | public double Longitude { get; set; } 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/OrchardCoreContrib.GoogleMaps/Views/GoogleMapPart.Edit.cshtml: -------------------------------------------------------------------------------- 1 | @using OrchardCoreContrib.GoogleMaps.ViewModels 2 | @model GoogleMapPartViewModel 3 | 4 |
5 | 6 | 7 | 8 |
9 | 10 |
11 | 12 | 13 | 14 |
15 | -------------------------------------------------------------------------------- /src/OrchardCoreContrib.GoogleMaps/Views/GoogleMapPart.cshtml: -------------------------------------------------------------------------------- 1 | @using OrchardCoreContrib.GoogleMaps 2 | @using OrchardCoreContrib.GoogleMaps.ViewModels 3 | @model GoogleMapPartViewModel 4 | 5 | @{ 6 | var queryString = Model.DevelopmentMode 7 | ? $"callback=loadMap" 8 | : $"key={Model.Settings.ApiKey}&callback=loadMap"; 9 | } 10 | 11 |
12 | 13 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /src/OrchardCoreContrib.GoogleMaps/Views/GoogleMapsSettings.Edit.cshtml: -------------------------------------------------------------------------------- 1 | @using OrchardCoreContrib.GoogleMaps.ViewModels 2 | @model GoogleMapsSettingsViewModel 3 | 4 |
5 | 6 | 7 | @T["The API key for authentication. If you left the API key empty, the map will be for development purposes only."] 8 |
9 | 10 |
11 | 12 | 13 | 14 |
15 | 16 |
17 | 18 | 19 | 20 |
21 | -------------------------------------------------------------------------------- /src/OrchardCoreContrib.GoogleMaps/Views/NavigationItemText-googlemaps.Id.cshtml: -------------------------------------------------------------------------------- 1 | @T["Google Maps"] 2 | -------------------------------------------------------------------------------- /src/OrchardCoreContrib.GoogleMaps/Views/_ViewImports.cshtml: -------------------------------------------------------------------------------- 1 | @inherits OrchardCore.DisplayManagement.Razor.RazorPage 2 | 3 | @addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers 4 | @addTagHelper *, OrchardCore.DisplayManagement 5 | @addTagHelper *, OrchardCore.ResourceManagement -------------------------------------------------------------------------------- /src/OrchardCoreContrib.Gravatar/GravatarConstants.cs: -------------------------------------------------------------------------------- 1 | namespace OrchardCoreContrib.Gravatar; 2 | 3 | public class GravatarConstants 4 | { 5 | public const int DefaultSize = 80; 6 | } 7 | -------------------------------------------------------------------------------- /src/OrchardCoreContrib.Gravatar/GravatarOptions.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.ComponentModel.DataAnnotations; 3 | 4 | namespace OrchardCoreContrib.Gravatar; 5 | 6 | public class GravatarOptions 7 | { 8 | public string DefaultImage { get; set; } 9 | 10 | public GravatarRating Rating { get; set; } = GravatarRating.PG; 11 | 12 | [Range(1, 512)] 13 | [Obsolete("This property has been deprecated.")] 14 | public int Size { get; set; } = GravatarConstants.DefaultSize; 15 | } 16 | -------------------------------------------------------------------------------- /src/OrchardCoreContrib.Gravatar/GravatarRating.cs: -------------------------------------------------------------------------------- 1 | namespace OrchardCoreContrib.Gravatar; 2 | 3 | public enum GravatarRating 4 | { 5 | G, 6 | PG, 7 | R, 8 | X 9 | } 10 | -------------------------------------------------------------------------------- /src/OrchardCoreContrib.Gravatar/Liquid/GravatarFilter.cs: -------------------------------------------------------------------------------- 1 | using Fluid; 2 | using Fluid.Values; 3 | using OrchardCore.Liquid; 4 | using OrchardCoreContrib.Gravatar.Services; 5 | using System.Threading.Tasks; 6 | 7 | namespace OrchardCoreContrib.Gravatar.Liquid; 8 | 9 | public class GravatarFilter : ILiquidFilter 10 | { 11 | private readonly IGravatarService _gravatarService; 12 | 13 | public GravatarFilter(IGravatarService gravatarService) 14 | { 15 | _gravatarService = gravatarService; 16 | } 17 | 18 | public ValueTask ProcessAsync(FluidValue input, FilterArguments arguments, LiquidTemplateContext context) 19 | { 20 | var email = input.ToStringValue(); 21 | 22 | if (input.IsNil()) 23 | { 24 | return NilValue.Empty; 25 | } 26 | else 27 | { 28 | var size = GravatarConstants.DefaultSize; 29 | if (arguments.Count == 1) 30 | { 31 | size = (int)arguments["size"].ToNumberValue(); 32 | } 33 | 34 | var gravatarUrl = _gravatarService.GetAvatarUrl(email, size); 35 | 36 | return FluidValue.Create(gravatarUrl, context.Options); 37 | } 38 | } 39 | 40 | 41 | } 42 | -------------------------------------------------------------------------------- /src/OrchardCoreContrib.Gravatar/Manifest.cs: -------------------------------------------------------------------------------- 1 | using OrchardCore.Modules.Manifest; 2 | using ManifestConstants = OrchardCoreContrib.Modules.Manifest.ManifestConstants; 3 | 4 | [assembly: Module( 5 | Name = "Gravatar", 6 | Author = ManifestConstants.Author, 7 | Website = ManifestConstants.Website, 8 | Version = "1.4.1", 9 | Category = "Profile", 10 | Description = "The gravatar module enables user avatar using gravatar service.", 11 | Dependencies = new[] { "OrchardCore.Users" } 12 | )] 13 | -------------------------------------------------------------------------------- /src/OrchardCoreContrib.Gravatar/Services/IGravatarService.cs: -------------------------------------------------------------------------------- 1 | namespace OrchardCoreContrib.Gravatar.Services; 2 | 3 | public interface IGravatarService 4 | { 5 | string GetAvatarUrl(string email, int size = GravatarConstants.DefaultSize); 6 | } 7 | -------------------------------------------------------------------------------- /src/OrchardCoreContrib.Gravatar/Startup.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.Extensions.DependencyInjection; 2 | using OrchardCore.Environment.Shell.Configuration; 3 | using OrchardCore.Liquid; 4 | using OrchardCore.Modules; 5 | using OrchardCoreContrib.Gravatar.Liquid; 6 | using OrchardCoreContrib.Gravatar.Services; 7 | using OrchardCoreContrib.Gravatar.TagHelpers; 8 | 9 | namespace OrchardCoreContrib.Gravatar; 10 | 11 | /// 12 | /// Represents an entry point to register the user avatar required services. 13 | /// 14 | public class Startup : StartupBase 15 | { 16 | private readonly IShellConfiguration _shellConfiguration; 17 | 18 | public Startup(IShellConfiguration shellConfiguration) 19 | { 20 | _shellConfiguration = shellConfiguration; 21 | } 22 | 23 | /// 24 | public override void ConfigureServices(IServiceCollection services) 25 | { 26 | services.AddScoped(); 27 | 28 | services.AddTagHelpers(); 29 | 30 | services.AddLiquidFilter("gravatar_url"); 31 | 32 | services.Configure(_shellConfiguration.GetSection("OrchardCoreContrib_Gravatar")); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/OrchardCoreContrib.Gravatar/TagHelpers/GravatarTagHelper.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.AspNetCore.Razor.TagHelpers; 2 | using OrchardCoreContrib.Gravatar.Services; 3 | using System; 4 | using System.ComponentModel.DataAnnotations; 5 | 6 | namespace OrchardCoreContrib.Gravatar.TagHelpers; 7 | 8 | [HtmlTargetElement("gravatar", TagStructure = TagStructure.NormalOrSelfClosing)] 9 | public class GravatarTagHelper : TagHelper 10 | { 11 | private readonly IGravatarService _gravatarService; 12 | 13 | public GravatarTagHelper(IGravatarService gravatarService) 14 | { 15 | _gravatarService = gravatarService; 16 | } 17 | 18 | public string Email { get; set; } 19 | 20 | [Range(1, 512)] 21 | public int Size { get; set; } = GravatarConstants.DefaultSize; 22 | 23 | public override void Process(TagHelperContext context, TagHelperOutput output) 24 | { 25 | output.TagName = "img"; 26 | 27 | var avatarUrl = _gravatarService.GetAvatarUrl(Email, Size); 28 | 29 | output.Attributes.Add("src", avatarUrl); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/OrchardCoreContrib.Gravatar/Views/_ViewImports.cshtml: -------------------------------------------------------------------------------- 1 | @inherits OrchardCore.DisplayManagement.Razor.RazorPage 2 | @addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers 3 | @addTagHelper *, OrchardCore.DisplayManagement 4 | @addTagHelper *, OrchardCore.ResourceManagement 5 | @addTagHelper *, OrchardCoreContrib.Gravatar 6 | 7 | @using Microsoft.Extensions.Localization; 8 | @using Microsoft.AspNetCore.Mvc.Localization; -------------------------------------------------------------------------------- /src/OrchardCoreContrib.HealthChecks/Manifest.cs: -------------------------------------------------------------------------------- 1 | using OrchardCore.Modules.Manifest; 2 | using ManifestConstants = OrchardCoreContrib.Modules.Manifest.ManifestConstants; 3 | 4 | [assembly: Module( 5 | Name = "Health Checks", 6 | Author = ManifestConstants.Author, 7 | Website = ManifestConstants.Website, 8 | Version = "1.2.1", 9 | Description = "Provides health checks for the website.", 10 | Category = "Infrastructure" 11 | )] 12 | -------------------------------------------------------------------------------- /src/OrchardCoreContrib.Html/Controllers/AdminController.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.AspNetCore.Mvc; 2 | using OrchardCore.Modules; 3 | 4 | namespace OrchardCoreContrib.Html.Controllers 5 | { 6 | [Feature("OrchardCoreContrib.Html.GrapesJS")] 7 | public class AdminController : Controller 8 | { 9 | [HttpGet] 10 | public ActionResult Index() => View(); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /src/OrchardCoreContrib.Html/Manifest.cs: -------------------------------------------------------------------------------- 1 | using OrchardCore.Modules.Manifest; 2 | using ManifestConstants = OrchardCoreContrib.Modules.Manifest.ManifestConstants; 3 | 4 | [assembly: Module( 5 | Name = "Html", 6 | Author = ManifestConstants.Author, 7 | Website = ManifestConstants.Website, 8 | Version = "1.2.1" 9 | )] 10 | 11 | [assembly: Feature( 12 | Id = "OrchardCoreContrib.Html.GrapesJS", 13 | Name = "GrapesJS HTML Editor", 14 | Description = "Enables GrapesJS editor for HtmlBody content.", 15 | Dependencies = new[] { "OrchardCore.Html" }, 16 | Category = "Content Management" 17 | )] 18 | -------------------------------------------------------------------------------- /src/OrchardCoreContrib.Html/Startup.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Microsoft.AspNetCore.Builder; 3 | using Microsoft.AspNetCore.Routing; 4 | using OrchardCore.Modules; 5 | using OrchardCore.Mvc.Core.Utilities; 6 | using OrchardCoreContrib.Html.Controllers; 7 | 8 | namespace OrchardCoreContrib.Html 9 | { 10 | [Feature("OrchardCoreContrib.Html.GrapesJS")] 11 | public class Startup : StartupBase 12 | { 13 | public override void Configure(IApplicationBuilder builder, IEndpointRouteBuilder routes, IServiceProvider serviceProvider) 14 | { 15 | routes.MapAreaControllerRoute( 16 | name: "GrapesJSEditor", 17 | areaName: "OrchardCoreContrib.Html", 18 | pattern: "GrapesJSEditor", 19 | defaults: new { controller = typeof(AdminController).ControllerName(), action = nameof(AdminController.Index) } 20 | ); 21 | } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/OrchardCoreContrib.Html/Views/Admin/Index.cshtml: -------------------------------------------------------------------------------- 1 | @{ 2 | Layout = null; 3 | } 4 | 5 | 6 | 7 | 8 |
9 |
10 | 11 | 12 | 13 | 14 | 15 | 18 |
-------------------------------------------------------------------------------- /src/OrchardCoreContrib.Html/Views/HtmlBodyPart-GrapeJS.Edit.cshtml: -------------------------------------------------------------------------------- 1 | @model HtmlBodyPartViewModel 2 | 3 |
4 | 5 | 6 | 7 | 9 | @T["The body of the content item."] 10 |
-------------------------------------------------------------------------------- /src/OrchardCoreContrib.Html/Views/HtmlBodyPart-GrapeJS.Option.cshtml: -------------------------------------------------------------------------------- 1 | @{ 2 | string currentEditor = Model.Editor; 3 | } 4 | 5 | -------------------------------------------------------------------------------- /src/OrchardCoreContrib.Html/Views/_ViewImports.cshtml: -------------------------------------------------------------------------------- 1 | @inherits OrchardCore.DisplayManagement.Razor.RazorPage 2 | @addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers 3 | @addTagHelper *, OrchardCore.DisplayManagement 4 | @addTagHelper *, OrchardCore.ResourceManagement 5 | @using OrchardCore.ContentManagement.Metadata.Models 6 | @using OrchardCore.DisplayManagement 7 | @using OrchardCore.Html.ViewModels 8 | -------------------------------------------------------------------------------- /src/OrchardCoreContrib.Html/wwwroot/Styles/grapes-editor.css: -------------------------------------------------------------------------------- 1 | .grapes-editor { 2 | border: 3px solid #444; 3 | } 4 | 5 | .gjs_override * { 6 | box-sizing: content-box !important; 7 | } 8 | 9 | .gjs-mdl-content pre { 10 | color: white !important; 11 | } 12 | 13 | body { 14 | margin: 0; 15 | } 16 | -------------------------------------------------------------------------------- /src/OrchardCoreContrib.Html/wwwroot/Styles/grapesjs-preset-webpage.min.css: -------------------------------------------------------------------------------- 1 | .gjs-one-bg{background-color:#463a3c}.gjs-one-color{color:#463a3c}.gjs-one-color-h:hover{color:#463a3c}.gjs-two-bg{background-color:#b9a5a6}.gjs-two-color{color:#b9a5a6}.gjs-two-color-h:hover{color:#b9a5a6}.gjs-three-bg{background-color:#804f7b}.gjs-three-color{color:#804f7b}.gjs-three-color-h:hover{color:#804f7b}.gjs-four-bg{background-color:#d97aa6}.gjs-four-color{color:#d97aa6}.gjs-four-color-h:hover{color:#d97aa6} 2 | -------------------------------------------------------------------------------- /src/OrchardCoreContrib.Html/wwwroot/fonts/main-fonts.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OrchardCoreContrib/OrchardCoreContrib.Modules/3a124143f9e750c2d34535492c353f555dbe1d4b/src/OrchardCoreContrib.Html/wwwroot/fonts/main-fonts.woff -------------------------------------------------------------------------------- /src/OrchardCoreContrib.Liquid/Environment.cs: -------------------------------------------------------------------------------- 1 | using Fluid.Values; 2 | 3 | namespace OrchardCoreContrib.Liquid; 4 | 5 | public class Environment 6 | { 7 | public BooleanValue IsDevelopment { get; set; } 8 | 9 | public BooleanValue IsStaging { get; set; } 10 | 11 | public BooleanValue IsProduction { get; set; } 12 | } 13 | -------------------------------------------------------------------------------- /src/OrchardCoreContrib.Liquid/Manifest.cs: -------------------------------------------------------------------------------- 1 | using OrchardCore.Modules.Manifest; 2 | using ManifestConstants = OrchardCoreContrib.Modules.Manifest.ManifestConstants; 3 | 4 | [assembly: Module( 5 | Name = "Liquid", 6 | Author = ManifestConstants.Author, 7 | Website = ManifestConstants.Website, 8 | Version = "1.2.1", 9 | Description = "Provides a list of useful liquid filters.", 10 | Category = "Content Management" 11 | )] 12 | -------------------------------------------------------------------------------- /src/OrchardCoreContrib.Liquid/Startup.cs: -------------------------------------------------------------------------------- 1 | using Fluid; 2 | using Fluid.Values; 3 | using Microsoft.Extensions.DependencyInjection; 4 | using Microsoft.Extensions.Hosting; 5 | using OrchardCore.Modules; 6 | 7 | namespace OrchardCoreContrib.Liquid; 8 | public class Startup : StartupBase 9 | { 10 | private readonly IHostEnvironment _hostEnvironment; 11 | 12 | public Startup(IHostEnvironment hostEnvironment) 13 | { 14 | _hostEnvironment = hostEnvironment; 15 | } 16 | 17 | public override void ConfigureServices(IServiceCollection services) 18 | { 19 | var environment = new Environment 20 | { 21 | IsDevelopment = BooleanValue.Create(_hostEnvironment.IsDevelopment()), 22 | IsStaging = BooleanValue.Create(_hostEnvironment.IsStaging()), 23 | IsProduction = BooleanValue.Create(_hostEnvironment.IsProduction()) 24 | }; 25 | 26 | services.Configure(options => 27 | { 28 | options.Scope.SetValue("Environment", new ObjectValue(environment)); 29 | 30 | options.MemberAccessStrategy.Register(); 31 | }); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/OrchardCoreContrib.Modules.Web/MigrationUpdater.cs: -------------------------------------------------------------------------------- 1 | using OrchardCore.Environment.Extensions.Features; 2 | using OrchardCore.Environment.Shell; 3 | using OrchardCoreContrib.Data.Migrations; 4 | using System.Threading.Tasks; 5 | 6 | namespace OrchardCoreContrib.Modules.Web; 7 | 8 | public class MigrationUpdater : IFeatureEventHandler 9 | { 10 | private readonly IMigrationRunner _migrationRunner; 11 | 12 | public MigrationUpdater(IMigrationRunner migrationRunner) 13 | { 14 | _migrationRunner = migrationRunner; 15 | } 16 | 17 | public Task DisabledAsync(IFeatureInfo feature) => Task.CompletedTask; 18 | 19 | public Task DisablingAsync(IFeatureInfo feature) => Task.CompletedTask; 20 | 21 | public Task EnabledAsync(IFeatureInfo feature) => Task.CompletedTask; 22 | 23 | public Task EnablingAsync(IFeatureInfo feature) => Task.CompletedTask; 24 | 25 | public async Task InstalledAsync(IFeatureInfo feature) 26 | => await _migrationRunner.MigrateAsync(feature.Extension.Manifest.ModuleInfo.Id); 27 | 28 | public Task InstallingAsync(IFeatureInfo feature) => Task.CompletedTask; 29 | 30 | public async Task UninstalledAsync(IFeatureInfo feature) 31 | => await _migrationRunner.RollbackAsync(feature.Extension.Manifest.ModuleInfo.Id); 32 | 33 | public Task UninstallingAsync(IFeatureInfo feature) => Task.CompletedTask; 34 | 35 | } 36 | -------------------------------------------------------------------------------- /src/OrchardCoreContrib.Modules.Web/Program.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.AspNetCore.Hosting; 2 | using Microsoft.Extensions.Hosting; 3 | 4 | namespace OrchardCoreContrib.Modules.Web 5 | { 6 | public class Program 7 | { 8 | public static void Main(string[] args) 9 | { 10 | CreateHostBuilder(args).Build().Run(); 11 | } 12 | 13 | public static IHostBuilder CreateHostBuilder(string[] args) => 14 | Host.CreateDefaultBuilder(args) 15 | .ConfigureWebHostDefaults(webBuilder => 16 | { 17 | webBuilder.UseStartup(); 18 | }); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/OrchardCoreContrib.Modules.Web/Properties/launchSettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "iisSettings": { 3 | "windowsAuthentication": false, 4 | "anonymousAuthentication": true, 5 | "iisExpress": { 6 | "applicationUrl": "http://localhost:51842", 7 | "sslPort": 44375 8 | } 9 | }, 10 | "profiles": { 11 | "IIS Express": { 12 | "commandName": "IISExpress", 13 | "launchBrowser": true, 14 | "environmentVariables": { 15 | "ASPNETCORE_ENVIRONMENT": "Development" 16 | } 17 | }, 18 | "OrchardCoreContrib.Modules.Web": { 19 | "commandName": "Project", 20 | "launchBrowser": true, 21 | "applicationUrl": "https://localhost:5001;http://localhost:5000", 22 | "environmentVariables": { 23 | "ASPNETCORE_ENVIRONMENT": "Development" 24 | } 25 | } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/OrchardCoreContrib.Modules.Web/Startup.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.AspNetCore.Builder; 2 | using Microsoft.AspNetCore.Hosting; 3 | using Microsoft.Extensions.DependencyInjection; 4 | using Microsoft.Extensions.Hosting; 5 | using OrchardCore.Environment.Shell; 6 | using OrchardCoreContrib.Users.Services; 7 | 8 | namespace OrchardCoreContrib.Modules.Web 9 | { 10 | public class Startup 11 | { 12 | public void ConfigureServices(IServiceCollection services) 13 | { 14 | services 15 | .AddOrchardCms(builder => 16 | { 17 | builder.AddSetupFeatures("OrchardCore.AutoSetup", "OrchardCoreContrib.Tenants"); 18 | //builder.ConfigureServices(builderServices => 19 | //{ 20 | // builderServices.AddYesSqlDataMigrations(); 21 | 22 | // builderServices.AddScoped(); 23 | // builderServices.AddScoped(sp => sp.GetRequiredService()); 24 | //}); 25 | }); 26 | 27 | // Workaround to avoid IOE on UserMenu shape 28 | services.AddScoped(); 29 | } 30 | 31 | public void Configure(IApplicationBuilder app, IWebHostEnvironment env) 32 | { 33 | if (env.IsDevelopment()) 34 | { 35 | app.UseDeveloperExceptionPage(); 36 | } 37 | 38 | app.UseOrchardCore(); 39 | } 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /src/OrchardCoreContrib.Modules.Web/appsettings.Development.json: -------------------------------------------------------------------------------- 1 | { 2 | "Logging": { 3 | "LogLevel": { 4 | "Default": "Information", 5 | "Microsoft": "Warning", 6 | "Microsoft.Hosting.Lifetime": "Information" 7 | } 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /src/OrchardCoreContrib.Modules.Web/wwwroot/.placeholder: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OrchardCoreContrib/OrchardCoreContrib.Modules/3a124143f9e750c2d34535492c353f555dbe1d4b/src/OrchardCoreContrib.Modules.Web/wwwroot/.placeholder -------------------------------------------------------------------------------- /src/OrchardCoreContrib.ReverseProxy.Yarp/Manifest.cs: -------------------------------------------------------------------------------- 1 | using OrchardCore.Modules.Manifest; 2 | using ManifestConstants = OrchardCoreContrib.Modules.Manifest.ManifestConstants; 3 | 4 | [assembly: Module( 5 | Name = "Yet Another Reverse Proxy (YARP)", 6 | Author = ManifestConstants.Author, 7 | Website = ManifestConstants.Website, 8 | Version = "1.2.1", 9 | Description = "Enables configuration of hosting scenarios with a reverse proxy using YARP", 10 | Category = "Infrastructure" 11 | )] 12 | -------------------------------------------------------------------------------- /src/OrchardCoreContrib.ReverseProxy.Yarp/Startup.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.AspNetCore.Builder; 2 | using Microsoft.AspNetCore.Routing; 3 | using Microsoft.Extensions.DependencyInjection; 4 | using OrchardCore.Environment.Shell.Configuration; 5 | using OrchardCore.Modules; 6 | using System; 7 | 8 | namespace OrchardCoreContrib.ReverseProxy.Yarp; 9 | 10 | public class Startup : StartupBase 11 | { 12 | private readonly IShellConfiguration _shellConfiguration; 13 | 14 | public Startup(IShellConfiguration shellConfiguration) 15 | { 16 | _shellConfiguration = shellConfiguration; 17 | } 18 | 19 | public override int Order => -1; 20 | 21 | public override void Configure(IApplicationBuilder app, IEndpointRouteBuilder routes, IServiceProvider serviceProvider) 22 | { 23 | routes.MapReverseProxy(); 24 | } 25 | 26 | public override void ConfigureServices(IServiceCollection services) 27 | { 28 | services 29 | .AddReverseProxy() 30 | .LoadFromConfig(_shellConfiguration.GetSection("OrchardCoreContrib_Yarp")); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/OrchardCoreContrib.Sms.Azure/AdminMenu.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.AspNetCore.Routing; 2 | using Microsoft.Extensions.Localization; 3 | using OrchardCore.Navigation; 4 | using OrchardCoreContrib.Navigation; 5 | using OrchardCoreContrib.Sms.Azure.Drivers; 6 | 7 | namespace OrchardCoreContrib.Sms.Azure; 8 | 9 | using OrchardCoreContrib.Navigation; 10 | 11 | public class AdminMenu(IStringLocalizer S) : AdminNavigationProvider 12 | { 13 | private static readonly RouteValueDictionary _routeValues = new() 14 | { 15 | { "area", "OrchardCore.Settings" }, 16 | { "groupId", AzureSmsSettingsDisplayDriver.GroupId }, 17 | }; 18 | 19 | public override void BuildNavigation(NavigationBuilder builder) 20 | { 21 | builder 22 | .Add(S["Configuration"], configuration => configuration 23 | .Add(S["Settings"], settings => settings 24 | .Add(S["Azure SMS"], S["Azure SMS"].PrefixPosition(), sms => sms 25 | .AddClass("azure-sms").Id("azuresms") 26 | .Action("Index", "Admin", _routeValues) 27 | .Permission(AzureSmsPermissions.ManageSettings) 28 | .LocalNav() 29 | ) 30 | ) 31 | ); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/OrchardCoreContrib.Sms.Azure/AzureSmsPermissionProvider.cs: -------------------------------------------------------------------------------- 1 | using OrchardCore.Security.Permissions; 2 | 3 | namespace OrchardCoreContrib.Sms.Azure; 4 | 5 | public class AzureSmsPermissionProvider : IPermissionProvider 6 | { 7 | private static readonly IEnumerable _permissions = [AzureSmsPermissions.ManageSettings]; 8 | 9 | public Task> GetPermissionsAsync() => Task.FromResult(_permissions); 10 | 11 | public IEnumerable GetDefaultStereotypes() => 12 | [ 13 | new PermissionStereotype 14 | { 15 | Name = "Administrator", 16 | Permissions = _permissions, 17 | } 18 | ]; 19 | } 20 | -------------------------------------------------------------------------------- /src/OrchardCoreContrib.Sms.Azure/AzureSmsPermissions.cs: -------------------------------------------------------------------------------- 1 | using OrchardCore.Security.Permissions; 2 | 3 | namespace OrchardCoreContrib.Sms.Azure; 4 | 5 | public class AzureSmsPermissions 6 | { 7 | public static readonly Permission ManageSettings = new("ManageSettings", "Manage Azure SMS Settings"); 8 | } 9 | -------------------------------------------------------------------------------- /src/OrchardCoreContrib.Sms.Azure/AzureSmsSettings.cs: -------------------------------------------------------------------------------- 1 | namespace OrchardCoreContrib.Sms.Azure; 2 | 3 | public class AzureSmsSettings 4 | { 5 | public string ConnectionString { get; set; } 6 | 7 | public string SenderPhoneNumber { get; set; } 8 | } 9 | -------------------------------------------------------------------------------- /src/OrchardCoreContrib.Sms.Azure/Manifest.cs: -------------------------------------------------------------------------------- 1 | using OrchardCore.Modules.Manifest; 2 | using ManifestConstants = OrchardCoreContrib.Modules.Manifest.ManifestConstants; 3 | 4 | [assembly: Module( 5 | Name = "Azure SMS", 6 | Author = ManifestConstants.Author, 7 | Website = ManifestConstants.Website, 8 | Version = "1.0.1", 9 | Description = "Provides settings and services to send SMS messages using Azure Communication Service.", 10 | Category = "Messaging" 11 | )] 12 | -------------------------------------------------------------------------------- /src/OrchardCoreContrib.Sms.Azure/Services/AzureSmsService.cs: -------------------------------------------------------------------------------- 1 | using Azure.Communication.Sms; 2 | using Microsoft.Extensions.Localization; 3 | using Microsoft.Extensions.Logging; 4 | using Microsoft.Extensions.Options; 5 | using OrchardCoreContrib.Infrastructure; 6 | 7 | namespace OrchardCoreContrib.Sms.Azure.Services; 8 | 9 | public class AzureSmsService( 10 | IOptions azureSmsOptions, 11 | ILogger logger, 12 | IStringLocalizer S) : ISmsService 13 | { 14 | private readonly AzureSmsSettings _azureSmsOptions = azureSmsOptions.Value; 15 | private readonly ILogger _logger = logger; 16 | 17 | public async Task SendAsync(SmsMessage message) 18 | { 19 | Guard.ArgumentNotNull(message, nameof(message)); 20 | 21 | _logger.LogDebug("Attempting to send SMS to {PhoneNumber}.", message.PhoneNumber); 22 | 23 | try 24 | { 25 | var client = new SmsClient(_azureSmsOptions.ConnectionString); 26 | var smsResult = await client.SendAsync(_azureSmsOptions.SenderPhoneNumber, message.PhoneNumber, message.Text); 27 | 28 | return SmsResult.Success; 29 | } 30 | catch (Exception ex) 31 | { 32 | _logger.LogError(ex, "An error occurred while sending an SMS using the Azure SMS."); 33 | 34 | return SmsResult.Failed(S["An error occurred while sending an SMS."]); 35 | } 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/OrchardCoreContrib.Sms.Azure/ViewModels/AzureSmsSettingsViewModel.cs: -------------------------------------------------------------------------------- 1 | using System.ComponentModel.DataAnnotations; 2 | 3 | namespace OrchardCoreContrib.Sms.Azure.ViewModels; 4 | 5 | public class AzureSmsSettingsViewModel 6 | { 7 | [Required] 8 | public string PhoneNumber { get; set; } 9 | 10 | [Required] 11 | public string Message { get; set; } 12 | } 13 | -------------------------------------------------------------------------------- /src/OrchardCoreContrib.Sms.Azure/Views/Admin/Index.cshtml: -------------------------------------------------------------------------------- 1 | @using OrchardCoreContrib.Sms.Azure.ViewModels 2 | @model AzureSmsSettingsViewModel 3 | 4 |

@RenderTitleSegments(T["Test Azure SMS Settings"])

5 | 6 |
7 | @Html.ValidationSummary() 8 | 9 |
10 | 11 | 12 | 13 |
14 |
15 | 16 | 17 | 18 |
19 |
20 | 21 |
22 |
23 | -------------------------------------------------------------------------------- /src/OrchardCoreContrib.Sms.Azure/Views/AzureSmsSettings.Edit.cshtml: -------------------------------------------------------------------------------- 1 | @using OrchardCoreContrib.Sms.Azure 2 | 3 | @model AzureSmsSettings 4 | 5 |

@T["The current tenant will be reloaded when the settings are saved."]

6 | 7 |
8 | 9 | 10 | @T["The phone number that provided by Azure Communication Services (ACS) to send the SMS."] 11 | 12 |
13 | 14 |
15 | 16 | 17 | 18 | @T["The connection string that provided by Azure Communication Services (ACS)."] 19 |
20 | -------------------------------------------------------------------------------- /src/OrchardCoreContrib.Sms.Azure/Views/AzureSmsSettings.TestButton.cshtml: -------------------------------------------------------------------------------- 1 | @T["Test settings"] 2 | -------------------------------------------------------------------------------- /src/OrchardCoreContrib.Sms.Azure/Views/NavigationItemText-azuresms.Id.cshtml: -------------------------------------------------------------------------------- 1 | @T["Azure SMS"] 2 | -------------------------------------------------------------------------------- /src/OrchardCoreContrib.Sms.Azure/Views/_ViewImports.cshtml: -------------------------------------------------------------------------------- 1 | @inherits OrchardCore.DisplayManagement.Razor.RazorPage 2 | 3 | @addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers 4 | @addTagHelper *, OrchardCore.DisplayManagement 5 | @addTagHelper *, OrchardCore.ResourceManagement 6 | -------------------------------------------------------------------------------- /src/OrchardCoreContrib.System/AdminMenu.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.Extensions.Localization; 2 | using OrchardCore.Navigation; 3 | using OrchardCoreContrib.Navigation; 4 | 5 | namespace OrchardCoreContrib.System; 6 | 7 | using OrchardCoreContrib.Navigation; 8 | 9 | /// 10 | /// Represents an admin menu for System module. 11 | /// 12 | public class AdminMenu : AdminNavigationProvider 13 | { 14 | private readonly IStringLocalizer S; 15 | 16 | /// 17 | /// Initializes a new instance of . 18 | /// 19 | /// The . 20 | public AdminMenu(IStringLocalizer stringLocalizer) 21 | { 22 | S = stringLocalizer; 23 | } 24 | 25 | /// 26 | public override void BuildNavigation(NavigationBuilder builder) 27 | { 28 | builder.Add(S["System"], "100", info => info 29 | .AddClass("system").Id("system") 30 | .Add(S["Info"], S["Info"].PrefixPosition(), updates => updates 31 | .AddClass("info").Id("info") 32 | .Action("About", "Admin", "OrchardCoreContrib.System") 33 | .LocalNav()) 34 | ); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/OrchardCoreContrib.System/Extensions/ApplicationBuilderExtensions.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.Extensions.DependencyInjection; 2 | using Microsoft.Extensions.Logging; 3 | using Microsoft.Extensions.Options; 4 | using OrchardCore.Admin; 5 | using OrchardCore.ContentManagement.Routing; 6 | using OrchardCore.Settings; 7 | using OrchardCore.Users; 8 | using OrchardCoreContrib.System.Services; 9 | 10 | namespace Microsoft.AspNetCore.Builder; 11 | 12 | public static class ApplicationBuilderExtensions 13 | { 14 | public static IApplicationBuilder UseMaintenanceRedirect(this IApplicationBuilder app) 15 | { 16 | if (app == null) 17 | { 18 | throw new ArgumentNullException(nameof(app)); 19 | } 20 | 21 | var siteService = app.ApplicationServices.GetService(); 22 | var adminOptions = app.ApplicationServices.GetService>(); 23 | var userOptions = app.ApplicationServices.GetService>(); 24 | var autorouteEntries = app.ApplicationServices.GetService(); 25 | var logger = app.ApplicationServices.GetService>(); 26 | 27 | return app.UseMiddleware(siteService, adminOptions, userOptions, autorouteEntries, logger); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/OrchardCoreContrib.System/HealthChecks/Extensions/SystemUpdatesHealthCheckExtensions.cs: -------------------------------------------------------------------------------- 1 | using OrchardCoreContrib.System.HealthChecks; 2 | 3 | namespace Microsoft.Extensions.DependencyInjection; 4 | 5 | public static class SystemUpdatesHealthCheckExtensions 6 | { 7 | public static IHealthChecksBuilder AddSystemUpdatesCheck(this IHealthChecksBuilder healthChecksBuilder) 8 | => healthChecksBuilder.AddCheck(SystemUpdatesHealthCheck.Name); 9 | } 10 | -------------------------------------------------------------------------------- /src/OrchardCoreContrib.System/HealthChecks/SystemUpdatesHealthCheck.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.Extensions.Diagnostics.HealthChecks; 2 | using Microsoft.Extensions.Localization; 3 | using OrchardCoreContrib.System.Services; 4 | 5 | namespace OrchardCoreContrib.System.HealthChecks; 6 | 7 | public class SystemUpdatesHealthCheck : IHealthCheck 8 | { 9 | internal const string Name = "System Updates Health Check"; 10 | 11 | private readonly SystemInformation _systemInformation; 12 | private readonly ISystemUpdateService _systemUpdateService; 13 | private readonly IStringLocalizer S; 14 | 15 | public SystemUpdatesHealthCheck( 16 | SystemInformation systemInformation, 17 | ISystemUpdateService systemUpdateService, 18 | IStringLocalizer stringLocalizer) 19 | { 20 | _systemInformation = systemInformation; 21 | _systemUpdateService = systemUpdateService; 22 | S = stringLocalizer; 23 | } 24 | 25 | public async Task CheckHealthAsync(HealthCheckContext context, CancellationToken cancellationToken = default) 26 | { 27 | var updates = await _systemUpdateService.GetUpdatesAsync(); 28 | 29 | var updatesCount = updates.Count(u => u.Version > _systemInformation.OrchardCoreVersion); 30 | 31 | return updatesCount == 0 32 | ? HealthCheckResult.Healthy() 33 | : HealthCheckResult.Unhealthy(S.Plural(updatesCount, "There's {0} update available.", "There're {0} updates available.", updatesCount)); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/OrchardCoreContrib.System/Manifest.cs: -------------------------------------------------------------------------------- 1 | using OrchardCore.Modules.Manifest; 2 | using ManifestConstants = OrchardCoreContrib.Modules.Manifest.ManifestConstants; 3 | 4 | [assembly: Module( 5 | Name = "System", 6 | Author = ManifestConstants.Author, 7 | Website = ManifestConstants.Website, 8 | Version = "1.4.1", 9 | Category = "Utilities" 10 | )] 11 | 12 | [assembly: Feature( 13 | Id = "OrchardCoreContrib.System", 14 | Name = "System", 15 | Description = "Provides an information about currently running application.", 16 | DefaultTenantOnly = true 17 | )] 18 | 19 | [assembly: Feature( 20 | Id = "OrchardCoreContrib.System.Updates", 21 | Name = "System Updates", 22 | Description = "Displays the available system updates.", 23 | Dependencies = new[] { "OrchardCoreContrib.System" }, 24 | DefaultTenantOnly = true 25 | )] 26 | 27 | [assembly: Feature( 28 | Id = "OrchardCoreContrib.System.Maintenance", 29 | Name = "System Maintenance", 30 | Description = "Put your site in maintenance mode while you're doing upgrades.", 31 | Dependencies = new[] { "OrchardCore.Autoroute" } 32 | )] 33 | -------------------------------------------------------------------------------- /src/OrchardCoreContrib.System/Models/SystemUpdate.cs: -------------------------------------------------------------------------------- 1 | using NuGet.Versioning; 2 | 3 | namespace OrchardCoreContrib.System.Models; 4 | 5 | public class SystemUpdate 6 | { 7 | private readonly NuGetVersion _version; 8 | 9 | public SystemUpdate(NuGetVersion version) 10 | { 11 | _version = version; 12 | } 13 | 14 | public Version Version => _version.Version; 15 | 16 | public override string ToString() => _version.ToFullString(); 17 | } 18 | -------------------------------------------------------------------------------- /src/OrchardCoreContrib.System/Permissions.cs: -------------------------------------------------------------------------------- 1 | using OrchardCore.Security.Permissions; 2 | 3 | namespace OrchardCoreContrib.System; 4 | 5 | /// 6 | /// Represents a permissions that will be applied into System module. 7 | /// 8 | public class Permissions : IPermissionProvider 9 | { 10 | /// 11 | /// Gets a permission for managing a System settings. 12 | /// 13 | public static readonly Permission ManageSystemSettings = new("ManageSystemSettings", "Manage System Settings"); 14 | 15 | /// 16 | public Task> GetPermissionsAsync() => Task.FromResult(new[] { ManageSystemSettings }.AsEnumerable()); 17 | 18 | /// 19 | public IEnumerable GetDefaultStereotypes() => new[] 20 | { 21 | new PermissionStereotype 22 | { 23 | Name = "Administrator", 24 | Permissions = new[] { ManageSystemSettings } 25 | }, 26 | }; 27 | } 28 | -------------------------------------------------------------------------------- /src/OrchardCoreContrib.System/Services/ISystemUpdateService.cs: -------------------------------------------------------------------------------- 1 | using OrchardCoreContrib.System.Models; 2 | 3 | namespace OrchardCoreContrib.System.Services; 4 | 5 | public interface ISystemUpdateService 6 | { 7 | Task> GetUpdatesAsync(); 8 | } 9 | -------------------------------------------------------------------------------- /src/OrchardCoreContrib.System/Services/SystemInformation.cs: -------------------------------------------------------------------------------- 1 | using OrchardCore; 2 | using OrchardCore.Data; 3 | using OrchardCore.Environment.Shell; 4 | using System.Reflection; 5 | using System.Runtime.InteropServices; 6 | 7 | namespace OrchardCoreContrib.System.Services; 8 | 9 | public class SystemInformation 10 | { 11 | private readonly ShellSettings _defaultShellSettings; 12 | private readonly Assembly _executedAssembly; 13 | 14 | public SystemInformation(IShellHost shellHost) 15 | { 16 | _executedAssembly = Assembly.GetEntryAssembly(); 17 | _defaultShellSettings = shellHost.GetSettings(ShellSettings.DefaultShellName); 18 | } 19 | 20 | public string ApplicationName => _executedAssembly.GetName().Name; 21 | 22 | public Version ApplicationVersion => _executedAssembly.GetName().Version; 23 | 24 | public Version OrchardCoreVersion => typeof(IOrchardHelper).Assembly.GetName().Version; 25 | 26 | public string AspNetCoreVersion => RuntimeInformation.FrameworkDescription; 27 | 28 | public string OSVersion => RuntimeInformation.OSDescription; 29 | 30 | public string DatabaseProvider => _defaultShellSettings["DatabaseProvider"] switch 31 | { 32 | DatabaseProviderValue.Sqlite => "SQLite", 33 | DatabaseProviderValue.SqlConnection => "SQL Server", 34 | DatabaseProviderValue.MySql => "MySQL", 35 | DatabaseProviderValue.Postgres => "Postgres SQL", 36 | _ => "Unknown" 37 | }; 38 | } 39 | -------------------------------------------------------------------------------- /src/OrchardCoreContrib.System/SystemMaintenanceConstants.cs: -------------------------------------------------------------------------------- 1 | namespace OrchardCoreContrib.System; 2 | 3 | public class SystemMaintenanceConstants 4 | { 5 | public const string MaintenancePath = "/maintenance"; 6 | 7 | public const string DefaultMaintenancePageContent = @"
8 |

Under Maintenance

9 |

This website is currently offline for maintenance. Please try again later.

10 |
"; 11 | } 12 | -------------------------------------------------------------------------------- /src/OrchardCoreContrib.System/SystemSettings.cs: -------------------------------------------------------------------------------- 1 | namespace OrchardCoreContrib.System; 2 | 3 | public class SystemSettings 4 | { 5 | public bool AllowMaintenanceMode { get; set; } 6 | } 7 | -------------------------------------------------------------------------------- /src/OrchardCoreContrib.System/SystemUpdatesConstants.cs: -------------------------------------------------------------------------------- 1 | namespace OrchardCoreContrib.System; 2 | 3 | public class SystemUpdatesConstants 4 | { 5 | public const string NugetPackageSource = "https://api.nuget.org/v3/index.json"; 6 | 7 | public const string NuGetPackageUrl = "https://www.nuget.org/packages"; 8 | 9 | public const string OrchardCorePackageId = "OrchardCore"; 10 | } 11 | -------------------------------------------------------------------------------- /src/OrchardCoreContrib.System/UpdatesAdminMenu.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.Extensions.Localization; 2 | using OrchardCore.Navigation; 3 | using OrchardCoreContrib.Navigation; 4 | 5 | namespace OrchardCoreContrib.System; 6 | 7 | using OrchardCoreContrib.Navigation; 8 | 9 | /// 10 | /// Represents an admin menu for System Updates feature. 11 | /// 12 | public class UpdatesAdminMenu : AdminNavigationProvider 13 | { 14 | private readonly IStringLocalizer S; 15 | 16 | /// 17 | /// Initializes a new instance of . 18 | /// 19 | /// The . 20 | public UpdatesAdminMenu(IStringLocalizer stringLocalizer) 21 | { 22 | S = stringLocalizer; 23 | } 24 | 25 | /// 26 | public override void BuildNavigation(NavigationBuilder builder) 27 | { 28 | builder.Add(S["System"], "100", info => info 29 | .AddClass("system").Id("system") 30 | .Add(S["Info"], S["Info"].PrefixPosition(), updates => updates 31 | .AddClass("info").Id("info") 32 | .Action("About", "Admin", "OrchardCoreContrib.System") 33 | .LocalNav()) 34 | .Add(S["Updates"], S["Updates"].PrefixPosition(), updates => updates 35 | .AddClass("updates").Id("updates") 36 | .Action("Updates", "Admin", "OrchardCoreContrib.System") 37 | .LocalNav()) 38 | ); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/OrchardCoreContrib.System/ViewModels/AboutViewModel.cs: -------------------------------------------------------------------------------- 1 | using OrchardCore.Environment.Extensions.Features; 2 | using OrchardCore.Environment.Shell; 3 | using OrchardCoreContrib.System.Services; 4 | 5 | namespace OrchardCoreContrib.System.ViewModels; 6 | 7 | public class AboutViewModel 8 | { 9 | public SystemInformation SystemInformation { get; set; } 10 | 11 | public IEnumerable Tenants { get; set; } 12 | 13 | public IEnumerable Features { get; set; } 14 | } 15 | -------------------------------------------------------------------------------- /src/OrchardCoreContrib.System/ViewModels/UpdatesViewModel.cs: -------------------------------------------------------------------------------- 1 | using NuGet.Versioning; 2 | using OrchardCoreContrib.System.Models; 3 | using OrchardCoreContrib.System.Services; 4 | 5 | namespace OrchardCoreContrib.System.ViewModels; 6 | 7 | public class UpdatesViewModel 8 | { 9 | public SystemInformation SystemInformation { get; set; } 10 | 11 | public IEnumerable Updates { get; set; } 12 | } 13 | -------------------------------------------------------------------------------- /src/OrchardCoreContrib.System/Views/Admin/Updates.cshtml: -------------------------------------------------------------------------------- 1 | @using NuGet.Versioning; 2 | @using OrchardCore.Environment.Shell; 3 | @using OrchardCoreContrib.System 4 | @using OrchardCoreContrib.System.ViewModels; 5 | @using System.Reflection; 6 | @model UpdatesViewModel 7 | @{ 8 | var hasUpdates = Model.Updates.Any(); 9 | } 10 | @functions 11 | { 12 | public static IEnumerable OrchardCoreAssemblies => Assembly.GetEntryAssembly() 13 | .GetReferencedAssemblies() 14 | .Where(a => a.Name.StartsWith("OrchardCore") && !a.Name.StartsWith("OrchardCoreContrib")); 15 | } 16 |

@RenderTitleSegments(T["System Updates"])

17 | 18 | @if (hasUpdates) 19 | { 20 | 21 | @foreach (var update in Model.Updates) 22 | { 23 | 24 | 25 | 32 | 33 | } 34 |
@update 26 | @foreach (var assembly in OrchardCoreAssemblies) 27 | { 28 | var packageUrl = String.Join("/", SystemUpdatesConstants.NuGetPackageUrl, assembly.Name, update); 29 | @assembly.Name 30 | } 31 |
35 | } 36 | else 37 | { 38 |
39 |

@T["You're all up to date!"]

40 |
41 | } 42 | -------------------------------------------------------------------------------- /src/OrchardCoreContrib.System/Views/NavigationItemText-info.Id.cshtml: -------------------------------------------------------------------------------- 1 | @T["Info"] 2 | -------------------------------------------------------------------------------- /src/OrchardCoreContrib.System/Views/NavigationItemText-system.Id.cshtml: -------------------------------------------------------------------------------- 1 | @T["System"] 2 | -------------------------------------------------------------------------------- /src/OrchardCoreContrib.System/Views/NavigationItemText-updates.Id.cshtml: -------------------------------------------------------------------------------- 1 | @T["Updates"] 2 | -------------------------------------------------------------------------------- /src/OrchardCoreContrib.System/Views/SystemSettings.Edit.cshtml: -------------------------------------------------------------------------------- 1 | @using OrchardCoreContrib.System 2 | @model SystemSettings 3 | 4 |
5 | 6 | 7 | @T["Check to let the maintenance page to be displayed instead of all the site pages, this is useful if you're doing an upgrade or maintenance to your website."] 8 |
9 | -------------------------------------------------------------------------------- /src/OrchardCoreContrib.System/Views/_ViewImports.cshtml: -------------------------------------------------------------------------------- 1 | @inherits OrchardCore.DisplayManagement.Razor.RazorPage 2 | @addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers 3 | @addTagHelper *, OrchardCore.DisplayManagement 4 | @addTagHelper *, OrchardCore.ResourceManagement 5 | @using OrchardCore.DisplayManagement 6 | -------------------------------------------------------------------------------- /src/OrchardCoreContrib.Tenants/HealthChecks/Extensions/TenantsHealthCheckExtensions.cs: -------------------------------------------------------------------------------- 1 | using OrchardCoreContrib.Tenants.HealthChecks; 2 | 3 | namespace Microsoft.Extensions.DependencyInjection; 4 | 5 | public static class TenantsHealthCheckExtensions 6 | { 7 | public static IHealthChecksBuilder AddTenantsCheck(this IHealthChecksBuilder healthChecksBuilder) 8 | => healthChecksBuilder.AddCheck(TenantsHealthCheck.Name); 9 | } 10 | -------------------------------------------------------------------------------- /src/OrchardCoreContrib.Tenants/HealthChecks/Startup.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.AspNetCore.Builder; 2 | using Microsoft.AspNetCore.Diagnostics.HealthChecks; 3 | using Microsoft.AspNetCore.Routing; 4 | using Microsoft.Extensions.DependencyInjection; 5 | using Microsoft.Extensions.Options; 6 | using OrchardCore.Modules; 7 | using OrchardCoreContrib.HealthChecks; 8 | 9 | namespace OrchardCoreContrib.Tenants.HealthChecks; 10 | 11 | [RequireFeatures("OrchardCoreContrib.HealthChecks")] 12 | public class Startup : StartupBase 13 | { 14 | public override void ConfigureServices(IServiceCollection services) 15 | { 16 | services.AddHealthChecks() 17 | .AddTenantsCheck(); 18 | } 19 | 20 | public override void Configure(IApplicationBuilder app, IEndpointRouteBuilder routes, IServiceProvider serviceProvider) 21 | { 22 | var healthChecksOptions = serviceProvider.GetService>().Value; 23 | 24 | routes.MapHealthChecks($"{healthChecksOptions.Url}/tenants", new HealthCheckOptions 25 | { 26 | Predicate = r => r.Name == TenantsHealthCheck.Name 27 | }); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/OrchardCoreContrib.Tenants/Manifest.cs: -------------------------------------------------------------------------------- 1 | using OrchardCore.Modules.Manifest; 2 | using ManifestConstants = OrchardCoreContrib.Modules.Manifest.ManifestConstants; 3 | 4 | [assembly: Module( 5 | Name = "Multitenancy", 6 | Author = ManifestConstants.Author, 7 | Website = ManifestConstants.Website, 8 | Version = "1.2.1", 9 | Description = "Provides a way to manage tenants from the admin.", 10 | Category = "Infrastructure", 11 | Dependencies = new [] { "OrchardCore.Tenants" }, 12 | DefaultTenantOnly = true 13 | )] 14 | -------------------------------------------------------------------------------- /src/OrchardCoreContrib.Themes.Admin/Assets.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "generateSourceMaps": false, 4 | "generateRTL": true, 5 | "inputs": [ 6 | "Assets/scss/admin.scss" 7 | ], 8 | "output": "wwwroot/css/TheAdmin.css" 9 | }, 10 | { 11 | "generateSourceMaps": false, 12 | "inputs": [ 13 | "node_modules/@popperjs/core/dist/umd/popper.js", 14 | "node_modules/bootstrap/dist/js/bootstrap.js", 15 | "Assets/js/*.js" 16 | ], 17 | "output": "wwwroot/js/TheAdmin.js" 18 | }, 19 | { 20 | "generateSourceMaps": false, 21 | "inputs": [ 22 | "Assets/js/header/userPreferencesLoader.js" 23 | ], 24 | "output": "wwwroot/js/TheAdmin-header.js" 25 | }, 26 | { 27 | "generateSourceMaps": false, 28 | "inputs": [ 29 | "node_modules/material-icons/iconfont/material-icons.scss" 30 | ], 31 | "output": "wwwroot/fonts/material-icons/material-icons.css" 32 | }, 33 | { 34 | "copy": true, 35 | "inputs": [ 36 | "node_modules/material-icons/iconfont/*.woff", 37 | "node_modules/material-icons/iconfont/*.woff2" 38 | ], 39 | "output": "wwwroot/fonts/material-icons/@" 40 | } 41 | ] 42 | -------------------------------------------------------------------------------- /src/OrchardCoreContrib.Themes.Admin/Assets/js/darkmode.js: -------------------------------------------------------------------------------- 1 | $('#btn-darkmode').click(function() { 2 | if($('html').attr('data-theme') === 'darkmode') 3 | { 4 | $('html').attr('data-theme', 'default'); 5 | $(this).children(':first').removeClass('fa-sun'); 6 | $(this).children(':first').addClass('fa-moon'); 7 | } 8 | else 9 | { 10 | $('html').attr('data-theme', 'darkmode'); 11 | $(this).children(':first').removeClass('fa-moon'); 12 | $(this).children(':first').addClass('fa-sun'); 13 | } 14 | 15 | persistAdminPreferences(); 16 | }); 17 | 18 | $(function() { 19 | if (window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches) 20 | { 21 | if($('html').attr('data-theme') === 'darkmode') 22 | { 23 | $('#btn-darkmode').children(':first').removeClass('fa-moon'); 24 | $('#btn-darkmode').children(':first').addClass('fa-sun'); 25 | } 26 | } 27 | }); 28 | -------------------------------------------------------------------------------- /src/OrchardCoreContrib.Themes.Admin/Assets/js/userPreferencesPersistor.js: -------------------------------------------------------------------------------- 1 | // Each time the sidebar status is modified, that is persisted to localStorage. 2 | // When the page is loaded again, userPreferencesLoader.js will read that info to 3 | // restore the sidebar to the previous state. 4 | function persistAdminPreferences() { 5 | setTimeout(function () { 6 | var tenant = $('html').attr('data-tenant'); 7 | var key = tenant + '-adminPreferences'; 8 | var adminPreferences = {}; 9 | adminPreferences.leftSidebarCompact = $('body').hasClass('left-sidebar-compact') ? true : false; 10 | adminPreferences.isCompactExplicit = isCompactExplicit; 11 | adminPreferences.darkMode = $('html').attr('data-theme') === 'darkmode' ? true : false; 12 | localStorage.setItem(key, JSON.stringify(adminPreferences)); 13 | Cookies.set(key, JSON.stringify(adminPreferences), { expires: 360 }); 14 | }, 200); 15 | } 16 | -------------------------------------------------------------------------------- /src/OrchardCoreContrib.Themes.Admin/Assets/scss/mixins/_cursors.scss: -------------------------------------------------------------------------------- 1 | // Used to @include a cursor within a pre-existing class 2 | @mixin cursor($cursor-type) { 3 | cursor: $cursor-type; 4 | } 5 | 6 | // Used to generate cursor classes 7 | @mixin cursor-class($cursor-type) { 8 | .cursor-#{$cursor-type} { 9 | cursor: $cursor-type; 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /src/OrchardCoreContrib.Themes.Admin/Assets/scss/mixins/_grid.scss: -------------------------------------------------------------------------------- 1 | // Row / Column Groupings 2 | // Creates mixins to target columns contained inside a column grouping to expand small sizes. 3 | // ------------------------------ 4 | 5 | @mixin make-col-fix($breakpoint) { 6 | .col-#{$breakpoint} { 7 | flex: 0 0 100%; 8 | max-width: 100%; 9 | } 10 | } 11 | 12 | @mixin make-col-grouping($grouping) { 13 | &.col-#{$grouping} { 14 | @each $breakpoint in map-keys($grid-breakpoints) { 15 | @include make-col-fix(#{$breakpoint}); 16 | @for $i from 1 through math.div($grid-columns, 2) { 17 | @include make-col-fix(#{$breakpoint}-#{$i}); 18 | } 19 | } 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/OrchardCoreContrib.Themes.Admin/Assets/scss/mixins/_word-wrap.scss: -------------------------------------------------------------------------------- 1 | @mixin word-wrap() { 2 | overflow-wrap: break-word; 3 | word-wrap: break-word; 4 | -ms-word-break: break-all; 5 | word-break: break-all; 6 | word-break: break-word; 7 | -ms-hyphens: auto; 8 | -moz-hyphens: auto; 9 | -webkit-hyphens: auto; 10 | hyphens: auto; 11 | } 12 | -------------------------------------------------------------------------------- /src/OrchardCoreContrib.Themes.Admin/Assets/scss/modules/admin/_bootstrap-select.scss: -------------------------------------------------------------------------------- 1 | // bootstrap-select customizations 2 | 3 | .multiselect__content-wrapper ul { 4 | padding-left: unset; 5 | } 6 | 7 | .bootstrap-select { 8 | .popover-header { 9 | .close { 10 | @extend .btn; 11 | @extend .btn-close; 12 | @extend .float-end; 13 | padding-top: 0px; 14 | padding-right: 0px; 15 | background: unset; 16 | } 17 | } 18 | } -------------------------------------------------------------------------------- /src/OrchardCoreContrib.Themes.Admin/Assets/scss/modules/admin/_codemirror.scss: -------------------------------------------------------------------------------- 1 | .CodeMirror { 2 | height: auto; 3 | border: 1px solid #ddd; 4 | } 5 | 6 | .CodeMirror-fullscreen { 7 | z-index: 1000; 8 | top: 0px !important; 9 | } 10 | 11 | .CodeMirror pre { 12 | padding-left: 7px; 13 | line-height: 1.25; 14 | margin-bottom: 0; 15 | overflow: unset; 16 | } 17 | 18 | .CodeMirror-activeline-background { 19 | background: transparent !important; 20 | } 21 | 22 | .CodeMirror-focused .CodeMirror-activeline-background { 23 | background: rgba(100, 100, 100, 0.1) !important; 24 | } 25 | -------------------------------------------------------------------------------- /src/OrchardCoreContrib.Themes.Admin/Assets/scss/modules/admin/_grid.scss: -------------------------------------------------------------------------------- 1 | // Responsive sizes 2 | // Creates mixins to target all breakpoints 3 | // ------------------------------ 4 | .col-xsmall { 5 | @extend .col-8, .col-sm-4, .col-md-3, .col-lg-2, .col-xl-1; 6 | } 7 | 8 | .col-small { 9 | @extend .col-12, .col-sm-9, .col-md-6, .col-lg-3, .col-xl-3; 10 | } 11 | 12 | .col-medium { 13 | @extend .col-12, .col-sm-12, .col-md-10, .col-lg-8, .col-xl-6; 14 | } 15 | 16 | .col-large { 17 | @extend .col-12, .col-sm-12, .col-md-12, .col-lg-12, .col-xl-9; 18 | } 19 | 20 | .col-xlarge { 21 | @extend .col-12, .col-sm-12, .col-md-12, .col-lg-12, .col-xl-12; 22 | } 23 | 24 | .ta-col-grouping { 25 | // Column fixes 26 | @each $breakpoint in map-keys($grid-breakpoints) { 27 | @if $grid-row-columns > 0 { 28 | // Column fixes 29 | @include make-col-grouping(#{$breakpoint}); // Include a fix for unspecified cols, i.e. col-md 30 | // Only apply to the lower half of the grid. 31 | @for $i from 1 through math.div($grid-columns, 2) { 32 | // Include a fix for specified cols, i.e. col-md-3 33 | @include make-col-grouping(#{$breakpoint}-#{$i}); 34 | } 35 | } 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/OrchardCoreContrib.Themes.Admin/Assets/scss/modules/admin/_jquery-ui.scss: -------------------------------------------------------------------------------- 1 | #ui-datepicker-div { 2 | z-index: 100 !important; 3 | } 4 | -------------------------------------------------------------------------------- /src/OrchardCoreContrib.Themes.Admin/Assets/scss/modules/admin/_list.scss: -------------------------------------------------------------------------------- 1 | .list-group li:hover { 2 | background-color: $li-hover-bg-color; 3 | } 4 | 5 | .list-group-item.first-child-visible { 6 | border-top-width: 1px !important; 7 | border-top-left-radius: inherit; 8 | border-top-right-radius: inherit; 9 | } 10 | 11 | .list-group-item.last-child-visible { 12 | border-bottom-left-radius: inherit; 13 | border-bottom-right-radius: inherit; 14 | } 15 | -------------------------------------------------------------------------------- /src/OrchardCoreContrib.Themes.Admin/Assets/scss/modules/admin/_login.scss: -------------------------------------------------------------------------------- 1 | .ta-content-login { 2 | margin-left: 0 !important; 3 | } 4 | 5 | .auth-form { 6 | label { 7 | display: block; 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /src/OrchardCoreContrib.Themes.Admin/Assets/scss/modules/admin/_messages.scss: -------------------------------------------------------------------------------- 1 | // Messages 2 | // ------------------------------ 3 | .message { 4 | @extend .alert; 5 | } 6 | 7 | .message-success { 8 | @extend .alert-success; 9 | } 10 | 11 | .message-information { 12 | @extend .alert-info; 13 | } 14 | 15 | .message-warning { 16 | @extend .alert-warning; 17 | } 18 | 19 | .message-error { 20 | @extend .alert-danger; 21 | } 22 | -------------------------------------------------------------------------------- /src/OrchardCoreContrib.Themes.Admin/Assets/scss/modules/admin/_monaco.scss: -------------------------------------------------------------------------------- 1 | div.editor-widget.find-widget { 2 | .button.codicon { 3 | background-color: transparent; 4 | border-color: transparent; 5 | display: flex; 6 | color: rgb(97,97,97); 7 | box-shadow: none; 8 | } 9 | 10 | .button.codicon:focus { 11 | background-color: transparent; 12 | border-color: transparent; 13 | } 14 | 15 | .button.codicon:active { 16 | background-color: transparent; 17 | border-color: transparent; 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/OrchardCoreContrib.Themes.Admin/Assets/scss/modules/admin/_pager.scss: -------------------------------------------------------------------------------- 1 | // Pager ======================== 2 | 3 | ul.pager { 4 | @extend .pagination; 5 | margin-top: 1rem; 6 | justify-content: center; 7 | } 8 | 9 | ul.pager li { 10 | @extend .page-item; 11 | } 12 | 13 | ul.pager li a { 14 | @extend .page-link; 15 | } 16 | -------------------------------------------------------------------------------- /src/OrchardCoreContrib.Themes.Admin/Assets/scss/modules/admin/_trumbowyg.scss: -------------------------------------------------------------------------------- 1 | .trumbowyg { 2 | font-size: 16px; 3 | } 4 | 5 | .trumbowyg-fullscreen { 6 | z-index: 1040; 7 | } 8 | -------------------------------------------------------------------------------- /src/OrchardCoreContrib.Themes.Admin/Assets/scss/modules/admin/_validations.scss: -------------------------------------------------------------------------------- 1 | .field-validation-error, .has-validation-error { 2 | @extend .text-danger; 3 | } 4 | 5 | span.field-validation-error { 6 | width: 100%; 7 | } 8 | -------------------------------------------------------------------------------- /src/OrchardCoreContrib.Themes.Admin/Assets/scss/modules/theme/darkmode/_admin-variables.scss: -------------------------------------------------------------------------------- 1 | // You can override any bootstrap or module variables here. 2 | 3 | $top-nav-height: 52px; 4 | $footer-height: 40px; 5 | $left-navigation-width: 260px; 6 | $left-navigation-width-when-compact: 48px; 7 | $border-content: 1px solid rgb(57, 62, 64); 8 | $link-padding-left: 16px !default; 9 | $zindex-sticky: 1000; 10 | $admin-menu-bg-color: rgb(36, 39, 40); 11 | $admin-menu-font-color: rgb(181, 175, 166); 12 | $admin-menu-font-color-hover: rgb(181, 175, 166); 13 | $admin-menu-item-bg-color: rgb(27, 30, 31); 14 | $admin-menu-item-font-color: rgb(189, 183, 175); 15 | $admin-menu-item-font-color-active: rgba(232, 230, 227, 0.9); 16 | $li-hover-bg-color: rgb(27, 30, 31); 17 | $scrollbar-color: #495057; 18 | -------------------------------------------------------------------------------- /src/OrchardCoreContrib.Themes.Admin/Assets/scss/modules/theme/darkmode/_forms.scss: -------------------------------------------------------------------------------- 1 | 2 | .has-filter .btn:not(.show) { 3 | border-color: #3C4144 !important; 4 | } 5 | 6 | .has-filter .form-control-feedback, .has-search .form-control-feedback { 7 | color: #aaa; 8 | } 9 | 10 | .has-filter .form-control, .has-search .form-control { 11 | color: #aaa; 12 | } 13 | -------------------------------------------------------------------------------- /src/OrchardCoreContrib.Themes.Admin/Assets/scss/modules/theme/default/_admin-variables.scss: -------------------------------------------------------------------------------- 1 | // You can override any bootstrap or module variables here. 2 | 3 | $top-nav-height: 52px; 4 | $footer-height: 40px; 5 | $left-navigation-width: 260px; 6 | $left-navigation-width-when-compact: 48px; 7 | $border-content: 1px solid #dedede; 8 | $link-padding-left: 16px !default; 9 | $zindex-sticky: 1000; 10 | $admin-menu-bg-color: #eaeaea; 11 | $admin-menu-font-color: $gray-800; 12 | $admin-menu-font-color-hover: $gray-100; 13 | $admin-menu-item-bg-color: $gray-100; 14 | $admin-menu-item-font-color: $gray-700; 15 | $admin-menu-item-font-color-active: black; 16 | $li-hover-bg-color: $gray-100; 17 | $scrollbar-color: #495057; 18 | -------------------------------------------------------------------------------- /src/OrchardCoreContrib.Themes.Admin/Assets/scss/modules/theme/default/_forms.scss: -------------------------------------------------------------------------------- 1 | .has-filter .btn:not(.show) { 2 | border-color: $gray-400 !important; 3 | } 4 | 5 | .has-filter .form-control-feedback, .has-search .form-control-feedback { 6 | color: #aaa; 7 | } 8 | -------------------------------------------------------------------------------- /src/OrchardCoreContrib.Themes.Admin/Assets/scss/modules/theme/default/_variables.scss: -------------------------------------------------------------------------------- 1 | // Override Bootstrap variables 2 | // Because !default means that a variable is not assigned if it already contains a value, 3 | // we alter the variable before importing boostrap as _variables.scss will use !default 4 | -------------------------------------------------------------------------------- /src/OrchardCoreContrib.Themes.Admin/Manifest.cs: -------------------------------------------------------------------------------- 1 | using OrchardCore.DisplayManagement.Manifest; 2 | using OrchardCore.Modules.Manifest; 3 | 4 | [assembly: Theme( 5 | Name = "Orchard Core Contrib Admin Theme", 6 | Author = "Orchard Core Contrib", 7 | Version = "1.0.0", 8 | Description = "The default Admin theme.", 9 | Tags = new[] { ManifestConstants.AdminTag } 10 | )] 11 | -------------------------------------------------------------------------------- /src/OrchardCoreContrib.Themes.Admin/OrchardCoreContrib.Themes.Admin.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | true 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /src/OrchardCoreContrib.Themes.Admin/Startup.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.Extensions.DependencyInjection; 2 | using Microsoft.Extensions.Options; 3 | using OrchardCore.DisplayManagement.Html; 4 | using OrchardCore.Environment.Shell.Configuration; 5 | using OrchardCore.Modules; 6 | using OrchardCore.ResourceManagement; 7 | 8 | namespace OrchardCoreContrib.Themes.Admin 9 | { 10 | public class Startup : StartupBase 11 | { 12 | private readonly IShellConfiguration _configuration; 13 | 14 | public Startup(IShellConfiguration configuration) 15 | { 16 | _configuration = configuration; 17 | } 18 | 19 | public override void ConfigureServices(IServiceCollection services) 20 | { 21 | // TODO: Check why the resources broken after upgrading to Orchard Core 1.8.2 22 | //services.AddTransient, ResourceManagementOptionsConfiguration>(); 23 | //services.Configure(_configuration.GetSection("TheAdminTheme:StyleSettings")); 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/OrchardCoreContrib.Themes.Admin/Views/Message.cshtml: -------------------------------------------------------------------------------- 1 | @{ 2 | string type = Model.Type.ToString().ToLowerInvariant(); 3 | } 4 | 8 | -------------------------------------------------------------------------------- /src/OrchardCoreContrib.Themes.Admin/Views/NavigationItemText.cshtml: -------------------------------------------------------------------------------- 1 | @using System.Linq 2 | 3 | @{ 4 | 5 | var prefix = "icon-class-"; 6 | 7 | //extract icon classes from Model.Classes 8 | var iconClasses = ((IEnumerable)Model.Classes) 9 | .ToList() 10 | .Where(c => c.StartsWith(prefix, StringComparison.OrdinalIgnoreCase)) 11 | .Select(c => c.Substring(prefix.Length)); 12 | 13 | if (iconClasses.Any()) 14 | { 15 | 16 | } 17 | else 18 | { 19 | @**@ 20 | } 21 | 22 | } 23 | @Model.Text 24 | -------------------------------------------------------------------------------- /src/OrchardCoreContrib.Themes.Admin/Views/_ViewImports.cshtml: -------------------------------------------------------------------------------- 1 | @* 2 | For more information on enabling MVC for empty projects, visit http://go.microsoft.com/fwlink/?LinkID=397860 3 | 4 | *@ 5 | 6 | @inherits OrchardCore.DisplayManagement.Razor.RazorPage 7 | @addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers 8 | @addTagHelper *, OrchardCore.DisplayManagement 9 | @addTagHelper *, OrchardCore.ResourceManagement 10 | 11 | @using Microsoft.Extensions.Options 12 | @using OrchardCore.Admin 13 | @using OrchardCore.Admin.Models 14 | @using OrchardCore.Entities 15 | @using OrchardCore.Themes.Services 16 | -------------------------------------------------------------------------------- /src/OrchardCoreContrib.Themes.Admin/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "orchardcore.theadmin", 3 | "version": "1.0.0", 4 | "dependencies": { 5 | "@popperjs/core": "2.11.5", 6 | "bootstrap": "5.1.3", 7 | "bootstrap-select": "1.14.0-beta2", 8 | "material-icons": "1.12.0", 9 | "nouislider": "15.6.1" 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /src/OrchardCoreContrib.Themes.Admin/wwwroot/Theme.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OrchardCoreContrib/OrchardCoreContrib.Modules/3a124143f9e750c2d34535492c353f555dbe1d4b/src/OrchardCoreContrib.Themes.Admin/wwwroot/Theme.png -------------------------------------------------------------------------------- /src/OrchardCoreContrib.Themes.Admin/wwwroot/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OrchardCoreContrib/OrchardCoreContrib.Modules/3a124143f9e750c2d34535492c353f555dbe1d4b/src/OrchardCoreContrib.Themes.Admin/wwwroot/favicon.ico -------------------------------------------------------------------------------- /src/OrchardCoreContrib.Themes.Admin/wwwroot/fonts/material-icons/material-icons-outlined.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OrchardCoreContrib/OrchardCoreContrib.Modules/3a124143f9e750c2d34535492c353f555dbe1d4b/src/OrchardCoreContrib.Themes.Admin/wwwroot/fonts/material-icons/material-icons-outlined.woff -------------------------------------------------------------------------------- /src/OrchardCoreContrib.Themes.Admin/wwwroot/fonts/material-icons/material-icons-outlined.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OrchardCoreContrib/OrchardCoreContrib.Modules/3a124143f9e750c2d34535492c353f555dbe1d4b/src/OrchardCoreContrib.Themes.Admin/wwwroot/fonts/material-icons/material-icons-outlined.woff2 -------------------------------------------------------------------------------- /src/OrchardCoreContrib.Themes.Admin/wwwroot/fonts/material-icons/material-icons-round.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OrchardCoreContrib/OrchardCoreContrib.Modules/3a124143f9e750c2d34535492c353f555dbe1d4b/src/OrchardCoreContrib.Themes.Admin/wwwroot/fonts/material-icons/material-icons-round.woff -------------------------------------------------------------------------------- /src/OrchardCoreContrib.Themes.Admin/wwwroot/fonts/material-icons/material-icons-round.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OrchardCoreContrib/OrchardCoreContrib.Modules/3a124143f9e750c2d34535492c353f555dbe1d4b/src/OrchardCoreContrib.Themes.Admin/wwwroot/fonts/material-icons/material-icons-round.woff2 -------------------------------------------------------------------------------- /src/OrchardCoreContrib.Themes.Admin/wwwroot/fonts/material-icons/material-icons-sharp.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OrchardCoreContrib/OrchardCoreContrib.Modules/3a124143f9e750c2d34535492c353f555dbe1d4b/src/OrchardCoreContrib.Themes.Admin/wwwroot/fonts/material-icons/material-icons-sharp.woff -------------------------------------------------------------------------------- /src/OrchardCoreContrib.Themes.Admin/wwwroot/fonts/material-icons/material-icons-sharp.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OrchardCoreContrib/OrchardCoreContrib.Modules/3a124143f9e750c2d34535492c353f555dbe1d4b/src/OrchardCoreContrib.Themes.Admin/wwwroot/fonts/material-icons/material-icons-sharp.woff2 -------------------------------------------------------------------------------- /src/OrchardCoreContrib.Themes.Admin/wwwroot/fonts/material-icons/material-icons-two-tone.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OrchardCoreContrib/OrchardCoreContrib.Modules/3a124143f9e750c2d34535492c353f555dbe1d4b/src/OrchardCoreContrib.Themes.Admin/wwwroot/fonts/material-icons/material-icons-two-tone.woff -------------------------------------------------------------------------------- /src/OrchardCoreContrib.Themes.Admin/wwwroot/fonts/material-icons/material-icons-two-tone.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OrchardCoreContrib/OrchardCoreContrib.Modules/3a124143f9e750c2d34535492c353f555dbe1d4b/src/OrchardCoreContrib.Themes.Admin/wwwroot/fonts/material-icons/material-icons-two-tone.woff2 -------------------------------------------------------------------------------- /src/OrchardCoreContrib.Themes.Admin/wwwroot/fonts/material-icons/material-icons.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OrchardCoreContrib/OrchardCoreContrib.Modules/3a124143f9e750c2d34535492c353f555dbe1d4b/src/OrchardCoreContrib.Themes.Admin/wwwroot/fonts/material-icons/material-icons.woff -------------------------------------------------------------------------------- /src/OrchardCoreContrib.Themes.Admin/wwwroot/fonts/material-icons/material-icons.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OrchardCoreContrib/OrchardCoreContrib.Modules/3a124143f9e750c2d34535492c353f555dbe1d4b/src/OrchardCoreContrib.Themes.Admin/wwwroot/fonts/material-icons/material-icons.woff2 -------------------------------------------------------------------------------- /src/OrchardCoreContrib.Themes.Admin/wwwroot/js/TheAdmin-header.min.js: -------------------------------------------------------------------------------- 1 | var observer=new MutationObserver((function(e){for(var t=document.querySelector("html"),a=t.getAttribute("data-tenant")+"-adminPreferences",d=JSON.parse(localStorage.getItem(a)),r=0;r S) : AdminNavigationProvider 11 | { 12 | public override void BuildNavigation(NavigationBuilder builder) 13 | { 14 | builder 15 | .Add(S["Security"], NavigationConstants.AdminMenuConfigurationPosition, builder => builder 16 | .Add(S["User Groups"], S["User Groups"].PrefixPosition(), builder => builder 17 | .Id("usergroups") 18 | .Action(nameof(AdminController.Index), typeof(AdminController).ControllerName(), "OrchardCoreContrib.UserGroups") 19 | .LocalNav())); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/OrchardCoreContrib.UserGroups/Drivers/UserGroupsDisplayDriver.cs: -------------------------------------------------------------------------------- 1 | using OrchardCore.DisplayManagement.Handlers; 2 | using OrchardCore.DisplayManagement.Views; 3 | using OrchardCore.Users.Models; 4 | using OrchardCoreContrib.UserGroups.Services; 5 | using OrchardCoreContrib.UserGroups.ViewModels; 6 | 7 | namespace OrchardCoreContrib.UserGroups.Drivers; 8 | 9 | public class UserGroupsDisplayDriver(UserGroupsManager userGroupsManager) : DisplayDriver 10 | { 11 | public override IDisplayResult Display(User user, BuildDisplayContext context) 12 | => Initialize("UserGroups", model => model.UserGroups = user.GetUserGroups()) 13 | .Location("DetailAdmin", "Content:10"); 14 | 15 | public async override Task EditAsync(User user, BuildEditorContext context) 16 | { 17 | var userGroupNames = await userGroupsManager.GetUserGroupNamesAsync(); 18 | 19 | return Initialize("UserGroups_Edit", model => 20 | { 21 | model.UserGroups = userGroupNames; 22 | model.SelectedUserGroups = user.GetUserGroups(); 23 | }).Location("Content:10"); 24 | } 25 | 26 | public async override Task UpdateAsync(User user, UpdateEditorContext context) 27 | { 28 | var model = new UserGroupsEditViewModel(); 29 | 30 | await context.Updater.TryUpdateModelAsync(model, Prefix); 31 | 32 | user.SetUserGroups(model.SelectedUserGroups); 33 | 34 | return Edit(user, context); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/OrchardCoreContrib.UserGroups/Extensions/UserExtensions.cs: -------------------------------------------------------------------------------- 1 | using OrchardCoreContrib.Infrastructure; 2 | using System.Text.Json.Nodes; 3 | 4 | namespace OrchardCore.Users.Models; 5 | 6 | internal static class UserExtensions 7 | { 8 | private const string UserGroupsPropertyName = "UserGroups"; 9 | 10 | public static string[] GetUserGroups(this User user) 11 | { 12 | Guard.ArgumentNotNull(user, nameof(user)); 13 | 14 | return user.Properties.TryGetPropertyValue(UserGroupsPropertyName, out var userGroupsJson) 15 | ? userGroupsJson.ToObject() 16 | : []; 17 | } 18 | 19 | public static void SetUserGroups(this User user, string[] groups) 20 | { 21 | Guard.ArgumentNotNull(user, nameof(user)); 22 | Guard.ArgumentNotNull(groups, nameof(groups)); 23 | 24 | user.Properties[UserGroupsPropertyName] = JNode.FromObject(groups); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/OrchardCoreContrib.UserGroups/Indexes/UserByGroupNameIndex.cs: -------------------------------------------------------------------------------- 1 | using YesSql.Indexes; 2 | 3 | namespace OrchardCoreContrib.UserGroups.Indexes; 4 | 5 | public class UserByGroupNameIndex : ReduceIndex 6 | { 7 | public string GroupName { get; set; } 8 | 9 | public int Count { get; set; } 10 | } 11 | -------------------------------------------------------------------------------- /src/OrchardCoreContrib.UserGroups/Indexes/UserByUserGroupNameIndexProvider.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.AspNetCore.Identity; 2 | using OrchardCore.Users.Models; 3 | using YesSql.Indexes; 4 | 5 | namespace OrchardCoreContrib.UserGroups.Indexes; 6 | 7 | public class UserByUserGroupNameIndexProvider(ILookupNormalizer keyNormalizer) : IndexProvider 8 | { 9 | public override void Describe(DescribeContext context) 10 | { 11 | context.For() 12 | .Map(user => user.GetUserGroups().Select(group => new UserByGroupNameIndex 13 | { 14 | GroupName = keyNormalizer.NormalizeName(group), 15 | Count = 1 16 | })) 17 | .Group(index => index.GroupName) 18 | .Reduce(group => new UserByGroupNameIndex 19 | { 20 | GroupName = group.Key, 21 | Count = group.Sum(x => x.Count) 22 | }) 23 | .Delete((index, map) => 24 | { 25 | index.Count -= map.Sum(x => x.Count); 26 | 27 | return index.Count > 0 28 | ? index 29 | : null; 30 | }); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/OrchardCoreContrib.UserGroups/Manifest.cs: -------------------------------------------------------------------------------- 1 | using OrchardCore.Modules.Manifest; 2 | using ManifestConstants = OrchardCoreContrib.Modules.Manifest.ManifestConstants; 3 | 4 | [assembly: Module( 5 | Name = "User Groups", 6 | Author = ManifestConstants.Author, 7 | Website = ManifestConstants.Website, 8 | Version = "1.0.0", 9 | Description = "Provides a way to organize the users into group(s).", 10 | Category = "Security" 11 | )] 12 | -------------------------------------------------------------------------------- /src/OrchardCoreContrib.UserGroups/Migrations.cs: -------------------------------------------------------------------------------- 1 | using OrchardCore.ContentManagement.Metadata; 2 | using OrchardCore.ContentManagement.Metadata.Settings; 3 | using OrchardCore.Data.Migration; 4 | using OrchardCoreContrib.UserGroups.Indexes; 5 | using YesSql.Sql; 6 | 7 | namespace OrchardCoreContrib.UserGroups; 8 | 9 | public class Migrations(IContentDefinitionManager contentDefinitionManager) : DataMigration 10 | { 11 | public async Task CreateAsync() 12 | { 13 | await contentDefinitionManager.AlterPartDefinitionAsync("UserGroupsListPart", builder => builder 14 | .Attachable() 15 | .WithDescription("Provides a way to add user group(s) for your content item.")); 16 | 17 | await SchemaBuilder.CreateReduceIndexTableAsync(table => table 18 | .Column("GroupName") 19 | .Column("Count")); 20 | 21 | await SchemaBuilder.AlterIndexTableAsync(table => table 22 | .CreateIndex("IDX_UserByGroupNameIndex_GroupName", "GroupName")); 23 | 24 | return 1; 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/OrchardCoreContrib.UserGroups/Models/UserGroup.cs: -------------------------------------------------------------------------------- 1 | namespace OrchardCoreContrib.UserGroups.Models; 2 | 3 | public class UserGroup 4 | { 5 | public string Name { get; set; } 6 | 7 | public string Description { get; set; } 8 | } 9 | -------------------------------------------------------------------------------- /src/OrchardCoreContrib.UserGroups/Models/UserGroupDocument.cs: -------------------------------------------------------------------------------- 1 | using OrchardCore.Data.Documents; 2 | 3 | namespace OrchardCoreContrib.UserGroups.Models; 4 | 5 | public class UserGroupDocument : Document 6 | { 7 | public Dictionary UserGroups { get; init; } = new(StringComparer.OrdinalIgnoreCase); 8 | } 9 | -------------------------------------------------------------------------------- /src/OrchardCoreContrib.UserGroups/Models/UserGroupsListPart.cs: -------------------------------------------------------------------------------- 1 | using OrchardCore.ContentManagement; 2 | 3 | namespace OrchardCoreContrib.UserGroups.Models; 4 | 5 | public class UserGroupsListPart : ContentPart 6 | { 7 | public string[] UserGroups { get; set; } = []; 8 | } 9 | -------------------------------------------------------------------------------- /src/OrchardCoreContrib.UserGroups/Permissions.cs: -------------------------------------------------------------------------------- 1 | using OrchardCore.Security.Permissions; 2 | using OrchardCore; 3 | 4 | namespace OrchardCoreContrib.UserGroups; 5 | 6 | public sealed class Permissions : IPermissionProvider 7 | { 8 | private readonly IEnumerable _permissions = [UserGroupsPermissions.ManageUserGroups]; 9 | 10 | public Task> GetPermissionsAsync() => Task.FromResult(_permissions); 11 | 12 | public IEnumerable GetDefaultStereotypes() => 13 | [ 14 | new PermissionStereotype 15 | { 16 | Name = OrchardCoreConstants.Roles.Administrator, 17 | Permissions = _permissions, 18 | }, 19 | ]; 20 | } 21 | -------------------------------------------------------------------------------- /src/OrchardCoreContrib.UserGroups/Startup.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.Extensions.DependencyInjection; 2 | using OrchardCore.ContentManagement; 3 | using OrchardCore.ContentManagement.Display.ContentDisplay; 4 | using OrchardCore.Data; 5 | using OrchardCore.Data.Migration; 6 | using OrchardCore.DisplayManagement.Handlers; 7 | using OrchardCore.Modules; 8 | using OrchardCore.Navigation; 9 | using OrchardCore.Security.Permissions; 10 | using OrchardCore.Users.Models; 11 | using OrchardCoreContrib.UserGroups.Drivers; 12 | using OrchardCoreContrib.UserGroups.Indexes; 13 | using OrchardCoreContrib.UserGroups.Models; 14 | using OrchardCoreContrib.UserGroups.Services; 15 | 16 | namespace OrchardCoreContrib.UserGroups; 17 | 18 | public sealed class Startup : StartupBase 19 | { 20 | public override void ConfigureServices(IServiceCollection services) 21 | { 22 | services.AddIndexProvider(); 23 | 24 | services.AddDataMigration(); 25 | services.AddPermissionProvider(); 26 | services.AddNavigationProvider(); 27 | 28 | services.AddContentPart() 29 | .UseDisplayDriver(); 30 | 31 | services.AddScoped, UserGroupsDisplayDriver>(); 32 | services.AddScoped(); 33 | services.AddScoped(); 34 | } 35 | } 36 | 37 | -------------------------------------------------------------------------------- /src/OrchardCoreContrib.UserGroups/UserGroupsPermissions.cs: -------------------------------------------------------------------------------- 1 | using OrchardCore.Security.Permissions; 2 | 3 | namespace OrchardCoreContrib.UserGroups; 4 | 5 | public static class UserGroupsPermissions 6 | { 7 | public static readonly Permission ManageUserGroups = new("ManageUserGroups", "Managing User Groups"); 8 | } 9 | -------------------------------------------------------------------------------- /src/OrchardCoreContrib.UserGroups/ViewModels/CreateUserGroupViewModel.cs: -------------------------------------------------------------------------------- 1 | using System.ComponentModel.DataAnnotations; 2 | 3 | namespace OrchardCoreContrib.UserGroups.ViewModels; 4 | 5 | public class CreateUserGroupViewModel 6 | { 7 | [Required] 8 | public string Name { get; set; } 9 | 10 | public string Description { get; set; } 11 | } 12 | -------------------------------------------------------------------------------- /src/OrchardCoreContrib.UserGroups/ViewModels/EditUserGroupViewModel.cs: -------------------------------------------------------------------------------- 1 | namespace OrchardCoreContrib.UserGroups.ViewModels; 2 | 3 | public class EditUserGroupViewModel 4 | { 5 | public string Name { get; set; } 6 | 7 | public string Description { get; set; } 8 | } 9 | -------------------------------------------------------------------------------- /src/OrchardCoreContrib.UserGroups/ViewModels/UserGroupsEditViewModel.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.AspNetCore.Mvc.ModelBinding; 2 | 3 | namespace OrchardCoreContrib.UserGroups.ViewModels; 4 | 5 | public class UserGroupsEditViewModel 6 | { 7 | [BindNever] 8 | public IEnumerable UserGroups { get; set; } 9 | 10 | public string[] SelectedUserGroups { get; set; } 11 | } 12 | -------------------------------------------------------------------------------- /src/OrchardCoreContrib.UserGroups/ViewModels/UserGroupsIndexViewModel.cs: -------------------------------------------------------------------------------- 1 | using OrchardCoreContrib.UserGroups.Models; 2 | 3 | namespace OrchardCoreContrib.UserGroups.ViewModels; 4 | 5 | public class UserGroupsIndexViewModel 6 | { 7 | public IEnumerable UserGroups { get; set; } = []; 8 | 9 | public string Search { get; set; } 10 | 11 | public dynamic Pager { get; set; } 12 | } 13 | -------------------------------------------------------------------------------- /src/OrchardCoreContrib.UserGroups/ViewModels/UserGroupsListPartEditViewModel.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.AspNetCore.Mvc.ModelBinding; 2 | namespace OrchardCoreContrib.UserGroups.ViewModels; 3 | 4 | public class UserGroupsListPartEditViewModel 5 | { 6 | [BindNever] 7 | public IEnumerable UserGroups { get; set; } 8 | 9 | public string[] SelectedUserGroups { get; set; } 10 | } 11 | -------------------------------------------------------------------------------- /src/OrchardCoreContrib.UserGroups/ViewModels/UserGroupsListPartViewModel.cs: -------------------------------------------------------------------------------- 1 | namespace OrchardCoreContrib.UserGroups.ViewModels; 2 | 3 | public class UserGroupsListPartViewModel 4 | { 5 | public string[] UserGroups { get; set; } 6 | } 7 | -------------------------------------------------------------------------------- /src/OrchardCoreContrib.UserGroups/ViewModels/UserGroupsViewModel.cs: -------------------------------------------------------------------------------- 1 | namespace OrchardCoreContrib.UserGroups.ViewModels; 2 | 3 | public class UserGroupsViewModel 4 | { 5 | public string[] UserGroups { get; set; } 6 | } 7 | -------------------------------------------------------------------------------- /src/OrchardCoreContrib.UserGroups/Views/Admin/Create.cshtml: -------------------------------------------------------------------------------- 1 | @model CreateUserGroupViewModel 2 | 3 |

@RenderTitleSegments(T["Create User Group"])

4 | 5 |
6 | 7 |
8 |
9 | 10 | 11 | 12 |
13 |
14 | 15 | 16 | 17 |
18 |
19 | 20 | @T["Cancel"] 21 |
22 |
23 | -------------------------------------------------------------------------------- /src/OrchardCoreContrib.UserGroups/Views/Admin/Edit.cshtml: -------------------------------------------------------------------------------- 1 | @model EditUserGroupViewModel 2 | 3 |

@RenderTitleSegments(T["Edit '{0}' User Group", Model.Name])

4 | 5 |
6 |
7 | 8 | 9 | 10 |
11 |
12 | 13 | @T["Cancel"] 14 |
15 |
16 | -------------------------------------------------------------------------------- /src/OrchardCoreContrib.UserGroups/Views/NavigationItemText-usergroups.Id.cshtml: -------------------------------------------------------------------------------- 1 | @T["User Groups"] 2 | -------------------------------------------------------------------------------- /src/OrchardCoreContrib.UserGroups/Views/UserGroups.Edit.cshtml: -------------------------------------------------------------------------------- 1 | @model UserGroupsEditViewModel 2 | 3 |
@T["User Groups"]
4 |
5 | @foreach (var userGroup in Model.UserGroups) 6 | { 7 | var selected = Model.SelectedUserGroups.Contains(userGroup); 8 |
9 |
10 | 11 | 12 |
13 |
14 | } 15 |
16 | -------------------------------------------------------------------------------- /src/OrchardCoreContrib.UserGroups/Views/UserGroups.cshtml: -------------------------------------------------------------------------------- 1 | @model UserGroupsViewModel 2 | 3 |

@T["User Groups"]

4 |
    5 | @foreach (var userGroup in Model.UserGroups) 6 | { 7 |
  • @userGroup
  • 8 | } 9 |
10 | -------------------------------------------------------------------------------- /src/OrchardCoreContrib.UserGroups/Views/UserGroupsListPart.Edit.cshtml: -------------------------------------------------------------------------------- 1 | @model UserGroupsListPartEditViewModel 2 | 3 |
@T["User Groups"]
4 |
5 | @foreach (var userGroup in Model.UserGroups) 6 | { 7 | var selected = Model.SelectedUserGroups.Contains(userGroup); 8 |
9 |
10 | 11 | 12 |
13 |
14 | } 15 |
16 | -------------------------------------------------------------------------------- /src/OrchardCoreContrib.UserGroups/Views/UserGroupsListPart.cshtml: -------------------------------------------------------------------------------- 1 | @model UserGroupsListPartViewModel 2 | 3 |
    4 | @foreach (var userGroup in Model.UserGroups) 5 | { 6 |
  • @userGroup
  • 7 | } 8 |
9 | -------------------------------------------------------------------------------- /src/OrchardCoreContrib.UserGroups/Views/_ViewImports.cshtml: -------------------------------------------------------------------------------- 1 | @inherits OrchardCore.DisplayManagement.Razor.RazorPage 2 | 3 | @addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers 4 | @addTagHelper *, OrchardCore.DisplayManagement 5 | @addTagHelper *, OrchardCore.ResourceManagement 6 | 7 | @using Microsoft.AspNetCore.Mvc.Localization 8 | @using OrchardCoreContrib.UserGroups.ViewModels 9 | -------------------------------------------------------------------------------- /src/OrchardCoreContrib.Users/AvatarOptions.cs: -------------------------------------------------------------------------------- 1 | namespace OrchardCoreContrib.Users; 2 | 3 | public class AvatarOptions 4 | { 5 | public string BackColor { get; set; } = "#55B670"; 6 | 7 | public string ForeColor { get; set; } = "#FFF"; 8 | } 9 | -------------------------------------------------------------------------------- /src/OrchardCoreContrib.Users/ClaimTypesExtended.cs: -------------------------------------------------------------------------------- 1 | namespace OrchardCoreContrib.Users 2 | { 3 | /// 4 | /// Represents a claim types that be used for impersonation process. 5 | /// 6 | public static class ClaimTypesExtended 7 | { 8 | /// 9 | /// Gets the impersonator name. 10 | /// 11 | public static readonly string ImpersonatorNameIdentifier = nameof(ImpersonatorNameIdentifier); 12 | 13 | /// 14 | /// Gets whether the current user is impersonated or not. 15 | /// 16 | public static readonly string IsImpersonating = nameof(IsImpersonating); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/OrchardCoreContrib.Users/Drivers/ImpersonationDisplayDriver.cs: -------------------------------------------------------------------------------- 1 | using OrchardCore.DisplayManagement.Handlers; 2 | using OrchardCore.DisplayManagement.Views; 3 | using OrchardCore.Modules; 4 | using OrchardCore.Users.Models; 5 | using OrchardCore.Users.ViewModels; 6 | 7 | namespace OrchardCoreContrib.Users.Drivers; 8 | 9 | [Feature("OrchardCoreContrib.Users.Impersonation")] 10 | public class ImpersonationDisplayDriver : DisplayDriver 11 | { 12 | public override IDisplayResult Display(User user, BuildDisplayContext context) 13 | => Initialize("ImpersonationButton", model => model.User = user) 14 | .Location("SummaryAdmin", "Actions:2"); 15 | } 16 | -------------------------------------------------------------------------------- /src/OrchardCoreContrib.Users/Manifest.cs: -------------------------------------------------------------------------------- 1 | using OrchardCore.Modules.Manifest; 2 | using ManifestConstants = OrchardCoreContrib.Modules.Manifest.ManifestConstants; 3 | 4 | [assembly: Module( 5 | Name = "Users", 6 | Author = ManifestConstants.Author, 7 | Website = ManifestConstants.Website, 8 | Version = "1.5.1", 9 | Category = "Security" 10 | )] 11 | 12 | [assembly: Feature( 13 | Id = "OrchardCoreContrib.Users.Avatar", 14 | Name = "User Avatar", 15 | Description = "This feature allow to display a user avatar on the admin menu.", 16 | Dependencies = new[] { "OrchardCore.Users" } 17 | )] 18 | 19 | [assembly: Feature( 20 | Id = "OrchardCoreContrib.Users.Impersonation", 21 | Name = "Users Impersonation", 22 | Description = "This feature allow administrators to sign in with other user identity.", 23 | Dependencies = new[] { "OrchardCore.Users" } 24 | )] 25 | 26 | -------------------------------------------------------------------------------- /src/OrchardCoreContrib.Users/Permissions.cs: -------------------------------------------------------------------------------- 1 | using OrchardCore.Modules; 2 | using OrchardCore.Security; 3 | using OrchardCore.Security.Permissions; 4 | using System.Collections.Generic; 5 | using System.Linq; 6 | using System.Threading.Tasks; 7 | 8 | namespace OrchardCoreContrib.Users 9 | { 10 | /// 11 | /// Represents a permissions that will be applied into users module. 12 | /// 13 | [Feature("OrchardCoreContrib.Users.Impersonation")] 14 | public class Permissions : IPermissionProvider 15 | { 16 | /// 17 | /// Gets a permission for managing a impersonation settings. 18 | /// 19 | public static readonly Permission ManageImpersonationSettings = new Permission("ManageImpersonationSettings", "Manage Impersonation Settings", isSecurityCritical: true); 20 | 21 | /// 22 | public Task> GetPermissionsAsync() 23 | { 24 | return Task.FromResult(new[] 25 | { 26 | ManageImpersonationSettings 27 | } 28 | .AsEnumerable()); 29 | } 30 | 31 | /// 32 | public IEnumerable GetDefaultStereotypes() 33 | { 34 | return new[] 35 | { 36 | new PermissionStereotype 37 | { 38 | Name = "Administrator", 39 | Permissions = new[] { ManageImpersonationSettings, StandardPermissions.SiteOwner } 40 | }, 41 | }; 42 | } 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /src/OrchardCoreContrib.Users/Services/IAvatarService.cs: -------------------------------------------------------------------------------- 1 | namespace OrchardCoreContrib.Users.Services; 2 | 3 | public interface IAvatarService 4 | { 5 | string Generate(string userName); 6 | } 7 | -------------------------------------------------------------------------------- /src/OrchardCoreContrib.Users/Services/NullAvatarService.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace OrchardCoreContrib.Users.Services; 4 | 5 | public class NullAvatarService : IAvatarService 6 | { 7 | public string Generate(string userName) => String.Empty; 8 | } 9 | -------------------------------------------------------------------------------- /src/OrchardCoreContrib.Users/Views/ImpersonationButton.cshtml: -------------------------------------------------------------------------------- 1 | @using OrchardCore.Modules 2 | @using OrchardCore.Users.Models 3 | @using OrchardCore.Users.ViewModels 4 | @model SummaryAdminUserViewModel 5 | @attribute [Feature("OrchardCoreContrib.Users.Impersonation")] 6 | @{ 7 | var user = Model.User as User; 8 | } 9 | 10 | @T["Impersonate"] -------------------------------------------------------------------------------- /src/OrchardCoreContrib.Users/Views/NavigationItemText-endImpersonation.Id.cshtml: -------------------------------------------------------------------------------- 1 | @T["End Impersonation"] 2 | -------------------------------------------------------------------------------- /src/OrchardCoreContrib.Users/Views/_ViewImports.cshtml: -------------------------------------------------------------------------------- 1 | @inherits OrchardCore.DisplayManagement.Razor.RazorPage 2 | @addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers 3 | @addTagHelper *, OrchardCore.DisplayManagement 4 | @addTagHelper *, OrchardCore.ResourceManagement 5 | 6 | @using Microsoft.Extensions.Localization; 7 | @using Microsoft.AspNetCore.Mvc.Localization; -------------------------------------------------------------------------------- /src/OrchardCoreContrib.ViewCount/Drivers/ViewCountPartDisplayDriver.cs: -------------------------------------------------------------------------------- 1 | using OrchardCore.ContentManagement.Display.ContentDisplay; 2 | using OrchardCore.ContentManagement.Display.Models; 3 | using OrchardCore.DisplayManagement.Views; 4 | using OrchardCoreContrib.ViewCount.Models; 5 | using OrchardCoreContrib.ViewCount.Services; 6 | using OrchardCoreContrib.ViewCount.ViewModels; 7 | 8 | namespace OrchardCoreContrib.ViewCount.Drivers; 9 | 10 | public sealed class ViewCountPartDisplayDriver(IViewCountService viewCountService) : ContentPartDisplayDriver 11 | { 12 | public async override Task DisplayAsync(ViewCountPart part, BuildPartDisplayContext context) 13 | { 14 | if (context.DisplayType == "Detail") 15 | { 16 | await viewCountService.ViewAsync(part.ContentItem); 17 | } 18 | 19 | return Initialize(GetDisplayShapeType(context), model => model.Count = part.Count) 20 | .Location("Detail", "Content:10"); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/OrchardCoreContrib.ViewCount/Handlers/IViewCountContentHandler.cs: -------------------------------------------------------------------------------- 1 | namespace OrchardCoreContrib.ViewCount.Handlers; 2 | 3 | public interface IViewCountContentHandler 4 | { 5 | Task ViewingAsync(ViewCountContentContext context); 6 | 7 | Task ViewedAsync(ViewCountContentContext context); 8 | } 9 | -------------------------------------------------------------------------------- /src/OrchardCoreContrib.ViewCount/Handlers/ViewCountContentContext.cs: -------------------------------------------------------------------------------- 1 | using OrchardCore.ContentManagement.Handlers; 2 | using OrchardCore.ContentManagement; 3 | 4 | namespace OrchardCoreContrib.ViewCount.Handlers; 5 | 6 | public class ViewCountContentContext(ContentItem contentItem, int count) : ContentContextBase(contentItem) 7 | { 8 | public int Count { get; set; } = count; 9 | } 10 | -------------------------------------------------------------------------------- /src/OrchardCoreContrib.ViewCount/Handlers/ViewCountContentHandlerBase.cs: -------------------------------------------------------------------------------- 1 | namespace OrchardCoreContrib.ViewCount.Handlers; 2 | 3 | public abstract class ViewCountContentHandlerBase : IViewCountContentHandler 4 | { 5 | public virtual Task ViewingAsync(ViewCountContentContext context) => Task.CompletedTask; 6 | 7 | public virtual Task ViewedAsync(ViewCountContentContext context) => Task.CompletedTask; 8 | } 9 | -------------------------------------------------------------------------------- /src/OrchardCoreContrib.ViewCount/Manifest.cs: -------------------------------------------------------------------------------- 1 | using OrchardCore.Modules.Manifest; 2 | using ManifestConstants = OrchardCoreContrib.Modules.Manifest.ManifestConstants; 3 | 4 | [assembly: Module( 5 | Name = "View Count", 6 | Author = ManifestConstants.Author, 7 | Website = ManifestConstants.Website, 8 | Version = "1.0.0", 9 | Description = "Allows to count the content item views.", 10 | Dependencies = ["OrchardCore.Contents"], 11 | Category = "Content Management" 12 | )] 13 | -------------------------------------------------------------------------------- /src/OrchardCoreContrib.ViewCount/Migrations.cs: -------------------------------------------------------------------------------- 1 | using OrchardCore.ContentManagement.Metadata; 2 | using OrchardCore.ContentManagement.Metadata.Settings; 3 | using OrchardCore.Data.Migration; 4 | 5 | namespace OrchardCoreContrib.ViewCount; 6 | 7 | public class Migrations(IContentDefinitionManager contentDefinitionManager) : DataMigration 8 | { 9 | public async Task CreateAsync() 10 | { 11 | await contentDefinitionManager.AlterPartDefinitionAsync("ViewCountPart", builder => builder 12 | .Attachable() 13 | .WithDescription("Enables counting of views for the content item.")); 14 | return 1; 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/OrchardCoreContrib.ViewCount/Models/ViewCountPart.cs: -------------------------------------------------------------------------------- 1 | using OrchardCore.ContentManagement; 2 | 3 | namespace OrchardCoreContrib.ViewCount.Models; 4 | public class ViewCountPart : ContentPart 5 | { 6 | public int Count { get; set; } 7 | } 8 | -------------------------------------------------------------------------------- /src/OrchardCoreContrib.ViewCount/Services/IViewCountService.cs: -------------------------------------------------------------------------------- 1 | using OrchardCore.ContentManagement; 2 | 3 | namespace OrchardCoreContrib.ViewCount.Services; 4 | 5 | public interface IViewCountService 6 | { 7 | int GetViewsCount(ContentItem contentItem); 8 | 9 | Task ViewAsync(ContentItem contentItem); 10 | } 11 | -------------------------------------------------------------------------------- /src/OrchardCoreContrib.ViewCount/Startup.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.Extensions.DependencyInjection; 2 | using OrchardCore.ContentManagement; 3 | using OrchardCore.ContentManagement.Display.ContentDisplay; 4 | using OrchardCore.Data.Migration; 5 | using OrchardCore.Modules; 6 | using OrchardCoreContrib.ViewCount.Drivers; 7 | using OrchardCoreContrib.ViewCount.Models; 8 | using OrchardCoreContrib.ViewCount.Services; 9 | 10 | namespace OrchardCoreContrib.ViewCount; 11 | 12 | public sealed class Startup : StartupBase 13 | { 14 | public override void ConfigureServices(IServiceCollection services) 15 | { 16 | services.AddContentPart() 17 | .UseDisplayDriver(); 18 | 19 | services.AddDataMigration(); 20 | services.AddScoped(); 21 | } 22 | } 23 | 24 | -------------------------------------------------------------------------------- /src/OrchardCoreContrib.ViewCount/ViewModels/ViewCountPartViewModel.cs: -------------------------------------------------------------------------------- 1 | namespace OrchardCoreContrib.ViewCount.ViewModels; 2 | 3 | public class ViewCountPartViewModel 4 | { 5 | public int Count { get; set; } 6 | } 7 | -------------------------------------------------------------------------------- /src/OrchardCoreContrib.ViewCount/Views/ViewCountPart.cshtml: -------------------------------------------------------------------------------- 1 | @using Microsoft.AspNetCore.Mvc.Localization 2 | @model ViewCountPartViewModel 3 | 4 |
@T.Plural(Model.Count, "1 view", "{0} views")
-------------------------------------------------------------------------------- /src/OrchardCoreContrib.ViewCount/Views/_ViewImports.cshtml: -------------------------------------------------------------------------------- 1 | 2 | @inherits OrchardCore.DisplayManagement.Razor.RazorPage 3 | @addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers 4 | @addTagHelper *, OrchardCore.DisplayManagement 5 | @addTagHelper *, OrchardCore.ResourceManagement 6 | @using OrchardCoreContrib.ViewCount.ViewModels 7 | -------------------------------------------------------------------------------- /test/OrchardCoreContrib.ContentPermissions.Tests/OrchardCoreContrib.ContentPermissions.Tests.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | true 5 | 6 | 7 | 8 | 9 | all 10 | runtime; build; native; contentfiles; analyzers; buildtransitive 11 | 12 | 13 | 14 | 15 | 16 | 17 | all 18 | runtime; build; native; contentfiles; analyzers; buildtransitive 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | -------------------------------------------------------------------------------- /test/OrchardCoreContrib.Garnet.Tests/OrchardCoreContrib.Garnet.Tests.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | true 5 | 6 | 7 | 8 | 9 | all 10 | runtime; build; native; contentfiles; analyzers; buildtransitive 11 | 12 | 13 | 14 | 15 | 16 | 17 | all 18 | runtime; build; native; contentfiles; analyzers; buildtransitive 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | -------------------------------------------------------------------------------- /test/OrchardCoreContrib.Garnet.Tests/TestBase.cs: -------------------------------------------------------------------------------- 1 | using Garnet; 2 | 3 | namespace OrchardCoreContrib.Garnet.Tests; 4 | 5 | public abstract class TestBase : IAsyncLifetime 6 | { 7 | private static readonly GarnetServer _garnetServer; 8 | 9 | static TestBase() 10 | { 11 | _garnetServer = new([]); 12 | _garnetServer.Start(); 13 | } 14 | 15 | public virtual async Task InitializeAsync() => await Task.CompletedTask; 16 | 17 | public virtual async Task DisposeAsync() => await Task.CompletedTask; 18 | } 19 | -------------------------------------------------------------------------------- /test/OrchardCoreContrib.Garnet.Tests/Utilities.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.Extensions.Hosting; 2 | using Microsoft.Extensions.Logging; 3 | using Microsoft.Extensions.Options; 4 | using Moq; 5 | using OrchardCoreContrib.Garnet.Services; 6 | 7 | namespace OrchardCoreContrib.Garnet.Tests; 8 | 9 | public static class Utilities 10 | { 11 | public static async Task CreateGarnetServiceAsync() 12 | { 13 | var garnetClientFactory = new GarnetClientFactory( 14 | Mock.Of(), 15 | Mock.Of>()); 16 | var garnetService = new GarnetService(garnetClientFactory, Options.Create(new GarnetOptions())); 17 | 18 | await garnetService.ConnectAsync(); 19 | 20 | return garnetService; 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /test/OrchardCoreContrib.Modules.Tests/ContentLocalization/TransliterationServiceTests.cs: -------------------------------------------------------------------------------- 1 | using OrchardCoreContrib.ContentLocalization.Services; 2 | using OrchardCoreContrib.ContentLocalization.Transliteration; 3 | using Xunit; 4 | 5 | namespace OrchardCoreContrib.Modules.ContentLocalization.Tests; 6 | 7 | public class TransliterationServiceTests 8 | { 9 | [Theory] 10 | [InlineData(TransliterateScript.Arabic, "ضروري", "drwry")] 11 | [InlineData(TransliterateScript.Arabic, "الوثائق والشهادات", "alwtha'eq walshhadat")] 12 | [InlineData(TransliterateScript.Cyrillic, "НЕОПХОДНИ", "NEOPHODNI")] 13 | [InlineData(TransliterateScript.Cyrillic, "Документа и уверења", "Dokumenta i uvereњa")] 14 | public void TransliterateText(TransliterateScript script, string text, string expectedTransliteratedText) 15 | { 16 | // Arrange 17 | var transliterationService = new TransliterationService(new DefaultTransliterateRuleProvider()); 18 | 19 | // Act 20 | var transliteratedText = transliterationService.Transliterate(script, text); 21 | 22 | // Assert 23 | Assert.Equal(expectedTransliteratedText, transliteratedText); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /test/OrchardCoreContrib.Modules.Tests/appsettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "Email": { 3 | "From": "", 4 | "To": "", 5 | "Gmail": { 6 | "Username": "", 7 | "Password": "" 8 | }, 9 | "Hotmail": { 10 | "Username": "", 11 | "Password": "" 12 | }, 13 | "SendGrid": { 14 | "ApiKey": "" 15 | }, 16 | "Yahoo": { 17 | "Username": "", 18 | "Password": "" 19 | } 20 | } 21 | } -------------------------------------------------------------------------------- /test/OrchardCoreContrib.UserGroups.Tests/Extensions/UserGroupsManagerExtensionsTests.cs: -------------------------------------------------------------------------------- 1 | using Moq; 2 | using OrchardCore.Documents; 3 | using OrchardCoreContrib.UserGroups.Helpers.Tests; 4 | using OrchardCoreContrib.UserGroups.Models; 5 | using OrchardCoreContrib.UserGroups.Services; 6 | 7 | namespace OrchardCoreContrib.UserGroups.Extensions.Tests; 8 | 9 | public class UserGroupsManagerExtensionsTests 10 | { 11 | [Fact] 12 | public async Task GetUserGroupNamesAsync_ShouldReturnUserGroupNames() 13 | { 14 | // Arrange 15 | var userGroup1 = new UserGroup { Name = "Group1" }; 16 | var userGroup2 = new UserGroup { Name = "Group2" }; 17 | var (userGroupsManager, _) = UserGroupsManagerHelper.Create(userGroup1, userGroup2); 18 | 19 | // Act 20 | var result = await userGroupsManager.GetUserGroupNamesAsync(); 21 | 22 | // Assert 23 | Assert.Equal([userGroup1.Name, userGroup2.Name], result); 24 | } 25 | 26 | [Fact] 27 | public async Task CreateAsync_ShouldCreatesUserGroup() 28 | { 29 | // Arrange 30 | var groupName = "TestGroup"; 31 | var (userGroupsManager, documentManager) = UserGroupsManagerHelper.Create(); 32 | 33 | // Act 34 | var result = await userGroupsManager.CreateAsync(groupName, string.Empty); 35 | 36 | // Assert 37 | Assert.True(result.Succeeded); 38 | 39 | var userGroupDocument = await documentManager.GetOrCreateImmutableAsync(); 40 | Assert.NotEmpty(userGroupDocument.UserGroups); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /test/OrchardCoreContrib.UserGroups.Tests/OrchardCoreContrib.UserGroups.Tests.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | true 5 | 6 | 7 | 8 | 9 | all 10 | runtime; build; native; contentfiles; analyzers; buildtransitive 11 | 12 | 13 | 14 | 15 | 16 | 17 | all 18 | runtime; build; native; contentfiles; analyzers; buildtransitive 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | --------------------------------------------------------------------------------