feat(contact): 添加联系信息提交功能
Build docker and publish / build (20.15.1) (push) Successful in 5m55s

实现联系信息提交功能,包括:
1. 新增ContactRequest类型定义
2. 添加POST /contact路由
3. 实现联系信息提交处理逻辑
4. 通过Telegram发送联系信息通知
5. 在Telegram配置中添加GroupChatID字段
This commit is contained in:
2025-12-21 19:32:23 -08:00
parent 2fdc9c8127
commit 74f4a12422
8 changed files with 207 additions and 12 deletions
+80 -6
View File
@@ -2,9 +2,14 @@ package notify
import (
"context"
"encoding/json"
"strconv"
"strings"
iapmodel "github.com/perfect-panel/server/internal/model/iap/apple"
"github.com/perfect-panel/server/internal/model/subscribe"
"github.com/perfect-panel/server/internal/svc"
"github.com/perfect-panel/server/internal/types"
iapapple "github.com/perfect-panel/server/pkg/iap/apple"
"github.com/perfect-panel/server/pkg/logger"
"gorm.io/gorm"
@@ -82,10 +87,79 @@ func (l *AppleIAPNotifyLogic) Handle(signedPayload string) error {
}
}
}
pm, _ := iapapple.ParseProductMap(l.svcCtx.Config.Site.CustomData)
m := pm.Items[txPayload.ProductId]
// 若产品映射缺失,记录警告日志(不影响事务入库)
if m.DurationDays == 0 {
var days int64
{
pid := strings.ToLower(txPayload.ProductId)
parts := strings.Split(pid, ".")
for i := len(parts) - 1; i >= 0; i-- {
p := parts[i]
var unit string
if strings.HasPrefix(p, "day") {
unit = "Day"
p = p[len("day"):]
} else if strings.HasPrefix(p, "month") {
unit = "Month"
p = p[len("month"):]
} else if strings.HasPrefix(p, "year") {
unit = "Year"
p = p[len("year"):]
}
if unit != "" {
digits := p
for j := 0; j < len(digits); j++ {
if digits[j] < '0' || digits[j] > '9' {
digits = digits[:j]
break
}
}
if q, e := strconv.ParseInt(digits, 10, 64); e == nil && q > 0 {
switch unit {
case "Day":
days = q
case "Month":
days = q * 30
case "Year":
days = q * 365
}
break
}
}
}
}
if days == 0 {
_, subs, e := l.svcCtx.SubscribeModel.FilterList(l.ctx, &subscribe.FilterParams{
Page: 1,
Size: 9999,
Show: true,
Sell: true,
DefaultLanguage: true,
})
if e == nil && len(subs) > 0 {
for _, item := range subs {
var discounts []types.SubscribeDiscount
if item.Discount != "" {
_ = json.Unmarshal([]byte(item.Discount), &discounts)
}
for _, d := range discounts {
if strings.Contains(strings.ToLower(txPayload.ProductId), strings.ToLower(item.UnitTime)) && d.Quantity > 0 {
// fallback not strict
if item.UnitTime == "Day" {
days = int64(d.Quantity)
} else if item.UnitTime == "Month" {
days = int64(d.Quantity) * 30
} else if item.UnitTime == "Year" {
days = int64(d.Quantity) * 365
}
break
}
}
if days > 0 {
break
}
}
}
}
if days == 0 {
l.Errorw("iap notify product mapping missing", logger.Field("productId", txPayload.ProductId))
}
token := "iap:" + txPayload.OriginalTransactionId
@@ -97,9 +171,9 @@ func (l *AppleIAPNotifyLogic) Handle(signedPayload string) error {
t := *txPayload.RevocationDate
sub.FinishedAt = &t
sub.ExpireTime = t
} else if m.DurationDays > 0 {
} else if days > 0 {
// 正常:根据映射天数续期
exp := iapapple.CalcExpire(txPayload.PurchaseDate, m.DurationDays)
exp := iapapple.CalcExpire(txPayload.PurchaseDate, days)
sub.ExpireTime = exp
sub.Status = 1
}