feat(DatabaseInitializer): add database migration logic and clean up initialization process

This commit is contained in:
shiyu
2025-05-23 21:31:04 +08:00
parent 7932240bbb
commit 3feb71493f
4 changed files with 32 additions and 38 deletions
+5 -14
View File
@@ -1,29 +1,21 @@
FROM mcr.microsoft.com/dotnet/aspnet:9.0 AS base FROM mcr.microsoft.com/dotnet/aspnet:9.0 AS base
WORKDIR /app WORKDIR /app
EXPOSE 8080
EXPOSE 8081
EXPOSE 80 EXPOSE 80
FROM oven/bun:alpine AS build-frontend FROM oven/bun:alpine AS build-frontend
WORKDIR /src/View WORKDIR /src/Web
COPY View/package*.json ./ COPY Web/package*.json ./
RUN bun install RUN bun install
COPY View/ ./ COPY Web/ ./
RUN bun run build RUN bun run build
FROM mcr.microsoft.com/dotnet/sdk:9.0 AS build FROM mcr.microsoft.com/dotnet/sdk:9.0 AS build
ARG BUILD_CONFIGURATION=Release ARG BUILD_CONFIGURATION=Release
ENV DEFAULT_CONNECTION="Host=yourhost;Username=foxel;Password=foxel;Database=foxel"
WORKDIR /src WORKDIR /src
COPY ["Foxel.csproj", "./"] COPY ["Foxel.csproj", "./"]
RUN dotnet restore "Foxel.csproj" RUN dotnet restore "Foxel.csproj"
COPY . . COPY . .
WORKDIR "/src/" WORKDIR "/src/"
# 安装EF Core工具并执行数据库迁移
RUN dotnet tool install --global dotnet-ef
ENV PATH="$PATH:/root/.dotnet/tools"
RUN dotnet ef migrations add InitialCreate -- --environment Production
RUN dotnet ef database update -- --environment Production
RUN dotnet build "./Foxel.csproj" -c $BUILD_CONFIGURATION -o /app/build RUN dotnet build "./Foxel.csproj" -c $BUILD_CONFIGURATION -o /app/build
FROM build AS publish FROM build AS publish
@@ -32,11 +24,10 @@ RUN dotnet publish "./Foxel.csproj" -c $BUILD_CONFIGURATION -o /app/publish /p:U
FROM base AS final FROM base AS final
WORKDIR /app WORKDIR /app
ENV DEFAULT_CONNECTION="Host=yourhost;Username=foxel;Password=foxel;Database=foxel"
COPY --from=publish /app/publish . COPY --from=publish /app/publish .
RUN apt-get update && apt-get install -y nginx && rm -rf /var/lib/apt/lists/* RUN apt-get update && apt-get install -y nginx && rm -rf /var/lib/apt/lists/*
COPY --from=build-frontend /src/View/dist /var/www/html COPY --from=build-frontend /src/Web/dist /var/www/html
COPY /View/nginx.conf /etc/nginx/nginx.conf COPY /Web/nginx.conf /etc/nginx/nginx.conf
RUN mkdir -p /var/lib/nginx/body /var/cache/nginx /var/run/nginx /app/Uploads \ RUN mkdir -p /var/lib/nginx/body /var/cache/nginx /var/run/nginx /app/Uploads \
&& chown -R $APP_UID:$APP_UID /var/lib/nginx /var/cache/nginx /var/run/nginx /var/log/nginx /etc/nginx /var/www/html /app/Uploads \ && chown -R $APP_UID:$APP_UID /var/lib/nginx /var/cache/nginx /var/run/nginx /var/log/nginx /etc/nginx /var/www/html /app/Uploads \
+2
View File
@@ -1,6 +1,8 @@
using Foxel;
using Foxel.Extensions; using Foxel.Extensions;
using Foxel.Services.Initializer; using Foxel.Services.Initializer;
using Microsoft.AspNetCore.HttpOverrides; using Microsoft.AspNetCore.HttpOverrides;
using Microsoft.EntityFrameworkCore;
var builder = WebApplication.CreateBuilder(args); var builder = WebApplication.CreateBuilder(args);
var environment = builder.Environment; var environment = builder.Environment;
+2
View File
@@ -38,7 +38,9 @@ public class AuthService(IDbContextFactory<MyDbContext> dbContextFactory, IConfi
var userCount = await context.Users.CountAsync(); var userCount = await context.Users.CountAsync();
if (userCount == 0) if (userCount == 0)
{ {
var role = await context.Roles.FirstOrDefaultAsync(r => r.Id == 1);
user.RoleId = 1; user.RoleId = 1;
user.Role = role;
} }
context.Users.Add(user); context.Users.Add(user);
await context.SaveChangesAsync(); await context.SaveChangesAsync();
+23 -24
View File
@@ -1,5 +1,3 @@
using System.Security.Cryptography;
using System.Text;
using Foxel.Models.DataBase; using Foxel.Models.DataBase;
using Foxel.Services.Configuration; using Foxel.Services.Configuration;
using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore;
@@ -18,6 +16,9 @@ public class DatabaseInitializer(
{ {
logger.LogInformation("开始检查数据库初始化状态..."); logger.LogInformation("开始检查数据库初始化状态...");
// 执行数据库迁移
await MigrateDatabaseAsync();
// 检查是否已经完成初始化 // 检查是否已经完成初始化
if (await configService.ExistsAsync(InitializationFlag) && if (await configService.ExistsAsync(InitializationFlag) &&
configService[InitializationFlag] == "true") configService[InitializationFlag] == "true")
@@ -41,7 +42,8 @@ public class DatabaseInitializer(
// 初始化GitHub认证配置 // 初始化GitHub认证配置
await EnsureConfigExistsAsync("Authentication:GitHubClientId", "placeholder_replace_with_actual_github_client_id"); await EnsureConfigExistsAsync("Authentication:GitHubClientId", "placeholder_replace_with_actual_github_client_id");
await EnsureConfigExistsAsync("Authentication:GitHubClientSecret", "placeholder_replace_with_actual_github_client_secret"); await EnsureConfigExistsAsync("Authentication:GitHubClientSecret", "placeholder_replace_with_actual_github_client_secret");
await EnsureConfigExistsAsync("Authentication:GitHubClientSecret", ""); await EnsureConfigExistsAsync("Authentication:GitHubCallbackUrl", "");
// 初始化AI相关配置 // 初始化AI相关配置
await EnsureConfigExistsAsync("AI:ApiEndpoint", ""); await EnsureConfigExistsAsync("AI:ApiEndpoint", "");
await EnsureConfigExistsAsync("AI:ApiKey", ""); await EnsureConfigExistsAsync("AI:ApiKey", "");
@@ -63,6 +65,24 @@ public class DatabaseInitializer(
logger.LogInformation("数据库配置初始化完成"); logger.LogInformation("数据库配置初始化完成");
} }
private async Task MigrateDatabaseAsync()
{
logger.LogInformation("开始执行数据库迁移...");
try
{
await using var context = await contextFactory.CreateDbContextAsync();
await context.Database.MigrateAsync();
logger.LogInformation("数据库迁移完成");
}
catch (Exception ex)
{
logger.LogWarning("数据库迁移过程中出现警告或错误: {Error}", ex.Message);
logger.LogInformation("尝试确保数据库已创建...");
await using var context = await contextFactory.CreateDbContextAsync();
await context.Database.EnsureCreatedAsync();
}
}
private async Task EnsureConfigExistsAsync(string key, string value) private async Task EnsureConfigExistsAsync(string key, string value)
{ {
if (!await configService.ExistsAsync(key)) if (!await configService.ExistsAsync(key))
@@ -93,25 +113,4 @@ public class DatabaseInitializer(
} }
logger.LogInformation("请注意,第一个注册的用户将自动成为管理员"); logger.LogInformation("请注意,第一个注册的用户将自动成为管理员");
} }
private string GenerateRandomPassword(int length)
{
const string chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
var random = new Random();
var password = new StringBuilder(length);
for (int i = 0; i < length; i++)
{
password.Append(chars[random.Next(chars.Length)]);
}
return password.ToString();
}
private string HashPassword(string password)
{
using var sha256 = SHA256.Create();
var hashedBytes = sha256.ComputeHash(Encoding.UTF8.GetBytes(password));
return Convert.ToBase64String(hashedBytes);
}
} }