using System; using System.Data; using System.Diagnostics; using System.Threading; using umbraco.DataLayer; namespace umbraco.BusinessLogic { /// /// Summary description for Log. /// public class Log { #region Statics private static ISqlHelper SqlHelper { get { return Application.SqlHelper; } } /// /// Adds the specified log item to the log. /// /// The log type. /// The user adding the item. /// The affected node id. /// Comment. public static void Add(LogTypes type, User user, int nodeId, string comment) { if(!UmbracoSettings.EnableLogging) return; if (UmbracoSettings.DisabledLogTypes != null && UmbracoSettings.DisabledLogTypes.SelectSingleNode(String.Format("//logTypeAlias [. = '{0}']", type.ToString().ToLower())) == null) { if (comment.Length > 3999) comment = comment.Substring(0, 3955) + "..."; if (UmbracoSettings.EnableAsyncLogging) { ThreadPool.QueueUserWorkItem( delegate { AddSynced(type, user == null ? 0 : user.Id, nodeId, comment); }); return; } AddSynced(type, user == null ? 0 : user.Id, nodeId, comment); } } /// /// Adds the specified log item to the log without any user information attached. /// /// The log type. /// The affected node id. /// Comment. public static void Add(LogTypes type, int nodeId, string comment) { Add(type, null, nodeId, comment); } /// /// Adds a log item to the log immidiately instead of Queuing it as a work item. /// /// The type. /// The user id. /// The node id. /// The comment. public static void AddSynced(LogTypes type, int userId, int nodeId, string comment) { try { SqlHelper.ExecuteNonQuery( "insert into umbracoLog (userId, nodeId, logHeader, logComment) values (@userId, @nodeId, @logHeader, @comment)", SqlHelper.CreateParameter("@userId", userId), SqlHelper.CreateParameter("@nodeId", nodeId), SqlHelper.CreateParameter("@logHeader", type.ToString()), SqlHelper.CreateParameter("@comment", comment)); } catch(Exception e) { Debug.WriteLine(e.ToString(), "Error"); Trace.WriteLine(e.ToString()); } } #region New GetLog methods - DataLayer layer compatible /// /// Gets a reader for the audit log. /// /// The node id. /// A reader for the audit log. public static IRecordsReader GetAuditLogReader(int NodeId) { return SqlHelper.ExecuteReader( "select u.userName as [User], logHeader as Action, DateStamp as Date, logComment as Comment from umbracoLog inner join umbracoUser u on u.id = userId where nodeId = @id and logHeader not in ('open','system') order by DateStamp desc", SqlHelper.CreateParameter("@id", NodeId)); } /// /// Gets a reader for the log for the specified types. /// /// The type of log message. /// The start date. /// A reader for the log. public static IRecordsReader GetLogReader(LogTypes Type, DateTime SinceDate) { return SqlHelper.ExecuteReader( "select userId, NodeId, DateStamp, logHeader, logComment from umbracoLog where logHeader = @logHeader and DateStamp >= @dateStamp order by dateStamp desc", SqlHelper.CreateParameter("@logHeader", Type.ToString()), SqlHelper.CreateParameter("@dateStamp", SinceDate)); } /// /// Gets a reader for the log of the specified node. /// /// The node id. /// A reader for the log. public static IRecordsReader GetLogReader(int NodeId) { return SqlHelper.ExecuteReader( "select u.userName, DateStamp, logHeader, logComment from umbracoLog inner join umbracoUser u on u.id = userId where nodeId = @id", SqlHelper.CreateParameter("@id", NodeId)); } /// /// Gets a reader for the log for the specified user. /// /// The user. /// The start date. /// A reader for the log. public static IRecordsReader GetLogReader(User user, DateTime SinceDate) { return SqlHelper.ExecuteReader( "select userId, NodeId, DateStamp, logHeader, logComment from umbracoLog where UserId = @user and DateStamp >= @dateStamp order by dateStamp desc", SqlHelper.CreateParameter("@user", user.Id), SqlHelper.CreateParameter("@dateStamp", SinceDate)); } /// /// Gets a reader of specific for the log for specific types and a specified user. /// /// The user. /// The type of log message. /// The since date. /// A reader for the log. public static IRecordsReader GetLogReader(User user, LogTypes Type, DateTime SinceDate) { return SqlHelper.ExecuteReader( "select userId, NodeId, DateStamp, logHeader, logComment from umbracoLog where UserId = @user and logHeader = @logHeader and DateStamp >= @dateStamp order by dateStamp desc", SqlHelper.CreateParameter("@logHeader", Type.ToString()), SqlHelper.CreateParameter("@user", user.Id), SqlHelper.CreateParameter("@dateStamp", SinceDate)); } #endregion #region Old GetLog methods - DataLayer incompatible #pragma warning disable 618 // ConvertToDataSet is obsolete /// /// Gets the log. /// /// The type. /// The start date. /// The log. /// Only guaranteed to work with SQL Server. Obsolete. [Obsolete("Not compatible with the data layer. Use GetLogReader instead.", true)] public static DataSet GetLog(LogTypes Type, DateTime SinceDate) { try { return ConvertToDataSet(GetLogReader(Type, SinceDate)); } catch (Exception) { throw new Exception("The GetLog method is not compatible with the data layer."); } } /// /// Returns a dataset of Log items with a specific type since a specific date. /// /// The type. /// The start date. /// Maximum number of results. /// The log. /// Only guaranteed to work with SQL Server. Obsolete. [Obsolete("Not compatible with the data layer. Use GetLogReader instead.", true)] public static DataSet GetLog(LogTypes Type, DateTime SinceDate, int Limit) { try { return ConvertToDataSet(SqlHelper.ExecuteReader( "select top " + Limit + " userId, NodeId, DateStamp, logHeader, logComment from umbracoLog where logHeader = @logHeader and DateStamp >= @dateStamp order by dateStamp desc", SqlHelper.CreateParameter("@logHeader", Type.ToString()), SqlHelper.CreateParameter("@dateStamp", SinceDate))); } catch (Exception) { throw new Exception("The GetLog method is not compatible with the data layer."); } } /// /// Returns a dataset of Log items for a specific node /// /// The node id. /// The log. /// Only guaranteed to work with SQL Server. Obsolete. [Obsolete("Not compatible with the data layer. Use GetLogReader instead.", true)] public static DataSet GetLog(int NodeId) { try { return ConvertToDataSet(GetLogReader(NodeId)); } catch (Exception) { throw new Exception("The GetLog method is not compatible with the data layer."); } } /// /// Returns a dataset of audit Log items for a specific node with more detailed user information /// /// The node id. /// The log. /// Only guaranteed to work with SQL Server. Obsolete. [Obsolete("Not compatible with the data layer. Use GetAuditLogReader instead.", true)] public static DataSet GetAuditLog(int NodeId) { try { return ConvertToDataSet(GetAuditLogReader(NodeId)); } catch (Exception) { throw new Exception("The GetAuditLog method is not compatible with the data layer."); } } /// /// Returns a dataset of Log items for a specific user, since a specific date /// /// The user. /// The start date. /// The log. /// Only guaranteed to work with SQL Server. Obsolete. [Obsolete("Not compatible with the data layer. Use GetAuditLogReader instead.", true)] public static DataSet GetLog(User u, DateTime SinceDate) { try { return ConvertToDataSet(GetLogReader(u, SinceDate)); } catch (Exception) { throw new Exception("The GetLog method is not compatible with the data layer."); } } /// /// Returns a dataset of Log items for a specific user of a specific type, since a specific date /// /// The user. /// The type. /// The start date. /// The log. /// Only guaranteed to work with SQL Server. Obsolete. [Obsolete("Not compatible with the data layer. Use GetLogReader instead.", true)] public static DataSet GetLog(User u, LogTypes Type, DateTime SinceDate) { try { return ConvertToDataSet(GetLogReader(u, Type, SinceDate)); } catch (Exception) { throw new Exception("The GetLog method is not compatible with the data layer."); } } /// /// Returns a dataset of Log items for a specific user of a specific type, since a specific date /// /// The user. /// The type. /// The since date. /// The limit. /// The log. /// Only guaranteed to work with SQL Server. Obsolete. [Obsolete("Not compatible with the data layer. Use GetLogReader instead.", true)] public static DataSet GetLog(User u, LogTypes Type, DateTime SinceDate, int Limit) { try { return ConvertToDataSet(SqlHelper.ExecuteReader( "select top " + Limit + " userId, NodeId, DateStamp, logHeader, logComment from umbracoLog where UserId = @user and logHeader = @logHeader and DateStamp >= @dateStamp order by dateStamp desc", SqlHelper.CreateParameter("@logHeader", Type.ToString()), SqlHelper.CreateParameter("@user", u.Id), SqlHelper.CreateParameter("@dateStamp", SinceDate))); } catch (Exception) { throw new Exception("The GetLog method is not compatible with the data layer."); } } /// /// Converts a records reader to a data set. /// /// The records reader. /// The data set /// Only works with DataLayer.SqlHelpers.SqlServer.SqlServerDataReader. /// When not an DataLayer.SqlHelpers.SqlServer.SqlServerDataReader. [Obsolete("Temporary workaround for old GetLog methods.", false)] private static DataSet ConvertToDataSet(IRecordsReader recordsReader) { // Get the internal RawDataReader (obsolete) System.Data.SqlClient.SqlDataReader reader = ((DataLayer.SqlHelpers.SqlServer.SqlServerDataReader)recordsReader).RawDataReader; DataSet dataSet = new DataSet(); do { DataTable dataTable = new DataTable(); DataTable schemaTable = reader.GetSchemaTable(); if (schemaTable != null) { // A query returning records was executed foreach (DataRow dataRow in schemaTable.Rows) { // Create a column name that is unique in the data table string columnName = (string)dataRow["ColumnName"]; // Add the column definition to the data table DataColumn column = new DataColumn(columnName, (Type)dataRow["DataType"]); dataTable.Columns.Add(column); } dataSet.Tables.Add(dataTable); // Fill the data table we just created while (reader.Read()) { DataRow dataRow = dataTable.NewRow(); for (int i = 0; i < reader.FieldCount; i++) dataRow[i] = reader.GetValue(i); dataTable.Rows.Add(dataRow); } } else { // No records were returned, return number of rows affected dataTable.Columns.Add(new DataColumn("RowsAffected")); dataSet.Tables.Add(dataTable); DataRow rowsAffectedRow = dataTable.NewRow(); rowsAffectedRow[0] = reader.RecordsAffected; dataTable.Rows.Add(rowsAffectedRow); } } // Go trough all result sets while (reader.NextResult()); // Close the data reader so the underlying connection is closed recordsReader.Close(); return dataSet; } #pragma warning restore 618 #endregion public static void CleanLogs(int maximumAgeOfLogsInMinutes) { try { DateTime oldestPermittedLogEntry = DateTime.Now.Subtract(new TimeSpan(0, maximumAgeOfLogsInMinutes, 0)); SqlHelper.ExecuteNonQuery("delete from umbracoLog where datestamp < @oldestPermittedLogEntry and logHeader in ('open','system')", SqlHelper.CreateParameter("@oldestPermittedLogEntry", oldestPermittedLogEntry)); Add(LogTypes.System, -1, "Log scrubbed. Removed all items older than " + oldestPermittedLogEntry); } catch (Exception e) { Debug.WriteLine(e.ToString(), "Error"); Trace.WriteLine(e.ToString()); } } #endregion } /// /// The collection of available log types. /// public enum LogTypes { /// /// Used when new nodes are added /// New, /// /// Used when nodes are saved /// Save, /// /// Used when nodes are opened /// Open, /// /// Used when nodes are deleted /// Delete, /// /// Used when nodes are published /// Publish, /// /// Used when nodes are send to publishing /// SendToPublish, /// /// Used when nodes are unpublished /// UnPublish, /// /// Used when nodes are moved /// Move, /// /// Used when nodes are copied /// Copy, /// /// Used when nodes are assígned a domain /// AssignDomain, /// /// Used when public access are changed for a node /// PublicAccess, /// /// Used when nodes are sorted /// Sort, /// /// Used when a notification are send to a user /// Notify, /// /// Used when a user logs into the umbraco back-end /// Login, /// /// Used when a user logs out of the umbraco back-end /// Logout, /// /// Used when a user login fails /// LoginFailure, /// /// General system notification /// System, /// /// System debugging notification /// Debug, /// /// System error notification /// Error, /// /// Notfound error notification /// NotFound, /// /// Used when a node's content is rolled back to a previous version /// RollBack, /// /// Used when a package is installed /// PackagerInstall, /// /// Used when a package is uninstalled /// PackagerUninstall, /// /// Used when a ping is send to/from the system /// Ping, /// /// Used when a node is send to translation /// SendToTranslate, /// /// Notification from a Scheduled task. /// ScheduledTask, /// /// Use this log action for custom log messages that should be shown in the audit trail /// Custom } }