├── .gitattributes ├── .github ├── FUNDING.yml └── dependabot.yml ├── .gitignore ├── .whitesource ├── CODE_OF_CONDUCT.md ├── CONTRIBUTING.md ├── LICENSE ├── README.md ├── azure-pipelines.yml ├── createLocalTemplate.cmd ├── docs ├── Makefile ├── conf.py ├── favicon.ico ├── features │ ├── dual_mode_blazor.rst │ ├── identityserver.rst │ ├── multitenancy.rst │ └── source_generators.rst ├── images │ ├── Blazor-Server.png │ ├── Blazor-WebAssembly.png │ ├── admin-multitenancy.png │ ├── blazorboilerplate-architecture.png │ ├── dual_mode_blazor.png │ ├── entity-generator.png │ ├── hosting_on_azure │ │ ├── image1.png │ │ ├── image10.png │ │ ├── image11.png │ │ ├── image12.png │ │ ├── image2.png │ │ ├── image3.png │ │ ├── image4.png │ │ ├── image5.png │ │ ├── image6.png │ │ ├── image7.png │ │ ├── image8.png │ │ └── image9.png │ └── logo-title.png ├── index.rst ├── intro │ └── architecture.rst ├── locales │ └── de_DE │ │ └── LC_MESSAGES │ │ ├── features │ │ ├── dual_mode_blazor.po │ │ ├── identityserver.po │ │ └── multitenancy.po │ │ ├── index.po │ │ ├── intro │ │ └── architecture.po │ │ └── quickstarts │ │ ├── breeze_sharp_with_blazor.po │ │ ├── entity_framework_core.po │ │ └── localization.po ├── make.bat ├── quickstarts │ ├── breeze_sharp_with_blazor.rst │ ├── deploy_with_terraform.rst │ ├── entity_framework_core.rst │ ├── hosting_on_azure.rst │ ├── localization.rst │ └── security.rst └── readme.md └── src ├── .editorconfig ├── .template.config └── template.json ├── BlazorBoilerplate.sln ├── Client └── BlazorBoilerplate.Client │ ├── BlazorBoilerplate.Client.csproj │ ├── Program.cs │ └── Properties │ └── launchSettings.json ├── Directory.Build.props ├── Server ├── BlazorBoilerplate.Server │ ├── .config │ │ └── dotnet-tools.json │ ├── Aop │ │ ├── ApiResponseExceptionAspect.cs │ │ ├── ApiResponseExceptionAttribute.cs │ │ ├── LogExceptionAspect.cs │ │ └── LogExceptionAttribute.cs │ ├── Authorization │ │ ├── AccountOptions.cs │ │ ├── AdditionalUserClaimsPrincipalFactory.cs │ │ ├── AuthorizationPolicyProvider.cs │ │ └── PermissionRequirement .cs │ ├── BlazorBoilerplate.Server.csproj │ ├── Controllers │ │ ├── AccountController.cs │ │ ├── AdminController.cs │ │ ├── AdminController.tt │ │ ├── ApplicationController.cs │ │ ├── CultureController.cs │ │ ├── EmailController.cs │ │ ├── ExternalAuthController.cs │ │ └── LocalizationController.cs │ ├── Extensions │ │ ├── Extensions.cs │ │ ├── LocalizedIdentityErrorDescriber.cs │ │ ├── ModuleLoader.cs │ │ └── SameSiteHandlingExtensions.cs │ ├── Factories │ │ ├── AopServicesFactory.cs │ │ └── EmailFactory.cs │ ├── Hubs │ │ └── ChatHub.cs │ ├── Localization │ │ ├── EmailFactory.pot │ │ ├── Global.pot │ │ ├── de-DE.po │ │ ├── en-US.po │ │ ├── fa-IR.po │ │ ├── it-IT.po │ │ └── pt-PT.po │ ├── Managers │ │ ├── AccountManager.cs │ │ ├── AdminManager.cs │ │ ├── EmailManager.cs │ │ ├── ExternalAuthManager.cs │ │ └── TenantSettingsManager.cs │ ├── Middleware │ │ ├── APIResponseRequestLoggingMiddleware.cs │ │ ├── BaseMiddleware.cs │ │ └── UserSessionMiddleware.cs │ ├── Modules │ │ └── placeholder.txt │ ├── Pages │ │ ├── Error.razor │ │ ├── ForgetTwoFactorClient.cshtml │ │ ├── ForgetTwoFactorClient.cshtml.cs │ │ ├── Login.cshtml │ │ ├── Login.cshtml.cs │ │ ├── LoginWith2fa.cshtml │ │ ├── LoginWith2fa.cshtml.cs │ │ ├── Logout.cshtml │ │ ├── Logout.cshtml.cs │ │ └── _Index.cshtml │ ├── Program.cs │ ├── Properties │ │ ├── PublishProfiles │ │ │ └── Release-win-x64.pubxml │ │ └── launchSettings.json │ ├── Providers │ │ └── UserIdProvider.cs │ ├── SecurityHeadersAttribute.cs │ ├── Services │ │ └── EmailService.cs │ ├── Startup.cs │ ├── appsettings.Development.json │ ├── appsettings.json │ ├── web.config │ └── wwwroot │ │ ├── icon-512.png │ │ ├── images │ │ ├── apple.svg │ │ ├── facebook.svg │ │ ├── google.svg │ │ ├── microsoft.svg │ │ └── twitter.svg │ │ ├── js │ │ └── interop.js │ │ ├── manifest.json │ │ ├── service-worker.js │ │ └── service-worker.published.js └── BlazorBoilerplate.Storage │ ├── ApplicationDbContext.cs │ ├── ApplicationPersistenceManager.cs │ ├── BasePersistenceManager.cs │ ├── BlazorBoilerplate - Backup.Storage.csproj │ ├── BlazorBoilerplate.Storage.csproj │ ├── ChangeTrackerExtensions.cs │ ├── Configurations │ └── MessageConfiguration.cs │ ├── Core │ └── Enums.cs │ ├── DatabaseInitializer.cs │ ├── LocalizationDbContext.cs │ ├── LocalizationPersistenceManager.cs │ ├── Mapping │ └── MappingProfile.cs │ ├── Migrations │ ├── ApplicationDb │ │ ├── 20240728152205_CreateApplicationDb.Designer.cs │ │ ├── 20240728152205_CreateApplicationDb.cs │ │ └── ApplicationDbContextModelSnapshot.cs │ ├── LocalizationDb │ │ ├── 20240728152153_CreateLocalizationDb.Designer.cs │ │ ├── 20240728152153_CreateLocalizationDb.cs │ │ └── LocalizationDbContextModelSnapshot.cs │ └── TenantStoreDb │ │ ├── 20240728152157_CreateTenantStoreDb.Designer.cs │ │ ├── 20240728152157_CreateTenantStoreDb.cs │ │ └── TenantStoreDbContextModelSnapshot.cs │ ├── ModelBuilderExtensions.cs │ ├── ServiceCollectionExtensions.cs │ ├── StorageLocalizationProvider.cs │ └── TenantStoreDbContext.cs ├── Shared ├── BlazorBoilerplate.Constants │ ├── BlazorBoilerplate.Constants.csproj │ ├── DefaultRoleNames.cs │ ├── DefaultUserNames.cs │ ├── EmailType.cs │ ├── HubPaths.cs │ ├── PasswordPolicy.cs │ ├── SettingKey.cs │ ├── SettingType.cs │ └── Settings.cs ├── BlazorBoilerplate.Infrastructure.AuthorizationDefinitions │ ├── BlazorBoilerplate.Infrastructure.AuthorizationDefinitions.csproj │ ├── ClaimConstants.cs │ ├── DomainRequirement.cs │ ├── EmailVerifiedRequirement.cs │ ├── Policies.cs │ ├── ScopeConstants.cs │ └── SharedAuthorizationPolicyProvider.cs ├── BlazorBoilerplate.Infrastructure.Storage │ ├── BlazorBoilerplate.Infrastructure.Storage.csproj │ ├── DataInterfaces │ │ ├── IAuditable.cs │ │ └── ISoftDelete.cs │ ├── DataModels │ │ ├── ApiLogItem.cs │ │ ├── ApplicationRole.cs │ │ ├── ApplicationUser.cs │ │ ├── ApplicationUserRole.cs │ │ ├── Company.cs │ │ ├── DbLog.cs │ │ ├── LocalizationRecord.cs │ │ ├── Message.cs │ │ ├── Person.cs │ │ ├── PluralFormRule.cs │ │ ├── PluralTranslation.cs │ │ ├── QueuedEmail.cs │ │ ├── TenantSetting.cs │ │ ├── Todo.cs │ │ └── UserProfile.cs │ └── Permissions │ │ ├── Actions.cs │ │ ├── EntityPermission.cs │ │ ├── EntityPermissions.cs │ │ ├── Permissions.cs │ │ ├── Permissions.tt │ │ └── PermissionsAttribute.cs ├── BlazorBoilerplate.Infrastructure │ ├── BlazorBoilerplate.Infrastructure.csproj │ ├── Extensions │ │ └── StringExtension.cs │ ├── Server │ │ ├── IAccountManager.cs │ │ ├── IAdminManager.cs │ │ ├── IAdminManager.tt │ │ ├── IEmailFactory.cs │ │ ├── IEmailManager.cs │ │ ├── IExternalAuthManager.cs │ │ ├── ITenantSettings.cs │ │ └── Models │ │ │ ├── APIResponse.cs │ │ │ ├── DomainException.cs │ │ │ └── ResponseMessage.cs │ └── Storage │ │ └── IDatabaseInitializer.cs ├── BlazorBoilerplate.Shared.DataInterfaces │ ├── BlazorBoilerplate.Shared.DataInterfaces.csproj │ └── EntityGeneratorConfig.json ├── BlazorBoilerplate.Shared.Localizer │ ├── BlazorBoilerplate.Shared.Localizer.csproj │ ├── Global.cs │ ├── IExtendedStringLocalizer.cs │ ├── ILocalizationProvider.cs │ ├── LocalizationManager.cs │ ├── LocalizationProvider.cs │ ├── LocalizationServiceCollectionExtensions.cs │ ├── NullStringLocalizer.cs │ ├── POCatalogExtensions.cs │ ├── POStringLocalizer.cs │ ├── Settings.cs │ ├── TextLocalizationOptions.cs │ └── TextLocalizerFactory.cs ├── BlazorBoilerplate.Shared │ ├── BlazorBoilerplate.Shared.csproj │ ├── Dto │ │ ├── Admin │ │ │ ├── RoleDto.cs │ │ │ └── TenantDto.cs │ │ ├── ApiResponseDto.cs │ │ ├── BaseDto.cs │ │ ├── Db │ │ │ ├── DbLog.cs │ │ │ ├── IdentityRoleClaim.cs │ │ │ ├── IdentityUserClaim.cs │ │ │ ├── IdentityUserLogin.cs │ │ │ ├── IdentityUserRole.cs │ │ │ ├── IdentityUserToken.cs │ │ │ ├── LocalizationRecord.cs │ │ │ ├── TenantSetting.cs │ │ │ ├── TenantSettingValues.cs │ │ │ ├── UserProfile.cs │ │ │ └── Validators │ │ │ │ └── TodoValidator.cs │ │ ├── Email │ │ │ ├── EmailAddressDto.cs │ │ │ ├── EmailDto.cs │ │ │ ├── EmailMessageDto.cs │ │ │ └── Validators │ │ │ │ └── EmailDtoValidator.cs │ │ ├── ErrorMessage.cs │ │ ├── ExternalAuth │ │ │ └── ErrorEnum.cs │ │ ├── IMementoDto.cs │ │ ├── LocalizationRecordKey.cs │ │ └── Sample │ │ │ ├── JobDto.cs │ │ │ ├── MessageDto.cs │ │ │ └── ReportPeriodDto.cs │ ├── EntityGeneratorConfig.json │ ├── Extensions │ │ ├── DateTimeExtensions.cs │ │ ├── GuidUtil.cs │ │ ├── HttpClientJsonExtensions.cs │ │ ├── HttpClientJsonInternalExtensions.cs │ │ ├── IJSRuntimeExtensions.cs │ │ ├── NavigationManagerExtensions.cs │ │ └── SkipEntityAspectContractResolver.cs │ ├── Helpers │ │ ├── RegexUtilities.cs │ │ └── TopologyUtils.cs │ ├── Interfaces │ │ ├── IAccountApiClient.cs │ │ ├── IApiClient.cs │ │ ├── IBaseApiClient.cs │ │ ├── IDateTimeFilter.cs │ │ ├── IDynamicComponent.cs │ │ ├── IFileUploadEntry.cs │ │ ├── ILocalizationApiClient.cs │ │ ├── IModule.cs │ │ ├── ITheme.cs │ │ ├── IUserSession.cs │ │ └── IViewNotifier.cs │ ├── Models │ │ ├── Account │ │ │ ├── AccountFormModel.cs │ │ │ ├── AuthenticatorVerificationCodeViewModel.cs │ │ │ ├── ChangePasswordViewModel.cs │ │ │ ├── ConfirmEmailViewModel.cs │ │ │ ├── ForgotPasswordViewModel.cs │ │ │ ├── LoggedOutViewModel.cs │ │ │ ├── LoginInputModel.cs │ │ │ ├── LoginResponseModel.cs │ │ │ ├── LoginViewModel.cs │ │ │ ├── LoginWith2faInputModel.cs │ │ │ ├── LoginWith2faModel.cs │ │ │ ├── LoginWithRecoveryCodeInputModel.cs │ │ │ ├── RegisterViewModel.cs │ │ │ ├── ResetPasswordViewModel.cs │ │ │ ├── UpdatePasswordViewModel.cs │ │ │ ├── UserViewModel.cs │ │ │ └── Validators │ │ │ │ ├── AuthenticatorVerificationCodeViewModelValidator.cs │ │ │ │ ├── ChangePasswordViewModelValidator.cs │ │ │ │ ├── ForgotPasswordViewModelValidator.cs │ │ │ │ ├── LoginInputModelValidator.cs │ │ │ │ ├── LoginViewModelValidator.cs │ │ │ │ ├── LoginWith2faInputModelValidator.cs │ │ │ │ ├── LoginWithRecoveryCodeInputModelValidator.cs │ │ │ │ ├── RegisterViewModelValidator.cs │ │ │ │ ├── ResetPasswordViewModelValidator.cs │ │ │ │ ├── RuleBuilderExtensions.cs │ │ │ │ ├── UpdatePasswordViewModelValidator.cs │ │ │ │ └── UserViewModelValidator.cs │ │ ├── BaseModule.cs │ │ ├── EmailConfiguration.cs │ │ ├── Localization │ │ │ ├── ChangeLocalizationRecordModel.cs │ │ │ └── LocalizationRecordFilterModel.cs │ │ ├── MainConfiguration.cs │ │ ├── QueryParameters.cs │ │ ├── SelectItem.cs │ │ ├── ToDoFilter.cs │ │ └── UserSession.cs │ ├── Providers │ │ ├── ExternalProvider.cs │ │ ├── IdentityAuthenticationStateProvider.cs │ │ └── ModuleProvider.cs │ ├── Services │ │ ├── AccountApiClient.cs │ │ ├── ApiClient.cs │ │ ├── AppState.cs │ │ ├── BaseApiClient.cs │ │ └── LocalizationApiClient.cs │ ├── TagHelpers │ │ └── AppTagHelperComponentTagHelper.cs │ └── Validators │ │ ├── Db │ │ ├── LocalizationRecordValidator.cs │ │ ├── PluralFormRuleValidator.cs │ │ └── PluralTranslationValidator.cs │ │ └── LocalizedAbstractValidator.cs ├── BlazorBoilerplate.UI.Base │ ├── BlazorBoilerplate.UI.Base.csproj │ ├── Pages │ │ ├── Account │ │ │ ├── ConfirmEmailPage.cs │ │ │ ├── LoginPage.cs │ │ │ ├── LoginWith2faPage.cs │ │ │ ├── ProfilePage.cs │ │ │ ├── RegisterPage.cs │ │ │ └── ResetPasswordPage.cs │ │ ├── Admin │ │ │ ├── ApiLogViewerPage.cs │ │ │ ├── DbLogViewerPage.cs │ │ │ ├── MultiTenancyPage.cs │ │ │ ├── PluralizationRules.cs │ │ │ ├── Roles.cs │ │ │ ├── Settings │ │ │ │ ├── EmailPage.cs │ │ │ │ ├── IndexPage.cs │ │ │ │ └── SettingsBase.cs │ │ │ ├── Translations.cs │ │ │ └── Users.cs │ │ └── ExternalAuth │ │ │ └── ErrorPage.cs │ └── Shared │ │ ├── Components │ │ ├── AutoFocus.razor │ │ ├── BaseComponent.cs │ │ ├── RedirectToLogin.razor │ │ ├── TopSection.cs │ │ └── ValidationSummaryBase.cs │ │ └── Layouts │ │ └── RootLayout.razor └── Modules │ ├── BlazorBoilerplate.GoogleAnalytics │ ├── BlazorBoilerplate.GoogleAnalytics.csproj │ ├── GoogleAnalyticsTagHelperComponent.cs │ ├── Module.cs │ ├── ModuleStrings.Designer.cs │ ├── ModuleStrings.it-IT.resx │ └── ModuleStrings.resx │ ├── BlazorBoilerplate.Theme.MudBlazor.Admin │ ├── BlazorBoilerplate.Theme.MudBlazor.Admin.csproj │ ├── Module.cs │ ├── Pages │ │ └── Admin │ │ │ ├── ApiLogViewer.razor │ │ │ ├── DbLogViewer.razor │ │ │ ├── Index.razor │ │ │ ├── MultiTenancy.razor │ │ │ ├── PluralizationRules.razor │ │ │ ├── Roles.razor │ │ │ ├── Settings │ │ │ ├── Email.razor │ │ │ └── Index.razor │ │ │ ├── Translations.razor │ │ │ └── Users.razor │ ├── Shared │ │ ├── Components │ │ │ ├── AdminNavMenu.razor │ │ │ └── TenantInfo.razor │ │ └── Layouts │ │ │ └── AdminLayout.razor │ └── _Imports.razor │ ├── BlazorBoilerplate.Theme.MudBlazor.Demo │ ├── BlazorBoilerplate.Theme.MudBlazor.Demo.csproj │ ├── Hubs │ │ └── ChatClient.cs │ ├── Module.cs │ ├── Pages │ │ ├── Dashboard.razor │ │ ├── DragNDrop.razor │ │ ├── Forum │ │ │ ├── Forum.razor │ │ │ ├── ForumMessage.razor │ │ │ ├── ForumMessageCreateForm.razor │ │ │ └── ForumPageModel.cs │ │ ├── Index.razor │ │ ├── Sponsors.razor │ │ ├── TestEmail.razor │ │ ├── TestEmailView.razor │ │ ├── TodoPaging.razor │ │ ├── TodoPaging.razor.cs │ │ └── TodoVirtualTable.razor │ ├── Shared │ │ └── Components │ │ │ ├── DonateButton.razor │ │ │ ├── DragNDrop │ │ │ ├── Job.razor │ │ │ ├── JobList.razor │ │ │ ├── JobsContainer.razor │ │ │ ├── ReportPeriod.razor │ │ │ ├── ReportPeriodList.razor │ │ │ └── ReportPeriodsContainer.razor │ │ │ ├── DrawerFooter.razor │ │ │ ├── Footer.razor │ │ │ ├── NavMenu.razor │ │ │ └── TopRightBarSection.razor │ ├── TagHelpers │ │ └── ThemeTagHelperComponent.cs │ ├── _Imports.razor │ └── wwwroot │ │ └── css │ │ └── site.css │ └── BlazorBoilerplate.Theme.MudBlazor │ ├── App.razor │ ├── BlazorBoilerplate.Theme.MudBlazor.csproj │ ├── Module.cs │ ├── Pages │ ├── Account │ │ ├── ConfirmEmail.razor │ │ ├── Login.razor │ │ ├── LoginWith2fa.razor │ │ ├── Profile.razor │ │ ├── Register.razor │ │ └── ResetPassword.razor │ └── ExternalAuth │ │ ├── Confirm.razor │ │ ├── Error.razor │ │ └── Success.razor │ ├── Services │ ├── FileUploadEntry.cs │ └── ViewNotifier.cs │ ├── Shared │ ├── Components │ │ ├── AuthorizingInProgress.razor │ │ ├── Breadcrumb.cs │ │ ├── Breadcrumbs.razor │ │ ├── Breadcrumbs.razor.cs │ │ ├── Breadcrumbs.razor.css │ │ ├── DateTimeFilter.razor │ │ ├── DrawerFooter.razor │ │ ├── DynamicComponentContainer.razor │ │ ├── Footer.razor │ │ ├── ItemsTableBase.cs │ │ ├── LoadingBackground.razor │ │ ├── Login.razor │ │ ├── MudValidationSummary.razor │ │ ├── NavMenu.razor │ │ ├── PageNotFound.razor │ │ ├── SelectCulture.razor │ │ ├── TopRightBarSection.razor │ │ ├── UserNotAuthorized.razor │ │ ├── UserProfile.razor │ │ └── UserProfile.razor.css │ └── Layouts │ │ ├── LoginLayout.razor │ │ ├── LoginLayout.razor.css │ │ ├── MainLayout.razor │ │ └── MainLayout.razor.css │ ├── TagHelpers │ ├── AppTagHelperComponentTagHelper.cs │ └── ThemeTagHelperComponent.cs │ ├── _Imports.razor │ └── wwwroot │ ├── css │ └── site.css │ └── images │ ├── apple-touch-icon-114x114.png │ ├── apple-touch-icon-120x120.png │ ├── apple-touch-icon-144x144.png │ ├── apple-touch-icon-152x152.png │ ├── apple-touch-icon-180x180.png │ ├── apple-touch-icon-57x57.png │ ├── apple-touch-icon-72x72.png │ ├── apple-touch-icon-76x76.png │ ├── apple-touch-icon.png │ ├── favicon.ico │ ├── logo-dark.svg │ ├── logo-title.png │ ├── logo.png │ ├── logo.svg │ ├── preloader.gif │ └── triangles.svg ├── Tests ├── BlazorBoilerplate.IdentityServer.Test1 │ ├── BlazorBoilerplate.IdentityServer.Test1.csproj │ ├── Program.cs │ └── SystemBrowser.cs ├── BlazorBoilerplate.IdentityServer.Test2 │ ├── BlazorBoilerplate.IdentityServer.Test2.csproj │ └── Program.cs └── BlazorBoilerplate.IdentityServer.Test3 │ ├── BlazorBoilerplate.IdentityServer.Test3.csproj │ └── Program.cs └── Utils ├── BlazorBoilerplate.SourceGenerator ├── AuditableGenerator.cs ├── BlazorBoilerplate.SourceGenerator.csproj ├── CrossPlatform.cs ├── EntityGenerator.cs └── EntityGeneratorConfig.cs ├── Docker ├── .dockerignore ├── Dockerfile ├── docker-compose.dcproj └── docker-compose.yml ├── Microk8s ├── blazorboilerplate-config.yaml ├── blazorboilerplate.yaml ├── deploy.sh └── sqlserver-config.yaml ├── Scripts ├── addTenantBindings.cmd ├── ctag.cmd ├── delObjBin.ps1 ├── ef-migrations-in-vs.txt ├── ef-migrations.cmd ├── makeTemplate.cmd ├── sphinx-prepare-docs-localization.cmd └── startLocal.cmd ├── T4 └── TemplateFilemanager.CS.ttinclude └── Terraform ├── AWS ├── .gitignore ├── bash.tmpl ├── docker-compose.tpl └── main.tf └── Azure └── .gitignore /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | 3 | github: ["enkodellc"] 4 | patreon: # Replace with a single Patreon username 5 | open_collective: # Replace with a single Open Collective username 6 | ko_fi: # Replace with a single Ko-fi username 7 | tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel 8 | community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry 9 | liberapay: # Replace with a single Liberapay username 10 | issuehunt: # Replace with a single IssueHunt username 11 | otechie: # Replace with a single Otechie username 12 | custom: ["https://www.paypal.com/paypalme/enkodellc","paypal.me/GiovanniQuarella","https://amzn.to/2L1eSMx"] 13 | -------------------------------------------------------------------------------- /.whitesource: -------------------------------------------------------------------------------- 1 | { 2 | "checkRunSettings": { 3 | "vulnerableCheckRunConclusionLevel": "failure" 4 | }, 5 | "issueSettings": { 6 | "minSeverityLevel": "LOW" 7 | } 8 | } -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 Keith 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /azure-pipelines.yml: -------------------------------------------------------------------------------- 1 | # ASP.NET 2 | # Build and test ASP.NET projects. 3 | # Add steps that publish symbols, save build artifacts, deploy, and more: 4 | # https://docs.microsoft.com/azure/devops/pipelines/apps/aspnet/build-aspnet-4 5 | 6 | pool: 7 | vmImage: 'windows-2019' 8 | 9 | variables: 10 | solution: '**/*.sln' 11 | buildPlatform: 'Any CPU' 12 | buildConfiguration: 'Release' 13 | 14 | 15 | steps: 16 | - task: UseDotNet@2 17 | displayName: 'Install SDK' 18 | inputs: 19 | packageType: sdk 20 | version: '7.0.x' 21 | includePreviewVersions: true 22 | 23 | # - task: NuGetToolInstaller@0 24 | 25 | - script: dotnet build ./src/BlazorBoilerplate.sln --configuration $(buildConfiguration) 26 | displayName: 'dotnet build blazorboilerplate' 27 | 28 | - task: DotNetCoreCLI@2 29 | displayName: 'Publishing App...' 30 | inputs: 31 | command: publish 32 | publishWebProjects: true 33 | arguments: '--configuration $(buildConfiguration) --output $(Build.ArtifactStagingDirectory)' 34 | zipAfterPublish: false 35 | 36 | - task: PublishBuildArtifacts@1 37 | displayName: 'Publishing Build Artifacts...' 38 | -------------------------------------------------------------------------------- /createLocalTemplate.cmd: -------------------------------------------------------------------------------- 1 | cd src 2 | dotnet new -i .\ 3 | pause -------------------------------------------------------------------------------- /docs/Makefile: -------------------------------------------------------------------------------- 1 | # Minimal makefile for Sphinx documentation 2 | # 3 | 4 | # You can set these variables from the command line, and also 5 | # from the environment for the first two. 6 | SPHINXOPTS ?= 7 | SPHINXBUILD ?= sphinx-build 8 | SOURCEDIR = . 9 | BUILDDIR = _build 10 | 11 | # Put it first so that "make" without argument is like "make help". 12 | help: 13 | @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) 14 | 15 | .PHONY: help Makefile 16 | 17 | # Catch-all target: route all unknown targets to Sphinx using the new 18 | # "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS). 19 | %: Makefile 20 | @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) 21 | -------------------------------------------------------------------------------- /docs/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/enkodellc/blazorboilerplate/90860470a5246949d0fe15b19e6f48154edcdf87/docs/favicon.ico -------------------------------------------------------------------------------- /docs/features/dual_mode_blazor.rst: -------------------------------------------------------------------------------- 1 | Dual mode Blazor 2 | ================ 3 | 4 | As stated in :doc:`doc home ` Blazor has two hosting models: **WebAssembly** or **Server**. 5 | Each hosting model has pros and cons, so you have to decide which is better for your web application. 6 | 7 | With Blazor Boilerplate you can switch at runtime between WebAssembly or Server in the Settings of Admin. 8 | 9 | .. image:: /images/dual_mode_blazor.png 10 | :align: center 11 | 12 | Choose the desired runtime in the dropdown list and then click on Save button. The application is then reloaded. 13 | -------------------------------------------------------------------------------- /docs/features/identityserver.rst: -------------------------------------------------------------------------------- 1 | IdentityServer4 2 | =============== 3 | 4 | `IdentityServer4 `_ has detailed documentation to read first. 5 | 6 | IdentityServer4 authentication is used with ApplicationController: 7 | 8 | :: 9 | 10 | [Route("api/data/[action]")] 11 | [Authorize(AuthenticationSchemes = AuthSchemes)] 12 | [BreezeQueryFilter] 13 | public class ApplicationController : Controller 14 | { 15 | private const string AuthSchemes = 16 | "Identity.Application" + "," + IdentityServerAuthenticationDefaults.AuthenticationScheme; //Cookie + Token authentication 17 | 18 | :: 19 | 20 | In fact as you can see ApplicationController uses both cookie and bearer token authentication scheme. 21 | 22 | Currently ApiClient uses cookie authentication to access ApplicationController. 23 | To see an example of external access with ApiClient and bearer authentication, you have to look at **BlazorBoilerplate.IdentityServer.Test#** projects. 24 | -------------------------------------------------------------------------------- /docs/features/source_generators.rst: -------------------------------------------------------------------------------- 1 | Source Generators 2 | ================= 3 | 4 | To avoid repetitive tasks, I created some `Generators`_ based on `Source Generators`_. 5 | 6 | Notes 7 | ^^^^^ 8 | Visual Studio 16 has some issues with Source Generators, especially when you clone BlazorBoilerplate and build the first time. 9 | 10 | Even rebuilding **BlazorBoilerplate.Shared** sometimes a lot of errors are listed, but they are fake. 11 | Ignore them and run **BlazorBoilerplate.Server** or close and reopen Visual Studio. 12 | 13 | Source generated is not visually updated. 14 | 15 | .. image:: /images/entity-generator.png 16 | :align: center 17 | 18 | Sometimes entities generated and present in the figure do not respect the most updated version of the source. 19 | 20 | .. _Generators: https://github.com/enkodellc/blazorboilerplate/tree/master/src/Utils/BlazorBoilerplate.SourceGenerator/ 21 | .. _Source Generators: https://devblogs.microsoft.com/dotnet/introducing-c-source-generators/ -------------------------------------------------------------------------------- /docs/images/Blazor-Server.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/enkodellc/blazorboilerplate/90860470a5246949d0fe15b19e6f48154edcdf87/docs/images/Blazor-Server.png -------------------------------------------------------------------------------- /docs/images/Blazor-WebAssembly.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/enkodellc/blazorboilerplate/90860470a5246949d0fe15b19e6f48154edcdf87/docs/images/Blazor-WebAssembly.png -------------------------------------------------------------------------------- /docs/images/admin-multitenancy.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/enkodellc/blazorboilerplate/90860470a5246949d0fe15b19e6f48154edcdf87/docs/images/admin-multitenancy.png -------------------------------------------------------------------------------- /docs/images/blazorboilerplate-architecture.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/enkodellc/blazorboilerplate/90860470a5246949d0fe15b19e6f48154edcdf87/docs/images/blazorboilerplate-architecture.png -------------------------------------------------------------------------------- /docs/images/dual_mode_blazor.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/enkodellc/blazorboilerplate/90860470a5246949d0fe15b19e6f48154edcdf87/docs/images/dual_mode_blazor.png -------------------------------------------------------------------------------- /docs/images/entity-generator.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/enkodellc/blazorboilerplate/90860470a5246949d0fe15b19e6f48154edcdf87/docs/images/entity-generator.png -------------------------------------------------------------------------------- /docs/images/hosting_on_azure/image1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/enkodellc/blazorboilerplate/90860470a5246949d0fe15b19e6f48154edcdf87/docs/images/hosting_on_azure/image1.png -------------------------------------------------------------------------------- /docs/images/hosting_on_azure/image10.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/enkodellc/blazorboilerplate/90860470a5246949d0fe15b19e6f48154edcdf87/docs/images/hosting_on_azure/image10.png -------------------------------------------------------------------------------- /docs/images/hosting_on_azure/image11.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/enkodellc/blazorboilerplate/90860470a5246949d0fe15b19e6f48154edcdf87/docs/images/hosting_on_azure/image11.png -------------------------------------------------------------------------------- /docs/images/hosting_on_azure/image12.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/enkodellc/blazorboilerplate/90860470a5246949d0fe15b19e6f48154edcdf87/docs/images/hosting_on_azure/image12.png -------------------------------------------------------------------------------- /docs/images/hosting_on_azure/image2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/enkodellc/blazorboilerplate/90860470a5246949d0fe15b19e6f48154edcdf87/docs/images/hosting_on_azure/image2.png -------------------------------------------------------------------------------- /docs/images/hosting_on_azure/image3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/enkodellc/blazorboilerplate/90860470a5246949d0fe15b19e6f48154edcdf87/docs/images/hosting_on_azure/image3.png -------------------------------------------------------------------------------- /docs/images/hosting_on_azure/image4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/enkodellc/blazorboilerplate/90860470a5246949d0fe15b19e6f48154edcdf87/docs/images/hosting_on_azure/image4.png -------------------------------------------------------------------------------- /docs/images/hosting_on_azure/image5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/enkodellc/blazorboilerplate/90860470a5246949d0fe15b19e6f48154edcdf87/docs/images/hosting_on_azure/image5.png -------------------------------------------------------------------------------- /docs/images/hosting_on_azure/image6.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/enkodellc/blazorboilerplate/90860470a5246949d0fe15b19e6f48154edcdf87/docs/images/hosting_on_azure/image6.png -------------------------------------------------------------------------------- /docs/images/hosting_on_azure/image7.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/enkodellc/blazorboilerplate/90860470a5246949d0fe15b19e6f48154edcdf87/docs/images/hosting_on_azure/image7.png -------------------------------------------------------------------------------- /docs/images/hosting_on_azure/image8.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/enkodellc/blazorboilerplate/90860470a5246949d0fe15b19e6f48154edcdf87/docs/images/hosting_on_azure/image8.png -------------------------------------------------------------------------------- /docs/images/hosting_on_azure/image9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/enkodellc/blazorboilerplate/90860470a5246949d0fe15b19e6f48154edcdf87/docs/images/hosting_on_azure/image9.png -------------------------------------------------------------------------------- /docs/images/logo-title.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/enkodellc/blazorboilerplate/90860470a5246949d0fe15b19e6f48154edcdf87/docs/images/logo-title.png -------------------------------------------------------------------------------- /docs/intro/architecture.rst: -------------------------------------------------------------------------------- 1 | Architecture 2 | ============ 3 | 4 | .. image:: /images/blazorboilerplate-architecture.png 5 | :align: center 6 | 7 | The diagram shows the dependencies of the main projects. 8 | Every project with text to localize depends on **Localization** project. 9 | 10 | **Client** project is used only with Blazor WebAssembly, so it runs on the browser. It initializes the WebAssembly startup. If you only use Blazor Server, remove this project from solution. 11 | 12 | **Server** project manages the main services: authentication, authorization, API, etc. 13 | 14 | **Storage** project manages the persistence of models in a database with `Entity Framework Core `_. 15 | 16 | **Infrastructure** project contains interfaces and models in common among projects running on server. 17 | 18 | **Shared** project contains base interfaces and models in common among projects running on server or client. 19 | 20 | **Module** projects contains UI, services, etc. that define your web application. -------------------------------------------------------------------------------- /docs/locales/de_DE/LC_MESSAGES/features/identityserver.po: -------------------------------------------------------------------------------- 1 | # SOME DESCRIPTIVE TITLE. 2 | # Copyright (C) 2020, Blazor Boilerplate Team 3 | # This file is distributed under the same license as the Blazor Boilerplate 4 | # package. 5 | # FIRST AUTHOR , 2020. 6 | # 7 | #, fuzzy 8 | msgid "" 9 | msgstr "" 10 | "Project-Id-Version: Blazor Boilerplate \n" 11 | "Report-Msgid-Bugs-To: \n" 12 | "POT-Creation-Date: 2020-07-06 17:43+0200\n" 13 | "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" 14 | "Last-Translator: FULL NAME \n" 15 | "Language-Team: LANGUAGE \n" 16 | "MIME-Version: 1.0\n" 17 | "Content-Type: text/plain; charset=utf-8\n" 18 | "Content-Transfer-Encoding: 8bit\n" 19 | "Generated-By: Babel 2.8.0\n" 20 | 21 | #: ../../features/identityserver.rst:2 1b58785483a145cebd7a6445e0b6f759 22 | msgid "IdentityServer4" 23 | msgstr "" 24 | 25 | #: ../../features/identityserver.rst:4 5c8a498edd3c48d3afbbe2173538ab61 26 | msgid "" 27 | "`IdentityServer4 `_ " 28 | "has been recently updated to version 4.0." 29 | msgstr "" 30 | 31 | #: ../../features/identityserver.rst:6 4c4d68e2089140f3af8b354a4b3d92ac 32 | msgid "" 33 | "There are some breaking changes and new configurations are needed, so the" 34 | " integration in Blazor Boilerplate is in the roadmap." 35 | msgstr "" 36 | 37 | -------------------------------------------------------------------------------- /docs/make.bat: -------------------------------------------------------------------------------- 1 | @ECHO OFF 2 | 3 | pushd %~dp0 4 | 5 | REM Command file for Sphinx documentation 6 | 7 | if "%SPHINXBUILD%" == "" ( 8 | set SPHINXBUILD=sphinx-build 9 | ) 10 | set SOURCEDIR=. 11 | set BUILDDIR=_build 12 | 13 | if "%1" == "" goto help 14 | 15 | %SPHINXBUILD% >NUL 2>NUL 16 | if errorlevel 9009 ( 17 | echo. 18 | echo.The 'sphinx-build' command was not found. Make sure you have Sphinx 19 | echo.installed, then set the SPHINXBUILD environment variable to point 20 | echo.to the full path of the 'sphinx-build' executable. Alternatively you 21 | echo.may add the Sphinx directory to PATH. 22 | echo. 23 | echo.If you don't have Sphinx installed, grab it from 24 | echo.http://sphinx-doc.org/ 25 | exit /b 1 26 | ) 27 | 28 | %SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O% 29 | goto end 30 | 31 | :help 32 | %SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O% 33 | 34 | :end 35 | popd 36 | -------------------------------------------------------------------------------- /docs/readme.md: -------------------------------------------------------------------------------- 1 | # Blazor Boilerplate documentation 2 | 3 | The folder contains the documentation for Blazor Boilerplate. 4 | 5 | We are using [Read the docs](https://readthedocs.org/) to host the documentation and the rendered version 6 | can be found [here](https://blazor-boilerplate.readthedocs.io/). 7 | 8 | Doc pages are authored in ReStructuredText (RST) - you can find a primer [here](http://www.sphinx-doc.org/en/stable/rest.html). 9 | 10 | You can find more information about RTD and Sphinx under the following links: 11 | 12 | * [Read the Docs documentation](https://docs.readthedocs.io/en/latest/index.html) 13 | * [Sphinx](http://www.sphinx-doc.org/) 14 | * [Getting started Screencast](https://www.youtube.com/watch?feature=player_embedded&v=oJsUvBQyHBs) -------------------------------------------------------------------------------- /src/.editorconfig: -------------------------------------------------------------------------------- 1 | charset = utf-8 -------------------------------------------------------------------------------- /src/.template.config/template.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "http://json.schemastore.org/template", 3 | "author": "Keith Fimreite", 4 | "classifications": [ "Web", "Blazor", "WebAssembly", "WebApi", "IdentityServer4" ], 5 | "name": "Blazor Boilerplate & Starter Kit", 6 | "defaultName": "BlazorBoilerplate", 7 | "description": "Blazor Boilerplate SPA Admin Template for Blazor Server and Client", 8 | "identity": "BlazorBoilerplate.CSharp", 9 | "groupIdentity": "BlazorBoilerplate", 10 | "shortName": "blazorboilerplate", 11 | "tags": { 12 | "language": "C#", 13 | "type":"project" 14 | }, 15 | "sourceName": "BlazorBoilerplate", 16 | "preferNameDirectory": true, 17 | "sources": [ 18 | { 19 | "source": "./", 20 | "target": "./", 21 | "exclude": [ 22 | ".template.config/**" 23 | ] 24 | } 25 | ] 26 | } -------------------------------------------------------------------------------- /src/Client/BlazorBoilerplate.Client/Properties/launchSettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "iisSettings": { 3 | "windowsAuthentication": false, 4 | "anonymousAuthentication": true, 5 | "iisExpress": { 6 | "applicationUrl": "http://localhost:53415/", 7 | "sslPort": 0 8 | } 9 | }, 10 | "profiles": { 11 | "IIS Express": { 12 | "commandName": "IISExpress", 13 | "launchBrowser": true, 14 | "inspectUri": "{wsProtocol}://{url.hostname}:{url.port}/_framework/debug/ws-proxy?browser={browserInspectUri}", 15 | "environmentVariables": { 16 | "ASPNETCORE_ENVIRONMENT": "Development" 17 | } 18 | }, 19 | "BlazorBoilerplate.Client": { 20 | "commandName": "Project", 21 | "launchBrowser": true, 22 | "inspectUri": "{wsProtocol}://{url.hostname}:{url.port}/_framework/debug/ws-proxy?browser={browserInspectUri}", 23 | "environmentVariables": { 24 | "ASPNETCORE_ENVIRONMENT": "Development" 25 | }, 26 | "applicationUrl": "http://localhost:53418/" 27 | } 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/Directory.Build.props: -------------------------------------------------------------------------------- 1 | 2 | 3 | 7.0.1 4 | preview 5 | Keith Fimreite, Giovanni Quarella 6 | EnkodeLLC 7 | Blazor Boilerplate is starter kit / SPA Admin Template for Blazor 8 | https://blazorboilerplate.com/ 9 | https://blazorboilerplate.com/ 10 | git 11 | https://github.com/enkodellc/blazorboilerplate 12 | $(MSBuildThisFileDirectory) 13 | false 14 | Full 15 | 16 | 17 | -------------------------------------------------------------------------------- /src/Server/BlazorBoilerplate.Server/.config/dotnet-tools.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": 1, 3 | "isRoot": true, 4 | "tools": { 5 | "dotnet-ef": { 6 | "version": "5.0.3", 7 | "commands": [ 8 | "dotnet-ef" 9 | ] 10 | } 11 | } 12 | } -------------------------------------------------------------------------------- /src/Server/BlazorBoilerplate.Server/Aop/ApiResponseExceptionAttribute.cs: -------------------------------------------------------------------------------- 1 | using AspectInjector.Broker; 2 | 3 | namespace BlazorBoilerplate.Server.Aop 4 | { 5 | [Injection(typeof(ApiResponseExceptionAspect))] 6 | public class ApiResponseExceptionAttribute : Attribute 7 | { 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /src/Server/BlazorBoilerplate.Server/Aop/LogExceptionAttribute.cs: -------------------------------------------------------------------------------- 1 | using AspectInjector.Broker; 2 | 3 | namespace BlazorBoilerplate.Server.Aop 4 | { 5 | [Injection(typeof(LogExceptionAspect))] 6 | public class LogExceptionAttribute : Attribute 7 | { 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /src/Server/BlazorBoilerplate.Server/Authorization/AccountOptions.cs: -------------------------------------------------------------------------------- 1 | namespace BlazorBoilerplate.Server.Authorization 2 | { 3 | public class AccountOptions 4 | { 5 | public static bool AllowLocalLogin = true; 6 | public static bool AllowRememberLogin = true; 7 | public static TimeSpan RememberMeLoginDuration = TimeSpan.FromDays(30); 8 | 9 | public static bool ShowLogoutPrompt = true; 10 | public static bool AutomaticRedirectAfterSignOut = false; 11 | 12 | // specify the Windows authentication scheme being used 13 | public static readonly string WindowsAuthenticationSchemeName = Microsoft.AspNetCore.Server.IISIntegration.IISDefaults.AuthenticationScheme; 14 | // if user uses windows auth, should we load the groups from windows 15 | public static bool IncludeWindowsGroups = false; 16 | 17 | public static string InvalidCredentialsErrorMessage = "Invalid username or password"; 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/Server/BlazorBoilerplate.Server/Authorization/AuthorizationPolicyProvider.cs: -------------------------------------------------------------------------------- 1 | using BlazorBoilerplate.Infrastructure.AuthorizationDefinitions; 2 | using Microsoft.AspNetCore.Authorization; 3 | using Microsoft.Extensions.Options; 4 | 5 | namespace BlazorBoilerplate.Server.Authorization 6 | { 7 | public class AuthorizationPolicyProvider : SharedAuthorizationPolicyProvider 8 | { 9 | private readonly AuthorizationOptions _options; 10 | 11 | public AuthorizationPolicyProvider(IOptions options) : base(options) 12 | { 13 | _options = options.Value; 14 | } 15 | 16 | public override async Task GetPolicyAsync(string policyName) 17 | { 18 | // Check static policies first 19 | var policy = await base.GetPolicyAsync(policyName); 20 | 21 | if (policy == null) 22 | { 23 | policy = new AuthorizationPolicyBuilder() 24 | .RequireAuthenticatedUser() 25 | .AddRequirements(new PermissionRequirement(policyName)) 26 | .Build(); 27 | 28 | // Add policy to the AuthorizationOptions, so we don't have to re-create it each time 29 | _options.AddPolicy(policyName, policy); 30 | } 31 | 32 | return policy; 33 | } 34 | } 35 | } -------------------------------------------------------------------------------- /src/Server/BlazorBoilerplate.Server/Authorization/PermissionRequirement .cs: -------------------------------------------------------------------------------- 1 | using BlazorBoilerplate.Infrastructure.AuthorizationDefinitions; 2 | using Microsoft.AspNetCore.Authorization; 3 | 4 | namespace BlazorBoilerplate.Server.Authorization 5 | { 6 | public class PermissionRequirement : IAuthorizationRequirement 7 | { 8 | public PermissionRequirement(string permission) 9 | { 10 | Permission = permission; 11 | } 12 | 13 | public string Permission { get; set; } 14 | } 15 | 16 | public class PermissionRequirementHandler : AuthorizationHandler, IAuthorizationRequirement 17 | { 18 | protected override Task HandleRequirementAsync(AuthorizationHandlerContext context, PermissionRequirement requirement) 19 | { 20 | if (context.User == null) 21 | return Task.CompletedTask; 22 | 23 | if (context.User.Claims.Any(c => c.Type == ApplicationClaimTypes.Permission && c.Value == requirement.Permission)) 24 | context.Succeed(requirement); 25 | else 26 | context.Fail(); 27 | 28 | return Task.CompletedTask; 29 | } 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/Server/BlazorBoilerplate.Server/Controllers/CultureController.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.AspNetCore.Localization; 2 | using Microsoft.AspNetCore.Mvc; 3 | using NSwag.Annotations; 4 | using System.Globalization; 5 | 6 | namespace BlazorBoilerplate.Server.Controllers 7 | { 8 | [OpenApiIgnore] 9 | [Route("[controller]/[action]")] 10 | public class CultureController : Controller 11 | { 12 | public IActionResult SetCulture(string culture, string redirectUri) 13 | { 14 | if (culture != null) 15 | { 16 | HttpContext.Response.Cookies.Append(CookieRequestCultureProvider.DefaultCookieName, 17 | CookieRequestCultureProvider.MakeCookieValue( 18 | new RequestCulture(CultureInfo.CurrentCulture, CultureInfo.CurrentUICulture)), 19 | new CookieOptions() { Expires = DateTimeOffset.Now.AddDays(30) }); 20 | } 21 | 22 | return LocalRedirect(redirectUri); 23 | } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/Server/BlazorBoilerplate.Server/Factories/AopServicesFactory.cs: -------------------------------------------------------------------------------- 1 | using BlazorBoilerplate.Server.Aop; 2 | using BlazorBoilerplate.Shared.Localizer; 3 | using Microsoft.AspNetCore.Localization; 4 | using Serilog.Extensions.Logging; 5 | 6 | namespace BlazorBoilerplate.Server.Factories 7 | { 8 | public static class AopServicesFactory 9 | { 10 | public static readonly ServiceProvider ServiceProvider; 11 | 12 | static AopServicesFactory() 13 | { 14 | ServiceProvider = new ServiceCollection() 15 | .AddLogging() 16 | .AddLocalization() 17 | .Configure(options => 18 | { 19 | options.DefaultRequestCulture = new RequestCulture(Settings.SupportedCultures[0]); 20 | options.AddSupportedCultures(Settings.SupportedCultures); 21 | options.AddSupportedUICultures(Settings.SupportedCultures); 22 | }) 23 | .AddTransient() 24 | .AddTransient() 25 | .AddSingleton(services => new SerilogLoggerFactory()) 26 | .BuildServiceProvider(); 27 | } 28 | 29 | public static object GetInstance(Type type) => ServiceProvider.GetRequiredService(type); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/Server/BlazorBoilerplate.Server/Managers/TenantSettingsManager.cs: -------------------------------------------------------------------------------- 1 | using BlazorBoilerplate.Infrastructure.Server; 2 | using BlazorBoilerplate.Shared.Dto.Db; 3 | using BlazorBoilerplate.Storage; 4 | using Microsoft.EntityFrameworkCore; 5 | using Newtonsoft.Json; 6 | 7 | namespace BlazorBoilerplate.Server.Managers 8 | { 9 | public class TenantSettingsManager : ITenantSettings where TSettings : class, new() 10 | { 11 | private readonly string prefix = $"{typeof(TSettings).Name}_"; 12 | private readonly ApplicationDbContext _dbContext; 13 | 14 | public TenantSettingsManager(ApplicationDbContext dbContext) 15 | { 16 | _dbContext = dbContext; 17 | } 18 | 19 | public TSettings Value 20 | { 21 | get 22 | { 23 | var settings = _dbContext.TenantSettings.AsNoTracking().ToDictionary(i => i.Key, i => i.Value.ToString()); 24 | var tsettings = settings.Concat(TenantSettingValues.Default.ToDictionary(i => i.Key, i => i.Value.Item1) 25 | .Where(kvp => !settings.ContainsKey(kvp.Key))) 26 | .Where(i => i.Key.ToString().StartsWith(prefix)) 27 | .ToDictionary(i => i.Key.ToString().Replace(prefix, string.Empty), i => i.Value); 28 | 29 | return JsonConvert.DeserializeObject(JsonConvert.SerializeObject(tsettings)); 30 | } 31 | } 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/Server/BlazorBoilerplate.Server/Modules/placeholder.txt: -------------------------------------------------------------------------------- 1 | this folder is for module dlls. -------------------------------------------------------------------------------- /src/Server/BlazorBoilerplate.Server/Pages/Error.razor: -------------------------------------------------------------------------------- 1 | @page "/error" 2 | 3 | 4 |

Error.

5 |

An error occurred while processing your request.

6 | 7 |

Development Mode

8 |

9 | Swapping to Development environment will display more detailed information about the error that occurred. 10 |

11 |

12 | The Development environment shouldn't be enabled for deployed applications. 13 | It can result in displaying sensitive information from exceptions to end users. 14 | For local debugging, enable the Development environment by setting the ASPNETCORE_ENVIRONMENT environment variable to Development 15 | and restarting the app. 16 |

-------------------------------------------------------------------------------- /src/Server/BlazorBoilerplate.Server/Pages/ForgetTwoFactorClient.cshtml: -------------------------------------------------------------------------------- 1 | @page "/server/forgettwofactorclient" 2 | @model BlazorBoilerplate.Server.Pages.ForgetTwoFactorClientModel -------------------------------------------------------------------------------- /src/Server/BlazorBoilerplate.Server/Pages/ForgetTwoFactorClient.cshtml.cs: -------------------------------------------------------------------------------- 1 | using BlazorBoilerplate.Constants; 2 | using BlazorBoilerplate.Infrastructure.Server; 3 | using BlazorBoilerplate.Shared.Models.Account; 4 | using Microsoft.AspNetCore.Authorization; 5 | using Microsoft.AspNetCore.Mvc; 6 | using Microsoft.AspNetCore.Mvc.RazorPages; 7 | 8 | namespace BlazorBoilerplate.Server.Pages 9 | { 10 | [Authorize] 11 | public class ForgetTwoFactorClientModel : PageModel 12 | { 13 | private readonly IAccountManager _accountManager; 14 | 15 | public ForgetTwoFactorClientModel(IAccountManager accountManager) 16 | { 17 | _accountManager = accountManager; 18 | } 19 | public async Task OnPostAsync(AccountFormModel model) 20 | { 21 | await _accountManager.ForgetTwoFactorClient(User); 22 | 23 | return LocalRedirect(Url.Content($"~{Settings.ProfilePath}")); 24 | } 25 | } 26 | } -------------------------------------------------------------------------------- /src/Server/BlazorBoilerplate.Server/Pages/Login.cshtml: -------------------------------------------------------------------------------- 1 | @page "/server/login" 2 | @model BlazorBoilerplate.Server.Pages.LoginModel 3 | -------------------------------------------------------------------------------- /src/Server/BlazorBoilerplate.Server/Pages/LoginWith2fa.cshtml: -------------------------------------------------------------------------------- 1 | @page "/server/loginwith2fa" 2 | @model BlazorBoilerplate.Server.Pages.LoginWith2faPageModel 3 | -------------------------------------------------------------------------------- /src/Server/BlazorBoilerplate.Server/Pages/Logout.cshtml: -------------------------------------------------------------------------------- 1 | @page "/server/logout" 2 | @model BlazorBoilerplate.Server.Pages.LogoutModel -------------------------------------------------------------------------------- /src/Server/BlazorBoilerplate.Server/Pages/Logout.cshtml.cs: -------------------------------------------------------------------------------- 1 | using BlazorBoilerplate.Infrastructure.Server; 2 | using BlazorBoilerplate.Shared.Models.Account; 3 | using Microsoft.AspNetCore.Authorization; 4 | using Microsoft.AspNetCore.Mvc; 5 | using Microsoft.AspNetCore.Mvc.RazorPages; 6 | 7 | namespace BlazorBoilerplate.Server.Pages 8 | { 9 | [Authorize] 10 | public class LogoutModel : PageModel 11 | { 12 | private readonly IAccountManager _accountManager; 13 | 14 | public LogoutModel(IAccountManager accountManager) 15 | { 16 | _accountManager = accountManager; 17 | } 18 | public async Task OnPostAsync(AccountFormModel model) 19 | { 20 | await _accountManager.Logout(User); 21 | 22 | return LocalRedirect(Url.Content($"~{model.ReturnUrl}")); 23 | } 24 | } 25 | } -------------------------------------------------------------------------------- /src/Server/BlazorBoilerplate.Server/Properties/PublishProfiles/Release-win-x64.pubxml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 8 | FileSystem 9 | FileSystem 10 | Release 11 | Any CPU 12 | 13 | True 14 | False 15 | bc324a5f-48c6-45b9-b3a5-0d63f46f5c56 16 | bin\Release\net5.0\publish\ 17 | True 18 | net7.0 19 | false 20 | win-x64 21 | 22 | -------------------------------------------------------------------------------- /src/Server/BlazorBoilerplate.Server/Properties/launchSettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "iisSettings": { 3 | "windowsAuthentication": false, 4 | "anonymousAuthentication": true, 5 | "iisExpress": { 6 | "applicationUrl": "http://localhost:53414/", 7 | "sslPort": 0 8 | } 9 | }, 10 | "profiles": { 11 | "IIS Express": { 12 | "commandName": "IISExpress", 13 | "launchBrowser": true, 14 | "inspectUri": "{wsProtocol}://{url.hostname}:{url.port}/_framework/debug/ws-proxy?browser={browserInspectUri}", 15 | "environmentVariables": { 16 | "ASPNETCORE_ENVIRONMENT": "Development" 17 | } 18 | }, 19 | "Kestrel": { 20 | "commandName": "Project", 21 | "launchBrowser": true, 22 | "inspectUri": "{wsProtocol}://{url.hostname}:{url.port}/_framework/debug/ws-proxy?browser={browserInspectUri}", 23 | "environmentVariables": { 24 | "ASPNETCORE_ENVIRONMENT": "Development" 25 | }, 26 | "applicationUrl": "http://localhost:53416/" 27 | }, 28 | "Docker": { 29 | "commandName": "Docker", 30 | "launchBrowser": true, 31 | "launchUrl": "{Scheme}://{ServiceHost}:{ServicePort}", 32 | "httpPort": 53415 33 | } 34 | } 35 | } -------------------------------------------------------------------------------- /src/Server/BlazorBoilerplate.Server/Providers/UserIdProvider.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.AspNetCore.SignalR; 2 | using System.Security.Claims; 3 | 4 | namespace BlazorBoilerplate.Server.Providers 5 | { 6 | public class UserIdProvider : IUserIdProvider 7 | { 8 | public virtual string GetUserId(HubConnectionContext connection) 9 | { 10 | return connection.User?.FindFirst(ClaimTypes.Name)?.Value; 11 | } 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /src/Server/BlazorBoilerplate.Server/appsettings.Development.json: -------------------------------------------------------------------------------- 1 | { 2 | "BlazorBoilerplate": { 3 | "ApplicationUrl": "http://localhost:53414", 4 | "IS4ApplicationUrl": "http://localhost:53414" 5 | }, 6 | "Serilog": { 7 | "MinimumLevel": { 8 | "Default": "Debug" 9 | } 10 | } 11 | } -------------------------------------------------------------------------------- /src/Server/BlazorBoilerplate.Server/web.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /src/Server/BlazorBoilerplate.Server/wwwroot/icon-512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/enkodellc/blazorboilerplate/90860470a5246949d0fe15b19e6f48154edcdf87/src/Server/BlazorBoilerplate.Server/wwwroot/icon-512.png -------------------------------------------------------------------------------- /src/Server/BlazorBoilerplate.Server/wwwroot/images/apple.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /src/Server/BlazorBoilerplate.Server/wwwroot/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "BlazorBoilerplate & Starter Kit", 3 | "short_name": "BlazorBoilerplate", 4 | "start_url": "/", 5 | "display": "standalone", 6 | "background_color": "#ffffff", 7 | "theme_color": "#5D2E8F", 8 | "icons": [ 9 | { 10 | "src": "icon-512.png", 11 | "type": "image/png", 12 | "sizes": "512x512" 13 | } 14 | ] 15 | } 16 | -------------------------------------------------------------------------------- /src/Server/BlazorBoilerplate.Server/wwwroot/service-worker.js: -------------------------------------------------------------------------------- 1 | // In development, always fetch from the network and do not enable offline support. 2 | // This is because caching would make development more difficult (changes would not 3 | // be reflected on the first load after each change). 4 | self.addEventListener('fetch', () => { }); 5 | -------------------------------------------------------------------------------- /src/Server/BlazorBoilerplate.Storage/Configurations/MessageConfiguration.cs: -------------------------------------------------------------------------------- 1 | using BlazorBoilerplate.Infrastructure.Storage.DataModels; 2 | using Microsoft.EntityFrameworkCore; 3 | using Microsoft.EntityFrameworkCore.Metadata.Builders; 4 | 5 | namespace BlazorBoilerplate.Storage.Configurations 6 | { 7 | public class MessageConfiguration : IEntityTypeConfiguration 8 | { 9 | public void Configure(EntityTypeBuilder builder) 10 | { 11 | builder.Property(g => g.UserName) 12 | .IsRequired(); 13 | 14 | builder.Property(g => g.Text) 15 | .IsRequired(); 16 | 17 | builder.HasOne(a => a.Sender) 18 | .WithMany(m => m.Messages) 19 | .HasForeignKey(u => u.UserID); 20 | } 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/Server/BlazorBoilerplate.Storage/Core/Enums.cs: -------------------------------------------------------------------------------- 1 | namespace BlazorBoilerplate.Storage.Core 2 | { 3 | public enum Gender 4 | { 5 | None, 6 | Female, 7 | Male 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /src/Server/BlazorBoilerplate.Storage/LocalizationDbContext.cs: -------------------------------------------------------------------------------- 1 | using BlazorBoilerplate.Infrastructure.Storage.DataModels; 2 | using Microsoft.EntityFrameworkCore; 3 | 4 | namespace BlazorBoilerplate.Storage 5 | { 6 | public class LocalizationDbContext : DbContext 7 | { 8 | public LocalizationDbContext(DbContextOptions options) : base(options) 9 | { } 10 | 11 | public DbSet PluralFormRules { get; set; } 12 | 13 | public DbSet PluralTranslations { get; set; } 14 | 15 | public DbSet LocalizationRecords { get; set; } 16 | 17 | protected override void OnModelCreating(ModelBuilder builder) 18 | { 19 | base.OnModelCreating(builder); 20 | 21 | builder.Entity().HasIndex(c => new { c.MsgId, c.Culture, c.ContextId }).IsUnique(); 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/Server/BlazorBoilerplate.Storage/LocalizationPersistenceManager.cs: -------------------------------------------------------------------------------- 1 | using BlazorBoilerplate.Infrastructure.Storage.DataModels; 2 | using BlazorBoilerplate.Shared.Localizer; 3 | using Breeze.Persistence; 4 | using Microsoft.AspNetCore.Http; 5 | using Microsoft.Extensions.Localization; 6 | 7 | namespace BlazorBoilerplate.Storage 8 | { 9 | public class LocalizationPersistenceManager : BasePersistenceManager 10 | { 11 | public LocalizationPersistenceManager(LocalizationDbContext dbContext, 12 | IHttpContextAccessor accessor, 13 | IServiceProvider serviceProvider, 14 | IStringLocalizer l) : base(dbContext, accessor, serviceProvider, l) 15 | { } 16 | 17 | protected override bool BeforeSaveEntity(EntityInfo entityInfo) 18 | { 19 | if (entityInfo.EntityState == EntityState.Added || entityInfo.EntityState == EntityState.Modified) 20 | if (entityInfo.Entity is LocalizationRecord localizationRecord) 21 | { 22 | if (string.IsNullOrEmpty(localizationRecord.MsgId)) 23 | return false; 24 | 25 | if (string.IsNullOrWhiteSpace(localizationRecord.MsgIdPlural)) 26 | localizationRecord.MsgIdPlural = null; 27 | } 28 | 29 | return base.BeforeSaveEntity(entityInfo); 30 | } 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/Server/BlazorBoilerplate.Storage/Mapping/MappingProfile.cs: -------------------------------------------------------------------------------- 1 | using AutoMapper; 2 | using AutoMapper.Configuration; 3 | using BlazorBoilerplate.Shared.Dto.Admin; 4 | using BlazorBoilerplate.Shared.Dto.Sample; 5 | using Finbuckle.MultiTenant; 6 | using Message = BlazorBoilerplate.Infrastructure.Storage.DataModels.Message; 7 | 8 | namespace BlazorBoilerplate.Storage.Mapping 9 | { 10 | public class MappingProfile : MapperConfigurationExpression 11 | { 12 | /// 13 | /// Create automap mapping profiles 14 | /// 15 | public MappingProfile() 16 | { 17 | CreateMap().ReverseMap(); 18 | CreateMap().ReverseMap(); 19 | } 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/Server/BlazorBoilerplate.Storage/TenantStoreDbContext.cs: -------------------------------------------------------------------------------- 1 | using BlazorBoilerplate.Constants; 2 | using Finbuckle.MultiTenant; 3 | using Finbuckle.MultiTenant.Stores; 4 | using Microsoft.EntityFrameworkCore; 5 | 6 | namespace BlazorBoilerplate.Storage 7 | { 8 | public class TenantStoreDbContext : EFCoreStoreDbContext 9 | { 10 | public static readonly TenantInfo DefaultTenant = new TenantInfo() { Id = Settings.DefaultTenantId, Identifier = Settings.DefaultTenantId, Name = Settings.DefaultTenantId }; 11 | 12 | public TenantStoreDbContext(DbContextOptions options) : base(options) 13 | { 14 | } 15 | 16 | protected override void OnModelCreating(ModelBuilder modelBuilder) 17 | { 18 | base.OnModelCreating(modelBuilder); 19 | 20 | modelBuilder.Entity() 21 | .Property(t => t.ConnectionString) 22 | .IsRequired(false); 23 | modelBuilder.Entity() 24 | .HasData(DefaultTenant); 25 | } 26 | } 27 | } -------------------------------------------------------------------------------- /src/Shared/BlazorBoilerplate.Constants/BlazorBoilerplate.Constants.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | net7.0 5 | enable 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /src/Shared/BlazorBoilerplate.Constants/DefaultRoleNames.cs: -------------------------------------------------------------------------------- 1 | namespace BlazorBoilerplate.Constants 2 | { 3 | public static class DefaultRoleNames 4 | { 5 | public const string Administrator = "Administrator"; 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /src/Shared/BlazorBoilerplate.Constants/DefaultUserNames.cs: -------------------------------------------------------------------------------- 1 | namespace BlazorBoilerplate.Constants 2 | { 3 | public static class DefaultUserNames 4 | { 5 | public const string Administrator = "admin"; 6 | public const string User = "user"; 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /src/Shared/BlazorBoilerplate.Constants/EmailType.cs: -------------------------------------------------------------------------------- 1 | namespace BlazorBoilerplate.Constants 2 | { 3 | public enum EmailType 4 | { 5 | Generic, 6 | Test, 7 | Confirmation, 8 | Password 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /src/Shared/BlazorBoilerplate.Constants/HubPaths.cs: -------------------------------------------------------------------------------- 1 | namespace BlazorBoilerplate.Constants 2 | { 3 | public static class HubPaths 4 | { 5 | public const string Chat = "/chathub"; 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /src/Shared/BlazorBoilerplate.Constants/PasswordPolicy.cs: -------------------------------------------------------------------------------- 1 | namespace BlazorBoilerplate.Constants 2 | { 3 | public static class PasswordPolicy 4 | { 5 | public const bool RequireDigit = false; 6 | public const int RequiredLength = 6; 7 | public const bool RequireNonAlphanumeric = false; 8 | public const bool RequireUppercase = false; 9 | public const bool RequireLowercase = false; 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /src/Shared/BlazorBoilerplate.Constants/SettingKey.cs: -------------------------------------------------------------------------------- 1 | namespace BlazorBoilerplate.Constants 2 | { 3 | public enum SettingKey 4 | { 5 | MainConfiguration_Runtime, 6 | MainConfiguration_Theme, 7 | 8 | EmailConfiguration_SmtpServer, 9 | EmailConfiguration_SmtpPort, 10 | EmailConfiguration_SmtpUsername, 11 | EmailConfiguration_SmtpPassword, 12 | EmailConfiguration_SmtpUseSSL, 13 | EmailConfiguration_SmtpSslProtocol, 14 | 15 | EmailConfiguration_FromName, 16 | EmailConfiguration_FromAddress, 17 | EmailConfiguration_ReplyToAddress, 18 | 19 | EmailConfiguration_PopServer, 20 | EmailConfiguration_PopPort, 21 | EmailConfiguration_PopUsername, 22 | EmailConfiguration_PopPassword, 23 | EmailConfiguration_PopUseSSL, 24 | 25 | EmailConfiguration_ImapServer, 26 | EmailConfiguration_ImapPort, 27 | EmailConfiguration_ImapUsername, 28 | EmailConfiguration_ImapPassword, 29 | EmailConfiguration_ImapUseSSL, 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/Shared/BlazorBoilerplate.Constants/SettingType.cs: -------------------------------------------------------------------------------- 1 | namespace BlazorBoilerplate.Constants 2 | { 3 | public enum SettingType 4 | { 5 | String, 6 | Int, 7 | Boolean, 8 | Decimal 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /src/Shared/BlazorBoilerplate.Constants/Settings.cs: -------------------------------------------------------------------------------- 1 | namespace BlazorBoilerplate.Constants 2 | { 3 | public static class Settings 4 | { 5 | public const string LoginPath = "/Account/Login"; 6 | public const string LoginWith2faPath = "/Account/LoginWith2fa"; 7 | public const string LoginWithRecoveryCodePath = "/Account/LoginWithRecoveryCode"; 8 | public const string ProfilePath = "/Account/Profile"; 9 | public const string DefaultTenantId = "Master"; 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /src/Shared/BlazorBoilerplate.Infrastructure.AuthorizationDefinitions/BlazorBoilerplate.Infrastructure.AuthorizationDefinitions.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | net7.0 5 | enable 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /src/Shared/BlazorBoilerplate.Infrastructure.AuthorizationDefinitions/ClaimConstants.cs: -------------------------------------------------------------------------------- 1 | namespace BlazorBoilerplate.Infrastructure.AuthorizationDefinitions 2 | { 3 | public static class ApplicationClaimTypes 4 | { 5 | ///A claim that specifies the permission of an entity 6 | public const string Permission = "permission"; 7 | public static string EmailVerified = "email_verified"; 8 | } 9 | 10 | public static class ClaimValues 11 | { 12 | public static string trueString = "true"; 13 | public static string falseString = "false"; 14 | 15 | public static string AuthenticationMethodMFA = "mfa"; 16 | public static string AuthenticationMethodPwd = "pwd"; 17 | } 18 | } -------------------------------------------------------------------------------- /src/Shared/BlazorBoilerplate.Infrastructure.AuthorizationDefinitions/EmailVerifiedRequirement.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.AspNetCore.Authorization; 2 | 3 | namespace BlazorBoilerplate.Infrastructure.AuthorizationDefinitions 4 | { 5 | public class EmailVerifiedRequirement : IAuthorizationRequirement 6 | { 7 | public bool IsEmailVerified { get; private set; } //not used 8 | 9 | public EmailVerifiedRequirement(bool isEmailVerified) 10 | { 11 | IsEmailVerified = isEmailVerified; 12 | } 13 | } 14 | 15 | public class EmailVerifiedHandler : AuthorizationHandler 16 | { 17 | protected override Task HandleRequirementAsync(AuthorizationHandlerContext context, 18 | EmailVerifiedRequirement requirement) 19 | { 20 | if (context.User.HasClaim(c => c.Type == ApplicationClaimTypes.EmailVerified)) 21 | { 22 | var claim = context.User.FindFirst(c => c.Type == ApplicationClaimTypes.EmailVerified); 23 | var isEmailVerified = Convert.ToBoolean(claim.Value); 24 | 25 | if (isEmailVerified) 26 | { 27 | context.Succeed(requirement); 28 | } 29 | } 30 | 31 | return Task.CompletedTask; 32 | } 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/Shared/BlazorBoilerplate.Infrastructure.AuthorizationDefinitions/Policies.cs: -------------------------------------------------------------------------------- 1 |  2 | namespace BlazorBoilerplate.Infrastructure.AuthorizationDefinitions 3 | { 4 | public static class Policies 5 | { 6 | public const string IsAdmin = "IsAdmin"; 7 | public const string IsUser = "IsUser"; 8 | public const string IsMyEmailDomain = "IsMyEmailDomain"; 9 | public const string TwoFactorEnabled = "TwoFactorEnabled"; 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /src/Shared/BlazorBoilerplate.Infrastructure.AuthorizationDefinitions/ScopeConstants.cs: -------------------------------------------------------------------------------- 1 | namespace BlazorBoilerplate.Infrastructure.AuthorizationDefinitions 2 | { 3 | public static class ScopeConstants 4 | { 5 | ///A scope that specifies the roles of an entity 6 | public const string Roles = "roles"; 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /src/Shared/BlazorBoilerplate.Infrastructure.Storage/DataInterfaces/IAuditable.cs: -------------------------------------------------------------------------------- 1 | namespace BlazorBoilerplate.Infrastructure.Storage.DataInterfaces 2 | { 3 | public interface IAuditable 4 | { 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /src/Shared/BlazorBoilerplate.Infrastructure.Storage/DataInterfaces/ISoftDelete.cs: -------------------------------------------------------------------------------- 1 | namespace BlazorBoilerplate.Infrastructure.Storage.DataInterfaces 2 | { 3 | public interface ISoftDelete 4 | { 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /src/Shared/BlazorBoilerplate.Infrastructure.Storage/DataModels/ApiLogItem.cs: -------------------------------------------------------------------------------- 1 | using BlazorBoilerplate.Infrastructure.Storage.Permissions; 2 | using System.ComponentModel.DataAnnotations; 3 | 4 | namespace BlazorBoilerplate.Infrastructure.Storage.DataModels 5 | { 6 | [Permissions(Actions.CRUD)] 7 | public partial class ApiLogItem 8 | { 9 | [Key] 10 | public long Id { get; set; } 11 | 12 | [Required(ErrorMessage = "FieldRequired")] 13 | public DateTime RequestTime { get; set; } 14 | 15 | [Required(ErrorMessage = "FieldRequired")] 16 | public long ResponseMillis { get; set; } 17 | 18 | [Required(ErrorMessage = "FieldRequired")] 19 | public int StatusCode { get; set; } 20 | 21 | [Required(ErrorMessage = "FieldRequired")] 22 | public string Method { get; set; } 23 | 24 | [Required(ErrorMessage = "FieldRequired")] 25 | [MaxLength(2048)] 26 | public string Path { get; set; } 27 | 28 | [MaxLength(2048)] 29 | public string QueryString { get; set; } 30 | 31 | [MaxLength(256)] 32 | public string RequestBody { get; set; } 33 | 34 | [MaxLength(256)] 35 | public string ResponseBody { get; set; } 36 | 37 | [MaxLength(45)] 38 | public string IPAddress { get; set; } 39 | 40 | public Guid? ApplicationUserId { get; set; } 41 | 42 | public ApplicationUser ApplicationUser { get; set; } 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /src/Shared/BlazorBoilerplate.Infrastructure.Storage/DataModels/ApplicationRole.cs: -------------------------------------------------------------------------------- 1 | using BlazorBoilerplate.Infrastructure.Storage.Permissions; 2 | using Finbuckle.MultiTenant; 3 | using Microsoft.AspNetCore.Identity; 4 | 5 | namespace BlazorBoilerplate.Infrastructure.Storage.DataModels 6 | { 7 | [MultiTenant] 8 | [Permissions(Actions.CRUD)] 9 | public partial class ApplicationRole : IdentityRole 10 | { 11 | public ApplicationRole() : base() { } 12 | public ApplicationRole(string roleName) : base(roleName) { } 13 | public virtual ICollection UserRoles { get; set; } 14 | public override Guid Id { get => base.Id; set => base.Id = value; } 15 | public override string Name { get => base.Name; set => base.Name = value; } 16 | public override string NormalizedName { get => base.NormalizedName; set => base.NormalizedName = value; } 17 | public override string ConcurrencyStamp { get => base.ConcurrencyStamp; set => base.ConcurrencyStamp = value; } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/Shared/BlazorBoilerplate.Infrastructure.Storage/DataModels/ApplicationUserRole.cs: -------------------------------------------------------------------------------- 1 | using BlazorBoilerplate.Infrastructure.Storage.Permissions; 2 | using Finbuckle.MultiTenant; 3 | using Microsoft.AspNetCore.Identity; 4 | 5 | namespace BlazorBoilerplate.Infrastructure.Storage.DataModels 6 | { 7 | [MultiTenant] 8 | [Permissions(Actions.CRUD)] 9 | public partial class ApplicationUserRole : IdentityUserRole 10 | { 11 | public virtual ApplicationUser User { get; set; } 12 | public virtual ApplicationRole Role { get; set; } 13 | public override Guid UserId { get => base.UserId; set => base.UserId = value; } 14 | public override Guid RoleId { get => base.RoleId; set => base.RoleId = value; } 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/Shared/BlazorBoilerplate.Infrastructure.Storage/DataModels/DbLog.cs: -------------------------------------------------------------------------------- 1 | using BlazorBoilerplate.Infrastructure.Storage.Permissions; 2 | using System.ComponentModel.DataAnnotations; 3 | 4 | namespace BlazorBoilerplate.Infrastructure.Storage.DataModels 5 | { 6 | [Permissions(Actions.CRUD)] 7 | public partial class DbLog 8 | { 9 | [Key] 10 | public int Id { get; set; } 11 | 12 | public string Message { get; set; } 13 | 14 | public string MessageTemplate { get; set; } 15 | 16 | public string Level { get; set; } 17 | 18 | public DateTime TimeStamp { get; set; } 19 | 20 | public string Exception { get; set; } 21 | 22 | public string Properties { get; set; } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/Shared/BlazorBoilerplate.Infrastructure.Storage/DataModels/LocalizationRecord.cs: -------------------------------------------------------------------------------- 1 | using BlazorBoilerplate.Infrastructure.Storage.Permissions; 2 | using BlazorBoilerplate.Shared.DataInterfaces; 3 | using System.ComponentModel.DataAnnotations; 4 | 5 | namespace BlazorBoilerplate.Infrastructure.Storage.DataModels 6 | { 7 | [Permissions(Actions.Create | Actions.Update | Actions.Delete)] 8 | public partial class LocalizationRecord : ILocalizationRecord 9 | { 10 | [Key] 11 | public long Id { get; set; } 12 | public string MsgId { get; set; } 13 | public string MsgIdPlural { get; set; } 14 | public string Translation { get; set; } 15 | public string Culture { get; set; } 16 | public string ContextId { get; set; } 17 | public ICollection PluralTranslations { get; set; } 18 | ICollection ILocalizationRecord.PluralTranslations { get => PluralTranslations?.Select(i => (IPluralTranslation)i).ToList(); } 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/Shared/BlazorBoilerplate.Infrastructure.Storage/DataModels/Message.cs: -------------------------------------------------------------------------------- 1 | using System.ComponentModel.DataAnnotations; 2 | 3 | namespace BlazorBoilerplate.Infrastructure.Storage.DataModels 4 | { 5 | public partial class Message 6 | { 7 | public int Id { get; set; } 8 | 9 | [Required] 10 | public string UserName { get; set; } 11 | 12 | [Required] 13 | public string Text { get; set; } 14 | public DateTime When { get; set; } 15 | public Guid UserID { get; set; } 16 | public ApplicationUser Sender { get; set; } 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/Shared/BlazorBoilerplate.Infrastructure.Storage/DataModels/PluralFormRule.cs: -------------------------------------------------------------------------------- 1 | using BlazorBoilerplate.Shared.DataInterfaces; 2 | using System.ComponentModel.DataAnnotations; 3 | 4 | namespace BlazorBoilerplate.Infrastructure.Storage.DataModels 5 | { 6 | public class PluralFormRule : IPluralFormRule 7 | { 8 | [Key] 9 | [StringLength(5, MinimumLength = 2)] 10 | public string Language { get; set; } 11 | 12 | public int Count { get; set; } 13 | 14 | [Required] 15 | public string Selector { get; set; } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/Shared/BlazorBoilerplate.Infrastructure.Storage/DataModels/PluralTranslation.cs: -------------------------------------------------------------------------------- 1 | using BlazorBoilerplate.Infrastructure.Storage.Permissions; 2 | using BlazorBoilerplate.Shared.DataInterfaces; 3 | using System.ComponentModel.DataAnnotations; 4 | 5 | namespace BlazorBoilerplate.Infrastructure.Storage.DataModels 6 | { 7 | [Permissions(Actions.Create | Actions.Update | Actions.Delete)] 8 | public class PluralTranslation : IPluralTranslation 9 | { 10 | [Key] 11 | public long Id { get; set; } 12 | 13 | public int Index { get; set; } 14 | 15 | [Required] 16 | public string Translation { get; set; } 17 | 18 | //Entity Framework generates the following key as shadow property https://docs.microsoft.com/en-us/ef/core/modeling/shadow-properties 19 | //Breeze Sharp DTO Entity needs this key. I explicitly add the key, so running BlazorBoilerplate.EntityGenerator I have the right entity 20 | public long LocalizationRecordId { get; set; } 21 | 22 | [Required] 23 | public LocalizationRecord LocalizationRecord { get; set; } 24 | ILocalizationRecord IPluralTranslation.LocalizationRecord { get => LocalizationRecord; set => LocalizationRecord = (LocalizationRecord)value; } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/Shared/BlazorBoilerplate.Infrastructure.Storage/DataModels/QueuedEmail.cs: -------------------------------------------------------------------------------- 1 | using BlazorBoilerplate.Constants; 2 | using System.ComponentModel.DataAnnotations; 3 | 4 | namespace BlazorBoilerplate.Infrastructure.Storage.DataModels 5 | { 6 | public class QueuedEmail 7 | { 8 | [Key] 9 | public long Id { get; set; } 10 | 11 | [Required] 12 | public string Email { get; set; } 13 | public EmailType EmailType { get; set; } 14 | public DateTime CreatedOn { get; set; } 15 | public DateTime? SentOn { get; set; } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/Shared/BlazorBoilerplate.Infrastructure.Storage/DataModels/TenantSetting.cs: -------------------------------------------------------------------------------- 1 | using BlazorBoilerplate.Constants; 2 | using BlazorBoilerplate.Infrastructure.Storage.Permissions; 3 | using Finbuckle.MultiTenant; 4 | using System.ComponentModel.DataAnnotations; 5 | using System.ComponentModel.DataAnnotations.Schema; 6 | 7 | namespace BlazorBoilerplate.Infrastructure.Storage.DataModels 8 | { 9 | [Permissions(Actions.CRUD)] 10 | [MultiTenant] 11 | public partial class TenantSetting 12 | { 13 | [Column(TypeName = "nvarchar(64)")] 14 | public string TenantId { get; set; } 15 | 16 | [Column(TypeName = "nvarchar(128)")] 17 | public SettingKey Key { get; set; } 18 | 19 | [Column(TypeName = "nvarchar(max)")] 20 | public string Value { get; set; } 21 | 22 | [Required(ErrorMessage = "FieldRequired")] 23 | public SettingType Type { get; set; } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/Shared/BlazorBoilerplate.Infrastructure.Storage/DataModels/Todo.cs: -------------------------------------------------------------------------------- 1 | using BlazorBoilerplate.Infrastructure.Storage.DataInterfaces; 2 | using BlazorBoilerplate.Infrastructure.Storage.Permissions; 3 | using System.ComponentModel.DataAnnotations; 4 | 5 | namespace BlazorBoilerplate.Infrastructure.Storage.DataModels 6 | { 7 | [Permissions(Actions.Delete)] 8 | public partial class Todo : IAuditable, ISoftDelete 9 | { 10 | [Key] 11 | public long Id { get; set; } 12 | 13 | [Required(ErrorMessage = "FieldRequired")] 14 | [MaxLength(128)] 15 | public string Title { get; set; } 16 | 17 | public bool IsCompleted { get; set; } 18 | } 19 | } -------------------------------------------------------------------------------- /src/Shared/BlazorBoilerplate.Infrastructure.Storage/DataModels/UserProfile.cs: -------------------------------------------------------------------------------- 1 | using Finbuckle.MultiTenant; 2 | using System.ComponentModel.DataAnnotations; 3 | using System.ComponentModel.DataAnnotations.Schema; 4 | 5 | namespace BlazorBoilerplate.Infrastructure.Storage.DataModels 6 | { 7 | [MultiTenant] 8 | public partial class UserProfile 9 | { 10 | [Key] 11 | public long Id { get; set; } 12 | 13 | public Guid UserId { get; set; } 14 | public ApplicationUser ApplicationUser { get; set; } 15 | 16 | public string LastPageVisited { get; set; } = "/"; 17 | public bool IsNavOpen { get; set; } = true; 18 | public bool IsNavMinified { get; set; } = false; 19 | public int Count { get; set; } = 0; 20 | public DateTime LastUpdatedDate { get; set; } = DateTime.MinValue; 21 | public string Culture { get; set; } 22 | 23 | [Column(TypeName = "nvarchar(64)")] 24 | public string TenantId { get; set; } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/Shared/BlazorBoilerplate.Infrastructure.Storage/Permissions/Actions.cs: -------------------------------------------------------------------------------- 1 | namespace BlazorBoilerplate.Infrastructure.Storage.Permissions 2 | { 3 | [Flags] 4 | public enum Actions 5 | { 6 | Create = 1, 7 | Update = 2, 8 | Read = 4, 9 | Delete = 8, 10 | CRUD = Create | Update | Read | Delete, 11 | CUD = Create | Update | Delete 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /src/Shared/BlazorBoilerplate.Infrastructure.Storage/Permissions/EntityPermission.cs: -------------------------------------------------------------------------------- 1 | namespace BlazorBoilerplate.Infrastructure.Storage.Permissions 2 | { 3 | public class EntityPermission 4 | { 5 | public EntityPermission() 6 | { } 7 | 8 | public EntityPermission(string name, string value, string groupName, string description = null) 9 | { 10 | Name = name; 11 | Value = value; 12 | GroupName = groupName; 13 | Description = description; 14 | } 15 | 16 | public string Name { get; set; } 17 | public string Value { get; set; } 18 | public string GroupName { get; set; } 19 | public string Description { get; set; } 20 | 21 | public override string ToString() 22 | { 23 | return Value; 24 | } 25 | 26 | public static implicit operator string(EntityPermission permission) 27 | { 28 | return permission.Value; 29 | } 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/Shared/BlazorBoilerplate.Infrastructure.Storage/Permissions/Permissions.tt: -------------------------------------------------------------------------------- 1 | <#@ template debug="false" hostspecific="false" language="C#" #> 2 | <#@ assembly name="System.Core" #> 3 | <#@ import namespace="System.Linq" #> 4 | <#@ import namespace="System.Text" #> 5 | <#@ import namespace="System.Collections.Generic" #> 6 | <#@ output extension=".cs" #> 7 | <# 8 | var permissionActions = new string[] { "Create", "Update", "Read", "Delete" }; 9 | var entities = new string[] { "User", "Role", "Tenant" }; 10 | #> 11 | //Autogenerated from Permissions.tt 12 | using System.ComponentModel.DataAnnotations; 13 | 14 | namespace BlazorBoilerplate.Infrastructure.Storage.Permissions 15 | { 16 | public static class Permissions 17 | { 18 | #region Admin 19 | <# 20 | foreach(var entity in entities) 21 | {#> 22 | public static class <#=entity#> 23 | { 24 | <# 25 | foreach(var permissionAction in permissionActions) 26 | {#> 27 | [Display(Name = "<#=permissionAction#><#=entity#>Permission")] 28 | public const string <#=permissionAction#> = "<#=entity#>.<#=permissionAction#>"; 29 | <#}#> 30 | } 31 | <#}#> 32 | #endregion 33 | } 34 | } -------------------------------------------------------------------------------- /src/Shared/BlazorBoilerplate.Infrastructure.Storage/Permissions/PermissionsAttribute.cs: -------------------------------------------------------------------------------- 1 | namespace BlazorBoilerplate.Infrastructure.Storage.Permissions 2 | { 3 | [AttributeUsage(AttributeTargets.Class)] 4 | public class PermissionsAttribute : Attribute 5 | { 6 | public Actions Actions; 7 | 8 | public PermissionsAttribute(Actions actions) 9 | { 10 | Actions = actions; 11 | } 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /src/Shared/BlazorBoilerplate.Infrastructure/BlazorBoilerplate.Infrastructure.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | net7.0 5 | enable 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | IAdminManager.cs 19 | TextTemplatingFileGenerator 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | True 30 | True 31 | IAdminManager.tt 32 | 33 | 34 | 35 | 36 | -------------------------------------------------------------------------------- /src/Shared/BlazorBoilerplate.Infrastructure/Extensions/StringExtension.cs: -------------------------------------------------------------------------------- 1 | using Newtonsoft.Json; 2 | using Newtonsoft.Json.Linq; 3 | 4 | namespace BlazorBoilerplate.Infrastructure.Extensions 5 | { 6 | public static class StringExtension 7 | { 8 | public static bool IsValidJson(this string text) 9 | { 10 | text = text.Trim(); 11 | if ((text.StartsWith("{") && text.EndsWith("}")) || //For object 12 | (text.StartsWith("[") && text.EndsWith("]"))) //For array 13 | { 14 | try 15 | { 16 | var obj = JToken.Parse(text); 17 | return true; 18 | } 19 | catch (JsonReaderException) 20 | { 21 | return false; 22 | } 23 | catch (System.Exception) 24 | { 25 | return false; 26 | } 27 | } 28 | else 29 | { 30 | return false; 31 | } 32 | } 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/Shared/BlazorBoilerplate.Infrastructure/Server/IAdminManager.cs: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | using System.Threading.Tasks; 10 | using BlazorBoilerplate.Infrastructure.Server.Models; 11 | using BlazorBoilerplate.Shared.Dto.Admin; 12 | using Microsoft.AspNetCore.Mvc; 13 | 14 | namespace BlazorBoilerplate.Infrastructure.Server 15 | { 16 | public interface IAdminManager 17 | { 18 | Task GetUsers(int pageSize = 10, int pageNumber = 0); 19 | 20 | ApiResponse GetPermissions(); 21 | 22 | 23 | #region Roles 24 | Task GetRolesAsync(int pageSize = 0, int pageNumber = 0); 25 | 26 | Task GetRoleAsync(string name); 27 | 28 | Task CreateRoleAsync(RoleDto roleDto); 29 | 30 | Task UpdateRoleAsync([FromBody] RoleDto roleDto); 31 | 32 | Task DeleteRoleAsync(string name); 33 | #endregion 34 | 35 | 36 | #region Tenants 37 | Task GetTenantsAsync(int pageSize = 0, int pageNumber = 0); 38 | 39 | Task GetTenantAsync(string id); 40 | 41 | Task CreateTenantAsync(TenantDto tenantDto); 42 | 43 | Task UpdateTenantAsync([FromBody] TenantDto tenantDto); 44 | 45 | Task DeleteTenantAsync(string id); 46 | #endregion 47 | 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /src/Shared/BlazorBoilerplate.Infrastructure/Server/IEmailFactory.cs: -------------------------------------------------------------------------------- 1 | using BlazorBoilerplate.Shared.Dto.Email; 2 | 3 | namespace BlazorBoilerplate.Infrastructure.Server 4 | { 5 | public interface IEmailFactory 6 | { 7 | EmailMessageDto BuildTestEmail(string recipient); 8 | EmailMessageDto GetPlainTextTestEmail(DateTime date); 9 | EmailMessageDto BuildNewUserConfirmationEmail(string fullName, string userName, string callbackUrl); 10 | EmailMessageDto BuildNewUserEmail(string fullName, string userName, string emailAddress, string password); 11 | EmailMessageDto BuilNewUserNotificationEmail(string creator, string name, string userName, string company, string roles); 12 | EmailMessageDto BuildForgotPasswordEmail(string name, string callbackUrl, string token); 13 | EmailMessageDto BuildPasswordResetEmail(string userName); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/Shared/BlazorBoilerplate.Infrastructure/Server/IEmailManager.cs: -------------------------------------------------------------------------------- 1 | using BlazorBoilerplate.Constants; 2 | using BlazorBoilerplate.Infrastructure.Server.Models; 3 | using BlazorBoilerplate.Shared.Dto.Email; 4 | 5 | namespace BlazorBoilerplate.Infrastructure.Server 6 | { 7 | public interface IEmailManager 8 | { 9 | Task SendTestEmail(EmailDto parameters); 10 | Task Receive(); 11 | Task QueueEmail(EmailMessageDto emailMessage, EmailType emailType); 12 | Task SendEmail(EmailMessageDto emailMessage); 13 | List ReceiveEmail(int maxCount = 10); 14 | Task ReceiveMailImapAsync(); 15 | Task ReceiveMailPopAsync(int min = 0, int max = 0); 16 | } 17 | } -------------------------------------------------------------------------------- /src/Shared/BlazorBoilerplate.Infrastructure/Server/IExternalAuthManager.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.AspNetCore.Http; 2 | 3 | namespace BlazorBoilerplate.Infrastructure.Server 4 | { 5 | public interface IExternalAuthManager 6 | { 7 | Task ExternalSignIn(HttpContext httpContext); 8 | } 9 | } -------------------------------------------------------------------------------- /src/Shared/BlazorBoilerplate.Infrastructure/Server/ITenantSettings.cs: -------------------------------------------------------------------------------- 1 | namespace BlazorBoilerplate.Infrastructure.Server 2 | { 3 | public interface ITenantSettings where TSettings : class, new() 4 | { 5 | TSettings Value { get; } 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /src/Shared/BlazorBoilerplate.Infrastructure/Server/Models/DomainException.cs: -------------------------------------------------------------------------------- 1 | namespace BlazorBoilerplate.Infrastructure.Server.Models 2 | { 3 | public class DomainException : Exception 4 | { 5 | public string Description { get; } 6 | 7 | public DomainException(string description) : base() 8 | { 9 | Description = description; 10 | } 11 | 12 | public DomainException(string description, string message) : base(message) 13 | { 14 | Description = description; 15 | 16 | } 17 | 18 | public DomainException(string description, string message, Exception innerException) : base(message, innerException) 19 | { 20 | Description = description; 21 | 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/Shared/BlazorBoilerplate.Infrastructure/Server/Models/ResponseMessage.cs: -------------------------------------------------------------------------------- 1 | using Humanizer; 2 | using Microsoft.AspNetCore.Http; 3 | 4 | namespace BlazorBoilerplate.Infrastructure.Server.Models 5 | { 6 | public static class ResponseMessage 7 | { 8 | public static string GetDescription(int httpStatusCode) 9 | { 10 | foreach (var field in typeof(StatusCodes).GetFields(System.Reflection.BindingFlags.Static | System.Reflection.BindingFlags.Public).Where(f => f.FieldType == typeof(int))) 11 | { 12 | if (httpStatusCode == (int)field.GetValue(null)) 13 | { 14 | return field.Name.Humanize(LetterCasing.Title); 15 | } 16 | } 17 | 18 | return "Unknown error"; 19 | } 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/Shared/BlazorBoilerplate.Infrastructure/Storage/IDatabaseInitializer.cs: -------------------------------------------------------------------------------- 1 | namespace BlazorBoilerplate.Infrastructure.Storage 2 | { 3 | public interface IDatabaseInitializer 4 | { 5 | Task SeedAsync(); 6 | Task EnsureAdminIdentitiesAsync(); 7 | } 8 | } -------------------------------------------------------------------------------- /src/Shared/BlazorBoilerplate.Shared.DataInterfaces/BlazorBoilerplate.Shared.DataInterfaces.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | net7.0 5 | enable 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /src/Shared/BlazorBoilerplate.Shared.DataInterfaces/EntityGeneratorConfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "EntitiesPath": "..\\BlazorBoilerplate.Infrastructure.Storage\\DataModels\\", 3 | "GenInterfaces": true 4 | } 5 | -------------------------------------------------------------------------------- /src/Shared/BlazorBoilerplate.Shared.Localizer/BlazorBoilerplate.Shared.Localizer.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | net7.0 5 | enable 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /src/Shared/BlazorBoilerplate.Shared.Localizer/Global.cs: -------------------------------------------------------------------------------- 1 | using System.Globalization; 2 | 3 | namespace BlazorBoilerplate.Shared.Localizer 4 | { 5 | public class Global 6 | { 7 | private static CultureInfo[] allCultures = CultureInfo.GetCultures(CultureTypes.AllCultures); 8 | public static string GetCountryName(string countryCode) 9 | { 10 | return countryCode != null ? new RegionInfo(Thread.CurrentThread.CurrentCulture.TwoLetterISOLanguageName + "-" + countryCode).NativeName.Replace("Itàlia", "Italia") : null; 11 | } 12 | 13 | public static string GetLanguageName(string languageCode) 14 | { 15 | return allCultures.FirstOrDefault(i => i.Name == languageCode).DisplayName; 16 | } 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/Shared/BlazorBoilerplate.Shared.Localizer/IExtendedStringLocalizer.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.Extensions.Localization; 2 | using System.Globalization; 3 | 4 | namespace BlazorBoilerplate.Shared.Localizer 5 | { 6 | public interface IExtendedStringLocalizer : IStringLocalizer 7 | { 8 | bool TryGetTranslation(string name, object[] arguments, out string value); 9 | IExtendedStringLocalizer WithCulture(CultureInfo culture); 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /src/Shared/BlazorBoilerplate.Shared.Localizer/ILocalizationProvider.cs: -------------------------------------------------------------------------------- 1 | using BlazorBoilerplate.Shared.DataInterfaces; 2 | using Karambolo.PO; 3 | 4 | namespace BlazorBoilerplate.Shared.Localizer 5 | { 6 | public interface ILocalizationProvider 7 | { 8 | string[] Cultures { get; } 9 | IReadOnlyDictionary TextCatalogs { get; } 10 | void Init(IEnumerable localizationRecords, IEnumerable pluralFormRules, bool reLoad = false); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /src/Shared/BlazorBoilerplate.Shared.Localizer/POCatalogExtensions.cs: -------------------------------------------------------------------------------- 1 | using Karambolo.PO; 2 | using Microsoft.AspNetCore.Components; 3 | using Microsoft.Extensions.Localization; 4 | using System.Globalization; 5 | 6 | namespace BlazorBoilerplate.Shared.Localizer 7 | { 8 | public static class POCatalogExtensions 9 | { 10 | public static string GetCultureName(this POCatalog catalogo) => new CultureInfo(catalogo.Language.Replace("_", "-")).Name; 11 | 12 | public static MarkupString ToMarkup(this LocalizedString localizedString) => (MarkupString)localizedString.Value; 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /src/Shared/BlazorBoilerplate.Shared.Localizer/Settings.cs: -------------------------------------------------------------------------------- 1 | namespace BlazorBoilerplate.Shared.Localizer 2 | { 3 | public static class Settings 4 | { 5 | public const string NeutralCulture = "en-US"; 6 | 7 | public static readonly string[] SupportedCultures = { NeutralCulture, "de-DE", "it-IT", "fa-IR", "pt-PT" }; 8 | 9 | public static readonly (string, string)[] SupportedCulturesWithName = new[] { ("English", NeutralCulture), ("Deutsch", "de-DE"), ("Italiano", "it-IT"), ("پارسی", "fa-IR"), ("Português", "pt-PT") }; 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /src/Shared/BlazorBoilerplate.Shared.Localizer/TextLocalizationOptions.cs: -------------------------------------------------------------------------------- 1 | namespace BlazorBoilerplate.Shared.Localizer 2 | { 3 | public class TextLocalizationOptions 4 | { 5 | public bool UseTypeFullNames { get; set; } 6 | 7 | public bool ReturnOnlyKeyIfNotFound { get; set; } 8 | 9 | public bool FallBackNeutralCulture { get; set; } 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /src/Shared/BlazorBoilerplate.Shared.Localizer/TextLocalizerFactory.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.Extensions.Localization; 2 | using Microsoft.Extensions.Options; 3 | 4 | namespace BlazorBoilerplate.Shared.Localizer 5 | { 6 | public class TextLocalizerFactory : IStringLocalizerFactory 7 | { 8 | private readonly ILocalizationProvider _provider; 9 | private readonly IOptions _options; 10 | public TextLocalizerFactory(ILocalizationProvider provider, IOptions localizationOptions) 11 | { 12 | _provider = provider; 13 | _options = localizationOptions; 14 | } 15 | 16 | IStringLocalizer IStringLocalizerFactory.Create(Type resourceSource) 17 | { 18 | var contextId = resourceSource.FullName; 19 | 20 | if (resourceSource == typeof(Global) || !_options.Value.UseTypeFullNames) 21 | contextId = resourceSource.Name; 22 | 23 | return new LocalizationManager(_provider, contextId, _options); 24 | } 25 | 26 | IStringLocalizer IStringLocalizerFactory.Create(string baseName, string location) 27 | { 28 | return new LocalizationManager(_provider, baseName + location, _options); 29 | } 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/Shared/BlazorBoilerplate.Shared/Dto/Admin/RoleDto.cs: -------------------------------------------------------------------------------- 1 | using System.ComponentModel.DataAnnotations; 2 | 3 | namespace BlazorBoilerplate.Shared.Dto.Admin 4 | { 5 | public class RoleDto 6 | { 7 | [StringLength(64, ErrorMessage = "ErrorInvalidLength", MinimumLength = 2)] 8 | [RegularExpression(@"[^\s]+", ErrorMessage = "SpacesNotPermitted")] 9 | [Display(Name = "Name")] 10 | public string Name { get; set; } 11 | 12 | public List Permissions { get; set; } 13 | 14 | public string FormattedPermissions 15 | { 16 | get 17 | { 18 | return String.Join(", ", Permissions.ToArray()); 19 | } 20 | } 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/Shared/BlazorBoilerplate.Shared/Dto/Admin/TenantDto.cs: -------------------------------------------------------------------------------- 1 | namespace BlazorBoilerplate.Shared.Dto.Admin 2 | { 3 | public class TenantDto : BaseDto 4 | { 5 | public string Id { get; set; } 6 | public string Identifier { get; set; } 7 | public string Name { get; set; } 8 | public IDictionary Items { get; } 9 | public string ConnectionString { get; set; } 10 | } 11 | } -------------------------------------------------------------------------------- /src/Shared/BlazorBoilerplate.Shared/Dto/ApiResponseDto.cs: -------------------------------------------------------------------------------- 1 | using System.Runtime.Serialization; 2 | 3 | namespace BlazorBoilerplate.Shared.Dto 4 | { 5 | [DataContract] 6 | public class ApiResponseDto 7 | { 8 | [DataMember] 9 | public string Version { get; set; } 10 | 11 | [DataMember] 12 | public int StatusCode { get; set; } 13 | 14 | public bool IsSuccessStatusCode => StatusCode >= 200 && StatusCode < 300; 15 | 16 | [DataMember] 17 | public string Message { get; set; } 18 | 19 | [DataMember(EmitDefaultValue = false)] 20 | public T Result { get; set; } 21 | } 22 | 23 | [DataContract] 24 | public class ApiResponseDto : ApiResponseDto 25 | { 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/Shared/BlazorBoilerplate.Shared/Dto/BaseDto.cs: -------------------------------------------------------------------------------- 1 | using ObjectCloner.Extensions; 2 | using System.Reflection; 3 | 4 | namespace BlazorBoilerplate.Shared.Dto 5 | { 6 | public abstract class BaseDto : IMementoDto 7 | { 8 | private object state; 9 | 10 | public void SaveState() 11 | { 12 | state = this.DeepClone(); 13 | } 14 | 15 | public void RestoreState() 16 | { 17 | if (state != null) 18 | foreach (PropertyInfo property in GetType().GetProperties().Where(p => p.CanWrite)) 19 | property.SetValue(this, property.GetValue(state, null), null); 20 | } 21 | public void ClearState() 22 | { 23 | state = null; 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/Shared/BlazorBoilerplate.Shared/Dto/Db/DbLog.cs: -------------------------------------------------------------------------------- 1 | using BlazorBoilerplate.Shared.Helpers; 2 | 3 | namespace BlazorBoilerplate.Shared.Dto.Db 4 | { 5 | public partial class DbLog 6 | { 7 | public IDictionary LogProperties 8 | { 9 | get 10 | { 11 | return RegexUtilities.DirtyXmlPropertyParser(Properties); 12 | } 13 | } 14 | 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/Shared/BlazorBoilerplate.Shared/Dto/Db/IdentityRoleClaim.cs: -------------------------------------------------------------------------------- 1 | using Breeze.Sharp; 2 | 3 | namespace BlazorBoilerplate.Shared.Dto.Db 4 | { 5 | public partial class IdentityRoleClaim : BaseEntity 6 | { 7 | 8 | public Int32 Id 9 | { 10 | get { return GetValue(); } 11 | set { SetValue(value); } 12 | } 13 | 14 | public String ClaimType 15 | { 16 | get { return GetValue(); } 17 | set { SetValue(value); } 18 | } 19 | 20 | public String ClaimValue 21 | { 22 | get { return GetValue(); } 23 | set { SetValue(value); } 24 | } 25 | 26 | public Guid RoleId 27 | { 28 | get { return GetValue(); } 29 | set { SetValue(value); } 30 | } 31 | 32 | public String TenantId 33 | { 34 | get { return GetValue(); } 35 | set { SetValue(value); } 36 | } 37 | 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/Shared/BlazorBoilerplate.Shared/Dto/Db/IdentityUserClaim.cs: -------------------------------------------------------------------------------- 1 | using Breeze.Sharp; 2 | 3 | namespace BlazorBoilerplate.Shared.Dto.Db 4 | { 5 | public partial class IdentityUserClaim : BaseEntity 6 | { 7 | 8 | public Int32 Id 9 | { 10 | get { return GetValue(); } 11 | set { SetValue(value); } 12 | } 13 | 14 | public String ClaimType 15 | { 16 | get { return GetValue(); } 17 | set { SetValue(value); } 18 | } 19 | 20 | public String ClaimValue 21 | { 22 | get { return GetValue(); } 23 | set { SetValue(value); } 24 | } 25 | 26 | public String TenantId 27 | { 28 | get { return GetValue(); } 29 | set { SetValue(value); } 30 | } 31 | 32 | public Guid UserId 33 | { 34 | get { return GetValue(); } 35 | set { SetValue(value); } 36 | } 37 | 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/Shared/BlazorBoilerplate.Shared/Dto/Db/IdentityUserLogin.cs: -------------------------------------------------------------------------------- 1 | using Breeze.Sharp; 2 | 3 | namespace BlazorBoilerplate.Shared.Dto.Db 4 | { 5 | public partial class IdentityUserLogin : BaseEntity 6 | { 7 | 8 | public String Id 9 | { 10 | get { return GetValue(); } 11 | set { SetValue(value); } 12 | } 13 | 14 | public String LoginProvider 15 | { 16 | get { return GetValue(); } 17 | set { SetValue(value); } 18 | } 19 | 20 | public String ProviderDisplayName 21 | { 22 | get { return GetValue(); } 23 | set { SetValue(value); } 24 | } 25 | 26 | public String ProviderKey 27 | { 28 | get { return GetValue(); } 29 | set { SetValue(value); } 30 | } 31 | 32 | public String TenantId 33 | { 34 | get { return GetValue(); } 35 | set { SetValue(value); } 36 | } 37 | 38 | public Guid UserId 39 | { 40 | get { return GetValue(); } 41 | set { SetValue(value); } 42 | } 43 | 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /src/Shared/BlazorBoilerplate.Shared/Dto/Db/IdentityUserRole.cs: -------------------------------------------------------------------------------- 1 | using Breeze.Sharp; 2 | 3 | namespace BlazorBoilerplate.Shared.Dto.Db 4 | { 5 | public partial class IdentityUserRole : BaseEntity 6 | { 7 | 8 | public Guid UserId 9 | { 10 | get { return GetValue(); } 11 | set { SetValue(value); } 12 | } 13 | 14 | public Guid RoleId 15 | { 16 | get { return GetValue(); } 17 | set { SetValue(value); } 18 | } 19 | 20 | public String Discriminator 21 | { 22 | get { return GetValue(); } 23 | set { SetValue(value); } 24 | } 25 | 26 | public String TenantId 27 | { 28 | get { return GetValue(); } 29 | set { SetValue(value); } 30 | } 31 | 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/Shared/BlazorBoilerplate.Shared/Dto/Db/IdentityUserToken.cs: -------------------------------------------------------------------------------- 1 | using Breeze.Sharp; 2 | 3 | namespace BlazorBoilerplate.Shared.Dto.Db 4 | { 5 | public partial class IdentityUserToken : BaseEntity 6 | { 7 | 8 | public Guid UserId 9 | { 10 | get { return GetValue(); } 11 | set { SetValue(value); } 12 | } 13 | 14 | public String LoginProvider 15 | { 16 | get { return GetValue(); } 17 | set { SetValue(value); } 18 | } 19 | 20 | public String Name 21 | { 22 | get { return GetValue(); } 23 | set { SetValue(value); } 24 | } 25 | 26 | public String TenantId 27 | { 28 | get { return GetValue(); } 29 | set { SetValue(value); } 30 | } 31 | 32 | public String Value 33 | { 34 | get { return GetValue(); } 35 | set { SetValue(value); } 36 | } 37 | 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/Shared/BlazorBoilerplate.Shared/Dto/Db/LocalizationRecord.cs: -------------------------------------------------------------------------------- 1 | using BlazorBoilerplate.Shared.Localizer; 2 | 3 | namespace BlazorBoilerplate.Shared.Dto.Db 4 | { 5 | public partial class LocalizationRecord : IEquatable 6 | { 7 | public LocalizationRecord() 8 | { 9 | Culture = Settings.NeutralCulture; 10 | ContextId = nameof(Global); 11 | } 12 | 13 | public override bool Equals(object obj) 14 | { 15 | return Equals(obj as LocalizationRecord); 16 | } 17 | 18 | public bool Equals(LocalizationRecord other) 19 | { 20 | return other != null && 21 | MsgId == other.MsgId && 22 | Culture == other.Culture && 23 | ContextId == other.ContextId; 24 | } 25 | 26 | public override int GetHashCode() 27 | { 28 | return HashCode.Combine(MsgId, Culture, ContextId); 29 | } 30 | 31 | public static bool operator ==(LocalizationRecord left, LocalizationRecord right) 32 | { 33 | return EqualityComparer.Default.Equals(left, right); 34 | } 35 | 36 | public static bool operator !=(LocalizationRecord left, LocalizationRecord right) 37 | { 38 | return !(left == right); 39 | } 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /src/Shared/BlazorBoilerplate.Shared/Dto/Db/TenantSetting.cs: -------------------------------------------------------------------------------- 1 | using System.ComponentModel; 2 | 3 | namespace BlazorBoilerplate.Shared.Dto.Db 4 | { 5 | public partial class TenantSetting 6 | { 7 | private T GetterValue() 8 | { 9 | TypeConverter converter = TypeDescriptor.GetConverter(typeof(T)); 10 | T result = default; 11 | 12 | try 13 | { 14 | result = (T)converter.ConvertFromString(Value); 15 | } 16 | catch (Exception) 17 | { 18 | Value = result.ToString(); 19 | } 20 | 21 | return result; 22 | } 23 | 24 | public int ValueAsInt 25 | { 26 | get => GetterValue(); 27 | 28 | set => Value = value.ToString(); 29 | } 30 | 31 | public bool ValueAsBool 32 | { 33 | get => GetterValue(); 34 | 35 | set => Value = value.ToString(); 36 | } 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/Shared/BlazorBoilerplate.Shared/Dto/Db/UserProfile.cs: -------------------------------------------------------------------------------- 1 | namespace BlazorBoilerplate.Shared.Dto.Db 2 | { 3 | public partial class UserProfile 4 | { 5 | public UserProfile() 6 | { 7 | LastPageVisited = "/"; 8 | IsNavOpen = true; 9 | IsNavMinified = false; 10 | } 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /src/Shared/BlazorBoilerplate.Shared/Dto/Db/Validators/TodoValidator.cs: -------------------------------------------------------------------------------- 1 | using BlazorBoilerplate.Shared.Localizer; 2 | using BlazorBoilerplate.Shared.Validators; 3 | using FluentValidation; 4 | using Microsoft.Extensions.Localization; 5 | 6 | namespace BlazorBoilerplate.Shared.Dto.Db.Validators 7 | { 8 | public class TodoValidator : LocalizedAbstractValidator 9 | { 10 | public TodoValidator(IStringLocalizer l) : base(l) 11 | { 12 | RuleFor(p => p.Title) 13 | .NotEmpty() 14 | .MaximumLength(128).WithName(L["Title"]); 15 | } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/Shared/BlazorBoilerplate.Shared/Dto/Email/EmailAddressDto.cs: -------------------------------------------------------------------------------- 1 | namespace BlazorBoilerplate.Shared.Dto.Email 2 | { 3 | public class EmailAddressDto 4 | { 5 | private string _name; 6 | 7 | public string Name 8 | { 9 | get 10 | { 11 | if (string.IsNullOrEmpty(_name)) 12 | { 13 | return Address; 14 | } 15 | return _name; 16 | } 17 | set 18 | { 19 | _name = value; 20 | } 21 | } 22 | public string Address { get; set; } 23 | 24 | public EmailAddressDto(string name, string address) 25 | { 26 | _name = name; 27 | Address = address; 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/Shared/BlazorBoilerplate.Shared/Dto/Email/EmailDto.cs: -------------------------------------------------------------------------------- 1 | namespace BlazorBoilerplate.Shared.Dto.Email 2 | { 3 | public class EmailDto 4 | { 5 | private string _name; 6 | public string ToAddress { get; set; } 7 | 8 | public string ToName 9 | { 10 | get 11 | { 12 | if (string.IsNullOrEmpty(_name)) 13 | { 14 | return ToAddress; 15 | } 16 | 17 | return _name; 18 | } 19 | set 20 | { 21 | _name = value; 22 | } 23 | } 24 | 25 | public string FromName { get; set; } 26 | 27 | public string FromAddress { get; set; } 28 | 29 | public string ReplyToAddress { get; set; } 30 | 31 | public string Subject { get; set; } 32 | 33 | public string Body { get; set; } 34 | 35 | public string TemplateName { get; set; } = "Test"; 36 | 37 | public bool Queued { get; set; } 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/Shared/BlazorBoilerplate.Shared/Dto/Email/EmailMessageDto.cs: -------------------------------------------------------------------------------- 1 | namespace BlazorBoilerplate.Shared.Dto.Email 2 | { 3 | public class EmailMessageDto 4 | { 5 | public EmailMessageDto() 6 | { 7 | ToAddresses = new List(); 8 | FromAddresses = new List(); 9 | CcAddresses = new List(); 10 | BccAddresses = new List(); 11 | } 12 | 13 | public List ToAddresses { get; set; } 14 | public List FromAddresses { get; set; } 15 | public List BccAddresses { get; set; } 16 | public List CcAddresses { get; set; } 17 | public string Subject { get; set; } 18 | public string Body { get; set; } 19 | public bool IsHtml { get; set; } = true; 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/Shared/BlazorBoilerplate.Shared/Dto/Email/Validators/EmailDtoValidator.cs: -------------------------------------------------------------------------------- 1 | using BlazorBoilerplate.Shared.Localizer; 2 | using BlazorBoilerplate.Shared.Validators; 3 | using FluentValidation; 4 | using Microsoft.Extensions.Localization; 5 | 6 | namespace BlazorBoilerplate.Shared.Dto.Email.Validators 7 | { 8 | public class EmailDtoValidator : LocalizedAbstractValidator 9 | { 10 | public EmailDtoValidator(IStringLocalizer l) : base(l) 11 | { 12 | RuleFor(p => p.ToAddress) 13 | .NotEmpty() 14 | .EmailAddress().WithName(L["Email"]); 15 | } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/Shared/BlazorBoilerplate.Shared/Dto/ExternalAuth/ErrorEnum.cs: -------------------------------------------------------------------------------- 1 | namespace BlazorBoilerplate.Shared.Dto.ExternalAuth 2 | { 3 | public enum ErrorEnum 4 | { 5 | Unknown = -99, 6 | UserCreationFailed = -1, 7 | UserIsNotAllowed = 0, 8 | UserLockedOut = 1, 9 | CannotAddExternalLogin = 2, 10 | ExternalAuthError = 3, 11 | ExternalUnknownUserId = 4, 12 | ProviderNotFound = 5, 13 | Domain = 6, 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/Shared/BlazorBoilerplate.Shared/Dto/IMementoDto.cs: -------------------------------------------------------------------------------- 1 | namespace BlazorBoilerplate.Shared.Dto 2 | { 3 | public interface IMementoDto 4 | { 5 | void SaveState(); 6 | void RestoreState(); 7 | void ClearState(); 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /src/Shared/BlazorBoilerplate.Shared/Dto/LocalizationRecordKey.cs: -------------------------------------------------------------------------------- 1 | using BlazorBoilerplate.Shared.Dto.Db; 2 | 3 | namespace BlazorBoilerplate.Shared.Dto 4 | { 5 | public class LocalizationRecordKey : IEquatable 6 | { 7 | public string ContextId { get; set; } 8 | public string MsgId { get; set; } 9 | public List LocalizationRecords { get; set; } 10 | 11 | public override bool Equals(object obj) 12 | { 13 | return Equals(obj as LocalizationRecordKey); 14 | } 15 | 16 | public bool Equals(LocalizationRecordKey other) 17 | { 18 | return other != null && 19 | ContextId == other.ContextId && 20 | MsgId == other.MsgId; 21 | } 22 | 23 | public override int GetHashCode() 24 | { 25 | return HashCode.Combine(ContextId, MsgId); 26 | } 27 | 28 | public override string ToString() 29 | { 30 | return $"{ContextId} - {MsgId}"; 31 | } 32 | 33 | public static bool operator ==(LocalizationRecordKey left, LocalizationRecordKey right) 34 | { 35 | return EqualityComparer.Default.Equals(left, right); 36 | } 37 | 38 | public static bool operator !=(LocalizationRecordKey left, LocalizationRecordKey right) 39 | { 40 | return !(left == right); 41 | } 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /src/Shared/BlazorBoilerplate.Shared/Dto/Sample/JobDto.cs: -------------------------------------------------------------------------------- 1 | namespace BlazorBoilerplate.Shared.Dto.Sample 2 | { 3 | public class JobDto 4 | { 5 | public int Id { get; set; } 6 | public JobStatuses Status { get; set; } 7 | public string Description { get; set; } 8 | public DateTime LastUpdated { get; set; } 9 | } 10 | 11 | public enum JobStatuses 12 | { 13 | Todo, 14 | Started, 15 | Completed 16 | } 17 | } -------------------------------------------------------------------------------- /src/Shared/BlazorBoilerplate.Shared/Dto/Sample/MessageDto.cs: -------------------------------------------------------------------------------- 1 | namespace BlazorBoilerplate.Shared.Dto.Sample 2 | { 3 | public class MessageDto 4 | { 5 | public int Id { get; set; } 6 | public string UserName { get; set; } 7 | public string Text { get; set; } 8 | public DateTime When { get; set; } 9 | public Guid UserID { get; set; } 10 | 11 | public bool Mine { get; set; } 12 | 13 | public MessageDto() { } 14 | 15 | public MessageDto(int id, string userName, string text, bool mine) 16 | { 17 | Id = id; 18 | UserName = userName; 19 | Text = text; 20 | Mine = mine; 21 | } 22 | 23 | /// 24 | /// Determine CSS classes to use for message div 25 | /// TODO: disambiguate between your and other members 26 | /// 27 | public string CSS 28 | { 29 | get 30 | { 31 | return Mine ? "sent" : "received"; 32 | } 33 | } 34 | } 35 | } -------------------------------------------------------------------------------- /src/Shared/BlazorBoilerplate.Shared/Dto/Sample/ReportPeriodDto.cs: -------------------------------------------------------------------------------- 1 | namespace BlazorBoilerplate.Shared.Dto.Sample 2 | { 3 | public class ReportPeriodDto 4 | { 5 | public int Id { get; set; } 6 | public DateTime StartDate { get; set; } 7 | public DateTime EndDate { get; set; } 8 | public bool IsBenchmark { get; set; } 9 | public bool IsComparison { get; set; } 10 | 11 | public string Title 12 | { 13 | get 14 | { 15 | return $"{StartDate:MM/dd/yy} - {EndDate:MM/dd/yy}"; 16 | } 17 | } 18 | } 19 | } -------------------------------------------------------------------------------- /src/Shared/BlazorBoilerplate.Shared/EntityGeneratorConfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "EntitiesPath": "..\\BlazorBoilerplate.Infrastructure.Storage\\DataModels\\", 3 | "GenEntities": true, 4 | "EntityWithInterface": true 5 | } 6 | -------------------------------------------------------------------------------- /src/Shared/BlazorBoilerplate.Shared/Extensions/GuidUtil.cs: -------------------------------------------------------------------------------- 1 | using System.Security.Cryptography; 2 | 3 | namespace BlazorBoilerplate.Shared.Extensions 4 | { 5 | public static class GuidUtil 6 | { 7 | public static string ToCompressedString(this Guid guid) 8 | { 9 | return Convert.ToBase64String(guid.ToByteArray()) 10 | .Substring(0, 22) 11 | .Replace('+', '-') 12 | .Replace('/', '_'); 13 | } 14 | 15 | public static Guid FromCompressedString(string compressedGuid) 16 | { 17 | string base64 = compressedGuid 18 | .Replace('_', '/') 19 | .Replace('-', '+') 20 | + "=="; 21 | 22 | return new Guid(Convert.FromBase64String(base64)); 23 | } 24 | 25 | public static Guid CreateCryptographicallySecureGuid() 26 | { 27 | Span bytes = stackalloc byte[16]; 28 | RandomNumberGenerator.Fill(bytes); 29 | return new Guid(bytes); 30 | } 31 | } 32 | } -------------------------------------------------------------------------------- /src/Shared/BlazorBoilerplate.Shared/Extensions/IJSRuntimeExtensions.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.JSInterop; 2 | using System.Text.RegularExpressions; 3 | 4 | namespace BlazorBoilerplate.Shared.Extensions 5 | { 6 | public static class IJSRuntimeExtensions 7 | { 8 | private static Regex regExAspNetCoreCulture = new Regex(@"c=(?[A-Za-z]{1,8}(-[A-Za-z0-9]{1,8}))\|uic=(?[A-Za-z]{1,8}(-[A-Za-z0-9]{1,8}))"); 9 | public static async Task GetAspNetCoreCultureCookie(this IJSRuntime js) 10 | { 11 | var culture = await js.InvokeAsync("cookieStorage.get", ".AspNetCore.Culture"); 12 | 13 | if (culture != null) 14 | { 15 | if (regExAspNetCoreCulture.IsMatch(culture)) 16 | culture = regExAspNetCoreCulture.Match(culture).Groups["uiculture"].Value; 17 | else 18 | culture = null; 19 | } 20 | 21 | return culture; 22 | } 23 | public static async Task SetAspNetCoreCultureCookie(this IJSRuntime js, string culture) 24 | { 25 | var escapedCulture = Uri.EscapeDataString($"c={culture}|uic={culture}"); 26 | await js.InvokeVoidAsync("cookieStorage.set", $".AspNetCore.Culture={escapedCulture}; max-age=2592000;path=/"); 27 | } 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/Shared/BlazorBoilerplate.Shared/Extensions/SkipEntityAspectContractResolver.cs: -------------------------------------------------------------------------------- 1 | using Breeze.Sharp; 2 | using Newtonsoft.Json; 3 | using Newtonsoft.Json.Serialization; 4 | 5 | namespace BlazorBoilerplate.Shared.Extensions 6 | { 7 | public class SkipEntityAspectContractResolver : DefaultContractResolver 8 | { 9 | protected override IList CreateProperties(Type type, MemberSerialization memberSerialization) 10 | { 11 | return base.CreateProperties(type, memberSerialization).Where(i => i.PropertyName != nameof(EntityAspect)).ToList(); 12 | } 13 | } 14 | } -------------------------------------------------------------------------------- /src/Shared/BlazorBoilerplate.Shared/Helpers/RegexUtilities.cs: -------------------------------------------------------------------------------- 1 | using System.Text.RegularExpressions; 2 | 3 | namespace BlazorBoilerplate.Shared.Helpers 4 | { 5 | public static class RegexUtilities 6 | { 7 | public static readonly Regex StringInterpolationHelper = new Regex("(?<=[\\ \"]{0,1}{)(.+?)(?=})(?:[\\ \\.\"]{0,2}|$)", RegexOptions.Compiled, TimeSpan.FromMilliseconds(100)); 8 | 9 | //[a-zA-Z0-9.+= \\/-:] 10 | private static readonly Regex DirtyXmlPropertyParserRegex = new Regex("(?<=[a-zA-Z0-9\\- :]+?)(?:'>)(?[^><]+?)(?=<\\/property>)", RegexOptions.Compiled, TimeSpan.FromMilliseconds(100)); 11 | 12 | 13 | public static Dictionary DirtyXmlPropertyParser(string input) 14 | { 15 | var propertyList = new Dictionary(); 16 | var xmlMatch = DirtyXmlPropertyParserRegex.Match(input); 17 | while (xmlMatch.Success) 18 | { 19 | propertyList.Add(xmlMatch.Groups["key"].Value, xmlMatch.Groups["value"].Value); 20 | xmlMatch = xmlMatch.NextMatch(); 21 | } 22 | return propertyList; 23 | } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/Shared/BlazorBoilerplate.Shared/Helpers/TopologyUtils.cs: -------------------------------------------------------------------------------- 1 | using NetTopologySuite; 2 | using NetTopologySuite.Geometries; 3 | 4 | namespace BlazorBoilerplate.Shared.Helpers 5 | { 6 | public static class TopologyUtils 7 | { 8 | private static readonly GeometryFactory gf; 9 | static TopologyUtils() 10 | { 11 | NtsGeometryServices.Instance = new NtsGeometryServices( 12 | NetTopologySuite.Geometries.Implementation.CoordinateArraySequenceFactory.Instance, 13 | new PrecisionModel(1000d), 4326); 14 | 15 | gf = NtsGeometryServices.Instance.CreateGeometryFactory(); 16 | } 17 | 18 | public static Point CreatePoint(double longitude, double latitude) 19 | { 20 | return gf.CreatePoint(new Coordinate(longitude, latitude)); 21 | } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/Shared/BlazorBoilerplate.Shared/Interfaces/IApiClient.cs: -------------------------------------------------------------------------------- 1 | using BlazorBoilerplate.Shared.Dto; 2 | using BlazorBoilerplate.Shared.Dto.Db; 3 | using BlazorBoilerplate.Shared.Dto.Email; 4 | using BlazorBoilerplate.Shared.Models; 5 | using Breeze.Sharp; 6 | using System.Linq.Expressions; 7 | 8 | namespace BlazorBoilerplate.Shared.Interfaces 9 | { 10 | public interface IApiClient : IBaseApiClient 11 | { 12 | Task GetUserProfile(); 13 | 14 | Task> GetTenantSettings(); 15 | Task> GetUsers(Expression> predicate = null, int? take = null, int? skip = null); 16 | Task> GetRoles(Expression> predicate = null, int? take = null, int? skip = null); 17 | 18 | Task> GetLogs(Expression> predicate = null, int? take = null, int? skip = null); 19 | Task> GetApiLogs(Expression> predicate = null, int? take = null, int? skip = null); 20 | 21 | Task> GetToDos(ToDoFilter filter, int? take = null, int? skip = null); 22 | Task> GetTodoCreators(ToDoFilter filter); 23 | Task> GetTodoEditors(ToDoFilter filter); 24 | 25 | Task SendTestEmail(EmailDto email); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/Shared/BlazorBoilerplate.Shared/Interfaces/IBaseApiClient.cs: -------------------------------------------------------------------------------- 1 | using Breeze.Sharp; 2 | using System.Linq.Expressions; 3 | 4 | namespace BlazorBoilerplate.Shared.Interfaces 5 | { 6 | public interface IBaseApiClient 7 | { 8 | void AddEntity(IEntity entity); 9 | 10 | void RemoveEntity(IEntity entity); 11 | 12 | void ClearEntitiesCache(); 13 | 14 | void CancelChanges(); 15 | 16 | event EventHandler EntityChanged; 17 | 18 | Task SaveChanges(); 19 | 20 | Task> GetItems(string from, 21 | Expression> predicate = null, 22 | Expression> orderBy = null, 23 | Expression> orderByDescending = null, 24 | int? take = null, 25 | int? skip = null, 26 | Dictionary parameters = null); 27 | 28 | Task> GetItemsByFilter( 29 | string from, 30 | string orderByDefaultField, 31 | string filter = null, 32 | string orderBy = null, 33 | string orderByDescending = null, 34 | int? take = null, int? skip = null, 35 | Dictionary parameters = null); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/Shared/BlazorBoilerplate.Shared/Interfaces/IDateTimeFilter.cs: -------------------------------------------------------------------------------- 1 | using System.ComponentModel; 2 | 3 | namespace BlazorBoilerplate.Shared.Interfaces 4 | { 5 | public interface IDateTimeFilter : INotifyPropertyChanged 6 | { 7 | DateTime? From { get; set; } 8 | DateTime? To { get; set; } 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /src/Shared/BlazorBoilerplate.Shared/Interfaces/IDynamicComponent.cs: -------------------------------------------------------------------------------- 1 | namespace BlazorBoilerplate.Shared.Interfaces 2 | { 3 | public interface IDynamicComponent 4 | { 5 | string IntoComponent { get; } 6 | int Order { get; } 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /src/Shared/BlazorBoilerplate.Shared/Interfaces/IFileUploadEntry.cs: -------------------------------------------------------------------------------- 1 | namespace BlazorBoilerplate.Shared.Interfaces 2 | { 3 | public interface IFileUploadEntry 4 | { 5 | string Name { get; } 6 | Task WriteToStreamAsync(Stream stream); 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /src/Shared/BlazorBoilerplate.Shared/Interfaces/ILocalizationApiClient.cs: -------------------------------------------------------------------------------- 1 | using BlazorBoilerplate.Shared.Dto; 2 | using BlazorBoilerplate.Shared.Dto.Db; 3 | using Breeze.Sharp; 4 | 5 | namespace BlazorBoilerplate.Shared.Interfaces 6 | { 7 | public interface ILocalizationApiClient : IBaseApiClient 8 | { 9 | void AddEntity(LocalizationRecord entity); 10 | void RemoveEntity(LocalizationRecord entity); 11 | Task> GetPluralFormRules(); 12 | Task> GetLocalizationRecords(LocalizationRecordKey key = null); 13 | Task> GetLocalizationRecordKeys(int? take, int? skip, string filter = null); 14 | Task DeleteLocalizationRecordKey(LocalizationRecordKey key); 15 | Task EditLocalizationRecordKey(LocalizationRecordKey oldkey, LocalizationRecordKey newKey); 16 | Task ReloadTranslations(); 17 | Task Upload(MultipartFormDataContent content); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/Shared/BlazorBoilerplate.Shared/Interfaces/IModule.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.AspNetCore.Components.WebAssembly.Hosting; 2 | using Microsoft.Extensions.DependencyInjection; 3 | 4 | namespace BlazorBoilerplate.Shared.Interfaces 5 | { 6 | public interface IModule 7 | { 8 | string Name { get; } 9 | 10 | string Description { get; } 11 | 12 | int Order { get; } 13 | 14 | void ConfigureServices(IServiceCollection services); 15 | 16 | void ConfigureWebAssemblyServices(IServiceCollection services); 17 | 18 | void ConfigureWebAssemblyHost(WebAssemblyHost webAssemblyHost); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/Shared/BlazorBoilerplate.Shared/Interfaces/ITheme.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.AspNetCore.Components.WebAssembly.Hosting; 2 | 3 | namespace BlazorBoilerplate.Shared.Interfaces 4 | { 5 | public interface ITheme 6 | { 7 | RootComponentMapping RootComponentMapping { get; } 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /src/Shared/BlazorBoilerplate.Shared/Interfaces/IUserSession.cs: -------------------------------------------------------------------------------- 1 | namespace BlazorBoilerplate.Shared.Interfaces 2 | { 3 | public interface IUserSession 4 | { 5 | Guid UserId { get; set; } 6 | string UserName { get; set; } 7 | List Roles { get; set; } 8 | List> ExposedClaims { get; set; } 9 | } 10 | } -------------------------------------------------------------------------------- /src/Shared/BlazorBoilerplate.Shared/Interfaces/IViewNotifier.cs: -------------------------------------------------------------------------------- 1 | namespace BlazorBoilerplate.Shared.Interfaces 2 | { 3 | public enum ViewNotifierType 4 | { 5 | Success, 6 | Info, 7 | Warning, 8 | Error 9 | } 10 | public interface IViewNotifier 11 | { 12 | void Show(string message, ViewNotifierType type, string title = null, string icon = null); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /src/Shared/BlazorBoilerplate.Shared/Models/Account/AccountFormModel.cs: -------------------------------------------------------------------------------- 1 | namespace BlazorBoilerplate.Shared.Models.Account 2 | { 3 | public class AccountFormModel 4 | { 5 | private string returnUrl; 6 | 7 | public bool RememberMe { get; set; } 8 | 9 | public string ReturnUrl 10 | { 11 | get => returnUrl ?? "/"; 12 | set 13 | { 14 | if (!string.IsNullOrEmpty(value)) 15 | { 16 | if (value.StartsWith("http")) 17 | value = new Uri(value).LocalPath; 18 | 19 | if (!value.StartsWith("/")) 20 | value = $"/{value}"; 21 | } 22 | 23 | returnUrl = value; 24 | } 25 | } 26 | 27 | public string __RequestVerificationToken { get; set; } 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/Shared/BlazorBoilerplate.Shared/Models/Account/AuthenticatorVerificationCodeViewModel.cs: -------------------------------------------------------------------------------- 1 | using System.ComponentModel.DataAnnotations; 2 | 3 | namespace BlazorBoilerplate.Shared.Models.Account 4 | { 5 | public class AuthenticatorVerificationCodeViewModel 6 | { 7 | [DataType(DataType.Text)] 8 | [Display(Name = "VerificationCode")] 9 | public string Code { get; set; } 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /src/Shared/BlazorBoilerplate.Shared/Models/Account/ChangePasswordViewModel.cs: -------------------------------------------------------------------------------- 1 | using System.ComponentModel.DataAnnotations; 2 | 3 | namespace BlazorBoilerplate.Shared.Models.Account 4 | { 5 | public class ChangePasswordViewModel 6 | { 7 | public string UserId { get; set; } 8 | 9 | [DataType(DataType.Password)] 10 | public string Password { get; set; } 11 | public string PasswordConfirm { get; set; } 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /src/Shared/BlazorBoilerplate.Shared/Models/Account/ConfirmEmailViewModel.cs: -------------------------------------------------------------------------------- 1 | using System.ComponentModel.DataAnnotations; 2 | 3 | namespace BlazorBoilerplate.Shared.Models.Account 4 | { 5 | public class ConfirmEmailViewModel 6 | { 7 | [Required(ErrorMessage = "FieldRequired")] 8 | public string UserId { get; set; } 9 | 10 | [Required(ErrorMessage = "FieldRequired")] 11 | public string Token { get; set; } 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /src/Shared/BlazorBoilerplate.Shared/Models/Account/ForgotPasswordViewModel.cs: -------------------------------------------------------------------------------- 1 | using System.ComponentModel.DataAnnotations; 2 | 3 | namespace BlazorBoilerplate.Shared.Models.Account 4 | { 5 | public class ForgotPasswordViewModel 6 | { 7 | [DataType(DataType.EmailAddress)] 8 | public string Email { get; set; } 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /src/Shared/BlazorBoilerplate.Shared/Models/Account/LoggedOutViewModel.cs: -------------------------------------------------------------------------------- 1 | namespace BlazorBoilerplate.Shared.Models.Account 2 | { 3 | public class LoggedOutViewModel : AccountFormModel 4 | { 5 | public string PostLogoutRedirectUri { get; set; } 6 | public string ClientName { get; set; } 7 | public string SignOutIframeUrl { get; set; } 8 | 9 | public bool AutomaticRedirectAfterSignOut { get; set; } 10 | 11 | public string LogoutId { get; set; } 12 | public bool TriggerExternalSignout => ExternalAuthenticationScheme != null; 13 | public string ExternalAuthenticationScheme { get; set; } 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/Shared/BlazorBoilerplate.Shared/Models/Account/LoginInputModel.cs: -------------------------------------------------------------------------------- 1 | using System.ComponentModel.DataAnnotations; 2 | 3 | namespace BlazorBoilerplate.Shared.Models.Account 4 | { 5 | public class LoginInputModel : AccountFormModel 6 | { 7 | public string UserName { get; set; } 8 | 9 | [DataType(DataType.Password)] 10 | public string Password { get; set; } 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /src/Shared/BlazorBoilerplate.Shared/Models/Account/LoginResponseModel.cs: -------------------------------------------------------------------------------- 1 | namespace BlazorBoilerplate.Shared.Models.Account 2 | { 3 | public class LoginResponseModel 4 | { 5 | public bool RequiresTwoFactor { get; set; } 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /src/Shared/BlazorBoilerplate.Shared/Models/Account/LoginViewModel.cs: -------------------------------------------------------------------------------- 1 | using BlazorBoilerplate.Shared.Providers; 2 | 3 | namespace BlazorBoilerplate.Shared.Models.Account 4 | { 5 | public class LoginViewModel : LoginInputModel 6 | { 7 | public bool AllowRememberLogin { get; set; } = true; 8 | public bool EnableLocalLogin { get; set; } = true; 9 | 10 | public IEnumerable ExternalProviders { get; set; } = Enumerable.Empty(); 11 | public IEnumerable VisibleExternalProviders => ExternalProviders.Where(x => !string.IsNullOrWhiteSpace(x.DisplayName)); 12 | 13 | public bool IsExternalLoginOnly => EnableLocalLogin == false && ExternalProviders?.Count() == 1; 14 | public string ExternalLoginScheme => IsExternalLoginOnly ? ExternalProviders?.SingleOrDefault()?.AuthenticationScheme : null; 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/Shared/BlazorBoilerplate.Shared/Models/Account/LoginWith2faInputModel.cs: -------------------------------------------------------------------------------- 1 | using System.ComponentModel.DataAnnotations; 2 | 3 | namespace BlazorBoilerplate.Shared.Models.Account 4 | { 5 | public class LoginWith2faInputModel : LoginWith2faModel 6 | { 7 | [DataType(DataType.Text)] 8 | public string TwoFactorCode { get; set; } 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /src/Shared/BlazorBoilerplate.Shared/Models/Account/LoginWith2faModel.cs: -------------------------------------------------------------------------------- 1 | using System.ComponentModel.DataAnnotations; 2 | 3 | namespace BlazorBoilerplate.Shared.Models.Account 4 | { 5 | public class LoginWith2faModel : AccountFormModel 6 | { 7 | [Display(Name = "RememberBrowser")] 8 | public bool RememberMachine { get; set; } 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /src/Shared/BlazorBoilerplate.Shared/Models/Account/LoginWithRecoveryCodeInputModel.cs: -------------------------------------------------------------------------------- 1 | using System.ComponentModel.DataAnnotations; 2 | 3 | namespace BlazorBoilerplate.Shared.Models.Account 4 | { 5 | public class LoginWithRecoveryCodeInputModel : LoginWith2faModel 6 | { 7 | [DataType(DataType.Text)] 8 | public string RecoveryCode { get; set; } 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /src/Shared/BlazorBoilerplate.Shared/Models/Account/RegisterViewModel.cs: -------------------------------------------------------------------------------- 1 | using System.ComponentModel.DataAnnotations; 2 | 3 | namespace BlazorBoilerplate.Shared.Models.Account 4 | { 5 | public class RegisterViewModel : LoginInputModel 6 | { 7 | [DataType(DataType.EmailAddress)] 8 | public string Email { get; set; } 9 | public string PasswordConfirm { get; set; } 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /src/Shared/BlazorBoilerplate.Shared/Models/Account/ResetPasswordViewModel.cs: -------------------------------------------------------------------------------- 1 | namespace BlazorBoilerplate.Shared.Models.Account 2 | { 3 | public class ResetPasswordViewModel : ChangePasswordViewModel 4 | { 5 | public string Token { get; set; } 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /src/Shared/BlazorBoilerplate.Shared/Models/Account/UpdatePasswordViewModel.cs: -------------------------------------------------------------------------------- 1 | using System.ComponentModel.DataAnnotations; 2 | 3 | namespace BlazorBoilerplate.Shared.Models.Account 4 | { 5 | public class UpdatePasswordViewModel 6 | { 7 | [DataType(DataType.Password)] 8 | public string NewPassword { get; set; } 9 | public string NewPasswordConfirm { get; set; } 10 | 11 | [DataType(DataType.Password)] 12 | public string CurrentPassword { get; set; } 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /src/Shared/BlazorBoilerplate.Shared/Models/Account/UserViewModel.cs: -------------------------------------------------------------------------------- 1 | using BlazorBoilerplate.Shared.Dto; 2 | 3 | namespace BlazorBoilerplate.Shared.Models.Account 4 | { 5 | public class UserViewModel : BaseDto 6 | { 7 | public bool IsAuthenticated { get; set; } 8 | public Guid UserId { get; set; } 9 | public string UserName { get; set; } 10 | public string TenantId { get; set; } 11 | public string Email { get; set; } 12 | public string FirstName { get; set; } 13 | public string LastName { get; set; } 14 | public bool HasPassword { get; set; } 15 | public string PhoneNumber { get; set; } 16 | public bool TwoFactorEnabled { get; set; } 17 | public bool HasAuthenticator { get; set; } 18 | public List> Logins { get; set; } 19 | public bool BrowserRemembered { get; set; } 20 | public string SharedKey { get; set; } 21 | public string AuthenticatorUri { get; set; } 22 | public string[] RecoveryCodes { get; set; } 23 | public int CountRecoveryCodes { get; set; } 24 | public List Roles { get; set; } 25 | public List> ExposedClaims { get; set; } 26 | } 27 | } -------------------------------------------------------------------------------- /src/Shared/BlazorBoilerplate.Shared/Models/Account/Validators/AuthenticatorVerificationCodeViewModelValidator.cs: -------------------------------------------------------------------------------- 1 | using BlazorBoilerplate.Shared.Localizer; 2 | using BlazorBoilerplate.Shared.Validators; 3 | using FluentValidation; 4 | using Microsoft.Extensions.Localization; 5 | 6 | namespace BlazorBoilerplate.Shared.Models.Account.Validators 7 | { 8 | public class AuthenticatorVerificationCodeViewModelValidator : LocalizedAbstractValidator 9 | { 10 | public AuthenticatorVerificationCodeViewModelValidator(IStringLocalizer l) : base(l) 11 | { 12 | RuleFor(p => p.Code) 13 | .NotEmpty() 14 | .Length(6, 7).WithName(L["VerificationCode"]); 15 | } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/Shared/BlazorBoilerplate.Shared/Models/Account/Validators/ChangePasswordViewModelValidator.cs: -------------------------------------------------------------------------------- 1 | using BlazorBoilerplate.Shared.Localizer; 2 | using BlazorBoilerplate.Shared.Validators; 3 | using FluentValidation; 4 | using Microsoft.Extensions.Localization; 5 | 6 | namespace BlazorBoilerplate.Shared.Models.Account.Validators 7 | { 8 | public class ChangePasswordViewModelValidator : LocalizedAbstractValidator where T : ChangePasswordViewModel 9 | { 10 | public ChangePasswordViewModelValidator(IStringLocalizer l) : base(l) 11 | { 12 | RuleFor(p => p.UserId) 13 | .NotEmpty(); 14 | 15 | RuleFor(p => p.Password).Password(L).WithName(L["NewPassword"]); 16 | 17 | RuleFor(p => p.PasswordConfirm) 18 | .Equal(p => p.Password).WithMessage(x => L["PasswordConfirmationFailed"]).WithName(L["ConfirmNewPassword"]); 19 | } 20 | } 21 | 22 | public class ChangePasswordViewModelValidator : ChangePasswordViewModelValidator 23 | { 24 | public ChangePasswordViewModelValidator(IStringLocalizer l) : base(l) 25 | { 26 | 27 | } 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/Shared/BlazorBoilerplate.Shared/Models/Account/Validators/ForgotPasswordViewModelValidator.cs: -------------------------------------------------------------------------------- 1 | using BlazorBoilerplate.Shared.Localizer; 2 | using BlazorBoilerplate.Shared.Validators; 3 | using FluentValidation; 4 | using Microsoft.Extensions.Localization; 5 | 6 | namespace BlazorBoilerplate.Shared.Models.Account.Validators 7 | { 8 | public class ForgotPasswordViewModelValidator : LocalizedAbstractValidator 9 | { 10 | public ForgotPasswordViewModelValidator(IStringLocalizer l) : base(l) 11 | { 12 | RuleFor(p => p.Email) 13 | .NotEmpty() 14 | .EmailAddress().WithName(L["Email"]); 15 | } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/Shared/BlazorBoilerplate.Shared/Models/Account/Validators/LoginInputModelValidator.cs: -------------------------------------------------------------------------------- 1 | using BlazorBoilerplate.Shared.Localizer; 2 | using BlazorBoilerplate.Shared.Validators; 3 | using FluentValidation; 4 | using Microsoft.Extensions.Localization; 5 | 6 | namespace BlazorBoilerplate.Shared.Models.Account.Validators 7 | { 8 | public class LoginInputModelValidator : LocalizedAbstractValidator where T : LoginInputModel 9 | { 10 | public LoginInputModelValidator(IStringLocalizer l) : base(l) 11 | { 12 | RuleFor(p => p.UserName) 13 | .NotEmpty() 14 | .Matches(@"^[^\s]+$").WithMessage(x => L["SpacesNotPermitted"]) 15 | .Length(2, 64).WithName(L["UserName"]); 16 | 17 | RuleFor(p => p.Password).Password(L); 18 | } 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/Shared/BlazorBoilerplate.Shared/Models/Account/Validators/LoginViewModelValidator.cs: -------------------------------------------------------------------------------- 1 | using BlazorBoilerplate.Shared.Localizer; 2 | using Microsoft.Extensions.Localization; 3 | 4 | namespace BlazorBoilerplate.Shared.Models.Account.Validators 5 | { 6 | public class LoginViewModelValidator : LoginInputModelValidator 7 | { 8 | public LoginViewModelValidator(IStringLocalizer l) : base(l) 9 | { 10 | } 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /src/Shared/BlazorBoilerplate.Shared/Models/Account/Validators/LoginWith2faInputModelValidator.cs: -------------------------------------------------------------------------------- 1 | using BlazorBoilerplate.Shared.Localizer; 2 | using BlazorBoilerplate.Shared.Validators; 3 | using FluentValidation; 4 | using Microsoft.Extensions.Localization; 5 | 6 | namespace BlazorBoilerplate.Shared.Models.Account.Validators 7 | { 8 | public class LoginWith2faInputModelValidator : LocalizedAbstractValidator 9 | { 10 | public LoginWith2faInputModelValidator(IStringLocalizer l) : base(l) 11 | { 12 | RuleFor(p => p.TwoFactorCode) 13 | .NotEmpty() 14 | .Length(6, 7).WithName(L["AuthenticatorCode"]); 15 | } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/Shared/BlazorBoilerplate.Shared/Models/Account/Validators/LoginWithRecoveryCodeInputModelValidator.cs: -------------------------------------------------------------------------------- 1 | using BlazorBoilerplate.Shared.Localizer; 2 | using BlazorBoilerplate.Shared.Validators; 3 | using FluentValidation; 4 | using Microsoft.Extensions.Localization; 5 | 6 | namespace BlazorBoilerplate.Shared.Models.Account.Validators 7 | { 8 | public class LoginWithRecoveryCodeInputModelValidator : LocalizedAbstractValidator 9 | { 10 | public LoginWithRecoveryCodeInputModelValidator(IStringLocalizer l) : base(l) 11 | { 12 | RuleFor(p => p.RecoveryCode) 13 | .NotEmpty().WithName(L["RecoveryCode"]); 14 | } 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/Shared/BlazorBoilerplate.Shared/Models/Account/Validators/RegisterViewModelValidator.cs: -------------------------------------------------------------------------------- 1 | using BlazorBoilerplate.Shared.Localizer; 2 | using FluentValidation; 3 | using Microsoft.Extensions.Localization; 4 | 5 | namespace BlazorBoilerplate.Shared.Models.Account.Validators 6 | { 7 | public class RegisterViewModelValidator : LoginInputModelValidator 8 | { 9 | public RegisterViewModelValidator(IStringLocalizer l) : base(l) 10 | { 11 | RuleFor(p => p.Email) 12 | .NotEmpty() 13 | .EmailAddress().WithName(L["Email"]); 14 | 15 | RuleFor(p => p.PasswordConfirm) 16 | .Equal(p => p.Password).WithMessage(x => L["PasswordConfirmationFailed"]).WithName(L["ConfirmPassword"]); 17 | } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/Shared/BlazorBoilerplate.Shared/Models/Account/Validators/ResetPasswordViewModelValidator.cs: -------------------------------------------------------------------------------- 1 | using BlazorBoilerplate.Shared.Localizer; 2 | using FluentValidation; 3 | using Microsoft.Extensions.Localization; 4 | 5 | namespace BlazorBoilerplate.Shared.Models.Account.Validators 6 | { 7 | public class ResetPasswordViewModelValidator : ChangePasswordViewModelValidator 8 | { 9 | public ResetPasswordViewModelValidator(IStringLocalizer l) : base(l) 10 | { 11 | RuleFor(p => p.Token) 12 | .NotEmpty().WithName(L["RecoveryCode"]); 13 | } 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/Shared/BlazorBoilerplate.Shared/Models/Account/Validators/RuleBuilderExtensions.cs: -------------------------------------------------------------------------------- 1 | using BlazorBoilerplate.Constants; 2 | using BlazorBoilerplate.Shared.Localizer; 3 | using FluentValidation; 4 | using Microsoft.Extensions.Localization; 5 | 6 | namespace BlazorBoilerplate.Shared.Models.Account.Validators 7 | { 8 | public static class RuleBuilderExtensions 9 | { 10 | public static IRuleBuilderOptions Password(this IRuleBuilder ruleBuilder, IStringLocalizer l) 11 | { 12 | var options = ruleBuilder 13 | .NotEmpty().WithName(l["Password"]) 14 | .MinimumLength(PasswordPolicy.RequiredLength).WithMessage(l["PasswordTooShort", PasswordPolicy.RequiredLength]) 15 | .Matches("[A-Z]").When(p => PasswordPolicy.RequireUppercase, ApplyConditionTo.CurrentValidator).WithMessage(l["PasswordRequiresUpper"]) 16 | .Matches("[a-z]").When(p => PasswordPolicy.RequireLowercase, ApplyConditionTo.CurrentValidator).WithMessage(l["PasswordRequiresLower"]) 17 | .Matches("[0-9]").When(p => PasswordPolicy.RequireDigit, ApplyConditionTo.CurrentValidator).WithMessage(l["PasswordRequiresDigit"]) 18 | .Matches("[^a-zA-Z0-9]").When(p => PasswordPolicy.RequireNonAlphanumeric, ApplyConditionTo.CurrentValidator).WithMessage(l["PasswordRequiresNonAlphanumeric"]); 19 | 20 | return options; 21 | } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/Shared/BlazorBoilerplate.Shared/Models/Account/Validators/UpdatePasswordViewModelValidator.cs: -------------------------------------------------------------------------------- 1 | using BlazorBoilerplate.Shared.Localizer; 2 | using BlazorBoilerplate.Shared.Validators; 3 | using FluentValidation; 4 | using Microsoft.Extensions.Localization; 5 | 6 | namespace BlazorBoilerplate.Shared.Models.Account.Validators 7 | { 8 | public class UpdatePasswordViewModelValidator : LocalizedAbstractValidator 9 | { 10 | public UpdatePasswordViewModelValidator(IStringLocalizer l) : base(l) 11 | { 12 | RuleFor(p => p.NewPassword).Password(L).WithName(L["NewPassword"]); 13 | 14 | RuleFor(p => p.NewPasswordConfirm) 15 | .Equal(p => p.NewPassword).WithMessage(x => L["PasswordConfirmationFailed"]).WithName(L["ConfirmNewPassword"]); 16 | 17 | RuleFor(p => p.CurrentPassword) 18 | .NotEmpty().WithName(L["CurrentPassword"]); 19 | } 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/Shared/BlazorBoilerplate.Shared/Models/Account/Validators/UserViewModelValidator.cs: -------------------------------------------------------------------------------- 1 | using BlazorBoilerplate.Shared.Localizer; 2 | using BlazorBoilerplate.Shared.Validators; 3 | using FluentValidation; 4 | using Microsoft.Extensions.Localization; 5 | 6 | namespace BlazorBoilerplate.Shared.Models.Account.Validators 7 | { 8 | public class UserViewModelValidator : LocalizedAbstractValidator 9 | { 10 | public UserViewModelValidator(IStringLocalizer l) : base(l) 11 | { 12 | RuleFor(p => p.UserName) 13 | .NotEmpty() 14 | .Matches(@"^[^\s]+$").WithMessage(x => L["SpacesNotPermitted"]) 15 | .Length(2, 64).WithName(L["UserName"]); 16 | 17 | RuleFor(p => p.Email) 18 | .NotEmpty() 19 | .EmailAddress().WithName(L["Email"]); 20 | } 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/Shared/BlazorBoilerplate.Shared/Models/BaseModule.cs: -------------------------------------------------------------------------------- 1 | using BlazorBoilerplate.Shared.Interfaces; 2 | using Microsoft.AspNetCore.Components.WebAssembly.Hosting; 3 | using Microsoft.Extensions.DependencyInjection; 4 | 5 | namespace BlazorBoilerplate.Shared.Models 6 | { 7 | public abstract class BaseModule : IModule 8 | { 9 | public virtual string Name => GetType().Namespace; 10 | 11 | public virtual string Description => GetType().Namespace; 12 | 13 | public virtual int Order => 1; 14 | 15 | public virtual void ConfigureServices(IServiceCollection services) 16 | { } 17 | 18 | public virtual void ConfigureWebAssemblyHost(WebAssemblyHost webAssemblyHost) 19 | { } 20 | 21 | public virtual void ConfigureWebAssemblyServices(IServiceCollection services) 22 | { } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/Shared/BlazorBoilerplate.Shared/Models/EmailConfiguration.cs: -------------------------------------------------------------------------------- 1 | using System.Security.Authentication; 2 | 3 | namespace BlazorBoilerplate.Shared.Models 4 | { 5 | public class EmailConfiguration 6 | { 7 | public string SmtpServer { get; set; } 8 | public int SmtpPort { get; set; } 9 | public string SmtpUsername { get; set; } 10 | public string SmtpPassword { get; set; } 11 | public bool SmtpUseSSL { get; set; } 12 | #pragma warning disable CS0618 // Type or member is obsolete 13 | public SslProtocols SmtpSslProtocol { get; set; } = SslProtocols.Default; 14 | #pragma warning restore CS0618 // Type or member is obsolete 15 | 16 | public string FromName { get; set; } 17 | public string FromAddress { get; set; } 18 | public string ReplyToAddress { get; set; } 19 | 20 | public string PopServer { get; set; } 21 | public int PopPort { get; set; } 22 | public string PopUsername { get; set; } 23 | public string PopPassword { get; set; } 24 | public bool PopUseSSL { get; set; } 25 | 26 | public string ImapServer { get; set; } 27 | public int ImapPort { get; set; } 28 | public string ImapUsername { get; set; } 29 | public string ImapPassword { get; set; } 30 | public bool ImapUseSSL { get; set; } 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/Shared/BlazorBoilerplate.Shared/Models/Localization/ChangeLocalizationRecordModel.cs: -------------------------------------------------------------------------------- 1 | namespace BlazorBoilerplate.Shared.Models.Localization 2 | { 3 | public class ChangeLocalizationRecordModel 4 | { 5 | public string ContextId { get; set; } 6 | public string MsgId { get; set; } 7 | 8 | public string NewContextId { get; set; } 9 | public string NewMsgId { get; set; } 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /src/Shared/BlazorBoilerplate.Shared/Models/Localization/LocalizationRecordFilterModel.cs: -------------------------------------------------------------------------------- 1 | namespace BlazorBoilerplate.Shared.Models.Localization 2 | { 3 | public class LocalizationRecordFilterModel 4 | { 5 | public string ContextId { get; set; } 6 | public string MsgId { get; set; } 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /src/Shared/BlazorBoilerplate.Shared/Models/MainConfiguration.cs: -------------------------------------------------------------------------------- 1 | using BlazorBoilerplate.Shared.Dto.Db; 2 | 3 | namespace BlazorBoilerplate.Shared.Models 4 | { 5 | public class MainConfiguration 6 | { 7 | public BlazorRuntime Runtime { get; set; } 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /src/Shared/BlazorBoilerplate.Shared/Models/QueryParameters.cs: -------------------------------------------------------------------------------- 1 | namespace BlazorBoilerplate.Shared.Models 2 | { 3 | public abstract class QueryParameters 4 | { 5 | public Dictionary ToDictionary() 6 | { 7 | var parameters = new Dictionary(); 8 | 9 | foreach (var prop in GetType().GetProperties()) 10 | { 11 | if (prop.PropertyType == typeof(DateTime?)) 12 | { 13 | var dt = (DateTime?)prop.GetValue(this); 14 | parameters.Add(prop.Name, dt?.ToString("s")); 15 | } 16 | else 17 | parameters.Add(prop.Name, prop.GetValue(this)); 18 | } 19 | 20 | return parameters; 21 | } 22 | 23 | public string ToQuery() 24 | { 25 | var queryOption = new List(); 26 | 27 | foreach (var i in ToDictionary().Where(p => p.Value != null)) 28 | queryOption.Add($"{i.Key}={i.Value}"); 29 | 30 | return string.Join('&', queryOption); 31 | } 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/Shared/BlazorBoilerplate.Shared/Models/SelectItem.cs: -------------------------------------------------------------------------------- 1 | namespace BlazorBoilerplate.Shared.Models 2 | { 3 | public class SelectItem : IEquatable> 4 | { 5 | public T Id { get; set; } 6 | 7 | public bool Selected { get; set; } 8 | 9 | public string DisplayValue { get; set; } 10 | 11 | public override bool Equals(object obj) 12 | { 13 | return Equals(obj as SelectItem); 14 | } 15 | 16 | public bool Equals(SelectItem other) 17 | { 18 | return other != null && 19 | Id.Equals(other.Id); 20 | } 21 | 22 | public override int GetHashCode() 23 | { 24 | return HashCode.Combine(Id); 25 | } 26 | 27 | public override string ToString() 28 | { 29 | return DisplayValue ?? " - "; 30 | } 31 | 32 | public static bool operator ==(SelectItem left, SelectItem right) 33 | { 34 | return EqualityComparer>.Default.Equals(left, right); 35 | } 36 | 37 | public static bool operator !=(SelectItem left, SelectItem right) 38 | { 39 | return !(left == right); 40 | } 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/Shared/BlazorBoilerplate.Shared/Models/ToDoFilter.cs: -------------------------------------------------------------------------------- 1 | using BlazorBoilerplate.Shared.Interfaces; 2 | using SourceGenerators; 3 | 4 | namespace BlazorBoilerplate.Shared.Models 5 | { 6 | public partial class ToDoFilter : QueryParameters, IDateTimeFilter 7 | { 8 | [AutoNotify] 9 | private DateTime? _from; 10 | 11 | [AutoNotify] 12 | private DateTime? _to; 13 | 14 | [AutoNotify] 15 | private Guid? _createdById; 16 | 17 | [AutoNotify] 18 | private Guid? _modifiedById; 19 | 20 | [AutoNotify] 21 | private bool? _isCompleted; 22 | 23 | [AutoNotify] 24 | private string _query; 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/Shared/BlazorBoilerplate.Shared/Models/UserSession.cs: -------------------------------------------------------------------------------- 1 | using BlazorBoilerplate.Shared.Interfaces; 2 | 3 | namespace BlazorBoilerplate.Shared.Models 4 | { 5 | public class UserSession : IUserSession 6 | { 7 | public bool IsAuthenticated { get; set; } 8 | public Guid UserId { get; set; } 9 | public string UserName { get; set; } 10 | public string Email { get; set; } 11 | public string FirstName { get; set; } 12 | public string LastName { get; set; } 13 | public List Roles { get; set; } 14 | public List> ExposedClaims { get; set; } 15 | 16 | public UserSession() 17 | { 18 | } 19 | 20 | public UserSession(Guid userId, string userName) 21 | { 22 | UserId = userId; 23 | UserName = userName; 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/Shared/BlazorBoilerplate.Shared/Providers/ExternalProvider.cs: -------------------------------------------------------------------------------- 1 | namespace BlazorBoilerplate.Shared.Providers 2 | { 3 | public class ExternalProvider 4 | { 5 | public string DisplayName { get; set; } 6 | public string AuthenticationScheme { get; set; } 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /src/Shared/BlazorBoilerplate.Shared/TagHelpers/AppTagHelperComponentTagHelper.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.AspNetCore.Mvc.Razor.TagHelpers; 2 | using Microsoft.AspNetCore.Razor.TagHelpers; 3 | using Microsoft.Extensions.Logging; 4 | using System.ComponentModel; 5 | 6 | namespace BlazorBoilerplate.Shared.TagHelpers 7 | { 8 | [HtmlTargetElement("app")] 9 | [EditorBrowsable(EditorBrowsableState.Never)] 10 | public class AppTagHelperComponentTagHelper : TagHelperComponentTagHelper 11 | { 12 | public AppTagHelperComponentTagHelper( 13 | ITagHelperComponentManager componentManager, 14 | ILoggerFactory loggerFactory) : base(componentManager, loggerFactory) 15 | { 16 | } 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/Shared/BlazorBoilerplate.Shared/Validators/Db/LocalizationRecordValidator.cs: -------------------------------------------------------------------------------- 1 | using BlazorBoilerplate.Shared.Dto.Db; 2 | using BlazorBoilerplate.Shared.Localizer; 3 | using FluentValidation; 4 | using Microsoft.Extensions.Localization; 5 | 6 | namespace BlazorBoilerplate.Shared.Validators.Db 7 | { 8 | public class LocalizationRecordValidator : LocalizedAbstractValidator 9 | { 10 | public LocalizationRecordValidator(IStringLocalizer l) : base(l) 11 | { 12 | RuleFor(p => p.ContextId) 13 | .NotEmpty().WithName(L["ContextId"]); 14 | 15 | RuleFor(p => p.MsgId) 16 | .NotEmpty().WithName(L["MsgId"]); 17 | 18 | RuleFor(p => p.Translation) 19 | .NotEmpty().WithName(L["Translation"]); 20 | } 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/Shared/BlazorBoilerplate.Shared/Validators/Db/PluralFormRuleValidator.cs: -------------------------------------------------------------------------------- 1 | using BlazorBoilerplate.Shared.Dto.Db; 2 | using BlazorBoilerplate.Shared.Localizer; 3 | using FluentValidation; 4 | using Microsoft.Extensions.Localization; 5 | 6 | namespace BlazorBoilerplate.Shared.Validators.Db 7 | { 8 | public class PluralFormRuleValidator : LocalizedAbstractValidator 9 | { 10 | public PluralFormRuleValidator(IStringLocalizer l) : base(l) 11 | { 12 | RuleFor(p => p.Language) 13 | .NotEmpty().WithName(L["Culture"]); 14 | 15 | RuleFor(p => p.Count) 16 | .GreaterThan(0).WithName(L["Count"]); 17 | 18 | RuleFor(p => p.Selector) 19 | .NotEmpty().WithName(L["Selector"]); 20 | } 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/Shared/BlazorBoilerplate.Shared/Validators/Db/PluralTranslationValidator.cs: -------------------------------------------------------------------------------- 1 | using BlazorBoilerplate.Shared.Dto.Db; 2 | using BlazorBoilerplate.Shared.Localizer; 3 | using FluentValidation; 4 | using Microsoft.Extensions.Localization; 5 | 6 | namespace BlazorBoilerplate.Shared.Validators.Db 7 | { 8 | public class PluralTranslationValidator : LocalizedAbstractValidator 9 | { 10 | public PluralTranslationValidator(IStringLocalizer l) : base(l) 11 | { 12 | RuleFor(p => p.Translation) 13 | .NotEmpty().WithName(L["Translation"]); 14 | } 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/Shared/BlazorBoilerplate.Shared/Validators/LocalizedAbstractValidator.cs: -------------------------------------------------------------------------------- 1 | using BlazorBoilerplate.Shared.Localizer; 2 | using FluentValidation; 3 | using Microsoft.Extensions.Localization; 4 | 5 | namespace BlazorBoilerplate.Shared.Validators 6 | { 7 | public class LocalizedAbstractValidator : AbstractValidator 8 | { 9 | protected readonly IStringLocalizer L; 10 | public LocalizedAbstractValidator(IStringLocalizer l) 11 | { 12 | L = l; 13 | } 14 | } 15 | 16 | public class LocalizedAbstractValidator : LocalizedAbstractValidator 17 | { 18 | public LocalizedAbstractValidator(IStringLocalizer l) : base(l) 19 | { 20 | 21 | } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/Shared/BlazorBoilerplate.UI.Base/BlazorBoilerplate.UI.Base.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | net7.0 5 | enable 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /src/Shared/BlazorBoilerplate.UI.Base/Pages/Admin/Settings/IndexPage.cs: -------------------------------------------------------------------------------- 1 | using BlazorBoilerplate.Shared.Dto.Db; 2 | 3 | namespace BlazorBoilerplate.UI.Base.Pages.Admin.Settings 4 | { 5 | public class IndexPage : SettingsBase 6 | { 7 | protected string[] BlazorRuntimes { get; set; } = ((BlazorRuntime[])Enum.GetValues(typeof(BlazorRuntime))).Select(i => i.ToString()).ToArray(); 8 | 9 | protected override async Task OnInitializedAsync() 10 | { 11 | await LoadSettings("MainConfiguration_"); 12 | } 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /src/Shared/BlazorBoilerplate.UI.Base/Shared/Components/AutoFocus.razor: -------------------------------------------------------------------------------- 1 | @code { 2 | [Parameter] 3 | public Func Control { get; set; } 4 | 5 | protected override async Task OnAfterRenderAsync(bool firstRender) 6 | { 7 | if (Control is null) 8 | throw new ArgumentNullException(nameof(Control)); 9 | 10 | if (firstRender) 11 | { 12 | await Control().FocusAsync(); 13 | } 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/Shared/BlazorBoilerplate.UI.Base/Shared/Components/BaseComponent.cs: -------------------------------------------------------------------------------- 1 | using BlazorBoilerplate.Shared.Interfaces; 2 | using BlazorBoilerplate.Shared.Localizer; 3 | using Microsoft.AspNetCore.Authorization; 4 | using Microsoft.AspNetCore.Components; 5 | using Microsoft.AspNetCore.Components.Authorization; 6 | using Microsoft.Extensions.Localization; 7 | 8 | namespace BlazorBoilerplate.UI.Base.Shared.Components 9 | { 10 | public abstract class BaseComponent : ComponentBase, IDisposable 11 | { 12 | [CascadingParameter] protected Task authenticationStateTask { get; set; } 13 | [Inject] protected IAuthorizationService authorizationService { get; set; } 14 | [Inject] protected NavigationManager navigationManager { get; set; } 15 | [Inject] protected IViewNotifier viewNotifier { get; set; } 16 | [Inject] protected IApiClient apiClient { get; set; } 17 | [Inject] protected IStringLocalizer L { get; set; } 18 | 19 | public virtual void Dispose() 20 | { 21 | apiClient.CancelChanges(); 22 | apiClient.ClearEntitiesCache(); 23 | } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/Shared/BlazorBoilerplate.UI.Base/Shared/Components/RedirectToLogin.razor: -------------------------------------------------------------------------------- 1 | @inject NavigationManager Navigation 2 | @code { 3 | protected override void OnInitialized() 4 | { 5 | Navigation.NavigateTo($"{BlazorBoilerplate.Constants.Settings.LoginPath}?returnurl={Uri.EscapeDataString(Navigation.Uri)}", true); 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /src/Shared/BlazorBoilerplate.UI.Base/Shared/Components/TopSection.cs: -------------------------------------------------------------------------------- 1 | using BlazorBoilerplate.UI.Base.Shared.Layouts; 2 | using Microsoft.AspNetCore.Components; 3 | 4 | namespace BlazorBoilerplate.UI.Base.Shared.Components 5 | { 6 | public partial class TopSection : ComponentBase, IDisposable 7 | { 8 | [CascadingParameter] 9 | public RootLayout RootLayout { get; set; } 10 | 11 | [Parameter] 12 | public RenderFragment ChildContent { get; set; } 13 | 14 | protected override void OnInitialized() 15 | { 16 | RootLayout?.SetTopSection(this); 17 | 18 | base.OnInitialized(); 19 | } 20 | 21 | protected override bool ShouldRender() 22 | { 23 | var shouldRender = base.ShouldRender(); 24 | 25 | if (shouldRender) 26 | RootLayout?.Update(); 27 | 28 | return base.ShouldRender(); 29 | } 30 | 31 | public void Dispose() 32 | { 33 | RootLayout?.SetTopSection(null); 34 | } 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/Shared/BlazorBoilerplate.UI.Base/Shared/Layouts/RootLayout.razor: -------------------------------------------------------------------------------- 1 | @inherits LayoutComponentBase 2 | @using BlazorBoilerplate.UI.Base.Shared.Components 3 | @Body 4 | 5 | @code { 6 | public RenderFragment TopSection => topSection?.ChildContent; 7 | 8 | TopSection topSection; 9 | 10 | public void SetTopSection(TopSection topSection) 11 | { 12 | this.topSection = topSection; 13 | Update(); 14 | } 15 | 16 | public void Update() 17 | { 18 | if (topSection != null) 19 | StateHasChanged(); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/Shared/Modules/BlazorBoilerplate.GoogleAnalytics/BlazorBoilerplate.GoogleAnalytics.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | net7.0 5 | enable 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | True 19 | True 20 | ModuleStrings.resx 21 | 22 | 23 | 24 | 25 | 26 | PublicResXFileCodeGenerator 27 | ModuleStrings.Designer.cs 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | -------------------------------------------------------------------------------- /src/Shared/Modules/BlazorBoilerplate.GoogleAnalytics/Module.cs: -------------------------------------------------------------------------------- 1 | using BlazorBoilerplate.Shared.Models; 2 | using Microsoft.AspNetCore.Razor.TagHelpers; 3 | using Microsoft.Extensions.DependencyInjection; 4 | 5 | namespace BlazorBoilerplate.GoogleAnalytics 6 | { 7 | public class Module : BaseModule 8 | { 9 | public override string Name => "Google Analytics"; 10 | 11 | public override string Description => ModuleStrings.Description; 12 | 13 | public override int Order => 1000; 14 | 15 | public override void ConfigureServices(IServiceCollection services) 16 | { 17 | services.AddTransient(); 18 | } 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/Shared/Modules/BlazorBoilerplate.Theme.MudBlazor.Admin/BlazorBoilerplate.Theme.MudBlazor.Admin.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | net7.0 5 | BlazorBoilerplate.Theme.Material.Admin 6 | enable 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /src/Shared/Modules/BlazorBoilerplate.Theme.MudBlazor.Admin/Module.cs: -------------------------------------------------------------------------------- 1 | using BlazorBoilerplate.Shared.Models; 2 | 3 | namespace BlazorBoilerplate.Theme.Material.Admin 4 | { 5 | public class Module : BaseModule 6 | { 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /src/Shared/Modules/BlazorBoilerplate.Theme.MudBlazor.Admin/Pages/Admin/Index.razor: -------------------------------------------------------------------------------- 1 | @page "/admin" 2 | @attribute [Authorize(Policies.IsAdmin)] 3 | @layout AdminLayout 4 | 5 | @code { 6 | 7 | } 8 | -------------------------------------------------------------------------------- /src/Shared/Modules/BlazorBoilerplate.Theme.MudBlazor.Admin/Pages/Admin/Settings/Index.razor: -------------------------------------------------------------------------------- 1 | @inherits IndexPage 2 | @page "/admin/settings" 3 | @layout AdminLayout 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | @L["MainSettings"] 13 | 14 | @if (settings == null) 15 | { 16 | 17 | 18 | 19 | } 20 | else 21 | { 22 | 23 | 24 | 25 | 26 | @foreach (var item in BlazorRuntimes) 27 | { 28 | @item 29 | } 30 | 31 | 32 | 33 | @L["Cancel"] 34 | @L["Save"] 35 | } 36 | 37 | @code { 38 | } 39 | -------------------------------------------------------------------------------- /src/Shared/Modules/BlazorBoilerplate.Theme.MudBlazor.Admin/Shared/Components/TenantInfo.razor: -------------------------------------------------------------------------------- 1 | @inject HttpClient Http 2 | 3 | Current Tenant: @tenant.Name 4 | 5 | @code { 6 | TenantDto tenant = new TenantDto(); 7 | 8 | protected override async Task OnParametersSetAsync() 9 | { 10 | var apiResponse = await Http.GetNewtonsoftJsonAsync>("api/admin/tenant"); 11 | if (apiResponse.StatusCode == Status200OK) 12 | { 13 | tenant = apiResponse.Result; 14 | } 15 | } 16 | } -------------------------------------------------------------------------------- /src/Shared/Modules/BlazorBoilerplate.Theme.MudBlazor.Demo/BlazorBoilerplate.Theme.MudBlazor.Demo.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | net7.0 5 | BlazorBoilerplate.Theme.Material.Demo 6 | BlazorBoilerplate Demo UI 7 | enable 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /src/Shared/Modules/BlazorBoilerplate.Theme.MudBlazor.Demo/Module.cs: -------------------------------------------------------------------------------- 1 | using BlazorBoilerplate.Shared.Interfaces; 2 | using BlazorBoilerplate.Shared.Models; 3 | using BlazorBoilerplate.Theme.Material.Demo.Shared.Components; 4 | using BlazorBoilerplate.Theme.Material.Demo.TagHelpers; 5 | using Microsoft.AspNetCore.Razor.TagHelpers; 6 | using Microsoft.Extensions.DependencyInjection; 7 | 8 | namespace BlazorBoilerplate.Theme.Material.Demo 9 | { 10 | public class Module : BaseModule 11 | { 12 | public override string Description => "BlazorBoilerplate demo"; 13 | 14 | public override int Order => 2; 15 | 16 | private void Init(IServiceCollection services) 17 | { 18 | services.AddSingleton(); 19 | services.AddSingleton(); 20 | services.AddSingleton(); 21 | services.AddSingleton(); 22 | } 23 | 24 | public override void ConfigureServices(IServiceCollection services) 25 | { 26 | services.AddTransient(); 27 | Init(services); 28 | } 29 | 30 | public override void ConfigureWebAssemblyServices(IServiceCollection services) 31 | { 32 | Init(services); 33 | } 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/Shared/Modules/BlazorBoilerplate.Theme.MudBlazor.Demo/Pages/Forum/Forum.razor: -------------------------------------------------------------------------------- 1 | @page "/forum" 2 | @inherits ForumPageModel 3 | @inject IStringLocalizer L 4 | 5 | Forum 6 | 7 |

This forum page uses SignalR and persists in a database.

8 | 9 | 10 | 11 | 12 | Log in to post a message. 13 | 14 | 15 | 16 | 17 | 18 | 19 | @if (Messages == null || Messages.Count == 0) 20 | { 21 | 22 | 23 | 24 | } 25 | else 26 | { 27 | @foreach (var message in Messages) 28 | { 29 | 30 | 31 | 32 | } 33 | } 34 | 35 | 36 | 37 | -------------------------------------------------------------------------------- /src/Shared/Modules/BlazorBoilerplate.Theme.MudBlazor.Demo/Pages/Forum/ForumMessage.razor: -------------------------------------------------------------------------------- 1 | @using BlazorBoilerplate.Shared.Dto.Sample 2 | @using Microsoft.AspNetCore.Components.Forms 3 | 4 | 5 | 6 | @messageDto.UserName 7 | 8 | @messageDto.Text 9 | 10 | 11 | 12 | 13 | 14 | @code 15 | { 16 | MessageDto messageDto { get; set; } 17 | 18 | [Parameter] 19 | public Func Delete { get; set; } 20 | 21 | [Parameter] 22 | public MessageDto Message { get; set; } 23 | 24 | protected override void OnParametersSet() 25 | { 26 | messageDto = Message; 27 | } 28 | 29 | async Task DeleteMessage() 30 | { 31 | await Delete(messageDto); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/Shared/Modules/BlazorBoilerplate.Theme.MudBlazor.Demo/Pages/Forum/ForumMessageCreateForm.razor: -------------------------------------------------------------------------------- 1 | @using BlazorBoilerplate.Shared.Dto.Sample 2 | @using Microsoft.AspNetCore.Components.Forms 3 | 4 | @if (Creating) 5 | { 6 | 7 | } 8 | else 9 | { 10 | 11 | 12 | 13 | 14 | 15 | 16 | Send 17 | 18 | 19 | 20 | } 21 | 22 | @code 23 | { 24 | MessageDto messageDto { get; set; } = new MessageDto(); 25 | 26 | [Parameter] 27 | public Func Send { get; set; } 28 | 29 | bool IsOpened { get; set; } 30 | 31 | bool Creating { get; set; } = false; 32 | 33 | async Task CreateMessage() 34 | { 35 | Creating = true; 36 | StateHasChanged(); 37 | await Send(messageDto); 38 | messageDto.Text = string.Empty; 39 | Creating = false; 40 | StateHasChanged(); 41 | } 42 | } -------------------------------------------------------------------------------- /src/Shared/Modules/BlazorBoilerplate.Theme.MudBlazor.Demo/Shared/Components/DonateButton.razor: -------------------------------------------------------------------------------- 1 | Donate 2 | @code { 3 | 4 | } 5 | -------------------------------------------------------------------------------- /src/Shared/Modules/BlazorBoilerplate.Theme.MudBlazor.Demo/Shared/Components/DragNDrop/Job.razor: -------------------------------------------------------------------------------- 1 | @using BlazorBoilerplate.Shared.Dto.Sample 2 |
  • 3 |

    @JobDto.Description

    4 |

    Last Updated @JobDto.LastUpdated.ToString("HH:mm.ss tt")

    5 |
  • 6 | 7 | @code { 8 | [CascadingParameter] JobsContainer Container { get; set; } 9 | [Parameter] public JobDto JobDto { get; set; } 10 | 11 | private void HandleDragStart(JobDto selectedJob) 12 | { 13 | Container.Payload = selectedJob; 14 | } 15 | } -------------------------------------------------------------------------------- /src/Shared/Modules/BlazorBoilerplate.Theme.MudBlazor.Demo/Shared/Components/DragNDrop/JobsContainer.razor: -------------------------------------------------------------------------------- 1 | @using BlazorBoilerplate.Shared.Dto.Sample 2 |
    3 | 4 | @ChildContent 5 | 6 |
    7 | 8 | @code { 9 | [Parameter] 10 | public List 11 | Jobs 12 | { get; set; } 13 | [Parameter] public RenderFragment ChildContent { get; set; } 14 | [Parameter] 15 | public EventCallback 16 | OnStatusUpdated 17 | { get; set; } 18 | 19 | public JobDto Payload { get; set; } 20 | 21 | public async Task UpdateJobAsync(JobStatuses newStatus) 22 | { 23 | var task = Jobs.SingleOrDefault(x => x.Id == Payload.Id); 24 | 25 | if (task != null) 26 | { 27 | task.Status = newStatus; 28 | task.LastUpdated = DateTime.Now; 29 | await OnStatusUpdated.InvokeAsync(Payload); 30 | } 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/Shared/Modules/BlazorBoilerplate.Theme.MudBlazor.Demo/Shared/Components/DragNDrop/ReportPeriod.razor: -------------------------------------------------------------------------------- 1 | @using BlazorBoilerplate.Shared.Dto.Sample 2 |
  • 3 | @ReportPeriodDto.Title 4 |
  • 5 | 6 | @code { 7 | [CascadingParameter] 8 | ReportPeriodsContainer Container { get; set; } 9 | 10 | [Parameter] 11 | public ReportPeriodDto ReportPeriodDto { get; set; } 12 | 13 | private void HandleDragStart(ReportPeriodDto selectedReportPeriod) 14 | { 15 | Container.Payload = selectedReportPeriod; 16 | } 17 | } -------------------------------------------------------------------------------- /src/Shared/Modules/BlazorBoilerplate.Theme.MudBlazor.Demo/Shared/Components/DragNDrop/ReportPeriodsContainer.razor: -------------------------------------------------------------------------------- 1 | @using BlazorBoilerplate.Shared.Dto.Sample 2 |
    3 | 4 | @ChildContent 5 | 6 |
    7 | 8 | @code { 9 | [Parameter] 10 | public List ReportPeriods { get; set; } 11 | 12 | [Parameter] 13 | public RenderFragment ChildContent { get; set; } 14 | 15 | [Parameter] 16 | public EventCallback OnReportPeriodUpdated { get; set; } 17 | 18 | public ReportPeriodDto Payload { get; set; } 19 | 20 | public DateTime PivotDate = DateTime.MinValue; 21 | 22 | public async Task UpdateReportPeriodAsync(bool isBenchmark, bool isComparison) 23 | { 24 | var task = ReportPeriods.SingleOrDefault(x => x.Id == Payload.Id); 25 | 26 | if (task != null) 27 | { 28 | task.IsBenchmark = isBenchmark; 29 | task.IsComparison = isComparison; 30 | await OnReportPeriodUpdated.InvokeAsync(Payload); 31 | } 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/Shared/Modules/BlazorBoilerplate.Theme.MudBlazor.Demo/Shared/Components/DrawerFooter.razor: -------------------------------------------------------------------------------- 1 | @implements IDynamicComponent 2 | @inject IStringLocalizer L 3 | 4 | 5 | @L["AppHelpAndSupport"] 6 | 7 | 8 | @code { 9 | public int Order { get => 1; } 10 | public string IntoComponent { get => "DrawerFooter"; } 11 | } 12 | -------------------------------------------------------------------------------- /src/Shared/Modules/BlazorBoilerplate.Theme.MudBlazor.Demo/Shared/Components/Footer.razor: -------------------------------------------------------------------------------- 1 | @implements IDynamicComponent 2 | @inject AppState appState 3 | © @DateTime.Now.Year @appState.AppName Version 7.0.17 - Developed by Enkode LLC  4 | and Github Contributors. 5 | 6 | @code { 7 | public int Order { get => 1; } 8 | public string IntoComponent { get => "Footer"; } 9 | } 10 | -------------------------------------------------------------------------------- /src/Shared/Modules/BlazorBoilerplate.Theme.MudBlazor.Demo/Shared/Components/TopRightBarSection.razor: -------------------------------------------------------------------------------- 1 | @implements IDynamicComponent 2 | 3 |
    4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 |
    13 | 14 |
    15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 |
    23 | 24 |
    25 | 26 | @code { 27 | public int Order { get => 1; } 28 | public string IntoComponent { get => "TopRightBarSection"; } 29 | } 30 | -------------------------------------------------------------------------------- /src/Shared/Modules/BlazorBoilerplate.Theme.MudBlazor.Demo/TagHelpers/ThemeTagHelperComponent.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.AspNetCore.Razor.TagHelpers; 2 | 3 | namespace BlazorBoilerplate.Theme.Material.Demo.TagHelpers 4 | { 5 | public class ThemeTagHelperComponent : TagHelperComponent 6 | { 7 | public override int Order => 1; 8 | public override Task ProcessAsync(TagHelperContext context, TagHelperOutput output) 9 | { 10 | var path = typeof(Module).Namespace.Replace("Material", "MudBlazor"); 11 | 12 | if (string.Equals(context.TagName, "head", StringComparison.OrdinalIgnoreCase)) 13 | { 14 | output.PostContent.AppendHtml(@$" 15 | 16 | "); 17 | } 18 | 19 | return Task.CompletedTask; 20 | } 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/Shared/Modules/BlazorBoilerplate.Theme.MudBlazor/BlazorBoilerplate.Theme.MudBlazor.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | net7.0 5 | BlazorBoilerplate.Theme.Material 6 | enable 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /src/Shared/Modules/BlazorBoilerplate.Theme.MudBlazor/Pages/ExternalAuth/Confirm.razor: -------------------------------------------------------------------------------- 1 | @page "/externalauth/confirm" 2 | 3 | @inject AppState appState 4 | @inject NavigationManager navigationManager 5 | @inject HttpClient Http 6 | @inject AuthenticationStateProvider authStateProvider 7 | @inject IStringLocalizer L 8 | @inject IViewNotifier viewNotifier 9 | 10 | 16 | 17 | 18 | @code { 19 | 20 | } 21 | -------------------------------------------------------------------------------- /src/Shared/Modules/BlazorBoilerplate.Theme.MudBlazor/Pages/ExternalAuth/Error.razor: -------------------------------------------------------------------------------- 1 | @inherits ErrorPage 2 | @page "/externalauth/error/{ErrorEnumValue}" 3 | @page "/externalauth/error/{ErrorEnumValue}/{Description}" 4 | 5 | 6 | 14 | 15 | 16 | @code { 17 | 18 | } 19 | -------------------------------------------------------------------------------- /src/Shared/Modules/BlazorBoilerplate.Theme.MudBlazor/Pages/ExternalAuth/Success.razor: -------------------------------------------------------------------------------- 1 | @page "/externalauth/success" 2 | 3 | @attribute [Authorize] 4 | @inject AppState appState 5 | @inject NavigationManager navigationManager 6 | @inject HttpClient Http 7 | @inject AuthenticationStateProvider authStateProvider 8 | @inject IStringLocalizer L 9 | @inject IViewNotifier viewNotifier 10 | 11 | 18 | 19 | 20 | @code { 21 | 22 | 23 | 24 | } 25 | -------------------------------------------------------------------------------- /src/Shared/Modules/BlazorBoilerplate.Theme.MudBlazor/Services/FileUploadEntry.cs: -------------------------------------------------------------------------------- 1 | using BlazorBoilerplate.Shared.Interfaces; 2 | using Microsoft.AspNetCore.Components.Forms; 3 | 4 | namespace BlazorBoilerplate.Theme.Material.Services 5 | { 6 | public class FileUploadEntry : IFileUploadEntry 7 | { 8 | private readonly IBrowserFile fileUploadEntry; 9 | public FileUploadEntry(IBrowserFile fileUploadEntry) 10 | { 11 | this.fileUploadEntry = fileUploadEntry; 12 | } 13 | public string Name => fileUploadEntry.Name; 14 | 15 | public async Task WriteToStreamAsync(Stream stream) 16 | { 17 | var buffer = new byte[fileUploadEntry.Size]; 18 | 19 | await fileUploadEntry.OpenReadStream(104857600).ReadAsync(buffer); 20 | 21 | await stream.WriteAsync(buffer); 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/Shared/Modules/BlazorBoilerplate.Theme.MudBlazor/Services/ViewNotifier.cs: -------------------------------------------------------------------------------- 1 | using BlazorBoilerplate.Shared.Interfaces; 2 | using MudBlazor; 3 | 4 | namespace BlazorBoilerplate.Theme.Material.Services 5 | { 6 | public class ViewNotifier : IViewNotifier 7 | { 8 | private readonly ISnackbar snackbar; 9 | public ViewNotifier(ISnackbar snackbar) 10 | { 11 | this.snackbar = snackbar; 12 | } 13 | public void Show(string message, ViewNotifierType type, string title = null, string icon = null) 14 | { 15 | var snackType = Severity.Success; 16 | 17 | switch (type) 18 | { 19 | case ViewNotifierType.Error: 20 | snackType = Severity.Error; 21 | break; 22 | case ViewNotifierType.Warning: 23 | snackType = Severity.Warning; 24 | break; 25 | case ViewNotifierType.Info: 26 | snackType = Severity.Info; 27 | break; 28 | } 29 | 30 | if (!string.IsNullOrWhiteSpace(title)) 31 | message = $"{title}
    {message}"; 32 | 33 | snackbar.Add(message, snackType, config => 34 | { 35 | if (icon != null) 36 | config.Icon = icon; 37 | }); 38 | } 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/Shared/Modules/BlazorBoilerplate.Theme.MudBlazor/Shared/Components/AuthorizingInProgress.razor: -------------------------------------------------------------------------------- 1 | @inject IStringLocalizer L 2 | 3 | 4 | -------------------------------------------------------------------------------- /src/Shared/Modules/BlazorBoilerplate.Theme.MudBlazor/Shared/Components/Breadcrumb.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.AspNetCore.Components; 2 | 3 | namespace BlazorBoilerplate.Theme.Material.Shared.Components 4 | { 5 | public partial class Breadcrumb : ComponentBase, IDisposable 6 | { 7 | [CascadingParameter] 8 | protected internal Breadcrumbs Parent { get; set; } 9 | 10 | [Parameter] 11 | public string Link { get; set; } 12 | 13 | [Parameter] 14 | public string Title { get; set; } 15 | 16 | protected override void OnInitialized() 17 | { 18 | Parent.Items.Add(this); 19 | } 20 | 21 | public void Dispose() 22 | { 23 | Parent.Items.Remove(this); 24 | } 25 | 26 | public static Breadcrumb New(string link, string title) => new Breadcrumb { Link = link, Title = title }; 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/Shared/Modules/BlazorBoilerplate.Theme.MudBlazor/Shared/Components/Breadcrumbs.razor: -------------------------------------------------------------------------------- 1 |  2 | 18 | 19 | -------------------------------------------------------------------------------- /src/Shared/Modules/BlazorBoilerplate.Theme.MudBlazor/Shared/Components/Breadcrumbs.razor.cs: -------------------------------------------------------------------------------- 1 | using BlazorBoilerplate.Shared.Localizer; 2 | using Microsoft.AspNetCore.Components; 3 | using Microsoft.Extensions.Localization; 4 | 5 | namespace BlazorBoilerplate.Theme.Material.Shared.Components 6 | { 7 | public partial class Breadcrumbs : ComponentBase 8 | { 9 | [Parameter] 10 | public RenderFragment ChildContent { get; set; } 11 | 12 | [Parameter] 13 | public bool IncludeRoot { get; set; } = true; 14 | 15 | protected internal List Items = new(); 16 | 17 | [Inject] protected IStringLocalizer L { get; set; } 18 | 19 | protected override void OnInitialized() 20 | { 21 | if (IncludeRoot) 22 | Items.Insert(0, Breadcrumb.New("/", L["BreadCrumbHome"])); 23 | } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/Shared/Modules/BlazorBoilerplate.Theme.MudBlazor/Shared/Components/Breadcrumbs.razor.css: -------------------------------------------------------------------------------- 1 | ul.breadcrumb { 2 | padding: 10px 16px; 3 | list-style: none; 4 | } 5 | 6 | /* Add a slash symbol (/) before/behind each list item */ 7 | ul.breadcrumb li + li:before { 8 | padding: 8px; 9 | content: "›"; 10 | } 11 | 12 | ul.breadcrumb li, 13 | ul.breadcrumb li a { 14 | text-transform: uppercase; 15 | text-shadow: none; 16 | font-size: 13px; 17 | text-decoration: none; 18 | display: inline; 19 | } 20 | 21 | ul.breadcrumb li a:hover { 22 | text-decoration: underline; 23 | } 24 | -------------------------------------------------------------------------------- /src/Shared/Modules/BlazorBoilerplate.Theme.MudBlazor/Shared/Components/DrawerFooter.razor: -------------------------------------------------------------------------------- 1 | @inherits DynamicComponentContainer 2 |
    3 | @foreach (var component in components) 4 | { 5 | @CreateDynamicComponent(component); 6 | } 7 |
    8 | @code { 9 | 10 | } 11 | -------------------------------------------------------------------------------- /src/Shared/Modules/BlazorBoilerplate.Theme.MudBlazor/Shared/Components/DynamicComponentContainer.razor: -------------------------------------------------------------------------------- 1 | @using Microsoft.Extensions.DependencyInjection 2 | @inherits OwningComponentBase 3 | @functions { 4 | protected RenderFragment CreateDynamicComponent(IDynamicComponent component) => builder => 5 | { 6 | builder.OpenComponent(0, component.GetType()); 7 | builder.CloseComponent(); 8 | }; 9 | } 10 | @code { 11 | protected IEnumerable components { get; set; } 12 | 13 | protected override void OnInitialized() 14 | { 15 | components = ScopedServices.GetServices().Where(i => i.IntoComponent == GetType().Name).OrderBy(i => i.Order); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/Shared/Modules/BlazorBoilerplate.Theme.MudBlazor/Shared/Components/Footer.razor: -------------------------------------------------------------------------------- 1 | @inherits DynamicComponentContainer 2 |
    3 | @foreach (var component in components) 4 | { 5 | @CreateDynamicComponent(component); 6 | } 7 |
    8 | @code { 9 | 10 | } 11 | -------------------------------------------------------------------------------- /src/Shared/Modules/BlazorBoilerplate.Theme.MudBlazor/Shared/Components/LoadingBackground.razor: -------------------------------------------------------------------------------- 1 | 
    2 | 3 | @ChildContent 4 |
    5 | 6 | @code { 7 | 8 | [Parameter] 9 | public RenderFragment ChildContent { get; set; } 10 | } 11 | -------------------------------------------------------------------------------- /src/Shared/Modules/BlazorBoilerplate.Theme.MudBlazor/Shared/Components/MudValidationSummary.razor: -------------------------------------------------------------------------------- 1 | @inherits ValidationSummaryBase 2 | 3 | 4 | @foreach (var message in CurrentEditContext.GetValidationMessages()) 5 | { 6 | @message 7 | } 8 | 9 | @code { 10 | 11 | } -------------------------------------------------------------------------------- /src/Shared/Modules/BlazorBoilerplate.Theme.MudBlazor/Shared/Components/NavMenu.razor: -------------------------------------------------------------------------------- 1 | @inherits DynamicComponentContainer 2 | 3 | @foreach (var component in components) 4 | { 5 | @CreateDynamicComponent(component); 6 | } 7 | 8 | @code { 9 | 10 | } 11 | -------------------------------------------------------------------------------- /src/Shared/Modules/BlazorBoilerplate.Theme.MudBlazor/Shared/Components/PageNotFound.razor: -------------------------------------------------------------------------------- 1 | @inject IStringLocalizer L 2 | 3 |
    4 | 5 |

    @L["This address does not exist"]

    6 |
    -------------------------------------------------------------------------------- /src/Shared/Modules/BlazorBoilerplate.Theme.MudBlazor/Shared/Components/TopRightBarSection.razor: -------------------------------------------------------------------------------- 1 | @inherits DynamicComponentContainer 2 | 3 | @foreach (var component in components) 4 | { 5 | @CreateDynamicComponent(component); 6 | } 7 | 8 | @code { 9 | 10 | } 11 | -------------------------------------------------------------------------------- /src/Shared/Modules/BlazorBoilerplate.Theme.MudBlazor/Shared/Components/UserNotAuthorized.razor: -------------------------------------------------------------------------------- 1 | @inject IStringLocalizer L 2 | 3 | @* 4 | 5 | 6 | @L["EnableTwoFactorAuthentication"] 7 | 8 | *@ 9 | 10 |
    11 | 12 |

    @L["You are not authorized to access this page"]

    13 |
    14 | 15 | -------------------------------------------------------------------------------- /src/Shared/Modules/BlazorBoilerplate.Theme.MudBlazor/Shared/Components/UserProfile.razor.css: -------------------------------------------------------------------------------- 1 | .drawer-profile { 2 | clip-path: inset(0); 3 | padding: 16px; 4 | border-bottom: solid 1px #777; 5 | color: #fff; 6 | font-size: 12px; 7 | } 8 | 9 | .drawer-profile a, .drawer-profile ::deep.mud-icon-button-label { 10 | color: #fff; 11 | } 12 | -------------------------------------------------------------------------------- /src/Shared/Modules/BlazorBoilerplate.Theme.MudBlazor/Shared/Layouts/LoginLayout.razor: -------------------------------------------------------------------------------- 1 | @inherits LayoutComponentBase 2 | 3 |
    4 |
    5 |
    6 |
    7 | 12 | 13 | -------------------------------------------------------------------------------- /src/Shared/Modules/BlazorBoilerplate.Theme.MudBlazor/Shared/Layouts/LoginLayout.razor.css: -------------------------------------------------------------------------------- 1 | .login-container { 2 | } 3 | 4 | .login-body { 5 | min-width: 400px; 6 | } 7 | 8 | .login-body ::deep.mud-expansion-panels .mud-expand-panel-header { 9 | flex-basis: 80%; 10 | } 11 | 12 | .login-body ::deep.mud-expansion-panels { 13 | background-color: #f4f4f4 !important; 14 | } 15 | -------------------------------------------------------------------------------- /src/Shared/Modules/BlazorBoilerplate.Theme.MudBlazor/Shared/Layouts/MainLayout.razor.css: -------------------------------------------------------------------------------- 1 | .hidden-mdc-down { 2 | white-space:nowrap; 3 | } -------------------------------------------------------------------------------- /src/Shared/Modules/BlazorBoilerplate.Theme.MudBlazor/TagHelpers/AppTagHelperComponentTagHelper.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.AspNetCore.Razor.TagHelpers; 2 | 3 | namespace BlazorBoilerplate.Theme.Material.TagHelpers 4 | { 5 | public class AppTagHelperComponent : TagHelperComponent 6 | { 7 | public override Task ProcessAsync(TagHelperContext context, TagHelperOutput output) 8 | { 9 | if (string.Equals(context.TagName, "app", 10 | StringComparison.OrdinalIgnoreCase) && 11 | output.Attributes.ContainsName("wasm")) 12 | { 13 | output.PostContent.AppendHtml(@$" 14 |
    15 |
    16 |
    17 |
    18 |
    19 |
    20 | Loading BlazorBoilerplate WebAssemblies ... 21 |
    "); 22 | } 23 | 24 | return Task.CompletedTask; 25 | } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/Shared/Modules/BlazorBoilerplate.Theme.MudBlazor/wwwroot/images/apple-touch-icon-114x114.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/enkodellc/blazorboilerplate/90860470a5246949d0fe15b19e6f48154edcdf87/src/Shared/Modules/BlazorBoilerplate.Theme.MudBlazor/wwwroot/images/apple-touch-icon-114x114.png -------------------------------------------------------------------------------- /src/Shared/Modules/BlazorBoilerplate.Theme.MudBlazor/wwwroot/images/apple-touch-icon-120x120.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/enkodellc/blazorboilerplate/90860470a5246949d0fe15b19e6f48154edcdf87/src/Shared/Modules/BlazorBoilerplate.Theme.MudBlazor/wwwroot/images/apple-touch-icon-120x120.png -------------------------------------------------------------------------------- /src/Shared/Modules/BlazorBoilerplate.Theme.MudBlazor/wwwroot/images/apple-touch-icon-144x144.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/enkodellc/blazorboilerplate/90860470a5246949d0fe15b19e6f48154edcdf87/src/Shared/Modules/BlazorBoilerplate.Theme.MudBlazor/wwwroot/images/apple-touch-icon-144x144.png -------------------------------------------------------------------------------- /src/Shared/Modules/BlazorBoilerplate.Theme.MudBlazor/wwwroot/images/apple-touch-icon-152x152.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/enkodellc/blazorboilerplate/90860470a5246949d0fe15b19e6f48154edcdf87/src/Shared/Modules/BlazorBoilerplate.Theme.MudBlazor/wwwroot/images/apple-touch-icon-152x152.png -------------------------------------------------------------------------------- /src/Shared/Modules/BlazorBoilerplate.Theme.MudBlazor/wwwroot/images/apple-touch-icon-180x180.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/enkodellc/blazorboilerplate/90860470a5246949d0fe15b19e6f48154edcdf87/src/Shared/Modules/BlazorBoilerplate.Theme.MudBlazor/wwwroot/images/apple-touch-icon-180x180.png -------------------------------------------------------------------------------- /src/Shared/Modules/BlazorBoilerplate.Theme.MudBlazor/wwwroot/images/apple-touch-icon-57x57.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/enkodellc/blazorboilerplate/90860470a5246949d0fe15b19e6f48154edcdf87/src/Shared/Modules/BlazorBoilerplate.Theme.MudBlazor/wwwroot/images/apple-touch-icon-57x57.png -------------------------------------------------------------------------------- /src/Shared/Modules/BlazorBoilerplate.Theme.MudBlazor/wwwroot/images/apple-touch-icon-72x72.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/enkodellc/blazorboilerplate/90860470a5246949d0fe15b19e6f48154edcdf87/src/Shared/Modules/BlazorBoilerplate.Theme.MudBlazor/wwwroot/images/apple-touch-icon-72x72.png -------------------------------------------------------------------------------- /src/Shared/Modules/BlazorBoilerplate.Theme.MudBlazor/wwwroot/images/apple-touch-icon-76x76.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/enkodellc/blazorboilerplate/90860470a5246949d0fe15b19e6f48154edcdf87/src/Shared/Modules/BlazorBoilerplate.Theme.MudBlazor/wwwroot/images/apple-touch-icon-76x76.png -------------------------------------------------------------------------------- /src/Shared/Modules/BlazorBoilerplate.Theme.MudBlazor/wwwroot/images/apple-touch-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/enkodellc/blazorboilerplate/90860470a5246949d0fe15b19e6f48154edcdf87/src/Shared/Modules/BlazorBoilerplate.Theme.MudBlazor/wwwroot/images/apple-touch-icon.png -------------------------------------------------------------------------------- /src/Shared/Modules/BlazorBoilerplate.Theme.MudBlazor/wwwroot/images/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/enkodellc/blazorboilerplate/90860470a5246949d0fe15b19e6f48154edcdf87/src/Shared/Modules/BlazorBoilerplate.Theme.MudBlazor/wwwroot/images/favicon.ico -------------------------------------------------------------------------------- /src/Shared/Modules/BlazorBoilerplate.Theme.MudBlazor/wwwroot/images/logo-title.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/enkodellc/blazorboilerplate/90860470a5246949d0fe15b19e6f48154edcdf87/src/Shared/Modules/BlazorBoilerplate.Theme.MudBlazor/wwwroot/images/logo-title.png -------------------------------------------------------------------------------- /src/Shared/Modules/BlazorBoilerplate.Theme.MudBlazor/wwwroot/images/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/enkodellc/blazorboilerplate/90860470a5246949d0fe15b19e6f48154edcdf87/src/Shared/Modules/BlazorBoilerplate.Theme.MudBlazor/wwwroot/images/logo.png -------------------------------------------------------------------------------- /src/Shared/Modules/BlazorBoilerplate.Theme.MudBlazor/wwwroot/images/preloader.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/enkodellc/blazorboilerplate/90860470a5246949d0fe15b19e6f48154edcdf87/src/Shared/Modules/BlazorBoilerplate.Theme.MudBlazor/wwwroot/images/preloader.gif -------------------------------------------------------------------------------- /src/Tests/BlazorBoilerplate.IdentityServer.Test1/BlazorBoilerplate.IdentityServer.Test1.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | Exe 5 | net7.0 6 | enable 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /src/Tests/BlazorBoilerplate.IdentityServer.Test2/BlazorBoilerplate.IdentityServer.Test2.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | Exe 5 | net7.0 6 | enable 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /src/Tests/BlazorBoilerplate.IdentityServer.Test3/BlazorBoilerplate.IdentityServer.Test3.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | Exe 5 | net7.0 6 | enable 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /src/Utils/BlazorBoilerplate.SourceGenerator/BlazorBoilerplate.SourceGenerator.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | netstandard2.0 5 | 8.0 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | $(GetTargetPathDependsOn);GetDependencyTargetPaths 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /src/Utils/BlazorBoilerplate.SourceGenerator/CrossPlatform.cs: -------------------------------------------------------------------------------- 1 | using System.IO; 2 | using System.Linq; 3 | namespace BlazorBoilerplate.SourceGenerator 4 | { 5 | public static class CrossPlatform 6 | { 7 | public static string PathCombine(string basePath, params string[] additional) 8 | { 9 | var splits = additional.Select(s => s.Split(pathSplitCharacters)).ToArray(); 10 | var totalLength = splits.Sum(arr => arr.Length); 11 | var segments = new string[totalLength + 1]; 12 | segments[0] = basePath; 13 | var i = 0; 14 | foreach (var split in splits) 15 | { 16 | foreach (var value in split) 17 | { 18 | i++; 19 | segments[i] = value; 20 | } 21 | } 22 | return Path.Combine(segments); 23 | } 24 | 25 | static char[] pathSplitCharacters = new char[] { '/', '\\' }; 26 | } 27 | } -------------------------------------------------------------------------------- /src/Utils/BlazorBoilerplate.SourceGenerator/EntityGeneratorConfig.cs: -------------------------------------------------------------------------------- 1 | namespace BlazorBoilerplate.SourceGenerator 2 | { 3 | public class EntityGeneratorConfig 4 | { 5 | public string EntitiesPath { get; set; } 6 | 7 | public bool GenEntities { get; set; } 8 | public bool GenInterfaces { get; set; } 9 | 10 | public bool EntityWithInterface { get; set; } 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /src/Utils/Docker/.dockerignore: -------------------------------------------------------------------------------- 1 | **/.classpath 2 | **/.dockerignore 3 | **/.env 4 | **/.git 5 | **/.gitignore 6 | **/.project 7 | **/.settings 8 | **/.toolstarget 9 | **/.vs 10 | **/.vscode 11 | **/*.*proj.user 12 | **/*.dbmdl 13 | **/*.jfm 14 | **/azds.yaml 15 | **/bin 16 | **/charts 17 | **/docker-compose* 18 | **/Dockerfile* 19 | **/node_modules 20 | **/npm-debug.log 21 | **/obj 22 | **/secrets.dev.yaml 23 | **/values.dev.yaml 24 | LICENSE 25 | README.md -------------------------------------------------------------------------------- /src/Utils/Docker/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM mcr.microsoft.com/dotnet/aspnet:5.0.13-buster-slim AS base 2 | WORKDIR / 3 | EXPOSE 443 4 | EXPOSE 80 5 | 6 | FROM mcr.microsoft.com/dotnet/sdk:5.0.402-buster-slim AS build 7 | WORKDIR / 8 | COPY . . 9 | RUN dotnet restore "src/Server/BlazorBoilerplate.Server/BlazorBoilerplate.Server.csproj" 10 | WORKDIR "/src/Server/BlazorBoilerplate.Server" 11 | RUN dotnet build "BlazorBoilerplate.Server.csproj" -c Release -o /app/build --no-restore 12 | 13 | FROM build AS publish 14 | RUN dotnet publish "BlazorBoilerplate.Server.csproj" -c Release -o /app/publish 15 | RUN dotnet dev-certs https --clean 16 | RUN dotnet dev-certs https -ep /app/publish/aspnetapp.pfx -p Admin123 17 | #if .pfx was provided from certificate authority uncomment the below 18 | #COPY src/Server/BlazorBoilerplate.Server/AuthSample.pfx /app/publish/aspnetapp.pfx 19 | 20 | FROM base AS final 21 | WORKDIR /app 22 | COPY --from=publish /app/publish . 23 | COPY --from=publish /app/publish/aspnetapp.pfx ./AuthSample.pfx 24 | ENTRYPOINT ["dotnet", "BlazorBoilerplate.Server.dll"] 25 | -------------------------------------------------------------------------------- /src/Utils/Microk8s/blazorboilerplate-config.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | data: 3 | ASPNETCORE_ENVIRONMENT: Development 4 | ASPNETCORE_Kestrel__Certificates__Default__Password: Admin123 5 | ASPNETCORE_Kestrel__Certificates__Default__Path: aspnetapp.pfx 6 | ASPNETCORE_URLS: https://+:443;http://+80 7 | BlazorBoilerplate__ApplicationUrl: blazorboilerplate 8 | BlazorBoilerplate__CertificatePassword: Admin123 9 | BlazorBoilerplate__IS4ApplicationUrl: blazorboilerplate 10 | BlazorBoilerplate__UseSqlServer: "true" 11 | ConnectionStrings__DefaultConnection: Server=sqlserver;Database=blazor_boilerplate;Trusted_Connection=True;MultipleActiveResultSets=true;User=sa;Password=yourVeryStrong(!)Password;Integrated Security=false 12 | Serilog__MinimumLevel__Default: Debug 13 | kind: ConfigMap 14 | metadata: 15 | name: blazorboilerplate-config 16 | namespace: default -------------------------------------------------------------------------------- /src/Utils/Microk8s/sqlserver-config.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | data: 3 | ACCEPT_EULA: "Y" 4 | SA_PASSWORD: yourVeryStrong(!)Password 5 | kind: ConfigMap 6 | metadata: 7 | name: sqlserver-config 8 | namespace: default 9 | -------------------------------------------------------------------------------- /src/Utils/Scripts/addTenantBindings.cmd: -------------------------------------------------------------------------------- 1 | @echo Add bindings in src\.vs\BlazorBoilerplate\applicationhost.config too 2 | @echo "" 3 | @echo "" 4 | @echo ************************************************************************ 5 | @echo Add 127.0.0.1 tenant1.local tenant2.local to file hosts 6 | @echo ************************************************************************ 7 | netsh http add urlacl url=http://localhost:53414/ user=everyone 8 | pause 9 | netsh http add urlacl url=http://tenant1.local:53414/ user=everyone 10 | pause 11 | netsh http add urlacl url=http://tenant2.local:53414/ user=everyone 12 | pause -------------------------------------------------------------------------------- /src/Utils/Scripts/ctag.cmd: -------------------------------------------------------------------------------- 1 | rem 2 | rem useage: ctag newtag oldtag 3 | rem 4 | git tag %1 %2 5 | git tag -d %2 6 | git push origin :refs/tags/%2 7 | git push --tags 8 | -------------------------------------------------------------------------------- /src/Utils/Scripts/delObjBin.ps1: -------------------------------------------------------------------------------- 1 | Get-ChildItem ..\..\ -include bin,obj -Recurse | foreach ($_) { remove-item $_.fullname -Force -Recurse } -------------------------------------------------------------------------------- /src/Utils/Scripts/ef-migrations-in-vs.txt: -------------------------------------------------------------------------------- 1 | Add-Migration -StartupProject "BlazorBoilerplate.Server" -Project "BlazorBoilerplate.Storage" -Name CreateLocalizationDb -Context LocalizationDbContext -Verbose -OutputDir "Migrations/LocalizationDb" 2 | Add-Migration -StartupProject "BlazorBoilerplate.Server" -Project "BlazorBoilerplate.Storage" -Name CreateTenantStoreDb -Context TenantStoreDbContext -Verbose -OutputDir "Migrations/TenantStoreDb" 3 | Add-Migration -StartupProject "BlazorBoilerplate.Server" -Project "BlazorBoilerplate.Storage" -Name CreateApplicationDb -Context ApplicationDbContext -Verbose -OutputDir "Migrations/ApplicationDb" 4 | -------------------------------------------------------------------------------- /src/Utils/Scripts/ef-migrations.cmd: -------------------------------------------------------------------------------- 1 | rem dotnet tool install -g dotnet-ef 2 | rem dotnet tool update -g dotnet-ef 3 | 4 | rem Microsoft.EntityFrameworkCore.Design package must be preset in the following project 5 | cd ..\..\Server\BlazorBoilerplate.Storage 6 | 7 | dotnet ef --startup-project ../BlazorBoilerplate.Server/ migrations add CreateLocalizationDb -c LocalizationDbContext --verbose --no-build --configuration Debug -o "Migrations/LocalizationDb" 8 | dotnet ef --startup-project ../BlazorBoilerplate.Server/ migrations add CreateTenantStoreDb -c TenantStoreDbContext --verbose --no-build --configuration Debug -o "Migrations/TenantStoreDb" 9 | dotnet ef --startup-project ../BlazorBoilerplate.Server/ migrations add CreateApplicationDb -c ApplicationDbContext --verbose --no-build --configuration Debug -o "Migrations/ApplicationDb" 10 | pause 11 | rem The following command revert db to previous migration in this case 20200326012204_DbLogging, just to test new migration on existing populated tables 12 | rem dotnet ef --startup-project ../BlazorBoilerplate.Server/ database update 20200326012204_DbLogging -c ApplicationDbContext --verbose --no-build --configuration Debug_SSB -------------------------------------------------------------------------------- /src/Utils/Scripts/makeTemplate.cmd: -------------------------------------------------------------------------------- 1 | dotnet new -i ..\..\ 2 | pause 3 | -------------------------------------------------------------------------------- /src/Utils/Scripts/sphinx-prepare-docs-localization.cmd: -------------------------------------------------------------------------------- 1 | cd ..\..\..\docs 2 | sphinx-build -b gettext . _build/gettext 3 | sphinx-intl update -p _build/gettext -l de_DE -------------------------------------------------------------------------------- /src/Utils/Scripts/startLocal.cmd: -------------------------------------------------------------------------------- 1 | cd ..\..\Server\BlazorBoilerplate.Server 2 | dotnet run --launch-profile Kestrel -------------------------------------------------------------------------------- /src/Utils/Terraform/AWS/.gitignore: -------------------------------------------------------------------------------- 1 | .terraform 2 | terraform.tfstate 3 | terraform.tfstate.backup 4 | .terraform.lock.hcl 5 | .terraform.tfstate.lock.info 6 | -------------------------------------------------------------------------------- /src/Utils/Terraform/AWS/bash.tmpl: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | sudo dd if=/dev/zero of=/swapfile bs=1M count=2048 3 | sudo mkswap /swapfile 4 | sudo chmod 600 /swapfile 5 | sudo swapon /swapfile 6 | if ! grep -q 'init-poky' /etc/fstab ; then 7 | sudo echo '# init-poky' >> /etc/fstab 8 | sudo echo '/swapfile swap swap defaults 0 0' >> /etc/fstab 9 | fi 10 | sudo apt update -y 11 | sudo apt-get install apt-transport-https ca-certificates curl gnupg lsb-release -y 12 | curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg 13 | echo "deb [arch=amd64 signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null 14 | sudo apt-get update -y 15 | sudo apt-get install docker-ce docker-ce-cli containerd.io docker-compose -y 16 | echo "{\"log-driver\": \"json-file\",\"log-opts\": {\"max-size\": \"20m\", \"max-file\": \"3\"}}" > /etc/docker/daemon.json 17 | sudo systemctl enable docker 18 | sudo systemctl start docker 19 | echo "${docker_compose}" > /opt/docker-compose.yml 20 | sudo docker-compose -f /opt/docker-compose.yml up -d 21 | -------------------------------------------------------------------------------- /src/Utils/Terraform/Azure/.gitignore: -------------------------------------------------------------------------------- 1 | .terraform 2 | terraform.tfstate 3 | terraform.tfstate.backup 4 | .terraform.lock.hcl 5 | .terraform.tfstate.lock.info 6 | --------------------------------------------------------------------------------