Files
nl-blogs/server/repositories/about_repository.go
2026-01-19 13:53:32 +08:00

316 lines
9.7 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 repositories
import (
"encoding/json"
"log"
"strconv"
"strings"
"time"
"github.com/niangaodev/art-code/config"
"github.com/niangaodev/art-code/models"
"gorm.io/gorm"
)
// unescapeJSONString 解码转义的 JSON 字符串
// 处理两种情况:
// 1. 被引号包裹的转义 JSON 字符串:`"[\"Vue 3\",...]"`
// 2. 包含转义引号的 JSON 字符串:`[\"Vue 3\",...]`
func unescapeJSONString(s string) (string, error) {
// 如果字符串以引号开头和结尾,说明是被引号包裹的转义 JSON 字符串
if len(s) >= 2 && s[0] == '"' && s[len(s)-1] == '"' {
unquoted, err := strconv.Unquote(s)
if err != nil {
return s, err
}
return unquoted, nil
}
// 如果字符串包含转义的引号 \",需要将其转换为普通引号
// 例如:[\"Vue 3\",...] -> ["Vue 3",...]
if len(s) > 0 {
// 尝试直接解析,如果失败则尝试替换转义引号
var test interface{}
if err := json.Unmarshal([]byte(s), &test); err != nil {
// 如果解析失败,尝试将 \" 替换为 "
unescaped := s
// 替换转义的反斜杠+引号
// 注意:这里需要小心处理,因为 \\" 应该变成 \"
// 但 \" 应该变成 "
// 使用正则表达式或字符串替换
// 简单方法:将 \" 替换为 "(但需要确保不会误替换 \\"
// 更安全的方法:使用 json.Unmarshal 两次解析
// 或者使用 strings.ReplaceAll 但需要小心
// 尝试将 \" 替换为 "
unescaped = strings.ReplaceAll(unescaped, `\"`, `"`)
// 如果替换后能解析,返回替换后的字符串
if err2 := json.Unmarshal([]byte(unescaped), &test); err2 == nil {
return unescaped, nil
}
} else {
// 如果能直接解析,返回原字符串
return s, nil
}
}
// 如果都失败,返回原字符串
return s, nil
}
// GetPrimaryAboutProfile 获取主页个人资料
func GetPrimaryAboutProfile() (*models.AboutProfile, error) {
var profile models.AboutProfile
err := config.DB.Model(&models.AboutProfile{}).
Where("is_primary = ? AND deleted_at = ?", true, 0).
First(&profile).Error
if err != nil {
if err == gorm.ErrRecordNotFound {
// If no primary profile, try to get the first one
return GetFirstAboutProfile()
}
log.Printf("Error getting primary about profile: %v", err)
return nil, err
}
// Unmarshal JSON - 确保 TechList 和 ExperienceList 始终是数组而不是 nil
profile.TechList = []string{}
profile.ExperienceList = []models.Experience{}
if profile.TechStack != "" {
if err := json.Unmarshal([]byte(profile.TechStack), &profile.TechList); err != nil {
log.Printf("Error unmarshaling techStack: %v, raw: %s", err, profile.TechStack)
profile.TechList = []string{}
}
}
if profile.ExperiencesStr != "" {
if err := json.Unmarshal([]byte(profile.ExperiencesStr), &profile.ExperienceList); err != nil {
log.Printf("Error unmarshaling experiences: %v, raw: %s", err, profile.ExperiencesStr)
profile.ExperienceList = []models.Experience{}
}
}
return &profile, nil
}
// GetFirstAboutProfile 获取第一个个人资料(备用)
func GetFirstAboutProfile() (*models.AboutProfile, error) {
var profile models.AboutProfile
err := config.DB.Model(&models.AboutProfile{}).
Where("deleted_at = ?", 0).
Order("id ASC").
First(&profile).Error
if err != nil {
if err == gorm.ErrRecordNotFound {
return nil, nil
}
log.Printf("Error getting first about profile: %v", err)
return nil, err
}
// Unmarshal JSON - 确保 TechList 和 ExperienceList 始终是数组而不是 nil
profile.TechList = []string{}
profile.ExperienceList = []models.Experience{}
if profile.TechStack != "" {
// 先尝试解码转义的 JSON 字符串
unescaped, err := unescapeJSONString(profile.TechStack)
if err != nil {
log.Printf("Error unescaping techStack: %v, raw: %s", err, profile.TechStack)
} else {
if err := json.Unmarshal([]byte(unescaped), &profile.TechList); err != nil {
log.Printf("Error unmarshaling techStack: %v, raw: %s, unescaped: %s", err, profile.TechStack, unescaped)
profile.TechList = []string{}
}
}
}
if profile.ExperiencesStr != "" {
// 先尝试解码转义的 JSON 字符串
unescaped, err := unescapeJSONString(profile.ExperiencesStr)
if err != nil {
log.Printf("Error unescaping experiences: %v, raw: %s", err, profile.ExperiencesStr)
} else {
if err := json.Unmarshal([]byte(unescaped), &profile.ExperienceList); err != nil {
log.Printf("Error unmarshaling experiences: %v, raw: %s, unescaped: %s", err, profile.ExperiencesStr, unescaped)
profile.ExperienceList = []models.Experience{}
}
}
}
return &profile, nil
}
// GetAboutProfileByID 根据 ID 获取个人资料
func GetAboutProfileByID(id uint) (*models.AboutProfile, error) {
var profile models.AboutProfile
err := config.DB.Model(&models.AboutProfile{}).
Where("id = ? AND deleted_at = ?", id, 0).
First(&profile).Error
if err != nil {
if err == gorm.ErrRecordNotFound {
return nil, nil
}
log.Printf("Error getting about profile by ID: %v", err)
return nil, err
}
// Unmarshal JSON - 确保 TechList 和 ExperienceList 始终是数组而不是 nil
profile.TechList = []string{}
profile.ExperienceList = []models.Experience{}
if profile.TechStack != "" {
// 先尝试解码转义的 JSON 字符串
unescaped, err := unescapeJSONString(profile.TechStack)
if err != nil {
log.Printf("Error unescaping techStack: %v, raw: %s", err, profile.TechStack)
} else {
if err := json.Unmarshal([]byte(unescaped), &profile.TechList); err != nil {
log.Printf("Error unmarshaling techStack: %v, raw: %s, unescaped: %s", err, profile.TechStack, unescaped)
profile.TechList = []string{}
}
}
}
if profile.ExperiencesStr != "" {
// 先尝试解码转义的 JSON 字符串
unescaped, err := unescapeJSONString(profile.ExperiencesStr)
if err != nil {
log.Printf("Error unescaping experiences: %v, raw: %s", err, profile.ExperiencesStr)
} else {
if err := json.Unmarshal([]byte(unescaped), &profile.ExperienceList); err != nil {
log.Printf("Error unmarshaling experiences: %v, raw: %s, unescaped: %s", err, profile.ExperiencesStr, unescaped)
profile.ExperienceList = []models.Experience{}
}
}
}
return &profile, nil
}
// GetAllAboutProfiles 获取所有个人资料(管理用)
func GetAllAboutProfiles() ([]models.AboutProfile, error) {
var profiles []models.AboutProfile
err := config.DB.Model(&models.AboutProfile{}).
Where("deleted_at = ?", 0).
Find(&profiles).Error
if err != nil {
log.Printf("Error querying about profiles: %v", err)
return nil, err
}
for i := range profiles {
var p = &profiles[i]
// Unmarshal JSON - 确保 TechList 和 ExperienceList 始终是数组而不是 nil
p.TechList = []string{}
p.ExperienceList = []models.Experience{}
if p.TechStack != "" {
// 先尝试解码转义的 JSON 字符串
unescaped, err := unescapeJSONString(p.TechStack)
if err != nil {
log.Printf("Error unescaping techStack: %v, raw: %s", err, p.TechStack)
} else {
if err := json.Unmarshal([]byte(unescaped), &p.TechList); err != nil {
log.Printf("Error unmarshaling techStack: %v, raw: %s, unescaped: %s", err, p.TechStack, unescaped)
p.TechList = []string{}
}
}
}
if p.ExperiencesStr != "" {
// 先尝试解码转义的 JSON 字符串
unescaped, err := unescapeJSONString(p.ExperiencesStr)
if err != nil {
log.Printf("Error unescaping experiences: %v, raw: %s", err, p.ExperiencesStr)
} else {
if err := json.Unmarshal([]byte(unescaped), &p.ExperienceList); err != nil {
log.Printf("Error unmarshaling experiences: %v, raw: %s, unescaped: %s", err, p.ExperiencesStr, unescaped)
p.ExperienceList = []models.Experience{}
}
}
}
}
return profiles, nil
}
// CreateAboutProfile 创建个人资料
func CreateAboutProfile(profile *models.AboutProfile) error {
// 确保 TechList 和 ExperienceList 不为 nil
if profile.TechList == nil {
profile.TechList = []string{}
}
if profile.ExperienceList == nil {
profile.ExperienceList = []models.Experience{}
}
// Marshal JSON
techBytes, _ := json.Marshal(profile.TechList)
profile.TechStack = string(techBytes)
expBytes, _ := json.Marshal(profile.ExperienceList)
profile.ExperiencesStr = string(expBytes)
err := config.DB.Create(profile).Error
if err != nil {
log.Printf("Error creating about profile: %v", err)
return err
}
return nil
}
// UpdateAboutProfile 更新个人资料
func UpdateAboutProfile(profile *models.AboutProfile) error {
// 确保 TechList 和 ExperienceList 不为 nil
if profile.TechList == nil {
profile.TechList = []string{}
}
if profile.ExperienceList == nil {
profile.ExperienceList = []models.Experience{}
}
// Marshal JSON
techBytes, _ := json.Marshal(profile.TechList)
profile.TechStack = string(techBytes)
expBytes, _ := json.Marshal(profile.ExperienceList)
profile.ExperiencesStr = string(expBytes)
err := config.DB.Model(&models.AboutProfile{}).
Where("id = ? AND deleted_at = ?", profile.ID, 0).
Updates(map[string]interface{}{
"name": profile.Name,
"avatar": profile.Avatar,
"location": profile.Location,
"bio": profile.Bio,
"email": profile.Email,
"wechat": profile.Wechat,
"tech_stack": profile.TechStack,
"experiences": profile.ExperiencesStr,
"is_primary": profile.IsPrimary,
"updated_at": time.Now().Unix(),
}).Error
if err != nil {
log.Printf("Error updating about profile: %v", err)
return err
}
return nil
}
// DeleteAboutProfile 删除个人资料 (Soft Delete)
func DeleteAboutProfile(id uint) error {
err := config.DB.Model(&models.AboutProfile{}).
Where("id = ?", id).
Update("deleted_at", time.Now().Unix()).Error
if err != nil {
log.Printf("Error deleting about profile: %v", err)
return err
}
return nil
}