feat: 为应用版本查询增加appCode参数支持
新增应用版本类型的AppCode字段,修改相关接口和实现以支持通过appCode查询指定应用的最新版本,增加appCode合法性校验,完善缓存键以区分不同应用的版本信息
This commit is contained in:
@@ -276,8 +276,9 @@ func (c *adminInternalClient) TenantLoginIPWhitelist(id types.TenantID) (*tenant
|
|||||||
return &result, nil
|
return &result, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *adminInternalClient) LatestAppRelease(platform, channel string) (*types.AppRelease, error) {
|
func (c *adminInternalClient) LatestAppRelease(appCode, platform, channel string) (*types.AppRelease, error) {
|
||||||
query := url.Values{}
|
query := url.Values{}
|
||||||
|
query.Set("app_code", strings.ToLower(strings.TrimSpace(appCode)))
|
||||||
query.Set("platform", strings.ToLower(strings.TrimSpace(platform)))
|
query.Set("platform", strings.ToLower(strings.TrimSpace(platform)))
|
||||||
query.Set("channel", strings.ToLower(strings.TrimSpace(channel)))
|
query.Set("channel", strings.ToLower(strings.TrimSpace(channel)))
|
||||||
var dto struct {
|
var dto struct {
|
||||||
|
|||||||
+22
-1
@@ -2287,10 +2287,18 @@ func serveIMAppReleaseLatest(wrt http.ResponseWriter, req *http.Request) {
|
|||||||
}
|
}
|
||||||
platform := strings.ToLower(strings.TrimSpace(req.URL.Query().Get("platform")))
|
platform := strings.ToLower(strings.TrimSpace(req.URL.Query().Get("platform")))
|
||||||
channel := strings.ToLower(strings.TrimSpace(req.URL.Query().Get("channel")))
|
channel := strings.ToLower(strings.TrimSpace(req.URL.Query().Get("channel")))
|
||||||
|
appCode := strings.ToLower(strings.TrimSpace(req.URL.Query().Get("app_code")))
|
||||||
currentVersion := strings.TrimSpace(req.URL.Query().Get("current_version"))
|
currentVersion := strings.TrimSpace(req.URL.Query().Get("current_version"))
|
||||||
if channel == "" {
|
if channel == "" {
|
||||||
channel = "stable"
|
channel = "stable"
|
||||||
}
|
}
|
||||||
|
if appCode == "" {
|
||||||
|
appCode = "im"
|
||||||
|
}
|
||||||
|
if !isValidAppCode(appCode) {
|
||||||
|
writeIMError(wrt, req, http.StatusBadRequest, 30000, imReasonMalformedRequest, "malformed request", map[string]any{"field": "app_code"})
|
||||||
|
return
|
||||||
|
}
|
||||||
if platform != "ios" && platform != "android" && platform != "web" {
|
if platform != "ios" && platform != "android" && platform != "web" {
|
||||||
writeIMError(wrt, req, http.StatusBadRequest, 30000, imReasonMalformedRequest, "malformed request", map[string]any{"field": "platform"})
|
writeIMError(wrt, req, http.StatusBadRequest, 30000, imReasonMalformedRequest, "malformed request", map[string]any{"field": "platform"})
|
||||||
return
|
return
|
||||||
@@ -2300,7 +2308,7 @@ func serveIMAppReleaseLatest(wrt http.ResponseWriter, req *http.Request) {
|
|||||||
writeIMError(wrt, req, http.StatusBadRequest, 30000, imReasonMalformedRequest, "malformed request", map[string]any{"field": "current_version"})
|
writeIMError(wrt, req, http.StatusBadRequest, 30000, imReasonMalformedRequest, "malformed request", map[string]any{"field": "current_version"})
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
release, err := store.AppReleases.Latest(platform, channel)
|
release, err := store.AppReleases.Latest(appCode, platform, channel)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if platform == "web" {
|
if platform == "web" {
|
||||||
logs.Warn.Println("im app release latest: using web fallback", err)
|
logs.Warn.Println("im app release latest: using web fallback", err)
|
||||||
@@ -8782,6 +8790,19 @@ func appReleasePayload(release *types.AppRelease, currentVersion string, hasUpda
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func isValidAppCode(raw string) bool {
|
||||||
|
if raw == "" || len(raw) > 32 {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
for _, r := range raw {
|
||||||
|
if (r >= 'a' && r <= 'z') || (r >= '0' && r <= '9') || r == '-' || r == '_' {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
func parseNumericAppVersion(raw string) ([]uint64, error) {
|
func parseNumericAppVersion(raw string) ([]uint64, error) {
|
||||||
raw = strings.TrimPrefix(strings.ToLower(strings.TrimSpace(raw)), "v")
|
raw = strings.TrimPrefix(strings.ToLower(strings.TrimSpace(raw)), "v")
|
||||||
parts := strings.Split(raw, ".")
|
parts := strings.Split(raw, ".")
|
||||||
|
|||||||
@@ -171,7 +171,7 @@ type AdminInternalConfigProvider interface {
|
|||||||
ListActiveTenants(limit int) ([]types.Tenant, error)
|
ListActiveTenants(limit int) ([]types.Tenant, error)
|
||||||
RegistrationSMSEnabled() (bool, error)
|
RegistrationSMSEnabled() (bool, error)
|
||||||
ThirdPartyConfig(group string, keys ...string) (map[string]string, error)
|
ThirdPartyConfig(group string, keys ...string) (map[string]string, error)
|
||||||
LatestAppRelease(platform, channel string) (*types.AppRelease, error)
|
LatestAppRelease(appCode, platform, channel string) (*types.AppRelease, error)
|
||||||
ModerationProvider() (*types.ModerationProviderConfig, error)
|
ModerationProvider() (*types.ModerationProviderConfig, error)
|
||||||
ModerationPolicy(tenantCode string) (*types.ModerationPolicy, error)
|
ModerationPolicy(tenantCode string) (*types.ModerationPolicy, error)
|
||||||
SensitiveWords(tenantCode string) (*types.SensitiveWordSet, error)
|
SensitiveWords(tenantCode string) (*types.SensitiveWordSet, error)
|
||||||
@@ -2654,20 +2654,21 @@ type profileMapper struct{}
|
|||||||
var Profiles ProfilePersistenceInterface
|
var Profiles ProfilePersistenceInterface
|
||||||
|
|
||||||
type AppReleasePersistenceInterface interface {
|
type AppReleasePersistenceInterface interface {
|
||||||
Latest(platform, channel string) (*types.AppRelease, error)
|
Latest(appCode, platform, channel string) (*types.AppRelease, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
type appReleaseMapper struct{}
|
type appReleaseMapper struct{}
|
||||||
|
|
||||||
var AppReleases AppReleasePersistenceInterface
|
var AppReleases AppReleasePersistenceInterface
|
||||||
|
|
||||||
func (appReleaseMapper) Latest(platform, channel string) (*types.AppRelease, error) {
|
func (appReleaseMapper) Latest(appCode, platform, channel string) (*types.AppRelease, error) {
|
||||||
platform = strings.ToLower(strings.TrimSpace(platform))
|
platform = strings.ToLower(strings.TrimSpace(platform))
|
||||||
channel = strings.ToLower(strings.TrimSpace(channel))
|
channel = strings.ToLower(strings.TrimSpace(channel))
|
||||||
if platform == "" || channel == "" {
|
appCode = strings.ToLower(strings.TrimSpace(appCode))
|
||||||
|
if platform == "" || channel == "" || appCode == "" {
|
||||||
return nil, types.ErrMalformed
|
return nil, types.ErrMalformed
|
||||||
}
|
}
|
||||||
cacheKey := platform + ":" + channel
|
cacheKey := appCode + ":" + platform + ":" + channel
|
||||||
if cached, ok := appReleaseConfigCache.get(cacheKey); ok {
|
if cached, ok := appReleaseConfigCache.get(cacheKey); ok {
|
||||||
copy := *cached
|
copy := *cached
|
||||||
return ©, nil
|
return ©, nil
|
||||||
@@ -2675,7 +2676,7 @@ func (appReleaseMapper) Latest(platform, channel string) (*types.AppRelease, err
|
|||||||
if adminInternalConfigProvider == nil {
|
if adminInternalConfigProvider == nil {
|
||||||
return nil, types.ErrUnsupported
|
return nil, types.ErrUnsupported
|
||||||
}
|
}
|
||||||
release, err := adminInternalConfigProvider.LatestAppRelease(platform, channel)
|
release, err := adminInternalConfigProvider.LatestAppRelease(appCode, platform, channel)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -56,6 +56,7 @@ type UserPrivacyPatch struct {
|
|||||||
|
|
||||||
type AppRelease struct {
|
type AppRelease struct {
|
||||||
ID int64
|
ID int64
|
||||||
|
AppCode string
|
||||||
Platform string
|
Platform string
|
||||||
Channel string
|
Channel string
|
||||||
LatestVersion string
|
LatestVersion string
|
||||||
|
|||||||
Reference in New Issue
Block a user