This commit is contained in:
2018-08-28 20:12:51 +00:00
parent ecb6b3d7c6
commit 5cd914767d
17 changed files with 62 additions and 53 deletions

View File

@@ -1,13 +1,15 @@
Business history log Business history log
FROM CASE 79 FROM CASE 79
A central event log used to track major changes to business objects and major events of significance in AyaNova. A central event log used to track major changes to business objects and major events of significance in AyaNova
??Has some sort of checksum or verification so we can tell it wasn't fucked with (too hard to implement, would be something like a blockchain?)
Consumed by various widgets for record history purposes Consumed by various widgets for record history purposes
Default feature, no need to turn on or off keeps logs for 45 days, users who want more can Default feature, no need to turn on or off
Items are only removed from log when source object is deleted (and replaced with a deleted entry and textual description of deleted item) Items are only removed from log when source object is deleted (and replaced with a deleted entry and textual description of deleted item)
Needs a cleaner job that periodically looks for non-existant objects that are logged
Has to handle a scenario where there is no data for an object because in future we will likely have a purge feature or maybe a feature to turn it off and needs to accept that scenario Has to handle a scenario where there is no data for an object because in future we will likely have a purge feature or maybe a feature to turn it off and needs to accept that scenario
?FUTURE: Has some sort of checksum or verification so we can tell it wasn't fucked with (too hard to implement, would be something like a blockchain?)
?FUTURE: Needs a cleaner job that periodically looks for non-existant objects that are logged
?FUTURE: keeps logs for 45 days initially keeps forever or until object is deleted
ROUTES ROUTES
------ ------

View File

@@ -20,7 +20,7 @@ CODING WORK
Overall plan for now: anything standing in the way of making the initial client shell UI needs to be done first, everything else can wait Overall plan for now: anything standing in the way of making the initial client shell UI needs to be done first, everything else can wait
- Audit log - Audit log
- Route for retrieving as log format for reading (like reports: one for specific object id and type, one for user id as log of what they've been doing etc) - Make sure trial generated data generates log events so that we can properly test with huge dataset
- Test with huge dataset - Test with huge dataset
- Remove CREATED from all objects now that event log tracks it - Remove CREATED from all objects now that event log tracks it
- Localized text - Localized text

View File

@@ -239,7 +239,7 @@ namespace AyaNova.Api.Controllers
}); });
//Log //Log
EventLogProcessor.AddEntry(new Event(UserId, attachToObject.ObjectId, attachToObject.ObjectType, AyaEvent.AttachmentCreate, v.DisplayFileName), ct); //EventLogProcessor.AddEntry(new Event(UserId, attachToObject.ObjectId, attachToObject.ObjectType, AyaEvent.AttachmentCreate, v.DisplayFileName), ct);
} }
} }
@@ -306,7 +306,7 @@ namespace AyaNova.Api.Controllers
FileUtil.deleteFileAttachment(dbObj, ct); FileUtil.deleteFileAttachment(dbObj, ct);
//Log //Log
EventLogProcessor.AddEntry(new Event(UserId, dbObj.AttachToObjectId, dbObj.AttachToObjectType, AyaEvent.AttachmentDelete, dbObj.DisplayFileName), ct); //EventLogProcessor.AddEntry(new Event(UserId, dbObj.AttachToObjectId, dbObj.AttachToObjectType, AyaEvent.AttachmentDelete, dbObj.DisplayFileName), ct);
return NoContent(); return NoContent();
} }
@@ -385,7 +385,7 @@ namespace AyaNova.Api.Controllers
} }
//Log //Log
EventLogProcessor.AddEntry(new Event(UserId, dbObj.AttachToObjectId, dbObj.AttachToObjectType, AyaEvent.AttachmentDownload, dbObj.DisplayFileName), ct); //EventLogProcessor.AddEntry(new Event(UserId, dbObj.AttachToObjectId, dbObj.AttachToObjectType, AyaEvent.AttachmentDownload, dbObj.DisplayFileName), ct);
return PhysicalFile(filePath, mimetype, dbObj.DisplayFileName); return PhysicalFile(filePath, mimetype, dbObj.DisplayFileName);

View File

@@ -127,7 +127,7 @@ namespace AyaNova.Api.Controllers
} }
var ret = AyaNova.Core.License.LicenseInfoAsJson; var ret = AyaNova.Core.License.LicenseInfoAsJson;
//Log //Log
EventLogProcessor.AddEntry(new Event(UserIdFromContext.Id(HttpContext.Items), 0, AyaType.License, AyaEvent.LicenseFetch), ct); //EventLogProcessor.AddEntry(new Event(UserIdFromContext.Id(HttpContext.Items), 0, AyaType.License, AyaEvent.LicenseFetch), ct);
return Ok(new ApiOkResponse(ret)); return Ok(new ApiOkResponse(ret));
} }
@@ -179,7 +179,7 @@ namespace AyaNova.Api.Controllers
var ret = Core.License.RequestTrial(requestData.EmailAddress, requestData.RegisteredTo, log); var ret = Core.License.RequestTrial(requestData.EmailAddress, requestData.RegisteredTo, log);
//Log //Log
EventLogProcessor.AddEntry(new Event(UserIdFromContext.Id(HttpContext.Items), 0, AyaType.License, AyaEvent.LicenseTrialRequest), ct); //EventLogProcessor.AddEntry(new Event(UserIdFromContext.Id(HttpContext.Items), 0, AyaType.License, AyaEvent.LicenseTrialRequest), ct);
return Ok(new ApiOkResponse(ret)); return Ok(new ApiOkResponse(ret));
} }

View File

@@ -163,7 +163,7 @@ namespace AyaNova.Api.Controllers
await ct.SaveChangesAsync(); await ct.SaveChangesAsync();
//Log //Log
EventLogProcessor.AddEntry(new Event(biz.userId, o.Id, AyaType.Locale, AyaEvent.Created), ct); //EventLogProcessor.AddEntry(new Event(biz.userId, o.Id, AyaType.Locale, AyaEvent.Created), ct);
return CreatedAtAction("GetLocale", new { id = o.Id }, new ApiCreatedResponse(o)); return CreatedAtAction("GetLocale", new { id = o.Id }, new ApiCreatedResponse(o));
} }
@@ -241,7 +241,7 @@ namespace AyaNova.Api.Controllers
} }
//Log //Log
EventLogProcessor.AddEntry(new Event(biz.userId, oDbParent.Id, AyaType.Locale, AyaEvent.Modified), ct); //EventLogProcessor.AddEntry(new Event(biz.userId, oDbParent.Id, AyaType.Locale, AyaEvent.Modified), ct);
return Ok(new ApiOkResponse(new { ConcurrencyToken = oFromDb.ConcurrencyToken })); return Ok(new ApiOkResponse(new { ConcurrencyToken = oFromDb.ConcurrencyToken }));
} }
@@ -310,7 +310,7 @@ namespace AyaNova.Api.Controllers
} }
//Log //Log
EventLogProcessor.AddEntry(new Event(biz.userId, oFromDb.Id, AyaType.Locale, AyaEvent.Modified), ct); //EventLogProcessor.AddEntry(new Event(biz.userId, oFromDb.Id, AyaType.Locale, AyaEvent.Modified), ct);
return Ok(new ApiOkResponse(new { ConcurrencyToken = oFromDb.ConcurrencyToken })); return Ok(new ApiOkResponse(new { ConcurrencyToken = oFromDb.ConcurrencyToken }));
} }

View File

@@ -82,7 +82,7 @@ namespace AyaNova.Api.Controllers
//Log //Log
EventLogProcessor.AddEntry(new Event(UserIdFromContext.Id(HttpContext.Items), 0, AyaType.LogFile, AyaEvent.Retrieved,logname), ct); // EventLogProcessor.AddEntry(new Event(UserIdFromContext.Id(HttpContext.Items), 0, AyaType.LogFile, AyaEvent.Retrieved,logname), ct);
return Content(System.IO.File.ReadAllText(logFilePath)); return Content(System.IO.File.ReadAllText(logFilePath));

View File

@@ -68,7 +68,7 @@ namespace AyaNova.Api.Controllers
string sResult = await GetTheMetrics("plain"); string sResult = await GetTheMetrics("plain");
//Log //Log
EventLogProcessor.AddEntry(new Event(UserIdFromContext.Id(HttpContext.Items), 0, AyaType.Metrics, AyaEvent.Retrieved), ct); //EventLogProcessor.AddEntry(new Event(UserIdFromContext.Id(HttpContext.Items), 0, AyaType.Metrics, AyaEvent.Retrieved), ct);
return Content(sResult); return Content(sResult);
} }
@@ -99,7 +99,7 @@ namespace AyaNova.Api.Controllers
JObject json = JObject.Parse(sResult); JObject json = JObject.Parse(sResult);
//Log //Log
EventLogProcessor.AddEntry(new Event(UserIdFromContext.Id(HttpContext.Items), 0, AyaType.Metrics, AyaEvent.Retrieved), ct); //EventLogProcessor.AddEntry(new Event(UserIdFromContext.Id(HttpContext.Items), 0, AyaType.Metrics, AyaEvent.Retrieved), ct);
return Ok(new ApiOkResponse(json)); return Ok(new ApiOkResponse(json));
} }

View File

@@ -95,7 +95,7 @@ namespace AyaNova.Api.Controllers
serverState.SetState(desiredState, state.Reason); serverState.SetState(desiredState, state.Reason);
//Log //Log
EventLogProcessor.AddEntry(new Event(UserIdFromContext.Id(HttpContext.Items), 0, AyaType.ServerState, AyaEvent.ServerStateChange, $"{state.ServerState}-{state.Reason}"), ct); //EventLogProcessor.AddEntry(new Event(UserIdFromContext.Id(HttpContext.Items), 0, AyaType.ServerState, AyaEvent.ServerStateChange, $"{state.ServerState}-{state.Reason}"), ct);
return NoContent(); return NoContent();
} }

View File

@@ -170,7 +170,7 @@ namespace AyaNova.Api.Controllers
await ct.SaveChangesAsync(); await ct.SaveChangesAsync();
//Log //Log
EventLogProcessor.AddEntry(new Event(biz.userId, o.Id, AyaType.Tag, AyaEvent.Created), ct); //EventLogProcessor.AddEntry(new Event(biz.userId, o.Id, AyaType.Tag, AyaEvent.Created), ct);
return CreatedAtAction("GetTag", new { id = o.Id }, new ApiCreatedResponse(o)); return CreatedAtAction("GetTag", new { id = o.Id }, new ApiCreatedResponse(o));
} }
@@ -241,7 +241,7 @@ namespace AyaNova.Api.Controllers
} }
//Log //Log
EventLogProcessor.AddEntry(new Event(biz.userId, oFromDb.Id, AyaType.Tag, AyaEvent.Modified), ct); //EventLogProcessor.AddEntry(new Event(biz.userId, oFromDb.Id, AyaType.Tag, AyaEvent.Modified), ct);
return Ok(new ApiOkResponse(new { ConcurrencyToken = oFromDb.ConcurrencyToken })); return Ok(new ApiOkResponse(new { ConcurrencyToken = oFromDb.ConcurrencyToken }));
} }
@@ -309,7 +309,7 @@ namespace AyaNova.Api.Controllers
} }
//Log //Log
EventLogProcessor.AddEntry(new Event(biz.userId, oFromDb.Id, AyaType.Tag, AyaEvent.Modified), ct); //EventLogProcessor.AddEntry(new Event(biz.userId, oFromDb.Id, AyaType.Tag, AyaEvent.Modified), ct);
return Ok(new ApiOkResponse(new { ConcurrencyToken = oFromDb.ConcurrencyToken })); return Ok(new ApiOkResponse(new { ConcurrencyToken = oFromDb.ConcurrencyToken }));
} }

View File

@@ -97,7 +97,7 @@ namespace AyaNova.Api.Controllers
JobsBiz.AddJob(j, ct); JobsBiz.AddJob(j, ct);
//Log //Log
EventLogProcessor.AddEntry(new Event(UserIdFromContext.Id(HttpContext.Items), 0, AyaType.TrialSeeder, AyaEvent.Created,size), ct); //EventLogProcessor.AddEntry(new Event(UserIdFromContext.Id(HttpContext.Items), 0, AyaType.TrialSeeder, AyaEvent.Created,size), ct);
return Accepted(new { JobId = j.GId });//202 accepted return Accepted(new { JobId = j.GId });//202 accepted

View File

@@ -86,7 +86,7 @@ namespace AyaNova.Api.Controllers
} }
//Log //Log
EventLogProcessor.AddEntry(new Event(biz.userId, o.Id, AyaType.Widget, AyaEvent.Retrieved), ct); EventLogProcessor.AddEntryAndSave(new Event(biz.userId, o.Id, AyaType.Widget, AyaEvent.Retrieved), ct);
return Ok(new ApiOkResponse(o)); return Ok(new ApiOkResponse(o));
} }
@@ -216,6 +216,8 @@ namespace AyaNova.Api.Controllers
try try
{ {
//Log
EventLogProcessor.AddEntryNoSave(new Event(biz.userId, o.Id, AyaType.Widget, AyaEvent.Modified), ct);
await ct.SaveChangesAsync(); await ct.SaveChangesAsync();
} }
catch (DbUpdateConcurrencyException) catch (DbUpdateConcurrencyException)
@@ -233,8 +235,7 @@ namespace AyaNova.Api.Controllers
} }
} }
//Log
EventLogProcessor.AddEntry(new Event(biz.userId, o.Id, AyaType.Widget, AyaEvent.Modified), ct);
return Ok(new ApiOkResponse(new { ConcurrencyToken = o.ConcurrencyToken })); return Ok(new ApiOkResponse(new { ConcurrencyToken = o.ConcurrencyToken }));
} }
@@ -291,6 +292,8 @@ namespace AyaNova.Api.Controllers
try try
{ {
//Log
EventLogProcessor.AddEntryNoSave(new Event(biz.userId, o.Id, AyaType.Widget, AyaEvent.Modified), ct);
await ct.SaveChangesAsync(); await ct.SaveChangesAsync();
} }
catch (DbUpdateConcurrencyException) catch (DbUpdateConcurrencyException)
@@ -306,8 +309,7 @@ namespace AyaNova.Api.Controllers
} }
//Log
EventLogProcessor.AddEntry(new Event(biz.userId, o.Id, AyaType.Widget, AyaEvent.Modified), ct);
return Ok(new ApiOkResponse(new { ConcurrencyToken = o.ConcurrencyToken })); return Ok(new ApiOkResponse(new { ConcurrencyToken = o.ConcurrencyToken }));
} }
@@ -353,11 +355,12 @@ namespace AyaNova.Api.Controllers
} }
else else
{ {
//Log
EventLogProcessor.AddEntryNoSave(new Event(biz.userId, o.Id, AyaType.Widget, AyaEvent.Created), ct);
//save and success return //save and success return
await ct.SaveChangesAsync(); await ct.SaveChangesAsync();
//Log
EventLogProcessor.AddEntry(new Event(biz.userId, o.Id, AyaType.Widget, AyaEvent.Created), ct);
return CreatedAtAction("GetWidget", new { id = o.Id }, new ApiCreatedResponse(o)); return CreatedAtAction("GetWidget", new { id = o.Id }, new ApiCreatedResponse(o));
} }

View File

@@ -378,12 +378,12 @@ namespace AyaNova
lb.ValidateLocales(); lb.ValidateLocales();
#if (DEBUG) #if (DEBUG)
// Util.DbUtil.DropAndRecreateDb(_log); Util.DbUtil.DropAndRecreateDb(_log);
// AySchema.CheckAndUpdate(dbContext, _log); AySchema.CheckAndUpdate(dbContext, _log);
// lb.ValidateLocales(); lb.ValidateLocales();
// AyaNova.Core.License.Initialize(apiServerState, dbContext, _log); AyaNova.Core.License.Initialize(apiServerState, dbContext, _log);
// AyaNova.Core.License.Fetch(apiServerState, dbContext, _log); AyaNova.Core.License.Fetch(apiServerState, dbContext, _log);
// Util.Seeder.SeedDatabase(dbContext, Util.Seeder.SeedLevel.SmallOneManShopTrialDataSet); Util.Seeder.SeedDatabase(dbContext, Util.Seeder.SeedLevel.MediumLocalServiceCompanyTrialDataSet);
#endif #endif

View File

@@ -17,11 +17,23 @@ namespace AyaNova.Biz
/// <summary> /// <summary>
/// Add an entry to the log /// Add an entry to the log
/// DOES NOT SAVE
/// </summary> /// </summary>
/// <param name="newEvent"></param> /// <param name="newEvent"></param>
/// <param name="ct"></param> /// <param name="ct"></param>
/// <returns></returns> /// <returns></returns>
internal static void AddEntry(Event newEvent, AyContext ct) internal static void AddEntryNoSave(Event newEvent, AyContext ct)
{
ct.Event.Add(newEvent);
}
/// <summary>
/// Add and SAVE entry to the log
/// </summary>
/// <param name="newEvent"></param>
/// <param name="ct"></param>
/// <returns></returns>
internal static void AddEntryAndSave(Event newEvent, AyContext ct)
{ {
ct.Event.Add(newEvent); ct.Event.Add(newEvent);
ct.SaveChanges(); ct.SaveChanges();

View File

@@ -16,7 +16,6 @@ namespace AyaNova.Models
[Required] [Required]
public long OwnerId { get; set; } public long OwnerId { get; set; }
public string Name { get; set; } public string Name { get; set; }
public DateTime Created { get; set; }
public decimal? DollarAmount { get; set; } public decimal? DollarAmount { get; set; }
public bool? Active { get; set; } public bool? Active { get; set; }
public AuthorizationRoles Roles { get; set; } public AuthorizationRoles Roles { get; set; }
@@ -24,12 +23,6 @@ namespace AyaNova.Models
public DateTime? EndDate { get; set; } public DateTime? EndDate { get; set; }
public Widget()
{
Created = System.DateTime.UtcNow;
}
} }
} }

View File

@@ -22,7 +22,7 @@ namespace AyaNova.Util
//!!!!WARNING: BE SURE TO UPDATE THE DbUtil::PrepareDatabaseForSeeding WHEN NEW TABLES ADDED!!!! //!!!!WARNING: BE SURE TO UPDATE THE DbUtil::PrepareDatabaseForSeeding WHEN NEW TABLES ADDED!!!!
private const int DESIRED_SCHEMA_LEVEL = 9; private const int DESIRED_SCHEMA_LEVEL = 9;
internal const long EXPECTED_COLUMN_COUNT = 76; internal const long EXPECTED_COLUMN_COUNT = 75;
internal const long EXPECTED_INDEX_COUNT = 15; internal const long EXPECTED_INDEX_COUNT = 15;
//!!!!WARNING: BE SURE TO UPDATE THE DbUtil::PrepareDatabaseForSeeding WHEN NEW TABLES ADDED!!!! //!!!!WARNING: BE SURE TO UPDATE THE DbUtil::PrepareDatabaseForSeeding WHEN NEW TABLES ADDED!!!!
@@ -172,7 +172,7 @@ namespace AyaNova.Util
//Add widget table //Add widget table
//id, text, longtext, boolean, currency, //id, text, longtext, boolean, currency,
exec("CREATE TABLE awidget (id BIGSERIAL PRIMARY KEY, ownerid bigint not null, name varchar(255) not null, created timestamp not null, " + exec("CREATE TABLE awidget (id BIGSERIAL PRIMARY KEY, ownerid bigint not null, name varchar(255) not null, " +
"startdate timestamp, enddate timestamp, dollaramount money, active bool, roles int4)"); "startdate timestamp, enddate timestamp, dollaramount money, active bool, roles int4)");
setSchemaLevel(++currentSchema); setSchemaLevel(++currentSchema);

View File

@@ -119,6 +119,7 @@ namespace AyaNova.Util
//2000 widgets //2000 widgets
GenSeedWidget(2000, ct); GenSeedWidget(2000, ct);
//GenSeedWidget(100, ct);
break; break;
//this is a large corporation with multiple branches in multiple locations all in the same country //this is a large corporation with multiple branches in multiple locations all in the same country
@@ -257,14 +258,13 @@ namespace AyaNova.Util
// //
public static void GenSeedWidget(int count, AyContext ct) public static void GenSeedWidget(int count, AyContext ct)
{ {
var s="blah";
for (int x = 0; x < count; x++) for (int x = 0; x < count; x++)
{ {
Widget o = new Widget(); Widget o = new Widget();
var f = new Bogus.Faker(); var f = new Bogus.Faker();
o.Name = f.Commerce.ProductName(); o.Name = f.Commerce.ProductName();
o.Active = f.Random.Bool(); o.Active = f.Random.Bool();
o.StartDate = f.Date.Between(DateTime.Now, DateTime.Now.AddMinutes(60)); o.StartDate = f.Date.Between(DateTime.Now, DateTime.Now.AddMinutes(60));
o.EndDate = f.Date.Between(DateTime.Now.AddMinutes(90), DateTime.Now.AddHours(5)); o.EndDate = f.Date.Between(DateTime.Now.AddMinutes(90), DateTime.Now.AddHours(5));
@@ -273,9 +273,13 @@ namespace AyaNova.Util
//this is nonsense but just to test an enum //this is nonsense but just to test an enum
o.Roles = AuthorizationRoles.DispatchLimited | AuthorizationRoles.InventoryLimited | AuthorizationRoles.OpsAdminLimited; o.Roles = AuthorizationRoles.DispatchLimited | AuthorizationRoles.InventoryLimited | AuthorizationRoles.OpsAdminLimited;
ct.Widget.Add(o); ct.Widget.Add(o);
ct.SaveChanges(); // ct.SaveChanges();
EventLogProcessor.AddEntry(new Event(o.OwnerId, o.Id, AyaType.Widget, AyaEvent.Created), ct);
//Log
EventLogProcessor.AddEntryNoSave(new Event(o.OwnerId, o.Id, AyaType.Widget, AyaEvent.Created), ct);
} }
ct.SaveChanges();
var v=s;
} }

View File

@@ -19,7 +19,6 @@ namespace raven_integration
{ {
"id": 0, "id": 0,
"name": "string", "name": "string",
"created": "2018-02-09T16:45:56.057Z",
"dollarAmount": 0, "dollarAmount": 0,
"active": true, "active": true,
"roles": 0 "roles": 0
@@ -28,7 +27,6 @@ namespace raven_integration
//CREATE //CREATE
dynamic w1 = new JObject(); dynamic w1 = new JObject();
w1.name = Util.Uniquify("First Test WIDGET"); w1.name = Util.Uniquify("First Test WIDGET");
w1.created = DateTime.Now.ToString();
w1.dollarAmount = 1.11m; w1.dollarAmount = 1.11m;
w1.active = true; w1.active = true;
w1.roles = 0; w1.roles = 0;
@@ -40,7 +38,6 @@ namespace raven_integration
dynamic w2 = new JObject(); dynamic w2 = new JObject();
w2.name = Util.Uniquify("Second Test WIDGET"); w2.name = Util.Uniquify("Second Test WIDGET");
w2.created = DateTime.Now.ToString();
w2.dollarAmount = 2.22m; w2.dollarAmount = 2.22m;
w2.active = true; w2.active = true;
w2.roles = 0; w2.roles = 0;
@@ -161,7 +158,6 @@ namespace raven_integration
dynamic w2 = new JObject(); dynamic w2 = new JObject();
w2.name = Util.Uniquify("PutConcurrencyViolationShouldFail"); w2.name = Util.Uniquify("PutConcurrencyViolationShouldFail");
w2.created = DateTime.Now.ToString();
w2.dollarAmount = 2.22m; w2.dollarAmount = 2.22m;
w2.active = true; w2.active = true;
w2.roles = 0; w2.roles = 0;
@@ -199,7 +195,6 @@ namespace raven_integration
dynamic w2 = new JObject(); dynamic w2 = new JObject();
w2.name = Util.Uniquify("PatchConcurrencyViolationShouldFail"); w2.name = Util.Uniquify("PatchConcurrencyViolationShouldFail");
w2.created = DateTime.Now.ToString();
w2.dollarAmount = 2.22m; w2.dollarAmount = 2.22m;
w2.active = true; w2.active = true;
w2.roles = 0; w2.roles = 0;