/*
Kooboo is a content management system based on ASP.NET MVC framework. Copyright 2009 Yardi Technology Limited.
This program is free software: you can redistribute it and/or modify it under the terms of the
GNU General Public License version 3 as published by the Free Software Foundation.
This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with this program.
If not, see http://www.kooboo.com/gpl3/.
*/
using System;
using System.IO;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Everest.CmsServices.Models;
using Ionic.Zip;
using Microsoft.Data.Extensions;
using Everest.Library;
using Everest.Library.Data;
using Everest.Library.Data.Entity;
using Everest.Library.ExtensionMethod;
using Everest.CmsServices.Extension.Module;
using Everest.CmsServices.Providers;
using System.Text.RegularExpressions;
using System.Data;
using Everest.Library.Providers.Caching;
using Everest.CmsServices.Search;
namespace Everest.CmsServices.Services{
public class ApplicationService
{
const string ExportedDesignsSQLFileName = "Designs.sql";
const string ExportedContentsSQLFileName = "Contents.sql";
const string ValueHolderFileName = "Value.txt";
static Regex guidRegex = new Regex(@"[0-9a-fA-F]{8}\-[0-9a-fA-F]{4}\-[0-9a-fA-F]{4}\-[0-9a-fA-F]{4}\-[0-9a-fA-F]{12}", RegexOptions.IgnoreCase | RegexOptions.Compiled);
#region Create
/// <summary>
/// Creates the application.
/// </summary>
/// <param name="application">The application.</param>
/// <param name="baseApplication">The base application.</param>
/// <param name="hostName">Name of the host.</param>
/// <param name="theme">The theme.</param>
/// <param name="javascript">The javascript.</param>
/// <param name="userName">Name of the user.</param>
public void CreateApplication(string application, string baseApplication, string hostName, string theme, string javascript, string virtualPath, string userName)
{
IEverestCmsDataContext dataContext = EverestCmsEntities.GetDataContext();
var initializer = UnityManager.Resolve<ApplicationInitializer>();
aspnet_Applications app = new aspnet_Applications();
app.ApplicationId = Guid.NewGuid();
app.ApplicationName = application;
app.HostName = hostName;
app.Theme = theme;
app.Javascript = javascript;
app.VirtualPath = virtualPath;
app.LoweredApplicationName = application.ToLower();
app.BaseApplication = baseApplication;
app.ApplicationLevel = dataContext.QueryApplication(baseApplication).First().ApplicationLevel + 1;
dataContext.AddToaspnet_Applications(app);
dataContext.SaveChanges();
SetUserToApplication(userName, application);
initializer.InitializeCmsApplication(app.ApplicationName);
}
/// <summary>
/// Sets the user to application.
/// </summary>
/// <param name="userName">Name of the user.</param>
/// <param name="application">The application.</param>
public void SetUserToApplication(string userName, string application)
{
IEverestCmsDataContext dataContext = EverestCmsEntities.GetDataContext();
aspnet_Users aspnetUser = dataContext.QueryUser(userName).First();
aspnetUser.UsersInCmsApplication.Add(dataContext.QueryApplication(application).First());
dataContext.SaveChanges();
}
#endregion
#region Remove
public void RemoveApplication(string application)
{
var initializer = UnityManager.Resolve<ApplicationInitializer>();
initializer.RemoveCmsApplication(application);
}
#endregion
#region Export
/// <summary>
/// Exports the specified application.
/// </summary>
/// <param name="application">The application.</param>
/// <param name="exportDesign">if set to <c>true</c> [export design].</param>
/// <param name="exportContent">if set to <c>true</c> [export content].</param>
public virtual void Export(string application, string packageName, bool exportSiteElements, bool exportContents)
{
SitePackageManager sitePackageManager = new SitePackageManager();
string filePath = Path.Combine(sitePackageManager.BasePath, packageName + ".zip");
if (File.Exists(filePath))
{
filePath = Path.Combine(sitePackageManager.BasePath, packageName + "_" + DateTime.Now.ToString("yyyy_MM_dd_HH_mm_ss") + ".zip");
}
ZipFile zipfile = new ZipFile(Encoding.UTF8);
zipfile.TempFileFolder = CmsGlobal.TempPath;
var applicationsFolder = CachedData.GetFolder(CmsGlobal.RootApplicationName, FolderType.Applications);
//ValueHolder AppName;ApplicationsUUID
string valueHolder = application + ";" + applicationsFolder.UUID.ToString();
zipfile.AddEntry(ValueHolderFileName, valueHolder, Encoding.UTF8);
IContentProvider contentProvider = UnityManager.Resolve<IContentProvider>();
//
if (exportSiteElements)
{
//include template
ZipTemplateFiles(application, zipfile);
////include module, not included module any more.
//var modulePath = ModuleManager.GetApplicationModulesBaseDirectory(application);
//if (Directory.Exists(modulePath))
//{
// zipfile.AddDirectoryByName(ModuleManager.ModuleDirName);
// zipfile.AddSelectedFiles(@"name != *.svn* and name != entries", modulePath, ModuleManager.ModuleDirName, true);
//}
//include assemblies this is mainly about pageplugin.
var assembliesPath = AssemblyFileManager.GetAbsoluteApplicationAssemblyPath(application);
if (Directory.Exists(assembliesPath))
{
zipfile.AddDirectoryByName(AssemblyFileManager.AssemblyDirName);
zipfile.AddSelectedFiles("name != *.svn* and name != entries", assembliesPath, AssemblyFileManager.AssemblyDirName, true);
}
//export site design elements that are saved in the database like folder, page, template.
string designsSQL = contentProvider.SystemManager.ExportSiteElementData(application);
zipfile.AddEntry(ExportedDesignsSQLFileName, designsSQL, Encoding.UTF8);
}
if (exportContents)
{
//include content files
string contentFilePath = ContentFileManager.GetAbsoluteApplicationContentFilePath(application);
if (Directory.Exists(contentFilePath))
{
zipfile.AddDirectoryByName(ContentFileManager.ContentFileDirName);
zipfile.AddSelectedFiles("name != *.svn* and name != entries", contentFilePath, ContentFileManager.ContentFileDirName, true);
}
// export site content to SQL script.
string contentsSQL = contentProvider.SystemManager.ExportContentData(application);
zipfile.AddEntry(ExportedContentsSQLFileName, contentsSQL, Encoding.UTF8);
}
zipfile.Save(filePath);
}
private static void ZipTemplateFiles(string application, ZipFile zipfile)
{
var templatePath = TemplateFileManager.GetAbsoluteTemplatePath(application);
if (Directory.Exists(templatePath))
{
zipfile.AddDirectoryByName(TemplateFileManager.TemplateDirName);
zipfile.AddSelectedFiles(@"name != *.svn* and name != entries", templatePath, TemplateFileManager.TemplateDirName, true);
}
}
/// <summary>
/// Exports the template.
/// </summary>
/// <param name="application">The application.</param>
/// <param name="packageName">Name of the package.</param>
public virtual void ExportTemplate(string application, string packageName)
{
TemplatePackageManager siteTemplateManager = new TemplatePackageManager();
string filePath = Path.Combine(siteTemplateManager.BasePath, packageName + ".zip");
if (File.Exists(filePath))
{
filePath = Path.Combine(siteTemplateManager.BasePath, packageName + "_" + DateTime.Now.ToString("yyyy_MM_dd_HH_mm_ss") + ".zip");
}
ZipFile zipfile = new ZipFile(Encoding.UTF8);
zipfile.TempFileFolder = CmsGlobal.TempPath;
ZipTemplateFiles(application, zipfile);
zipfile.Save(filePath);
}
#endregion
#region Import
#region Import Application
/// <summary>
/// Imports the specified application.
/// </summary>
/// <param name="application">The application.</param>
/// <param name="sitePackageFileName">Name of the site package file.</param>
public virtual void Import(string application, string sitePackageFileName, bool renewId)
{
bool imported = false;
EnsureApplicationInexistent(application);
string packageFilePath = Path.Combine((new SitePackageManager()).BasePath, sitePackageFileName);
var unzipTempPath = Path.Combine(CmsGlobal.TempPath, Guid.NewGuid().ToString());
try
{
UnzipFile(packageFilePath, unzipTempPath);
var applicationsFolder = CachedData.GetFolder(CmsGlobal.RootApplicationName, FolderType.Applications);
string oldApplicationName;
string oldApplicationsFolderUUID;
string valueHolderFile = Path.Combine(unzipTempPath, ValueHolderFileName);
if (!File.Exists(valueHolderFile))
{
throw new Exception(Resources.UnsupportedSitePackage);
}
GetValueHolder(valueHolderFile, out oldApplicationName, out oldApplicationsFolderUUID);
string designsSQL = string.Empty;
var designsSQLFile = Path.Combine(unzipTempPath, ExportedDesignsSQLFileName);
designsSQL = ReadFileAsText(designsSQLFile);
string contentsSQL = string.Empty;
var contentsSQLFile = Path.Combine(unzipTempPath, ExportedContentsSQLFileName);
if (File.Exists(contentsSQLFile))
{
contentsSQL = ReadFileAsText(contentsSQLFile);
contentsSQL = ReplaceDynamicTableName(contentsSQL, oldApplicationName, application);
}
Dictionary<string, string> replacingStrings = new Dictionary<string, string>();
//renew id.
if (renewId)
{
if (!StringExtensions.IsNullOrEmptyTrim(designsSQL))
{
MatchAllGuid(designsSQL, replacingStrings);
}
if (!StringExtensions.IsNullOrEmptyTrim(contentsSQL))
{
MatchAllGuid(contentsSQL, replacingStrings);
}
}
else
{
EnsurePrimaryKeysUsable(designsSQL);
}
//replace Applications Folder UUID.
replacingStrings[oldApplicationsFolderUUID] = applicationsFolder.UUID.ToString();
try
{
//import site elements sql;
if (!StringExtensions.IsNullOrEmptyTrim(designsSQL))
{
designsSQL = RepleaceString(replacingStrings, designsSQL);
designsSQL = ReplaceDesignsSQLApplicationName(designsSQL, oldApplicationName, application);
ExecSQL(designsSQL);
//Build schema tables.
BuildSchemaTables(application);
}
//copy template
var unzippedTemplatePath = Path.Combine(unzipTempPath, TemplateFileManager.TemplateDirName);
if (Directory.Exists(unzippedTemplatePath))
{
var templatePath = TemplateFileManager.GetAbsoluteTemplatePath(application);
FileExtensions.CopyDirectory(unzippedTemplatePath, templatePath);
}
//copy assemblies
var unzippedAssembliesPath = Path.Combine(unzipTempPath, AssemblyFileManager.AssemblyDirName);
if (Directory.Exists(unzippedAssembliesPath))
{
var assembliesPath = AssemblyFileManager.GetAbsoluteApplicationAssemblyPath(application);
FileExtensions.CopyDirectory(unzippedAssembliesPath, assembliesPath);
}
}
catch (Exception e)
{
throw new Exception(Resources.ImportSiteElementsError, e);
}
imported = true;
try
{
//import contents
if (!StringExtensions.IsNullOrEmptyTrim(contentsSQL))
{
contentsSQL = RepleaceString(replacingStrings, contentsSQL);
contentsSQL = ReplaceContentSQLApplicationName(contentsSQL, oldApplicationName, application);
ExecSQL(contentsSQL);
}
var unzippedContentFilesPath = Path.Combine(unzipTempPath, ContentFileManager.ContentFileDirName);
if (Directory.Exists(unzippedContentFilesPath))
{
string contentFilePath = ContentFileManager.GetAbsoluteApplicationContentFilePath(application);
FileExtensions.CopyDirectory(unzippedContentFilesPath, contentFilePath);
if (renewId)
{
//replace content file folder name.
foreach (var item in replacingStrings)
{
var dirs = Directory.GetDirectories(contentFilePath, item.Key, SearchOption.AllDirectories);
foreach (var dir in dirs)
{
var newDir = Path.Combine(Path.GetDirectoryName(dir), item.Value);
Directory.Move(dir, newDir);
}
}
}
}
}
catch (Exception e)
{
throw new Exception(Resources.ImportContentsError, e);
}
}
finally
{
try
{
if (Directory.Exists(unzipTempPath))
Directory.Delete(unzipTempPath, true);
}
catch (Exception e)
{
Everest.Library.HealthMonitor.HealthMonitoringLogging.LogError(e);
}
if (imported == true)
{
CacheManager.RemoveAllGroups();
try
{
IContentProvider contentProvider = UnityManager.Resolve<IContentProvider>();
contentProvider.SystemManager.AddContentIndex(EverestCmsEntities.GetDataContext(), application, IndexType.Add);
if (Directory.Exists(unzipTempPath))
Directory.Delete(unzipTempPath, true);
}
catch (Exception e)
{
Everest.Library.HealthMonitor.HealthMonitoringLogging.LogError(e);
}
}
}
}
private string ReplaceDesignsSQLApplicationName(string designsSQL, string oldApplicationName, string newApplicationName)
{
var insertApplication = GetInsertApplicationSQL(designsSQL);
var newInsertApplication = Regex.Replace(insertApplication, string.Format("\\b{0}\\b", oldApplicationName), string.Format("{0}", newApplicationName), RegexOptions.IgnoreCase);
designsSQL = designsSQL.Replace(insertApplication, newInsertApplication);
designsSQL = designsSQL.Replace(TemplateFileManager.GetRelativeTemplatePath(oldApplicationName), TemplateFileManager.GetRelativeTemplatePath(newApplicationName));
designsSQL = designsSQL.Replace(string.Format(@"'{0}\Content\'", oldApplicationName), string.Format(@"'{0}\Content\'", newApplicationName));
return designsSQL;
}
private string ReplaceContentSQLApplicationName(string contentSQL, string oldApplicationName, string newApplicationName)
{
contentSQL = contentSQL.Replace(string.Format(@"'~/ContentFiles/{0}/Content", oldApplicationName), string.Format("'~/ContentFiles/{0}/Content", newApplicationName), true);
return contentSQL;
}
private string ReplaceDynamicTableName(string contentSQL, string oldApplicationName, string newApplicationName)
{
return contentSQL.Replace(string.Format("INSERT INTO [Cms_{0}_", oldApplicationName), string.Format("INSERT INTO [Cms_{0}_", newApplicationName));
}
/// <summary>
/// Ensures the application inexistent.
/// </summary>
/// <param name="applicationName">Name of the application.</param>
private void EnsureApplicationInexistent(string applicationName)
{
if (CachedData.GetApplication(applicationName) != null)
{
throw new Exception(Resources.ApplicationIsAlreadyExists);
}
}
/// <summary>
/// Ensures the primary keys usable.
/// </summary>
/// <param name="designsSQL">The designs SQL.</param>
private void EnsurePrimaryKeysUsable(string designsSQL)
{
var insertApplication = GetInsertApplicationSQL(designsSQL);
var applicationIdMatch = Regex.Match(insertApplication, "'(?<ApplicationId>[A-Za-z0-9]{8}-[A-Za-z0-9]{4}-[A-Za-z0-9]{4}-[A-Za-z0-9]{4}-[A-Za-z0-9]{12})'");
var guidString = applicationIdMatch.Groups["ApplicationId"].Value;
var applicationId = new Guid(guidString);
EnsureApplicationInexistent(applicationId);
}
private static string GetInsertApplicationSQL(string designsSQL)
{
using (StringReader reader = new StringReader(designsSQL))
{
var insertApplication = reader.ReadLine();
return insertApplication;
}
}
/// <summary>
/// Ensures the application inexistent.
/// </summary>
/// <param name="applicationGuid">The application GUID.</param>
private void EnsureApplicationInexistent(Guid applicationGuid)
{
if (CachedData.GetApplication(applicationGuid) != null)
{
throw new Exception(Resources.ImportPrimaryKeyIsConflict);
}
}
private static void MatchAllGuid(string designsSQL, Dictionary<string, string> replacingStrings)
{
var guidMatched = guidRegex.Matches(designsSQL);
foreach (Match guidMatch in guidMatched)
{
if (!replacingStrings.ContainsKey(guidMatch.Value))
{
replacingStrings.Add(guidMatch.Value, Guid.NewGuid().ToString());
}
}
}
private void UnzipFile(string zipFilePath, string destPath)
{
using (ZipFile zipFile = new ZipFile(zipFilePath, Encoding.UTF8))
{
zipFile.ExtractAll(destPath, ExtractExistingFileAction.OverwriteSilently);
}
}
private static void GetValueHolder(string valueHolderFile, out string oldApplicationName, out string oldApplicationsFolderUUID)
{
//ValueHolder AppName;ApplicationsUUID
string valueHolder = ReadFileAsText(valueHolderFile);
string[] oldValues = valueHolder.Split(';');
//the comment is old application name
oldApplicationName = oldValues[0];
oldApplicationsFolderUUID = oldValues[1];
}
private static string ReadFileAsText(string file)
{
using (FileStream fs = new FileStream(file, FileMode.Open, FileAccess.Read, FileShare.Read))
{
return fs.ReadString();
}
}
private static void BuildSchemaTables(string application)
{
var dataContext = EverestCmsEntities.GetDataContext();
var contentProvider = UnityManager.Resolve<IContentProvider>();
var schemas = dataContext.Cms_Schema.Where(s => s.aspnet_Applications.ApplicationName == application);
foreach (var schema in schemas)
{
contentProvider.TextContentManager.CreateSchema(dataContext, schema);
}
}
/// <summary>
/// Replaces the name of the application.
/// </summary>
/// <param name="sql">The SQL.</param>
/// <param name="oldApplicationName">Old name of the application.</param>
/// <param name="newApplicationName">New name of the application.</param>
/// <returns></returns>
private string RepleaceString(Dictionary<string, string> replacingStrings, string s)
{
foreach (var item in replacingStrings)
{
s = Regex.Replace(s, "(?<=_|\\b)" + item.Key + "(?=_|\\b)", item.Value, RegexOptions.IgnoreCase);
}
return s;
}
#endregion
#region Import Template
/// <summary>
/// Imports the template.
/// </summary>
/// <param name="application">The application.</param>
/// <param name="templatePackage">The template package.</param>
/// <param name="override">if set to <c>true</c> [@override].</param>
public virtual void ImportTemplate(string application, string templatePackage, bool @override)
{
string packageFilePath = Path.Combine((new TemplatePackageManager()).BasePath, templatePackage);
var unzipTempPath = Path.Combine(CmsGlobal.TempPath, Guid.NewGuid().ToString());
UnzipFile(packageFilePath, unzipTempPath);
//copy template
var unzippedTemplatePath = Path.Combine(unzipTempPath, TemplateFileManager.TemplateDirName);
if (Directory.Exists(unzippedTemplatePath))
{
var templatePath = TemplateFileManager.GetAbsoluteTemplatePath(application);
FileExtensions.CopyDirectory(unzippedTemplatePath, templatePath, @override);
}
if (Directory.Exists(unzipTempPath))
Directory.Delete(unzipTempPath, true);
}
#endregion
#endregion
#region ExecSQL
/// <summary>
/// Execs the SQL.
/// </summary>
/// <param name="sql">The SQL.</param>
private void ExecSQL(string sql)
{
var dataContext = EverestCmsEntities.GetDataContext();
var command = dataContext.ObjectContext.CreateStoreCommand(sql, CommandType.Text);
using (command.Connection.CreateConnectionScope())
{
using (var trans = command.Connection.BeginTransaction())
{
command.Transaction = trans;
command.ExecuteNonQuery();
trans.Commit();
}
}
}
#endregion
}
}
|