@@ -2,12 +2,14 @@ package youlianghui | |||||
import ( | import ( | ||||
"applet/app/cfg" | "applet/app/cfg" | ||||
"applet/app/lib/youlianghui/md" | |||||
) | ) | ||||
type ApiService struct { | 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方法 | 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 { | if cfg.Prd { | ||||
apiService.Host = "http://api.adnet.qq.com/open/v1.1" | 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 | return | ||||
} | } | ||||
// MediumAdd 创建媒体 | // 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 | |||||
} |
@@ -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,8 +2,8 @@ package md | |||||
type MediumAdd struct { | type MediumAdd struct { | ||||
MediumName string `json:"medium_name" example:"媒体名字"` | 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(支持的各个商店域名约束)"` | DetailUrl string `json:"detail_url" example:"详情页url(支持的各个商店域名约束)"` | ||||
Affiliation string `json:"affiliation" example:"媒体隶属关系"` | Affiliation string `json:"affiliation" example:"媒体隶属关系"` | ||||
PackageName string `json:"package_name" example:"主程序包名"` | PackageName string `json:"package_name" example:"主程序包名"` | ||||
@@ -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() | |||||
} | |||||
} |
@@ -25,6 +25,19 @@ func Init() *gin.Engine { | |||||
ginSwagger.DisablingWrapHandler(swaggerFiles.Handler, "SWAGGER")(c) | 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) | r.Use(mw.ChangeHeader) | ||||
// 是否打印访问日志, 在非正式环境都打印 | // 是否打印访问日志, 在非正式环境都打印 | ||||
@@ -30,6 +30,20 @@ func GetUser(c *gin.Context) *model.Admin { | |||||
func CheckUser(c *gin.Context) (*model.Admin, string, error) { | func CheckUser(c *gin.Context) (*model.Admin, string, error) { | ||||
token := c.GetHeader("Authorization") | token := c.GetHeader("Authorization") | ||||
if token == "" { | 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") | return nil, "", errors.New("token not exist") | ||||
} | } | ||||
// 按空格分割 | // 按空格分割 | ||||
@@ -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." |