Files
photography/backend/pkg/migration/migrations.go
xujiang 5dd0bc19e4
Some checks failed
部署管理后台 / 🧪 测试和构建 (push) Failing after 1m5s
部署管理后台 / 🔒 安全扫描 (push) Has been skipped
部署后端服务 / 🧪 测试后端 (push) Failing after 3m13s
部署前端网站 / 🧪 测试和构建 (push) Failing after 2m10s
部署管理后台 / 🚀 部署到生产环境 (push) Has been skipped
部署后端服务 / 🚀 构建并部署 (push) Has been skipped
部署管理后台 / 🔄 回滚部署 (push) Has been skipped
部署前端网站 / 🚀 部署到生产环境 (push) Has been skipped
部署后端服务 / 🔄 回滚部署 (push) Has been skipped
style: 统一代码格式化 (go fmt + 配置更新)
- 后端:应用 go fmt 自动格式化,统一代码风格
- 前端:更新 API 配置,完善类型安全
- 所有代码符合项目规范,准备生产部署
2025-07-14 10:02:04 +08:00

322 lines
11 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package migration
import (
"time"
)
// GetAllMigrations 返回所有迁移定义
func GetAllMigrations() []Migration {
return []Migration{
{
Version: "20250101_000001",
Description: "Create initial tables - users, categories, photos",
Timestamp: time.Date(2025, 1, 1, 0, 0, 1, 0, time.UTC),
UpSQL: `
-- 用户表
CREATE TABLE IF NOT EXISTS user (
id INTEGER PRIMARY KEY AUTOINCREMENT,
username VARCHAR(50) UNIQUE NOT NULL,
password VARCHAR(255) NOT NULL,
email VARCHAR(100) UNIQUE NOT NULL,
avatar VARCHAR(255) DEFAULT '',
status INTEGER DEFAULT 1, -- 1:启用 0:禁用
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
updated_at DATETIME DEFAULT CURRENT_TIMESTAMP
);
-- 分类表
CREATE TABLE IF NOT EXISTS category (
id INTEGER PRIMARY KEY AUTOINCREMENT,
name VARCHAR(100) NOT NULL,
description TEXT,
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
updated_at DATETIME DEFAULT CURRENT_TIMESTAMP
);
-- 照片表
CREATE TABLE IF NOT EXISTS photo (
id INTEGER PRIMARY KEY AUTOINCREMENT,
title VARCHAR(255) NOT NULL,
description TEXT,
file_path VARCHAR(500) NOT NULL,
thumbnail_path VARCHAR(500),
user_id INTEGER NOT NULL,
category_id INTEGER,
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
updated_at DATETIME DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (user_id) REFERENCES user(id),
FOREIGN KEY (category_id) REFERENCES category(id)
);
-- 创建索引
CREATE INDEX IF NOT EXISTS idx_user_username ON user(username);
CREATE INDEX IF NOT EXISTS idx_user_email ON user(email);
CREATE INDEX IF NOT EXISTS idx_photo_user_id ON photo(user_id);
CREATE INDEX IF NOT EXISTS idx_photo_category_id ON photo(category_id);
CREATE INDEX IF NOT EXISTS idx_photo_created_at ON photo(created_at);
`,
DownSQL: `
-- 删除索引
DROP INDEX IF EXISTS idx_photo_created_at;
DROP INDEX IF EXISTS idx_photo_category_id;
DROP INDEX IF EXISTS idx_photo_user_id;
DROP INDEX IF EXISTS idx_user_email;
DROP INDEX IF EXISTS idx_user_username;
-- 删除表(注意外键约束,先删除依赖表)
DROP TABLE IF EXISTS photo;
DROP TABLE IF EXISTS category;
DROP TABLE IF EXISTS user;
`,
},
{
Version: "20250101_000002",
Description: "Insert default admin user and categories",
Timestamp: time.Date(2025, 1, 1, 0, 0, 2, 0, time.UTC),
UpSQL: `
-- 插入默认管理员用户
INSERT OR IGNORE INTO user (username, password, email, avatar, status)
VALUES ('admin', '$2a$10$K8H7YjN5hOcE0zWTz1YuAuYqFyQ9cqUdFHJgJdKxA5wGv3LUQHgKq', 'admin@example.com', '', 1);
-- 密码是 admin123 的 bcrypt 哈希
-- 插入默认分类
INSERT OR IGNORE INTO category (name, description)
VALUES
('风景', '自然风景摄影作品'),
('人像', '人物肖像摄影作品'),
('建筑', '建筑摄影作品'),
('街拍', '街头摄影作品');
`,
DownSQL: `
-- 删除默认数据(保留用户数据的完整性)
DELETE FROM photo WHERE category_id IN (SELECT id FROM category WHERE name IN ('风景', '人像', '建筑', '街拍'));
DELETE FROM category WHERE name IN ('风景', '人像', '建筑', '街拍');
DELETE FROM user WHERE username = 'admin' AND email = 'admin@example.com';
`,
},
{
Version: "20250111_000001",
Description: "Add photo metadata fields - EXIF data, tags, location",
Timestamp: time.Date(2025, 1, 11, 0, 0, 1, 0, time.UTC),
UpSQL: `
-- 为照片表添加元数据字段
ALTER TABLE photo ADD COLUMN exif_data TEXT DEFAULT '{}';
ALTER TABLE photo ADD COLUMN tags VARCHAR(500) DEFAULT '';
ALTER TABLE photo ADD COLUMN location VARCHAR(200) DEFAULT '';
ALTER TABLE photo ADD COLUMN camera_model VARCHAR(100) DEFAULT '';
ALTER TABLE photo ADD COLUMN lens_model VARCHAR(100) DEFAULT '';
ALTER TABLE photo ADD COLUMN focal_length INTEGER DEFAULT 0;
ALTER TABLE photo ADD COLUMN aperture VARCHAR(10) DEFAULT '';
ALTER TABLE photo ADD COLUMN shutter_speed VARCHAR(20) DEFAULT '';
ALTER TABLE photo ADD COLUMN iso INTEGER DEFAULT 0;
ALTER TABLE photo ADD COLUMN flash_used BOOLEAN DEFAULT FALSE;
ALTER TABLE photo ADD COLUMN orientation INTEGER DEFAULT 1;
-- 创建标签索引(用于搜索)
CREATE INDEX IF NOT EXISTS idx_photo_tags ON photo(tags);
CREATE INDEX IF NOT EXISTS idx_photo_location ON photo(location);
`,
DownSQL: `
-- 删除索引
DROP INDEX IF EXISTS idx_photo_location;
DROP INDEX IF EXISTS idx_photo_tags;
-- 注意SQLite 不支持 DROP COLUMN需要重建表
-- 创建临时表(不包含新添加的列)
CREATE TABLE photo_temp (
id INTEGER PRIMARY KEY AUTOINCREMENT,
title VARCHAR(255) NOT NULL,
description TEXT,
file_path VARCHAR(500) NOT NULL,
thumbnail_path VARCHAR(500),
user_id INTEGER NOT NULL,
category_id INTEGER,
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
updated_at DATETIME DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (user_id) REFERENCES user(id),
FOREIGN KEY (category_id) REFERENCES category(id)
);
-- 复制数据
INSERT INTO photo_temp (id, title, description, file_path, thumbnail_path, user_id, category_id, created_at, updated_at)
SELECT id, title, description, file_path, thumbnail_path, user_id, category_id, created_at, updated_at FROM photo;
-- 删除原表
DROP TABLE photo;
-- 重命名临时表
ALTER TABLE photo_temp RENAME TO photo;
-- 重新创建索引
CREATE INDEX IF NOT EXISTS idx_photo_user_id ON photo(user_id);
CREATE INDEX IF NOT EXISTS idx_photo_category_id ON photo(category_id);
CREATE INDEX IF NOT EXISTS idx_photo_created_at ON photo(created_at);
`,
},
{
Version: "20250111_000002",
Description: "Create photo collections and favorites system",
Timestamp: time.Date(2025, 1, 11, 0, 0, 2, 0, time.UTC),
UpSQL: `
-- 照片集合表
CREATE TABLE IF NOT EXISTS collection (
id INTEGER PRIMARY KEY AUTOINCREMENT,
name VARCHAR(100) NOT NULL,
description TEXT,
user_id INTEGER NOT NULL,
is_public BOOLEAN DEFAULT FALSE,
cover_photo_id INTEGER,
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
updated_at DATETIME DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (user_id) REFERENCES user(id),
FOREIGN KEY (cover_photo_id) REFERENCES photo(id)
);
-- 照片集合关联表(多对多)
CREATE TABLE IF NOT EXISTS collection_photo (
id INTEGER PRIMARY KEY AUTOINCREMENT,
collection_id INTEGER NOT NULL,
photo_id INTEGER NOT NULL,
sort_order INTEGER DEFAULT 0,
added_at DATETIME DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (collection_id) REFERENCES collection(id) ON DELETE CASCADE,
FOREIGN KEY (photo_id) REFERENCES photo(id) ON DELETE CASCADE,
UNIQUE(collection_id, photo_id)
);
-- 用户收藏表
CREATE TABLE IF NOT EXISTS user_favorite (
id INTEGER PRIMARY KEY AUTOINCREMENT,
user_id INTEGER NOT NULL,
photo_id INTEGER NOT NULL,
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (user_id) REFERENCES user(id) ON DELETE CASCADE,
FOREIGN KEY (photo_id) REFERENCES photo(id) ON DELETE CASCADE,
UNIQUE(user_id, photo_id)
);
-- 创建索引
CREATE INDEX IF NOT EXISTS idx_collection_user_id ON collection(user_id);
CREATE INDEX IF NOT EXISTS idx_collection_public ON collection(is_public);
CREATE INDEX IF NOT EXISTS idx_collection_photo_collection ON collection_photo(collection_id);
CREATE INDEX IF NOT EXISTS idx_collection_photo_photo ON collection_photo(photo_id);
CREATE INDEX IF NOT EXISTS idx_user_favorite_user ON user_favorite(user_id);
CREATE INDEX IF NOT EXISTS idx_user_favorite_photo ON user_favorite(photo_id);
`,
DownSQL: `
-- 删除索引
DROP INDEX IF EXISTS idx_user_favorite_photo;
DROP INDEX IF EXISTS idx_user_favorite_user;
DROP INDEX IF EXISTS idx_collection_photo_photo;
DROP INDEX IF EXISTS idx_collection_photo_collection;
DROP INDEX IF EXISTS idx_collection_public;
DROP INDEX IF EXISTS idx_collection_user_id;
-- 删除表
DROP TABLE IF EXISTS user_favorite;
DROP TABLE IF EXISTS collection_photo;
DROP TABLE IF EXISTS collection;
`,
},
{
Version: "20250111_000003",
Description: "Add user profile and preferences",
Timestamp: time.Date(2025, 1, 11, 0, 0, 3, 0, time.UTC),
UpSQL: `
-- 为用户表添加更多字段
ALTER TABLE user ADD COLUMN bio TEXT DEFAULT '';
ALTER TABLE user ADD COLUMN website VARCHAR(255) DEFAULT '';
ALTER TABLE user ADD COLUMN location VARCHAR(100) DEFAULT '';
ALTER TABLE user ADD COLUMN birth_date DATE;
ALTER TABLE user ADD COLUMN phone VARCHAR(20) DEFAULT '';
ALTER TABLE user ADD COLUMN is_verified BOOLEAN DEFAULT FALSE;
ALTER TABLE user ADD COLUMN last_login_at DATETIME;
-- 用户设置表
CREATE TABLE IF NOT EXISTS user_setting (
id INTEGER PRIMARY KEY AUTOINCREMENT,
user_id INTEGER UNIQUE NOT NULL,
theme VARCHAR(20) DEFAULT 'light', -- light, dark, auto
language VARCHAR(10) DEFAULT 'zh-CN',
timezone VARCHAR(50) DEFAULT 'Asia/Shanghai',
email_notifications BOOLEAN DEFAULT TRUE,
public_profile BOOLEAN DEFAULT TRUE,
show_exif BOOLEAN DEFAULT TRUE,
watermark_enabled BOOLEAN DEFAULT FALSE,
watermark_text VARCHAR(100) DEFAULT '',
watermark_position VARCHAR(20) DEFAULT 'bottom-right',
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
updated_at DATETIME DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (user_id) REFERENCES user(id) ON DELETE CASCADE
);
-- 为新字段创建索引
CREATE INDEX IF NOT EXISTS idx_user_verified ON user(is_verified);
CREATE INDEX IF NOT EXISTS idx_user_last_login ON user(last_login_at);
`,
DownSQL: `
-- 删除索引
DROP INDEX IF EXISTS idx_user_last_login;
DROP INDEX IF EXISTS idx_user_verified;
-- 删除用户设置表
DROP TABLE IF EXISTS user_setting;
-- SQLite 不支持 DROP COLUMN需要重建用户表
CREATE TABLE user_temp (
id INTEGER PRIMARY KEY AUTOINCREMENT,
username VARCHAR(50) UNIQUE NOT NULL,
password VARCHAR(255) NOT NULL,
email VARCHAR(100) UNIQUE NOT NULL,
avatar VARCHAR(255) DEFAULT '',
status INTEGER DEFAULT 1,
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
updated_at DATETIME DEFAULT CURRENT_TIMESTAMP
);
-- 复制原始数据
INSERT INTO user_temp (id, username, password, email, avatar, status, created_at, updated_at)
SELECT id, username, password, email, avatar, status, created_at, updated_at FROM user;
-- 删除原表
DROP TABLE user;
-- 重命名临时表
ALTER TABLE user_temp RENAME TO user;
-- 重新创建索引
CREATE INDEX IF NOT EXISTS idx_user_username ON user(username);
CREATE INDEX IF NOT EXISTS idx_user_email ON user(email);
`,
},
}
}
// GetMigrationByVersion 根据版本号获取迁移
func GetMigrationByVersion(version string) *Migration {
migrations := GetAllMigrations()
for _, migration := range migrations {
if migration.Version == version {
return &migration
}
}
return nil
}
// GetLatestMigrationVersion 获取最新的迁移版本
func GetLatestMigrationVersion() string {
migrations := GetAllMigrations()
if len(migrations) == 0 {
return ""
}
latest := migrations[0]
for _, migration := range migrations {
if migration.Version > latest.Version {
latest = migration
}
}
return latest.Version
}