feat(server/reward): GET /v1/invite — 邀请码/链接/战绩/TG 任务态
This commit is contained in:
@@ -0,0 +1,55 @@
|
||||
package reward
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"net/http"
|
||||
|
||||
"github.com/wangjia/pangolin/server/internal/apierr"
|
||||
"github.com/wangjia/pangolin/server/internal/auth"
|
||||
)
|
||||
|
||||
const inviteLinkBase = "https://pangolin.yanmeiai.com/i/"
|
||||
|
||||
type Handler struct {
|
||||
svc *Service
|
||||
st *Store
|
||||
tgEnabled bool
|
||||
channel string
|
||||
}
|
||||
|
||||
func NewHandler(s *Service, st *Store, tgEnabled bool, channel string) *Handler {
|
||||
return &Handler{svc: s, st: st, tgEnabled: tgEnabled, channel: channel}
|
||||
}
|
||||
|
||||
func (h *Handler) GetInvite(w http.ResponseWriter, r *http.Request) {
|
||||
ctx := r.Context()
|
||||
uid, ok := auth.UserIDFromContext(ctx)
|
||||
if !ok {
|
||||
apierr.WriteJSON(w, http.StatusUnauthorized, apierr.ErrUnauthorized)
|
||||
return
|
||||
}
|
||||
code, err := h.svc.EnsureCode(ctx, uid)
|
||||
if err != nil {
|
||||
apierr.WriteJSON(w, http.StatusInternalServerError, apierr.ErrInternal)
|
||||
return
|
||||
}
|
||||
invited, converted, earned, err := h.st.Summary(ctx, uid)
|
||||
if err != nil {
|
||||
apierr.WriteJSON(w, http.StatusInternalServerError, apierr.ErrInternal)
|
||||
return
|
||||
}
|
||||
joined, _ := h.st.TelegramClaimed(ctx, uid)
|
||||
w.Header().Set("Content-Type", "application/json; charset=utf-8")
|
||||
_ = json.NewEncoder(w).Encode(map[string]any{
|
||||
"invite_code": code,
|
||||
"invite_link": inviteLinkBase + code,
|
||||
"invited": invited,
|
||||
"converted": converted,
|
||||
"earned_days": earned,
|
||||
"telegram": map[string]any{
|
||||
"enabled": h.tgEnabled,
|
||||
"joined": joined,
|
||||
"channel": h.channel,
|
||||
},
|
||||
})
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
package reward
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/wangjia/pangolin/server/internal/codes"
|
||||
)
|
||||
|
||||
func TestGetInvite_ReturnsCodeAndSummary(t *testing.T) {
|
||||
db := openDB(t)
|
||||
seedU(t, db, 1, "u1")
|
||||
st := NewStore(db)
|
||||
g := codes.NewService(codes.NewStore(db), nil, 5, time.Hour)
|
||||
svc := NewService(db, st, g, Config{RegDays: 3, PaidDays: 7, TgDays: 3, RegMonthlyCap: 10}, time.Now)
|
||||
h := NewHandler(svc, st, true, "@pangolin_app")
|
||||
|
||||
r := httptest.NewRequest(http.MethodGet, "/v1/invite", nil)
|
||||
r = r.WithContext(context.WithValue(r.Context(), codes.CtxKeyUserID, int64(1)))
|
||||
w := httptest.NewRecorder()
|
||||
h.GetInvite(w, r) // 直接调 handler,不经 router
|
||||
|
||||
if w.Code != 200 {
|
||||
t.Fatalf("code=%d body=%s", w.Code, w.Body)
|
||||
}
|
||||
var got map[string]any
|
||||
json.Unmarshal(w.Body.Bytes(), &got)
|
||||
if got["invite_code"] == "" || got["invite_code"] == nil {
|
||||
t.Fatalf("no invite_code: %v", got)
|
||||
}
|
||||
tg, _ := got["telegram"].(map[string]any)
|
||||
if tg == nil || tg["enabled"] != true {
|
||||
t.Fatalf("telegram block wrong: %v", got["telegram"])
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user