Files
raven/server/AyaNova/util/Seeder.cs
2020-04-16 22:58:41 +00:00

947 lines
44 KiB
C#

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<string> RandomTags(Faker f)
{
var t = f.PickRandom(TagSet, f.Random.Int(1, 5));//pick up to 5 tags to apply
return new List<string>(t);
}
//////////////////////////////////////////////////////
//Seed test data for integration tests
//
public static async Task SeedKnownUsersAsync(ILogger log)
{
try
{
var KnownUserTags = new List<string>();
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;
}
}
/// <summary>
/// Generate seed user with active=true
/// (override to save typing)
/// </summary>
public static async Task GenSeedUserAsync(ILogger log, int count, AuthorizationRoles roles, UserType userType, string login, string password, List<string> 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<string> 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.WikiContent=@"
## Example Markdown for Wiki pages
Headings
# Heading 1st level
## Heading 2nd level
### Heading 3rd level
#### Heading 4th level
##### Heading 5th level
###### Heading 6th level
Emphasis text styles
*Italic*
**Bold**
Hyperlink
[Link](https://ayanova.com)
Image
![Image](https://www.ayanova.com/images/AyaNovaIcon256.png)
Quote block
> ""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.""
> The overriding design goal for Markdown's
> formatting syntax is to make it as readable
> as possible. The idea is that a
> Markdown-formatted document should be
> publishable as-is, as plain text, without
> looking like it's been marked up with tags
>> or formatting instructions.
Unordered list
* List
* List
* List
Ordered list
1. One
2. Two
3. Three
Nested lists
* First
* subitem One
* subitem Two
* Second
1. sub one
2. sub two
Horizontal rule
---
`Inline block` with backticks
```
# Multi-line block
print '3 backticks or'
print 'indent 4 spaces'
```
Add Tasks
- [ ] task one
- [x] task two (completed)
Markdown Quick Reference
========================
This guide is a very brief overview, with examples, of the syntax that [Markdown] supports. It is itself written in Markdown and you can copy the samples over to the left-hand pane for experimentation. It's shown as *text* and not *rendered HTML*.
[Markdown]: http://daringfireball.net/projects/markdown/
Simple Text Formatting
======================
First thing is first. You can use *stars* or _underscores_ for italics. **Double stars** and __double underscores__ do bold. ***Three together*** do ___both___.
Paragraphs are pretty easy too. Just have a blank line between chunks of text.
> This chunk of text is in a block quote. Its multiple lines will all be
> indended a bit from the rest of the text.
>
> > Multiple levels of block quotes also work.
Sometimes you want to include some code, such as when you are explaining how `<h1>` HTML tags work, or maybe you are a programmer and you are discussing `someMethod()`.
If you want to include some code and have
newlines preserved, indent the line with a tab
or at least four spaces.
Extra spaces work here too.
This is also called preformatted text and it is useful for showing examples.
The text will stay as text, so any *markdown* or <u>HTML</u> you add will
not show up formatted. This way you can show markdown examples in a
markdown document.
> You can also use preformatted text with your blockquotes
> as long as you add at least five spaces.
Headings
========
There are a couple of ways to make headings. Using three or more equals signs on a line under a heading makes it into an ""h1"" style. Three or more hyphens under a line makes it \""h2\"" (slightly smaller). You can also use multiple pound symbols before and after a heading. Pounds after the title are ignored. Here's some examples:
This is H1
==========
This is H2
----------
# This is H1
## This is H2
### This is H3 with some extra pounds ###
#### You get the idea ####
##### I don't need extra pounds at the end
###### H6 is the max
Links
=====
Let's link to a few sites. First, let's use the bare URL, like <http://www.github.com>. Great for text, but ugly for HTML.
Next is an inline link to [Google](http://www.google.com). A little nicer.
This is a reference-style link to [Wikipedia] [1].
Lastly, here's a pretty link to [Yahoo]. The reference-style and pretty links both automatically use the links defined below, but they could be defined *anywhere* in the markdown and are removed from the HTML. The names are also case insensitive, so you can use [YaHoO] and have it link properly.
[1]: http://www.wikipedia.org/
[Yahoo]: http://www.yahoo.com/
Title attributes may be added to links by adding text after a link.
This is the [inline link](http://www.bing.com \""Bing\"") with a \""Bing\"" title.
You can also go to [W3C] [2] and maybe visit a [friend].
[2]: http://w3c.org (The W3C puts out specs for web-based things)
[Friend]: http://facebook.com/ \""Facebook!\""
Email addresses in plain text are not linked: test@example.com.
Email addresses wrapped in angle brackets are linked: <test@example.com>.
They are also obfuscated so that email harvesting spam robots hopefully won't get them.
Lists
=====
* This is a bulleted list
* Great for shopping lists
- You can also use hyphens
+ Or plus symbols
The above is an \""unordered\"" list. Now, on for a bit of order.
1. Numbered lists are also easy
2. Just start with a number
3738762. However, the actual number doesn't matter when converted to HTML.
1. This will still show up as 4.
You might want a few advanced lists:
- This top-level list is wrapped in paragraph tags
- This generates an extra space between each top-level item.
- You do it by adding a blank line
- This nested list also has blank lines between the list items.
- How to create nested lists
1. Start your regular list
2. Indent nested lists with four spaces
3. Further nesting means you should indent with four more spaces
* This line is indented with eight spaces.
- List items can be quite lengthy. You can keep typing and either continue
them on the next line with no indentation.
- Alternately, if that looks ugly, you can also
indent the next line a bit for a prettier look.
- You can put large blocks of text in your list by just indenting with four spaces.
This is formatted the same as code, but you can inspect the HTML
and find that it's just wrapped in a `<p>` tag and *won't* be shown
as preformatted text.
You can keep adding more and more paragraphs to a single
list item by adding the traditional blank line and then keep
on indenting the paragraphs with four spaces. You really need
to only indent the first line, but that looks ugly.
- Lists support blockquotes
> Just like this example here. By the way, you can
> nest lists inside blockquotes!
> - Fantastic!
- Lists support preformatted text
You just need to indent eight spaces.
Even More
=========
Horizontal Rule
---------------
If you need a horizontal rule you just need to put at least three hyphens, asterisks, or underscores on a line by themselves. You can also even put spaces between the characters.
---
****************************
_ _ _ _ _ _ _
Those three all produced horizontal lines. Keep in mind that three hyphens under any text turns that text into a heading, so add a blank like if you use hyphens.
Images
------
Images work exactly like links, but they have exclamation points in front. They work with references and titles too.
![Google Logo](http://www.google.com/images/errors/logo_sm.gif) and ![Happy].
[Happy]: http://www.wpclipart.com/smiley/simple_smiley/smiley_face_simple_green_small.png (\""Smiley face\"")
Inline HTML
-----------
If markdown is too limiting, you can just insert your own <strike>crazy</strike> HTML. Span-level HTML <u>can *still* use markdown</u>. Block level elements must be separated from text by a blank line and must not have any spaces before the opening and closing HTML.
<div style='font-family: \""Comic Sans\"", sans-serif;'>
It is a pity, but markdown does **not** work in here for most markdown parsers. [Marked] handles it pretty well.
</div>
";
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