using System; using System.Collections; using System.Collections.Generic; using System.Linq; using System.Web; using System.Xml; using umbraco.BusinessLogic; using umbraco.BusinessLogic.Actions; using umbraco.cms.businesslogic.property; using umbraco.cms.businesslogic.relation; using umbraco.cms.helpers; using umbraco.DataLayer; using umbraco.IO; using umbraco.interfaces; using umbraco.cms.businesslogic.datatype.controls; using System.IO; using System.Diagnostics; namespace umbraco.cms.businesslogic.web { /// /// Document represents a webpage, /// type (umbraco.cms.businesslogic.web.DocumentType) /// /// Pubished Documents are exposed to the runtime/the public website in a cached xml document. /// public class Document : Content { #region Constructors /// /// Constructs a new document /// /// Id of the document /// true if the data shouldn't loaded from the db public Document(Guid id, bool noSetup) : base(id, noSetup) { } /// /// Initializes a new instance of the Document class. /// You can set an optional flag noSetup, used for optimizing for loading nodes in the tree, /// therefor only data needed by the tree is initialized. /// /// Id of the document /// true if the data shouldn't loaded from the db public Document(int id, bool noSetup) : base(id, noSetup) { } /// /// Initializes a new instance of the Document class to a specific version, used for rolling back data from a previous version /// of the document. /// /// The id of the document /// The version of the document public Document(int id, Guid Version) : base(id) { this.Version = Version; } /// /// Initializes a new instance of the Document class. /// /// The id of the document public Document(int id) : base(id) { } /// /// Initialize the document /// /// The id of the document public Document(Guid id) : base(id) { } /// /// Initializes a Document object with one SQL query instead of many /// /// /// public Document(bool optimizedMode, int id) : base(id, optimizedMode) { this._optimizedMode = optimizedMode; if (optimizedMode) { using (IRecordsReader dr = SqlHelper.ExecuteReader(string.Format(m_SQLOptimizedSingle.Trim(), "umbracoNode.id = @id", "cmsContentVersion.id desc"), SqlHelper.CreateParameter("@nodeObjectType", Document._objectType), SqlHelper.CreateParameter("@id", id))) { if (dr.Read()) { // Initialize node and basic document properties bool _hc = false; if (dr.GetInt("children") > 0) _hc = true; int? masterContentType = null; if (!dr.IsNull("masterContentType")) masterContentType = dr.GetInt("masterContentType"); SetupDocumentForTree(dr.GetGuid("uniqueId") , dr.GetShort("level") , dr.GetInt("parentId") , dr.GetInt("nodeUser") , dr.GetInt("documentUser") , dr.GetBoolean("published") , dr.GetString("path") , dr.GetString("text") , dr.GetDateTime("createDate") , dr.GetDateTime("updateDate") , dr.GetDateTime("versionDate") , dr.GetString("icon") , _hc , dr.GetString("alias") , dr.GetString("thumbnail") , dr.GetString("description") , masterContentType , dr.GetInt("contentTypeId") , dr.GetInt("templateId") ); // initialize content object InitializeContent(dr.GetInt("ContentType"), dr.GetGuid("versionId"), dr.GetDateTime("versionDate"), dr.GetString("icon")); // initialize final document properties DateTime tmpReleaseDate = new DateTime(); DateTime tmpExpireDate = new DateTime(); if (!dr.IsNull("releaseDate")) tmpReleaseDate = dr.GetDateTime("releaseDate"); if (!dr.IsNull("expireDate")) tmpExpireDate = dr.GetDateTime("expireDate"); InitializeDocument( new User(dr.GetInt("nodeUser"), true), new User(dr.GetInt("documentUser"), true), dr.GetString("documentText"), dr.GetInt("templateId"), tmpReleaseDate, tmpExpireDate, dr.GetDateTime("updateDate"), dr.GetBoolean("published") ); } } } } #endregion #region Constants and Static members private const string m_SQLOptimizedSingle = @" Select (select count(id) from umbracoNode where parentId = @id) as Children, (select Count(published) as tmp from cmsDocument where published = 1 And nodeId = @id) as Published, cmsContentVersion.VersionId, cmsContentVersion.versionDate, contentTypeNode.uniqueId as ContentTypeGuid, cmsContent.ContentType, cmsContentType.icon, cmsContentType.alias, cmsContentType.thumbnail, cmsContentType.description, cmsContentType.masterContentType, cmsContentType.nodeId as contentTypeId, published, documentUser, coalesce(templateId, cmsDocumentType.templateNodeId) as templateId, cmsDocument.text as DocumentText, releaseDate, expireDate, updateDate, umbracoNode.createDate, umbracoNode.trashed, umbracoNode.parentId, umbracoNode.nodeObjectType, umbracoNode.nodeUser, umbracoNode.level, umbracoNode.path, umbracoNode.sortOrder, umbracoNode.uniqueId, umbracoNode.text from umbracoNode inner join cmsContentVersion on cmsContentVersion.contentID = umbracoNode.id inner join cmsDocument on cmsDocument.versionId = cmsContentVersion.versionId inner join cmsContent on cmsDocument.nodeId = cmsContent.NodeId inner join cmsContentType on cmsContentType.nodeId = cmsContent.ContentType inner join umbracoNode contentTypeNode on contentTypeNode.id = cmsContentType.nodeId left join cmsDocumentType on cmsDocumentType.contentTypeNodeId = cmsContent.contentType and cmsDocumentType.IsDefault = 1 where umbracoNode.nodeObjectType = @nodeObjectType AND {0} order by {1} "; private const string m_SQLOptimizedMany = @" select count(children.id) as children, umbracoNode.id, umbracoNode.uniqueId, umbracoNode.level, umbracoNode.parentId, cmsDocument.documentUser, coalesce(cmsDocument.templateId, cmsDocumentType.templateNodeId) as templateId, umbracoNode.path, umbracoNode.sortOrder, coalesce(publishCheck.published,0) as published, umbracoNode.createDate, cmsDocument.text, cmsDocument.updateDate, cmsContentVersion.versionDate, cmsContentType.icon, cmsContentType.alias, cmsContentType.thumbnail, cmsContentType.description, cmsContentType.masterContentType, cmsContentType.nodeId as contentTypeId, umbracoNode.nodeUser from umbracoNode left join umbracoNode children on children.parentId = umbracoNode.id inner join cmsContent on cmsContent.nodeId = umbracoNode.id inner join cmsContentType on cmsContentType.nodeId = cmsContent.contentType inner join cmsContentVersion on cmsContentVersion.contentId = umbracoNode.id inner join (select contentId, max(versionDate) as versionDate from cmsContentVersion group by contentId) temp on cmsContentVersion.contentId = temp.contentId and cmsContentVersion.versionDate = temp.versionDate inner join cmsDocument on cmsDocument.versionId = cmsContentversion.versionId left join cmsDocument publishCheck on publishCheck.nodeId = cmsContent.nodeID and publishCheck.published = 1 left join cmsDocumentType on cmsDocumentType.contentTypeNodeId = cmsContent.contentType and cmsDocumentType.IsDefault = 1 where umbracoNode.nodeObjectType = @nodeObjectType AND {0} group by umbracoNode.id, umbracoNode.uniqueId, umbracoNode.level, umbracoNode.parentId, cmsDocument.documentUser, cmsDocument.templateId, cmsDocumentType.templateNodeId, umbracoNode.path, umbracoNode.sortOrder, coalesce(publishCheck.published,0), umbracoNode.createDate, cmsDocument.text, cmsContentType.icon, cmsContentType.alias, cmsContentType.thumbnail, cmsContentType.description, cmsContentType.masterContentType, cmsContentType.nodeId, cmsDocument.updateDate, cmsContentVersion.versionDate, umbracoNode.nodeUser order by {1} "; private const string m_SQLOptimizedForPreview = @" select umbracoNode.id, umbracoNode.parentId, umbracoNode.level, umbracoNode.sortOrder, cmsDocument.versionId, cmsPreviewXml.xml from cmsDocument inner join umbracoNode on umbracoNode.id = cmsDocument.nodeId inner join cmsPreviewXml on cmsPreviewXml.nodeId = cmsDocument.nodeId and cmsPreviewXml.versionId = cmsDocument.versionId where newest = 1 and trashed = 0 and path like '{0}' order by level,sortOrder "; public static Guid _objectType = new Guid("c66ba18e-eaf3-4cff-8a22-41b16d66a972"); #endregion #region Private properties private DateTime _updated; private DateTime _release; private DateTime _expire; private int _template; private bool _published; private XmlNode _xml; private User _creator; private User _writer; private int? _writerId; private bool _optimizedMode; /// /// This is used to cache the child documents of Document when the children property /// is accessed or enumerated over, this will save alot of database calls. /// private IEnumerable _children = null; // special for passing httpcontext object //private HttpContext _httpContext; // special for tree performance private int _userId = -1; //private Dictionary _knownProperties = new Dictionary(); //private Func, string, bool> propertyTypeByAlias = (pt, alias) => pt.Key.PropertyType.Alias == alias; #endregion #region Static Methods /// /// Imports (create) a document from a xmlrepresentation of a document, used by the packager /// /// The id to import to /// Creator of the new document /// Xmlsource public static int Import(int ParentId, User Creator, XmlElement Source) { // check what schema is used for the xml bool sourceIsLegacySchema = Source.Name.ToLower() == "node" ? true : false; // check whether or not to create a new document int id = int.Parse(Source.GetAttribute("id")); Document d = null; if (Document.IsDocument(id)) { try { // if the parent is the same, we'll update the existing document. Else we'll create a new document below d = new Document(id); if (d.ParentId != ParentId) d = null; } catch { } } // document either didn't exist or had another parent so we'll create a new one if (d == null) { string nodeTypeAlias = sourceIsLegacySchema ? Source.GetAttribute("nodeTypeAlias") : Source.Name; d = MakeNew( Source.GetAttribute("nodeName"), DocumentType.GetByAlias(nodeTypeAlias), Creator, ParentId); } else { // update name of the document d.Text = Source.GetAttribute("nodeName"); } d.CreateDateTime = DateTime.Parse(Source.GetAttribute("createDate")); // Properties string propertyXPath = sourceIsLegacySchema ? "data" : "* [not(@isDoc)]"; foreach (XmlElement n in Source.SelectNodes(propertyXPath)) { string propertyAlias = sourceIsLegacySchema ? n.GetAttribute("alias") : n.Name; Property prop = d.getProperty(propertyAlias); string propValue = xmlHelper.GetNodeValue(n); if (prop != null) { // only update real values if (!String.IsNullOrEmpty(propValue)) { //test if the property has prevalues, of so, try to convert the imported values so they match the new ones SortedList prevals = cms.businesslogic.datatype.PreValues.GetPreValues(prop.PropertyType.DataTypeDefinition.Id); //Okey we found some prevalue, let's replace the vals with some ids if (prevals.Count > 0) { System.Collections.Generic.List list = new System.Collections.Generic.List(propValue.Split(',')); foreach (DictionaryEntry item in prevals) { string pval = ((umbraco.cms.businesslogic.datatype.PreValue)item.Value).Value; string pid = ((umbraco.cms.businesslogic.datatype.PreValue)item.Value).Id.ToString(); if (list.Contains(pval)) list[list.IndexOf(pval)] = pid; } //join the list of new values and return it as the new property value System.Text.StringBuilder builder = new System.Text.StringBuilder(); bool isFirst = true; foreach (string str in list) { if (!isFirst) builder.Append(","); builder.Append(str); isFirst = false; } prop.Value = builder.ToString(); } else prop.Value = propValue; } } else { Log.Add(LogTypes.Error, d.Id, String.Format("Couldn't import property '{0}' as the property type doesn't exist on this document type", propertyAlias)); } } d.Save(); // Subpages string subXPath = sourceIsLegacySchema ? "node" : "* [@isDoc]"; foreach (XmlElement n in Source.SelectNodes(subXPath)) Import(d.Id, Creator, n); return d.Id; } /// /// Creates a new document /// /// The name (.Text property) of the document /// The documenttype /// The usercontext under which the action are performed /// The id of the parent to the document /// The newly created document public static Document MakeNew(string Name, DocumentType dct, User u, int ParentId) { //allows you to cancel a document before anything goes to the DB var newingArgs = new DocumentNewingEventArgs() { Text = Name, DocumentType = dct, User = u, ParentId = ParentId }; Document.OnNewing(newingArgs); if (newingArgs.Cancel) { return null; } Guid newId = Guid.NewGuid(); // Updated to match level from base node CMSNode n = new CMSNode(ParentId); int newLevel = n.Level; newLevel++; //create the cms node first CMSNode newNode = MakeNew(ParentId, _objectType, u.Id, newLevel, Name, newId); //we need to create an empty document and set the underlying text property Document tmp = new Document(newId, true); tmp.SetText(Name); //create the content data for the new document tmp.CreateContent(dct); //now create the document data SqlHelper.ExecuteNonQuery("insert into cmsDocument (newest, nodeId, published, documentUser, versionId, Text) values (1, " + tmp.Id + ", 0, " + u.Id + ", @versionId, @text)", SqlHelper.CreateParameter("@versionId", tmp.Version), SqlHelper.CreateParameter("@text", tmp.Text)); // Update the sortOrder if the parent was the root! if (ParentId == -1) { newNode.sortOrder = GetRootDocuments().Length + 1; } //read the whole object from the db Document d = new Document(newId); //event NewEventArgs e = new NewEventArgs(); d.OnNew(e); // Log Log.Add(LogTypes.New, u, d.Id, ""); // Run Handler umbraco.BusinessLogic.Actions.Action.RunActionHandlers(d, ActionNew.Instance); // Save doc d.Save(); return d; } /// /// Check if a node is a document /// /// /// public static bool IsDocument(int nodeId) { bool isDoc = false; using (IRecordsReader dr = SqlHelper.ExecuteReader(string.Format("select nodeId from cmsDocument where nodeId = @id"), SqlHelper.CreateParameter("@id", nodeId))) { if (dr.Read()) { isDoc = true; } } return isDoc; } /// Used to get the firstlevel/root documents of the hierachy /// /// Root documents public static Document[] GetRootDocuments() { Guid[] topNodeIds = TopMostNodeIds(_objectType); var docs = new List(); for (int i = 0; i < topNodeIds.Length; i++) { docs.Add(new Document(topNodeIds[i])); } return docs.ToArray(); } public static int CountSubs(int parentId, bool publishedOnly) { if (!publishedOnly) { return CountSubs(parentId); } else { return SqlHelper.ExecuteScalar("SELECT COUNT(distinct nodeId) FROM umbracoNode INNER JOIN cmsDocument ON cmsDocument.published = 1 and cmsDocument.nodeId = umbracoNode.id WHERE ','+path+',' LIKE '%," + parentId.ToString() + ",%'"); } } /// /// Deletes all documents of a type, will be invoked if a documenttype is deleted. /// /// Note: use with care: this method can result in wast amount of data being deleted. /// /// The type of which documents should be deleted public static void DeleteFromType(DocumentType dt) { //get all document for the document type and order by level (top level first) var docs = Document.GetDocumentsOfDocumentType(dt.Id) .OrderByDescending(x => x.Level); foreach (Document doc in docs) { //before we delete this document, we need to make sure we don't end up deleting other documents that //are not of this document type that are children. So we'll move all of it's children to the trash first. foreach (Document c in doc.GetDescendants()) { if (c.ContentType.Id != dt.Id) { c.MoveToTrash(); } } doc.DeletePermanently(); } } public static IEnumerable GetDocumentsOfDocumentType(int docTypeId) { var tmp = new List(); using (IRecordsReader dr = SqlHelper.ExecuteReader( string.Format(m_SQLOptimizedMany.Trim(), "cmsContent.contentType = @contentTypeId", "umbracoNode.sortOrder"), SqlHelper.CreateParameter("@nodeObjectType", Document._objectType), SqlHelper.CreateParameter("@contentTypeId", docTypeId))) { while (dr.Read()) { Document d = new Document(dr.GetInt("id"), true); d.PopulateDocumentFromReader(dr); tmp.Add(d); } } return tmp.ToArray(); } public static void RemoveTemplateFromDocument(int templateId) { SqlHelper.ExecuteNonQuery("update cmsDocument set templateId = NULL where templateId = @templateId", SqlHelper.CreateParameter("@templateId", templateId)); } /// /// Performance tuned method for use in the tree /// /// The parentdocuments id /// public static Document[] GetChildrenForTree(int NodeId) { var tmp = new List(); using (IRecordsReader dr = SqlHelper.ExecuteReader( string.Format(m_SQLOptimizedMany.Trim(), "umbracoNode.parentID = @parentId", "umbracoNode.sortOrder"), SqlHelper.CreateParameter("@nodeObjectType", Document._objectType), SqlHelper.CreateParameter("@parentId", NodeId))) { while (dr.Read()) { Document d = new Document(dr.GetInt("id"), true); d.PopulateDocumentFromReader(dr); tmp.Add(d); } } return tmp.ToArray(); } public static List GetChildrenBySearch(int NodeId, string searchString) { var tmp = new List(); using (IRecordsReader dr = SqlHelper.ExecuteReader( string.Format(m_SQLOptimizedMany.Trim(), "umbracoNode.parentID = @parentId and umbracoNode.text like @search", "umbracoNode.sortOrder"), SqlHelper.CreateParameter("@nodeObjectType", Document._objectType), SqlHelper.CreateParameter("@search", searchString), SqlHelper.CreateParameter("@parentId", NodeId))) { while (dr.Read()) { Document d = new Document(dr.GetInt("id"), true); d.PopulateDocumentFromReader(dr); tmp.Add(d); } } return tmp; } public static void RePublishAll() { XmlDocument xd = new XmlDocument(); SqlHelper.ExecuteNonQuery("truncate table cmsContentXml"); IRecordsReader dr = SqlHelper.ExecuteReader("select nodeId from cmsDocument where published = 1"); while (dr.Read()) { try { new Document(dr.GetInt("nodeId")).XmlGenerate(xd); } catch (Exception ee) { Log.Add(LogTypes.Error, User.GetUser(0), dr.GetInt("nodeId"), string.Format("Error generating xml: {0}", ee)); } } dr.Close(); } public static void RegeneratePreviews() { XmlDocument xd = new XmlDocument(); IRecordsReader dr = SqlHelper.ExecuteReader("select nodeId from cmsDocument"); while (dr.Read()) { try { new Document(dr.GetInt("nodeId")).SaveXmlPreview(xd); } catch (Exception ee) { Log.Add(LogTypes.Error, User.GetUser(0), dr.GetInt("nodeId"), string.Format("Error generating preview xml: {0}", ee)); } } dr.Close(); } /// /// Retrieve a list of documents with an expirationdate greater than today /// /// A list of documents with expirationdates than today public static Document[] GetDocumentsForExpiration() { ArrayList docs = new ArrayList(); IRecordsReader dr = SqlHelper.ExecuteReader("select distinct nodeId from cmsDocument where newest = 1 and not expireDate is null and expireDate <= @today", SqlHelper.CreateParameter("@today", DateTime.Now)); while (dr.Read()) docs.Add(dr.GetInt("nodeId")); dr.Close(); Document[] retval = new Document[docs.Count]; for (int i = 0; i < docs.Count; i++) retval[i] = new Document((int)docs[i]); return retval; } /// /// Retrieve a list of documents with with releasedate greater than today /// /// Retrieve a list of documents with with releasedate greater than today public static Document[] GetDocumentsForRelease() { ArrayList docs = new ArrayList(); IRecordsReader dr = SqlHelper.ExecuteReader("select distinct nodeId, level, sortOrder from cmsDocument inner join umbracoNode on umbracoNode.id = cmsDocument.nodeId where newest = 1 and not releaseDate is null and releaseDate <= @today order by [level], sortOrder", SqlHelper.CreateParameter("@today", DateTime.Now)); while (dr.Read()) docs.Add(dr.GetInt("nodeId")); dr.Close(); Document[] retval = new Document[docs.Count]; for (int i = 0; i < docs.Count; i++) retval[i] = new Document((int)docs[i]); return retval; } #endregion #region Public Properties /// /// Gets a value indicating whether the document was constructed for the optimized mode /// /// true if the document is working in the optimized mode; otherwise, false. public bool OptimizedMode { get { return this._optimizedMode; } } /// /// The id of the user whom created the document /// public int UserId { get { if (_userId == -1) _userId = User.Id; return _userId; } } /// /// Gets the user who created the document. /// /// The creator. public User Creator { get { if (_creator == null) { _creator = User; } return _creator; } } /// /// Gets the writer. /// /// The writer. public User Writer { get { if (_writer == null) { if (!_writerId.HasValue) { throw new NullReferenceException("Writer ID has not been specified for this document"); } _writer = User.GetUser(_writerId.Value); } return _writer; } } /// /// The current HTTPContext /// [Obsolete("DO NOT USE THIS! Get the HttpContext via regular ASP.Net methods instead")] public HttpContext HttpContext { set { /*THERE IS NO REASON TO DO THIS. _httpContext = value; */} get { //if (_httpContext == null) // _httpContext = HttpContext.Current; //return _httpContext; return System.Web.HttpContext.Current; } } /// /// Published flag is on if the document are published /// public bool Published { get { return _published; } set { _published = value; SqlHelper.ExecuteNonQuery( string.Format("update cmsDocument set published = {0} where nodeId = {1}", Id, value ? 1 : 0)); } } public override string Text { get { return base.Text; } set { value = value.Trim(); base.Text = value; SqlHelper.ExecuteNonQuery("update cmsDocument set text = @text where versionId = @versionId", SqlHelper.CreateParameter("@text", value), SqlHelper.CreateParameter("@versionId", Version)); //CMSNode c = new CMSNode(Id); //c.Text = value; } } /// /// The date of the last update of the document /// public DateTime UpdateDate { get { return _updated; } set { _updated = value; SqlHelper.ExecuteNonQuery("update cmsDocument set updateDate = @value where versionId = @versionId", SqlHelper.CreateParameter("@value", value), SqlHelper.CreateParameter("@versionId", Version)); } } /// /// A datestamp which indicates when a document should be published, used in automated publish/unpublish scenarios /// public DateTime ReleaseDate { get { return _release; } set { _release = value; if (_release.Year != 1 || _release.Month != 1 || _release.Day != 1) SqlHelper.ExecuteNonQuery("update cmsDocument set releaseDate = @value where versionId = @versionId", SqlHelper.CreateParameter("@value", value), SqlHelper.CreateParameter("@versionId", Version)); else SqlHelper.ExecuteNonQuery("update cmsDocument set releaseDate = NULL where versionId = @versionId", SqlHelper.CreateParameter("@versionId", Version)); } } /// /// A datestamp which indicates when a document should be unpublished, used in automated publish/unpublish scenarios /// public DateTime ExpireDate { get { return _expire; } set { _expire = value; if (_expire.Year != 1 || _expire.Month != 1 || _expire.Day != 1) SqlHelper.ExecuteNonQuery("update cmsDocument set expireDate = @value where versionId=@versionId", SqlHelper.CreateParameter("@value", value), SqlHelper.CreateParameter("@versionId", Version)); else SqlHelper.ExecuteNonQuery("update cmsDocument set expireDate = NULL where versionId=@versionId", SqlHelper.CreateParameter("@versionId", Version)); } } /// /// The id of the template associated to the document /// /// When a document is created, it will get have default template given by it's documenttype, /// an editor is able to assign alternative templates (allowed by it's the documenttype) /// /// You are always able to override the template in the runtime by appending the following to the querystring to the Url: /// /// ?altTemplate=[templatealias] /// public int Template { get { return _template; } set { _template = value; if (value == 0) { SqlHelper.ExecuteNonQuery("update cmsDocument set templateId = @value where versionId = @versionId", SqlHelper.CreateParameter("@value", DBNull.Value), SqlHelper.CreateParameter("@versionId", Version)); } else { SqlHelper.ExecuteNonQuery("update cmsDocument set templateId = @value where versionId = @versionId", SqlHelper.CreateParameter("@value", _template), SqlHelper.CreateParameter("@versionId", Version)); } } } /// /// A collection of documents imidiately underneath this document ie. the childdocuments /// public new Document[] Children { get { //cache the documents children so that this db call doesn't have to occur again if (this._children == null) this._children = Document.GetChildrenForTree(this.Id); return this._children.ToArray(); } } /// /// Indexed property to return the property value by name /// /// /// //public object this[string alias] //{ // get // { // if (this._optimizedMode) // { // return this._knownProperties.Single(p => propertyTypeByAlias(p, alias)).Value; // } // else // { // return this.getProperty(alias).Value; // } // } // set // { // if (this._optimizedMode) // { // if (this._knownProperties.SingleOrDefault(p => propertyTypeByAlias(p, alias)).Key == null) // { // var pt = this.getProperty(alias); // this._knownProperties.Add(pt, pt.Value); // } // else // { // var pt = this._knownProperties.Single(p => propertyTypeByAlias(p, alias)).Key; // this._knownProperties[pt] = value; // } // } // else // { // this.getProperty(alias).Value = value; // } // } //} #endregion #region Public Methods /// /// Executes handlers and events for the Send To Publication action. /// /// The User public bool SendToPublication(User u) { SendToPublishEventArgs e = new SendToPublishEventArgs(); FireBeforeSendToPublish(e); if (!e.Cancel) { BusinessLogic.Log.Add(BusinessLogic.LogTypes.SendToPublish, u, this.Id, ""); BusinessLogic.Actions.Action.RunActionHandlers(this, ActionToPublish.Instance); FireAfterSendToPublish(e); return true; } return false; } /// /// Publishing a document /// A xmlrepresentation of the document and its data are exposed to the runtime data /// (an xmlrepresentation is added -or updated if the document previously are published) , /// this will lead to a new version of the document being created, for continuing editing of /// the data. /// /// The usercontext under which the action are performed public void Publish(User u) { PublishWithResult(u); } /// /// Publishing a document /// A xmlrepresentation of the document and its data are exposed to the runtime data /// (an xmlrepresentation is added -or updated if the document previously are published) , /// this will lead to a new version of the document being created, for continuing editing of /// the data. /// /// The usercontext under which the action are performed /// True if the publishing succeed. Possible causes for not publishing is if an event aborts the publishing public bool PublishWithResult(User u) { PublishEventArgs e = new PublishEventArgs(); FireBeforePublish(e); if (!e.Cancel) { // make a lookup to see if template is 0 as the template is not initialized in the optimized // Document.Children method which is used in PublishWithChildrenWithResult methhod if (_template == 0) { _template = new DocumentType(this.ContentType.Id).DefaultTemplate; } _published = true; string tempVersion = Version.ToString(); Guid newVersion = createNewVersion(); Log.Add(LogTypes.Publish, u, Id, ""); //PPH make sure that there is only 1 newest node, this is important in regard to schedueled publishing... SqlHelper.ExecuteNonQuery("update cmsDocument set newest = 0 where nodeId = " + Id); SqlHelper.ExecuteNonQuery("insert into cmsDocument (newest, nodeId, published, documentUser, versionId, Text, TemplateId) values (1,@id, 0, @userId, @versionId, @text, @template)", SqlHelper.CreateParameter("@id", Id), SqlHelper.CreateParameter("@template", _template > 0 ? (object)_template : (object)DBNull.Value), //pass null in if the template doesn't have a valid id SqlHelper.CreateParameter("@userId", u.Id), SqlHelper.CreateParameter("@versionId", newVersion), SqlHelper.CreateParameter("@text", Text)); SqlHelper.ExecuteNonQuery("update cmsDocument set published = 0 where nodeId = " + Id); SqlHelper.ExecuteNonQuery("update cmsDocument set published = 1, newest = 0 where versionId = @versionId", SqlHelper.CreateParameter("@versionId", tempVersion)); // update release and expire dates Document newDoc = new Document(Id, newVersion); if (ReleaseDate != new DateTime()) newDoc.ReleaseDate = ReleaseDate; if (ExpireDate != new DateTime()) newDoc.ExpireDate = ExpireDate; // Update xml in db using the new document (has correct version date) newDoc.XmlGenerate(new XmlDocument()); FireAfterPublish(e); return true; } else { return false; } } public bool PublishWithChildrenWithResult(User u) { if (PublishWithResult(u)) { foreach (cms.businesslogic.web.Document dc in Children.ToList()) { dc.PublishWithChildrenWithResult(u); } } else { return false; } return true; } /// /// Rollbacks a document to a previous version, this will create a new version of the document and copy /// all of the old documents data. /// /// The usercontext under which the action are performed /// The unique Id of the version to roll back to public void RollBack(Guid VersionId, User u) { RollBackEventArgs e = new RollBackEventArgs(); FireBeforeRollBack(e); if (!e.Cancel) { Guid newVersion = createNewVersion(); SqlHelper.ExecuteNonQuery("insert into cmsDocument (nodeId, published, documentUser, versionId, Text, TemplateId) values (" + Id + ", 0, " + u.Id + ", @versionId, @text, " + _template + ")", SqlHelper.CreateParameter("@versionId", newVersion), SqlHelper.CreateParameter("@text", Text)); // Get new version Document dNew = new Document(Id, newVersion); // Old version Document dOld = new Document(Id, VersionId); // Revert title dNew.Text = dOld.Text; // Revert all properties var props = dOld.getProperties; foreach (Property p in props) try { dNew.getProperty(p.PropertyType).Value = p.Value; } catch { // property doesn't exists } FireAfterRollBack(e); } } /// /// Recursive publishing. /// /// Envoking this method will publish the documents and all children recursive. /// /// The usercontext under which the action are performed public void PublishWithSubs(User u) { PublishEventArgs e = new PublishEventArgs(); FireBeforePublish(e); if (!e.Cancel) { _published = true; string tempVersion = Version.ToString(); Guid newVersion = createNewVersion(); SqlHelper.ExecuteNonQuery("insert into cmsDocument (nodeId, published, documentUser, versionId, Text) values (" + Id + ", 0, " + u.Id + ", @versionId, @text)", SqlHelper.CreateParameter("@versionId", newVersion), SqlHelper.CreateParameter("@text", Text)); SqlHelper.ExecuteNonQuery("update cmsDocument set published = 0 where nodeId = " + Id); SqlHelper.ExecuteNonQuery("update cmsDocument set published = 1 where versionId = @versionId", SqlHelper.CreateParameter("@versionId", tempVersion)); BusinessLogic.Log.Add(LogTypes.Debug, -1, newVersion.ToString() + " - " + Id.ToString()); // Update xml in db XmlGenerate(new XmlDocument()); foreach (Document dc in Children.ToList()) dc.PublishWithSubs(u); FireAfterPublish(e); } } public void UnPublish() { UnPublishEventArgs e = new UnPublishEventArgs(); FireBeforeUnPublish(e); if (!e.Cancel) { SqlHelper.ExecuteNonQuery(string.Format("update cmsDocument set published = 0 where nodeId = {0}", Id)); _published = false; FireAfterUnPublish(e); } } /// /// Used to persist object changes to the database. /// public override void Save() { SaveEventArgs e = new SaveEventArgs(); FireBeforeSave(e); if (!e.Cancel) { //if (this._optimizedMode) //{ // foreach (var property in this._knownProperties) // { // var pt = property.Key; // pt.Value = property.Value; // } //} UpdateDate = DateTime.Now; //set the updated date to now base.Save(); // update preview xml SaveXmlPreview(new XmlDocument()); FireAfterSave(e); } } public bool HasPublishedVersion() { return (SqlHelper.ExecuteScalar("select Count(published) as tmp from cmsDocument where published = 1 And nodeId =" + Id) > 0); } /// /// Pending changes means that there have been property/data changes since the last published version. /// This is determined by the comparing the version date to the updated date. if they are different by .5 seconds, /// then this is considered a change. /// /// public bool HasPendingChanges() { return new TimeSpan(UpdateDate.Ticks - VersionDate.Ticks).TotalMilliseconds > 500; } /// /// Used for rolling back documents to a previous version /// /// Previous published versions of the document public DocumentVersionList[] GetVersions() { ArrayList versions = new ArrayList(); using (IRecordsReader dr = SqlHelper.ExecuteReader("select documentUser, versionId, updateDate, text from cmsDocument where nodeId = @nodeId order by updateDate", SqlHelper.CreateParameter("@nodeId", Id))) { while (dr.Read()) { DocumentVersionList dv = new DocumentVersionList(dr.GetGuid("versionId"), dr.GetDateTime("updateDate"), dr.GetString("text"), User.GetUser(dr.GetInt("documentUser"))); versions.Add(dv); } } DocumentVersionList[] retVal = new DocumentVersionList[versions.Count]; int i = 0; foreach (DocumentVersionList dv in versions) { retVal[i] = dv; i++; } return retVal; } /// /// /// /// Returns a breadcrumlike path for the document like: /ancestorname/ancestorname public string GetTextPath() { string tempPath = ""; string[] splitPath = Path.Split(".".ToCharArray()); for (int i = 1; i < Level; i++) { tempPath += new Document(int.Parse(splitPath[i])).Text + "/"; } if (tempPath.Length > 0) tempPath = tempPath.Substring(0, tempPath.Length - 1); return tempPath; } /// /// Creates a new document of the same type and copies all data from the current onto it /// /// The parentid where the document should be copied to /// The usercontext under which the action are performed public void Copy(int CopyTo, User u) { Copy(CopyTo, u, false); } public void Copy(int CopyTo, User u, bool RelateToOrignal) { CopyEventArgs e = new CopyEventArgs(); FireBeforeCopy(e); if (!e.Cancel) { // Make the new document Document NewDoc = MakeNew(Text, new DocumentType(ContentType.Id), u, CopyTo); // update template if a template is set if (this.Template > 0) NewDoc.Template = Template; //update the trashed property as it could be copied inside the recycle bin NewDoc.IsTrashed = this.IsTrashed; // Copy the properties of the current document var props = getProperties; foreach (Property p in props) NewDoc.getProperty(p.PropertyType.Alias).Value = p.Value; // Relate? if (RelateToOrignal) { Relation.MakeNew(Id, NewDoc.Id, RelationType.GetByAlias("relateDocumentOnCopy"), ""); // Add to audit trail Log.Add(LogTypes.Copy, u, NewDoc.Id, "Copied and related from " + Text + " (id: " + Id.ToString() + ")"); } // Copy the children //store children array here because iterating over an Array object is very inneficient. var c = Children; foreach (Document d in c) d.Copy(NewDoc.Id, u, RelateToOrignal); FireAfterCopy(e); } } /// /// Puts the current document in the trash /// public override void delete() { MoveToTrash(); } /// /// With either move the document to the trash or permanently remove it from the database. /// /// flag to set whether or not to completely remove it from the database or just send to trash public void delete(bool deletePermanently) { if (!deletePermanently) { MoveToTrash(); } else { DeletePermanently(); } } /// /// Returns all decendants of the current document /// /// public override IEnumerable GetDescendants() { var tmp = new List(); using (IRecordsReader dr = SqlHelper.ExecuteReader( string.Format(m_SQLOptimizedMany.Trim(), "umbracoNode.path LIKE '%," + this.Id + ",%'", "umbracoNode.level"), SqlHelper.CreateParameter("@nodeObjectType", Document._objectType))) { while (dr.Read()) { Document d = new Document(dr.GetInt("id"), true); d.PopulateDocumentFromReader(dr); tmp.Add(d); } } return tmp.ToArray(); } /// /// Refreshes the xml, used when publishing data on a document which already is published /// /// The source xmldocument /// The previous xmlrepresentation of the document public void XmlNodeRefresh(XmlDocument xd, ref XmlNode x) { x.Attributes.RemoveAll(); foreach (XmlNode xDel in x.SelectNodes("./data")) x.RemoveChild(xDel); XmlPopulate(xd, ref x, false); } /// /// Creates an xmlrepresentation of the document and saves it to the database /// /// public override void XmlGenerate(XmlDocument xd) { XmlNode x = generateXmlWithoutSaving(xd); /* if (!UmbracoSettings.UseFriendlyXmlSchema) { } else { XmlNode childNodes = xmlHelper.addTextNode(xd, "data", ""); x.AppendChild(childNodes); XmlPopulate(xd, ref childNodes, false); } */ // Save to db saveXml(x); } /// /// A xmlrepresentaion of the document, used when publishing/exporting the document, /// /// Optional: Recursive get childdocuments xmlrepresentation /// /// The xmldocument /// Recursive add of childdocuments /// public override XmlNode ToXml(XmlDocument xd, bool Deep) { if (Published) { if (_xml == null) { // Load xml from db if _xml hasn't been loaded yet _xml = importXml(); // Generate xml if xml still null (then it hasn't been initialized before) if (_xml == null) { XmlGenerate(new XmlDocument()); _xml = importXml(); } } XmlNode x = xd.ImportNode(_xml, true); if (Deep) { var c = Children; foreach (Document d in c) { if (d.Published) x.AppendChild(d.ToXml(xd, true)); } } return x; } else return null; } /// /// Populate a documents xmlnode /// /// Xmldocument context /// The node to fill with data /// If true the documents childrens xmlrepresentation will be appended to the Xmlnode recursive public override void XmlPopulate(XmlDocument xd, ref XmlNode x, bool Deep) { string urlName = this.Text; foreach (Property p in GenericProperties) if (p != null) { x.AppendChild(p.ToXml(xd)); if (p.PropertyType.Alias == "umbracoUrlName" && p.Value.ToString().Trim() != string.Empty) urlName = p.Value.ToString(); } // attributes x.Attributes.Append(addAttribute(xd, "id", Id.ToString())); // x.Attributes.Append(addAttribute(xd, "version", Version.ToString())); if (Level > 1) x.Attributes.Append(addAttribute(xd, "parentID", Parent.Id.ToString())); else x.Attributes.Append(addAttribute(xd, "parentID", "-1")); x.Attributes.Append(addAttribute(xd, "level", Level.ToString())); x.Attributes.Append(addAttribute(xd, "writerID", Writer.Id.ToString())); x.Attributes.Append(addAttribute(xd, "creatorID", Creator.Id.ToString())); if (ContentType != null) x.Attributes.Append(addAttribute(xd, "nodeType", ContentType.Id.ToString())); x.Attributes.Append(addAttribute(xd, "template", _template.ToString())); x.Attributes.Append(addAttribute(xd, "sortOrder", sortOrder.ToString())); x.Attributes.Append(addAttribute(xd, "createDate", CreateDateTime.ToString("s"))); x.Attributes.Append(addAttribute(xd, "updateDate", VersionDate.ToString("s"))); x.Attributes.Append(addAttribute(xd, "nodeName", Text)); x.Attributes.Append(addAttribute(xd, "urlName", url.FormatUrl(urlName.ToLower()))); x.Attributes.Append(addAttribute(xd, "writerName", Writer.Name)); x.Attributes.Append(addAttribute(xd, "creatorName", Creator.Name.ToString())); if (ContentType != null && UmbracoSettings.UseLegacyXmlSchema) x.Attributes.Append(addAttribute(xd, "nodeTypeAlias", ContentType.Alias)); x.Attributes.Append(addAttribute(xd, "path", Path)); if (!UmbracoSettings.UseLegacyXmlSchema) { x.Attributes.Append(addAttribute(xd, "isDoc", "")); } if (Deep) { //store children array here because iterating over an Array object is very inneficient. var c = Children; foreach (Document d in c) { XmlNode xml = d.ToXml(xd, true); if (xml != null) { x.AppendChild(xml); } else { Log.Add(LogTypes.System, d.Id, "Document not published so XML cannot be generated"); } } } } public void refreshXmlSortOrder() { if (Published) { if (_xml == null) // Load xml from db if _xml hasn't been loaded yet _xml = importXml(); // Generate xml if xml still null (then it hasn't been initialized before) if (_xml == null) { XmlGenerate(new XmlDocument()); _xml = importXml(); } else { // Update the sort order attr _xml.Attributes.GetNamedItem("sortOrder").Value = sortOrder.ToString(); saveXml(_xml); } } } public override List GetNodesForPreview(bool childrenOnly) { List nodes = new List(); string pathExp = childrenOnly ? Path + ",%" : Path; IRecordsReader dr = SqlHelper.ExecuteReader(String.Format(m_SQLOptimizedForPreview, pathExp)); while (dr.Read()) nodes.Add(new CMSPreviewNode(dr.GetInt("id"), dr.GetGuid("versionId"), dr.GetInt("parentId"), dr.GetShort("level"), dr.GetInt("sortOrder"), dr.GetString("xml"))); dr.Close(); return nodes; } public override XmlNode ToPreviewXml(XmlDocument xd) { if (!PreviewExists(Version)) { SaveXmlPreview(xd); } return GetPreviewXml(xd, Version); } #endregion #region Protected Methods protected override void setupNode() { base.setupNode(); using (var dr = SqlHelper.ExecuteReader("select published, documentUser, coalesce(templateId, cmsDocumentType.templateNodeId) as templateId, text, releaseDate, expireDate, updateDate from cmsDocument inner join cmsContent on cmsDocument.nodeId = cmsContent.Nodeid left join cmsDocumentType on cmsDocumentType.contentTypeNodeId = cmsContent.contentType and cmsDocumentType.IsDefault = 1 where versionId = @versionId", SqlHelper.CreateParameter("@versionId", Version))) { if (dr.Read()) { _creator = User; _writer = User.GetUser(dr.GetInt("documentUser")); if (!dr.IsNull("templateId")) _template = dr.GetInt("templateId"); if (!dr.IsNull("releaseDate")) _release = dr.GetDateTime("releaseDate"); if (!dr.IsNull("expireDate")) _expire = dr.GetDateTime("expireDate"); if (!dr.IsNull("updateDate")) _updated = dr.GetDateTime("updateDate"); } else { throw new ArgumentException(string.Format("No Document exists with Version '{0}'", Version)); } } _published = HasPublishedVersion(); } protected void InitializeDocument(User InitUser, User InitWriter, string InitText, int InitTemplate, DateTime InitReleaseDate, DateTime InitExpireDate, DateTime InitUpdateDate, bool InitPublished) { if (InitUser == null) { throw new ArgumentNullException("InitUser"); } if (InitWriter == null) { throw new ArgumentNullException("InitWriter"); } _creator = InitUser; _writer = InitWriter; SetText(InitText); _template = InitTemplate; _release = InitReleaseDate; _expire = InitExpireDate; _updated = InitUpdateDate; _published = InitPublished; } protected void PopulateDocumentFromReader(IRecordsReader dr) { bool _hc = false; if (dr.GetInt("children") > 0) _hc = true; int? masterContentType = null; if (!dr.IsNull("masterContentType")) masterContentType = dr.GetInt("masterContentType"); SetupDocumentForTree(dr.GetGuid("uniqueId") , dr.GetShort("level") , dr.GetInt("parentId") , dr.GetInt("nodeUser") , dr.GetInt("documentUser") , (dr.GetInt("published") == 1) , dr.GetString("path") , dr.GetString("text") , dr.GetDateTime("createDate") , dr.GetDateTime("updateDate") , dr.GetDateTime("versionDate") , dr.GetString("icon") , _hc , dr.GetString("alias") , dr.GetString("thumbnail") , dr.GetString("description") , masterContentType , dr.GetInt("contentTypeId") , dr.GetInt("templateId")); } protected void SaveXmlPreview(XmlDocument xd) { SavePreviewXml(generateXmlWithoutSaving(xd), Version); } #endregion #region Private Methods private void SetupDocumentForTree(Guid uniqueId, int level, int parentId, int creator, int writer, bool publish, string path, string text, DateTime createDate, DateTime updateDate, DateTime versionDate, string icon, bool hasChildren, string contentTypeAlias, string contentTypeThumb, string contentTypeDesc, int? masterContentType, int contentTypeId, int templateId) { SetupNodeForTree(uniqueId, _objectType, level, parentId, creator, path, text, createDate, hasChildren); _writerId = writer; _published = publish; _updated = updateDate; _template = templateId; ContentType = new ContentType(contentTypeId, contentTypeAlias, icon, contentTypeThumb, masterContentType); ContentTypeIcon = icon; VersionDate = versionDate; } private XmlAttribute addAttribute(XmlDocument Xd, string Name, string Value) { XmlAttribute temp = Xd.CreateAttribute(Name); temp.Value = Value; return temp; } private void saveXml(XmlNode x) { bool exists = (SqlHelper.ExecuteScalar("SELECT COUNT(nodeId) FROM cmsContentXml WHERE nodeId=@nodeId", SqlHelper.CreateParameter("@nodeId", Id)) != 0); string sql = exists ? "UPDATE cmsContentXml SET xml = @xml WHERE nodeId=@nodeId" : "INSERT INTO cmsContentXml(nodeId, xml) VALUES (@nodeId, @xml)"; SqlHelper.ExecuteNonQuery(sql, SqlHelper.CreateParameter("@nodeId", Id), SqlHelper.CreateParameter("@xml", x.OuterXml)); } private XmlNode importXml() { XmlDocument xmlDoc = new XmlDocument(); XmlReader xmlRdr = SqlHelper.ExecuteXmlReader(string.Format( "select xml from cmsContentXml where nodeID = {0}", Id)); xmlDoc.Load(xmlRdr); return xmlDoc.FirstChild; } /// /// Used internally to permanently delete the data from the database /// /// returns true if deletion isn't cancelled private bool DeletePermanently() { DeleteEventArgs e = new DeleteEventArgs(); FireBeforeDelete(e); if (!e.Cancel) { foreach (Document d in Children.ToList()) { d.DeletePermanently(); } umbraco.BusinessLogic.Actions.Action.RunActionHandlers(this, ActionDelete.Instance); // Remove all files DeleteAssociatedMediaFiles(); //remove any domains associated var domains = Domain.GetDomainsById(this.Id).ToList(); domains.ForEach(x => x.Delete()); SqlHelper.ExecuteNonQuery("delete from cmsDocument where NodeId = " + Id); base.delete(); FireAfterDelete(e); } return !e.Cancel; } /// /// Used internally to move the node to the recyle bin /// /// Returns true if the move was not cancelled private bool MoveToTrash() { MoveToTrashEventArgs e = new MoveToTrashEventArgs(); FireBeforeMoveToTrash(e); if (!e.Cancel) { umbraco.BusinessLogic.Actions.Action.RunActionHandlers(this, ActionDelete.Instance); UnPublish(); Move((int)RecycleBin.RecycleBinType.Content); FireAfterMoveToTrash(e); } return !e.Cancel; } #endregion #region Events /// /// The save event handler /// public delegate void SaveEventHandler(Document sender, SaveEventArgs e); /// /// The New event handler /// public delegate void NewEventHandler(Document sender, NewEventArgs e); /// /// The delete event handler /// public delegate void DeleteEventHandler(Document sender, DeleteEventArgs e); /// /// The publish event handler /// public delegate void PublishEventHandler(Document sender, PublishEventArgs e); /// /// The Send To Publish event handler /// public delegate void SendToPublishEventHandler(Document sender, SendToPublishEventArgs e); /// /// The unpublish event handler /// public delegate void UnPublishEventHandler(Document sender, UnPublishEventArgs e); /// /// The copy event handler /// public delegate void CopyEventHandler(Document sender, CopyEventArgs e); /// /// The rollback event handler /// public delegate void RollBackEventHandler(Document sender, RollBackEventArgs e); /// /// The Move to trash event handler /// public delegate void MoveToTrashEventHandler(Document sender, MoveToTrashEventArgs e); /// /// Occurs when [before save]. /// public static event SaveEventHandler BeforeSave; /// /// Raises the event. /// /// The instance containing the event data. protected internal new virtual void FireBeforeSave(SaveEventArgs e) { if (BeforeSave != null) { BeforeSave(this, e); } } /// /// Occurs when [after save]. /// public static event SaveEventHandler AfterSave; /// /// Raises the event. /// /// The instance containing the event data. protected virtual void FireAfterSave(SaveEventArgs e) { if (AfterSave != null) { AfterSave(this, e); } } /// /// Occurs when [new]. /// public static event NewEventHandler New; /// /// Raises the event. /// /// The instance containing the event data. protected virtual void OnNew(NewEventArgs e) { if (New != null) New(this, e); } //TODO: Slace - Document this public static event EventHandler Newing; protected static void OnNewing(DocumentNewingEventArgs e) { if (Newing != null) { Newing(null, e); } } /// /// Occurs when [before delete]. /// public new static event DeleteEventHandler BeforeDelete; /// /// Raises the event. /// /// The instance containing the event data. protected new virtual void FireBeforeDelete(DeleteEventArgs e) { if (BeforeDelete != null) BeforeDelete(this, e); } /// /// Occurs when [after delete]. /// public new static event DeleteEventHandler AfterDelete; /// /// Raises the event. /// /// The instance containing the event data. protected new virtual void FireAfterDelete(DeleteEventArgs e) { if (AfterDelete != null) AfterDelete(this, e); } /// /// Occurs when [before delete]. /// public static event MoveToTrashEventHandler BeforeMoveToTrash; /// /// Raises the event. /// /// The instance containing the event data. protected virtual void FireBeforeMoveToTrash(MoveToTrashEventArgs e) { if (BeforeMoveToTrash != null) BeforeMoveToTrash(this, e); } /// /// Occurs when [after move to trash]. /// public static event MoveToTrashEventHandler AfterMoveToTrash; /// /// Fires the after move to trash. /// /// The instance containing the event data. protected virtual void FireAfterMoveToTrash(MoveToTrashEventArgs e) { if (AfterMoveToTrash != null) AfterMoveToTrash(this, e); } /// /// Occurs when [before publish]. /// public static event PublishEventHandler BeforePublish; /// /// Raises the event. /// /// The instance containing the event data. protected virtual void FireBeforePublish(PublishEventArgs e) { if (BeforePublish != null) BeforePublish(this, e); } /// /// Occurs when [after publish]. /// public static event PublishEventHandler AfterPublish; /// /// Raises the event. /// /// The instance containing the event data. protected virtual void FireAfterPublish(PublishEventArgs e) { if (AfterPublish != null) AfterPublish(this, e); } /// /// Occurs when [before publish]. /// public static event SendToPublishEventHandler BeforeSendToPublish; /// /// Raises the event. /// /// The instance containing the event data. protected virtual void FireBeforeSendToPublish(SendToPublishEventArgs e) { if (BeforeSendToPublish != null) BeforeSendToPublish(this, e); } /// /// Occurs when [after publish]. /// public static event SendToPublishEventHandler AfterSendToPublish; /// /// Raises the event. /// /// The instance containing the event data. protected virtual void FireAfterSendToPublish(SendToPublishEventArgs e) { if (AfterSendToPublish != null) AfterSendToPublish(this, e); } /// /// Occurs when [before un publish]. /// public static event UnPublishEventHandler BeforeUnPublish; /// /// Raises the event. /// /// The instance containing the event data. protected virtual void FireBeforeUnPublish(UnPublishEventArgs e) { if (BeforeUnPublish != null) BeforeUnPublish(this, e); } /// /// Occurs when [after un publish]. /// public static event UnPublishEventHandler AfterUnPublish; /// /// Raises the event. /// /// The instance containing the event data. protected virtual void FireAfterUnPublish(UnPublishEventArgs e) { if (AfterUnPublish != null) AfterUnPublish(this, e); } /// /// Occurs when [before copy]. /// public static event CopyEventHandler BeforeCopy; /// /// Raises the event. /// /// The instance containing the event data. protected virtual void FireBeforeCopy(CopyEventArgs e) { if (BeforeCopy != null) BeforeCopy(this, e); } /// /// Occurs when [after copy]. /// public static event CopyEventHandler AfterCopy; /// /// Raises the event. /// /// The instance containing the event data. protected virtual void FireAfterCopy(CopyEventArgs e) { if (AfterCopy != null) AfterCopy(this, e); } /// /// Occurs when [before roll back]. /// public static event RollBackEventHandler BeforeRollBack; /// /// Raises the event. /// /// The instance containing the event data. protected virtual void FireBeforeRollBack(RollBackEventArgs e) { if (BeforeRollBack != null) BeforeRollBack(this, e); } /// /// Occurs when [after roll back]. /// public static event RollBackEventHandler AfterRollBack; /// /// Raises the event. /// /// The instance containing the event data. protected virtual void FireAfterRollBack(RollBackEventArgs e) { if (AfterRollBack != null) AfterRollBack(this, e); } #endregion } }