diff --git a/WebsitePanel/Database/update_db.sql b/WebsitePanel/Database/update_db.sql
index 84df2fb6..31f110b4 100644
--- a/WebsitePanel/Database/update_db.sql
+++ b/WebsitePanel/Database/update_db.sql
@@ -432,4 +432,13 @@ GO
UPDATE Providers SET ProviderType = N'WebsitePanel.Providers.HostedSolution.CRMProvider2011, WebsitePanel.Providers.HostedSolution.CRM2011' WHERE ProviderID = 1201
+GO
+IF NOT EXISTS (SELECT * FROM [dbo].[Providers] WHERE [DisplayName] = 'Hosted SharePoint Foundation 2013')
+BEGIN
+INSERT [dbo].[Providers] ([ProviderID], [GroupID], [ProviderName], [DisplayName], [ProviderType], [EditorControl], [DisableAutoDiscovery])
+VALUES (1301, 20, N'HostedSharePoint2013', N'Hosted SharePoint Foundation 2013', N'WebsitePanel.Providers.HostedSolution.HostedSharePointServer2013, WebsitePanel.Providers.HostedSolution.SharePoint2013', N'HostedSharePoint30', NULL)
+END
+GO
+
+UPDATE Providers SET ProviderType = N'WebsitePanel.Providers.HostedSolution.HostedSharePointServer2013, WebsitePanel.Providers.HostedSolution.SharePoint2013' WHERE ProviderID = 1301
GO
\ No newline at end of file
diff --git a/WebsitePanel/Sources/WebsitePanel.Providers.HostedSolution.SharePoint2013/HostedSharePointServer2013.cs b/WebsitePanel/Sources/WebsitePanel.Providers.HostedSolution.SharePoint2013/HostedSharePointServer2013.cs
new file mode 100644
index 00000000..9244de46
--- /dev/null
+++ b/WebsitePanel/Sources/WebsitePanel.Providers.HostedSolution.SharePoint2013/HostedSharePointServer2013.cs
@@ -0,0 +1,327 @@
+// 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.IO;
+using Microsoft.Win32;
+using WebsitePanel.Providers.SharePoint;
+using WebsitePanel.Providers.Utils;
+using WebsitePanel.Server.Utils;
+
+namespace WebsitePanel.Providers.HostedSolution
+{
+ ///
+ /// Provides hosted SharePoint server functionality implementation.
+ ///
+ public class HostedSharePointServer2013 : HostingServiceProviderBase, IHostedSharePointServer
+ {
+ #region Delegate
+
+ private delegate TReturn SharePointAction(HostedSharePointServer2013Impl impl);
+
+ #endregion
+
+ #region Fields
+
+ protected string LanguagePacksPath;
+ protected string Wss3Registry32Key;
+ protected string Wss3RegistryKey;
+
+ #endregion
+
+ #region Properties
+
+ public string BackupTemporaryFolder
+ {
+ get { return ProviderSettings["BackupTemporaryFolder"]; }
+ }
+
+ public Uri RootWebApplicationUri
+ {
+ get { return new Uri(ProviderSettings["RootWebApplicationUri"]); }
+ }
+
+ #endregion
+
+ #region Constructor
+
+ public HostedSharePointServer2013()
+ {
+ Wss3RegistryKey = @"SOFTWARE\Microsoft\Shared Tools\Web Server Extensions\15.0";
+ Wss3Registry32Key = @"SOFTWARE\Wow6432Node\Microsoft\Shared Tools\Web Server Extensions\15.0";
+ LanguagePacksPath = @"%commonprogramfiles%\microsoft shared\Web Server Extensions\15\HCCab\";
+ }
+
+ #endregion
+
+ #region Methods
+
+ /// Gets list of supported languages by this installation of SharePoint.
+ /// List of supported languages
+ public int[] GetSupportedLanguages()
+ {
+ var impl = new HostedSharePointServer2013Impl();
+ return impl.GetSupportedLanguages(RootWebApplicationUri);
+ }
+
+ /// Gets list of SharePoint collections within root web application.
+ /// List of SharePoint collections within root web application.
+ public SharePointSiteCollection[] GetSiteCollections()
+ {
+ return ExecuteSharePointAction(impl => impl.GetSiteCollections(RootWebApplicationUri));
+ }
+
+ /// Gets SharePoint collection within root web application with given name.
+ /// Url that uniquely identifies site collection to be loaded.
+ /// SharePoint collection within root web application with given name.
+ public SharePointSiteCollection GetSiteCollection(string url)
+ {
+ return ExecuteSharePointAction(impl => impl.GetSiteCollection(RootWebApplicationUri, url));
+ }
+
+ /// Creates site collection within predefined root web application.
+ /// Information about site coolection to be created.
+ public void CreateSiteCollection(SharePointSiteCollection siteCollection)
+ {
+ ExecuteSharePointAction(delegate(HostedSharePointServer2013Impl impl)
+ {
+ impl.CreateSiteCollection(RootWebApplicationUri, siteCollection);
+ return null;
+ });
+ }
+
+ /// Deletes site collection under given url.
+ /// The site collection to be deleted.
+ public void DeleteSiteCollection(SharePointSiteCollection siteCollection)
+ {
+ ExecuteSharePointAction(delegate(HostedSharePointServer2013Impl impl)
+ {
+ impl.DeleteSiteCollection(RootWebApplicationUri, siteCollection);
+ return null;
+ });
+ }
+
+ /// Backups site collection under give url.
+ /// Url that uniquely identifies site collection to be deleted.
+ /// Resulting backup file name.
+ /// A value which shows whether created backup must be archived.
+ /// Created backup full path.
+ public string BackupSiteCollection(string url, string filename, bool zip)
+ {
+ return ExecuteSharePointAction(impl => impl.BackupSiteCollection(RootWebApplicationUri, url, filename, zip, BackupTemporaryFolder));
+ }
+
+ /// Restores site collection under given url from backup.
+ /// Site collection to be restored.
+ /// Backup file name to restore from.
+ public void RestoreSiteCollection(SharePointSiteCollection siteCollection, string filename)
+ {
+ ExecuteSharePointAction(delegate(HostedSharePointServer2013Impl impl)
+ {
+ impl.RestoreSiteCollection(RootWebApplicationUri, siteCollection, filename);
+ return null;
+ });
+ }
+
+ /// Gets binary data chunk of specified size from specified offset.
+ /// Path to file to get bunary data chunk from.
+ /// Offset from which to start data reading.
+ /// Binary data chunk length.
+ /// Binary data chunk read from file.
+ public virtual byte[] GetTempFileBinaryChunk(string path, int offset, int length)
+ {
+ byte[] buffer = FileUtils.GetFileBinaryChunk(path, offset, length);
+
+ if (buffer.Length < length)
+ {
+ FileUtils.DeleteFile(path);
+ }
+
+ return buffer;
+ }
+
+ /// Appends supplied binary data chunk to file.
+ /// Non existent file name to append to.
+ /// Full path to existent file to append to.
+ /// Binary data chunk to append to.
+ /// Path to file that was appended with chunk.
+ public virtual string AppendTempFileBinaryChunk(string fileName, string path, byte[] chunk)
+ {
+ if (path == null)
+ {
+ path = Path.Combine(Path.GetTempPath(), fileName);
+ if (FileUtils.FileExists(path))
+ {
+ FileUtils.DeleteFile(path);
+ }
+ }
+
+ FileUtils.AppendFileBinaryContent(path, chunk);
+
+ return path;
+ }
+
+ public void UpdateQuotas(string url, long maxStorage, long warningStorage)
+ {
+ ExecuteSharePointAction(delegate(HostedSharePointServer2013Impl impl)
+ {
+ impl.UpdateQuotas(RootWebApplicationUri, url, maxStorage, warningStorage);
+ return null;
+ });
+ }
+
+ public SharePointSiteDiskSpace[] CalculateSiteCollectionsDiskSpace(string[] urls)
+ {
+ return ExecuteSharePointAction(impl => impl.CalculateSiteCollectionDiskSpace(RootWebApplicationUri, urls));
+ }
+
+ public long GetSiteCollectionSize(string url)
+ {
+ return ExecuteSharePointAction(impl => impl.GetSiteCollectionSize(RootWebApplicationUri, url));
+ }
+
+ public void SetPeoplePickerOu(string site, string ou)
+ {
+ ExecuteSharePointAction(delegate(HostedSharePointServer2013Impl impl)
+ {
+ impl.SetPeoplePickerOu(site, ou);
+ return null;
+ });
+ }
+
+
+ public override bool IsInstalled()
+ {
+ return IsSharePointInstalled();
+ }
+
+ /// Deletes service items that represent SharePoint site collection.
+ /// Items to be deleted.
+ public override void DeleteServiceItems(ServiceProviderItem[] items)
+ {
+ foreach (ServiceProviderItem item in items)
+ {
+ var sharePointSiteCollection = item as SharePointSiteCollection;
+
+ if (sharePointSiteCollection != null)
+ {
+ try
+ {
+ DeleteSiteCollection(sharePointSiteCollection);
+ }
+ catch (Exception ex)
+ {
+ Log.WriteError(String.Format("Error deleting '{0}' {1}", item.Name, item.GetType().Name), ex);
+ }
+ }
+ }
+ }
+
+ /// Calculates diskspace used by supplied service items.
+ /// Service items to get diskspace usage for.
+ /// Calculated disk space usage statistics.
+ public override ServiceProviderItemDiskSpace[] GetServiceItemsDiskSpace(ServiceProviderItem[] items)
+ {
+ var itemsDiskspace = new List();
+
+ foreach (ServiceProviderItem item in items)
+ {
+ if (item is SharePointSiteCollection)
+ {
+ try
+ {
+ Log.WriteStart(String.Format("Calculating '{0}' site logs size", item.Name));
+
+ SharePointSiteCollection site = GetSiteCollection(item.Name);
+ var diskspace = new ServiceProviderItemDiskSpace {ItemId = item.Id, DiskSpace = site.Diskspace};
+ itemsDiskspace.Add(diskspace);
+
+ Log.WriteEnd(String.Format("Calculating '{0}' site logs size", item.Name));
+ }
+ catch (Exception ex)
+ {
+ Log.WriteError(ex);
+ }
+ }
+ }
+
+ return itemsDiskspace.ToArray();
+ }
+
+ /// Checks whether SharePoint 2013 is installed.
+ /// true - if it is installed; false - otherwise.
+ private bool IsSharePointInstalled()
+ {
+ RegistryKey spKey = Registry.LocalMachine.OpenSubKey(Wss3RegistryKey);
+ RegistryKey spKey32 = Registry.LocalMachine.OpenSubKey(Wss3Registry32Key);
+
+ if (spKey == null && spKey32 == null)
+ {
+ return false;
+ }
+
+ var spVal = (string) spKey.GetValue("SharePoint");
+
+ return (String.Compare(spVal, "installed", true) == 0);
+ }
+
+ /// Executes supplied action within separate application domain.
+ /// Action to be executed.
+ /// Any object that results from action execution or null if nothing is supposed to be returned.
+ /// Is thrown in case supplied action is null.
+ private static TReturn ExecuteSharePointAction(SharePointAction action)
+ {
+ if (action == null)
+ {
+ throw new ArgumentNullException("action");
+ }
+
+ AppDomain domain = null;
+
+ try
+ {
+ Type type = typeof (HostedSharePointServer2013Impl);
+ var info = new AppDomainSetup {ApplicationBase = Path.GetDirectoryName(AppDomain.CurrentDomain.BaseDirectory), PrivateBinPath = "bin; bin/debug"};
+ domain = AppDomain.CreateDomain("WSS30", null, info);
+ var impl = (HostedSharePointServer2013Impl) domain.CreateInstanceAndUnwrap(type.Assembly.FullName, type.FullName);
+
+ return action(impl);
+ }
+ finally
+ {
+ if (domain != null)
+ {
+ AppDomain.Unload(domain);
+ }
+ }
+ }
+
+ #endregion
+ }
+}
\ No newline at end of file
diff --git a/WebsitePanel/Sources/WebsitePanel.Providers.HostedSolution.SharePoint2013/HostedSharePointServer2013Impl.cs b/WebsitePanel/Sources/WebsitePanel.Providers.HostedSolution.SharePoint2013/HostedSharePointServer2013Impl.cs
new file mode 100644
index 00000000..46a3a065
--- /dev/null
+++ b/WebsitePanel/Sources/WebsitePanel.Providers.HostedSolution.SharePoint2013/HostedSharePointServer2013Impl.cs
@@ -0,0 +1,851 @@
+// 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.Collections.ObjectModel;
+using System.IO;
+using System.Linq;
+using System.Management.Automation;
+using System.Management.Automation.Runspaces;
+using System.Security.Principal;
+using Microsoft.SharePoint;
+using Microsoft.SharePoint.Administration;
+using WebsitePanel.Providers.SharePoint;
+using WebsitePanel.Providers.Utils;
+
+namespace WebsitePanel.Providers.HostedSolution
+{
+ public class HostedSharePointServer2013Impl : MarshalByRefObject
+ {
+ #region Fields
+
+ private static RunspaceConfiguration runspaceConfiguration;
+
+ #endregion
+
+ #region Properties
+
+ private string SharepointSnapInName
+ {
+ get { return "Microsoft.SharePoint.Powershell"; }
+ }
+
+ #endregion
+
+ #region Methods
+
+ /// Gets list of SharePoint collections within root web application.
+ /// The root web application Uri.
+ /// List of SharePoint collections within root web application.
+ public SharePointSiteCollection[] GetSiteCollections(Uri rootWebApplicationUri)
+ {
+ return GetSPSiteCollections(rootWebApplicationUri).Select(pair => NewSiteCollection(pair.Value)).ToArray();
+ }
+
+ /// Gets list of supported languages by this installation of SharePoint.
+ /// The root web application Uri.
+ /// List of supported languages
+ public int[] GetSupportedLanguages(Uri rootWebApplicationUri)
+ {
+ var languages = new List();
+
+ try
+ {
+ WindowsImpersonationContext wic = WindowsIdentity.GetCurrent().Impersonate();
+
+ try
+ {
+ languages.AddRange(from SPLanguage lang in SPRegionalSettings.GlobalInstalledLanguages select lang.LCID);
+ }
+ finally
+ {
+ wic.Undo();
+ }
+ }
+ catch (Exception ex)
+ {
+ throw new InvalidOperationException("Failed to create site collection.", ex);
+ }
+
+ return languages.ToArray();
+ }
+
+ /// Gets site collection size in bytes.
+ /// The root web application uri.
+ /// The site collection url.
+ /// Size in bytes.
+ public long GetSiteCollectionSize(Uri rootWebApplicationUri, string url)
+ {
+ Dictionary sizes = GetSitesCollectionSize(rootWebApplicationUri, new[] {url});
+
+ if (sizes.Count() == 1)
+ {
+ return sizes.First().Value;
+ }
+
+ throw new ApplicationException(string.Format("SiteCollection {0} does not exist", url));
+ }
+
+ /// Gets sites disk space.
+ /// The root web application uri.
+ /// The sites urls.
+ /// The disk space.
+ public SharePointSiteDiskSpace[] CalculateSiteCollectionDiskSpace(Uri rootWebApplicationUri, string[] urls)
+ {
+ return GetSitesCollectionSize(rootWebApplicationUri, urls).Select(pair => new SharePointSiteDiskSpace {Url = pair.Key, DiskSpace = (long) Math.Round(pair.Value/1024.0/1024.0)}).ToArray();
+ }
+
+ /// Calculates size of the required seti collections.
+ /// The root web application uri.
+ /// The sites urls.
+ /// Calculated sizes.
+ private Dictionary GetSitesCollectionSize(Uri rootWebApplicationUri, IEnumerable urls)
+ {
+ Runspace runspace = null;
+ var result = new Dictionary();
+
+ try
+ {
+ runspace = OpenRunspace();
+
+ foreach (string url in urls)
+ {
+ string siteCollectionUrl = String.Format("{0}:{1}", url, rootWebApplicationUri.Port);
+ var scripts = new List {string.Format("$site=Get-SPSite -Identity \"{0}\"", siteCollectionUrl), "$site.RecalculateStorageUsed()", "$site.Usage.Storage"};
+ Collection scriptResult = ExecuteShellCommand(runspace, scripts);
+
+ if (scriptResult != null && scriptResult.Any())
+ {
+ result.Add(url, Convert.ToInt64(scriptResult.First().BaseObject));
+ }
+ }
+ }
+ finally
+ {
+ CloseRunspace(runspace);
+ }
+
+ return result;
+ }
+
+ /// Sets people picker OU.
+ /// The site.
+ /// OU.
+ public void SetPeoplePickerOu(string site, string ou)
+ {
+ HostedSolutionLog.LogStart("SetPeoplePickerOu");
+ HostedSolutionLog.LogInfo(" Site: {0}", site);
+ HostedSolutionLog.LogInfo(" OU: {0}", ou);
+
+ Runspace runspace = null;
+
+ try
+ {
+ runspace = OpenRunspace();
+ var cmd = new Command("Set-SPSite");
+ cmd.Parameters.Add("Identity", site);
+ cmd.Parameters.Add("UserAccountDirectoryPath", ou);
+ ExecuteShellCommand(runspace, cmd);
+ }
+ finally
+ {
+ CloseRunspace(runspace);
+ }
+
+ HostedSolutionLog.LogEnd("SetPeoplePickerOu");
+ }
+
+ /// Gets SharePoint collection within root web application with given name.
+ /// Root web application uri.
+ /// Url that uniquely identifies site collection to be loaded.
+ /// SharePoint collection within root web application with given name.
+ public SharePointSiteCollection GetSiteCollection(Uri rootWebApplicationUri, string url)
+ {
+ return NewSiteCollection(GetSPSiteCollection(rootWebApplicationUri, url));
+ }
+
+ /// Deletes quota.
+ /// The quota name.
+ private static void DeleteQuotaTemplate(string name)
+ {
+ SPFarm farm = SPFarm.Local;
+
+ var webService = farm.Services.GetValue("");
+ SPQuotaTemplateCollection quotaColl = webService.QuotaTemplates;
+ quotaColl.Delete(name);
+ }
+
+ /// Updates site collection quota.
+ /// The root uri.
+ /// The site collection url.
+ /// The max storage.
+ /// The warning storage value.
+ public void UpdateQuotas(Uri root, string url, long maxStorage, long warningStorage)
+ {
+ if (maxStorage != -1)
+ {
+ maxStorage = maxStorage*1024*1024;
+ }
+ else
+ {
+ maxStorage = 0;
+ }
+
+ if (warningStorage != -1 && maxStorage != -1)
+ {
+ warningStorage = Math.Min(warningStorage, maxStorage)*1024*1024;
+ }
+ else
+ {
+ warningStorage = 0;
+ }
+
+ Runspace runspace = null;
+
+ try
+ {
+ runspace = OpenRunspace();
+ GrantAccess(runspace, root);
+ string siteCollectionUrl = String.Format("{0}:{1}", url, root.Port);
+ var command = new Command("Set-SPSite");
+ command.Parameters.Add("Identity", siteCollectionUrl);
+ command.Parameters.Add("MaxSize", maxStorage);
+ command.Parameters.Add("WarningSize", warningStorage);
+ ExecuteShellCommand(runspace, command);
+ }
+ finally
+ {
+ CloseRunspace(runspace);
+ }
+ }
+
+ /// Grants acces to current user.
+ /// The runspace.
+ /// The root web application uri.
+ private void GrantAccess(Runspace runspace, Uri rootWebApplicationUri)
+ {
+ ExecuteShellCommand(runspace, new List {string.Format("$webApp=Get-SPWebApplication {0}", rootWebApplicationUri.AbsoluteUri), string.Format("$webApp.GrantAccessToProcessIdentity(\"{0}\")", WindowsIdentity.GetCurrent().Name)});
+ }
+
+ /// Deletes site collection.
+ /// The runspace.
+ /// The site collection url.
+ /// True - if active directory accounts should be deleted.
+ private void DeleteSiteCollection(Runspace runspace, string url, bool deleteADAccounts)
+ {
+ var command = new Command("Remove-SPSite");
+ command.Parameters.Add("Identity", url);
+ command.Parameters.Add("DeleteADAccounts", deleteADAccounts);
+ ExecuteShellCommand(runspace, command);
+ }
+
+ /// Creates site collection within predefined root web application.
+ /// Root web application uri.
+ /// Information about site coolection to be created.
+ /// Is thrown in case requested operation fails for any reason.
+ public void CreateSiteCollection(Uri rootWebApplicationUri, SharePointSiteCollection siteCollection)
+ {
+ HostedSolutionLog.LogStart("CreateSiteCollection");
+ WindowsImpersonationContext wic = null;
+ Runspace runspace = null;
+
+ try
+ {
+ wic = WindowsIdentity.GetCurrent().Impersonate();
+ runspace = OpenRunspace();
+ CreateCollection(runspace, rootWebApplicationUri, siteCollection);
+ }
+ finally
+ {
+ CloseRunspace(runspace);
+ HostedSolutionLog.LogEnd("CreateSiteCollection");
+
+ if (wic != null)
+ {
+ wic.Undo();
+ }
+ }
+ }
+
+ /// Creates site collection within predefined root web application.
+ /// The runspace.
+ /// Root web application uri.
+ /// Information about site coolection to be created.
+ /// Is thrown in case requested operation fails for any reason.
+ private void CreateCollection(Runspace runspace, Uri rootWebApplicationUri, SharePointSiteCollection siteCollection)
+ {
+ string siteCollectionUrl = String.Format("{0}:{1}", siteCollection.Url, rootWebApplicationUri.Port);
+ HostedSolutionLog.DebugInfo("siteCollectionUrl: {0}", siteCollectionUrl);
+
+ try
+ {
+ SPWebApplication rootWebApplication = SPWebApplication.Lookup(rootWebApplicationUri);
+ rootWebApplication.Sites.Add(siteCollectionUrl, siteCollection.Title, siteCollection.Description, (uint) siteCollection.LocaleId, String.Empty, siteCollection.OwnerLogin, siteCollection.OwnerName, siteCollection.OwnerEmail, null, null, null, true);
+ rootWebApplication.Update();
+ }
+ catch (Exception)
+ {
+ DeleteSiteCollection(runspace, siteCollectionUrl, true);
+ throw;
+ }
+
+ try
+ {
+ GrantAccess(runspace, rootWebApplicationUri);
+ var command = new Command("Set-SPSite");
+ command.Parameters.Add("Identity", siteCollectionUrl);
+
+ if (siteCollection.MaxSiteStorage != -1)
+ {
+ command.Parameters.Add("MaxSize", siteCollection.MaxSiteStorage*1024*1024);
+ }
+
+ if (siteCollection.WarningStorage != -1 && siteCollection.MaxSiteStorage != -1)
+ {
+ command.Parameters.Add("WarningSize", Math.Min(siteCollection.WarningStorage, siteCollection.MaxSiteStorage)*1024*1024);
+ }
+
+ ExecuteShellCommand(runspace, command);
+ }
+ catch (Exception)
+ {
+ DeleteQuotaTemplate(siteCollection.Title);
+ DeleteSiteCollection(runspace, siteCollectionUrl, true);
+ throw;
+ }
+
+ AddHostsRecord(siteCollection);
+ }
+
+ /// Deletes site collection under given url.
+ /// Root web application uri.
+ /// The site collection to be deleted.
+ /// Is thrown in case requested operation fails for any reason.
+ public void DeleteSiteCollection(Uri rootWebApplicationUri, SharePointSiteCollection siteCollection)
+ {
+ HostedSolutionLog.LogStart("DeleteSiteCollection");
+ Runspace runspace = null;
+
+ try
+ {
+ string siteCollectionUrl = String.Format("{0}:{1}", siteCollection.Url, rootWebApplicationUri.Port);
+ HostedSolutionLog.DebugInfo("siteCollectionUrl: {0}", siteCollectionUrl);
+ runspace = OpenRunspace();
+ DeleteSiteCollection(runspace, siteCollectionUrl, false);
+ RemoveHostsRecord(siteCollection);
+ }
+ catch (Exception ex)
+ {
+ throw new InvalidOperationException("Failed to delete site collection.", ex);
+ }
+ finally
+ {
+ CloseRunspace(runspace);
+ HostedSolutionLog.LogEnd("DeleteSiteCollection");
+ }
+ }
+
+ /// Backups site collection under give url.
+ /// Root web application uri.
+ /// Url that uniquely identifies site collection to be deleted.
+ /// Resulting backup file name.
+ /// A value which shows whether created backup must be archived.
+ /// Custom temp path for backup
+ /// Full path to created backup.
+ /// Is thrown in case requested operation fails for any reason.
+ public string BackupSiteCollection(Uri rootWebApplicationUri, string url, string filename, bool zip, string tempPath)
+ {
+ try
+ {
+ string siteCollectionUrl = String.Format("{0}:{1}", url, rootWebApplicationUri.Port);
+ HostedSolutionLog.LogStart("BackupSiteCollection");
+ HostedSolutionLog.DebugInfo("siteCollectionUrl: {0}", siteCollectionUrl);
+
+ if (String.IsNullOrEmpty(tempPath))
+ {
+ tempPath = Path.GetTempPath();
+ }
+
+ string backupFileName = Path.Combine(tempPath, (zip ? StringUtils.CleanIdentifier(siteCollectionUrl) + ".bsh" : StringUtils.CleanIdentifier(filename)));
+ HostedSolutionLog.DebugInfo("backupFilePath: {0}", backupFileName);
+ Runspace runspace = null;
+
+ try
+ {
+ runspace = OpenRunspace();
+ var command = new Command("Backup-SPSite");
+ command.Parameters.Add("Identity", siteCollectionUrl);
+ command.Parameters.Add("Path", backupFileName);
+ ExecuteShellCommand(runspace, command);
+
+ if (zip)
+ {
+ string zipFile = Path.Combine(tempPath, filename);
+ string zipRoot = Path.GetDirectoryName(backupFileName);
+
+ FileUtils.ZipFiles(zipFile, zipRoot, new[] {Path.GetFileName(backupFileName)});
+ FileUtils.DeleteFile(backupFileName);
+
+ backupFileName = zipFile;
+ }
+
+ return backupFileName;
+ }
+ finally
+ {
+ CloseRunspace(runspace);
+ HostedSolutionLog.LogEnd("BackupSiteCollection");
+ }
+ }
+ catch (Exception ex)
+ {
+ throw new InvalidOperationException("Failed to backup site collection.", ex);
+ }
+ }
+
+ /// Restores site collection under given url from backup.
+ /// Root web application uri.
+ /// Site collection to be restored.
+ /// Backup file name to restore from.
+ /// Is thrown in case requested operation fails for any reason.
+ public void RestoreSiteCollection(Uri rootWebApplicationUri, SharePointSiteCollection siteCollection, string filename)
+ {
+ string url = siteCollection.Url;
+
+ try
+ {
+ string siteCollectionUrl = String.Format("{0}:{1}", url, rootWebApplicationUri.Port);
+ HostedSolutionLog.LogStart("RestoreSiteCollection");
+ HostedSolutionLog.DebugInfo("siteCollectionUrl: {0}", siteCollectionUrl);
+
+ HostedSolutionLog.DebugInfo("backupFilePath: {0}", filename);
+ Runspace runspace = null;
+
+ try
+ {
+ string tempPath = Path.GetTempPath();
+ string expandedFile = filename;
+
+ if (Path.GetExtension(filename).ToLower() == ".zip")
+ {
+ expandedFile = FileUtils.UnzipFiles(filename, tempPath)[0];
+
+ // Delete zip archive.
+ FileUtils.DeleteFile(filename);
+ }
+
+ runspace = OpenRunspace();
+ DeleteSiteCollection(runspace, siteCollectionUrl, false);
+ var command = new Command("Restore-SPSite");
+ command.Parameters.Add("Identity", siteCollectionUrl);
+ command.Parameters.Add("Path", filename);
+ ExecuteShellCommand(runspace, command);
+
+ command = new Command("Set-SPSite");
+ command.Parameters.Add("Identity", siteCollectionUrl);
+ command.Parameters.Add("OwnerAlias", siteCollection.OwnerLogin);
+ ExecuteShellCommand(runspace, command);
+
+ command = new Command("Set-SPUser");
+ command.Parameters.Add("Identity", siteCollection.OwnerLogin);
+ command.Parameters.Add("Email", siteCollection.OwnerEmail);
+ command.Parameters.Add("DisplayName", siteCollection.Name);
+ ExecuteShellCommand(runspace, command);
+
+ FileUtils.DeleteFile(expandedFile);
+ }
+ finally
+ {
+ CloseRunspace(runspace);
+ HostedSolutionLog.LogEnd("RestoreSiteCollection");
+ }
+ }
+ catch (Exception ex)
+ {
+ throw new InvalidOperationException("Failed to restore site collection.", ex);
+ }
+ }
+
+ /// Creates new site collection with information from administration object.
+ /// Administration object.
+ private static SharePointSiteCollection NewSiteCollection(SPSite site)
+ {
+ var siteUri = new Uri(site.Url);
+ string url = (siteUri.Port > 0) ? site.Url.Replace(String.Format(":{0}", siteUri.Port), String.Empty) : site.Url;
+
+ return new SharePointSiteCollection {Url = url, OwnerLogin = site.Owner.LoginName, OwnerName = site.Owner.Name, OwnerEmail = site.Owner.Email, LocaleId = site.RootWeb.Locale.LCID, Title = site.RootWeb.Title, Description = site.RootWeb.Description, Bandwidth = site.Usage.Bandwidth, Diskspace = site.Usage.Storage, MaxSiteStorage = site.Quota.StorageMaximumLevel, WarningStorage = site.Quota.StorageWarningLevel};
+ }
+
+ /// Gets SharePoint sites collection.
+ /// The root web application uri.
+ /// The SharePoint sites.
+ private Dictionary GetSPSiteCollections(Uri rootWebApplicationUri)
+ {
+ Runspace runspace = null;
+ var collections = new Dictionary();
+
+ try
+ {
+ runspace = OpenRunspace();
+ var cmd = new Command("Get-SPSite");
+ cmd.Parameters.Add("WebApplication", rootWebApplicationUri.AbsoluteUri);
+ Collection result = ExecuteShellCommand(runspace, cmd);
+
+ if (result != null)
+ {
+ foreach (PSObject psObject in result)
+ {
+ var spSite = psObject.BaseObject as SPSite;
+
+ if (spSite != null)
+ {
+ collections.Add(spSite.Url, spSite);
+ }
+ }
+ }
+ }
+ finally
+ {
+ CloseRunspace(runspace);
+ }
+
+ return collections;
+ }
+
+ /// Gets SharePoint site collection.
+ /// The root web application uri.
+ /// The required site url.
+ /// The SharePoint sites.
+ private SPSite GetSPSiteCollection(Uri rootWebApplicationUri, string url)
+ {
+ Runspace runspace = null;
+
+ try
+ {
+ string siteCollectionUrl = String.Format("{0}:{1}", url, rootWebApplicationUri.Port);
+ runspace = OpenRunspace();
+ var cmd = new Command("Get-SPSite");
+ cmd.Parameters.Add("Identity", siteCollectionUrl);
+ Collection result = ExecuteShellCommand(runspace, cmd);
+
+ if (result != null && result.Count() == 1)
+ {
+ var spSite = result.First().BaseObject as SPSite;
+
+ if (spSite == null)
+ {
+ throw new ApplicationException(string.Format("SiteCollection {0} does not exist", url));
+ }
+
+ return result.First().BaseObject as SPSite;
+ }
+ else
+ {
+ throw new ApplicationException(string.Format("SiteCollection {0} does not exist", url));
+ }
+ }
+ catch (Exception ex)
+ {
+ HostedSolutionLog.LogError(ex);
+ throw;
+ }
+ finally
+ {
+ CloseRunspace(runspace);
+ }
+ }
+
+ /// Opens PowerShell runspace.
+ /// The runspace.
+ private Runspace OpenRunspace()
+ {
+ HostedSolutionLog.LogStart("OpenRunspace");
+
+ if (runspaceConfiguration == null)
+ {
+ runspaceConfiguration = RunspaceConfiguration.Create();
+ PSSnapInException exception;
+ runspaceConfiguration.AddPSSnapIn(SharepointSnapInName, out exception);
+ HostedSolutionLog.LogInfo("Sharepoint snapin loaded");
+
+ if (exception != null)
+ {
+ HostedSolutionLog.LogWarning("SnapIn error", exception);
+ }
+ }
+
+ Runspace runspace = RunspaceFactory.CreateRunspace(runspaceConfiguration);
+ runspace.Open();
+ runspace.SessionStateProxy.SetVariable("ConfirmPreference", "none");
+ HostedSolutionLog.LogEnd("OpenRunspace");
+
+ return runspace;
+ }
+
+ /// Closes runspace.
+ /// The runspace.
+ private void CloseRunspace(Runspace runspace)
+ {
+ try
+ {
+ if (runspace != null && runspace.RunspaceStateInfo.State == RunspaceState.Opened)
+ {
+ runspace.Close();
+ }
+ }
+ catch (Exception ex)
+ {
+ HostedSolutionLog.LogError("Runspace error", ex);
+ }
+ }
+
+ /// Executes shell command.
+ /// The runspace.
+ /// The command to be executed.
+ /// PSobjecs collection.
+ private Collection ExecuteShellCommand(Runspace runspace, object cmd)
+ {
+ object[] errors;
+ var command = cmd as Command;
+
+ if (command != null)
+ {
+ return ExecuteShellCommand(runspace, command, out errors);
+ }
+
+ return ExecuteShellCommand(runspace, cmd as List, out errors);
+ }
+
+ /// Executes shell command.
+ /// The runspace.
+ /// The command to be executed.
+ /// The errors.
+ /// PSobjecs collection.
+ private Collection ExecuteShellCommand(Runspace runspace, Command cmd, out object[] errors)
+ {
+ HostedSolutionLog.LogStart("ExecuteShellCommand");
+ var errorList = new List();
+ Collection results;
+
+ using (Pipeline pipeLine = runspace.CreatePipeline())
+ {
+ pipeLine.Commands.Add(cmd);
+ results = pipeLine.Invoke();
+
+ if (pipeLine.Error != null && pipeLine.Error.Count > 0)
+ {
+ foreach (object item in pipeLine.Error.ReadToEnd())
+ {
+ errorList.Add(item);
+ string errorMessage = string.Format("Invoke error: {0}", item);
+ HostedSolutionLog.LogWarning(errorMessage);
+ }
+ }
+ }
+
+ errors = errorList.ToArray();
+ HostedSolutionLog.LogEnd("ExecuteShellCommand");
+
+ return results;
+ }
+
+ /// Executes shell command.
+ /// The runspace.
+ /// The scripts to be executed.
+ /// The errors.
+ /// PSobjecs collection.
+ private Collection ExecuteShellCommand(Runspace runspace, List scripts, out object[] errors)
+ {
+ HostedSolutionLog.LogStart("ExecuteShellCommand");
+ var errorList = new List();
+ Collection results;
+
+ using (Pipeline pipeLine = runspace.CreatePipeline())
+ {
+ foreach (string script in scripts)
+ {
+ pipeLine.Commands.AddScript(script);
+ }
+
+ results = pipeLine.Invoke();
+
+ if (pipeLine.Error != null && pipeLine.Error.Count > 0)
+ {
+ foreach (object item in pipeLine.Error.ReadToEnd())
+ {
+ errorList.Add(item);
+ string errorMessage = string.Format("Invoke error: {0}", item);
+ HostedSolutionLog.LogWarning(errorMessage);
+
+ throw new ArgumentException(scripts.First());
+ }
+ }
+ }
+
+ errors = errorList.ToArray();
+ HostedSolutionLog.LogEnd("ExecuteShellCommand");
+
+ return results;
+ }
+
+ /// Adds record to hosts file.
+ /// The site collection object.
+ public void AddHostsRecord(SharePointSiteCollection siteCollection)
+ {
+ try
+ {
+ if (siteCollection.RootWebApplicationInteralIpAddress != string.Empty)
+ {
+ string dirPath = FileUtils.EvaluateSystemVariables(@"%windir%\system32\drivers\etc");
+ string path = dirPath + "\\hosts";
+
+ if (FileUtils.FileExists(path))
+ {
+ string content = FileUtils.GetFileTextContent(path);
+ content = content.Replace("\r\n", "\n").Replace("\n\r", "\n");
+ string[] contentArr = content.Split(new[] {'\n'});
+ bool bRecordExist = false;
+
+ foreach (string s in contentArr)
+ {
+ if (s != string.Empty)
+ {
+ string hostName = string.Empty;
+
+ if (s[0] != '#')
+ {
+ bool bSeperator = false;
+
+ foreach (char c in s)
+ {
+ if ((c != ' ') & (c != '\t'))
+ {
+ if (bSeperator)
+ {
+ hostName += c;
+ }
+ }
+ else
+ {
+ bSeperator = true;
+ }
+ }
+
+ if (hostName.ToLower() == siteCollection.RootWebApplicationFQDN.ToLower())
+ {
+ bRecordExist = true;
+ break;
+ }
+ }
+ }
+ }
+
+ if (!bRecordExist)
+ {
+ string outPut = contentArr.Where(o => o != string.Empty).Aggregate(string.Empty, (current, o) => current + (o + "\r\n"));
+ outPut += siteCollection.RootWebApplicationInteralIpAddress + '\t' + siteCollection.RootWebApplicationFQDN + "\r\n";
+ FileUtils.UpdateFileTextContent(path, outPut);
+ }
+ }
+ }
+ }
+ catch (Exception ex)
+ {
+ HostedSolutionLog.LogError(ex);
+ }
+ }
+
+ /// Removes record from hosts file.
+ /// The site collection object.
+ private void RemoveHostsRecord(SharePointSiteCollection siteCollection)
+ {
+ try
+ {
+ if (siteCollection.RootWebApplicationInteralIpAddress != string.Empty)
+ {
+ string dirPath = FileUtils.EvaluateSystemVariables(@"%windir%\system32\drivers\etc");
+ string path = dirPath + "\\hosts";
+
+ if (FileUtils.FileExists(path))
+ {
+ string content = FileUtils.GetFileTextContent(path);
+ content = content.Replace("\r\n", "\n").Replace("\n\r", "\n");
+ string[] contentArr = content.Split(new[] {'\n'});
+ string outPut = string.Empty;
+
+ foreach (string s in contentArr)
+ {
+ if (s != string.Empty)
+ {
+ string hostName = string.Empty;
+
+ if (s[0] != '#')
+ {
+ bool bSeperator = false;
+
+ foreach (char c in s)
+ {
+ if ((c != ' ') & (c != '\t'))
+ {
+ if (bSeperator)
+ {
+ hostName += c;
+ }
+ }
+ else
+ {
+ bSeperator = true;
+ }
+ }
+
+ if (hostName.ToLower() != siteCollection.RootWebApplicationFQDN.ToLower())
+ {
+ outPut += s + "\r\n";
+ }
+ }
+ else
+ {
+ outPut += s + "\r\n";
+ }
+ }
+ }
+
+ FileUtils.UpdateFileTextContent(path, outPut);
+ }
+ }
+ }
+ catch (Exception ex)
+ {
+ HostedSolutionLog.LogError(ex);
+ }
+ }
+
+ #endregion
+ }
+}
\ No newline at end of file
diff --git a/WebsitePanel/Sources/WebsitePanel.Providers.HostedSolution.SharePoint2013/Properties/AssemblyInfo.cs b/WebsitePanel/Sources/WebsitePanel.Providers.HostedSolution.SharePoint2013/Properties/AssemblyInfo.cs
new file mode 100644
index 00000000..edfe08e0
--- /dev/null
+++ b/WebsitePanel/Sources/WebsitePanel.Providers.HostedSolution.SharePoint2013/Properties/AssemblyInfo.cs
@@ -0,0 +1,64 @@
+// 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.Reflection;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+
+// General Information about an assembly is controlled through the following
+// set of attributes. Change these attribute values to modify the information
+// associated with an assembly.
+[assembly: AssemblyTitle("WebsitePanel.Providers.HostedSolution.SharePoint2013")]
+[assembly: AssemblyDescription("")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("")]
+[assembly: AssemblyProduct("WebsitePanel.Providers.HostedSolution.SharePoint2013")]
+[assembly: AssemblyCopyright("Copyright © 2013")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+
+// Setting ComVisible to false makes the types in this assembly not visible
+// to COM components. If you need to access a type in this assembly from
+// COM, set the ComVisible attribute to true on that type.
+[assembly: ComVisible(false)]
+
+// The following GUID is for the ID of the typelib if this project is exposed to COM
+[assembly: Guid("9bb9c655-3db4-4ca4-b856-1bce9cd727ba")]
+
+// Version information for an assembly consists of the following four values:
+//
+// Major Version
+// Minor Version
+// Build Number
+// Revision
+//
+// You can specify all the values or you can default the Build and Revision Numbers
+// by using the '*' as shown below:
+// [assembly: AssemblyVersion("1.0.*")]
+[assembly: AssemblyVersion("1.0.0.0")]
+[assembly: AssemblyFileVersion("1.0.0.0")]
diff --git a/WebsitePanel/Sources/WebsitePanel.Providers.HostedSolution.SharePoint2013/WebsitePanel.Providers.HostedSolution.SharePoint2013.csproj b/WebsitePanel/Sources/WebsitePanel.Providers.HostedSolution.SharePoint2013/WebsitePanel.Providers.HostedSolution.SharePoint2013.csproj
new file mode 100644
index 00000000..7d724426
--- /dev/null
+++ b/WebsitePanel/Sources/WebsitePanel.Providers.HostedSolution.SharePoint2013/WebsitePanel.Providers.HostedSolution.SharePoint2013.csproj
@@ -0,0 +1,74 @@
+
+
+
+
+ Debug
+ AnyCPU
+ {24762DC8-6078-4F10-A524-C94ED59BD5D1}
+ Library
+ Properties
+ WebsitePanel.Providers.HostedSolution.SharePoint2013
+ WebsitePanel.Providers.HostedSolution.SharePoint2013
+ v4.5
+ 512
+
+
+ true
+ full
+ false
+ ..\WebsitePanel.Server\bin\
+ DEBUG;TRACE
+ prompt
+ 4
+
+
+ pdbonly
+ true
+ bin\Release\
+ TRACE
+ prompt
+ 4
+
+
+
+ False
+ ..\..\Lib\References\Microsoft\Microsoft.SharePoint.dll
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {684C932A-6C75-46AC-A327-F3689D89EB42}
+ WebsitePanel.Providers.Base
+
+
+ {A06DE5E4-4331-47E1-8F46-7B846146B559}
+ WebsitePanel.Providers.HostedSolution
+
+
+ {E91E52F3-9555-4D00-B577-2B1DBDD87CA7}
+ WebsitePanel.Server.Utils
+
+
+
+
+
\ No newline at end of file
diff --git a/WebsitePanel/Sources/WebsitePanel.Providers.HostedSolution/WebsitePanel.Providers.HostedSolution.csproj b/WebsitePanel/Sources/WebsitePanel.Providers.HostedSolution/WebsitePanel.Providers.HostedSolution.csproj
index 6325906e..05169241 100644
--- a/WebsitePanel/Sources/WebsitePanel.Providers.HostedSolution/WebsitePanel.Providers.HostedSolution.csproj
+++ b/WebsitePanel/Sources/WebsitePanel.Providers.HostedSolution/WebsitePanel.Providers.HostedSolution.csproj
@@ -144,6 +144,8 @@
+
+
diff --git a/WebsitePanel/Sources/WebsitePanel.Server.sln b/WebsitePanel/Sources/WebsitePanel.Server.sln
index 6e34a22d..8eb00736 100644
--- a/WebsitePanel/Sources/WebsitePanel.Server.sln
+++ b/WebsitePanel/Sources/WebsitePanel.Server.sln
@@ -130,6 +130,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WebsitePanel.Providers.Host
{E91E52F3-9555-4D00-B577-2B1DBDD87CA7} = {E91E52F3-9555-4D00-B577-2B1DBDD87CA7}
EndProjectSection
EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WebsitePanel.Providers.HostedSolution.SharePoint2013", "WebsitePanel.Providers.HostedSolution.SharePoint2013\WebsitePanel.Providers.HostedSolution.SharePoint2013.csproj", "{24762DC8-6078-4F10-A524-C94ED59BD5D1}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -660,6 +662,16 @@ Global
{E5DB0722-CDC2-4D7F-8EEB-563578085FA7}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
{E5DB0722-CDC2-4D7F-8EEB-563578085FA7}.Release|Mixed Platforms.Build.0 = Release|Any CPU
{E5DB0722-CDC2-4D7F-8EEB-563578085FA7}.Release|x86.ActiveCfg = Release|Any CPU
+ {24762DC8-6078-4F10-A524-C94ED59BD5D1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {24762DC8-6078-4F10-A524-C94ED59BD5D1}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {24762DC8-6078-4F10-A524-C94ED59BD5D1}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
+ {24762DC8-6078-4F10-A524-C94ED59BD5D1}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
+ {24762DC8-6078-4F10-A524-C94ED59BD5D1}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {24762DC8-6078-4F10-A524-C94ED59BD5D1}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {24762DC8-6078-4F10-A524-C94ED59BD5D1}.Release|Any CPU.Build.0 = Release|Any CPU
+ {24762DC8-6078-4F10-A524-C94ED59BD5D1}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
+ {24762DC8-6078-4F10-A524-C94ED59BD5D1}.Release|Mixed Platforms.Build.0 = Release|Any CPU
+ {24762DC8-6078-4F10-A524-C94ED59BD5D1}.Release|x86.ActiveCfg = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
diff --git a/WebsitePanel/Sources/WebsitePanel.WebPortal/DesktopModules/WebsitePanel/HostedSharePointEditSiteCollection.ascx.cs b/WebsitePanel/Sources/WebsitePanel.WebPortal/DesktopModules/WebsitePanel/HostedSharePointEditSiteCollection.ascx.cs
index bc712364..8f1a77d4 100644
--- a/WebsitePanel/Sources/WebsitePanel.WebPortal/DesktopModules/WebsitePanel/HostedSharePointEditSiteCollection.ascx.cs
+++ b/WebsitePanel/Sources/WebsitePanel.WebPortal/DesktopModules/WebsitePanel/HostedSharePointEditSiteCollection.ascx.cs
@@ -29,6 +29,7 @@
using System;
using System.Collections.Generic;
using System.Globalization;
+using System.Linq;
using System.Web.UI.WebControls;
using WebsitePanel.EnterpriseServer;
using WebsitePanel.Providers.DNS;
@@ -148,20 +149,11 @@ namespace WebsitePanel.Portal
}
Organization org = ES.Services.Organizations.GetOrganization(OrganizationId);
+
if (org != null)
{
- maxStorage.ParentQuotaValue = org.MaxSharePointStorage;
- maxStorage.QuotaValue = org.MaxSharePointStorage;
-
- editMaxStorage.ParentQuotaValue = org.MaxSharePointStorage;
-
-
-
- warningStorage.ParentQuotaValue = org.WarningSharePointStorage;
- warningStorage.QuotaValue = org.WarningSharePointStorage;
- editWarningStorage.ParentQuotaValue = org.WarningSharePointStorage;
+ SetStorageQuotas(org, item);
}
-
}
//OrganizationDomainName[] domains = ES.Services.Organizations.GetOrganizationDomains(PanelRequest.ItemID);
@@ -192,6 +184,51 @@ namespace WebsitePanel.Portal
}
}
+ /// Checks and sets disk quotas values.
+ /// The organization.
+ /// The site collection.
+ private void SetStorageQuotas(Organization organization, SharePointSiteCollection collection)
+ {
+ var quotaValue = organization.MaxSharePointStorage;
+
+ if (quotaValue != -1)
+ {
+ var spaceResrved = GetReservedDiskStorageSpace();
+
+ if (spaceResrved > quotaValue)
+ {
+ quotaValue = 0;
+ }
+ else
+ {
+ quotaValue -= spaceResrved;
+ }
+
+ if (collection != null)
+ {
+ quotaValue += (int)collection.MaxSiteStorage;
+ }
+ }
+
+ maxStorage.ParentQuotaValue = quotaValue;
+ maxStorage.QuotaValue = quotaValue;
+ editMaxStorage.ParentQuotaValue = quotaValue;
+ warningStorage.ParentQuotaValue = quotaValue;
+ warningStorage.QuotaValue = quotaValue;
+ editWarningStorage.ParentQuotaValue = quotaValue;
+
+ btnUpdate.Enabled = quotaValue != 0;
+ }
+
+ /// Gets disk space reserved by existing site collections.
+ /// Reserved disk space vallue.
+ private int GetReservedDiskStorageSpace()
+ {
+ var existingCollections = ES.Services.HostedSharePointServers.GetSiteCollections(PanelSecurity.PackageId, false);
+
+ return (int)existingCollections.Sum(siteCollection => siteCollection.MaxSiteStorage);
+ }
+
private void SaveItem()
{
if (!Page.IsValid)