thread-master/backend/internal/bootstrap/init.go

133 lines
5.1 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 bootstrap
import (
"context"
"fmt"
"haixun-backend/internal/config"
libcrypto "haixun-backend/internal/library/crypto"
libmongo "haixun-backend/internal/library/mongo"
brandrepo "haixun-backend/internal/model/brand/repository"
cmatrixrepo "haixun-backend/internal/model/content_matrix/repository"
copydraftrepo "haixun-backend/internal/model/copy_draft/repository"
copymissionrepo "haixun-backend/internal/model/copy_mission/repository"
jobrepo "haixun-backend/internal/model/job/repository"
kgrepo "haixun-backend/internal/model/knowledge_graph/repository"
memberrepo "haixun-backend/internal/model/member/repository"
outreachdraftrepo "haixun-backend/internal/model/outreach_draft/repository"
permissionrepo "haixun-backend/internal/model/permission/repository"
permissionuc "haixun-backend/internal/model/permission/usecase"
personarepo "haixun-backend/internal/model/persona/repository"
placementtopicrepo "haixun-backend/internal/model/placement_topic/repository"
scanpostrepo "haixun-backend/internal/model/scan_post/repository"
settingrepo "haixun-backend/internal/model/setting/repository"
threadsaccountrepo "haixun-backend/internal/model/threads_account/repository"
)
type InitOptions struct {
TenantID string
AdminEmail string
AdminPass string
DisplayName string
}
type InitReport struct {
IndexesEnsured bool
PermissionsSeeded bool
RolePermissionsSeeded bool
AdminUID string
AdminCreated bool
}
func Init(ctx context.Context, cfg config.Config, opts InitOptions) (*InitReport, error) {
if cfg.Mongo.URI == "" || cfg.Mongo.Database == "" {
return nil, fmt.Errorf("mongo URI and database are required")
}
if opts.TenantID == "" {
return nil, fmt.Errorf("tenant_id is required")
}
if opts.AdminEmail == "" || opts.AdminPass == "" {
return nil, fmt.Errorf("admin email and password are required")
}
mongoClient, err := libmongo.NewClient(ctx, cfg.Mongo)
if err != nil {
return nil, fmt.Errorf("connect mongo: %w", err)
}
defer func() { _ = mongoClient.Close(ctx) }()
db := mongoClient.Database()
report := &InitReport{}
// cipher 只用於資料加解密EnsureIndexes 不會用到,但 secrets repo 建構子需要它。
secretsCipher, err := libcrypto.New(cfg.Secrets.EncryptionKey)
if err != nil {
return nil, fmt.Errorf("init secrets cipher: %w", err)
}
settingRepository := settingrepo.NewMongoRepository(db)
memberRepository := memberrepo.NewMongoRepository(db)
permissionRepository := permissionrepo.NewMongoPermissionRepository(db)
rolePermissionRepository := permissionrepo.NewMongoRolePermissionRepository(db)
jobTemplateRepository := jobrepo.NewMongoTemplateRepository(db)
jobRunRepository := jobrepo.NewMongoRunRepository(db)
jobScheduleRepository := jobrepo.NewMongoScheduleRepository(db)
jobEventRepository := jobrepo.NewMongoEventRepository(db)
repos := []struct {
name string
fn func(context.Context) error
}{
{"settings", settingRepository.EnsureIndexes},
{"members", memberRepository.EnsureIndexes},
{"permissions", permissionRepository.EnsureIndexes},
{"role_permissions", rolePermissionRepository.EnsureIndexes},
{"job_templates", jobTemplateRepository.EnsureIndexes},
{"job_runs", jobRunRepository.EnsureIndexes},
{"job_schedules", jobScheduleRepository.EnsureIndexes},
{"job_events", jobEventRepository.EnsureIndexes},
{"copy_missions", copymissionrepo.NewMongoRepository(db).EnsureIndexes},
{"copy_drafts", copydraftrepo.NewMongoRepository(db).EnsureIndexes},
{"scan_posts", scanpostrepo.NewMongoRepository(db).EnsureIndexes},
{"outreach_drafts", outreachdraftrepo.NewMongoRepository(db).EnsureIndexes},
{"content_matrix", cmatrixrepo.NewMongoRepository(db).EnsureIndexes},
{"knowledge_graph", kgrepo.NewMongoRepository(db).EnsureIndexes},
{"personas", personarepo.NewMongoRepository(db).EnsureIndexes},
{"brands", brandrepo.NewMongoRepository(db).EnsureIndexes},
{"placement_topics", placementtopicrepo.NewMongoRepository(db).EnsureIndexes},
{"threads_accounts", threadsaccountrepo.NewMongoRepository(db).EnsureIndexes},
{"threads_account_secrets", threadsaccountrepo.NewSecretsMongoRepository(db, secretsCipher).EnsureIndexes},
}
for _, repo := range repos {
if err := repo.fn(ctx); err != nil {
return nil, fmt.Errorf("ensure %s indexes: %w", repo.name, err)
}
}
report.IndexesEnsured = true
permissionUseCase := permissionuc.NewUseCase(permissionRepository, rolePermissionRepository)
if err := permissionUseCase.EnsureDefaultPermissions(ctx); err != nil {
return nil, fmt.Errorf("seed permissions catalog: %w", err)
}
report.PermissionsSeeded = true
if err := permissionUseCase.EnsureDefaultRolePermissions(ctx, opts.TenantID); err != nil {
return nil, fmt.Errorf("seed role permissions: %w", err)
}
report.RolePermissionsSeeded = true
admin, created, err := EnsureAdminMember(ctx, memberRepository, AdminOptions{
TenantID: opts.TenantID,
Email: opts.AdminEmail,
Password: opts.AdminPass,
DisplayName: opts.DisplayName,
})
if err != nil {
return nil, err
}
report.AdminUID = admin.UID
report.AdminCreated = created
return report, nil
}