更新
This commit is contained in:
@@ -4,6 +4,8 @@ import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"photowall/internal/model"
|
||||
"regexp"
|
||||
"strings"
|
||||
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
@@ -30,32 +32,176 @@ func (s *UserService) GetProfile(userID uint) (*ProfileResp, error) {
|
||||
}
|
||||
var contacts []model.UserContact
|
||||
s.db.Where("user_id = ?", userID).Order("type, is_primary desc, id").Find(&contacts)
|
||||
|
||||
// 融合基本资料与联系方式:若 contacts 中缺少基本资料中的 phone/email/address,补齐展示
|
||||
hasPhone := false
|
||||
hasEmail := false
|
||||
hasAddress := false
|
||||
for _, c := range contacts {
|
||||
if c.Type == model.ContactPhone {
|
||||
hasPhone = true
|
||||
}
|
||||
if c.Type == model.ContactEmail {
|
||||
hasEmail = true
|
||||
}
|
||||
if c.Type == model.ContactAddress {
|
||||
hasAddress = true
|
||||
}
|
||||
}
|
||||
if !hasPhone && user.Phone != "" {
|
||||
contacts = append(contacts, model.UserContact{
|
||||
UserID: userID,
|
||||
Type: model.ContactPhone,
|
||||
Value: user.Phone,
|
||||
IsPrimary: true,
|
||||
})
|
||||
}
|
||||
if !hasEmail && user.Email != "" {
|
||||
contacts = append(contacts, model.UserContact{
|
||||
UserID: userID,
|
||||
Type: model.ContactEmail,
|
||||
Value: user.Email,
|
||||
IsPrimary: true,
|
||||
})
|
||||
}
|
||||
if !hasAddress && user.Address != "" {
|
||||
contacts = append(contacts, model.UserContact{
|
||||
UserID: userID,
|
||||
Type: model.ContactAddress,
|
||||
Value: user.Address,
|
||||
IsPrimary: true,
|
||||
})
|
||||
}
|
||||
|
||||
var edu []model.EducationHistory
|
||||
s.db.Where("user_id = ?", userID).Order("start_year desc, id desc").Find(&edu)
|
||||
return &ProfileResp{User: user, Contacts: contacts, Education: edu}, nil
|
||||
}
|
||||
|
||||
// IsValidIDCard 校验中国大陆18位二代居民身份证合法性
|
||||
func IsValidIDCard(idCard string) bool {
|
||||
idCard = strings.ToUpper(strings.TrimSpace(idCard))
|
||||
if len(idCard) != 18 {
|
||||
return false
|
||||
}
|
||||
// 正则粗筛:前17位数字,第18位数字或字母X
|
||||
matched, _ := regexp.MatchString(`^[1-9]\d{5}(18|19|20)\d{2}(0[1-9]|1[0-2])(0[1-9]|[12]\d|3[01])\d{3}[0-9X]$`, idCard)
|
||||
if !matched {
|
||||
return false
|
||||
}
|
||||
// ISO 7064:1983.MOD 11-2 校验码加权
|
||||
weights := []int{7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2}
|
||||
checkCodes := []byte{'1', '0', 'X', '9', '8', '7', '6', '5', '4', '3', '2'}
|
||||
sum := 0
|
||||
for i := 0; i < 17; i++ {
|
||||
sum += int(idCard[i]-'0') * weights[i]
|
||||
}
|
||||
expectedCheck := checkCodes[sum%11]
|
||||
return idCard[17] == expectedCheck
|
||||
}
|
||||
|
||||
type UpdateProfileReq struct {
|
||||
Nickname string `json:"nickname"`
|
||||
Bio string `json:"bio"`
|
||||
Avatar string `json:"avatar"`
|
||||
RealName string `json:"real_name"`
|
||||
Gender string `json:"gender"`
|
||||
Nation string `json:"nation"`
|
||||
PoliticalStatus string `json:"political_status"`
|
||||
IdCard string `json:"id_card"`
|
||||
Address string `json:"address"`
|
||||
Phone string `json:"phone"`
|
||||
Nickname string `json:"nickname"`
|
||||
Email string `json:"email"`
|
||||
Bio string `json:"bio"`
|
||||
Avatar string `json:"avatar"`
|
||||
}
|
||||
|
||||
func (s *UserService) UpdateProfile(userID uint, req *UpdateProfileReq) error {
|
||||
updates := map[string]interface{}{}
|
||||
updates["real_name"] = strings.TrimSpace(req.RealName)
|
||||
updates["gender"] = strings.TrimSpace(req.Gender)
|
||||
updates["nation"] = strings.TrimSpace(req.Nation)
|
||||
updates["political_status"] = strings.TrimSpace(req.PoliticalStatus)
|
||||
|
||||
idCard := strings.ToUpper(strings.TrimSpace(req.IdCard))
|
||||
if idCard != "" && !strings.Contains(idCard, "*") {
|
||||
if !IsValidIDCard(idCard) {
|
||||
return errors.New("身份证号码格式不正确,请输入18位有效居民身份证号")
|
||||
}
|
||||
updates["id_card"] = idCard
|
||||
} else if idCard == "" {
|
||||
updates["id_card"] = ""
|
||||
}
|
||||
|
||||
address := strings.TrimSpace(req.Address)
|
||||
updates["address"] = address
|
||||
phone := strings.TrimSpace(req.Phone)
|
||||
updates["phone"] = phone
|
||||
|
||||
if req.Nickname != "" {
|
||||
updates["nickname"] = req.Nickname
|
||||
updates["nickname"] = strings.TrimSpace(req.Nickname)
|
||||
}
|
||||
if req.Bio != "" {
|
||||
updates["bio"] = req.Bio
|
||||
email := strings.TrimSpace(req.Email)
|
||||
if email != "" {
|
||||
updates["email"] = email
|
||||
}
|
||||
if req.Avatar != "" {
|
||||
updates["avatar"] = req.Avatar
|
||||
updates["bio"] = req.Bio
|
||||
updates["avatar"] = strings.TrimSpace(req.Avatar)
|
||||
|
||||
if err := s.db.Model(&model.User{}).Where("id = ?", userID).Updates(updates).Error; err != nil {
|
||||
return err
|
||||
}
|
||||
if len(updates) == 0 {
|
||||
return nil
|
||||
|
||||
// 融合基本资料与联系方式:同步手机号、邮箱、住址到联系方式表
|
||||
if phone != "" {
|
||||
var primaryPhone model.UserContact
|
||||
if err := s.db.Where("user_id = ? AND type = ? AND is_primary = ?", userID, model.ContactPhone, true).First(&primaryPhone).Error; err == nil {
|
||||
s.db.Model(&primaryPhone).Update("value", phone)
|
||||
} else {
|
||||
var anyPhone model.UserContact
|
||||
if err := s.db.Where("user_id = ? AND type = ?", userID, model.ContactPhone).First(&anyPhone).Error; err == nil {
|
||||
s.db.Model(&anyPhone).Updates(map[string]interface{}{"value": phone, "is_primary": true})
|
||||
} else {
|
||||
s.db.Create(&model.UserContact{
|
||||
UserID: userID,
|
||||
Type: model.ContactPhone,
|
||||
Value: phone,
|
||||
IsPrimary: true,
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
return s.db.Model(&model.User{}).Where("id = ?", userID).Updates(updates).Error
|
||||
if email != "" {
|
||||
var primaryEmail model.UserContact
|
||||
if err := s.db.Where("user_id = ? AND type = ? AND is_primary = ?", userID, model.ContactEmail, true).First(&primaryEmail).Error; err == nil {
|
||||
s.db.Model(&primaryEmail).Update("value", email)
|
||||
} else {
|
||||
var anyEmail model.UserContact
|
||||
if err := s.db.Where("user_id = ? AND type = ?", userID, model.ContactEmail).First(&anyEmail).Error; err == nil {
|
||||
s.db.Model(&anyEmail).Updates(map[string]interface{}{"value": email, "is_primary": true})
|
||||
} else {
|
||||
s.db.Create(&model.UserContact{
|
||||
UserID: userID,
|
||||
Type: model.ContactEmail,
|
||||
Value: email,
|
||||
IsPrimary: true,
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
if address != "" {
|
||||
var anyAddr model.UserContact
|
||||
if err := s.db.Where("user_id = ? AND type = ?", userID, model.ContactAddress).First(&anyAddr).Error; err == nil {
|
||||
s.db.Model(&anyAddr).Updates(map[string]interface{}{"value": address, "is_primary": true})
|
||||
} else {
|
||||
s.db.Create(&model.UserContact{
|
||||
UserID: userID,
|
||||
Type: model.ContactAddress,
|
||||
Value: address,
|
||||
IsPrimary: true,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// AddContact 添加联系方式,校验各类型数量上限
|
||||
@@ -85,6 +231,19 @@ func (s *UserService) AddContact(userID uint, contactType model.ContactType, val
|
||||
if err := s.db.Create(c).Error; err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// 融合基本资料与联系方式:若设为主要联系方式或为首个联系方式,同步回写到 User 表中
|
||||
if isPrimary || count == 0 {
|
||||
switch contactType {
|
||||
case model.ContactPhone:
|
||||
s.db.Model(&model.User{}).Where("id = ?", userID).Update("phone", value)
|
||||
case model.ContactEmail:
|
||||
s.db.Model(&model.User{}).Where("id = ?", userID).Update("email", value)
|
||||
case model.ContactAddress:
|
||||
s.db.Model(&model.User{}).Where("id = ?", userID).Update("address", value)
|
||||
}
|
||||
}
|
||||
|
||||
return c, nil
|
||||
}
|
||||
|
||||
@@ -99,11 +258,24 @@ func (s *UserService) UpdateContact(userID, contactID uint, value string, isPrim
|
||||
if isPrimary != nil && *isPrimary {
|
||||
s.db.Model(&model.UserContact{}).Where("user_id = ? AND type = ?", userID, c.Type).Update("is_primary", false)
|
||||
c.IsPrimary = true
|
||||
// 同步回写至 User 表
|
||||
switch c.Type {
|
||||
case model.ContactPhone:
|
||||
s.db.Model(&model.User{}).Where("id = ?", userID).Update("phone", c.Value)
|
||||
case model.ContactEmail:
|
||||
s.db.Model(&model.User{}).Where("id = ?", userID).Update("email", c.Value)
|
||||
case model.ContactAddress:
|
||||
s.db.Model(&model.User{}).Where("id = ?", userID).Update("address", c.Value)
|
||||
}
|
||||
}
|
||||
return s.db.Save(&c).Error
|
||||
}
|
||||
|
||||
func (s *UserService) DeleteContact(userID, contactID uint) error {
|
||||
var c model.UserContact
|
||||
if err := s.db.Where("id = ? AND user_id = ?", contactID, userID).First(&c).Error; err != nil {
|
||||
return errors.New("联系方式不存在")
|
||||
}
|
||||
res := s.db.Where("id = ? AND user_id = ?", contactID, userID).Delete(&model.UserContact{})
|
||||
if res.Error != nil {
|
||||
return res.Error
|
||||
@@ -111,6 +283,35 @@ func (s *UserService) DeleteContact(userID, contactID uint) error {
|
||||
if res.RowsAffected == 0 {
|
||||
return errors.New("联系方式不存在")
|
||||
}
|
||||
|
||||
// 若删除的是主联系方式,同步 User 表中对应信息
|
||||
switch c.Type {
|
||||
case model.ContactPhone:
|
||||
var nextPhone model.UserContact
|
||||
if err := s.db.Where("user_id = ? AND type = ?", userID, model.ContactPhone).Order("is_primary desc, id").First(&nextPhone).Error; err == nil {
|
||||
s.db.Model(&nextPhone).Update("is_primary", true)
|
||||
s.db.Model(&model.User{}).Where("id = ?", userID).Update("phone", nextPhone.Value)
|
||||
} else {
|
||||
s.db.Model(&model.User{}).Where("id = ?", userID).Update("phone", "")
|
||||
}
|
||||
case model.ContactEmail:
|
||||
var nextEmail model.UserContact
|
||||
if err := s.db.Where("user_id = ? AND type = ?", userID, model.ContactEmail).Order("is_primary desc, id").First(&nextEmail).Error; err == nil {
|
||||
s.db.Model(&nextEmail).Update("is_primary", true)
|
||||
s.db.Model(&model.User{}).Where("id = ?", userID).Update("email", nextEmail.Value)
|
||||
} else {
|
||||
s.db.Model(&model.User{}).Where("id = ?", userID).Update("email", "")
|
||||
}
|
||||
case model.ContactAddress:
|
||||
var nextAddr model.UserContact
|
||||
if err := s.db.Where("user_id = ? AND type = ?", userID, model.ContactAddress).Order("is_primary desc, id").First(&nextAddr).Error; err == nil {
|
||||
s.db.Model(&nextAddr).Update("is_primary", true)
|
||||
s.db.Model(&model.User{}).Where("id = ?", userID).Update("address", nextAddr.Value)
|
||||
} else {
|
||||
s.db.Model(&model.User{}).Where("id = ?", userID).Update("address", "")
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -175,6 +376,32 @@ func (s *UserService) GetUserByID(userID uint) (*model.User, error) {
|
||||
// GetUserContacts 公开用户联系方式(同班同学可查看)
|
||||
func (s *UserService) GetUserContacts(userID uint) []model.UserContact {
|
||||
var list []model.UserContact
|
||||
s.db.Where("user_id = ?", userID).Order("type, is_primary desc").Find(&list)
|
||||
s.db.Where("user_id = ?", userID).Order("type, is_primary desc, id").Find(&list)
|
||||
var u model.User
|
||||
if s.db.Select("id, phone, email, address").First(&u, userID).Error == nil {
|
||||
hasPhone := false
|
||||
hasEmail := false
|
||||
hasAddress := false
|
||||
for _, c := range list {
|
||||
if c.Type == model.ContactPhone {
|
||||
hasPhone = true
|
||||
}
|
||||
if c.Type == model.ContactEmail {
|
||||
hasEmail = true
|
||||
}
|
||||
if c.Type == model.ContactAddress {
|
||||
hasAddress = true
|
||||
}
|
||||
}
|
||||
if !hasPhone && u.Phone != "" {
|
||||
list = append(list, model.UserContact{UserID: userID, Type: model.ContactPhone, Value: u.Phone, IsPrimary: true})
|
||||
}
|
||||
if !hasEmail && u.Email != "" {
|
||||
list = append(list, model.UserContact{UserID: userID, Type: model.ContactEmail, Value: u.Email, IsPrimary: true})
|
||||
}
|
||||
if !hasAddress && u.Address != "" {
|
||||
list = append(list, model.UserContact{UserID: userID, Type: model.ContactAddress, Value: u.Address, IsPrimary: true})
|
||||
}
|
||||
}
|
||||
return list
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user