/*
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 System.Web.Routing;
using System.Reflection;
using System.Web.Mvc;
using System.Security.Principal;
using Everest.Library.Providers.Caching;
using Everest.Library.ExtensionMethod;
using Everest.Library.Mvc.Routing;
using Everest.CmsServices.Models;
using Everest.CmsServices.Services;
using Everest.Library.Web;
namespace Everest.CmsServices.Extension.Module{
public class ModuleInfo
{
public const string Const_ModuleConfigFile = "module.config";
public const string Const_ModuleRouteTableFile = "routes.config";
static object configurationLockHelper = new object();
static object routeTableLockHelper = new object();
static object permissionLockHelper = new object();
static object moduleSettingsLockHelper = new object();
/// <summary>
/// Initializes a new instance of the <see cref="ModuleInfo"/> class.
/// </summary>
/// <param name="moduleName">Name of the module.</param>
/// <param name="runtimeApplication">The runtime application.</param>
/// <param name="hostInCms">if set to <c>true</c> [host in CMS].</param>
protected ModuleInfo(string moduleName, string runtimeApplication, bool hostInCms)
{
this.ModuleName = moduleName;
this.HostInCms = hostInCms;
this.RuntimeApplication = runtimeApplication;
this.Authorizer = new ModuleAuthorizer();
if (hostInCms)
{
this.ModuleBaseDirectory = ModuleManager.GetModuleDirectory(moduleName);
}
else
{
this.ModuleBaseDirectory = AppDomain.CurrentDomain.BaseDirectory;
}
}
/// <summary>
/// Gets the module.
/// </summary>
/// <param name="moduleName">Name of the module.</param>
/// <param name="runtimeApplication">The runtime application.</param>
/// <param name="hostInCms">if set to <c>true</c> [host in CMS].</param>
/// <returns></returns>
public static ModuleInfo GetModule(string moduleName, string runtimeApplication, bool hostInCms)
{
if (hostInCms)
{
var moduleDirectory = ModuleManager.GetModuleDirectory(moduleName);
if (!Directory.Exists(moduleDirectory))
{
throw new Exception(string.Format(Resources.ModuleNotFound, moduleName));
}
}
return new ModuleInfo(moduleName, runtimeApplication, hostInCms);
}
/// <summary>
/// Gets or sets the name of the module.
/// </summary>
/// <value>The name of the module.</value>
public string ModuleName { get; private set; }
/// <summary>
/// Gets or sets the module base directory.
/// </summary>
/// <value>The module base diretory.</value>
public string ModuleBaseDirectory { get; private set; }
/// <summary>
/// Gets or sets the runtime application.
/// </summary>
/// <value>The runtime application.</value>
public string RuntimeApplication { get; private set; }
/// <summary>
/// Gets or sets a value indicating whether [host in CMS].
/// </summary>
/// <value><c>true</c> if [host in CMS]; otherwise, <c>false</c>.</value>
public bool HostInCms { get; private set; }
public ModuleAuthorizer Authorizer { get; set; }
/// <summary>
/// Gets or sets the configuration.
/// </summary>
/// <value>The configuration.</value>
public ModuleConfiguration Configuration
{
get
{
string cacheKey = string.Format("ModuleConfiguration_ModuleName:{0}", ModuleName);
ModuleConfiguration moduleConfiguration = CacheManager.Get(cacheKey) as ModuleConfiguration;
if (moduleConfiguration == null)
{
lock (configurationLockHelper)
{
moduleConfiguration = CacheManager.Get(cacheKey) as ModuleConfiguration;
if (moduleConfiguration == null)
{
string configFile = ModuleConfigFilePath;
moduleConfiguration = ObjectExtensions.DeserializeFromXmlFile<ModuleConfiguration>(configFile);
CacheManager.Add(cacheKey, moduleConfiguration, CacheItemPriority.Normal, null, new FileDependency(configFile));
}
}
}
return moduleConfiguration;
}
}
/// <summary>
/// Gets the route table.
/// </summary>
/// <value>The route table.</value>
public RouteCollection RouteTable
{
get
{
string cacheKey = string.Format("ModuleRouteTable_ModuleName:{0}", ModuleName);
RouteCollection routeTable = CacheManager.Get(cacheKey) as RouteCollection;
if (routeTable == null)
{
lock (routeTableLockHelper)
{
routeTable = CacheManager.Get(cacheKey) as RouteCollection;
if (routeTable == null)
{
routeTable = new RouteCollection();
string routeTableFile = RouteConfigFilePath;
RouteTableRegister.RegisterRoutes(routeTable, routeTableFile);
CacheManager.Add(cacheKey, routeTable, CacheItemPriority.Normal, null, new FileDependency(routeTableFile));
}
}
}
return routeTable;
}
}
/// <summary>
/// Saves the configuration.
/// </summary>
/// <param name="configuration">The configuration.</param>
public void SaveConfiguration(ModuleConfiguration configuration)
{
configuration.SerializeToXml(ModuleConfigFilePath);
}
/// <summary>
/// Gets the module config file path.
/// </summary>
/// <value>The module config file path.</value>
private string ModuleConfigFilePath
{
get
{
return Path.Combine(ModuleBaseDirectory, Const_ModuleConfigFile);
}
}
private string RouteConfigFilePath
{
get
{
return System.IO.Path.Combine(ModuleBaseDirectory, Const_ModuleRouteTableFile);
}
}
/// <summary>
/// Verifies this Module.
/// </summary>
/// <returns></returns>
public bool Verify()
{
if (!File.Exists(ModuleConfigFilePath))
{
return false;
}
if (!File.Exists(RouteConfigFilePath))
{
return false;
}
return true;
}
/// <summary>
/// Gets all functions.
/// </summary>
/// <returns></returns>
public IEnumerable<FunctionAttribute> GetAllFunctions()
{
List<FunctionAttribute> functions = new List<FunctionAttribute>();
foreach (var assembly in Configuration.Assemblies.Where(a => a.ContainsController = true))
{
functions.AddRange(GetFunctions(assembly));
}
return functions.Distinct();
}
/// <summary>
/// Gets the functions.
/// </summary>
/// <param name="moduleAssembly">The module assembly.</param>
/// <returns></returns>
private IEnumerable<FunctionAttribute> GetFunctions(ModuleAssembly moduleAssembly)
{
List<FunctionAttribute> functions = new List<FunctionAttribute>();
//GlobalAssemblyCache == false to prevent System.Security.Permissions.FileIOPermission when medium trust level.
Assembly controllerAssembly = AppDomain.CurrentDomain.GetAssemblies().Where(a => a.GlobalAssemblyCache == false && a.FullName.ToLower().Contains(moduleAssembly.AssemblyName.ToLower() + ",")).FirstOrDefault();
if (controllerAssembly != null)
{
Type controllerInterface = typeof(IController);
var controllerTypes = controllerAssembly.GetTypes().Where(t => controllerInterface.IsAssignableFrom(t));
foreach (var controllerType in controllerTypes)
{
var typeFunctionAttributes = controllerType.GetCustomAttributes(typeof(FunctionAttribute), false);
foreach (var function in typeFunctionAttributes)
{
functions.Add((FunctionAttribute)function);
}
var methods = controllerType.GetMethods(BindingFlags.Public | BindingFlags.Instance);
foreach (var method in methods)
{
var methodFunctionAttributes = method.GetCustomAttributes(typeof(FunctionAttribute), false);
foreach (var function in methodFunctionAttributes)
{
functions.Add((FunctionAttribute)function);
}
}
}
}
return functions;
}
private ModuleSettingCollection moduleSettings;
/// <summary>
/// Gets or sets the module settings.
/// </summary>
/// <value>The module settings.</value>
public ModuleSettingCollection ModuleSettings
{
get
{
if (moduleSettings == null)
{
moduleSettings = new ModuleSettingCollection(Configuration.Settings);
}
return moduleSettings;
}
set
{
moduleSettings = value;
}
}
/// <summary>
/// Determines whether the specified function name is authorized.
/// </summary>
/// <param name="functionName">Name of the function.</param>
/// <param name="user">The user.</param>
/// <returns>
/// <c>true</c> if the specified function name is authorized; otherwise, <c>false</c>.
/// </returns>
public bool IsAuthorized(string functionName, IPrincipal user)
{
var modulePermission = this.Permissions.Where(mp => mp.FunctionName == functionName).FirstOrDefault();
return Authorizer.IsAuthorized(this.RuntimeApplication, modulePermission, user);
}
#region Theme
/// <summary>
/// Get the theme path.
/// </summary>
public string ThemePath
{
get
{
return Path.Combine(this.ModuleBaseDirectory, TemplateFileManager.ThemeDirName);
}
}
/// <summary>
/// Gets the theme stylesheets.
/// </summary>
/// <returns></returns>
public IEnumerable<string> GetThemeStylesheets(string theme)
{
string themePath = GetThemePath(theme);
if (Directory.Exists(themePath))
{
return Directory.GetFiles(themePath, "*.css", SearchOption.AllDirectories).OrderBy(f => f);
}
return new string[0];
}
public string GetThemePath(string theme)
{
return Path.Combine(this.ModuleBaseDirectory, string.Format("{0}/{1}", TemplateFileManager.ThemeDirName, theme));
}
/// <summary>
/// Resolves the theme file URL.
/// </summary>
/// <param name="themeFile">The theme file.e.g: images/logo.gif </param>
/// <returns></returns>
public string ResolveThemeFileUrl(string themeFile)
{
return string.Format("~/{0}/{1}/{2}", TemplateFileManager.ThemeDirName, this.ModuleSettings.Theme, themeFile);
}
/// <summary>
/// Gets the themes.
/// </summary>
/// <returns></returns>
public IEnumerable<string> GetThemes()
{
List<string> themes = new List<string>();
string themesPath = this.ThemePath;
if (Directory.Exists(themesPath))
{
var themeDirs = (new DirectoryInfo(themesPath)).GetDirectories();
foreach (var themeDir in themeDirs)
{
if ((themeDir.Attributes & FileAttributes.Hidden) != FileAttributes.Hidden)
{
themes.Add(themeDir.Name);
}
}
}
return themes;
}
#endregion
#region Javascripts
/// <summary>
/// Gets the javascript files.
/// </summary>
/// <returns></returns>
public IEnumerable<string> GetJavascriptFiles()
{
string javascriptPath = Path.Combine(this.ModuleBaseDirectory, TemplateFileManager.JavascriptDirName);
if (Directory.Exists(javascriptPath))
{
return Directory.GetFiles(javascriptPath, "*.js", SearchOption.AllDirectories).OrderBy(f => f);
}
return new string[0];
}
#endregion
#region AllowedApplications
/// <summary>
/// Deletes the module in applications.
/// </summary>
/// <param name="dataContext">The data context.</param>
/// <param name="moduleName">Name of the module.</param>
internal static void DeleteModuleInApplications(IEverestCmsDataContext dataContext, string moduleName)
{
var moduleApplications = dataContext.QueryModuleApplications(moduleName).ToArray();
foreach (var item in moduleApplications)
{
dataContext.DeleteObject(item);
}
dataContext.SaveChanges();
}
/// <summary>
/// Saves the allowed applications.
/// </summary>
/// <param name="applications">The applications.</param>
public void SaveAllowedApplications(IEverestCmsDataContext dataContext, string applications)
{
applications = applications ?? string.Empty;
string[] arrApplicaitons = applications.Split(',');
try
{
var dbTrans = dataContext.BeginTransaction();
{
DeleteModuleInApplications(dataContext, this.ModuleName);
foreach (var app in arrApplicaitons)
{
if (!string.IsNullOrEmpty(app))
{
Cms_ModuleApplication moduleApplication = new Cms_ModuleApplication() { ModuleName = this.ModuleName };
moduleApplication.aspnet_Applications = dataContext.QueryApplication(app).First();
dataContext.AddToCms_ModuleApplication(moduleApplication);
}
}
dataContext.SaveChanges();
dataContext.Commit();
}
}
catch
{
dataContext.Rollback();
throw;
}
}
/// <summary>
/// Gets the allowed applications.
/// </summary>
/// <returns></returns>
public string[] GetAllowedApplications()
{
var dataContext = EverestCmsEntities.GetDataContext();
var moduleApplications = dataContext.QueryModuleApplications(this.ModuleName).Select(ma => ma.aspnet_Applications.ApplicationName).ToArray().OrderBy(s => s);
return moduleApplications.ToArray();
}
#endregion
#region Permission
/// <summary>
/// Gets the permissions.
/// The same module run at different application,with the disparate permission setting.
/// </summary>
/// <value>The permissions.</value>
/// <returns></returns>
public IEnumerable<ModulePermission> Permissions
{
get
{
string cacheKey = string.Format("__Permissions_ModuleName:{0}_RuntimeApplication:{1}", ModuleName, this.RuntimeApplication);
if (CacheManager.Get(CachedData.Permission, cacheKey) == null)
{
lock (permissionLockHelper)
{
if (CacheManager.Get(CachedData.Permission, cacheKey) == null)
{
IEverestCmsDataContext dataContext = EverestCmsEntities.GetDataContext();
var dbPermissions = dataContext.QueryModulePermissions(RuntimeApplication, ModuleName).Select(mp => new
{
mp.aspnet_Applications.ApplicationName,
mp.ModuleName,
mp.FunctionName,
mp.Allows,
mp.Denies,
}).ToArray();
var functions = this.GetAllFunctions();
List<ModulePermission> modulePermissions = new List<ModulePermission>();
foreach (var function in functions)
{
ModulePermission permission = new ModulePermission(RuntimeApplication, ModuleName, function.Name) { Description = function.Description };
var db = dbPermissions.Where(mp => mp.FunctionName == function.Name).FirstOrDefault();
if (db != null)
{
permission.Allows = db.Allows;
permission.Denies = db.Denies;
}
modulePermissions.Add(permission);
}
CacheManager.Add(CachedData.Permission, cacheKey, modulePermissions, CacheItemPriority.Normal, null, new FileDependency(ModuleConfigFilePath));
}
}
}
return (IEnumerable<ModulePermission>)CacheManager.Get(CachedData.Permission, cacheKey);
}
}
public void SavePermission(IEverestCmsDataContext dataContext, string application, IEnumerable<ModulePermission> modulePermissions)
{
DeletePermissions(dataContext, application, this.ModuleName);
var app = dataContext.QueryApplication(application).First();
try
{
var dbTrans = dataContext.BeginTransaction();
{
foreach (var modulePermission in modulePermissions)
{
var newPermission = new Cms_ModulePermission();
newPermission.aspnet_Applications = app;
newPermission.ModuleName = this.ModuleName;
newPermission.FunctionName = modulePermission.FunctionName;
newPermission.Allows = modulePermission.Allows;
newPermission.Denies = modulePermission.Denies;
dataContext.AddToCms_ModulePermission(newPermission);
}
dataContext.SaveChanges();
dataContext.Commit();
}
}
catch
{
dataContext.Rollback();
throw;
}
}
/// <summary>
/// Deletes the permissions.
/// </summary>
/// <param name="dataContext">The data context.</param>
/// <param name="application">The application.</param>
internal static void DeletePermissions(IEverestCmsDataContext dataContext, string application, string moduleName)
{
var oldPermissions = dataContext.QueryModulePermissions(application, moduleName);
foreach (var item in oldPermissions)
{
dataContext.DeleteObject(item);
}
dataContext.SaveChanges();
}
#endregion
}
}
|