Create & Init Project...

This commit is contained in:
2019-04-22 18:49:16 +08:00
commit fc4fa37393
25440 changed files with 4054998 additions and 0 deletions

22
app/admin/ep/marthe/BUILD Normal file
View File

@ -0,0 +1,22 @@
package(default_visibility = ["//visibility:public"])
filegroup(
name = "package-srcs",
srcs = glob(["**"]),
tags = ["automanaged"],
visibility = ["//visibility:private"],
)
filegroup(
name = "all-srcs",
srcs = [
":package-srcs",
"//app/admin/ep/marthe/cmd:all-srcs",
"//app/admin/ep/marthe/conf:all-srcs",
"//app/admin/ep/marthe/dao:all-srcs",
"//app/admin/ep/marthe/model:all-srcs",
"//app/admin/ep/marthe/server/http:all-srcs",
"//app/admin/ep/marthe/service:all-srcs",
],
tags = ["automanaged"],
)

View File

@ -0,0 +1,4 @@
##### marthe
##### Version 1. 0. 1
1. 拉取bugly原始数据以自定义的格式落库

View File

@ -0,0 +1,14 @@
# Owner
maojian
yuanmin
fengyifeng
xuneng
# Author
yuanmin
fengyifeng
xuneng
# Reviewer
zhapuyu
wangxu01

View File

@ -0,0 +1,19 @@
# See the OWNERS docs at https://go.k8s.io/owners
approvers:
- fengyifeng
- maojian
- xuneng
- yuanmin
labels:
- admin
- admin/ep/marthe
- ep
options:
no_parent_owners: true
reviewers:
- fengyifeng
- wangxu01
- xuneng
- yuanmin
- zhapuyu

View File

@ -0,0 +1,19 @@
# Marthe-service
# 项目简介
### 背景/Background
* 目前移动端crash信息会上报到buglybugly系统查询数据比较慢且没有足够的数据分析功能影响开发查询分析crash的效率
* 目前项目需求bug等信息记录在tapd, 同样tapd系统现有的报表功能并不满足我们PMO的需求使PMO拿不到充足的数据做分析
* 于是Marthe项目为了解决这些问题孕育而生
### 概览Overview
* Marthe会根据开发和测试的需求从bugly拉取原始数据并进行二次处理
# 编译环境
# 依赖包
# 编译执行

View File

@ -0,0 +1,44 @@
package(default_visibility = ["//visibility:public"])
load(
"@io_bazel_rules_go//go:def.bzl",
"go_binary",
"go_library",
)
go_binary(
name = "cmd",
embed = [":go_default_library"],
tags = ["automanaged"],
)
go_library(
name = "go_default_library",
srcs = ["main.go"],
data = ["admin.toml"],
importpath = "go-common/app/admin/ep/marthe/cmd",
tags = ["automanaged"],
visibility = ["//visibility:public"],
deps = [
"//app/admin/ep/marthe/conf:go_default_library",
"//app/admin/ep/marthe/server/http:go_default_library",
"//app/admin/ep/marthe/service:go_default_library",
"//library/ecode/tip:go_default_library",
"//library/log:go_default_library",
"//library/net/trace:go_default_library",
],
)
filegroup(
name = "package-srcs",
srcs = glob(["**"]),
tags = ["automanaged"],
visibility = ["//visibility:private"],
)
filegroup(
name = "all-srcs",
srcs = [":package-srcs"],
tags = ["automanaged"],
visibility = ["//visibility:public"],
)

View File

@ -0,0 +1,130 @@
[bm]
addr = "0.0.0.0:9001"
timeout = "10s"
[httpClient]
key = "c05dd4e1638a8af0"
secret = "7daa7f8c06cd33c5c3067063c746fdcb"
dial = "2s"
timeout = "100s"
keepAlive = "60s"
timer = 1000
[httpClient.breaker]
window = "10s"
sleep = "2000ms"
bucket = 10
ratio = 0.5
request = 100
[mail]
host = "smtp.exmail.qq.com"
port = 465
username = "merlin@bilibili.com"
password = ""
noticeOwner = ["fengyifeng@bilibili.com"]
[memcache]
name = "merlin"
proto = "tcp"
addr = "172.18.33.61:11232"
idle = 5
active = 10
dialTimeout = "1s"
readTimeout = "1s"
writeTimeout = "1s"
idleTimeout = "10s"
expire = "12h"
[bugly]
#bugly URL
host = "https://bugly.qq.com"
#bugly请求尝试次数
urlRetryCount = 3
#cookie 使用上限次数
cookieUsageUpper = 300
#bugly 每页获取issue个数
issuePageSize = 50
#bugly 抓取issue上限个数
issueCountUpper = 100
#bugly 超级管理员
superOwner = ["fengyifeng","yuanmin"]
[tapd]
#tapd bug相关操作 是否认证tapd权限
bugOperateAuth = false
[Scheduler]
#每过30分钟 跑enable version 抓bugly数据
batchRunEnableVersion = "0 */30 * * * ?"
#每天晚上23点 定时更新tapd bug
batchRunUpdateTapdBug = "0 0 23 * * ?"
#每10分钟定时删除超过三小时为执行完毕的任务
disableBatchRunOverTime = "0 */10 * * * ?"
#过期时限
batchRunOverHourTime = 3
#每天晚上22点更新同步wechat contact
syncWechatContact = "0 0 22 * * ?"
#是否开启定时任务
active = false
[orm]
dsn = "root:123456@tcp(172.18.33.130:3306)/Marthe2?timeout=200ms&readTimeout=2000ms&writeTimeout=2000ms&parseTime=true&loc=Local&charset=utf8,utf8mb4"
active = 5
idle = 5
idleTimeout = "4h"
[auth]
managerHost = "http://uat-manager.bilibili.co"
dashboardHost = "http://dashboard-mng.bilibili.co"
dashboardCaller = "marthe"
[auth.DsHTTPClient]
key = "marthe"
secret = "4344bea3587b383bc0b9de5de0efcc3f"
dial = "1s"
timeout = "1s"
keepAlive = "60s"
[auth.DsHTTPClient.breaker]
window = "3s"
sleep = "100ms"
bucket = 10
ratio = 0.5
request = 100
[auth.MaHTTPClient]
key = "f6433799dbd88751"
secret = "36f8ddb1806207fe07013ab6a77a3935"
dial = "1ms"
timeout = "1ms"
keepAlive = "60s"
[auth.MaHTTPClient.breaker]
window = "3s"
sleep = "100ms"
bucket = 10
ratio = 0.5
request = 100
[auth.session]
sessionIDLength = 32
cookieLifeTime = 1
cookieName = "mng-go"
domain = ".bilibili.co"
[auth.session.Memcache]
name = "go-business/auth"
proto = "tcp"
addr = "172.18.33.61:11232"
active = 10
idle = 10
dialTimeout = "1ms"
readTimeout = "1ms"
writeTimeout = "1ms"
idleTimeout = "80s"

View File

@ -0,0 +1,106 @@
[bm]
addr = "0.0.0.0:9001"
timeout = "10s"
[httpClient]
key = "c05dd4e1638a8af0"
secret = "7daa7f8c06cd33c5c3067063c746fdcb"
dial = "2s"
timeout = "100s"
keepAlive = "60s"
timer = 1000
[httpClient.breaker]
window = "10s"
sleep = "2000ms"
bucket = 10
ratio = 0.5
request = 100
[mail]
host = "smtp.exmail.qq.com"
port = 465
username = "merlin@bilibili.com"
password = ""
noticeOwner = ["fengyifeng@bilibili.com"]
[memcache]
name = "merlin"
proto = "tcp"
addr = "172.18.33.61:11232"
idle = 5
active = 10
dialTimeout = "1s"
readTimeout = "1s"
writeTimeout = "1s"
idleTimeout = "10s"
expire = "12h"
[bugly]
host = "https://bugly.qq.com"
urlRetryCount = 3
cookieUsageUpper = 300
issuePageSize = 50
issueCountUpper = 100
[Scheduler]
#每过10分钟 更新表
batchRunEnableVersion = "0 */10 * * * ?"
batchRunUpdateTapdBug = "0 */10 * * * ?"
disableBatchRunOverTime = "0 */10 * * * ?"
batchRunOverHourTime = 3
active = false
[orm]
dsn = "root:123456@tcp(172.18.33.130:3306)/Marthe2?timeout=200ms&readTimeout=2000ms&writeTimeout=2000ms&parseTime=true&loc=Local&charset=utf8,utf8mb4"
active = 5
idle = 5
idleTimeout = "4h"
[auth]
managerHost = "http://uat-manager.bilibili.co"
dashboardHost = "http://dashboard-mng.bilibili.co"
dashboardCaller = "merlin"
[auth.DsHTTPClient]
key = "merlin"
secret = "4fb521f66dfd5efcf6e77d078ed2eb0a"
dial = "1s"
timeout = "1s"
keepAlive = "60s"
[auth.DsHTTPClient.breaker]
window = "3s"
sleep = "100ms"
bucket = 10
ratio = 0.5
request = 100
[auth.MaHTTPClient]
key = "f6433799dbd88751"
secret = "36f8ddb1806207fe07013ab6a77a3935"
dial = "1ms"
timeout = "1ms"
keepAlive = "60s"
[auth.MaHTTPClient.breaker]
window = "3s"
sleep = "100ms"
bucket = 10
ratio = 0.5
request = 100
[auth.session]
sessionIDLength = 32
cookieLifeTime = 1
cookieName = "mng-go"
domain = ".bilibili.co"
[auth.session.Memcache]
name = "go-business/auth"
proto = "tcp"
addr = "172.18.33.61:11232"
active = 10
idle = 10
dialTimeout = "1ms"
readTimeout = "1ms"
writeTimeout = "1ms"
idleTimeout = "80s"

View File

@ -0,0 +1,46 @@
package main
import (
"flag"
"os"
"os/signal"
"syscall"
"go-common/app/admin/ep/marthe/conf"
"go-common/app/admin/ep/marthe/server/http"
"go-common/app/admin/ep/marthe/service"
ecode "go-common/library/ecode/tip"
"go-common/library/log"
"go-common/library/net/trace"
)
func main() {
flag.Parse()
if err := conf.Init(); err != nil {
panic(err)
}
log.Init(conf.Conf.Log)
defer log.Close()
log.Info("start")
defer trace.Close()
ecode.Init(conf.Conf.Ecode)
s := service.New(conf.Conf)
http.Init(conf.Conf, s)
c := make(chan os.Signal, 1)
signal.Notify(c, syscall.SIGHUP, syscall.SIGQUIT, syscall.SIGTERM, syscall.SIGINT)
for {
si := <-c
log.Info("get a signal %s", si.String())
switch si {
case syscall.SIGQUIT, syscall.SIGTERM, syscall.SIGINT:
log.Info("exit")
s.Close()
return
case syscall.SIGHUP:
default:
return
}
}
}

View File

@ -0,0 +1,39 @@
package(default_visibility = ["//visibility:public"])
load(
"@io_bazel_rules_go//go:def.bzl",
"go_library",
)
go_library(
name = "go_default_library",
srcs = ["conf.go"],
importpath = "go-common/app/admin/ep/marthe/conf",
tags = ["automanaged"],
visibility = ["//visibility:public"],
deps = [
"//library/cache/memcache:go_default_library",
"//library/conf:go_default_library",
"//library/database/orm:go_default_library",
"//library/ecode/tip:go_default_library",
"//library/log:go_default_library",
"//library/net/http/blademaster:go_default_library",
"//library/net/http/blademaster/middleware/permit:go_default_library",
"//library/time:go_default_library",
"//vendor/github.com/BurntSushi/toml:go_default_library",
],
)
filegroup(
name = "package-srcs",
srcs = glob(["**"]),
tags = ["automanaged"],
visibility = ["//visibility:private"],
)
filegroup(
name = "all-srcs",
srcs = [":package-srcs"],
tags = ["automanaged"],
visibility = ["//visibility:public"],
)

View File

@ -0,0 +1,162 @@
package conf
import (
"errors"
"flag"
"go-common/library/cache/memcache"
"go-common/library/conf"
"go-common/library/database/orm"
ecode "go-common/library/ecode/tip"
"go-common/library/log"
bm "go-common/library/net/http/blademaster"
"go-common/library/net/http/blademaster/middleware/permit"
xtime "go-common/library/time"
"github.com/BurntSushi/toml"
)
var (
confPath string
client *conf.Client
// Conf Config
Conf = &Config{}
)
// Config .
type Config struct {
Log *log.Config
Bugly *BuglyConf
BM *bm.ServerConfig
Ecode *ecode.Config
ORM *orm.Config
HTTPClient *bm.ClientConfig
Mail *Mail
Auth *permit.Config
Memcache *Memcache
Scheduler *Scheduler
Tapd *TapdConf
}
func init() {
flag.StringVar(&confPath, "conf", "", "default config path")
}
// Scheduler scheduler
type Scheduler struct {
BatchRunEnableVersion string
BatchRunUpdateTapdBug string
DisableBatchRunOverTime string
BatchRunOverHourTime int
SyncWechatContact string
Active bool
}
// Memcache memcache
type Memcache struct {
*memcache.Config
Expire xtime.Duration
}
// Mail mail
type Mail struct {
Host string
Port int
Username string
Password string
NoticeOwner []string
}
// BuglyConf Bugly Conf.
type BuglyConf struct {
Host string
UrlRetryCount int
CookieUsageUpper int
IssuePageSize int
IssueCountUpper int
SuperOwner []string
}
// TapdConf Tapd Conf.
type TapdConf struct {
BugOperateAuth bool
}
// Tapd Tapd info
type Tapd struct {
IterationWorkspaceIDs []string
StoryWorkspaceIDs []string
BugWorkspaceIDs []string
IPS int
SPS int
SCPS int
CPS int
StoryFilePath string
ChangeFilePath string
IterationFilePath string
BugFilePath string
RetryTime int
WaitTime xtime.Duration
}
// Init init conf
func Init() error {
if confPath != "" {
return local()
}
return remote()
}
func local() (err error) {
_, err = toml.DecodeFile(confPath, &Conf)
return
}
func remote() (err error) {
if client, err = conf.New(); err != nil {
return
}
if err = load(); err != nil {
return
}
go func() {
for range client.Event() {
log.Info("config reload")
if load() != nil {
log.Error("config reload error (%v)", err)
}
}
}()
return
}
func load() (err error) {
var (
s string
ok bool
tmpConf *Config
)
if s, ok = client.Toml2(); !ok {
return errors.New("load config center error")
}
if _, err = toml.Decode(s, &tmpConf); err != nil {
return errors.New("could not decode config")
}
*Conf = *tmpConf
return
}

View File

@ -0,0 +1,87 @@
package(default_visibility = ["//visibility:public"])
load(
"@io_bazel_rules_go//go:def.bzl",
"go_library",
"go_test",
)
go_library(
name = "go_default_library",
srcs = [
"bugly.go",
"dao.go",
"mail.go",
"mysql_bugly_batch_run.go",
"mysql_bugly_cookie.go",
"mysql_bugly_issue.go",
"mysql_bugly_project.go",
"mysql_bugly_version.go",
"mysql_contact_info.go",
"mysql_schedule_task.go",
"mysql_tapd_bug_priority_conf.go",
"mysql_tapd_bug_record.go",
"mysql_tapd_bug_template.go",
"mysql_tapd_bug_version_template.go",
"mysql_user.go",
"tapd.go",
"wechat.go",
],
importpath = "go-common/app/admin/ep/marthe/dao",
tags = ["automanaged"],
visibility = ["//visibility:public"],
deps = [
"//app/admin/ep/marthe/conf:go_default_library",
"//app/admin/ep/marthe/model:go_default_library",
"//library/cache/memcache:go_default_library",
"//library/database/orm:go_default_library",
"//library/ecode:go_default_library",
"//library/log:go_default_library",
"//library/net/http/blademaster:go_default_library",
"//library/sync/pipeline/fanout:go_default_library",
"//vendor/github.com/jinzhu/gorm:go_default_library",
"//vendor/github.com/pkg/errors:go_default_library",
"//vendor/gopkg.in/gomail.v2:go_default_library",
],
)
filegroup(
name = "package-srcs",
srcs = glob(["**"]),
tags = ["automanaged"],
visibility = ["//visibility:private"],
)
filegroup(
name = "all-srcs",
srcs = [":package-srcs"],
tags = ["automanaged"],
visibility = ["//visibility:public"],
)
go_test(
name = "go_default_test",
srcs = [
"dao_test.go",
"mysql_bugly_batch_run_test.go",
"mysql_bugly_cookie_test.go",
"mysql_bugly_issue_test.go",
"mysql_bugly_version_test.go",
"mysql_schedule_task_test.go",
"mysql_tapd_bug_priority_confg_test.go",
"mysql_tapd_bug_record_test.go",
"mysql_tapd_bug_template_test.go",
"mysql_tapd_bug_version_template_test.go",
"mysql_user_test.go",
],
embed = [":go_default_library"],
tags = ["automanaged"],
deps = [
"//app/admin/ep/marthe/conf:go_default_library",
"//app/admin/ep/marthe/model:go_default_library",
"//vendor/github.com/go-sql-driver/mysql:go_default_library",
"//vendor/github.com/satori/go.uuid:go_default_library",
"//vendor/github.com/smartystreets/goconvey/convey:go_default_library",
"//vendor/gopkg.in/h2non/gock.v1:go_default_library",
],
)

View File

@ -0,0 +1,192 @@
package dao
import (
"context"
"fmt"
"net/http"
"strconv"
"go-common/app/admin/ep/marthe/model"
"go-common/library/ecode"
"go-common/library/log"
)
const (
_buglyOkCode = 200
_buglyCookieExpiredCode = 100006
_issueDetailCode = 100000
_issueDetailList = "/v2/lastCrashInfo/appId/%s/platformId/%s/issues/%s/crashDataType/null?offsetTop=56&fsn=6d0260aa-331f-48b9-8557-c2aaf6e0be90"
_issueList = "/v2/issueList?sortOrder=desc&sortField=uploadTime&rows=50&fsn=45cdb5aa-eb6f-4bda-9bba-ba0b264bfc93&appId=%s&platformId=%s&version=%s&start=%s&rows=%s&exceptionTypeList=%s"
_issueVersionList = "/v2/getSelector/appId/%s/platformId/%s?types=version&fsn=8b8782b5-053d-4f58-bc17-d5c43d7f5ece"
_issueExceptionList = "/v2/issueInfo/appId/%s/platformId/%s/issueId/%s/exceptionTypeList/Crash,Native,ExtensionCrash?fsn=114a8d02-586d-4fe4-8c23-79003fbe6882"
)
// BuglyVersion Bugly Version .
func (d *Dao) BuglyVersion(c context.Context, buglyCookie *model.BuglyCookie, projectID, platformID string) (ret []*model.BugVersion, err error) {
var (
req *http.Request
res *model.BugVersionResponse
hostStr string
)
hostStr = d.c.Bugly.Host + fmt.Sprintf(_issueVersionList, projectID, platformID)
if req, err = d.newRequest("GET", hostStr, nil); err != nil {
return
}
req.Header.Set("Cookie", buglyCookie.Cookie)
req.Header.Set("x-token", buglyCookie.Token)
req.Header.Set("content-type", "application/json;charset=utf-8")
req.Header.Set("x-csrf-token", "undefined")
if err = d.httpClient.Do(c, req, &res); err != nil {
log.Error("d.BugVersion url(%s) err(%v)", "BugVersion", err)
return
}
if res.Status != _buglyOkCode {
if res.Code == _buglyCookieExpiredCode {
err = ecode.MartheCookieExpired
log.Error("maybe need to update cookie and token")
} else {
err = ecode.MartheBuglyErr
}
log.Error("Status url(%s) res(%v) err(%v)", "BugVersion", res, err)
return
}
ret = res.Ret.BugVersionList
return
}
// BuglyIssueAndRetry Bugly Issue And Retry.
func (d *Dao) BuglyIssueAndRetry(c context.Context, buglyCookie *model.BuglyCookie, bugIssueRequest *model.BugIssueRequest) (ret *model.BugRet, err error) {
for i := 0; i < d.c.Bugly.UrlRetryCount; i++ {
if ret, err = d.BuglyIssue(c, buglyCookie, bugIssueRequest); err == nil {
break
}
}
return
}
// BuglyIssue Get Issue.
func (d *Dao) BuglyIssue(c context.Context, buglyCookie *model.BuglyCookie, bugIssueRequest *model.BugIssueRequest) (ret *model.BugRet, err error) {
var (
req *http.Request
res *model.BugIssueResponse
hostStr string
)
hostStr = d.c.Bugly.Host + fmt.Sprintf(_issueList, bugIssueRequest.ProjectID, bugIssueRequest.PlatformID, bugIssueRequest.Version, strconv.Itoa(bugIssueRequest.StartNum), strconv.Itoa(bugIssueRequest.Rows), bugIssueRequest.ExceptionType)
if req, err = d.newRequest("GET", hostStr, nil); err != nil {
return
}
req.Header.Set("Cookie", buglyCookie.Cookie)
req.Header.Set("x-token", buglyCookie.Token)
req.Header.Set("content-type", "application/json;charset=utf-8")
req.Header.Set("x-csrf-token", "undefined")
if err = d.httpClient.Do(c, req, &res); err != nil {
log.Error("d.BuglyIssue url(%s) err(%v)", "BuglyIssue", err)
return
}
if res.Status != _buglyOkCode {
if res.Code == _buglyCookieExpiredCode {
err = ecode.MartheCookieExpired
log.Error("maybe need to update cookie and token")
} else {
err = ecode.MartheBuglyErr
}
log.Error("Status url(%s) res(%v) err(%v)", "BuglyIssue", res, err)
return
}
ret = res.Ret
return
}
// BuglyIssueDetailAndRetry Bugly Issue Detail And Retry.
func (d *Dao) BuglyIssueDetailAndRetry(c context.Context, buglyCookie *model.BuglyCookie, projectID, platformID, issueNo string) (bugIssueDetail *model.BugIssueDetail, err error) {
for i := 0; i < d.c.Bugly.UrlRetryCount; i++ {
if bugIssueDetail, err = d.BuglyIssueDetail(c, buglyCookie, projectID, platformID, issueNo); err == nil {
break
}
}
return
}
// BuglyIssueDetail Get Issue Detail.
func (d *Dao) BuglyIssueDetail(c context.Context, buglyCookie *model.BuglyCookie, projectID, platformID, issueNo string) (bugIssueDetail *model.BugIssueDetail, err error) {
var (
req *http.Request
res *model.BugIssueDetailResponse
hostStr string
)
hostStr = d.c.Bugly.Host + fmt.Sprintf(_issueDetailList, projectID, platformID, issueNo)
if req, err = d.newRequest("GET", hostStr, nil); err != nil {
return
}
req.Header.Set("Cookie", buglyCookie.Cookie)
req.Header.Set("x-token", buglyCookie.Token)
req.Header.Set("content-type", "application/json;charset=utf-8")
req.Header.Set("x-csrf-token", "undefined")
if err = d.httpClient.Do(c, req, &res); err != nil {
log.Error("d.BuglyIssue url(%s) err(%v)", "BuglyIssue", err)
return
}
if res.Code != _issueDetailCode {
err = ecode.MartheBuglyErr
log.Error("Status url(%s) res(%v) err(%v)", "BuglyIssue", res, err)
return
}
bugIssueDetail = res.Data
return
}
// BuglyIssueExceptionList Bugly Issue Exception List.
func (d *Dao) BuglyIssueExceptionList(c context.Context, buglyCookie *model.BuglyCookie, projectID, platformID, issueNo string) (bugIssueException *model.IssueException, err error) {
var (
req *http.Request
res *model.BugIssueExceptionListResponse
hostStr string
)
hostStr = d.c.Bugly.Host + fmt.Sprintf(_issueExceptionList, projectID, platformID, issueNo)
if req, err = d.newRequest("GET", hostStr, nil); err != nil {
return
}
req.Header.Set("Cookie", buglyCookie.Cookie)
req.Header.Set("x-token", buglyCookie.Token)
req.Header.Set("content-type", "application/json;charset=utf-8")
req.Header.Set("x-csrf-token", "undefined")
if err = d.httpClient.Do(c, req, &res); err != nil {
log.Error("d.BuglyIssueExceptionList url(%s) err(%v)", "BuglyIssueExceptionList", err)
return
}
if res.Status != _buglyOkCode {
err = ecode.MartheBuglyErr
log.Error("Status url(%s) res(%v) err(%v)", "BuglyIssueExceptionList", res, err)
return
}
if res.Ret != nil && len(res.Ret.IssueException) != 0 && res.Ret.IssueException[0].IssueID == issueNo {
bugIssueException = res.Ret.IssueException[0]
}
return
}

View File

@ -0,0 +1,100 @@
package dao
import (
"bytes"
"context"
"encoding/json"
"net/http"
"time"
"go-common/app/admin/ep/marthe/conf"
"go-common/library/cache/memcache"
"go-common/library/database/orm"
"go-common/library/log"
xhttp "go-common/library/net/http/blademaster"
"go-common/library/sync/pipeline/fanout"
"github.com/jinzhu/gorm"
"gopkg.in/gomail.v2"
)
const _wildcards = "%"
// Dao dao
type Dao struct {
c *conf.Config
httpClient *xhttp.Client
email *gomail.Dialer
db *gorm.DB
cache *fanout.Fanout
mc *memcache.Pool
expire int32
}
// New init mysql db
func New(c *conf.Config) (dao *Dao) {
dao = &Dao{
c: c,
email: gomail.NewDialer(c.Mail.Host, c.Mail.Port, c.Mail.Username, c.Mail.Password),
httpClient: xhttp.NewClient(c.HTTPClient),
cache: fanout.New("mcCache", fanout.Worker(1), fanout.Buffer(1024)),
mc: memcache.NewPool(c.Memcache.Config),
expire: int32(time.Duration(c.Memcache.Expire) / time.Second),
}
if c.ORM != nil {
dao.db = orm.NewMySQL(c.ORM)
}
return
}
// Close close the resource.
func (d *Dao) Close() {
if d.db != nil {
d.db.Close()
}
if d.mc != nil {
d.mc.Close()
}
}
// Ping verify server is ok.
func (d *Dao) Ping(c context.Context) (err error) {
if d.db != nil {
if err = d.db.DB().Ping(); err != nil {
log.Info("dao.cloudDB.Ping() error(%v)", err)
}
}
return
}
func (d *Dao) newRequest(method, url string, v interface{}) (req *http.Request, err error) {
body := &bytes.Buffer{}
if method != http.MethodGet {
if err = json.NewEncoder(body).Encode(v); err != nil {
log.Error("json encode value(%s) err(%v) ", v, err)
return
}
}
if req, err = http.NewRequest(method, url, body); err != nil {
log.Error("http new request url(%s) err(%v)", url, err)
}
return
}
// cacheSave cache Save.
func (d *Dao) cacheSave(c context.Context, cacheItem *memcache.Item) {
var f = func(ctx context.Context) {
var (
conn = d.mc.Get(c)
err error
)
defer conn.Close()
if err = conn.Set(cacheItem); err != nil {
log.Error("Add Cache conn.Set(%s) error(%v)", cacheItem.Key, err)
}
}
if err := d.cache.Do(c, f); err != nil {
log.Error("ReleaseName cache save err(%v)", err)
}
}

View File

@ -0,0 +1,30 @@
package dao
import (
"context"
"flag"
"path/filepath"
"go-common/app/admin/ep/marthe/conf"
_ "github.com/go-sql-driver/mysql"
"gopkg.in/h2non/gock.v1"
)
var (
d *Dao
c context.Context
)
func init() {
dir, _ := filepath.Abs("../cmd/convey-test.toml")
flag.Set("conf", dir)
conf.Init()
d = New(conf.Conf)
d.httpClient.SetTransport(gock.DefaultTransport)
c = ctx()
}
func ctx() context.Context {
return context.Background()
}

View File

@ -0,0 +1,35 @@
package dao
import (
"context"
"strings"
"gopkg.in/gomail.v2"
)
const (
_MailBoxNotFound = "Mailbox not found"
)
// SendMail asynchronous send mail.
func (d *Dao) SendMail(message *gomail.Message) {
message.SetAddressHeader("From", d.email.Username, "merlin")
d.cache.Do(context.TODO(), func(ctx context.Context) {
d.SendMailIfFailed(message)
})
}
// SendMailIfFailed Send Mail If Failed
func (d *Dao) SendMailIfFailed(message *gomail.Message) {
if err := d.email.DialAndSend(message); err != nil {
if strings.Contains(err.Error(), _MailBoxNotFound) {
headerMsg := message.GetHeader("Subject")
headerMsg = append(headerMsg, "Mail Send Error:"+err.Error()+",Receiver:")
headerMsg = append(headerMsg, message.GetHeader("To")...)
message.SetHeader("To", d.c.Mail.NoticeOwner...)
message.SetHeader("Subject", headerMsg...)
d.email.DialAndSend(message)
}
}
}

View File

@ -0,0 +1,92 @@
package dao
import (
"go-common/app/admin/ep/marthe/model"
"go-common/library/ecode"
pkgerr "github.com/pkg/errors"
)
// InsertBuglyBatchRuns Insert Bugly Batch Runs.
func (d *Dao) InsertBuglyBatchRuns(buglyBatchRuns []*model.BuglyBatchRun) (err error) {
tx := d.db.Begin()
defer func() {
if err != nil {
if err == ecode.NothingFound {
err = nil
} else {
err = pkgerr.WithStack(err)
}
}
}()
if err = tx.Error; err != nil {
return
}
for _, buglyBatchRun := range buglyBatchRuns {
if err = d.db.Create(buglyBatchRun).Error; err != nil {
tx.Rollback()
return
}
}
if err = tx.Commit().Error; err != nil {
tx.Rollback()
}
return
}
// InsertBuglyBatchRun Insert Bugly Batch Run.
func (d *Dao) InsertBuglyBatchRun(buglyBatchRun *model.BuglyBatchRun) error {
return pkgerr.WithStack(d.db.Create(buglyBatchRun).Error)
}
// UpdateBuglyBatchRun Update Bugly Batch Run.
func (d *Dao) UpdateBuglyBatchRun(buglyBatchRun *model.BuglyBatchRun) error {
return pkgerr.WithStack(d.db.Model(&model.BuglyBatchRun{}).Where("id=?", buglyBatchRun.ID).Updates(buglyBatchRun).Error)
}
// FindBuglyBatchRuns Find Bugly Batch Runs.
func (d *Dao) FindBuglyBatchRuns(req *model.QueryBuglyBatchRunsRequest) (total int64, buglyBatchRuns []*model.BuglyBatchRun, err error) {
gDB := d.db.Model(&model.BuglyBatchRun{})
if req.Version != "" {
gDB = gDB.Where("version=?", req.Version)
}
if req.Status != 0 {
gDB = gDB.Where("status=?", req.Status)
}
if req.BatchID != "" {
gDB = gDB.Where("batch_id=?", req.BatchID)
}
if err = pkgerr.WithStack(gDB.Count(&total).Error); err != nil {
return
}
err = pkgerr.WithStack(gDB.Order("ctime desc").Offset((req.PageNum - 1) * req.PageSize).Limit(req.PageSize).Find(&buglyBatchRuns).Error)
return
}
// QueryBuglyBatchRunsByStatus Find Bugly Batch Runs By Status.
func (d *Dao) QueryBuglyBatchRunsByStatus(status int) (buglyBatchRuns []*model.BuglyBatchRun, err error) {
err = pkgerr.WithStack(d.db.Where("status = ?", status).Find(&buglyBatchRuns).Error)
return
}
// QueryLastSuccessBatchRunByVersion Find Last Success Batch Run By Version.
func (d *Dao) QueryLastSuccessBatchRunByVersion(version string) (buglyBatchRun *model.BuglyBatchRun, err error) {
buglyBatchRun = &model.BuglyBatchRun{}
if err = d.db.Where("version = ? and status = ?", version, model.BuglyBatchRunStatusDone).Order("id desc").First(&buglyBatchRun).Error; err != nil {
if err == ecode.NothingFound {
err = nil
} else {
err = pkgerr.WithStack(err)
}
}
return
}

View File

@ -0,0 +1,58 @@
package dao
import (
"testing"
"time"
"go-common/app/admin/ep/marthe/model"
"github.com/satori/go.uuid"
. "github.com/smartystreets/goconvey/convey"
)
var (
tmpVersion = time.Now().Format("2006_01_02_15_04_05")
buglyBatchRun = &model.BuglyBatchRun{
BuglyVersionID: 1,
Version: tmpVersion,
BatchID: uuid.NewV4().String(),
RetryCount: 0,
Status: model.BuglyBatchRunStatusRunning,
ErrorMsg: "no",
}
queryBuglyBatchRunsRequest = &model.QueryBuglyBatchRunsRequest{
Pagination: model.Pagination{
PageSize: 10,
PageNum: 1,
},
Version: tmpVersion,
}
)
func Test_Bugly_batch_run(t *testing.T) {
Convey("test insert bugly batch run", t, func() {
err := d.InsertBuglyBatchRun(buglyBatchRun)
So(err, ShouldBeNil)
})
Convey("test update bugly batch run", t, func() {
buglyBatchRun.Status = model.BuglyBatchRunStatusDone
err := d.UpdateBuglyBatchRun(buglyBatchRun)
So(err, ShouldBeNil)
})
Convey("test Find Bugly Batch Runs", t, func() {
buglyBatchRun.Status = model.BuglyBatchRunStatusDone
total, buglyBatchRuns, err := d.FindBuglyBatchRuns(queryBuglyBatchRunsRequest)
So(err, ShouldBeNil)
So(total, ShouldEqual, 1)
So(buglyBatchRun.BatchID, ShouldEqual, buglyBatchRuns[0].BatchID)
})
Convey("test Find Last Success Batch Run By Version", t, func() {
tmpBuglyBatchRun, err := d.QueryLastSuccessBatchRunByVersion(tmpVersion)
So(err, ShouldBeNil)
So(buglyBatchRun.BatchID, ShouldEqual, tmpBuglyBatchRun.BatchID)
})
}

View File

@ -0,0 +1,67 @@
package dao
import (
"go-common/app/admin/ep/marthe/model"
"go-common/library/ecode"
pkgerr "github.com/pkg/errors"
)
// InsertCookie Insert Cookie.
func (d *Dao) InsertCookie(buglyCookie *model.BuglyCookie) error {
return pkgerr.WithStack(d.db.Create(buglyCookie).Error)
}
// UpdateCookie Update cookie.
func (d *Dao) UpdateCookie(buglyCookie *model.BuglyCookie) error {
return pkgerr.WithStack(d.db.Model(&model.BuglyCookie{}).Updates(buglyCookie).Error)
}
// UpdateCookieStatus Update Cookie Status.
func (d *Dao) UpdateCookieStatus(id int64, status int) error {
return pkgerr.WithStack(d.db.Model(&model.BuglyCookie{}).Where("id = ?", id).Update("status", status).Error)
}
// UpdateCookieUsageCount Update Cookie Usage Count.
func (d *Dao) UpdateCookieUsageCount(id int64, usageCount int) error {
return pkgerr.WithStack(d.db.Model(&model.BuglyCookie{}).Where("id = ?", id).Update("usage_count", usageCount).Error)
}
// QueryCookieByStatus Query Cookie By Status.
func (d *Dao) QueryCookieByStatus(status int) (buglyCookies []*model.BuglyCookie, err error) {
err = pkgerr.WithStack(d.db.Where("status=?", status).Order("ctime desc").Find(&buglyCookies).Error)
return
}
// QueryCookieByQQAccount Query Cookie By QQ Account.
func (d *Dao) QueryCookieByQQAccount(qqAccount int) (buglyCookie *model.BuglyCookie, err error) {
buglyCookie = &model.BuglyCookie{}
if err = d.db.Where("qq_account=?", qqAccount).First(buglyCookie).Error; err != nil {
if err == ecode.NothingFound {
err = nil
} else {
err = pkgerr.WithStack(err)
}
}
return
}
// FindCookies Find Cookies.
func (d *Dao) FindCookies(req *model.QueryBuglyCookiesRequest) (total int64, buglyCookies []*model.BuglyCookie, err error) {
gDB := d.db.Model(&model.BuglyCookie{})
if req.QQAccount != 0 {
gDB = gDB.Where("qq_account=?", req.QQAccount)
}
if req.Status != 0 {
gDB = gDB.Where("status=?", req.Status)
}
if err = pkgerr.WithStack(gDB.Count(&total).Error); err != nil {
return
}
err = pkgerr.WithStack(gDB.Order("ctime desc").Offset((req.PageNum - 1) * req.PageSize).Limit(req.PageSize).Find(&buglyCookies).Error)
return
}

View File

@ -0,0 +1,51 @@
package dao
import (
"testing"
"go-common/app/admin/ep/marthe/model"
. "github.com/smartystreets/goconvey/convey"
)
var (
buglyCookie = &model.BuglyCookie{
QQAccount: 246802468,
Cookie: "eas_sid=6105G3k2D0Q428f5u0c6B527B0; pgv_pvi=95820800; RK=kfyEYkBgS6; btcu_id=c64abeb0e4f6485712c0bb79bf16c19d5b6aa5326be74; vc=vc-01c6b914-d8f9-4449-adcb-abba3ebe137c; vc.sig=b8t0PNSdSX1m4wOr-B12whzwaf75BlJjOjz5Jy7YTkE; _ga=GA1.2.1955813367.1533715741; pgv_si=s229603328; _qpsvr_localtk=0.0198901072762101; o_cookie=972360526; pac_uid=1_972360526; csrfToken=gekJ-F5QdGgVTZqLC0NiBEOA; ptui_loginuin=1211712225; ptisp=ctc; ptcz=f45f877d04ce6b659e432a158d35cbc9dea2c565d17eb6ee23640a0c7f82aaf9; uin=o1211712225; skey=@FGItvXrQ6; pt2gguin=o1211712225; IED_LOG_INFO2=userUin%3D1211712225%26nickName%3D%2525E5%2525B0%25258F%2525E7%2525BE%25258E+%26userLoginTime%3D1545802497; midas_openid=1211712225; midas_openkey=@FGItvXrQ6; pgv_info=ssid=s2529006206&pgvReferrer=; pgv_pvid=7939868100; NODINX_SESS=7XIt-RXcFpUaAwKwVFHFbIsssGiryDAw_dF_oP1uVFP2V5vV95jh92eADSSJIq0v; token-skey=771060e7-cd54-f0b3-960c-c8fe485fde10; token-lifeTime=1545828885; bugly_session=eyJpdiI6IldLOHM2V2lhNXFyemdMV1d6YXQ0SHc9PSIsInZhbHVlIjoiekt5UllBZWU4OEltSDVzTzJOeHRESjdQMWY5Y1wveEpYbUlDNmxrV25XTHR3ME5RMkRUdk9VaGlKbGFrQ0cxc2xoUzBOVXdCM0hzVWZIemlFR1BLZXJnPT0iLCJtYWMiOiJhZTI5ZmVjNmVjNzZjMWI2MTMyM2U4NWE5MGZiNWMxMjQzZmEzMWEyMGZhMTcxZjg1N2FiOTY4OTgxNWZjMDExIn0%3D; referrer=eyJpdiI6Im9FZ00yMHdsS2hIeHp3UERSaFVhWlE9PSIsInZhbHVlIjoiZXN6dmZFWmJ4V3R6UmordnowVXZkMXdhbm8zN3QrNzVcL2NSc1I0eWw1ZUVYbVFvTnlwdDB2QWVoaXp4VmZxY2tFV2VSdDIrWG40bEpqb3hvWTZmaVAwXC9vR1JqNEE5NG1MQnlkR1dvV1dkWitSakV6RjV1dWF4dEtzbGpXRFhsNW10SEhrSDVrZk1tRE9EXC9zUEVBRGxwSzhoTHRzSHhuTktFV1g1ckpOTEo0PSIsIm1hYyI6IjAzZWJiMjQ0YjkyNmUyYTk2MDRmNTdjYjY2OWYwNzIzZjZjMmNiMzU0NWRhZmExZWFhYWUzMGFiMTI2MDI4NzIifQ%3D%3F",
Token: "1768129694",
UsageCount: 0,
Status: model.BuglyCookieStatusEnable,
}
queryBuglyCookiesRequest = &model.QueryBuglyCookiesRequest{
Pagination: model.Pagination{
PageSize: 10,
PageNum: 1,
},
QQAccount: buglyCookie.QQAccount,
}
)
func Test_Bugly_cookie(t *testing.T) {
Convey("test insert bugly cookie", t, func() {
err := d.InsertCookie(buglyCookie)
So(err, ShouldBeNil)
})
Convey("test Update Cookie Status", t, func() {
err := d.UpdateCookieStatus(buglyCookie.ID, model.BuglyCookieStatusDisable)
So(err, ShouldBeNil)
})
Convey("test Update Cookie Usage Count", t, func() {
err := d.UpdateCookieUsageCount(buglyCookie.ID, 5)
So(err, ShouldBeNil)
})
Convey("test Find Cookies", t, func() {
total, buglyCookies, err := d.FindCookies(queryBuglyCookiesRequest)
So(err, ShouldBeNil)
So(total, ShouldBeGreaterThan, 0)
So(len(buglyCookies), ShouldBeGreaterThan, 0)
})
}

View File

@ -0,0 +1,104 @@
package dao
import (
"go-common/app/admin/ep/marthe/model"
"go-common/library/ecode"
pkgerr "github.com/pkg/errors"
)
// GetBuglyIssue Get Issue Record.
func (d *Dao) GetBuglyIssue(issueNo, version string) (buglyIssue *model.BuglyIssue, err error) {
buglyIssue = &model.BuglyIssue{}
if err = d.db.Where("issue_no = ? and version = ?", issueNo, version).First(buglyIssue).Error; err != nil {
if err == ecode.NothingFound {
err = nil
} else {
err = pkgerr.WithStack(err)
}
}
return
}
// UpdateBuglyIssue Update Issue Record.
func (d *Dao) UpdateBuglyIssue(buglyIssue *model.BuglyIssue) error {
return pkgerr.WithStack(d.db.Model(&model.BuglyIssue{}).Where("issue_no = ? and version = ?", buglyIssue.IssueNo, buglyIssue.Version).UpdateColumn(map[string]interface{}{
"last_time": buglyIssue.LastTime,
"happen_times": buglyIssue.HappenTimes,
"user_times": buglyIssue.UserTimes,
}).Error)
}
// InsertBuglyIssue Insert Issue Record.
func (d *Dao) InsertBuglyIssue(buglyIssue *model.BuglyIssue) (err error) {
return pkgerr.WithStack(d.db.Model(&model.BuglyIssue{}).Create(buglyIssue).Error)
}
// GetBuglyIssuesByFilterSQL Get Bugly Issues By Filter SQL.
func (d *Dao) GetBuglyIssuesByFilterSQL(issueFilterSQL string) (buglyIssues []*model.BuglyIssue, err error) {
if err = d.db.Raw(issueFilterSQL).Order("id asc").Find(&buglyIssues).Error; err != nil {
if err == ecode.NothingFound {
err = nil
} else {
err = pkgerr.WithStack(err)
}
}
return
}
// UpdateBuglyIssueTapdBugID Update Issue Record Tapd Bug ID.
func (d *Dao) UpdateBuglyIssueTapdBugID(id int64, tapdBugID string) error {
return pkgerr.WithStack(d.db.Model(&model.BuglyIssue{}).Where("id=?", id).Update("tapd_bug_id", tapdBugID).Error)
}
// FindBuglyIssues Find Bugly Issues.
func (d *Dao) FindBuglyIssues(req *model.QueryBuglyIssueRequest) (total int64, buglyIssues []*model.BuglyIssue, err error) {
gDB := d.db.Model(&model.BuglyIssue{})
if req.IssueNo != "" {
gDB = gDB.Where("issue_no = ?", req.IssueNo)
}
if req.Title != "" {
gDB = gDB.Where("title like ?", _wildcards+req.Title+_wildcards)
}
if req.ExceptionMsg != "" {
gDB = gDB.Where("exception_msg like ?", _wildcards+req.ExceptionMsg+_wildcards)
}
if req.KeyStack != "" {
gDB = gDB.Where("key_stack like ?", _wildcards+req.KeyStack+_wildcards)
}
if req.Detail != "" {
gDB = gDB.Where("detail like ?", _wildcards+req.Detail+_wildcards)
}
if req.Tags != "" {
gDB = gDB.Where("tags like ?", _wildcards+req.Tags+_wildcards)
}
if req.Version != "" {
gDB = gDB.Where("version like ?", _wildcards+req.Version+_wildcards)
}
if req.ProjectID != "" {
gDB = gDB.Where("project_id like ?", _wildcards+req.ProjectID+_wildcards)
}
if req.TapdBugID != "" {
gDB = gDB.Where("tapd_bug_id = ?", req.TapdBugID)
}
if err = pkgerr.WithStack(gDB.Count(&total).Error); err != nil {
return
}
err = pkgerr.WithStack(gDB.Order("mtime desc").Offset((req.PageNum - 1) * req.PageSize).Limit(req.PageSize).Find(&buglyIssues).Error)
return
}
// GetBuglyIssuesHasInTapd Get Bugly Issues Has In Tapd.
func (d *Dao) GetBuglyIssuesHasInTapd() (buglyIssues []*model.BuglyIssue, err error) {
if err = d.db.Where("tapd_bug_id<>''").Find(&buglyIssues).Error; err != nil {
if err == ecode.NothingFound {
err = nil
} else {
err = pkgerr.WithStack(err)
}
}
return
}

View File

@ -0,0 +1,78 @@
package dao
import (
"strconv"
"testing"
"time"
"go-common/app/admin/ep/marthe/model"
. "github.com/smartystreets/goconvey/convey"
)
var (
tmpIssueNoStr = strconv.FormatInt(time.Now().Unix(), 10)
tmpTapdBugID = "bug" + tmpIssueNoStr
buglyIssue = &model.BuglyIssue{
IssueNo: tmpIssueNoStr,
Title: "Title" + tmpIssueNoStr,
ExceptionMsg: "ExceptionMsg" + tmpIssueNoStr,
KeyStack: "KeyStack" + tmpIssueNoStr,
Detail: "Detail" + tmpIssueNoStr,
Tags: "Tags" + tmpIssueNoStr,
LastTime: time.Now(),
HappenTimes: 10,
UserTimes: 20,
Version: "Version" + tmpIssueNoStr,
ProjectID: "ProjectID" + tmpIssueNoStr,
IssueLink: "IssueLink" + tmpIssueNoStr,
}
queryBuglyIssueRequest = &model.QueryBuglyIssueRequest{
Pagination: model.Pagination{
PageSize: 10,
PageNum: 1,
},
IssueNo: buglyIssue.IssueNo,
}
)
func Test_Bugly_Issue(t *testing.T) {
Convey("test insert bugly issue", t, func() {
err := d.InsertBuglyIssue(buglyIssue)
So(err, ShouldBeNil)
})
Convey("test update Bugly Issue", t, func() {
buglyIssue.ExceptionMsg = "update exception message"
err := d.UpdateBuglyIssue(buglyIssue)
So(err, ShouldBeNil)
})
Convey("test update Bugly Issue tapd bug id", t, func() {
err := d.UpdateBuglyIssueTapdBugID(buglyIssue.ID, tmpTapdBugID)
So(err, ShouldBeNil)
})
Convey("test Get Bugly Issue", t, func() {
tmpBuglyIssue, err := d.GetBuglyIssue(buglyIssue.IssueNo, buglyIssue.Version)
So(err, ShouldBeNil)
So(tmpBuglyIssue.ID, ShouldEqual, buglyIssue.ID)
})
Convey("test Get Bugly Issues By Filter SQL", t, func() {
sql := "select * from bugly_issues where issue_no = '" + buglyIssue.IssueNo + "'"
tmpBuglyIssues, err := d.GetBuglyIssuesByFilterSQL(sql)
So(err, ShouldBeNil)
So(tmpBuglyIssues[0].IssueNo, ShouldEqual, buglyIssue.IssueNo)
})
Convey("test Find Bugly Issues", t, func() {
total, tmpBuglyIssues, err := d.FindBuglyIssues(queryBuglyIssueRequest)
So(err, ShouldBeNil)
So(total, ShouldBeGreaterThan, 0)
So(len(tmpBuglyIssues), ShouldBeGreaterThan, 0)
})
}

View File

@ -0,0 +1,89 @@
package dao
import (
"database/sql"
"go-common/app/admin/ep/marthe/model"
"go-common/library/ecode"
pkgerr "github.com/pkg/errors"
)
// InsertBuglyProject Insert Bugly Project.
func (d *Dao) InsertBuglyProject(buglyProject *model.BuglyProject) error {
return pkgerr.WithStack(d.db.Create(buglyProject).Error)
}
// UpdateBuglyProject Update Bugly Project.
func (d *Dao) UpdateBuglyProject(buglyProject *model.BuglyProject) error {
return pkgerr.WithStack(d.db.Model(&model.BuglyProject{}).Updates(buglyProject).Error)
}
// QueryBuglyProject Query Bugly Project.
func (d *Dao) QueryBuglyProject(id int64) (buglyProject *model.BuglyProject, err error) {
buglyProject = &model.BuglyProject{}
err = pkgerr.WithStack(d.db.Where("id = ?", id).First(buglyProject).Error)
return
}
// QueryBuglyProjectByName Query Bugly Project.
func (d *Dao) QueryBuglyProjectByName(projectName string) (buglyProject *model.BuglyProject, err error) {
buglyProject = &model.BuglyProject{}
if err = d.db.Where("project_name = ?", projectName).First(buglyProject).Error; err == ecode.NothingFound {
err = nil
}
return
}
// QueryAllBuglyProjects Query All Bugly Project.
func (d *Dao) QueryAllBuglyProjects() (buglyProjects []*model.BuglyProject, err error) {
err = pkgerr.WithStack(d.db.Model(&model.BuglyProject{}).Find(&buglyProjects).Error)
return
}
// FindBuglyProjects Find Bugly Project.
func (d *Dao) FindBuglyProjects(req *model.QueryBuglyProjectRequest) (total int64, buglyProject []*model.BuglyProject, err error) {
gDB := d.db.Model(&model.BuglyProject{})
if req.ProjectID != "" {
gDB = gDB.Where("project_id=?", req.ProjectID)
}
if req.ProjectName != "" {
gDB = gDB.Where("project_name like ?", _wildcards+req.ProjectName+_wildcards)
}
if req.PlatformID != "" {
gDB = gDB.Where("platform_id=?", req.PlatformID)
}
if req.UpdateBy != "" {
gDB = gDB.Where("update_by=?", req.UpdateBy)
}
if err = pkgerr.WithStack(gDB.Count(&total).Error); err != nil {
return
}
err = pkgerr.WithStack(gDB.Order("ctime desc").Offset((req.PageNum - 1) * req.PageSize).Limit(req.PageSize).Find(&buglyProject).Error)
return
}
// QueryBuglyProjectList Query Bugly Project List.
func (d *Dao) QueryBuglyProjectList() (projectList []string, err error) {
var (
rows *sql.Rows
)
sql := "select DISTINCT project_name from bugly_projects"
if rows, err = d.db.Raw(sql).Rows(); err != nil {
return
}
defer rows.Close()
for rows.Next() {
var ver string
if err = rows.Scan(&ver); err != nil {
return
}
projectList = append(projectList, ver)
}
return
}

View File

@ -0,0 +1,139 @@
package dao
import (
"database/sql"
"fmt"
"go-common/app/admin/ep/marthe/model"
"go-common/library/ecode"
pkgerr "github.com/pkg/errors"
)
const (
_versionInnerJoinProjectSql = "select a.id,a.version,a.bugly_project_id,a.action,a.task_status,a.update_by,a.ctime,a.mtime,b.project_name,b.exception_type from bugly_versions as a inner join bugly_projects as b on a.bugly_project_id = b.id"
_versionInnerJoinProjectSqlCount = "select count(-1) as totalCount from bugly_versions as a inner join bugly_projects as b on a.bugly_project_id = b.id"
_where = "WHERE"
_and = "AND"
)
// InsertBuglyVersion Insert Bugly Version.
func (d *Dao) InsertBuglyVersion(buglyVersion *model.BuglyVersion) error {
return pkgerr.WithStack(d.db.Create(buglyVersion).Error)
}
// UpdateBuglyVersion Update Bugly Version.
func (d *Dao) UpdateBuglyVersion(buglyVersion *model.BuglyVersion) error {
return pkgerr.WithStack(d.db.Model(&model.BuglyVersion{}).Updates(buglyVersion).Error)
}
// QueryBuglyVersionByVersion Query Bugly Version By Version.
func (d *Dao) QueryBuglyVersionByVersion(version string) (buglyVersion *model.BuglyVersion, err error) {
buglyVersion = &model.BuglyVersion{}
if err = d.db.Where("version = ?", version).First(buglyVersion).Error; err != nil {
if err == ecode.NothingFound {
err = nil
} else {
err = pkgerr.WithStack(err)
}
}
return
}
// QueryBuglyVersion Query Bugly Version .
func (d *Dao) QueryBuglyVersion(id int64) (buglyVersion *model.BuglyVersion, err error) {
buglyVersion = &model.BuglyVersion{}
if err = d.db.Where("id = ?", id).First(buglyVersion).Error; err != nil {
if err == ecode.NothingFound {
err = nil
} else {
err = pkgerr.WithStack(err)
}
}
return
}
// QueryBuglyVersionList Query Bugly Version List.
func (d *Dao) QueryBuglyVersionList() (versionList []string, err error) {
var (
rows *sql.Rows
)
sql := "select DISTINCT version from bugly_versions"
if rows, err = d.db.Raw(sql).Rows(); err != nil {
return
}
defer rows.Close()
for rows.Next() {
var ver string
if err = rows.Scan(&ver); err != nil {
return
}
versionList = append(versionList, ver)
}
return
}
// FindBuglyProjectVersions Find Bugly Project Versions.
func (d *Dao) FindBuglyProjectVersions(req *model.QueryBuglyVersionRequest) (total int64, buglyProjectVersions []*model.BuglyProjectVersion, err error) {
var (
qSQL = _versionInnerJoinProjectSql
cSQL = _versionInnerJoinProjectSqlCount
rows *sql.Rows
)
if req.UpdateBy != "" || req.ProjectName != "" || req.Action > 0 || req.Version != "" {
var (
partSql string
logicalWord = _where
)
if req.UpdateBy != "" {
partSql = fmt.Sprintf("%s %s a.update_by = '%s'", partSql, logicalWord, req.UpdateBy)
logicalWord = _and
}
if req.ProjectName != "" {
partSql = fmt.Sprintf("%s %s b.project_name like '%s'", partSql, logicalWord, _wildcards+req.ProjectName+_wildcards)
logicalWord = _and
}
if req.Action > 0 {
partSql = fmt.Sprintf("%s %s a.action = %d", partSql, logicalWord, req.Action)
logicalWord = _and
}
if req.Version != "" {
partSql = fmt.Sprintf("%s %s a.version like '%s'", partSql, logicalWord, _wildcards+req.Version+_wildcards)
logicalWord = _and
}
qSQL = qSQL + partSql
cSQL = cSQL + partSql
}
cDB := d.db.Raw(cSQL)
if err = pkgerr.WithStack(cDB.Count(&total).Error); err != nil {
return
}
gDB := d.db.Raw(qSQL)
if rows, err = gDB.Order("a.ctime DESC").Offset((req.PageNum - 1) * req.PageSize).Limit(req.PageSize).Rows(); err != nil {
return
}
defer rows.Close()
for rows.Next() {
pv := &model.BuglyProjectVersion{}
if err = rows.Scan(&pv.ID, &pv.Version, &pv.BuglyProjectID, &pv.Action, &pv.TaskStatus, &pv.UpdateBy, &pv.CTime, &pv.MTime, &pv.ProjectName, &pv.ExceptionType); err != nil {
return
}
buglyProjectVersions = append(buglyProjectVersions, pv)
}
return
}
// FindEnableAndReadyVersions Find Enable And Ready Versions.
func (d *Dao) FindEnableAndReadyVersions() (buglyVersions []*model.BuglyVersion, err error) {
err = pkgerr.WithStack(d.db.Where("action = ? and task_status = ?", model.BuglyVersionActionEnable, model.BuglyVersionTaskStatusReady).Find(&buglyVersions).Error)
return
}

View File

@ -0,0 +1,49 @@
package dao
import (
"strconv"
"testing"
"time"
"go-common/app/admin/ep/marthe/model"
. "github.com/smartystreets/goconvey/convey"
)
var (
tmpIssueNoStr2 = strconv.FormatInt(time.Now().Unix(), 10)
buglyVersion = &model.BuglyVersion{
Version: "Version" + tmpIssueNoStr2,
BuglyProjectID: 1,
Action: model.BuglyVersionActionDisable,
TaskStatus: 1,
UpdateBy: "fengyifeng",
}
)
func Test_Bugly_Version(t *testing.T) {
Convey("test insert bugly Version", t, func() {
err := d.InsertBuglyVersion(buglyVersion)
So(err, ShouldBeNil)
})
Convey("test update bugly Version", t, func() {
buglyVersion.Version = "update" + tmpIssueNoStr2
err := d.UpdateBuglyVersion(buglyVersion)
So(err, ShouldBeNil)
})
Convey("test Query Bugly Version By Version", t, func() {
tmpBuglyVersion, err := d.QueryBuglyVersionByVersion(buglyVersion.Version)
So(err, ShouldBeNil)
So(tmpBuglyVersion.Version, ShouldEqual, buglyVersion.Version)
})
Convey("test Query Bugly Version By Id", t, func() {
tmpBuglyVersion, err := d.QueryBuglyVersion(buglyVersion.ID)
So(err, ShouldBeNil)
So(tmpBuglyVersion.Version, ShouldEqual, buglyVersion.Version)
})
}

View File

@ -0,0 +1,50 @@
package dao
import (
"go-common/app/admin/ep/marthe/model"
"go-common/library/ecode"
pkgerr "github.com/pkg/errors"
)
// InsertContactInfo Insert Contact Info.
func (d *Dao) InsertContactInfo(contactInfo *model.ContactInfo) error {
return pkgerr.WithStack(d.db.Create(contactInfo).Error)
}
// UpdateContactInfo Update Contact Info.
func (d *Dao) UpdateContactInfo(contactInfo *model.ContactInfo) error {
return pkgerr.WithStack(d.db.Save(&contactInfo).Error)
}
// QueryContactInfoByUserID Query Contact Info By User ID
func (d *Dao) QueryContactInfoByUserID(userID string) (contactInfo *model.ContactInfo, err error) {
contactInfo = &model.ContactInfo{}
if err = d.db.Where("user_id = ?", userID).First(contactInfo).Error; err != nil {
if err == ecode.NothingFound {
err = nil
} else {
err = pkgerr.WithStack(err)
}
}
return
}
// QueryContactInfoByUsername Query Contact Info By Username
func (d *Dao) QueryContactInfoByUsername(username string) (contactInfo *model.ContactInfo, err error) {
contactInfo = &model.ContactInfo{}
if err = d.db.Where("username = ?", username).First(contactInfo).Error; err != nil {
if err == ecode.NothingFound {
err = nil
} else {
err = pkgerr.WithStack(err)
}
}
return
}
// QueryAllContactInfos Query All Contact Infos
func (d *Dao) QueryAllContactInfos() (contactInfos []*model.ContactInfo, err error) {
err = pkgerr.WithStack(d.db.Find(&contactInfos).Error)
return
}

View File

@ -0,0 +1,17 @@
package dao
import (
"go-common/app/admin/ep/marthe/model"
pkgerr "github.com/pkg/errors"
)
// InsertScheduleTask Insert Schedule Task.
func (d *Dao) InsertScheduleTask(scheduleTask *model.ScheduleTask) error {
return pkgerr.WithStack(d.db.Create(scheduleTask).Error)
}
// UpdateScheduleTask Update Schedule Task.
func (d *Dao) UpdateScheduleTask(scheduleTask *model.ScheduleTask) error {
return pkgerr.WithStack(d.db.Model(&model.ScheduleTask{}).Updates(scheduleTask).Error)
}

View File

@ -0,0 +1,33 @@
package dao
import (
"strconv"
"testing"
"time"
"go-common/app/admin/ep/marthe/model"
. "github.com/smartystreets/goconvey/convey"
)
var (
tmpIssueNoStr3 = strconv.FormatInt(time.Now().Unix(), 10)
scheduleTask = &model.ScheduleTask{
Name: tmpIssueNoStr3,
Status: model.TaskStatusRunning,
}
)
func Test_Schedule_task(t *testing.T) {
Convey("test insert schedule task", t, func() {
err := d.InsertScheduleTask(scheduleTask)
So(err, ShouldBeNil)
})
Convey("test update schedule task", t, func() {
scheduleTask.Status = model.TaskStatusDone
err := d.UpdateScheduleTask(scheduleTask)
So(err, ShouldBeNil)
})
}

View File

@ -0,0 +1,47 @@
package dao
import (
"go-common/app/admin/ep/marthe/model"
pkgerr "github.com/pkg/errors"
)
// InsertTapdBugPriorityConf Insert Tapd Bug Priority Conf.
func (d *Dao) InsertTapdBugPriorityConf(tapdBugPriorityConf *model.TapdBugPriorityConf) error {
return pkgerr.WithStack(d.db.Create(tapdBugPriorityConf).Error)
}
// UpdateTapdBugPriorityConf Update Tapd Bug Priority Conf.
func (d *Dao) UpdateTapdBugPriorityConf(tapdBugPriorityConf *model.TapdBugPriorityConf) error {
return pkgerr.WithStack(d.db.Save(&tapdBugPriorityConf).Error)
}
// QueryTapdBugPriorityConfsByProjectTemplateIdAndStatus Query Tapd Bug Priority Confs By Project TemplateId And tatus.
func (d *Dao) QueryTapdBugPriorityConfsByProjectTemplateIdAndStatus(projectTemplateID int64, status int) (tapdBugPriorityConfs []*model.TapdBugPriorityConf, err error) {
err = pkgerr.WithStack(d.db.Where("project_template_id = ? and status = ?", projectTemplateID, status).Find(&tapdBugPriorityConfs).Error)
return
}
// FindTapdBugPriorityConfs Find Tapd Bug Priority Confs.
func (d *Dao) FindTapdBugPriorityConfs(req *model.QueryTapdBugPriorityConfsRequest) (total int64, tapdBugPriorityConfs []*model.TapdBugPriorityConf, err error) {
gDB := d.db.Model(&model.TapdBugPriorityConf{})
if req.ProjectTemplateID > 0 {
gDB = gDB.Where("project_template_id=?", req.ProjectTemplateID)
}
if req.UpdateBy != "" {
gDB = gDB.Where("update_by=?", req.UpdateBy)
}
if req.Status > 0 {
gDB = gDB.Where("status=?", req.Status)
}
if err = pkgerr.WithStack(gDB.Count(&total).Error); err != nil {
return
}
err = pkgerr.WithStack(gDB.Order("ctime desc").Offset((req.PageNum - 1) * req.PageSize).Limit(req.PageSize).Find(&tapdBugPriorityConfs).Error)
return
}

View File

@ -0,0 +1,52 @@
package dao
import (
"testing"
"go-common/app/admin/ep/marthe/model"
. "github.com/smartystreets/goconvey/convey"
"time"
)
var (
tapdBugPriorityConf = &model.TapdBugPriorityConf{
ProjectTemplateID: 1000,
Urgent: 123,
High: 321,
Medium: 111,
UpdateBy: "fengyifeng",
StartTime: time.Now(),
EndTime: time.Now().AddDate(0, 1, 0),
Status: model.TapdBugPriorityConfDisable,
}
queryTapdBugPriorityConfsRequest = &model.QueryTapdBugPriorityConfsRequest{
Pagination: model.Pagination{
PageSize: 10,
PageNum: 1,
},
ProjectTemplateID: 1000,
}
)
func Test_Tapd_Bug_Priority_Conf(t *testing.T) {
Convey("test Insert Tapd Bug Priority Conf", t, func() {
err := d.InsertTapdBugPriorityConf(tapdBugPriorityConf)
So(err, ShouldBeNil)
})
Convey("test Update Tapd Bug Priority Conf", t, func() {
tapdBugPriorityConf.Urgent = 10010
err := d.UpdateTapdBugPriorityConf(tapdBugPriorityConf)
So(err, ShouldBeNil)
})
Convey("test Find Tapd Bug Priority Confs", t, func() {
total, tapdBugPriorityConfs, err := d.FindTapdBugPriorityConfs(queryTapdBugPriorityConfsRequest)
So(err, ShouldBeNil)
So(total, ShouldBeGreaterThan, 0)
So(len(tapdBugPriorityConfs), ShouldBeGreaterThan, 0)
})
}

View File

@ -0,0 +1,57 @@
package dao
import (
"go-common/app/admin/ep/marthe/model"
pkgerr "github.com/pkg/errors"
)
// InsertTapdBugRecord Insert Tapd Bug Insert Log.
func (d *Dao) InsertTapdBugRecord(tapdBugRecord *model.TapdBugRecord) error {
return pkgerr.WithStack(d.db.Create(tapdBugRecord).Error)
}
// UpdateTapdBugRecord Update Tapd Bug Insert Log.
func (d *Dao) UpdateTapdBugRecord(tapdBugRecord *model.TapdBugRecord) error {
return pkgerr.WithStack(d.db.Save(&tapdBugRecord).Error)
}
// QueryTapdBugRecordByProjectIDAndStatus Query Tapd Bug Record By Project ID and status
func (d *Dao) QueryTapdBugRecordByProjectIDAndStatus(projectID int64, status int) (tapdBugRecords []*model.TapdBugRecord, err error) {
err = pkgerr.WithStack(d.db.Where("project_template_id = ? and status = ?", projectID, status).Find(&tapdBugRecords).Error)
return
}
// QueryTapdBugRecordByStatus Query Tapd Bug Record By and status
func (d *Dao) QueryTapdBugRecordByStatus(status int) (tapdBugRecords []*model.TapdBugRecord, err error) {
err = pkgerr.WithStack(d.db.Where("status = ?", status).Find(&tapdBugRecords).Error)
return
}
// FindBugRecords Find Bug Records.
func (d *Dao) FindBugRecords(req *model.QueryBugRecordsRequest) (total int64, tapdBugRecords []*model.TapdBugRecord, err error) {
gDB := d.db.Model(&model.TapdBugRecord{})
if req.ProjectTemplateID > 0 {
gDB = gDB.Where("project_template_id=?", req.ProjectTemplateID)
}
if req.VersionTemplateID > 0 {
gDB = gDB.Where("version_template_id=?", req.VersionTemplateID)
}
if req.Operator != "" {
gDB = gDB.Where("operator=?", req.Operator)
}
if req.Status > 0 {
gDB = gDB.Where("status=?", req.Status)
}
if err = pkgerr.WithStack(gDB.Count(&total).Error); err != nil {
return
}
err = pkgerr.WithStack(gDB.Order("ctime desc").Offset((req.PageNum - 1) * req.PageSize).Limit(req.PageSize).Find(&tapdBugRecords).Error)
return
}

View File

@ -0,0 +1,42 @@
package dao
import (
"testing"
"time"
"go-common/app/admin/ep/marthe/model"
. "github.com/smartystreets/goconvey/convey"
)
var (
tmpID = time.Now().Unix()
tapdBugRecord = &model.TapdBugRecord{
ProjectTemplateID: tmpID,
VersionTemplateID: tmpID + 1,
Operator: "fengyifeng",
Count: 10,
Status: model.InsertBugStatusRunning,
IssueFilterSQL: "SELECT * FROM bugly_issues WHERE issue_no = '265'",
}
)
func Test_Tapd_bug_record(t *testing.T) {
Convey("test Insert Tapd Bug Record", t, func() {
err := d.InsertTapdBugRecord(tapdBugRecord)
So(err, ShouldBeNil)
})
Convey("test Update Tapd Bug Record", t, func() {
tapdBugRecord.Status = model.InsertBugStatusDone
err := d.UpdateTapdBugRecord(tapdBugRecord)
So(err, ShouldBeNil)
})
Convey("test Query Tapd Bug Record By Project ID And Status", t, func() {
tapdBugRecords, err := d.QueryTapdBugRecordByProjectIDAndStatus(tapdBugRecord.ProjectTemplateID, model.InsertBugStatusDone)
So(err, ShouldBeNil)
So(len(tapdBugRecords), ShouldEqual, 1)
})
}

View File

@ -0,0 +1,66 @@
package dao
import (
"go-common/app/admin/ep/marthe/model"
"go-common/library/ecode"
pkgerr "github.com/pkg/errors"
)
// InsertTapdBugTemplate Insert Tapd Bug Template.
func (d *Dao) InsertTapdBugTemplate(tapdBugTemplate *model.TapdBugTemplate) error {
return pkgerr.WithStack(d.db.Create(tapdBugTemplate).Error)
}
// UpdateTapdBugTemplate Update Tapd Bug Template.
func (d *Dao) UpdateTapdBugTemplate(tapdBugTemplate *model.TapdBugTemplate) error {
return pkgerr.WithStack(d.db.Save(&tapdBugTemplate).Error)
}
// QueryTapdBugTemplate Query Tapd Bug Template.
func (d *Dao) QueryTapdBugTemplate(id int64) (tapdBugTemplate *model.TapdBugTemplate, err error) {
tapdBugTemplate = &model.TapdBugTemplate{}
if err = d.db.Where("id=?", id).First(&tapdBugTemplate).Error; err != nil {
if err == ecode.NothingFound {
err = nil
} else {
err = pkgerr.WithStack(err)
}
}
return
}
// QueryTapdBugTemplateByProjectID Query Tapd Bug Template by project id.
func (d *Dao) QueryTapdBugTemplateByProjectID(projectID string) (tapdBugTemplate *model.TapdBugTemplate, err error) {
tapdBugTemplate = &model.TapdBugTemplate{}
if err = d.db.Where("project_id=?", projectID).First(&tapdBugTemplate).Error; err != nil {
if err == ecode.NothingFound {
err = nil
} else {
err = pkgerr.WithStack(err)
}
}
return
}
// QueryAllTapdBugTemplates Query All Tapd Bug Templates.
func (d *Dao) QueryAllTapdBugTemplates() (tapdBugTemplates []*model.TapdBugTemplate, err error) {
err = pkgerr.WithStack(d.db.Model(&model.TapdBugTemplate{}).Find(&tapdBugTemplates).Error)
return
}
// FindTapdBugTemplates Find tapd Bug Templates.
func (d *Dao) FindTapdBugTemplates(req *model.QueryTapdBugTemplateRequest) (total int64, tapdBugTemplates []*model.TapdBugTemplate, err error) {
gDB := d.db.Model(&model.TapdBugTemplate{})
if req.UpdateBy != "" {
gDB = gDB.Where("update_by=?", req.UpdateBy)
}
if err = pkgerr.WithStack(gDB.Count(&total).Error); err != nil {
return
}
err = pkgerr.WithStack(gDB.Order("ctime desc").Offset((req.PageNum - 1) * req.PageSize).Limit(req.PageSize).Find(&tapdBugTemplates).Error)
return
}

View File

@ -0,0 +1,75 @@
package dao
import (
"strconv"
"testing"
"time"
"go-common/app/admin/ep/marthe/model"
. "github.com/smartystreets/goconvey/convey"
)
var (
tmp5 = strconv.FormatInt(time.Now().Unix(), 10)
tapdBugTemplate = &model.TapdBugTemplate{
WorkspaceID: tmp5,
IssueFilterSQL: "SELECT * FROM bugly_issues WHERE issue_no = '265'",
SeverityKey: "SeverityKey" + tmp5,
UpdateBy: "fengyifeng",
TapdProperty: model.TapdProperty{
Title: "Title" + tmp5,
Description: "Description" + tmp5,
CurrentOwner: "CurrentOwner" + tmp5,
Platform: "Platform" + tmp5,
Module: "Module" + tmp5,
IterationID: "IterationID" + tmp5,
ReleaseID: "ReleaseID" + tmp5,
Priority: "Priority" + tmp5,
Severity: "Severity" + tmp5,
Source: "Source" + tmp5,
CustomFieldFour: "CustomFieldFour" + tmp5,
BugType: "BugType" + tmp5,
OriginPhase: "OriginPhase" + tmp5,
CustomFieldThree: "CustomFieldThree" + tmp5,
Reporter: "Reporter" + tmp5,
Status: "Status" + tmp5,
},
}
queryTapdBugTemplateRequest = &model.QueryTapdBugTemplateRequest{
Pagination: model.Pagination{
PageSize: 10,
PageNum: 1,
},
}
)
func Test_Tapd_bug_template(t *testing.T) {
Convey("test Insert Tapd Bug Template", t, func() {
err := d.InsertTapdBugTemplate(tapdBugTemplate)
So(err, ShouldBeNil)
})
Convey("test Update Tapd Bug Template", t, func() {
tapdBugTemplate.UpdateBy = "xuneng"
err := d.UpdateTapdBugTemplate(tapdBugTemplate)
So(err, ShouldBeNil)
})
Convey("test Query Tapd Bug Template", t, func() {
tmpTapdBugTemplate, err := d.QueryTapdBugTemplate(tapdBugTemplate.ID)
So(err, ShouldBeNil)
So(tmpTapdBugTemplate.ID, ShouldEqual, tapdBugTemplate.ID)
})
Convey("test Find Tapd Bug Templates", t, func() {
total, tapdBugTemplates, err := d.FindTapdBugTemplates(queryTapdBugTemplateRequest)
So(err, ShouldBeNil)
So(total, ShouldBeGreaterThan, 0)
So(len(tapdBugTemplates), ShouldBeGreaterThan, 0)
})
}

View File

@ -0,0 +1,68 @@
package dao
import (
"go-common/app/admin/ep/marthe/model"
"go-common/library/ecode"
pkgerr "github.com/pkg/errors"
)
// InsertTapdBugVersionTemplate Insert TapdBug Version Template.
func (d *Dao) InsertTapdBugVersionTemplate(tapdBugVersionTemplate *model.TapdBugVersionTemplate) error {
return pkgerr.WithStack(d.db.Create(tapdBugVersionTemplate).Error)
}
// UpdateTapdBugVersionTemplate Update Tapd Bug Version Template.
func (d *Dao) UpdateTapdBugVersionTemplate(tapdBugVersionTemplate *model.TapdBugVersionTemplate) error {
return pkgerr.WithStack(d.db.Save(&tapdBugVersionTemplate).Error)
}
// QueryTapdBugVersionTemplate Query Tapd Bug Version Template.
func (d *Dao) QueryTapdBugVersionTemplate(id int64) (tapdBugVersionTemplate *model.TapdBugVersionTemplate, err error) {
tapdBugVersionTemplate = &model.TapdBugVersionTemplate{}
if err = d.db.Where("id=?", id).First(&tapdBugVersionTemplate).Error; err != nil {
if err == ecode.NothingFound {
err = nil
} else {
err = pkgerr.WithStack(err)
}
}
return
}
// QueryTapdBugVersionTemplateByVersion Query Tapd Bug Version Template.
func (d *Dao) QueryTapdBugVersionTemplateByVersion(version string) (tapdBugVersionTemplate *model.TapdBugVersionTemplate, err error) {
tapdBugVersionTemplate = &model.TapdBugVersionTemplate{}
if err = d.db.Where("version=?", version).First(&tapdBugVersionTemplate).Error; err != nil {
if err == ecode.NothingFound {
err = nil
} else {
err = pkgerr.WithStack(err)
}
}
return
}
// FindTapdBugVersionTemplates Find Tapd Bug Version Templates.
func (d *Dao) FindTapdBugVersionTemplates(req *model.QueryTapdBugVersionTemplateRequest) (total int64, tapdBugVersionTemplate []*model.TapdBugVersionTemplate, err error) {
gDB := d.db.Model(&model.TapdBugVersionTemplate{})
if req.ProjectID > 0 {
gDB = gDB.Where("project_template_id = ?", req.ProjectID)
}
if req.Version != "" {
gDB = gDB.Where("version like ?", req.Version+_wildcards)
}
if req.UpdateBy != "" {
gDB = gDB.Where("update_by = ?", req.UpdateBy)
}
if err = pkgerr.WithStack(gDB.Count(&total).Error); err != nil {
return
}
err = pkgerr.WithStack(gDB.Order("ctime desc").Offset((req.PageNum - 1) * req.PageSize).Limit(req.PageSize).Find(&tapdBugVersionTemplate).Error)
return
}

View File

@ -0,0 +1,82 @@
package dao
import (
"strconv"
"testing"
"time"
"go-common/app/admin/ep/marthe/model"
. "github.com/smartystreets/goconvey/convey"
)
var (
tmp6 = strconv.FormatInt(time.Now().Unix(), 10)
tapdBugVersionTemplate = &model.TapdBugVersionTemplate{
Version: "version" + tmp6,
ProjectTemplateID: 10,
IssueFilterSQL: "SELECT * FROM bugly_issues WHERE issue_no = '265'",
SeverityKey: "SeverityKey" + tmp6,
UpdateBy: "fengyifeng",
TapdProperty: model.TapdProperty{
Title: "Title" + tmp6,
Description: "Description" + tmp6,
CurrentOwner: "CurrentOwner" + tmp6,
Platform: "Platform" + tmp6,
Module: "Module" + tmp6,
IterationID: "IterationID" + tmp6,
ReleaseID: "ReleaseID" + tmp6,
Priority: "Priority" + tmp6,
Severity: "Severity" + tmp6,
Source: "Source" + tmp6,
CustomFieldFour: "CustomFieldFour" + tmp6,
BugType: "BugType" + tmp6,
OriginPhase: "OriginPhase" + tmp6,
CustomFieldThree: "CustomFieldThree" + tmp6,
Reporter: "Reporter" + tmp6,
Status: "Status" + tmp6,
},
}
queryTapdBugVersionTemplateRequest = &model.QueryTapdBugVersionTemplateRequest{
Pagination: model.Pagination{
PageSize: 10,
PageNum: 1,
},
Version: tapdBugVersionTemplate.Version,
}
)
func Test_Tapd_bug_version_template(t *testing.T) {
Convey("test Insert Tapd Bug version Template", t, func() {
err := d.InsertTapdBugVersionTemplate(tapdBugVersionTemplate)
So(err, ShouldBeNil)
})
Convey("test Update Tapd Bug version Template", t, func() {
tapdBugTemplate.UpdateBy = "xuneng"
err := d.UpdateTapdBugVersionTemplate(tapdBugVersionTemplate)
So(err, ShouldBeNil)
})
Convey("test Query Tapd Bug version Template", t, func() {
tmpTapdBugVersionTemplate, err := d.QueryTapdBugVersionTemplate(tapdBugVersionTemplate.ID)
So(err, ShouldBeNil)
So(tmpTapdBugVersionTemplate.ID, ShouldEqual, tapdBugVersionTemplate.ID)
})
Convey("test Query Tapd Bug Version Template By version", t, func() {
tmpTapdBugVersionTemplate, err := d.QueryTapdBugVersionTemplateByVersion(tapdBugVersionTemplate.Version)
So(err, ShouldBeNil)
So(tmpTapdBugVersionTemplate.ID, ShouldEqual, tapdBugVersionTemplate.ID)
})
Convey("test Find Tapd Bug version Templates", t, func() {
total, tapdBugVersionTemplate, err := d.FindTapdBugVersionTemplates(queryTapdBugVersionTemplateRequest)
So(err, ShouldBeNil)
So(total, ShouldBeGreaterThan, 0)
So(len(tapdBugVersionTemplate), ShouldBeGreaterThan, 0)
})
}

View File

@ -0,0 +1,43 @@
package dao
import (
"go-common/app/admin/ep/marthe/model"
"go-common/library/ecode"
pkgerr "github.com/pkg/errors"
)
// FindUserByUserName find user by username.
func (d *Dao) FindUserByUserName(name string) (user *model.User, err error) {
user = &model.User{}
if err = d.db.Where("name = ?", name).First(user).Error; err != nil {
if err == ecode.NothingFound {
err = nil
} else {
err = pkgerr.WithStack(err)
}
}
return
}
// FindUserByID find user by id.
func (d *Dao) FindUserByID(ID int64) (user *model.User, err error) {
user = &model.User{}
err = pkgerr.WithStack(d.db.Where("id = ?", ID).First(user).Error)
return
}
// CreateUser create user.
func (d *Dao) CreateUser(user *model.User) error {
return pkgerr.WithStack(d.db.Create(user).Error)
}
// DelUser delete user.
func (d *Dao) DelUser(user *model.User) error {
return pkgerr.WithStack(d.db.Delete(user).Error)
}
// UpdateUserVisibleBugly Update User Visible Bugly.
func (d *Dao) UpdateUserVisibleBugly(ID int64, visibleBugly bool) error {
return pkgerr.WithStack(d.db.Model(&model.User{}).Where("id = ?", ID).Update("visible_bugly", visibleBugly).Error)
}

View File

@ -0,0 +1,42 @@
package dao
import (
"testing"
"time"
. "github.com/smartystreets/goconvey/convey"
"go-common/app/admin/ep/marthe/model"
)
var (
testTime = time.Now().Format("2006_01_02_15_04_05")
testUser = model.User{
Name: testTime,
EMail: testTime + "@bilibili.com"}
)
func Test_User(t *testing.T) {
Convey("test CreateUser", t, func() {
err := d.CreateUser(&testUser)
So(err, ShouldBeNil)
})
Convey("find user by user name", t, func() {
userInDb, err := d.FindUserByUserName(testUser.Name)
So(userInDb.EMail, ShouldEqual, testUser.EMail)
So(err, ShouldBeNil)
})
Convey("find user by id", t, func() {
userID := testUser.ID
userInDb, err := d.FindUserByID(userID)
So(userInDb.EMail, ShouldEqual, testUser.EMail)
So(err, ShouldBeNil)
})
Convey("delete user", t, func() {
err := d.DelUser(&testUser)
So(err, ShouldBeNil)
})
}

View File

@ -0,0 +1,221 @@
package dao
import (
"context"
"encoding/json"
"fmt"
"net/http"
"go-common/app/admin/ep/marthe/model"
"go-common/library/cache/memcache"
"go-common/library/ecode"
"go-common/library/log"
)
const (
_userName = "bilibilinik"
_password = "0989D4F0-AF9D-949F-C950-E22A3F891NIK"
_successCode = 1
_releaseURL = "https://api.tapd.cn/releases?workspace_id=%s&id=%s"
_bugPreURL = "https://api.tapd.cn/bugs?workspace_id=%s&id=%s"
_createBugURL = "https://api.tapd.cn/bugs"
_workspaceUserURL = "https://api.tapd.cn/workspaces/users?workspace_id=%s&fields=user"
)
//Bug Bug
func (d *Dao) Bug(bugURL string) (res *model.BugResponse, err error) {
var req *http.Request
res = &model.BugResponse{}
if req, err = d.newTapdRequest(http.MethodGet, bugURL, nil); err != nil {
log.Error("Bug url(%s) res(%v) err(%v)", bugURL, res, err)
return nil, ecode.MartheTapdErr
}
if err = d.httpClient.Do(context.TODO(), req, res); err != nil {
log.Error("WorkspaceUser url(%s) res(%v) err(%v)", bugURL, res, err)
err = ecode.MartheTapdResDataErr
return
}
if res.Status != _successCode {
log.Error("WorkspaceUser url(%s) res(%v) err(%v)", bugURL, res, err)
err = ecode.MartheTapdResDataErr
}
return
}
//BugPre Bug Pre
func (d *Dao) BugPre(workSpaceID, bugID string) (bug *model.Bug, err error) {
var (
req *http.Request
res = &model.BugSingleResponse{}
)
url := fmt.Sprintf(_bugPreURL, workSpaceID, bugID)
if req, err = d.newTapdRequest(http.MethodGet, url, nil); err != nil {
log.Error("BugPre url(%s) res(%v) err(%v)", url, res, err)
err = ecode.MartheTapdErr
return
}
if err = d.httpClient.Do(context.TODO(), req, res); err != nil || res.Data == nil {
log.Error("BugPre url(%s) res(%v) err(%v)", url, res, err)
err = ecode.MartheTapdErr
return
}
if res.Status != _successCode || res.Data == nil {
log.Error("BugPre url(%s) res(%v) err(%v)", url, res, err)
err = ecode.MartheTapdResDataErr
return
}
bug = res.Data.Bug
return
}
//Release Release
func (d *Dao) Release(workSpaceID, releaseID string) (release *model.Release, err error) {
var (
req *http.Request
res = &model.ReleaseResponse{}
)
releaseURL := fmt.Sprintf(_releaseURL, workSpaceID, releaseID)
if req, err = d.newTapdRequest(http.MethodGet, releaseURL, nil); err != nil {
log.Error("Release url(%s) res(%v) err(%v)", _releaseURL, res, err)
err = ecode.MartheTapdErr
return
}
if err = d.httpClient.Do(context.TODO(), req, res); err != nil || res.Data == nil {
log.Error("Release url(%s) res(%v) err(%v)", _releaseURL, res, err)
err = ecode.MartheTapdErr
return
}
if res.Status != _successCode || res.Data == nil {
log.Error("Release url(%s) res(%v) err(%v)", _releaseURL, res, err)
err = ecode.MartheTapdResDataErr
return
}
release = res.Data.Release
return
}
// ReleaseName ReleaseName
func (d *Dao) ReleaseName(workspaceID, releaseID string) (releaseName string, err error) {
var (
item *memcache.Item
conn = d.mc.Get(context.Background())
release *model.Release
)
defer conn.Close()
if item, err = conn.Get(workspaceID + releaseID); err == nil {
if err = json.Unmarshal(item.Value, &releaseName); err != nil {
log.Error("Json unmarshal err(%v)", err)
}
return
}
if release, err = d.Release(workspaceID, releaseID); err != nil {
return
}
releaseName = release.Name
item = &memcache.Item{Key: workspaceID + releaseID, Object: release.Name, Flags: memcache.FlagJSON, Expiration: d.expire}
d.cacheSave(context.Background(), item)
return
}
//newTapdRequest new tapd request
func (d *Dao) newTapdRequest(method, url string, v interface{}) (req *http.Request, err error) {
req, err = d.newRequest(method, url, v)
req.SetBasicAuth(_userName, _password)
return
}
// CreateBug Create Bug.
func (d *Dao) CreateBug(bug *model.Bug) (bugID string, err error) {
var (
req *http.Request
res = &model.BugSingleResponse{}
)
if req, err = d.newTapdRequest(http.MethodPost, _createBugURL, bug); err != nil {
log.Error("CreateBug url(%s) res(%v) err(%v)", _createBugURL, res, err)
err = ecode.MartheTapdErr
return
}
if err = d.httpClient.Do(context.TODO(), req, res); err != nil {
log.Error("CreateBug url(%s) res(%v) err(%v)", _createBugURL, res, err)
err = ecode.MartheTapdErr
return
}
if res.Status != _successCode {
log.Error("CreateBug url(%s) res(%v) err(%v)", _createBugURL, res, err)
err = ecode.MartheTapdResDataErr
}
bugID = res.Data.Bug.ID
return
}
// UpdateBug Update Bug.
func (d *Dao) UpdateBug(bug *model.UpdateBug) (err error) {
var (
req *http.Request
res = &model.BugSingleResponse{}
)
if req, err = d.newTapdRequest(http.MethodPost, _createBugURL, bug); err != nil {
log.Error("UpdateBug url(%s) res(%v) err(%v)", _createBugURL, res, err)
err = ecode.MartheTapdErr
return
}
if err = d.httpClient.Do(context.TODO(), req, res); err != nil {
log.Error("UpdateBug url(%s) res(%v) err(%v)", _createBugURL, res, err)
err = ecode.MartheTapdErr
return
}
if res.Status != _successCode {
log.Error("UpdateBug url(%s) res(%v) err(%v)", _createBugURL, res, err)
err = ecode.MartheTapdResDataErr
}
return
}
// WorkspaceUser Workspace User
func (d *Dao) WorkspaceUser(workspaceID string) (usernames []string, err error) {
var (
req *http.Request
res = &model.WorkspaceUserResponse{}
)
workspaceUserURL := fmt.Sprintf(_workspaceUserURL, workspaceID)
if req, err = d.newTapdRequest(http.MethodGet, workspaceUserURL, nil); err != nil {
log.Error("WorkspaceUser url(%s) res(%v) err(%v)", workspaceUserURL, res, err)
err = ecode.MartheTapdErr
return
}
if err = d.httpClient.Do(context.TODO(), req, res); err != nil {
log.Error("WorkspaceUser url(%s) res(%v) err(%v)", workspaceUserURL, res, err)
err = ecode.MartheTapdErr
return
}
if res.Status != _successCode || res.Data == nil {
log.Error("WorkspaceUser url(%s) res(%v) err(%v)", workspaceUserURL, res, err)
err = ecode.MartheTapdResDataErr
return
}
for _, workspaceUser := range res.Data {
usernames = append(usernames, workspaceUser.UserWrapper.User)
}
return
}

View File

@ -0,0 +1,80 @@
package dao
import (
"context"
"net/url"
"go-common/app/admin/ep/marthe/model"
)
const (
_qyWechatURL = "https://qyapi.weixin.qq.com"
_corpID = "wx0833ac9926284fa5" // 企业微信Bilibili的企业ID
_departmentID = "12" // 公司统一用部门ID
_corpsecret = "WveODxk3xpT9box48wcxkmArx3mu6d4vJHdJkNy_iTk"
_getToken = "/cgi-bin/gettoken"
_userList = "/cgi-bin/user/list"
)
// WechatAccessToken query access token with the specified secret 企业微信api获取公司token
func (d *Dao) WechatAccessToken(c context.Context) (token string, err error) {
var (
u string
params = url.Values{}
res struct {
ErrCode int `json:"errcode"`
ErrMsg string `json:"errmsg"`
AccessToken string `json:"access_token"`
ExpiresIn int32 `json:"expires_in"`
}
)
u = _qyWechatURL + _getToken
params.Set("corpid", _corpID)
params.Set("corpsecret", _corpsecret)
if err = d.httpClient.Get(c, u, "", params, &res); err != nil {
return
}
if res.ErrCode != 0 {
return
}
token = res.AccessToken
return
}
// WechatContacts Wechat Contacts 获取用户信息列表
func (d *Dao) WechatContacts(c context.Context) (contacts []*model.WechatContact, err error) {
var (
token string
u string
params = url.Values{}
res struct {
ErrCode int `json:"errcode"`
ErrMsg string `json:"errmsg"`
UserList []*model.WechatContact `json:"userlist"`
}
)
//get token
if token, err = d.WechatAccessToken(c); err != nil {
return
}
u = _qyWechatURL + _userList
params.Set("access_token", token)
params.Set("department_id", _departmentID)
params.Set("fetch_child", "1")
if err = d.httpClient.Get(c, u, "", params, &res); err != nil {
return
}
if res.ErrCode != 0 {
return
}
contacts = res.UserList
return
}

View File

@ -0,0 +1,36 @@
package(default_visibility = ["//visibility:public"])
load(
"@io_bazel_rules_go//go:def.bzl",
"go_library",
)
go_library(
name = "go_default_library",
srcs = [
"bugly.go",
"constants.go",
"marthe.go",
"model.go",
"tapd.go",
"wechat.go",
],
importpath = "go-common/app/admin/ep/marthe/model",
tags = ["automanaged"],
visibility = ["//visibility:public"],
deps = ["//library/ecode:go_default_library"],
)
filegroup(
name = "package-srcs",
srcs = glob(["**"]),
tags = ["automanaged"],
visibility = ["//visibility:private"],
)
filegroup(
name = "all-srcs",
srcs = [":package-srcs"],
tags = ["automanaged"],
visibility = ["//visibility:public"],
)

View File

@ -0,0 +1,89 @@
package model
// BugIssueRequest Bug Issue Request.
type BugIssueRequest struct {
StartNum int
Version string
Rows int
PlatformID string
ProjectID string
ExceptionType string
}
// BugIssueResponse Bug Issue Response.
type BugIssueResponse struct {
Status int `json:"status"`
Code int `json:"code"`
Ret *BugRet `json:"ret"`
}
// BugRet Bug Ret.
type BugRet struct {
NumFound int `json:"numFound"`
BugIssues []*BugIssues `json:"issueList"`
}
// BugIssues Bug Issues.
type BugIssues struct {
IssueID string `json:"issueId"`
Title string `json:"exceptionName"`
ExceptionMsg string `json:"exceptionMessage"`
KeyStack string `json:"keyStack"`
LastTime string `json:"lastestUploadTime"`
Count int `json:"count"`
Tags []*BugTag `json:"tagInfoList"`
UserCount int `json:"imeiCount"`
Version string `json:"version"`
}
// BugTag Bug Tag.
type BugTag struct {
TagName string `json:"tagName"`
}
// BugIssueDetailResponse Bug Issue Detail Response.
type BugIssueDetailResponse struct {
Code int `json:"code"`
Data *BugIssueDetail `json:"data"`
}
// BugIssueDetail Bug Issue Detail.
type BugIssueDetail struct {
CallStack string `json:"callStack"`
}
// BugVersionResponse Bug Version Response.
type BugVersionResponse struct {
Status int `json:"status"`
Code int `json:"code"`
Ret *SelectorPropertyList `json:"ret"`
}
// SelectorPropertyList SelectorPropertyList.
type SelectorPropertyList struct {
BugVersionList []*BugVersion `json:"versionList"`
}
// BugVersion BugVersion.
type BugVersion struct {
Name string `json:"name"`
Enable int `json:"enable"`
SDKVersion string `json:"sdkVersion"`
}
// BugIssueExceptionListResponse Bug Issue Exception List Response.
type BugIssueExceptionListResponse struct {
Status int `json:"status"`
Ret *IssueExceptionList `json:"ret"`
}
// IssueExceptionList IssueExceptionList.
type IssueExceptionList struct {
IssueException []*IssueException `json:"issueList"`
}
// IssueException IssueException.
type IssueException struct {
IssueID string `json:"issueId"`
Status int `json:"status"`
}

View File

@ -0,0 +1,65 @@
package model
// TimeLayout
const (
TimeLayout = "2006-01-02 15:04:05"
)
// page
const (
DefaultPageSize = 5
DefaultPageNum = 1
)
// BuglyVersion task status
const (
BuglyVersionTaskStatusReady = 1
BuglyVersionTaskStatusRunning = 2
)
// BuglyVersion action
const (
BuglyVersionActionEnable = 1
BuglyVersionActionDisable = 2
)
// BuglyCookie status
const (
BuglyCookieStatusEnable = 1
BuglyCookieStatusDisable = 2
)
// BuglyBatchRun status
const (
BuglyBatchRunStatusRunning = 1
BuglyBatchRunStatusDone = 2
BuglyBatchRunStatusFailed = 3
)
// Insert bug status
const (
InsertBugStatusRunning = 1
InsertBugStatusDone = 2
InsertBugStatusFailed = 3
)
// Tapd Bug Priority Conf Enable
const (
TapdBugPriorityConfEnable = 1
TapdBugPriorityConfDisable = 2
)
// Task Status
const (
TaskStatusRunning = 1
TaskStatusDone = 2
TaskStatusFailed = 3
)
// Task Type
const (
TaskBatchRunVersions = "BatchRunVersions"
TaskDisableBatchRunOverTime = "DisableBatchRunOverTime"
TaskBatchRunUpdateBugInTapd = "BatchRunUpdateBugInTapd"
TaskSyncWechatContact = "SyncWechatContact"
)

View File

@ -0,0 +1,260 @@
package model
import "go-common/library/ecode"
// AddVersionRequest Add Version Request.
type AddVersionRequest struct {
ID int64 `json:"id"`
BuglyProjectID int64 `json:"bugly_project_id"`
Version string `json:"version"`
Action int `json:"action"`
}
// AddProjectRequest Add Project Request.
type AddProjectRequest struct {
ID int64 `json:"id"`
ProjectName string `json:"project_name"`
ProjectID string `json:"project_id"`
PlatformID string `json:"platform_id"`
ExceptionType string `json:"exception_type"`
}
// AddCookieRequest Add Cookie Request.
type AddCookieRequest struct {
ID int64 `json:"id"`
Cookie string `json:"cookie"`
Token string `json:"token"`
Status int `json:"status"`
QQAccount int `json:"qq_account"`
}
// BuglyIssueImportRequest Bugly Issue Import Request.
type BuglyIssueImportRequest struct {
IssueImportInfo []*IssueImportInfo `json:"import_info"`
}
// IssueImportInfo Issue Import Info.
type IssueImportInfo struct {
ProjectID string `json:"project_id"`
PlatformID string `json:"platform_id"`
Version []string `json:"version"`
}
// Pagination Pagination.
type Pagination struct {
PageSize int `form:"page_size" json:"page_size"`
PageNum int `form:"page_num" json:"page_num"`
}
// PaginationRep Pagination Response.
type PaginationRep struct {
PageSize int `json:"page_size"`
PageNum int `json:"page_num"`
Total int64 `json:"total"`
}
// Verify verify the value of pageNum and pageSize.
func (p *Pagination) Verify() error {
if p.PageNum < 0 {
return ecode.MerlinIllegalPageNumErr
} else if p.PageNum == 0 {
p.PageNum = DefaultPageNum
}
if p.PageSize < 0 {
return ecode.MerlinIllegalPageSizeErr
} else if p.PageSize == 0 {
p.PageSize = DefaultPageSize
}
return nil
}
// QueryBuglyVersionRequest Query Bugly Version Request.
type QueryBuglyVersionRequest struct {
Pagination
Version string `json:"version"`
ProjectName string `json:"project_name"`
Action int `json:"action"`
TaskStatus int `json:"task_status"`
UpdateBy string `json:"update_by"`
}
// QueryBuglyBatchRunsRequest Query Bugly Batch Runs Request.
type QueryBuglyBatchRunsRequest struct {
Pagination
Version string `json:"version"`
Status int `json:"status"`
BatchID string `json:"batch_id"`
}
// PaginateBuglyBatchRuns Paginate Bugly Batch Runs.
type PaginateBuglyBatchRuns struct {
PaginationRep
BuglyBatchRuns []*BuglyBatchRun `json:"bugly_batch_runs"`
}
// QueryBugRecordsRequest Query Bug Records Request.
type QueryBugRecordsRequest struct {
Pagination
ProjectTemplateID int64 `json:"project_template_id"`
VersionTemplateID int64 `json:"version_template_id"`
Operator string `json:"operator"`
Status int `json:"status"`
}
// QueryTapdBugPriorityConfsRequest Query Tapd Bug Priority Confs Request.
type QueryTapdBugPriorityConfsRequest struct {
Pagination
ProjectTemplateID int64 `json:"project_template_id"`
UpdateBy string `json:"update_by"`
Status int `json:"status"`
}
// PaginateTapdBugPriorityConfs Paginate Tapd Bug Priority Confs.
type PaginateTapdBugPriorityConfs struct {
PaginationRep
TapdBugPriorityConfs []*TapdBugPriorityConf `json:"tapd_bug_priority_confs"`
}
// PaginateBugRecords Paginate Bug Records.
type PaginateBugRecords struct {
PaginationRep
TapdBugRecords []*TapdBugRecord `json:"tapd_bug_records"`
}
// QueryBuglyCookiesRequest Query Bugly Batch Runs Request.
type QueryBuglyCookiesRequest struct {
Pagination
QQAccount int `json:"qq_account"`
Status int `json:"status"`
}
// PaginateBuglyCookies Paginate Bugly Cookies.
type PaginateBuglyCookies struct {
PaginationRep
BuglyCookies []*BuglyCookie `json:"bugly_cookies"`
}
// PaginateBuglyProjectVersions Paginate Bugly Project Versions.
type PaginateBuglyProjectVersions struct {
PaginationRep
BuglyProjectVersions []*BuglyProjectVersion `json:"bugly_project_versions"`
}
// QueryTapdBugTemplateRequest Query tapd Bug Template Request.
type QueryTapdBugTemplateRequest struct {
Pagination
ProjectName string `json:"project_name"`
UpdateBy string `json:"update_by"`
}
// QueryTapdBugVersionTemplateRequest Query Tapd Bug Version Template Request.
type QueryTapdBugVersionTemplateRequest struct {
Pagination
ProjectID int64 `json:"project_template_id"`
Version string `json:"version"`
UpdateBy string `json:"update_by"`
}
// PaginateTapdBugTemplates Paginate Tapd Bug Template.
type PaginateTapdBugTemplates struct {
PaginationRep
TapdBugTemplateWithProjectNames []*TapdBugTemplateWithProjectName `json:"tapd_bug_templates"`
}
// TapdBugTemplateWithProjectName Paginate Tapd Bug Template.
type TapdBugTemplateWithProjectName struct {
*TapdBugTemplate
ProjectName string `json:"project_name"`
}
// PaginateTapdBugVersionTemplates Paginate Tapd Bug Version Template.
type PaginateTapdBugVersionTemplates struct {
PaginationRep
TapdBugVersionTemplates []*TapdBugVersionTemplate `json:"tapd_bug_version_templates"`
}
// UpdateTapdBugTplRequest Update Tapd Bug Tpl Request.
type UpdateTapdBugTplRequest struct {
ID int64 `json:"id" `
WorkspaceID string `json:"workspace_id"`
BuglyProjectId int64 `json:"bugly_project_id" `
IssueFilterSQL string `json:"issue_filter_sql"`
SeverityKey string `json:"severity_key"`
TapdProperty
}
// UpdateTapdBugVersionTplRequest Update Tapd Bug Tpl Request.
type UpdateTapdBugVersionTplRequest struct {
ID int64 `json:"id" `
Version string `json:"version" `
ProjectTemplateID int64 `json:"project_template_id"`
IssueFilterSQL string `json:"issue_filter_sql"`
SeverityKey string `json:"severity_key"`
TapdProperty
}
// QueryBuglyIssueRequest Query Bugly Issue Request.
type QueryBuglyIssueRequest struct {
Pagination
IssueNo string `json:"issue_no"`
Title string `json:"title"`
ExceptionMsg string `json:"exception_msg" `
KeyStack string `json:"key_stack"`
Detail string `json:"detail"`
Tags string `json:"tags"`
Version string `json:"version" `
ProjectID string `json:"project_id"`
TapdBugID string `json:"tapd_bug_id"`
}
// PaginateBuglyIssues Paginate Bugly Issues.
type PaginateBuglyIssues struct {
PaginationRep
BuglyIssues []*BuglyIssue `json:"bugly_issues"`
}
// UpdateTapdBugPriorityConfRequest Update Tapd Bug Priority Conf Request.
type UpdateTapdBugPriorityConfRequest struct {
ID int64 `json:"id" `
ProjectTemplateID int64 `json:"project_template_id"`
Urgent int `json:"urgent"`
High int `json:"high"`
Medium int `json:"medium"`
StartTime string `json:"start_time"`
EndTime string `json:"end_time"`
Status int `json:"status"`
}
// QueryBuglyProjectRequest Query Bugly Project Request.
type QueryBuglyProjectRequest struct {
Pagination
ProjectName string `json:"project_name"`
ProjectID string `json:"project_id"`
PlatformID string `json:"platform_id"`
UpdateBy string `json:"update_by"`
}
// PaginateBuglyProjects Paginate Bugly Projects.
type PaginateBuglyProjects struct {
PaginationRep
BuglyProjects []*BuglyProject `json:"bugly_projects"`
}
// BuglyProjectVersion Bugly Project Version.
type BuglyProjectVersion struct {
BuglyVersion
ProjectName string `json:"project_name"`
ExceptionType string `json:"exception_type"`
}
// TapdBugTemplateShortResponse Tapd Bug Template Short Response.
type TapdBugTemplateShortResponse struct {
ID int64 `json:"id"`
WorkspaceID string `json:"workspace_id"`
BuglyProjectId int64 `json:"bugly_project_id"`
BuglyProjectName string `json:"project_name"`
}

View File

@ -0,0 +1,183 @@
package model
import (
"time"
)
// BuglyIssue Issue Record.
type BuglyIssue struct {
ID int64 `json:"id" gorm:"auto_increment;primary_key;column:id"`
IssueNo string `json:"issue_no" gorm:"column:issue_no"`
Title string `json:"title" gorm:"column:title"`
ExceptionMsg string `json:"exception_msg" gorm:"column:exception_msg"`
KeyStack string `json:"key_stack" gorm:"column:key_stack"`
Detail string `json:"detail" gorm:"column:detail"`
Tags string `json:"tags" gorm:"column:tags"`
LastTime time.Time `json:"last_time" gorm:"column:last_time"`
HappenTimes int `json:"happen_times" gorm:"column:happen_times"`
UserTimes int `json:"user_times" gorm:"column:user_times"`
Version string `json:"version" gorm:"column:version"`
ProjectID string `json:"project_id" gorm:"column:project_id"`
IssueLink string `json:"issue_link" gorm:"column:issue_link"`
TapdBugID string `json:"tapd_bug_id" gorm:"column:tapd_bug_id"`
CTime time.Time `json:"ctime" gorm:"column:ctime"`
MTime time.Time `json:"mtime" gorm:"column:mtime"`
}
// TapdProperty TapdProperty.
type TapdProperty struct {
Title string `json:"title" gorm:"column:title"`
Description string `json:"description" gorm:"column:description"`
CurrentOwner string `json:"current_owner" gorm:"column:current_owner"`
Platform string `json:"platform" gorm:"column:platform"`
Module string `json:"module" gorm:"column:module"`
IterationID string `json:"iteration_id" gorm:"column:iteration_id"`
ReleaseID string `json:"release_id" gorm:"column:release_id"`
Priority string `json:"priority" gorm:"column:priority"`
Severity string `json:"severity" gorm:"column:severity"`
Source string `json:"source" gorm:"column:source"`
CustomFieldFour string `json:"custom_field_four" gorm:"column:custom_field_four"`
BugType string `json:"bugtype" gorm:"column:bugtype"`
OriginPhase string `json:"originphase" gorm:"column:originphase"`
CustomFieldThree string `json:"custom_field_three" gorm:"column:custom_field_three"`
Reporter string `json:"reporter" gorm:"column:reporter"`
Status string `json:"status" gorm:"column:status"`
}
// TapdBugTemplate TapdBugTemplate.
type TapdBugTemplate struct {
ID int64 `json:"id" gorm:"auto_increment;primary_key;column:id"`
WorkspaceID string `json:"workspace_id" gorm:"column:workspace_id"`
BuglyProjectId int64 `json:"bugly_project_id" gorm:"column:bugly_project_id"`
TapdProperty
IssueFilterSQL string `json:"issue_filter_sql" gorm:"column:issue_filter_sql"`
SeverityKey string `json:"severity_key" gorm:"column:severity_key"`
CTime time.Time `json:"ctime" gorm:"column:ctime"`
MTime time.Time `json:"mtime" gorm:"column:mtime"`
UpdateBy string `json:"update_by" gorm:"column:update_by"`
}
// TapdBugVersionTemplate TapdBugVersionTemplate.
type TapdBugVersionTemplate struct {
ID int64 `json:"id" gorm:"auto_increment;primary_key;column:id"`
Version string `json:"version" gorm:"column:version"`
ProjectTemplateID int64 `json:"project_template_id" gorm:"column:project_template_id"`
TapdProperty
IssueFilterSQL string `json:"issue_filter_sql" gorm:"column:issue_filter_sql"`
SeverityKey string `json:"severity_key" gorm:"column:severity_key"`
CTime time.Time `json:"ctime" gorm:"column:ctime"`
MTime time.Time `json:"mtime" gorm:"column:mtime"`
UpdateBy string `json:"update_by" gorm:"column:update_by"`
}
// BuglyVersion Bugly Version Record.
type BuglyVersion struct {
ID int64 `json:"id" gorm:"auto_increment;primary_key;column:id"`
Version string `json:"version" gorm:"column:version"`
BuglyProjectID int64 `json:"bugly_project_id" gorm:"column:bugly_project_id"`
Action int `json:"action" gorm:"column:action"`
TaskStatus int `json:"task_status" gorm:"column:task_status"`
UpdateBy string `json:"update_by" gorm:"column:update_by"`
CTime time.Time `json:"ctime" gorm:"column:ctime"`
MTime time.Time `json:"mtime" gorm:"column:mtime"`
}
// BuglyBatchRun Bugly Batch Run.
type BuglyBatchRun struct {
ID int64 `json:"id" gorm:"auto_increment;primary_key;column:id"`
BuglyVersionID int64 `json:"bugly_version_id" gorm:"column:bugly_version_id"`
Version string `json:"version" gorm:"column:version"`
BatchID string `json:"batch_id" gorm:"column:batch_id"`
RetryCount int `json:"retry_count" gorm:"retry_times:retry_count"`
Status int `json:"status" gorm:"column:status"`
ErrorMsg string `json:"error_msg" gorm:"column:error_msg"`
CTime time.Time `json:"ctime" gorm:"column:ctime"`
MTime time.Time `json:"mtime" gorm:"column:mtime"`
EndTime time.Time `json:"end_time" gorm:"column:end_time"`
}
// BuglyCookie Bugly Cookie.
type BuglyCookie struct {
ID int64 `json:"id" gorm:"auto_increment;primary_key;column:id"`
QQAccount int `json:"qq_account" gorm:"column:qq_account"`
Cookie string `json:"cookie" gorm:"column:cookie"`
Token string `json:"token" gorm:"column:token"`
UsageCount int `json:"usage_count" gorm:"column:usage_count"`
Status int `json:"status" gorm:"column:status"`
UpdateBy string `json:"update_by" gorm:"column:update_by"`
CTime time.Time `json:"ctime" gorm:"column:ctime"`
MTime time.Time `json:"mtime" gorm:"column:mtime"`
}
// User User.
type User struct {
ID int64 `json:"id" gorm:"auto_increment;primary_key;column:id"`
Name string `json:"username" gorm:"column:name"`
EMail string `json:"email" gorm:"column:email"`
VisibleBugly bool `json:"visible_bugly" gorm:"column:visible_bugly"`
CTime time.Time `gorm:"column:ctime;default:current_timestamp"`
UTime time.Time `gorm:"column:mtime;default:current_timestamp on update current_timestamp"`
}
// TapdBugRecord Tapd Bug Insert Log.
type TapdBugRecord struct {
ID int64 `json:"id" gorm:"auto_increment;primary_key;column:id"`
ProjectTemplateID int64 `json:"project_template_id" gorm:"column:project_template_id"`
VersionTemplateID int64 `json:"version_template_id" gorm:"column:version_template_id"`
Operator string `json:"operator" gorm:"column:operator"`
Count int `json:"count" gorm:"column:count"`
Status int `json:"status" gorm:"column:status"`
IssueFilterSQL string `json:"issue_filter_sql" gorm:"column:issue_filter_sql"`
CTime time.Time `json:"ctime" gorm:"column:ctime"`
MTime time.Time `json:"mtime" gorm:"column:mtime"`
}
// ScheduleTask Schedule Task.
type ScheduleTask struct {
ID int64 `json:"id" gorm:"auto_increment;primary_key;column:id"`
Name string `json:"username" gorm:"column:name"`
Status int `json:"status" gorm:"column:status"`
CTime time.Time `gorm:"column:ctime;default:current_timestamp"`
MTime time.Time `gorm:"column:mtime;default:current_timestamp on update current_timestamp"`
}
// TapdBugPriorityConf Tapd Bug Priority Conf.
type TapdBugPriorityConf struct {
ID int64 `json:"id" gorm:"auto_increment;primary_key;column:id"`
ProjectTemplateID int64 `json:"project_template_id" gorm:"column:project_template_id"`
Urgent int `json:"urgent" gorm:"column:urgent"`
High int `json:"high" gorm:"column:high"`
Medium int `json:"medium" gorm:"column:medium"`
StartTime time.Time `json:"start_time" gorm:"column:start_time"`
EndTime time.Time `json:"end_time" gorm:"column:end_time"`
CTime time.Time `json:"ctime" gorm:"column:ctime"`
MTime time.Time `json:"mtime" gorm:"column:mtime"`
UpdateBy string `json:"update_by" gorm:"column:update_by"`
Status int `json:"status" gorm:"column:status"`
}
// ContactInfo Contact Info
type ContactInfo struct {
ID int64 `json:"id" gorm:"column:id"`
UserName string `json:"username" gorm:"column:username"`
UserID string `json:"user_id" gorm:"column:user_id"`
NickName string `json:"nick_name" gorm:"column:nick_name"`
CTime time.Time `json:"ctime" gorm:"column:ctime"`
MTime time.Time `json:"mtime" gorm:"column:mtime"`
}
// BuglyProject Bugly Project.
type BuglyProject struct {
ID int64 `json:"id" gorm:"auto_increment;primary_key;column:id"`
ProjectID string `json:"project_id" gorm:"column:project_id"`
ProjectName string `json:"project_name" gorm:"column:project_name"`
PlatformID string `json:"platform_id" gorm:"column:platform_id"`
UpdateBy string `json:"update_by" gorm:"column:update_by"`
ExceptionType string `json:"exception_type" gorm:"column:exception_type"`
CTime time.Time `json:"ctime" gorm:"column:ctime"`
MTime time.Time `json:"mtime" gorm:"column:mtime"`
}

View File

@ -0,0 +1,182 @@
package model
// ReleaseResponse Release Response
type ReleaseResponse struct {
Status int `json:"status"`
Data *ReleaseWrapper `json:"data"`
Info string `json:"info"`
}
// ReleaseWrapper Release Wrapper
type ReleaseWrapper struct {
Release *Release `json:"Release"`
}
// WorkspaceUserResponse Workspace User Response
type WorkspaceUserResponse struct {
Status int `json:"status"`
Data []*WorkspaceUserWrapper `json:"data"`
Info string `json:"info"`
}
// WorkspaceUserWrapper Workspace User Wrapper
type WorkspaceUserWrapper struct {
UserWrapper *UserWrapper `json:"UserWorkspace"`
}
// UserWrapper User Wrapper
type UserWrapper struct {
User string `json:"user"`
}
// Release Release
type Release struct {
ID string `json:"id"`
WorkSpaceID string `json:"workspace_id"`
Name string `json:"name"`
Description string `json:"description"`
StartDate string `json:"startdate"`
EndDate string `json:"enddate"`
Creator string `json:"creator"`
Created string `json:"created"`
Modified string `json:"modified"`
Status string `json:"status"`
}
// BugResponse Bug Response
type BugResponse struct {
Status int `json:"status"`
Data []*BugWrapper `json:"data"`
Info string `json:"info"`
}
// BugSingleResponse Bug Response
type BugSingleResponse struct {
Status int `json:"status"`
Data *BugWrapper `json:"data"`
Info string `json:"info"`
}
// BugWrapper Bug Wrapper
type BugWrapper struct {
Bug *Bug `json:"Bug"`
}
// Bug Bug
type Bug struct {
ID string `json:"id"`
Title string `json:"title"`
Description string `json:"description"`
Priority string `json:"priority"`
Severity string `json:"severity"`
Module string `json:"module"`
Status string `json:"status"`
Reporter string `json:"reporter"`
Deadline string `json:"deadline"`
Created string `json:"created"`
BugType string `json:"bugtype"`
Resolved string `json:"resolved"`
Closed string `json:"closed"`
Modified string `json:"modified"`
LastModify string `json:"lastmodify"`
Auditer string `json:"auditer"`
DE string `json:"de"`
VersionTest string `json:"version_test"`
VersionReport string `json:"version_report"`
VersionClose string `json:"version_close"`
VersionFix string `json:"version_fix"`
BaselineFind string `json:"baseline_find"`
BaselineJoin string `json:"baseline_join"`
BaselineClose string `json:"baseline_close"`
BaselineTest string `json:"baseline_test"`
SourcePhase string `json:"sourcephase"`
TE string `json:"te"`
CurrentOwner string `json:"current_owner"`
IterationID string `json:"iteration_id"`
Resolution string `json:"resolution"`
Source string `json:"source"`
OriginPhase string `json:"originphase"`
Confirmer string `json:"confirmer"`
Milestone string `json:"milestone"`
Participator string `json:"participator"`
Closer string `json:"closer"`
Platform string `json:"platform"`
OS string `json:"os"`
TestType string `json:"testtype"`
TestPhase string `json:"testphase"`
Frequency string `json:"frequency"`
CC string `json:"cc"`
RegressionNumber string `json:"regression_number"`
Flows string `json:"flows"`
Feature string `json:"feature"`
TestMode string `json:"testmode"`
Estimate string `json:"estimate"`
IssueID string `json:"issue_id"`
CreatedFrom string `json:"created_from"`
InProgressTime string `json:"in_progress_time"`
VerifyTime string `json:"verify_time"`
RejectTime string `json:"reject_time"`
ReopenTime string `json:"reopen_time"`
AuditTime string `json:"audit_time"`
SuspendTime string `json:"suspend_time"`
Due string `json:"due"`
Begin string `json:"begin"`
ReleaseID string `json:"release_id"`
WorkspaceID string `json:"workspace_id"`
CustomFieldOne string `json:"custom_field_one"`
CustomFieldTwo string `json:"custom_field_two"`
CustomFieldThree string `json:"custom_field_three"`
CustomFieldFour string `json:"custom_field_four"`
CustomFieldFive string `json:"custom_field_five"`
CustomField6 string `json:"custom_field_6"`
CustomField7 string `json:"custom_field_7"`
CustomField8 string `json:"custom_field_8"`
CustomField9 string `json:"custom_field_9"`
CustomField10 string `json:"custom_field_10"`
CustomField11 string `json:"custom_field_11"`
CustomField12 string `json:"custom_field_12"`
CustomField13 string `json:"custom_field_13"`
CustomField14 string `json:"custom_field_14"`
CustomField15 string `json:"custom_field_15"`
CustomField16 string `json:"custom_field_16"`
CustomField17 string `json:"custom_field_17"`
CustomField18 string `json:"custom_field_18"`
CustomField19 string `json:"custom_field_19"`
CustomField20 string `json:"custom_field_20"`
CustomField21 string `json:"custom_field_21"`
CustomField22 string `json:"custom_field_22"`
CustomField23 string `json:"custom_field_23"`
CustomField24 string `json:"custom_field_24"`
CustomField25 string `json:"custom_field_25"`
CustomField26 string `json:"custom_field_26"`
CustomField27 string `json:"custom_field_27"`
CustomField28 string `json:"custom_field_28"`
CustomField29 string `json:"custom_field_29"`
CustomField30 string `json:"custom_field_30"`
CustomField31 string `json:"custom_field_31"`
CustomField32 string `json:"custom_field_32"`
CustomField33 string `json:"custom_field_33"`
CustomField34 string `json:"custom_field_34"`
CustomField35 string `json:"custom_field_35"`
CustomField36 string `json:"custom_field_36"`
CustomField37 string `json:"custom_field_37"`
CustomField38 string `json:"custom_field_38"`
CustomField39 string `json:"custom_field_39"`
CustomField40 string `json:"custom_field_40"`
CustomField41 string `json:"custom_field_41"`
CustomField42 string `json:"custom_field_42"`
CustomField43 string `json:"custom_field_43"`
CustomField44 string `json:"custom_field_44"`
CustomField45 string `json:"custom_field_45"`
CustomField46 string `json:"custom_field_46"`
CustomField47 string `json:"custom_field_47"`
CustomField48 string `json:"custom_field_48"`
CustomField49 string `json:"custom_field_49"`
CustomField50 string `json:"custom_field_50"`
}
// UpdateBug Update Bug
type UpdateBug struct {
*Bug
CurrentUser string `json:"current_user"`
}

View File

@ -0,0 +1,8 @@
package model
// WechatContact Wechat Contact
type WechatContact struct {
EnglishName string `json:"english_name"`
UserID string `json:"userid"`
Name string `json:"name"`
}

View File

@ -0,0 +1,43 @@
package(default_visibility = ["//visibility:public"])
load(
"@io_bazel_rules_go//go:def.bzl",
"go_library",
)
go_library(
name = "go_default_library",
srcs = [
"bugly.go",
"http.go",
"tapd.go",
"user.go",
],
importpath = "go-common/app/admin/ep/marthe/server/http",
tags = ["automanaged"],
visibility = ["//visibility:public"],
deps = [
"//app/admin/ep/marthe/conf:go_default_library",
"//app/admin/ep/marthe/model:go_default_library",
"//app/admin/ep/marthe/service:go_default_library",
"//library/ecode:go_default_library",
"//library/log:go_default_library",
"//library/net/http/blademaster:go_default_library",
"//library/net/http/blademaster/binding:go_default_library",
"//library/net/http/blademaster/middleware/permit:go_default_library",
],
)
filegroup(
name = "package-srcs",
srcs = glob(["**"]),
tags = ["automanaged"],
visibility = ["//visibility:private"],
)
filegroup(
name = "all-srcs",
srcs = [":package-srcs"],
tags = ["automanaged"],
visibility = ["//visibility:public"],
)

View File

@ -0,0 +1,218 @@
package http
import (
"go-common/app/admin/ep/marthe/model"
bm "go-common/library/net/http/blademaster"
"go-common/library/net/http/blademaster/binding"
)
// bugly version
func updateVersion(c *bm.Context) {
var (
req = &model.AddVersionRequest{}
err error
username string
)
if err = c.BindWith(req, binding.JSON); err != nil {
return
}
if username, err = getUsername(c); err != nil {
return
}
c.JSON(srv.UpdateBuglyVersion(c, username, req))
}
func getVersionAndProjectList(c *bm.Context) {
c.JSON(srv.BuglyVersionAndProjectList(c))
}
func queryVersions(c *bm.Context) {
var (
req = &model.QueryBuglyVersionRequest{}
err error
)
if err = req.Verify(); err != nil {
c.JSON(nil, err)
return
}
if err = c.BindWith(req, binding.JSON); err != nil {
return
}
c.JSON(srv.QueryBuglyVersions(c, req))
}
func runVersions(c *bm.Context) {
var (
v = new(struct {
ID int64 `form:"id"`
})
err error
)
if err = c.Bind(v); err != nil {
return
}
c.JSON(srv.RunVersions(v.ID))
}
// bugly cookie
func updateCookie(c *bm.Context) {
var (
req = &model.AddCookieRequest{}
err error
username string
)
if username, err = getUsername(c); err != nil {
return
}
if err = c.BindWith(req, binding.JSON); err != nil {
return
}
c.JSON(srv.UpdateCookie(c, username, req))
}
func queryCookies(c *bm.Context) {
var (
req = &model.QueryBuglyCookiesRequest{}
err error
)
if err = req.Verify(); err != nil {
c.JSON(nil, err)
return
}
if err = c.BindWith(req, binding.JSON); err != nil {
return
}
c.JSON(srv.QueryCookies(c, req))
}
func updateCookieStatus(c *bm.Context) {
var (
v = new(struct {
ID int64 `form:"id"`
Status int `form:"status"`
})
err error
)
if err = c.Bind(v); err != nil {
return
}
c.JSON(nil, srv.UpdateCookieStatus(c, v.ID, v.Status))
}
// bugly issue
func queryBuglyIssue(c *bm.Context) {
var (
err error
v = &model.QueryBuglyIssueRequest{}
)
if err = c.BindWith(v, binding.JSON); err != nil {
return
}
c.JSON(srv.QueryBuglyIssueRecords(c, v))
}
func queryBatchRun(c *bm.Context) {
var (
err error
v = &model.QueryBuglyBatchRunsRequest{}
)
if err = c.BindWith(v, binding.JSON); err != nil {
return
}
c.JSON(srv.QueryBatchRuns(c, v))
}
// bugly project
func updateProject(c *bm.Context) {
var (
req = &model.AddProjectRequest{}
err error
username string
)
if err = c.BindWith(req, binding.JSON); err != nil {
return
}
if username, err = getUsername(c); err != nil {
return
}
c.JSON(srv.UpdateBuglyProject(c, username, req))
}
func queryProjects(c *bm.Context) {
var (
req = &model.QueryBuglyProjectRequest{}
err error
)
if err = req.Verify(); err != nil {
c.JSON(nil, err)
return
}
if err = c.BindWith(req, binding.JSON); err != nil {
return
}
c.JSON(srv.QueryBuglyProjects(c, req))
}
func queryProjectVersions(c *bm.Context) {
var (
v = new(struct {
ID int64 `form:"id"`
})
err error
)
if err = c.Bind(v); err != nil {
return
}
c.JSON(srv.QueryBuglyProjectVersions(c, v.ID))
}
func queryProject(c *bm.Context) {
var (
v = new(struct {
ID int64 `form:"id"`
})
err error
)
if err = c.Bind(v); err != nil {
return
}
c.JSON(srv.QueryBuglyProject(c, v.ID))
}
func queryAllProjects(c *bm.Context) {
c.JSON(srv.QueryAllBuglyProjects(c))
}
//test
func test(c *bm.Context) {
srv.BatchRunTask(model.TaskBatchRunUpdateBugInTapd, srv.BatchRunUpdateBugInTapd)
c.JSON(nil, nil)
}

View File

@ -0,0 +1,122 @@
package http
import (
"net/http"
"go-common/app/admin/ep/marthe/conf"
"go-common/app/admin/ep/marthe/service"
"go-common/library/log"
bm "go-common/library/net/http/blademaster"
"go-common/library/net/http/blademaster/middleware/permit"
)
var (
srv *service.Service
authSvc *permit.Permit
)
// Init Init.
func Init(c *conf.Config, s *service.Service) {
srv = s
authSvc = permit.New(c.Auth)
engine := bm.DefaultServer(c.BM)
engine.Ping(ping)
outerRouter(engine)
if err := engine.Start(); err != nil {
log.Error("engine.Start error(%v)", err)
panic(err)
}
}
func outerRouter(e *bm.Engine) {
base := e.Group("/ep/admin/marthe/v1", authSvc.Permit(""))
{
base.GET("/version", getVersion)
bugly := base.Group("/bugly")
{
bugly.GET("/test", test)
project := bugly.Group("/project") //done test
{
project.GET("", queryProject) //done test
project.POST("/update", accessToBugly, updateProject) //done test
project.POST("/query", queryProjects) //done test
project.GET("/all", queryAllProjects) //done test
project.GET("/versions", queryProjectVersions) // done test
}
version := bugly.Group("/version") //done test
{
version.GET("/run", accessToBugly, runVersions) //done test
version.POST("/update", accessToBugly, updateVersion) //done test
version.POST("/query", queryVersions) //done test
version.GET("/list", getVersionAndProjectList) // done test
version.POST("/batch/query", queryBatchRun)
}
cookie := bugly.Group("/cookie")
{
cookie.POST("/add", updateCookie) // done test
cookie.POST("/update", updateCookie) // done test
cookie.POST("/query", queryCookies) // done test
cookie.GET("/status/update", updateCookieStatus) //done test
}
issue := bugly.Group("/issue")
{
issue.POST("/query", queryBuglyIssue) // done test
}
}
tapd := base.Group("/tapd")
{
bug := tapd.Group("/bug")
{
bug.GET("/project/insert", bugInsertTapdWithProject) // done test access
bug.GET("/version/insert", bugInsertTapdWithVersion) // done test access
bug.POST("/filtersql/check", checkFilterSql) // done test
bug.POST("/record/query", queryBugRecord) // done test
bug.POST("/template/update", updateTapdBugTpl) // done test access
bug.POST("/template/query", queryTapdBugTpl) // done test
bug.GET("/template/all", queryAllTapdBugTpl) // done test
bug.POST("/version/template/update", updateTapdBugVersionTpl) //done test access
bug.POST("/version/template/query", queryTapdBugVersionTpl) //done test
bug.POST("/conf/priority/update", updateTapdBugPriorityConf) //done test
bug.POST("/conf/priority/query", queryTapdBugPriorityConf) //done test
bug.GET("/conf/auth/check", checkAuth)
}
}
user := base.Group("/user")
{
user.GET("/query", queryUserInfo) // done test
user.GET("/wechat/contact/sync", syncWechatContact) // done test
user.GET("/visible/bugly", updateVisibleBugly) // done test
}
}
}
func ping(c *bm.Context) {
if err := srv.Ping(c); err != nil {
log.Error("ping error(%v)", err)
c.AbortWithStatus(http.StatusServiceUnavailable)
}
}
func getVersion(c *bm.Context) {
v := new(struct {
Version string `json:"version"`
})
v.Version = "v.0.0.0.3"
log.Info("marthe current version [%s]", v.Version)
c.JSON(v, nil)
}

View File

@ -0,0 +1,187 @@
package http
import (
"go-common/app/admin/ep/marthe/model"
bm "go-common/library/net/http/blademaster"
"go-common/library/net/http/blademaster/binding"
)
func updateTapdBugTpl(c *bm.Context) {
var (
err error
v = &model.UpdateTapdBugTplRequest{}
username string
)
if err = c.BindWith(v, binding.JSON); err != nil {
return
}
if username, err = getUsername(c); err != nil {
return
}
c.JSON(srv.UpdateTapdBugTpl(c, username, v))
}
func queryTapdBugTpl(c *bm.Context) {
var (
err error
v = &model.QueryTapdBugTemplateRequest{}
)
if err = c.BindWith(v, binding.JSON); err != nil {
return
}
c.JSON(srv.QueryTapdBugTpl(c, v))
}
func queryAllTapdBugTpl(c *bm.Context) {
c.JSON(srv.QueryAllTapdBugTpl(c))
}
func updateTapdBugVersionTpl(c *bm.Context) {
var (
err error
v = &model.UpdateTapdBugVersionTplRequest{}
username string
)
if err = c.BindWith(v, binding.JSON); err != nil {
return
}
if username, err = getUsername(c); err != nil {
return
}
c.JSON(srv.UpdateTapdBugVersionTpl(c, username, v))
}
func queryTapdBugVersionTpl(c *bm.Context) {
var (
err error
v = &model.QueryTapdBugVersionTemplateRequest{}
)
if err = c.BindWith(v, binding.JSON); err != nil {
return
}
c.JSON(srv.QueryTapdBugVersionTpl(c, v))
}
func checkFilterSql(c *bm.Context) {
var (
err error
v = new(struct {
SQL string `json:"issue_filter_sql"`
})
)
if err = c.BindWith(v, binding.JSON); err != nil {
return
}
c.JSON(srv.CheckTapdBugTplSQL(c, v.SQL))
}
func bugInsertTapdWithProject(c *bm.Context) {
var (
v = new(struct {
ID int64 `form:"id"`
})
err error
username string
)
if err = c.Bind(v); err != nil {
return
}
if username, err = getUsername(c); err != nil {
return
}
c.JSON(srv.BugInsertTapdWithProject(c, v.ID, username))
}
func bugInsertTapdWithVersion(c *bm.Context) {
var (
v = new(struct {
ID int64 `form:"id"`
})
err error
username string
)
if err = c.Bind(v); err != nil {
return
}
if username, err = getUsername(c); err != nil {
return
}
c.JSON(srv.BugInsertTapdWithVersion(c, v.ID, username))
}
func queryBugRecord(c *bm.Context) {
var (
err error
v = &model.QueryBugRecordsRequest{}
)
if err = c.BindWith(v, binding.JSON); err != nil {
return
}
c.JSON(srv.QueryBugRecords(c, v))
}
func updateTapdBugPriorityConf(c *bm.Context) {
var (
err error
v = &model.UpdateTapdBugPriorityConfRequest{}
username string
)
if err = c.BindWith(v, binding.JSON); err != nil {
return
}
if username, err = getUsername(c); err != nil {
return
}
c.JSON(srv.UpdateTapdBugPriorityConf(c, username, v))
}
func queryTapdBugPriorityConf(c *bm.Context) {
var (
err error
v = &model.QueryTapdBugPriorityConfsRequest{}
)
if err = c.BindWith(v, binding.JSON); err != nil {
return
}
c.JSON(srv.QueryTapdBugPriorityConfsRequest(c, v))
}
func checkAuth(c *bm.Context) {
var (
v = new(struct {
Username string `form:"username"`
WorkspaceID string `form:"workspace_id"`
})
err error
)
if err = c.Bind(v); err != nil {
return
}
c.JSON(srv.HttpAccessToWorkspace(c, v.WorkspaceID, v.Username))
}

View File

@ -0,0 +1,74 @@
package http
import (
"go-common/library/ecode"
bm "go-common/library/net/http/blademaster"
)
const (
_sessUnKey = "username"
)
func queryUserInfo(c *bm.Context) {
var (
username string
err error
)
if username, err = getUsername(c); err != nil {
return
}
c.JSON(srv.QueryUserInfo(c, username))
}
func syncWechatContact(c *bm.Context) {
c.JSON(nil, srv.HttpSyncWechatContacts(c))
}
func updateVisibleBugly(c *bm.Context) {
var (
v = new(struct {
UpdateUsername string `form:"username"`
VisibleBugly bool `form:"visible_bugly"`
})
err error
username string
)
if err = c.Bind(v); err != nil {
return
}
if username, err = getUsername(c); err != nil {
return
}
c.JSON(nil, srv.UpdateUserVisibleBugly(c, username, v.UpdateUsername, v.VisibleBugly))
}
func accessToBugly(c *bm.Context) {
var (
username string
err error
)
if username, err = getUsername(c); err != nil {
return
}
if !srv.AccessToBugly(c, username) {
c.JSON(nil, ecode.AccessDenied)
c.Abort()
return
}
}
func getUsername(c *bm.Context) (username string, err error) {
user, exist := c.Get(_sessUnKey)
if !exist {
err = ecode.AccessKeyErr
c.JSON(nil, err)
return
}
username = user.(string)
return
}

View File

@ -0,0 +1,46 @@
package(default_visibility = ["//visibility:public"])
load(
"@io_bazel_rules_go//go:def.bzl",
"go_library",
)
go_library(
name = "go_default_library",
srcs = [
"bugly.go",
"bugly_batch_run.go",
"mail.go",
"service.go",
"tapd.go",
"user.go",
],
importpath = "go-common/app/admin/ep/marthe/service",
tags = ["automanaged"],
visibility = ["//visibility:public"],
deps = [
"//app/admin/ep/marthe/conf:go_default_library",
"//app/admin/ep/marthe/dao:go_default_library",
"//app/admin/ep/marthe/model:go_default_library",
"//library/ecode:go_default_library",
"//library/log:go_default_library",
"//library/sync/pipeline/fanout:go_default_library",
"//vendor/github.com/robfig/cron:go_default_library",
"//vendor/github.com/satori/go.uuid:go_default_library",
"//vendor/gopkg.in/gomail.v2:go_default_library",
],
)
filegroup(
name = "package-srcs",
srcs = glob(["**"]),
tags = ["automanaged"],
visibility = ["//visibility:private"],
)
filegroup(
name = "all-srcs",
srcs = [":package-srcs"],
tags = ["automanaged"],
visibility = ["//visibility:public"],
)

View File

@ -0,0 +1,386 @@
package service
import (
"context"
"go-common/app/admin/ep/marthe/model"
"go-common/library/ecode"
)
// UpdateBuglyVersion update Bugly Version.
func (s *Service) UpdateBuglyVersion(c context.Context, username string, req *model.AddVersionRequest) (rep map[string]interface{}, err error) {
var (
bugVersionID int64
buglyProject *model.BuglyProject
)
// check project
if buglyProject, err = s.dao.QueryBuglyProject(req.BuglyProjectID); err != nil {
return
}
if buglyProject.ID == 0 {
err = ecode.NothingFound
return
}
if req.ID > 0 {
// update
var tmpVersion *model.BuglyVersion
if tmpVersion, err = s.dao.QueryBuglyVersion(req.ID); err != nil {
return
}
if tmpVersion.ID == 0 {
err = ecode.NothingFound
return
}
tmpVersion.BuglyProjectID = req.BuglyProjectID
tmpVersion.Version = req.Version
tmpVersion.Action = req.Action
if err = s.dao.UpdateBuglyVersion(tmpVersion); err != nil {
return
}
bugVersionID = tmpVersion.ID
} else {
// add
var tmpVersion *model.BuglyVersion
//check name
if tmpVersion, err = s.dao.QueryBuglyVersionByVersion(req.Version); err != nil {
return
}
if tmpVersion.ID > 0 {
err = ecode.MartheDuplicateErr
return
}
buglyVersion := &model.BuglyVersion{
ID: req.ID,
Version: req.Version,
BuglyProjectID: req.BuglyProjectID,
Action: req.Action,
TaskStatus: model.BuglyVersionTaskStatusReady,
UpdateBy: username,
}
if err = s.dao.InsertBuglyVersion(buglyVersion); err != nil {
return
}
bugVersionID = buglyVersion.ID
}
rep = make(map[string]interface{})
rep["bug_version_id"] = bugVersionID
return
}
// QueryBuglyVersions Query Bugly Versions.
func (s *Service) QueryBuglyVersions(c context.Context, req *model.QueryBuglyVersionRequest) (rep *model.PaginateBuglyProjectVersions, err error) {
var (
total int64
buglyProjectVersions []*model.BuglyProjectVersion
)
if total, buglyProjectVersions, err = s.dao.FindBuglyProjectVersions(req); err != nil {
return
}
rep = &model.PaginateBuglyProjectVersions{
PaginationRep: model.PaginationRep{
Total: total,
PageSize: req.PageSize,
PageNum: req.PageNum,
},
BuglyProjectVersions: buglyProjectVersions,
}
return
}
// BuglyVersionAndProjectList Bugly Version and project List.
func (s *Service) BuglyVersionAndProjectList(c context.Context) (rep map[string]interface{}, err error) {
var (
versionList []string
projectList []string
)
rep = make(map[string]interface{})
if versionList, err = s.dao.QueryBuglyVersionList(); err != nil {
return
}
if projectList, err = s.dao.QueryBuglyProjectList(); err != nil {
return
}
rep["versions"] = versionList
rep["projects"] = projectList
return
}
// UpdateCookie update Cookie.
func (s *Service) UpdateCookie(c context.Context, username string, req *model.AddCookieRequest) (rep map[string]interface{}, err error) {
var cookieID int64
if req.ID > 0 {
buglyCookie := &model.BuglyCookie{
ID: req.ID,
QQAccount: req.QQAccount,
Cookie: req.Cookie,
Token: req.Token,
Status: req.Status,
UpdateBy: username,
}
if err = s.dao.UpdateCookie(buglyCookie); err != nil {
return
}
cookieID = req.ID
} else {
buglyCookie := &model.BuglyCookie{
QQAccount: req.QQAccount,
Cookie: req.Cookie,
Token: req.Token,
Status: req.Status,
UpdateBy: username,
}
if err = s.dao.InsertCookie(buglyCookie); err != nil {
return
}
cookieID = buglyCookie.ID
}
rep = make(map[string]interface{})
rep["cookie_id"] = cookieID
return
}
// QueryCookies Add Cookie.
func (s *Service) QueryCookies(c context.Context, req *model.QueryBuglyCookiesRequest) (rep *model.PaginateBuglyCookies, err error) {
var (
total int64
buglyCookies []*model.BuglyCookie
)
if total, buglyCookies, err = s.dao.FindCookies(req); err != nil {
return
}
rep = &model.PaginateBuglyCookies{
PaginationRep: model.PaginationRep{
Total: total,
PageSize: req.PageSize,
PageNum: req.PageNum,
},
BuglyCookies: buglyCookies,
}
return
}
// UpdateCookieStatus Update Cookie Status.
func (s *Service) UpdateCookieStatus(c context.Context, cookieID int64, status int) (err error) {
err = s.dao.UpdateCookieStatus(cookieID, status)
return
}
// GetEnableCookie Get Enable Cookie.
func (s *Service) GetEnableCookie() (buglyCookie *model.BuglyCookie, err error) {
var buglyCookies []*model.BuglyCookie
if buglyCookies, err = s.dao.QueryCookieByStatus(model.BuglyCookieStatusEnable); err != nil {
return
}
/*for _, ele := range buglyCookies {
if ele.UsageCount < s.c.Bugly.CookieUsageUpper {
buglyCookie = ele
err = s.dao.UpdateCookieUsageCount(buglyCookie.ID, buglyCookie.UsageCount+1)
return
}
}*/
if len(buglyCookies) > 0 {
buglyCookie = buglyCookies[0]
err = s.dao.UpdateCookieUsageCount(buglyCookie.ID, buglyCookie.UsageCount+1)
return
}
//not found enable cookie
s.DoWhenNoEnableCookie()
err = ecode.MartheNoCookie
return
}
// DisableCookie Disable Cookie.
func (s *Service) DisableCookie(c context.Context, cookieID int64) (err error) {
err = s.dao.UpdateCookieStatus(cookieID, model.BuglyCookieStatusDisable)
return
}
// DoWhenNoEnableCookie Do When No Enable Cookie.
func (s *Service) DoWhenNoEnableCookie() {
// todo notice
s.SendMail(s.c.Mail.NoticeOwner, "marthe has no enable cookie", "")
}
// QueryBuglyIssueRecords Query Bugly Issue Records
func (s *Service) QueryBuglyIssueRecords(c context.Context, req *model.QueryBuglyIssueRequest) (rep *model.PaginateBuglyIssues, err error) {
var (
total int64
buglyIssues []*model.BuglyIssue
)
if total, buglyIssues, err = s.dao.FindBuglyIssues(req); err != nil {
return
}
rep = &model.PaginateBuglyIssues{
PaginationRep: model.PaginationRep{
Total: total,
PageSize: req.PageSize,
PageNum: req.PageNum,
},
BuglyIssues: buglyIssues,
}
return
}
// QueryBatchRuns Query Batch Runs
func (s *Service) QueryBatchRuns(c context.Context, req *model.QueryBuglyBatchRunsRequest) (rep *model.PaginateBuglyBatchRuns, err error) {
var (
total int64
buglyBatchRuns []*model.BuglyBatchRun
)
if total, buglyBatchRuns, err = s.dao.FindBuglyBatchRuns(req); err != nil {
return
}
rep = &model.PaginateBuglyBatchRuns{
PaginationRep: model.PaginationRep{
Total: total,
PageSize: req.PageSize,
PageNum: req.PageNum,
},
BuglyBatchRuns: buglyBatchRuns,
}
return
}
// UpdateBuglyProject update bugly project.
func (s *Service) UpdateBuglyProject(c context.Context, username string, req *model.AddProjectRequest) (rep map[string]interface{}, err error) {
var buglyProjectID int64
if req.ID > 0 {
buglyProject := &model.BuglyProject{
ID: req.ID,
ProjectID: req.ProjectID,
//ProjectName: req.ProjectName,
PlatformID: req.PlatformID,
ExceptionType: req.ExceptionType,
UpdateBy: username,
}
if err = s.dao.UpdateBuglyProject(buglyProject); err != nil {
return
}
buglyProjectID = req.ID
} else {
var buglyProjectInDB *model.BuglyProject
if buglyProjectInDB, err = s.dao.QueryBuglyProjectByName(req.ProjectName); err != nil {
return
}
if buglyProjectInDB.ID > 0 {
err = ecode.MartheDuplicateErr
return
}
buglyProject := &model.BuglyProject{
ProjectID: req.ProjectID,
ProjectName: req.ProjectName,
PlatformID: req.PlatformID,
ExceptionType: req.ExceptionType,
UpdateBy: username,
}
if err = s.dao.InsertBuglyProject(buglyProject); err != nil {
return
}
buglyProjectID = buglyProject.ID
}
rep = make(map[string]interface{})
rep["bugly_project_id"] = buglyProjectID
return
}
// QueryBuglyProjects Query Bugly Project.
func (s *Service) QueryBuglyProjects(c context.Context, req *model.QueryBuglyProjectRequest) (rep *model.PaginateBuglyProjects, err error) {
var (
total int64
buglyProjects []*model.BuglyProject
)
if total, buglyProjects, err = s.dao.FindBuglyProjects(req); err != nil {
return
}
rep = &model.PaginateBuglyProjects{
PaginationRep: model.PaginationRep{
Total: total,
PageSize: req.PageSize,
PageNum: req.PageNum,
},
BuglyProjects: buglyProjects,
}
return
}
// QueryBuglyProject Query Bugly Project.
func (s *Service) QueryBuglyProject(c context.Context, id int64) (buglyProject *model.BuglyProject, err error) {
return s.dao.QueryBuglyProject(id)
}
// QueryAllBuglyProjects Query All Bugly Projects.
func (s *Service) QueryAllBuglyProjects(c context.Context) (buglyProjects []*model.BuglyProject, err error) {
return s.dao.QueryAllBuglyProjects()
}
// QueryBuglyProjectVersions Query Bugly Project Versions.
func (s *Service) QueryBuglyProjectVersions(c context.Context, buglyProjectID int64) (rep map[string]interface{}, err error) {
var (
buglyProject *model.BuglyProject
buglyCookie *model.BuglyCookie
buglyVersions []*model.BugVersion
versions []string
)
defer func() {
if err != nil && err == ecode.MartheCookieExpired {
s.DisableCookie(c, buglyCookie.ID)
}
}()
if buglyProject, err = s.dao.QueryBuglyProject(buglyProjectID); err != nil {
return
}
if buglyProject.ID == 0 {
err = ecode.NothingFound
return
}
//get enable cookie
if buglyCookie, err = s.GetEnableCookie(); err != nil {
return
}
if buglyVersions, err = s.dao.BuglyVersion(c, buglyCookie, buglyProject.ProjectID, buglyProject.PlatformID); err != nil || buglyVersions == nil {
return
}
for _, buglyVersion := range buglyVersions {
versions = append(versions, buglyVersion.Name)
}
rep = make(map[string]interface{})
rep["versions"] = versions
return
}

View File

@ -0,0 +1,358 @@
package service
import (
"context"
"fmt"
"sync"
"time"
"go-common/app/admin/ep/marthe/model"
"go-common/library/ecode"
"go-common/library/log"
"github.com/satori/go.uuid"
)
// RunVersions Run Versions.
func (s *Service) RunVersions(buglyVersionID int64) (rep map[string]interface{}, err error) {
lock := s.getBatchRunLock(buglyVersionID)
lock.Lock()
defer lock.Unlock()
var (
buglyRunVersions []*model.BuglyVersion
uid string
isEnableRun bool
)
// 获取可以跑的版本号list
if buglyRunVersions, err = s.GetBatchRunVersions(); err != nil {
log.Error("GetBatchRunVersions err(%v) ", err)
return
}
for _, buglyRunVersion := range buglyRunVersions {
if buglyRunVersion.ID == buglyVersionID {
isEnableRun = true
uid = uuid.NewV4().String()
// 插入batchrun表
buglyBatchRun := &model.BuglyBatchRun{
BuglyVersionID: buglyRunVersion.ID,
Version: buglyRunVersion.Version,
BatchID: uid,
Status: model.BuglyBatchRunStatusRunning,
}
if err = s.dao.InsertBuglyBatchRun(buglyBatchRun); err != nil {
return
}
s.batchRunCache.Do(context.Background(), func(ctx context.Context) {
if err = s.runPerVersion(uid, buglyRunVersion); err != nil {
log.Error("runPerVersion uid(%s) version(%s) err(%v) ", uid, buglyRunVersion.Version, err)
}
defer func() {
// batch run 并且更新batch run表
batchStatus := model.BuglyBatchRunStatusDone
errMsg := ""
endTime := time.Now()
if err != nil {
batchStatus = model.BuglyBatchRunStatusFailed
errMsg = err.Error()
}
updateBuglyBatchRun := &model.BuglyBatchRun{
ID: buglyBatchRun.ID,
Status: batchStatus,
ErrorMsg: errMsg,
EndTime: endTime,
}
if err = s.dao.UpdateBuglyBatchRun(updateBuglyBatchRun); err != nil {
log.Error("runPerVersion UpdateBuglyBatchRun uid(%s) version(%s) err(%v) ", uid, buglyRunVersion.Version, err)
}
}()
})
break
}
}
rep = make(map[string]interface{})
rep["uid"] = uid
rep["enable_to_run"] = isEnableRun
if !isEnableRun {
err = ecode.MartheTaskInRunning
}
return
}
// BatchRunVersions Batch Run Versions
func (s *Service) BatchRunVersions() (err error) {
var (
buglyRunVersions []*model.BuglyVersion
uid = uuid.NewV4().String()
)
// 获取可以跑的版本号list
if buglyRunVersions, err = s.dao.FindEnableAndReadyVersions(); err != nil {
log.Error("GetBatchRunVersions err(%v) ", err)
return
}
for _, buglyRunVersion := range buglyRunVersions {
if _, err = s.RunVersions(buglyRunVersion.ID); err != nil {
log.Error("runPerVersion uid(%s) version(%s) err(%v) ", uid, buglyRunVersion.Version, err)
}
}
return
}
func (s *Service) runPerVersion(uid string, buglyRunVersion *model.BuglyVersion) (err error) {
var (
buglyRet *model.BugRet
buglyCookie *model.BuglyCookie
requestPageCnt int
c = context.Background()
lastRunTime time.Time
buglyBatchRun *model.BuglyBatchRun
buglyProject *model.BuglyProject
)
log.Info("start run version: [%s] batchId: [%s]", buglyRunVersion.Version, uid)
if buglyProject, err = s.dao.QueryBuglyProject(buglyRunVersion.BuglyProjectID); err != nil {
return
}
if buglyProject.ID == 0 {
err = ecode.NothingFound
return
}
//get issue total count
bugIssueRequest := &model.BugIssueRequest{
ProjectID: buglyProject.ProjectID,
PlatformID: buglyProject.PlatformID,
Version: buglyRunVersion.Version,
ExceptionType: buglyProject.ExceptionType,
StartNum: 0,
Rows: 1,
}
//get last run time
if buglyBatchRun, err = s.dao.QueryLastSuccessBatchRunByVersion(buglyRunVersion.Version); err != nil {
return
}
if buglyBatchRun.ID > 0 {
lastRunTime = buglyBatchRun.CTime
} else {
loc, _ := time.LoadLocation("Local")
if lastRunTime, err = time.ParseInLocation(model.TimeLayout, model.TimeLayout, loc); err != nil {
return
}
}
//get enable cookie
if buglyCookie, err = s.GetEnableCookie(); err != nil {
return
}
// if cookie, update cookie as expired
defer func() {
if err != nil && err == ecode.MartheCookieExpired {
s.DisableCookie(c, buglyCookie.ID)
}
}()
if buglyRet, err = s.dao.BuglyIssueAndRetry(c, buglyCookie, bugIssueRequest); err != nil || len(buglyRet.BugIssues) < 1 {
return
}
//获取issue count 和 page 上限
requestPageCnt = int(buglyRet.NumFound/s.c.Bugly.IssuePageSize) + 1
requestPageCntMax := s.c.Bugly.IssueCountUpper / s.c.Bugly.IssuePageSize
if requestPageCnt > requestPageCntMax {
requestPageCnt = requestPageCntMax
}
// update or add issue
for i := 0; i < requestPageCnt; i++ {
innerBreak := false
bugIssueRequest.StartNum = s.c.Bugly.IssuePageSize * i
bugIssueRequest.Rows = s.c.Bugly.IssuePageSize
var ret *model.BugRet
if ret, err = s.dao.BuglyIssueAndRetry(c, buglyCookie, bugIssueRequest); err != nil {
return
}
loc, _ := time.LoadLocation("Local")
issueLink := "/v2/crash-reporting/errors/%s/%s/report?pid=%s&searchType=detail&version=%s&start=0&date=all"
for _, issueDto := range ret.BugIssues {
var (
issueTime time.Time
bugIssueDetail *model.BugIssueDetail
tagStr string
bugDetail = "no detail"
)
tmpTime := []rune(issueDto.LastTime)
issueTime, _ = time.ParseInLocation(model.TimeLayout, string(tmpTime[:len(tmpTime)-4]), loc)
//issue时间早于库里面最新时间的跳出
if issueTime.Before(lastRunTime) {
innerBreak = true
break
}
var tmpBuglyIssue *model.BuglyIssue
if tmpBuglyIssue, err = s.dao.GetBuglyIssue(issueDto.IssueID, issueDto.Version); err != nil {
log.Error("d.GetSaveIssues url(%s) err(%v)", "GetSaveIssues", err)
continue
}
for _, bugTag := range issueDto.Tags {
tagStr = tagStr + bugTag.TagName + ","
}
if tmpBuglyIssue.ID != 0 {
//update
issueRecord := &model.BuglyIssue{
IssueNo: issueDto.IssueID,
Title: issueDto.Title,
LastTime: issueTime,
HappenTimes: issueDto.Count,
UserTimes: issueDto.UserCount,
Version: issueDto.Version,
Tags: tagStr,
}
s.dao.UpdateBuglyIssue(issueRecord)
} else {
//create
if bugIssueDetail, err = s.dao.BuglyIssueDetailAndRetry(c, buglyCookie, buglyProject.ProjectID, buglyProject.PlatformID, issueDto.IssueID); err == nil {
bugDetail = bugIssueDetail.CallStack
}
issueURL := s.c.Bugly.Host + fmt.Sprintf(issueLink, buglyProject.ProjectID, issueDto.IssueID, buglyProject.PlatformID, buglyRunVersion.Version)
issueRecord := &model.BuglyIssue{
IssueNo: issueDto.IssueID,
Title: issueDto.Title,
LastTime: issueTime,
HappenTimes: issueDto.Count,
UserTimes: issueDto.UserCount,
Version: issueDto.Version,
Tags: tagStr,
Detail: bugDetail,
ExceptionMsg: issueDto.ExceptionMsg,
KeyStack: issueDto.KeyStack,
IssueLink: issueURL,
ProjectID: buglyProject.ProjectID,
}
s.dao.InsertBuglyIssue(issueRecord)
}
}
if innerBreak {
break
}
}
log.Info("end run version: [%s] batchId: [%s]", buglyRunVersion.Version, uid)
return
}
// GetBatchRunVersions Get Batch Run Versions.
func (s *Service) GetBatchRunVersions() (buglyRunVersions []*model.BuglyVersion, err error) {
var (
buglyVersions []*model.BuglyVersion
buglyBatchRuns []*model.BuglyBatchRun
)
if buglyVersions, err = s.dao.FindEnableAndReadyVersions(); err != nil {
return
}
if buglyBatchRuns, err = s.dao.QueryBuglyBatchRunsByStatus(model.BuglyBatchRunStatusRunning); err != nil {
return
}
// 排除正在执行的版本
for _, buglyVersion := range buglyVersions {
var isVersionRun bool
for _, buglyBatchRun := range buglyBatchRuns {
if buglyBatchRun.Version == buglyVersion.Version {
isVersionRun = true
break
}
}
if !isVersionRun {
buglyRunVersions = append(buglyRunVersions, buglyVersion)
}
}
return
}
// DisableBatchRunOverTime Disable Batch Run OverTime.
func (s *Service) DisableBatchRunOverTime() (err error) {
var (
buglyBatchRuns []*model.BuglyBatchRun
tapdBugRecords []*model.TapdBugRecord
timeNow = time.Now()
)
//清 未完成 disable batch run
if buglyBatchRuns, err = s.dao.QueryBuglyBatchRunsByStatus(model.BuglyBatchRunStatusRunning); err != nil {
return
}
for _, buglyBatchRun := range buglyBatchRuns {
if timeNow.Sub(buglyBatchRun.CTime).Hours() > float64(s.c.Scheduler.BatchRunOverHourTime) {
updateBuglyBatchRun := &model.BuglyBatchRun{
ID: buglyBatchRun.ID,
Status: model.BuglyBatchRunStatusFailed,
ErrorMsg: "over time",
EndTime: timeNow,
}
if err = s.dao.UpdateBuglyBatchRun(updateBuglyBatchRun); err != nil {
continue
}
}
}
// 清 未完成 disable insert tapd bug
if tapdBugRecords, err = s.dao.QueryTapdBugRecordByStatus(model.InsertBugStatusRunning); err != nil {
return
}
for _, tapdBugRecord := range tapdBugRecords {
if timeNow.Sub(tapdBugRecord.CTime).Hours() > float64(s.c.Scheduler.BatchRunOverHourTime) {
tapdBugRecord.Status = model.InsertBugStatusFailed
if err = s.dao.UpdateTapdBugRecord(tapdBugRecord); err != nil {
continue
}
}
}
return
}
func (s *Service) getBatchRunLock(buglyVersionId int64) (batchRunLock *sync.Mutex) {
s.syncBatchRunLock.Lock()
defer s.syncBatchRunLock.Unlock()
var ok bool
if batchRunLock, ok = s.mapBatchRunLocks[buglyVersionId]; !ok {
batchRunLock = new(sync.Mutex)
s.mapBatchRunLocks[buglyVersionId] = batchRunLock
}
return
}

View File

@ -0,0 +1,12 @@
package service
import "gopkg.in/gomail.v2"
// SendMail Send Mail.
func (s *Service) SendMail(receiver []string, header, body string) {
m := gomail.NewMessage()
m.SetHeader("To", receiver...)
m.SetHeader("Subject", header)
m.SetBody("text/html", body)
s.dao.SendMail(m)
}

View File

@ -0,0 +1,106 @@
package service
import (
"context"
"sync"
"go-common/app/admin/ep/marthe/conf"
"go-common/app/admin/ep/marthe/dao"
"go-common/app/admin/ep/marthe/model"
"go-common/library/sync/pipeline/fanout"
"github.com/robfig/cron"
)
// Service struct
type Service struct {
c *conf.Config
dao *dao.Dao
batchRunCache *fanout.Fanout
tapdBugCache *fanout.Fanout
taskCache *fanout.Fanout
cron *cron.Cron
syncWechatContactsLock sync.Mutex
syncTapdBugInsertLock sync.Mutex
mapTapdBugInsertLocks map[int64]*sync.Mutex
syncBatchRunLock sync.Mutex
mapBatchRunLocks map[int64]*sync.Mutex
}
// New init
func New(c *conf.Config) (s *Service) {
s = &Service{
c: c,
dao: dao.New(c),
batchRunCache: fanout.New("batchRunCache", fanout.Worker(5), fanout.Buffer(10240)),
tapdBugCache: fanout.New("tapdBugCache", fanout.Worker(5), fanout.Buffer(10240)),
taskCache: fanout.New("taskCache", fanout.Worker(5), fanout.Buffer(10240)),
mapTapdBugInsertLocks: make(map[int64]*sync.Mutex),
mapBatchRunLocks: make(map[int64]*sync.Mutex),
}
if c.Scheduler.Active {
s.cron = cron.New()
// 定时批量 跑enable version 抓bugly数据
if err := s.cron.AddFunc(c.Scheduler.BatchRunEnableVersion, func() { s.BatchRunTask(model.TaskBatchRunVersions, s.BatchRunVersions) }); err != nil {
panic(err)
}
// 定时把超过三小时为执行完毕的任务修改为失败
if err := s.cron.AddFunc(c.Scheduler.DisableBatchRunOverTime, func() { s.BatchRunTask(model.TaskDisableBatchRunOverTime, s.DisableBatchRunOverTime) }); err != nil {
panic(err)
}
// 定时更新tapd bug
if err := s.cron.AddFunc(c.Scheduler.BatchRunUpdateTapdBug, func() { s.BatchRunTask(model.TaskBatchRunUpdateBugInTapd, s.BatchRunUpdateBugInTapd) }); err != nil {
panic(err)
}
// 定时更新SyncWechatContact
if err := s.cron.AddFunc(c.Scheduler.SyncWechatContact, func() { s.BatchRunTask(model.TaskSyncWechatContact, s.SyncWechatContacts) }); err != nil {
panic(err)
}
s.cron.Start()
}
return s
}
// Ping Service
func (s *Service) Ping(c context.Context) (err error) {
return s.dao.Ping(c)
}
// Close Service
func (s *Service) Close() {
s.dao.Close()
}
// BatchRunTask Batch Run Task.
func (s *Service) BatchRunTask(taskName string, task func() error) {
var err error
scheduleTask := &model.ScheduleTask{
Name: taskName,
Status: model.TaskStatusRunning,
}
if err = s.dao.InsertScheduleTask(scheduleTask); err != nil {
return
}
err = task()
defer func() {
if err != nil {
scheduleTask.Status = model.TaskStatusFailed
} else {
scheduleTask.Status = model.TaskStatusDone
}
if err = s.dao.UpdateScheduleTask(scheduleTask); err != nil {
return
}
}()
}

View File

@ -0,0 +1,764 @@
package service
import (
"context"
"fmt"
"strconv"
"strings"
"sync"
"time"
"go-common/app/admin/ep/marthe/model"
"go-common/library/ecode"
"go-common/library/log"
)
// UpdateTapdBugTpl Update Tapd Bug Tpl.
func (s *Service) UpdateTapdBugTpl(c context.Context, username string, req *model.UpdateTapdBugTplRequest) (rep map[string]interface{}, err error) {
//check if access to workspace
if !s.AccessToWorkspace(req.WorkspaceID, username) {
err = ecode.AccessDenied
return
}
//check sql
if _, err = s.CheckTapdBugTplSQL(c, req.IssueFilterSQL); err != nil {
return
}
tapdBugTemplate := &model.TapdBugTemplate{
ID: req.ID,
WorkspaceID: req.WorkspaceID,
BuglyProjectId: req.BuglyProjectId,
IssueFilterSQL: req.IssueFilterSQL,
SeverityKey: req.SeverityKey,
UpdateBy: username,
TapdProperty: req.TapdProperty,
}
if req.ID > 0 {
err = s.dao.UpdateTapdBugTemplate(tapdBugTemplate)
} else {
// add new
err = s.dao.InsertTapdBugTemplate(tapdBugTemplate)
}
rep = make(map[string]interface{})
rep["template_id"] = tapdBugTemplate.ID
return
}
// QueryTapdBugTpl Query Tapd Bug Tpl
func (s *Service) QueryTapdBugTpl(c context.Context, req *model.QueryTapdBugTemplateRequest) (rep *model.PaginateTapdBugTemplates, err error) {
var (
total int64
tapdBugTemplates []*model.TapdBugTemplate
tapdBugTemplateWithProjectNames []*model.TapdBugTemplateWithProjectName
)
if total, tapdBugTemplates, err = s.dao.FindTapdBugTemplates(req); err != nil {
return
}
for _, tapdBugTemplate := range tapdBugTemplates {
var buglyProject *model.BuglyProject
if buglyProject, err = s.dao.QueryBuglyProject(tapdBugTemplate.BuglyProjectId); err != nil {
return
}
if req.ProjectName == "" || strings.Contains(buglyProject.ProjectName, req.ProjectName) {
tapdBugTemplateWithProjectName := &model.TapdBugTemplateWithProjectName{
TapdBugTemplate: tapdBugTemplate,
ProjectName: buglyProject.ProjectName,
}
tapdBugTemplateWithProjectNames = append(tapdBugTemplateWithProjectNames, tapdBugTemplateWithProjectName)
}
}
rep = &model.PaginateTapdBugTemplates{
PaginationRep: model.PaginationRep{
Total: total,
PageSize: req.PageSize,
PageNum: req.PageNum,
},
TapdBugTemplateWithProjectNames: tapdBugTemplateWithProjectNames,
}
return
}
// QueryAllTapdBugTpl Query All Tapd Bug Tpl
func (s *Service) QueryAllTapdBugTpl(c context.Context) (rep []*model.TapdBugTemplateShortResponse, err error) {
var tapdBugTemplates []*model.TapdBugTemplate
if tapdBugTemplates, err = s.dao.QueryAllTapdBugTemplates(); err != nil {
return
}
for _, tapdBugTemplate := range tapdBugTemplates {
var buglyProject *model.BuglyProject
if buglyProject, err = s.dao.QueryBuglyProject(tapdBugTemplate.BuglyProjectId); err != nil {
return
}
ret := &model.TapdBugTemplateShortResponse{
ID: tapdBugTemplate.ID,
WorkspaceID: tapdBugTemplate.WorkspaceID,
BuglyProjectId: tapdBugTemplate.BuglyProjectId,
BuglyProjectName: buglyProject.ProjectName,
}
rep = append(rep, ret)
}
return
}
// UpdateTapdBugVersionTpl Update Tapd Bug Version Tpl.
func (s *Service) UpdateTapdBugVersionTpl(c context.Context, username string, req *model.UpdateTapdBugVersionTplRequest) (rep map[string]interface{}, err error) {
// check sql
if req.IssueFilterSQL != "" {
if _, err = s.CheckTapdBugTplSQL(c, req.IssueFilterSQL); err != nil {
return
}
}
//check project id
var tmp *model.TapdBugTemplate
if tmp, err = s.dao.QueryTapdBugTemplate(req.ProjectTemplateID); err != nil {
return
}
if tmp.ID == 0 {
err = ecode.NothingFound
return
}
//check if access to workspace
if !s.AccessToWorkspace(tmp.WorkspaceID, username) {
err = ecode.AccessDenied
return
}
tapdBugVersionTemplate := &model.TapdBugVersionTemplate{
ID: req.ID,
Version: req.Version,
ProjectTemplateID: req.ProjectTemplateID,
IssueFilterSQL: req.IssueFilterSQL,
SeverityKey: req.SeverityKey,
UpdateBy: username,
TapdProperty: req.TapdProperty,
}
if req.ID > 0 {
err = s.dao.UpdateTapdBugVersionTemplate(tapdBugVersionTemplate)
} else {
// add new
err = s.dao.InsertTapdBugVersionTemplate(tapdBugVersionTemplate)
}
rep = make(map[string]interface{})
rep["version_template_id"] = tapdBugVersionTemplate.ID
return
}
// QueryTapdBugVersionTpl Query Tapd Bug Version Tpl
func (s *Service) QueryTapdBugVersionTpl(c context.Context, req *model.QueryTapdBugVersionTemplateRequest) (rep *model.PaginateTapdBugVersionTemplates, err error) {
var (
total int64
tapdBugVersionTemplates []*model.TapdBugVersionTemplate
)
if total, tapdBugVersionTemplates, err = s.dao.FindTapdBugVersionTemplates(req); err != nil {
return
}
rep = &model.PaginateTapdBugVersionTemplates{
PaginationRep: model.PaginationRep{
Total: total,
PageSize: req.PageSize,
PageNum: req.PageNum,
},
TapdBugVersionTemplates: tapdBugVersionTemplates,
}
return
}
// CheckTapdBugTplSQL Check Tapd Bug Tpl SQL.
func (s *Service) CheckTapdBugTplSQL(c context.Context, sql string) (rep map[string]interface{}, err error) {
var buglyIssues []*model.BuglyIssue
if buglyIssues, err = s.getBuglyIssuesByFilterSQLWithNoTapdBug(sql); err != nil {
err = ecode.MartheFilterSqlError
return
}
rep = make(map[string]interface{})
rep["count"] = len(buglyIssues)
return
}
// BugInsertTapdWithProject Bug Insert Tapd With Project.
func (s *Service) BugInsertTapdWithProject(c context.Context, id int64, username string) (rep map[string]interface{}, err error) {
var count int
count, err = s.bugInsertTapd(id, 0, username)
rep = make(map[string]interface{})
rep["tapd_bug_count"] = count
return
}
// BugInsertTapdWithVersion Bug Insert Tapd With Version.
func (s *Service) BugInsertTapdWithVersion(c context.Context, id int64, username string) (rep map[string]interface{}, err error) {
var count int
count, err = s.bugInsertTapd(0, id, username)
rep = make(map[string]interface{})
rep["tapd_bug_count"] = count
return
}
func (s *Service) bugInsertTapd(projectTemplateId, versionTemplateId int64, username string) (count int, err error) {
var (
tapdBugTemplate *model.TapdBugTemplate
tapdBugVersionTemplate *model.TapdBugVersionTemplate
buglyIssues []*model.BuglyIssue
tapdBugRecords []*model.TapdBugRecord
)
if (projectTemplateId == 0 && versionTemplateId == 0) || (projectTemplateId > 0 && versionTemplateId > 0) {
return
}
if projectTemplateId > 0 {
if tapdBugTemplate, err = s.dao.QueryTapdBugTemplate(projectTemplateId); err != nil {
return
}
if tapdBugTemplate.ID == 0 {
err = ecode.NothingFound
return
}
} else if versionTemplateId > 0 {
if tapdBugVersionTemplate, err = s.dao.QueryTapdBugVersionTemplate(versionTemplateId); err != nil {
return
}
if tapdBugVersionTemplate.ID == 0 {
err = ecode.NothingFound
return
}
projectTemplateId = tapdBugVersionTemplate.ProjectTemplateID
if tapdBugTemplate, err = s.dao.QueryTapdBugTemplate(projectTemplateId); err != nil {
return
}
if tapdBugTemplate.ID == 0 {
err = ecode.NothingFound
return
}
if err = s.UpdateTplAsVersionTpl(tapdBugVersionTemplate, tapdBugTemplate); err != nil {
return
}
}
// get map lock, every project tpl 串行
insertLock := s.getTapdBugInsertLock(projectTemplateId)
insertLock.Lock()
defer insertLock.Unlock()
//check if access to workspace
if !s.AccessToWorkspace(tapdBugTemplate.WorkspaceID, username) {
err = ecode.AccessDenied
return
}
if tapdBugRecords, err = s.dao.QueryTapdBugRecordByProjectIDAndStatus(projectTemplateId, model.InsertBugStatusRunning); err != nil {
return
}
if len(tapdBugRecords) > 0 {
err = ecode.MartheTaskInRunning
return
}
if buglyIssues, err = s.getBuglyIssuesByFilterSQLWithNoTapdBug(tapdBugTemplate.IssueFilterSQL); err != nil {
return
}
count = len(buglyIssues)
if count > 0 {
tapdBugInsertLog := &model.TapdBugRecord{
ProjectTemplateID: projectTemplateId,
VersionTemplateID: versionTemplateId,
Operator: username,
Count: count,
IssueFilterSQL: tapdBugTemplate.IssueFilterSQL,
Status: model.InsertBugStatusRunning,
}
if err = s.dao.InsertTapdBugRecord(tapdBugInsertLog); err != nil {
return
}
s.tapdBugCache.Do(context.TODO(), func(ctx context.Context) {
defer func() {
if err != nil {
tapdBugInsertLog.Status = model.InsertBugStatusFailed
} else {
tapdBugInsertLog.Status = model.InsertBugStatusDone
}
err = s.dao.UpdateTapdBugRecord(tapdBugInsertLog)
}()
for _, buglyIssue := range buglyIssues {
var (
bug *model.Bug
bugID string
)
if bug, err = s.getBugModel(buglyIssue, tapdBugTemplate); err != nil {
log.Error("getLiveIOSBugModel error (%v)", err)
continue
}
if bugID, err = s.dao.CreateBug(bug); err != nil && bugID == "" {
log.Error("CreateBug error (%v)", err)
continue
}
log.Info("insert issue no: [%s], bug number [%s]", buglyIssue.IssueNo, bugID)
if err = s.dao.UpdateBuglyIssueTapdBugID(buglyIssue.ID, bugID); err != nil {
log.Error("UpdateIssueRecordTapdBugID error (%v)", err)
continue
}
buglyIssue.TapdBugID = bugID
if err = s.updateBugInTapd(tapdBugTemplate, buglyIssue, time.Now()); err != nil {
continue
}
log.Info("update issue no [%s], bug number [%s]", buglyIssue.IssueNo, buglyIssue.TapdBugID)
}
})
}
return
}
func (s *Service) getBugModel(bugIssue *model.BuglyIssue, bugTemplate *model.TapdBugTemplate) (bug *model.Bug, err error) {
title := fmt.Sprintf(bugTemplate.Title, bugIssue.IssueNo, bugIssue.Version, bugIssue.Title, strconv.Itoa(bugIssue.HappenTimes), strconv.Itoa(bugIssue.UserTimes))
description := fmt.Sprintf(bugTemplate.Description, title, bugIssue.KeyStack,
bugIssue.IssueLink, bugIssue.IssueLink, bugIssue.IssueLink,
bugIssue.Detail)
bug = &model.Bug{
Title: title,
Description: description,
Priority: bugTemplate.Priority,
Severity: bugTemplate.Severity,
Module: bugTemplate.Module,
Status: bugTemplate.Status,
Reporter: bugTemplate.Reporter,
BugType: bugTemplate.BugType,
CurrentOwner: bugTemplate.CurrentOwner,
Source: bugTemplate.Source,
OriginPhase: bugTemplate.OriginPhase,
Platform: bugTemplate.Platform,
ReleaseID: bugTemplate.ReleaseID,
CustomFieldThree: bugTemplate.CustomFieldThree,
CustomFieldFour: bugTemplate.CustomFieldFour,
WorkspaceID: bugTemplate.WorkspaceID,
IterationID: bugTemplate.IterationID,
}
return
}
// UpdateTplAsVersionTpl Update Tpl As Version Tpl.
func (s *Service) UpdateTplAsVersionTpl(tapdBugVersionTemplate *model.TapdBugVersionTemplate, tapdBugTemplate *model.TapdBugTemplate) (err error) {
if tapdBugVersionTemplate.ProjectTemplateID != tapdBugTemplate.ID {
log.Error("projectID should be [%s],actual [%s]", tapdBugVersionTemplate.ProjectTemplateID, tapdBugTemplate.ID)
return
}
if strings.TrimSpace(tapdBugVersionTemplate.Title) != "" {
tapdBugTemplate.Title = tapdBugVersionTemplate.Title
}
if strings.TrimSpace(tapdBugVersionTemplate.Description) != "" {
tapdBugTemplate.Description = tapdBugVersionTemplate.Description
}
if strings.TrimSpace(tapdBugVersionTemplate.CurrentOwner) != "" {
tapdBugTemplate.CurrentOwner = tapdBugVersionTemplate.CurrentOwner
}
if strings.TrimSpace(tapdBugVersionTemplate.Platform) != "" {
tapdBugTemplate.Platform = tapdBugVersionTemplate.Platform
}
if strings.TrimSpace(tapdBugVersionTemplate.Module) != "" {
tapdBugTemplate.Module = tapdBugVersionTemplate.Module
}
if strings.TrimSpace(tapdBugVersionTemplate.IterationID) != "" {
tapdBugTemplate.IterationID = tapdBugVersionTemplate.IterationID
}
if strings.TrimSpace(tapdBugVersionTemplate.ReleaseID) != "" {
tapdBugTemplate.ReleaseID = tapdBugVersionTemplate.ReleaseID
}
if strings.TrimSpace(tapdBugVersionTemplate.Priority) != "" {
tapdBugTemplate.Priority = tapdBugVersionTemplate.Priority
}
if strings.TrimSpace(tapdBugVersionTemplate.Severity) != "" {
tapdBugTemplate.Severity = tapdBugVersionTemplate.Severity
}
if strings.TrimSpace(tapdBugVersionTemplate.Source) != "" {
tapdBugTemplate.Source = tapdBugVersionTemplate.Source
}
if strings.TrimSpace(tapdBugVersionTemplate.CustomFieldFour) != "" {
tapdBugTemplate.CustomFieldFour = tapdBugVersionTemplate.CustomFieldFour
}
if strings.TrimSpace(tapdBugVersionTemplate.BugType) != "" {
tapdBugTemplate.BugType = tapdBugVersionTemplate.BugType
}
if strings.TrimSpace(tapdBugVersionTemplate.OriginPhase) != "" {
tapdBugTemplate.OriginPhase = tapdBugVersionTemplate.OriginPhase
}
if strings.TrimSpace(tapdBugVersionTemplate.CustomFieldThree) != "" {
tapdBugTemplate.CustomFieldThree = tapdBugVersionTemplate.CustomFieldThree
}
if strings.TrimSpace(tapdBugVersionTemplate.Reporter) != "" {
tapdBugTemplate.Reporter = tapdBugVersionTemplate.Reporter
}
if strings.TrimSpace(tapdBugVersionTemplate.Status) != "" {
tapdBugTemplate.Status = tapdBugVersionTemplate.Status
}
if strings.TrimSpace(tapdBugVersionTemplate.IssueFilterSQL) != "" {
tapdBugTemplate.IssueFilterSQL = tapdBugVersionTemplate.IssueFilterSQL
}
if strings.TrimSpace(tapdBugVersionTemplate.SeverityKey) != "" {
tapdBugTemplate.SeverityKey = tapdBugVersionTemplate.SeverityKey
}
return
}
// BatchRunUpdateBugInTapd Batch Run Update Bug In Tapd.
func (s *Service) BatchRunUpdateBugInTapd() (err error) {
var buglyIssues []*model.BuglyIssue
if buglyIssues, err = s.dao.GetBuglyIssuesHasInTapd(); err != nil {
return
}
for _, buglyIssue := range buglyIssues {
var (
tapdBugTemplate *model.TapdBugTemplate
tapdBugVersionTemplate *model.TapdBugVersionTemplate
)
if tapdBugTemplate, err = s.dao.QueryTapdBugTemplateByProjectID(buglyIssue.ProjectID); err != nil {
continue
}
if tapdBugTemplate.ID == 0 {
continue
}
if tapdBugVersionTemplate, err = s.dao.QueryTapdBugVersionTemplateByVersion(buglyIssue.Version); err != nil {
continue
}
if tapdBugVersionTemplate.ID > 0 {
if err = s.UpdateTplAsVersionTpl(tapdBugVersionTemplate, tapdBugTemplate); err != nil {
continue
}
}
err = s.updateBugInTapd(tapdBugTemplate, buglyIssue, time.Now())
}
return
}
func (s *Service) updateBugInTapd(tapdBugTemplate *model.TapdBugTemplate, bugIssue *model.BuglyIssue, timeNow time.Time) (err error) {
var bug *model.Bug
// update title
title := fmt.Sprintf(tapdBugTemplate.Title, bugIssue.IssueNo, bugIssue.Version, bugIssue.Title, strconv.Itoa(bugIssue.HappenTimes), strconv.Itoa(bugIssue.UserTimes))
if bug, err = s.dao.BugPre(tapdBugTemplate.WorkspaceID, bugIssue.TapdBugID); err != nil {
log.Error("BugPre projectId %s, error (%v)", bugIssue.ProjectID, err)
return
}
bug.Title = title
// update priority
var (
tapdBugPriorityConfs []*model.TapdBugPriorityConf
)
if tapdBugPriorityConfs, err = s.dao.QueryTapdBugPriorityConfsByProjectTemplateIdAndStatus(tapdBugTemplate.ID, model.TapdBugPriorityConfEnable); err != nil {
return
}
for _, tmpTapdBugPriorityConf := range tapdBugPriorityConfs {
if timeNow.After(tmpTapdBugPriorityConf.StartTime) && timeNow.Before(tmpTapdBugPriorityConf.EndTime) {
if bugIssue.UserTimes >= tmpTapdBugPriorityConf.Urgent || bugIssue.HappenTimes >= tmpTapdBugPriorityConf.Urgent {
bug.Priority = "urgent"
} else if bugIssue.UserTimes >= tmpTapdBugPriorityConf.High || bugIssue.HappenTimes >= tmpTapdBugPriorityConf.High {
bug.Priority = "high"
} else if bugIssue.UserTimes >= tmpTapdBugPriorityConf.Medium || bugIssue.HappenTimes >= tmpTapdBugPriorityConf.Medium {
bug.Priority = "medium"
}
break
}
}
// update serious
if strings.TrimSpace(tapdBugTemplate.SeverityKey) != "" {
keys := strings.Split(tapdBugTemplate.SeverityKey, ",")
for _, key := range keys {
if strings.Contains(bug.Description, key) {
bug.Severity = "serious"
break
}
}
}
updateBug := &model.UpdateBug{
Bug: bug,
CurrentUser: bug.CurrentOwner,
}
if err := s.dao.UpdateBug(updateBug); err != nil {
log.Error("UpdateBug bugid %s, error (%v)", bug.ID, err)
}
return
}
// QueryBugRecords Query Bug Records
func (s *Service) QueryBugRecords(c context.Context, req *model.QueryBugRecordsRequest) (rep *model.PaginateBugRecords, err error) {
var (
total int64
tapdBugRecords []*model.TapdBugRecord
)
if total, tapdBugRecords, err = s.dao.FindBugRecords(req); err != nil {
return
}
rep = &model.PaginateBugRecords{
PaginationRep: model.PaginationRep{
Total: total,
PageSize: req.PageSize,
PageNum: req.PageNum,
},
TapdBugRecords: tapdBugRecords,
}
return
}
// QueryTapdBugPriorityConfsRequest Query Tapd Bug Priority Confs Request
func (s *Service) QueryTapdBugPriorityConfsRequest(c context.Context, req *model.QueryTapdBugPriorityConfsRequest) (rep *model.PaginateTapdBugPriorityConfs, err error) {
var (
total int64
tapdBugPriorityConfs []*model.TapdBugPriorityConf
)
if total, tapdBugPriorityConfs, err = s.dao.FindTapdBugPriorityConfs(req); err != nil {
return
}
rep = &model.PaginateTapdBugPriorityConfs{
PaginationRep: model.PaginationRep{
Total: total,
PageSize: req.PageSize,
PageNum: req.PageNum,
},
TapdBugPriorityConfs: tapdBugPriorityConfs,
}
return
}
// UpdateTapdBugPriorityConf Update Tapd Bug Priority Conf.
func (s *Service) UpdateTapdBugPriorityConf(c context.Context, username string, req *model.UpdateTapdBugPriorityConfRequest) (rep map[string]interface{}, err error) {
var (
startTime time.Time
endTime time.Time
tapdBugPriorityConfsInDB []*model.TapdBugPriorityConf
tapdBugTemplate *model.TapdBugTemplate
)
//check project id
if tapdBugTemplate, err = s.dao.QueryTapdBugTemplate(req.ProjectTemplateID); err != nil {
return
}
if tapdBugTemplate.ID == 0 {
err = ecode.NothingFound
return
}
//check if access to workspace
if !s.AccessToWorkspace(tapdBugTemplate.WorkspaceID, username) {
err = ecode.AccessDenied
return
}
if startTime, err = time.ParseInLocation(model.TimeLayout, req.StartTime, time.Local); err != nil {
return
}
if endTime, err = time.ParseInLocation(model.TimeLayout, req.EndTime, time.Local); err != nil {
return
}
// when status == enable, check time if conflict
if req.Status == model.TapdBugPriorityConfEnable {
if tapdBugPriorityConfsInDB, err = s.dao.QueryTapdBugPriorityConfsByProjectTemplateIdAndStatus(req.ProjectTemplateID, model.TapdBugPriorityConfEnable); err != nil {
return
}
for _, tapdBugPriorityConfInDB := range tapdBugPriorityConfsInDB {
isStartTimeInDuration := tapdBugPriorityConfInDB.StartTime.After(startTime) && tapdBugPriorityConfInDB.StartTime.Before(endTime)
isEndTimeInDuration := tapdBugPriorityConfInDB.EndTime.After(startTime) && tapdBugPriorityConfInDB.EndTime.Before(endTime)
if isStartTimeInDuration || isEndTimeInDuration {
err = ecode.MartheTimeConflictError
return
}
}
}
tapdBugPriorityConf := &model.TapdBugPriorityConf{
ID: req.ID,
ProjectTemplateID: req.ProjectTemplateID,
Urgent: req.Urgent,
High: req.High,
Medium: req.Medium,
UpdateBy: username,
Status: req.Status,
StartTime: startTime,
EndTime: endTime,
}
if req.ID > 0 {
err = s.dao.UpdateTapdBugPriorityConf(tapdBugPriorityConf)
} else {
// add new
err = s.dao.InsertTapdBugPriorityConf(tapdBugPriorityConf)
}
rep = make(map[string]interface{})
rep["tapd_bug_priority_conf"] = tapdBugPriorityConf.ID
return
}
// AccessToWorkspace Access To Workspace.
func (s *Service) AccessToWorkspace(workspaceID, username string) (isAccess bool) {
if !s.c.Tapd.BugOperateAuth {
return true
}
var (
usernames []string
contactInfo *model.ContactInfo
err error
)
if contactInfo, err = s.dao.QueryContactInfoByUsername(username); err != nil {
return
}
if contactInfo.ID == 0 {
err = ecode.NothingFound
return
}
if usernames, err = s.dao.WorkspaceUser(workspaceID); err != nil {
return
}
for _, u := range usernames {
if u == contactInfo.NickName {
return true
}
}
return
}
// HttpAccessToWorkspace Access To Workspace.
func (s *Service) HttpAccessToWorkspace(c context.Context, workspaceID, username string) (rep map[string]interface{}, err error) {
var (
usernames []string
contactInfo *model.ContactInfo
isAccess bool
)
if contactInfo, err = s.dao.QueryContactInfoByUsername(username); err != nil {
return
}
if contactInfo.ID == 0 {
err = ecode.NothingFound
return
}
if usernames, err = s.dao.WorkspaceUser(workspaceID); err != nil {
return
}
for _, u := range usernames {
if u == contactInfo.NickName {
isAccess = true
break
}
}
rep = make(map[string]interface{})
rep["is_access"] = isAccess
rep["names"] = usernames
return
}
func (s *Service) getBuglyIssuesByFilterSQLWithNoTapdBug(issueFilterSQL string) (buglyIssues []*model.BuglyIssue, err error) {
var tmpBuglyIssues []*model.BuglyIssue
if tmpBuglyIssues, err = s.dao.GetBuglyIssuesByFilterSQL(issueFilterSQL); err != nil {
return
}
for _, buglyIssue := range tmpBuglyIssues {
if buglyIssue.TapdBugID == "" {
buglyIssues = append(buglyIssues, buglyIssue)
}
}
return
}
func (s *Service) getTapdBugInsertLock(projectTplId int64) (tapdBugInsertLock *sync.Mutex) {
s.syncTapdBugInsertLock.Lock()
defer s.syncTapdBugInsertLock.Unlock()
var ok bool
if tapdBugInsertLock, ok = s.mapTapdBugInsertLocks[projectTplId]; !ok {
tapdBugInsertLock = new(sync.Mutex)
s.mapTapdBugInsertLocks[projectTplId] = tapdBugInsertLock
}
return
}

View File

@ -0,0 +1,134 @@
package service
import (
"context"
"go-common/library/log"
"go-common/app/admin/ep/marthe/model"
"go-common/library/ecode"
)
// QueryUserInfo query user info.
func (s *Service) QueryUserInfo(c context.Context, username string) (userInfo *model.User, err error) {
if userInfo, err = s.dao.FindUserByUserName(username); err != nil {
return
}
if userInfo.ID == 0 {
user := model.User{Name: username, EMail: username + "@bilibili.com"}
s.dao.CreateUser(&user)
userInfo, err = s.dao.FindUserByUserName(username)
}
return
}
// HttpSyncWechatContacts Http Sync Wechat Contacts.
func (s *Service) HttpSyncWechatContacts(ctx context.Context) (err error) {
s.taskCache.Do(context.TODO(), func(ctx context.Context) {
s.SyncWechatContacts()
})
return
}
// SyncWechatContacts Sync Wechat Contacts.
func (s *Service) SyncWechatContacts() (err error) {
s.syncWechatContactsLock.Lock()
defer s.syncWechatContactsLock.Unlock()
log.Info("start")
var (
wechatContacts []*model.WechatContact
contactInfosInDB []*model.ContactInfo
)
if wechatContacts, err = s.dao.WechatContacts(context.Background()); err != nil {
return
}
if contactInfosInDB, err = s.dao.QueryAllContactInfos(); err != nil {
return
}
for _, wechatContact := range wechatContacts {
var (
tmpContactInfoInDB *model.ContactInfo
)
for _, contactInfoInDB := range contactInfosInDB {
if contactInfoInDB.UserID == wechatContact.UserID {
tmpContactInfoInDB = contactInfoInDB
break
}
}
if tmpContactInfoInDB != nil {
//update
tmpContactInfoInDB.UserName = wechatContact.EnglishName
tmpContactInfoInDB.NickName = wechatContact.Name
if err = s.dao.UpdateContactInfo(tmpContactInfoInDB); err != nil {
continue
}
} else {
//add
tmpContactInfoInDB = &model.ContactInfo{
UserName: wechatContact.EnglishName,
NickName: wechatContact.Name,
UserID: wechatContact.UserID,
}
if err = s.dao.InsertContactInfo(tmpContactInfoInDB); err != nil {
continue
}
}
}
log.Info("end")
return
}
// AccessToBugly Access To Bugly.
func (s *Service) AccessToBugly(c context.Context, username string) (isAccess bool) {
var (
userInfo *model.User
err error
)
if userInfo, err = s.QueryUserInfo(c, username); err != nil {
return
}
isAccess = userInfo.VisibleBugly
return
}
// UpdateUserVisibleBugly Update User Visible Bugly.
func (s *Service) UpdateUserVisibleBugly(c context.Context, username, updateUsername string, visibleBugly bool) (err error) {
var (
hasRight bool
userInfo *model.User
)
for _, super := range s.c.Bugly.SuperOwner {
if username == super {
hasRight = true
break
}
}
if !hasRight {
err = ecode.AccessDenied
return
}
if userInfo, err = s.dao.FindUserByUserName(updateUsername); err != nil {
return
}
if userInfo.ID == 0 {
err = ecode.NothingFound
return
}
err = s.dao.UpdateUserVisibleBugly(userInfo.ID, visibleBugly)
return
}