mirror of
https://github.com/MHSanaei/3x-ui.git
synced 2026-08-16 16:20:59 +00:00
119 lines
3.1 KiB
Go
119 lines
3.1 KiB
Go
package sub
|
|
|
|
import (
|
|
"errors"
|
|
"net/url"
|
|
"strings"
|
|
|
|
"gorm.io/gorm"
|
|
|
|
"github.com/mhsanaei/3x-ui/v3/internal/database"
|
|
"github.com/mhsanaei/3x-ui/v3/internal/database/model"
|
|
"github.com/mhsanaei/3x-ui/v3/internal/logger"
|
|
)
|
|
|
|
type subPlaceholderData struct {
|
|
SubID string
|
|
Context remarkContext
|
|
HasCtx bool
|
|
Escape bool
|
|
}
|
|
|
|
type renderedSubMetadata struct {
|
|
Title string
|
|
SupportURL string
|
|
ProfileURL string
|
|
Announce string
|
|
}
|
|
|
|
func renderSubPlaceholders(value string, data subPlaceholderData) string {
|
|
if value == "" || !strings.Contains(value, "{") {
|
|
return value
|
|
}
|
|
|
|
ctx := data.Context
|
|
if !data.HasCtx {
|
|
ctx = remarkContext{
|
|
client: model.Client{
|
|
SubID: data.SubID,
|
|
},
|
|
}
|
|
}
|
|
if ctx.client.SubID == "" {
|
|
ctx.client.SubID = data.SubID
|
|
}
|
|
return strings.TrimSpace(expandSubMetadataVars(value, ctx, data.Escape))
|
|
}
|
|
|
|
var subMetadataTokens = map[string]bool{
|
|
"EMAIL": true,
|
|
"ID": true,
|
|
"SHORT_ID": true,
|
|
"TELEGRAM_ID": true,
|
|
"SUB_ID": true,
|
|
}
|
|
|
|
func expandSubMetadataVars(template string, ctx remarkContext, escape bool) string {
|
|
return remarkVarRe.ReplaceAllStringFunc(template, func(match string) string {
|
|
token := match[2 : len(match)-2]
|
|
if !subMetadataTokens[token] {
|
|
return match
|
|
}
|
|
value := remarkVarValue(token, ctx)
|
|
if escape {
|
|
return url.QueryEscape(value)
|
|
}
|
|
return value
|
|
})
|
|
}
|
|
|
|
func subMetadataUsesPlaceholders(values ...string) bool {
|
|
for _, value := range values {
|
|
if strings.Contains(value, "{") {
|
|
return true
|
|
}
|
|
}
|
|
return false
|
|
}
|
|
|
|
func (a *SUBController) metadataForSubRequest(getSubReq func() *SubService, subID string, fallbackProfileURL string) renderedSubMetadata {
|
|
var context remarkContext
|
|
var hasContext bool
|
|
if subMetadataUsesPlaceholders(a.subTitle, a.subSupportUrl, a.subProfileUrl, a.subAnnounce) {
|
|
var err error
|
|
subReq := getSubReq()
|
|
context, hasContext, err = subReq.subscriptionTemplateContextBySubID(subID)
|
|
if err != nil {
|
|
logger.Warning("sub: load template contexts for subscription metadata:", err)
|
|
}
|
|
}
|
|
profileURL := a.subProfileUrl
|
|
if profileURL == "" {
|
|
profileURL = fallbackProfileURL
|
|
} else {
|
|
profileURL = renderSubPlaceholders(profileURL, subPlaceholderData{SubID: subID, Context: context, HasCtx: hasContext, Escape: true})
|
|
}
|
|
data := subPlaceholderData{SubID: subID, Context: context, HasCtx: hasContext}
|
|
return renderedSubMetadata{
|
|
Title: renderSubPlaceholders(a.subTitle, data),
|
|
SupportURL: renderSubPlaceholders(a.subSupportUrl, subPlaceholderData{SubID: subID, Context: context, HasCtx: hasContext, Escape: true}),
|
|
ProfileURL: profileURL,
|
|
Announce: renderSubPlaceholders(a.subAnnounce, data),
|
|
}
|
|
}
|
|
|
|
func (s *SubService) subscriptionTemplateContextBySubID(subID string) (remarkContext, bool, error) {
|
|
if subID == "" {
|
|
return remarkContext{}, false, nil
|
|
}
|
|
var rec model.ClientRecord
|
|
err := database.GetDB().Where("sub_id = ?", subID).Order("id ASC").First(&rec).Error
|
|
if errors.Is(err, gorm.ErrRecordNotFound) {
|
|
return remarkContext{}, false, nil
|
|
}
|
|
if err != nil {
|
|
return remarkContext{}, false, err
|
|
}
|
|
return remarkContext{client: *rec.ToClient()}, true, nil
|
|
}
|