182 lines
5.0 KiB
Go
182 lines
5.0 KiB
Go
// Package gueststore 游客(免登录模块)通用存储。
|
|
//
|
|
// 一条业务条目 = yz_guest_data 一行 JSON 文档,按 guest_id + module 隔离;
|
|
// 删除只做软删(is_deleted=1)永久保留,合并进正式账号后置 is_deleted=2。
|
|
// 业务控制器通过 identity.IsGuest 分流到这里,响应结构与登录态接口保持一致。
|
|
package gueststore
|
|
|
|
import (
|
|
"encoding/json"
|
|
"errors"
|
|
"strings"
|
|
"time"
|
|
|
|
"server/models"
|
|
|
|
"github.com/beego/beego/v2/client/orm"
|
|
)
|
|
|
|
// ErrNotFound 条目不存在(或不属于该游客 / 已被删除)。
|
|
var ErrNotFound = errors.New("记录不存在")
|
|
|
|
// Row 一条游客数据文档(对外统一用表 ID 作为条目 ID,payload 内的 id 仅冗余)。
|
|
type Row struct {
|
|
ID uint64
|
|
Payload json.RawMessage
|
|
CreateTime time.Time
|
|
UpdateTime *time.Time
|
|
}
|
|
|
|
// Upsert 按手机号定位/创建游客身份,并刷新 openid / 活跃时间。
|
|
// 已合并(merged_uid>0)的旧记录会被复位为新的游客周期:
|
|
// 历史数据行在合并时已置 is_deleted=2,不会再次出现在列表里。
|
|
func Upsert(phone, openid, unionid string) (*models.GuestUser, error) {
|
|
phone = strings.TrimSpace(phone)
|
|
if phone == "" {
|
|
return nil, errors.New("手机号不能为空")
|
|
}
|
|
now := time.Now()
|
|
|
|
var row models.GuestUser
|
|
err := models.Orm.QueryTable(new(models.GuestUser)).Filter("phone", phone).One(&row)
|
|
if err == orm.ErrNoRows {
|
|
row = models.GuestUser{Phone: phone, OpenID: openid, UnionID: unionid, LastActiveTime: &now}
|
|
id, ierr := models.Orm.Insert(&row)
|
|
if ierr != nil {
|
|
return nil, ierr
|
|
}
|
|
row.ID = uint64(id)
|
|
return &row, nil
|
|
}
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
upd := map[string]interface{}{"last_active_time": now}
|
|
if openid != "" {
|
|
upd["openid"] = openid
|
|
}
|
|
if unionid != "" {
|
|
upd["unionid"] = unionid
|
|
}
|
|
if row.MergedUID > 0 {
|
|
// 复位游客周期,允许同一手机号再次以游客身份产生新数据
|
|
upd["merged_uid"] = uint64(0)
|
|
upd["merged_time"] = nil
|
|
row.MergedUID = 0
|
|
}
|
|
if _, err = models.Orm.QueryTable(new(models.GuestUser)).Filter("id", row.ID).Update(upd); err != nil {
|
|
return nil, err
|
|
}
|
|
row.LastActiveTime = &now
|
|
return &row, nil
|
|
}
|
|
|
|
// Insert 写入一条业务条目,返回行 ID(即条目 ID)。
|
|
func Insert(guestID uint64, module string, payload interface{}) (uint64, error) {
|
|
b, err := json.Marshal(payload)
|
|
if err != nil {
|
|
return 0, err
|
|
}
|
|
now := time.Now()
|
|
id, err := models.Orm.Insert(&models.GuestData{
|
|
GuestID: guestID,
|
|
Module: module,
|
|
Payload: string(b),
|
|
CreateTime: now,
|
|
UpdateTime: &now,
|
|
})
|
|
if err != nil {
|
|
return 0, err
|
|
}
|
|
return uint64(id), nil
|
|
}
|
|
|
|
// Get 读取单条(限本游客 + 本模块 + 未删除)。
|
|
func Get(guestID uint64, module string, id uint64) (Row, error) {
|
|
var d models.GuestData
|
|
err := models.Orm.QueryTable(new(models.GuestData)).
|
|
Filter("id", id).
|
|
Filter("guest_id", guestID).
|
|
Filter("module", module).
|
|
Filter("is_deleted", 0).
|
|
One(&d)
|
|
if err == orm.ErrNoRows {
|
|
return Row{}, ErrNotFound
|
|
}
|
|
if err != nil {
|
|
return Row{}, err
|
|
}
|
|
return toRow(d), nil
|
|
}
|
|
|
|
// List 列出某游客某模块的全部有效条目(新→旧)。
|
|
func List(guestID uint64, module string) ([]Row, error) {
|
|
var rows []models.GuestData
|
|
_, err := models.Orm.QueryTable(new(models.GuestData)).
|
|
Filter("guest_id", guestID).
|
|
Filter("module", module).
|
|
Filter("is_deleted", 0).
|
|
OrderBy("-id").
|
|
All(&rows)
|
|
if err != nil && err != orm.ErrNoRows {
|
|
return nil, err
|
|
}
|
|
out := make([]Row, 0, len(rows))
|
|
for _, d := range rows {
|
|
out = append(out, toRow(d))
|
|
}
|
|
return out, nil
|
|
}
|
|
|
|
// Update 覆盖一条条目的 payload。
|
|
func Update(guestID uint64, module string, id uint64, payload interface{}) error {
|
|
b, err := json.Marshal(payload)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
n, err := models.Orm.QueryTable(new(models.GuestData)).
|
|
Filter("id", id).
|
|
Filter("guest_id", guestID).
|
|
Filter("module", module).
|
|
Filter("is_deleted", 0).
|
|
Update(map[string]interface{}{"payload": string(b), "update_time": time.Now()})
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if n == 0 {
|
|
return ErrNotFound
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// Delete 软删除一条条目(保留数据行,永久不清理)。
|
|
func Delete(guestID uint64, module string, id uint64) error {
|
|
n, err := models.Orm.QueryTable(new(models.GuestData)).
|
|
Filter("id", id).
|
|
Filter("guest_id", guestID).
|
|
Filter("module", module).
|
|
Filter("is_deleted", 0).
|
|
Update(map[string]interface{}{"is_deleted": 1, "update_time": time.Now()})
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if n == 0 {
|
|
return ErrNotFound
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// MarkMerged 游客转正后:该游客全部有效数据行置 is_deleted=2(保留行本身)。
|
|
func MarkMerged(guestID uint64) error {
|
|
_, err := models.Orm.QueryTable(new(models.GuestData)).
|
|
Filter("guest_id", guestID).
|
|
Filter("is_deleted", 0).
|
|
Update(map[string]interface{}{"is_deleted": 2, "update_time": time.Now()})
|
|
return err
|
|
}
|
|
|
|
func toRow(d models.GuestData) Row {
|
|
return Row{ID: d.ID, Payload: json.RawMessage(d.Payload), CreateTime: d.CreateTime, UpdateTime: d.UpdateTime}
|
|
}
|