├── ZauberCMS.Template ├── template │ ├── ZauberCMSTemplate.Site │ │ ├── wwwroot │ │ │ └── .gitkeep │ │ ├── Program.cs │ │ ├── Properties │ │ │ └── launchSettings.json │ │ └── ZauberCMSTemplate.Site.csproj │ ├── ZauberCMSTemplate.sln │ └── .template.config │ │ └── template.json ├── images │ └── logo.png └── LICENSE ├── ZauberCMS ├── Components │ ├── Pages │ │ └── Index.razor │ ├── Routes.razor │ └── _Imports.razor └── ZauberCMS.targets ├── ZauberCMS.Web ├── app.db ├── wwwroot │ └── assets │ │ ├── favicon.ico │ │ └── img │ │ ├── about-bg.jpg │ │ ├── home-bg.jpg │ │ ├── post-bg.jpg │ │ ├── contact-bg.jpg │ │ └── post-sample-image.jpg ├── ZauberCMS.Web.csproj.user ├── ContentBlockPreviews │ ├── Image.razor │ ├── Quote.razor │ ├── RichTextEditor.razor │ └── FAQItem.razor ├── Layouts │ └── MainLayout.razor.css ├── Shared │ └── BlogPostPreview.razor ├── ContentBlocks │ ├── RTEBlock.razor │ ├── QuoteBlock.razor │ └── ImageBlock.razor ├── Program.cs └── ZauberCMS.Web.csproj ├── ZauberCMS.Components ├── SharedResource.cs ├── wwwroot │ └── img │ │ ├── hat.jpg │ │ └── zauber-logo.svg ├── Admin │ ├── _Imports.razor │ ├── SettingsSection │ │ └── Navigation │ │ │ ├── SettingsTree.razor │ │ │ ├── SettingsAdvancedNavGroup.cs │ │ │ ├── SettingsLanguageNavGroup.cs │ │ │ ├── SettingsNavGroup.cs │ │ │ └── SettingsAdvancedTree.razor │ ├── Layout │ │ ├── SectionLayout.razor.css │ │ ├── ProfileMenuItem.razor │ │ ├── UserProfile.razor │ │ └── SectionLinks.razor │ ├── MediaSection │ │ ├── Navigation │ │ │ └── MediaNavGroup.cs │ │ ├── MediaIndex.razor │ │ ├── Buttons │ │ │ └── CreateMediaButtons.razor │ │ └── CreateMedia.razor │ ├── UsersSection │ │ ├── Navigation │ │ │ └── UsersNavGroup.cs │ │ └── UsersIndex.razor │ ├── StructureSection │ │ ├── Navigation │ │ │ ├── CompositionsNavGroup.cs │ │ │ ├── ContentTypesNavGroup.cs │ │ │ └── ElementTypesNavGroup.cs │ │ ├── Dialogs │ │ │ └── ChangeTab.razor │ │ └── StructureIndex.razor │ ├── ContentSection │ │ ├── Navigation │ │ │ └── ContentNavGroup.cs │ │ ├── Dialogs │ │ │ └── UnpublishedContentList.razor │ │ └── ContentIndex.razor │ ├── Dashboards │ │ └── StructureInfoDashboard.razor │ └── Shared │ │ ├── Dialogs │ │ └── ChangeAlias.razor │ │ └── ExtendedDataEditor.razor ├── Shared │ ├── PageScript.razor │ ├── SortableList.razor.css │ ├── PropertyInfo.razor │ ├── ZauberLogo.razor │ ├── SortableList.razor.js │ └── TreeButton.razor ├── Seo │ ├── Models │ │ ├── SeoConstants.cs │ │ └── SeoSitemap.cs │ ├── Navigation │ │ └── SettingsSeoNavGroup.cs │ ├── PageChecker.razor │ └── Startup │ │ └── SeoSitemapStartUp.cs ├── Editors │ ├── Models │ │ ├── TextContentSettingsModel.cs │ │ ├── TagPropertySettingsModel.cs │ │ ├── RatingPropertySettingsModel.cs │ │ ├── ColourThemePickerSettings.cs │ │ ├── ListManagerItem.cs │ │ ├── BlockListEditorSettingsModel.cs │ │ ├── MediaPickerSettings.cs │ │ ├── ContentPickerSettings.cs │ │ ├── GoogleMapsSettingsModel.cs │ │ ├── DatePickerPropertySettingsModel.cs │ │ ├── NumericPropertySettingsModel.cs │ │ ├── ZauberCMSEditorSettingsModel.cs │ │ ├── ListPropertySettingsModel.cs │ │ ├── EditorNotesSettingsModel.cs │ │ └── CodeEditorPropertySettingsModel.cs │ ├── Dialogs │ │ ├── EditorNotesDialog.razor │ │ └── Models │ │ │ └── ContentLinkResult.cs │ ├── MultipleMediaUpload.razor.js │ └── RadioButtonListProperty.razor ├── Account │ └── Shared │ │ └── RedirectToLogin.razor ├── ContentComponents │ └── ContentBlockPreviewFallback.razor ├── package.json ├── tailwind.config.js ├── Pages │ ├── MissingView.razor │ ├── NotFound404.razor │ ├── NewSite.razor.css │ └── NewSite.razor ├── ContextMenus │ ├── ITreeContextMenu.cs │ └── SectionNavGroups │ │ ├── CreateMediaNavMenu.cs │ │ ├── CreateContentNavMenu.cs │ │ ├── CreateMediaFolderNavMenu.cs │ │ ├── CreateContentTypeFolder.cs │ │ ├── CreateCompositionFolder.cs │ │ ├── CreateElementTypeFolder.cs │ │ ├── CreateCompositionNavMenu.cs │ │ ├── CreateContentTypeNavMenu.cs │ │ └── CreateElementTypeNavMenu.cs ├── Controllers │ └── AuthController.cs └── Resources │ └── SharedResource.resx ├── ZauberCMS.Routing ├── Views │ ├── _ViewImports.cshtml │ ├── ZauberRender │ │ └── Index.cshtml │ └── Shared │ │ ├── Components │ │ ├── RenderBlocks │ │ │ ├── RenderBlocksModel.cs │ │ │ ├── Default.cshtml │ │ │ └── RenderBlocksViewComponent.cs │ │ └── BootstrapPager │ │ │ ├── BootstrapPagerViewComponent.cs │ │ │ └── Default.cshtml │ │ └── _ZauberLayout.cshtml ├── _Imports.razor └── CatchAll.razor ├── ZauberCMS.Core ├── Rendering │ ├── IZauberViewPage.cs │ └── ZauberViewPage.cs ├── Data │ ├── Interfaces │ │ ├── IMsSqlMigration.cs │ │ ├── ISQLiteMigration.cs │ │ ├── ISeedData.cs │ │ ├── IQueryModel.cs │ │ └── IDataService.cs │ ├── Parameters │ │ ├── SaveGlobalDataParameters.cs │ │ ├── GetGlobalDataParameters.cs │ │ ├── MultiQueryParameters.cs │ │ └── DataGridParameters.cs │ ├── Models │ │ ├── GlobalData.cs │ │ └── QueryModel.cs │ ├── Mapping │ │ └── GlobalDataDbMapping.cs │ ├── ZauberDbContext.cs │ ├── PostgreSqlZauberDbContext.cs │ └── SqliteZauberDbContext.cs ├── Content │ ├── Parameters │ │ ├── CachedDomainsParameters.cs │ │ ├── GetContentLanguagesParameters.cs │ │ ├── HasChildContentParameters.cs │ │ ├── SaveDomainParameters.cs │ │ ├── HasChildContentTypeParameters.cs │ │ ├── SaveContentTypeParameters.cs │ │ ├── GetContentTypeParameters.cs │ │ ├── DeleteContentParameters.cs │ │ ├── DeleteContentTypeParameters.cs │ │ ├── ClearUnpublishedContentParameters.cs │ │ ├── CleanupOrphanedRelatedContentParameters.cs │ │ ├── DeleteDomainParameters.cs │ │ ├── GetDomainParameters.cs │ │ ├── CopyContentParameters.cs │ │ ├── DataGridContentParameters.cs │ │ ├── GetContentFromRequestParameters.cs │ │ ├── SaveContentParameters.cs │ │ ├── GetContentParameters.cs │ │ └── QueryDomainParameters.cs │ ├── Interfaces │ │ ├── IHasPropertyValues.cs │ │ ├── IContentBlock.cs │ │ ├── IContent.cs │ │ ├── ICustomContentComponent.cs │ │ ├── IContentBlockPreview.cs │ │ ├── IContentBlockView.cs │ │ ├── IPropertyValue.cs │ │ ├── IContentFinder.cs │ │ ├── IContentPropertySettings.cs │ │ ├── IContentView.cs │ │ ├── IContentProperty.cs │ │ └── IDataListSource.cs │ ├── Models │ │ ├── DataListItem.cs │ │ ├── EntryContentResult.cs │ │ ├── EntryModel.cs │ │ ├── BlockListChanges.cs │ │ ├── UnpublishedContent.cs │ │ └── ContentPropertyValue.cs │ ├── Mapping │ │ ├── ContentPropertyValueDbMapping.cs │ │ ├── DomainDbMapping.cs │ │ └── UnpublishedContentDbMapping.cs │ ├── Validation │ │ └── ValidateContentType.cs │ └── ContentFinders │ │ └── ContentFinderPipeline.cs ├── Membership │ ├── Interfaces │ │ └── IAccountLayout.cs │ ├── Models │ │ ├── RoleClaim.cs │ │ ├── UserClaim.cs │ │ ├── UserLogin.cs │ │ ├── UserToken.cs │ │ ├── Permission.cs │ │ ├── UserRole.cs │ │ ├── MediaRole.cs │ │ ├── ContentRole.cs │ │ ├── AuthenticationResult.cs │ │ ├── Privilage.cs │ │ └── UserPropertyValue.cs │ ├── Parameters │ │ ├── SaveRoleParameters.cs │ │ ├── GetUserParameters.cs │ │ ├── GetRoleParameters.cs │ │ ├── DeleteRoleParameters.cs │ │ ├── DeleteUserParameters.cs │ │ ├── ConfirmEmailParameters.cs │ │ ├── ForgotPasswordParameters.cs │ │ ├── SaveUserParameters.cs │ │ ├── ExternalLoginParameters.cs │ │ ├── CreateUpdateUserParameters.cs │ │ ├── LoginUserParameters.cs │ │ ├── ResetPasswordParameters.cs │ │ ├── QueryRolesParameters.cs │ │ ├── RegisterUserParameters.cs │ │ └── QueryUsersParameters.cs │ ├── Mapping │ │ ├── UserTokenDbMapping.cs │ │ ├── UserLoginDbMapping.cs │ │ ├── UserClaimDbMapping.cs │ │ ├── RoleClaimDbMapping.cs │ │ ├── UserRoleDbMapping.cs │ │ ├── UserPropertyValueDbMapping.cs │ │ ├── RoleDbMapping.cs │ │ ├── MediaRoleDbMapping.cs │ │ ├── ContentRoleDbMapping.cs │ │ └── UserDbMapping.cs │ ├── IdentityUserAccessor.cs │ ├── Validation │ │ ├── CreateUpdateUserCommandValidator.cs │ │ ├── UserValidation.cs │ │ └── ValidateRole.cs │ └── Authentication │ │ ├── GoogleAuthentication.cs │ │ └── MicrosoftAuthentication.cs ├── Shared │ ├── Models │ │ ├── AlertType.cs │ │ ├── ResultMessageType.cs │ │ ├── DataGridResult.cs │ │ ├── ContentViewName.cs │ │ ├── HandlerResult.cs │ │ ├── Tab.cs │ │ ├── ResultMessage.cs │ │ ├── TreeBranch.cs │ │ ├── TreeStub.cs │ │ ├── NavigationItem.cs │ │ ├── PropertyType.cs │ │ └── PaginatedList.cs │ ├── Interfaces │ │ ├── ITreeItem.cs │ │ ├── IBaseItem.cs │ │ └── IAfterEntitySave.cs │ ├── Validation │ │ ├── Models │ │ │ └── ValidateResult.cs │ │ ├── Interfaces │ │ │ └── IValidate.cs │ │ └── BaseFluentValidator.cs │ ├── Comparers │ │ └── ITreeEqualityComparer.cs │ ├── ZauberRouteValueTransformer.cs │ ├── Dictionary.cs │ └── Services │ │ ├── ICacheService.cs │ │ ├── ValidateService.cs │ │ └── IHtmlSanitizerService.cs ├── Languages │ ├── Parameters │ │ ├── GetCachedAllLanguageDictionariesParameters.cs │ │ ├── DeleteLanguageDictionaryParameters.cs │ │ ├── SaveLanguageDictionaryParameters.cs │ │ ├── DeleteLanguageParameters.cs │ │ ├── GetLanguageParameters.cs │ │ ├── SaveLanguageParameters.cs │ │ ├── DataGridLanguageDictionaryParameters.cs │ │ └── QueryLanguageParameters.cs │ ├── Models │ │ ├── LanguageDictionary.cs │ │ └── LanguageText.cs │ ├── Mapping │ │ ├── LanguageTextDbMapping.cs │ │ ├── LanguageDbMapping.cs │ │ └── LanguageDictionaryDbMapping.cs │ └── Validation │ │ └── ValidateLanguageDictionary.cs ├── Audit │ ├── Parameters │ │ ├── CleanupOldAuditsParameters.cs │ │ ├── SaveAuditParameters.cs │ │ └── QueryAuditsParameters.cs │ ├── Models │ │ └── Audit.cs │ ├── Mapping │ │ └── AuditDbMapper.cs │ └── Interfaces │ │ └── IAuditService.cs ├── Media │ ├── Parameters │ │ ├── GetRestrictedMediaUrlsParameters.cs │ │ ├── HasChildMediaParameters.cs │ │ ├── DeleteMediaParameters.cs │ │ ├── SaveMediaParameters.cs │ │ ├── GetMediaParameters.cs │ │ └── QueryMediaParameters.cs │ ├── Models │ │ └── MediaTypes.cs │ ├── Validation │ │ └── ValidateMedia.cs │ └── Interfaces │ │ └── IMediaService.cs ├── Sections │ └── Interfaces │ │ ├── ISectionNav.cs │ │ ├── ISectionDashboard.cs │ │ ├── ISection.cs │ │ ├── ISectionNavGroup.cs │ │ └── ISectionNavGroupAction.cs ├── Seo │ ├── Models │ │ ├── SeoSitemapChangeFrequency.cs │ │ ├── ISeoCheck.cs │ │ ├── SeoCheckResultItem.cs │ │ ├── SeoCheckResult.cs │ │ └── Meta.cs │ ├── Parameters │ │ ├── SaveRedirectParameters.cs │ │ ├── DeleteRedirectParameters.cs │ │ └── QueryRedirectsParameters.cs │ ├── Interfaces │ │ └── ISeoService.cs │ ├── Mapping │ │ └── SeoRedirectDbMapping.cs │ └── Checks │ │ └── CanonicalSeoChecker.cs ├── Plugins │ ├── Interfaces │ │ ├── IEmailProvider.cs │ │ ├── IStartupPlugin.cs │ │ └── IExternalAuthenticationProvider.cs │ └── AssemblyManager.cs ├── Tags │ ├── Parameters │ │ ├── DeleteTagParameters.cs │ │ ├── DeleteTagItemParameters.cs │ │ ├── SaveTagParameters.cs │ │ ├── SaveTagItemParameters.cs │ │ └── QueryTagParameters.cs │ ├── Models │ │ ├── TagItem.cs │ │ └── Tag.cs │ ├── Mapping │ │ ├── TagItemDbMapping.cs │ │ └── TagDbMapping.cs │ └── Interfaces │ │ └── ITagService.cs ├── Email │ ├── Parameters │ │ └── SendEmailConfirmationParameters.cs │ ├── Interfaces │ │ └── IEmailService.cs │ └── IdentityEmailSender.cs ├── Extensions │ ├── TupleExtensions.cs │ ├── DialogExtensions.cs │ └── HttpContextExtensions.cs ├── Settings │ └── GlobalSettings.cs └── Providers │ └── IStorageProvider.cs ├── .claude └── settings.local.json └── LICENSE /ZauberCMS.Template/template/ZauberCMSTemplate.Site/wwwroot/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /ZauberCMS/Components/Pages/Index.razor: -------------------------------------------------------------------------------- 1 | @page "/" 2 | -------------------------------------------------------------------------------- /ZauberCMS.Web/app.db: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/YodasMyDad/ZauberCMS/HEAD/ZauberCMS.Web/app.db -------------------------------------------------------------------------------- /ZauberCMS.Components/SharedResource.cs: -------------------------------------------------------------------------------- 1 | namespace ZauberCMS.Components; 2 | 3 | public class SharedResource 4 | { 5 | 6 | } -------------------------------------------------------------------------------- /ZauberCMS.Routing/Views/_ViewImports.cshtml: -------------------------------------------------------------------------------- 1 | @using ZauberCMS.Routing 2 | @addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers -------------------------------------------------------------------------------- /ZauberCMS.Template/images/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/YodasMyDad/ZauberCMS/HEAD/ZauberCMS.Template/images/logo.png -------------------------------------------------------------------------------- /ZauberCMS.Components/wwwroot/img/hat.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/YodasMyDad/ZauberCMS/HEAD/ZauberCMS.Components/wwwroot/img/hat.jpg -------------------------------------------------------------------------------- /ZauberCMS.Web/wwwroot/assets/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/YodasMyDad/ZauberCMS/HEAD/ZauberCMS.Web/wwwroot/assets/favicon.ico -------------------------------------------------------------------------------- /ZauberCMS.Core/Rendering/IZauberViewPage.cs: -------------------------------------------------------------------------------- 1 | namespace ZauberCMS.Core.Rendering; 2 | 3 | public interface IZauberViewPage 4 | { 5 | 6 | } -------------------------------------------------------------------------------- /ZauberCMS.Web/wwwroot/assets/img/about-bg.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/YodasMyDad/ZauberCMS/HEAD/ZauberCMS.Web/wwwroot/assets/img/about-bg.jpg -------------------------------------------------------------------------------- /ZauberCMS.Web/wwwroot/assets/img/home-bg.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/YodasMyDad/ZauberCMS/HEAD/ZauberCMS.Web/wwwroot/assets/img/home-bg.jpg -------------------------------------------------------------------------------- /ZauberCMS.Web/wwwroot/assets/img/post-bg.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/YodasMyDad/ZauberCMS/HEAD/ZauberCMS.Web/wwwroot/assets/img/post-bg.jpg -------------------------------------------------------------------------------- /ZauberCMS.Core/Data/Interfaces/IMsSqlMigration.cs: -------------------------------------------------------------------------------- 1 | namespace ZauberCMS.Core.Data.Interfaces; 2 | 3 | public interface IMsSqlMigration 4 | { 5 | 6 | } -------------------------------------------------------------------------------- /ZauberCMS.Web/wwwroot/assets/img/contact-bg.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/YodasMyDad/ZauberCMS/HEAD/ZauberCMS.Web/wwwroot/assets/img/contact-bg.jpg -------------------------------------------------------------------------------- /ZauberCMS.Core/Data/Interfaces/ISQLiteMigration.cs: -------------------------------------------------------------------------------- 1 | namespace ZauberCMS.Core.Data.Interfaces; 2 | 3 | public interface ISqLiteMigration 4 | { 5 | 6 | } -------------------------------------------------------------------------------- /ZauberCMS.Core/Content/Parameters/CachedDomainsParameters.cs: -------------------------------------------------------------------------------- 1 | namespace ZauberCMS.Core.Content.Parameters; 2 | 3 | public class CachedDomainsParameters 4 | { 5 | } -------------------------------------------------------------------------------- /ZauberCMS.Core/Membership/Interfaces/IAccountLayout.cs: -------------------------------------------------------------------------------- 1 | namespace ZauberCMS.Core.Membership.Interfaces; 2 | 3 | public interface IAccountLayout 4 | { 5 | 6 | } -------------------------------------------------------------------------------- /ZauberCMS.Web/wwwroot/assets/img/post-sample-image.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/YodasMyDad/ZauberCMS/HEAD/ZauberCMS.Web/wwwroot/assets/img/post-sample-image.jpg -------------------------------------------------------------------------------- /ZauberCMS.Components/Admin/_Imports.razor: -------------------------------------------------------------------------------- 1 | @using Microsoft.AspNetCore.Authorization 2 | @using ZauberCMS.Core 3 | @attribute [Authorize(Roles = Constants.Roles.AdminRoleName)] -------------------------------------------------------------------------------- /ZauberCMS.Components/Shared/PageScript.razor: -------------------------------------------------------------------------------- 1 | 2 | @code { 3 | [Parameter, EditorRequired] public string Src { get; set; } = null!; 4 | } -------------------------------------------------------------------------------- /ZauberCMS.Core/Content/Parameters/GetContentLanguagesParameters.cs: -------------------------------------------------------------------------------- 1 | namespace ZauberCMS.Core.Content.Parameters; 2 | 3 | public class GetContentLanguagesParameters 4 | { 5 | } -------------------------------------------------------------------------------- /ZauberCMS.Core/Data/Interfaces/ISeedData.cs: -------------------------------------------------------------------------------- 1 | namespace ZauberCMS.Core.Data.Interfaces; 2 | 3 | public interface ISeedData 4 | { 5 | void Initialise(IZauberDbContext dbContext); 6 | } -------------------------------------------------------------------------------- /ZauberCMS.Core/Shared/Models/AlertType.cs: -------------------------------------------------------------------------------- 1 | namespace ZauberCMS.Core.Shared.Models; 2 | 3 | public enum AlertType 4 | { 5 | Success, 6 | Warning, 7 | Error, 8 | Info 9 | } -------------------------------------------------------------------------------- /ZauberCMS.Components/Seo/Models/SeoConstants.cs: -------------------------------------------------------------------------------- 1 | namespace ZauberCMS.Components.Seo.Models; 2 | 3 | public static class SeoConstants 4 | { 5 | public const string SeoSitemapName = "SeoSitemap"; 6 | } -------------------------------------------------------------------------------- /ZauberCMS.Core/Shared/Interfaces/ITreeItem.cs: -------------------------------------------------------------------------------- 1 | namespace ZauberCMS.Core.Shared.Interfaces; 2 | 3 | public interface ITreeItem 4 | { 5 | Guid Id { get; set; } 6 | string? Name { get; set; } 7 | } -------------------------------------------------------------------------------- /ZauberCMS.Core/Shared/Models/ResultMessageType.cs: -------------------------------------------------------------------------------- 1 | namespace ZauberCMS.Core.Shared.Models; 2 | 3 | public enum ResultMessageType 4 | { 5 | Info, 6 | Success, 7 | Warning, 8 | Error 9 | } -------------------------------------------------------------------------------- /ZauberCMS.Core/Content/Interfaces/IHasPropertyValues.cs: -------------------------------------------------------------------------------- 1 | namespace ZauberCMS.Core.Content.Interfaces; 2 | 3 | public interface IHasPropertyValues 4 | { 5 | Dictionary ContentValues(); 6 | } -------------------------------------------------------------------------------- /ZauberCMS.Core/Languages/Parameters/GetCachedAllLanguageDictionariesParameters.cs: -------------------------------------------------------------------------------- 1 | namespace ZauberCMS.Core.Languages.Parameters; 2 | 3 | public class GetCachedAllLanguageDictionariesParameters 4 | { 5 | } -------------------------------------------------------------------------------- /ZauberCMS.Components/Editors/Models/TextContentSettingsModel.cs: -------------------------------------------------------------------------------- 1 | namespace ZauberCMS.Components.Editors.Models; 2 | 3 | public class TextContentSettingsModel 4 | { 5 | public long? MaxLength { get; set; } 6 | } -------------------------------------------------------------------------------- /ZauberCMS.Core/Membership/Models/RoleClaim.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.AspNetCore.Identity; 2 | 3 | namespace ZauberCMS.Core.Membership.Models; 4 | 5 | public class RoleClaim : IdentityRoleClaim 6 | { 7 | 8 | } -------------------------------------------------------------------------------- /ZauberCMS.Core/Membership/Models/UserClaim.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.AspNetCore.Identity; 2 | 3 | namespace ZauberCMS.Core.Membership.Models; 4 | 5 | public class UserClaim : IdentityUserClaim 6 | { 7 | 8 | } -------------------------------------------------------------------------------- /ZauberCMS.Core/Membership/Models/UserLogin.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.AspNetCore.Identity; 2 | 3 | namespace ZauberCMS.Core.Membership.Models; 4 | 5 | public class UserLogin : IdentityUserLogin 6 | { 7 | 8 | } -------------------------------------------------------------------------------- /ZauberCMS.Core/Membership/Models/UserToken.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.AspNetCore.Identity; 2 | 3 | namespace ZauberCMS.Core.Membership.Models; 4 | 5 | public class UserToken : IdentityUserToken 6 | { 7 | 8 | } -------------------------------------------------------------------------------- /ZauberCMS.Components/Editors/Models/TagPropertySettingsModel.cs: -------------------------------------------------------------------------------- 1 | namespace ZauberCMS.Components.Editors.Models; 2 | 3 | public class TagPropertySettingsModel 4 | { 5 | public bool AllowTagEditing { get; set; } 6 | } -------------------------------------------------------------------------------- /ZauberCMS.Core/Audit/Parameters/CleanupOldAuditsParameters.cs: -------------------------------------------------------------------------------- 1 | namespace ZauberCMS.Core.Audit.Parameters; 2 | 3 | public class CleanupOldAuditsParameters 4 | { 5 | public int DaysToKeep { get; set; } = 90; 6 | } -------------------------------------------------------------------------------- /ZauberCMS.Core/Membership/Models/Permission.cs: -------------------------------------------------------------------------------- 1 | namespace ZauberCMS.Core.Membership.Models; 2 | 3 | public class Permission 4 | { 5 | public string? Name { get; set; } 6 | public bool Allowed { get; set; } 7 | } -------------------------------------------------------------------------------- /ZauberCMS.Core/Shared/Validation/Models/ValidateResult.cs: -------------------------------------------------------------------------------- 1 | namespace ZauberCMS.Core.Shared.Validation.Models; 2 | 3 | public class ValidateResult 4 | { 5 | public List ErrorMessages { get; set; } = []; 6 | } -------------------------------------------------------------------------------- /ZauberCMS.Components/Editors/Models/RatingPropertySettingsModel.cs: -------------------------------------------------------------------------------- 1 | namespace ZauberCMS.Components.Editors.Models; 2 | 3 | public class RatingPropertySettingsModel 4 | { 5 | public int AmountOfStars { get; set; } = 5; 6 | } -------------------------------------------------------------------------------- /ZauberCMS.Core/Media/Parameters/GetRestrictedMediaUrlsParameters.cs: -------------------------------------------------------------------------------- 1 | namespace ZauberCMS.Core.Media.Parameters; 2 | 3 | public class GetRestrictedMediaUrlsParameters 4 | { 5 | public bool Cached { get; set; } = true; 6 | } -------------------------------------------------------------------------------- /ZauberCMS.Core/Media/Parameters/HasChildMediaParameters.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace ZauberCMS.Core.Media.Parameters; 4 | 5 | public class HasChildMediaParameters 6 | { 7 | public Guid ParentId { get; set; } 8 | } -------------------------------------------------------------------------------- /ZauberCMS.Routing/Views/ZauberRender/Index.cshtml: -------------------------------------------------------------------------------- 1 | @{ 2 | Layout = "_ZauberLayout"; 3 | } 4 | @section Head { 5 | Hmmm 6 | } 7 |

Looks like there was an error, you should not have got here

8 | 9 | -------------------------------------------------------------------------------- /ZauberCMS.Core/Content/Interfaces/IContentBlock.cs: -------------------------------------------------------------------------------- 1 | namespace ZauberCMS.Core.Content.Interfaces; 2 | 3 | public interface IContentBlock 4 | { 5 | string ContentTypeAlias { get; } 6 | Models.Content? Content { get; set; } 7 | } -------------------------------------------------------------------------------- /ZauberCMS.Core/Shared/Models/DataGridResult.cs: -------------------------------------------------------------------------------- 1 | namespace ZauberCMS.Core.Shared.Models; 2 | 3 | public class DataGridResult 4 | { 5 | public IEnumerable Items { get; set; } = []; 6 | public int Count { get; set; } 7 | } -------------------------------------------------------------------------------- /ZauberCMS.Components/Editors/Models/ColourThemePickerSettings.cs: -------------------------------------------------------------------------------- 1 | namespace ZauberCMS.Components.Editors.Models; 2 | 3 | public class ColourThemePickerSettings 4 | { 5 | public List HexColours { get; set; } = []; 6 | } 7 | -------------------------------------------------------------------------------- /ZauberCMS.Core/Sections/Interfaces/ISectionNav.cs: -------------------------------------------------------------------------------- 1 | namespace ZauberCMS.Core.Sections.Interfaces; 2 | 3 | public interface ISectionNav : IDisposable 4 | { 5 | int SortOrder { get; } 6 | string SectionNavGroupAlias { get; } 7 | } -------------------------------------------------------------------------------- /ZauberCMS.Core/Content/Interfaces/IContent.cs: -------------------------------------------------------------------------------- 1 | using ZauberCMS.Core.Shared.Interfaces; 2 | 3 | namespace ZauberCMS.Core.Content.Interfaces; 4 | 5 | public interface IContent : IBaseItem 6 | { 7 | List PropertyData { get; set; } 8 | } -------------------------------------------------------------------------------- /ZauberCMS.Core/Content/Interfaces/ICustomContentComponent.cs: -------------------------------------------------------------------------------- 1 | namespace ZauberCMS.Core.Content.Interfaces; 2 | 3 | public interface ICustomContentComponent 4 | { 5 | string Name { get; } 6 | Models.Content? Content { get; set; } 7 | } -------------------------------------------------------------------------------- /ZauberCMS.Core/Data/Parameters/SaveGlobalDataParameters.cs: -------------------------------------------------------------------------------- 1 | namespace ZauberCMS.Core.Data.Parameters; 2 | 3 | public class SaveGlobalDataParameters 4 | { 5 | public string? Alias { get; set; } 6 | public string? Data { get; set; } 7 | } -------------------------------------------------------------------------------- /ZauberCMS.Core/Audit/Parameters/SaveAuditParameters.cs: -------------------------------------------------------------------------------- 1 | using ZauberCMS.Core.Shared.Models; 2 | 3 | namespace ZauberCMS.Core.Audit.Parameters; 4 | 5 | public class SaveAuditParameters 6 | { 7 | public Models.Audit? Audit { get; set; } 8 | } -------------------------------------------------------------------------------- /ZauberCMS.Core/Content/Models/DataListItem.cs: -------------------------------------------------------------------------------- 1 | namespace ZauberCMS.Core.Content.Models; 2 | 3 | public class DataListItem 4 | { 5 | public string Name { get; set; } = string.Empty; 6 | public string Value { get; set; } = string.Empty; 7 | } -------------------------------------------------------------------------------- /ZauberCMS.Core/Data/Parameters/GetGlobalDataParameters.cs: -------------------------------------------------------------------------------- 1 | namespace ZauberCMS.Core.Data.Parameters; 2 | 3 | public class GetGlobalDataParameters 4 | { 5 | public string? Alias { get; set; } 6 | public bool Cached { get; set; } = true; 7 | } -------------------------------------------------------------------------------- /ZauberCMS.Components/Editors/Models/ListManagerItem.cs: -------------------------------------------------------------------------------- 1 | namespace ZauberCMS.Components.Editors.Models; 2 | 3 | public class ListManagerItem 4 | { 5 | public string Value { get; set; } = string.Empty; 6 | public int SortOrder { get; set; } 7 | } -------------------------------------------------------------------------------- /ZauberCMS.Core/Sections/Interfaces/ISectionDashboard.cs: -------------------------------------------------------------------------------- 1 | namespace ZauberCMS.Core.Sections.Interfaces; 2 | 3 | public interface ISectionDashboard 4 | { 5 | string TabName { get; } 6 | int SortOrder { get; } 7 | string SectionAlias { get; } 8 | } -------------------------------------------------------------------------------- /ZauberCMS.Core/Shared/Models/ContentViewName.cs: -------------------------------------------------------------------------------- 1 | namespace ZauberCMS.Core.Shared.Models; 2 | 3 | public class ContentViewName 4 | { 5 | public string Name { get; set; } = string.Empty; 6 | public string FullName { get; set; } = string.Empty; 7 | } -------------------------------------------------------------------------------- /ZauberCMS.Core/Sections/Interfaces/ISection.cs: -------------------------------------------------------------------------------- 1 | namespace ZauberCMS.Core.Sections.Interfaces; 2 | 3 | public interface ISection 4 | { 5 | string Name { get; } 6 | string Alias { get; } 7 | string IndexUrl { get; } 8 | int SortOrder { get; } 9 | } -------------------------------------------------------------------------------- /ZauberCMS.Core/Shared/Validation/Interfaces/IValidate.cs: -------------------------------------------------------------------------------- 1 | using ZauberCMS.Core.Shared.Validation.Models; 2 | 3 | namespace ZauberCMS.Core.Shared.Validation.Interfaces; 4 | 5 | public interface IValidate 6 | { 7 | Task Validate(T item); 8 | } -------------------------------------------------------------------------------- /ZauberCMS.Core/Content/Interfaces/IContentBlockPreview.cs: -------------------------------------------------------------------------------- 1 | using ZauberCMS.Core.Content.Models; 2 | 3 | namespace ZauberCMS.Core.Content.Interfaces; 4 | 5 | public interface IContentBlockPreview : IContentBlock 6 | { 7 | ContentType? ContentType { get; set; } 8 | } -------------------------------------------------------------------------------- /ZauberCMS.Core/Seo/Models/SeoSitemapChangeFrequency.cs: -------------------------------------------------------------------------------- 1 | namespace ZauberCMS.Core.Seo.Models; 2 | 3 | public enum SeoSitemapChangeFrequency 4 | { 5 | Always, 6 | Hourly, 7 | Daily, 8 | Weekly, 9 | Monthly, 10 | Yearly, 11 | Never 12 | } -------------------------------------------------------------------------------- /ZauberCMS.Core/Content/Interfaces/IContentBlockView.cs: -------------------------------------------------------------------------------- 1 | namespace ZauberCMS.Core.Content.Interfaces; 2 | using RenderMode = Microsoft.AspNetCore.Mvc.Rendering.RenderMode; 3 | 4 | public interface IContentBlockView : IContentBlock 5 | { 6 | RenderMode RenderMode { get; } 7 | } -------------------------------------------------------------------------------- /ZauberCMS.Core/Content/Parameters/HasChildContentParameters.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace ZauberCMS.Core.Content.Parameters; 4 | 5 | public class HasChildContentParameters 6 | { 7 | public bool Cached { get; set; } = true; 8 | public Guid ParentId { get; set; } 9 | } -------------------------------------------------------------------------------- /ZauberCMS.Core/Data/Interfaces/IQueryModel.cs: -------------------------------------------------------------------------------- 1 | namespace ZauberCMS.Core.Data.Interfaces; 2 | 3 | public interface IQueryModel 4 | { 5 | string? Name { get; } 6 | Task> ExecuteQuery(IZauberDbContext dbContext, CancellationToken cancellationToken); 7 | } -------------------------------------------------------------------------------- /ZauberCMS.Components/Editors/Dialogs/EditorNotesDialog.razor: -------------------------------------------------------------------------------- 1 | @using ZauberCMS.Components.Editors.Models 2 | 3 |
4 | @((MarkupString)(Model.Note ?? string.Empty)) 5 |
6 | 7 | @code { 8 | [Parameter] public EditorNotesSettingsModel Model { get; set; } = new(); 9 | } -------------------------------------------------------------------------------- /ZauberCMS.Core/Content/Parameters/SaveDomainParameters.cs: -------------------------------------------------------------------------------- 1 | using ZauberCMS.Core.Content.Models; 2 | using ZauberCMS.Core.Shared.Models; 3 | 4 | namespace ZauberCMS.Core.Content.Parameters; 5 | 6 | public class SaveDomainParameters 7 | { 8 | public Domain? Domain { get; set; } 9 | } -------------------------------------------------------------------------------- /ZauberCMS.Core/Membership/Parameters/SaveRoleParameters.cs: -------------------------------------------------------------------------------- 1 | using ZauberCMS.Core.Membership.Models; 2 | using ZauberCMS.Core.Shared.Models; 3 | 4 | namespace ZauberCMS.Core.Membership.Parameters; 5 | 6 | public class SaveRoleParameters 7 | { 8 | public Role? Role { get; set; } 9 | } -------------------------------------------------------------------------------- /ZauberCMS.Core/Sections/Interfaces/ISectionNavGroup.cs: -------------------------------------------------------------------------------- 1 | namespace ZauberCMS.Core.Sections.Interfaces; 2 | 3 | public interface ISectionNavGroup 4 | { 5 | string Heading { get; } 6 | string Alias { get; } 7 | int SortOrder { get; } 8 | string SectionAlias { get; } 9 | } -------------------------------------------------------------------------------- /ZauberCMS.Core/Seo/Parameters/SaveRedirectParameters.cs: -------------------------------------------------------------------------------- 1 | using ZauberCMS.Core.Seo.Models; 2 | using ZauberCMS.Core.Shared.Models; 3 | 4 | namespace ZauberCMS.Core.Seo.Parameters; 5 | 6 | public class SaveRedirectParameters 7 | { 8 | public SeoRedirect? Redirect { get; set; } 9 | } -------------------------------------------------------------------------------- /ZauberCMS.Core/Content/Models/EntryContentResult.cs: -------------------------------------------------------------------------------- 1 | namespace ZauberCMS.Core.Content.Models; 2 | 3 | public class EntryContentResult 4 | { 5 | public Guid? ContentId { get; set; } 6 | public bool IncludeChildren { get; set; } 7 | public string? LanguageIsoCode { get; set; } 8 | } -------------------------------------------------------------------------------- /ZauberCMS.Core/Content/Parameters/HasChildContentTypeParameters.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace ZauberCMS.Core.Content.Parameters; 4 | 5 | public class HasChildContentTypeParameters 6 | { 7 | public bool Cached { get; set; } = true; 8 | public Guid ParentId { get; set; } 9 | } -------------------------------------------------------------------------------- /ZauberCMS.Web/ZauberCMS.Web.csproj.user: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | https 5 | 6 | -------------------------------------------------------------------------------- /ZauberCMS.Core/Data/Parameters/MultiQueryParameters.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using ZauberCMS.Core.Data.Interfaces; 3 | 4 | namespace ZauberCMS.Core.Data.Parameters; 5 | 6 | public class MultiQueryParameters 7 | { 8 | public List Queries { get; set; } = []; 9 | } -------------------------------------------------------------------------------- /ZauberCMS.Core/Membership/Models/UserRole.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.AspNetCore.Identity; 2 | 3 | namespace ZauberCMS.Core.Membership.Models; 4 | 5 | public class UserRole : IdentityUserRole 6 | { 7 | public Role Role { get; set; } = null!; 8 | public User User { get; set; } = null!; 9 | } -------------------------------------------------------------------------------- /ZauberCMS.Core/Content/Models/EntryModel.cs: -------------------------------------------------------------------------------- 1 | namespace ZauberCMS.Core.Content.Models; 2 | 3 | public class EntryModel 4 | { 5 | public Content? Content { get; set; } 6 | public Dictionary LanguageKeys { get; set; } = []; 7 | public string? LanguageIsoCode { get; set; } 8 | } -------------------------------------------------------------------------------- /ZauberCMS.Core/Content/Parameters/SaveContentTypeParameters.cs: -------------------------------------------------------------------------------- 1 | using ZauberCMS.Core.Content.Models; 2 | using ZauberCMS.Core.Shared.Models; 3 | 4 | namespace ZauberCMS.Core.Content.Parameters; 5 | 6 | public class SaveContentTypeParameters 7 | { 8 | public ContentType? ContentType { get; set; } 9 | } -------------------------------------------------------------------------------- /ZauberCMS.Core/Seo/Parameters/DeleteRedirectParameters.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using ZauberCMS.Core.Seo.Models; 3 | using ZauberCMS.Core.Shared.Models; 4 | 5 | namespace ZauberCMS.Core.Seo.Parameters; 6 | 7 | public class DeleteRedirectParameters 8 | { 9 | public Guid? Id { get; set; } 10 | } -------------------------------------------------------------------------------- /ZauberCMS.Components/Editors/Models/BlockListEditorSettingsModel.cs: -------------------------------------------------------------------------------- 1 | namespace ZauberCMS.Components.Editors.Models; 2 | 3 | public class BlockListEditorSettingsModel 4 | { 5 | public List Styleheets { get; set; } = []; 6 | public IEnumerable AllowedElementTypeIds { get; set; } = []; 7 | } -------------------------------------------------------------------------------- /ZauberCMS.Core/Membership/Parameters/GetUserParameters.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using ZauberCMS.Core.Membership.Models; 3 | 4 | namespace ZauberCMS.Core.Membership.Parameters; 5 | 6 | public class GetUserParameters 7 | { 8 | public bool Cached { get; set; } 9 | public Guid Id { get; set; } 10 | } -------------------------------------------------------------------------------- /ZauberCMS.Components/Editors/Models/MediaPickerSettings.cs: -------------------------------------------------------------------------------- 1 | using ZauberCMS.Core.Media.Models; 2 | 3 | namespace ZauberCMS.Components.Editors.Models; 4 | 5 | public class MediaPickerSettings 6 | { 7 | public int? MaxAllowed { get; set; } 8 | public IEnumerable? AllowedMediaTypes { get; set; } 9 | } -------------------------------------------------------------------------------- /ZauberCMS.Core/Content/Parameters/GetContentTypeParameters.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using ZauberCMS.Core.Content.Models; 3 | using ZauberCMS.Core.Shared.Models; 4 | 5 | namespace ZauberCMS.Core.Content.Parameters; 6 | 7 | public class GetContentTypeParameters 8 | { 9 | public Guid Id { get; set; } 10 | } -------------------------------------------------------------------------------- /ZauberCMS.Core/Media/Parameters/DeleteMediaParameters.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using ZauberCMS.Core.Shared.Models; 3 | 4 | namespace ZauberCMS.Core.Media.Parameters; 5 | 6 | public class DeleteMediaParameters 7 | { 8 | public Guid MediaId { get; set; } 9 | public bool DeleteFile { get; set; } 10 | } -------------------------------------------------------------------------------- /ZauberCMS.Core/Content/Interfaces/IPropertyValue.cs: -------------------------------------------------------------------------------- 1 | namespace ZauberCMS.Core.Content.Interfaces; 2 | 3 | public interface IPropertyValue 4 | { 5 | public Guid Id { get; set; } 6 | public string Alias { get; set; } 7 | public string Value { get; set; } 8 | public DateTime? DateUpdated { get; set; } 9 | } -------------------------------------------------------------------------------- /ZauberCMS.Core/Media/Models/MediaTypes.cs: -------------------------------------------------------------------------------- 1 | namespace ZauberCMS.Core.Media.Models; 2 | 3 | public enum MediaType 4 | { 5 | Folder, 6 | Image, 7 | Video, 8 | Audio, 9 | Pdf, 10 | Document, 11 | Spreadsheet, 12 | Presentation, 13 | Archive, 14 | Text, 15 | Unknown 16 | } -------------------------------------------------------------------------------- /ZauberCMS.Core/Plugins/Interfaces/IEmailProvider.cs: -------------------------------------------------------------------------------- 1 | namespace ZauberCMS.Core.Plugins.Interfaces; 2 | 3 | public interface IEmailProvider 4 | { 5 | Task SendEmailWithTemplateAsync(string toEmail, string subject, List paragraphs); 6 | Task SendEmailAsync(string toEmail, string subject, string message); 7 | } -------------------------------------------------------------------------------- /ZauberCMS.Components/Editors/Models/ContentPickerSettings.cs: -------------------------------------------------------------------------------- 1 | namespace ZauberCMS.Components.Editors.Models; 2 | 3 | public class ContentPickerSettings 4 | { 5 | public int? MaxAllowed { get; set; } 6 | public IEnumerable? AllowedContentTypes { get; set; } 7 | public bool OnlyRootContent { get; set; } 8 | } -------------------------------------------------------------------------------- /ZauberCMS.Core/Membership/Models/MediaRole.cs: -------------------------------------------------------------------------------- 1 | namespace ZauberCMS.Core.Membership.Models; 2 | 3 | public class MediaRole 4 | { 5 | public Media.Models.Media Media { get; set; } = null!; 6 | public Guid MediaId { get; set; } 7 | public Role Role { get; set; } = null!; 8 | public Guid RoleId { get; set; } 9 | } -------------------------------------------------------------------------------- /ZauberCMS.Core/Membership/Parameters/GetRoleParameters.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using ZauberCMS.Core.Membership.Models; 3 | 4 | namespace ZauberCMS.Core.Membership.Parameters; 5 | 6 | public class GetRoleParameters 7 | { 8 | public Guid? Id { get; set; } 9 | public bool AsNoTracking { get; set; } = true; 10 | } -------------------------------------------------------------------------------- /ZauberCMS.Core/Seo/Models/ISeoCheck.cs: -------------------------------------------------------------------------------- 1 | using HtmlAgilityPack; 2 | 3 | namespace ZauberCMS.Core.Seo.Models; 4 | 5 | public interface ISeoCheck 6 | { 7 | string Name { get; } 8 | Task Check(string url, HtmlDocument document, Content.Models.Content content); 9 | int SortOrder { get; } 10 | } -------------------------------------------------------------------------------- /ZauberCMS.Components/Editors/Models/GoogleMapsSettingsModel.cs: -------------------------------------------------------------------------------- 1 | namespace ZauberCMS.Components.Editors.Models; 2 | 3 | public class GoogleMapsSettingsModel 4 | { 5 | public double? DefaultLat { get; set; } = 51.5074; 6 | public double? DefaultLng { get; set; } = 0.1278; 7 | public int ZoomLevel { get; set; } = 3; 8 | } -------------------------------------------------------------------------------- /ZauberCMS.Core/Content/Parameters/DeleteContentParameters.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using ZauberCMS.Core.Shared.Models; 3 | 4 | namespace ZauberCMS.Core.Content.Parameters; 5 | 6 | public class DeleteContentParameters 7 | { 8 | public Guid ContentId { get; set; } 9 | public bool MoveToRecycleBin { get; set; } 10 | } -------------------------------------------------------------------------------- /ZauberCMS.Core/Content/Parameters/DeleteContentTypeParameters.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using ZauberCMS.Core.Content.Models; 3 | using ZauberCMS.Core.Shared.Models; 4 | 5 | namespace ZauberCMS.Core.Content.Parameters; 6 | 7 | public class DeleteContentTypeParameters 8 | { 9 | public Guid ContentTypeId { get; set; } 10 | } -------------------------------------------------------------------------------- /ZauberCMS.Core/Plugins/Interfaces/IStartupPlugin.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.Extensions.Configuration; 2 | using Microsoft.Extensions.DependencyInjection; 3 | 4 | namespace ZauberCMS.Core.Plugins.Interfaces; 5 | 6 | public interface IStartupPlugin 7 | { 8 | void Register(IServiceCollection services, IConfiguration configuration); 9 | } -------------------------------------------------------------------------------- /ZauberCMS.Core/Membership/Models/ContentRole.cs: -------------------------------------------------------------------------------- 1 | namespace ZauberCMS.Core.Membership.Models; 2 | 3 | public class ContentRole 4 | { 5 | public Content.Models.Content Content { get; set; } = null!; 6 | public Guid ContentId { get; set; } 7 | public Role Role { get; set; } = null!; 8 | public Guid RoleId { get; set; } 9 | } -------------------------------------------------------------------------------- /.claude/settings.local.json: -------------------------------------------------------------------------------- 1 | { 2 | "permissions": { 3 | "allow": [ 4 | "WebSearch", 5 | "WebFetch(domain:github.com)", 6 | "Bash(dotnet build:*)", 7 | "Bash(dotnet restore:*)", 8 | "Bash(cat:*)", 9 | "Bash(xargs cat:*)" 10 | ], 11 | "deny": [], 12 | "ask": [] 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /ZauberCMS.Core/Content/Parameters/ClearUnpublishedContentParameters.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using ZauberCMS.Core.Content.Models; 3 | using ZauberCMS.Core.Shared.Models; 4 | 5 | namespace ZauberCMS.Core.Content.Parameters; 6 | 7 | public class ClearUnpublishedContentParameters 8 | { 9 | public Guid ContentId { get; set; } 10 | } -------------------------------------------------------------------------------- /ZauberCMS.Core/Languages/Parameters/DeleteLanguageDictionaryParameters.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using ZauberCMS.Core.Languages.Models; 3 | using ZauberCMS.Core.Shared.Models; 4 | 5 | namespace ZauberCMS.Core.Languages.Parameters; 6 | 7 | public class DeleteLanguageDictionaryParameters 8 | { 9 | public Guid? Id { get; set; } 10 | } -------------------------------------------------------------------------------- /ZauberCMS.Core/Languages/Parameters/SaveLanguageDictionaryParameters.cs: -------------------------------------------------------------------------------- 1 | using ZauberCMS.Core.Languages.Models; 2 | using ZauberCMS.Core.Shared.Models; 3 | 4 | namespace ZauberCMS.Core.Languages.Parameters; 5 | 6 | public class SaveLanguageDictionaryParameters 7 | { 8 | public LanguageDictionary? LanguageDictionary { get; set; } 9 | } -------------------------------------------------------------------------------- /ZauberCMS.Core/Tags/Parameters/DeleteTagParameters.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using ZauberCMS.Core.Shared.Models; 3 | using ZauberCMS.Core.Tags.Models; 4 | 5 | namespace ZauberCMS.Core.Tags.Parameters; 6 | 7 | public class DeleteTagParameters 8 | { 9 | public Guid? Id { get; set; } 10 | public string? TagName { get; set; } 11 | } -------------------------------------------------------------------------------- /ZauberCMS.Components/Account/Shared/RedirectToLogin.razor: -------------------------------------------------------------------------------- 1 | @inject NavigationManager NavigationManager 2 | 3 | @code { 4 | 5 | protected override void OnInitialized() 6 | { 7 | NavigationManager.NavigateTo($"Account/Login?returnUrl={Uri.EscapeDataString(NavigationManager.Uri)}", forceLoad: true); 8 | } 9 | 10 | } -------------------------------------------------------------------------------- /ZauberCMS.Components/ContentComponents/ContentBlockPreviewFallback.razor: -------------------------------------------------------------------------------- 1 | 2 |
@Content?.Name
3 |
@ContentType?.Name
4 | 5 | @code { 6 | [Parameter] public Content? Content { get; set; } 7 | [Parameter] public ContentType? ContentType { get; set; } 8 | } -------------------------------------------------------------------------------- /ZauberCMS.Core/Content/Interfaces/IContentFinder.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.AspNetCore.Http; 2 | using Microsoft.AspNetCore.Routing; 3 | 4 | namespace ZauberCMS.Core.Content.Interfaces; 5 | 6 | public interface IContentFinder 7 | { 8 | Task TryFindContent(HttpContext context); 9 | int SortOrder { get; } 10 | } -------------------------------------------------------------------------------- /ZauberCMS.Core/Content/Parameters/CleanupOrphanedRelatedContentParameters.cs: -------------------------------------------------------------------------------- 1 | namespace ZauberCMS.Core.Content.Parameters; 2 | 3 | public class CleanupOrphanedRelatedContentParameters 4 | { 5 | // Simple parameter class for consistency with other cleanup operations 6 | // Could be extended in the future for additional options 7 | } 8 | -------------------------------------------------------------------------------- /ZauberCMS.Core/Tags/Parameters/DeleteTagItemParameters.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using ZauberCMS.Core.Shared.Models; 3 | using ZauberCMS.Core.Tags.Models; 4 | 5 | namespace ZauberCMS.Core.Tags.Parameters; 6 | 7 | public class DeleteTagItemParameters 8 | { 9 | public Guid? TagId { get; set; } 10 | public Guid? ItemId { get; set; } 11 | } -------------------------------------------------------------------------------- /ZauberCMS.Core/Content/Parameters/DeleteDomainParameters.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using ZauberCMS.Core.Content.Models; 3 | using ZauberCMS.Core.Shared.Models; 4 | 5 | namespace ZauberCMS.Core.Content.Parameters; 6 | 7 | public class DeleteDomainParameters 8 | { 9 | public Guid? Id { get; set; } 10 | public Guid? ContentId { get; set; } 11 | } -------------------------------------------------------------------------------- /ZauberCMS.Core/Content/Parameters/GetDomainParameters.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using ZauberCMS.Core.Content.Models; 3 | 4 | namespace ZauberCMS.Core.Content.Parameters; 5 | 6 | public class GetDomainParameters 7 | { 8 | public Guid? Id { get; set; } 9 | public bool AsNoTracking { get; set; } 10 | public string? Url { get; set; } 11 | } -------------------------------------------------------------------------------- /ZauberCMS.Core/Membership/Parameters/DeleteRoleParameters.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using ZauberCMS.Core.Membership.Models; 3 | using ZauberCMS.Core.Shared.Models; 4 | 5 | namespace ZauberCMS.Core.Membership.Parameters; 6 | 7 | public class DeleteRoleParameters 8 | { 9 | public Guid RoleId { get; set; } 10 | public Guid Id { get; set; } 11 | } -------------------------------------------------------------------------------- /ZauberCMS.Core/Membership/Parameters/DeleteUserParameters.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using ZauberCMS.Core.Membership.Models; 3 | using ZauberCMS.Core.Shared.Models; 4 | 5 | namespace ZauberCMS.Core.Membership.Parameters; 6 | 7 | public class DeleteUserParameters 8 | { 9 | public Guid UserId { get; set; } 10 | public Guid Id { get; set; } 11 | } -------------------------------------------------------------------------------- /ZauberCMS.Core/Shared/Models/HandlerResult.cs: -------------------------------------------------------------------------------- 1 | namespace ZauberCMS.Core.Shared.Models; 2 | 3 | public class HandlerResult 4 | { 5 | public T? Entity { get; set; } 6 | 7 | public bool Success { get; set; } 8 | 9 | public List Messages { get; set; } = new(); 10 | 11 | public bool RefreshSignIn { get; set; } 12 | } -------------------------------------------------------------------------------- /ZauberCMS.Components/Editors/Models/DatePickerPropertySettingsModel.cs: -------------------------------------------------------------------------------- 1 | namespace ZauberCMS.Components.Editors.Models; 2 | 3 | public class DatePickerPropertySettingsModel 4 | { 5 | public bool ShowTimeOnly { get; set; } 6 | public DateTime? MinDate { get; set; } 7 | public DateTime? MaxDate { get; set; } 8 | public bool InlineCalendar { get; set; } 9 | } -------------------------------------------------------------------------------- /ZauberCMS.Core/Content/Interfaces/IContentPropertySettings.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.AspNetCore.Components; 2 | 3 | namespace ZauberCMS.Core.Content.Interfaces; 4 | 5 | public interface IContentPropertySettings 6 | { 7 | EventCallback ValueChanged { get; set; } 8 | public string? SettingsModel { get; set; } 9 | public T Settings { get; set; } 10 | } -------------------------------------------------------------------------------- /ZauberCMS.Core/Content/Parameters/CopyContentParameters.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using ZauberCMS.Core.Shared.Models; 3 | 4 | namespace ZauberCMS.Core.Content.Parameters; 5 | 6 | public class CopyContentParameters 7 | { 8 | public Guid ContentToCopy { get; set; } 9 | public bool IncludeDescendants { get; set; } 10 | public Guid? CopyTo { get; set; } 11 | } -------------------------------------------------------------------------------- /ZauberCMS.Core/Languages/Parameters/DeleteLanguageParameters.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using ZauberCMS.Core.Languages.Models; 3 | using ZauberCMS.Core.Shared.Models; 4 | 5 | namespace ZauberCMS.Core.Languages.Parameters; 6 | 7 | public class DeleteLanguageParameters 8 | { 9 | public Guid? Id { get; set; } 10 | public string? LanguageIsoCode { get; set; } 11 | } -------------------------------------------------------------------------------- /ZauberCMS.Core/Languages/Parameters/GetLanguageParameters.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using ZauberCMS.Core.Languages.Models; 3 | 4 | namespace ZauberCMS.Core.Languages.Parameters; 5 | 6 | public class GetLanguageParameters 7 | { 8 | public Guid? Id { get; set; } 9 | public bool AsNoTracking { get; set; } 10 | public string? LanguageIsoCode { get; set; } 11 | } -------------------------------------------------------------------------------- /ZauberCMS.Core/Seo/Models/SeoCheckResultItem.cs: -------------------------------------------------------------------------------- 1 | using ZauberCMS.Core.Shared.Models; 2 | 3 | namespace ZauberCMS.Core.Seo.Models; 4 | 5 | public class SeoCheckResultItem 6 | { 7 | public AlertType Status { get; set; } = AlertType.Success; 8 | public string? DefaultMessage { get; set; } 9 | public List AdditionalMessages { get; set; } = []; 10 | } -------------------------------------------------------------------------------- /ZauberCMS.Core/Email/Parameters/SendEmailConfirmationParameters.cs: -------------------------------------------------------------------------------- 1 | using ZauberCMS.Core.Membership.Models; 2 | 3 | namespace ZauberCMS.Core.Email.Parameters; 4 | 5 | public class SendEmailConfirmationParameters 6 | { 7 | public User? User { get; set; } 8 | public string? NewEmailAddress { get; set; } 9 | public string? ReturnUrl { get; set; } = "/"; 10 | } -------------------------------------------------------------------------------- /ZauberCMS.Core/Tags/Parameters/SaveTagParameters.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using ZauberCMS.Core.Shared.Models; 3 | using ZauberCMS.Core.Tags.Models; 4 | 5 | namespace ZauberCMS.Core.Tags.Parameters; 6 | 7 | public class SaveTagParameters 8 | { 9 | public Guid? Id { get; set; } 10 | public string? TagName { get; set; } 11 | public int SortOrder { get; set; } 12 | } -------------------------------------------------------------------------------- /ZauberCMS.Core/Shared/Interfaces/IBaseItem.cs: -------------------------------------------------------------------------------- 1 | namespace ZauberCMS.Core.Shared.Interfaces; 2 | 3 | public interface IBaseItem : ITreeItem 4 | { 5 | string? Url { get; set; } 6 | int SortOrder { get; set; } 7 | Guid? ParentId { get; set; } 8 | DateTime DateCreated { get; set; } 9 | DateTime DateUpdated { get; set; } 10 | List Path { get; set; } 11 | } -------------------------------------------------------------------------------- /ZauberCMS.Core/Email/Interfaces/IEmailService.cs: -------------------------------------------------------------------------------- 1 | using System.Threading; 2 | using System.Threading.Tasks; 3 | using ZauberCMS.Core.Email.Parameters; 4 | 5 | namespace ZauberCMS.Core.Email.Interfaces; 6 | 7 | public interface IEmailService 8 | { 9 | Task SendEmailConfirmationAsync(SendEmailConfirmationParameters parameters, CancellationToken cancellationToken = default); 10 | } -------------------------------------------------------------------------------- /ZauberCMS.Core/Tags/Parameters/SaveTagItemParameters.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using ZauberCMS.Core.Shared.Models; 4 | using ZauberCMS.Core.Tags.Models; 5 | 6 | namespace ZauberCMS.Core.Tags.Parameters; 7 | 8 | public class SaveTagItemParameters 9 | { 10 | public List TagIds { get; set; } = []; 11 | public Guid ItemId { get; set; } 12 | } -------------------------------------------------------------------------------- /ZauberCMS.Components/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "devDependencies": { 3 | "autoprefixer": "^10.4.20", 4 | "postcss": "^8.4.49", 5 | "tailwindcss": "^3.4.15" 6 | }, 7 | "dependencies": { 8 | "@tailwindcss/typography": "^0.5.13" 9 | }, 10 | "scripts": { 11 | "site-css": "npx tailwindcss -i tailwind/input.css -o wwwroot/css/admin.css --minify --watch" 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /ZauberCMS.Core/Languages/Parameters/SaveLanguageParameters.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Globalization; 3 | using ZauberCMS.Core.Languages.Models; 4 | using ZauberCMS.Core.Shared.Models; 5 | 6 | namespace ZauberCMS.Core.Languages.Parameters; 7 | 8 | public class SaveLanguageParameters 9 | { 10 | public CultureInfo? CultureInfo { get; set; } 11 | public Guid? Id { get; set; } 12 | } -------------------------------------------------------------------------------- /ZauberCMS.Core/Membership/Parameters/ConfirmEmailParameters.cs: -------------------------------------------------------------------------------- 1 | using ZauberCMS.Core.Membership.Models; 2 | 3 | namespace ZauberCMS.Core.Membership.Parameters; 4 | 5 | public class ConfirmEmailParameters 6 | { 7 | public string? UserId { get; set; } 8 | public string? Code { get; set; } 9 | public bool IsEmailUpdate { get; set; } 10 | public string? ReturnUrl { get; set; } 11 | } -------------------------------------------------------------------------------- /ZauberCMS.Core/Membership/Parameters/ForgotPasswordParameters.cs: -------------------------------------------------------------------------------- 1 | using System.ComponentModel.DataAnnotations; 2 | using ZauberCMS.Core.Membership.Models; 3 | 4 | namespace ZauberCMS.Core.Membership.Parameters; 5 | 6 | public class ForgotPasswordParameters 7 | { 8 | [Required] 9 | [EmailAddress] 10 | public string? Email { get; set; } 11 | public string? ReturnUrl { get; set; } 12 | } -------------------------------------------------------------------------------- /ZauberCMS.Core/Languages/Parameters/DataGridLanguageDictionaryParameters.cs: -------------------------------------------------------------------------------- 1 | using ZauberCMS.Core.Shared.Models; 2 | 3 | namespace ZauberCMS.Core.Languages.Parameters; 4 | 5 | public class DataGridLanguageDictionaryParameters 6 | { 7 | public int Skip { get; set; } 8 | public int Take { get; set; } = 20; 9 | public string? Order { get; set; } 10 | public string? Filter { get; set; } 11 | } -------------------------------------------------------------------------------- /ZauberCMS.Core/Content/Parameters/DataGridContentParameters.cs: -------------------------------------------------------------------------------- 1 | using ZauberCMS.Core.Shared.Models; 2 | 3 | namespace ZauberCMS.Core.Content.Parameters; 4 | 5 | public class DataGridContentParameters : BaseQueryContentParameters 6 | { 7 | public int Skip { get; set; } 8 | public int Take { get; set; } = 20; 9 | public string? Order { get; set; } 10 | public string? Filter { get; set; } 11 | } -------------------------------------------------------------------------------- /ZauberCMS.Components/Admin/SettingsSection/Navigation/SettingsTree.razor: -------------------------------------------------------------------------------- 1 | @implements ZauberCMS.Core.Sections.Interfaces.ISectionNav 2 | 3 | 4 | 5 | @code { 6 | public int SortOrder => 0; 7 | public string SectionNavGroupAlias => Constants.Sections.SectionNavGroups.SettingsNavGroup; 8 | public void Dispose(){} 9 | } -------------------------------------------------------------------------------- /ZauberCMS.Core/Content/Parameters/GetContentFromRequestParameters.cs: -------------------------------------------------------------------------------- 1 | namespace ZauberCMS.Core.Content.Parameters; 2 | 3 | public class GetContentFromRequestParameters 4 | { 5 | public string? Slug { get; set; } 6 | public bool IsRootContent { get; set; } 7 | public bool IncludeChildren { get; set; } 8 | public bool IgnoreInternalRedirect { get; set; } 9 | public string? Url { get; set; } 10 | } -------------------------------------------------------------------------------- /ZauberCMS.Core/Seo/Models/SeoCheckResult.cs: -------------------------------------------------------------------------------- 1 | namespace ZauberCMS.Core.Seo.Models; 2 | 3 | public class SeoCheckResult 4 | { 5 | public SeoCheckResult() 6 | { 7 | 8 | } 9 | 10 | public SeoCheckResult(string name) 11 | { 12 | Name = name; 13 | } 14 | 15 | public string? Name { get; set; } 16 | public List Items { get; set; } = []; 17 | 18 | } -------------------------------------------------------------------------------- /ZauberCMS.Core/Membership/Parameters/SaveUserParameters.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using ZauberCMS.Core.Membership.Models; 3 | using ZauberCMS.Core.Shared.Models; 4 | 5 | namespace ZauberCMS.Core.Membership.Parameters; 6 | 7 | public class SaveUserParameters 8 | { 9 | public User? User { get; set; } 10 | public string? Password { get; set; } 11 | public List? Roles { get; set; } 12 | } -------------------------------------------------------------------------------- /ZauberCMS.Components/Shared/SortableList.razor.css: -------------------------------------------------------------------------------- 1 | /* 2 | you need the ::deep identifier if you are using scoped styles like this 3 | because scoped styles are only applied to markup in the component, not 4 | to the markup inside the render fragment. 5 | */ 6 | 7 | /* 8 | ::deep .sortable-ghost { 9 | visibility: hidden; 10 | } 11 | 12 | ::deep .sortable-fallback { 13 | opacity: 1 !important 14 | } 15 | */ 16 | -------------------------------------------------------------------------------- /ZauberCMS.Core/Membership/Parameters/ExternalLoginParameters.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.AspNetCore.Identity; 2 | using ZauberCMS.Core.Membership.Models; 3 | 4 | namespace ZauberCMS.Core.Membership.Parameters; 5 | 6 | public class ExternalLoginParameters 7 | { 8 | public string? ProviderDisplayName { get; set; } 9 | public ExternalLoginInfo? ExternalLoginInfo { get; set; } 10 | public string? ReturnUrl { get; set; } 11 | } -------------------------------------------------------------------------------- /ZauberCMS.Web/ContentBlockPreviews/Image.razor: -------------------------------------------------------------------------------- 1 | @using ZauberCMS.Web.ContentBlocks 2 | @implements ZauberCMS.Core.Content.Interfaces.IContentBlockPreview 3 | @if (Content != null) 4 | { 5 | 6 | } 7 | 8 | @code { 9 | [Parameter] public Content? Content { get; set; } 10 | [Parameter] public ContentType? ContentType { get; set; } 11 | public string ContentTypeAlias => "Image"; 12 | } -------------------------------------------------------------------------------- /ZauberCMS.Core/Data/Parameters/DataGridParameters.cs: -------------------------------------------------------------------------------- 1 | using ZauberCMS.Core.Shared.Interfaces; 2 | using ZauberCMS.Core.Shared.Models; 3 | 4 | namespace ZauberCMS.Core.Data.Parameters; 5 | 6 | public class DataGridParameters where T : class, ITreeItem 7 | { 8 | public int Skip { get; set; } 9 | public int Take { get; set; } = 20; 10 | public string? OrderBy { get; set; } 11 | public string? Filter { get; set; } 12 | } -------------------------------------------------------------------------------- /ZauberCMS.Components/Editors/Models/NumericPropertySettingsModel.cs: -------------------------------------------------------------------------------- 1 | namespace ZauberCMS.Components.Editors.Models; 2 | 3 | public class NumericPropertySettingsModel 4 | { 5 | public decimal? Min { get; set; } 6 | public decimal? Max { get; set; } 7 | public string? Step { get; set; } 8 | public string? Placeholder { get; set; } 9 | public string? Format { get; set; } 10 | public bool AlignRight { get; set; } 11 | } -------------------------------------------------------------------------------- /ZauberCMS.Core/Shared/Models/Tab.cs: -------------------------------------------------------------------------------- 1 | namespace ZauberCMS.Core.Shared.Models; 2 | 3 | public class Tab 4 | { 5 | public Guid Id { get; set; } = Guid.NewGuid(); 6 | public string Name { get; set; } = string.Empty; 7 | public string Alias => Name.ToLowerInvariant().Replace(" ", "-"); 8 | public int SortOrder { get; set; } 9 | public bool IsSystemTab { get; set; } 10 | public bool IsCompositionTab { get; set; } 11 | } -------------------------------------------------------------------------------- /ZauberCMS.Core/Rendering/ZauberViewPage.cs: -------------------------------------------------------------------------------- 1 | namespace ZauberCMS.Core.Rendering; 2 | 3 | public abstract class ZauberViewPage : Microsoft.AspNetCore.Mvc.Razor.RazorPage, IZauberViewPage 4 | { 5 | //public Content.Models.Content? CurrentPage => TempData["CurrentPage"] as Content.Models.Content; 6 | public Dictionary LanguageKeys => TempData["LanguageKeys"] as Dictionary ?? new Dictionary(); 7 | } -------------------------------------------------------------------------------- /ZauberCMS.Web/ContentBlockPreviews/Quote.razor: -------------------------------------------------------------------------------- 1 | 2 | @using ZauberCMS.Web.ContentBlocks 3 | @implements ZauberCMS.Core.Content.Interfaces.IContentBlockPreview 4 | 5 | @if (Content != null) 6 | { 7 | 8 | } 9 | 10 | @code { 11 | public string ContentTypeAlias => "Quote"; 12 | [Parameter] public Content? Content { get; set; } 13 | [Parameter] public ContentType? ContentType { get; set; } 14 | } 15 | -------------------------------------------------------------------------------- /ZauberCMS.Core/Content/Interfaces/IContentView.cs: -------------------------------------------------------------------------------- 1 | namespace ZauberCMS.Core.Content.Interfaces; 2 | 3 | public interface IContentView 4 | { 5 | /// 6 | /// The Content that the View uses 7 | /// 8 | Models.Content? Content { get; set; } 9 | 10 | /// 11 | /// Language dicts for the currently set language 12 | /// 13 | Dictionary? LanguageKeys { get; set; } 14 | } -------------------------------------------------------------------------------- /ZauberCMS.Components/tailwind.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | corePlugins: { 3 | preflight: false, 4 | }, 5 | mode: "jit", 6 | content: [ 7 | "./**/*.razor", 8 | "!./obj/**/*", 9 | "!./**/obj/**/*", 10 | "!./bin/**/*", 11 | "!./**/bin/**/*" 12 | 13 | ], 14 | theme: { 15 | extend: {} 16 | }, 17 | plugins: [ 18 | require("@tailwindcss/typography"), 19 | ] 20 | } -------------------------------------------------------------------------------- /ZauberCMS.Core/Membership/Models/AuthenticationResult.cs: -------------------------------------------------------------------------------- 1 | using ZauberCMS.Core.Shared.Models; 2 | 3 | namespace ZauberCMS.Core.Membership.Models; 4 | 5 | /// 6 | /// The result of either an attempted login or registration 7 | /// 8 | public class AuthenticationResult 9 | { 10 | public bool Success { get; set; } 11 | public List Messages { get; set; } = []; 12 | public string? NavigateToUrl { get; set; } 13 | } -------------------------------------------------------------------------------- /ZauberCMS.Core/Plugins/Interfaces/IExternalAuthenticationProvider.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.AspNetCore.Authentication; 2 | using Microsoft.Extensions.Configuration; 3 | using Microsoft.Extensions.DependencyInjection; 4 | 5 | namespace ZauberCMS.Core.Plugins.Interfaces; 6 | 7 | public interface IExternalAuthenticationProvider 8 | { 9 | void Add(IServiceCollection servicesCollection, AuthenticationBuilder authenticationBuilder, IConfiguration configuration); 10 | } -------------------------------------------------------------------------------- /ZauberCMS.Components/Seo/Models/SeoSitemap.cs: -------------------------------------------------------------------------------- 1 | using ZauberCMS.Core.Content.Models; 2 | 3 | namespace ZauberCMS.Components.Seo.Models; 4 | 5 | public class SeoSitemap 6 | { 7 | public string? Name { get; set; } 8 | public string? Domain { get; set; } 9 | public string? FileName { get; set; } 10 | public Guid RootContentId { get; set; } 11 | public Content? RootContent { get; set; } 12 | public List ContentTypeIds { get; set; } = []; 13 | } -------------------------------------------------------------------------------- /ZauberCMS.Core/Content/Models/BlockListChanges.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | 3 | namespace ZauberCMS.Core.Content.Models; 4 | 5 | public class BlockListChanges 6 | { 7 | public List AddedItems { get; set; } = []; 8 | public List UpdatedItems { get; set; } = []; 9 | public List DeletedItems { get; set; } = []; 10 | public bool HasChanges => AddedItems.Any() || UpdatedItems.Any() || DeletedItems.Any(); 11 | } 12 | -------------------------------------------------------------------------------- /ZauberCMS.Core/Media/Parameters/SaveMediaParameters.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Microsoft.AspNetCore.Components.Forms; 3 | using ZauberCMS.Core.Shared.Models; 4 | 5 | namespace ZauberCMS.Core.Media.Parameters; 6 | 7 | public class SaveMediaParameters 8 | { 9 | public IBrowserFile? FileToSave { get; set; } 10 | public Media.Models.Media? MediaToSave { get; set; } 11 | public Guid? ParentFolderId { get; set; } 12 | public bool IsUpdate { get; set; } 13 | } -------------------------------------------------------------------------------- /ZauberCMS.Web/ContentBlockPreviews/RichTextEditor.razor: -------------------------------------------------------------------------------- 1 | @using ZauberCMS.Web.ContentBlocks 2 | @implements ZauberCMS.Core.Content.Interfaces.IContentBlockPreview 3 | 4 | @if (Content != null) 5 | { 6 | 7 | } 8 | 9 | @code { 10 | [Parameter] public Content? Content { get; set; } 11 | [Parameter] public ContentType? ContentType { get; set; } 12 | public string ContentTypeAlias => "RichTextEditor"; 13 | } -------------------------------------------------------------------------------- /ZauberCMS.Components/Editors/Models/ZauberCMSEditorSettingsModel.cs: -------------------------------------------------------------------------------- 1 | namespace ZauberCMS.Components.Editors.Models; 2 | 3 | public class ZauberCMSEditorSettingsModel 4 | { 5 | // Optional initial height 6 | public string? Height { get; set; } 7 | 8 | // Toolbar layout: "Full" or "Minimal" 9 | public string ToolbarLayout { get; set; } = "Full"; 10 | 11 | // Image constraints 12 | public bool AllowBase64ImageUpload { get; set; } = false; 13 | } -------------------------------------------------------------------------------- /ZauberCMS.Core/Data/Models/GlobalData.cs: -------------------------------------------------------------------------------- 1 | using ZauberCMS.Core.Extensions; 2 | 3 | namespace ZauberCMS.Core.Data.Models; 4 | 5 | public class GlobalData 6 | { 7 | public Guid Id { get; set; } = Guid.NewGuid().NewSequentialGuid(); 8 | public string? Alias { get; set; } 9 | 10 | public string? Data { get; set; } 11 | public DateTime DateCreated { get; set; } = DateTime.UtcNow; 12 | public DateTime DateUpdated { get; set; } = DateTime.UtcNow; 13 | } -------------------------------------------------------------------------------- /ZauberCMS.Core/Membership/Models/Privilage.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.AspNetCore.Authorization; 2 | 3 | namespace ZauberCMS.Core.Membership.Models; 4 | 5 | #pragma warning disable CS9113 // Parameter is unread. 6 | public abstract class Privilege(IAuthorizationService authorizationService) 7 | #pragma warning restore CS9113 // Parameter is unread. 8 | { 9 | public abstract bool CanCreate(T item, User user); 10 | public abstract bool CanEdit(T item, User user); 11 | } -------------------------------------------------------------------------------- /ZauberCMS.Components/Seo/Navigation/SettingsSeoNavGroup.cs: -------------------------------------------------------------------------------- 1 | using ZauberCMS.Core; 2 | using ZauberCMS.Core.Sections.Interfaces; 3 | 4 | namespace ZauberCMS.Components.Seo.Navigation; 5 | 6 | public class SeoNavGroup : ISectionNavGroup 7 | { 8 | public string Heading => "Seo"; 9 | public string Alias => Constants.Sections.SectionNavGroups.SettingsSeoNavGroup; 10 | public int SortOrder => 25; 11 | public string SectionAlias => Constants.Sections.SettingsSection; 12 | } -------------------------------------------------------------------------------- /ZauberCMS.Core/Tags/Models/TagItem.cs: -------------------------------------------------------------------------------- 1 | using ZauberCMS.Core.Extensions; 2 | 3 | namespace ZauberCMS.Core.Tags.Models; 4 | 5 | public class TagItem 6 | { 7 | public Guid Id { get; set; } = Guid.NewGuid().NewSequentialGuid(); 8 | public DateTime DateCreated { get; set; } = DateTime.UtcNow; 9 | public DateTime DateUpdated { get; set; } = DateTime.UtcNow; 10 | public Guid TagId { get; set; } 11 | public Tag? Tag { get; set; } 12 | public Guid ItemId { get; set; } 13 | } -------------------------------------------------------------------------------- /ZauberCMS.Routing/Views/Shared/Components/RenderBlocks/RenderBlocksModel.cs: -------------------------------------------------------------------------------- 1 | using ZauberCMS.Core.Content.Interfaces; 2 | using ZauberCMS.Core.Content.Models; 3 | 4 | namespace ZauberCMS.Routing.Views.Shared.Components.RenderBlocks; 5 | 6 | public class RenderBlocksModel 7 | { 8 | public List Blocks { get; set; } = []; 9 | public string? SeparatorCssClasses { get; set; } 10 | public Dictionary ContentBlockViews { get; set; } = new(); 11 | } -------------------------------------------------------------------------------- /ZauberCMS.Core/Media/Parameters/GetMediaParameters.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using ZauberCMS.Core.Media.Models; 3 | 4 | namespace ZauberCMS.Core.Media.Parameters; 5 | 6 | public class GetMediaParameters 7 | { 8 | public Guid? Id { get; set; } 9 | public bool IncludeChildren { get; set; } 10 | public bool IncludeParent { get; set; } 11 | public bool Cached { get; set; } 12 | public bool AsNoTracking { get; set; } = true; 13 | public MediaType? MediaType { get; set; } 14 | } -------------------------------------------------------------------------------- /ZauberCMS.Routing/Views/Shared/Components/BootstrapPager/BootstrapPagerViewComponent.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.AspNetCore.Mvc; 2 | using ZauberCMS.Core.Content.Models; 3 | using ZauberCMS.Core.Shared.Models; 4 | 5 | namespace ZauberCMS.Routing.Views.Shared.Components.BootstrapPager; 6 | 7 | public class BootstrapPagerViewComponent : ViewComponent 8 | { 9 | public IViewComponentResult Invoke(PaginatedList model, string baseUrl) 10 | { 11 | return View(model); 12 | } 13 | } -------------------------------------------------------------------------------- /ZauberCMS.Components/Admin/Layout/SectionLayout.razor.css: -------------------------------------------------------------------------------- 1 | #blazor-error-ui { 2 | background: lightyellow; 3 | bottom: 0; 4 | box-shadow: 0 -1px 2px rgba(0, 0, 0, 0.2); 5 | display: none; 6 | left: 0; 7 | padding: 0.6rem 1.25rem 0.7rem 1.25rem; 8 | position: fixed; 9 | width: 100%; 10 | z-index: 1000; 11 | } 12 | 13 | #blazor-error-ui .dismiss { 14 | cursor: pointer; 15 | position: absolute; 16 | right: 0.75rem; 17 | top: 0.5rem; 18 | } 19 | 20 | -------------------------------------------------------------------------------- /ZauberCMS.Core/Shared/Models/ResultMessage.cs: -------------------------------------------------------------------------------- 1 | namespace ZauberCMS.Core.Shared.Models; 2 | 3 | public class ResultMessage 4 | { 5 | public ResultMessage() 6 | { 7 | 8 | } 9 | 10 | public ResultMessage(string message, ResultMessageType messageType) 11 | { 12 | Message = message; 13 | MessageType = messageType; 14 | } 15 | 16 | public string Message { get; set; } = string.Empty; 17 | public ResultMessageType MessageType { get; set; } 18 | } -------------------------------------------------------------------------------- /ZauberCMS.Components/Admin/MediaSection/Navigation/MediaNavGroup.cs: -------------------------------------------------------------------------------- 1 | using ZauberCMS.Core; 2 | using ZauberCMS.Core.Sections.Interfaces; 3 | 4 | namespace ZauberCMS.Components.Admin.MediaSection.Navigation; 5 | 6 | public class MediaNavGroup : ISectionNavGroup 7 | { 8 | public string Heading => "Media"; 9 | public string Alias => Constants.Sections.SectionNavGroups.MediaNavGroup; 10 | public int SortOrder => 0; 11 | public string SectionAlias => Constants.Sections.MediaSection; 12 | } -------------------------------------------------------------------------------- /ZauberCMS.Web/Layouts/MainLayout.razor.css: -------------------------------------------------------------------------------- 1 | #blazor-error-ui { 2 | background: lightyellow; 3 | bottom: 0; 4 | box-shadow: 0 -1px 2px rgba(0, 0, 0, 0.2); 5 | display: none; 6 | left: 0; 7 | padding: 0.6rem 1.25rem 0.7rem 1.25rem; 8 | position: fixed; 9 | width: 100%; 10 | z-index: 1000; 11 | } 12 | 13 | #blazor-error-ui .dismiss { 14 | cursor: pointer; 15 | position: absolute; 16 | right: 0.75rem; 17 | top: 0.5rem; 18 | } 19 | -------------------------------------------------------------------------------- /ZauberCMS.Components/Admin/UsersSection/Navigation/UsersNavGroup.cs: -------------------------------------------------------------------------------- 1 | using ZauberCMS.Core; 2 | using ZauberCMS.Core.Sections.Interfaces; 3 | 4 | namespace ZauberCMS.Components.Admin.UsersSection.Navigation; 5 | 6 | public class UsersNavGroup : ISectionNavGroup 7 | { 8 | public string Heading => "User Management"; 9 | public string Alias => Constants.Sections.SectionNavGroups.UsersNavGroup; 10 | public int SortOrder => 0; 11 | public string SectionAlias => Constants.Sections.UsersSection; 12 | } -------------------------------------------------------------------------------- /ZauberCMS/ZauberCMS.targets: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 7 | 8 | -------------------------------------------------------------------------------- /ZauberCMS.Core/Membership/Mapping/UserTokenDbMapping.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.EntityFrameworkCore; 2 | using Microsoft.EntityFrameworkCore.Metadata.Builders; 3 | using ZauberCMS.Core.Membership.Models; 4 | 5 | namespace ZauberCMS.Core.Membership.Mapping 6 | { 7 | public class UserTokenDbMapping : IEntityTypeConfiguration 8 | { 9 | public void Configure(EntityTypeBuilder builder) 10 | { 11 | builder.Property(x => x.Value).HasMaxLength(4000); 12 | } 13 | } 14 | } -------------------------------------------------------------------------------- /ZauberCMS.Core/Seo/Models/Meta.cs: -------------------------------------------------------------------------------- 1 | namespace ZauberCMS.Core.Seo.Models; 2 | 3 | public class Meta 4 | { 5 | public string? PageTitle { get; set; } 6 | public string? MetaDescription { get; set; } 7 | public Guid? OpenGraphImage { get; set; } 8 | public bool HideFromSearchEngines { get; set; } 9 | public bool ExcludeFromSitemap { get; set; } 10 | public SeoSitemapChangeFrequency ChangeFrequency { get; set; } = SeoSitemapChangeFrequency.Weekly; 11 | public double Priority { get; set; } = 0.5; 12 | } -------------------------------------------------------------------------------- /ZauberCMS.Core/Shared/Models/TreeBranch.cs: -------------------------------------------------------------------------------- 1 | using ZauberCMS.Core.Extensions; 2 | using ZauberCMS.Core.Shared.Interfaces; 3 | 4 | namespace ZauberCMS.Core.Shared.Models; 5 | 6 | public class TreeBranch : ITreeItem 7 | { 8 | public Guid Id { get; set; } = Guid.NewGuid().NewSequentialGuid(); 9 | public string? Name { get; set; } 10 | public string? Icon { get; set; } 11 | public string? Url { get; set; } 12 | public List Branches { get; set; } = []; 13 | public Type? BranchType { get; set; } 14 | } -------------------------------------------------------------------------------- /ZauberCMS.Core/Membership/Mapping/UserLoginDbMapping.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.EntityFrameworkCore; 2 | using Microsoft.EntityFrameworkCore.Metadata.Builders; 3 | using ZauberCMS.Core.Membership.Models; 4 | 5 | namespace ZauberCMS.Core.Membership.Mapping 6 | { 7 | public class UserLoginDbMapping : IEntityTypeConfiguration 8 | { 9 | public void Configure(EntityTypeBuilder builder) 10 | { 11 | builder.Property(x => x.ProviderDisplayName).HasMaxLength(3000); 12 | } 13 | } 14 | } -------------------------------------------------------------------------------- /ZauberCMS.Components/Seo/PageChecker.razor: -------------------------------------------------------------------------------- 1 | @attribute [Route(Urls.AdminSeoPageChecker)] 2 | @using ZauberCMS.Core 3 | 4 | @layout SectionLayout 5 | 6 | SEO Page Checker 7 | 8 | 9 | 10 | 11 | 12 | 13 | @code { 14 | 15 | [CascadingParameter] protected SectionLayout? Layout { get; set; } 16 | 17 | protected override void OnInitialized() 18 | { 19 | Layout?.SetSection(Constants.Sections.SettingsSection); 20 | } 21 | 22 | } -------------------------------------------------------------------------------- /ZauberCMS.Components/Admin/SettingsSection/Navigation/SettingsAdvancedNavGroup.cs: -------------------------------------------------------------------------------- 1 | using ZauberCMS.Core; 2 | using ZauberCMS.Core.Sections.Interfaces; 3 | 4 | namespace ZauberCMS.Components.Admin.SettingsSection.Navigation; 5 | 6 | public class SettingsAdvancedNavGroup : ISectionNavGroup 7 | { 8 | public string Heading => "Advanced"; 9 | public string Alias => Constants.Sections.SectionNavGroups.SettingsAdvancedNavGroup; 10 | public int SortOrder => 40; 11 | public string SectionAlias => Constants.Sections.SettingsSection; 12 | } -------------------------------------------------------------------------------- /ZauberCMS.Components/Admin/SettingsSection/Navigation/SettingsLanguageNavGroup.cs: -------------------------------------------------------------------------------- 1 | using ZauberCMS.Core; 2 | using ZauberCMS.Core.Sections.Interfaces; 3 | 4 | namespace ZauberCMS.Components.Admin.SettingsSection.Navigation; 5 | 6 | public class SettingsLanguageNavGroup : ISectionNavGroup 7 | { 8 | public string Heading => "Languages"; 9 | public string Alias => Constants.Sections.SectionNavGroups.SettingsLanguagesNavGroup; 10 | public int SortOrder => 30; 11 | public string SectionAlias => Constants.Sections.SettingsSection; 12 | } -------------------------------------------------------------------------------- /ZauberCMS.Components/Pages/MissingView.razor: -------------------------------------------------------------------------------- 1 | @implements ZauberCMS.Core.Content.Interfaces.IContentView 2 | @layout BlankLayout 3 | 4 | Missing View 5 | 6 |
7 |

Missing View

8 |

It looks like you haven't selected a Component View for the @Content?.Name page, or the Component View has been deleted.

9 |
10 | 11 | @code { 12 | [Parameter] public Content? Content { get; set; } 13 | [Parameter] public Dictionary? LanguageKeys { get; set; } 14 | } -------------------------------------------------------------------------------- /ZauberCMS.Web/ContentBlockPreviews/FAQItem.razor: -------------------------------------------------------------------------------- 1 | @using ZauberCMS.Web.ContentBlocks 2 | @implements ZauberCMS.Core.Content.Interfaces.IContentBlockPreview 3 | @if (Content != null) 4 | { 5 |
6 |

@(Content.GetValue("Question"))

7 | 8 |
9 | } 10 | 11 | @code { 12 | [Parameter] public Content? Content { get; set; } 13 | [Parameter] public ContentType? ContentType { get; set; } 14 | public string ContentTypeAlias => "FAQItem"; 15 | } -------------------------------------------------------------------------------- /ZauberCMS.Components/Admin/StructureSection/Navigation/CompositionsNavGroup.cs: -------------------------------------------------------------------------------- 1 | using ZauberCMS.Core; 2 | using ZauberCMS.Core.Sections.Interfaces; 3 | 4 | namespace ZauberCMS.Components.Admin.StructureSection.Navigation; 5 | 6 | public class CompositionsNavGroup : ISectionNavGroup 7 | { 8 | public string Heading => "Compositions"; 9 | public string Alias => Constants.Sections.SectionNavGroups.StructureCompositionsNavGroup; 10 | public int SortOrder => 30; 11 | public string SectionAlias => Constants.Sections.StructureSection; 12 | } -------------------------------------------------------------------------------- /ZauberCMS.Components/Admin/StructureSection/Navigation/ContentTypesNavGroup.cs: -------------------------------------------------------------------------------- 1 | using ZauberCMS.Core; 2 | using ZauberCMS.Core.Sections.Interfaces; 3 | 4 | namespace ZauberCMS.Components.Admin.StructureSection.Navigation; 5 | 6 | public class ContentTypesNavGroup : ISectionNavGroup 7 | { 8 | public string Heading => "Content Types"; 9 | public string Alias => Constants.Sections.SectionNavGroups.StructureContentTypesNavGroup; 10 | public int SortOrder => 10; 11 | public string SectionAlias => Constants.Sections.StructureSection; 12 | } -------------------------------------------------------------------------------- /ZauberCMS.Components/Admin/StructureSection/Navigation/ElementTypesNavGroup.cs: -------------------------------------------------------------------------------- 1 | using ZauberCMS.Core; 2 | using ZauberCMS.Core.Sections.Interfaces; 3 | 4 | namespace ZauberCMS.Components.Admin.StructureSection.Navigation; 5 | 6 | public class ElementTypesNavGroup : ISectionNavGroup 7 | { 8 | public string Heading => "Element Types"; 9 | public string Alias => Constants.Sections.SectionNavGroups.StructureElementTypesNavGroup; 10 | public int SortOrder => 20; 11 | public string SectionAlias => Constants.Sections.StructureSection; 12 | } -------------------------------------------------------------------------------- /ZauberCMS.Components/Seo/Startup/SeoSitemapStartUp.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.Extensions.Configuration; 2 | using Microsoft.Extensions.DependencyInjection; 3 | using ZauberCMS.Core.Plugins.Interfaces; 4 | 5 | namespace ZauberCMS.Components.Seo.Startup; 6 | 7 | public class SeoSitemapStartUp : IStartupPlugin 8 | { 9 | public void Register(IServiceCollection services, IConfiguration configuration) 10 | { 11 | // Register the sitemap generator as a hosted service 12 | services.AddHostedService(); 13 | } 14 | } -------------------------------------------------------------------------------- /ZauberCMS.Components/Editors/MultipleMediaUpload.razor.js: -------------------------------------------------------------------------------- 1 | export function initializeFilePaste(fileDropContainer, inputFile) { 2 | 3 | function onPaste(e) { 4 | inputFile.files = e.clipboardData.files; 5 | const event = new Event('change', { bubbles: true }); 6 | inputFile.dispatchEvent(event); 7 | } 8 | 9 | fileDropContainer.addEventListener('paste', onPaste); 10 | 11 | return { 12 | dispose: () => { 13 | fileDropContainer.removeEventListener('paste', onPaste); 14 | } 15 | } 16 | } -------------------------------------------------------------------------------- /ZauberCMS.Core/Content/Parameters/SaveContentParameters.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using ZauberCMS.Core.Membership.Models; 3 | using ZauberCMS.Core.Shared.Models; 4 | 5 | namespace ZauberCMS.Core.Content.Parameters; 6 | 7 | public class SaveContentParameters 8 | { 9 | public Content.Models.Content? Content { get; set; } 10 | public List Roles { get; set; } = []; 11 | public bool UpdateContentRoles { get; set; } 12 | public bool ExcludePropertyData { get; set; } 13 | public bool SaveUnpublishedOnly { get; set; } 14 | } -------------------------------------------------------------------------------- /ZauberCMS.Core/Membership/Mapping/UserClaimDbMapping.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.EntityFrameworkCore; 2 | using Microsoft.EntityFrameworkCore.Metadata.Builders; 3 | using ZauberCMS.Core.Membership.Models; 4 | 5 | namespace ZauberCMS.Core.Membership.Mapping; 6 | 7 | public class UserClaimDbMapping : IEntityTypeConfiguration 8 | { 9 | public void Configure(EntityTypeBuilder builder) 10 | { 11 | builder.Property(x => x.ClaimValue).HasMaxLength(3000); 12 | builder.Property(x => x.ClaimType).HasMaxLength(3000); 13 | } 14 | } -------------------------------------------------------------------------------- /ZauberCMS.Core/Shared/Models/TreeStub.cs: -------------------------------------------------------------------------------- 1 | using ZauberCMS.Core.Extensions; 2 | using ZauberCMS.Core.Shared.Interfaces; 3 | 4 | namespace ZauberCMS.Core.Shared.Models; 5 | 6 | public class TreeStub : ITreeItem 7 | { 8 | public Guid Id { get; set; } = Guid.NewGuid().NewSequentialGuid(); 9 | public string? Name { get; set; } 10 | public string? Icon { get; set; } 11 | public int SortOrder { get; set; } 12 | public string? Url { get; set; } 13 | public Type? StubType { get; set; } 14 | public List Branches { get; set; } = []; 15 | } -------------------------------------------------------------------------------- /ZauberCMS.Components/Admin/ContentSection/Navigation/ContentNavGroup.cs: -------------------------------------------------------------------------------- 1 | using ZauberCMS.Core; 2 | using ZauberCMS.Core.Sections.Interfaces; 3 | 4 | namespace ZauberCMS.Components.Admin.ContentSection.Navigation; 5 | 6 | public class ContentNavGroup : ISectionNavGroup 7 | { 8 | public string Heading => "Content"; 9 | public string Alias => Constants.Sections.SectionNavGroups.ContentNavGroup; 10 | public int SortOrder => 0; 11 | public string SectionAlias => Constants.Sections.ContentSection; 12 | public List Actions => []; 13 | } -------------------------------------------------------------------------------- /ZauberCMS.Web/Shared/BlogPostPreview.razor: -------------------------------------------------------------------------------- 1 | @using ZauberCMS.Core.Seo.Models 2 | @if (Content != null) 3 | { 4 |
5 | 6 |

@Content.Name

7 |

@(Content.GetValue("SEO")?.MetaDescription)

8 |
9 | 12 |
13 | } 14 | 15 | @code { 16 | [Parameter] public Content? Content { get; set; } 17 | } -------------------------------------------------------------------------------- /ZauberCMS.Core/Sections/Interfaces/ISectionNavGroupAction.cs: -------------------------------------------------------------------------------- 1 | using Blazored.Modal.Services; 2 | using Microsoft.AspNetCore.Components; 3 | using Radzen; 4 | 5 | namespace ZauberCMS.Core.Sections.Interfaces; 6 | 7 | public interface ISectionNavGroupAction 8 | { 9 | string Text { get; } 10 | string Icon { get; } 11 | string IconColor { get; } 12 | string SectionNavGroupAlias { get; } 13 | int SortOrder { get; } 14 | Task ContextMenuAction(MenuItemEventArgs e, NavigationManager navigationManager, ContextMenuService contextMenuService, IModalService modalService); 15 | } -------------------------------------------------------------------------------- /ZauberCMS.Core/Audit/Models/Audit.cs: -------------------------------------------------------------------------------- 1 | using ZauberCMS.Core.Extensions; 2 | using ZauberCMS.Core.Shared.Interfaces; 3 | 4 | namespace ZauberCMS.Core.Audit.Models; 5 | 6 | public class Audit : ITreeItem 7 | { 8 | public Guid Id { get; set; } = Guid.NewGuid().NewSequentialGuid(); 9 | public DateTime DateCreated { get; set; } = DateTime.UtcNow; 10 | public DateTime DateUpdated { get; set; } = DateTime.UtcNow; 11 | public string? Description { get; set; } 12 | public string? Name 13 | { 14 | get => Description; 15 | set => Description = value; 16 | } 17 | } -------------------------------------------------------------------------------- /ZauberCMS.Core/Extensions/TupleExtensions.cs: -------------------------------------------------------------------------------- 1 | namespace ZauberCMS.Core.Extensions; 2 | 3 | public static class TupleExtensions 4 | { 5 | public static void SortList((int oldIndex, int newIndex) indices, List items) 6 | { 7 | var (oldIndex, newIndex) = indices; 8 | 9 | var itemToMove = items[oldIndex]; 10 | items.RemoveAt(oldIndex); 11 | 12 | if (newIndex < items.Count) 13 | { 14 | items.Insert(newIndex, itemToMove); 15 | } 16 | else 17 | { 18 | items.Add(itemToMove); 19 | } 20 | } 21 | } -------------------------------------------------------------------------------- /ZauberCMS.Core/Membership/Mapping/RoleClaimDbMapping.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.EntityFrameworkCore; 2 | using Microsoft.EntityFrameworkCore.Metadata.Builders; 3 | using ZauberCMS.Core.Membership.Models; 4 | 5 | namespace ZauberCMS.Core.Membership.Mapping 6 | { 7 | public class RoleClaimDbMapping : IEntityTypeConfiguration 8 | { 9 | public void Configure(EntityTypeBuilder builder) 10 | { 11 | builder.Property(x => x.ClaimType).HasMaxLength(3000); 12 | builder.Property(x => x.ClaimValue).HasMaxLength(3000); 13 | } 14 | } 15 | } -------------------------------------------------------------------------------- /ZauberCMS.Web/ContentBlocks/RTEBlock.razor: -------------------------------------------------------------------------------- 1 | @using RenderMode = Microsoft.AspNetCore.Mvc.Rendering.RenderMode 2 | @implements ZauberCMS.Core.Content.Interfaces.IContentBlockView 3 | @if (Content != null) 4 | { 5 |
6 | @((MarkupString)(Content.GetValue(PropertyName) ?? string.Empty)) 7 |
8 | } 9 | 10 | @code { 11 | [Parameter] public Content? Content { get; set; } 12 | [Parameter] public string PropertyName { get; set; } = "Text"; 13 | public string ContentTypeAlias => "RichTextEditor"; 14 | public RenderMode RenderMode => RenderMode.Static; 15 | } -------------------------------------------------------------------------------- /ZauberCMS.Web/Program.cs: -------------------------------------------------------------------------------- 1 | using ZauberCMS.Components; 2 | using ZauberCMS.Core; 3 | 4 | var builder = WebApplication.CreateBuilder(args); 5 | 6 | builder.AddZauberCms(); 7 | 8 | var app = builder.Build(); 9 | 10 | // Configure the HTTP request pipeline. 11 | if (!app.Environment.IsDevelopment()) 12 | { 13 | app.UseExceptionHandler("/Home/Error", createScopeForErrors: true); 14 | // The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts. 15 | app.UseHsts(); 16 | } 17 | 18 | app.AddZauberCms(); 19 | 20 | app.Run(); -------------------------------------------------------------------------------- /ZauberCMS.Routing/Views/Shared/Components/RenderBlocks/Default.cshtml: -------------------------------------------------------------------------------- 1 | @model ZauberCMS.Routing.Views.Shared.Components.RenderBlocks.RenderBlocksModel 2 | 3 | @foreach (var block in Model.Blocks) 4 | { 5 | if (Model.ContentBlockViews.TryGetValue(block.ContentTypeAlias ?? "", out var contentBlockView)) 6 | { 7 |
8 | 11 |
12 | } 13 | } -------------------------------------------------------------------------------- /ZauberCMS.Core/Shared/Comparers/ITreeEqualityComparer.cs: -------------------------------------------------------------------------------- 1 | using ZauberCMS.Core.Shared.Interfaces; 2 | 3 | namespace ZauberCMS.Core.Shared.Comparers; 4 | 5 | public class ITreeEqualityComparer : IEqualityComparer where T : class, ITreeItem 6 | { 7 | public bool Equals(T? x, T? y) 8 | { 9 | if (x is null && y is null) return true; 10 | if (x is null || y is null) return false; 11 | return x.Id == y.Id; // Compare based on Id 12 | } 13 | 14 | public int GetHashCode(T obj) 15 | { 16 | return obj.Id.GetHashCode(); // Use Id for hash code 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /ZauberCMS.Core/Shared/Validation/BaseFluentValidator.cs: -------------------------------------------------------------------------------- 1 | using FluentValidation; 2 | 3 | namespace ZauberCMS.Core.Shared.Validation; 4 | 5 | public class BaseFluentValidator : AbstractValidator 6 | { 7 | public Func>> ValidateValue => async (model, propertyName) => 8 | { 9 | var result = await ValidateAsync(ValidationContext.CreateWithOptions((T)model, x => x.IncludeProperties(propertyName))); 10 | if (result.IsValid) 11 | return Array.Empty(); 12 | return result.Errors.Select(e => e.ErrorMessage); 13 | }; 14 | } -------------------------------------------------------------------------------- /ZauberCMS.Core/Audit/Mapping/AuditDbMapper.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.EntityFrameworkCore; 2 | using Microsoft.EntityFrameworkCore.Metadata.Builders; 3 | 4 | namespace ZauberCMS.Core.Audit.Mapping; 5 | 6 | public class AuditDbMapper : IEntityTypeConfiguration 7 | { 8 | public void Configure(EntityTypeBuilder builder) 9 | { 10 | builder.ToTable("ZauberAudits"); 11 | builder.HasKey(x => x.Id); 12 | builder.Property(x => x.Id).IsRequired(); 13 | builder.Property(x => x.Description).HasMaxLength(3000); 14 | 15 | builder.Ignore(x => x.Name); 16 | } 17 | } -------------------------------------------------------------------------------- /ZauberCMS.Components/Admin/SettingsSection/Navigation/SettingsNavGroup.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.Extensions.Localization; 2 | using ZauberCMS.Core; 3 | using ZauberCMS.Core.Sections.Interfaces; 4 | 5 | namespace ZauberCMS.Components.Admin.SettingsSection.Navigation; 6 | 7 | public class SettingsNavGroup(IStringLocalizer localizer) : ISectionNavGroup 8 | { 9 | public string Heading => localizer["Heading.Settings"]; 10 | public string Alias => Constants.Sections.SectionNavGroups.SettingsNavGroup; 11 | public int SortOrder => 10; 12 | public string SectionAlias => Constants.Sections.SettingsSection; 13 | } -------------------------------------------------------------------------------- /ZauberCMS.Core/Data/Models/QueryModel.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.EntityFrameworkCore; 2 | using ZauberCMS.Core.Data.Interfaces; 3 | 4 | namespace ZauberCMS.Core.Data.Models; 5 | 6 | public class QueryModel : IQueryModel 7 | { 8 | public string? Name { get; set; } 9 | public Func> Query { get; set; } = null!; 10 | 11 | public async Task> ExecuteQuery(IZauberDbContext dbContext, CancellationToken cancellationToken) 12 | { 13 | var queryResult = await Query(dbContext).ToListAsync(cancellationToken); 14 | return queryResult.Cast(); 15 | } 16 | } -------------------------------------------------------------------------------- /ZauberCMS.Core/Shared/ZauberRouteValueTransformer.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.AspNetCore.Http; 2 | using Microsoft.AspNetCore.Mvc.Routing; 3 | using Microsoft.AspNetCore.Routing; 4 | using ZauberCMS.Core.Content.ContentFinders; 5 | 6 | namespace ZauberCMS.Core.Shared; 7 | 8 | public class ZauberRouteValueTransformer(ContentFinderPipeline contentFinderPipeline) : DynamicRouteValueTransformer 9 | { 10 | public override async ValueTask TransformAsync(HttpContext httpContext, RouteValueDictionary values) 11 | { 12 | return await contentFinderPipeline.FindContent(httpContext, values); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /ZauberCMS.Core/Languages/Models/LanguageDictionary.cs: -------------------------------------------------------------------------------- 1 | using ZauberCMS.Core.Extensions; 2 | 3 | namespace ZauberCMS.Core.Languages.Models; 4 | 5 | public class LanguageDictionary 6 | { 7 | /// 8 | /// The ID 9 | /// 10 | public Guid Id { get; set; } = Guid.NewGuid().NewSequentialGuid(); 11 | 12 | /// 13 | /// The text key for the language text 14 | /// 15 | public string Key { get; set; } = string.Empty; 16 | 17 | /// 18 | /// Child language texts 19 | /// 20 | public List Texts { get; set; } = []; 21 | } -------------------------------------------------------------------------------- /ZauberCMS.Template/template/ZauberCMSTemplate.Site/Program.cs: -------------------------------------------------------------------------------- 1 | using ZauberCMS.Components; 2 | using ZauberCMS.Core; 3 | 4 | var builder = WebApplication.CreateBuilder(args); 5 | 6 | builder.AddZauberCms(); 7 | 8 | var app = builder.Build(); 9 | 10 | // Configure the HTTP request pipeline. 11 | if (!app.Environment.IsDevelopment()) 12 | { 13 | // app.UseExceptionHandler("/Home/Error", createScopeForErrors: true); 14 | // The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts. 15 | app.UseHsts(); 16 | } 17 | 18 | app.AddZauberCms(); 19 | 20 | app.Run(); -------------------------------------------------------------------------------- /ZauberCMS.Core/Content/Parameters/GetContentParameters.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace ZauberCMS.Core.Content.Parameters; 4 | 5 | public class GetContentParameters 6 | { 7 | public bool Cached { get; set; } 8 | public bool IncludeUnpublishedContent { get; set; } 9 | public bool IncludeContentRoles { get; set; } 10 | public Guid? Id { get; set; } 11 | public bool IncludeChildren { get; set; } 12 | public bool IncludeParent { get; set; } 13 | public bool IncludeUnpublished { get; set; } 14 | public bool AsNoTracking { get; set; } = true; 15 | public string ContentTypeAlias { get; set; } = string.Empty; 16 | } -------------------------------------------------------------------------------- /ZauberCMS.Components/Admin/Dashboards/StructureInfoDashboard.razor: -------------------------------------------------------------------------------- 1 | @implements ZauberCMS.Core.Sections.Interfaces.ISectionDashboard 2 | 3 |
4 |

Content Types - These are the blue prints for the content you create.

5 |

Element Types - These are used in the Block List Editor

6 | @*

Compositions - These are used as re-usable groups of tabs and editors for your content types

*@ 7 |
8 | 9 | @code { 10 | public string TabName => "Info"; 11 | public int SortOrder => 1; 12 | public string SectionAlias => Constants.Sections.StructureSection; 13 | } 14 | -------------------------------------------------------------------------------- /ZauberCMS.Core/Shared/Dictionary.cs: -------------------------------------------------------------------------------- 1 | namespace ZauberCMS.Core.Shared; 2 | 3 | public class Dictionary : Dictionary, TValue> 4 | { 5 | 6 | public TValue this[TKey1 key1, TKey2 key2] 7 | { 8 | get => base[Tuple.Create(key1, key2)]; 9 | set => base[Tuple.Create(key1, key2)] = value; 10 | } 11 | 12 | public void Add(TKey1 key1, TKey2 key2, TValue value) 13 | { 14 | base.Add(Tuple.Create(key1, key2), value); 15 | } 16 | 17 | public bool ContainsKey(TKey1 key1, TKey2 key2) 18 | { 19 | return base.ContainsKey(Tuple.Create(key1, key2)); 20 | } 21 | } -------------------------------------------------------------------------------- /ZauberCMS.Components/Editors/Models/ListPropertySettingsModel.cs: -------------------------------------------------------------------------------- 1 | using ZauberCMS.Core.Content.Models; 2 | 3 | namespace ZauberCMS.Components.Editors.Models; 4 | 5 | public class ListPropertySettingsModel 6 | { 7 | /// 8 | /// The optional data source for the list 9 | /// 10 | public string? DataSource { get; set; } 11 | 12 | /// 13 | /// Manual items for the list 14 | /// 15 | public List Items { get; set; } = []; 16 | 17 | /// 18 | /// Limit the maximum amount selectable 19 | /// 20 | public int MaxAmount { get; set; } 21 | } -------------------------------------------------------------------------------- /ZauberCMS.Components/Admin/ContentSection/Dialogs/UnpublishedContentList.razor: -------------------------------------------------------------------------------- 1 | @using ZauberCMS.Core.Content.Parameters 2 | 3 | @foreach (var content in UnpublishedContent) 4 | { 5 |

6 | @content.Name 7 |

8 | } 9 | 10 | @code { 11 | private IEnumerable UnpublishedContent { get; set; } = []; 12 | 13 | protected override async Task OnInitializedAsync() 14 | { 15 | var items = await ContentService.QueryContentAsync(new QueryContentParameters { AmountPerPage = 100, OnlyUnpublished = true }); 16 | UnpublishedContent = items.Items; 17 | } 18 | } -------------------------------------------------------------------------------- /ZauberCMS.Core/Membership/IdentityUserAccessor.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.AspNetCore.Components.Authorization; 2 | using Microsoft.AspNetCore.Identity; 3 | using ZauberCMS.Core.Membership.Models; 4 | 5 | namespace ZauberCMS.Core.Membership; 6 | 7 | public sealed class IdentityUserAccessor( 8 | UserManager userManager, 9 | AuthenticationStateProvider authenticationStateProvider) 10 | { 11 | public async Task GetRequiredUserAsync() 12 | { 13 | var authState = await authenticationStateProvider.GetAuthenticationStateAsync(); 14 | var user = await userManager.GetUserAsync(authState.User); 15 | return user; 16 | } 17 | } -------------------------------------------------------------------------------- /ZauberCMS.Routing/_Imports.razor: -------------------------------------------------------------------------------- 1 | @using System.Net.Http 2 | @using System.Net.Http.Json 3 | @using Microsoft.AspNetCore.Components.Forms 4 | @using Microsoft.AspNetCore.Components.Routing 5 | @using Microsoft.AspNetCore.Components.Web 6 | @using static Microsoft.AspNetCore.Components.Web.RenderMode 7 | @using Microsoft.AspNetCore.Components.Web.Virtualization 8 | @using Microsoft.JSInterop 9 | @using ZauberCMS.Core.Extensions 10 | @using ZauberCMS.Core.Content.Models 11 | @using Microsoft.AspNetCore.Components.Sections 12 | @using Radzen 13 | @using Radzen.Blazor 14 | @using Blazored.Modal 15 | @using Blazored.Modal.Services 16 | @inject NavigationManager NavigationManager -------------------------------------------------------------------------------- /ZauberCMS.Core/Membership/Parameters/CreateUpdateUserParameters.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.AspNetCore.Components.Forms; 2 | using ZauberCMS.Core.Membership.Models; 3 | using ZauberCMS.Core.Shared.Models; 4 | 5 | namespace ZauberCMS.Core.Membership.Parameters; 6 | 7 | public class CreateUpdateUserParameters 8 | { 9 | public string? CurrentPassword { get; set; } 10 | public string? NewPassword { get; set; } 11 | public string? NewPasswordConfirmation { get; set; } 12 | public User User { get; set; } = new(); 13 | public IBrowserFile? ProfileImageUpload { get; set; } 14 | public string? Password { get; set; } 15 | public List? Roles { get; set; } 16 | } -------------------------------------------------------------------------------- /ZauberCMS.Core/Tags/Models/Tag.cs: -------------------------------------------------------------------------------- 1 | using ZauberCMS.Core.Extensions; 2 | 3 | namespace ZauberCMS.Core.Tags.Models; 4 | 5 | public class Tag 6 | { 7 | public Guid Id { get; set; } = Guid.NewGuid().NewSequentialGuid(); 8 | public string TagName { get; set; } = string.Empty; 9 | public string Slug { get; set; } = string.Empty; 10 | public DateTime DateCreated { get; set; } = DateTime.UtcNow; 11 | public DateTime DateUpdated { get; set; } = DateTime.UtcNow; 12 | public int SortOrder { get; set; } 13 | 14 | public List TagItems { get; set; } = []; 15 | 16 | // Not mapped, used for querying 17 | public int Count { get; set; } 18 | } -------------------------------------------------------------------------------- /ZauberCMS.Core/Media/Validation/ValidateMedia.cs: -------------------------------------------------------------------------------- 1 | using ZauberCMS.Core.Extensions; 2 | using ZauberCMS.Core.Shared.Validation.Interfaces; 3 | using ZauberCMS.Core.Shared.Validation.Models; 4 | 5 | namespace ZauberCMS.Core.Media.Validation; 6 | 7 | public class ValidateMedia : IValidate 8 | { 9 | public Task Validate(Models.Media item) 10 | { 11 | var validateResult = new ValidateResult(); 12 | 13 | if (item.Name.IsNullOrWhiteSpace()) 14 | { 15 | validateResult.ErrorMessages.Add("You cannot leave the name empty"); 16 | } 17 | 18 | return Task.FromResult(validateResult); 19 | } 20 | } -------------------------------------------------------------------------------- /ZauberCMS.Routing/CatchAll.razor: -------------------------------------------------------------------------------- 1 | @page "/{**slug}" 2 | @using ZauberCMS.Components.Pages 3 | 4 | @code{ 5 | @* 6 | This page is the final catch all for any routes that are not hard coded 7 | usually these are the front end pages which are then fetched from the DB 8 | this single page is in the project, because how the Blazor routing works 9 | I need to pass this assembly in last so it loads all routes from all 10 | other assemblies first, making this the fall back and so it doesn't interfere 11 | or intercept routes that is should not 12 | *@ 13 | [Parameter] public string? Slug { get; set; } 14 | } -------------------------------------------------------------------------------- /ZauberCMS.Core/Membership/Parameters/LoginUserParameters.cs: -------------------------------------------------------------------------------- 1 | using System.ComponentModel.DataAnnotations; 2 | using ZauberCMS.Core.Membership.Models; 3 | 4 | namespace ZauberCMS.Core.Membership.Parameters; 5 | 6 | public class LoginUserParameters 7 | { 8 | [Required] 9 | [EmailAddress] 10 | [Display(Name = "Email")] 11 | public string Email { get; set; } = string.Empty; 12 | 13 | [Required] 14 | [DataType(DataType.Password)] 15 | [Display(Name = "Password")] 16 | public string Password { get; set; } = string.Empty; 17 | 18 | [Display(Name = "Remember me?")] 19 | public bool RememberMe { get; set; } 20 | 21 | public string? ReturnUrl { get; set; } 22 | } -------------------------------------------------------------------------------- /ZauberCMS.Core/Audit/Interfaces/IAuditService.cs: -------------------------------------------------------------------------------- 1 | using System.Threading; 2 | using System.Threading.Tasks; 3 | using ZauberCMS.Core.Audit.Parameters; 4 | using ZauberCMS.Core.Shared.Models; 5 | 6 | namespace ZauberCMS.Core.Audit.Interfaces; 7 | 8 | public interface IAuditService 9 | { 10 | Task> SaveAuditAsync(SaveAuditParameters parameters, CancellationToken cancellationToken = default); 11 | Task> QueryAuditsAsync(QueryAuditsParameters parameters, CancellationToken cancellationToken = default); 12 | Task> CleanupOldAuditsAsync(CleanupOldAuditsParameters parameters, CancellationToken cancellationToken = default); 13 | } -------------------------------------------------------------------------------- /ZauberCMS.Core/Shared/Models/NavigationItem.cs: -------------------------------------------------------------------------------- 1 | using System.ComponentModel.DataAnnotations; 2 | using ZauberCMS.Core.Extensions; 3 | using ZauberCMS.Core.Shared.Interfaces; 4 | 5 | namespace ZauberCMS.Core.Shared.Models; 6 | 7 | public class NavigationItem : ITreeItem 8 | { 9 | public Guid Id { get; set; } = Guid.NewGuid().NewSequentialGuid(); 10 | 11 | [Required] 12 | public string? Name { get; set; } 13 | 14 | [Required] 15 | public string? Url { get; set; } 16 | 17 | public List Children { get; set; } = []; 18 | public Guid? ContentId { get; set; } 19 | public int SortOrder { get; set; } 20 | public bool OpenInNewWindow { get; set; } 21 | } -------------------------------------------------------------------------------- /ZauberCMS.Core/Data/Mapping/GlobalDataDbMapping.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.EntityFrameworkCore; 2 | using Microsoft.EntityFrameworkCore.Metadata.Builders; 3 | using ZauberCMS.Core.Data.Models; 4 | 5 | namespace ZauberCMS.Core.Data.Mapping; 6 | 7 | public class GlobalDataDbMapping : IEntityTypeConfiguration 8 | { 9 | public void Configure(EntityTypeBuilder builder) 10 | { 11 | builder.ToTable("ZauberGlobalData"); 12 | builder.HasKey(x => x.Id); 13 | builder.Property(x => x.Id).IsRequired(); 14 | builder.Property(x => x.Alias).IsRequired().HasMaxLength(1000); 15 | builder.HasIndex(x => x.Alias).HasDatabaseName("IX_GlobalDataAlias"); 16 | } 17 | } -------------------------------------------------------------------------------- /ZauberCMS.Web/ContentBlocks/QuoteBlock.razor: -------------------------------------------------------------------------------- 1 | @using RenderMode = Microsoft.AspNetCore.Mvc.Rendering.RenderMode 2 | @implements ZauberCMS.Core.Content.Interfaces.IContentBlockView 3 | @if (Content != null) 4 | { 5 |
6 |
7 |

@(Content.GetValue("Quote"))

8 |
9 | 12 |
13 | } 14 | 15 | @code{ 16 | [Parameter] public Content? Content { get; set; } 17 | public string ContentTypeAlias => "Quote"; 18 | public RenderMode RenderMode => RenderMode.Static; 19 | } -------------------------------------------------------------------------------- /ZauberCMS.Components/wwwroot/img/zauber-logo.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /ZauberCMS.Core/Membership/Models/UserPropertyValue.cs: -------------------------------------------------------------------------------- 1 | using ZauberCMS.Core.Content.Interfaces; 2 | using ZauberCMS.Core.Extensions; 3 | 4 | namespace ZauberCMS.Core.Membership.Models; 5 | 6 | public class UserPropertyValue : IPropertyValue 7 | { 8 | public Guid Id { get; set; } = Guid.NewGuid().NewSequentialGuid(); 9 | public string Alias { get; set; } = string.Empty; 10 | public Guid ContentTypePropertyId { get; set; } 11 | // ReSharper disable once EntityFramework.ModelValidation.UnlimitedStringLength 12 | public string Value { get; set; } = string.Empty; 13 | public DateTime? DateUpdated { get; set; } = DateTime.UtcNow; 14 | public Guid UserId { get; set; } 15 | public User? User { get; set; } 16 | } -------------------------------------------------------------------------------- /ZauberCMS.Core/Membership/Mapping/UserRoleDbMapping.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.EntityFrameworkCore; 2 | using Microsoft.EntityFrameworkCore.Metadata.Builders; 3 | using ZauberCMS.Core.Membership.Models; 4 | 5 | namespace ZauberCMS.Core.Membership.Mapping; 6 | 7 | public class UserRoleDbMapping : IEntityTypeConfiguration 8 | { 9 | public void Configure(EntityTypeBuilder builder) 10 | { 11 | builder 12 | .HasOne(ur => ur.User) 13 | .WithMany(u => u.UserRoles) 14 | .HasForeignKey(ur => ur.UserId); 15 | 16 | builder 17 | .HasOne(ur => ur.Role) 18 | .WithMany(r => r.UserRoles) 19 | .HasForeignKey(ur => ur.RoleId); 20 | } 21 | } -------------------------------------------------------------------------------- /ZauberCMS.Core/Languages/Mapping/LanguageTextDbMapping.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.EntityFrameworkCore; 2 | using Microsoft.EntityFrameworkCore.Metadata.Builders; 3 | using ZauberCMS.Core.Languages.Models; 4 | 5 | namespace ZauberCMS.Core.Languages.Mapping; 6 | 7 | public class LanguageTextDbMapping : IEntityTypeConfiguration 8 | { 9 | public void Configure(EntityTypeBuilder builder) 10 | { 11 | builder.ToTable("ZauberLanguageTexts"); 12 | builder.HasKey(x => x.Id); 13 | builder.Property(x => x.Id).IsRequired(); 14 | builder.Property(x => x.Value).IsRequired().HasMaxLength(1000); 15 | 16 | builder.HasIndex(x => x.Value).HasDatabaseName("IX_LanguageText_Value"); 17 | } 18 | } -------------------------------------------------------------------------------- /ZauberCMS.Routing/Views/Shared/_ZauberLayout.cshtml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | @await RenderSectionAsync("Head", required: true) 9 | 10 | 11 | 12 | 13 | 14 | @RenderBody() 15 | 16 | 17 | -------------------------------------------------------------------------------- /ZauberCMS/Components/Routes.razor: -------------------------------------------------------------------------------- 1 | @using Microsoft.AspNetCore.Components.Authorization 2 | @using ZauberCMS.Core.Plugins 3 | @using ZauberCMS.Components.Account.Shared 4 | 5 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | @**@ 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /ZauberCMS.Components/Pages/NotFound404.razor: -------------------------------------------------------------------------------- 1 | @using Microsoft.AspNetCore.Http 2 | @implements ZauberCMS.Core.Content.Interfaces.IContentView 3 | @layout BlankLayout 4 | 5 | 404 Missing Page 6 | 7 |
8 |

Whooops, we can't find that page!

9 |
10 | 11 | @code { 12 | [CascadingParameter] private HttpContext? HttpContext { get; set; } 13 | protected override void OnInitialized() 14 | { 15 | if (HttpContext != null) 16 | { 17 | HttpContext.Response.StatusCode = StatusCodes.Status404NotFound; 18 | } 19 | } 20 | 21 | [Parameter] public Content? Content { get; set; } 22 | [Parameter] public Dictionary? LanguageKeys { get; set; } 23 | } -------------------------------------------------------------------------------- /ZauberCMS.Core/Content/Interfaces/IContentProperty.cs: -------------------------------------------------------------------------------- 1 | using Blazored.Modal.Services; 2 | using Microsoft.AspNetCore.Components; 3 | 4 | namespace ZauberCMS.Core.Content.Interfaces; 5 | 6 | public interface IContentProperty 7 | { 8 | string Name { get; } 9 | string Alias { get; } 10 | string Description { get;} 11 | string Icon { get; } 12 | public Type? SettingsComponent { get; set; } 13 | 14 | string? Value { get; set; } 15 | EventCallback ValueChanged { get; set; } 16 | string? Settings { get; set; } 17 | Models.Content? Content { get; set; } 18 | IModalService? ModalService { get; set; } 19 | List Scripts { get; set; } 20 | List Styles { get; set; } 21 | public bool FullWidth { get; set; } 22 | } -------------------------------------------------------------------------------- /ZauberCMS.Core/Seo/Interfaces/ISeoService.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.Threading; 3 | using System.Threading.Tasks; 4 | using ZauberCMS.Core.Seo.Models; 5 | using ZauberCMS.Core.Seo.Parameters; 6 | using ZauberCMS.Core.Shared.Models; 7 | 8 | namespace ZauberCMS.Core.Seo.Interfaces; 9 | 10 | public interface ISeoService 11 | { 12 | Task> SaveRedirectAsync(SaveRedirectParameters parameters, CancellationToken cancellationToken = default); 13 | Task> QueryRedirectsAsync(QueryRedirectsParameters parameters, CancellationToken cancellationToken = default); 14 | Task> DeleteRedirectAsync(DeleteRedirectParameters parameters, CancellationToken cancellationToken = default); 15 | } -------------------------------------------------------------------------------- /ZauberCMS.Components/Pages/NewSite.razor.css: -------------------------------------------------------------------------------- 1 | 2 | .full-page { 3 | font-size: 1.1rem !important; 4 | background-image: url('img/hat.jpg'); 5 | background-size: cover; 6 | background-position: center; 7 | background-repeat: no-repeat; 8 | height: 100%; 9 | width: 100%; 10 | position: relative; 11 | display: flex; 12 | justify-content: center; 13 | align-items: center; 14 | background-color: rgba(0, 0, 0, 0.5); /* For slight transparency */ 15 | } 16 | 17 | .centered-div { 18 | background-color: rgba(255, 255, 255, 0.9); /* White background with slight transparency */ 19 | max-width: 600px; 20 | padding: 25px 25px; 21 | margin: 0 10px; 22 | border-radius: 5px; 23 | box-shadow: 0 4px 8px rgba(0, 0, 0, 0.2); 24 | } -------------------------------------------------------------------------------- /ZauberCMS.Core/Membership/Mapping/UserPropertyValueDbMapping.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.EntityFrameworkCore; 2 | using Microsoft.EntityFrameworkCore.Metadata.Builders; 3 | using ZauberCMS.Core.Membership.Models; 4 | 5 | namespace ZauberCMS.Core.Membership.Mapping; 6 | 7 | public class UserPropertyValueDbMapping : IEntityTypeConfiguration 8 | { 9 | public void Configure(EntityTypeBuilder builder) 10 | { 11 | builder.ToTable("ZauberUserPropertyValues"); 12 | builder.HasKey(x => x.Id); 13 | builder.Property(x => x.Alias).IsRequired().HasMaxLength(500); 14 | builder.Property(x => x.Value); 15 | 16 | builder.HasIndex(x => x.Alias).HasDatabaseName("IX_ZauberUserPropertyValue_Alias"); 17 | } 18 | } -------------------------------------------------------------------------------- /ZauberCMS.Components/Admin/Layout/ProfileMenuItem.razor: -------------------------------------------------------------------------------- 1 |
  • 2 |
    3 | 7 |
    8 |
  • 9 | 10 | @code { 11 | [Parameter] public string? Icon { get; set; } 12 | [Parameter] public string? Name { get; set; } 13 | [Parameter] public EventCallback OnClick { get; set; } 14 | 15 | private async Task HandleClick(MouseEventArgs e) 16 | { 17 | if (OnClick.HasDelegate) 18 | { 19 | await OnClick.InvokeAsync(e); 20 | } 21 | } 22 | } -------------------------------------------------------------------------------- /ZauberCMS.Components/ContextMenus/ITreeContextMenu.cs: -------------------------------------------------------------------------------- 1 | using Blazored.Modal.Services; 2 | using Microsoft.AspNetCore.Components; 3 | using Radzen; 4 | 5 | namespace ZauberCMS.Components.ContextMenus; 6 | 7 | public interface ITreeContextMenu 8 | { 9 | List Sections { get; } 10 | List TreeAlias { get; } 11 | string Text(TreeItemContextMenuEventArgs args); 12 | string Icon(TreeItemContextMenuEventArgs args); 13 | string IconColor(TreeItemContextMenuEventArgs args); 14 | bool CanShowContextMenu(TreeItemContextMenuEventArgs args); 15 | Task ContextMenuAction(TreeItemContextMenuEventArgs args, MenuItemEventArgs e, NavigationManager navigationManager, ContextMenuService contextMenuService, IModalService modalService); 16 | int SortOrder { get; } 17 | } -------------------------------------------------------------------------------- /ZauberCMS.Core/Content/Mapping/ContentPropertyValueDbMapping.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.EntityFrameworkCore; 2 | using Microsoft.EntityFrameworkCore.Metadata.Builders; 3 | using ZauberCMS.Core.Content.Models; 4 | 5 | namespace ZauberCMS.Core.Content.Mapping; 6 | 7 | public class ContentPropertyValueDbMapping : IEntityTypeConfiguration 8 | { 9 | public void Configure(EntityTypeBuilder builder) 10 | { 11 | builder.ToTable("ZauberContentPropertyValues"); 12 | builder.HasKey(x => x.Id); 13 | builder.Property(x => x.Alias).IsRequired().HasMaxLength(500); 14 | builder.Property(x => x.Value); 15 | 16 | builder.HasIndex(x => x.Alias).HasDatabaseName("IX_ZauberContentPropertyValue_Alias"); 17 | } 18 | } -------------------------------------------------------------------------------- /ZauberCMS.Core/Content/Mapping/DomainDbMapping.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.EntityFrameworkCore; 2 | using Microsoft.EntityFrameworkCore.Metadata.Builders; 3 | using ZauberCMS.Core.Content.Models; 4 | 5 | namespace ZauberCMS.Core.Content.Mapping; 6 | 7 | public class DomainDbMapping : IEntityTypeConfiguration 8 | { 9 | public void Configure(EntityTypeBuilder builder) 10 | { 11 | builder.ToTable("ZauberDomains"); 12 | builder.HasKey(x => x.Id); 13 | builder.Property(x => x.Id).IsRequired(); 14 | builder.Property(x => x.Url).HasMaxLength(350); 15 | 16 | builder.HasOne(x => x.Language) 17 | .WithMany(x => x.Domains) 18 | .HasForeignKey(x => x.LanguageId) 19 | .OnDelete(DeleteBehavior.NoAction); 20 | } 21 | } -------------------------------------------------------------------------------- /ZauberCMS.Web/ZauberCMS.Web.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | net10.0 5 | enable 6 | enable 7 | true 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /ZauberCMS.Core/Tags/Mapping/TagItemDbMapping.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.EntityFrameworkCore; 2 | using Microsoft.EntityFrameworkCore.Metadata.Builders; 3 | using ZauberCMS.Core.Tags.Models; 4 | 5 | namespace ZauberCMS.Core.Tags.Mapping; 6 | 7 | public class TagItemDbMapping : IEntityTypeConfiguration 8 | { 9 | public void Configure(EntityTypeBuilder builder) 10 | { 11 | builder.ToTable("ZauberTagItems"); 12 | builder.HasKey(x => x.Id); 13 | builder.Property(x => x.Id).IsRequired(); 14 | 15 | builder.HasOne(d => d.Tag) 16 | .WithMany(p => p.TagItems) 17 | .HasForeignKey(d => d.TagId) 18 | .OnDelete(DeleteBehavior.Cascade); 19 | 20 | builder.HasIndex(x => x.ItemId).HasDatabaseName("IX_ZauberTagItems_ItemId");; 21 | } 22 | } -------------------------------------------------------------------------------- /ZauberCMS.Core/Seo/Parameters/QueryRedirectsParameters.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using ZauberCMS.Core.Seo.Models; 5 | 6 | namespace ZauberCMS.Core.Seo.Parameters; 7 | 8 | public class QueryRedirectsParameters 9 | { 10 | public bool Cached { get; set; } = true; 11 | public bool AsNoTracking { get; set; } = true; 12 | public List Ids { get; set; } = []; 13 | public int Amount { get; set; } = 5000; 14 | public GetSeoRedirectOrderBy OrderBy { get; set; } = GetSeoRedirectOrderBy.DateUpdatedDescending; 15 | public Func>? Query { get; set; } 16 | } 17 | 18 | public enum GetSeoRedirectOrderBy 19 | { 20 | DateCreated, 21 | DateCreatedDescending, 22 | DateUpdated, 23 | DateUpdatedDescending, 24 | FromUrl 25 | } -------------------------------------------------------------------------------- /ZauberCMS.Components/Editors/Dialogs/Models/ContentLinkResult.cs: -------------------------------------------------------------------------------- 1 | using ZauberCMS.Core.Content.Models; 2 | 3 | namespace ZauberCMS.Components.Editors.Dialogs.Models; 4 | 5 | public class ContentLinkResult 6 | { 7 | public required Content Content { get; set; } 8 | public required string LinkText { get; set; } 9 | public required string Url { get; set; } 10 | public bool IsContentLink => true; 11 | } 12 | 13 | public class ManualLinkResult 14 | { 15 | public required string Url { get; set; } 16 | public required string Text { get; set; } 17 | public string? Title { get; set; } 18 | public string? Target { get; set; } 19 | public string? Rel { get; set; } 20 | public Guid? ContentId { get; set; } // If link originated from content selection 21 | public bool IsContentLink => false; 22 | } 23 | 24 | -------------------------------------------------------------------------------- /ZauberCMS.Core/Shared/Services/ICacheService.cs: -------------------------------------------------------------------------------- 1 | using ZauberCMS.Core.Extensions; 2 | 3 | namespace ZauberCMS.Core.Shared.Services; 4 | 5 | public interface ICacheService 6 | { 7 | Task GetSetCachedItemAsync(string cacheKey, Func> getCacheItemAsync, int cacheTimeInMinutes = CacheExtensions.MemoryCacheInMinutes); 8 | Task GetSetCachedItemAsync(string cacheKey, Func> getCacheItemAsync, int cacheTimeInMinutes, int cacheTimeInSeconds); 9 | T? GetSetCachedItem(string cacheKey, Func getCacheItem, int cacheTimeInMinutes = CacheExtensions.MemoryCacheInMinutes); 10 | T? GetSetCachedItem(string cacheKey, Func getCacheItem, int cacheTimeInMinutes, int cacheTimeInSeconds); 11 | void ClearCachedItem(string cacheKey); 12 | void ClearCachedItemsWithPrefix(string cacheKeyPrefix); 13 | 14 | } -------------------------------------------------------------------------------- /ZauberCMS.Core/Shared/Models/PropertyType.cs: -------------------------------------------------------------------------------- 1 | using ZauberCMS.Core.Extensions; 2 | 3 | namespace ZauberCMS.Core.Shared.Models; 4 | 5 | public class PropertyType 6 | { 7 | public Guid Id { get; set; } = Guid.NewGuid().NewSequentialGuid(); 8 | public string? Name { get; set; } 9 | public string? Alias { get; set; } 10 | public string? Description { get; set; } 11 | public string? Component { get; set; } 12 | public string? ComponentAlias { get; set; } 13 | public string? Settings { get; set; } 14 | public bool IsRequired { get; set; } 15 | public bool FullWidth { get; set; } 16 | public int SortOrder { get; set; } 17 | public Guid? TabId { get; set; } 18 | public string? TabAlias { get; set; } 19 | public bool ShowAlias { get; set; } = true; 20 | public bool IsFromComposition { get; set; } 21 | } -------------------------------------------------------------------------------- /ZauberCMS.Core/Membership/Mapping/RoleDbMapping.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.EntityFrameworkCore; 2 | using Microsoft.EntityFrameworkCore.Metadata.Builders; 3 | using ZauberCMS.Core.Extensions; 4 | using ZauberCMS.Core.Membership.Models; 5 | 6 | namespace ZauberCMS.Core.Membership.Mapping; 7 | 8 | public class RoleDbMapping : IEntityTypeConfiguration 9 | { 10 | public void Configure(EntityTypeBuilder builder) 11 | { 12 | builder.Property(x => x.Description).HasMaxLength(200); 13 | builder.Property(x => x.Icon).HasMaxLength(20); 14 | builder.Property(x => x.ConcurrencyStamp).HasMaxLength(3000); 15 | builder.Property(e => e.ExtendedData).ToJsonConversion(3000); 16 | builder.Property(e => e.Tabs).ToJsonConversion(4000); 17 | builder.Property(e => e.Properties).ToJsonConversion(null); 18 | } 19 | } -------------------------------------------------------------------------------- /ZauberCMS.Core/Content/Mapping/UnpublishedContentDbMapping.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.EntityFrameworkCore; 2 | using Microsoft.EntityFrameworkCore.Metadata.Builders; 3 | using ZauberCMS.Core.Content.Models; 4 | using ZauberCMS.Core.Extensions; 5 | 6 | namespace ZauberCMS.Core.Content.Mapping; 7 | 8 | public class UnpublishedContentDbMapping : IEntityTypeConfiguration 9 | { 10 | public void Configure(EntityTypeBuilder builder) 11 | { 12 | builder.ToTable("ZauberUnpublishedContent"); 13 | builder.HasKey(x => x.Id); 14 | builder.Property(x => x.Id).IsRequired(); 15 | builder.Property(x => x.DateCreated).IsRequired(); 16 | builder.Property(x => x.DateUpdated).IsRequired(); 17 | builder.Property(e => e.JsonContent).ToJsonConversion(null); 18 | 19 | 20 | } 21 | } -------------------------------------------------------------------------------- /ZauberCMS.Core/Content/Models/UnpublishedContent.cs: -------------------------------------------------------------------------------- 1 | using ZauberCMS.Core.Extensions; 2 | 3 | namespace ZauberCMS.Core.Content.Models; 4 | 5 | public class UnpublishedContent 6 | { 7 | /// 8 | /// Id 9 | /// 10 | public Guid Id { get; set; } = Guid.NewGuid().NewSequentialGuid(); 11 | 12 | /// 13 | /// Json string of the unpublished content 14 | /// 15 | public Content JsonContent { get; set; } = new(); 16 | 17 | /// 18 | /// The date and time when the content was created. 19 | /// 20 | public DateTime DateCreated { get; set; } = DateTime.UtcNow; 21 | 22 | /// 23 | /// Gets or sets the date and time of the last update for the content. 24 | /// 25 | public DateTime DateUpdated { get; set; } = DateTime.UtcNow; 26 | } -------------------------------------------------------------------------------- /ZauberCMS.Core/Tags/Mapping/TagDbMapping.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.EntityFrameworkCore; 2 | using Microsoft.EntityFrameworkCore.Metadata.Builders; 3 | using ZauberCMS.Core.Tags.Models; 4 | 5 | namespace ZauberCMS.Core.Tags.Mapping; 6 | 7 | public class TagDbMapping : IEntityTypeConfiguration 8 | { 9 | public void Configure(EntityTypeBuilder builder) 10 | { 11 | builder.ToTable("ZauberTags"); 12 | builder.HasKey(x => x.Id); 13 | builder.Property(x => x.Id).IsRequired(); 14 | builder.Property(x => x.TagName).HasMaxLength(1000); 15 | builder.Property(x => x.Slug).HasMaxLength(1000); 16 | 17 | builder.Ignore(x => x.Count); 18 | 19 | builder.HasIndex(x => x.TagName).HasDatabaseName("IX_ZauberTag_TagName"); 20 | builder.HasIndex(x => x.Slug).HasDatabaseName("IX_ZauberTag_Slug"); 21 | } 22 | } -------------------------------------------------------------------------------- /ZauberCMS.Components/Shared/PropertyInfo.razor: -------------------------------------------------------------------------------- 1 | @if (!Name.IsNullOrWhiteSpace()) 2 | { 3 | 4 | } 5 | @if (!Alias.IsNullOrWhiteSpace()) 6 | { 7 | 8 | @Alias 9 | 10 | } 11 | @if (!Description.IsNullOrWhiteSpace()) 12 | { 13 | 14 | } 15 | 16 | @code { 17 | [Parameter] public string? Name { get; set; } 18 | [Parameter] public string? Alias { get; set; } 19 | [Parameter] public string? Description { get; set; } 20 | } -------------------------------------------------------------------------------- /ZauberCMS.Components/Editors/Models/EditorNotesSettingsModel.cs: -------------------------------------------------------------------------------- 1 | namespace ZauberCMS.Components.Editors.Models; 2 | 3 | public class EditorNotesSettingsModel 4 | { 5 | /// 6 | /// Optional background colour override 7 | /// 8 | public string? BackgroundColor { get; set; } 9 | 10 | /// 11 | /// Title 12 | /// 13 | public string? Title { get; set; } 14 | 15 | /// 16 | /// Main note to editor 17 | /// 18 | public string? Note { get; set; } 19 | 20 | /// 21 | /// Optional icon override 22 | /// 23 | public string? Icon { get; set; } = "lightbulb_outline"; 24 | 25 | /// 26 | /// Defaults to dialog, but can be made to show inline 27 | /// 28 | public bool ShowInline { get; set; } 29 | } -------------------------------------------------------------------------------- /ZauberCMS.Core/Audit/Parameters/QueryAuditsParameters.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Linq.Expressions; 5 | using ZauberCMS.Core.Shared.Models; 6 | 7 | namespace ZauberCMS.Core.Audit.Parameters; 8 | 9 | public class QueryAuditsParameters 10 | { 11 | public bool AsNoTracking { get; set; } = true; 12 | public int PageIndex { get; set; } = 1; 13 | public int AmountPerPage { get; set; } = 10; 14 | public string? Username { get; set; } 15 | public GetAuditsOrderBy OrderBy { get; set; } = GetAuditsOrderBy.DateCreatedDescending; 16 | public Expression>? WhereClause { get; set; } 17 | public Func>? Query { get; set; } 18 | } 19 | 20 | public enum GetAuditsOrderBy 21 | { 22 | DateCreated, 23 | DateCreatedDescending, 24 | Username 25 | } -------------------------------------------------------------------------------- /ZauberCMS.Core/Content/Models/ContentPropertyValue.cs: -------------------------------------------------------------------------------- 1 | using System.Text.Json.Serialization; 2 | using ZauberCMS.Core.Content.Interfaces; 3 | using ZauberCMS.Core.Extensions; 4 | 5 | namespace ZauberCMS.Core.Content.Models; 6 | 7 | public class ContentPropertyValue : IPropertyValue 8 | { 9 | public Guid Id { get; set; } = Guid.NewGuid().NewSequentialGuid(); 10 | public Guid ContentId { get; set; } 11 | [JsonIgnore] 12 | public Content? Content { get; set; } 13 | public string Alias { get; set; } = string.Empty; 14 | public Guid ContentTypePropertyId { get; set; } 15 | // ReSharper disable once EntityFramework.ModelValidation.UnlimitedStringLength 16 | public string Value { get; set; } = string.Empty; 17 | public DateTime? DateCreated { get; set; } = DateTime.UtcNow; 18 | public DateTime? DateUpdated { get; set; } = DateTime.UtcNow; 19 | } -------------------------------------------------------------------------------- /ZauberCMS.Core/Data/Interfaces/IDataService.cs: -------------------------------------------------------------------------------- 1 | using ZauberCMS.Core.Data.Models; 2 | using ZauberCMS.Core.Data.Parameters; 3 | using ZauberCMS.Core.Shared.Interfaces; 4 | using ZauberCMS.Core.Shared.Models; 5 | 6 | namespace ZauberCMS.Core.Data.Interfaces; 7 | 8 | public interface IDataService 9 | { 10 | Task GetGlobalDataAsync(GetGlobalDataParameters parameters, CancellationToken cancellationToken = default); 11 | Task> SaveGlobalDataAsync(SaveGlobalDataParameters parameters, CancellationToken cancellationToken = default); 12 | Task>> MultiQueryAsync(MultiQueryParameters parameters, CancellationToken cancellationToken = default); 13 | Task> GetDataGridAsync(DataGridParameters parameters, CancellationToken cancellationToken = default) where T : class, ITreeItem; 14 | } -------------------------------------------------------------------------------- /ZauberCMS.Components/Shared/ZauberLogo.razor: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | @code { 5 | [Parameter] public string CssClasses { get; set; } = ""; 6 | [Parameter] public string Styles { get; set; } = ""; 7 | } -------------------------------------------------------------------------------- /ZauberCMS.Core/Membership/Validation/CreateUpdateUserCommandValidator.cs: -------------------------------------------------------------------------------- 1 | using FluentValidation; 2 | using ZauberCMS.Core.Extensions; 3 | using ZauberCMS.Core.Membership.Parameters; 4 | using ZauberCMS.Core.Shared.Validation; 5 | 6 | namespace ZauberCMS.Core.Membership.Validation 7 | { 8 | public class CreateUpdateUserCommandValidator : BaseFluentValidator 9 | { 10 | public CreateUpdateUserCommandValidator() 11 | { 12 | 13 | RuleFor(p => p.NewPasswordConfirmation).NotEmpty().When(p => !p.NewPassword.IsNullOrWhiteSpace()); 14 | RuleFor(p => p.NewPasswordConfirmation).Equal(p => p.NewPassword).When(p => !p.NewPassword.IsNullOrWhiteSpace()); 15 | 16 | RuleFor(model => model.User) 17 | .SetValidator(model => new UserValidation()); 18 | 19 | } 20 | } 21 | } -------------------------------------------------------------------------------- /ZauberCMS.Core/Membership/Validation/UserValidation.cs: -------------------------------------------------------------------------------- 1 | using FluentValidation; 2 | using Microsoft.IdentityModel.Tokens; 3 | using ZauberCMS.Core.Membership.Models; 4 | using ZauberCMS.Core.Shared.Validation; 5 | 6 | namespace ZauberCMS.Core.Membership.Validation; 7 | 8 | public class UserValidation : BaseFluentValidator 9 | { 10 | public UserValidation() 11 | { 12 | RuleFor(p => p.UserName).NotEmpty().WithMessage("You must enter a username"); 13 | RuleFor(p => p.UserName).MaximumLength(100).WithMessage("Cannot be longer than 100 characters"); 14 | 15 | RuleFor(p => p.Email).NotEmpty().EmailAddress().MaximumLength(100); 16 | 17 | RuleFor(p => p.PhoneNumber).MaximumLength(100).WithMessage("PhoneNumber Cannot be longer than 100 characters"); 18 | RuleFor(p => p.PhoneNumber).Matches("[0-9]+").When(p => !p.PhoneNumber.IsNullOrEmpty()); 19 | } 20 | } -------------------------------------------------------------------------------- /ZauberCMS.Components/Editors/Models/CodeEditorPropertySettingsModel.cs: -------------------------------------------------------------------------------- 1 | namespace ZauberCMS.Components.Editors.Models; 2 | 3 | public class CodeEditorPropertySettingsModel 4 | { 5 | public int Height { get; set; } = 200; 6 | public string Language { get; set; } = "javascript"; 7 | 8 | public List Languages { get; set; } = [ 9 | "csharp", 10 | "dart", 11 | "fsharp", 12 | "go", 13 | "html", 14 | "java", 15 | "javascript", 16 | "liquid", 17 | "markdown", 18 | "mysql", 19 | "pascal", 20 | "perl", 21 | "php", 22 | "powershell", 23 | "python", 24 | "razor", 25 | "ruby", 26 | "rust", 27 | "scala", 28 | "scss", 29 | "sql", 30 | "swift", 31 | "typescript", 32 | "xml", 33 | "yaml", 34 | ]; 35 | } -------------------------------------------------------------------------------- /ZauberCMS.Core/Content/Parameters/QueryDomainParameters.cs: -------------------------------------------------------------------------------- 1 | using System.Linq.Expressions; 2 | using ZauberCMS.Core.Content.Models; 3 | 4 | namespace ZauberCMS.Core.Content.Parameters; 5 | 6 | public class QueryDomainParameters 7 | { 8 | public bool AsNoTracking { get; set; } = true; 9 | public List Ids { get; set; } = []; 10 | public int PageIndex { get; set; } = 1; 11 | public int AmountPerPage { get; set; } = 10; 12 | public bool IncludeChildren { get; set; } 13 | public Guid? ContentId { get; set; } 14 | public Guid? LanguageId { get; set; } 15 | public GetDomainOrderBy OrderBy { get; set; } = GetDomainOrderBy.DateCreatedDescending; 16 | public Expression>? WhereClause { get; set; } 17 | public Func>? Query { get; set; } 18 | } 19 | 20 | public enum GetDomainOrderBy 21 | { 22 | DateCreated, 23 | DateCreatedDescending, 24 | Url 25 | } -------------------------------------------------------------------------------- /ZauberCMS.Core/Membership/Validation/ValidateRole.cs: -------------------------------------------------------------------------------- 1 | using ZauberCMS.Core.Extensions; 2 | using ZauberCMS.Core.Membership.Models; 3 | using ZauberCMS.Core.Shared.Validation.Interfaces; 4 | using ZauberCMS.Core.Shared.Validation.Models; 5 | 6 | namespace ZauberCMS.Core.Membership.Validation; 7 | 8 | public class ValidateRole : IValidate 9 | { 10 | public Task Validate(Role item) 11 | { 12 | var validateResult = new ValidateResult(); 13 | 14 | if (item.Name.IsNullOrWhiteSpace()) 15 | { 16 | validateResult.ErrorMessages.Add("You cannot leave the name empty"); 17 | } 18 | 19 | if (item.Properties.Any(x => x.Name.IsNullOrWhiteSpace())) 20 | { 21 | validateResult.ErrorMessages.Add("Some properties are missing a name (and alias)"); 22 | } 23 | 24 | return Task.FromResult(validateResult); 25 | } 26 | } -------------------------------------------------------------------------------- /ZauberCMS.Core/Settings/GlobalSettings.cs: -------------------------------------------------------------------------------- 1 | namespace ZauberCMS.Core.Settings; 2 | 3 | public class GlobalSettings 4 | { 5 | // General 6 | public Dictionary ApiKeys { get; set; } = []; 7 | 8 | // Media 9 | public long MaxUploadFileSizeInBytes { get; set; } = 5242880; 10 | public int MaxImageSizeInPixels { get; set; } = 2500; 11 | public List AllowedFileTypes { get; set; } = 12 | [ 13 | // Images 14 | ".jpg", ".jpeg", ".png", ".gif", ".webp", ".svg", ".ico", 15 | 16 | // Documents (safer formats) 17 | ".pdf", ".txt", 18 | 19 | // Video 20 | ".mp4", ".webm", 21 | 22 | // Audio 23 | ".mp3", ".wav", ".ogg" 24 | ]; 25 | 26 | // Identity 27 | public List AllowedAdminIpAddress { get; set; } = []; 28 | public List AdminEmailAddresses { get; set; } = []; 29 | } -------------------------------------------------------------------------------- /ZauberCMS.Core/Membership/Parameters/ResetPasswordParameters.cs: -------------------------------------------------------------------------------- 1 | using System.ComponentModel.DataAnnotations; 2 | using ZauberCMS.Core.Membership.Models; 3 | 4 | namespace ZauberCMS.Core.Membership.Parameters; 5 | 6 | public class ResetPasswordParameters 7 | { 8 | [Required] 9 | [EmailAddress] 10 | public string? Email { get; set; } 11 | 12 | [Required] 13 | [StringLength(100, ErrorMessage = "The {0} must be at least {2} and at max {1} characters long.", MinimumLength = 8)] 14 | [DataType(DataType.Password)] 15 | public string? Password { get; set; } 16 | 17 | [DataType(DataType.Password)] 18 | [Display(Name = "Confirm password")] 19 | [Compare("Password", ErrorMessage = "The password and confirmation password do not match.")] 20 | public string? ConfirmPassword { get; set; } 21 | 22 | [Required] 23 | public string? Code { get; set; } 24 | public string? ReturnUrl { get; set; } 25 | } -------------------------------------------------------------------------------- /ZauberCMS.Core/Content/Validation/ValidateContentType.cs: -------------------------------------------------------------------------------- 1 | using ZauberCMS.Core.Content.Models; 2 | using ZauberCMS.Core.Extensions; 3 | using ZauberCMS.Core.Shared.Validation.Interfaces; 4 | using ZauberCMS.Core.Shared.Validation.Models; 5 | 6 | namespace ZauberCMS.Core.Content.Validation; 7 | 8 | public class ValidateContentType : IValidate 9 | { 10 | public Task Validate(ContentType item) 11 | { 12 | var validateResult = new ValidateResult(); 13 | if (item.Name.IsNullOrWhiteSpace()) 14 | { 15 | validateResult.ErrorMessages.Add("You cannot leave the name empty"); 16 | } 17 | 18 | if (item.ContentProperties.Any(x => x.Name.IsNullOrWhiteSpace())) 19 | { 20 | validateResult.ErrorMessages.Add("Some properties are missing a name (and alias)"); 21 | } 22 | 23 | return Task.FromResult(validateResult); 24 | } 25 | } -------------------------------------------------------------------------------- /ZauberCMS.Core/Languages/Mapping/LanguageDbMapping.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.EntityFrameworkCore; 2 | using Microsoft.EntityFrameworkCore.Metadata.Builders; 3 | using ZauberCMS.Core.Languages.Models; 4 | 5 | namespace ZauberCMS.Core.Languages.Mapping; 6 | 7 | public class LanguageDbMapping : IEntityTypeConfiguration 8 | { 9 | public void Configure(EntityTypeBuilder builder) 10 | { 11 | builder.ToTable("ZauberLanguages"); 12 | builder.HasKey(x => x.Id); 13 | builder.Property(x => x.Id).IsRequired(); 14 | builder.Property(x => x.LanguageIsoCode).HasMaxLength(14); 15 | builder.Property(x => x.LanguageCultureName).HasMaxLength(100); 16 | 17 | builder.Ignore(x => x.Name); 18 | 19 | builder.HasMany(x => x.LanguageTexts) 20 | .WithOne(x => x.Language) 21 | .HasForeignKey(x => x.LanguageId) 22 | .OnDelete(DeleteBehavior.Cascade); 23 | } 24 | } -------------------------------------------------------------------------------- /ZauberCMS.Template/template/ZauberCMSTemplate.Site/Properties/launchSettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://json.schemastore.org/launchsettings.json", 3 | "iisSettings": { 4 | "windowsAuthentication": false, 5 | "anonymousAuthentication": true, 6 | "iisExpress": { 7 | "applicationUrl": "http://localhost:38357", 8 | "sslPort": 44340 9 | } 10 | }, 11 | "profiles": { 12 | "IIS Express": { 13 | "commandName": "IISExpress", 14 | "launchBrowser": true, 15 | "environmentVariables": { 16 | "ASPNETCORE_ENVIRONMENT": "Development" 17 | } 18 | }, 19 | "Umbraco.Web.UI": { 20 | "commandName": "Project", 21 | "dotnetRunMessages": true, 22 | "launchBrowser": true, 23 | "applicationUrl": "https://localhost:44340;http://localhost:38357", 24 | "environmentVariables": { 25 | "ASPNETCORE_ENVIRONMENT": "Development" 26 | } 27 | } 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /ZauberCMS.Web/ContentBlocks/ImageBlock.razor: -------------------------------------------------------------------------------- 1 | @using ZauberCMS.Core.Media.Models 2 | @using RenderMode = Microsoft.AspNetCore.Mvc.Rendering.RenderMode 3 | @implements ZauberCMS.Core.Content.Interfaces.IContentBlockView 4 | 5 | @if (Content != null && Media != null) 6 | { 7 | @Media.AltTag 8 | @(Content.GetValue("Summary")) 9 | } 10 | 11 | @code { 12 | [Parameter] public Content? Content { get; set; } 13 | public string ContentTypeAlias => "Image"; 14 | public RenderMode RenderMode => RenderMode.Static; 15 | private Media? Media { get; set; } 16 | protected override async Task OnInitializedAsync() 17 | { 18 | if (Content != null) 19 | { 20 | var media = await Content.GetMediaItems("Image", MediaService); 21 | Media = media.FirstOrDefault(); 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /ZauberCMS/Components/_Imports.razor: -------------------------------------------------------------------------------- 1 | @using System.Net.Http 2 | @using System.Net.Http.Json 3 | @using Microsoft.AspNetCore.Components.Forms 4 | @using Microsoft.AspNetCore.Components.Routing 5 | @using Microsoft.AspNetCore.Components.Web 6 | @using static Microsoft.AspNetCore.Components.Web.RenderMode 7 | @using Microsoft.AspNetCore.Components.Web.Virtualization 8 | @using Microsoft.JSInterop 9 | @using ZauberCMS.Components 10 | @using ZauberCMS.Core 11 | @using ZauberCMS.Core.Extensions 12 | @using ZauberCMS.Core.Content.Models 13 | @using ZauberCMS.Components.Editors 14 | @using Microsoft.AspNetCore.Components.Sections 15 | @using Humanizer 16 | @using Radzen 17 | @using Radzen.Blazor 18 | @using Blazored.Modal 19 | @using Blazored.Modal.Services 20 | @using ZauberCMS.Core.Content.Interfaces 21 | @using ZauberCMS.Core.Media.Interfaces 22 | @inject IContentService ContentService 23 | @inject IMediaService MediaService 24 | @inject NavigationManager NavigationManager -------------------------------------------------------------------------------- /ZauberCMS.Core/Tags/Interfaces/ITagService.cs: -------------------------------------------------------------------------------- 1 | using System.Threading; 2 | using System.Threading.Tasks; 3 | using ZauberCMS.Core.Shared.Models; 4 | using ZauberCMS.Core.Tags.Models; 5 | using ZauberCMS.Core.Tags.Parameters; 6 | 7 | namespace ZauberCMS.Core.Tags.Interfaces; 8 | 9 | public interface ITagService 10 | { 11 | Task> SaveTagAsync(SaveTagParameters parameters, CancellationToken cancellationToken = default); 12 | Task> QueryTagAsync(QueryTagParameters parameters, CancellationToken cancellationToken = default); 13 | Task> DeleteTagAsync(DeleteTagParameters parameters, CancellationToken cancellationToken = default); 14 | 15 | Task> SaveTagItemAsync(SaveTagItemParameters parameters, CancellationToken cancellationToken = default); 16 | Task> DeleteTagItemAsync(DeleteTagItemParameters parameters, CancellationToken cancellationToken = default); 17 | } -------------------------------------------------------------------------------- /ZauberCMS.Components/Admin/MediaSection/MediaIndex.razor: -------------------------------------------------------------------------------- 1 | @attribute [Route(Url)] 2 | @layout SectionLayout 3 | @implements ZauberCMS.Core.Sections.Interfaces.ISection 4 | 5 | @Name 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | @code { 14 | private const string Url = Urls.AdminMediaBaseUrl; // So we only have on string 15 | public string Name => "Media"; 16 | public string Alias => Constants.Sections.MediaSection; 17 | public string IndexUrl => Url; 18 | public int SortOrder => 1; 19 | 20 | [CascadingParameter] protected SectionLayout? Layout { get; set; } 21 | 22 | protected override void OnInitialized() 23 | { 24 | Layout?.SetSection(Alias); 25 | } 26 | } 27 | 28 | 29 | 30 | -------------------------------------------------------------------------------- /ZauberCMS.Components/ContextMenus/SectionNavGroups/CreateMediaNavMenu.cs: -------------------------------------------------------------------------------- 1 | using Blazored.Modal.Services; 2 | using Microsoft.AspNetCore.Components; 3 | using Radzen; 4 | using ZauberCMS.Core; 5 | using ZauberCMS.Core.Sections.Interfaces; 6 | 7 | namespace ZauberCMS.Components.ContextMenus.SectionNavGroups; 8 | 9 | public class CreateMediaNavMenu : ISectionNavGroupAction 10 | { 11 | public string Text => "Create Media"; 12 | public string Icon => "add"; 13 | public string IconColor => string.Empty; 14 | public string SectionNavGroupAlias => Constants.Sections.SectionNavGroups.MediaNavGroup; 15 | public int SortOrder => -50; 16 | 17 | public Task ContextMenuAction(MenuItemEventArgs e, NavigationManager navigationManager, ContextMenuService contextMenuService, 18 | IModalService modalService) 19 | { 20 | contextMenuService.Close(); 21 | navigationManager.NavigateTo(Urls.AdminCreateMedia, true); 22 | return Task.CompletedTask; 23 | } 24 | } -------------------------------------------------------------------------------- /ZauberCMS.Core/Languages/Mapping/LanguageDictionaryDbMapping.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.EntityFrameworkCore; 2 | using Microsoft.EntityFrameworkCore.Metadata.Builders; 3 | using ZauberCMS.Core.Languages.Models; 4 | 5 | namespace ZauberCMS.Core.Languages.Mapping; 6 | 7 | public class LanguageDictionaryDbMapping : IEntityTypeConfiguration 8 | { 9 | public void Configure(EntityTypeBuilder builder) 10 | { 11 | builder.ToTable("ZauberLanguageDictionaries"); 12 | builder.HasKey(x => x.Id); 13 | builder.Property(x => x.Id).IsRequired(); 14 | builder.Property(x => x.Key).IsRequired().HasMaxLength(1000); 15 | 16 | builder.HasMany(d => d.Texts) 17 | .WithOne(p => p.LanguageDictionary) 18 | .HasForeignKey(d => d.LanguageDictionaryId) 19 | .OnDelete(DeleteBehavior.Cascade); 20 | 21 | builder.HasIndex(x => x.Key).HasDatabaseName("IX_LanguageDictionary_Key"); 22 | } 23 | } -------------------------------------------------------------------------------- /ZauberCMS.Template/template/ZauberCMSTemplate.Site/ZauberCMSTemplate.Site.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | net10.0 5 | enable 6 | enable 7 | true 8 | 9 | 10 | 11 | 12 | all 13 | build 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | -------------------------------------------------------------------------------- /ZauberCMS.Components/ContextMenus/SectionNavGroups/CreateContentNavMenu.cs: -------------------------------------------------------------------------------- 1 | using Blazored.Modal.Services; 2 | using Microsoft.AspNetCore.Components; 3 | using Radzen; 4 | using ZauberCMS.Core; 5 | using ZauberCMS.Core.Sections.Interfaces; 6 | 7 | namespace ZauberCMS.Components.ContextMenus.SectionNavGroups; 8 | 9 | public class CreateContentNavMenu : ISectionNavGroupAction 10 | { 11 | public string Text => "Create Content"; 12 | public string Icon => "add"; 13 | public string IconColor => string.Empty; 14 | public string SectionNavGroupAlias => Constants.Sections.SectionNavGroups.ContentNavGroup; 15 | public int SortOrder => -100; 16 | 17 | public Task ContextMenuAction(MenuItemEventArgs e, NavigationManager navigationManager, ContextMenuService contextMenuService, 18 | IModalService modalService) 19 | { 20 | contextMenuService.Close(); 21 | navigationManager.NavigateTo(Urls.AdminCreateContent, true); 22 | return Task.CompletedTask; 23 | } 24 | } -------------------------------------------------------------------------------- /ZauberCMS.Core/Extensions/DialogExtensions.cs: -------------------------------------------------------------------------------- 1 | using Blazored.Modal; 2 | using Blazored.Modal.Services; 3 | using Microsoft.AspNetCore.Components; 4 | 5 | namespace ZauberCMS.Core.Extensions; 6 | 7 | public static class DialogExtensions 8 | { 9 | public static IModalReference OpenSidePanel(this IModalService dialogService, string title, Dictionary? parameters = null) where T : ComponentBase 10 | { 11 | var modalParameters = new ModalParameters(); 12 | if (parameters != null) 13 | { 14 | foreach (var p in parameters) 15 | { 16 | modalParameters.Add(p.Key, p.Value); 17 | } 18 | 19 | } 20 | var options = new ModalOptions 21 | { 22 | Size = ModalSize.Large, 23 | Position = ModalPosition.Custom, 24 | PositionCustomClass = "side-panel" 25 | }; 26 | return dialogService.Show(title, modalParameters, options); 27 | } 28 | } -------------------------------------------------------------------------------- /ZauberCMS.Components/ContextMenus/SectionNavGroups/CreateMediaFolderNavMenu.cs: -------------------------------------------------------------------------------- 1 | using Blazored.Modal.Services; 2 | using Microsoft.AspNetCore.Components; 3 | using Radzen; 4 | using ZauberCMS.Core; 5 | using ZauberCMS.Core.Sections.Interfaces; 6 | 7 | namespace ZauberCMS.Components.ContextMenus.SectionNavGroups; 8 | 9 | public class CreateMediaFolderNavMenu : ISectionNavGroupAction 10 | { 11 | public string Text => "Create Folder"; 12 | public string Icon => "folder"; 13 | public string IconColor => string.Empty; 14 | public string SectionNavGroupAlias => Constants.Sections.SectionNavGroups.MediaNavGroup; 15 | public int SortOrder => -100; 16 | 17 | public Task ContextMenuAction(MenuItemEventArgs e, NavigationManager navigationManager, ContextMenuService contextMenuService, 18 | IModalService modalService) 19 | { 20 | contextMenuService.Close(); 21 | navigationManager.NavigateTo(Urls.AdminCreateMediaFolder, true); 22 | return Task.CompletedTask; 23 | } 24 | } -------------------------------------------------------------------------------- /ZauberCMS.Components/Controllers/AuthController.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.AspNetCore.Identity; 2 | using Microsoft.AspNetCore.Mvc; 3 | using ZauberCMS.Core.Membership.Models; 4 | 5 | namespace ZauberCMS.Components.Controllers; 6 | 7 | [Route("api/[controller]")] 8 | [ApiController] 9 | public class AuthController( 10 | UserManager userManager, 11 | SignInManager signInManager) 12 | : ControllerBase 13 | { 14 | [HttpGet("refreshsignin")] 15 | public async Task RefreshSignIn(string? redirectUrl = null) 16 | { 17 | var user = await userManager.GetUserAsync(User); 18 | if (user != null) await signInManager.RefreshSignInAsync(user); 19 | return Redirect(redirectUrl ?? "/"); 20 | } 21 | 22 | [HttpGet("logout")] 23 | public async Task Logout(string? redirectUrl = null) 24 | { 25 | await signInManager.SignOutAsync(); 26 | return Redirect(redirectUrl ?? "/"); // Redirect to the home page after logout 27 | } 28 | } -------------------------------------------------------------------------------- /ZauberCMS.Components/ContextMenus/SectionNavGroups/CreateContentTypeFolder.cs: -------------------------------------------------------------------------------- 1 | using Blazored.Modal.Services; 2 | using Microsoft.AspNetCore.Components; 3 | using Radzen; 4 | using ZauberCMS.Core; 5 | using ZauberCMS.Core.Sections.Interfaces; 6 | 7 | namespace ZauberCMS.Components.ContextMenus.SectionNavGroups; 8 | 9 | public class CreateContentTypeFolder : ISectionNavGroupAction 10 | { 11 | public string Text => "Create Folder"; 12 | public string Icon => "folder"; 13 | public string IconColor => string.Empty; 14 | public string SectionNavGroupAlias => Constants.Sections.SectionNavGroups.StructureContentTypesNavGroup; 15 | public int SortOrder => -50; 16 | 17 | public Task ContextMenuAction(MenuItemEventArgs e, NavigationManager navigationManager, ContextMenuService contextMenuService, 18 | IModalService modalService) 19 | { 20 | contextMenuService.Close(); 21 | navigationManager.NavigateTo(Urls.AdminStructureCreateFolder, true); 22 | return Task.CompletedTask; 23 | } 24 | } -------------------------------------------------------------------------------- /ZauberCMS.Components/Shared/SortableList.razor.js: -------------------------------------------------------------------------------- 1 | export function init(id, group, pull, put, sort, handle, filter, component, forceFallback, ignoreDomChanges) { 2 | var sortable = new Sortable(document.getElementById(id), { 3 | animation: 200, 4 | group: { 5 | name: group, 6 | pull: pull || true, 7 | put: put 8 | }, 9 | filter: filter || undefined, 10 | sort: sort, 11 | forceFallback: forceFallback, 12 | handle: handle || undefined, 13 | onUpdate: (event) => { 14 | // Revert the DOM to match the .NET state 15 | if(!ignoreDomChanges){ 16 | event.item.remove(); 17 | event.to.insertBefore(event.item, event.to.childNodes[event.oldIndex]); 18 | } 19 | 20 | // Notify .NET to update its model and re-render 21 | component.invokeMethodAsync('OnUpdateJS', event.oldDraggableIndex, event.newDraggableIndex); 22 | } 23 | }); 24 | } 25 | -------------------------------------------------------------------------------- /ZauberCMS.Core/Shared/Models/PaginatedList.cs: -------------------------------------------------------------------------------- 1 | namespace ZauberCMS.Core.Shared.Models; 2 | 3 | public class PaginatedList 4 | { 5 | public PaginatedList() 6 | { 7 | } 8 | 9 | public int PageIndex { get; set; } = 1; 10 | public int TotalPages { get; set; } 11 | public int TotalItems { get; set; } 12 | public IEnumerable Items { get; set; } = []; 13 | public bool IsFirstPage => PageIndex <= 1; 14 | public bool IsLastPage => PageIndex >= TotalPages; 15 | public bool HasPreviousPage => PageIndex > 1; 16 | public bool HasNextPage => PageIndex < TotalPages; 17 | public PaginatedList(IQueryable items, int pageIndex, int pageSize) 18 | { 19 | PageIndex = pageIndex; 20 | var count = items.Count(); 21 | TotalPages = (int) Math.Ceiling(count / (double) pageSize); 22 | var skip = (pageIndex-1) * pageSize; 23 | Items = skip > 0 ? items.Skip(skip).Take(pageSize).ToList() : items.Take(pageSize).ToList(); 24 | TotalItems = count; 25 | } 26 | } -------------------------------------------------------------------------------- /ZauberCMS.Components/Admin/UsersSection/UsersIndex.razor: -------------------------------------------------------------------------------- 1 | @attribute [Route(Url)] 2 | @layout SectionLayout 3 | @implements ZauberCMS.Core.Sections.Interfaces.ISection 4 | 5 | @Name 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | @code { 14 | private const string Url = Urls.AdminUsersBaseUrl; 15 | public string Name => "Users"; 16 | public string Alias => Constants.Sections.UsersSection; 17 | public string IndexUrl => Url; 18 | public int SortOrder => 4; 19 | 20 | [CascadingParameter] protected SectionLayout? Layout { get; set; } 21 | 22 | protected override void OnInitialized() 23 | { 24 | Layout?.SetSection(Alias); 25 | } 26 | } -------------------------------------------------------------------------------- /ZauberCMS.Components/ContextMenus/SectionNavGroups/CreateCompositionFolder.cs: -------------------------------------------------------------------------------- 1 | using Blazored.Modal.Services; 2 | using Microsoft.AspNetCore.Components; 3 | using Radzen; 4 | using ZauberCMS.Core; 5 | using ZauberCMS.Core.Sections.Interfaces; 6 | 7 | namespace ZauberCMS.Components.ContextMenus.SectionNavGroups; 8 | 9 | public class CreateCompositionFolder : ISectionNavGroupAction 10 | { 11 | public string Text => "Create Folder"; 12 | public string Icon => "folder"; 13 | public string IconColor => string.Empty; 14 | public string SectionNavGroupAlias => Constants.Sections.SectionNavGroups.StructureCompositionsNavGroup; 15 | public int SortOrder => -50; 16 | 17 | public Task ContextMenuAction(MenuItemEventArgs e, NavigationManager navigationManager, ContextMenuService contextMenuService, 18 | IModalService modalService) 19 | { 20 | contextMenuService.Close(); 21 | navigationManager.NavigateTo($"{Urls.AdminStructureCreateFolder}/2", true); 22 | return Task.CompletedTask; 23 | } 24 | } -------------------------------------------------------------------------------- /ZauberCMS.Components/ContextMenus/SectionNavGroups/CreateElementTypeFolder.cs: -------------------------------------------------------------------------------- 1 | using Blazored.Modal.Services; 2 | using Microsoft.AspNetCore.Components; 3 | using Radzen; 4 | using ZauberCMS.Core; 5 | using ZauberCMS.Core.Sections.Interfaces; 6 | 7 | namespace ZauberCMS.Components.ContextMenus.SectionNavGroups; 8 | 9 | public class CreateElementTypeFolder : ISectionNavGroupAction 10 | { 11 | public string Text => "Create Folder"; 12 | public string Icon => "folder"; 13 | public string IconColor => string.Empty; 14 | public string SectionNavGroupAlias => Constants.Sections.SectionNavGroups.StructureElementTypesNavGroup; 15 | public int SortOrder => -50; 16 | 17 | public Task ContextMenuAction(MenuItemEventArgs e, NavigationManager navigationManager, ContextMenuService contextMenuService, 18 | IModalService modalService) 19 | { 20 | contextMenuService.Close(); 21 | navigationManager.NavigateTo($"{Urls.AdminStructureCreateFolder}/1", true); 22 | return Task.CompletedTask; 23 | } 24 | } -------------------------------------------------------------------------------- /ZauberCMS.Components/ContextMenus/SectionNavGroups/CreateCompositionNavMenu.cs: -------------------------------------------------------------------------------- 1 | using Blazored.Modal.Services; 2 | using Microsoft.AspNetCore.Components; 3 | using Radzen; 4 | using ZauberCMS.Core; 5 | using ZauberCMS.Core.Sections.Interfaces; 6 | 7 | namespace ZauberCMS.Components.ContextMenus.SectionNavGroups; 8 | 9 | public class CreateCompositionNavMenu : ISectionNavGroupAction 10 | { 11 | public string Text => "Create Composition"; 12 | public string Icon => "add"; 13 | public string IconColor => string.Empty; 14 | public string SectionNavGroupAlias => Constants.Sections.SectionNavGroups.StructureCompositionsNavGroup; 15 | public int SortOrder => -100; 16 | 17 | public Task ContextMenuAction(MenuItemEventArgs e, NavigationManager navigationManager, ContextMenuService contextMenuService, 18 | IModalService modalService) 19 | { 20 | contextMenuService.Close(); 21 | navigationManager.NavigateTo(Urls.AdminStructureCreateComposition, true); 22 | return Task.CompletedTask; 23 | } 24 | } -------------------------------------------------------------------------------- /ZauberCMS.Components/ContextMenus/SectionNavGroups/CreateContentTypeNavMenu.cs: -------------------------------------------------------------------------------- 1 | using Blazored.Modal.Services; 2 | using Microsoft.AspNetCore.Components; 3 | using Radzen; 4 | using ZauberCMS.Core; 5 | using ZauberCMS.Core.Sections.Interfaces; 6 | 7 | namespace ZauberCMS.Components.ContextMenus.SectionNavGroups; 8 | 9 | public class CreateContentTypeNavMenu : ISectionNavGroupAction 10 | { 11 | public string Text => "Create Content Type"; 12 | public string Icon => "add"; 13 | public string IconColor => string.Empty; 14 | public string SectionNavGroupAlias => Constants.Sections.SectionNavGroups.StructureContentTypesNavGroup; 15 | public int SortOrder => -100; 16 | 17 | public Task ContextMenuAction(MenuItemEventArgs e, NavigationManager navigationManager, ContextMenuService contextMenuService, 18 | IModalService modalService) 19 | { 20 | contextMenuService.Close(); 21 | navigationManager.NavigateTo(Urls.AdminStructureCreateContentType, true); 22 | return Task.CompletedTask; 23 | } 24 | } -------------------------------------------------------------------------------- /ZauberCMS.Components/ContextMenus/SectionNavGroups/CreateElementTypeNavMenu.cs: -------------------------------------------------------------------------------- 1 | using Blazored.Modal.Services; 2 | using Microsoft.AspNetCore.Components; 3 | using Radzen; 4 | using ZauberCMS.Core; 5 | using ZauberCMS.Core.Sections.Interfaces; 6 | 7 | namespace ZauberCMS.Components.ContextMenus.SectionNavGroups; 8 | 9 | public class CreateElementTypeNavMenu : ISectionNavGroupAction 10 | { 11 | public string Text => "Create Element Type"; 12 | public string Icon => "add"; 13 | public string IconColor => string.Empty; 14 | public string SectionNavGroupAlias => Constants.Sections.SectionNavGroups.StructureElementTypesNavGroup; 15 | public int SortOrder => -100; 16 | 17 | public Task ContextMenuAction(MenuItemEventArgs e, NavigationManager navigationManager, ContextMenuService contextMenuService, 18 | IModalService modalService) 19 | { 20 | contextMenuService.Close(); 21 | navigationManager.NavigateTo(Urls.AdminStructureCreateElementType, true); 22 | return Task.CompletedTask; 23 | } 24 | } -------------------------------------------------------------------------------- /ZauberCMS.Core/Membership/Mapping/MediaRoleDbMapping.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.EntityFrameworkCore; 2 | using Microsoft.EntityFrameworkCore.Metadata.Builders; 3 | using ZauberCMS.Core.Membership.Models; 4 | 5 | namespace ZauberCMS.Core.Membership.Mapping; 6 | 7 | public class MediaRoleDbMapping : IEntityTypeConfiguration 8 | { 9 | public void Configure(EntityTypeBuilder builder) 10 | { 11 | builder.ToTable("ZauberMediaRole"); 12 | 13 | // Define composite primary key 14 | builder.HasKey(ur => new { ur.MediaId, ur.RoleId }); 15 | 16 | builder 17 | .HasOne(x => x.Media) 18 | .WithMany(x => x.MediaRoles) 19 | .HasForeignKey(x => x.MediaId) 20 | .OnDelete(DeleteBehavior.Cascade); 21 | 22 | builder 23 | .HasOne(x => x.Role) 24 | .WithMany(x => x.MediaRoles) 25 | .HasForeignKey(x => x.RoleId) 26 | .OnDelete(DeleteBehavior.Cascade); 27 | 28 | } 29 | } -------------------------------------------------------------------------------- /ZauberCMS.Core/Shared/Interfaces/IAfterEntitySave.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.EntityFrameworkCore; 2 | 3 | namespace ZauberCMS.Core.Shared.Interfaces; 4 | 5 | /// 6 | /// Defines a contract for handling operations that need to occur after saving an entity to the database. 7 | /// 8 | // ReSharper disable once TypeParameterCanBeVariant 9 | public interface IAfterEntitySave 10 | { 11 | /// 12 | /// Executes operations needed after saving an entity to the database. 13 | /// 14 | /// The entity instance that is about to be saved. 15 | /// The state of the entity within the context (e.g., Added, Modified, Deleted). 16 | /// True if the entity needs to be resaved 17 | bool AfterSave(TEntity entity, EntityState entityState); 18 | 19 | /// 20 | /// Gets or sets the order in which the operation should be executed after saving an entity. 21 | /// 22 | int SortOrder { get; } 23 | } -------------------------------------------------------------------------------- /ZauberCMS.Routing/Views/Shared/Components/BootstrapPager/Default.cshtml: -------------------------------------------------------------------------------- 1 | @model ZauberCMS.Core.Shared.Models.PaginatedList 2 | 3 | @if (Model.TotalPages > 1) 4 | { 5 | 29 | } -------------------------------------------------------------------------------- /ZauberCMS.Components/Admin/StructureSection/Dialogs/ChangeTab.razor: -------------------------------------------------------------------------------- 1 | @page "/ChangeTab/{ContentTypeId:guid}" 2 | @using ZauberCMS.Core.Shared.Models 3 | 4 | 11 | 14 | 15 | 16 | @code { 17 | [CascadingParameter] BlazoredModalInstance BlazoredModal { get; set; } = null!; 18 | 19 | [Parameter] public Guid ContentTypeId { get; set; } 20 | [Parameter] public List Tabs { get; set; } = []; 21 | private Guid SelectedTabId { get; set; } 22 | 23 | private async Task OnPropertySelected() 24 | { 25 | await BlazoredModal.CloseAsync(ModalResult.Ok(SelectedTabId)); 26 | } 27 | } -------------------------------------------------------------------------------- /ZauberCMS.Components/Pages/NewSite.razor: -------------------------------------------------------------------------------- 1 | @implements ZauberCMS.Core.Content.Interfaces.IContentView 2 | @layout BlankLayout 3 | New Install 4 | 5 |
    6 |
    7 | 8 |

    Looks like you haven't created any content yet. If you are not sure where to start, then go to the admin page, and register an account, 9 | the first user is created as an admin then you will be redirected to the admin section.

    10 |

    Then make sure you check out our documentation and videos, they show you everything you 11 | need to know about building your first website.

    12 |
    13 |
    14 | 15 | @code { 16 | [Parameter] public Content? Content { get; set; } 17 | [Parameter] public Dictionary? LanguageKeys { get; set; } 18 | } 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /ZauberCMS.Core/Languages/Models/LanguageText.cs: -------------------------------------------------------------------------------- 1 | using ZauberCMS.Core.Extensions; 2 | 3 | namespace ZauberCMS.Core.Languages.Models; 4 | 5 | public class LanguageText 6 | { 7 | /// 8 | /// The ID 9 | /// 10 | public Guid Id { get; set; } = Guid.NewGuid().NewSequentialGuid(); 11 | 12 | /// 13 | /// ID of the parent Language Dictionary 14 | /// 15 | public Guid LanguageDictionaryId { get; set; } 16 | 17 | /// 18 | /// Parent Language Dictionary 19 | /// 20 | public LanguageDictionary? LanguageDictionary { get; set; } 21 | 22 | /// 23 | /// Language ID this relates to 24 | /// 25 | public Guid LanguageId { get; set; } 26 | 27 | /// 28 | /// Language this relates to 29 | /// 30 | public Language? Language { get; set; } 31 | 32 | /// 33 | /// The language text value 34 | /// 35 | public string Value { get; set; } = string.Empty; 36 | } -------------------------------------------------------------------------------- /ZauberCMS.Components/Shared/TreeButton.razor: -------------------------------------------------------------------------------- 1 |
    2 |
      3 |
    • 4 |
      5 |
      6 | @Icon @Name 7 |
      8 |
      9 |
    • 10 |
    11 |
    12 | 13 | @code 14 | { 15 | [Parameter, EditorRequired] public string? Icon { get; set; } 16 | [Parameter, EditorRequired] public string? Name { get; set; } 17 | [Parameter] public string? Url { get; set; } 18 | [Parameter] public EventCallback OnClick { get; set; } 19 | 20 | private async Task HandleClick() 21 | { 22 | if (OnClick.HasDelegate) 23 | { 24 | await OnClick.InvokeAsync(); 25 | } 26 | else if (!string.IsNullOrEmpty(Url)) 27 | { 28 | NavigationManager.NavigateTo(Url); 29 | } 30 | } 31 | 32 | } 33 | -------------------------------------------------------------------------------- /ZauberCMS.Core/Membership/Mapping/ContentRoleDbMapping.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.EntityFrameworkCore; 2 | using Microsoft.EntityFrameworkCore.Metadata.Builders; 3 | using ZauberCMS.Core.Membership.Models; 4 | 5 | namespace ZauberCMS.Core.Membership.Mapping; 6 | 7 | public class ContentRoleDbMapping : IEntityTypeConfiguration 8 | { 9 | public void Configure(EntityTypeBuilder builder) 10 | { 11 | builder.ToTable("ZauberContentRole"); 12 | 13 | // Define composite primary key 14 | builder.HasKey(ur => new { ur.ContentId, ur.RoleId }); 15 | 16 | builder 17 | .HasOne(ur => ur.Content) 18 | .WithMany(u => u.ContentRoles) 19 | .HasForeignKey(ur => ur.ContentId) 20 | .OnDelete(DeleteBehavior.Cascade); 21 | 22 | builder 23 | .HasOne(ur => ur.Role) 24 | .WithMany(r => r.ContentRoles) 25 | .HasForeignKey(ur => ur.RoleId) 26 | .OnDelete(DeleteBehavior.Cascade); 27 | 28 | } 29 | } -------------------------------------------------------------------------------- /ZauberCMS.Routing/Views/Shared/Components/RenderBlocks/RenderBlocksViewComponent.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.AspNetCore.Mvc; 2 | using ZauberCMS.Core.Content.Interfaces; 3 | using ZauberCMS.Core.Content.Models; 4 | using ZauberCMS.Core.Plugins; 5 | 6 | namespace ZauberCMS.Routing.Views.Shared.Components.RenderBlocks; 7 | 8 | public class RenderBlocksViewComponent(ExtensionManager extensionManager) : ViewComponent 9 | { 10 | public IViewComponentResult Invoke(List blocks, string cssSeparatorClasses) 11 | { 12 | var contentBlockViews = extensionManager.GetInstances(true); 13 | 14 | var renderBlockModel = new RenderBlocksModel 15 | { 16 | SeparatorCssClasses = cssSeparatorClasses, 17 | Blocks = blocks, 18 | ContentBlockViews = contentBlockViews 19 | .Select(x => x.Value) 20 | .DistinctBy(x => x.ContentTypeAlias) 21 | .ToDictionary(x => x.ContentTypeAlias, x => x) 22 | }; 23 | return View(renderBlockModel); 24 | } 25 | } -------------------------------------------------------------------------------- /ZauberCMS.Core/Content/ContentFinders/ContentFinderPipeline.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.AspNetCore.Http; 2 | using Microsoft.AspNetCore.Routing; 3 | using ZauberCMS.Core.Content.Interfaces; 4 | using ZauberCMS.Core.Plugins; 5 | 6 | namespace ZauberCMS.Core.Content.ContentFinders; 7 | 8 | public class ContentFinderPipeline(ExtensionManager extensionManager) 9 | { 10 | public async Task FindContent(HttpContext context, RouteValueDictionary defaultRouteValueDictionary) 11 | { 12 | var contentFinders = extensionManager.GetInstances(true); 13 | 14 | foreach (var finder in contentFinders.Values.OrderBy(x => x.SortOrder)) 15 | { 16 | var routeValueDictionary = await finder.TryFindContent(context); 17 | if(routeValueDictionary != null) 18 | { 19 | return routeValueDictionary; // Return the new route values if found 20 | } 21 | } 22 | 23 | return defaultRouteValueDictionary; // If nothing found, return the default route values 24 | } 25 | } -------------------------------------------------------------------------------- /ZauberCMS.Core/Languages/Parameters/QueryLanguageParameters.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Linq.Expressions; 5 | using ZauberCMS.Core.Languages.Models; 6 | using ZauberCMS.Core.Shared.Models; 7 | 8 | namespace ZauberCMS.Core.Languages.Parameters; 9 | 10 | public class QueryLanguageParameters 11 | { 12 | public bool AsNoTracking { get; set; } = true; 13 | public List Ids { get; set; } = []; 14 | public int PageIndex { get; set; } = 1; 15 | public int AmountPerPage { get; set; } = 10; 16 | public bool IncludeChildren { get; set; } 17 | public List LanguageIsoCodes { get; set; } = []; 18 | public GetLanguageOrderBy OrderBy { get; set; } = GetLanguageOrderBy.DateCreatedDescending; 19 | public Expression>? WhereClause { get; set; } 20 | public Func>? Query { get; set; } 21 | } 22 | 23 | public enum GetLanguageOrderBy 24 | { 25 | DateCreated, 26 | DateCreatedDescending, 27 | LanguageIsoCode, 28 | LanguageCultureName 29 | } -------------------------------------------------------------------------------- /ZauberCMS.Core/Membership/Parameters/QueryRolesParameters.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Linq.Expressions; 5 | using ZauberCMS.Core.Membership.Models; 6 | using ZauberCMS.Core.Shared.Models; 7 | 8 | namespace ZauberCMS.Core.Membership.Parameters; 9 | 10 | public class QueryRolesParameters 11 | { 12 | public List Roles { get; set; } = []; 13 | public bool AsNoTracking { get; set; } = true; 14 | public List Ids { get; set; } = []; 15 | public int PageIndex { get; set; } = 1; 16 | public int AmountPerPage { get; set; } = 10; 17 | public GetRolesOrderBy OrderBy { get; set; } = GetRolesOrderBy.DateUpdatedDescending; 18 | public Expression>? WhereClause { get; set; } 19 | public Func>? Query { get; set; } 20 | public string? SearchTerm { get; set; } 21 | } 22 | 23 | public enum GetRolesOrderBy 24 | { 25 | DateUpdated, 26 | DateUpdatedDescending, 27 | DateCreated, 28 | DateCreatedDescending, 29 | Name, 30 | NameDescending 31 | } -------------------------------------------------------------------------------- /ZauberCMS.Core/Membership/Parameters/RegisterUserParameters.cs: -------------------------------------------------------------------------------- 1 | using System.ComponentModel.DataAnnotations; 2 | using ZauberCMS.Core.Membership.Models; 3 | 4 | namespace ZauberCMS.Core.Membership.Parameters; 5 | 6 | public class RegisterUserParameters 7 | { 8 | [Required] 9 | [StringLength(150)] 10 | [Display(Name = "Username")] 11 | public string Username { get; set; } = string.Empty; 12 | 13 | [Required] 14 | [EmailAddress] 15 | [Display(Name = "Email")] 16 | public string Email { get; set; } = string.Empty; 17 | 18 | [Required] 19 | [StringLength(100, ErrorMessage = "The {0} must be at least {2} and at max {1} characters long.", MinimumLength = 8)] 20 | [DataType(DataType.Password)] 21 | [Display(Name = "Password")] 22 | public string Password { get; set; } = string.Empty; 23 | 24 | [Display(Name = "Remember me?")] 25 | public bool RememberMe { get; set; } 26 | 27 | public string? ReturnUrl { get; set; } 28 | 29 | public bool AutoLogin { get; set; } = true; 30 | 31 | public string? Name { get; set; } 32 | } -------------------------------------------------------------------------------- /ZauberCMS.Core/Membership/Parameters/QueryUsersParameters.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Linq.Expressions; 5 | using ZauberCMS.Core.Membership.Models; 6 | using ZauberCMS.Core.Shared.Models; 7 | 8 | namespace ZauberCMS.Core.Membership.Parameters; 9 | 10 | public class QueryUsersParameters 11 | { 12 | public bool Cached { get; set; } 13 | public List Roles { get; set; } = []; 14 | public bool AsNoTracking { get; set; } = true; 15 | public List Ids { get; set; } = []; 16 | public int PageIndex { get; set; } = 1; 17 | public int AmountPerPage { get; set; } = 10; 18 | public string? SearchTerm { get; set; } 19 | public GetUsersOrderBy OrderBy { get; set; } = GetUsersOrderBy.DateUpdatedDescending; 20 | public Expression>? WhereClause { get; set; } 21 | public Func>? Query { get; set; } 22 | } 23 | 24 | public enum GetUsersOrderBy 25 | { 26 | DateUpdated, 27 | DateUpdatedDescending, 28 | DateCreated, 29 | DateCreatedDescending 30 | } -------------------------------------------------------------------------------- /ZauberCMS.Components/Resources/SharedResource.resx: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | text/microsoft-resx 11 | 12 | 13 | 1.3 14 | 15 | 16 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 17 | 18 | 19 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 20 | 21 | 22 | Settings 23 | 24 | -------------------------------------------------------------------------------- /ZauberCMS.Components/Admin/StructureSection/StructureIndex.razor: -------------------------------------------------------------------------------- 1 | @attribute [Route(Url)] 2 | @layout SectionLayout 3 | @implements ZauberCMS.Core.Sections.Interfaces.ISection 4 | 5 | @Name 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | @code { 14 | private const string Url = Urls.AdminStructureBaseUrl; // So we only have on string 15 | public string Name => "Structure"; 16 | public string Alias => Constants.Sections.StructureSection; 17 | public string IndexUrl => Url; 18 | public int SortOrder => 2; 19 | 20 | [CascadingParameter] protected SectionLayout? Layout { get; set; } 21 | 22 | protected override void OnInitialized() 23 | { 24 | Layout?.SetSection(Alias); 25 | } 26 | } -------------------------------------------------------------------------------- /ZauberCMS.Core/Membership/Mapping/UserDbMapping.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.EntityFrameworkCore; 2 | using Microsoft.EntityFrameworkCore.Metadata.Builders; 3 | using ZauberCMS.Core.Extensions; 4 | using ZauberCMS.Core.Membership.Models; 5 | 6 | namespace ZauberCMS.Core.Membership.Mapping; 7 | 8 | public class UserDbMapping : IEntityTypeConfiguration 9 | { 10 | public void Configure(EntityTypeBuilder builder) 11 | { 12 | builder.Property(e => e.ExtendedData).ToJsonConversion(3500); 13 | builder.Property(x => x.PasswordHash).HasMaxLength(300); 14 | builder.Property(x => x.SecurityStamp).HasMaxLength(3000); 15 | builder.Property(x => x.ConcurrencyStamp).HasMaxLength(3000); 16 | builder.Property(x => x.PhoneNumber).HasMaxLength(100); 17 | builder.Property(x => x.UserName).HasMaxLength(150); 18 | 19 | builder.HasMany(c => c.PropertyData) 20 | .WithOne(x => x.User) 21 | .HasForeignKey(p => p.UserId) 22 | .OnDelete(DeleteBehavior.NoAction); 23 | 24 | builder.Ignore(x => x.Name); 25 | } 26 | } -------------------------------------------------------------------------------- /ZauberCMS.Components/Admin/ContentSection/ContentIndex.razor: -------------------------------------------------------------------------------- 1 | @attribute [Route(Url)] 2 | @attribute [Route(Urls.AdminBaseUrl)] 3 | @layout SectionLayout 4 | @implements ZauberCMS.Core.Sections.Interfaces.ISection 5 | 6 | @Name 7 | 8 | 9 | 10 | 11 | 12 | 13 | @code { 14 | private const string Url = Urls.AdminContentBaseUrl; // So we only have on string 15 | public string Name => "Content"; 16 | public string Alias => Constants.Sections.ContentSection; 17 | public string IndexUrl => Url; 18 | public int SortOrder => 0; 19 | 20 | [CascadingParameter] protected SectionLayout? Layout { get; set; } 21 | 22 | protected override void OnInitialized() 23 | { 24 | Layout?.SetSection(Alias); 25 | } 26 | } -------------------------------------------------------------------------------- /ZauberCMS.Core/Tags/Parameters/QueryTagParameters.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Linq.Expressions; 5 | using ZauberCMS.Core.Shared.Models; 6 | using ZauberCMS.Core.Tags.Models; 7 | 8 | namespace ZauberCMS.Core.Tags.Parameters; 9 | 10 | public class QueryTagParameters 11 | { 12 | public bool Cached { get; set; } 13 | public bool AsNoTracking { get; set; } = true; 14 | public List Ids { get; set; } = []; 15 | public List TagNames { get; set; } = []; 16 | public List TagSlugs { get; set; } = []; 17 | public List ItemIds { get; set; } = []; 18 | public int PageIndex { get; set; } = 1; 19 | public int AmountPerPage { get; set; } = 10; 20 | public GetTagOrderBy OrderBy { get; set; } = GetTagOrderBy.TagName; 21 | public Expression>? WhereClause { get; set; } 22 | public Func>? Query { get; set; } 23 | } 24 | 25 | public enum GetTagOrderBy 26 | { 27 | DateCreated, 28 | DateCreatedDescending, 29 | TagName, 30 | TagNameDescending, 31 | SortOrder 32 | } -------------------------------------------------------------------------------- /ZauberCMS.Core/Email/IdentityEmailSender.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.AspNetCore.Identity; 2 | using ZauberCMS.Core.Membership.Models; 3 | using ZauberCMS.Core.Providers; 4 | 5 | namespace ZauberCMS.Core.Email; 6 | 7 | public class IdentityEmailSender(ProviderService providerService) : IEmailSender 8 | { 9 | public Task SendConfirmationLinkAsync(User user, string email, string confirmationLink)=> 10 | providerService.EmailProvider!.SendEmailAsync(email, "Confirm your email", 11 | $"Please confirm your account by clicking here."); 12 | 13 | public Task SendPasswordResetLinkAsync(User user, string email, string resetLink) => 14 | providerService.EmailProvider!.SendEmailAsync(email, "Reset your password", 15 | $"Please reset your password by clicking here."); 16 | 17 | public Task SendPasswordResetCodeAsync(User user, string email, string resetCode) => 18 | providerService.EmailProvider!.SendEmailAsync(email, "Reset your password", 19 | $"Please reset your password using the following code: {resetCode}"); 20 | } -------------------------------------------------------------------------------- /ZauberCMS.Core/Shared/Services/ValidateService.cs: -------------------------------------------------------------------------------- 1 | using Radzen; 2 | using ZauberCMS.Core.Extensions; 3 | using ZauberCMS.Core.Plugins; 4 | using ZauberCMS.Core.Shared.Validation.Interfaces; 5 | 6 | namespace ZauberCMS.Core.Shared.Services; 7 | 8 | public class ValidateService(ExtensionManager extensionManager, NotificationService notificationService) 9 | { 10 | private Dictionary> Validates { get; set; } = extensionManager.GetInstances>(true); 11 | 12 | public async Task CanSave(T item) 13 | { 14 | var canSave = true; 15 | if (Validates.Count != 0) 16 | { 17 | foreach (var validate in Validates) 18 | { 19 | var result = await validate.Value.Validate(item); 20 | if (result.ErrorMessages.Count != 0) 21 | { 22 | canSave = false; 23 | notificationService.ShowNotifications("Validation Error", NotificationSeverity.Error, result.ErrorMessages); 24 | } 25 | } 26 | } 27 | return canSave; 28 | } 29 | 30 | } -------------------------------------------------------------------------------- /ZauberCMS.Components/Admin/SettingsSection/Navigation/SettingsAdvancedTree.razor: -------------------------------------------------------------------------------- 1 | @using ZauberCMS.Core.Shared.Models 2 | 3 | @implements ZauberCMS.Core.Sections.Interfaces.ISectionNav 4 | 5 | 6 | 7 | @code { 8 | 9 | public int SortOrder => 0; 10 | public string SectionNavGroupAlias => Constants.Sections.SectionNavGroups.SettingsAdvancedNavGroup; 11 | 12 | private IEnumerable AdvancedData { get; set; } = []; 13 | 14 | protected override void OnInitialized() 15 | { 16 | GetSeoTree(); 17 | } 18 | 19 | private void GetSeoTree() 20 | { 21 | var tree = new List(); 22 | 23 | var auditTree = new TreeStub 24 | { 25 | Id = Constants.Guids.AuditTreeRootId, 26 | Name = "Audit Log", 27 | Icon = "sync_alt", 28 | SortOrder = 10, 29 | Url = Urls.AdminSettingsAuditLog 30 | }; 31 | 32 | tree.Add(auditTree); 33 | 34 | AdvancedData = tree; 35 | } 36 | 37 | public void Dispose() 38 | { 39 | 40 | } 41 | 42 | } -------------------------------------------------------------------------------- /ZauberCMS.Template/template/ZauberCMSTemplate.sln: -------------------------------------------------------------------------------- 1 | 2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 17 4 | VisualStudioVersion = 17.0.31903.59 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ZauberCMSTemplate.Site", "ZauberCMSTemplate.Site\ZauberCMSTemplate.Site.csproj", "{75B02D0F-915C-4965-9E89-6794E9761806}" 7 | EndProject 8 | Global 9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 10 | Debug|Any CPU = Debug|Any CPU 11 | Release|Any CPU = Release|Any CPU 12 | EndGlobalSection 13 | GlobalSection(SolutionProperties) = preSolution 14 | HideSolutionNode = FALSE 15 | EndGlobalSection 16 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 17 | {75B02D0F-915C-4965-9E89-6794E9761806}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 18 | {75B02D0F-915C-4965-9E89-6794E9761806}.Debug|Any CPU.Build.0 = Debug|Any CPU 19 | {75B02D0F-915C-4965-9E89-6794E9761806}.Release|Any CPU.ActiveCfg = Release|Any CPU 20 | {75B02D0F-915C-4965-9E89-6794E9761806}.Release|Any CPU.Build.0 = Release|Any CPU 21 | EndGlobalSection 22 | EndGlobal 23 | -------------------------------------------------------------------------------- /ZauberCMS.Core/Media/Parameters/QueryMediaParameters.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Linq.Expressions; 5 | using ZauberCMS.Core.Media.Models; 6 | using ZauberCMS.Core.Shared.Models; 7 | 8 | namespace ZauberCMS.Core.Media.Parameters; 9 | 10 | public class QueryMediaParameters 11 | { 12 | public bool Cached { get; set; } 13 | public bool AsNoTracking { get; set; } = true; 14 | public List Ids { get; set; } = []; 15 | public int PageIndex { get; set; } = 1; 16 | public int AmountPerPage { get; set; } = 10; 17 | public bool IncludeChildren { get; set; } 18 | public List MediaTypes { get; set; } = []; 19 | public GetMediaOrderBy OrderBy { get; set; } = GetMediaOrderBy.DateUpdatedDescending; 20 | public Expression>? WhereClause { get; set; } 21 | public Func>? Query { get; set; } 22 | } 23 | 24 | public enum GetMediaOrderBy 25 | { 26 | DateUpdated, 27 | DateUpdatedDescending, 28 | DateCreated, 29 | DateCreatedDescending, 30 | Name, 31 | NameDescending 32 | } -------------------------------------------------------------------------------- /ZauberCMS.Components/Admin/Shared/Dialogs/ChangeAlias.razor: -------------------------------------------------------------------------------- 1 | @using ZauberCMS.Core.Shared.Models 2 |
    3 | 4 |
    5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | @code { 20 | [Parameter, EditorRequired] public PropertyType PropertyType { get; set; } = null!; 21 | 22 | [CascadingParameter] BlazoredModalInstance BlazoredModal { get; set; } = null!; 23 | 24 | private async Task Save() 25 | { 26 | await BlazoredModal.CloseAsync(ModalResult.Ok(PropertyType)); 27 | } 28 | } -------------------------------------------------------------------------------- /ZauberCMS.Core/Media/Interfaces/IMediaService.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Threading; 4 | using System.Threading.Tasks; 5 | using ZauberCMS.Core.Media.Parameters; 6 | using ZauberCMS.Core.Shared.Models; 7 | 8 | namespace ZauberCMS.Core.Media.Interfaces; 9 | 10 | public interface IMediaService 11 | { 12 | Task GetMediaAsync(GetMediaParameters parameters, CancellationToken cancellationToken = default); 13 | Task> SaveMediaAsync(SaveMediaParameters parameters, CancellationToken cancellationToken = default); 14 | Task> QueryMediaAsync(QueryMediaParameters parameters, CancellationToken cancellationToken = default); 15 | Task> DeleteMediaAsync(DeleteMediaParameters parameters, CancellationToken cancellationToken = default); 16 | Task HasChildMediaAsync(HasChildMediaParameters parameters, CancellationToken cancellationToken = default); 17 | Task> GetRestrictedMediaUrlsAsync(GetRestrictedMediaUrlsParameters parameters, CancellationToken cancellationToken = default); 18 | } -------------------------------------------------------------------------------- /ZauberCMS.Core/Plugins/AssemblyManager.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Concurrent; 2 | using System.Reflection; 3 | 4 | namespace ZauberCMS.Core.Plugins; 5 | 6 | public static class AssemblyManager 7 | { 8 | private static IEnumerable _assemblies = null!; 9 | #pragma warning disable CA2211 10 | public static ConcurrentDictionary> Types = null!; 11 | #pragma warning restore CA2211 12 | public static ConcurrentDictionary TypesByName = null!; 13 | 14 | /// 15 | /// Gets the cached assemblies that have been set by the SetAssemblies method. 16 | /// 17 | public static IEnumerable Assemblies => _assemblies; 18 | 19 | /// 20 | /// Sets the assemblies and invalidates the type cache. 21 | /// 22 | /// The assemblies to set. 23 | public static void SetAssemblies(IEnumerable assems) 24 | { 25 | _assemblies = assems; 26 | Types = new ConcurrentDictionary>(); 27 | TypesByName = new ConcurrentDictionary(); 28 | } 29 | } -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2024 Lee Messenger (ZauberCMS) 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 | -------------------------------------------------------------------------------- /ZauberCMS.Core/Shared/Services/IHtmlSanitizerService.cs: -------------------------------------------------------------------------------- 1 | namespace ZauberCMS.Core.Shared.Services; 2 | 3 | /// 4 | /// Service for sanitizing HTML content to prevent XSS attacks. 5 | /// Developers can implement this interface to provide custom sanitization logic. 6 | /// 7 | public interface IHtmlSanitizerService 8 | { 9 | /// 10 | /// Sanitizes the provided HTML string by removing potentially dangerous content. 11 | /// 12 | /// The HTML string to sanitize 13 | /// The sanitized HTML string 14 | string Sanitize(string? html); 15 | 16 | /// 17 | /// Sanitizes the provided HTML string asynchronously. Override this for custom async logic. 18 | /// 19 | /// The HTML string to sanitize 20 | /// Cancellation token 21 | /// The sanitized HTML string 22 | Task SanitizeAsync(string? html, CancellationToken cancellationToken = default) 23 | { 24 | return Task.FromResult(Sanitize(html)); 25 | } 26 | } 27 | 28 | -------------------------------------------------------------------------------- /ZauberCMS.Template/LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2025 Lee Messenger 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 | -------------------------------------------------------------------------------- /ZauberCMS.Components/Admin/Layout/UserProfile.razor: -------------------------------------------------------------------------------- 1 | @using Microsoft.AspNetCore.Components.Authorization 2 | 3 | 4 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | @code { 14 | 15 | [Inject] public AuthenticationStateProvider AuthenticationStateProvider { get; set; } = null!; 16 | private AuthenticationState AuthState { get; set; } = null!; 17 | 18 | private void Edit() 19 | { 20 | NavigationManager.NavigateTo($"{Urls.AdminUsersEdit}/{AuthState.User.GetUserId()}"); 21 | } 22 | 23 | private void Logout() 24 | { 25 | NavigationManager.NavigateTo(Urls.ApiLogout, true); 26 | } 27 | 28 | protected override async Task OnInitializedAsync() 29 | { 30 | AuthState = await AuthenticationStateProvider.GetAuthenticationStateAsync(); 31 | } 32 | 33 | } 34 | 35 | -------------------------------------------------------------------------------- /ZauberCMS.Components/Editors/RadioButtonListProperty.razor: -------------------------------------------------------------------------------- 1 | @implements ZauberCMS.Core.Content.Interfaces.IContentProperty 2 | @using ZauberCMS.Components.Editors.Settings 3 | @inherits ZauberCMS.Components.Editors.Models.ListPropertyBaseComponent 4 | 5 | 12 | 13 | @code { 14 | public string Name { get; set; } = "Radio Button List"; 15 | public string Alias { get; set; } = "ZauberCMS.RadioButtonList"; 16 | public string Icon { get; set; } = "radio_button_checked"; 17 | public string Description { get; set; } = "Radio button list using manual or custom data"; 18 | public Type? SettingsComponent { get; set; } = typeof(ListPropertySettings); 19 | public List Scripts { get; set; } = []; 20 | public List Styles { get; set; } = []; 21 | public bool FullWidth { get; set; } 22 | } -------------------------------------------------------------------------------- /ZauberCMS.Core/Languages/Validation/ValidateLanguageDictionary.cs: -------------------------------------------------------------------------------- 1 | using ZauberCMS.Core.Extensions; 2 | using ZauberCMS.Core.Languages.Models; 3 | using ZauberCMS.Core.Shared.Validation.Interfaces; 4 | using ZauberCMS.Core.Shared.Validation.Models; 5 | 6 | namespace ZauberCMS.Core.Languages.Validation; 7 | 8 | public class ValidateLanguageDictionary : IValidate 9 | { 10 | public Task Validate(LanguageDictionary item) 11 | { 12 | var validateResult = new ValidateResult(); 13 | if (item.Key.IsNullOrWhiteSpace()) 14 | { 15 | validateResult.ErrorMessages.Add("You cannot leave key name empty"); 16 | } 17 | 18 | // Make sure the Language texts are not null 19 | foreach (var languageText in item.Texts) 20 | { 21 | if (languageText.Value.IsNullOrWhiteSpace()) 22 | { 23 | validateResult.ErrorMessages.Add("You cannot leave the language values empty"); 24 | return Task.FromResult(validateResult); 25 | } 26 | } 27 | 28 | return Task.FromResult(validateResult); 29 | } 30 | } -------------------------------------------------------------------------------- /ZauberCMS.Core/Providers/IStorageProvider.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.AspNetCore.Components.Forms; 2 | using ZauberCMS.Core.Shared.Models; 3 | 4 | namespace ZauberCMS.Core.Providers; 5 | 6 | public interface IStorageProvider 7 | { 8 | /// 9 | /// Saves the file 10 | /// 11 | /// 12 | /// 13 | /// 14 | /// 15 | public Task> SaveFile(IBrowserFile browserFile, Media.Models.Media? existingMedia = null, string? parentFolderName = null, bool overwrite = true); 16 | 17 | /// 18 | /// Deletes the file 19 | /// 20 | /// 21 | public Task DeleteFile(string? url); 22 | 23 | /// 24 | /// Checks to determine if a file can be used 25 | /// 26 | /// 27 | /// 28 | public Task> CanUseFile(IBrowserFile browserFile, bool onlyImages = false); 29 | 30 | } -------------------------------------------------------------------------------- /ZauberCMS.Core/Seo/Mapping/SeoRedirectDbMapping.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.EntityFrameworkCore; 2 | using Microsoft.EntityFrameworkCore.Metadata.Builders; 3 | using ZauberCMS.Core.Seo.Models; 4 | 5 | namespace ZauberCMS.Core.Seo.Mapping; 6 | 7 | public class SeoRedirectDbMapping : IEntityTypeConfiguration 8 | { 9 | public void Configure(EntityTypeBuilder builder) 10 | { 11 | builder.ToTable("ZauberRedirects"); 12 | builder.HasKey(x => x.Id); 13 | builder.Property(x => x.Id).IsRequired(); 14 | builder.Property(x => x.FromUrl).IsRequired().HasMaxLength(500); 15 | builder.Property(x => x.ToUrl).IsRequired().HasMaxLength(500); 16 | builder.Property(x => x.DateCreated).IsRequired(); 17 | builder.Property(x => x.DateUpdated).IsRequired(); 18 | 19 | builder.Ignore(x => x.Name); 20 | 21 | builder.HasOne(d => d.Domain) 22 | .WithMany(p => p.Redirects) 23 | .HasForeignKey(d => d.DomainId) 24 | .OnDelete(DeleteBehavior.Cascade); 25 | 26 | builder.HasIndex(x => x.FromUrl).HasDatabaseName("IX_ZauberRedirects_FromUrl"); 27 | } 28 | } -------------------------------------------------------------------------------- /ZauberCMS.Core/Data/ZauberDbContext.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.EntityFrameworkCore; 2 | using Microsoft.EntityFrameworkCore.Diagnostics; 3 | using Microsoft.Extensions.Configuration; 4 | 5 | namespace ZauberCMS.Core.Data; 6 | 7 | public class ZauberDbContext(DbContextOptions options, IConfiguration configuration) 8 | : ZauberDbContextBase(options, configuration), IZauberDbContext 9 | { 10 | private readonly IConfiguration _configuration = configuration; 11 | 12 | protected override void OnConfiguring(DbContextOptionsBuilder options) 13 | { 14 | var section = _configuration.GetSection("Zauber"); 15 | var connectionString = section.GetValue("ConnectionString"); 16 | options.UseSqlServer(connectionString, builder => 17 | { 18 | builder.MigrationsHistoryTable(tableName: "ZauberMigrations"); 19 | builder.UseQuerySplittingBehavior(QuerySplittingBehavior.SplitQuery); 20 | }); 21 | #if DEBUG 22 | options.EnableSensitiveDataLogging(); 23 | #endif 24 | options 25 | .ConfigureWarnings(warnings => warnings.Ignore(RelationalEventId.PendingModelChangesWarning)); 26 | } 27 | } -------------------------------------------------------------------------------- /ZauberCMS.Components/Admin/MediaSection/Buttons/CreateMediaButtons.razor: -------------------------------------------------------------------------------- 1 | @using ZauberCMS.Core.Media.Parameters 2 | @using ZauberCMS.Core.Media.Models 3 | OnClick(args, "CreateMedia")) 4 | Text="Create Folder"> 5 | 6 | @if (Media is { MediaType: MediaType.Folder }) 7 | { 8 | 9 | } 10 | 11 | 12 | @code { 13 | [Parameter] public Guid? ParentId { get; set; } 14 | private Media? Media { get; set; } 15 | 16 | protected override async Task OnParametersSetAsync() 17 | { 18 | if (ParentId != null) 19 | { 20 | Media = await MediaService.GetMediaAsync(new GetMediaParameters { Id = ParentId.Value }); 21 | } 22 | } 23 | 24 | private void OnClick(RadzenSplitButtonItem? item, string buttonName) 25 | { 26 | var action = item != null ? Urls.AdminCreateMedia : Urls.AdminCreateMediaFolder; 27 | var path = ParentId != null ? $"{action}/{ParentId}" : $"{action}"; 28 | NavigationManager.NavigateTo(path); 29 | } 30 | } -------------------------------------------------------------------------------- /ZauberCMS.Core/Membership/Authentication/GoogleAuthentication.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.AspNetCore.Authentication; 2 | using Microsoft.Extensions.Configuration; 3 | using Microsoft.Extensions.DependencyInjection; 4 | using ZauberCMS.Core.Extensions; 5 | using ZauberCMS.Core.Plugins.Interfaces; 6 | 7 | namespace ZauberCMS.Core.Membership.Authentication; 8 | 9 | public class GoogleAuthentication : IExternalAuthenticationProvider 10 | { 11 | public void Add(IServiceCollection servicesCollection, AuthenticationBuilder authenticationBuilder, IConfiguration configuration) 12 | { 13 | var googleId = configuration.GetValue("Zauber:Identity:ExternalProviders:Google:ClientId"); 14 | if (!googleId.IsNullOrWhiteSpace()) 15 | { 16 | // https://docs.microsoft.com/en-us/aspnet/core/security/authentication/social/google-logins?view=aspnetcore-5.0 17 | authenticationBuilder.AddGoogle(options => 18 | { 19 | options.ClientId = googleId; 20 | options.ClientSecret = configuration.GetValue("Zauber:Identity:ExternalProviders:Google:ClientSecret") ?? ""; 21 | }); 22 | } 23 | } 24 | } -------------------------------------------------------------------------------- /ZauberCMS.Components/Admin/Shared/ExtendedDataEditor.razor: -------------------------------------------------------------------------------- 1 | 2 |
    3 | @foreach (var extData in ExtendedData) 4 | { 5 |
    6 |
    7 |
    8 | 9 |
    10 |
    11 | 12 |
    13 |
    14 |
    15 | 16 |
    17 |
    18 | } 19 | 20 |
    21 | 22 | 23 | @code { 24 | [Parameter] public Dictionary ExtendedData { get; set; } = []; 25 | [Parameter] public EventCallback> ValueChanged { get; set; } 26 | 27 | private async Task Changed() 28 | { 29 | await ValueChanged.InvokeAsync(ExtendedData); 30 | } 31 | 32 | } -------------------------------------------------------------------------------- /ZauberCMS.Template/template/.template.config/template.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "http://json.schemastore.org/template", 3 | "author": "Lee Messenger", 4 | "classifications": [ "template", "blazor", "cms" ], 5 | "identity": "ZauberCMS.Template", 6 | "name": "ZauberCMS Website Template", 7 | "shortName": "zaubercms", 8 | "tags": { 9 | "language": "C#", 10 | "type": "solution" 11 | }, 12 | "sourceName": "ZauberCMSTemplate", 13 | "preferNameDirectory": true, 14 | "sources": [ 15 | { 16 | "modifiers": [ 17 | { 18 | "exclude": [ 19 | "**/.git/**", 20 | "**/.vs/**" 21 | ], 22 | "CopyOnly": [ 23 | ] 24 | } 25 | ] 26 | } 27 | ], 28 | "symbols": { 29 | "httpPort": { 30 | "type": "generated", 31 | "generator": "port", 32 | "parameters": { 33 | "fallback": 5000 34 | }, 35 | "replaces": "38357" 36 | }, 37 | "httpsPort": { 38 | "type": "generated", 39 | "generator": "port", 40 | "parameters": { 41 | "low": 44300, 42 | "high": 44399, 43 | "fallback": 5001 44 | }, 45 | "replaces": "44340" 46 | } 47 | } 48 | } -------------------------------------------------------------------------------- /ZauberCMS.Core/Extensions/HttpContextExtensions.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.AspNetCore.Http; 2 | using Microsoft.AspNetCore.WebUtilities; 3 | 4 | namespace ZauberCMS.Core.Extensions; 5 | 6 | public static class HttpContextExtensions 7 | { 8 | /// 9 | /// Helper to create urls in services and commands/handlers 10 | /// 11 | /// 12 | /// var url = _httpContextAccessor.ToAbsoluteUrl("/Identity/Account/ConfirmEmail", new { userId = applicationUser.Id, code }); 13 | /// 14 | /// 15 | /// 16 | /// 17 | /// 18 | public static string ToAbsoluteUrl(this IHttpContextAccessor httpContextAccessor, string relativeUrl, object? parameters = null) 19 | { 20 | var request = httpContextAccessor.HttpContext?.Request; 21 | 22 | var url = new Uri(new Uri($"{request?.Scheme}://{request?.Host.Value}"), relativeUrl).ToString(); 23 | 24 | if (parameters != null) 25 | { 26 | url = QueryHelpers.AddQueryString(url, parameters.ToDictionary()!); 27 | } 28 | 29 | return url; 30 | } 31 | } -------------------------------------------------------------------------------- /ZauberCMS.Components/Admin/Layout/SectionLinks.razor: -------------------------------------------------------------------------------- 1 | @using ZauberCMS.Core.Plugins 2 | @using ZauberCMS.Core.Sections.Interfaces 3 | @using ZauberCMS.Core.Shared 4 | @foreach (var section in Sections.OrderBy(x => x.Value.SortOrder)) 5 | { 6 | NavigateTo(section.Value.IndexUrl))/> 7 | } 8 | 9 | @code { 10 | 11 | [Inject] public ExtensionManager ExtensionManager { get; set; } = null!; 12 | [Inject] public TreeState TreeState { get; set; } = null!; 13 | 14 | private Dictionary Sections { get; set; } = new(); 15 | 16 | [Parameter] public string? CurrentSection { get; set; } 17 | 18 | protected override void OnInitialized() 19 | { 20 | Sections = ExtensionManager.GetInstances(true); 21 | } 22 | 23 | private void NavigateTo(string url) 24 | { 25 | // If we click the top nav items we need to clear the tree state value 26 | TreeState.TreeValue = null; 27 | StateHasChanged(); 28 | NavigationManager.NavigateTo(url); 29 | } 30 | } -------------------------------------------------------------------------------- /ZauberCMS.Core/Data/PostgreSqlZauberDbContext.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.EntityFrameworkCore; 2 | using Microsoft.EntityFrameworkCore.Diagnostics; 3 | using Microsoft.Extensions.Configuration; 4 | 5 | namespace ZauberCMS.Core.Data; 6 | 7 | public class PostgreSqlZauberDbContext( 8 | DbContextOptions options, 9 | IConfiguration configuration) 10 | : ZauberDbContextBase(options, configuration), IZauberDbContext 11 | { 12 | private readonly IConfiguration _configuration = configuration; 13 | 14 | protected override void OnConfiguring(DbContextOptionsBuilder options) 15 | { 16 | var section = _configuration.GetSection("Zauber"); 17 | var connectionString = section.GetValue("ConnectionString"); 18 | options.UseNpgsql(connectionString, builder => 19 | { 20 | builder.MigrationsHistoryTable(tableName: "ZauberMigrations"); 21 | builder.UseQuerySplittingBehavior(QuerySplittingBehavior.SplitQuery); 22 | }); 23 | #if DEBUG 24 | options.EnableSensitiveDataLogging(); 25 | #endif 26 | options 27 | .ConfigureWarnings(warnings => warnings.Ignore(RelationalEventId.PendingModelChangesWarning)); 28 | } 29 | } -------------------------------------------------------------------------------- /ZauberCMS.Components/Admin/MediaSection/CreateMedia.razor: -------------------------------------------------------------------------------- 1 | @attribute [Route(Urls.AdminCreateMedia)] 2 | @attribute [Route($"{Urls.AdminCreateMedia}/{{ParentId:guid}}")] 3 | @layout SectionLayout 4 | 5 | Create Media 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | @code { 18 | [Parameter] public Guid? ParentId { get; set; } 19 | 20 | [Inject] NotificationService NotificationService { get; set; } = null!; 21 | 22 | [CascadingParameter] protected SectionLayout? Layout { get; set; } 23 | 24 | protected override void OnInitialized() 25 | { 26 | Layout?.SetSection(Constants.Sections.MediaSection); 27 | } 28 | 29 | private static string GetCompositeKey(Guid? parentId) 30 | { 31 | return $"{parentId?.ToString() ?? "null"}"; 32 | } 33 | } -------------------------------------------------------------------------------- /ZauberCMS.Core/Content/Interfaces/IDataListSource.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.Extensions.DependencyInjection; 2 | using ZauberCMS.Core.Content.Models; 3 | 4 | namespace ZauberCMS.Core.Content.Interfaces; 5 | 6 | public interface IDataListSource 7 | { 8 | /// 9 | /// Name of the data list source 10 | /// 11 | string Name { get; } 12 | 13 | /// 14 | /// Description of the data list source. 15 | /// 16 | string Description { get; } 17 | 18 | /// 19 | /// Represents the Icon property of a data list source. 20 | /// 21 | string Icon { get; } 22 | 23 | /// 24 | /// The full name of the implemented data source class including namespace. 25 | /// 26 | string FullName { get; } 27 | 28 | /// 29 | /// Retrieves a list of items from a data source. 30 | /// 31 | /// The service scope used for dependency injection. 32 | /// The current content object. 33 | /// A collection of DataListItem objects. 34 | IEnumerable GetItems(IServiceScope scope, Models.Content? currentContent); 35 | } -------------------------------------------------------------------------------- /ZauberCMS.Core/Membership/Authentication/MicrosoftAuthentication.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.AspNetCore.Authentication; 2 | using Microsoft.Extensions.Configuration; 3 | using Microsoft.Extensions.DependencyInjection; 4 | using ZauberCMS.Core.Extensions; 5 | using ZauberCMS.Core.Plugins.Interfaces; 6 | 7 | namespace ZauberCMS.Core.Membership.Authentication; 8 | 9 | public class MicrosoftAuthentication : IExternalAuthenticationProvider 10 | { 11 | public void Add(IServiceCollection servicesCollection, AuthenticationBuilder authenticationBuilder, IConfiguration configuration) 12 | { 13 | var microsoftId = configuration.GetValue("Zauber:Identity:ExternalProviders:Microsoft:ClientId"); 14 | if (!microsoftId.IsNullOrWhiteSpace()) 15 | { 16 | // https://docs.microsoft.com/en-us/aspnet/core/security/authentication/social/microsoft-logins?view=aspnetcore-5.0 17 | authenticationBuilder.AddMicrosoftAccount(microsoftOptions => 18 | { 19 | microsoftOptions.ClientId = microsoftId; 20 | microsoftOptions.ClientSecret = configuration.GetValue("Zauber:Identity:ExternalProviders:Microsoft:ClientSecret") ?? ""; 21 | }); 22 | } 23 | } 24 | } -------------------------------------------------------------------------------- /ZauberCMS.Core/Seo/Checks/CanonicalSeoChecker.cs: -------------------------------------------------------------------------------- 1 | using HtmlAgilityPack; 2 | using ZauberCMS.Core.Seo.Models; 3 | using ZauberCMS.Core.Shared.Models; 4 | 5 | namespace ZauberCMS.Core.Seo.Checks; 6 | 7 | public class CanonicalSeoChecker : ISeoCheck 8 | { 9 | public string Name => "Canonical Link Checker"; 10 | public Task Check(string url, HtmlDocument document, Content.Models.Content content) 11 | { 12 | var result = new SeoCheckResult(Name); 13 | 14 | // Check if canonical link is missing 15 | var canonicalLinkExists = document.DocumentNode 16 | .SelectSingleNode("//link[@rel='canonical']") != null; 17 | 18 | var seoItem = new SeoCheckResultItem(); 19 | 20 | if (!canonicalLinkExists) 21 | { 22 | seoItem.Status = AlertType.Warning; 23 | seoItem.DefaultMessage = "Canonical link is missing."; 24 | } 25 | 26 | if (seoItem.Status == AlertType.Success) 27 | { 28 | seoItem.DefaultMessage = "Canonical link is present."; 29 | } 30 | 31 | result.Items.Add(seoItem); 32 | 33 | return Task.FromResult(result); 34 | } 35 | 36 | public int SortOrder => 5; 37 | } -------------------------------------------------------------------------------- /ZauberCMS.Core/Data/SqliteZauberDbContext.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.EntityFrameworkCore; 2 | using Microsoft.EntityFrameworkCore.Diagnostics; 3 | using Microsoft.Extensions.Configuration; 4 | 5 | namespace ZauberCMS.Core.Data; 6 | 7 | public class SqliteZauberDbContext( 8 | DbContextOptions options, 9 | IConfiguration configuration) 10 | : ZauberDbContextBase(options, configuration), IZauberDbContext 11 | { 12 | private readonly IConfiguration _configuration = configuration; 13 | 14 | protected override void OnConfiguring(DbContextOptionsBuilder options) 15 | { 16 | var section = _configuration.GetSection("Zauber"); 17 | var connectionString = section.GetValue("ConnectionString"); 18 | options.UseSqlite(connectionString, builder => 19 | { 20 | builder.MigrationsHistoryTable(tableName: "ZauberMigrations"); 21 | builder.UseQuerySplittingBehavior(QuerySplittingBehavior.SplitQuery); 22 | }); 23 | #if DEBUG 24 | options.EnableSensitiveDataLogging(); 25 | #endif 26 | options 27 | .ConfigureWarnings(warnings => warnings.Ignore(RelationalEventId.PendingModelChangesWarning)); 28 | 29 | } 30 | } --------------------------------------------------------------------------------