AuditTrail: used file-scope namespaces

This commit is contained in:
Maksim Chegulov 2022-02-03 14:16:34 +03:00
parent 0cc387a4b8
commit fdc4652edb
20 changed files with 520 additions and 539 deletions

View File

@ -1,17 +1,16 @@
using System; using System;
namespace ASC.AuditTrail.Attributes namespace ASC.AuditTrail.Attributes;
{
[AttributeUsage(AttributeTargets.Property)]
public class EventAttribute : Attribute
{
public string Resource { get; private set; }
public int Order { get; private set; }
public EventAttribute(string resource, int order = 0) [AttributeUsage(AttributeTargets.Property)]
{ public class EventAttribute : Attribute
Resource = resource; {
Order = order; public string Resource { get; private set; }
} public int Order { get; private set; }
public EventAttribute(string resource, int order = 0)
{
Resource = resource;
Order = order;
} }
} }

View File

@ -43,58 +43,57 @@ using CsvHelper;
using Microsoft.Extensions.Options; using Microsoft.Extensions.Options;
namespace ASC.AuditTrail namespace ASC.AuditTrail;
[Scope]
public class AuditReportCreator
{ {
[Scope] private readonly GlobalFolderHelper _globalFolderHelper;
public class AuditReportCreator private readonly FileUploader _fileUploader;
{ private readonly FilesLinkUtility _filesLinkUtility;
private readonly GlobalFolderHelper _globalFolderHelper; private readonly CommonLinkUtility _commonLinkUtility;
private readonly FileUploader _fileUploader; private readonly ILog _logger;
private readonly FilesLinkUtility _filesLinkUtility;
private readonly CommonLinkUtility _commonLinkUtility;
private readonly ILog _logger;
public AuditReportCreator(
GlobalFolderHelper globalFolderHelper,
IOptionsMonitor<ILog> options,
FileUploader fileUploader,
FilesLinkUtility filesLinkUtility,
CommonLinkUtility commonLinkUtility)
{
_globalFolderHelper = globalFolderHelper;
_logger = options.CurrentValue;
_fileUploader = fileUploader;
_filesLinkUtility = filesLinkUtility;
_commonLinkUtility = commonLinkUtility;
}
public string CreateCsvReport<TEvent>(IEnumerable<TEvent> events, string reportName) where TEvent : BaseEvent
{
try
{
using var stream = new MemoryStream();
using var writer = new StreamWriter(stream, Encoding.UTF8);
using var csv = new CsvWriter(writer, CultureInfo.CurrentCulture);
csv.Configuration.RegisterClassMap(new BaseEventMap<TEvent>()); public AuditReportCreator(
GlobalFolderHelper globalFolderHelper,
IOptionsMonitor<ILog> options,
FileUploader fileUploader,
FilesLinkUtility filesLinkUtility,
CommonLinkUtility commonLinkUtility)
{
_globalFolderHelper = globalFolderHelper;
_logger = options.CurrentValue;
_fileUploader = fileUploader;
_filesLinkUtility = filesLinkUtility;
_commonLinkUtility = commonLinkUtility;
}
csv.WriteHeader<TEvent>(); public string CreateCsvReport<TEvent>(IEnumerable<TEvent> events, string reportName) where TEvent : BaseEvent
csv.NextRecord(); {
csv.WriteRecords(events); try
writer.Flush(); {
using var stream = new MemoryStream();
using var writer = new StreamWriter(stream, Encoding.UTF8);
using var csv = new CsvWriter(writer, CultureInfo.CurrentCulture);
var file = _fileUploader.Exec(_globalFolderHelper.FolderMy, reportName, stream.Length, stream, true); csv.Configuration.RegisterClassMap(new BaseEventMap<TEvent>());
var fileUrl = _commonLinkUtility.GetFullAbsolutePath(_filesLinkUtility.GetFileWebEditorUrl(file.ID));
fileUrl += string.Format("&options={{\"codePage\":{0}}}", Encoding.UTF8.CodePage); csv.WriteHeader<TEvent>();
csv.NextRecord();
csv.WriteRecords(events);
writer.Flush();
return fileUrl; var file = _fileUploader.Exec(_globalFolderHelper.FolderMy, reportName, stream.Length, stream, true);
} var fileUrl = _commonLinkUtility.GetFullAbsolutePath(_filesLinkUtility.GetFileWebEditorUrl(file.ID));
catch (Exception ex)
{ fileUrl += string.Format("&options={{\"codePage\":{0}}}", Encoding.UTF8.CodePage);
_logger.Error("Error while generating login report: " + ex);
throw; return fileUrl;
} }
} catch (Exception ex)
} {
_logger.Error("Error while generating login report: " + ex);
throw;
}
}
} }

View File

@ -35,120 +35,119 @@ using ASC.MessagingSystem;
using Microsoft.Extensions.Options; using Microsoft.Extensions.Options;
namespace ASC.AuditTrail.Mappers namespace ASC.AuditTrail.Mappers;
[Singletone]
public class AuditActionMapper
{ {
[Singletone] private readonly Dictionary<MessageAction, MessageMaps> _actions;
public class AuditActionMapper private readonly ILog _logger;
{
private readonly Dictionary<MessageAction, MessageMaps> _actions; public AuditActionMapper(IOptionsMonitor<ILog> options)
private readonly ILog _logger; {
_actions = new Dictionary<MessageAction, MessageMaps>();
public AuditActionMapper(IOptionsMonitor<ILog> options) _logger = options.CurrentValue;
{
_actions = new Dictionary<MessageAction, MessageMaps>(); _actions = _actions
_logger = options.CurrentValue; .Union(LoginActionsMapper.GetMaps())
.Union(ProjectsActionsMapper.GetMaps())
_actions = _actions .Union(CrmActionMapper.GetMaps())
.Union(LoginActionsMapper.GetMaps()) .Union(PeopleActionMapper.GetMaps())
.Union(ProjectsActionsMapper.GetMaps()) .Union(DocumentsActionMapper.GetMaps())
.Union(CrmActionMapper.GetMaps()) .Union(SettingsActionsMapper.GetMaps())
.Union(PeopleActionMapper.GetMaps()) .Union(OthersActionsMapper.GetMaps())
.Union(DocumentsActionMapper.GetMaps()) .ToDictionary(x => x.Key, x => x.Value);
.Union(SettingsActionsMapper.GetMaps()) }
.Union(OthersActionsMapper.GetMaps())
.ToDictionary(x => x.Key, x => x.Value); public string GetActionText(AuditEventDto evt)
} {
var action = (MessageAction)evt.Action;
public string GetActionText(AuditEvent evt) if (!_actions.ContainsKey(action))
{ {
var action = (MessageAction)evt.Action; _logger.Error(string.Format("There is no action text for \"{0}\" type of event", action));
if (!_actions.ContainsKey(action))
{ return string.Empty;
_logger.Error(string.Format("There is no action text for \"{0}\" type of event", action)); }
return string.Empty; try
} {
var actionText = _actions[(MessageAction)evt.Action].GetActionText();
try
{ if (evt.Description == null || !evt.Description.Any()) return actionText;
var actionText = _actions[(MessageAction)evt.Action].GetActionText();
var description = evt.Description
if (evt.Description == null || !evt.Description.Any()) return actionText; .Select(t => t.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries))
.Select(split => string.Join(", ", split.Select(ToLimitedText))).ToArray();
var description = evt.Description
.Select(t => t.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries))
.Select(split => string.Join(", ", split.Select(ToLimitedText))).ToArray(); return string.Format(actionText, description);
}
catch
return string.Format(actionText, description); {
} //log.Error(string.Format("Error while building action text for \"{0}\" type of event", action));
catch return string.Empty;
{ }
//log.Error(string.Format("Error while building action text for \"{0}\" type of event", action)); }
return string.Empty;
} public string GetActionText(LoginEventDTO evt)
} {
var action = (MessageAction)evt.Action;
public string GetActionText(LoginEvent evt) if (!_actions.ContainsKey(action))
{ {
var action = (MessageAction)evt.Action; //log.Error(string.Format("There is no action text for \"{0}\" type of event", action));
if (!_actions.ContainsKey(action)) return string.Empty;
{ }
//log.Error(string.Format("There is no action text for \"{0}\" type of event", action));
return string.Empty; try
} {
var actionText = _actions[(MessageAction)evt.Action].GetActionText();
try
{ if (evt.Description == null || !evt.Description.Any()) return actionText;
var actionText = _actions[(MessageAction)evt.Action].GetActionText();
var description = evt.Description
if (evt.Description == null || !evt.Description.Any()) return actionText; .Select(t => t.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries))
.Select(split => string.Join(", ", split.Select(ToLimitedText))).ToArray();
var description = evt.Description
.Select(t => t.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries)) return string.Format(actionText, description);
.Select(split => string.Join(", ", split.Select(ToLimitedText))).ToArray(); }
catch
return string.Format(actionText, description); {
} //log.Error(string.Format("Error while building action text for \"{0}\" type of event", action));
catch return string.Empty;
{ }
//log.Error(string.Format("Error while building action text for \"{0}\" type of event", action)); }
return string.Empty;
} public string GetActionTypeText(AuditEventDto evt)
} {
var action = (MessageAction)evt.Action;
public string GetActionTypeText(AuditEvent evt)
{ return !_actions.ContainsKey(action)
var action = (MessageAction)evt.Action; ? string.Empty
: _actions[(MessageAction)evt.Action].GetActionTypeText();
return !_actions.ContainsKey(action) }
? string.Empty
: _actions[(MessageAction)evt.Action].GetActionTypeText(); public string GetProductText(AuditEventDto evt)
} {
var action = (MessageAction)evt.Action;
public string GetProductText(AuditEvent evt)
{ return !_actions.ContainsKey(action)
var action = (MessageAction)evt.Action; ? string.Empty
: _actions[(MessageAction)evt.Action].GetProduct();
return !_actions.ContainsKey(action) }
? string.Empty
: _actions[(MessageAction)evt.Action].GetProduct(); public string GetModuleText(AuditEventDto evt)
} {
var action = (MessageAction)evt.Action;
public string GetModuleText(AuditEvent evt)
{ return !_actions.ContainsKey(action)
var action = (MessageAction)evt.Action; ? string.Empty
: _actions[(MessageAction)evt.Action].GetModule();
return !_actions.ContainsKey(action) }
? string.Empty
: _actions[(MessageAction)evt.Action].GetModule(); private string ToLimitedText(string text)
} {
if (text == null) return null;
private string ToLimitedText(string text)
{ return text.Length < 50 ? text : string.Format("{0}...", text.Substring(0, 47));
if (text == null) return null; }
return text.Length < 50 ? text : string.Format("{0}...", text.Substring(0, 47));
}
}
} }

View File

@ -30,13 +30,13 @@ using System.Collections.Generic;
using ASC.MessagingSystem; using ASC.MessagingSystem;
namespace ASC.AuditTrail.Mappers namespace ASC.AuditTrail.Mappers;
{
internal class CrmActionMapper internal class CrmActionMapper
{ {
public static Dictionary<MessageAction, MessageMaps> GetMaps() => public static Dictionary<MessageAction, MessageMaps> GetMaps() =>
new Dictionary<MessageAction, MessageMaps> new Dictionary<MessageAction, MessageMaps>
{ {
#region companies #region companies
{ {
@ -1618,9 +1618,8 @@ namespace ASC.AuditTrail.Mappers
ProductResourceName = "CrmProduct", ProductResourceName = "CrmProduct",
ModuleResourceName = "CasesModule" ModuleResourceName = "CasesModule"
} }
}, },
#endregion #endregion
}; };
}
} }

View File

@ -29,13 +29,13 @@ using System.Collections.Generic;
using ASC.MessagingSystem; using ASC.MessagingSystem;
namespace ASC.AuditTrail.Mappers namespace ASC.AuditTrail.Mappers;
{
internal class DocumentsActionMapper internal class DocumentsActionMapper
{ {
public static Dictionary<MessageAction, MessageMaps> GetMaps() => public static Dictionary<MessageAction, MessageMaps> GetMaps() =>
new Dictionary<MessageAction, MessageMaps> new Dictionary<MessageAction, MessageMaps>
{ {
{ {
MessageAction.FileRenamed, new MessageMaps MessageAction.FileRenamed, new MessageMaps
{ {
@ -413,7 +413,6 @@ namespace ASC.AuditTrail.Mappers
ProductResourceName = "DocumentsProduct", ProductResourceName = "DocumentsProduct",
ModuleResourceName = "FilesModule" ModuleResourceName = "FilesModule"
} }
}, },
}; };
}
} }

View File

@ -30,13 +30,13 @@ using System.Collections.Generic;
using ASC.MessagingSystem; using ASC.MessagingSystem;
namespace ASC.AuditTrail.Mappers namespace ASC.AuditTrail.Mappers;
{
internal class LoginActionsMapper internal class LoginActionsMapper
{ {
public static Dictionary<MessageAction, MessageMaps> GetMaps() => public static Dictionary<MessageAction, MessageMaps> GetMaps() =>
new Dictionary<MessageAction, MessageMaps> new Dictionary<MessageAction, MessageMaps>
{ {
{ MessageAction.LoginSuccess, new MessageMaps { ActionTextResourceName = "LoginSuccess"} }, { MessageAction.LoginSuccess, new MessageMaps { ActionTextResourceName = "LoginSuccess"} },
{ MessageAction.LoginSuccessViaSocialAccount, new MessageMaps { ActionTextResourceName = "LoginSuccessSocialAccount"} }, { MessageAction.LoginSuccessViaSocialAccount, new MessageMaps { ActionTextResourceName = "LoginSuccessSocialAccount"} },
{ MessageAction.LoginSuccessViaSocialApp, new MessageMaps { ActionTextResourceName = "LoginSuccessSocialApp"} }, { MessageAction.LoginSuccessViaSocialApp, new MessageMaps { ActionTextResourceName = "LoginSuccessSocialApp"} },
@ -63,7 +63,6 @@ namespace ASC.AuditTrail.Mappers
{ MessageAction.LoginFailRecaptcha, new MessageMaps { ActionTextResourceName = "LoginFailRecaptcha" } }, { MessageAction.LoginFailRecaptcha, new MessageMaps { ActionTextResourceName = "LoginFailRecaptcha" } },
{ MessageAction.Logout, new MessageMaps { ActionTextResourceName = "Logout" } }, { MessageAction.Logout, new MessageMaps { ActionTextResourceName = "Logout" } },
{ MessageAction.SessionStarted, new MessageMaps { ActionTextResourceName = "SessionStarted" } }, { MessageAction.SessionStarted, new MessageMaps { ActionTextResourceName = "SessionStarted" } },
{ MessageAction.SessionCompleted, new MessageMaps { ActionTextResourceName = "SessionCompleted" } } { MessageAction.SessionCompleted, new MessageMaps { ActionTextResourceName = "SessionCompleted" } }
}; };
}
} }

View File

@ -28,61 +28,60 @@
namespace ASC.AuditTrail.Mappers namespace ASC.AuditTrail.Mappers;
internal class MessageMaps
{ {
internal class MessageMaps public string ActionTypeTextResourceName { get; set; }
public string ActionTextResourceName { get; set; }
public string ProductResourceName { get; set; }
public string ModuleResourceName { get; set; }
public string GetActionTypeText()
{ {
public string ActionTypeTextResourceName { get; set; } try
public string ActionTextResourceName { get; set; }
public string ProductResourceName { get; set; }
public string ModuleResourceName { get; set; }
public string GetActionTypeText()
{ {
try return AuditReportResource.ResourceManager.GetString(ActionTypeTextResourceName);
{
return AuditReportResource.ResourceManager.GetString(ActionTypeTextResourceName);
}
catch
{
return null;
}
} }
catch
public string GetActionText()
{ {
try return null;
{
return AuditReportResource.ResourceManager.GetString(ActionTextResourceName);
}
catch
{
return null;
}
} }
}
public string GetProduct() public string GetActionText()
{
try
{ {
try return AuditReportResource.ResourceManager.GetString(ActionTextResourceName);
{
return AuditReportResource.ResourceManager.GetString(ProductResourceName);
}
catch
{
return null;
}
} }
catch
public string GetModule()
{ {
try return null;
{ }
return AuditReportResource.ResourceManager.GetString(ModuleResourceName); }
}
catch public string GetProduct()
{ {
return null; try
} {
return AuditReportResource.ResourceManager.GetString(ProductResourceName);
}
catch
{
return null;
}
}
public string GetModule()
{
try
{
return AuditReportResource.ResourceManager.GetString(ModuleResourceName);
}
catch
{
return null;
} }
} }
} }

View File

@ -30,13 +30,13 @@ using System.Collections.Generic;
using ASC.MessagingSystem; using ASC.MessagingSystem;
namespace ASC.AuditTrail.Mappers namespace ASC.AuditTrail.Mappers;
{
internal class OthersActionsMapper internal class OthersActionsMapper
{ {
public static Dictionary<MessageAction, MessageMaps> GetMaps() => public static Dictionary<MessageAction, MessageMaps> GetMaps() =>
new Dictionary<MessageAction, MessageMaps> new Dictionary<MessageAction, MessageMaps>
{ {
{ {
MessageAction.ContactAdminMailSent, new MessageMaps MessageAction.ContactAdminMailSent, new MessageMaps
{ {
@ -44,7 +44,6 @@ namespace ASC.AuditTrail.Mappers
ActionTextResourceName = "ContactAdminMailSent", ActionTextResourceName = "ContactAdminMailSent",
ProductResourceName = "OthersProduct" ProductResourceName = "OthersProduct"
} }
} }
}; };
}
} }

View File

@ -30,13 +30,13 @@ using System.Collections.Generic;
using ASC.MessagingSystem; using ASC.MessagingSystem;
namespace ASC.AuditTrail.Mappers namespace ASC.AuditTrail.Mappers;
{
internal class PeopleActionMapper internal class PeopleActionMapper
{ {
public static Dictionary<MessageAction, MessageMaps> GetMaps() => public static Dictionary<MessageAction, MessageMaps> GetMaps() =>
new Dictionary<MessageAction, MessageMaps> new Dictionary<MessageAction, MessageMaps>
{ {
{ {
MessageAction.UserCreated, new MessageMaps MessageAction.UserCreated, new MessageMaps
{ {
@ -351,7 +351,6 @@ namespace ASC.AuditTrail.Mappers
ProductResourceName = "PeopleProduct", ProductResourceName = "PeopleProduct",
ModuleResourceName = "UsersModule" ModuleResourceName = "UsersModule"
} }
} }
}; };
}
} }

View File

@ -29,13 +29,13 @@ using System.Collections.Generic;
using ASC.MessagingSystem; using ASC.MessagingSystem;
namespace ASC.AuditTrail.Mappers namespace ASC.AuditTrail.Mappers;
{
internal class ProjectsActionsMapper internal class ProjectsActionsMapper
{ {
public static Dictionary<MessageAction, MessageMaps> GetMaps() => public static Dictionary<MessageAction, MessageMaps> GetMaps() =>
new Dictionary<MessageAction, MessageMaps> new Dictionary<MessageAction, MessageMaps>
{ {
#region projects #region projects
{ {
@ -604,9 +604,8 @@ namespace ASC.AuditTrail.Mappers
ProductResourceName = "ProjectsProduct", ProductResourceName = "ProjectsProduct",
ModuleResourceName = "ProjectsModule" ModuleResourceName = "ProjectsModule"
} }
}, },
#endregion #endregion
}; };
}
} }

View File

@ -29,13 +29,13 @@ using System.Collections.Generic;
using ASC.MessagingSystem; using ASC.MessagingSystem;
namespace ASC.AuditTrail.Mappers namespace ASC.AuditTrail.Mappers;
{
internal class SettingsActionsMapper internal class SettingsActionsMapper
{ {
public static Dictionary<MessageAction, MessageMaps> GetMaps() => public static Dictionary<MessageAction, MessageMaps> GetMaps() =>
new Dictionary<MessageAction, MessageMaps> new Dictionary<MessageAction, MessageMaps>
{ {
{ {
MessageAction.LanguageSettingsUpdated, new MessageMaps MessageAction.LanguageSettingsUpdated, new MessageMaps
{ {
@ -476,7 +476,6 @@ namespace ASC.AuditTrail.Mappers
ProductResourceName = "SettingsProduct", ProductResourceName = "SettingsProduct",
ModuleResourceName = "ProductsModule" ModuleResourceName = "ProductsModule"
} }
} }
}; };
}
} }

View File

@ -32,38 +32,37 @@ using ASC.Core.Common.EF;
using ASC.AuditTrail.Models.Mapping.Actions; using ASC.AuditTrail.Models.Mapping.Actions;
using ASC.Core.Common.EF.Model; using ASC.Core.Common.EF.Model;
namespace ASC.AuditTrail.Models namespace ASC.AuditTrail.Models;
public class AuditEventDto : BaseEvent, IMapFrom<AuditEventQuery>
{ {
public class AuditEventDto : BaseEvent, IMapFrom<AuditEventQuery> public string Initiator { get; set; }
[Event("ActionIdCol", 33)]
public int Action { get; set; }
[Event("ActionTypeCol", 30)]
public string ActionTypeText { get; set; }
[Event("ProductCol", 31)]
public string Product { get; set; }
[Event("ModuleCol", 32)]
public string Module { get; set; }
[Event("TargetIdCol", 34)]
public MessageTarget Target { get; set; }
public void Mapping(Profile profile)
{ {
public string Initiator { get; set; } profile.CreateMap<AuditEvent, AuditEventDto>()
.ForMember(src => src.Description, opt => opt.Ignore());
[Event("ActionIdCol", 33)] profile.CreateMap<User, AuditEventDto>()
public int Action { get; set; } .ForMember(src => src.Id, opt => opt.Ignore());
[Event("ActionTypeCol", 30)] profile.CreateMap<AuditEventQuery, AuditEventDto>()
public string ActionTypeText { get; set; } .IncludeMembers(src => src.AuditEvent, src => src.User)
.AfterMap<AuditEventMappingAction>();
[Event("ProductCol", 31)]
public string Product { get; set; }
[Event("ModuleCol", 32)]
public string Module { get; set; }
[Event("TargetIdCol", 34)]
public MessageTarget Target { get; set; }
public void Mapping(Profile profile)
{
profile.CreateMap<AuditEvent, AuditEventDto>()
.ForMember(src => src.Description, opt => opt.Ignore());
profile.CreateMap<User, AuditEventDto>()
.ForMember(src => src.Id, opt => opt.Ignore());
profile.CreateMap<AuditEventQuery, AuditEventDto>()
.IncludeMembers(src => src.AuditEvent, src => src.User)
.AfterMap<AuditEventMappingAction>();
}
} }
} }

View File

@ -1,10 +1,10 @@
using ASC.Core.Common.EF; using ASC.Core.Common.EF;
using ASC.Core.Common.EF.Model;
namespace ASC.AuditTrail.Models namespace ASC.AuditTrail.Models;
public class AuditEventQuery
{ {
public class AuditEventQuery public AuditEvent AuditEvent { get; set; }
{ public User User { get; set; }
public Core.Common.EF.Model.AuditEvent AuditEvent { get; set; }
public User User { get; set; }
}
} }

View File

@ -35,53 +35,52 @@ using ASC.AuditTrail.Attributes;
using CsvHelper.Configuration; using CsvHelper.Configuration;
namespace ASC.AuditTrail.Models namespace ASC.AuditTrail.Models;
public class BaseEvent
{ {
public class BaseEvent public int Id { get; set; }
public int TenantId { get; set; }
public Guid UserId { get; set; }
public bool Mobile { get; set; }
public IList<string> Description { get; set; }
[Event("IpCol")]
public string Ip { get; set; }
[Event("BrowserCol")]
public string Browser { get; set; }
[Event("PlatformCol")]
public string Platform { get; set; }
[Event("DateCol")]
public DateTime Date { get; set; }
[Event("UserCol")]
public string UserName { get; set; }
[Event("PageCol")]
public string Page { get; set; }
[Event("ActionCol")]
public string ActionText { get; set; }
}
internal class BaseEventMap<T> : ClassMap<T> where T : BaseEvent
{
public BaseEventMap()
{ {
public int Id { get; set; } var eventType = typeof(T);
public int TenantId { get; set; } var eventProps = eventType
public Guid UserId { get; set; } .GetProperties()
public bool Mobile { get; set; } .Where(r => r.GetCustomAttribute<EventAttribute>() != null)
public IList<string> Description { get; set; } .OrderBy(r => r.GetCustomAttribute<EventAttribute>().Order);
[Event("IpCol")] foreach (var prop in eventProps)
public string Ip { get; set; }
[Event("BrowserCol")]
public string Browser { get; set; }
[Event("PlatformCol")]
public string Platform { get; set; }
[Event("DateCol")]
public DateTime Date { get; set; }
[Event("UserCol")]
public string UserName { get; set; }
[Event("PageCol")]
public string Page { get; set; }
[Event("ActionCol")]
public string ActionText { get; set; }
}
internal class BaseEventMap<T> : ClassMap<T> where T : BaseEvent
{
public BaseEventMap()
{ {
var eventType = typeof(T); var attr = prop.GetCustomAttribute<EventAttribute>().Resource;
var eventProps = eventType Map(eventType, prop).Name(AuditReportResource.ResourceManager.GetString(attr));
.GetProperties()
.Where(r => r.GetCustomAttribute<EventAttribute>() != null)
.OrderBy(r=> r.GetCustomAttribute<EventAttribute>().Order);
foreach (var prop in eventProps)
{
var attr = prop.GetCustomAttribute<EventAttribute>().Resource;
Map(eventType, prop).Name(AuditReportResource.ResourceManager.GetString(attr));
}
} }
} }
} }

View File

@ -33,24 +33,23 @@ using ASC.Core.Common.EF.Model;
using AutoMapper; using AutoMapper;
namespace ASC.AuditTrail.Models namespace ASC.AuditTrail.Models;
public class LoginEventDTO : BaseEvent, IMapFrom<LoginEventQuery>
{ {
public class LoginEventDTO : BaseEvent, IMapFrom<LoginEventQuery> public string Login { get; set; }
public int Action { get; set; }
public void Mapping(Profile profile)
{ {
public string Login { get; set; } profile.CreateMap<LoginEvent, LoginEventDTO>()
public int Action { get; set; } .ForMember(src => src.Description, opt => opt.Ignore());
public void Mapping(Profile profile) profile.CreateMap<User, LoginEventDTO>()
{ .ForMember(src => src.Id, opt => opt.Ignore());
profile.CreateMap<LoginEvents, LoginEventDTO>()
.ForMember(src => src.Description, opt => opt.Ignore());
profile.CreateMap<User, LoginEventDTO>() profile.CreateMap<LoginEventQuery, LoginEventDTO>()
.ForMember(src => src.Id, opt => opt.Ignore()); .IncludeMembers(src => src.LoginEvents, src => src.User)
.AfterMap<LoginEventMappingAction>();
profile.CreateMap<LoginEventQuery, LoginEventDTO>()
.IncludeMembers(src => src.LoginEvents, src => src.User)
.AfterMap<LoginEventMappingAction>();
}
} }
} }

View File

@ -1,11 +1,10 @@
using ASC.Core.Common.EF; using ASC.Core.Common.EF;
using ASC.Core.Common.EF.Model; using ASC.Core.Common.EF.Model;
namespace ASC.AuditTrail.Models namespace ASC.AuditTrail.Models;
public class LoginEventQuery
{ {
public class LoginEventQuery public LoginEvent LoginEvents { get; set; }
{ public User User { get; set; }
public LoginEvents LoginEvents { get; set; } }
public User User { get; set; }
}
}

View File

@ -8,42 +8,41 @@ using ASC.MessagingSystem;
using ASC.Core.Users; using ASC.Core.Users;
using ASC.AuditTrail.Mappers; using ASC.AuditTrail.Mappers;
namespace ASC.AuditTrail.Models.Mapping.Actions namespace ASC.AuditTrail.Models.Mapping.Actions;
public class AuditEventMappingAction : IMappingAction<AuditEventQuery, AuditEventDto>
{ {
public class AuditEventMappingAction : IMappingAction<AuditEventQuery, AuditEventDto> private MessageTarget _messageTarget;
private UserFormatter _userFormatter;
private AuditActionMapper _auditActionMapper;
public AuditEventMappingAction(
MessageTarget messageTarget,
UserFormatter userFormatter,
AuditActionMapper auditActionMapper)
{ {
private MessageTarget _messageTarget; _messageTarget = messageTarget;
private UserFormatter _userFormatter; _userFormatter = userFormatter;
private AuditActionMapper _auditActionMapper; _auditActionMapper = auditActionMapper;
}
public AuditEventMappingAction( public void Process(AuditEventQuery source, AuditEventDto destination, ResolutionContext context)
MessageTarget messageTarget, {
UserFormatter userFormatter, if (source.AuditEvent.Description != null)
AuditActionMapper auditActionMapper) destination.Description = JsonConvert.DeserializeObject<IList<string>>(
{ Convert.ToString(source.AuditEvent.Description),
_messageTarget = messageTarget; new JsonSerializerSettings { DateTimeZoneHandling = DateTimeZoneHandling.Utc });
_userFormatter = userFormatter;
_auditActionMapper = auditActionMapper;
}
public void Process(AuditEventQuery source, AuditEventDto destination, ResolutionContext context) destination.Target = _messageTarget.Parse(source.AuditEvent.Target);
{
if (source.AuditEvent.Description != null)
destination.Description = JsonConvert.DeserializeObject<IList<string>>(
Convert.ToString(source.AuditEvent.Description),
new JsonSerializerSettings { DateTimeZoneHandling = DateTimeZoneHandling.Utc });
destination.Target = _messageTarget.Parse(source.AuditEvent.Target); destination.UserName = (source.User.FirstName != null && source.User.LastName != null) ? _userFormatter.GetUserName(source.User.FirstName, source.User.LastName) :
source.AuditEvent.UserId == Core.Configuration.Constants.CoreSystem.ID ? AuditReportResource.SystemAccount :
source.AuditEvent.UserId == Core.Configuration.Constants.Guest.ID ? AuditReportResource.GuestAccount :
source.AuditEvent.Initiator ?? AuditReportResource.UnknownAccount;
destination.UserName = (source.User.FirstName != null && source.User.LastName != null) ? _userFormatter.GetUserName(source.User.FirstName, source.User.LastName) : destination.ActionText = _auditActionMapper.GetActionText(destination);
source.AuditEvent.UserId == Core.Configuration.Constants.CoreSystem.ID ? AuditReportResource.SystemAccount : destination.ActionTypeText = _auditActionMapper.GetActionTypeText(destination);
source.AuditEvent.UserId == Core.Configuration.Constants.Guest.ID ? AuditReportResource.GuestAccount : destination.Product = _auditActionMapper.GetProductText(destination);
source.AuditEvent.Initiator ?? AuditReportResource.UnknownAccount; destination.Module = _auditActionMapper.GetModuleText(destination);
destination.ActionText = _auditActionMapper.GetActionText(destination);
destination.ActionTypeText = _auditActionMapper.GetActionTypeText(destination);
destination.Product = _auditActionMapper.GetProductText(destination);
destination.Module = _auditActionMapper.GetModuleText(destination);
}
} }
} }

View File

@ -7,38 +7,37 @@ using AutoMapper;
using Newtonsoft.Json; using Newtonsoft.Json;
namespace ASC.AuditTrail.Models.Mapping.Actions namespace ASC.AuditTrail.Models.Mapping.Actions;
public class LoginEventMappingAction : IMappingAction<LoginEventQuery, LoginEventDTO>
{ {
public class LoginEventMappingAction : IMappingAction<LoginEventQuery, LoginEventDTO> private readonly UserFormatter _userFormatter;
private readonly AuditActionMapper _auditActionMapper;
public LoginEventMappingAction(UserFormatter userFormatter, AuditActionMapper auditActionMapper)
{ {
private readonly UserFormatter _userFormatter; _userFormatter = userFormatter;
private readonly AuditActionMapper _auditActionMapper; _auditActionMapper = auditActionMapper;
}
public LoginEventMappingAction(UserFormatter userFormatter, AuditActionMapper auditActionMapper) public void Process(LoginEventQuery source, LoginEventDTO destination, ResolutionContext context)
{ {
_userFormatter = userFormatter; if (source.LoginEvents.Description != null)
_auditActionMapper = auditActionMapper; destination.Description = JsonConvert.DeserializeObject<IList<string>>(
} source.LoginEvents.Description,
new JsonSerializerSettings
{
DateTimeZoneHandling = DateTimeZoneHandling.Utc
});
public void Process(LoginEventQuery source, LoginEventDTO destination, ResolutionContext context) destination.UserName = (!string.IsNullOrEmpty(source.User?.FirstName) && !string.IsNullOrEmpty(source.User?.LastName))
{ ? _userFormatter.GetUserName(source.User.FirstName, source.User.LastName)
if (source.LoginEvents.Description != null) : !string.IsNullOrWhiteSpace(source.LoginEvents.Login)
destination.Description = JsonConvert.DeserializeObject<IList<string>>( ? source.LoginEvents.Login
source.LoginEvents.Description, : source.LoginEvents.UserId == Core.Configuration.Constants.Guest.ID
new JsonSerializerSettings ? AuditReportResource.GuestAccount
{ : AuditReportResource.UnknownAccount;
DateTimeZoneHandling = DateTimeZoneHandling.Utc
});
destination.UserName = (!string.IsNullOrEmpty(source.User?.FirstName) && !string.IsNullOrEmpty(source.User?.LastName)) destination.ActionText = _auditActionMapper.GetActionText(destination);
? _userFormatter.GetUserName(source.User.FirstName, source.User.LastName)
: !string.IsNullOrWhiteSpace(source.LoginEvents.Login)
? source.LoginEvents.Login
: source.LoginEvents.UserId == Core.Configuration.Constants.Guest.ID
? AuditReportResource.GuestAccount
: AuditReportResource.UnknownAccount;
destination.ActionText = _auditActionMapper.GetActionText(destination);
}
} }
} }

View File

@ -35,55 +35,54 @@ using ASC.Core.Common.EF.Context;
using AutoMapper; using AutoMapper;
namespace ASC.AuditTrail.Repositories namespace ASC.AuditTrail.Repositories;
[Scope]
public class AuditEventsRepository
{ {
[Scope] private AuditTrailContext AuditTrailContext => _lazyAuditTrailContext.Value;
public class AuditEventsRepository
private readonly Lazy<AuditTrailContext> _lazyAuditTrailContext;
private readonly IMapper _mapper;
public AuditEventsRepository(
DbContextManager<AuditTrailContext> dbContextManager,
IMapper mapper)
{ {
private AuditTrailContext AuditTrailContext => _lazyAuditTrailContext.Value; _lazyAuditTrailContext = new Lazy<AuditTrailContext>(() => dbContextManager.Value);
_mapper = mapper;
}
private readonly Lazy<AuditTrailContext> _lazyAuditTrailContext; public IEnumerable<AuditEventDto> GetLast(int tenant, int chunk) => Get(tenant, null, null, chunk);
private readonly IMapper _mapper;
public AuditEventsRepository( public IEnumerable<AuditEventDto> Get(int tenant, DateTime from, DateTime to) => Get(tenant, from, to, null);
DbContextManager<AuditTrailContext> dbContextManager,
IMapper mapper)
{
_lazyAuditTrailContext = new Lazy<AuditTrailContext>(() => dbContextManager.Value);
_mapper = mapper;
}
public IEnumerable<AuditEvent> GetLast(int tenant, int chunk) => Get(tenant, null, null, chunk); public int GetCount(int tenant, DateTime? from = null, DateTime? to = null)
{
IQueryable<Core.Common.EF.Model.AuditEvent> query = AuditTrailContext.AuditEvents
.Where(a => a.TenantId == tenant)
.OrderByDescending(a => a.Date);
public IEnumerable<AuditEvent> Get(int tenant, DateTime from, DateTime to) => Get(tenant, from, to, null); if (from.HasValue && to.HasValue)
query = query.Where(a => a.Date >= from & a.Date <= to);
private IEnumerable<AuditEvent> Get(int tenant, DateTime? fromDate, DateTime? to, int? limit) return query.Count();
{ }
var query =
from q in AuditTrailContext.AuditEvents
from p in AuditTrailContext.Users.Where(p => q.UserId == p.Id).DefaultIfEmpty()
where q.TenantId == tenant
orderby q.Date descending
select new AuditEventQuery { AuditEvent = q, User = p };
if (fromDate.HasValue && to.HasValue) private IEnumerable<AuditEventDto> Get(int tenant, DateTime? fromDate, DateTime? to, int? limit)
query = query.Where(q => q.AuditEvent.Date >= fromDate & q.AuditEvent.Date <= to); {
var query =
from q in AuditTrailContext.AuditEvents
from p in AuditTrailContext.Users.Where(p => q.UserId == p.Id).DefaultIfEmpty()
where q.TenantId == tenant
orderby q.Date descending
select new AuditEventQuery { AuditEvent = q, User = p };
if (limit.HasValue) query = query.Take((int)limit); if (fromDate.HasValue && to.HasValue)
query = query.Where(q => q.AuditEvent.Date >= fromDate & q.AuditEvent.Date <= to);
return query.AsEnumerable().Select(_mapper.Map<AuditEvent>).ToList(); if (limit.HasValue) query = query.Take((int)limit);
}
public int GetCount(int tenant, DateTime? from = null, DateTime? to = null) return query.AsEnumerable().Select(_mapper.Map<AuditEventDto>).ToList();
{
IQueryable<Core.Common.EF.Model.AuditEvent> query = AuditTrailContext.AuditEvents
.Where(a => a.TenantId == tenant)
.OrderByDescending(a => a.Date);
if (from.HasValue && to.HasValue)
query = query.Where(a => a.Date >= from & a.Date <= to);
return query.Count();
}
} }
} }

View File

@ -36,59 +36,58 @@ using ASC.Core.Common.EF.Context;
using AutoMapper; using AutoMapper;
namespace ASC.AuditTrail.Data.Repositories namespace ASC.AuditTrail.Data.Repositories;
[Scope]
public class LoginEventsRepository
{ {
[Scope] private MessagesContext MessagesContext => _lazyMessagesContext.Value;
public class LoginEventsRepository
private readonly Lazy<MessagesContext> _lazyMessagesContext;
private readonly IMapper _mapper;
public LoginEventsRepository(
DbContextManager<MessagesContext> dbMessagesContext,
IMapper mapper)
{ {
private MessagesContext MessagesContext => _lazyMessagesContext.Value; _lazyMessagesContext = new Lazy<MessagesContext>(() => dbMessagesContext.Value);
_mapper = mapper;
}
private readonly Lazy<MessagesContext> _lazyMessagesContext; public IEnumerable<LoginEventDTO> GetLast(int tenant, int chunk)
private readonly IMapper _mapper; {
var query =
(from b in MessagesContext.LoginEvents
from p in MessagesContext.Users.Where(p => b.UserId == p.Id).DefaultIfEmpty()
where b.TenantId == tenant
orderby b.Date descending
select new LoginEventQuery { LoginEvents = b, User = p })
.Take(chunk);
public LoginEventsRepository( return query.AsEnumerable().Select(_mapper.Map<LoginEventDTO>).ToList();
DbContextManager<MessagesContext> dbMessagesContext, }
IMapper mapper)
{
_lazyMessagesContext = new Lazy<MessagesContext>(() => dbMessagesContext.Value);
_mapper = mapper;
}
public IEnumerable<LoginEvent> GetLast(int tenant, int chunk) public IEnumerable<LoginEventDTO> Get(int tenant, DateTime fromDate, DateTime to)
{ {
var query = var query =
(from b in MessagesContext.LoginEvents from q in MessagesContext.LoginEvents
from p in MessagesContext.Users.Where(p => b.UserId == p.Id).DefaultIfEmpty() from p in MessagesContext.Users.Where(p => q.UserId == p.Id).DefaultIfEmpty()
where b.TenantId == tenant where q.TenantId == tenant
orderby b.Date descending where q.Date >= fromDate
select new LoginEventQuery { LoginEvents = b, User = p }) where q.Date <= to
.Take(chunk); orderby q.Date descending
select new LoginEventQuery { LoginEvents = q, User = p };
return query.AsEnumerable().Select(_mapper.Map<LoginEvent>).ToList(); return query.AsEnumerable().Select(_mapper.Map<LoginEventDTO>).ToList();
} }
public IEnumerable<LoginEvent> Get(int tenant, DateTime fromDate, DateTime to) public int GetCount(int tenant, DateTime? from = null, DateTime? to = null)
{ {
var query = var query = MessagesContext.LoginEvents
from q in MessagesContext.LoginEvents .Where(l => l.TenantId == tenant);
from p in MessagesContext.Users.Where(p => q.UserId == p.Id).DefaultIfEmpty()
where q.TenantId == tenant
where q.Date >= fromDate
where q.Date <= to
orderby q.Date descending
select new LoginEventQuery { LoginEvents = q, User = p };
return query.AsEnumerable().Select(_mapper.Map<LoginEvent>).ToList(); if (from.HasValue && to.HasValue) query = query.Where(l => l.Date >= from & l.Date <= to);
}
public int GetCount(int tenant, DateTime? from = null, DateTime? to = null) return query.Count();
{
var query = MessagesContext.LoginEvents
.Where(l => l.TenantId == tenant);
if (from.HasValue && to.HasValue) query = query.Where(l => l.Date >= from & l.Date <= to);
return query.Count();
}
} }
} }