diff --git a/devdocs/specs/core-log-business.txt b/devdocs/specs/core-log-business.txt index a4506795..5bc483ae 100644 --- a/devdocs/specs/core-log-business.txt +++ b/devdocs/specs/core-log-business.txt @@ -1,13 +1,15 @@ Business history log FROM CASE 79 -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?) +A central event log used to track major changes to business objects and major events of significance in AyaNova 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) -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 +?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 ------ diff --git a/devdocs/todo.txt b/devdocs/todo.txt index bcb9be65..9b53327e 100644 --- a/devdocs/todo.txt +++ b/devdocs/todo.txt @@ -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 - 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 - Remove CREATED from all objects now that event log tracks it - Localized text diff --git a/server/AyaNova/Controllers/AttachmentController.cs b/server/AyaNova/Controllers/AttachmentController.cs index 29e366f2..43193b8d 100644 --- a/server/AyaNova/Controllers/AttachmentController.cs +++ b/server/AyaNova/Controllers/AttachmentController.cs @@ -239,7 +239,7 @@ namespace AyaNova.Api.Controllers }); //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); //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(); } @@ -385,7 +385,7 @@ namespace AyaNova.Api.Controllers } //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); diff --git a/server/AyaNova/Controllers/LicenseController.cs b/server/AyaNova/Controllers/LicenseController.cs index a309fe49..dc67d7d9 100644 --- a/server/AyaNova/Controllers/LicenseController.cs +++ b/server/AyaNova/Controllers/LicenseController.cs @@ -127,7 +127,7 @@ namespace AyaNova.Api.Controllers } var ret = AyaNova.Core.License.LicenseInfoAsJson; //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)); } @@ -179,7 +179,7 @@ namespace AyaNova.Api.Controllers var ret = Core.License.RequestTrial(requestData.EmailAddress, requestData.RegisteredTo, 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)); } diff --git a/server/AyaNova/Controllers/LocaleController.cs b/server/AyaNova/Controllers/LocaleController.cs index 6550a15b..2e9a6175 100644 --- a/server/AyaNova/Controllers/LocaleController.cs +++ b/server/AyaNova/Controllers/LocaleController.cs @@ -163,7 +163,7 @@ namespace AyaNova.Api.Controllers await ct.SaveChangesAsync(); //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)); } @@ -241,7 +241,7 @@ namespace AyaNova.Api.Controllers } //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 })); } @@ -310,7 +310,7 @@ namespace AyaNova.Api.Controllers } //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 })); } diff --git a/server/AyaNova/Controllers/LogFilesController.cs b/server/AyaNova/Controllers/LogFilesController.cs index 11521b08..43a1ba16 100644 --- a/server/AyaNova/Controllers/LogFilesController.cs +++ b/server/AyaNova/Controllers/LogFilesController.cs @@ -82,7 +82,7 @@ namespace AyaNova.Api.Controllers //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)); diff --git a/server/AyaNova/Controllers/MetricsController.cs b/server/AyaNova/Controllers/MetricsController.cs index 43d2c5f7..49cf898a 100644 --- a/server/AyaNova/Controllers/MetricsController.cs +++ b/server/AyaNova/Controllers/MetricsController.cs @@ -68,7 +68,7 @@ namespace AyaNova.Api.Controllers string sResult = await GetTheMetrics("plain"); //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); } @@ -99,7 +99,7 @@ namespace AyaNova.Api.Controllers JObject json = JObject.Parse(sResult); //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)); } diff --git a/server/AyaNova/Controllers/ServerStateController.cs b/server/AyaNova/Controllers/ServerStateController.cs index a2ae33f4..f08bfd84 100644 --- a/server/AyaNova/Controllers/ServerStateController.cs +++ b/server/AyaNova/Controllers/ServerStateController.cs @@ -95,7 +95,7 @@ namespace AyaNova.Api.Controllers serverState.SetState(desiredState, state.Reason); //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(); } diff --git a/server/AyaNova/Controllers/TagController.cs b/server/AyaNova/Controllers/TagController.cs index ad0cfc9c..77caddea 100644 --- a/server/AyaNova/Controllers/TagController.cs +++ b/server/AyaNova/Controllers/TagController.cs @@ -170,7 +170,7 @@ namespace AyaNova.Api.Controllers await ct.SaveChangesAsync(); //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)); } @@ -241,7 +241,7 @@ namespace AyaNova.Api.Controllers } //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 })); } @@ -309,7 +309,7 @@ namespace AyaNova.Api.Controllers } //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 })); } diff --git a/server/AyaNova/Controllers/TrialController.cs b/server/AyaNova/Controllers/TrialController.cs index 98f5d01a..8260650a 100644 --- a/server/AyaNova/Controllers/TrialController.cs +++ b/server/AyaNova/Controllers/TrialController.cs @@ -97,7 +97,7 @@ namespace AyaNova.Api.Controllers JobsBiz.AddJob(j, ct); //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 diff --git a/server/AyaNova/Controllers/WidgetController.cs b/server/AyaNova/Controllers/WidgetController.cs index 17604f1a..235732e1 100644 --- a/server/AyaNova/Controllers/WidgetController.cs +++ b/server/AyaNova/Controllers/WidgetController.cs @@ -86,7 +86,7 @@ namespace AyaNova.Api.Controllers } //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)); } @@ -216,6 +216,8 @@ namespace AyaNova.Api.Controllers try { + //Log + EventLogProcessor.AddEntryNoSave(new Event(biz.userId, o.Id, AyaType.Widget, AyaEvent.Modified), ct); await ct.SaveChangesAsync(); } 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 })); } @@ -291,6 +292,8 @@ namespace AyaNova.Api.Controllers try { + //Log + EventLogProcessor.AddEntryNoSave(new Event(biz.userId, o.Id, AyaType.Widget, AyaEvent.Modified), ct); await ct.SaveChangesAsync(); } 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 })); } @@ -353,11 +355,12 @@ namespace AyaNova.Api.Controllers } else { + //Log + EventLogProcessor.AddEntryNoSave(new Event(biz.userId, o.Id, AyaType.Widget, AyaEvent.Created), ct); //save and success return 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)); } diff --git a/server/AyaNova/Startup.cs b/server/AyaNova/Startup.cs index dd400287..0b0207b0 100644 --- a/server/AyaNova/Startup.cs +++ b/server/AyaNova/Startup.cs @@ -378,12 +378,12 @@ namespace AyaNova lb.ValidateLocales(); #if (DEBUG) - // Util.DbUtil.DropAndRecreateDb(_log); - // AySchema.CheckAndUpdate(dbContext, _log); - // lb.ValidateLocales(); - // AyaNova.Core.License.Initialize(apiServerState, dbContext, _log); - // AyaNova.Core.License.Fetch(apiServerState, dbContext, _log); - // Util.Seeder.SeedDatabase(dbContext, Util.Seeder.SeedLevel.SmallOneManShopTrialDataSet); + Util.DbUtil.DropAndRecreateDb(_log); + AySchema.CheckAndUpdate(dbContext, _log); + lb.ValidateLocales(); + AyaNova.Core.License.Initialize(apiServerState, dbContext, _log); + AyaNova.Core.License.Fetch(apiServerState, dbContext, _log); + Util.Seeder.SeedDatabase(dbContext, Util.Seeder.SeedLevel.MediumLocalServiceCompanyTrialDataSet); #endif diff --git a/server/AyaNova/biz/EventLogProcessor.cs b/server/AyaNova/biz/EventLogProcessor.cs index 4d2ed1f9..23ee8f7c 100644 --- a/server/AyaNova/biz/EventLogProcessor.cs +++ b/server/AyaNova/biz/EventLogProcessor.cs @@ -17,11 +17,23 @@ namespace AyaNova.Biz /// /// Add an entry to the log + /// DOES NOT SAVE /// /// /// /// - internal static void AddEntry(Event newEvent, AyContext ct) + internal static void AddEntryNoSave(Event newEvent, AyContext ct) + { + ct.Event.Add(newEvent); + } + + /// + /// Add and SAVE entry to the log + /// + /// + /// + /// + internal static void AddEntryAndSave(Event newEvent, AyContext ct) { ct.Event.Add(newEvent); ct.SaveChanges(); diff --git a/server/AyaNova/models/Widget.cs b/server/AyaNova/models/Widget.cs index 109fb913..0eed2ac6 100644 --- a/server/AyaNova/models/Widget.cs +++ b/server/AyaNova/models/Widget.cs @@ -16,7 +16,6 @@ namespace AyaNova.Models [Required] public long OwnerId { get; set; } public string Name { get; set; } - public DateTime Created { get; set; } public decimal? DollarAmount { get; set; } public bool? Active { get; set; } public AuthorizationRoles Roles { get; set; } @@ -24,12 +23,6 @@ namespace AyaNova.Models public DateTime? EndDate { get; set; } - public Widget() - { - Created = System.DateTime.UtcNow; - } - - } } diff --git a/server/AyaNova/util/AySchema.cs b/server/AyaNova/util/AySchema.cs index b97b3159..3174bb0f 100644 --- a/server/AyaNova/util/AySchema.cs +++ b/server/AyaNova/util/AySchema.cs @@ -22,7 +22,7 @@ namespace AyaNova.Util //!!!!WARNING: BE SURE TO UPDATE THE DbUtil::PrepareDatabaseForSeeding WHEN NEW TABLES ADDED!!!! 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; //!!!!WARNING: BE SURE TO UPDATE THE DbUtil::PrepareDatabaseForSeeding WHEN NEW TABLES ADDED!!!! @@ -172,7 +172,7 @@ namespace AyaNova.Util //Add widget table //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)"); setSchemaLevel(++currentSchema); diff --git a/server/AyaNova/util/Seeder.cs b/server/AyaNova/util/Seeder.cs index 2dbc1205..b6e8eae6 100644 --- a/server/AyaNova/util/Seeder.cs +++ b/server/AyaNova/util/Seeder.cs @@ -119,6 +119,7 @@ namespace AyaNova.Util //2000 widgets GenSeedWidget(2000, ct); + //GenSeedWidget(100, ct); break; //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) { - + var s="blah"; for (int x = 0; x < count; x++) { Widget o = new Widget(); var f = new Bogus.Faker(); o.Name = f.Commerce.ProductName(); o.Active = f.Random.Bool(); - o.StartDate = f.Date.Between(DateTime.Now, DateTime.Now.AddMinutes(60)); 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 o.Roles = AuthorizationRoles.DispatchLimited | AuthorizationRoles.InventoryLimited | AuthorizationRoles.OpsAdminLimited; ct.Widget.Add(o); - ct.SaveChanges(); - EventLogProcessor.AddEntry(new Event(o.OwnerId, o.Id, AyaType.Widget, AyaEvent.Created), ct); +// ct.SaveChanges(); + + //Log + EventLogProcessor.AddEntryNoSave(new Event(o.OwnerId, o.Id, AyaType.Widget, AyaEvent.Created), ct); } + ct.SaveChanges(); + var v=s; } diff --git a/test/raven-integration/Widget/WidgetCrud.cs b/test/raven-integration/Widget/WidgetCrud.cs index 53f38671..51515dc6 100644 --- a/test/raven-integration/Widget/WidgetCrud.cs +++ b/test/raven-integration/Widget/WidgetCrud.cs @@ -19,7 +19,6 @@ namespace raven_integration { "id": 0, "name": "string", - "created": "2018-02-09T16:45:56.057Z", "dollarAmount": 0, "active": true, "roles": 0 @@ -28,7 +27,6 @@ namespace raven_integration //CREATE dynamic w1 = new JObject(); w1.name = Util.Uniquify("First Test WIDGET"); - w1.created = DateTime.Now.ToString(); w1.dollarAmount = 1.11m; w1.active = true; w1.roles = 0; @@ -40,7 +38,6 @@ namespace raven_integration dynamic w2 = new JObject(); w2.name = Util.Uniquify("Second Test WIDGET"); - w2.created = DateTime.Now.ToString(); w2.dollarAmount = 2.22m; w2.active = true; w2.roles = 0; @@ -161,7 +158,6 @@ namespace raven_integration dynamic w2 = new JObject(); w2.name = Util.Uniquify("PutConcurrencyViolationShouldFail"); - w2.created = DateTime.Now.ToString(); w2.dollarAmount = 2.22m; w2.active = true; w2.roles = 0; @@ -199,7 +195,6 @@ namespace raven_integration dynamic w2 = new JObject(); w2.name = Util.Uniquify("PatchConcurrencyViolationShouldFail"); - w2.created = DateTime.Now.ToString(); w2.dollarAmount = 2.22m; w2.active = true; w2.roles = 0;