using System; using System.Collections; using System.Collections.Generic; using System.Web; using System.Reflection; using umbraco.BasePages; using umbraco.BusinessLogic.Utils; using umbraco.cms.businesslogic.web; using umbraco.cms.businesslogic.workflow; using umbraco.interfaces; namespace umbraco.BusinessLogic.Actions { /// /// Actions and Actionhandlers are a key concept to umbraco and a developer whom wish to apply /// businessrules whenever data is changed within umbraco, by implementing the IActionHandler /// interface it's possible to invoke methods (foreign to umbraco) - this can be used whenever /// there is a specific rule which needs to be applied to content. /// /// The Action class itself has responsibility for registering actions and actionhandlers, /// and contains methods which will be invoked whenever a change is made to ex. a document, media or member /// /// An action/actionhandler will automatically be registered, using reflection /// which is enabling thirdparty developers to extend the core functionality of /// umbraco without changing the codebase. /// public class Action { private static readonly List _actions = new List(); private static readonly Dictionary _actionJs = new Dictionary(); private static readonly List _actionHandlers = new List(); private static readonly List _actionJSReference = new List(); static Action() { RegisterIActions(); RegisterIActionHandlers(); } /// /// Stores all IActionHandlers that have been loaded into memory into a list /// private static void RegisterIActionHandlers() { if (_actionHandlers.Count > 0) return; List foundIActionHandlers = TypeFinder.FindClassesOfType(true); foreach (Type type in foundIActionHandlers) { IActionHandler typeInstance; typeInstance = Activator.CreateInstance(type) as IActionHandler; if (typeInstance != null) _actionHandlers.Add(typeInstance); } } /// /// Stores all IActions that have been loaded into memory into a list /// private static void RegisterIActions() { if (_actions.Count > 0) return; List foundIActions = TypeFinder.FindClassesOfType(true); foreach (Type type in foundIActions) { IAction typeInstance; PropertyInfo instance = type.GetProperty("Instance", BindingFlags.Public | BindingFlags.Static); //if the singletone initializer is not found, try simply creating an instance of the IAction if it supports public constructors if (instance == null) typeInstance = Activator.CreateInstance(type) as IAction; else typeInstance = instance.GetValue(null, null) as IAction; if (typeInstance != null) { if (!string.IsNullOrEmpty(typeInstance.JsSource)) _actionJSReference.Add(typeInstance.JsSource); _actions.Add(typeInstance); } } } /// /// Whenever an action is performed upon a document/media/member, this method is executed, ensuring that /// all registered handlers will have an oppotunity to handle the action. /// /// The document being operated on /// The action triggered public static void RunActionHandlers(Document d, IAction action) { foreach (IActionHandler ia in _actionHandlers) { try { foreach (IAction a in ia.ReturnActions()) { if (a.Alias == action.Alias) { // Uncommented for auto publish support // System.Web.HttpContext.Current.Trace.Write("BusinessLogic.Action.RunActionHandlers", "Running " + ia.HandlerName() + " (matching action: " + a.Alias + ")"); ia.Execute(d, action); } } } catch (Exception iaExp) { Log.Add(LogTypes.Error, User.GetUser(0), -1, string.Format("Error loading actionhandler '{0}': {1}", ia.HandlerName(), iaExp)); } } // Run notification // Find current user User u; try { u = new UmbracoEnsuredPage().getUser(); } catch { u = User.GetUser(0); } Notification.GetNotifications(d, u, action); } /// /// Jacascript for the contextmenu /// Suggestion: this method should be moved to the presentation layer. /// /// /// String representation public string ReturnJavascript(string language) { return findActions(language); } /// /// Returns a list of JavaScript file paths. /// /// public static List GetJavaScriptFileReferences() { return _actionJSReference; } /// /// Javascript menuitems - tree contextmenu /// Umbraco console /// /// Suggestion: this method should be moved to the presentation layer. /// /// /// private static string findActions(string language) { if (!_actionJs.ContainsKey(language)) { string _actionJsList = ""; foreach (IAction action in _actions) { // Adding try/catch so this rutine doesn't fail if one of the actions fail // Add to language JsList try { // NH: Add support for css sprites string icon = action.Icon; if (!string.IsNullOrEmpty(icon) && icon.StartsWith(".")) icon = icon.Substring(1, icon.Length - 1); else icon = "images/" + icon; _actionJsList += string.Format(",\n\tmenuItem(\"{0}\", \"{1}\", \"{2}\", \"{3}\")", action.Letter, icon, ui.GetText("actions", action.Alias, language), action.JsFunctionName); } catch (Exception ee) { Log.Add(LogTypes.Error, -1, "Error registrering action to javascript: " + ee.ToString()); } } if (_actionJsList.Length > 0) _actionJsList = _actionJsList.Substring(2, _actionJsList.Length - 2); _actionJsList = "\nvar menuMethods = new Array(\n" + _actionJsList + "\n)\n"; _actionJs.Add(language, _actionJsList); } return _actionJs[language]; } /// /// /// /// An arraylist containing all javascript variables for the contextmenu in the tree public static ArrayList GetAll() { return new ArrayList(_actions); } /// /// This method will return a list of IAction's based on a string list. Each character in the list may represent /// an IAction. This will associate any found IActions based on the Letter property of the IAction with the character being referenced. /// /// /// returns a list of actions that have an associated letter found in the action string list public static List FromString(string actions) { List list = new List(); foreach (char c in actions.ToCharArray()) { IAction action = _actions.Find( delegate(IAction a) { return a.Letter == c; } ); if (action != null) list.Add(action); } return list; } /// /// Returns the string representation of the actions that make up the actions collection /// /// public static string ToString(List actions) { string[] strMenu = Array.ConvertAll(actions.ToArray(), delegate(IAction a) { return (a.Letter.ToString()); }); return string.Join("", strMenu); } /// /// Returns a list of IActions that are permission assignable /// /// public static List GetPermissionAssignable() { return _actions.FindAll( delegate(IAction a) { return (a.CanBePermissionAssigned); } ); } } }