mirror of
https://github.com/aaronpo97/the-biergarten-app.git
synced 2026-02-16 10:42:08 +00:00
Initiate db drop/recreation in seed application, update broken procs
This commit is contained in:
@@ -12,6 +12,8 @@ AS
|
||||
BEGIN
|
||||
SET NOCOUNT ON;
|
||||
|
||||
DECLARE @Inserted TABLE (UserAccountID UNIQUEIDENTIFIER);
|
||||
|
||||
INSERT INTO UserAccount
|
||||
(
|
||||
Username,
|
||||
@@ -20,6 +22,7 @@ BEGIN
|
||||
DateOfBirth,
|
||||
Email
|
||||
)
|
||||
OUTPUT INSERTED.UserAccountID INTO @Inserted
|
||||
VALUES
|
||||
(
|
||||
@Username,
|
||||
@@ -29,5 +32,5 @@ BEGIN
|
||||
@Email
|
||||
);
|
||||
|
||||
SELECT @UserAccountId AS UserAccountId;
|
||||
SELECT @UserAccountId = UserAccountID FROM @Inserted;
|
||||
END;
|
||||
|
||||
@@ -27,10 +27,9 @@ BEGIN
|
||||
THROW 50000, 'Failed to create user account.', 1;
|
||||
END
|
||||
|
||||
|
||||
EXEC dbo.usp_RotateUserCredential
|
||||
@UserAccountId = @UserAccountId_,
|
||||
@Hash = @Hash;
|
||||
INSERT INTO dbo.UserCredential
|
||||
(UserAccountId, Hash)
|
||||
VALUES (@UserAccountId_, @Hash);
|
||||
|
||||
IF @@ROWCOUNT = 0
|
||||
BEGIN
|
||||
|
||||
@@ -14,9 +14,11 @@
|
||||
Version="1.3.1"
|
||||
/>
|
||||
<PackageReference Include="Microsoft.Data.SqlClient" Version="6.1.3" />
|
||||
<PackageReference Include="dbup" Version="5.0.41" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Database.Core\Database.Core.csproj" />
|
||||
<ProjectReference Include="..\..\Repository\Repository.Core\Repository.Core.csproj" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
using DBSeed;
|
||||
using Microsoft.Data.SqlClient;
|
||||
using DbUp;
|
||||
using System.Reflection;
|
||||
|
||||
try
|
||||
{
|
||||
@@ -14,8 +16,47 @@ try
|
||||
await using var connection = new SqlConnection(connectionString);
|
||||
await connection.OpenAsync();
|
||||
|
||||
// drop and recreate the database
|
||||
var useMaster = connection.CreateCommand();
|
||||
useMaster.CommandText = "USE master;";
|
||||
await useMaster.ExecuteNonQueryAsync();
|
||||
|
||||
var dbName = "Biergarten";
|
||||
var dropDb = connection.CreateCommand();
|
||||
dropDb.CommandText = $@"
|
||||
IF DB_ID(N'{dbName}') IS NOT NULL
|
||||
BEGIN
|
||||
ALTER DATABASE [{dbName}] SET SINGLE_USER WITH ROLLBACK IMMEDIATE;
|
||||
DROP DATABASE [{dbName}];
|
||||
END";
|
||||
await dropDb.ExecuteNonQueryAsync();
|
||||
|
||||
var createDb = connection.CreateCommand();
|
||||
createDb.CommandText = $@"CREATE DATABASE [{dbName}];";
|
||||
await createDb.ExecuteNonQueryAsync();
|
||||
await connection.CloseAsync();
|
||||
await connection.OpenAsync();
|
||||
|
||||
|
||||
Console.WriteLine("Connected to database.");
|
||||
|
||||
Console.WriteLine("Starting migrations...");
|
||||
|
||||
// Run Database.Core migrations (embedded resources) via DbUp
|
||||
var migrationAssembly = Assembly.Load("Database.Core");
|
||||
var upgrader = DeployChanges
|
||||
.To.SqlDatabase(connectionString)
|
||||
.WithScriptsEmbeddedInAssembly(migrationAssembly)
|
||||
.LogToConsole()
|
||||
.Build();
|
||||
|
||||
var upgradeResult = upgrader.PerformUpgrade();
|
||||
if (!upgradeResult.Successful)
|
||||
throw upgradeResult.Error;
|
||||
|
||||
Console.WriteLine("Migrations completed.");
|
||||
|
||||
|
||||
ISeeder[] seeders =
|
||||
[
|
||||
new LocationSeeder(),
|
||||
@@ -30,6 +71,7 @@ try
|
||||
}
|
||||
|
||||
Console.WriteLine("Seed completed successfully.");
|
||||
await connection.CloseAsync();
|
||||
return 0;
|
||||
}
|
||||
catch (Exception ex)
|
||||
|
||||
@@ -9,11 +9,8 @@ using Microsoft.Data.SqlClient;
|
||||
|
||||
namespace DBSeed
|
||||
{
|
||||
|
||||
internal class UserSeeder : ISeeder
|
||||
{
|
||||
|
||||
|
||||
private static readonly IReadOnlyList<(
|
||||
string FirstName,
|
||||
string LastName
|
||||
@@ -129,36 +126,38 @@ namespace DBSeed
|
||||
int createdCredentials = 0;
|
||||
int createdVerifications = 0;
|
||||
|
||||
|
||||
foreach (var (firstName, lastName) in SeedNames)
|
||||
{
|
||||
// create the user in the database
|
||||
var userAccountId = Guid.NewGuid();
|
||||
await AddUserAccountAsync(connection, new UserAccount
|
||||
{
|
||||
UserAccountId = userAccountId,
|
||||
FirstName = firstName,
|
||||
LastName = lastName,
|
||||
Email = $"{firstName}.{lastName}@thebiergarten.app",
|
||||
Username = $"{firstName[0]}.{lastName}",
|
||||
DateOfBirth = GenerateDateOfBirth(rng)
|
||||
});
|
||||
createdUsers++;
|
||||
// prepare user fields
|
||||
var username = $"{firstName[0]}.{lastName}";
|
||||
var email = $"{firstName}.{lastName}@thebiergarten.app";
|
||||
var dob = GenerateDateOfBirth(rng);
|
||||
|
||||
// add user credentials
|
||||
if (!await HasUserCredentialAsync(connection, userAccountId))
|
||||
{
|
||||
// generate a password and hash it
|
||||
string pwd = generator.Generate(
|
||||
length: 64,
|
||||
numberOfDigits: 10,
|
||||
numberOfSymbols: 10
|
||||
);
|
||||
string hash = GeneratePasswordHash(pwd);
|
||||
await AddUserCredentialAsync(connection, userAccountId, hash);
|
||||
|
||||
// register the user (creates account + credential)
|
||||
var userAccountId = await RegisterUserAsync(
|
||||
connection,
|
||||
username,
|
||||
firstName,
|
||||
lastName,
|
||||
dob,
|
||||
email,
|
||||
hash
|
||||
);
|
||||
createdUsers++;
|
||||
createdCredentials++;
|
||||
}
|
||||
|
||||
// add user verification
|
||||
if (await HasUserVerificationAsync(connection, userAccountId)) continue;
|
||||
|
||||
await AddUserVerificationAsync(connection, userAccountId);
|
||||
createdVerifications++;
|
||||
}
|
||||
@@ -168,19 +167,34 @@ namespace DBSeed
|
||||
Console.WriteLine($"Added {createdVerifications} user verifications.");
|
||||
}
|
||||
|
||||
private static async Task AddUserAccountAsync(SqlConnection connection, UserAccount ua)
|
||||
private static async Task<Guid> RegisterUserAsync(
|
||||
SqlConnection connection,
|
||||
string username,
|
||||
string firstName,
|
||||
string lastName,
|
||||
DateTime dateOfBirth,
|
||||
string email,
|
||||
string hash
|
||||
)
|
||||
{
|
||||
await using var command = new SqlCommand("usp_CreateUserAccount", connection);
|
||||
await using var command = new SqlCommand("dbo.USP_RegisterUser", connection);
|
||||
command.CommandType = CommandType.StoredProcedure;
|
||||
|
||||
command.Parameters.Add("@UserAccountId", SqlDbType.UniqueIdentifier).Value = ua.UserAccountId;
|
||||
command.Parameters.Add("@Username", SqlDbType.NVarChar, 100).Value = ua.Username;
|
||||
command.Parameters.Add("@FirstName", SqlDbType.NVarChar, 100).Value = ua.FirstName;
|
||||
command.Parameters.Add("@LastName", SqlDbType.NVarChar, 100).Value = ua.LastName;
|
||||
command.Parameters.Add("@Email", SqlDbType.NVarChar, 256).Value = ua.Email;
|
||||
command.Parameters.Add("@DateOfBirth", SqlDbType.Date).Value = ua.DateOfBirth;
|
||||
var idParam = new SqlParameter("@UserAccountId_", SqlDbType.UniqueIdentifier)
|
||||
{
|
||||
Direction = ParameterDirection.Output
|
||||
};
|
||||
command.Parameters.Add(idParam);
|
||||
|
||||
command.Parameters.Add("@Username", SqlDbType.VarChar, 64).Value = username;
|
||||
command.Parameters.Add("@FirstName", SqlDbType.NVarChar, 128).Value = firstName;
|
||||
command.Parameters.Add("@LastName", SqlDbType.NVarChar, 128).Value = lastName;
|
||||
command.Parameters.Add("@DateOfBirth", SqlDbType.DateTime).Value = dateOfBirth;
|
||||
command.Parameters.Add("@Email", SqlDbType.VarChar, 128).Value = email;
|
||||
command.Parameters.Add("@Hash", SqlDbType.NVarChar, -1).Value = hash;
|
||||
|
||||
await command.ExecuteNonQueryAsync();
|
||||
return (Guid)idParam.Value;
|
||||
}
|
||||
|
||||
private static string GeneratePasswordHash(string pwd)
|
||||
@@ -199,39 +213,6 @@ namespace DBSeed
|
||||
return $"{Convert.ToBase64String(salt)}:{Convert.ToBase64String(hash)}";
|
||||
}
|
||||
|
||||
private static async Task<bool> HasUserCredentialAsync(
|
||||
SqlConnection connection,
|
||||
Guid userAccountId
|
||||
)
|
||||
{
|
||||
const string sql = $"""
|
||||
SELECT 1
|
||||
FROM dbo.UserCredential
|
||||
WHERE UserAccountId = @UserAccountId;
|
||||
""";
|
||||
await using var command = new SqlCommand(sql, connection);
|
||||
command.Parameters.AddWithValue("@UserAccountId", userAccountId);
|
||||
object? result = await command.ExecuteScalarAsync();
|
||||
return result is not null;
|
||||
}
|
||||
|
||||
private static async Task AddUserCredentialAsync(
|
||||
SqlConnection connection,
|
||||
Guid userAccountId,
|
||||
string hash
|
||||
)
|
||||
{
|
||||
await using var command = new SqlCommand(
|
||||
"dbo.USP_AddUserCredential",
|
||||
connection
|
||||
);
|
||||
command.CommandType = CommandType.StoredProcedure;
|
||||
command.Parameters.AddWithValue("@UserAccountId", userAccountId);
|
||||
command.Parameters.AddWithValue("@Hash", hash);
|
||||
|
||||
await command.ExecuteNonQueryAsync();
|
||||
}
|
||||
|
||||
private static async Task<bool> HasUserVerificationAsync(
|
||||
SqlConnection connection,
|
||||
Guid userAccountId
|
||||
@@ -258,7 +239,7 @@ namespace DBSeed
|
||||
connection
|
||||
);
|
||||
command.CommandType = CommandType.StoredProcedure;
|
||||
command.Parameters.AddWithValue("@UserAccountID", userAccountId);
|
||||
command.Parameters.AddWithValue("@UserAccountID_", userAccountId);
|
||||
|
||||
await command.ExecuteNonQueryAsync();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user