diff --git a/WebsitePanel/Sources/WebsitePanel.EnterpriseServer.Client/EnterpriseStorageProxy.cs b/WebsitePanel/Sources/WebsitePanel.EnterpriseServer.Client/EnterpriseStorageProxy.cs index a64f9834..b08a2233 100644 --- a/WebsitePanel/Sources/WebsitePanel.EnterpriseServer.Client/EnterpriseStorageProxy.cs +++ b/WebsitePanel/Sources/WebsitePanel.EnterpriseServer.Client/EnterpriseStorageProxy.cs @@ -304,20 +304,26 @@ namespace WebsitePanel.EnterpriseServer /// [System.Web.Services.Protocols.SoapDocumentMethodAttribute("http://smbsaas/websitepanel/enterpriseserver/CreateEnterpriseFolder", RequestNamespace = "http://smbsaas/websitepanel/enterpriseserver", ResponseNamespace = "http://smbsaas/websitepanel/enterpriseserver", Use = System.Web.Services.Description.SoapBindingUse.Literal, ParameterStyle = System.Web.Services.Protocols.SoapParameterStyle.Wrapped)] - public ResultObject CreateEnterpriseFolder(int itemId, string folderName) + public ResultObject CreateEnterpriseFolder(int itemId, string folderName, int quota, QuotaType quotaType, bool addDefaultGroup) { object[] results = this.Invoke("CreateEnterpriseFolder", new object[] { itemId, - folderName}); + folderName, + quota, + quotaType, + addDefaultGroup}); return ((ResultObject)(results[0])); } /// - public System.IAsyncResult BeginCreateEnterpriseFolder(int itemId, string folderName, System.AsyncCallback callback, object asyncState) + public System.IAsyncResult BeginCreateEnterpriseFolder(int itemId, string folderName, int quota, QuotaType quotaType, bool addDefaultGroup, System.AsyncCallback callback, object asyncState) { return this.BeginInvoke("CreateEnterpriseFolder", new object[] { itemId, - folderName}, callback, asyncState); + folderName, + quota, + quotaType, + addDefaultGroup}, callback, asyncState); } /// @@ -328,13 +334,13 @@ namespace WebsitePanel.EnterpriseServer } /// - public void CreateEnterpriseFolderAsync(int itemId, string folderName) + public void CreateEnterpriseFolderAsync(int itemId, string folderName, int quota, QuotaType quotaType, bool addDefaultGroup) { - this.CreateEnterpriseFolderAsync(itemId, folderName, null); + this.CreateEnterpriseFolderAsync(itemId, folderName, quota, quotaType, addDefaultGroup, null); } /// - public void CreateEnterpriseFolderAsync(int itemId, string folderName, object userState) + public void CreateEnterpriseFolderAsync(int itemId, string folderName, int quota, QuotaType quotaType, bool addDefaultGroup, object userState) { if ((this.CreateEnterpriseFolderOperationCompleted == null)) { @@ -342,7 +348,10 @@ namespace WebsitePanel.EnterpriseServer } this.InvokeAsync("CreateEnterpriseFolder", new object[] { itemId, - folderName}, this.CreateEnterpriseFolderOperationCompleted, userState); + folderName, + quota, + quotaType, + addDefaultGroup}, this.CreateEnterpriseFolderOperationCompleted, userState); } private void OnCreateEnterpriseFolderOperationCompleted(object arg) diff --git a/WebsitePanel/Sources/WebsitePanel.EnterpriseServer.Code/Data/DataProvider.cs b/WebsitePanel/Sources/WebsitePanel.EnterpriseServer.Code/Data/DataProvider.cs index 1022a16c..e28068b5 100644 --- a/WebsitePanel/Sources/WebsitePanel.EnterpriseServer.Code/Data/DataProvider.cs +++ b/WebsitePanel/Sources/WebsitePanel.EnterpriseServer.Code/Data/DataProvider.cs @@ -3098,6 +3098,17 @@ namespace WebsitePanel.EnterpriseServer ); } + public static IDataReader GetOrganizationGroupsByDisplayName(int itemId, string displayName) + { + return SqlHelper.ExecuteReader( + ConnectionString, + CommandType.StoredProcedure, + "GetOrganizationGroupsByDisplayName", + new SqlParameter("@ItemID", itemId), + new SqlParameter("@DisplayName", displayName) + ); + } + public static IDataReader SearchOrganizationAccounts(int actorId, int itemId, string filterColumn, string filterValue, string sortColumn, bool includeMailboxes) { @@ -4164,7 +4175,7 @@ namespace WebsitePanel.EnterpriseServer #region Enterprise Storage - public static int AddEntepriseFolder(int itemId, string folderName) + public static int AddEntepriseFolder(int itemId, string folderName, int folderQuota, string locationDrive, string homeFolder, string domain) { SqlParameter prmId = new SqlParameter("@FolderID", SqlDbType.Int); prmId.Direction = ParameterDirection.Output; @@ -4175,7 +4186,12 @@ namespace WebsitePanel.EnterpriseServer "AddEnterpriseFolder", prmId, new SqlParameter("@ItemID", itemId), - new SqlParameter("@FolderName", folderName)); + new SqlParameter("@FolderName", folderName), + new SqlParameter("@FolderQuota", folderQuota), + new SqlParameter("@LocationDrive", locationDrive), + new SqlParameter("@HomeFolder", homeFolder), + new SqlParameter("@Domain", domain) + ); // read identity return Convert.ToInt32(prmId.Value); @@ -4203,6 +4219,27 @@ namespace WebsitePanel.EnterpriseServer new SqlParameter("@FolderQuota", folderQuota)); } + public static IDataReader GetEnterpriseFolders(int itemId) + { + return SqlHelper.ExecuteReader( + ConnectionString, + CommandType.StoredProcedure, + "GetEnterpriseFolders", + new SqlParameter("@ItemID", itemId) + ); + } + + public static IDataReader GetEnterpriseFolder(int itemId, string folderName) + { + return SqlHelper.ExecuteReader( + ConnectionString, + CommandType.StoredProcedure, + "GetEnterpriseFolder", + new SqlParameter("@ItemID", itemId), + new SqlParameter("@FolderName", folderName) + ); + } + #endregion } } diff --git a/WebsitePanel/Sources/WebsitePanel.EnterpriseServer.Code/EnterpriseStorage/EnterpriseStorageController.cs b/WebsitePanel/Sources/WebsitePanel.EnterpriseServer.Code/EnterpriseStorage/EnterpriseStorageController.cs index bc333377..f3654fa5 100644 --- a/WebsitePanel/Sources/WebsitePanel.EnterpriseServer.Code/EnterpriseStorage/EnterpriseStorageController.cs +++ b/WebsitePanel/Sources/WebsitePanel.EnterpriseServer.Code/EnterpriseStorage/EnterpriseStorageController.cs @@ -87,12 +87,12 @@ namespace WebsitePanel.EnterpriseServer public static ResultObject CreateFolder(int itemId) { - return CreateFolder(itemId, string.Empty); + return CreateFolder(itemId, string.Empty, 0, QuotaType.Soft, false); } - public static ResultObject CreateFolder(int itemId, string folderName) + public static ResultObject CreateFolder(int itemId, string folderName, int quota, QuotaType quotaType, bool addDefaultGroup) { - return CreateFolderInternal(itemId, folderName); + return CreateFolderInternal(itemId, folderName, quota, quotaType, addDefaultGroup); } public static ResultObject DeleteFolder(int itemId) @@ -354,7 +354,10 @@ namespace WebsitePanel.EnterpriseServer EnterpriseStorage es = GetEnterpriseStorage(serviceId); - return es.GetFolders(org.OrganizationId); + var webDavSettings = ObjectUtils.CreateListFromDataReader( + DataProvider.GetEnterpriseFolders(itemId)).ToArray(); + + return es.GetFolders(org.OrganizationId, webDavSettings); } catch (Exception ex) { @@ -375,7 +378,10 @@ namespace WebsitePanel.EnterpriseServer EnterpriseStorage es = GetEnterpriseStorage(GetEnterpriseStorageServiceID(org.PackageId)); - return es.GetFolder(org.OrganizationId, folderName); + var webDavSetting = ObjectUtils.FillObjectFromDataReader( + DataProvider.GetEnterpriseFolder(itemId, folderName)); + + return es.GetFolder(org.OrganizationId, folderName, webDavSetting); } catch (Exception ex) { @@ -396,9 +402,12 @@ namespace WebsitePanel.EnterpriseServer EnterpriseStorage es = GetEnterpriseStorage(GetEnterpriseStorageServiceID(org.PackageId)); - if (es.GetFolder(org.OrganizationId, newFolder) == null) + var webDavSetting = ObjectUtils.FillObjectFromDataReader( + DataProvider.GetEnterpriseFolder(itemId, oldFolder)); + + if (webDavSetting == null) { - SystemFile folder = es.RenameFolder(org.OrganizationId, oldFolder, newFolder); + SystemFile folder = es.RenameFolder(org.OrganizationId, oldFolder, newFolder, webDavSetting); DataProvider.UpdateEnterpriseFolder(itemId, oldFolder, newFolder, folder.FRSMQuotaGB); @@ -413,7 +422,7 @@ namespace WebsitePanel.EnterpriseServer } } - protected static ResultObject CreateFolderInternal(int itemId, string folderName) + protected static ResultObject CreateFolderInternal(int itemId, string folderName, int quota, QuotaType quotaType, bool addDefaultGroup) { ResultObject result = TaskManager.StartResultTask("ENTERPRISE_STORAGE", "CREATE_FOLDER"); @@ -430,11 +439,56 @@ namespace WebsitePanel.EnterpriseServer EnterpriseStorage es = GetEnterpriseStorage(GetEnterpriseStorageServiceID(org.PackageId)); - if (es.GetFolder(org.OrganizationId, folderName) == null) - { - es.CreateFolder(org.OrganizationId, folderName); + var webDavSetting = ObjectUtils.FillObjectFromDataReader( + DataProvider.GetEnterpriseFolder(itemId, folderName)); - DataProvider.AddEntepriseFolder(itemId, folderName); + if (webDavSetting == null) + { + int esId = PackageController.GetPackageServiceId(org.PackageId, ResourceGroups.EnterpriseStorage); + + StringDictionary esSesstings = ServerController.GetServiceSettings(esId); + + var setting = ObjectUtils.CreateListFromDataReader( + DataProvider.GetEnterpriseFolders(itemId)).LastOrDefault(x => !x.IsEmpty()) + ?? new WebDavSetting(esSesstings["LocationDrive"], esSesstings["UsersHome"], esSesstings["UsersDomain"]); + + + es.CreateFolder(org.OrganizationId, folderName, setting); + + DataProvider.AddEntepriseFolder(itemId, folderName, quota, + setting.LocationDrive, setting.HomeFolder, setting.Domain); + + SetFolderQuota(org.PackageId, org.OrganizationId, folderName, quota, quotaType, setting); + + DataProvider.UpdateEnterpriseFolder(itemId, folderName, folderName, quota); + + if (addDefaultGroup) + { + var groupName = string.Format("{0} Folder Users", folderName); + + var account = ObjectUtils.CreateListFromDataReader( + DataProvider.GetOrganizationGroupsByDisplayName(itemId, groupName)).FirstOrDefault(); + + var accountId = account == null + ? OrganizationController.CreateSecurityGroup(itemId, groupName) + : account.AccountId; + + + var securityGroup = OrganizationController.GetSecurityGroupGeneralSettings(itemId, accountId); + + var rules = new List() { + new WebDavFolderRule + { + Roles = new List() { securityGroup.AccountName }, + Read = true, + Write = true, + Source = true, + Pathes = new List() { "*" } + } + }; + + es.SetFolderWebDavRules(org.OrganizationId, folderName, webDavSetting, rules.ToArray()); + } } else { @@ -475,14 +529,13 @@ namespace WebsitePanel.EnterpriseServer return; } - EnterpriseStorage es = GetEnterpriseStorage(GetEnterpriseStorageServiceID(org.PackageId)); - - es.CreateFolder(org.OrganizationId, folderName); - // check if it's not root folder if (!string.IsNullOrEmpty(folderName)) { - SetFolderQuota(org.PackageId, org.OrganizationId, folderName, quota, quotaType); + var webDavSetting = ObjectUtils.FillObjectFromDataReader( + DataProvider.GetEnterpriseFolder(itemId, folderName)); + + SetFolderQuota(org.PackageId, org.OrganizationId, folderName, quota, quotaType, webDavSetting); DataProvider.UpdateEnterpriseFolder(itemId, folderName, folderName, quota); } @@ -519,7 +572,10 @@ namespace WebsitePanel.EnterpriseServer EnterpriseStorage es = GetEnterpriseStorage(GetEnterpriseStorageServiceID(org.PackageId)); - es.DeleteFolder(org.OrganizationId, folderName); + var webDavSetting = ObjectUtils.FillObjectFromDataReader( + DataProvider.GetEnterpriseFolder(itemId, folderName)); + + es.DeleteFolder(org.OrganizationId, folderName, webDavSetting); DataProvider.DeleteEnterpriseFolder(itemId, folderName); } @@ -562,21 +618,23 @@ namespace WebsitePanel.EnterpriseServer DataProvider.SearchExchangeAccountsByTypes(SecurityContext.User.UserId, itemId, accountTypes, filterColumn, filterValue, sortColumn)); + return tmpAccounts; - List exAccounts = new List(); + // on large lists is very slow - foreach (ExchangeAccount tmpAccount in tmpAccounts.ToArray()) - { - if (tmpAccount.AccountType == ExchangeAccountType.SecurityGroup || tmpAccount.AccountType == ExchangeAccountType.DefaultSecurityGroup - ? OrganizationController.GetSecurityGroupGeneralSettings(itemId, tmpAccount.AccountId) == null - : OrganizationController.GetUserGeneralSettings(itemId, tmpAccount.AccountId) == null) - continue; + //List exAccounts = new List(); - exAccounts.Add(tmpAccount); - } + //foreach (ExchangeAccount tmpAccount in tmpAccounts.ToArray()) + //{ + // if (tmpAccount.AccountType == ExchangeAccountType.SecurityGroup || tmpAccount.AccountType == ExchangeAccountType.DefaultSecurityGroup + // ? OrganizationController.GetSecurityGroupGeneralSettings(itemId, tmpAccount.AccountId) == null + // : OrganizationController.GetUserGeneralSettings(itemId, tmpAccount.AccountId) == null) + // continue; - return exAccounts; + // exAccounts.Add(tmpAccount); + //} + //return exAccounts; } protected static SystemFilesPaged GetEnterpriseFoldersPagedInternal(int itemId, string filterValue, string sortColumn, int startRow, int maximumRows) @@ -595,7 +653,11 @@ namespace WebsitePanel.EnterpriseServer if (CheckUsersDomainExistsInternal(itemId, org.PackageId)) { EnterpriseStorage es = GetEnterpriseStorage(GetEnterpriseStorageServiceID(org.PackageId)); - List folders = es.GetFolders(org.OrganizationId).Where(x => x.Name.Contains(filterValue)).ToList(); + + var webDavSettings = ObjectUtils.CreateListFromDataReader( + DataProvider.GetEnterpriseFolders(itemId)).ToArray(); + + List folders = es.GetFolders(org.OrganizationId, webDavSettings).Where(x => x.Name.Contains(filterValue)).ToList(); switch (sortColumn) { @@ -720,7 +782,10 @@ namespace WebsitePanel.EnterpriseServer EnterpriseStorage es = GetEnterpriseStorage(GetEnterpriseStorageServiceID(org.PackageId)); - es.SetFolderWebDavRules(org.OrganizationId, folder, rules); + var webDavSetting = ObjectUtils.FillObjectFromDataReader( + DataProvider.GetEnterpriseFolder(itemId, folder)); + + es.SetFolderWebDavRules(org.OrganizationId, folder, webDavSetting, rules); } catch (Exception ex) { @@ -754,7 +819,10 @@ namespace WebsitePanel.EnterpriseServer EnterpriseStorage es = GetEnterpriseStorage(GetEnterpriseStorageServiceID(org.PackageId)); - return es.GetFolderWebDavRules(org.OrganizationId, folder); + var webDavSetting = ObjectUtils.FillObjectFromDataReader( + DataProvider.GetEnterpriseFolder(itemId, folder)); + + return es.GetFolderWebDavRules(org.OrganizationId, folder, webDavSetting); } catch (Exception ex) { @@ -831,15 +899,17 @@ namespace WebsitePanel.EnterpriseServer if (permission.Access.ToLower().Contains("read-only")) { rule.Read = true; - rule.Source = true; } if (permission.Access.ToLower().Contains("read-write")) { rule.Write = true; rule.Read = true; + rule.Source = true; } + rule.Source = true; + rule.Pathes.Add("*"); rules.Add(rule); @@ -901,8 +971,11 @@ namespace WebsitePanel.EnterpriseServer } - private static void SetFolderQuota(int packageId, string orgId, string folderName, int quotaSize, QuotaType quotaType) + private static void SetFolderQuota(int packageId, string orgId, string folderName, int quotaSize, QuotaType quotaType, WebDavSetting setting) { + if (quotaSize == 0) + return; + int accountCheck = SecurityContext.CheckAccount(DemandAccount.NotDemo | DemandAccount.IsActive); if (accountCheck < 0) return; @@ -915,13 +988,16 @@ namespace WebsitePanel.EnterpriseServer if (esServiceId != 0) { - StringDictionary esSesstings = ServerController.GetServiceSettings(esServiceId); + var curSetting = setting; - string usersHome = esSesstings["UsersHome"]; - string usersDomain = esSesstings["UsersDomain"]; - string locationDrive = esSesstings["LocationDrive"]; + if (curSetting == null || curSetting.IsEmpty()) + { + StringDictionary esSesstings = ServerController.GetServiceSettings(esServiceId); - var orgFolder = Path.Combine(usersHome, orgId, folderName); + curSetting = new WebDavSetting(esSesstings["LocationDrive"], esSesstings["UsersHome"], esSesstings["UsersDomain"]); + } + + var orgFolder = Path.Combine(curSetting.HomeFolder, orgId, folderName); var os = GetOS(packageId); @@ -946,7 +1022,7 @@ namespace WebsitePanel.EnterpriseServer #endregion - os.SetQuotaLimitOnFolder(orgFolder, locationDrive, quotaType, quotaSize.ToString() + unit, 0, String.Empty, String.Empty); + os.SetQuotaLimitOnFolder(orgFolder, curSetting.LocationDrive, quotaType, quotaSize.ToString() + unit, 0, String.Empty, String.Empty); } catch (Exception ex) { diff --git a/WebsitePanel/Sources/WebsitePanel.EnterpriseServer.Code/HostedSolution/OrganizationController.cs b/WebsitePanel/Sources/WebsitePanel.EnterpriseServer.Code/HostedSolution/OrganizationController.cs index fa03a722..fd00ef60 100644 --- a/WebsitePanel/Sources/WebsitePanel.EnterpriseServer.Code/HostedSolution/OrganizationController.cs +++ b/WebsitePanel/Sources/WebsitePanel.EnterpriseServer.Code/HostedSolution/OrganizationController.cs @@ -2867,33 +2867,36 @@ namespace WebsitePanel.EnterpriseServer DataProvider.SearchExchangeAccountsByTypes(SecurityContext.User.UserId, itemId, accountTypes, filterColumn, filterValue, sortColumn)); + return tmpAccounts; - List accounts = new List(); + // on large lists is very slow - foreach (ExchangeAccount tmpAccount in tmpAccounts.ToArray()) - { - bool bSuccess = false; + //List accounts = new List(); - switch (tmpAccount.AccountType) - { - case ExchangeAccountType.SecurityGroup: - bSuccess = GetSecurityGroupGeneralSettings(itemId, tmpAccount.AccountId) != null; - break; - case ExchangeAccountType.DistributionList: - bSuccess = ExchangeServerController.GetDistributionListGeneralSettings(itemId, tmpAccount.AccountId) != null; - break; - default: - bSuccess = GetUserGeneralSettings(itemId, tmpAccount.AccountId) != null; - break; - } + //foreach (ExchangeAccount tmpAccount in tmpAccounts.ToArray()) + //{ + // bool bSuccess = false; - if (bSuccess) - { - accounts.Add(tmpAccount); - } - } + // switch (tmpAccount.AccountType) + // { + // case ExchangeAccountType.SecurityGroup: + // bSuccess = GetSecurityGroupGeneralSettings(itemId, tmpAccount.AccountId) != null; + // break; + // case ExchangeAccountType.DistributionList: + // bSuccess = ExchangeServerController.GetDistributionListGeneralSettings(itemId, tmpAccount.AccountId) != null; + // break; + // default: + // bSuccess = GetUserGeneralSettings(itemId, tmpAccount.AccountId) != null; + // break; + // } - return accounts; + // if (bSuccess) + // { + // accounts.Add(tmpAccount); + // } + //} + + //return accounts; } } } diff --git a/WebsitePanel/Sources/WebsitePanel.EnterpriseServer/esEnterpriseStorage.asmx.cs b/WebsitePanel/Sources/WebsitePanel.EnterpriseServer/esEnterpriseStorage.asmx.cs index bfa15387..3af2cd32 100644 --- a/WebsitePanel/Sources/WebsitePanel.EnterpriseServer/esEnterpriseStorage.asmx.cs +++ b/WebsitePanel/Sources/WebsitePanel.EnterpriseServer/esEnterpriseStorage.asmx.cs @@ -76,9 +76,9 @@ namespace WebsitePanel.EnterpriseServer } [WebMethod] - public ResultObject CreateEnterpriseFolder(int itemId, string folderName) + public ResultObject CreateEnterpriseFolder(int itemId, string folderName, int quota, QuotaType quotaType, bool addDefaultGroup) { - return EnterpriseStorageController.CreateFolder(itemId, folderName); + return EnterpriseStorageController.CreateFolder(itemId, folderName, quota, quotaType, addDefaultGroup); } [WebMethod] diff --git a/WebsitePanel/Sources/WebsitePanel.Providers.Base/EnterpriseStorage/IEnterpriseStorage.cs b/WebsitePanel/Sources/WebsitePanel.Providers.Base/EnterpriseStorage/IEnterpriseStorage.cs index dbcc97cc..df3c489f 100644 --- a/WebsitePanel/Sources/WebsitePanel.Providers.Base/EnterpriseStorage/IEnterpriseStorage.cs +++ b/WebsitePanel/Sources/WebsitePanel.Providers.Base/EnterpriseStorage/IEnterpriseStorage.cs @@ -38,13 +38,13 @@ namespace WebsitePanel.Providers.EnterpriseStorage /// public interface IEnterpriseStorage { - SystemFile[] GetFolders(string organizationId); - SystemFile GetFolder(string organizationId, string folderName); - void CreateFolder(string organizationId, string folder); - SystemFile RenameFolder(string organizationId, string originalFolder, string newFolder); - void DeleteFolder(string organizationId, string folder); - bool SetFolderWebDavRules(string organizationId, string folder, WebDavFolderRule[] rules); - WebDavFolderRule[] GetFolderWebDavRules(string organizationId, string folder); + SystemFile[] GetFolders(string organizationId, WebDavSetting[] settings); + SystemFile GetFolder(string organizationId, string folderName, WebDavSetting setting); + void CreateFolder(string organizationId, string folder, WebDavSetting setting); + SystemFile RenameFolder(string organizationId, string originalFolder, string newFolder, WebDavSetting setting); + void DeleteFolder(string organizationId, string folder, WebDavSetting setting); + bool SetFolderWebDavRules(string organizationId, string folder, WebDavSetting setting, WebDavFolderRule[] rules); + WebDavFolderRule[] GetFolderWebDavRules(string organizationId, string folder, WebDavSetting setting); bool CheckFileServicesInstallation(); } diff --git a/WebsitePanel/Sources/WebsitePanel.Providers.Base/Web/WebDavFolderRule.cs b/WebsitePanel/Sources/WebsitePanel.Providers.Base/Web/WebDavFolderRule.cs index 44815d80..f0cc3f4a 100644 --- a/WebsitePanel/Sources/WebsitePanel.Providers.Base/Web/WebDavFolderRule.cs +++ b/WebsitePanel/Sources/WebsitePanel.Providers.Base/Web/WebDavFolderRule.cs @@ -6,7 +6,6 @@ using WebsitePanel.Providers.HostedSolution; namespace WebsitePanel.Providers.Web { - public enum WebDavAccess { Read = 1, diff --git a/WebsitePanel/Sources/WebsitePanel.Providers.Base/Web/WebDavSetting.cs b/WebsitePanel/Sources/WebsitePanel.Providers.Base/Web/WebDavSetting.cs new file mode 100644 index 00000000..c96007ee --- /dev/null +++ b/WebsitePanel/Sources/WebsitePanel.Providers.Base/Web/WebDavSetting.cs @@ -0,0 +1,56 @@ +// Copyright (c) 2012, Outercurve Foundation. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// - Redistributions of source code must retain the above copyright notice, this +// list of conditions and the following disclaimer. +// +// - Redistributions in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// +// - Neither the name of the Outercurve Foundation nor the names of its +// contributors may be used to endorse or promote products derived from this +// software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR +// ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +// ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace WebsitePanel.Providers.Web +{ + public class WebDavSetting + { + public string LocationDrive { get; set; } + public string HomeFolder { get; set; } + public string Domain { get; set; } + + public WebDavSetting() { } + + public WebDavSetting(string locationDrive, string homeFolder, string domain) + { + LocationDrive = locationDrive; + HomeFolder = homeFolder; + Domain = domain; + } + + public bool IsEmpty() + { + return string.IsNullOrEmpty(LocationDrive) && string.IsNullOrEmpty(HomeFolder) && string.IsNullOrEmpty(Domain); + } + } +} diff --git a/WebsitePanel/Sources/WebsitePanel.Providers.Base/WebsitePanel.Providers.Base.csproj b/WebsitePanel/Sources/WebsitePanel.Providers.Base/WebsitePanel.Providers.Base.csproj index 76bc8c69..3e0c109c 100644 --- a/WebsitePanel/Sources/WebsitePanel.Providers.Base/WebsitePanel.Providers.Base.csproj +++ b/WebsitePanel/Sources/WebsitePanel.Providers.Base/WebsitePanel.Providers.Base.csproj @@ -332,6 +332,7 @@ + diff --git a/WebsitePanel/Sources/WebsitePanel.Providers.EnterpriseStorage.Windows2012/Windows2012.cs b/WebsitePanel/Sources/WebsitePanel.Providers.EnterpriseStorage.Windows2012/Windows2012.cs index 28896298..4575b22c 100644 --- a/WebsitePanel/Sources/WebsitePanel.Providers.EnterpriseStorage.Windows2012/Windows2012.cs +++ b/WebsitePanel/Sources/WebsitePanel.Providers.EnterpriseStorage.Windows2012/Windows2012.cs @@ -62,55 +62,66 @@ namespace WebsitePanel.Providers.EnterpriseStorage #endregion #region Folders - public SystemFile[] GetFolders(string organizationId) + public SystemFile[] GetFolders(string organizationId, WebDavSetting[] settings) { ArrayList items = new ArrayList(); - string rootPath = string.Format("{0}:\\{1}\\{2}", LocationDrive, UsersHome, organizationId); - var windows = new WebsitePanel.Providers.OS.Windows2012(); + var webDavSettings = GetWebDavSettings(settings); - if (Directory.Exists(rootPath)) + foreach (var setting in webDavSettings) { - DirectoryInfo root = new DirectoryInfo(rootPath); - IWebDav webdav = new Web.WebDav(UsersDomain); + string rootPath = string.Format("{0}:\\{1}\\{2}", setting.LocationDrive, setting.HomeFolder, organizationId); - // get directories - DirectoryInfo[] dirs = root.GetDirectories(); - foreach (DirectoryInfo dir in dirs) + var windows = new WebsitePanel.Providers.OS.Windows2012(); + + if (Directory.Exists(rootPath)) { - string fullName = System.IO.Path.Combine(rootPath, dir.Name); + DirectoryInfo root = new DirectoryInfo(rootPath); + IWebDav webdav = new Web.WebDav(setting); - SystemFile folder = new SystemFile(); - - folder.Name = dir.Name; - folder.FullName = dir.FullName; - folder.IsDirectory = true; + // get directories + DirectoryInfo[] dirs = root.GetDirectories(); + var quotas = windows.GetQuotasForOrganization(rootPath, string.Empty, string.Empty); - Quota quota = windows.GetQuotaOnFolder(fullName, string.Empty, string.Empty); - - folder.Size = quota.Usage; - - if (folder.Size == -1) + foreach (DirectoryInfo dir in dirs) { - folder.Size = FileUtils.BytesToMb(FileUtils.CalculateFolderSize(dir.FullName)); - } + string fullName = System.IO.Path.Combine(rootPath, dir.Name); - folder.Url = string.Format("https://{0}/{1}/{2}", UsersDomain, organizationId, dir.Name); - folder.Rules = webdav.GetFolderWebDavRules(organizationId, dir.Name); - folder.FRSMQuotaMB = quota.Size; - folder.FRSMQuotaGB = windows.ConvertMegaBytesToGB(folder.FRSMQuotaMB); - folder.FsrmQuotaType = quota.QuotaType; - - items.Add(folder); + SystemFile folder = new SystemFile(); + + folder.Name = dir.Name; + folder.FullName = dir.FullName; + folder.IsDirectory = true; + + if (quotas.ContainsKey(fullName)) + { + folder.Size = quotas[fullName].Usage; + + if (folder.Size == -1) + { + folder.Size = FileUtils.BytesToMb(FileUtils.CalculateFolderSize(dir.FullName)); + } + + folder.Url = string.Format("https://{0}/{1}/{2}", setting.Domain, organizationId, dir.Name); + folder.Rules = webdav.GetFolderWebDavRules(organizationId, dir.Name); + folder.FRSMQuotaMB = quotas[fullName].Size; + folder.FRSMQuotaGB = windows.ConvertMegaBytesToGB(folder.FRSMQuotaMB); + folder.FsrmQuotaType = quotas[fullName].QuotaType; + + items.Add(folder); + } + } } } return (SystemFile[])items.ToArray(typeof(SystemFile)); } - public SystemFile GetFolder(string organizationId, string folderName) + public SystemFile GetFolder(string organizationId, string folderName, WebDavSetting setting) { - string fullName = string.Format("{0}:\\{1}\\{2}\\{3}", LocationDrive, UsersHome, organizationId, folderName); + var webDavSetting = GetWebDavSetting(setting); + + string fullName = string.Format("{0}:\\{1}\\{2}\\{3}", webDavSetting.LocationDrive, webDavSetting.HomeFolder, organizationId, folderName); SystemFile folder = null; var windows = new WebsitePanel.Providers.OS.Windows2012(); @@ -134,8 +145,8 @@ namespace WebsitePanel.Providers.EnterpriseStorage folder.Size = FileUtils.BytesToMb(FileUtils.CalculateFolderSize(root.FullName)); } - folder.Url = string.Format("https://{0}/{1}/{2}", UsersDomain, organizationId, folderName); - folder.Rules = GetFolderWebDavRules(organizationId, folderName); + folder.Url = string.Format("https://{0}/{1}/{2}", webDavSetting.Domain, organizationId, folderName); + folder.Rules = GetFolderWebDavRules(organizationId, folderName, webDavSetting); folder.FRSMQuotaMB = quota.Size; folder.FRSMQuotaGB = windows.ConvertMegaBytesToGB(folder.FRSMQuotaMB); folder.FsrmQuotaType = quota.QuotaType; @@ -144,29 +155,35 @@ namespace WebsitePanel.Providers.EnterpriseStorage return folder; } - public void CreateFolder(string organizationId, string folder) + public void CreateFolder(string organizationId, string folder, WebDavSetting setting) { - FileUtils.CreateDirectory(string.Format("{0}:\\{1}\\{2}\\{3}", LocationDrive, UsersHome, organizationId, folder)); + var webDavSetting = GetWebDavSetting(setting); + + FileUtils.CreateDirectory(string.Format("{0}:\\{1}\\{2}\\{3}", webDavSetting.LocationDrive, webDavSetting.HomeFolder, organizationId, folder)); } - public SystemFile RenameFolder(string organizationId, string originalFolder, string newFolder) + public SystemFile RenameFolder(string organizationId, string originalFolder, string newFolder, WebDavSetting setting) { - var oldPath = string.Format("{0}:\\{1}\\{2}\\{3}", LocationDrive, UsersHome, organizationId, originalFolder); - var newPath = string.Format("{0}:\\{1}\\{2}\\{3}", LocationDrive, UsersHome, organizationId, newFolder); + var webDavSetting = GetWebDavSetting(setting); + + var oldPath = string.Format("{0}:\\{1}\\{2}\\{3}", webDavSetting.LocationDrive, webDavSetting.HomeFolder, organizationId, originalFolder); + var newPath = string.Format("{0}:\\{1}\\{2}\\{3}", webDavSetting.LocationDrive, webDavSetting.HomeFolder, organizationId, newFolder); FileUtils.MoveFile(oldPath,newPath); - IWebDav webdav = new WebDav(UsersDomain); + IWebDav webdav = new WebDav(webDavSetting); //deleting old folder rules webdav.DeleteAllWebDavRules(organizationId, originalFolder); - return GetFolder(organizationId, newFolder); + return GetFolder(organizationId, newFolder, webDavSetting); } - public void DeleteFolder(string organizationId, string folder) + public void DeleteFolder(string organizationId, string folder, WebDavSetting setting) { - string rootPath = string.Format("{0}:\\{1}\\{2}\\{3}", LocationDrive, UsersHome, organizationId, folder); + var webDavSetting = GetWebDavSetting(setting); + + string rootPath = string.Format("{0}:\\{1}\\{2}\\{3}", webDavSetting.LocationDrive, webDavSetting.HomeFolder, organizationId, folder); DirectoryInfo treeRoot = new DirectoryInfo(rootPath); @@ -176,7 +193,7 @@ namespace WebsitePanel.Providers.EnterpriseStorage while (dirs.Length > 0) { foreach (DirectoryInfo dir in dirs) - DeleteFolder(organizationId, folder != string.Empty ? string.Format("{0}\\{1}", folder, dir.Name) : dir.Name); + DeleteFolder(organizationId, folder != string.Empty ? string.Format("{0}\\{1}", folder, dir.Name) : dir.Name, webDavSetting); dirs = treeRoot.GetDirectories(); } @@ -189,7 +206,7 @@ namespace WebsitePanel.Providers.EnterpriseStorage File.Delete(file); } - IWebDav webdav = new WebDav(UsersDomain); + IWebDav webdav = new WebDav(webDavSetting); webdav.DeleteAllWebDavRules(organizationId, folder); @@ -197,7 +214,7 @@ namespace WebsitePanel.Providers.EnterpriseStorage } } - public bool SetFolderWebDavRules(string organizationId, string folder, WebDavFolderRule[] rules) + public bool SetFolderWebDavRules(string organizationId, string folder, WebDavSetting setting, WebDavFolderRule[] rules) { var users = new List(); @@ -224,20 +241,24 @@ namespace WebsitePanel.Providers.EnterpriseStorage } } - string path = string.Format("{0}:\\{1}\\{2}\\{3}", LocationDrive, UsersHome, organizationId, folder); + var webDavSetting = GetWebDavSetting(setting); + + string path = string.Format("{0}:\\{1}\\{2}\\{3}", webDavSetting.LocationDrive, webDavSetting.HomeFolder, organizationId, folder); SecurityUtils.ResetNtfsPermissions(path); SecurityUtils.GrantGroupNtfsPermissions(path, users.ToArray(), false, new RemoteServerSettings(), null, null); - IWebDav webdav = new WebDav(UsersDomain); + IWebDav webdav = new WebDav(webDavSetting); return webdav.SetFolderWebDavRules(organizationId, folder, rules); } - public WebDavFolderRule[] GetFolderWebDavRules(string organizationId, string folder) + public WebDavFolderRule[] GetFolderWebDavRules(string organizationId, string folder, WebDavSetting setting) { - IWebDav webdav = new WebDav(UsersDomain); + var webDavSetting = GetWebDavSetting(setting); + + IWebDav webdav = new WebDav(webDavSetting); return webdav.GetFolderWebDavRules(organizationId, folder); } @@ -326,5 +347,34 @@ namespace WebsitePanel.Providers.EnterpriseStorage return version == WebsitePanel.Server.Utils.OS.WindowsVersion.WindowsServer2012; } + protected WebDavSetting GetWebDavSetting(WebDavSetting setting) + { + if (setting == null || setting.IsEmpty()) + { + return new WebDavSetting(LocationDrive, UsersHome, UsersDomain); + } + + return setting; + } + + protected WebDavSetting[] GetWebDavSettings(WebDavSetting[] settings) + { + var webDavSettings = new ArrayList(); + + foreach (var setting in settings) + { + if (!setting.IsEmpty()) + { + webDavSettings.Add(setting); + } + } + + if (webDavSettings.Count == 0) + { + return new WebDavSetting[] { GetWebDavSetting(new WebDavSetting()) }; + } + + return settings; + } } } diff --git a/WebsitePanel/Sources/WebsitePanel.Providers.OS.Windows2003/Windows2003.cs b/WebsitePanel/Sources/WebsitePanel.Providers.OS.Windows2003/Windows2003.cs index 80d66840..c88effdd 100644 --- a/WebsitePanel/Sources/WebsitePanel.Providers.OS.Windows2003/Windows2003.cs +++ b/WebsitePanel/Sources/WebsitePanel.Providers.OS.Windows2003/Windows2003.cs @@ -220,6 +220,11 @@ namespace WebsitePanel.Providers.OS throw new NotImplementedException(); } + public virtual Dictionary GetQuotasForOrganization(string folderPath, string wmiUserName, string wmiPassword) + { + throw new NotImplementedException(); + } + public virtual void DeleteDirectoryRecursive(string rootPath) { FileUtils.DeleteDirectoryRecursive(rootPath); diff --git a/WebsitePanel/Sources/WebsitePanel.Providers.OS.Windows2012/Windows2012.cs b/WebsitePanel/Sources/WebsitePanel.Providers.OS.Windows2012/Windows2012.cs index 4d05643c..35d18c9b 100644 --- a/WebsitePanel/Sources/WebsitePanel.Providers.OS.Windows2012/Windows2012.cs +++ b/WebsitePanel/Sources/WebsitePanel.Providers.OS.Windows2012/Windows2012.cs @@ -175,6 +175,53 @@ namespace WebsitePanel.Providers.OS return quota; } + public override Dictionary GetQuotasForOrganization(string folderPath, string wmiUserName, string wmiPassword) + { + Log.WriteStart("GetQuotasLimitsForOrganization"); + + + Runspace runSpace = null; + Quota quota = null; + var quotas = new Dictionary(); + + try + { + runSpace = OpenRunspace(); + + Command cmd = new Command("Get-FsrmQuota"); + cmd.Parameters.Add("Path", folderPath + "\\*"); + var result = ExecuteShellCommand(runSpace, cmd, false); + + if (result.Count > 0) + { + foreach (var element in result) + { + quota = new Quota(); + + quota.Size = ConvertBytesToMB(Convert.ToInt64(GetPSObjectProperty(element, "Size"))); + quota.QuotaType = Convert.ToBoolean(GetPSObjectProperty(element, "SoftLimit")) ? QuotaType.Soft : QuotaType.Hard; + quota.Usage = ConvertBytesToMB(Convert.ToInt64(GetPSObjectProperty(element, "usage"))); + + quotas.Add(Convert.ToString(GetPSObjectProperty(element, "Path")), quota); + } + } + + } + catch (Exception ex) + { + Log.WriteError("GetQuotasLimitsForOrganization", ex); + throw; + } + finally + { + CloseRunspace(runSpace); + } + + Log.WriteEnd("GetQuotasLimitsForOrganization"); + + return quotas; + } + public UInt64 CalculateQuota(string quota) { UInt64 OneKb = 1024; diff --git a/WebsitePanel/Sources/WebsitePanel.Providers.Web.WebDav/WebDav.cs b/WebsitePanel/Sources/WebsitePanel.Providers.Web.WebDav/WebDav.cs index 1ec41b3d..48b947de 100644 --- a/WebsitePanel/Sources/WebsitePanel.Providers.Web.WebDav/WebDav.cs +++ b/WebsitePanel/Sources/WebsitePanel.Providers.Web.WebDav/WebDav.cs @@ -13,13 +13,13 @@ namespace WebsitePanel.Providers.Web { #region Fields - private string _usersDomain; + protected WebDavSetting _Setting; #endregion - public WebDav(string domain) + public WebDav(WebDavSetting setting) { - _usersDomain = domain; + _Setting = setting; } public void CreateWebDavRule(string organizationId, string folder, WebDavFolderRule rule) @@ -28,7 +28,7 @@ namespace WebsitePanel.Providers.Web { Configuration config = serverManager.GetApplicationHostConfiguration(); - ConfigurationSection authoringRulesSection = config.GetSection("system.webServer/webdav/authoringRules", string.Format("{0}/{1}/{2}", _usersDomain, organizationId, folder)); + ConfigurationSection authoringRulesSection = config.GetSection("system.webServer/webdav/authoringRules", string.Format("{0}/{1}/{2}", _Setting.Domain, organizationId, folder)); ConfigurationElementCollection authoringRulesCollection = authoringRulesSection.GetCollection(); @@ -61,7 +61,7 @@ namespace WebsitePanel.Providers.Web { Configuration config = serverManager.GetApplicationHostConfiguration(); - ConfigurationSection authoringRulesSection = config.GetSection("system.webServer/webdav/authoringRules", string.Format("{0}/{1}/{2}", _usersDomain, organizationId, folder)); + ConfigurationSection authoringRulesSection = config.GetSection("system.webServer/webdav/authoringRules", string.Format("{0}/{1}/{2}", _Setting.Domain, organizationId, folder)); ConfigurationElementCollection authoringRulesCollection = authoringRulesSection.GetCollection(); @@ -107,7 +107,7 @@ namespace WebsitePanel.Providers.Web { Configuration config = serverManager.GetApplicationHostConfiguration(); - ConfigurationSection authoringRulesSection = config.GetSection("system.webServer/webdav/authoringRules", string.Format("{0}/{1}/{2}", _usersDomain, organizationId, folder)); + ConfigurationSection authoringRulesSection = config.GetSection("system.webServer/webdav/authoringRules", string.Format("{0}/{1}/{2}", _Setting.Domain, organizationId, folder)); ConfigurationElementCollection authoringRulesCollection = authoringRulesSection.GetCollection(); @@ -133,7 +133,7 @@ namespace WebsitePanel.Providers.Web Configuration config = serverManager.GetApplicationHostConfiguration(); - config.RemoveLocationPath(string.Format("{0}/{1}/{2}", _usersDomain, organizationId, folder)); + config.RemoveLocationPath(string.Format("{0}/{1}/{2}", _Setting.Domain, organizationId, folder)); serverManager.CommitChanges(); return true; } diff --git a/WebsitePanel/Sources/WebsitePanel.Server.Client/EnterpriseStorageProxy.cs b/WebsitePanel/Sources/WebsitePanel.Server.Client/EnterpriseStorageProxy.cs index 81bed424..2fe1d914 100644 --- a/WebsitePanel/Sources/WebsitePanel.Server.Client/EnterpriseStorageProxy.cs +++ b/WebsitePanel/Sources/WebsitePanel.Server.Client/EnterpriseStorageProxy.cs @@ -112,18 +112,20 @@ namespace WebsitePanel.Providers.EnterpriseStorage /// [System.Web.Services.Protocols.SoapHeaderAttribute("ServiceProviderSettingsSoapHeaderValue")] [System.Web.Services.Protocols.SoapDocumentMethodAttribute("http://smbsaas/websitepanel/server/GetFolders", RequestNamespace = "http://smbsaas/websitepanel/server/", ResponseNamespace = "http://smbsaas/websitepanel/server/", Use = System.Web.Services.Description.SoapBindingUse.Literal, ParameterStyle = System.Web.Services.Protocols.SoapParameterStyle.Wrapped)] - public SystemFile[] GetFolders(string organizationId) + public SystemFile[] GetFolders(string organizationId, WebDavSetting[] settings) { object[] results = this.Invoke("GetFolders", new object[] { - organizationId}); + organizationId, + settings}); return ((SystemFile[])(results[0])); } /// - public System.IAsyncResult BeginGetFolders(string organizationId, System.AsyncCallback callback, object asyncState) + public System.IAsyncResult BeginGetFolders(string organizationId, WebDavSetting[] settings, System.AsyncCallback callback, object asyncState) { return this.BeginInvoke("GetFolders", new object[] { - organizationId}, callback, asyncState); + organizationId, + settings}, callback, asyncState); } /// @@ -134,20 +136,21 @@ namespace WebsitePanel.Providers.EnterpriseStorage } /// - public void GetFoldersAsync(string organizationId) + public void GetFoldersAsync(string organizationId, WebDavSetting[] settings) { - this.GetFoldersAsync(organizationId, null); + this.GetFoldersAsync(organizationId, settings, null); } /// - public void GetFoldersAsync(string organizationId, object userState) + public void GetFoldersAsync(string organizationId, WebDavSetting[] settings, object userState) { if ((this.GetFoldersOperationCompleted == null)) { this.GetFoldersOperationCompleted = new System.Threading.SendOrPostCallback(this.OnGetFoldersOperationCompleted); } this.InvokeAsync("GetFolders", new object[] { - organizationId}, this.GetFoldersOperationCompleted, userState); + organizationId, + settings}, this.GetFoldersOperationCompleted, userState); } private void OnGetFoldersOperationCompleted(object arg) @@ -162,20 +165,22 @@ namespace WebsitePanel.Providers.EnterpriseStorage /// [System.Web.Services.Protocols.SoapHeaderAttribute("ServiceProviderSettingsSoapHeaderValue")] [System.Web.Services.Protocols.SoapDocumentMethodAttribute("http://smbsaas/websitepanel/server/GetFolder", RequestNamespace = "http://smbsaas/websitepanel/server/", ResponseNamespace = "http://smbsaas/websitepanel/server/", Use = System.Web.Services.Description.SoapBindingUse.Literal, ParameterStyle = System.Web.Services.Protocols.SoapParameterStyle.Wrapped)] - public SystemFile GetFolder(string organizationId, string folder) + public SystemFile GetFolder(string organizationId, string folder, WebDavSetting setting) { object[] results = this.Invoke("GetFolder", new object[] { organizationId, - folder}); + folder, + setting}); return ((SystemFile)(results[0])); } /// - public System.IAsyncResult BeginGetFolder(string organizationId, string folder, System.AsyncCallback callback, object asyncState) + public System.IAsyncResult BeginGetFolder(string organizationId, string folder, WebDavSetting setting, System.AsyncCallback callback, object asyncState) { return this.BeginInvoke("GetFolder", new object[] { organizationId, - folder}, callback, asyncState); + folder, + setting}, callback, asyncState); } /// @@ -186,13 +191,13 @@ namespace WebsitePanel.Providers.EnterpriseStorage } /// - public void GetFolderAsync(string organizationId, string folder) + public void GetFolderAsync(string organizationId, string folder, WebDavSetting setting) { - this.GetFolderAsync(organizationId, folder, null); + this.GetFolderAsync(organizationId, folder, setting, null); } /// - public void GetFolderAsync(string organizationId, string folder, object userState) + public void GetFolderAsync(string organizationId, string folder, WebDavSetting setting, object userState) { if ((this.GetFolderOperationCompleted == null)) { @@ -200,7 +205,8 @@ namespace WebsitePanel.Providers.EnterpriseStorage } this.InvokeAsync("GetFolder", new object[] { organizationId, - folder}, this.GetFolderOperationCompleted, userState); + folder, + setting}, this.GetFolderOperationCompleted, userState); } private void OnGetFolderOperationCompleted(object arg) @@ -215,19 +221,21 @@ namespace WebsitePanel.Providers.EnterpriseStorage /// [System.Web.Services.Protocols.SoapHeaderAttribute("ServiceProviderSettingsSoapHeaderValue")] [System.Web.Services.Protocols.SoapDocumentMethodAttribute("http://smbsaas/websitepanel/server/CreateFolder", RequestNamespace = "http://smbsaas/websitepanel/server/", ResponseNamespace = "http://smbsaas/websitepanel/server/", Use = System.Web.Services.Description.SoapBindingUse.Literal, ParameterStyle = System.Web.Services.Protocols.SoapParameterStyle.Wrapped)] - public void CreateFolder(string organizationId, string folder) + public void CreateFolder(string organizationId, string folder, WebDavSetting setting) { this.Invoke("CreateFolder", new object[] { organizationId, - folder}); + folder, + setting}); } /// - public System.IAsyncResult BeginCreateFolder(string organizationId, string folder, System.AsyncCallback callback, object asyncState) + public System.IAsyncResult BeginCreateFolder(string organizationId, string folder, WebDavSetting setting, System.AsyncCallback callback, object asyncState) { return this.BeginInvoke("CreateFolder", new object[] { organizationId, - folder}, callback, asyncState); + folder, + setting}, callback, asyncState); } /// @@ -237,13 +245,13 @@ namespace WebsitePanel.Providers.EnterpriseStorage } /// - public void CreateFolderAsync(string organizationId, string folder) + public void CreateFolderAsync(string organizationId, string folder, WebDavSetting setting) { - this.CreateFolderAsync(organizationId, folder, null); + this.CreateFolderAsync(organizationId, folder, setting, null); } /// - public void CreateFolderAsync(string organizationId, string folder, object userState) + public void CreateFolderAsync(string organizationId, string folder, WebDavSetting setting, object userState) { if ((this.CreateFolderOperationCompleted == null)) { @@ -251,7 +259,8 @@ namespace WebsitePanel.Providers.EnterpriseStorage } this.InvokeAsync("CreateFolder", new object[] { organizationId, - folder}, this.CreateFolderOperationCompleted, userState); + folder, + setting}, this.CreateFolderOperationCompleted, userState); } private void OnCreateFolderOperationCompleted(object arg) @@ -266,19 +275,21 @@ namespace WebsitePanel.Providers.EnterpriseStorage /// [System.Web.Services.Protocols.SoapHeaderAttribute("ServiceProviderSettingsSoapHeaderValue")] [System.Web.Services.Protocols.SoapDocumentMethodAttribute("http://smbsaas/websitepanel/server/DeleteFolder", RequestNamespace = "http://smbsaas/websitepanel/server/", ResponseNamespace = "http://smbsaas/websitepanel/server/", Use = System.Web.Services.Description.SoapBindingUse.Literal, ParameterStyle = System.Web.Services.Protocols.SoapParameterStyle.Wrapped)] - public void DeleteFolder(string organizationId, string folder) + public void DeleteFolder(string organizationId, string folder, WebDavSetting setting) { this.Invoke("DeleteFolder", new object[] { organizationId, - folder}); + folder, + setting}); } /// - public System.IAsyncResult BeginDeleteFolder(string organizationId, string folder, System.AsyncCallback callback, object asyncState) + public System.IAsyncResult BeginDeleteFolder(string organizationId, string folder, WebDavSetting setting, System.AsyncCallback callback, object asyncState) { return this.BeginInvoke("DeleteFolder", new object[] { organizationId, - folder}, callback, asyncState); + folder, + setting}, callback, asyncState); } /// @@ -288,13 +299,13 @@ namespace WebsitePanel.Providers.EnterpriseStorage } /// - public void DeleteFolderAsync(string organizationId, string folder) + public void DeleteFolderAsync(string organizationId, string folder, WebDavSetting setting) { - this.DeleteFolderAsync(organizationId, folder, null); + this.DeleteFolderAsync(organizationId, folder, setting, null); } /// - public void DeleteFolderAsync(string organizationId, string folder, object userState) + public void DeleteFolderAsync(string organizationId, string folder, WebDavSetting setting, object userState) { if ((this.DeleteFolderOperationCompleted == null)) { @@ -302,7 +313,8 @@ namespace WebsitePanel.Providers.EnterpriseStorage } this.InvokeAsync("DeleteFolder", new object[] { organizationId, - folder}, this.DeleteFolderOperationCompleted, userState); + folder, + setting}, this.DeleteFolderOperationCompleted, userState); } private void OnDeleteFolderOperationCompleted(object arg) @@ -317,21 +329,23 @@ namespace WebsitePanel.Providers.EnterpriseStorage /// [System.Web.Services.Protocols.SoapHeaderAttribute("ServiceProviderSettingsSoapHeaderValue")] [System.Web.Services.Protocols.SoapDocumentMethodAttribute("http://smbsaas/websitepanel/server/SetFolderWebDavRules", RequestNamespace = "http://smbsaas/websitepanel/server/", ResponseNamespace = "http://smbsaas/websitepanel/server/", Use = System.Web.Services.Description.SoapBindingUse.Literal, ParameterStyle = System.Web.Services.Protocols.SoapParameterStyle.Wrapped)] - public bool SetFolderWebDavRules(string organizationId, string folder, WebDavFolderRule[] rules) + public bool SetFolderWebDavRules(string organizationId, string folder, WebDavSetting setting, WebDavFolderRule[] rules) { object[] results = this.Invoke("SetFolderWebDavRules", new object[] { organizationId, folder, + setting, rules}); return ((bool)(results[0])); } /// - public System.IAsyncResult BeginSetFolderWebDavRules(string organizationId, string folder, WebDavFolderRule[] rules, System.AsyncCallback callback, object asyncState) + public System.IAsyncResult BeginSetFolderWebDavRules(string organizationId, string folder, WebDavSetting setting, WebDavFolderRule[] rules, System.AsyncCallback callback, object asyncState) { return this.BeginInvoke("SetFolderWebDavRules", new object[] { organizationId, folder, + setting, rules}, callback, asyncState); } @@ -343,13 +357,13 @@ namespace WebsitePanel.Providers.EnterpriseStorage } /// - public void SetFolderWebDavRulesAsync(string organizationId, string folder, WebDavFolderRule[] rules) + public void SetFolderWebDavRulesAsync(string organizationId, string folder, WebDavSetting setting, WebDavFolderRule[] rules) { - this.SetFolderWebDavRulesAsync(organizationId, folder, rules, null); + this.SetFolderWebDavRulesAsync(organizationId, folder, setting, rules, null); } /// - public void SetFolderWebDavRulesAsync(string organizationId, string folder, WebDavFolderRule[] rules, object userState) + public void SetFolderWebDavRulesAsync(string organizationId, string folder, WebDavSetting setting, WebDavFolderRule[] rules, object userState) { if ((this.SetFolderWebDavRulesOperationCompleted == null)) { @@ -358,6 +372,7 @@ namespace WebsitePanel.Providers.EnterpriseStorage this.InvokeAsync("SetFolderWebDavRules", new object[] { organizationId, folder, + setting, rules}, this.SetFolderWebDavRulesOperationCompleted, userState); } @@ -373,20 +388,22 @@ namespace WebsitePanel.Providers.EnterpriseStorage /// [System.Web.Services.Protocols.SoapHeaderAttribute("ServiceProviderSettingsSoapHeaderValue")] [System.Web.Services.Protocols.SoapDocumentMethodAttribute("http://smbsaas/websitepanel/server/GetFolderWebDavRules", RequestNamespace = "http://smbsaas/websitepanel/server/", ResponseNamespace = "http://smbsaas/websitepanel/server/", Use = System.Web.Services.Description.SoapBindingUse.Literal, ParameterStyle = System.Web.Services.Protocols.SoapParameterStyle.Wrapped)] - public WebDavFolderRule[] GetFolderWebDavRules(string organizationId, string folder) + public WebDavFolderRule[] GetFolderWebDavRules(string organizationId, string folder, WebDavSetting setting) { object[] results = this.Invoke("GetFolderWebDavRules", new object[] { organizationId, - folder}); + folder, + setting}); return ((WebDavFolderRule[])(results[0])); } /// - public System.IAsyncResult BeginGetFolderWebDavRules(string organizationId, string folder, System.AsyncCallback callback, object asyncState) + public System.IAsyncResult BeginGetFolderWebDavRules(string organizationId, string folder, WebDavSetting setting, System.AsyncCallback callback, object asyncState) { return this.BeginInvoke("GetFolderWebDavRules", new object[] { organizationId, - folder}, callback, asyncState); + folder, + setting}, callback, asyncState); } /// @@ -397,13 +414,13 @@ namespace WebsitePanel.Providers.EnterpriseStorage } /// - public void GetFolderWebDavRulesAsync(string organizationId, string folder) + public void GetFolderWebDavRulesAsync(string organizationId, string folder, WebDavSetting setting) { - this.GetFolderWebDavRulesAsync(organizationId, folder, null); + this.GetFolderWebDavRulesAsync(organizationId, folder, setting, null); } /// - public void GetFolderWebDavRulesAsync(string organizationId, string folder, object userState) + public void GetFolderWebDavRulesAsync(string organizationId, string folder, WebDavSetting setting, object userState) { if ((this.GetFolderWebDavRulesOperationCompleted == null)) { @@ -411,7 +428,8 @@ namespace WebsitePanel.Providers.EnterpriseStorage } this.InvokeAsync("GetFolderWebDavRules", new object[] { organizationId, - folder}, this.GetFolderWebDavRulesOperationCompleted, userState); + folder, + setting}, this.GetFolderWebDavRulesOperationCompleted, userState); } private void OnGetFolderWebDavRulesOperationCompleted(object arg) @@ -473,22 +491,24 @@ namespace WebsitePanel.Providers.EnterpriseStorage /// [System.Web.Services.Protocols.SoapHeaderAttribute("ServiceProviderSettingsSoapHeaderValue")] [System.Web.Services.Protocols.SoapDocumentMethodAttribute("http://smbsaas/websitepanel/server/RenameFolder", RequestNamespace = "http://smbsaas/websitepanel/server/", ResponseNamespace = "http://smbsaas/websitepanel/server/", Use = System.Web.Services.Description.SoapBindingUse.Literal, ParameterStyle = System.Web.Services.Protocols.SoapParameterStyle.Wrapped)] - public SystemFile RenameFolder(string organizationId, string originalFolder, string newFolder) + public SystemFile RenameFolder(string organizationId, string originalFolder, string newFolder, WebDavSetting setting) { object[] results = this.Invoke("RenameFolder", new object[] { organizationId, originalFolder, - newFolder}); + newFolder, + setting}); return ((SystemFile)(results[0])); } /// - public System.IAsyncResult BeginRenameFolder(string organizationId, string originalFolder, string newFolder, System.AsyncCallback callback, object asyncState) + public System.IAsyncResult BeginRenameFolder(string organizationId, string originalFolder, string newFolder, WebDavSetting setting, System.AsyncCallback callback, object asyncState) { return this.BeginInvoke("RenameFolder", new object[] { organizationId, originalFolder, - newFolder}, callback, asyncState); + newFolder, + setting}, callback, asyncState); } /// @@ -499,13 +519,13 @@ namespace WebsitePanel.Providers.EnterpriseStorage } /// - public void RenameFolderAsync(string organizationId, string originalFolder, string newFolder) + public void RenameFolderAsync(string organizationId, string originalFolder, string newFolder, WebDavSetting setting) { - this.RenameFolderAsync(organizationId, originalFolder, newFolder, null); + this.RenameFolderAsync(organizationId, originalFolder, newFolder, setting, null); } /// - public void RenameFolderAsync(string organizationId, string originalFolder, string newFolder, object userState) + public void RenameFolderAsync(string organizationId, string originalFolder, string newFolder, WebDavSetting setting, object userState) { if ((this.RenameFolderOperationCompleted == null)) { @@ -514,7 +534,8 @@ namespace WebsitePanel.Providers.EnterpriseStorage this.InvokeAsync("RenameFolder", new object[] { organizationId, originalFolder, - newFolder}, this.RenameFolderOperationCompleted, userState); + newFolder, + setting}, this.RenameFolderOperationCompleted, userState); } private void OnRenameFolderOperationCompleted(object arg) diff --git a/WebsitePanel/Sources/WebsitePanel.Server/EnterpriseStorage.asmx.cs b/WebsitePanel/Sources/WebsitePanel.Server/EnterpriseStorage.asmx.cs index 002a4c98..54eeea5e 100644 --- a/WebsitePanel/Sources/WebsitePanel.Server/EnterpriseStorage.asmx.cs +++ b/WebsitePanel/Sources/WebsitePanel.Server/EnterpriseStorage.asmx.cs @@ -39,6 +39,7 @@ using WebsitePanel.Providers; using WebsitePanel.Providers.EnterpriseStorage; using WebsitePanel.Providers.OS; using WebsitePanel.Server.Utils; +using WebsitePanel.Providers.Web; namespace WebsitePanel.Server { @@ -58,12 +59,12 @@ namespace WebsitePanel.Server [WebMethod, SoapHeader("settings")] - public SystemFile[] GetFolders(string organizationId) + public SystemFile[] GetFolders(string organizationId, WebDavSetting[] settings) { try { Log.WriteStart("'{0}' GetFolders", ProviderSettings.ProviderName); - SystemFile[] result = EnterpriseStorageProvider.GetFolders(organizationId); + SystemFile[] result = EnterpriseStorageProvider.GetFolders(organizationId, settings); Log.WriteEnd("'{0}' GetFolders", ProviderSettings.ProviderName); return result; } @@ -75,12 +76,12 @@ namespace WebsitePanel.Server } [WebMethod, SoapHeader("settings")] - public SystemFile GetFolder(string organizationId, string folder) + public SystemFile GetFolder(string organizationId, string folder, WebDavSetting setting) { try { Log.WriteStart("'{0}' GetFolder", ProviderSettings.ProviderName); - SystemFile result = EnterpriseStorageProvider.GetFolder(organizationId, folder); + SystemFile result = EnterpriseStorageProvider.GetFolder(organizationId, folder, setting); Log.WriteEnd("'{0}' GetFolder", ProviderSettings.ProviderName); return result; } @@ -92,12 +93,12 @@ namespace WebsitePanel.Server } [WebMethod, SoapHeader("settings")] - public void CreateFolder(string organizationId, string folder) + public void CreateFolder(string organizationId, string folder, WebDavSetting setting) { try { Log.WriteStart("'{0}' CreateFolder", ProviderSettings.ProviderName); - EnterpriseStorageProvider.CreateFolder(organizationId, folder); + EnterpriseStorageProvider.CreateFolder(organizationId, folder, setting); Log.WriteEnd("'{0}' CreateFolder", ProviderSettings.ProviderName); } catch (Exception ex) @@ -108,12 +109,12 @@ namespace WebsitePanel.Server } [WebMethod, SoapHeader("settings")] - public void DeleteFolder(string organizationId, string folder) + public void DeleteFolder(string organizationId, string folder, WebDavSetting setting) { try { Log.WriteStart("'{0}' DeleteFolder", ProviderSettings.ProviderName); - EnterpriseStorageProvider.DeleteFolder(organizationId, folder); + EnterpriseStorageProvider.DeleteFolder(organizationId, folder, setting); Log.WriteEnd("'{0}' DeleteFolder", ProviderSettings.ProviderName); } catch (Exception ex) @@ -124,12 +125,12 @@ namespace WebsitePanel.Server } [WebMethod, SoapHeader("settings")] - public bool SetFolderWebDavRules(string organizationId, string folder, Providers.Web.WebDavFolderRule[] rules) + public bool SetFolderWebDavRules(string organizationId, string folder, WebDavSetting setting, Providers.Web.WebDavFolderRule[] rules) { try { Log.WriteStart("'{0}' SetFolderWebDavRules", ProviderSettings.ProviderName); - return EnterpriseStorageProvider.SetFolderWebDavRules(organizationId, folder, rules); + return EnterpriseStorageProvider.SetFolderWebDavRules(organizationId, folder, setting, rules); Log.WriteEnd("'{0}' SetFolderWebDavRules", ProviderSettings.ProviderName); } catch (Exception ex) @@ -140,12 +141,12 @@ namespace WebsitePanel.Server } [WebMethod, SoapHeader("settings")] - public Providers.Web.WebDavFolderRule[] GetFolderWebDavRules(string organizationId, string folder) + public Providers.Web.WebDavFolderRule[] GetFolderWebDavRules(string organizationId, string folder, WebDavSetting setting) { try { Log.WriteStart("'{0}' GetFolderWebDavRules", ProviderSettings.ProviderName); - return EnterpriseStorageProvider.GetFolderWebDavRules(organizationId, folder); + return EnterpriseStorageProvider.GetFolderWebDavRules(organizationId, folder, setting); Log.WriteEnd("'{0}' GetFolderWebDavRules", ProviderSettings.ProviderName); } catch (Exception ex) @@ -172,12 +173,12 @@ namespace WebsitePanel.Server } [WebMethod, SoapHeader("settings")] - public SystemFile RenameFolder(string organizationId, string originalFolder, string newFolder) + public SystemFile RenameFolder(string organizationId, string originalFolder, string newFolder, WebDavSetting setting) { try { Log.WriteStart("'{0}' RenameFolder", ProviderSettings.ProviderName); - return EnterpriseStorageProvider.RenameFolder(organizationId, originalFolder, newFolder); + return EnterpriseStorageProvider.RenameFolder(organizationId, originalFolder, newFolder, setting); Log.WriteEnd("'{0}' RenameFolder", ProviderSettings.ProviderName); } catch (Exception ex) diff --git a/WebsitePanel/Sources/WebsitePanel.WebPortal/App_Data/WebsitePanel_Pages.config b/WebsitePanel/Sources/WebsitePanel.WebPortal/App_Data/WebsitePanel_Pages.config index bb162c93..437fbfb4 100644 --- a/WebsitePanel/Sources/WebsitePanel.WebPortal/App_Data/WebsitePanel_Pages.config +++ b/WebsitePanel/Sources/WebsitePanel.WebPortal/App_Data/WebsitePanel_Pages.config @@ -27,7 +27,7 @@ - + @@ -127,6 +127,9 @@ - + @@ -552,7 +563,7 @@ - + diff --git a/WebsitePanel/Sources/WebsitePanel.WebPortal/App_Skins/Default/Browse2.ascx b/WebsitePanel/Sources/WebsitePanel.WebPortal/App_Skins/Default/Browse2.ascx index 5d7a7432..0abbf788 100644 --- a/WebsitePanel/Sources/WebsitePanel.WebPortal/App_Skins/Default/Browse2.ascx +++ b/WebsitePanel/Sources/WebsitePanel.WebPortal/App_Skins/Default/Browse2.ascx @@ -33,21 +33,17 @@
- + + +
-
- -
- -
-
- -
+
+
- + + +
-
- -
- -
+
diff --git a/WebsitePanel/Sources/WebsitePanel.WebPortal/App_Skins/Default/Edit.ascx b/WebsitePanel/Sources/WebsitePanel.WebPortal/App_Skins/Default/Edit.ascx index 7d87ddcd..0e9074ff 100644 --- a/WebsitePanel/Sources/WebsitePanel.WebPortal/App_Skins/Default/Edit.ascx +++ b/WebsitePanel/Sources/WebsitePanel.WebPortal/App_Skins/Default/Edit.ascx @@ -33,7 +33,9 @@
- + + +
diff --git a/WebsitePanel/Sources/WebsitePanel.WebPortal/App_Skins/Default/Exchange.ascx b/WebsitePanel/Sources/WebsitePanel.WebPortal/App_Skins/Default/Exchange.ascx index 55014f68..d675d9f9 100644 --- a/WebsitePanel/Sources/WebsitePanel.WebPortal/App_Skins/Default/Exchange.ascx +++ b/WebsitePanel/Sources/WebsitePanel.WebPortal/App_Skins/Default/Exchange.ascx @@ -33,9 +33,10 @@
- + + +
-
diff --git a/WebsitePanel/Sources/WebsitePanel.WebPortal/App_Skins/Default/Storefront2.ascx b/WebsitePanel/Sources/WebsitePanel.WebPortal/App_Skins/Default/Storefront2.ascx index 7ae9c2f0..56925464 100644 --- a/WebsitePanel/Sources/WebsitePanel.WebPortal/App_Skins/Default/Storefront2.ascx +++ b/WebsitePanel/Sources/WebsitePanel.WebPortal/App_Skins/Default/Storefront2.ascx @@ -28,17 +28,15 @@
- + + +
-
- -
-
diff --git a/WebsitePanel/Sources/WebsitePanel.WebPortal/App_Themes/Default/Styles/Menus.css b/WebsitePanel/Sources/WebsitePanel.WebPortal/App_Themes/Default/Styles/Menus.css index 51ed7485..04555d46 100644 --- a/WebsitePanel/Sources/WebsitePanel.WebPortal/App_Themes/Default/Styles/Menus.css +++ b/WebsitePanel/Sources/WebsitePanel.WebPortal/App_Themes/Default/Styles/Menus.css @@ -19,6 +19,17 @@ z-index: 502; } +.TopMenu ul.AspNet-Menu li ul li.AspNet-Menu-WithChildren span +{ + color: #000000 !important; + background: transparent url(../Images/menu_popup2.gif) right center no-repeat !important; + text-align: left !important; + border-right: none !important; + display: table !important; +} + +.TopMenu ul.AspNet-Menu li span + .TopMenu li.AspNet-Menu-Leaf a, /* leaves */ .TopMenu li.AspNet-Menu-Leaf span { diff --git a/WebsitePanel/Sources/WebsitePanel.WebPortal/App_Themes/Default/Styles/SkinLayout.css b/WebsitePanel/Sources/WebsitePanel.WebPortal/App_Themes/Default/Styles/SkinLayout.css index 0705da62..e4fcc83a 100644 --- a/WebsitePanel/Sources/WebsitePanel.WebPortal/App_Themes/Default/Styles/SkinLayout.css +++ b/WebsitePanel/Sources/WebsitePanel.WebPortal/App_Themes/Default/Styles/SkinLayout.css @@ -278,14 +278,14 @@ BODY #Center { float: left; - width: 540px; + width: 730px; padding: 10px 0px 10px 10px; } #StorefrontCenter { float: left; - width: 755px; + width: 955px; padding: 10px 0px 10px 10px; } diff --git a/WebsitePanel/Sources/WebsitePanel.WebPortal/Code/PortalConfiguration.cs b/WebsitePanel/Sources/WebsitePanel.WebPortal/Code/PortalConfiguration.cs index 5de61c70..c1de8652 100644 --- a/WebsitePanel/Sources/WebsitePanel.WebPortal/Code/PortalConfiguration.cs +++ b/WebsitePanel/Sources/WebsitePanel.WebPortal/Code/PortalConfiguration.cs @@ -295,6 +295,7 @@ namespace WebsitePanel.WebPortal page.Enabled = (xmlPage.Attributes["enabled"] != null) ? Boolean.Parse(xmlPage.Attributes["enabled"].Value) : true; page.Hidden = (xmlPage.Attributes["hidden"] != null) ? Boolean.Parse(xmlPage.Attributes["hidden"].Value) : false; + page.Align = (xmlPage.Attributes["align"] != null) ? xmlPage.Attributes["align"].Value : null; page.SkinSrc = (xmlPage.Attributes["skin"] != null) ? xmlPage.Attributes["skin"].Value : null; page.AdminSkinSrc = (xmlPage.Attributes["adminskin"] != null) ? xmlPage.Attributes["adminskin"].Value : null; diff --git a/WebsitePanel/Sources/WebsitePanel.WebPortal/Code/PortalPage.cs b/WebsitePanel/Sources/WebsitePanel.WebPortal/Code/PortalPage.cs index 77df175c..a39a595c 100644 --- a/WebsitePanel/Sources/WebsitePanel.WebPortal/Code/PortalPage.cs +++ b/WebsitePanel/Sources/WebsitePanel.WebPortal/Code/PortalPage.cs @@ -45,6 +45,7 @@ namespace WebsitePanel.WebPortal private Dictionary contentPanes = new Dictionary(); private string url; private string target; + private string align; public string Name { @@ -108,5 +109,11 @@ namespace WebsitePanel.WebPortal get { return this.target; } set { this.target = value; } } + + public string Align + { + get { return this.align; } + set { this.align = value; } + } } } diff --git a/WebsitePanel/Sources/WebsitePanel.WebPortal/Code/WebsitePanelSiteMapProvider.cs b/WebsitePanel/Sources/WebsitePanel.WebPortal/Code/WebsitePanelSiteMapProvider.cs index acb25348..99990030 100644 --- a/WebsitePanel/Sources/WebsitePanel.WebPortal/Code/WebsitePanelSiteMapProvider.cs +++ b/WebsitePanel/Sources/WebsitePanel.WebPortal/Code/WebsitePanelSiteMapProvider.cs @@ -199,6 +199,7 @@ namespace WebsitePanel.WebPortal NameValueCollection attrs = new NameValueCollection(); attrs["target"] = page.Target; + attrs["align"] = page.Align; SiteMapNode node = new SiteMapNode(this, page.Name, url, diff --git a/WebsitePanel/Sources/WebsitePanel.WebPortal/Default.aspx.cs b/WebsitePanel/Sources/WebsitePanel.WebPortal/Default.aspx.cs index 50c487d0..383e2a53 100644 --- a/WebsitePanel/Sources/WebsitePanel.WebPortal/Default.aspx.cs +++ b/WebsitePanel/Sources/WebsitePanel.WebPortal/Default.aspx.cs @@ -58,6 +58,7 @@ namespace WebsitePanel.WebPortal public const string SKINS_FOLDER = "App_Skins"; public const string CONTAINERS_FOLDER = "App_Containers"; public const string CONTENT_PANE_NAME = "ContentPane"; + public const string LEFT_PANE_NAME = "LeftPane"; public const string MODULE_TITLE_CONTROL_ID = "lblModuleTitle"; public const string MODULE_ICON_CONTROL_ID = "imgModuleIcon"; public const string DESKTOP_MODULES_FOLDER = "DesktopModules"; @@ -234,10 +235,24 @@ namespace WebsitePanel.WebPortal if (ctrlPane != null) { // add "edit" module - if(PortalConfiguration.Site.Modules.ContainsKey(ModuleID)) + if (PortalConfiguration.Site.Modules.ContainsKey(ModuleID)) AddModuleToContentPane(ctrlPane, PortalConfiguration.Site.Modules[ModuleID], ModuleControlID, editMode); } + // find LeftPane + ctrlPane = ctrlSkin.FindControl(LEFT_PANE_NAME); + if (ctrlPane != null) + { + ContentPane pane = page.ContentPanes[LEFT_PANE_NAME]; + foreach (PageModule module in pane.Modules) + { + if (IsAccessibleToUser(Context, module.ViewRoles)) + { + // add module + AddModuleToContentPane(ctrlPane, module, "", false); + } + } + } } } diff --git a/WebsitePanel/Sources/WebsitePanel.WebPortal/DesktopModules/WebsitePanel/ExchangeServer/App_LocalResources/EnterpriseStorageCreateFolder.ascx.resx b/WebsitePanel/Sources/WebsitePanel.WebPortal/DesktopModules/WebsitePanel/ExchangeServer/App_LocalResources/EnterpriseStorageCreateFolder.ascx.resx index 82a41d20..4e4c8df5 100644 --- a/WebsitePanel/Sources/WebsitePanel.WebPortal/DesktopModules/WebsitePanel/ExchangeServer/App_LocalResources/EnterpriseStorageCreateFolder.ascx.resx +++ b/WebsitePanel/Sources/WebsitePanel.WebPortal/DesktopModules/WebsitePanel/ExchangeServer/App_LocalResources/EnterpriseStorageCreateFolder.ascx.resx @@ -141,4 +141,28 @@ Create New Folder + + Add Default Group + + + Folder Limit Size (Gb): + + + Quota Type: + + + * + + + Hard + + + Soft + + + valRequireFolderSize + + + Enter Folder Size + \ No newline at end of file diff --git a/WebsitePanel/Sources/WebsitePanel.WebPortal/DesktopModules/WebsitePanel/ExchangeServer/EnterpriseStorageCreateFolder.ascx b/WebsitePanel/Sources/WebsitePanel.WebPortal/DesktopModules/WebsitePanel/ExchangeServer/EnterpriseStorageCreateFolder.ascx index 396fa46e..bf805b3d 100644 --- a/WebsitePanel/Sources/WebsitePanel.WebPortal/DesktopModules/WebsitePanel/ExchangeServer/EnterpriseStorageCreateFolder.ascx +++ b/WebsitePanel/Sources/WebsitePanel.WebPortal/DesktopModules/WebsitePanel/ExchangeServer/EnterpriseStorageCreateFolder.ascx @@ -32,6 +32,31 @@ ErrorMessage="Enter Folder Name" ValidationGroup="CreateFolder" Display="Dynamic" Text="*" SetFocusOnError="True"> + + + + + + + + + + + + + + + + + + + + + +
diff --git a/WebsitePanel/Sources/WebsitePanel.WebPortal/DesktopModules/WebsitePanel/ExchangeServer/EnterpriseStorageCreateFolder.ascx.cs b/WebsitePanel/Sources/WebsitePanel.WebPortal/DesktopModules/WebsitePanel/ExchangeServer/EnterpriseStorageCreateFolder.ascx.cs index 1d369fa8..94e2f6a1 100644 --- a/WebsitePanel/Sources/WebsitePanel.WebPortal/DesktopModules/WebsitePanel/ExchangeServer/EnterpriseStorageCreateFolder.ascx.cs +++ b/WebsitePanel/Sources/WebsitePanel.WebPortal/DesktopModules/WebsitePanel/ExchangeServer/EnterpriseStorageCreateFolder.ascx.cs @@ -30,11 +30,18 @@ using System; using WebsitePanel.EnterpriseServer; using WebsitePanel.Providers.Common; using WebsitePanel.Providers.HostedSolution; +using WebsitePanel.Providers.OS; namespace WebsitePanel.Portal.ExchangeServer { public partial class EnterpriseStorageCreateFolder : WebsitePanelModuleBase { + #region Constants + + private const int OneGb = 1024; + + #endregion + protected void Page_Load(object sender, EventArgs e) { if (!IsPostBack) @@ -44,6 +51,17 @@ namespace WebsitePanel.Portal.ExchangeServer Response.Redirect(EditUrl("SpaceID", PanelSecurity.PackageId.ToString(), "enterprisestorage_folders", "ItemID=" + PanelRequest.ItemID)); } + + OrganizationStatistics organizationStats = ES.Services.Organizations.GetOrganizationStatisticsByOrganization(PanelRequest.ItemID); + + if (organizationStats.AllocatedEnterpriseStorageSpace != -1) + { + OrganizationStatistics tenantStats = ES.Services.Organizations.GetOrganizationStatistics(PanelRequest.ItemID); + + rangeFolderSize.MaximumValue = Math.Round((tenantStats.AllocatedEnterpriseStorageSpace - (decimal)tenantStats.UsedEnterpriseStorageSpace) / OneGb + + Utils.ParseDecimal(txtFolderSize.Text, 0), 2).ToString(); + rangeFolderSize.ErrorMessage = string.Format("The quota you’ve entered exceeds the available quota for tenant ({0}Gb)", rangeFolderSize.MaximumValue); + } } } @@ -69,13 +87,18 @@ namespace WebsitePanel.Portal.ExchangeServer ES.Services.EnterpriseStorage.CreateEnterpriseStorage(PanelSecurity.PackageId, PanelRequest.ItemID); } - ResultObject result = ES.Services.EnterpriseStorage.CreateEnterpriseFolder(PanelRequest.ItemID, txtFolderName.Text); + ResultObject result = ES.Services.EnterpriseStorage.CreateEnterpriseFolder( + PanelRequest.ItemID, + txtFolderName.Text, + (int)(decimal.Parse(txtFolderSize.Text) * OneGb), + rbtnQuotaSoft.Checked ? QuotaType.Soft : QuotaType.Hard, + chkAddDefaultGroup.Checked); - if (!result.IsSuccess && result.ErrorCodes.Count > 0) + /*if (!result.IsSuccess && result.ErrorCodes.Count > 0) { messageBox.ShowMessage(result, "ENTERPRISE_STORAGE_CREATE_FOLDER", "Enterprise Storage"); return; - } + }*/ Response.Redirect(EditUrl("SpaceID", PanelSecurity.PackageId.ToString(), "enterprisestorage_folder_settings", "FolderID=" + txtFolderName.Text, diff --git a/WebsitePanel/Sources/WebsitePanel.WebPortal/DesktopModules/WebsitePanel/ExchangeServer/EnterpriseStorageCreateFolder.ascx.designer.cs b/WebsitePanel/Sources/WebsitePanel.WebPortal/DesktopModules/WebsitePanel/ExchangeServer/EnterpriseStorageCreateFolder.ascx.designer.cs index dc641ab6..57461823 100644 --- a/WebsitePanel/Sources/WebsitePanel.WebPortal/DesktopModules/WebsitePanel/ExchangeServer/EnterpriseStorageCreateFolder.ascx.designer.cs +++ b/WebsitePanel/Sources/WebsitePanel.WebPortal/DesktopModules/WebsitePanel/ExchangeServer/EnterpriseStorageCreateFolder.ascx.designer.cs @@ -121,6 +121,87 @@ namespace WebsitePanel.Portal.ExchangeServer { /// protected global::System.Web.UI.WebControls.RequiredFieldValidator valRequireFolderName; + /// + /// locFolderSize control. + /// + /// + /// Auto-generated field. + /// To modify move field declaration from designer file to code-behind file. + /// + protected global::System.Web.UI.WebControls.Localize locFolderSize; + + /// + /// txtFolderSize control. + /// + /// + /// Auto-generated field. + /// To modify move field declaration from designer file to code-behind file. + /// + protected global::System.Web.UI.WebControls.TextBox txtFolderSize; + + /// + /// valRequireFolderSize control. + /// + /// + /// Auto-generated field. + /// To modify move field declaration from designer file to code-behind file. + /// + protected global::System.Web.UI.WebControls.RequiredFieldValidator valRequireFolderSize; + + /// + /// rangeFolderSize control. + /// + /// + /// Auto-generated field. + /// To modify move field declaration from designer file to code-behind file. + /// + protected global::System.Web.UI.WebControls.RangeValidator rangeFolderSize; + + /// + /// locQuotaType control. + /// + /// + /// Auto-generated field. + /// To modify move field declaration from designer file to code-behind file. + /// + protected global::System.Web.UI.WebControls.Localize locQuotaType; + + /// + /// rbtnQuotaSoft control. + /// + /// + /// Auto-generated field. + /// To modify move field declaration from designer file to code-behind file. + /// + protected global::System.Web.UI.WebControls.RadioButton rbtnQuotaSoft; + + /// + /// rbtnQuotaHard control. + /// + /// + /// Auto-generated field. + /// To modify move field declaration from designer file to code-behind file. + /// + protected global::System.Web.UI.WebControls.RadioButton rbtnQuotaHard; + + /// + /// locAddDefaultGroup control. + /// + /// + /// Auto-generated field. + /// To modify move field declaration from designer file to code-behind file. + /// + protected global::System.Web.UI.WebControls.Localize locAddDefaultGroup; + + /// + /// chkAddDefaultGroup control. + /// + /// + /// Auto-generated field. + /// To modify move field declaration from designer file to code-behind file. + /// + protected global::System.Web.UI.WebControls.CheckBox chkAddDefaultGroup; + /// /// btnCreate control. /// diff --git a/WebsitePanel/Sources/WebsitePanel.WebPortal/DesktopModules/WebsitePanel/ExchangeServer/OrganizationHome.ascx.cs b/WebsitePanel/Sources/WebsitePanel.WebPortal/DesktopModules/WebsitePanel/ExchangeServer/OrganizationHome.ascx.cs index 481699f4..7d27a3e2 100644 --- a/WebsitePanel/Sources/WebsitePanel.WebPortal/DesktopModules/WebsitePanel/ExchangeServer/OrganizationHome.ascx.cs +++ b/WebsitePanel/Sources/WebsitePanel.WebPortal/DesktopModules/WebsitePanel/ExchangeServer/OrganizationHome.ascx.cs @@ -339,14 +339,14 @@ namespace WebsitePanel.Portal.ExchangeServer enterpriseStorageSpaceStats.QuotaUsedValue = stats.UsedEnterpriseStorageSpace; if (stats.AllocatedEnterpriseStorageSpace != -1) enterpriseStorageSpaceStats.QuotaAvailable = tenantStats.AllocatedEnterpriseStorageSpace - tenantStats.UsedEnterpriseStorageSpace; - lnkBESUsers.NavigateUrl = EditUrl("ItemID", PanelRequest.ItemID.ToString(), "enterprisestorage_folders", + lnkEnterpriseStorageSpace.NavigateUrl = EditUrl("ItemID", PanelRequest.ItemID.ToString(), "enterprisestorage_folders", "SpaceID=" + PanelSecurity.PackageId.ToString()); enterpriseStorageFoldersStats.QuotaValue = stats.AllocatedEnterpriseStorageFolders; enterpriseStorageFoldersStats.QuotaUsedValue = stats.CreatedEnterpriseStorageFolders; if (stats.AllocatedEnterpriseStorageFolders != -1) enterpriseStorageFoldersStats.QuotaAvailable = tenantStats.AllocatedEnterpriseStorageFolders - tenantStats.CreatedEnterpriseStorageFolders; - lnkBESUsers.NavigateUrl = EditUrl("ItemID", PanelRequest.ItemID.ToString(), "enterprisestorage_folders", + lnkEnterpriseStorageFolders.NavigateUrl = EditUrl("ItemID", PanelRequest.ItemID.ToString(), "enterprisestorage_folders", "SpaceID=" + PanelSecurity.PackageId.ToString()); } diff --git a/WebsitePanel/Sources/WebsitePanel.WebPortal/DesktopModules/WebsitePanel/SkinControls/TopMenu.ascx b/WebsitePanel/Sources/WebsitePanel.WebPortal/DesktopModules/WebsitePanel/SkinControls/TopMenu.ascx index 5c7b570b..96aebfa2 100644 --- a/WebsitePanel/Sources/WebsitePanel.WebPortal/DesktopModules/WebsitePanel/SkinControls/TopMenu.ascx +++ b/WebsitePanel/Sources/WebsitePanel.WebPortal/DesktopModules/WebsitePanel/SkinControls/TopMenu.ascx @@ -2,6 +2,6 @@ \ No newline at end of file diff --git a/WebsitePanel/Sources/WebsitePanel.WebPortal/DesktopModules/WebsitePanel/SkinControls/TopMenu.ascx.cs b/WebsitePanel/Sources/WebsitePanel.WebPortal/DesktopModules/WebsitePanel/SkinControls/TopMenu.ascx.cs index cf6542e8..d6c540cb 100644 --- a/WebsitePanel/Sources/WebsitePanel.WebPortal/DesktopModules/WebsitePanel/SkinControls/TopMenu.ascx.cs +++ b/WebsitePanel/Sources/WebsitePanel.WebPortal/DesktopModules/WebsitePanel/SkinControls/TopMenu.ascx.cs @@ -41,6 +41,19 @@ namespace WebsitePanel.Portal.SkinControls { public partial class TopMenu : System.Web.UI.UserControl { + public string Align + { + get + { + if (ViewState["Align"] == null) + { + return "top"; + } + return ViewState["Align"].ToString(); + } + set { ViewState["Align"] = value; } + } + protected void Page_Load(object sender, EventArgs e) { @@ -48,7 +61,15 @@ namespace WebsitePanel.Portal.SkinControls protected void topMenu_MenuItemDataBound(object sender, MenuEventArgs e) { - string target = ((SiteMapNode)e.Item.DataItem)["target"]; + var node = ((SiteMapNode)e.Item.DataItem); + + if (node["align"] == Align) + { + topMenu.Items.Remove(e.Item); + return; + } + + string target = node["target"]; if(!String.IsNullOrEmpty(target)) e.Item.Target = target; diff --git a/WebsitePanel/Sources/WebsitePanel.WebPortal/DesktopModules/WebsitePanel/SkinControls/TopMenu.ascx.designer.cs b/WebsitePanel/Sources/WebsitePanel.WebPortal/DesktopModules/WebsitePanel/SkinControls/TopMenu.ascx.designer.cs index b92c932e..e0659174 100644 --- a/WebsitePanel/Sources/WebsitePanel.WebPortal/DesktopModules/WebsitePanel/SkinControls/TopMenu.ascx.designer.cs +++ b/WebsitePanel/Sources/WebsitePanel.WebPortal/DesktopModules/WebsitePanel/SkinControls/TopMenu.ascx.designer.cs @@ -1,10 +1,37 @@ +// Copyright (c) 2012, Outercurve Foundation. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// - Redistributions of source code must retain the above copyright notice, this +// list of conditions and the following disclaimer. +// +// - Redistributions in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// +// - Neither the name of the Outercurve Foundation nor the names of its +// contributors may be used to endorse or promote products derived from this +// software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR +// ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +// ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + //------------------------------------------------------------------------------ // // This code was generated by a tool. -// Runtime Version:2.0.50727.3074 // // Changes to this file may cause incorrect behavior and will be lost if -// the code is regenerated. +// the code is regenerated. // //------------------------------------------------------------------------------ diff --git a/WebsitePanel/Sources/WebsitePanel.WebPortal/DesktopModules/WebsitePanel/SpaceMenu.ascx b/WebsitePanel/Sources/WebsitePanel.WebPortal/DesktopModules/WebsitePanel/SpaceMenu.ascx index fae4127d..60311a77 100644 --- a/WebsitePanel/Sources/WebsitePanel.WebPortal/DesktopModules/WebsitePanel/SpaceMenu.ascx +++ b/WebsitePanel/Sources/WebsitePanel.WebPortal/DesktopModules/WebsitePanel/SpaceMenu.ascx @@ -1,11 +1,9 @@ <%@ Control Language="C#" AutoEventWireup="true" CodeBehind="SpaceMenu.ascx.cs" Inherits="WebsitePanel.Portal.SpaceMenu" %> - - \ No newline at end of file + + + + + diff --git a/WebsitePanel/Sources/WebsitePanel.WebPortal/DesktopModules/WebsitePanel/SpaceMenu.ascx.cs b/WebsitePanel/Sources/WebsitePanel.WebPortal/DesktopModules/WebsitePanel/SpaceMenu.ascx.cs index ac690b70..dcd41537 100644 --- a/WebsitePanel/Sources/WebsitePanel.WebPortal/DesktopModules/WebsitePanel/SpaceMenu.ascx.cs +++ b/WebsitePanel/Sources/WebsitePanel.WebPortal/DesktopModules/WebsitePanel/SpaceMenu.ascx.cs @@ -53,7 +53,12 @@ namespace WebsitePanel.Portal cntx = PackagesHelper.GetCachedPackageContext(PanelSecurity.PackageId); // bind root node - BindMenu(menu.Items, PortalUtils.GetModuleMenuItems(this)); + MenuItem rootItem = new MenuItem(locMenuTitle.Text); + rootItem.Selectable = false; + + menu.Items.Add(rootItem); + + BindMenu(rootItem.ChildItems, PortalUtils.GetModuleMenuItems(this)); } private void BindMenu(MenuItemCollection items, XmlNodeList nodes) diff --git a/WebsitePanel/Sources/WebsitePanel.WebPortal/DesktopModules/WebsitePanel/SpaceMenu.ascx.designer.cs b/WebsitePanel/Sources/WebsitePanel.WebPortal/DesktopModules/WebsitePanel/SpaceMenu.ascx.designer.cs index fbf07849..2c9d7e10 100644 --- a/WebsitePanel/Sources/WebsitePanel.WebPortal/DesktopModules/WebsitePanel/SpaceMenu.ascx.designer.cs +++ b/WebsitePanel/Sources/WebsitePanel.WebPortal/DesktopModules/WebsitePanel/SpaceMenu.ascx.designer.cs @@ -1,17 +1,61 @@ +// Copyright (c) 2012, Outercurve Foundation. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// - Redistributions of source code must retain the above copyright notice, this +// list of conditions and the following disclaimer. +// +// - Redistributions in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// +// - Neither the name of the Outercurve Foundation nor the names of its +// contributors may be used to endorse or promote products derived from this +// software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR +// ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +// ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + //------------------------------------------------------------------------------ // // This code was generated by a tool. -// Runtime Version:2.0.50727.42 // // Changes to this file may cause incorrect behavior and will be lost if -// the code is regenerated. +// the code is regenerated. // //------------------------------------------------------------------------------ namespace WebsitePanel.Portal { + public partial class SpaceMenu { - protected System.Web.UI.WebControls.Localize locMenuTitle; - protected System.Web.UI.WebControls.Menu menu; + + /// + /// locMenuTitle control. + /// + /// + /// Auto-generated field. + /// To modify move field declaration from designer file to code-behind file. + /// + protected global::System.Web.UI.WebControls.Localize locMenuTitle; + + /// + /// menu control. + /// + /// + /// Auto-generated field. + /// To modify move field declaration from designer file to code-behind file. + /// + protected global::System.Web.UI.WebControls.Menu menu; } } diff --git a/WebsitePanel/Sources/WebsitePanel.WebPortal/DesktopModules/WebsitePanel/UserAccountMenu.ascx b/WebsitePanel/Sources/WebsitePanel.WebPortal/DesktopModules/WebsitePanel/UserAccountMenu.ascx index 611b51a7..d1c072d4 100644 --- a/WebsitePanel/Sources/WebsitePanel.WebPortal/DesktopModules/WebsitePanel/UserAccountMenu.ascx +++ b/WebsitePanel/Sources/WebsitePanel.WebPortal/DesktopModules/WebsitePanel/UserAccountMenu.ascx @@ -1,11 +1,9 @@ <%@ Control Language="C#" AutoEventWireup="true" CodeBehind="UserAccountMenu.ascx.cs" Inherits="WebsitePanel.Portal.UserAccountMenu" %> - - \ No newline at end of file + + + + + diff --git a/WebsitePanel/Sources/WebsitePanel.WebPortal/DesktopModules/WebsitePanel/UserAccountMenu.ascx.cs b/WebsitePanel/Sources/WebsitePanel.WebPortal/DesktopModules/WebsitePanel/UserAccountMenu.ascx.cs index 7652383e..41bba3ba 100644 --- a/WebsitePanel/Sources/WebsitePanel.WebPortal/DesktopModules/WebsitePanel/UserAccountMenu.ascx.cs +++ b/WebsitePanel/Sources/WebsitePanel.WebPortal/DesktopModules/WebsitePanel/UserAccountMenu.ascx.cs @@ -47,7 +47,12 @@ namespace WebsitePanel.Portal { protected void Page_Load(object sender, EventArgs e) { - BindMenu(menu.Items, PortalUtils.GetModuleMenuItems(this)); + MenuItem rootItem = new MenuItem(locMenuTitle.Text); + rootItem.Selectable = false; + + menu.Items.Add(rootItem); + + BindMenu(rootItem.ChildItems, PortalUtils.GetModuleMenuItems(this)); } private void BindMenu(MenuItemCollection items, XmlNodeList nodes)