148 lines
4.7 KiB
Go
148 lines
4.7 KiB
Go
package handler
|
|
|
|
import (
|
|
"fmt"
|
|
|
|
"past/internal/httpapi"
|
|
"past/internal/store"
|
|
)
|
|
|
|
// 绑定前的姨姨记录可能双方都有。只允许一份成为情侣的当前记录;
|
|
// 在用户选择前保留两份,选择时在同一事务中删除另一份并迁入当前情侣空间。
|
|
func periodSourceState(c *httpapi.Ctx) (required bool, me, partner int64, err error) {
|
|
cid, uid := c.CoupleID(), c.UID()
|
|
if cid == 0 {
|
|
return false, uid, 0, nil
|
|
}
|
|
couple, err := c.DB.QueryOne("SELECT user1_id, user2_id, period_source_user_id FROM couples WHERE id = ?", cid)
|
|
if err != nil || couple == nil {
|
|
return false, 0, 0, err
|
|
}
|
|
if couple.Int("user1_id") == uid {
|
|
partner = couple.Int("user2_id")
|
|
} else if couple.Int("user2_id") == uid {
|
|
partner = couple.Int("user1_id")
|
|
} else {
|
|
return false, 0, 0, fmt.Errorf("账号不属于当前情侣")
|
|
}
|
|
if couple.Int("period_source_user_id") != 0 {
|
|
return false, uid, partner, nil
|
|
}
|
|
myCount, err := periodSourceCount(c.DB, uid)
|
|
if err != nil {
|
|
return false, 0, 0, err
|
|
}
|
|
partnerCount, err := periodSourceCount(c.DB, partner)
|
|
if err != nil {
|
|
return false, 0, 0, err
|
|
}
|
|
if myCount > 0 && partnerCount > 0 {
|
|
return true, uid, partner, nil
|
|
}
|
|
if myCount > 0 {
|
|
err = selectPeriodSource(c, uid)
|
|
} else if partnerCount > 0 {
|
|
err = selectPeriodSource(c, partner)
|
|
}
|
|
return false, uid, partner, err
|
|
}
|
|
|
|
func periodSourceCount(db store.Querier, uid int64) (int64, error) {
|
|
row, err := db.QueryOne(`SELECT
|
|
(SELECT COUNT(*) FROM period_records WHERE user_id = ? AND couple_id IS NULL) +
|
|
(SELECT COUNT(*) FROM period_daily_records WHERE user_id = ? AND couple_id IS NULL) +
|
|
(SELECT COUNT(*) FROM period_sex_records WHERE user_id = ? AND couple_id IS NULL) AS n`,
|
|
uid, uid, uid)
|
|
if err != nil {
|
|
return 0, err
|
|
}
|
|
return row.Int("n"), nil
|
|
}
|
|
|
|
func periodSourcePreview(db store.Querier, uid int64) (M, error) {
|
|
row, err := db.QueryOne("SELECT COUNT(*) AS cycles, MAX(start_date) AS latest FROM period_records WHERE user_id = ? AND couple_id IS NULL", uid)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
total, err := periodSourceCount(db, uid)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return M{"cycles": row.Int("cycles"), "latest": row.Str("latest"), "items": total}, nil
|
|
}
|
|
|
|
func selectPeriodSource(c *httpapi.Ctx, keepUserID int64) error {
|
|
cid := c.CoupleID()
|
|
if cid == 0 {
|
|
return c.Err(400, "未绑定伴侣")
|
|
}
|
|
tx, err := c.DB.Begin()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
defer tx.Rollback()
|
|
couple, err := tx.QueryOne("SELECT user1_id, user2_id, period_source_user_id FROM couples WHERE id = ? FOR UPDATE", cid)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if couple == nil || (keepUserID != couple.Int("user1_id") && keepUserID != couple.Int("user2_id")) {
|
|
return c.Err(400, "记录来源不是当前情侣成员")
|
|
}
|
|
if existing := couple.Int("period_source_user_id"); existing != 0 {
|
|
if existing == keepUserID {
|
|
return nil
|
|
}
|
|
return c.Err(409, "姨姨记录来源已经选定")
|
|
}
|
|
deleteUserID := couple.Int("user1_id")
|
|
if deleteUserID == keepUserID {
|
|
deleteUserID = couple.Int("user2_id")
|
|
}
|
|
for _, table := range []string{"period_records", "period_daily_records", "period_sex_records"} {
|
|
if _, err := tx.Exec("DELETE FROM "+table+" WHERE user_id = ? AND couple_id IS NULL", deleteUserID); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
// daily 的旧 NULL 记录可能有重复日期,逐条迁入以避免情侣日期唯一索引冲突。
|
|
daily, err := tx.Query("SELECT id, record_date FROM period_daily_records WHERE user_id = ? AND couple_id IS NULL ORDER BY id DESC FOR UPDATE", keepUserID)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
for _, record := range daily {
|
|
existing, err := tx.QueryOne("SELECT id FROM period_daily_records WHERE couple_id = ? AND record_date = ? LIMIT 1", cid, record["record_date"])
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if existing != nil {
|
|
if _, err := tx.Exec("DELETE FROM period_daily_records WHERE id = ?", record.Int("id")); err != nil {
|
|
return err
|
|
}
|
|
} else if _, err := tx.Exec("UPDATE period_daily_records SET couple_id = ? WHERE id = ?", cid, record.Int("id")); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
for _, table := range []string{"period_records", "period_sex_records"} {
|
|
if _, err := tx.Exec("UPDATE "+table+" SET couple_id = ? WHERE user_id = ? AND couple_id IS NULL", cid, keepUserID); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
if _, err := tx.Exec("UPDATE couples SET period_source_user_id = ? WHERE id = ?", keepUserID, cid); err != nil {
|
|
return err
|
|
}
|
|
return tx.Commit()
|
|
}
|
|
|
|
func periodSourceSelect(c *httpapi.Ctx) error {
|
|
if err := c.RequirePOST(); err != nil {
|
|
return err
|
|
}
|
|
if err := requirePeriodAccess(c); err != nil {
|
|
return err
|
|
}
|
|
keepUserID := c.InInt("user_id")
|
|
if err := selectPeriodSource(c, keepUserID); err != nil {
|
|
return err
|
|
}
|
|
return c.OK(M{"success": true, "source_user_id": keepUserID})
|
|
}
|