diff --git a/DNN Platform/DotNetNuke.Abstractions/Collections/IObjectList.cs b/DNN Platform/DotNetNuke.Abstractions/Collections/IObjectList.cs new file mode 100644 index 00000000000..ed17ee7cf15 --- /dev/null +++ b/DNN Platform/DotNetNuke.Abstractions/Collections/IObjectList.cs @@ -0,0 +1,23 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information + +namespace DotNetNuke.Abstractions.Collections; + +using System.Collections.Generic; + +/// +public interface IObjectList : IList +{ + /// + /// Adds a new instance of to the list. + /// + /// The new instance. + T AddNew(); + + /// + /// Adds a range of items to the list. + /// + /// The items to add. + void AddRange(IEnumerable items); +} diff --git a/DNN Platform/DotNetNuke.Abstractions/Skins/ISkinInfo.cs b/DNN Platform/DotNetNuke.Abstractions/Skins/ISkinInfo.cs new file mode 100644 index 00000000000..cfa0dad141e --- /dev/null +++ b/DNN Platform/DotNetNuke.Abstractions/Skins/ISkinInfo.cs @@ -0,0 +1,18 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information + +namespace DotNetNuke.Abstractions.Skins; + +/// Represents a skin. +public interface ISkinInfo +{ + /// Gets or sets the ID of the skin. + int SkinId { get; set; } + + /// Gets or sets the ID of the skin package. + int SkinPackageId { get; set; } + + /// Gets or sets the source of the skin. + string SkinSrc { get; set; } +} diff --git a/DNN Platform/DotNetNuke.Abstractions/Skins/ISkinPackageInfo.cs b/DNN Platform/DotNetNuke.Abstractions/Skins/ISkinPackageInfo.cs new file mode 100644 index 00000000000..78461278248 --- /dev/null +++ b/DNN Platform/DotNetNuke.Abstractions/Skins/ISkinPackageInfo.cs @@ -0,0 +1,32 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information + +namespace DotNetNuke.Abstractions.Skins; + +using System.Collections.Generic; + +using DotNetNuke.Abstractions.Collections; + +/// The skin package info. +public interface ISkinPackageInfo +{ + /// Gets or sets the ID of the package. + int PackageId { get; set; } + + /// Gets or sets the ID of the skin package. + int SkinPackageId { get; set; } + + /// Gets or sets the ID of the portal. + /// If the portal ID is -1, then the skin package is a global skin package. + int PortalId { get; set; } + + /// Gets or sets the name of the skin. + string SkinName { get; set; } + + /// Gets the skins in the skin package. + IObjectList Skins { get; } + + /// Gets or sets the type of the skin. + SkinPackageType SkinType { get; set; } +} diff --git a/DNN Platform/DotNetNuke.Abstractions/Skins/ISkinService.cs b/DNN Platform/DotNetNuke.Abstractions/Skins/ISkinService.cs new file mode 100644 index 00000000000..358fec6eaef --- /dev/null +++ b/DNN Platform/DotNetNuke.Abstractions/Skins/ISkinService.cs @@ -0,0 +1,122 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information + +namespace DotNetNuke.Abstractions.Skins; + +using System.Collections.Generic; + +using DotNetNuke.Abstractions.Portals; + +/// Handles the Business Control Layer for Skins. +public interface ISkinService +{ + /// Gets the folder name for the specified . + /// The type of the skin package. + /// The folder name. + string GetFolderName(SkinPackageType packageType); + + /// Gets the global default skin src. + /// The type of the skin package. + /// The type of the skin. + /// The global default edit skin. + string GetDefaultSkinSrc(SkinPackageType packageType, SkinType skinType); + + /// Gets a skin package by its id. + /// The skin package id. + /// The skin package. + ISkinPackageInfo GetSkinPackageById(int packageId); + + /// Gets a skin package by its id. + /// The portal id. + /// The name of the skin. + /// The type of the skin package. + /// The skin package. + ISkinPackageInfo GetSkinPackage(int portalId, string skinName, SkinPackageType packageType); + + /// Creates a new instance of . + /// The skin. + ISkinInfo CreateSkin(); + + /// Creates a new instance of . + /// The skin package. + ISkinPackageInfo CreateSkinPackage(); + + /// Adds a new skin. + /// The skin to add. + /// The skin id. + int AddSkin(ISkinInfo skin); + + /// Adds a skin package. + /// The skin package to add. + /// The skin package id. + int AddSkinPackage(ISkinPackageInfo skinPackage); + + /// Checks if a skin can be deleted. + /// Path to the skin folder. + /// Path to the portal home directory (). + /// True if the skin can be deleted. + bool CanDeleteSkinFolder(string folderPath, string portalHomeDirMapPath); + + /// Deletes a skin. + /// The skin to delete. + void DeleteSkin(ISkinInfo skin); + + /// Deletes a skin package. + /// The skin package to delete. + void DeleteSkinPackage(ISkinPackageInfo skinPackage); + + /// Gets the skin source path. + /// + /// [G]Skins/Xcillion/Inner.ascx becomes [G]Skins/Xcillion. + /// + /// The input skin source path. + /// The skin source path. + string FormatSkinPath(string skinSrc); + + /// Formats the skin source path. + /// + /// By default the following tokens are replaced:
+ /// [G] - Host path (default: '/Portals/_default/').
+ /// [S] - Home system directory (default: '/Portals/[PortalID]-System/').
+ /// [L] - Home directory (default: '/Portals/[PortalID]/'). + ///
+ /// + /// [G]Skins/Xcillion/Inner.ascx becomes /Portals/_default/Skins/Xcillion/Inner.ascx. + /// + /// The input skin source path. + /// The portal settings containing configuration data. + /// The formatted skin source path. + string FormatSkinSrc(string skinSrc, IPortalSettings portalSettings); + + /// Determines if a given skin is defined as a global skin. + /// This is the app relative path and filename of the skin to be checked. + /// True if the skin is located in the HostPath child directories. + /// This function performs a quick check to detect the type of skin that is + /// passed as a parameter. Using this method abstracts knowledge of the actual location + /// of skins in the file system. + /// + bool IsGlobalSkin(string skinSrc); + + /// Sets the skin for the specified and . + /// The type of the skin package. + /// The portal to set the skin for or -1 for the global skin. + /// The type of the skin. + /// The skin source path. + void SetSkin(SkinPackageType packageType, int portalId, SkinType skinType, string skinSrc); + + /// Updates a existing skin. + /// The skin to update. + void UpdateSkin(ISkinInfo skin); + + /// Updates a existing skin package. + /// The skin package to update. + void UpdateSkinPackage(ISkinPackageInfo skinPackage); + + /// Get all skins for the specified within the specified . + /// The portal to get the skins for. + /// The skin type to search for skins. Default: . + /// The scope to search for skins. Default: . + /// A list of skins. + IEnumerable> GetSkinsInFolder(IPortalInfo portalInfo, SkinType skinRoot = SkinType.Site, SkinFolder folder = SkinFolder.All); +} diff --git a/DNN Platform/DotNetNuke.Abstractions/Skins/SkinFolder.cs b/DNN Platform/DotNetNuke.Abstractions/Skins/SkinFolder.cs new file mode 100644 index 00000000000..bbc09f41be2 --- /dev/null +++ b/DNN Platform/DotNetNuke.Abstractions/Skins/SkinFolder.cs @@ -0,0 +1,23 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information + +namespace DotNetNuke.Abstractions.Skins; + +using System; + +/// The scope of a skin. +/// This enum is used for . +public enum SkinFolder +{ + /// All scopes are specified. + All = 0, + + /// The skin can be used for all portals. + /// These skins are by default in the folder 'Portals\_default\'. + Host = 1, + + /// The skin can only be used for the given portal. + /// These skins are by default in the folder 'Portals\[PortalId]\' and 'Portals\[PortalId]-System\'. + Portal = 2, +} diff --git a/DNN Platform/DotNetNuke.Abstractions/Skins/SkinPackageType.cs b/DNN Platform/DotNetNuke.Abstractions/Skins/SkinPackageType.cs new file mode 100644 index 00000000000..922b9d1738e --- /dev/null +++ b/DNN Platform/DotNetNuke.Abstractions/Skins/SkinPackageType.cs @@ -0,0 +1,15 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information + +namespace DotNetNuke.Abstractions.Skins; + +/// The type of a skin package. +public enum SkinPackageType +{ + /// The skin package is a skin. + Skin = 0, + + /// The skin package is a container. + Container = 1, +} diff --git a/DNN Platform/DotNetNuke.Abstractions/Skins/SkinType.cs b/DNN Platform/DotNetNuke.Abstractions/Skins/SkinType.cs new file mode 100644 index 00000000000..d976a20d69a --- /dev/null +++ b/DNN Platform/DotNetNuke.Abstractions/Skins/SkinType.cs @@ -0,0 +1,15 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information + +namespace DotNetNuke.Abstractions.Skins; + +/// The type of a skin. +public enum SkinType +{ + /// The skin is a site skin. + Site = 0, + + /// The skin is an edit skin. + Edit = 1, +} diff --git a/DNN Platform/Library/Collections/AbstractionList.cs b/DNN Platform/Library/Collections/AbstractionList.cs new file mode 100644 index 00000000000..c92a8267dc3 --- /dev/null +++ b/DNN Platform/Library/Collections/AbstractionList.cs @@ -0,0 +1,128 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information + +namespace DotNetNuke.Collections; + +using System.Collections; +using System.Collections.Generic; +using System.Linq; + +using DotNetNuke.Abstractions.Collections; + +/// +/// +/// This class is used to abstract a list of objects of type to a list of objects of +/// type . +/// +public class AbstractionList : IObjectList + where TImplementation : TInterface, new() +{ + private readonly IList list; + + /// + /// Initializes a new instance of the class. + /// + /// The list. + public AbstractionList(IList list) + { + this.list = list; + } + + /// + public int Count => this.list.Count; + + /// + public bool IsReadOnly => this.list.IsReadOnly; + + /// + public TInterface this[int index] + { + get => (TInterface)this.list[index]; + set => this.list[index] = value; + } + + /// + public TInterface AddNew() + { + var item = new TImplementation(); + this.list.Add(item); + return item; + } + + /// + public void AddRange(IEnumerable items) + { + foreach (var item in items) + { + this.Add(item); + } + } + + /// + public IEnumerator GetEnumerator() + { + return this.list.Cast().GetEnumerator(); + } + + /// + IEnumerator IEnumerable.GetEnumerator() + { + return this.GetEnumerator(); + } + + /// + public void Add(TInterface item) + { + if (item is not TImplementation implementation) + { + throw new System.InvalidCastException(); + } + + this.list.Add(implementation); + } + + /// + public void Clear() + { + this.list.Clear(); + } + + /// + public bool Contains(TInterface item) + { + return this.list.Contains(item); + } + + /// + public void CopyTo(TInterface[] array, int arrayIndex) + { + this.list.CopyTo(array, arrayIndex); + } + + /// + public bool Remove(TInterface item) + { + var count = this.list.Count; + this.list.Remove(item); + return count != this.list.Count; + } + + /// + public int IndexOf(TInterface item) + { + return this.list.IndexOf(item); + } + + /// + public void Insert(int index, TInterface item) + { + this.list.Insert(index, item); + } + + /// + public void RemoveAt(int index) + { + this.list.RemoveAt(index); + } +} diff --git a/DNN Platform/Library/Common/Utilities/SkinUtils.cs b/DNN Platform/Library/Common/Utilities/SkinUtils.cs new file mode 100644 index 00000000000..92a8ddf09a0 --- /dev/null +++ b/DNN Platform/Library/Common/Utilities/SkinUtils.cs @@ -0,0 +1,53 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information + +namespace DotNetNuke.Common.Utilities; + +using System; + +using DotNetNuke.Abstractions.Skins; + +/// +/// Skin utilities. +/// +public class SkinUtils +{ + /// Gets the database name of a skin package type. + /// The type of the skin package. + /// The database name of the skin package type. + /// Thrown when is not a valid skin package type. + public static string ToDatabaseName(SkinPackageType type) + { + return type switch + { + SkinPackageType.Skin => "Skin", + SkinPackageType.Container => "Container", + _ => throw new ArgumentOutOfRangeException(nameof(type), type, "Invalid skin package type."), + }; + } + + /// Gets the skin package type from a database name. + /// The database name of the skin package type. + /// The skin package type. + /// Thrown when is not a valid skin package type database name. + public static SkinPackageType FromDatabaseName(string databaseName) + { + if (databaseName == null) + { + throw new ArgumentNullException(nameof(databaseName)); + } + + if (string.Equals(databaseName, "Skin", StringComparison.OrdinalIgnoreCase)) + { + return SkinPackageType.Skin; + } + + if (string.Equals(databaseName, "Container", StringComparison.OrdinalIgnoreCase)) + { + return SkinPackageType.Container; + } + + throw new ArgumentOutOfRangeException(nameof(databaseName), databaseName, "Invalid skin package type database name."); + } +} diff --git a/DNN Platform/Library/DotNetNuke.Library.csproj b/DNN Platform/Library/DotNetNuke.Library.csproj index 641837c2b71..5d1e3996c5a 100644 --- a/DNN Platform/Library/DotNetNuke.Library.csproj +++ b/DNN Platform/Library/DotNetNuke.Library.csproj @@ -188,6 +188,7 @@ + @@ -200,6 +201,7 @@ + diff --git a/DNN Platform/Library/Startup.cs b/DNN Platform/Library/Startup.cs index b94b0182800..dda765073e5 100644 --- a/DNN Platform/Library/Startup.cs +++ b/DNN Platform/Library/Startup.cs @@ -10,6 +10,7 @@ namespace DotNetNuke using DotNetNuke.Abstractions.Logging; using DotNetNuke.Abstractions.Portals; using DotNetNuke.Abstractions.Security.Permissions; + using DotNetNuke.Abstractions.Skins; using DotNetNuke.Application; using DotNetNuke.Common; using DotNetNuke.Common.Internal; @@ -22,6 +23,7 @@ namespace DotNetNuke using DotNetNuke.Services.Mail.OAuth; using DotNetNuke.UI.Modules; using DotNetNuke.UI.Modules.Html5; + using DotNetNuke.UI.Skins; using Microsoft.Extensions.DependencyInjection; @@ -42,6 +44,8 @@ public void ConfigureServices(IServiceCollection services) services.AddScoped(); services.AddScoped(); + services.AddScoped(); + services.AddTransient(x => PortalController.Instance); services.AddScoped(); services.AddScoped(); diff --git a/DNN Platform/Library/UI/Skins/SkinController.cs b/DNN Platform/Library/UI/Skins/SkinController.cs index f9c4d7b7344..ab9ff3d3d1b 100644 --- a/DNN Platform/Library/UI/Skins/SkinController.cs +++ b/DNN Platform/Library/UI/Skins/SkinController.cs @@ -10,6 +10,8 @@ namespace DotNetNuke.UI.Skins using System.IO.Compression; using System.Text.RegularExpressions; + using DotNetNuke.Abstractions.Portals; + using DotNetNuke.Abstractions.Skins; using DotNetNuke.Common; using DotNetNuke.Common.Utilities; using DotNetNuke.Data; @@ -18,6 +20,7 @@ namespace DotNetNuke.UI.Skins using DotNetNuke.Entities.Portals; using DotNetNuke.Entities.Users; using DotNetNuke.Instrumentation; + using DotNetNuke.Internal.SourceGenerators; using DotNetNuke.Services.Localization; using DotNetNuke.Services.Log.EventLog; @@ -25,7 +28,7 @@ namespace DotNetNuke.UI.Skins /// Class : SkinController /// /// Handles the Business Control Layer for Skins. - public class SkinController + public partial class SkinController : ISkinService { private const string GlobalSkinPrefix = "[G]"; private const string PortalSystemSkinPrefix = "[S]"; @@ -35,6 +38,8 @@ public class SkinController private static readonly Regex SdirRegex = new Regex("\\[s]", RegexOptions.IgnoreCase | RegexOptions.Compiled); private static readonly Regex LdirRegex = new Regex("\\[l]", RegexOptions.IgnoreCase | RegexOptions.Compiled); + /// + [Obsolete($"Deprecated in DotNetNuke 9.13.1. Use {nameof(SkinType)}.{nameof(ISkinService.GetFolderName)} instead. Scheduled removal in v12.0.0.")] public static string RootSkin { get @@ -43,6 +48,8 @@ public static string RootSkin } } + /// + [Obsolete($"Deprecated in DotNetNuke 9.13.1. Use {nameof(SkinType)}.{nameof(ISkinService.GetFolderName)} instead. Scheduled removal in v12.0.0.")] public static string RootContainer { get @@ -51,18 +58,23 @@ public static string RootContainer } } - public static int AddSkin(int skinPackageID, string skinSrc) + /// + [DnnDeprecated(9, 13, 1, $"Use {nameof(ISkinService)}.{nameof(ISkinService.AddSkin)} instead.")] + public static partial int AddSkin(int skinPackageID, string skinSrc) { return DataProvider.Instance().AddSkin(skinPackageID, skinSrc); } - public static int AddSkinPackage(SkinPackageInfo skinPackage) + /// + [DnnDeprecated(9, 13, 1, $"Use {nameof(ISkinService)}.{nameof(ISkinService.AddSkinPackage)} instead.")] + public static partial int AddSkinPackage(SkinPackageInfo skinPackage) { - EventLogController.Instance.AddLog(skinPackage, PortalController.Instance.GetCurrentPortalSettings(), UserController.Instance.GetCurrentUserInfo().UserID, string.Empty, EventLogController.EventLogType.SKINPACKAGE_CREATED); - return DataProvider.Instance().AddSkinPackage(skinPackage.PackageID, skinPackage.PortalID, skinPackage.SkinName, skinPackage.SkinType, UserController.Instance.GetCurrentUserInfo().UserID); + return AddSkinPackage((ISkinPackageInfo)skinPackage); } - public static bool CanDeleteSkin(string folderPath, string portalHomeDirMapPath) + /// + [DnnDeprecated(9, 13, 1, $"Use {nameof(ISkinService)}.{nameof(ISkinService.CanDeleteSkinFolder)} instead.")] + public static partial bool CanDeleteSkin(string folderPath, string portalHomeDirMapPath) { string skinType; string skinFolder; @@ -113,15 +125,18 @@ public static bool CanDeleteSkin(string folderPath, string portalHomeDirMapPath) return canDelete; } - public static void DeleteSkin(int skinID) + /// + [DnnDeprecated(9, 13, 1, $"Use {nameof(ISkinService)}.{nameof(ISkinService.DeleteSkin)} instead.")] + public static partial void DeleteSkin(int skinID) { DataProvider.Instance().DeleteSkin(skinID); } - public static void DeleteSkinPackage(SkinPackageInfo skinPackage) + /// + [DnnDeprecated(9, 13, 1, $"Use {nameof(ISkinService)}.{nameof(ISkinService.DeleteSkinPackage)} instead.")] + public static partial void DeleteSkinPackage(SkinPackageInfo skinPackage) { - DataProvider.Instance().DeleteSkinPackage(skinPackage.SkinPackageID); - EventLogController.Instance.AddLog(skinPackage, PortalController.Instance.GetCurrentPortalSettings(), UserController.Instance.GetCurrentUserInfo().UserID, string.Empty, EventLogController.EventLogType.SKINPACKAGE_DELETED); + DeleteSkinPackage((ISkinPackageInfo)skinPackage); } public static string FormatMessage(string title, string body, int level, bool isError) @@ -151,7 +166,9 @@ public static string FormatMessage(string title, string body, int level, bool is return message + ": " + body + Environment.NewLine; } - public static string FormatSkinPath(string skinSrc) + /// + [DnnDeprecated(9, 13, 1, $"Use {nameof(ISkinService)}.{nameof(ISkinService.FormatSkinPath)} instead.")] + public static partial string FormatSkinPath(string skinSrc) { string strSkinSrc = skinSrc; if (!string.IsNullOrEmpty(strSkinSrc)) @@ -162,63 +179,89 @@ public static string FormatSkinPath(string skinSrc) return strSkinSrc; } - public static string FormatSkinSrc(string skinSrc, PortalSettings portalSettings) + /// + [DnnDeprecated(9, 13, 1, $"Use {nameof(ISkinService)}.{nameof(ISkinService.FormatSkinSrc)} instead.")] + public static partial string FormatSkinSrc(string skinSrc, PortalSettings portalSettings) { - string strSkinSrc = skinSrc; - if (!string.IsNullOrEmpty(strSkinSrc)) - { - switch (strSkinSrc.Substring(0, 3).ToLowerInvariant()) - { - case "[g]": - strSkinSrc = GdirRegex.Replace(strSkinSrc, Globals.HostPath); - break; - case "[s]": - strSkinSrc = SdirRegex.Replace(strSkinSrc, portalSettings.HomeSystemDirectory); - break; - case "[l]": // to be compliant with all versions - strSkinSrc = LdirRegex.Replace(strSkinSrc, portalSettings.HomeDirectory); - break; - } - } - - return strSkinSrc; + return FormatSkinSrc(skinSrc, (IPortalSettings)portalSettings); } - public static string GetDefaultAdminContainer() + /// Gets the global default admin container. + /// + /// This is not the default admin container for the portal. + /// To get the default admin container for the portal use instead. + /// + /// The global default admin container. + [DnnDeprecated(9, 13, 1, $"Use {nameof(ISkinService)}.{nameof(ISkinService.GetDefaultSkinSrc)} instead.")] + public static partial string GetDefaultAdminContainer() { SkinDefaults defaultContainer = SkinDefaults.GetSkinDefaults(SkinDefaultType.ContainerInfo); return "[G]" + RootContainer + defaultContainer.Folder + defaultContainer.AdminDefaultName; } - public static string GetDefaultAdminSkin() + /// Gets the global default admin skin. + /// + /// This is not the default admin skin for the portal. + /// To get the default admin skin for the portal use instead. + /// + /// The global default admin skin. + [DnnDeprecated(9, 13, 1, $"Use {nameof(ISkinService)}.{nameof(ISkinService.GetDefaultSkinSrc)} instead.")] + public static partial string GetDefaultAdminSkin() { SkinDefaults defaultSkin = SkinDefaults.GetSkinDefaults(SkinDefaultType.SkinInfo); return "[G]" + RootSkin + defaultSkin.Folder + defaultSkin.AdminDefaultName; } - public static string GetDefaultPortalContainer() + /// Gets the global default skin. + /// + /// This is not the default skin for the portal. + /// To get the default skin for the portal use instead. + /// + /// The global default skin. + [DnnDeprecated(9, 13, 1, $"Use {nameof(ISkinService)}.{nameof(ISkinService.GetDefaultSkinSrc)} instead.")] + public static partial string GetDefaultPortalContainer() { SkinDefaults defaultContainer = SkinDefaults.GetSkinDefaults(SkinDefaultType.ContainerInfo); return "[G]" + RootContainer + defaultContainer.Folder + defaultContainer.DefaultName; } - public static string GetDefaultPortalSkin() + /// Gets the global default skin. + /// + /// This is not the default skin for the portal. + /// To get the default skin for the portal use instead. + /// + /// The global default skin. + [DnnDeprecated(9, 13, 1, $"Use {nameof(ISkinService)}.{nameof(ISkinService.GetDefaultSkinSrc)} instead.")] + public static partial string GetDefaultPortalSkin() { SkinDefaults defaultSkin = SkinDefaults.GetSkinDefaults(SkinDefaultType.SkinInfo); return "[G]" + RootSkin + defaultSkin.Folder + defaultSkin.DefaultName; } - public static SkinPackageInfo GetSkinByPackageID(int packageID) + /// + [DnnDeprecated(9, 13, 1, $"Use {nameof(ISkinService)}.{nameof(ISkinService.GetSkinPackageById)} instead.")] + public static partial SkinPackageInfo GetSkinByPackageID(int packageID) { return CBO.FillObject(DataProvider.Instance().GetSkinByPackageID(packageID)); } - public static SkinPackageInfo GetSkinPackage(int portalId, string skinName, string skinType) + /// ] + [DnnDeprecated(9, 13, 1, $"Use {nameof(ISkinService)}.{nameof(ISkinService.GetSkinPackage)} instead.")] + public static partial SkinPackageInfo GetSkinPackage(int portalId, string skinName, string skinType) { return CBO.FillObject(DataProvider.Instance().GetSkinPackage(portalId, skinName, skinType)); } - public static List> GetSkins(PortalInfo portalInfo, string skinRoot, SkinScope scope) + /// + [DnnDeprecated(9, 13, 1, $"Use {nameof(ISkinService)}.{nameof(ISkinService.GetSkinsInFolder)} instead.")] + public static partial List> GetSkins(PortalInfo portalInfo, string skinRoot, SkinScope scope) + { + return GetSkins((IPortalInfo)portalInfo, skinRoot, scope); + } + + /// + [DnnDeprecated(9, 13, 1, $"Use {nameof(ISkinService)}.{nameof(ISkinService.GetSkinsInFolder)} instead.")] + public static partial List> GetSkins(IPortalInfo portalInfo, string skinRoot, SkinScope scope) { var skins = new List>(); switch (scope) @@ -238,19 +281,16 @@ public static List> GetSkins(PortalInfo portalInfo, return skins; } - /// Determines if a given skin is defined as a global skin. - /// This is the app relative path and filename of the skin to be checked. - /// True if the skin is located in the HostPath child directories. - /// This function performs a quick check to detect the type of skin that is - /// passed as a parameter. Using this method abstracts knowledge of the actual location - /// of skins in the file system. - /// - public static bool IsGlobalSkin(string skinSrc) + /// + [DnnDeprecated(9, 13, 1, $"Use {nameof(ISkinService)}.{nameof(ISkinService.IsGlobalSkin)} instead.")] + public static partial bool IsGlobalSkin(string skinSrc) { return skinSrc.Contains(Globals.HostPath); } - public static void SetSkin(string skinRoot, int portalId, SkinType skinType, string skinSrc) + /// + [DnnDeprecated(9, 13, 1, $"Use {nameof(ISkinService)}.{nameof(ISkinService.SetSkin)} instead.")] + public static partial void SetSkin(string skinRoot, int portalId, SkinType skinType, string skinSrc) { var selectedCultureCode = LocaleController.Instance.GetCurrentLocale(portalId).Code; switch (skinRoot) @@ -305,31 +345,27 @@ public static void SetSkin(string skinRoot, int portalId, SkinType skinType, str } break; + default: + throw new ArgumentOutOfRangeException(nameof(skinRoot), skinRoot, "Expected either 'Skins' or 'Containers'"); } } - public static void UpdateSkin(int skinID, string skinSrc) + /// + [DnnDeprecated(9, 13, 1, $"Use {nameof(ISkinService)}.{nameof(ISkinService.UpdateSkin)} instead.")] + public static partial void UpdateSkin(int skinID, string skinSrc) { DataProvider.Instance().UpdateSkin(skinID, skinSrc); } - public static void UpdateSkinPackage(SkinPackageInfo skinPackage) + /// + [DnnDeprecated(9, 13, 1, $"Use {nameof(ISkinService)}.{nameof(ISkinService.UpdateSkin)} instead.")] + public static partial void UpdateSkinPackage(SkinPackageInfo skinPackage) { - DataProvider.Instance().UpdateSkinPackage( - skinPackage.SkinPackageID, - skinPackage.PackageID, - skinPackage.PortalID, - skinPackage.SkinName, - skinPackage.SkinType, - UserController.Instance.GetCurrentUserInfo().UserID); - EventLogController.Instance.AddLog(skinPackage, PortalController.Instance.GetCurrentPortalSettings(), UserController.Instance.GetCurrentUserInfo().UserID, string.Empty, EventLogController.EventLogType.SKINPACKAGE_UPDATED); - foreach (KeyValuePair kvp in skinPackage.Skins) - { - UpdateSkin(kvp.Key, kvp.Value); - } + UpdateSkinPackage((ISkinPackageInfo)skinPackage); } - public static string UploadLegacySkin(string rootPath, string skinRoot, string skinName, Stream inputStream) + [DnnDeprecated(10, 0, 0, "No replacement")] + public static partial string UploadLegacySkin(string rootPath, string skinRoot, string skinName, Stream inputStream) { var objZipInputStream = new ZipArchive(inputStream, ZipArchiveMode.Read); @@ -455,6 +491,170 @@ public static string UploadLegacySkin(string rootPath, string skinRoot, string s return strMessage; } + /// + ISkinPackageInfo ISkinService.GetSkinPackageById(int packageId) => GetSkinByPackageID(packageId); + + /// + ISkinPackageInfo ISkinService.GetSkinPackage(int portalId, string skinName, SkinPackageType packageType) + => GetSkinPackage(portalId, skinName, SkinUtils.ToDatabaseName(packageType)); + + /// + ISkinInfo ISkinService.CreateSkin() => new SkinInfo(); + + /// + ISkinPackageInfo ISkinService.CreateSkinPackage() => new SkinPackageInfo(); + + /// + int ISkinService.AddSkin(ISkinInfo skin) => AddSkin(skin.SkinPackageId, skin.SkinSrc); + + /// + int ISkinService.AddSkinPackage(ISkinPackageInfo skinPackage) => AddSkinPackage(skinPackage); + + /// + bool ISkinService.CanDeleteSkinFolder(string folderPath, string portalHomeDirMapPath) + => CanDeleteSkin(folderPath, portalHomeDirMapPath); + + /// + void ISkinService.DeleteSkin(ISkinInfo skin) => DeleteSkin(skin.SkinId); + + /// + void ISkinService.DeleteSkinPackage(ISkinPackageInfo skinPackage) => DeleteSkinPackage(skinPackage); + + /// + string ISkinService.GetFolderName(SkinPackageType packageType) + { + return packageType switch + { + SkinPackageType.Skin => RootSkin, + SkinPackageType.Container => RootContainer, + _ => throw new ArgumentOutOfRangeException(nameof(packageType), packageType, "The skin package type is not supported.") + }; + } + + /// + string ISkinService.GetDefaultSkinSrc(SkinPackageType packageType, DotNetNuke.Abstractions.Skins.SkinType skinType) + { + return (packageType, skinType) switch + { + (SkinPackageType.Skin, DotNetNuke.Abstractions.Skins.SkinType.Site) => GetDefaultPortalSkin(), + (SkinPackageType.Skin, DotNetNuke.Abstractions.Skins.SkinType.Edit) => GetDefaultAdminSkin(), + (SkinPackageType.Container, DotNetNuke.Abstractions.Skins.SkinType.Site) => GetDefaultPortalContainer(), + (SkinPackageType.Container, DotNetNuke.Abstractions.Skins.SkinType.Edit) => GetDefaultAdminContainer(), + _ => throw new ArgumentOutOfRangeException(nameof(packageType), packageType, "The skin package type is not supported.") + }; + } + + /// + string ISkinService.FormatSkinPath(string skinSrc) => FormatSkinPath(skinSrc); + + /// + string ISkinService.FormatSkinSrc(string skinSrc, IPortalSettings portalSettings) + => FormatSkinSrc(skinSrc, portalSettings); + + /// + bool ISkinService.IsGlobalSkin(string skinSrc) => IsGlobalSkin(skinSrc); + + /// + void ISkinService.SetSkin(SkinPackageType packageType, int portalId, DotNetNuke.Abstractions.Skins.SkinType skinType, string skinSrc) + { + var librarySkinType = skinType switch + { + Abstractions.Skins.SkinType.Site => SkinType.Portal, + Abstractions.Skins.SkinType.Edit => SkinType.Admin, + _ => throw new ArgumentOutOfRangeException(nameof(skinType), skinType, "The skin type is not supported."), + }; + + var skinRoot = packageType switch + { + SkinPackageType.Skin => RootSkin, + SkinPackageType.Container => RootContainer, + _ => throw new ArgumentOutOfRangeException(nameof(packageType), packageType, "The skin package type is not supported."), + }; + + SetSkin(skinRoot, portalId, librarySkinType, skinSrc); + } + + /// + void ISkinService.UpdateSkin(ISkinInfo skin) => UpdateSkin(skin.SkinId, skin.SkinSrc); + + /// + void ISkinService.UpdateSkinPackage(ISkinPackageInfo skinPackage) => UpdateSkinPackage(skinPackage); + + /// + IEnumerable> ISkinService.GetSkinsInFolder(IPortalInfo portalInfo, DotNetNuke.Abstractions.Skins.SkinType skinType, SkinFolder folder) + { + var libraryScope = folder switch + { + SkinFolder.All => SkinScope.All, + SkinFolder.Host => SkinScope.Host, + SkinFolder.Portal => SkinScope.Site, + _ => throw new ArgumentOutOfRangeException(nameof(folder), folder, "The skin scope is not supported."), + }; + + var skinRoot = skinType switch + { + Abstractions.Skins.SkinType.Site => RootSkin, + Abstractions.Skins.SkinType.Edit => RootContainer, + _ => throw new ArgumentOutOfRangeException(nameof(skinType), skinType, "The skin type is not supported."), + }; + + return GetSkins(portalInfo, skinRoot, libraryScope); + } + + /// + private static string FormatSkinSrc(string skinSrc, IPortalSettings portalSettings) + { + string strSkinSrc = skinSrc; + if (!string.IsNullOrEmpty(strSkinSrc)) + { + switch (strSkinSrc.Substring(0, 3).ToLowerInvariant()) + { + case "[g]": + strSkinSrc = GdirRegex.Replace(strSkinSrc, Globals.HostPath); + break; + case "[s]": + strSkinSrc = SdirRegex.Replace(strSkinSrc, portalSettings.HomeSystemDirectory); + break; + case "[l]": // to be compliant with all versions + strSkinSrc = LdirRegex.Replace(strSkinSrc, portalSettings.HomeDirectory); + break; + } + } + + return strSkinSrc; + } + + /// + private static void DeleteSkinPackage(ISkinPackageInfo skinPackage) + { + DataProvider.Instance().DeleteSkinPackage(skinPackage.SkinPackageId); + EventLogController.Instance.AddLog(skinPackage, PortalController.Instance.GetCurrentPortalSettings(), UserController.Instance.GetCurrentUserInfo().UserID, string.Empty, EventLogController.EventLogType.SKINPACKAGE_DELETED); + } + + /// + private static int AddSkinPackage(ISkinPackageInfo skinPackage) + { + EventLogController.Instance.AddLog(skinPackage, PortalController.Instance.GetCurrentPortalSettings(), UserController.Instance.GetCurrentUserInfo().UserID, string.Empty, EventLogController.EventLogType.SKINPACKAGE_CREATED); + return DataProvider.Instance().AddSkinPackage(skinPackage.PackageId, skinPackage.PortalId, skinPackage.SkinName, SkinUtils.ToDatabaseName(skinPackage.SkinType), UserController.Instance.GetCurrentUserInfo().UserID); + } + + /// + private static void UpdateSkinPackage(ISkinPackageInfo skinPackage) + { + DataProvider.Instance().UpdateSkinPackage( + skinPackage.SkinPackageId, + skinPackage.PackageId, + skinPackage.PortalId, + skinPackage.SkinName, + SkinUtils.ToDatabaseName(skinPackage.SkinType), + UserController.Instance.GetCurrentUserInfo().UserID); + EventLogController.Instance.AddLog(skinPackage, PortalController.Instance.GetCurrentPortalSettings(), UserController.Instance.GetCurrentUserInfo().UserID, string.Empty, EventLogController.EventLogType.SKINPACKAGE_UPDATED); + foreach (var skin in skinPackage.Skins) + { + UpdateSkin(skin.SkinId, skin.SkinSrc); + } + } + private static void AddSkinFiles(List> skins, string skinRoot, string skinFolder, string skinPrefix) { foreach (string skinFile in Directory.GetFiles(skinFolder, "*.ascx")) @@ -487,7 +687,7 @@ private static List> GetHostSkins(string skinRoot) return skins; } - private static List> GetPortalSkins(PortalInfo portalInfo, string skinRoot) + private static List> GetPortalSkins(IPortalInfo portalInfo, string skinRoot) { var skins = new List>(); diff --git a/DNN Platform/Library/UI/Skins/SkinInfo.cs b/DNN Platform/Library/UI/Skins/SkinInfo.cs index dc5a231191b..7095e509bb3 100644 --- a/DNN Platform/Library/UI/Skins/SkinInfo.cs +++ b/DNN Platform/Library/UI/Skins/SkinInfo.cs @@ -1,19 +1,22 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information namespace DotNetNuke.UI.Skins { - using System; - + using System; + + using DotNetNuke.Abstractions.Skins; + /// Project : DotNetNuke /// Class : SkinInfo /// /// Handles the Business Object for Skins. [Serializable] - public class SkinInfo + public class SkinInfo : ISkinInfo { private int portalId; private int skinId; + private int skinPackageId; private string skinRoot; private string skinSrc; private SkinType skinType; @@ -31,6 +34,19 @@ public int SkinId } } + public int SkinPackageId + { + get + { + return this.skinPackageId; + } + + set + { + this.skinPackageId = value; + } + } + public int PortalId { get @@ -57,6 +73,7 @@ public string SkinRoot } } + [Obsolete("Deprecated in DotNetNuke 10.0.0. No replacement. Scheduled removal in v12.0.0.")] public SkinType SkinType { get diff --git a/DNN Platform/Library/UI/Skins/SkinPackageInfo.cs b/DNN Platform/Library/UI/Skins/SkinPackageInfo.cs index 46e35aaea22..a9b54b0cf7d 100644 --- a/DNN Platform/Library/UI/Skins/SkinPackageInfo.cs +++ b/DNN Platform/Library/UI/Skins/SkinPackageInfo.cs @@ -1,71 +1,84 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information namespace DotNetNuke.UI.Skins { using System; using System.Collections.Generic; using System.Data; + using System.Linq; using System.Xml.Serialization; - + + using DotNetNuke.Abstractions.Collections; + using DotNetNuke.Abstractions.Skins; + using DotNetNuke.Collections; using DotNetNuke.Common.Utilities; using DotNetNuke.Entities; - using DotNetNuke.Entities.Modules; - using Newtonsoft.Json; - + using DotNetNuke.Entities.Modules; + using Newtonsoft.Json; + /// Project : DotNetNuke /// Class : SkinPackageInfo /// /// Handles the Business Object for Skins. [Serializable] - public class SkinPackageInfo : BaseEntityInfo, IHydratable + public class SkinPackageInfo : BaseEntityInfo, IHydratable, ISkinPackageInfo { - private int packageID = Null.NullInteger; - private int portalID = Null.NullInteger; + private int packageId = Null.NullInteger; + private int portalId = Null.NullInteger; private string skinName; - private int skinPackageID = Null.NullInteger; + private int skinPackageId = Null.NullInteger; private string skinType; private Dictionary skins = new Dictionary(); + private List skinsList = new List(); + private AbstractionList abstractSkins; + /// + [Obsolete($"Deprecated in DotNetNuke 9.13.1. Use {nameof(ISkinPackageInfo)}.{nameof(ISkinPackageInfo.PackageId)} instead. Scheduled for removal in v11.0.0.")] public int PackageID { get { - return this.packageID; + return ((ISkinPackageInfo)this).PackageId; } set { - this.packageID = value; + ((ISkinPackageInfo)this).PackageId = value; } } + /// + [Obsolete($"Deprecated in DotNetNuke 9.13.1. Use {nameof(ISkinPackageInfo)}.{nameof(ISkinPackageInfo.SkinPackageId)} instead. Scheduled for removal in v11.0.0.")] public int SkinPackageID { get { - return this.skinPackageID; + return ((ISkinPackageInfo)this).SkinPackageId; } set { - this.skinPackageID = value; + ((ISkinPackageInfo)this).SkinPackageId = value; } } + /// + [Obsolete($"Deprecated in DotNetNuke 9.13.1. Use {nameof(ISkinPackageInfo)}.{nameof(ISkinPackageInfo.PortalId)} instead. Scheduled for removal in v11.0.0.")] public int PortalID { get { - return this.portalID; + return ((ISkinPackageInfo)this).PortalId; } set { - this.portalID = value; + ((ISkinPackageInfo)this).PortalId = value; } } + /// public string SkinName { get @@ -79,8 +92,10 @@ public string SkinName } } - [XmlIgnore] + /// Gets or sets a dictionary mapping from to . + [XmlIgnore] [JsonIgnore] + [Obsolete($"Deprecated in DotNetNuke 9.13.1. Use {nameof(ISkinPackageInfo)}.{nameof(ISkinPackageInfo.Skins)} instead. Scheduled for removal in v11.0.0.")] public Dictionary Skins { get @@ -94,6 +109,23 @@ public Dictionary Skins } } + /// + [XmlIgnore] + [JsonIgnore] + public List SkinsList + { + get + { + return this.skinsList; + } + + set + { + this.skinsList = value; + } + } + + /// public string SkinType { get @@ -105,41 +137,103 @@ public string SkinType { this.skinType = value; } - } - - /// + } + + /// public int KeyID { get { - return this.SkinPackageID; + return ((ISkinPackageInfo)this).SkinPackageId; } set { - this.SkinPackageID = value; + ((ISkinPackageInfo)this).SkinPackageId = value; + } + } + + /// + [XmlIgnore] + [JsonIgnore] + int ISkinPackageInfo.PackageId + { + get => this.packageId; + set => this.packageId = value; + } + + /// + [XmlIgnore] + [JsonIgnore] + int ISkinPackageInfo.SkinPackageId + { + get => this.skinPackageId; + set => this.skinPackageId = value; + } + + /// + [XmlIgnore] + [JsonIgnore] + IObjectList ISkinPackageInfo.Skins + { + get + { + return this.abstractSkins ??= new AbstractionList(this.SkinsList); } - } - - /// + } + + /// + [XmlIgnore] + [JsonIgnore] + SkinPackageType ISkinPackageInfo.SkinType + { + get => SkinUtils.FromDatabaseName(this.SkinType); + set => this.SkinType = SkinUtils.ToDatabaseName(value); + } + + /// + [XmlIgnore] + [JsonIgnore] + int ISkinPackageInfo.PortalId + { + get => this.portalId; + set => this.portalId = value; + } + + /// public void Fill(IDataReader dr) { - this.SkinPackageID = Null.SetNullInteger(dr["SkinPackageID"]); - this.PackageID = Null.SetNullInteger(dr["PackageID"]); - this.SkinName = Null.SetNullString(dr["SkinName"]); + var @this = (ISkinPackageInfo)this; + @this.SkinPackageId = Null.SetNullInteger(dr["SkinPackageID"]); + @this.PackageId = Null.SetNullInteger(dr["PackageID"]); + @this.SkinName = Null.SetNullString(dr["SkinName"]); this.SkinType = Null.SetNullString(dr["SkinType"]); - // Call the base classes fill method to populate base class proeprties + // Call the base classes fill method to populate base class properties this.FillInternal(dr); if (dr.NextResult()) { while (dr.Read()) { - int skinID = Null.SetNullInteger(dr["SkinID"]); - if (skinID > Null.NullInteger) + int skinId = Null.SetNullInteger(dr["SkinID"]); + if (skinId > Null.NullInteger) { - this.skins[skinID] = Null.SetNullString(dr["SkinSrc"]); + var skinSrc = Null.SetNullString(dr["SkinSrc"]); + this.skins[skinId] = skinSrc; + this.skinsList.Add(new SkinInfo + { + SkinId = skinId, + SkinSrc = skinSrc, + SkinPackageId = @this.SkinPackageId, + PortalId = @this.PortalId, + SkinRoot = SkinUtils.FromDatabaseName(this.SkinType) switch + { + SkinPackageType.Container => SkinController.RootContainer, + SkinPackageType.Skin => SkinController.RootSkin, + _ => throw new ArgumentOutOfRangeException(nameof(this.SkinType), this.SkinType, "Invalid skin type."), + }, + }); } } } diff --git a/DNN Platform/Library/UI/Skins/SkinScope.cs b/DNN Platform/Library/UI/Skins/SkinScope.cs index 745128b1116..6c9acafb893 100644 --- a/DNN Platform/Library/UI/Skins/SkinScope.cs +++ b/DNN Platform/Library/UI/Skins/SkinScope.cs @@ -1,7 +1,7 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information - +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information + namespace DotNetNuke.UI.Skins { public enum SkinScope diff --git a/DNN Platform/Library/UI/Skins/SkinType.cs b/DNN Platform/Library/UI/Skins/SkinType.cs index 4e0b4b6a524..746879ddf56 100644 --- a/DNN Platform/Library/UI/Skins/SkinType.cs +++ b/DNN Platform/Library/UI/Skins/SkinType.cs @@ -1,7 +1,7 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information - +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information + namespace DotNetNuke.UI.Skins { public enum SkinType