using System; using System.Threading.Tasks; using System.Collections.Generic; using AyaNova.Models; using AyaNova.Biz; using Microsoft.Extensions.Logging; using Microsoft.EntityFrameworkCore; using Bogus; using AyaNova.Api.ControllerHelpers; using System.Diagnostics; namespace AyaNova.Util { public static class Seeder { public enum SeedLevel { NotValid, SmallOneManShopTrialDataSet, MediumLocalServiceCompanyTrialDataSet, LargeCorporateMultiRegionalTrialDataSet, HugeForLoadTest }; public static int SeededUserCount = 0; public static SeedLevel StringToSeedLevel(string size) { switch (size.ToLowerInvariant()) { case "small": return SeedLevel.SmallOneManShopTrialDataSet; case "medium": return SeedLevel.MediumLocalServiceCompanyTrialDataSet; case "large": return SeedLevel.LargeCorporateMultiRegionalTrialDataSet; case "huge": return SeedLevel.HugeForLoadTest; default: return SeedLevel.NotValid; } } ////////////////////////////////////////////////////// //Seed database for trial and testing purposes // public static async Task SeedDatabaseAsync(SeedLevel slevel, Decimal timeZoneOffset) { await SeedDatabaseAsync(slevel, Guid.Empty, timeZoneOffset); } public static async Task SeedDatabaseAsync(SeedLevel slevel, Guid JobId, Decimal timeZoneOffset) { bool LogJob = JobId != Guid.Empty; SeededUserCount = 0; ILogger log = AyaNova.Util.ApplicationLogging.CreateLogger("Seeder"); ApiServerState apiServerState = (ApiServerState)ServiceProviderProvider.Provider.GetService(typeof(ApiServerState)); //get the current server state so can set back to it later ApiServerState.ServerState wasServerState = apiServerState.GetState(); string wasReason = apiServerState.Reason; //START SERIAL NUMBER GENERATORS if (ServerBootConfig.WIDGET_SERIAL == null) ServerBootConfig.WIDGET_SERIAL = new AutoId(0); try { await LogStatusAsync(JobId, LogJob, log, $"SEEDER: Seeding data level is {slevel.ToString()}, time zone offset is {timeZoneOffset.ToString()}"); //Only allow this in a trial database if (!AyaNova.Core.License.ActiveKey.TrialLicense) { var msg = $"This database has a registered license key so it can't be seeded: {AyaNova.Core.License.LicenseInfoLogFormat}"; await LogStatusAsync(JobId, LogJob, log, msg); throw new System.NotSupportedException(msg); } //validate timezone offset if (timeZoneOffset > 14 || timeZoneOffset < (-12)) { var msg = $"Time zone offset \"{timeZoneOffset.ToString()}\" is not valid"; await LogStatusAsync(JobId, LogJob, log, msg); throw new System.NotSupportedException(msg); } apiServerState.SetOpsOnly("Seeding database"); //Erase all the data except for the license, schema and the manager user await DbUtil.EmptyBizDataFromDatabaseForSeedingOrImportingAsync(log); // //Set the default user options of the manager account // using (var cct = ServiceProviderProvider.DBContext) // { // var mgr = await cct.UserOptions.FirstAsync(m => m.Id == 1); // mgr.TimeZoneOffset = timeZoneOffset; // await cct.SaveChangesAsync(); // } //WIDGET sample form customization { var fc = new FormCustom() { FormKey = AyaType.Widget.ToString(), Template = @"[ { ""fld"": ""Notes"", ""required"": true }, { ""fld"": ""WidgetCustom1"", ""required"": false, ""type"": 1 }, { ""fld"": ""WidgetCustom2"", ""required"": true, ""type"": 4 }, { ""fld"": ""WidgetCustom3"", ""required"": false, ""type"": 5 }, { ""fld"": ""WidgetCustom4"", ""required"": false, ""type"": 6 }, { ""fld"": ""WidgetCustom5"", ""required"": false, ""type"": 8 }, { ""fld"": ""WidgetCustom6"", ""required"": false, ""type"": 2 }, { ""fld"": ""WidgetCustom7"", ""required"": false, ""type"": 3 } ]" }; //Create and save to db using (var cct = ServiceProviderProvider.DBContext) { await FormCustomBiz.GetBiz(cct).CreateAsync(fc); } } //Create a couple of DataListView's for development and testing { var dlv = new DataListView() { Name = "Name starts with generic", UserId = 1, ListKey = "TestWidgetDataList", Public = true, ListView = @"[{""fld"": ""widgetname"",""filter"": {""any"":false,""items"": [{""op"": ""%-"",""value"": ""Generic""}]}}]" }; //Create and save to db using (var cct = ServiceProviderProvider.DBContext) { await DataListViewBiz.GetBiz(cct).CreateAsync(dlv); } dlv = new DataListView() { Name = "Awesome (lots of fields)", UserId = 1, ListKey = "TestWidgetDataList", Public = true, ListView = @"[{""fld"": ""widgetname"",""filter"": {""any"":false,""items"": [{""op"": ""%-"",""value"": ""Awesome""}]}},{""fld"":""widgetserial""},{""fld"":""widgetdollaramount""},{""fld"":""widgetusertype""},{""fld"":""widgetstartdate""},{""fld"":""widgetactive""},{""fld"":""username""},{""fld"":""widgettags""},{""fld"":""widgetcustom1""},{""fld"":""widgetcustom2""}]" }; //Create and save to db using (var cct = ServiceProviderProvider.DBContext) { await DataListViewBiz.GetBiz(cct).CreateAsync(dlv); } } //Seed special test data for integration testing //log.LogInformation("Seeding known users"); await SeedKnownUsersAsync(log); //log.LogInformation("Seeding all other data"); switch (slevel) { case SeedLevel.SmallOneManShopTrialDataSet: { #region GenSmall //This is for a busy but one man shop with a single office person handling stuff back at the shop //PERF await LogStatusAsync(JobId, LogJob, log, $"Seeding SMALL number of user(s)...."); var watch = new Stopwatch(); watch.Start(); //Generate owner and lead tech await GenSeedUserAsync(log, 1, AuthorizationRoles.BizAdminFull | AuthorizationRoles.DispatchFull | AuthorizationRoles.InventoryFull | AuthorizationRoles.OpsAdminFull, UserType.Schedulable); //Generate one office person / secretary await GenSeedUserAsync(log, 1, AuthorizationRoles.DispatchFull | AuthorizationRoles.InventoryFull | AuthorizationRoles.AccountingFull, UserType.NonSchedulable); //PERF watch.Stop(); await LogStatusAsync(JobId, LogJob, log, $"{SeededUserCount} Users seeded in {watch.ElapsedMilliseconds} ms"); //100 widgets watch = new Stopwatch(); watch.Start(); await GenSeedWidgetAsync(log, 100); //PERF watch.Stop(); await LogStatusAsync(JobId, LogJob, log, $"100 Widgets seeded in {watch.ElapsedMilliseconds} ms"); #endregion gensmall } break; case SeedLevel.MediumLocalServiceCompanyTrialDataSet: { #region GenMedium //This is for a typical AyaNova medium busy shop //has one location, many techs and full staff for each department //PERF await LogStatusAsync(JobId, LogJob, log, $"Seeding MEDIUM number of user(s)...."); var watch = new Stopwatch(); watch.Start(); //One IT administrator, can change ops but nothing else await GenSeedUserAsync(log, 1, AuthorizationRoles.OpsAdminFull, UserType.NonSchedulable); //One business administrator, can view ops issues await GenSeedUserAsync(log, 1, AuthorizationRoles.BizAdminFull | AuthorizationRoles.OpsAdminLimited, UserType.NonSchedulable); //One owner who doesn't control anything but views stuff await GenSeedUserAsync(log, 1, AuthorizationRoles.BizAdminLimited | AuthorizationRoles.DispatchLimited | AuthorizationRoles.InventoryLimited | AuthorizationRoles.OpsAdminLimited | AuthorizationRoles.SalesLimited, UserType.NonSchedulable); //20 techs await GenSeedUserAsync(log, 20, AuthorizationRoles.TechFull | AuthorizationRoles.DispatchLimited, UserType.Schedulable); //2 subcontractors await GenSeedUserAsync(log, 2, AuthorizationRoles.SubContractorFull, UserType.Subcontractor); //3 generic office people people await GenSeedUserAsync(log, 3, AuthorizationRoles.DispatchLimited | AuthorizationRoles.InventoryLimited, UserType.NonSchedulable); //2 Full sales people await GenSeedUserAsync(log, 2, AuthorizationRoles.SalesFull, UserType.NonSchedulable); //1 dispatch manager await GenSeedUserAsync(log, 1, AuthorizationRoles.DispatchFull | AuthorizationRoles.InventoryLimited, UserType.NonSchedulable); //1 Inventory manager await GenSeedUserAsync(log, 1, AuthorizationRoles.InventoryFull | AuthorizationRoles.DispatchLimited, UserType.NonSchedulable); //1 accountant / bookkeeper await GenSeedUserAsync(log, 1, AuthorizationRoles.AccountingFull | AuthorizationRoles.BizAdminLimited, UserType.NonSchedulable); //10 full on customer users await GenSeedUserAsync(log, 10, AuthorizationRoles.CustomerLimited, UserType.Customer); //10 limited customer users await GenSeedUserAsync(log, 10, AuthorizationRoles.CustomerLimited, UserType.Customer); //PERF watch.Stop(); await LogStatusAsync(JobId, LogJob, log, $"{SeededUserCount} Users seeded in {watch.ElapsedMilliseconds} ms"); //500 widgets await LogStatusAsync(JobId, LogJob, log, $"Seeding 500 Widgets...."); watch = new Stopwatch(); watch.Start(); //await GenSeedWidgetAsync(log, 500); await GenSeedWidgetAsync(log, 500); //PERF watch.Stop(); await LogStatusAsync(JobId, LogJob, log, $"500 Widgets seeded in {watch.ElapsedMilliseconds} ms"); #endregion genmedium } break; case SeedLevel.LargeCorporateMultiRegionalTrialDataSet: { #region GenLarge //this is a large corporation with multiple branches in multiple locations all in the same country //Each location has a full staff and corporate head office has an overarching staff member in charge of each location //PERF await LogStatusAsync(JobId, LogJob, log, $"Seeding LARGE number of user(s)...."); var watch = new Stopwatch(); watch.Start(); //IT administrator, can change ops but nothing else await GenSeedUserAsync(log, 2, AuthorizationRoles.OpsAdminFull, UserType.NonSchedulable); //business administrator, can view ops issues await GenSeedUserAsync(log, 2, AuthorizationRoles.BizAdminFull | AuthorizationRoles.OpsAdminLimited, UserType.NonSchedulable); //owner / upper management who doesn't control anything but views stuff await GenSeedUserAsync(log, 5, AuthorizationRoles.BizAdminLimited | AuthorizationRoles.DispatchLimited | AuthorizationRoles.InventoryLimited | AuthorizationRoles.OpsAdminLimited, UserType.NonSchedulable); //100 techs await GenSeedUserAsync(log, 100, AuthorizationRoles.TechFull | AuthorizationRoles.DispatchLimited, UserType.Schedulable); //limited techs await GenSeedUserAsync(log, 50, AuthorizationRoles.TechLimited | AuthorizationRoles.DispatchLimited, UserType.Schedulable); //20 subcontractors await GenSeedUserAsync(log, 20, AuthorizationRoles.SubContractorFull, UserType.Subcontractor); //10 limited subcontractors await GenSeedUserAsync(log, 10, AuthorizationRoles.SubContractorLimited, UserType.Subcontractor); //30 generic office people people await GenSeedUserAsync(log, 30, AuthorizationRoles.DispatchLimited | AuthorizationRoles.InventoryLimited, UserType.NonSchedulable); //10 Full sales people await GenSeedUserAsync(log, 10, AuthorizationRoles.SalesFull, UserType.NonSchedulable); //5 Limited sales people await GenSeedUserAsync(log, 5, AuthorizationRoles.SalesLimited, UserType.NonSchedulable); //5 dispatch manager await GenSeedUserAsync(log, 5, AuthorizationRoles.DispatchFull | AuthorizationRoles.InventoryLimited, UserType.NonSchedulable); //5 Inventory manager await GenSeedUserAsync(log, 5, AuthorizationRoles.InventoryFull | AuthorizationRoles.DispatchLimited, UserType.NonSchedulable); //10 Inventory manager assistants await GenSeedUserAsync(log, 5, AuthorizationRoles.InventoryLimited, UserType.NonSchedulable); //5 accountant / bookkeeper await GenSeedUserAsync(log, 5, AuthorizationRoles.AccountingFull | AuthorizationRoles.BizAdminLimited, UserType.NonSchedulable); //100 full on customer users await GenSeedUserAsync(log, 20, AuthorizationRoles.CustomerFull, UserType.Customer); //100 limited customer users await GenSeedUserAsync(log, 20, AuthorizationRoles.CustomerLimited, UserType.Customer); //PERF watch.Stop(); await LogStatusAsync(JobId, LogJob, log, $"{SeededUserCount} Users seeded in {watch.ElapsedMilliseconds} ms"); //5000 widgets await LogStatusAsync(JobId, LogJob, log, $"Seeding 5,000 Widgets...."); watch = new Stopwatch(); watch.Start(); //await GenSeedWidgetAsync(log, 5000); await GenSeedWidgetAsync(log, 5000); //PERF watch.Stop(); await LogStatusAsync(JobId, LogJob, log, $"5k Widgets seeded in {watch.ElapsedMilliseconds} ms"); #endregion genlarge } break; case SeedLevel.HugeForLoadTest: { #region GenHuge //this is the HUGE dataset for load and other testing //It is acceptable for this seeding to take many hours as it would normally be used rarely //PERF await LogStatusAsync(JobId, LogJob, log, $"Seeding HUGE number of user(s)...."); var watch = new Stopwatch(); watch.Start(); //IT administrator, can change ops but nothing else await GenSeedUserAsync(log, 10, AuthorizationRoles.OpsAdminFull, UserType.NonSchedulable); //business administrator, can view ops issues await GenSeedUserAsync(log, 10, AuthorizationRoles.BizAdminFull | AuthorizationRoles.OpsAdminLimited, UserType.NonSchedulable); //owner / upper management who doesn't control anything but views stuff await GenSeedUserAsync(log, 20, AuthorizationRoles.BizAdminLimited | AuthorizationRoles.DispatchLimited | AuthorizationRoles.InventoryLimited | AuthorizationRoles.OpsAdminLimited, UserType.NonSchedulable); //regular techs await GenSeedUserAsync(log, 500, AuthorizationRoles.TechFull | AuthorizationRoles.DispatchLimited, UserType.Schedulable); //limited techs await GenSeedUserAsync(log, 200, AuthorizationRoles.TechLimited | AuthorizationRoles.DispatchLimited, UserType.Schedulable); //subcontractors await GenSeedUserAsync(log, 80, AuthorizationRoles.SubContractorFull, UserType.Subcontractor); //limited subcontractors await GenSeedUserAsync(log, 40, AuthorizationRoles.SubContractorLimited, UserType.Subcontractor); //generic office people people await GenSeedUserAsync(log, 200, AuthorizationRoles.DispatchLimited | AuthorizationRoles.InventoryLimited, UserType.NonSchedulable); //20 Full sales people await GenSeedUserAsync(log, 20, AuthorizationRoles.SalesFull, UserType.NonSchedulable); //10 Limited sales people await GenSeedUserAsync(log, 10, AuthorizationRoles.SalesLimited, UserType.NonSchedulable); //dispatch manager await GenSeedUserAsync(log, 20, AuthorizationRoles.DispatchFull | AuthorizationRoles.InventoryLimited, UserType.NonSchedulable); //Inventory manager await GenSeedUserAsync(log, 40, AuthorizationRoles.InventoryFull | AuthorizationRoles.DispatchLimited, UserType.NonSchedulable); //Inventory manager assistants await GenSeedUserAsync(log, 20, AuthorizationRoles.InventoryLimited, UserType.NonSchedulable); //accountant / bookkeeper await GenSeedUserAsync(log, 20, AuthorizationRoles.AccountingFull | AuthorizationRoles.BizAdminLimited, UserType.NonSchedulable); //full on customer users await GenSeedUserAsync(log, 200, AuthorizationRoles.CustomerFull, UserType.Customer); //limited customer users await GenSeedUserAsync(log, 50, AuthorizationRoles.CustomerLimited, UserType.Customer); //PERF watch.Stop(); await LogStatusAsync(JobId, LogJob, log, $"{SeededUserCount} Users seeded in {watch.ElapsedMilliseconds} ms"); //20000 widgets await LogStatusAsync(JobId, LogJob, log, $"Seeding 20,000 Widgets...."); watch = new Stopwatch(); watch.Start(); //await GenSeedWidgetAsync(log, 20000); await GenSeedWidgetAsync(log, 20000); watch.Stop(); await LogStatusAsync(JobId, LogJob, log, $"20k Widgets seeded in {watch.ElapsedMilliseconds} ms"); #endregion genhuge } break; } await LogStatusAsync(JobId, LogJob, log, "Seeding completed successfully"); } catch (Exception ex) { log.LogError(ex, "Seeder:SeedDatabase error during ops"); if (LogJob) await JobsBiz.LogJobAsync(JobId, $"Seeder:SeedDatabase error during ops\r\n{ex.Message}"); throw ex; } finally { //TODO: fully async: watch the job and don't turn the state back until the job is done? log.LogInformation($"Seeder: setting server state back to {wasServerState.ToString()}"); apiServerState.SetState(wasServerState, wasReason); } } //Log the status and also job if it's run via job private static async Task LogStatusAsync(Guid JobId, bool LogJob, ILogger log, string msg) { log.LogInformation(msg); if (LogJob) await JobsBiz.LogJobAsync(JobId, msg); } public static long RUNNING_COUNT = 0; public static string Uniquify(string s) { return s + " " + (++RUNNING_COUNT).ToString(); } private static string[] TagSet = new[] { "red", "orange", "yellow", "green", "blue", "indigo", "violet", "brown", "black", "white", "silver", "gold", "fuchsia", "jade", "mauve", "purple", "quince", "xanthic", "zebra", "zone0", "zone1", "zone2", "zone3", "zone4", "zone5", "zone6", "zone7", "zone8", "zone9" }; private static List RandomTags(Faker f) { var t = f.PickRandom(TagSet, f.Random.Int(1, 5));//pick up to 5 tags to apply return new List(t); } ////////////////////////////////////////////////////// //Seed test data for integration tests // public static async Task SeedKnownUsersAsync(ILogger log) { try { var KnownUserTags = new List(); KnownUserTags.Add("known-user"); KnownUserTags.Add("test-role-user"); //TEST USERS //one of each role type await GenSeedUserAsync(log, 1, AuthorizationRoles.BizAdminLimited, UserType.NonSchedulable, "BizAdminLimited", "BizAdminLimited", KnownUserTags); await GenSeedUserAsync(log, 1, AuthorizationRoles.BizAdminFull, UserType.NonSchedulable, "BizAdminFull", "BizAdminFull", KnownUserTags); await GenSeedUserAsync(log, 1, AuthorizationRoles.DispatchLimited, UserType.NonSchedulable, "DispatchLimited", "DispatchLimited", KnownUserTags); await GenSeedUserAsync(log, 1, AuthorizationRoles.DispatchFull, UserType.NonSchedulable, "DispatchFull", "DispatchFull", KnownUserTags); await GenSeedUserAsync(log, 1, AuthorizationRoles.InventoryLimited, UserType.NonSchedulable, "InventoryLimited", "InventoryLimited", KnownUserTags); await GenSeedUserAsync(log, 1, AuthorizationRoles.InventoryFull, UserType.NonSchedulable, "InventoryFull", "InventoryFull", KnownUserTags); await GenSeedUserAsync(log, 1, AuthorizationRoles.AccountingFull, UserType.NonSchedulable, "Accounting", "Accounting", KnownUserTags); await GenSeedUserAsync(log, 1, AuthorizationRoles.TechLimited, UserType.Schedulable, "TechLimited", "TechLimited", KnownUserTags); await GenSeedUserAsync(log, 1, AuthorizationRoles.TechFull, UserType.Schedulable, "TechFull", "TechFull", KnownUserTags); await GenSeedUserAsync(log, 1, AuthorizationRoles.SalesLimited, UserType.NonSchedulable, "SalesLimited", "SalesLimited", KnownUserTags); await GenSeedUserAsync(log, 1, AuthorizationRoles.SalesFull, UserType.NonSchedulable, "SalesFull", "SalesFull", KnownUserTags); await GenSeedUserAsync(log, 1, AuthorizationRoles.SubContractorLimited, UserType.Subcontractor, "SubContractorLimited", "SubContractorLimited", KnownUserTags); await GenSeedUserAsync(log, 1, AuthorizationRoles.SubContractorFull, UserType.Subcontractor, "SubContractorFull", "SubContractorFull", KnownUserTags); await GenSeedUserAsync(log, 1, AuthorizationRoles.CustomerLimited, UserType.Customer, "CustomerLimited", "CustomerLimited", KnownUserTags); await GenSeedUserAsync(log, 1, AuthorizationRoles.CustomerFull, UserType.Customer, "CustomerFull", "CustomerFull", KnownUserTags); await GenSeedUserAsync(log, 1, AuthorizationRoles.CustomerFull, UserType.HeadOffice, "HeadOffice", "HeadOffice", KnownUserTags); await GenSeedUserAsync(log, 1, AuthorizationRoles.OpsAdminLimited, UserType.NonSchedulable, "OpsAdminLimited", "OpsAdminLimited", KnownUserTags); await GenSeedUserAsync(log, 1, AuthorizationRoles.OpsAdminFull, UserType.NonSchedulable, "OpsAdminFull", "OpsAdminFull", KnownUserTags); //PRIVACY TEST USER - this is used for a test to see if user info leaks into the logs await GenSeedUserAsync(log, 1, AuthorizationRoles.OpsAdminLimited, UserType.NonSchedulable, "TEST_PRIVACY_USER_ACCOUNT", "TEST_PRIVACY_USER_ACCOUNT", KnownUserTags); //TEST NOT ACTIVE - this is used for a test to see if inactive user can login await GenSeedUserAsync(log, 1, AuthorizationRoles.OpsAdminLimited, UserType.NonSchedulable, false, "TEST_INACTIVE", "TEST_INACTIVE", 0, KnownUserTags); //Alternate translation users for each stock translation await GenSeedUserAsync(log, 1, AuthorizationRoles.All, UserType.Administrator, true, "de", "de", await TranslationBiz.TranslationNameToIdStaticAsync("de"), KnownUserTags); await GenSeedUserAsync(log, 1, AuthorizationRoles.All, UserType.Administrator, true, "es", "es", await TranslationBiz.TranslationNameToIdStaticAsync("es"), KnownUserTags); await GenSeedUserAsync(log, 1, AuthorizationRoles.All, UserType.Administrator, true, "fr", "fr", await TranslationBiz.TranslationNameToIdStaticAsync("fr"), KnownUserTags); } catch { throw; } } /// /// Generate seed user with active=true /// (override to save typing) /// public static async Task GenSeedUserAsync(ILogger log, int count, AuthorizationRoles roles, UserType userType, string login, string password, List tags = null) { try { await GenSeedUserAsync(log, count, roles, userType, true, login, password, 0, tags); } catch { throw; } } public static async Task GenSeedUserAsync(ILogger log, int count, AuthorizationRoles roles, UserType userType, bool active = true, string login = null, string password = null, long translationId = 0, List tags = null) { if (translationId == 0) translationId = ServerBootConfig.AYANOVA_DEFAULT_TRANSLATION_ID; //Don't do the following commented out, it's slower // using (var ct = ServiceProviderProvider.DBContext) // { // UserBiz Biz = UserBiz.GetBiz(ct); Faker Fake = new Faker(); for (int x = 0; x < count; x++) { User u = new User(); u.Active = active; var p = new Bogus.Person(); u.Name = Uniquify(p.FullName); if (login != null) { u.Login = login; u.Name += " - " + login; } else u.Login = p.FirstName; if (password != null) u.Password = password; else u.Password = u.Login; u.Roles = roles; u.UserType = userType; u.EmployeeNumber = "A-" + (454 + SeededUserCount).ToString() + "-Y"; u.Notes = Fake.Lorem.Sentence();//Fake.Lorem.Paragraph(2); //TODO: After have USER and HEADOFFICE and VENDOR, if usertype is subcontractor or client or headoffice it needs to set a corresponding user's parent org record id to go with it //use provided tags or generate them if (tags == null) u.Tags = RandomTags(Fake); else u.Tags = tags; //Children and relations u.UserOptions = new UserOptions(); u.UserOptions.TranslationId = translationId; u.UserOptions.EmailAddress = p.Email.Replace("gmail.com", "helloayanova.com").Replace("hotmail.com", "helloayanova.com").Replace("yahoo.com", "helloayanova.com"); u.UserOptions.Hour12 = true; u.UserOptions.CurrencyName = "USD"; u.UserOptions.UiColor = Fake.Internet.Color(); //this seems wrong but is actually faster!? UserBiz Biz = UserBiz.GetBiz(ServiceProviderProvider.DBContext); //allow creation of not entirely ready users (missing client id or subcontractor vendor id etc) Biz.SeedOrImportRelaxedRulesMode = true; var NewObject = await Biz.CreateAsync(u); if (NewObject == null) { log.LogError($"Seeder::GenSeedUser error creating user {u.Name}\r\n" + Biz.GetErrorsAsString()); throw new System.Exception("Seeder::GenSeedUser error creating user\r\n" + Biz.GetErrorsAsString()); } //} } SeededUserCount += count; } ////////////////////////////////////////////////////// //Seed widget for testing // public static async Task GenSeedWidgetAsync(ILogger log, int count) { //this is 4 times slower than doing it inside the loop below //seems counterintuitive but maybe it's to do with the db context not being refreshed? // WidgetBiz biz = WidgetBiz.GetBiz(ServiceProviderProvider.DBContext); var f = new Bogus.Faker(); //RANDOM ROLES Array values = Enum.GetValues(typeof(UserType)); Random random = new Random(); DateTime seedStartWindow = DateTime.Now.AddYears(-1); DateTime seedEndWindow = DateTime.Now.AddYears(1); for (int x = 0; x < count; x++) { Widget o = new Widget(); o.Name = Uniquify(f.Commerce.ProductName()); o.Active = true; // o.StartDate = f.Date.Between(DateTime.Now, DateTime.Now.AddMinutes(60)).ToUniversalTime(); // o.EndDate = f.Date.Between(DateTime.Now.AddMinutes(90), DateTime.Now.AddHours(5)).ToUniversalTime(); // o.StartDate = DateTime.Now.ToUniversalTime(); // o.EndDate = DateTime.Now.AddMinutes(60).ToUniversalTime(); DateTime dtSeed = f.Date.Between(seedStartWindow, seedEndWindow).ToUniversalTime(); o.StartDate = dtSeed; o.EndDate = dtSeed.AddMinutes(60).ToUniversalTime(); o.DollarAmount = Convert.ToDecimal(f.Commerce.Price()); //Random but valid enum UserType randomUserType = (UserType)values.GetValue(random.Next(values.Length)); o.UserType = randomUserType; o.Notes = f.Lorem.Sentence(); o.Wiki=@" # Markdown quick reference for Wiki pages *** ***
## Markdown and Wiki documents Wiki's are formatted using **[Markdown](https://en.wikipedia.org/wiki/Markdown)** a plain text formatting language. This document is a quick reference guide and at the bottom is a link to a more comprehensive guide online. You can also use the formatting toolbar above to perform the same tasks. # Headings # Heading 1st level ## Heading 2nd level ### Heading 3rd level #### Heading 4th level ##### Heading 5th level ###### Heading 6th level *** # Emphasis text styles *Italic* **Bold** ~~Strike-through~~ ***Bold And Italic*** # Quote blocks > ""Morbi eget dapibus felis. Vivamus venenatis porttitor tortor sit amet rutrum. Pellentesque aliquet quam enim, eu volutpat urna rutrum a. Nam vehicula nunc > > mauris, a ultricies libero efficitur sed. *Class aptent* taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Sed molestie imperdiet consectetur."" # Lists ### Unordered list * List * List * List ### Ordered list 1. One 2. Two 3. Three ### Auto number ordered list Ordered lists don't need the numbers to be in order, just that they start with 1: 1. Item 1. another item 1. more item ### Nested lists * First * subitem One * subitem Two * Second 1. sub one 2. sub two # Blank lines You can force extra blank lines by entering `
` here are two blank ...

...lines. # Horizontal rules *** # Blocks `Inline block` with backticks ``` Multi-line block print '3 backticks or' print 'indent 4 spaces' ``` # Task lists - [ ] task one - [x] task two (completed) # TABLES | First | Last | Year | | -------- | -------- | -------- | | John | Doe | 2000 | | Mary | Smith | 2001 | | T. | Persson | 2010 | # Hyperlinks Inline text link and and optional tooltip: Link to [our website](https://ayanova.com ""Hover text tooltip"") example If you don't need an inline link you can simply enter it in angle brackets: Even email links work:
You can also use emphasis characters with links: Link to **[our website](https://ayanova.com)** example # Image This is how you insert an image into a wiki ![Image](https://www.ayanova.com/images/AyaNovaIcon256.png) # Emojis As with all areas of AyaNova where you can enter text, you can also use emoji characters: # 😀⚽🏒🍕🚗☀❤😎
# Markdown guide A more detailed markdown guide is available here: *** "; o.Tags = RandomTags(f); o.UserId = f.Random.Int(1, SeededUserCount); //RANDOM CUSTOM FIELD DATA var c1 = DateUtil.UniversalISO8661Format(f.Date.Between(DateTime.Now.AddYears(-1), DateTime.Now.AddYears(1))); var c2 = f.Lorem.Sentence(); var c3 = f.Random.Int(1, 99999999); var c4 = f.Random.Bool().ToString().ToLowerInvariant(); var c5 = f.Random.Decimal(); o.CustomFields = $@"{{c1:""{c1}"",c2:""{c2}"",c3:{c3},c4:{c4},c5:{c5}}}"; //This seems wrong to do in a loop but is 4 times faster this way ?!? WidgetBiz biz = WidgetBiz.GetBiz(ServiceProviderProvider.DBContext); var NewObject = await biz.CreateAsync(o); if (NewObject == null) { log.LogError($"Seeder::GenSeedWidget error creating widget {o.Name}\r\n" + biz.GetErrorsAsString()); throw new System.Exception("Seeder::GenSeedWidget error creating widget\r\n" + biz.GetErrorsAsString()); } } } }//eoc }//eons