dengbiao 1 settimana fa
parent
commit
4ef4df8681
8 ha cambiato i file con 5136 aggiunte e 32 eliminazioni
  1. +42
    -30
      app/lib/youlianghui/api.go
  2. +84
    -0
      app/lib/youlianghui/curl.go
  3. +2
    -2
      app/lib/youlianghui/md/api_md.go
  4. +38
    -0
      app/mw/mw_swag_auth.go
  5. +13
    -0
      app/router/router.go
  6. +14
    -0
      app/svc/svc_auth.go
  7. +4816
    -0
      docs/open.json
  8. +127
    -0
      generate_swagger.sh

+ 42
- 30
app/lib/youlianghui/api.go Vedi File

@@ -2,12 +2,14 @@ package youlianghui

import (
"applet/app/cfg"
"applet/app/lib/youlianghui/md"
)

type ApiService struct {
MemberId string `json:"member_id"`
Secret string `json:"secret"`
Host string `json:"host"`
MemberId string `json:"member_id"`
Secret string `json:"secret"`
Host string `json:"host"`
Header map[string]string `json:"header"`
}

func NewApiService(memberId, secret string) (apiService ApiService, err error) { // set方法
@@ -17,34 +19,44 @@ func NewApiService(memberId, secret string) (apiService ApiService, err error) {
if cfg.Prd {
apiService.Host = "http://api.adnet.qq.com/open/v1.1"
}

apiService.Header = make(map[string]string)
apiService.Header["Content-Type"] = "multipart/form-data"
apiService.Header["token"] = GetToken(apiService.MemberId, apiService.Secret)
return
}

// MediumAdd 创建媒体
// func (apiService *ApiService) MediumAdd() (appId string, err error) { // set方法
// token := GetToken(apiService.MemberId, apiService.Secret)
// url := apiService.Host + "/medium/add"
// params := map[string]interface{}{
// "name": name,
// "type": string(adunitType),
// }
// if adunitType == enum.AdunitTypeForVideoFeeds {
// params["video_duration_min"] = 6
// params["video_duration_max"] = 60
// }
// postBody, err := utils.CurlPost(url, utils.SerializeStr(params), nil)
// if err != nil {
// return
// }
// var resp md.AgencyCreateAdunit
// err = json.Unmarshal(postBody, &resp)
// if err != nil {
// return
// }
// if resp.Ret != 0 {
// err = errors.New(resp.ErrMsg)
// }
// adUnitId = resp.AdUnitId
// return
// }
func (apiService *ApiService) MediumAdd(req md.MediumAdd) (appId string, err error) { // set方法
url := apiService.Host + "/medium/add"
if req.Affiliation == "" {
req.Affiliation = "Agency" // Own:应用开发者、Agency:应用发行/代理方
}
params := map[string]string{
"member_id": apiService.MemberId,
"medium_name": req.MediumName,
"industry_id_v2": req.IndustryIdV2,
"os": req.Os,
"affiliation": req.Affiliation,
"package_name": req.PackageName,
"full_package_name": req.FullPackageName,
"wechat_app_id": req.WechatAppId,
"package_name_wx_appid_rel": req.PackageNameWxAppidRel,
"wechat_universal_link": req.WechatUniversalLink,
}

postBody, err := MultipartFormDataRequest(url, params, nil, apiService.Header)
if err != nil {
return "", err
}

var resp md.AgencyCreateAdunit
err = json.Unmarshal(postBody, &resp)
if err != nil {
return
}
if resp.Ret != 0 {
err = errors.New(resp.ErrMsg)
}
adUnitId = resp.AdUnitId
return
}

+ 84
- 0
app/lib/youlianghui/curl.go Vedi File

@@ -0,0 +1,84 @@
package youlianghui

import (
"bytes"
"fmt"
"io"
"io/ioutil"
"mime/multipart"
"net/http"
"os"
)

// MultipartFormDataRequest 封装 multipart/form-data 请求
func MultipartFormDataRequest(url string, fields map[string]string, files map[string]string, headers map[string]string) ([]byte, error) {
// 创建一个缓冲区来存储表单数据
var b bytes.Buffer
w := multipart.NewWriter(&b)

// 添加文本字段
for key, value := range fields {
if err := addFormValue(w, key, value); err != nil {
return nil, err
}
}

// 添加文件字段
for fieldName, filePath := range files {
file, err := os.Open(filePath)
if err != nil {
return nil, fmt.Errorf("error opening file %s: %v", filePath, err)
}
defer file.Close()

part, err := w.CreateFormFile(fieldName, filePath)
if err != nil {
return nil, fmt.Errorf("error creating form file %s: %v", fieldName, err)
}

if _, err := io.Copy(part, file); err != nil {
return nil, fmt.Errorf("error copying file %s to part: %v", filePath, err)
}
}

// 完成多部分表单
if err := w.Close(); err != nil {
return nil, fmt.Errorf("error closing multipart writer: %v", err)
}

// 创建请求
req, err := http.NewRequest("POST", url, &b)
if err != nil {
return nil, fmt.Errorf("error creating request: %v", err)
}

// 设置头部
req.Header.Set("Content-Type", w.FormDataContentType())
for key, value := range headers {
req.Header.Set(key, value)
}

// 发送请求
client := &http.Client{}
resp, err := client.Do(req)
if err != nil {
return nil, fmt.Errorf("error sending request: %v", err)
}
defer resp.Body.Close()
body, err := ioutil.ReadAll(resp.Body) // 读取响应
if err != nil {
return nil, err
}

return body, nil
}

// addFormValue 辅助函数:添加表单值
func addFormValue(w *multipart.Writer, key, value string) error {
fw, err := w.CreateFormField(key)
if err != nil {
return fmt.Errorf("error creating form field %s: %v", key, err)
}
_, err = fw.Write([]byte(value))
return err
}

+ 2
- 2
app/lib/youlianghui/md/api_md.go Vedi File

@@ -2,8 +2,8 @@ package md

type MediumAdd struct {
MediumName string `json:"medium_name" example:"媒体名字"`
IndustryIdV2 int `json:"industry_id_v2" example:"媒体所属新3级行业id"`
Os int `json:"os" example:"操作系统,数字含义1-Android, 2-iOS"`
IndustryIdV2 string `json:"industry_id_v2" example:"媒体所属新3级行业id"`
Os string `json:"os" example:"操作系统,数字含义1-Android, 2-iOS"`
DetailUrl string `json:"detail_url" example:"详情页url(支持的各个商店域名约束)"`
Affiliation string `json:"affiliation" example:"媒体隶属关系"`
PackageName string `json:"package_name" example:"主程序包名"`


+ 38
- 0
app/mw/mw_swag_auth.go Vedi File

@@ -0,0 +1,38 @@
package mw

import "github.com/gin-gonic/gin"

//func SwagAuth(c *gin.Context) {
// // 这里的 "user" 和 "password" 是示例,需要替换为实际的用户名和密码
// username := c.Query("user")
// password := c.Query("password")
//
// // 验证用户名和密码
// if username != "micro_group" || password != "123456" {
// //e.OutErr(c, e.ERR_UNAUTHORIZED, "Unauthorized!")
// //return
// c.AbortWithStatusJSON(401, gin.H{"error": "Unauthorized"})
// return
// }
//
// // 如果密码正确,则继续执行后续的处理函数
// c.Next()
//}

// @summary 用于密码验证的中间件
func SwagAuth() gin.HandlerFunc {
return func(c *gin.Context) {
// 这里的 "user" 和 "password" 是示例,需要替换为实际的用户名和密码
username := c.Query("user")
password := c.Query("password")

// 验证用户名和密码
if username != "admin" || password != "secret" {
c.AbortWithStatusJSON(401, gin.H{"error": "Unauthorized"})
return
}

// 如果密码正确,则继续执行后续的处理函数
c.Next()
}
}

+ 13
- 0
app/router/router.go Vedi File

@@ -25,6 +25,19 @@ func Init() *gin.Engine {
ginSwagger.DisablingWrapHandler(swaggerFiles.Handler, "SWAGGER")(c)
})

// TODO::指定open的文档的位置
// 设置静态文件服务,提供 group2.json 文件
r.Static("/api-docs", "./docs")
r.GET("/open/swagger/*any", gin.BasicAuth(gin.Accounts{
"zhiYin": "123456",
}), func(c *gin.Context) {
requestTls := "http://"
if c.Request.TLS != nil {
requestTls = "https://"
}
r.Use(mw.SwagAuth())
ginSwagger.WrapHandler(swaggerFiles.Handler, ginSwagger.URL(requestTls+c.Request.Host+"/api-docs/open.json"))(c)
})
r.Use(mw.ChangeHeader)

// 是否打印访问日志, 在非正式环境都打印


+ 14
- 0
app/svc/svc_auth.go Vedi File

@@ -30,6 +30,20 @@ func GetUser(c *gin.Context) *model.Admin {
func CheckUser(c *gin.Context) (*model.Admin, string, error) {
token := c.GetHeader("Authorization")
if token == "" {
//TODO::兼容open
appSecret := c.GetHeader("AppSecret")
if appSecret != "" {
//TODO::暂时给激活鸟写死
if appSecret == "2F125D59EE826535D7E84E407A13C107" {
// 获取admin
adminDb := implement.NewAdminDb(db.DBs[GetMasterId(c)])
admin, err := adminDb.GetAdmin(1001)
if err != nil {
return nil, "", err
}
return admin, "", nil
}
}
return nil, "", errors.New("token not exist")
}
// 按空格分割


+ 4816
- 0
docs/open.json
File diff soppresso perché troppo grande
Vedi File


+ 127
- 0
generate_swagger.sh Vedi File

@@ -0,0 +1,127 @@
#!/bin/bash

# 生成基础Swagger JSON文件
swag init --parseDependency --parseInternal --output ./docs

# 提取带有 "open" 标签的路径
jq '.paths | with_entries(
select(
(.value.post?.tags? | type == "array" and any(. == "数据中心------嘉俊")) or
(.value.get?.tags? | type == "array" and any(. == "数据中心------嘉俊")) or
(.value.put?.tags? | type == "array" and any(. == "数据中心------嘉俊")) or
(.value.delete?.tags? | type == "array" and any(. == "数据中心------嘉俊"))
)
) // {} as $filtered_paths | . * { paths: $filtered_paths }' docs/swagger.json > open_paths.json

# 提取 definitions 和 securityDefinitions
jq '.definitions' docs/swagger.json > definitions.json
jq '.securityDefinitions' docs/swagger.json > securityDefinitions.json

# 替换 description 中的内容
jq 'with_entries(
.value |= (
if .post then
.post.parameters |= map(
if .description == "验证参数Bearer和token空格拼接" then
.description = "秘钥内容"
else
.
end
)
else
.
end,
if .get then
.get.parameters |= map(
if .description == "验证参数Bearer和token空格拼接" then
.description = "秘钥内容"
else
.
end
)
else
.
end,
if .put then
.put.parameters |= map(
if .description == "验证参数Bearer和token空格拼接" then
.description = "秘钥内容"
else
.
end
)
else
.
end,
if .delete then
.delete.parameters |= map(
if .description == "验证参数Bearer和token空格拼接" then
.description = "秘钥内容"
else
.
end
)
else
.
end
)
)' open_paths.json > updated_tmp_open_paths.json

# 将 "name": "Authorization" 替换成 "name": "AppSecret"
jq 'walk(if type == "object" and has("name") and .name == "Authorization" then .name = "AppSecret" else . end)' updated_tmp_open_paths.json > updated_open_paths.json

# 创建新的 Swagger 配置文件
cat <<EOF > temp.json
{
"swagger": "2.0",
"info": {
"description": "广告联盟接口",
"title": "广告联盟",
"termsOfService": "http://swagger.io/terms/",
"contact": {
"name": "zhiying",
"url": "http://www.swagger.io/support",
"email": "zhiyongos@163.com"
},
"license": {
"name": "Apache 2.0",
"url": "http://www.apache.org/licenses/LICENSE-2.0.html"
},
"version": "1.0"
},
"host": "xxxxx.adcms.zhiyingos.cn",
"paths": {

},
"definitions": {

},
"securityDefinitions": {

}
}
EOF

# 合并路径信息到open.json
jq -n '
input as $paths |
input as $config |
$config | .paths = $paths
' updated_open_paths.json temp.json > temp_1.json
jq -n '
input as $paths |
input as $config |
$config | .definitions = $paths
' definitions.json temp_1.json > temp_2.json
jq -n '
input as $paths |
input as $config |
$config | .securityDefinitions = $paths
' securityDefinitions.json temp_2.json > open.json

# 删除中间生成的文件
rm -f open_paths.json temp_1.json temp_2.json updated_open_paths.json temp.json definitions.json securityDefinitions.json updated_tmp_open_paths.json

# 将最终生成的文件移动到docs目录下
mv open.json docs/open.json
echo "Generated open.json successfully."

Caricamento…
Annulla
Salva