@@ -0,0 +1,93 @@
|
||||
package rechargeser
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
"unicode/utf8"
|
||||
|
||||
"91porn-server/models/commod"
|
||||
"91porn-server/models/v/vipcardexperimentmod"
|
||||
|
||||
"go.mongodb.org/mongo-driver/bson/primitive"
|
||||
)
|
||||
|
||||
const maxAttributionValueLength = 128
|
||||
|
||||
func (r *RechargeRequest) normalizeAttribution() {
|
||||
r.SourcePage = NormalizeOrderSourcePage(r.SourcePage)
|
||||
r.SourceRef = strings.TrimSpace(r.SourceRef)
|
||||
r.VideoID = strings.TrimSpace(r.VideoID)
|
||||
r.ActivityID = strings.TrimSpace(r.ActivityID)
|
||||
r.ExperimentID = strings.TrimSpace(r.ExperimentID)
|
||||
r.ExperimentVariant = strings.ToUpper(strings.TrimSpace(r.ExperimentVariant))
|
||||
r.SessionID = strings.TrimSpace(r.SessionID)
|
||||
r.CheckoutContextID = strings.TrimSpace(r.CheckoutContextID)
|
||||
}
|
||||
|
||||
func (r *RechargeRequest) validateAttribution(uid uint64) error {
|
||||
r.normalizeAttribution()
|
||||
if utf8.RuneCountInString(r.SourcePage) > maxAttributionValueLength {
|
||||
return fmt.Errorf("sourcePage must not exceed %d characters", maxAttributionValueLength)
|
||||
}
|
||||
if r.SourcePage == OrderSourcePageDramaPaywall {
|
||||
if r.BuyType != commod.BuyGold && r.BuyType != commod.BuyProduct {
|
||||
return fmt.Errorf("buyType must be 1 or 4 for DRAMA_PAYWALL")
|
||||
}
|
||||
// sourceRef is the generic order attribution field. For drama paywall
|
||||
// orders, derive it from the backend-issued checkout context instead of
|
||||
// requiring clients to submit the same identifier twice. The remaining
|
||||
// drama fields are attribution-only and must not block a real payment.
|
||||
if len(r.CheckoutContextID) > maxAttributionValueLength {
|
||||
r.CheckoutContextID = ""
|
||||
}
|
||||
r.SourceRef = r.CheckoutContextID
|
||||
}
|
||||
values := map[string]string{
|
||||
"sourceRef": r.SourceRef,
|
||||
"videoId": r.VideoID,
|
||||
"activityId": r.ActivityID,
|
||||
"experimentId": r.ExperimentID,
|
||||
"experimentVariant": r.ExperimentVariant,
|
||||
"sessionId": r.SessionID,
|
||||
"checkoutContextId": r.CheckoutContextID,
|
||||
}
|
||||
for name, value := range values {
|
||||
if len(value) > maxAttributionValueLength {
|
||||
return fmt.Errorf("%s must not exceed %d characters", name, maxAttributionValueLength)
|
||||
}
|
||||
}
|
||||
if r.ExperimentID == "" {
|
||||
r.ExperimentVariant = ""
|
||||
return nil
|
||||
}
|
||||
if r.ExperimentVariant == "" || r.SessionID == "" {
|
||||
return fmt.Errorf("experimentVariant and sessionId are required with experimentId")
|
||||
}
|
||||
experiment, err := vipcardexperimentmod.FindByExperimentID(r.ExperimentID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if experiment == nil {
|
||||
return fmt.Errorf("experiment does not exist")
|
||||
}
|
||||
config, ok := experiment.ConfigFor(r.ExperimentVariant)
|
||||
if !ok {
|
||||
return fmt.Errorf("experimentVariant must be A or B")
|
||||
}
|
||||
if assigned := experiment.Assign(uid); assigned != r.ExperimentVariant {
|
||||
return fmt.Errorf("experimentVariant does not match user assignment")
|
||||
}
|
||||
if !containsObjectID(config.ProductIDs, r.ProductID) {
|
||||
return fmt.Errorf("productID does not belong to experiment variant")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func containsObjectID(ids []primitive.ObjectID, target primitive.ObjectID) bool {
|
||||
for _, id := range ids {
|
||||
if id == target {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
Reference in New Issue
Block a user