You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
242 lines
6.8 KiB
242 lines
6.8 KiB
package http |
|
|
|
import ( |
|
"fmt" |
|
"io/ioutil" |
|
"net/http" |
|
"regexp" |
|
"time" |
|
|
|
"encoding/json" |
|
"go-common/app/admin/main/appstatic/model" |
|
"go-common/library/ecode" |
|
"go-common/library/log" |
|
bm "go-common/library/net/http/blademaster" |
|
) |
|
|
|
const nameFmt = `^[a-zA-Z0-9._-]+$` |
|
const fileFmt = "Mod_%d-%s/%s" |
|
|
|
func httpCode(c *bm.Context, message string, err error) { |
|
c.JSON(map[string]interface{}{ |
|
"message": message, |
|
}, err) |
|
} |
|
|
|
// validate required data |
|
func validateRequired(reqInfo *model.RequestVer) (err error) { |
|
reg := regexp.MustCompile(nameFmt) |
|
if res := reg.MatchString(reqInfo.ModName); !res { |
|
err = fmt.Errorf("mod_name %s contains illegal character", reqInfo.ModName) |
|
return |
|
} |
|
if res := reg.MatchString(reqInfo.Department); !res { |
|
err = fmt.Errorf("department %s contains illegal character", reqInfo.Department) |
|
return |
|
} |
|
return |
|
} |
|
|
|
// check whether the build range is valid |
|
func checkRange(build *model.Build) (res bool) { |
|
if (build.GE != 0 && build.GT != 0) || (build.LE != 0 && build.LT != 0) { // two values by one side |
|
return false |
|
} |
|
var ( |
|
gt = build.GT |
|
lt = build.LT |
|
) |
|
// transform E to T |
|
if build.GE != 0 { |
|
gt = build.GE - 1 |
|
} |
|
if build.LE != 0 { |
|
lt = build.LE + 1 |
|
} |
|
// range check |
|
if lt != 0 && gt != 0 && lt-gt <= 1 { |
|
return false |
|
} |
|
return true |
|
} |
|
|
|
// transform []int to []string |
|
func sliceString(is []int) (ss []string) { |
|
for _, v := range is { |
|
ss = append(ss, fmt.Sprintf("%d", v)) |
|
} |
|
return |
|
} |
|
|
|
// check limit data and build the Limit Struct, error is json error here |
|
func checkLimit(reqInfo *model.RequestVer) (res *model.Limit, err error) { |
|
getFormat := "GetLimit Param (%s), Value = (%s)" |
|
res = &model.Limit{} |
|
// mobi_app |
|
if len(reqInfo.MobiAPP) != 0 { |
|
res.MobiApp = reqInfo.MobiAPP |
|
} |
|
// device |
|
if len(reqInfo.Device) != 0 { |
|
res.Device = reqInfo.Device |
|
} |
|
// plat |
|
if len(reqInfo.Plat) != 0 { |
|
res.Plat = reqInfo.Plat |
|
} |
|
if reqInfo.IsWifi != 0 { |
|
res.IsWifi = reqInfo.IsWifi |
|
} |
|
// Scale & Arch & Level |
|
if len(reqInfo.Scale) != 0 { |
|
res.Scale = sliceString(reqInfo.Scale) |
|
} |
|
if len(reqInfo.Arch) != 0 { |
|
res.Arch = sliceString(reqInfo.Arch) |
|
} |
|
if reqInfo.Level != 0 { |
|
res.Level = sliceString([]int{reqInfo.Level}) // treat level as others ( []int ) |
|
} |
|
// build_range |
|
if buildStr := reqInfo.BuildRange; buildStr != "" { |
|
log.Info(getFormat, "build_range", buildStr) |
|
var build = model.Build{} |
|
if err = json.Unmarshal([]byte(buildStr), &build); err != nil { // json err |
|
log.Error("buildStr (%s) json.Unmarshal error(%v)", buildStr, err) |
|
return |
|
} |
|
if isValid := checkRange(&build); !isValid { // range not valid |
|
err = fmt.Errorf("build range (%s) not valid", buildStr) |
|
log.Error("buildStr CheckRange Error (%v)", err) |
|
return |
|
} |
|
res.Build = &build |
|
} |
|
// sysver |
|
if sysverStr := reqInfo.Sysver; sysverStr != "" { |
|
var build = model.Build{} |
|
if err = json.Unmarshal([]byte(sysverStr), &build); err != nil { // json err |
|
log.Error("buildStr (%s) json.Unmarshal error(%v)", sysverStr, err) |
|
return |
|
} |
|
if isValid := checkRange(&build); !isValid { // range not valid |
|
err = fmt.Errorf("build range (%s) not valid", sysverStr) |
|
log.Error("sysverStr CheckRange Error (%v)", err) |
|
return |
|
} |
|
res.Sysver = &build |
|
} |
|
// time_range |
|
if timeStr := reqInfo.TimeRange; timeStr != "" { |
|
log.Info(getFormat, "time_range", timeStr) |
|
var tr = model.TimeRange{} |
|
if err = json.Unmarshal([]byte(timeStr), &tr); err != nil { |
|
log.Error("timeStr (%s) json.Unmarshal error(%v)", timeStr, err) |
|
return |
|
} |
|
if tr.Stime != 0 && tr.Etime != 0 && tr.Stime > tr.Etime { |
|
err = fmt.Errorf("Stime(%d) is bigger than Etime(%d)", tr.Stime, tr.Etime) |
|
log.Error("Time Range Error(%v)", err) |
|
return |
|
} |
|
res.TimeRange = &tr |
|
} |
|
return |
|
} |
|
|
|
// validate the file type, content and upload it to the BFS storage |
|
func validateFile(ctx *bm.Context, req *http.Request, pool *model.ResourcePool) (fInfo *model.FileInfo, err error) { |
|
// get the file |
|
file, header, err := req.FormFile("file") |
|
if err != nil { |
|
return |
|
} |
|
defer file.Close() |
|
// read the file |
|
content, err := ioutil.ReadAll(file) |
|
if err != nil { |
|
log.Error("resource uploadFile.ReadAll error(%v)", err) |
|
return |
|
} |
|
// parse file, get type, size, md5 |
|
fInfo, err = apsSvc.ParseFile(content) |
|
if err != nil { |
|
log.Error("[validateFile]-[ParseFile] Error-[%v]", err) |
|
return |
|
} |
|
if !apsSvc.TypeCheck(fInfo.Type) { |
|
log.Error("[validateFile]-[FileType] Error-[%v]", fInfo.Type) |
|
err = fmt.Errorf("请上传指定类型文件") |
|
return |
|
} |
|
// regex checking |
|
reg := regexp.MustCompile(nameFmt) |
|
if res := reg.MatchString(header.Filename); !res { |
|
err = fmt.Errorf("fileName %s contains illegal character", header.Filename) |
|
return |
|
} |
|
// upload file to BFS |
|
fInfo.Name = fmt.Sprintf(fileFmt, pool.ID, fInfo.Md5, header.Filename) // rename with the MD5 and poolID |
|
location, err := apsSvc.Upload(ctx, fInfo.Name, fInfo.Type, time.Now().Unix(), content) |
|
if err != nil { |
|
log.Error("[validateFile]-[UploadBFS] Error-[%v]", err) |
|
return |
|
} |
|
fInfo.URL = location |
|
return |
|
} |
|
|
|
// for other systems |
|
func addVer(c *bm.Context) { |
|
var ( |
|
pool = model.ResourcePool{} |
|
department = model.Department{} |
|
req = c.Request |
|
limitData *model.Limit |
|
fInfo *model.FileInfo |
|
err error |
|
reqInfo = model.RequestVer{} |
|
respData = &model.RespAdd{} |
|
) |
|
req.ParseMultipartForm(apsSvc.MaxSize) |
|
if err = c.Bind(&reqInfo); err != nil { |
|
return |
|
} |
|
// validate required data |
|
if err = validateRequired(&reqInfo); err != nil { |
|
log.Error("addVer ModName, ResName Error (%v)", err) |
|
c.JSON(nil, err) |
|
return |
|
} |
|
// validate department |
|
if err = apsSvc.DB.Where("`name` = ?", reqInfo.Department).First(&department).Error; err != nil { |
|
log.Error("addVer First department Error (%v)", err) |
|
httpCode(c, fmt.Sprintf("department %s doesn't exist", reqInfo.Department), ecode.RequestErr) |
|
return |
|
} |
|
// validate mod Name |
|
if err = apsSvc.DB.Where("`name` = ? AND `department_id` = ? AND `deleted` = 0 AND `action` = 1", reqInfo.ModName, department.ID).First(&pool).Error; err != nil { |
|
log.Error("addVer First Pool Error (%v)", err) |
|
httpCode(c, fmt.Sprintf("Mod_name %s doesn't exist", reqInfo.ModName), ecode.RequestErr) |
|
return |
|
} |
|
// check limit & config data |
|
if limitData, err = checkLimit(&reqInfo); err != nil { |
|
log.Error("addVer CheckLimit Error (%v)", err) |
|
httpCode(c, fmt.Sprintf("Limit Params JSON Error:(%v)", err), ecode.RequestErr) |
|
return |
|
} |
|
// validate file data |
|
if fInfo, err = validateFile(c, req, &pool); err != nil { |
|
log.Error("addVer ValidateFile Error (%v)", err) |
|
httpCode(c, fmt.Sprintf("File Error:(%v)", err), ecode.RequestErr) |
|
return |
|
} |
|
// DB & storage operation |
|
if respData.ResID, respData.Version, err = apsSvc.GenerateVer(reqInfo.ResName, limitData, fInfo, &pool, reqInfo.DefaultPackage); err != nil { |
|
log.Error("addVer GenerateVer Error (%v)", err) |
|
httpCode(c, fmt.Sprintf("Generate Version Error:(%v)", err), ecode.ServerErr) |
|
return |
|
} |
|
c.JSON(respData, nil) |
|
}
|
|
|