migrate from github

This commit is contained in:
2026-07-15 22:42:31 +08:00
commit 3ad559f05e
262 changed files with 21637 additions and 0 deletions
+59
View File
@@ -0,0 +1,59 @@
package main
import (
"fmt"
"github.com/XingfenD/yoresee_doc/internal/model"
"github.com/XingfenD/yoresee_doc/internal/utils"
"github.com/sirupsen/logrus"
"gorm.io/gorm"
)
func createUserInTx(tx *gorm.DB, username, email, password string) error {
logrus.Printf("Creating user %s in transaction...", username)
hashedPwd, err := utils.HashPassword(password)
if err != nil {
return err
}
externalID := utils.GenerateExternalID(utils.ExternalIDContextDocument)
user := model.User{
ExternalID: externalID,
Username: username,
PasswordHash: hashedPwd,
Email: email,
Nickname: username,
Status: 1,
}
var count int64
tx.Model(&model.User{}).Where("email = ?", user.Email).Count(&count)
if count == 0 {
if err := tx.Create(&user).Error; err != nil {
return err
}
logrus.Printf("User %s created successfully in transaction.", username)
} else {
logrus.Printf("User %s already exists in transaction.", username)
}
return nil
}
func createUserWithUsername(tx *gorm.DB, username string) error {
email := fmt.Sprintf("%s@yoresee.cc", username)
password := username
return createUserInTx(tx, username, email, password)
}
func createAdminUserInTx(tx *gorm.DB) error {
logrus.Println("Creating admin user in transaction...")
if err := createUserWithUsername(tx, "admin"); err != nil {
return err
}
logrus.Println("Admin permission granted successfully in transaction.")
return nil
}
+34
View File
@@ -0,0 +1,34 @@
package main
import (
"context"
"github.com/XingfenD/yoresee_doc/internal/constant"
"github.com/XingfenD/yoresee_doc/internal/utils"
"github.com/XingfenD/yoresee_doc/pkg/storage"
)
func initializeConfigInConsul(ctx context.Context) error {
registerModeKey := utils.GenConfigKey(
constant.ConfigKey_First_System,
constant.ConfigKey_Second_Security,
constant.ConfigKey_Third_RegisterMode,
)
if _, ok, err := storage.Consul.Get(ctx, registerModeKey); err != nil {
return err
} else if !ok {
if err := storage.Consul.Set(ctx, registerModeKey, constant.RegisterMode_Invite); err != nil {
return err
}
}
return nil
}
func markDatabaseInitializedInConsul(ctx context.Context) error {
initializedKey := utils.GenConfigKey(
constant.ConfigKey_First_System,
constant.ConfigKey_Second_Database,
constant.ConfigKey_Third_Initialized,
)
return storage.Consul.Set(ctx, initializedKey, constant.Database_Initialized_True)
}
+182
View File
@@ -0,0 +1,182 @@
package main
import (
"github.com/XingfenD/yoresee_doc/internal/model"
"github.com/XingfenD/yoresee_doc/internal/utils"
"github.com/sirupsen/logrus"
"gorm.io/gorm"
)
type DocumentInput struct {
Title string
Content string
Summary string
ParentID int64
Tags []string
KnowledgeID *int64
}
func createDocumentWithAllTables(tx *gorm.DB, adminUserID int64, input DocumentInput) (*model.Document, error) {
document := model.Document{
ExternalID: utils.GenerateExternalID(utils.ExternalIDContextDocument),
Title: input.Title,
Type: "markdown",
Summary: input.Summary,
ParentID: input.ParentID,
UserID: adminUserID,
Content: input.Content,
Tags: input.Tags,
ViewCount: 0,
EditCount: 0,
KnowledgeID: input.KnowledgeID,
Path: "0",
Depth: 0,
}
if err := tx.Create(&document).Error; err != nil {
return nil, err
}
if err := updateDocumentPathDepth(tx, document.ID, document.ParentID); err != nil {
return nil, err
}
documentVersion := model.DocumentVersion{
DocumentID: document.ID,
Version: 1,
Title: document.Title,
Content: document.Content,
UserID: adminUserID,
ChangeSummary: "Initial version",
}
if err := tx.Create(&documentVersion).Error; err != nil {
return nil, err
}
return &document, nil
}
func initializeDocumentsInTx(tx *gorm.DB) error {
logrus.Println("Initializing default documents in transaction...")
var adminUser model.User
if err := tx.Where("username = ?", "admin").First(&adminUser).Error; err != nil {
return err
}
var count int64
tx.Model(&model.Document{}).Where("title = ?", "欢迎使用 Yoresee Doc").Count(&count)
if count > 0 {
logrus.Println("Default document already exists in transaction.")
return nil
}
contentString := "# 欢迎使用 Yoresee Doc\n\n这是您的第一个文档。Yoresee Doc 是一个功能强大的文档管理系统,支持以下特性:\n\n- 📝 富文本编辑\n- 📁 文档分类管理\n- 🔍 全文搜索\n- 👥 协作编辑\n- 📊 版本控制\n- 🔒 权限管理\n\n## 快速开始\n\n1. 点击左侧菜单创建新文档\n2. 使用编辑器撰写内容\n3. 保存文档并分享给团队成员\n\n祝您使用愉快!"
document := model.Document{
ExternalID: utils.GenerateExternalID(utils.ExternalIDContextDocument),
Title: "欢迎使用 Yoresee Doc",
Type: "markdown",
Summary: "Yoresee Doc 系统欢迎文档",
ParentID: 0,
UserID: adminUser.ID,
Content: contentString,
Tags: []string{"guide", "welcome"},
ViewCount: 0,
EditCount: 0,
Path: "0",
Depth: 0,
}
if err := tx.Create(&document).Error; err != nil {
return err
}
if err := updateDocumentPathDepth(tx, document.ID, document.ParentID); err != nil {
return err
}
documentVersion := model.DocumentVersion{
DocumentID: document.ID,
Version: 1,
Title: document.Title,
Content: contentString,
UserID: adminUser.ID,
ChangeSummary: "Initial version",
}
if err := tx.Create(&documentVersion).Error; err != nil {
return err
}
logrus.Println("Adding child documents to welcome document...")
childDocumentTitles := []string{
"功能介绍",
"使用教程",
"常见问题",
"更新日志",
"联系我们",
}
for _, title := range childDocumentTitles {
childDoc, err := createDocumentWithAllTables(tx, adminUser.ID, DocumentInput{
Title: title,
Content: "# " + title + "\n\n这是" + title + "的详细文档内容。",
Summary: title + "相关文档",
ParentID: document.ID,
Tags: []string{"welcome", title},
KnowledgeID: nil,
})
if err != nil {
logrus.Warnf("Failed to create child document %s: %v", title, err)
continue
}
for k := 1; k <= 2; k++ {
grandchildTitle := title + " - 详情" + string(rune('0'+k))
_, err := createDocumentWithAllTables(tx, adminUser.ID, DocumentInput{
Title: grandchildTitle,
Content: "# " + grandchildTitle + "\n\n这是" + grandchildTitle + "的详细文档内容。",
Summary: grandchildTitle + "相关文档",
ParentID: childDoc.ID,
Tags: []string{"welcome", title, "详情"},
KnowledgeID: nil,
})
if err != nil {
logrus.Warnf("Failed to create grandchild document %s: %v", grandchildTitle, err)
}
}
}
logrus.Println("Child documents added to welcome document successfully")
logrus.Println("Default document created successfully in transaction")
return nil
}
func updateDocumentPathDepth(tx *gorm.DB, docID int64, parentID int64) error {
if parentID == 0 {
return tx.Exec(`
UPDATE document_metas
SET path = (id::text)::ltree, depth = 0
WHERE id = ?
`, docID).Error
}
type pathDepth struct {
Path string
Depth int
}
var parent pathDepth
if err := tx.Model(&model.Document{}).
Select("path, depth").
Where("id = ?", parentID).
Take(&parent).Error; err != nil {
return err
}
return tx.Exec(`
UPDATE document_metas
SET path = (?::ltree) || (id::text)::ltree, depth = ?
WHERE id = ?
`, parent.Path, parent.Depth+1, docID).Error
}
+117
View File
@@ -0,0 +1,117 @@
package main
import (
"github.com/XingfenD/yoresee_doc/internal/model"
"github.com/XingfenD/yoresee_doc/internal/utils"
"github.com/sirupsen/logrus"
"gorm.io/gorm"
)
func initializeKnowledgeBasesInTx(tx *gorm.DB) error {
logrus.Println("Initializing default knowledge bases in transaction...")
var adminUser model.User
if err := tx.Where("username = ?", "admin").First(&adminUser).Error; err != nil {
return err
}
var count int64
tx.Model(&model.KnowledgeBase{}).Where("name = ?", "默认知识库").Count(&count)
if count > 0 {
logrus.Println("Default knowledge base already exists in transaction.")
return nil
}
defaultKnowledgeBase := model.KnowledgeBase{
ExternalID: utils.GenerateExternalID(utils.ExternalIDKnowledgeBase),
Name: "默认知识库",
Description: "系统默认创建的知识库,用于存储常用文档和资料",
Cover: "",
CreatorUserID: adminUser.ID,
IsPublic: false,
}
if err := tx.Create(&defaultKnowledgeBase).Error; err != nil {
return err
}
exampleKnowledgeBase := model.KnowledgeBase{
ExternalID: utils.GenerateExternalID(utils.ExternalIDKnowledgeBase),
Name: "示例知识库",
Description: "示例知识库,展示知识库功能",
Cover: "",
CreatorUserID: adminUser.ID,
IsPublic: true,
}
if err := tx.Create(&exampleKnowledgeBase).Error; err != nil {
return err
}
logrus.Println("Adding documents to default knowledge base...")
rootDocumentTitles := []string{
"项目概述",
"系统架构",
"开发规范",
"API文档",
"数据库设计",
"前端开发",
"后端开发",
"测试计划",
"部署指南",
"安全规范",
"用户手册",
}
for _, title := range rootDocumentTitles {
rootDoc, err := createDocumentWithAllTables(tx, adminUser.ID, DocumentInput{
Title: title,
Content: "# " + title + "\n\n这是" + title + "的详细文档内容。",
Summary: title + "相关文档",
ParentID: 0,
Tags: []string{title},
KnowledgeID: &defaultKnowledgeBase.ID,
})
if err != nil {
logrus.Warnf("Failed to create root document %s: %v", title, err)
continue
}
for j := 1; j <= 3; j++ {
childTitle := title + " - 子文档" + string(rune('0'+j))
childDoc, err := createDocumentWithAllTables(tx, adminUser.ID, DocumentInput{
Title: childTitle,
Content: "# " + childTitle + "\n\n这是" + childTitle + "的详细文档内容。",
Summary: childTitle + "相关文档",
ParentID: rootDoc.ID,
Tags: []string{title, "子文档"},
KnowledgeID: &defaultKnowledgeBase.ID,
})
if err != nil {
logrus.Warnf("Failed to create child document %s: %v", childTitle, err)
continue
}
for k := 1; k <= 2; k++ {
grandchildTitle := childTitle + " - 孙文档" + string(rune('0'+k))
_, err := createDocumentWithAllTables(tx, adminUser.ID, DocumentInput{
Title: grandchildTitle,
Content: "# " + grandchildTitle + "\n\n这是" + grandchildTitle + "的详细文档内容。",
Summary: grandchildTitle + "相关文档",
ParentID: childDoc.ID,
Tags: []string{title, "子文档", "孙文档"},
KnowledgeID: &defaultKnowledgeBase.ID,
})
if err != nil {
logrus.Warnf("Failed to create grandchild document %s: %v", grandchildTitle, err)
}
}
}
}
logrus.Println("Documents added to default knowledge base successfully")
logrus.Println("Default knowledge bases created successfully in transaction")
return nil
}
+91
View File
@@ -0,0 +1,91 @@
package main
import (
"context"
"github.com/XingfenD/yoresee_doc/internal/bootstrap"
"github.com/XingfenD/yoresee_doc/internal/constant"
"github.com/XingfenD/yoresee_doc/internal/utils"
"github.com/XingfenD/yoresee_doc/pkg/storage"
"github.com/sirupsen/logrus"
"gorm.io/gorm"
)
func main() {
initializer := bootstrap.NewInitializer().
InitConfig().
InitPostgres().
InitConsul().
RequireConsulEnabled()
if err := initializer.Err(); err != nil {
logrus.Fatalf("Init db_init failed: %v", err)
}
defer initializer.Shutdown()
if isDatabaseInitialized() {
logrus.Println("Database already initialized, skipping initialization steps")
} else {
if err := initializeDatabaseInTransaction(); err != nil {
logrus.Fatalf("Database initialization failed: %v", err)
}
if err := initializeConfigInConsul(context.Background()); err != nil {
logrus.Fatalf("Consul config initialization failed: %v", err)
}
if err := markDatabaseInitializedInConsul(context.Background()); err != nil {
logrus.Fatalf("Mark database initialized failed: %v", err)
}
logrus.Println("Database initialized successfully")
}
logrus.Println("All initialization tasks completed successfully!")
}
func isDatabaseInitialized() bool {
value, ok, err := storage.Consul.Get(context.Background(), utils.GenConfigKey(
constant.ConfigKey_First_System,
constant.ConfigKey_Second_Database,
constant.ConfigKey_Third_Initialized,
))
if err != nil || !ok {
return false
}
return value == constant.Database_Initialized_True
}
func initializeDatabaseInTransaction() error {
return utils.WithTransaction(storage.DB, func(tx *gorm.DB) error {
if err := initializePermissionsInTx(tx); err != nil {
return err
}
if err := createAdminUserInTx(tx); err != nil {
return err
}
if err := createTestUserIntx(tx); err != nil {
return err
}
if err := initializeDocumentsInTx(tx); err != nil {
return err
}
if err := initializeKnowledgeBasesInTx(tx); err != nil {
return err
}
if err := initializeTemplatesInTx(tx); err != nil {
return err
}
if err := createNormalUserInTx(tx); err != nil {
return err
}
if err := initializeUserGroupsInTx(tx); err != nil {
return err
}
return nil
})
}
+57
View File
@@ -0,0 +1,57 @@
package main
import (
"strconv"
"github.com/XingfenD/yoresee_doc/internal/model"
"github.com/XingfenD/yoresee_doc/internal/utils"
"github.com/sirupsen/logrus"
"gorm.io/gorm"
)
func createTestUserIntx(tx *gorm.DB) error {
logrus.Println("Creating test user in transaction...")
return createUserWithUsername(tx, "test")
}
func createNormalUserInTx(tx *gorm.DB) error {
logrus.Println("Creating 100 users in transaction...")
for i := 1; i <= 20; i++ {
username := "user" + strconv.Itoa(i)
if err := createUserWithUsername(tx, username); err != nil {
return err
}
var user model.User
if err := tx.Where("username = ?", username).First(&user).Error; err != nil {
return err
}
userNum := strconv.Itoa(i)
logrus.Printf("User%s created successfully with ID: %s in transaction.\n", userNum, user.ExternalID)
logrus.Printf("Creating knowledge base for user%s...\n", userNum)
kbExternalID := utils.GenerateExternalID(utils.ExternalIDKnowledgeBase)
knowledgeBase := model.KnowledgeBase{
ExternalID: kbExternalID,
Name: "User" + userNum + "'s Knowledge Base",
Description: "Knowledge base created by user" + userNum,
CreatorUserID: user.ID,
IsPublic: false,
}
var kbCount int64
tx.Model(&model.KnowledgeBase{}).Where("name = ?", knowledgeBase.Name).Count(&kbCount)
if kbCount == 0 {
if err := tx.Create(&knowledgeBase).Error; err != nil {
return err
}
logrus.Printf("Knowledge base created successfully for user%s: %s\n", userNum, knowledgeBase.Name)
} else {
logrus.Printf("Knowledge base for user%s already exists.\n", userNum)
}
}
return nil
}
+22
View File
@@ -0,0 +1,22 @@
package main
import (
"gorm.io/gorm"
)
func initializePermissionsInTx(tx *gorm.DB) error {
// logrus.Println("Starting permission initialization in transaction...")
// adminSubject := model.Subject{
// ID: "1",
// Type: model.SubjectTypeUser,
// }
// if err := tx.Where("id = ?", adminSubject.ID).FirstOrCreate(&adminSubject).Error; err != nil {
// return err
// }
// logrus.Println("Admin subject created successfully in transaction.")
// logrus.Println("Permission initialization completed successfully in transaction.")
return nil
}
+141
View File
@@ -0,0 +1,141 @@
package main
import (
"github.com/XingfenD/yoresee_doc/internal/model"
"github.com/sirupsen/logrus"
"gorm.io/gorm"
)
type templateSeed struct {
Name string
Description string
Content string
Scope string
KnowledgeBaseID *int64
Tags []string
}
func initializeTemplatesInTx(tx *gorm.DB) error {
logrus.Println("Initializing default templates in transaction...")
var adminUser model.User
if err := tx.Where("username = ?", "admin").First(&adminUser).Error; err != nil {
return err
}
var defaultKB model.KnowledgeBase
if err := tx.Where("name = ?", "默认知识库").First(&defaultKB).Error; err != nil {
return err
}
seeds := []templateSeed{
{
Name: "个人周报模板",
Description: "用于个人每周工作复盘与计划",
Content: `# 个人周报
## 本周完成
-
## 问题与风险
-
## 下周计划
- `,
Scope: "private",
Tags: []string{"个人", "周报"},
},
{
Name: "会议纪要模板",
Description: "通用会议记录模板",
Content: `# 会议纪要
## 会议信息
- 时间:
- 参与人:
## 讨论内容
-
## 行动项
- [ ] `,
Scope: "private",
Tags: []string{"个人", "会议"},
},
{
Name: "需求评审模板",
Description: "知识库内需求评审记录模板",
KnowledgeBaseID: &defaultKB.ID,
Scope: "knowledge_base",
Content: `# 需求评审
## 背景
## 目标
## 方案评审
- 优点:
- 风险:
## 结论`,
Tags: []string{"知识库", "需求"},
},
{
Name: "技术方案模板",
Description: "知识库内技术方案沉淀模板",
KnowledgeBaseID: &defaultKB.ID,
Scope: "knowledge_base",
Content: `# 技术方案
## 问题定义
## 方案设计
## 数据模型
## 发布计划
`,
Tags: []string{"知识库", "技术"},
},
}
for _, seed := range seeds {
if err := createTemplateIfNotExists(tx, adminUser.ID, seed); err != nil {
return err
}
}
logrus.Println("Default templates initialized successfully in transaction")
return nil
}
func createTemplateIfNotExists(tx *gorm.DB, userID int64, seed templateSeed) error {
query := tx.Model(&model.Template{}).
Where("user_id = ? AND name = ? AND scope = ?", userID, seed.Name, seed.Scope)
if seed.KnowledgeBaseID == nil {
query = query.Where("knowledge_base_id IS NULL")
} else {
query = query.Where("knowledge_base_id = ?", *seed.KnowledgeBaseID)
}
var count int64
if err := query.Count(&count).Error; err != nil {
return err
}
if count > 0 {
return nil
}
template := model.Template{
Name: seed.Name,
Description: seed.Description,
DocumentType: model.DocumentType_Markdown,
Content: seed.Content,
UserID: userID,
Scope: seed.Scope,
KnowledgeBaseID: seed.KnowledgeBaseID,
IsPublic: false,
Tags: seed.Tags,
}
return tx.Create(&template).Error
}
+127
View File
@@ -0,0 +1,127 @@
package main
import (
"errors"
"strings"
"github.com/XingfenD/yoresee_doc/internal/model"
"github.com/XingfenD/yoresee_doc/internal/utils"
"github.com/sirupsen/logrus"
"gorm.io/gorm"
)
type seedUserGroup struct {
Name string
Description string
MemberUsers []string
}
func initializeUserGroupsInTx(tx *gorm.DB) error {
logrus.Println("Creating user groups in transaction...")
adminUser, err := getUserByUsername(tx, "admin")
if err != nil {
return err
}
user2, err := getUserByUsername(tx, "user2")
if err != nil {
return err
}
seedGroups := []seedUserGroup{
{
Name: "Admin Group",
Description: "Group for admin only",
MemberUsers: []string{"admin"},
},
{
Name: "User2 Group",
Description: "Group for user2 only",
MemberUsers: []string{"user2"},
},
{
Name: "Admin & User2 Group",
Description: "Group for admin and user2",
MemberUsers: []string{"admin", "user2"},
},
{
Name: "Empty Group",
Description: "Group with no members",
MemberUsers: []string{},
},
}
for _, seed := range seedGroups {
group, err := findOrCreateGroup(tx, seed.Name, seed.Description, adminUser.ID)
if err != nil {
return err
}
for _, username := range seed.MemberUsers {
var userID int64
switch username {
case "admin":
userID = adminUser.ID
case "user2":
userID = user2.ID
default:
continue
}
if err := ensureMembership(tx, group.ID, userID); err != nil {
return err
}
}
}
logrus.Println("User groups initialized successfully in transaction.")
return nil
}
func getUserByUsername(tx *gorm.DB, username string) (*model.User, error) {
var user model.User
if err := tx.Where("username = ?", username).First(&user).Error; err != nil {
return nil, err
}
return &user, nil
}
func findOrCreateGroup(tx *gorm.DB, name, description string, creatorID int64) (*model.UserGroupMeta, error) {
name = strings.TrimSpace(name)
if name == "" {
return nil, gorm.ErrInvalidValue
}
var group model.UserGroupMeta
if err := tx.Where("name = ?", name).First(&group).Error; err == nil {
return &group, nil
} else if !errors.Is(err, gorm.ErrRecordNotFound) {
return nil, err
}
group = model.UserGroupMeta{
ExternalID: utils.GenerateExternalID(utils.ExternalIDContextUserGroup),
Name: name,
Description: strings.TrimSpace(description),
CreatorID: creatorID,
}
if err := tx.Create(&group).Error; err != nil {
return nil, err
}
return &group, nil
}
func ensureMembership(tx *gorm.DB, groupID, userID int64) error {
var count int64
if err := tx.Model(&model.MembershipRelation{}).
Where("type = ? AND membership_id = ? AND user_id = ?", model.MembershipType_UserGroup, groupID, userID).
Count(&count).Error; err != nil {
return err
}
if count > 0 {
return nil
}
return tx.Create(&model.MembershipRelation{
Type: model.MembershipType_UserGroup,
MembershipID: groupID,
UserID: userID,
}).Error
}