chore: merge delta-force-guide-server into server/

git-subtree-dir: server
git-subtree-mainline: 2a3d7fdb25
git-subtree-split: 099f138206
This commit is contained in:
siujamo committed 2026-08-28 09:37:41 +08:00
commit 25da2564a4
146 files changed
+7935

No files matched your search

@@ -0,0 +1,60 @@
spring:
application:
name: delta-force-guide
cache:
type: redis
redis:
time-to-live: PT2H
data:
redis:
repositories:
# Disable redis repositories
enabled: false
jta:
# Disable JTA support
enabled: false
jpa:
properties:
hibernate:
transaction:
jta:
# No need to use distributed transaction manager for 1 datasource.
platform: org.hibernate.engine.transaction.jta.platform.internal.NoJtaPlatform
hibernate:
ddl-auto: none
open-in-view: false
datasource:
hikari:
minimum-idle: 1
maximum-pool-size: 10
flyway:
enabled: true
baseline-on-migrate: true
thymeleaf:
enabled: false
check-template-location: false
mail:
# This configuration is used to suppressing warnings of no beans found of JavaMailSender.
host: example.smtp.com
username: app@dfguide.onixbyte.cn
mybatis:
configuration:
log-impl: org.apache.ibatis.logging.slf4j.Slf4jImpl
map-underscore-to-camel-case: true
type-aliases-package: com.onixbyte.deltaforceguide.domain.entity
type-handlers-package: com.onixbyte.deltaforceguide.mapper.handler
mapper-locations: classpath:/mapper/*.xml
logging:
pattern:
dateformat: dd MMM yyyy HH:mm:ss
level:
org.hibernate:
orm.connections.pooling: off
app:
common:
version: ${appVersion}
channel: ${channel}
vendor: ${vendor}
@@ -0,0 +1,34 @@
DROP TABLE IF EXISTS firearm CASCADE;
DROP TABLE IF EXISTS modification CASCADE;
CREATE TABLE IF NOT EXISTS firearm
(
id BIGSERIAL NOT NULL PRIMARY KEY,
name VARCHAR(64) NOT NULL,
type INT NOT NULL,
level VARCHAR(10) NOT NULL,
review TEXT NULL
);
CREATE TABLE IF NOT EXISTS modification
(
id BIGSERIAL NOT NULL PRIMARY KEY,
firearm_id BIGINT NOT NULL,
name VARCHAR(64) NOT NULL,
code VARCHAR(64) NOT NULL,
tags JSONB NULL,
note TEXT NULL,
author VARCHAR(64) NULL,
video_url VARCHAR(512) NULL,
CONSTRAINT fk_modification_firearm
FOREIGN KEY (firearm_id)
REFERENCES firearm (id)
ON DELETE CASCADE
ON UPDATE RESTRICT
);
CREATE INDEX idx_modification_firearm_id ON modification (firearm_id);
@@ -0,0 +1,61 @@
-- 创建新表
DROP TABLE IF EXISTS firearm_new;
CREATE TABLE firearm_new
(
id BIGSERIAL NOT NULL,
name VARCHAR(64) NOT NULL,
type INTEGER NOT NULL,
level VARCHAR(10) NOT NULL,
calibre VARCHAR(20) NOT NULL,
fire_rate INTEGER NOT NULL,
armour_damage INTEGER NOT NULL,
body_damage INTEGER NOT NULL,
review TEXT NULL,
CONSTRAINT firearm_new_pkey PRIMARY KEY (id)
);
-- 迁移数据
INSERT INTO firearm_new(id, name, type, level, calibre, fire_rate, armour_damage, body_damage,
review)
SELECT id,
name,
type,
level,
'',
0,
0,
0,
review
FROM firearm;
-- 处理外键(关键步骤)
-- 先删除指向旧表的外键约束
ALTER TABLE modification
DROP CONSTRAINT fk_modification_firearm;
-- 重命名旧表和索引
ALTER TABLE firearm
RENAME TO firearm_legacy;
ALTER INDEX firearm_pkey RENAME TO firearm_legacy_pkey;
-- 重命名新表和索引
ALTER TABLE firearm_new
RENAME TO firearm;
ALTER INDEX firearm_new_pkey RENAME TO firearm_pkey;
-- 重新建立外键,指向新的 firearm 表
ALTER TABLE modification
ADD CONSTRAINT fk_modification_firearm
FOREIGN KEY (firearm_id) REFERENCES firearm (id);
-- 序列所有权与名称修正
ALTER SEQUENCE firearm_id_seq RENAME TO firearm_legacy_id_seq;
ALTER SEQUENCE firearm_new_id_seq RENAME TO firearm_id_seq;
ALTER SEQUENCE firearm_id_seq OWNED BY firearm.id;
-- 更新序列计数器
SELECT setval('firearm_id_seq', coalesce(max(id), 1))
FROM firearm;
-- 删除旧表
DROP TABLE IF EXISTS firearm_legacy CASCADE;
@@ -0,0 +1,18 @@
DROP TABLE IF EXISTS app_user CASCADE;
CREATE TABLE app_user
(
id BIGSERIAL NOT NULL PRIMARY KEY,
username VARCHAR(255) NOT NULL,
email VARCHAR(255) NOT NULL,
CONSTRAINT app_user_username_key UNIQUE (username),
CONSTRAINT app_user_email_key UNIQUE (email)
);
DROP TABLE IF EXISTS app_user_credential CASCADE;
CREATE TABLE app_user_credential
(
user_id BIGINT NOT NULL REFERENCES app_user (id),
provider VARCHAR(255) NOT NULL,
credential VARCHAR(255) NOT NULL,
CONSTRAINT app_user_credential_pkey PRIMARY KEY (user_id, provider)
);
@@ -0,0 +1,2 @@
ALTER TABLE modification
ADD accessories JSONB NOT NULL DEFAULT '[]';
@@ -0,0 +1,6 @@
ALTER TABLE app_user
ADD COLUMN nickname VARCHAR(64),
ADD COLUMN avatar_url VARCHAR(512),
ADD COLUMN enabled BOOLEAN NOT NULL DEFAULT TRUE,
ADD COLUMN created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
ADD COLUMN updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW();
@@ -0,0 +1,6 @@
CREATE TABLE user_role
(
user_id BIGINT NOT NULL REFERENCES app_user (id),
role VARCHAR(32) NOT NULL,
CONSTRAINT user_role_pkey PRIMARY KEY (user_id)
);
@@ -0,0 +1,71 @@
BEGIN;
CREATE TABLE IF NOT EXISTS modification_new
(
id BIGSERIAL NOT NULL PRIMARY KEY,
user_id BIGINT NULL REFERENCES app_user (id),
firearm_id BIGINT NOT NULL REFERENCES firearm (id),
name VARCHAR(64) NOT NULL,
code VARCHAR(64) NOT NULL,
tags JSONB NOT NULL DEFAULT '[]'::JSONB,
note TEXT NULL,
author VARCHAR(64) NULL,
video_url VARCHAR(512) NULL,
accessories JSONB NOT NULL DEFAULT '[]'::JSONB,
status INTEGER NOT NULL DEFAULT 0,
create_by BIGINT NULL,
create_time TIMESTAMPTZ NOT NULL,
CONSTRAINT tags_must_be_string_array CHECK (
jsonb_typeof(tags) = 'array' AND
NOT jsonb_path_exists(tags, '$[*] ? (@.type() != "string")')
)
);
DO
$$
DECLARE
v_super_user_id BIGINT;
BEGIN
-- Added explicit table reference and LIMIT 1 to prevent multiple-row errors
SELECT app_user.id
INTO v_super_user_id
FROM app_user
LEFT JOIN user_role ur ON app_user.id = ur.user_id
WHERE ur.role = 'SUPER_USER'
LIMIT 1;
-- Explicitly check for NULL rather than evaluating the integer
IF v_super_user_id IS NOT NULL THEN
INSERT INTO modification_new(id, user_id, firearm_id, name, code, tags, note, author,
video_url, accessories, status, create_by, create_time)
SELECT m.id,
NULL,
m.firearm_id,
m.name,
m.code,
COALESCE(m.tags, '[]'::JSONB),
m.note,
m.author,
m.video_url,
COALESCE(m.accessories, '[]'::JSONB),
2,
v_super_user_id,
now()
FROM modification m;
ELSE
-- Fixed RAISE NOTICE parameter formatting
RAISE NOTICE 'Super user not found. Please execute the manual SQL commands after adding a super user.';
END IF;
END
$$;
ALTER INDEX idx_modification_firearm_id RENAME TO idx_modification_lagacy_firearm_id;
CREATE INDEX idx_modification_firearm_id ON modification_new (firearm_id);
ALTER TABLE modification
RENAME TO modification_legacy;
ALTER TABLE modification_new
RENAME TO modification;
COMMIT;
@@ -0,0 +1,71 @@
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org" lang="zh-CN">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>账号验证</title>
</head>
<body style="margin: 0; padding: 0; background-color: #f1f5f9; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'PingFang SC', 'Hiragino Sans GB', 'Microsoft YaHei', sans-serif; -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale;">
<table role="presentation" border="0" cellpadding="0" cellspacing="0" width="100%" style="background-color: #f1f5f9; padding: 40px 16px;">
<tr>
<td align="center">
<!-- 主容器 -->
<table role="presentation" border="0" cellpadding="0" cellspacing="0" width="100%" style="max-width: 520px; background-color: #ffffff; border-radius: 12px; overflow: hidden; box-shadow: 0 4px 12px rgba(15, 23, 42, 0.06); border: 1px solid #e2e8f0;">
<!-- 顶部标题 -->
<tr>
<td align="center" style="padding: 36px 32px 24px; background-color: #ffffff;">
<h1 style="margin: 0; font-size: 22px; font-weight: 700; color: #0f172a; letter-spacing: -0.3px;" th:text="${appName != null ? appName : '账号注册验证'}">账号注册验证</h1>
</td>
</tr>
<!-- 分割线 -->
<tr>
<td style="padding: 0 32px;">
<div style="height: 1px; background-color: #f1f5f9; width: 100%;"></div>
</td>
</tr>
<!-- 正文内容 -->
<tr>
<td style="padding: 32px 32px 24px;">
<p style="margin: 0 0 16px; font-size: 15px; line-height: 1.6; color: #334155;">
您好 <strong th:text="${username}">用户</strong>,
</p>
<p style="margin: 0 0 24px; font-size: 14px; line-height: 1.6; color: #64748b;">
感谢注册我们的服务。请使用下方的验证码完成账号验证,该验证码在 <strong style="color: #334155;"><span th:text="${expireMinutes}">10</span> 分钟</strong> 内有效:
</p>
<!-- 验证码展示区域 -->
<table role="presentation" border="0" cellpadding="0" cellspacing="0" width="100%" style="margin: 8px 0 24px;">
<tr>
<td align="center" style="padding: 20px; background-color: #f8fafc; border: 1px dashed #cbd5e1; border-radius: 8px;">
<span style="font-family: 'SF Mono', Consolas, 'Liberation Mono', Menlo, monospace; font-size: 32px; font-weight: 700; color: #2563eb; letter-spacing: 8px; margin-left: 8px;" th:text="${code}">123456</span>
</td>
</tr>
</table>
<p style="margin: 0 0 12px; font-size: 13px; line-height: 1.6; color: #94a3b8;">
若您未发起此操作或未尝试注册该账号,请直接忽略本邮件。
</p>
</td>
</tr>
<!-- 页脚 -->
<tr>
<td align="center" style="padding: 24px 32px; background-color: #f8fafc; border-top: 1px solid #e2e8f0;">
<p style="margin: 0 0 6px; font-size: 12px; line-height: 1.4; color: #94a3b8;">
此邮件为系统自动发送,请勿直接回复。
</p>
<p style="margin: 0; font-size: 12px; color: #cbd5e1;">
&copy; <span th:text="${#calendars.year(#calendars.createNow())}">2026</span> <span>阿萨拉向导</span>. 保留所有权利。
</p>
</td>
</tr>
</table>
</td>
</tr>
</table>
</body>
</html>