|
|
package manage
|
|
|
|
|
|
import (
|
|
|
"encoding/json"
|
|
|
"fmt"
|
|
|
"net/http"
|
|
|
"regexp"
|
|
|
"strconv"
|
|
|
"strings"
|
|
|
"time"
|
|
|
|
|
|
"github.com/mafanr/juz/api/manage/audit"
|
|
|
"github.com/mafanr/juz/misc"
|
|
|
|
|
|
"github.com/mafanr/g"
|
|
|
|
|
|
"github.com/labstack/echo"
|
|
|
"github.com/sunface/talent"
|
|
|
"go.uber.org/zap"
|
|
|
)
|
|
|
|
|
|
/*---------------------API相关-----------------------------*/
|
|
|
func (m *Manage) QueryAPI(c echo.Context) error {
|
|
|
service := talent.FormValue(c, "service")
|
|
|
q := talent.FormValue(c, "q")
|
|
|
pageS := talent.FormValue(c, "page")
|
|
|
if service == "" || pageS == "" {
|
|
|
return c.JSON(http.StatusBadRequest, g.Result{
|
|
|
Status: http.StatusBadRequest,
|
|
|
ErrCode: g.ParamEmptyC,
|
|
|
Message: g.ParamEmptyE,
|
|
|
})
|
|
|
}
|
|
|
|
|
|
page, _ := strconv.Atoi(pageS)
|
|
|
if page <= 0 {
|
|
|
return c.JSON(http.StatusBadRequest, g.Result{
|
|
|
Status: http.StatusBadRequest,
|
|
|
ErrCode: g.ParamInvalidC,
|
|
|
Message: g.ParamInvalidE,
|
|
|
})
|
|
|
}
|
|
|
role := talent.FormValue(c, "app_priv")
|
|
|
if !m.canView(role) {
|
|
|
return c.JSON(http.StatusForbidden, g.Result{
|
|
|
Status: http.StatusForbidden,
|
|
|
ErrCode: g.ForbiddenC,
|
|
|
Message: g.ForbiddenE,
|
|
|
})
|
|
|
}
|
|
|
|
|
|
apis := make([]*misc.API, 0)
|
|
|
var query string
|
|
|
if q == "" {
|
|
|
query = fmt.Sprintf("select * from api_define where service='%s' order by modify_date desc limit %d offset %d", service, g.PER_PAGE, g.PER_PAGE*(page-1))
|
|
|
} else {
|
|
|
query = fmt.Sprintf("select * from api_define where service='%s' and ", service) + "api_id like '%" + q + "%' " + fmt.Sprintf(" order by modify_date desc limit %d offset %d", g.PER_PAGE, g.PER_PAGE*(page-1))
|
|
|
}
|
|
|
|
|
|
err := g.DB.Select(&apis, query)
|
|
|
if err != nil {
|
|
|
g.Info("access database error", zap.Error(err), zap.String("query", query))
|
|
|
return c.JSON(http.StatusInternalServerError, g.Result{
|
|
|
Status: http.StatusInternalServerError,
|
|
|
ErrCode: g.DatabaseC,
|
|
|
Message: g.DatabaseE,
|
|
|
})
|
|
|
}
|
|
|
|
|
|
for _, api := range apis {
|
|
|
if api.ParamTable != nil {
|
|
|
d, _ := g.B64.DecodeString(*api.ParamTable)
|
|
|
d1 := talent.Bytes2String(d)
|
|
|
api.ParamTable = &d1
|
|
|
}
|
|
|
}
|
|
|
|
|
|
return c.JSON(http.StatusOK, g.Result{
|
|
|
Status: http.StatusOK,
|
|
|
Data: apis,
|
|
|
})
|
|
|
}
|
|
|
|
|
|
func (m *Manage) CountAPI(c echo.Context) error {
|
|
|
service := talent.FormValue(c, "service")
|
|
|
q := talent.FormValue(c, "q")
|
|
|
if service == "" {
|
|
|
return c.JSON(http.StatusBadRequest, g.Result{
|
|
|
Status: http.StatusBadRequest,
|
|
|
ErrCode: g.ParamEmptyC,
|
|
|
Message: g.ParamEmptyE,
|
|
|
})
|
|
|
}
|
|
|
|
|
|
var query string
|
|
|
if q == "" {
|
|
|
query = fmt.Sprintf("select count(1) from api_release where service='%s'", service)
|
|
|
} else {
|
|
|
query = fmt.Sprintf("select count(1) from api_release where service='%s' and api_id like '%%", service) + q + "%'"
|
|
|
}
|
|
|
|
|
|
rows, err := g.DB.Query(query)
|
|
|
if err != nil {
|
|
|
g.Info("access database error", zap.Error(err), zap.String("query", query))
|
|
|
return c.JSON(http.StatusInternalServerError, g.Result{
|
|
|
Status: http.StatusInternalServerError,
|
|
|
ErrCode: g.DatabaseC,
|
|
|
Message: g.DatabaseE,
|
|
|
})
|
|
|
}
|
|
|
|
|
|
var total int
|
|
|
rows.Next()
|
|
|
rows.Scan(&total)
|
|
|
|
|
|
return c.JSON(http.StatusOK, g.Result{
|
|
|
Status: http.StatusOK,
|
|
|
Data: total,
|
|
|
})
|
|
|
}
|
|
|
|
|
|
func (m *Manage) DefineAPI(c echo.Context) error {
|
|
|
api, ecode, emsg := m.parseAPI(c)
|
|
|
if ecode != 0 {
|
|
|
return c.JSON(http.StatusBadRequest, g.Result{
|
|
|
Status: http.StatusBadRequest,
|
|
|
ErrCode: ecode,
|
|
|
Message: emsg,
|
|
|
})
|
|
|
}
|
|
|
|
|
|
//必须是该service的管理员或者创建者
|
|
|
if !m.canOperate(talent.FormValue(c, "app_priv")) {
|
|
|
return c.JSON(http.StatusForbidden, g.Result{
|
|
|
Status: http.StatusForbidden,
|
|
|
ErrCode: g.ForbiddenC,
|
|
|
Message: g.ForbiddenE,
|
|
|
})
|
|
|
}
|
|
|
|
|
|
action := talent.FormValue(c, "action")
|
|
|
now := time.Now()
|
|
|
date := talent.Time2StringSecond(now)
|
|
|
|
|
|
pr := g.B64.EncodeToString(talent.String2Bytes(*api.ParamTable))
|
|
|
if action == "create" {
|
|
|
query := fmt.Sprintf(`insert into api_define (api_id,path_type,service,description,route_type,route_addr,route_proto,bw_strategy,retry_strategy,traffic_strategy,mock_data,traffic_on,traffic_api,traffic_ratio,traffic_ips,verify_on,param_rules,cached_time,revise_version,create_date,app)
|
|
|
values ('%s','%d','%s','%s','%d','%s','%d','%d','%d','%d','%s','%d','%s','%d','%s','%d','%s','%d','%s', '%s','%s')`,
|
|
|
api.APIID, api.PathType, api.Service, *api.Desc, api.RouteType, api.RouteAddr, api.RouteProto, api.BwStrategy, api.RetryStrategy, api.TrafficStrategy, *api.MockData, api.TrafficOn, api.TrafficAPI, api.TrafficRatio, api.TrafficIPs, api.VerifyOn, pr, api.CachedTime, talent.Time2Version(now), date, api.App)
|
|
|
_, err := g.DB.Exec(query)
|
|
|
if err != nil {
|
|
|
if strings.Contains(err.Error(), g.DUP_KEY_ERR) {
|
|
|
return c.JSON(http.StatusConflict, g.Result{
|
|
|
Status: http.StatusConflict,
|
|
|
ErrCode: g.AlreadyExistC,
|
|
|
Message: g.AlreadyExistE,
|
|
|
})
|
|
|
}
|
|
|
g.Info("access database error", zap.Error(err), zap.String("query", query))
|
|
|
return c.JSON(http.StatusInternalServerError, g.Result{
|
|
|
Status: http.StatusInternalServerError,
|
|
|
ErrCode: g.DatabaseC,
|
|
|
Message: g.DatabaseE,
|
|
|
})
|
|
|
}
|
|
|
// 初始化api发布表,并设置为未发布状态
|
|
|
// 这里把不能再修改的值进行初始化
|
|
|
query = fmt.Sprintf(`insert into api_release (api_id,path_type,service,route_addr,status,create_date) values ('%s','%d','%s','%s','%d','%s')`,
|
|
|
api.APIID, api.PathType, api.Service, api.RouteAddr, misc.API_OFFLINE, date)
|
|
|
_, err = g.DB.Exec(query)
|
|
|
if err != nil {
|
|
|
g.Info("access database error", zap.Error(err), zap.String("query", query))
|
|
|
return c.JSON(http.StatusInternalServerError, g.Result{
|
|
|
Status: http.StatusInternalServerError,
|
|
|
ErrCode: g.DatabaseC,
|
|
|
Message: g.DatabaseE,
|
|
|
})
|
|
|
}
|
|
|
audit.Log(c.FormValue("username"), api.Service, audit.TypeApi, api.APIID, audit.OpCreate, c.FormValue("api"), "")
|
|
|
} else {
|
|
|
query := fmt.Sprintf("update api_define set description='%s',route_type='%d',route_addr='%s',route_proto='%d',bw_strategy='%d',retry_strategy='%d',traffic_strategy='%d',mock_data='%s',traffic_on='%d',traffic_api='%s',traffic_ratio='%d',traffic_ips='%s',verify_on='%d',param_rules='%s',cached_time='%d',app='%s' where api_id='%s'",
|
|
|
*api.Desc, api.RouteType, api.RouteAddr, api.RouteProto, api.BwStrategy, api.RetryStrategy, api.TrafficStrategy, *api.MockData, api.TrafficOn, api.TrafficAPI, api.TrafficRatio, api.TrafficIPs, api.VerifyOn, pr, api.CachedTime, api.App, api.APIID)
|
|
|
res, err := g.DB.Exec(query)
|
|
|
if err != nil {
|
|
|
g.Info("access database error", zap.Error(err), zap.String("query", query))
|
|
|
return c.JSON(http.StatusInternalServerError, g.Result{
|
|
|
Status: http.StatusInternalServerError,
|
|
|
ErrCode: g.DatabaseC,
|
|
|
Message: g.DatabaseE,
|
|
|
})
|
|
|
}
|
|
|
|
|
|
n, _ := res.RowsAffected()
|
|
|
if n == 0 {
|
|
|
return c.JSON(http.StatusOK, g.Result{
|
|
|
Status: http.StatusOK,
|
|
|
ErrCode: g.NoUpdateHappenedC,
|
|
|
Message: g.NoUpdateHappenedE,
|
|
|
})
|
|
|
}
|
|
|
|
|
|
query = fmt.Sprintf("update api_define set revise_version='%s' where api_id='%s'", talent.Time2Version(now), api.APIID)
|
|
|
g.DB.Exec(query)
|
|
|
audit.Log(c.FormValue("username"), api.Service, audit.TypeApi, api.APIID, audit.OpEdit, c.FormValue("api"), "")
|
|
|
}
|
|
|
|
|
|
// 查询并返回最新的api
|
|
|
api1 := misc.API{}
|
|
|
g.DB.Get(&api1, fmt.Sprintf("select * from api_define where api_id='%s'", api.APIID))
|
|
|
|
|
|
if api1.ParamTable != nil {
|
|
|
d, _ := g.B64.DecodeString(*api1.ParamTable)
|
|
|
d1 := talent.Bytes2String(d)
|
|
|
api1.ParamTable = &d1
|
|
|
}
|
|
|
|
|
|
return c.JSON(http.StatusOK, g.Result{
|
|
|
Status: http.StatusOK,
|
|
|
Data: api1,
|
|
|
})
|
|
|
}
|
|
|
|
|
|
// API下线10分钟后,方可删除
|
|
|
func (m *Manage) DeleteAPI(c echo.Context) error {
|
|
|
service := talent.FormValue(c, "service")
|
|
|
apiID := talent.FormValue(c, "api_id")
|
|
|
userID := talent.FormValue(c, "username")
|
|
|
if apiID == "" || userID == "" || service == "" {
|
|
|
return c.JSON(http.StatusBadRequest, g.Result{
|
|
|
Status: http.StatusBadRequest,
|
|
|
ErrCode: g.ParamEmptyC,
|
|
|
Message: g.ParamEmptyE,
|
|
|
})
|
|
|
}
|
|
|
|
|
|
//必须是该service的管理员或者创建者
|
|
|
if !m.canOperate(talent.FormValue(c, "app_priv")) {
|
|
|
return c.JSON(http.StatusForbidden, g.Result{
|
|
|
Status: http.StatusForbidden,
|
|
|
ErrCode: g.ForbiddenC,
|
|
|
Message: g.ForbiddenE,
|
|
|
})
|
|
|
}
|
|
|
|
|
|
// 查询API的发布状态,只有下线10分钟后,才能删除
|
|
|
query := fmt.Sprintf("select status,modify_date from api_release where api_id='%s'", apiID)
|
|
|
rows, err := g.DB.Query(query)
|
|
|
if err != nil {
|
|
|
g.Info("access database error", zap.Error(err), zap.String("query", query))
|
|
|
return c.JSON(http.StatusInternalServerError, g.Result{
|
|
|
Status: http.StatusInternalServerError,
|
|
|
ErrCode: g.DatabaseC,
|
|
|
Message: g.DatabaseE,
|
|
|
})
|
|
|
}
|
|
|
|
|
|
if !rows.Next() {
|
|
|
return c.JSON(http.StatusNotFound, g.Result{
|
|
|
Status: http.StatusNotFound,
|
|
|
ErrCode: APIOfflineC,
|
|
|
Message: APIOfflineE,
|
|
|
})
|
|
|
}
|
|
|
var status int
|
|
|
var ud string
|
|
|
rows.Scan(&status, &ud)
|
|
|
// 已经发布的不能删除
|
|
|
if status == misc.API_RELEASED {
|
|
|
return c.JSON(http.StatusBadRequest, g.Result{
|
|
|
Status: http.StatusBadRequest,
|
|
|
ErrCode: ApiStillReleasedC,
|
|
|
Message: ApiStillReleasedE,
|
|
|
})
|
|
|
}
|
|
|
|
|
|
// 下线不到30秒,不能删除
|
|
|
t, _ := talent.StringToTime(ud)
|
|
|
if time.Now().Sub(t) < 30*time.Second {
|
|
|
return c.JSON(http.StatusBadRequest, g.Result{
|
|
|
Status: http.StatusBadRequest,
|
|
|
ErrCode: ApiInactiveNotLongEnoughC,
|
|
|
Message: ApiInactiveNotLongEnoughE,
|
|
|
})
|
|
|
}
|
|
|
|
|
|
// 将api发布表的状态设置为已删除
|
|
|
query = fmt.Sprintf("delete from api_release where api_id='%s'", apiID)
|
|
|
_, err = g.DB.Exec(query)
|
|
|
if err != nil {
|
|
|
g.Info("access database error", zap.Error(err), zap.String("query", query))
|
|
|
return c.JSON(http.StatusInternalServerError, g.Result{
|
|
|
Status: http.StatusInternalServerError,
|
|
|
ErrCode: g.DatabaseC,
|
|
|
Message: g.DatabaseE,
|
|
|
})
|
|
|
}
|
|
|
|
|
|
// 查询api定义,为了记录审计日志
|
|
|
api := misc.API{}
|
|
|
query = fmt.Sprintf("select * from api_define where api_id='%s'", apiID)
|
|
|
err = g.DB.Get(&api, query)
|
|
|
if err != nil {
|
|
|
g.Info("access database error", zap.Error(err), zap.String("query", query))
|
|
|
}
|
|
|
if api.ParamTable != nil {
|
|
|
d, _ := g.B64.DecodeString(*api.ParamTable)
|
|
|
d1 := talent.Bytes2String(d)
|
|
|
api.ParamTable = &d1
|
|
|
}
|
|
|
|
|
|
b, _ := json.Marshal(api)
|
|
|
|
|
|
// 从api定义表删除
|
|
|
query = fmt.Sprintf("delete from api_define where api_id='%s'", apiID)
|
|
|
_, err = g.DB.Exec(query)
|
|
|
if err != nil {
|
|
|
g.Info("access database error", zap.Error(err), zap.String("query", query))
|
|
|
return c.JSON(http.StatusInternalServerError, g.Result{
|
|
|
Status: http.StatusInternalServerError,
|
|
|
ErrCode: g.DatabaseC,
|
|
|
Message: g.DatabaseE,
|
|
|
})
|
|
|
}
|
|
|
|
|
|
audit.Log(userID, service, audit.TypeApi, apiID, audit.OpDelete, talent.Bytes2String(b), "")
|
|
|
|
|
|
return c.JSON(http.StatusOK, g.Result{
|
|
|
Status: http.StatusOK,
|
|
|
})
|
|
|
}
|
|
|
|
|
|
func (m *Manage) parseAPI(c echo.Context) (*misc.API, int, string) {
|
|
|
apiR := c.FormValue("api")
|
|
|
|
|
|
api := &misc.API{}
|
|
|
err := json.Unmarshal([]byte(apiR), &api)
|
|
|
if err != nil {
|
|
|
g.Info("parse api", zap.Error(err), zap.String("api", string(apiR)))
|
|
|
return nil, g.ParamInvalidC, g.ParamInvalidE
|
|
|
}
|
|
|
|
|
|
if api.Service == "" {
|
|
|
return nil, ServiceEmptyC, ServiceEmptyE
|
|
|
}
|
|
|
|
|
|
if api.PathType != misc.OFF && api.PathType != misc.ON {
|
|
|
return nil, ApiPathTypeInvalidC, ApiPathTypeInvalidE
|
|
|
}
|
|
|
|
|
|
if api.PathType == misc.OFF {
|
|
|
// 非路径格式,api名组成形式
|
|
|
if !talent.OnlyAlphaNumAndDot(api.APIID) {
|
|
|
return nil, ApiOnlyAlphaNumAndDotC, ApiOnlyAlphaNumAndDotE
|
|
|
}
|
|
|
// 检查api id的前缀
|
|
|
if !strings.HasPrefix(api.APIID, api.Service+".") {
|
|
|
return nil, ApiWithServicePrefixC, ApiWithServicePrefixE
|
|
|
}
|
|
|
} else {
|
|
|
// @todo,检查路径形式的参数是否合法,/a/b/c
|
|
|
//路径不能为保留的
|
|
|
if !talent.OnlyAlphaNumAndUri(api.APIID) {
|
|
|
return nil, ApiOnlyAlphaNumAndUriC, ApiOnlyAlphaNumAndUriE
|
|
|
}
|
|
|
|
|
|
name := api.APIID[:len(api.APIID)-3]
|
|
|
if name == "/service/api" || name == "/notify" {
|
|
|
return nil, ApiReservePathC, ApiReservePathE
|
|
|
}
|
|
|
}
|
|
|
|
|
|
// 检查api id的后缀
|
|
|
if api.APIID[len(api.APIID)-2] != 'v' || api.APIID[len(api.APIID)-3] != '.' {
|
|
|
return nil, ApiWithServiceSuffixC, ApiWithServiceSuffixE
|
|
|
}
|
|
|
|
|
|
if api.RouteAddr == "" || strings.TrimSpace(api.RouteAddr) == "http://" || strings.TrimSpace(api.RouteAddr) == "https://" {
|
|
|
return nil, RouteAddrEmptyC, RouteAddrEmptyE
|
|
|
}
|
|
|
|
|
|
if api.RouteAddr != "" {
|
|
|
if !strings.HasPrefix(api.RouteAddr, "http") {
|
|
|
return nil, RouteAddrWithHTTPPrefixC, RouteAddrWithHTTPPrefixE
|
|
|
}
|
|
|
}
|
|
|
|
|
|
if (api.RouteProto != 1) && (api.RouteProto != 2) {
|
|
|
return nil, RouteProtoInvalidC, RouteProtoInvalidE
|
|
|
}
|
|
|
|
|
|
if api.TrafficAPI != "" {
|
|
|
_, ok := misc.Apis.Load(api.TrafficAPI)
|
|
|
if !ok {
|
|
|
return nil, ApiNotExistC, ApiNotExistE
|
|
|
}
|
|
|
}
|
|
|
|
|
|
if api.TrafficRatio < 0 || api.TrafficRatio > 100 {
|
|
|
return nil, TrafficRatioInvalidC, TrafficRatioInvalidE
|
|
|
}
|
|
|
|
|
|
if (api.TrafficOn != 0) && (api.TrafficOn != 1) {
|
|
|
api.TrafficOn = 0
|
|
|
}
|
|
|
|
|
|
if (api.VerifyOn != 0) && (api.VerifyOn != 1) {
|
|
|
api.VerifyOn = 0
|
|
|
}
|
|
|
|
|
|
if (api.CachedTime < 0) || (api.CachedTime > 30) {
|
|
|
api.CachedTime = 0
|
|
|
}
|
|
|
|
|
|
return api, 0, ""
|
|
|
}
|
|
|
|
|
|
func (m *Manage) APIRelease(c echo.Context) error {
|
|
|
apiID := c.FormValue("api_id")
|
|
|
userID := c.FormValue("username")
|
|
|
|
|
|
if apiID == "" {
|
|
|
return c.JSON(http.StatusBadRequest, g.Result{
|
|
|
Status: http.StatusBadRequest,
|
|
|
ErrCode: g.ParamEmptyC,
|
|
|
Message: g.ParamEmptyE,
|
|
|
})
|
|
|
}
|
|
|
|
|
|
//必须是该service的管理员或者创建者
|
|
|
if !m.canOperate(talent.FormValue(c, "app_priv")) {
|
|
|
return c.JSON(http.StatusForbidden, g.Result{
|
|
|
Status: http.StatusForbidden,
|
|
|
ErrCode: g.ForbiddenC,
|
|
|
Message: g.ForbiddenE,
|
|
|
})
|
|
|
}
|
|
|
|
|
|
// 查询最新的api定义
|
|
|
api := misc.API{}
|
|
|
query := fmt.Sprintf("select * from api_define where api_id='%s'", apiID)
|
|
|
err := g.DB.Get(&api, query)
|
|
|
if err != nil {
|
|
|
g.Info("access database error", zap.Error(err), zap.String("query", query))
|
|
|
return c.JSON(http.StatusInternalServerError, g.Result{
|
|
|
Status: http.StatusInternalServerError,
|
|
|
ErrCode: g.DatabaseC,
|
|
|
Message: g.DatabaseE,
|
|
|
})
|
|
|
}
|
|
|
|
|
|
// 更新release
|
|
|
query = fmt.Sprintf("update api_release set description='%s',route_type='%d',route_addr='%s',route_proto='%d',mock_data='%s',retry_strategy='%d',bw_strategy='%d',traffic_strategy='%d',traffic_on='%d',traffic_api='%s',traffic_ratio='%d',traffic_ips='%s',verify_on='%d',param_rules='%s', cached_time='%d',status='%d',app='%s' where api_id='%s'",
|
|
|
*api.Desc, api.RouteType, api.RouteAddr, api.RouteProto, *api.MockData, api.RetryStrategy, api.BwStrategy, api.TrafficStrategy, api.TrafficOn, api.TrafficAPI, api.TrafficRatio, api.TrafficIPs, api.VerifyOn, *api.ParamTable, api.CachedTime, misc.API_RELEASED, api.App, api.APIID)
|
|
|
|
|
|
_, err = g.DB.Exec(query)
|
|
|
if err != nil {
|
|
|
g.Info("access database error", zap.Error(err), zap.String("query", query))
|
|
|
return c.JSON(http.StatusInternalServerError, g.Result{
|
|
|
Status: http.StatusInternalServerError,
|
|
|
ErrCode: g.DatabaseC,
|
|
|
Message: g.DatabaseE,
|
|
|
})
|
|
|
}
|
|
|
|
|
|
query = fmt.Sprintf("update api_define set release_version='%s' where api_id='%s'", api.ReviseVersion, api.APIID)
|
|
|
_, err = g.DB.Exec(query)
|
|
|
if err != nil {
|
|
|
g.Info("access database error", zap.Error(err), zap.String("query", query))
|
|
|
return c.JSON(http.StatusInternalServerError, g.Result{
|
|
|
Status: http.StatusInternalServerError,
|
|
|
ErrCode: g.DatabaseC,
|
|
|
Message: g.DatabaseE,
|
|
|
})
|
|
|
}
|
|
|
|
|
|
if api.ParamTable != nil {
|
|
|
d, _ := g.B64.DecodeString(*api.ParamTable)
|
|
|
d1 := talent.Bytes2String(d)
|
|
|
api.ParamTable = &d1
|
|
|
}
|
|
|
b, _ := json.Marshal(api)
|
|
|
audit.Log(userID, api.Service, audit.TypeApi, api.APIID, audit.OpRelease, talent.Bytes2String(b), "")
|
|
|
|
|
|
return c.JSON(http.StatusOK, g.Result{
|
|
|
Status: http.StatusOK,
|
|
|
})
|
|
|
}
|
|
|
|
|
|
func (m *Manage) APIOffline(c echo.Context) error {
|
|
|
apiID := c.FormValue("api_id")
|
|
|
userID := c.FormValue("username")
|
|
|
|
|
|
if apiID == "" {
|
|
|
return c.JSON(http.StatusBadRequest, g.Result{
|
|
|
Status: http.StatusBadRequest,
|
|
|
ErrCode: g.ParamEmptyC,
|
|
|
Message: g.ParamEmptyE,
|
|
|
})
|
|
|
}
|
|
|
|
|
|
//必须是该service的管理员或者创建者
|
|
|
if !m.canOperate(talent.FormValue(c, "app_priv")) {
|
|
|
return c.JSON(http.StatusForbidden, g.Result{
|
|
|
Status: http.StatusForbidden,
|
|
|
ErrCode: g.ForbiddenC,
|
|
|
Message: g.ForbiddenE,
|
|
|
})
|
|
|
}
|
|
|
|
|
|
query := fmt.Sprintf("update api_release set status='%d' where api_id='%s'",
|
|
|
misc.API_OFFLINE, apiID)
|
|
|
_, err := g.DB.Exec(query)
|
|
|
if err != nil {
|
|
|
g.Info("access database error", zap.Error(err), zap.String("query", query))
|
|
|
return c.JSON(http.StatusInternalServerError, g.Result{
|
|
|
Status: http.StatusInternalServerError,
|
|
|
ErrCode: g.DatabaseC,
|
|
|
Message: g.DatabaseE,
|
|
|
})
|
|
|
}
|
|
|
|
|
|
// 更新api_define表的发布时间
|
|
|
query = fmt.Sprintf("update api_define set release_version='%s' where api_id='%s'", "", apiID)
|
|
|
_, err = g.DB.Exec(query)
|
|
|
if err != nil {
|
|
|
g.Info("access database error", zap.Error(err), zap.String("query", query))
|
|
|
return c.JSON(http.StatusInternalServerError, g.Result{
|
|
|
Status: http.StatusInternalServerError,
|
|
|
ErrCode: g.DatabaseC,
|
|
|
Message: g.DatabaseE,
|
|
|
})
|
|
|
}
|
|
|
|
|
|
// 查询已发布的api定义
|
|
|
api := misc.API{}
|
|
|
query = fmt.Sprintf("select * from api_release where api_id='%s'", apiID)
|
|
|
err = g.DB.Get(&api, query)
|
|
|
if err != nil {
|
|
|
g.Info("access database error", zap.Error(err), zap.String("query", query))
|
|
|
}
|
|
|
if api.ParamTable != nil {
|
|
|
d, _ := g.B64.DecodeString(*api.ParamTable)
|
|
|
d1 := talent.Bytes2String(d)
|
|
|
api.ParamTable = &d1
|
|
|
}
|
|
|
|
|
|
b, _ := json.Marshal(api)
|
|
|
audit.Log(userID, api.Service, audit.TypeApi, api.APIID, audit.OpOffline, talent.Bytes2String(b), "")
|
|
|
|
|
|
return c.JSON(http.StatusOK, g.Result{
|
|
|
Status: http.StatusOK,
|
|
|
})
|
|
|
}
|
|
|
|
|
|
// 请求参数验证
|
|
|
func (m *Manage) VerifyParamRule(c echo.Context) error {
|
|
|
param := strings.TrimSpace(c.FormValue("param"))
|
|
|
rule := strings.TrimSpace(c.FormValue("rule"))
|
|
|
testData := strings.TrimSpace(c.FormValue("test_data"))
|
|
|
if param == "" || rule == "" || testData == "" {
|
|
|
return c.JSON(http.StatusBadRequest, g.Result{
|
|
|
Status: http.StatusBadRequest,
|
|
|
ErrCode: g.ParamEmptyC,
|
|
|
Message: g.ParamEmptyE,
|
|
|
})
|
|
|
}
|
|
|
|
|
|
// 验证正则是否合法
|
|
|
r, err := regexp.Compile(rule)
|
|
|
if err != nil {
|
|
|
return c.JSON(http.StatusBadRequest, g.Result{
|
|
|
Status: http.StatusBadRequest,
|
|
|
ErrCode: InvalidVerifyTableC,
|
|
|
Message: InvalidVerifyTableE,
|
|
|
})
|
|
|
}
|
|
|
// 验证测试数据跟正则是否匹配
|
|
|
if !r.Match([]byte(testData)) {
|
|
|
return c.JSON(http.StatusBadRequest, g.Result{
|
|
|
Status: http.StatusBadRequest,
|
|
|
ErrCode: InvalidVerifyRuleC,
|
|
|
Message: InvalidVerifyRuleE,
|
|
|
})
|
|
|
}
|
|
|
|
|
|
return c.JSON(http.StatusOK, g.Result{
|
|
|
Status: http.StatusOK,
|
|
|
})
|
|
|
}
|
|
|
|
|
|
//批量设置策略
|
|
|
func (m *Manage) APIBatchStrategy(c echo.Context) error {
|
|
|
apiIDS := strings.TrimSpace(c.FormValue("api_ids"))
|
|
|
bw := strings.TrimSpace(c.FormValue("batch_bw"))
|
|
|
retry := strings.TrimSpace(c.FormValue("batch_retry"))
|
|
|
traffic := strings.TrimSpace(c.FormValue("batch_traffic"))
|
|
|
service := c.FormValue("service")
|
|
|
if apiIDS == "" || (bw == "" && retry == "" && traffic == "") || service == "" {
|
|
|
return c.JSON(http.StatusBadRequest, g.Result{
|
|
|
Status: http.StatusBadRequest,
|
|
|
ErrCode: g.ParamEmptyC,
|
|
|
Message: g.ParamEmptyE,
|
|
|
})
|
|
|
}
|
|
|
|
|
|
var apiIds []string
|
|
|
err := json.Unmarshal([]byte(apiIDS), &apiIds)
|
|
|
if err != nil {
|
|
|
return c.JSON(http.StatusBadRequest, g.Result{
|
|
|
Status: http.StatusBadRequest,
|
|
|
ErrCode: g.ParamInvalidC,
|
|
|
Message: g.ParamInvalidE,
|
|
|
})
|
|
|
}
|
|
|
|
|
|
//必须是该service的管理员或者创建者
|
|
|
if !m.canOperate(talent.FormValue(c, "app_priv")) {
|
|
|
return c.JSON(http.StatusForbidden, g.Result{
|
|
|
Status: http.StatusForbidden,
|
|
|
ErrCode: g.ForbiddenC,
|
|
|
Message: g.ForbiddenE,
|
|
|
})
|
|
|
}
|
|
|
|
|
|
now := time.Now()
|
|
|
for _, apiID := range apiIds {
|
|
|
var query = "update api_define set"
|
|
|
if bw != "" {
|
|
|
query = fmt.Sprintf("%s bw_strategy='%s', ", query, bw)
|
|
|
}
|
|
|
if retry != "" {
|
|
|
query = fmt.Sprintf("%s retry_strategy='%s', ", query, retry)
|
|
|
}
|
|
|
if traffic != "" {
|
|
|
query = fmt.Sprintf("%s traffic_strategy='%s'", query, traffic)
|
|
|
}
|
|
|
|
|
|
query = fmt.Sprintf("%s where api_id = '%s'", query, apiID)
|
|
|
res, err := g.DB.Exec(query)
|
|
|
if err != nil {
|
|
|
g.Info("access database error", zap.Error(err), zap.String("query", query))
|
|
|
return c.JSON(http.StatusInternalServerError, g.Result{
|
|
|
Status: http.StatusInternalServerError,
|
|
|
ErrCode: g.DatabaseC,
|
|
|
Message: g.DatabaseE,
|
|
|
})
|
|
|
}
|
|
|
|
|
|
n, _ := res.RowsAffected()
|
|
|
if n == 0 {
|
|
|
continue
|
|
|
}
|
|
|
// 更新版本号
|
|
|
query = fmt.Sprintf("update api_define set revise_version='%s' where api_id='%s'", talent.Time2Version(now), apiID)
|
|
|
g.DB.Exec(query)
|
|
|
}
|
|
|
|
|
|
userID := c.FormValue("username")
|
|
|
audit.Log(userID, service, audit.TypeBatch, fmt.Sprintf("bw: %s,retry: %s", bw, retry), audit.OpCreate, apiIDS, "批量添加策略")
|
|
|
|
|
|
return c.JSON(http.StatusOK, g.Result{
|
|
|
Status: http.StatusOK,
|
|
|
})
|
|
|
}
|
|
|
|
|
|
// 批量删除策略
|
|
|
func (m *Manage) APIBatchDelStrategy(c echo.Context) error {
|
|
|
apiIDS := strings.TrimSpace(c.FormValue("api_ids"))
|
|
|
service := c.FormValue("service")
|
|
|
if apiIDS == "" {
|
|
|
return c.JSON(http.StatusBadRequest, g.Result{
|
|
|
Status: http.StatusBadRequest,
|
|
|
ErrCode: g.ParamEmptyC,
|
|
|
Message: g.ParamEmptyE,
|
|
|
})
|
|
|
}
|
|
|
|
|
|
var apiIds []string
|
|
|
err := json.Unmarshal([]byte(apiIDS), &apiIds)
|
|
|
if err != nil {
|
|
|
return c.JSON(http.StatusBadRequest, g.Result{
|
|
|
Status: http.StatusBadRequest,
|
|
|
ErrCode: g.ParamInvalidC,
|
|
|
Message: g.ParamInvalidE,
|
|
|
})
|
|
|
}
|
|
|
|
|
|
//必须是该service的管理员或者创建者
|
|
|
if !m.canOperate(talent.FormValue(c, "app_priv")) {
|
|
|
return c.JSON(http.StatusForbidden, g.Result{
|
|
|
Status: http.StatusForbidden,
|
|
|
ErrCode: g.ForbiddenC,
|
|
|
Message: g.ForbiddenE,
|
|
|
})
|
|
|
}
|
|
|
|
|
|
tp, _ := strconv.Atoi(c.FormValue("type"))
|
|
|
|
|
|
now := time.Now()
|
|
|
for _, apiID := range apiIds {
|
|
|
var query string
|
|
|
switch tp {
|
|
|
case misc.STRATEGY_BWLIST:
|
|
|
query = fmt.Sprintf("update api_define set bw_strategy='%d' where api_id = '%s'", misc.STRATEGY_EMPTY, apiID)
|
|
|
case misc.STRATEGY_RETRY:
|
|
|
query = fmt.Sprintf("update api_define set retry_strategy='%d' where api_id = '%s'", misc.STRATEGY_EMPTY, apiID)
|
|
|
case misc.STRATEGY_TRAFFIC:
|
|
|
query = fmt.Sprintf("update api_define set traffic_strategy='%d' where api_id = '%s'", misc.STRATEGY_EMPTY, apiID)
|
|
|
default:
|
|
|
return c.JSON(http.StatusBadRequest, g.Result{
|
|
|
Status: http.StatusBadRequest,
|
|
|
ErrCode: g.ParamInvalidC,
|
|
|
Message: g.ParamInvalidE,
|
|
|
})
|
|
|
}
|
|
|
|
|
|
res, err := g.DB.Exec(query)
|
|
|
if err != nil {
|
|
|
g.Info("access database error", zap.Error(err), zap.String("query", query))
|
|
|
return c.JSON(http.StatusInternalServerError, g.Result{
|
|
|
Status: http.StatusInternalServerError,
|
|
|
ErrCode: g.DatabaseC,
|
|
|
Message: g.DatabaseE,
|
|
|
})
|
|
|
}
|
|
|
|
|
|
n, _ := res.RowsAffected()
|
|
|
if n == 0 {
|
|
|
continue
|
|
|
}
|
|
|
// 更新版本号
|
|
|
query = fmt.Sprintf("update api_define set revise_version='%s' where api_id='%s'", talent.Time2Version(now), apiID)
|
|
|
g.DB.Exec(query)
|
|
|
}
|
|
|
|
|
|
userID := c.FormValue("username")
|
|
|
var msg string
|
|
|
switch tp {
|
|
|
case misc.STRATEGY_BWLIST:
|
|
|
msg = "White/Black List"
|
|
|
case misc.STRATEGY_RETRY:
|
|
|
msg = "Timeout/Retry"
|
|
|
case misc.STRATEGY_TRAFFIC:
|
|
|
msg = "Traffic Control"
|
|
|
}
|
|
|
audit.Log(userID, service, audit.TypeBatch, msg, audit.OpDelete, apiIDS, "Batch delete strategy")
|
|
|
|
|
|
return c.JSON(http.StatusOK, g.Result{
|
|
|
Status: http.StatusOK,
|
|
|
})
|
|
|
}
|
|
|
|
|
|
func (m *Manage) APIBatchRelease(c echo.Context) error {
|
|
|
apiIDS := strings.TrimSpace(c.FormValue("api_ids"))
|
|
|
if apiIDS == "" {
|
|
|
return c.JSON(http.StatusBadRequest, g.Result{
|
|
|
Status: http.StatusBadRequest,
|
|
|
ErrCode: g.ParamEmptyC,
|
|
|
Message: g.ParamEmptyE,
|
|
|
})
|
|
|
}
|
|
|
|
|
|
var apiIds []string
|
|
|
err := json.Unmarshal([]byte(apiIDS), &apiIds)
|
|
|
if err != nil {
|
|
|
return c.JSON(http.StatusBadRequest, g.Result{
|
|
|
Status: http.StatusBadRequest,
|
|
|
ErrCode: g.ParamInvalidC,
|
|
|
Message: g.ParamInvalidE,
|
|
|
})
|
|
|
}
|
|
|
|
|
|
//必须是该service的管理员或者创建者
|
|
|
if !m.canOperate(talent.FormValue(c, "app_priv")) {
|
|
|
return c.JSON(http.StatusForbidden, g.Result{
|
|
|
Status: http.StatusForbidden,
|
|
|
ErrCode: g.ForbiddenC,
|
|
|
Message: g.ForbiddenE,
|
|
|
})
|
|
|
}
|
|
|
|
|
|
for _, apiID := range apiIds {
|
|
|
// 查询最新的api定义
|
|
|
api := misc.API{}
|
|
|
query := fmt.Sprintf("select * from api_define where api_id='%s'", apiID)
|
|
|
err := g.DB.Get(&api, query)
|
|
|
if err != nil {
|
|
|
g.Info("access database error", zap.Error(err), zap.String("query", query))
|
|
|
return c.JSON(http.StatusInternalServerError, g.Result{
|
|
|
Status: http.StatusInternalServerError,
|
|
|
ErrCode: g.DatabaseC,
|
|
|
Message: g.DatabaseE,
|
|
|
})
|
|
|
}
|
|
|
|
|
|
// 更新release
|
|
|
query = fmt.Sprintf("update api_release set description='%s',route_type='%d',route_addr='%s',route_proto='%d',mock_data='%s',retry_strategy='%d',bw_strategy='%d',traffic_on='%d',traffic_api='%s',traffic_ratio='%d',traffic_ips='%s',verify_on='%d',param_rules='%s', cached_time='%d',status='%d',app='%s' where api_id='%s'",
|
|
|
*api.Desc, api.RouteType, api.RouteAddr, api.RouteProto, *api.MockData, api.RetryStrategy, api.BwStrategy, api.TrafficOn, api.TrafficAPI, api.TrafficRatio, api.TrafficIPs, api.VerifyOn, *api.ParamTable, api.CachedTime, misc.API_RELEASED, api.App, api.APIID)
|
|
|
|
|
|
_, err = g.DB.Exec(query)
|
|
|
if err != nil {
|
|
|
g.Info("access database error", zap.Error(err), zap.String("query", query))
|
|
|
return c.JSON(http.StatusInternalServerError, g.Result{
|
|
|
Status: http.StatusInternalServerError,
|
|
|
ErrCode: g.DatabaseC,
|
|
|
Message: g.DatabaseE,
|
|
|
})
|
|
|
}
|
|
|
|
|
|
query = fmt.Sprintf("update api_define set release_version='%s' where api_id='%s'", api.ReviseVersion, api.APIID)
|
|
|
_, err = g.DB.Exec(query)
|
|
|
if err != nil {
|
|
|
g.Info("access database error", zap.Error(err), zap.String("query", query))
|
|
|
return c.JSON(http.StatusInternalServerError, g.Result{
|
|
|
Status: http.StatusInternalServerError,
|
|
|
ErrCode: g.DatabaseC,
|
|
|
Message: g.DatabaseE,
|
|
|
})
|
|
|
}
|
|
|
|
|
|
userID := c.FormValue("username")
|
|
|
if api.ParamTable != nil {
|
|
|
d, _ := g.B64.DecodeString(*api.ParamTable)
|
|
|
d1 := talent.Bytes2String(d)
|
|
|
api.ParamTable = &d1
|
|
|
}
|
|
|
b, _ := json.Marshal(api)
|
|
|
audit.Log(userID, api.Service, audit.TypeApi, api.APIID, audit.OpRelease, talent.Bytes2String(b), "")
|
|
|
}
|
|
|
|
|
|
return c.JSON(http.StatusOK, g.Result{
|
|
|
Status: http.StatusOK,
|
|
|
})
|
|
|
}
|