diff --git a/src/AliasGenerators/AliasGenerators.csproj b/src/AliasGenerators/AliasGenerators.csproj index 35d83fef2..05d0f107a 100644 --- a/src/AliasGenerators/AliasGenerators.csproj +++ b/src/AliasGenerators/AliasGenerators.csproj @@ -27,4 +27,15 @@ + + + + + + + + + + + diff --git a/src/AliasGenerators/Identity/IIdentityGenerator.cs b/src/AliasGenerators/Identity/IIdentityGenerator.cs index 7addd5a15..f3b85efa2 100644 --- a/src/AliasGenerators/Identity/IIdentityGenerator.cs +++ b/src/AliasGenerators/Identity/IIdentityGenerator.cs @@ -4,6 +4,7 @@ // Licensed under the MIT license. See LICENSE.md file in the project root for full license information. // //----------------------------------------------------------------------- + namespace AliasGenerators.Identity; /// diff --git a/src/AliasGenerators/Identity/Implementations/Base/IdentityGenerator.cs b/src/AliasGenerators/Identity/Implementations/Base/IdentityGenerator.cs new file mode 100644 index 000000000..031172731 --- /dev/null +++ b/src/AliasGenerators/Identity/Implementations/Base/IdentityGenerator.cs @@ -0,0 +1,137 @@ +//----------------------------------------------------------------------- +// +// Copyright (c) lanedirt. All rights reserved. +// Licensed under the MIT license. See LICENSE.md file in the project root for full license information. +// +//----------------------------------------------------------------------- + +namespace AliasGenerators.Identity.Implementations.Base; + +using System.Reflection; +using AliasGenerators.Identity; +using AliasGenerators.Identity.Models; + +/// +/// Dutch identity generator which implements IIdentityGenerator and generates +/// random dutch identities. +/// +public abstract class IdentityGenerator : IIdentityGenerator +{ + /// + /// List of male first names in memory. + /// + private readonly List _firstNamesMale; + + /// + /// List of female first names in memory. + /// + private readonly List _firstNamesFemale; + + /// + /// List of last names in memory. + /// + private readonly List _lastNames; + + /// + /// Random instance. + /// + private readonly Random _random = new(); + + /// + /// Initializes a new instance of the class. + /// + protected IdentityGenerator() + { + _firstNamesMale = LoadList(FirstNamesListMale); + _firstNamesFemale = LoadList(FirstNamesListFemale); + _lastNames = LoadList(LastNamesList); + } + + /// + /// Gets namespace path to the male first names list for the correct language. + /// + protected virtual string FirstNamesListMale => "AliasGenerators.Identity.Implementations.Dictionaries.nl.firstnames_male"; + + /// + /// Gets namespace path to the female first names list for the correct language. + /// + protected virtual string FirstNamesListFemale => "AliasGenerators.Identity.Implementations.Dictionaries.nl.firstnames_female"; + + /// + /// Gets namespace path to the last names list for the correct language. + /// + protected virtual string LastNamesList => "AliasGenerators.Identity.Implementations.Dictionaries.nl.lastnames"; + + /// + public async Task GenerateRandomIdentityAsync() + { + await Task.Yield(); // Add an await statement to make the method truly asynchronous. + + // Generate identity. + var identity = new Identity(); + + // Determine gender. + if (_random.Next(2) == 0) + { + identity.FirstName = _firstNamesMale[_random.Next(_firstNamesMale.Count)]; + identity.Gender = Gender.Male; + } + else + { + identity.FirstName = _firstNamesFemale[_random.Next(_firstNamesFemale.Count)]; + identity.Gender = Gender.Female; + } + + identity.LastName = _lastNames[_random.Next(_lastNames.Count)]; + + // Generate random date of birth between 21 and 65 years of age. + identity.BirthDate = GenerateRandomDateOfBirth(); + identity.EmailPrefix = new UsernameEmailGenerator().GenerateEmailPrefix(identity); + identity.NickName = new UsernameEmailGenerator().GenerateUsername(identity); + + return identity; + } + + /// + /// Load a list of words from a resource file. + /// + /// Name of the resource file to load. + /// List of words from the resource file. + /// Thrown if resource file cannot be found. + private static List LoadList(string resourceName) + { + var assembly = Assembly.GetExecutingAssembly(); + + using var stream = assembly.GetManifestResourceStream(resourceName); + if (stream == null) + { + throw new FileNotFoundException("Resource '" + resourceName + "' not found.", resourceName); + } + + using var reader = new StreamReader(stream); + var words = new List(); + while (!reader.EndOfStream) + { + var line = reader.ReadLine(); + if (line != null) + { + words.Add(line); + } + } + + return words; + } + + /// + /// Generate a random date of birth. + /// + /// DateTime representing date of birth. + private DateTime GenerateRandomDateOfBirth() + { + // Generate random date of birth between 21 and 65 years of age. + var now = DateTime.Now; + var minDob = now.AddYears(-65); + var maxDob = now.AddYears(-21); + return minDob.AddDays(_random.Next((int)(maxDob - minDob).TotalDays)); + } +} diff --git a/src/AliasGenerators/Identity/Implementations/Dictionaries/en/firstnames_female b/src/AliasGenerators/Identity/Implementations/Dictionaries/en/firstnames_female new file mode 100644 index 000000000..dfc32a1e2 --- /dev/null +++ b/src/AliasGenerators/Identity/Implementations/Dictionaries/en/firstnames_female @@ -0,0 +1,153 @@ +Emily +Emma +Olivia +Ava +Sophia +Isabella +Mia +Charlotte +Amelia +Harper +Evelyn +Abigail +Elizabeth +Sofia +Avery +Ella +Madison +Scarlett +Victoria +Aria +Grace +Chloe +Camila +Penelope +Riley +Layla +Zoey +Nora +Lily +Eleanor +Hannah +Lillian +Addison +Aubrey +Ellie +Stella +Natalie +Zoe +Leah +Hazel +Violet +Aurora +Savannah +Audrey +Brooklyn +Bella +Claire +Skylar +Lucy +Paisley +Everly +Anna +Caroline +Nova +Genesis +Emilia +Kennedy +Samantha +Maya +Willow +Kinsley +Naomi +Aaliyah +Elena +Sarah +Ariana +Allison +Gabriella +Alice +Madelyn +Cora +Ruby +Eva +Serenity +Autumn +Adeline +Hailey +Gianna +Valentina +Isla +Eliana +Quinn +Nevaeh +Ivy +Sadie +Piper +Lydia +Alexa +Josephine +Emery +Julia +Delilah +Arianna +Vivian +Kaylee +Sophie +Brielle +Madeline +Peyton +Rylee +Clara +Hadley +Melanie +Mackenzie +Reagan +Adalyn +Liliana +Aubree +Jade +Katherine +Isabelle +Natalia +Raelynn +Maria +Athena +Ximena +Arya +Leilani +Taylor +Faith +Rose +Kylie +Alexandra +Mary +Margaret +Lyla +Ashley +Amaya +Eliza +Brianna +Bailey +Andrea +Khloe +Jasmine +Melody +Iris +Isabel +Norah +Annabelle +Valeria +Emerson +Adalynn +Ryleigh +Eden +Emersyn +Anastasia +Kayla +Alyssa +Anna +Juliana +Charlie +Lucia +Stella diff --git a/src/AliasGenerators/Identity/Implementations/Dictionaries/en/firstnames_male b/src/AliasGenerators/Identity/Implementations/Dictionaries/en/firstnames_male new file mode 100644 index 000000000..ceddb7bd2 --- /dev/null +++ b/src/AliasGenerators/Identity/Implementations/Dictionaries/en/firstnames_male @@ -0,0 +1,142 @@ +Michael +Christopher +Matthew +Joshua +Daniel +David +Andrew +Joseph +James +John +Robert +William +Ryan +Jason +Nicholas +Jonathan +Jacob +Brandon +Tyler +Zachary +Kevin +Justin +Benjamin +Anthony +Samuel +Thomas +Alexander +Ethan +Noah +Dylan +Nathan +Christian +Austin +Adam +Caleb +Cody +Jordan +Logan +Aaron +Kyle +Jose +Brian +Gabriel +Timothy +Luke +Jared +Connor +Sean +Evan +Isaac +Jack +Cameron +Hunter +Jackson +Charles +Devin +Stephen +Patrick +Steven +Elijah +Scott +Mark +Jeffrey +Corey +Juan +Luis +Derek +Chase +Travis +Alex +Spencer +Ian +Trevor +Bryan +Tanner +Marcus +Jeremy +Eric +Jaden +Garrett +Isaiah +Dustin +Jesse +Seth +Blake +Nathaniel +Mason +Liam +Paul +Carlos +Mitchell +Parker +Lucas +Richard +Cole +Adrian +Colin +Bradley +Jesus +Peter +Kenneth +Joel +Victor +Bryce +Casey +Vincent +Edward +Henry +Dominic +Riley +Shane +Dalton +Grant +Shawn +Braden +Caden +Max +Hayden +Owen +Brett +Trevor +Philip +Brendan +Wesley +Aidan +Brady +Colton +Tristan +George +Gavin +Dawson +Miguel +Antonio +Nolan +Dakota +Jace +Collin +Preston +Levi +Alan +Jorge +Carson diff --git a/src/AliasGenerators/Identity/Implementations/Dictionaries/en/lastnames b/src/AliasGenerators/Identity/Implementations/Dictionaries/en/lastnames new file mode 100644 index 000000000..43ef2f61a --- /dev/null +++ b/src/AliasGenerators/Identity/Implementations/Dictionaries/en/lastnames @@ -0,0 +1,167 @@ +Smith +Johnson +Williams +Brown +Jones +Garcia +Miller +Davis +Rodriguez +Martinez +Hernandez +Lopez +Gonzalez +Wilson +Anderson +Thomas +Taylor +Moore +Jackson +Martin +Lee +Perez +Thompson +White +Harris +Sanchez +Clark +Ramirez +Lewis +Robinson +Walker +Young +Allen +King +Wright +Scott +Torres +Nguyen +Hill +Flores +Green +Adams +Nelson +Baker +Hall +Rivera +Campbell +Mitchell +Carter +Roberts +Gomez +Phillips +Evans +Turner +Diaz +Parker +Cruz +Edwards +Collins +Reyes +Stewart +Morris +Morales +Murphy +Cook +Rogers +Gutierrez +Ortiz +Morgan +Cooper +Peterson +Bailey +Reed +Kelly +Howard +Ramos +Kim +Cox +Ward +Richardson +Watson +Brooks +Chavez +Wood +James +Bennett +Gray +Mendoza +Ruiz +Hughes +Price +Alvarez +Castillo +Sanders +Patel +Myers +Long +Ross +Foster +Jimenez +Powell +Jenkins +Perry +Russell +Sullivan +Bell +Coleman +Butler +Henderson +Barnes +Gonzales +Fisher +Vasquez +Simmons +Romero +Jordan +Patterson +Alexander +Hamilton +Graham +Reynolds +Griffin +Wallace +Moreno +West +Cole +Hayes +Bryant +Herrera +Gibson +Ellis +Tran +Medina +Aguilar +Stevens +Murray +Ford +Castro +Marshall +Owens +Harrison +Fernandez +McDonald +Woods +Washington +Kennedy +Wells +Vargas +Henry +Chen +Freeman +Webb +Tucker +Guzman +Burns +Crawford +Olson +Simpson +Porter +Hunter +Gordon +Mendez +Silva +Shaw +Snyder +Mason +Dixon diff --git a/src/AliasGenerators/Identity/Implementations/Dictionaries/nl/firstnames_female b/src/AliasGenerators/Identity/Implementations/Dictionaries/nl/firstnames_female new file mode 100644 index 000000000..b722363f6 --- /dev/null +++ b/src/AliasGenerators/Identity/Implementations/Dictionaries/nl/firstnames_female @@ -0,0 +1,104 @@ +Emma +Sophie +Julia +Mila +Tess +Sara +Anna +Noor +Lotte +Liv +Eva +Nora +Zoë +Evi +Yara +Saar +Nina +Fenna +Lieke +Fleur +Isa +Roos +Lynn +Sofie +Sarah +Milou +Olivia +Maud +Lisa +Vera +Luna +Lina +Noa +Feline +Loïs +Lena +Floor +Charlotte +Esmee +Julie +Iris +Lara +Amber +Hailey +Mia +Lize +Isabelle +Cato +Fenne +Sanne +Norah +Sophia +Ella +Nova +Elin +Femke +Lizzy +Linde +Lauren +Rosalie +Lana +Emily +Elise +Esmée +Anne +Isabelle +Demi +Hannah +Liva +Suze +Fay +Isabel +Benthe +Evi +Amy +Jasmijn +Niene +Sterre +Fenna +Fiene +Liz +Ise +Mara +Nienke +Indy +Romy +Lola +Puck +Nora +Merel +Bente +Eline +Lily +Leah +Naomi +Mirthe +Valerie +Noor +Liva +Jade +Juul +Lise +Myrthe +Veerle diff --git a/src/AliasGenerators/Identity/Implementations/Dictionaries/nl/firstnames_male b/src/AliasGenerators/Identity/Implementations/Dictionaries/nl/firstnames_male new file mode 100644 index 000000000..2420060f1 --- /dev/null +++ b/src/AliasGenerators/Identity/Implementations/Dictionaries/nl/firstnames_male @@ -0,0 +1,101 @@ +Daan +Luuk +Sem +Finn +Milan +Levi +Noah +Lucas +Jesse +Thijs +Jayden +Bram +Lars +Ruben +Thomas +Tim +Sam +Liam +Julian +Mees +Ties +Sven +Max +Gijs +David +Stijn +Jasper +Niels +Jens +Timo +Cas +Joep +Roan +Tom +Tygo +Teun +Siem +Mats +Thijmen +Rens +Niek +Tobias +Dex +Hugo +Robin +Nick +Floris +Pepijn +Boaz +Olivier +Luca +Jurre +Jelle +Guus +Koen +Bart +Olaf +Wessel +Daniël +Job +Sander +Tijmen +Kai +Quinten +Owen +Morris +Fedde +Joris +Jesper +Mick +Ryan +Milo +Stan +Benjamin +Melle +Jip +Dylan +Brent +Mick +Dean +Otis +Abel +Luc +Sepp +Vince +Rayan +Noud +Hidde +Fabian +Jort +Damian +Boris +Sil +Moos +Aiden +Sep +Mika +Mijs +Mika +Felix +Merlijn diff --git a/src/AliasGenerators/Identity/Implementations/Dictionaries/nl/lastnames b/src/AliasGenerators/Identity/Implementations/Dictionaries/nl/lastnames new file mode 100644 index 000000000..21d1b590c --- /dev/null +++ b/src/AliasGenerators/Identity/Implementations/Dictionaries/nl/lastnames @@ -0,0 +1,106 @@ +de Jong +Jansen +de Vries +van den Berg +van Dijk +Bakker +Janssen +Visser +Smit +Meijer +de Boer +Mulder +de Groot +Bos +Vos +Peters +Hendriks +van Leeuwen +Dekker +Brouwer +de Wit +Dijkstra +Smits +de Graaf +van der Meer +van der Linden +Kok +Jacobs +de Haan +Vermeulen +van den Heuvel +van der Veen +van den Broek +de Bruijn +de Bruin +van der Heijden +Schouten +van Beek +Willems +van Vliet +van de Ven +Hoekstra +Maas +Verhoeven +Koster +van Dam +van der Wal +Prins +Blom +Huisman +Peeters +Kuipers +van Veen +van Dongen +Veenstra +Kramer +van den Bosch +van der Meulen +Mol +Zwart +van der Laan +Martens +van de Pol +Postma +Tromp +Borst +Boon +van Doorn +Jonker +van der Velden +Willemsen +van Wijk +Groen +Gerritsen +Bosch +van Loon +van der Ploeg +de Ruiter +Molenaar +Boer +Klein +de Koning +van de Kamp +van der Horst +Verbeek +Vink +Goossens +Scholten +Hartman +van Dalen +van Elst +Brink +Boekel +van de Berg +Berends +van der Hoek +Kuiper +Kooijman +de Lange +van der Sluis +van Gelder +Martens +van Asselt +Timmermans +van Vliet +van Rijn diff --git a/src/AliasGenerators/Identity/Implementations/Factories/IdentityGeneratorFactory.cs b/src/AliasGenerators/Identity/Implementations/Factories/IdentityGeneratorFactory.cs new file mode 100644 index 000000000..86314c0e9 --- /dev/null +++ b/src/AliasGenerators/Identity/Implementations/Factories/IdentityGeneratorFactory.cs @@ -0,0 +1,32 @@ +//----------------------------------------------------------------------- +// +// Copyright (c) lanedirt. All rights reserved. +// Licensed under the MIT license. See LICENSE.md file in the project root for full license information. +// +//----------------------------------------------------------------------- + +namespace AliasGenerators.Identity.Implementations; + +using AliasGenerators.Identity.Implementations.Base; + +/// +/// Identity generator factory which creates an identity generator based on the language code. +/// +public static class IdentityGeneratorFactory +{ + /// + /// Creates an identity generator based on the language code. + /// + /// Two letter language code. + /// The IdentityGenerator for the requested language. + /// Thrown if no identity generator is found for the requested language. + public static IdentityGenerator CreateIdentityGenerator(string languageCode) + { + return languageCode.ToLower() switch + { + "nl" => new IdentityGeneratorNl(), + "en" => new IdentityGeneratorEn(), + _ => throw new ArgumentException($"Unsupported language code: {languageCode}", nameof(languageCode)), + }; + } +} diff --git a/src/AliasGenerators/Identity/Implementations/FigIdentityGenerator.cs b/src/AliasGenerators/Identity/Implementations/FigIdentityGenerator.cs deleted file mode 100644 index b5128eadb..000000000 --- a/src/AliasGenerators/Identity/Implementations/FigIdentityGenerator.cs +++ /dev/null @@ -1,39 +0,0 @@ -//----------------------------------------------------------------------- -// -// Copyright (c) lanedirt. All rights reserved. -// Licensed under the MIT license. See LICENSE.md file in the project root for full license information. -// -//----------------------------------------------------------------------- -namespace AliasGenerators.Identity.Implementations; - -using System.Text.Json; - -/// -/// Identity generator which generates random identities using the identiteitgenerator.nl semi-public API. -/// -public class FigIdentityGenerator : IIdentityGenerator -{ - private static readonly HttpClient HttpClient = new(); - private static readonly string Url = "https://api.identiteitgenerator.nl/generate/identity"; - private static readonly JsonSerializerOptions JsonSerializerOptions = new() - { - PropertyNameCaseInsensitive = true, - }; - - /// - public async Task GenerateRandomIdentityAsync() - { - var response = await HttpClient.GetAsync(Url); - response.EnsureSuccessStatusCode(); - - var json = await response.Content.ReadAsStringAsync(); - var identity = JsonSerializer.Deserialize(json, JsonSerializerOptions); - - if (identity is null) - { - throw new InvalidOperationException("Failed to deserialize the identity from FIG WebApi."); - } - - return identity; - } -} diff --git a/src/AliasGenerators/Identity/Implementations/IdentityGeneratorEn.cs b/src/AliasGenerators/Identity/Implementations/IdentityGeneratorEn.cs new file mode 100644 index 000000000..0df424c9f --- /dev/null +++ b/src/AliasGenerators/Identity/Implementations/IdentityGeneratorEn.cs @@ -0,0 +1,26 @@ +//----------------------------------------------------------------------- +// +// Copyright (c) lanedirt. All rights reserved. +// Licensed under the MIT license. See LICENSE.md file in the project root for full license information. +// +//----------------------------------------------------------------------- + +namespace AliasGenerators.Identity.Implementations; + +using AliasGenerators.Identity.Implementations.Base; + +/// +/// Dutch identity generator which implements IIdentityGenerator and generates +/// random dutch identities. +/// +public class IdentityGeneratorEn : IdentityGenerator +{ + /// + protected override string FirstNamesListMale => "AliasGenerators.Identity.Implementations.Dictionaries.en.firstnames_male"; + + /// + protected override string FirstNamesListFemale => "AliasGenerators.Identity.Implementations.Dictionaries.en.firstnames_female"; + + /// + protected override string LastNamesList => "AliasGenerators.Identity.Implementations.Dictionaries.en.lastnames"; +} diff --git a/src/AliasGenerators/Identity/Implementations/IdentityGeneratorNl.cs b/src/AliasGenerators/Identity/Implementations/IdentityGeneratorNl.cs new file mode 100644 index 000000000..ba38c2d20 --- /dev/null +++ b/src/AliasGenerators/Identity/Implementations/IdentityGeneratorNl.cs @@ -0,0 +1,26 @@ +//----------------------------------------------------------------------- +// +// Copyright (c) lanedirt. All rights reserved. +// Licensed under the MIT license. See LICENSE.md file in the project root for full license information. +// +//----------------------------------------------------------------------- + +namespace AliasGenerators.Identity.Implementations; + +using AliasGenerators.Identity.Implementations.Base; + +/// +/// Dutch identity generator which implements IIdentityGenerator and generates +/// random dutch identities. +/// +public class IdentityGeneratorNl : IdentityGenerator +{ + /// + protected override string FirstNamesListMale => "AliasGenerators.Identity.Implementations.Dictionaries.nl.firstnames_male"; + + /// + protected override string FirstNamesListFemale => "AliasGenerators.Identity.Implementations.Dictionaries.nl.firstnames_female"; + + /// + protected override string LastNamesList => "AliasGenerators.Identity.Implementations.Dictionaries.nl.lastnames"; +} diff --git a/src/AliasGenerators/Identity/Implementations/StaticIdentityGenerator.cs b/src/AliasGenerators/Identity/Implementations/StaticIdentityGenerator.cs deleted file mode 100644 index 5b56f52d0..000000000 --- a/src/AliasGenerators/Identity/Implementations/StaticIdentityGenerator.cs +++ /dev/null @@ -1,27 +0,0 @@ -//----------------------------------------------------------------------- -// -// Copyright (c) lanedirt. All rights reserved. -// Licensed under the MIT license. See LICENSE.md file in the project root for full license information. -// -//----------------------------------------------------------------------- -namespace AliasGenerators.Identity.Implementations; - -using AliasGenerators.Identity; - -/// -/// Static identity generator which implements IIdentityGenerator but always returns -/// the same static identity for testing purposes. -/// -public class StaticIdentityGenerator : IIdentityGenerator -{ - /// - public async Task GenerateRandomIdentityAsync() - { - await Task.Yield(); // Add an await statement to make the method truly asynchronous. - return new Identity.Models.Identity - { - FirstName = "John", - LastName = "Doe", - }; - } -} diff --git a/src/AliasGenerators/Identity/Models/Address.cs b/src/AliasGenerators/Identity/Models/Address.cs deleted file mode 100644 index 2cac78a54..000000000 --- a/src/AliasGenerators/Identity/Models/Address.cs +++ /dev/null @@ -1,38 +0,0 @@ -//----------------------------------------------------------------------- -// -// Copyright (c) lanedirt. All rights reserved. -// Licensed under the MIT license. See LICENSE.md file in the project root for full license information. -// -//----------------------------------------------------------------------- -namespace AliasGenerators.Identity.Models; - -/// -/// Address model. -/// -public class Address -{ - /// - /// Gets or sets the street. - /// - public string Street { get; set; } = null!; - - /// - /// Gets or sets the city. - /// - public string City { get; set; } = null!; - - /// - /// Gets or sets the state. - /// - public string State { get; set; } = null!; - - /// - /// Gets or sets the zip code. - /// - public string ZipCode { get; set; } = null!; - - /// - /// Gets or sets the country. - /// - public string Country { get; set; } = null!; -} diff --git a/src/AliasGenerators/Identity/Models/Gender.cs b/src/AliasGenerators/Identity/Models/Gender.cs new file mode 100644 index 000000000..b8f0b0eb1 --- /dev/null +++ b/src/AliasGenerators/Identity/Models/Gender.cs @@ -0,0 +1,24 @@ +//----------------------------------------------------------------------- +// +// Copyright (c) lanedirt. All rights reserved. +// Licensed under the MIT license. See LICENSE.md file in the project root for full license information. +// +//----------------------------------------------------------------------- + +namespace AliasGenerators.Identity.Models; + +/// +/// Identity model. +/// +public enum Gender +{ + /// + /// Male gender. + /// + Male, + + /// + /// Female gender. + /// + Female, +} diff --git a/src/AliasGenerators/Identity/Models/Identity.cs b/src/AliasGenerators/Identity/Models/Identity.cs index 15b79fac9..18a14eb82 100644 --- a/src/AliasGenerators/Identity/Models/Identity.cs +++ b/src/AliasGenerators/Identity/Models/Identity.cs @@ -4,6 +4,7 @@ // Licensed under the MIT license. See LICENSE.md file in the project root for full license information. // //----------------------------------------------------------------------- + namespace AliasGenerators.Identity.Models; /// @@ -19,7 +20,7 @@ public class Identity /// /// Gets or sets the gender. /// - public int Gender { get; set; } + public Gender Gender { get; set; } /// /// Gets or sets the first name. @@ -41,48 +42,8 @@ public class Identity /// public DateTime BirthDate { get; set; } - /// - /// Gets or sets the address. - /// - public Address Address { get; set; } = null!; - - /// - /// Gets or sets the job. - /// - public Job Job { get; set; } = null!; - - /// - /// Gets or sets the hobbies. - /// - public List Hobbies { get; set; } = null!; - /// /// Gets or sets the email address prefix. /// public string EmailPrefix { get; set; } = null!; - - /// - /// Gets or sets the password. - /// - public string Password { get; set; } = null!; - - /// - /// Gets or sets the phone mobile. - /// - public string PhoneMobile { get; set; } = null!; - - /// - /// Gets or sets the bank account IBAN. - /// - public string BankAccountIBAN { get; set; } = null!; - - /// - /// Gets or sets the profile photo in base64 format. - /// - public string ProfilePhotoBase64 { get; set; } = null!; - - /// - /// Gets or sets the profile photo prompt. - /// - public string ProfilePhotoPrompt { get; set; } = null!; } diff --git a/src/AliasGenerators/Identity/Models/Job.cs b/src/AliasGenerators/Identity/Models/Job.cs deleted file mode 100644 index 842aaa8cc..000000000 --- a/src/AliasGenerators/Identity/Models/Job.cs +++ /dev/null @@ -1,38 +0,0 @@ -//----------------------------------------------------------------------- -// -// Copyright (c) lanedirt. All rights reserved. -// Licensed under the MIT license. See LICENSE.md file in the project root for full license information. -// -//----------------------------------------------------------------------- -namespace AliasGenerators.Identity.Models; - -/// -/// Job model. -/// -public class Job -{ - /// - /// Gets or sets the title. - /// - public string Title { get; set; } = null!; - - /// - /// Gets or sets the company. - /// - public string Company { get; set; } = null!; - - /// - /// Gets or sets the salary. - /// - public string Salary { get; set; } = null!; - - /// - /// Gets or sets the calculated salary. - /// - public decimal SalaryCalculated { get; set; } - - /// - /// Gets or sets the description. - /// - public string Description { get; set; } = null!; -} diff --git a/src/AliasGenerators/Identity/UsernameEmailGenerator.cs b/src/AliasGenerators/Identity/UsernameEmailGenerator.cs new file mode 100644 index 000000000..bc5c3391b --- /dev/null +++ b/src/AliasGenerators/Identity/UsernameEmailGenerator.cs @@ -0,0 +1,143 @@ +//----------------------------------------------------------------------- +// +// Copyright (c) lanedirt. All rights reserved. +// Licensed under the MIT license. See LICENSE.md file in the project root for full license information. +// +//----------------------------------------------------------------------- + +namespace AliasGenerators.Identity; + +using System.Text.RegularExpressions; + +/// +/// Generates usernames and email prefixes based on an identity. +/// +public class UsernameEmailGenerator +{ + /// + /// Minimum length of the generated username. + /// + private const int MinLength = 6; + + /// + /// Maximum length of the generated username. + /// + private const int MaxLength = 20; + + /// + /// Create a new random instance for generating random values. + /// + private readonly Random _random = new(); + + /// + /// List of allowed symbols to use in usernames. + /// + private readonly List _symbols = [".", "-"]; + + /// + /// Generates a username based on a identity. + /// + /// Identity to generate username for. + /// Username as string. + public string GenerateUsername(Models.Identity identity) + { + // Generate username based on email prefix but strip all non-alphanumeric characters + string username = GenerateEmailPrefix(identity); + username = Regex.Replace(username, @"[^a-zA-Z0-9]", string.Empty, RegexOptions.NonBacktracking); + + // Adjust length + if (username.Length < MinLength) + { + username += GenerateRandomString(MinLength - username.Length); + } + else if (username.Length > MaxLength) + { + username = username.Substring(0, MaxLength); + } + + return username; + } + + /// + /// Generates a valid email prefix based on an identity. + /// + /// Identity to generate email prefix for. + /// Valid email prefix as string. + public string GenerateEmailPrefix(Models.Identity identity) + { + var parts = new List(); + + // Use first initial + last name + if (_random.Next(2) == 0) + { + parts.Add(identity.FirstName.Substring(0, 1).ToLower() + identity.LastName.ToLower()); + } + else + { + // Use full name + parts.Add((identity.FirstName + identity.LastName).ToLower()); + } + + // Add birth year + if (_random.Next(2) == 0) + { + parts.Add(identity.BirthDate.Year.ToString().Substring(2)); + } + + // Join parts and sanitize + var emailPrefix = string.Join(GetRandomSymbol(), parts); + emailPrefix = SanitizeEmailPrefix(emailPrefix); + + // Adjust length + if (emailPrefix.Length < MinLength) + { + emailPrefix += GenerateRandomString(MinLength - emailPrefix.Length); + } + else if (emailPrefix.Length > MaxLength) + { + emailPrefix = emailPrefix.Substring(0, MaxLength); + } + + return emailPrefix; + } + + /// + /// Sanitize the email prefix by removing invalid characters and ensuring it's a valid email prefix. + /// + /// The input string to sanitize. + /// The sanitized string. + private static string SanitizeEmailPrefix(string input) + { + // Remove any character that's not a letter, number, dot, underscore, or hyphen including special characters + string sanitized = Regex.Replace(input, @"[^a-zA-Z0-9._-]", string.Empty, RegexOptions.NonBacktracking); + + // Remove consecutive dots, underscores, or hyphens + sanitized = Regex.Replace(sanitized, @"[-_.]{2,}", m => m.Value[0].ToString(), RegexOptions.NonBacktracking); + + // Ensure it doesn't start or end with a dot, underscore, or hyphen + sanitized = sanitized.Trim('.', '_', '-'); + + return sanitized; + } + + /// + /// Get a random symbol from the list of symbols. + /// + /// Random symbol. + private string GetRandomSymbol() + { + return _random.Next(3) == 0 ? _symbols[_random.Next(_symbols.Count)] : string.Empty; + } + + /// + /// Generate a random string of a given length. + /// + /// Length of string to generate. + /// String with random characters. + private string GenerateRandomString(int length) + { + const string chars = "abcdefghijklmnopqrstuvwxyz0123456789"; + return new string(Enumerable.Repeat(chars, length) + .Select(s => s[_random.Next(s.Length)]).ToArray()); + } +} diff --git a/src/AliasVault.Api/Controllers/IdentityController.cs b/src/AliasVault.Api/Controllers/IdentityController.cs index e30e1a5f1..d99aece27 100644 --- a/src/AliasVault.Api/Controllers/IdentityController.cs +++ b/src/AliasVault.Api/Controllers/IdentityController.cs @@ -21,7 +21,7 @@ using Microsoft.AspNetCore.Mvc; public class IdentityController(UserManager userManager) : AuthenticatedRequestController(userManager) { /// - /// Proxies the request to the identity generator to generate a random identity. + /// Proxies the request to the english identity generator to generate a random identity. /// /// Identity model. [HttpGet("Generate")] @@ -33,7 +33,7 @@ public class IdentityController(UserManager userManager) : Authe return Unauthorized(); } - var identityGenerator = new FigIdentityGenerator(); + var identityGenerator = new IdentityGeneratorEn(); return Ok(await identityGenerator.GenerateRandomIdentityAsync()); } } diff --git a/src/AliasVault.Client/Main/Pages/Credentials/AddEdit.razor b/src/AliasVault.Client/Main/Pages/Credentials/AddEdit.razor index ed956ade4..fbaab63de 100644 --- a/src/AliasVault.Client/Main/Pages/Credentials/AddEdit.razor +++ b/src/AliasVault.Client/Main/Pages/Credentials/AddEdit.razor @@ -3,6 +3,8 @@ @inherits MainBase @inject CredentialService CredentialService @using System.Globalization +@using AliasGenerators.Identity.Implementations +@using AliasGenerators.Identity.Models @using AliasGenerators.Password @using AliasGenerators.Password.Implementations @@ -126,30 +128,6 @@ else - - - - - - - - - - - - - - - - - - - - - - - - @@ -266,27 +244,19 @@ else StateHasChanged(); // Generate a random identity using the IIdentityGenerator implementation. - var identity = await CredentialService.GenerateRandomIdentityAsync(); + var identity = await IdentityGeneratorFactory.CreateIdentityGenerator(DbService.Settings.DefaultIdentityLanguage).GenerateRandomIdentityAsync(); // Generate random values for the Identity properties Obj.Username = identity.NickName; Obj.Alias.FirstName = identity.FirstName; Obj.Alias.LastName = identity.LastName; Obj.Alias.NickName = identity.NickName; - Obj.Alias.Gender = identity.Gender == 1 ? "Male" : "Female"; + Obj.Alias.Gender = identity.Gender == Gender.Male ? "Male" : "Female"; Obj.AliasBirthDate = identity.BirthDate.ToString("yyyy-MM-dd"); - Obj.Alias.AddressStreet = identity.Address.Street; - Obj.Alias.AddressCity = identity.Address.City; - Obj.Alias.AddressState = identity.Address.State; - Obj.Alias.AddressZipCode = identity.Address.ZipCode; - Obj.Alias.AddressCountry = identity.Address.Country; - Obj.Alias.Hobbies = identity.Hobbies[0]; // Set the email var emailDomain = GetDefaultEmailDomain(); Obj.Alias.Email = $"{identity.EmailPrefix}@{emailDomain}"; - Obj.Alias.PhoneMobile = identity.PhoneMobile; - Obj.Alias.BankAccountIBAN = identity.BankAccountIBAN; // Generate password GenerateRandomPassword(); diff --git a/src/AliasVault.Client/Main/Pages/Credentials/View.razor b/src/AliasVault.Client/Main/Pages/Credentials/View.razor index 341c282f6..22d5c676c 100644 --- a/src/AliasVault.Client/Main/Pages/Credentials/View.razor +++ b/src/AliasVault.Client/Main/Pages/Credentials/View.razor @@ -95,40 +95,6 @@ else - - - Contact - - - - - - - - - - - - - - Address - - - - - - - - - - - - - - - - - } diff --git a/src/AliasVault.Client/Main/Pages/Settings/General.razor b/src/AliasVault.Client/Main/Pages/Settings/General.razor index cd9419348..a1be0d2f7 100644 --- a/src/AliasVault.Client/Main/Pages/Settings/General.razor +++ b/src/AliasVault.Client/Main/Pages/Settings/General.razor @@ -44,6 +44,21 @@ + + Identity Settings + + + Identity generation language + + English + Dutch + + + Set the default language that will be used when generating new identities. + + + + @code { private List PrivateDomains => Config.PrivateEmailDomains; private List PublicDomains => Config.PublicEmailDomains; @@ -51,6 +66,7 @@ private string DefaultEmailDomain { get; set; } = string.Empty; private bool AutoEmailRefresh { get; set; } + private string DefaultIdentityLanguage { get; set; } = string.Empty; /// protected override async Task OnInitializedAsync() @@ -60,6 +76,7 @@ DefaultEmailDomain = DbService.Settings.DefaultEmailDomain; AutoEmailRefresh = DbService.Settings.AutoEmailRefresh; + DefaultIdentityLanguage = DbService.Settings.DefaultIdentityLanguage; } /// @@ -79,4 +96,13 @@ await DbService.Settings.SetAutoEmailRefresh(AutoEmailRefresh); StateHasChanged(); } + + /// + /// Updates the auto email refresh setting. + /// + private async Task UpdateDefaultIdentityLanguage() + { + await DbService.Settings.SetDefaultIdentityLanguage(DefaultIdentityLanguage); + StateHasChanged(); + } } diff --git a/src/AliasVault.Client/Services/CredentialService.cs b/src/AliasVault.Client/Services/CredentialService.cs index 48f57d393..048891cf3 100644 --- a/src/AliasVault.Client/Services/CredentialService.cs +++ b/src/AliasVault.Client/Services/CredentialService.cs @@ -64,15 +64,7 @@ public class CredentialService(HttpClient httpClient, DbService dbService) LastName = loginObject.Alias.LastName, BirthDate = loginObject.Alias.BirthDate, Gender = loginObject.Alias.Gender, - AddressStreet = loginObject.Alias.AddressStreet, - AddressCity = loginObject.Alias.AddressCity, - AddressState = loginObject.Alias.AddressState, - AddressZipCode = loginObject.Alias.AddressZipCode, - AddressCountry = loginObject.Alias.AddressCountry, - Hobbies = loginObject.Alias.Hobbies, Email = loginObject.Alias.Email, - PhoneMobile = loginObject.Alias.PhoneMobile, - BankAccountIBAN = loginObject.Alias.BankAccountIBAN, CreatedAt = DateTime.UtcNow, UpdatedAt = DateTime.UtcNow, }, @@ -137,15 +129,7 @@ public class CredentialService(HttpClient httpClient, DbService dbService) login.Alias.LastName = loginObject.Alias.LastName; login.Alias.BirthDate = loginObject.Alias.BirthDate; login.Alias.Gender = loginObject.Alias.Gender; - login.Alias.AddressStreet = loginObject.Alias.AddressStreet; - login.Alias.AddressCity = loginObject.Alias.AddressCity; - login.Alias.AddressState = loginObject.Alias.AddressState; - login.Alias.AddressZipCode = loginObject.Alias.AddressZipCode; - login.Alias.AddressCountry = loginObject.Alias.AddressCountry; - login.Alias.Hobbies = loginObject.Alias.Hobbies; login.Alias.Email = loginObject.Alias.Email; - login.Alias.PhoneMobile = loginObject.Alias.PhoneMobile; - login.Alias.BankAccountIBAN = loginObject.Alias.BankAccountIBAN; login.Passwords = loginObject.Passwords; diff --git a/src/AliasVault.Client/Services/SettingsService.cs b/src/AliasVault.Client/Services/SettingsService.cs index d7f97ad15..242cf70c5 100644 --- a/src/AliasVault.Client/Services/SettingsService.cs +++ b/src/AliasVault.Client/Services/SettingsService.cs @@ -27,7 +27,7 @@ public class SettingsService private bool _initialized; /// - /// Gets the DefaultEmailDomain setting asynchronously. + /// Gets the DefaultEmailDomain setting. /// /// Default email domain as string. public string DefaultEmailDomain => GetSetting("DefaultEmailDomain"); @@ -39,19 +39,32 @@ public class SettingsService public bool AutoEmailRefresh => GetSetting("AutoEmailRefresh", true); /// - /// Sets the DefaultEmailDomain setting asynchronously. + /// Gets the DefaultIdentityLanguage setting. /// - /// The new DeafultEmailDomain setting. + /// Default identity language as two-letter code. + public string DefaultIdentityLanguage => GetSetting("DefaultIdentityLanguage", "en")!; + + /// + /// Sets the DefaultEmailDomain setting. + /// + /// The new DefaultEmailDomain setting. /// Task. public Task SetDefaultEmailDomain(string value) => SetSettingAsync("DefaultEmailDomain", value); /// - /// Sets the AutoEmailRefresh setting asynchronously as a string. + /// Sets the AutoEmailRefresh setting as a string. /// /// The new value. /// Task. public Task SetAutoEmailRefresh(bool value) => SetSettingAsync("AutoEmailRefresh", value); + /// + /// Sets the DefaultIdentityLanguage setting. + /// + /// The new value. + /// Task. + public Task SetDefaultIdentityLanguage(string value) => SetSettingAsync("DefaultIdentityLanguage", value); + /// /// Initializes the settings service asynchronously. /// diff --git a/src/Databases/AliasClientDb/Alias.cs b/src/Databases/AliasClientDb/Alias.cs index d23cd1c88..bbd6d2798 100644 --- a/src/Databases/AliasClientDb/Alias.cs +++ b/src/Databases/AliasClientDb/Alias.cs @@ -53,65 +53,12 @@ public class Alias /// public DateTime BirthDate { get; set; } - /// - /// Gets or sets the address street. - /// - [StringLength(255)] - [Column(TypeName = "VARCHAR")] - public string? AddressStreet { get; set; } - - /// - /// Gets or sets the address city. - /// - [StringLength(255)] - [Column(TypeName = "VARCHAR")] - public string? AddressCity { get; set; } - - /// - /// Gets or sets the address state. - /// - [StringLength(255)] - [Column(TypeName = "VARCHAR")] - public string? AddressState { get; set; } - - /// - /// Gets or sets the address zip code. - /// - [StringLength(255)] - [Column(TypeName = "VARCHAR")] - public string? AddressZipCode { get; set; } - - /// - /// Gets or sets the address country. - /// - [StringLength(255)] - [Column(TypeName = "VARCHAR")] - public string? AddressCountry { get; set; } - - /// - /// Gets or sets the hobbies in CSV format, can contain multiple values separated by ";". - /// - [StringLength(255)] - public string? Hobbies { get; set; } - /// /// Gets or sets the generated email. /// [StringLength(255)] public string? Email { get; set; } - /// - /// Gets or sets the random generated mobile phone number. - /// - [StringLength(255)] - public string? PhoneMobile { get; set; } - - /// - /// Gets or sets the generated IBAN bank account number. - /// - [StringLength(255)] - public string? BankAccountIBAN { get; set; } - /// /// Gets or sets the created timestamp. /// diff --git a/src/Databases/AliasClientDb/Migrations/20240805122422_1.3.0-UpdateIdentityStructure.Designer.cs b/src/Databases/AliasClientDb/Migrations/20240805122422_1.3.0-UpdateIdentityStructure.Designer.cs new file mode 100644 index 000000000..41924fcbf --- /dev/null +++ b/src/Databases/AliasClientDb/Migrations/20240805122422_1.3.0-UpdateIdentityStructure.Designer.cs @@ -0,0 +1,296 @@ +// +using System; +using AliasClientDb; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; + +#nullable disable + +namespace AliasClientDb.Migrations +{ + [DbContext(typeof(AliasClientDbContext))] + [Migration("20240805122422_1.3.0-UpdateIdentityStructure")] + partial class _130UpdateIdentityStructure + { + /// + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "8.0.7") + .HasAnnotation("Proxies:ChangeTracking", false) + .HasAnnotation("Proxies:CheckEquality", false) + .HasAnnotation("Proxies:LazyLoading", true); + + modelBuilder.Entity("AliasClientDb.Alias", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("TEXT"); + + b.Property("BirthDate") + .HasColumnType("TEXT"); + + b.Property("CreatedAt") + .HasColumnType("TEXT"); + + b.Property("Email") + .HasMaxLength(255) + .HasColumnType("TEXT"); + + b.Property("FirstName") + .HasMaxLength(255) + .HasColumnType("VARCHAR"); + + b.Property("Gender") + .HasMaxLength(255) + .HasColumnType("VARCHAR"); + + b.Property("LastName") + .HasMaxLength(255) + .HasColumnType("VARCHAR"); + + b.Property("NickName") + .HasMaxLength(255) + .HasColumnType("VARCHAR"); + + b.Property("UpdatedAt") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.ToTable("Aliases"); + }); + + modelBuilder.Entity("AliasClientDb.Attachment", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("TEXT"); + + b.Property("Blob") + .IsRequired() + .HasColumnType("BLOB"); + + b.Property("CreatedAt") + .HasColumnType("TEXT"); + + b.Property("CredentialId") + .HasColumnType("TEXT"); + + b.Property("Filename") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("TEXT"); + + b.Property("UpdatedAt") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("CredentialId"); + + b.ToTable("Attachment"); + }); + + modelBuilder.Entity("AliasClientDb.Credential", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("TEXT"); + + b.Property("AliasId") + .HasColumnType("TEXT"); + + b.Property("CreatedAt") + .HasColumnType("TEXT"); + + b.Property("Notes") + .HasColumnType("TEXT"); + + b.Property("ServiceId") + .HasColumnType("TEXT"); + + b.Property("UpdatedAt") + .HasColumnType("TEXT"); + + b.Property("Username") + .IsRequired() + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("AliasId"); + + b.HasIndex("ServiceId"); + + b.ToTable("Credentials"); + }); + + modelBuilder.Entity("AliasClientDb.EncryptionKey", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("TEXT"); + + b.Property("CreatedAt") + .HasColumnType("TEXT"); + + b.Property("IsPrimary") + .HasColumnType("INTEGER"); + + b.Property("PrivateKey") + .IsRequired() + .HasMaxLength(2000) + .HasColumnType("TEXT"); + + b.Property("PublicKey") + .IsRequired() + .HasMaxLength(2000) + .HasColumnType("TEXT"); + + b.Property("UpdatedAt") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.ToTable("EncryptionKeys"); + }); + + modelBuilder.Entity("AliasClientDb.Password", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("TEXT"); + + b.Property("CreatedAt") + .HasColumnType("TEXT"); + + b.Property("CredentialId") + .HasColumnType("TEXT"); + + b.Property("UpdatedAt") + .HasColumnType("TEXT"); + + b.Property("Value") + .HasMaxLength(255) + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("CredentialId"); + + b.ToTable("Passwords"); + }); + + modelBuilder.Entity("AliasClientDb.Service", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("TEXT"); + + b.Property("CreatedAt") + .HasColumnType("TEXT"); + + b.Property("Logo") + .HasColumnType("BLOB"); + + b.Property("Name") + .HasMaxLength(255) + .HasColumnType("TEXT"); + + b.Property("UpdatedAt") + .HasColumnType("TEXT"); + + b.Property("Url") + .HasMaxLength(255) + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.ToTable("Services"); + }); + + modelBuilder.Entity("AliasClientDb.Setting", b => + { + b.Property("Key") + .HasMaxLength(255) + .HasColumnType("TEXT"); + + b.Property("CreatedAt") + .HasColumnType("TEXT"); + + b.Property("UpdatedAt") + .HasColumnType("TEXT"); + + b.Property("Value") + .HasColumnType("TEXT"); + + b.HasKey("Key"); + + b.ToTable("Settings"); + }); + + modelBuilder.Entity("AliasClientDb.Attachment", b => + { + b.HasOne("AliasClientDb.Credential", "Credential") + .WithMany("Attachments") + .HasForeignKey("CredentialId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Credential"); + }); + + modelBuilder.Entity("AliasClientDb.Credential", b => + { + b.HasOne("AliasClientDb.Alias", "Alias") + .WithMany("Credentials") + .HasForeignKey("AliasId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("AliasClientDb.Service", "Service") + .WithMany("Credentials") + .HasForeignKey("ServiceId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Alias"); + + b.Navigation("Service"); + }); + + modelBuilder.Entity("AliasClientDb.Password", b => + { + b.HasOne("AliasClientDb.Credential", "Credential") + .WithMany("Passwords") + .HasForeignKey("CredentialId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Credential"); + }); + + modelBuilder.Entity("AliasClientDb.Alias", b => + { + b.Navigation("Credentials"); + }); + + modelBuilder.Entity("AliasClientDb.Credential", b => + { + b.Navigation("Attachments"); + + b.Navigation("Passwords"); + }); + + modelBuilder.Entity("AliasClientDb.Service", b => + { + b.Navigation("Credentials"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/src/Databases/AliasClientDb/Migrations/20240805122422_1.3.0-UpdateIdentityStructure.cs b/src/Databases/AliasClientDb/Migrations/20240805122422_1.3.0-UpdateIdentityStructure.cs new file mode 100644 index 000000000..3ab32bc85 --- /dev/null +++ b/src/Databases/AliasClientDb/Migrations/20240805122422_1.3.0-UpdateIdentityStructure.cs @@ -0,0 +1,107 @@ +// +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace AliasClientDb.Migrations +{ + /// + public partial class _130UpdateIdentityStructure : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropColumn( + name: "AddressCity", + table: "Aliases"); + + migrationBuilder.DropColumn( + name: "AddressCountry", + table: "Aliases"); + + migrationBuilder.DropColumn( + name: "AddressState", + table: "Aliases"); + + migrationBuilder.DropColumn( + name: "AddressStreet", + table: "Aliases"); + + migrationBuilder.DropColumn( + name: "AddressZipCode", + table: "Aliases"); + + migrationBuilder.DropColumn( + name: "BankAccountIBAN", + table: "Aliases"); + + migrationBuilder.DropColumn( + name: "Hobbies", + table: "Aliases"); + + migrationBuilder.DropColumn( + name: "PhoneMobile", + table: "Aliases"); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.AddColumn( + name: "AddressCity", + table: "Aliases", + type: "VARCHAR", + maxLength: 255, + nullable: true); + + migrationBuilder.AddColumn( + name: "AddressCountry", + table: "Aliases", + type: "VARCHAR", + maxLength: 255, + nullable: true); + + migrationBuilder.AddColumn( + name: "AddressState", + table: "Aliases", + type: "VARCHAR", + maxLength: 255, + nullable: true); + + migrationBuilder.AddColumn( + name: "AddressStreet", + table: "Aliases", + type: "VARCHAR", + maxLength: 255, + nullable: true); + + migrationBuilder.AddColumn( + name: "AddressZipCode", + table: "Aliases", + type: "VARCHAR", + maxLength: 255, + nullable: true); + + migrationBuilder.AddColumn( + name: "BankAccountIBAN", + table: "Aliases", + type: "TEXT", + maxLength: 255, + nullable: true); + + migrationBuilder.AddColumn( + name: "Hobbies", + table: "Aliases", + type: "TEXT", + maxLength: 255, + nullable: true); + + migrationBuilder.AddColumn( + name: "PhoneMobile", + table: "Aliases", + type: "TEXT", + maxLength: 255, + nullable: true); + } + } +} diff --git a/src/Databases/AliasClientDb/Migrations/AliasClientDbContextModelSnapshot.cs b/src/Databases/AliasClientDb/Migrations/AliasClientDbContextModelSnapshot.cs index 64a5bd707..29dbdec70 100644 --- a/src/Databases/AliasClientDb/Migrations/AliasClientDbContextModelSnapshot.cs +++ b/src/Databases/AliasClientDb/Migrations/AliasClientDbContextModelSnapshot.cs @@ -27,30 +27,6 @@ namespace AliasClientDb.Migrations .ValueGeneratedOnAdd() .HasColumnType("TEXT"); - b.Property("AddressCity") - .HasMaxLength(255) - .HasColumnType("VARCHAR"); - - b.Property("AddressCountry") - .HasMaxLength(255) - .HasColumnType("VARCHAR"); - - b.Property("AddressState") - .HasMaxLength(255) - .HasColumnType("VARCHAR"); - - b.Property("AddressStreet") - .HasMaxLength(255) - .HasColumnType("VARCHAR"); - - b.Property("AddressZipCode") - .HasMaxLength(255) - .HasColumnType("VARCHAR"); - - b.Property("BankAccountIBAN") - .HasMaxLength(255) - .HasColumnType("TEXT"); - b.Property("BirthDate") .HasColumnType("TEXT"); @@ -69,10 +45,6 @@ namespace AliasClientDb.Migrations .HasMaxLength(255) .HasColumnType("VARCHAR"); - b.Property("Hobbies") - .HasMaxLength(255) - .HasColumnType("TEXT"); - b.Property("LastName") .HasMaxLength(255) .HasColumnType("VARCHAR"); @@ -81,10 +53,6 @@ namespace AliasClientDb.Migrations .HasMaxLength(255) .HasColumnType("VARCHAR"); - b.Property("PhoneMobile") - .HasMaxLength(255) - .HasColumnType("TEXT"); - b.Property("UpdatedAt") .HasColumnType("TEXT"); diff --git a/src/Tests/AliasVault.UnitTests/Generators/IdentityGeneratorTest.cs b/src/Tests/AliasVault.UnitTests/Generators/IdentityGeneratorTest.cs new file mode 100644 index 000000000..158b2aa40 --- /dev/null +++ b/src/Tests/AliasVault.UnitTests/Generators/IdentityGeneratorTest.cs @@ -0,0 +1,96 @@ +//----------------------------------------------------------------------- +// +// Copyright (c) lanedirt. All rights reserved. +// Licensed under the MIT license. See LICENSE.md file in the project root for full license information. +// +//----------------------------------------------------------------------- + +namespace AliasVault.Tests.Generators; + +using System.Net.Mail; +using AliasGenerators.Identity.Implementations; +using AliasGenerators.Identity.Models; + +/// +/// Tests for the CsvImportExport class. +/// +public class IdentityGeneratorTest +{ + /// + /// Tests the generation of random dutch identities. + /// + /// Task. + [Test] + public async Task TestNlGenerator() + { + // Generate random NL identity. + var generator = IdentityGeneratorFactory.CreateIdentityGenerator("nl"); + + // Generate 10 identities, check if they are all unique. + var identities = new List(); + for (var i = 0; i < 10; i++) + { + var identity = await generator.GenerateRandomIdentityAsync(); + Console.WriteLine($"Generated identity: {identity.FirstName} {identity.LastName} ({identity.Gender}) - {identity.BirthDate.ToShortDateString()} - {identity.NickName} - {identity.EmailPrefix}@domain.tld"); + + identities.Add(identity); + } + + Assert.That(identities, Has.Count.EqualTo(10), "Should generate 10 identities"); + Assert.That( + identities, + Is.All.Matches( + i => + !string.IsNullOrWhiteSpace(i.FirstName) && !string.IsNullOrWhiteSpace(i.LastName)), + "All identities should have non-empty first and last names"); + Assert.That(identities, Is.Unique, "All identities should be unique"); + + foreach (var identity in identities) + { + var email = identity.EmailPrefix + "@domain.tld"; + Assert.DoesNotThrow( + () => + new MailAddress(email), + $"Email address '{email}' is not a valid email. Check email prefix generation logic."); + } + } + + /// + /// Tests the generation of random english identities. + /// + /// Task. + [Test] + public async Task TestEnGenerator() + { + // Generate random EN identity. + var generator = IdentityGeneratorFactory.CreateIdentityGenerator("en"); + + // Generate 10 identities, check if they are all unique. + var identities = new List(); + for (var i = 0; i < 10; i++) + { + var identity = await generator.GenerateRandomIdentityAsync(); + Console.WriteLine($"Generated identity: {identity.FirstName} {identity.LastName} ({identity.Gender}) - {identity.BirthDate.ToShortDateString()} - {identity.NickName} - {identity.EmailPrefix}@domain.tld"); + + identities.Add(identity); + } + + Assert.That(identities, Has.Count.EqualTo(10), "Should generate 10 identities"); + Assert.That( + identities, + Is.All.Matches( + i => + !string.IsNullOrWhiteSpace(i.FirstName) && !string.IsNullOrWhiteSpace(i.LastName)), + "All identities should have non-empty first and last names"); + Assert.That(identities, Is.Unique, "All identities should be unique"); + + foreach (var identity in identities) + { + var email = identity.EmailPrefix + "@domain.tld"; + Assert.DoesNotThrow( + () => + new MailAddress(email), + $"Email address '{email}' is not a valid email. Check email prefix generation logic."); + } + } +} diff --git a/src/Tests/AliasVault.UnitTests/Utilities/CsvImportExportTests.cs b/src/Tests/AliasVault.UnitTests/Utilities/CsvImportExportTests.cs index 438ff8699..5d807865f 100644 --- a/src/Tests/AliasVault.UnitTests/Utilities/CsvImportExportTests.cs +++ b/src/Tests/AliasVault.UnitTests/Utilities/CsvImportExportTests.cs @@ -38,15 +38,7 @@ public class CsvImportExportTests LastName = "Doe", NickName = "JD", BirthDate = new DateTime(1990, 1, 1, 0, 0, 0, DateTimeKind.Utc), - AddressStreet = "123 Main St", - AddressCity = "New York", - AddressState = "NY", - AddressZipCode = "12345", - AddressCountry = "USA", - Hobbies = "Reading, Writing", Email = "johndoe", - PhoneMobile = "123-456-7890", - BankAccountIBAN = "US1234567890", CreatedAt = DateTime.Now, UpdatedAt = DateTime.Now, }, @@ -93,15 +85,7 @@ public class CsvImportExportTests Assert.That(importedCredential.Alias.LastName, Is.EqualTo(credential.Alias.LastName)); Assert.That(importedCredential.Alias.NickName, Is.EqualTo(credential.Alias.NickName)); Assert.That(importedCredential.Alias.BirthDate, Is.EqualTo(credential.Alias.BirthDate)); - Assert.That(importedCredential.Alias.AddressStreet, Is.EqualTo(credential.Alias.AddressStreet)); - Assert.That(importedCredential.Alias.AddressCity, Is.EqualTo(credential.Alias.AddressCity)); - Assert.That(importedCredential.Alias.AddressState, Is.EqualTo(credential.Alias.AddressState)); - Assert.That(importedCredential.Alias.AddressZipCode, Is.EqualTo(credential.Alias.AddressZipCode)); - Assert.That(importedCredential.Alias.AddressCountry, Is.EqualTo(credential.Alias.AddressCountry)); - Assert.That(importedCredential.Alias.Hobbies, Is.EqualTo(credential.Alias.Hobbies)); Assert.That(importedCredential.Alias.Email, Is.EqualTo(credential.Alias.Email)); - Assert.That(importedCredential.Alias.PhoneMobile, Is.EqualTo(credential.Alias.PhoneMobile)); - Assert.That(importedCredential.Alias.BankAccountIBAN, Is.EqualTo(credential.Alias.BankAccountIBAN)); Assert.That(importedCredential.Alias.CreatedAt.ToString("yyyy-MM-dd"), Is.EqualTo(credential.Alias.CreatedAt.ToString("yyyy-MM-dd"))); Assert.That(importedCredential.Alias.UpdatedAt.ToString("yyyy-MM-dd"), Is.EqualTo(credential.Alias.UpdatedAt.ToString("yyyy-MM-dd"))); Assert.That(importedCredential.ServiceId, Is.EqualTo(credential.ServiceId)); diff --git a/src/Utilities/CsvImportExport/CredentialCsvService.cs b/src/Utilities/CsvImportExport/CredentialCsvService.cs index ca28ca919..7a25561ed 100644 --- a/src/Utilities/CsvImportExport/CredentialCsvService.cs +++ b/src/Utilities/CsvImportExport/CredentialCsvService.cs @@ -40,15 +40,7 @@ public static class CredentialCsvService AliasLastName = credential.Alias?.LastName ?? string.Empty, AliasNickName = credential.Alias?.NickName ?? string.Empty, AliasBirthDate = credential.Alias?.BirthDate, - AliasAddressStreet = credential.Alias?.AddressStreet ?? string.Empty, - AliasAddressCity = credential.Alias?.AddressCity ?? string.Empty, - AliasAddressState = credential.Alias?.AddressState ?? string.Empty, - AliasAddressZipCode = credential.Alias?.AddressZipCode ?? string.Empty, - AliasAddressCountry = credential.Alias?.AddressCountry ?? string.Empty, - AliasHobbies = credential.Alias?.Hobbies ?? string.Empty, AliasEmail = credential.Alias?.Email ?? string.Empty, - AliasPhoneMobile = credential.Alias?.PhoneMobile ?? string.Empty, - AliasBankAccountIBAN = credential.Alias?.BankAccountIBAN ?? string.Empty, AliasCreatedAt = credential.Alias?.CreatedAt, AliasUpdatedAt = credential.Alias?.UpdatedAt, ServiceId = credential.ServiceId, @@ -111,15 +103,7 @@ public static class CredentialCsvService LastName = record.AliasLastName, NickName = record.AliasNickName, BirthDate = record.AliasBirthDate ?? DateTime.MinValue, - AddressStreet = record.AliasAddressStreet, - AddressCity = record.AliasAddressCity, - AddressState = record.AliasAddressState, - AddressZipCode = record.AliasAddressZipCode, - AddressCountry = record.AliasAddressCountry, - Hobbies = record.AliasHobbies, Email = record.AliasEmail, - PhoneMobile = record.AliasPhoneMobile, - BankAccountIBAN = record.AliasBankAccountIBAN, CreatedAt = record.AliasCreatedAt ?? DateTime.UtcNow, UpdatedAt = record.AliasUpdatedAt ?? DateTime.UtcNow }, @@ -164,15 +148,7 @@ public class CredentialCsvRecord public string AliasLastName { get; set; } = string.Empty; public string AliasNickName { get; set; } = string.Empty; public DateTime? AliasBirthDate { get; set; } = null; - public string AliasAddressStreet { get; set; } = string.Empty; - public string AliasAddressCity { get; set; } = string.Empty; - public string AliasAddressState { get; set; } = string.Empty; - public string AliasAddressZipCode { get; set; } = string.Empty; - public string AliasAddressCountry { get; set; } = string.Empty; - public string AliasHobbies { get; set; } = string.Empty; public string AliasEmail { get; set; } = string.Empty; - public string AliasPhoneMobile { get; set; } = string.Empty; - public string AliasBankAccountIBAN { get; set; } = string.Empty; public DateTime? AliasCreatedAt { get; set; } = null; public DateTime? AliasUpdatedAt { get; set; } = null; public Guid ServiceId { get; set; } = Guid.Empty;