/// <summary> /// Creates a log entry representing the changes in the diff tree /// </summary> /// <param name="document">Document changes were made to</param> /// <param name="tree">Tree that should be logged</param> /// <param name="extraInfo">Text that should be displayed when clicking the magnifying glass in the audit log form</param> /// <returns></returns> public static AuditLogEntry CreateSettingsChangeEntry(SrmDocument document, DiffTree tree, string extraInfo = null) { if (tree.Root == null) { return(null); } var result = new AuditLogEntry(document, tree.TimeStamp, string.Empty, true, extraInfo); var nodeNamePair = tree.Root.FindFirstMultiChildParent(tree, PropertyName.ROOT, true, false); // Remove "Settings" from property name if possible if (nodeNamePair.Name != null && nodeNamePair.Name.Parent != PropertyName.ROOT) { var name = nodeNamePair.Name; while (name.Parent.Parent != PropertyName.ROOT) { name = name.Parent; } if (name.Parent.Name == "{0:Settings}") // Not L10N { name = RemoveTopmostParent(nodeNamePair.Name); nodeNamePair = nodeNamePair.ChangeName(name); } } result.UndoRedo = nodeNamePair.ToMessage(LogLevel.undo_redo); result.Summary = tree.Root.FindFirstMultiChildParent(tree, PropertyName.ROOT, false, false) .ToMessage(LogLevel.summary); result.AllInfo = tree.Root.FindAllLeafNodes(tree, PropertyName.ROOT, true) .Select(n => n.ToMessage(LogLevel.all_info)).ToArray(); return(result); }
public AuditLogEntry ChangeParent(AuditLogEntry parent) { return(ChangeProp(ImClone(this), im => { im.Parent = parent; im.Count = parent.Count + 1; })); }
/// <summary> /// Creates a simple entry only containing one message in each category with the given type and names and /// extra info /// </summary> public static AuditLogEntry CreateSingleMessageEntry(SrmDocument document, MessageInfo info, string extraInfo = null) { var result = new AuditLogEntry(document, DateTime.Now, string.Empty, true, extraInfo) { UndoRedo = info.ToMessage(LogLevel.undo_redo), Summary = info.ToMessage(LogLevel.summary), AllInfo = new LogMessage[0]//new[] { info.ToMessage(LogLevel.all_info) } }; return(result); }
/// <summary> /// Updates the document with the given AuditLogEntry. If the entry is non-null and logging is enabled, /// it is added to the document. If audit logging changed from being disabled to enabled and the document is different /// from the default document(no children, default settings) a "start from existing document" entry is added. If audit logging /// changes from being enabled to disabled, the log is cleared. /// </summary> /// <param name="entry">The entry to add</param> /// <param name="docPair">Document pair containing the new document the entry should get added to</param> /// <returns>A new document with this entry added</returns> public static SrmDocument UpdateDocument(AuditLogEntry entry, SrmDocumentPair docPair) { var newDoc = docPair.NewDoc; /*if (Settings.Default.AuditLogging || CountEntryType == MessageType.log_cleared) * { * newDoc = newDoc.ChangeAuditLog(ChangeParent(docPair.NewDoc.AuditLog.AuditLogEntries)); * } * else * { * var entry = CreateUnloggedEntry(document, out var replace); * * // This is the only property we have to copy over, since we don't care about the content of the log message * // but still want the ability to undo unlogged entries. We only change the undo action for the first * // unlogged message entry, otherwise clicking the undo button in the grid would undo the unlogged changes one-by-one * // instead of in a single "batch undo." TODO: Is this how it should be? * // (This one-by-one behavior can still be achieved by using the undo redo buffer) * if (!replace) * entry = entry.ChangeUndoAction(_undoAction); * * var oldEntries = document.AuditLog.AuditLogEntries; * var newEntries = replace * ? entry.ChangeParent(oldEntries?.Parent) * : entry.ChangeParent(oldEntries); * * newDoc = document.ChangeAuditLog(newEntries); * }*/ var oldLogging = docPair.OldDoc.Settings.DataSettings.AuditLogging; var newLogging = docPair.NewDoc.Settings.DataSettings.AuditLogging; if (oldLogging && !newLogging) { return(newDoc.ChangeAuditLog(ROOT)); } else if (!oldLogging && newLogging) { var startEntry = GetAuditLoggingStartExistingDocEntry(newDoc); if (startEntry != null && entry != null) { startEntry = startEntry.ChangeParent(entry); } entry = startEntry ?? entry; } if (newLogging) { newDoc = entry?.AppendEntryToDocument(newDoc) ?? newDoc; } return(newDoc); }
/// <summary> /// Creates a log entry indicating that logging was enabled or disabled /// </summary> public static AuditLogEntry CreateLogEnabledDisabledEntry(SrmDocument document) { var result = new AuditLogEntry(document, DateTime.Now, string.Empty); var type = Settings.Default.AuditLogging ? MessageType.log_enabled : MessageType.log_disabled; result.UndoRedo = new LogMessage(LogLevel.undo_redo, type, string.Empty, false); result.Summary = new LogMessage(LogLevel.summary, type, string.Empty, false); result.AllInfo = new List <LogMessage> { new LogMessage(LogLevel.all_info, type, string.Empty, false) }; return(result); }
public void ReadXml(XmlReader reader) { var isEmpty = reader.IsEmptyElement; reader.ReadStartElement(); AuditLogEntries = ReadEntries(reader); if (!isEmpty) { reader.ReadEndElement(); } Validate(); }
/// <summary> /// Merges two audit log entries, by adding the other entries /// all info messages and extra info to the current entry /// </summary> /// <param name="other">Entry to merge into the current one</param> /// <param name="append">true if all info and extra info should be appended, if false they are replaced</param> /// <returns>A new, merged entry</returns> public AuditLogEntry Merge(AuditLogEntry other, bool append = true) { if (other == null) { return(this); } var entry = append ? AppendAllInfo(other._mergeAllInfo) : ChangeAllInfo(other._mergeAllInfo.ToList()); if (!string.IsNullOrEmpty(other.ExtraInfo)) { entry = entry.ChangeExtraInfo(string.IsNullOrEmpty(ExtraInfo) || !append ? other.ExtraInfo : TextUtil.LineSeparate(ExtraInfo, other.ExtraInfo)); } return(entry); }
public string GetHash() { // Surprisingly, the XmlTextWriter disposes the stream using (var stream = new MemoryStream()) { using (var writer = new XmlTextWriter(stream, Encoding.UTF8) { Formatting = Formatting.Indented }) { WriteToXmlWriter(writer); stream.Seek(0, SeekOrigin.Begin); // Leave stream open, otherwise XmlTextWriter will try to close it which causes an exception using (var reader = new StreamReader(stream, Encoding.UTF8, true, 1024, true)) { return(AuditLogEntry.Hash(reader.ReadToEnd())); } } } }
protected virtual AuditLogEntry CreateEntry(SrmDocumentPair docPair) { var baseEntry = CreateBaseEntry(docPair); var rootProp = RootProperty.Create(typeof(T)); var objectInfo = new ObjectInfo <object>() .ChangeObjectPair(ObjectPair <object> .Create(null, this)) .ChangeRootObjectPair(docPair.ToObjectType()); var diffTree = DiffTree.FromEnumerator(Reflector <T> .EnumerateDiffNodes(docPair.ToObjectType(), rootProp, (T)this), DateTime.Now); if (diffTree.Root == null) { return(baseEntry); } var settingsString = Reflector <T> .ToString(objectInfo.RootObjectPair, diffTree.Root, ToStringState.DEFAULT.ChangeFormatWhitespace(true)); var entry = AuditLogEntry.CreateSettingsChangeEntry(docPair.OldDoc, diffTree, settingsString); return(baseEntry.Merge(entry)); }
protected virtual AuditLogEntry CreateBaseEntry(SrmDocumentPair docPair) { return(MessageInfo.Type == MessageType.none ? AuditLogEntry.CreateEmptyEntry(docPair.OldDoc).ChangeAllInfo(new LogMessage[0]) : AuditLogEntry.CreateSingleMessageEntry(docPair.OldDoc, MessageInfo)); }
public AuditLogEntryAddedEventArgs(AuditLogEntry entry) { Entry = entry; }
public void Add(params MessageInfo[] allInfoMessages) { Add(docPair => AuditLogEntry.CreateEmptyEntry(docPair.OldDoc).ChangeAllInfo(allInfoMessages)); }
public AuditLogList(AuditLogEntry entries) { AuditLogEntries = entries; }