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

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/main/usersuit/cmd:all-srcs",
"//app/admin/main/usersuit/conf:all-srcs",
"//app/admin/main/usersuit/dao:all-srcs",
"//app/admin/main/usersuit/http:all-srcs",
"//app/admin/main/usersuit/model:all-srcs",
"//app/admin/main/usersuit/service:all-srcs",
],
tags = ["automanaged"],
)

View File

@@ -0,0 +1,85 @@
### Version 1.7.3
> 1. 使用 grpc 请求account-service
### Version 1.7.2
> 1. 修正 waitgroup 的用法
### Version 1.7.1
> 1. 邀请码展示 IPv6 地址
> 2. 去除依赖基础库的 ip 包
### Version 1.6.4
> 1. 邀请码后台增加字段并区分权限
### Version 1.6.3
> 1. update user pkg api.
### Version 1.6.2
> 1. update max medal batch size.
### Version 1.6.1
> 1. fix medal add.
### Version 1.6.0
> 1. 新增挂件红点提醒
> 2. context.todo -> context.backround
### Version 1.5.0
> 1. 改为 metadata RemoteIP
### Version 1.4.11
> 1.use account notify
### Version 1.4.10
> 1.change medal owners mc key
### Version 1.4.9
> 1.fix notify struct
### Version 1.4.8
> 1.fix closure
### Version 1.4.7
> 1.update sql
### Version 1.4.6
> 1.update sql
### Version 1.4.1
> 1.fix 勋章cond字段bug
### Version 1.4.0
> 1.勋章后台重构
### Version 1.3.5
> 1.服务添加code描述load入
### Version 1.3.4
> 1.新增批量发放挂件code码
### Version 1.3.3
> 1.move path
### Version 1.3.2
> 1.mysql big count timeout
### Version 1.3.1
> 1.mysql defualt null bug
### Version 1.3.0
> 1.挂件后台重构初始化
> 2.新增上传接口
### Version 1.2.1
> 1.call account v7
### Version 1.2.0
> 1.从老库迁移挂件信息至新库
#### Version 1.1.0
> 1.add auth to APIs
> 2.change ut to convey
> 3.fix data race for generating invite codes and fetching multi info in concurrency
#### Version 1.0.0
> 1.初始化邀请码管理功能:包括批量发放邀请码、获取用户邀请码列表

View File

@@ -0,0 +1,13 @@
# Owner
zhaogangtao
wanghuan01
zhoujiahui
# Author
wanghuan01
wucongyou
hekai
# Reviewer
wanghuan01
zhaogangtao

View File

@@ -0,0 +1,19 @@
# See the OWNERS docs at https://go.k8s.io/owners
approvers:
- hekai
- wanghuan01
- wucongyou
- zhaogangtao
- zhoujiahui
labels:
- admin
- admin/main/usersuit
- main
options:
no_parent_owners: true
reviewers:
- hekai
- wanghuan01
- wucongyou
- zhaogangtao

View File

@@ -0,0 +1,10 @@
#### usersuit-admin
##### 项目简介
> 1.用户套装服务管理
##### 编译环境
> 请只用golang v1.8.x以上版本编译执行。
##### 依赖包
> 1.公共包go-common

View File

@@ -0,0 +1,46 @@
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 = [
"usersuit-admin-test.toml",
],
importpath = "go-common/app/admin/main/usersuit/cmd",
tags = ["automanaged"],
visibility = ["//visibility:public"],
deps = [
"//app/admin/main/usersuit/conf:go_default_library",
"//app/admin/main/usersuit/http:go_default_library",
"//app/admin/main/usersuit/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,50 @@
package main
import (
"flag"
"os"
"os/signal"
"syscall"
"go-common/app/admin/main/usersuit/conf"
"go-common/app/admin/main/usersuit/http"
"go-common/app/admin/main/usersuit/service"
ecode "go-common/library/ecode/tip"
"go-common/library/log"
"go-common/library/net/trace"
)
func main() {
flag.Parse()
// init conf,log,trace,stat,perf.
if err := conf.Init(); err != nil {
panic(err)
}
log.Init(conf.Conf.Log)
defer log.Close()
trace.Init(conf.Conf.Tracer)
defer trace.Close()
// service init
svr := service.New(conf.Conf)
http.Init(conf.Conf, svr)
// service init
ecode.Init(conf.Conf.Ecode)
// signal handler
log.Info("usersuit-admin start")
c := make(chan os.Signal, 1)
signal.Notify(c, syscall.SIGHUP, syscall.SIGQUIT, syscall.SIGTERM, syscall.SIGINT)
for {
s := <-c
log.Info("usersuit-admin get a signal %s", s.String())
switch s {
case syscall.SIGQUIT, syscall.SIGTERM, syscall.SIGINT:
svr.Close()
log.Info("usersuit-admin exit")
return
case syscall.SIGHUP:
// TODO reload
default:
return
}
}
}

View File

@@ -0,0 +1,175 @@
# This is a TOML document. Boom.
version = "1.0.0"
user = "nobody"
dir = "./"
perf = "0.0.0.0:7270"
family = "usersuit-admin"
env = "qa"
[xlog]
dir = "/data/log/usersuit-admin"
[tracer]
family = "usersuit-admin"
proto = "unixgram"
addr = "/var/run/dapper-collect/dapper-collect.sock"
[bm]
[bm.inner]
addr = "0.0.0.0:7271"
maxListen = 1000
timeout = "1s"
[auth]
managerHost = "http://uat-manager.bilibili.co"
dashboardHost = "http://uat-dashboard-mng.bilibili.co"
dashboardCaller = "manager-go"
[auth.DsHTTPClient]
key = "manager-go"
secret = "949bbb2dd3178252638c2407578bc7ad"
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 = "1s"
timeout = "1s"
keepAlive = "60s"
[auth.MaHTTPClient.breaker]
window = "3s"
sleep = "100ms"
bucket = 10
ratio = 0.5
request = 100
[auth.session]
sessionIDLength = 32
cookieLifeTime = 1800
cookieName = "mng-go"
domain = ".bilibili.co"
[auth.session.Memcache]
name = "go-business/auth"
proto = "tcp"
addr = "172.18.33.61:11219"
active = 5
idle = 10
dialTimeout = "1s"
readTimeout = "1s"
writeTimeout = "1s"
idleTimeout = "80s"
[accountRPC]
timeout = "1s"
[db]
[db.usersuit]
addr = "172.16.33.205:3309"
dsn = "usersuit:cDXL6vncmCQanx4iMgGogu6gYz33NmA1@tcp(172.16.33.205:3309)/usersuit?timeout=5s&readTimeout=5s&writeTimeout=5s&parseTime=true&loc=Local&charset=utf8,utf8mb4"
readDSN = ["usersuit:cDXL6vncmCQanx4iMgGogu6gYz33NmA1@tcp(172.16.33.205:3309)/usersuit?timeout=5s&readTimeout=5s&writeTimeout=5s&parseTime=true&loc=Local&charset=utf8,utf8mb4"]
active = 5
idle = 2
queryTimeout = "100ms"
execTimeout = "100ms"
tranTimeout = "200ms"
[db.usersuit.breaker]
window = "3s"
sleep = "100ms"
bucket = 10
ratio = 0.5
request = 100
[host]
bfs = "http://uat-bfs.bilibili.co"
#bfs = "http://bfs.bilibili.co"
manager = "http://manager.bilibili.co"
msg = "http://message.bilibili.co"
passport = "http://passport.bilibili.co"
[bfs]
bucket = "face"
key = "792d70f16e958493"
secret = "08525fe929bdb26c3a6009afd7318f"
[httpClient]
key = "837f620f5c0a8010"
secret = "2a9057021014b4b843b635664c69d5df"
dial = "500ms"
timeout = "1s"
keepAlive = "60s"
[httpClient.breaker]
window = "3s"
sleep = "100ms"
bucket = 10
ratio = 0.5
request = 100
[redis]
name = "usersuit"
proto = "tcp"
addr = "127.0.0.1:6379"
idle = 100
active = 100
dialTimeout = "1s"
readTimeout = "1s"
writeTimeout = "1s"
idleTimeout = "10s"
[accountNotify]
key = "4ba46ba31f9a44ef"
secret = "99985eb4451cfb1b899ca0fbe3c4bdc8"
group = "AccountNotify-MainAccount-P"
topic = "AccountNotify-T"
action = "pub"
offset = "old"
buffer = 128
name = "usersuit-admin/databus"
proto = "tcp"
addr = "172.16.33.158:6205"
active = 1
idle = 1
dialTimeout = "1s"
readTimeout = "1s"
writeTimeout = "1s"
idleTimeout = "10s"
[memcache]
name = "usersuit-service"
proto = "tcp"
addr = "172.18.33.61:11219"
idle = 5
active = 10
dialTimeout = "1s"
readTimeout = "1s"
writeTimeout = "1s"
idleTimeout = "10s"
expire = "24h"
pointexpire = "168h"
[ecode]
domain = "172.16.33.248:6401"
all = "1h"
diff = "10m"
[ecode.clientconfig]
key = "test"
secret = "e6c4c252dc7e3d8a90805eecd7c73396"
dial = "2s"
timeout = "2s"
keepAlive = "10s"
[ecode.clientconfig.breaker]
window ="3s"
sleep ="100ms"
bucket = 10
ratio = 0.5
request = 100
[ecode.app]
key = "test"
secret = "e6c4c252dc7e3d8a90805eecd7c73396"

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 = ["conf.go"],
importpath = "go-common/app/admin/main/usersuit/conf",
tags = ["automanaged"],
visibility = ["//visibility:public"],
deps = [
"//library/cache/memcache:go_default_library",
"//library/cache/redis:go_default_library",
"//library/conf:go_default_library",
"//library/database/sql: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/net/rpc/warden:go_default_library",
"//library/net/trace:go_default_library",
"//library/queue/databus: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,136 @@
package conf
import (
"errors"
"flag"
"go-common/library/cache/memcache"
"go-common/library/cache/redis"
"go-common/library/conf"
"go-common/library/database/sql"
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"
"go-common/library/net/rpc/warden"
"go-common/library/net/trace"
"go-common/library/queue/databus"
"go-common/library/time"
"github.com/BurntSushi/toml"
)
// Conf global variable.
var (
Conf = &Config{}
client *conf.Client
confPath string
)
// Config struct of conf.
type Config struct {
// base
// log
Log *log.Config
// tracer
Tracer *trace.Config
// http
BM *bm.ServerConfig
// Auth auth
Auth *permit.Config
// MySQL mysql
DB *DB
// BFS
BFS *BFS
// redis
Redis *redis.Config
// memcache
Memcache *Memcache
// AccountGRPC account grpc
AccountGRPC *warden.ClientConfig
// http client
HTTPClient *bm.ClientConfig
// databus
AccountNotify *databus.Config
// host
Host *Host
// ecodes
Ecode *ecode.Config
}
// Host host config .
type Host struct {
Bfs string
Msg string
Manager string
}
// BFS bfs config
type BFS struct {
Bucket string
Key string
Secret string
}
// DB .
type DB struct {
Usersuit *sql.Config
}
// Memcache config.
type Memcache struct {
*memcache.Config
Expire time.Duration
PointExpire time.Duration
}
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
}
func init() {
flag.StringVar(&confPath, "conf", "", "default config path")
}
// Init int config
func Init() error {
if confPath != "" {
return local()
}
return remote()
}

View File

@@ -0,0 +1,78 @@
package(default_visibility = ["//visibility:public"])
load(
"@io_bazel_rules_go//go:def.bzl",
"go_test",
"go_library",
)
go_test(
name = "go_default_test",
srcs = [
"dao_test.go",
"invite_test.go",
"manager_test.go",
"medal_mc_test.go",
"medal_test.go",
"msg_test.go",
"pendant_redis_test.go",
"pendant_test.go",
],
embed = [":go_default_library"],
rundir = ".",
tags = ["automanaged"],
deps = [
"//app/admin/main/usersuit/conf:go_default_library",
"//app/admin/main/usersuit/model:go_default_library",
"//library/time: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",
],
)
go_library(
name = "go_default_library",
srcs = [
"dao.go",
"invite.go",
"manager.go",
"medal.go",
"medal_mc.go",
"msg.go",
"pendant.go",
"pendant_mc.go",
"pendant_redis.go",
"upload.go",
],
importpath = "go-common/app/admin/main/usersuit/dao",
tags = ["automanaged"],
visibility = ["//visibility:public"],
deps = [
"//app/admin/main/usersuit/conf:go_default_library",
"//app/admin/main/usersuit/model:go_default_library",
"//library/cache/memcache:go_default_library",
"//library/cache/redis:go_default_library",
"//library/database/sql:go_default_library",
"//library/ecode:go_default_library",
"//library/log:go_default_library",
"//library/net/http/blademaster:go_default_library",
"//library/sync/errgroup:go_default_library",
"//library/xstr:go_default_library",
"//vendor/github.com/pkg/errors: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,82 @@
package dao
import (
"context"
"time"
"go-common/app/admin/main/usersuit/conf"
"go-common/library/cache/memcache"
"go-common/library/cache/redis"
"go-common/library/database/sql"
bm "go-common/library/net/http/blademaster"
)
const (
_msgURL = "/api/notify/send.user.notify.do"
_managersURI = "/x/admin/manager/users"
_managerTotalURI = "/x/admin/manager/users/total"
)
// Dao struct answer history of Dao
type Dao struct {
db *sql.DB
c *conf.Config
// redis
redis *redis.Pool
// http
client *bm.Client
mc *memcache.Pool
mcExpire int32
pointExpire int32
msgURL string
managersURL string
managerTotalURL string
bucket string
key string
secret string
bfs string
}
// New new a Dao and return.
func New(c *conf.Config) (d *Dao) {
d = &Dao{
c: c,
db: sql.NewMySQL(c.DB.Usersuit),
// http client
client: bm.NewClient(c.HTTPClient),
// redis
redis: redis.NewPool(c.Redis),
mc: memcache.NewPool(c.Memcache.Config),
mcExpire: int32(time.Duration(c.Memcache.Expire) / time.Second),
pointExpire: int32(time.Duration(c.Memcache.PointExpire) / time.Second),
}
d.msgURL = c.Host.Msg + _msgURL
d.managersURL = c.Host.Manager + _managersURI
d.managerTotalURL = c.Host.Manager + _managerTotalURI
d.bucket = c.BFS.Bucket
d.key = c.BFS.Key
d.secret = c.BFS.Secret
d.bfs = c.Host.Bfs
return
}
// BeginTran begin tran.
func (d *Dao) BeginTran(c context.Context) (tx *sql.Tx, err error) {
tx, err = d.db.Begin(c)
return
}
// Close close connections of mc, redis, db.
func (d *Dao) Close() {
if d.db != nil {
d.db.Close()
}
if d.redis != nil {
d.redis.Close()
}
}
// Ping ping health.
func (d *Dao) Ping(c context.Context) (err error) {
return d.db.Ping(c)
}

View File

@@ -0,0 +1,46 @@
package dao
import (
"flag"
"go-common/app/admin/main/usersuit/conf"
"os"
"strings"
"testing"
gock "gopkg.in/h2non/gock.v1"
)
var (
d *Dao
)
func TestMain(m *testing.M) {
if os.Getenv("DEPLOY_ENV") != "" {
flag.Set("app_id", "main.account.usersuit-admin")
flag.Set("conf_appid", "main.account.usersuit-admin")
flag.Set("conf_token", "DJOLMyoiZhqTIrk0r9zGrhewXiBMirIH")
flag.Set("tree_id", "6814")
flag.Set("conf_version", "docker-1")
flag.Set("deploy_env", "uat")
flag.Set("conf_env", "10")
flag.Set("conf_host", "config.bilibili.co")
flag.Set("conf_path", "/tmp")
flag.Set("region", "sh")
flag.Set("zone", "sh001")
} else {
flag.Set("conf", "../cmd/usersuit-admin-test.toml")
}
flag.Parse()
if err := conf.Init(); err != nil {
panic(err)
}
d = New(conf.Conf)
d.client.SetTransport(gock.DefaultTransport)
os.Exit(m.Run())
}
func httpMock(method, url string) *gock.Request {
r := gock.New(url)
r.Method = strings.ToUpper(method)
return r
}

View File

@@ -0,0 +1,46 @@
package dao
import (
"context"
"database/sql"
"time"
"go-common/app/admin/main/usersuit/model"
xsql "go-common/library/database/sql"
"go-common/library/log"
)
const (
_addIgnoreInviteSQL = "INSERT IGNORE INTO invite_code(mid,code,buy_ip,buy_ip_ng,expires,ctime) VALUES(?,?,?,?,?,?)"
_getRangeInvitesSQL = "SELECT mid,imid,code,buy_ip,buy_ip_ng,expires,used_at,ctime FROM invite_code WHERE mid=? AND ctime>=? AND ctime<=?"
)
// AddIgnoreInvite add ignore invite code.
func (d *Dao) AddIgnoreInvite(c context.Context, inv *model.Invite) (affected int64, err error) {
var res sql.Result
if res, err = d.db.Exec(c, _addIgnoreInviteSQL, inv.Mid, inv.Code, inv.IP, inv.IPng, inv.Expires, inv.Ctime); err != nil {
log.Error("add invite, dao.db.Exec(%d, %s, %d, %v, %d, %v) error(%v)", inv.Mid, inv.Code, inv.IP, inv.IPng, inv.Expires, inv.Ctime, err)
return
}
return res.RowsAffected()
}
// RangeInvites range invites.
func (d *Dao) RangeInvites(c context.Context, mid int64, start, end time.Time) (res []*model.Invite, err error) {
var rows *xsql.Rows
if rows, err = d.db.Query(c, _getRangeInvitesSQL, mid, start, end); err != nil {
log.Error("get range invites, dao.db.Query(%v, %v, %v) error(%v)", mid, start, end, err)
return
}
defer rows.Close()
for rows.Next() {
inv := new(model.Invite)
if err = rows.Scan(&inv.Mid, &inv.Imid, &inv.Code, &inv.IP, &inv.IPng, &inv.Expires, &inv.UsedAt, &inv.Ctime); err != nil {
log.Error("row.Scan() error(%v)", err)
return
}
res = append(res, inv)
}
err = rows.Err()
return
}

View File

@@ -0,0 +1,49 @@
package dao
import (
"context"
"net"
"testing"
"time"
"github.com/satori/go.uuid"
"go-common/app/admin/main/usersuit/model"
xtime "go-common/library/time"
. "github.com/smartystreets/goconvey/convey"
)
func TestDao_RangeInvites(t *testing.T) {
mid := int64(2)
Convey("add invite", t, func() {
now := time.Now().Unix()
inv := &model.Invite{
Mid: mid,
Code: uuid.NewV4().String(),
IPng: net.ParseIP("127.0.0.1"),
Expires: now + int64(time.Hour*72/time.Second),
Ctime: xtime.Time(now),
}
affected, err := d.AddIgnoreInvite(context.Background(), inv)
So(err, ShouldBeNil)
So(affected, ShouldEqual, 1)
})
Convey("range a test account's current month invite codes", t, func() {
now := time.Now()
start, end := rangeMonth(now)
res, err := d.RangeInvites(context.Background(), mid, start, end)
So(err, ShouldBeNil)
So(res, ShouldNotBeNil)
})
}
func rangeMonth(now time.Time) (start, end time.Time) {
year := now.Year()
month := now.Month()
loc := now.Location()
start = time.Date(year, month, 1, 0, 0, 0, 0, loc)
end = time.Date(year, month+1, 0, 23, 59, 59, 0, loc)
return
}

View File

@@ -0,0 +1,101 @@
package dao
import (
"context"
"net/url"
"strconv"
"sync"
"go-common/app/admin/main/usersuit/model"
"go-common/library/log"
"go-common/library/sync/errgroup"
)
// Managers get manager users info.
func (d *Dao) Managers(c context.Context) (manMap map[int64]string, err error) {
var (
count, page int64
g errgroup.Group
l sync.RWMutex
)
if count, err = d.ManagerTotal(c); err != nil {
log.Error("d.ManagerTotal error(%v)", err)
return
}
if count <= 0 {
return
}
manMap = make(map[int64]string, count)
ps := int64(500)
pageNum := count / ps
if count%ps != 0 {
pageNum++
}
for page = 1; page <= pageNum; page++ {
tmpPage := page
g.Go(func() (err error) {
mi, err := d.Manager(c, tmpPage, ps)
if err != nil {
log.Error("d.Manager(%d,%d) error(%v) ", tmpPage, ps, err)
err = nil
return
}
for _, v := range mi {
l.Lock()
manMap[v.OID] = v.Uname
l.Unlock()
}
return
})
}
g.Wait()
return
}
// Manager get manager users.
func (d *Dao) Manager(c context.Context, pn, ps int64) (mi []*model.MangerInfo, err error) {
params := url.Values{}
params.Set("pn", strconv.FormatInt(pn, 10))
params.Set("ps", strconv.FormatInt(ps, 10))
var res struct {
Code int `json:"code"`
Data *struct {
Items []*model.MangerInfo `json:"items"`
} `json:"data"`
}
if err = d.client.Get(c, d.managersURL, "", params, &res); err != nil {
log.Error("Manager(%s) error(%v)", d.managersURL+"?"+params.Encode(), err)
return
}
if res.Code != 0 {
log.Warn("Manager(%s) code(%d) data(%+v)", d.managersURL+"?"+params.Encode(), res.Code, res.Data)
return
}
if res.Data != nil {
mi = res.Data.Items
}
return
}
// ManagerTotal get manager user total.
func (d *Dao) ManagerTotal(c context.Context) (count int64, err error) {
params := url.Values{}
var res struct {
Code int `json:"code"`
Data *struct {
Total int64 `json:"total"`
} `json:"data"`
}
if err = d.client.Get(c, d.managerTotalURL, "", params, &res); err != nil {
log.Error("ManagerTotal(%s) error(%v)", d.managerTotalURL+"?"+params.Encode(), err)
return
}
if res.Code != 0 {
log.Warn("ManagerTotal(%s) code(%d) data(%+v)", d.managerTotalURL+"?"+params.Encode(), res.Code, res.Data)
return
}
if res.Data != nil {
count = res.Data.Total
}
return
}

View File

@@ -0,0 +1,32 @@
package dao
import (
"context"
"testing"
. "github.com/smartystreets/goconvey/convey"
)
func Test_Managers(t *testing.T) {
Convey("return someting", t, func() {
res, err := d.Managers(context.Background())
So(err, ShouldBeNil)
So(res, ShouldNotBeNil)
})
}
func Test_Manager(t *testing.T) {
Convey("return someting", t, func() {
res, err := d.Manager(context.Background(), 1, 2)
So(err, ShouldBeNil)
So(res, ShouldNotBeNil)
})
}
func Test_ManagerTotal(t *testing.T) {
Convey("return someting", t, func() {
res, err := d.ManagerTotal(context.Background())
So(err, ShouldBeNil)
So(res, ShouldNotBeNil)
})
}

View File

@@ -0,0 +1,353 @@
package dao
import (
"context"
"database/sql"
"fmt"
"go-common/app/admin/main/usersuit/model"
xsql "go-common/library/database/sql"
"go-common/library/log"
"github.com/pkg/errors"
)
const (
_sharding = 10
_selMedal = "SELECT id,name,description,cond,gid,level,level_rank,sort,is_online FROM medal_info"
_selMedalByID = "SELECT id,name,description,image,image_small,cond,gid,level,level_rank,sort,is_online FROM medal_info WHERE id= ?"
_insertMedal = "INSERT INTO medal_info (name,description,cond,gid,level,sort,level_rank,is_online,image,image_small) VALUES(?,?,?,?,?,?,?,?,?,?)"
_updateMedal = "UPDATE medal_info SET name=?,description=?,cond=?,gid=?,level=?,sort=?,level_rank=?,is_online=?,image=?,image_small=? WHERE id=?"
_sellMedalGroup = "SELECT id,name,pid,rank,is_online FROM medal_group ORDER BY id ASC, rank ASC"
_sellMedalGroupInfo = "SELECT m1.id,m1.name,m1.pid,m1.rank,m1.is_online,ifnull(m2.name,'无') FROM medal_group m1 left join medal_group m2 on m1.pid=m2.id ORDER BY pid ASC, rank ASC"
_selMedalGroupParent = "SELECT id,name,pid,rank,is_online FROM medal_group WHERE pid=0"
_selMedalGroupByID = "SELECT id,name,pid,rank,is_online FROM medal_group WHERE id= ?"
_insertMedalGroup = "INSERT INTO medal_group (name,pid,rank,is_online) VALUES (?,?,?,?)"
_updateMedalGroupByID = "UPDATE medal_group SET name=?,pid=?,rank=?,is_online=? WHERE id =?"
_selMedalOwnerByMID = "SELECT o.id,o.nid,o.is_activated,o.is_del,i.name FROM medal_owner_%s o LEFT JOIN medal_info i ON o.nid=i.id WHERE o.mid=?"
_selMedalAddList = "SELECT id,name FROM medal_info WHERE id NOT IN (SELECT nid FROM medal_owner_%s WHERE mid=?)"
_countOwnerBYNidMidSQL = "SELECT COUNT(*) FROM medal_owner_%s WHERE mid=? AND nid=?"
_insertMedalOwner = "INSERT INTO medal_owner_%s (mid,nid) VALUES (?,?)"
_updatMedalOwnerActivated = "UPDATE medal_owner_%s SET is_activated=1 WHERE mid=? AND nid=?"
_updatMedalOwnerNoActivated = "UPDATE medal_owner_%s SET is_activated=0 WHERE mid=? AND nid!=?"
_updatMedalOwnerDel = "UPDATE medal_owner_%s SET is_del=? WHERE mid=? AND nid=?"
_insertMedalOperationLogSQL = "INSERT INTO medal_operation_log(oper_id,mid,medal_id,source_type,action) VALUES (?,?,?,?,?)"
_medalOperationLogTotalSQL = "SELECT COUNT(*) FROM medal_operation_log WHERE mid=?"
_medalOperationLogSQL = "SELECT oper_id,action,mid,medal_id,source_type,ctime,mtime FROM medal_operation_log WHERE mid=? ORDER BY mtime DESC LIMIT ?,?"
)
func (d *Dao) hit(id int64) string {
return fmt.Sprintf("%d", id%_sharding)
}
// Medal medal info .
func (d *Dao) Medal(c context.Context) (ms []*model.Medal, err error) {
var rows *xsql.Rows
if rows, err = d.db.Query(c, _selMedal); err != nil {
log.Error("Medal, d.db.Query() error(%v)", err)
return
}
defer rows.Close()
for rows.Next() {
m := &model.Medal{}
if err = rows.Scan(&m.ID, &m.Name, &m.Description, &m.Condition, &m.GID, &m.Level, &m.LevelRank, &m.Sort, &m.IsOnline); err != nil {
log.Error("Medal, rows.Scan(%+v) error(%v)", m, err)
return
}
ms = append(ms, m)
}
err = rows.Err()
return
}
// MedalByID medal info by id .
func (d *Dao) MedalByID(c context.Context, id int64) (m *model.Medal, err error) {
var row = d.db.QueryRow(c, _selMedalByID, id)
m = &model.Medal{}
if err = row.Scan(&m.ID, &m.Name, &m.Description, &m.Image, &m.ImageSmall, &m.Condition, &m.GID, &m.Level, &m.LevelRank, &m.Sort, &m.IsOnline); err != nil {
log.Error("MedalByID, rows.Scan(%+v) error(%v)", m, err)
}
return
}
// AddMedal add medal .
func (d *Dao) AddMedal(c context.Context, m *model.Medal) (affected int64, err error) {
var res sql.Result
if res, err = d.db.Exec(c, _insertMedal, m.Name, m.Description, m.Condition, m.GID, m.Level, m.Sort, m.LevelRank, m.IsOnline, m.Image, m.ImageSmall); err != nil {
log.Error("AddMedal, rows.Exec(%+v) error(%v)", m, err)
return
}
return res.RowsAffected()
}
// UpMedal update nameplate .
func (d *Dao) UpMedal(c context.Context, id int64, m *model.Medal) (affected int64, err error) {
var res sql.Result
if res, err = d.db.Exec(c, _updateMedal, m.Name, m.Description, m.Condition, m.GID, m.Level, m.Sort, m.LevelRank, m.IsOnline, m.Image, m.ImageSmall, id); err != nil {
log.Error("UpMedal, d.db.Exec(%+v,%d) error(%v)", m, id, err)
return
}
return res.RowsAffected()
}
// MedalGroup return medal group all .
func (d *Dao) MedalGroup(c context.Context) (res map[int64]*model.MedalGroup, err error) {
res = make(map[int64]*model.MedalGroup)
var rows *xsql.Rows
if rows, err = d.db.Query(c, _sellMedalGroup); err != nil {
log.Error("MedalGroup, d.db.Query() error(%v)", err)
return
}
defer rows.Close()
for rows.Next() {
re := &model.MedalGroup{}
if err = rows.Scan(&re.ID, &re.Name, &re.PID, &re.Rank, &re.IsOnline); err != nil {
log.Error("MedalGroup, rows.Scan(%+v) error(%v)", re, err)
return
}
res[re.ID] = re
}
err = rows.Err()
return
}
// MedalGroupInfo return medal group all info include parent group name .
func (d *Dao) MedalGroupInfo(c context.Context) (res []*model.MedalGroup, err error) {
res = make([]*model.MedalGroup, 0)
var rows *xsql.Rows
if rows, err = d.db.Query(c, _sellMedalGroupInfo); err != nil {
log.Error("MedalGroupInfo, d.db.Query() error(%v)", err)
return
}
defer rows.Close()
for rows.Next() {
re := &model.MedalGroup{}
if err = rows.Scan(&re.ID, &re.Name, &re.PID, &re.Rank, &re.IsOnline, &re.PName); err != nil {
log.Error("MedalGroupInfo, rows.Scan(%+v) error(%v)", re, err)
return
}
res = append(res, re)
}
err = rows.Err()
return
}
// MedalGroupParent return medal group parent info .
func (d *Dao) MedalGroupParent(c context.Context) (res []*model.MedalGroup, err error) {
res = make([]*model.MedalGroup, 0)
var rows *xsql.Rows
if rows, err = d.db.Query(c, _selMedalGroupParent); err != nil {
log.Error("MedalGroupInfo, d.db.Query() error(%v)", err)
return
}
defer rows.Close()
for rows.Next() {
re := &model.MedalGroup{}
if err = rows.Scan(&re.ID, &re.Name, &re.PID, &re.Rank, &re.IsOnline); err != nil {
log.Error("MedalGroupParent, rows.Scan(%+v) error(%v)", re, err)
return
}
res = append(res, re)
}
err = rows.Err()
return
}
// MedalGroupByID medal group by gid .
func (d *Dao) MedalGroupByID(c context.Context, id int64) (mg *model.MedalGroup, err error) {
var row = d.db.QueryRow(c, _selMedalGroupByID, id)
mg = &model.MedalGroup{}
if err = row.Scan(&mg.ID, &mg.Name, &mg.PID, &mg.Rank, &mg.IsOnline); err != nil {
log.Error("MedalGroupByID, rows.Scan(%+v) error(%v)", mg, err)
return
}
return
}
// MedalGroupAdd add medal group .
func (d *Dao) MedalGroupAdd(c context.Context, mg *model.MedalGroup) (affected int64, err error) {
var res sql.Result
if res, err = d.db.Exec(c, _insertMedalGroup, mg.Name, mg.PID, mg.Rank, mg.IsOnline); err != nil {
log.Error("MedalGroupAdd, d.db.Exec(%+v) error(%v)", mg, err)
return
}
return res.RowsAffected()
}
// MedalGroupUp update name group .
func (d *Dao) MedalGroupUp(c context.Context, id int64, mg *model.MedalGroup) (affected int64, err error) {
var res sql.Result
if res, err = d.db.Exec(c, _updateMedalGroupByID, mg.Name, mg.PID, mg.Rank, mg.IsOnline, id); err != nil {
log.Error("MedalGroupUp, d.db.Exec(%+v %d) error(%v)", mg, id, err)
return
}
return res.RowsAffected()
}
// MedalOwner medal owner .
func (d *Dao) MedalOwner(c context.Context, mid int64) (res []*model.MedalMemberMID, err error) {
var (
rows *xsql.Rows
sqlStr string
)
res = make([]*model.MedalMemberMID, 0)
sqlStr = fmt.Sprintf(_selMedalOwnerByMID, d.hit(mid))
if rows, err = d.db.Query(c, sqlStr, mid); err != nil {
log.Error("MedalOwner, d.db.Query(%s %d) error(%v)", sqlStr, mid, err)
return
}
defer rows.Close()
for rows.Next() {
re := &model.MedalMemberMID{}
if err = rows.Scan(&re.ID, &re.NID, &re.IsActivated, &re.IsDel, &re.MedalName); err != nil {
log.Error("MedalOwner, rows.Scan(%+v) error(%v)", re, err)
return
}
res = append(res, re)
}
err = rows.Err()
return
}
// CountOwnerBYNidMid retun number of medal_owner by mid and nid.
func (d *Dao) CountOwnerBYNidMid(c context.Context, mid, nid int64) (count int64, err error) {
row := d.db.QueryRow(c, fmt.Sprintf(_countOwnerBYNidMidSQL, d.hit(mid)), mid, nid)
if err = row.Scan(&count); err != nil {
if err != sql.ErrNoRows {
err = errors.Wrap(err, "CountOwnerBYNidMid")
return
}
count = 0
err = nil
}
return
}
// MedalOwnerAdd add medal owner .
func (d *Dao) MedalOwnerAdd(c context.Context, mid, nid int64) (affected int64, err error) {
var (
res sql.Result
sqlStr string
)
sqlStr = fmt.Sprintf(_insertMedalOwner, d.hit(mid))
if res, err = d.db.Exec(c, sqlStr, mid, nid); err != nil {
log.Error("MedalOwnerAdd, d.db.Exec(%s %d %d) error(%v)", sqlStr, mid, nid, err)
return
}
return res.RowsAffected()
}
// MedalAddList .
func (d *Dao) MedalAddList(c context.Context, mid int64) (ms []*model.MedalMemberAddList, err error) {
var (
rows *xsql.Rows
sqlStr string
)
sqlStr = fmt.Sprintf(_selMedalAddList, d.hit(mid))
if rows, err = d.db.Query(c, sqlStr, mid); err != nil {
log.Error("MedalAddList, d.db.Query(%s %d) error(%v)", sqlStr, mid, err)
return
}
defer rows.Close()
for rows.Next() {
m := &model.MedalMemberAddList{}
if err = rows.Scan(&m.ID, &m.MedalName); err != nil {
log.Error("MedalAddList, rows.Scan(%+v) error(%v)", m, err)
return
}
ms = append(ms, m)
}
err = rows.Err()
return
}
// MedalOwnerUpActivated update medal owner is_activated=1.
func (d *Dao) MedalOwnerUpActivated(c context.Context, mid, nid int64) (affected int64, err error) {
var (
res sql.Result
sqlStr string
)
sqlStr = fmt.Sprintf(_updatMedalOwnerActivated, d.hit(mid))
if res, err = d.db.Exec(c, sqlStr, mid, nid); err != nil {
log.Error("MedalOwnerUpActivated, d.db.Exec(%s %d %d) error(%v)", sqlStr, mid, nid, err)
return
}
return res.RowsAffected()
}
// MedalOwnerUpNotActivated update medal owner is_activated=0.
func (d *Dao) MedalOwnerUpNotActivated(c context.Context, mid, nid int64) (affected int64, err error) {
var (
res sql.Result
sqlStr string
)
sqlStr = fmt.Sprintf(_updatMedalOwnerNoActivated, d.hit(mid))
if res, err = d.db.Exec(c, sqlStr, mid, nid); err != nil {
log.Error("MedalOwnerUpNotActivated, d.db.Exec(%s %d %d) error(%v)", sqlStr, mid, nid, err)
return
}
return res.RowsAffected()
}
// MedalOwnerDel update medal owner is_del=1.
func (d *Dao) MedalOwnerDel(c context.Context, mid, nid int64, isDel int8) (affected int64, err error) {
var (
res sql.Result
sqlStr string
)
sqlStr = fmt.Sprintf(_updatMedalOwnerDel, d.hit(mid))
if res, err = d.db.Exec(c, sqlStr, isDel, mid, nid); err != nil {
log.Error("MedalOwnerDel, d.db.Exec(%s %d %d %d) error(%v)", sqlStr, isDel, mid, nid, err)
return
}
return res.RowsAffected()
}
// AddMedalOperLog insert medal operation log.
func (d *Dao) AddMedalOperLog(c context.Context, oid int64, mid int64, medalID int64, action string) (affected int64, err error) {
var res sql.Result
// oper_id,mid,medal_id,source_type,action
if res, err = d.db.Exec(c, _insertMedalOperationLogSQL, oid, mid, medalID, model.MedalSourceTypeAdmin, action); err != nil {
log.Error("MedalGroupAdd, d.db.Exec() error(%v)", err)
return
}
return res.RowsAffected()
}
// MedalOperLog get medal operation log.
func (d *Dao) MedalOperLog(c context.Context, mid int64, pn, ps int) (opers []*model.MedalOperLog, uids []int64, err error) {
var (
rows *xsql.Rows
offset = (pn - 1) * ps
)
if rows, err = d.db.Query(c, _medalOperationLogSQL, mid, offset, ps); err != nil {
err = errors.Wrapf(err, "MedalOperLog d.db.Query(%d,%d,%d)", mid, offset, ps)
return
}
defer rows.Close()
for rows.Next() {
oper := new(model.MedalOperLog)
if err = rows.Scan(&oper.OID, &oper.Action, &oper.MID, &oper.MedalID, &oper.SourceType, &oper.CTime, &oper.MTime); err != nil {
err = errors.Wrap(err, "MedalOperLog row.Scan()")
return
}
opers = append(opers, oper)
uids = append(uids, oper.MID)
}
err = rows.Err()
return
}
// MedalOperationLogTotal medal operation log total.
func (d *Dao) MedalOperationLogTotal(c context.Context, mid int64) (count int64, err error) {
row := d.db.QueryRow(c, _medalOperationLogTotalSQL, mid)
if err = row.Scan(&count); err != nil {
err = errors.Wrap(err, "d.dao.MedalOperationLogTotal")
return
}
return
}

View File

@@ -0,0 +1,234 @@
package dao
import (
"context"
"strconv"
"go-common/app/admin/main/usersuit/model"
gmc "go-common/library/cache/memcache"
"go-common/library/log"
)
const (
_prefixActivatedNid = "usma:" // key of activated medal nid
_prefixOwners = "umos:" // key of owners info
_prefixRedPoint = "usrp:" // key of red point
_prefixPopup = "uspp:" // key of new medal popup
)
// medalactivated medal nid key.
func activatedNidKey(mid int64) string {
return _prefixActivatedNid + strconv.FormatInt(mid, 10)
}
// ownersKey medal_owner key.
func ownersKey(mid int64) string {
return _prefixOwners + strconv.FormatInt(mid, 10)
}
//RedPointKey new medal RedPoint key.
func RedPointKey(mid int64) string {
return _prefixRedPoint + strconv.FormatInt(mid, 10)
}
// PopupKey new medal popup key.
func PopupKey(mid int64) string {
return _prefixPopup + strconv.FormatInt(mid, 10)
}
func (d *Dao) pingMC(c context.Context) (err error) {
conn := d.mc.Get(c)
defer conn.Close()
if err = conn.Set(&gmc.Item{Key: "ping", Value: []byte{1}, Expiration: d.mcExpire}); err != nil {
log.Error("conn.Store(set, ping, 1) error(%v)", err)
}
return
}
// MedalOwnersCache get medal_owner cache.
func (d *Dao) MedalOwnersCache(c context.Context, mid int64) (res []*model.MedalOwner, err error) {
conn := d.mc.Get(c)
defer conn.Close()
item, err := conn.Get(ownersKey(mid))
if err != nil {
if err == gmc.ErrNotFound {
res = nil
err = nil
return
}
log.Error("d.MedalOwnersCache err(%v)", err)
return
}
res = make([]*model.MedalOwner, 0)
if err = conn.Scan(item, &res); err != nil {
log.Error("d.MedalOwnersCache err(%v)", err)
}
return
}
// SetMedalOwnersache set medal_owner cache.
func (d *Dao) SetMedalOwnersache(c context.Context, mid int64, nos []*model.MedalOwner) (err error) {
key := ownersKey(mid)
item := &gmc.Item{Key: key, Object: nos, Expiration: d.mcExpire, Flags: gmc.FlagJSON}
conn := d.mc.Get(c)
defer conn.Close()
if err = conn.Set(item); err != nil {
log.Error("SetMedalOwnersache err(%v)", err)
}
return
}
// DelMedalOwnersCache delete medal_owner cache.
func (d *Dao) DelMedalOwnersCache(c context.Context, mid int64) (err error) {
key := ownersKey(mid)
conn := d.mc.Get(c)
defer conn.Close()
if err = conn.Delete(key); err != nil {
if err == gmc.ErrNotFound {
err = nil
} else {
log.Error("d.DelMedalOwnersCache(%s) error(%v)", key, err)
}
}
return
}
// MedalActivatedCache get user activated medal nid.
func (d *Dao) MedalActivatedCache(c context.Context, mid int64) (nid int64, err error) {
conn := d.mc.Get(c)
defer conn.Close()
item, err := conn.Get(activatedNidKey(mid))
if err != nil {
if err == gmc.ErrNotFound {
nid = 0
err = nil
return
}
log.Error("d.MedalActivatedCache(mid:%d) err(%v)", mid, err)
return
}
if err = conn.Scan(item, &nid); err != nil {
log.Error("d.MedalActivatedCache(mid:%d) err(%v)", mid, err)
}
return
}
// SetMedalActivatedCache set activated medal cache.
func (d *Dao) SetMedalActivatedCache(c context.Context, mid, nid int64) (err error) {
key := activatedNidKey(mid)
item := &gmc.Item{Key: key, Object: nid, Expiration: d.mcExpire, Flags: gmc.FlagJSON}
conn := d.mc.Get(c)
defer conn.Close()
if err = conn.Set(item); err != nil {
log.Error("SetMedalActivatedCache err(%v)", err)
}
return
}
// DelMedalActivatedCache delete activated medal cache.
func (d *Dao) DelMedalActivatedCache(c context.Context, mid int64) (err error) {
key := activatedNidKey(mid)
conn := d.mc.Get(c)
defer conn.Close()
if err = conn.Delete(key); err != nil {
if err == gmc.ErrNotFound {
err = nil
} else {
log.Error("d.DelMedalActivatedCache(%s) error(%v)", key, err)
}
}
return
}
// PopupCache get new medal info popup cache.
func (d *Dao) PopupCache(c context.Context, mid int64) (nid int64, err error) {
conn := d.mc.Get(c)
defer conn.Close()
item, err := conn.Get(PopupKey(mid))
if err != nil {
if err == gmc.ErrNotFound {
nid = 0
err = nil
return
}
log.Error("d.PopupCache(mid:%d) err(%v)", mid, err)
return
}
if err = conn.Scan(item, &nid); err != nil {
log.Error("d.PopupCache(mid:%d) err(%v)", mid, err)
}
return
}
// SetPopupCache set popup cache.
func (d *Dao) SetPopupCache(c context.Context, mid, nid int64) (err error) {
key := PopupKey(mid)
item := &gmc.Item{Key: key, Object: nid, Expiration: d.pointExpire, Flags: gmc.FlagJSON}
conn := d.mc.Get(c)
defer conn.Close()
if err = conn.Set(item); err != nil {
log.Error("SetMedalOwnersache err(%v)", err)
}
return
}
// DelPopupCache delete new medal info popup cache.
func (d *Dao) DelPopupCache(c context.Context, mid int64) (err error) {
key := PopupKey(mid)
conn := d.mc.Get(c)
defer conn.Close()
if err = conn.Delete(key); err != nil {
if err == gmc.ErrNotFound {
err = nil
} else {
log.Error("d.DelPopupCache(%s) error(%v)", key, err)
}
}
return
}
// RedPointCache get new medal info red point cache.
func (d *Dao) RedPointCache(c context.Context, mid int64) (nid int64, err error) {
conn := d.mc.Get(c)
defer conn.Close()
item, err := conn.Get(RedPointKey(mid))
if err != nil {
if err == gmc.ErrNotFound {
err = nil
return
}
log.Error("d.RedPointCache(mid:%d) err(%v)", mid, err)
return
}
if err = conn.Scan(item, &nid); err != nil {
log.Error("d.RedPointCache(mid:%d) err(%v)", mid, err)
}
return
}
// SetRedPointCache set red point cache.
func (d *Dao) SetRedPointCache(c context.Context, mid, nid int64) (err error) {
key := RedPointKey(mid)
item := &gmc.Item{Key: key, Object: nid, Expiration: d.pointExpire, Flags: gmc.FlagJSON}
conn := d.mc.Get(c)
defer conn.Close()
if err = conn.Set(item); err != nil {
log.Error("SetRedPointCache(%d %d) err(%v)", mid, nid, err)
}
return
}
// DelRedPointCache delete new medal info red point cache.
func (d *Dao) DelRedPointCache(c context.Context, mid int64) (err error) {
key := RedPointKey(mid)
conn := d.mc.Get(c)
defer conn.Close()
if err = conn.Delete(key); err != nil {
if err == gmc.ErrNotFound {
err = nil
} else {
log.Error("d.DelRedPointCache(%d) error(%v)", mid, err)
}
}
return
}

View File

@@ -0,0 +1,118 @@
package dao
import (
"context"
"fmt"
"testing"
"time"
"go-common/app/admin/main/usersuit/model"
xtime "go-common/library/time"
. "github.com/smartystreets/goconvey/convey"
)
// TestMcJury .
func Test_pingMC(t *testing.T) {
Convey("should return err be nil", t, func() {
err := d.pingMC(context.Background())
So(err, ShouldBeNil)
})
}
func Test_SetMedalOwnersache(t *testing.T) {
Convey("should return err be nil", t, func() {
nos := make([]*model.MedalOwner, 0)
no := &model.MedalOwner{}
no.ID = 1
no.MID = 1
no.NID = 2
no.CTime = xtime.Time(time.Now().Second())
no.MTime = xtime.Time(time.Now().Second())
nos = append(nos, no)
err := d.SetMedalOwnersache(context.Background(), 1, nos)
So(err, ShouldBeNil)
})
Convey("should return err be nil", t, func() {
res, err := d.MedalOwnersCache(context.Background(), 1)
So(err, ShouldBeNil)
So(res, ShouldNotBeNil)
})
}
func Test_DelMedalOwnersCache(t *testing.T) {
Convey("should return err be nil", t, func() {
err := d.DelMedalOwnersCache(context.Background(), 1)
So(err, ShouldBeNil)
})
}
func Test_MedalActivatedCache(t *testing.T) {
Convey("should return err be nil", t, func() {
nid, err := d.MedalActivatedCache(context.Background(), 1)
fmt.Printf("%+v\n", nid)
So(nid, ShouldNotBeNil)
So(err, ShouldBeNil)
})
}
func Test_SetMedalActivatedCache(t *testing.T) {
Convey("should return err be nil", t, func() {
err := d.SetMedalActivatedCache(context.Background(), 1, 22)
So(err, ShouldBeNil)
})
}
func Test_DelMedalActivatedCache(t *testing.T) {
Convey("should return err be nil", t, func() {
err := d.DelMedalActivatedCache(context.Background(), 1)
So(err, ShouldBeNil)
})
}
func Test_PopupCache(t *testing.T) {
Convey("should return err be nil", t, func() {
nid, err := d.PopupCache(context.Background(), 1)
fmt.Printf("%+v\n", nid)
So(nid, ShouldNotBeNil)
So(nid, ShouldBeGreaterThanOrEqualTo, 0)
So(err, ShouldBeNil)
})
}
func Test_SetPopupCache(t *testing.T) {
Convey("should return err be nil", t, func() {
err := d.SetPopupCache(context.Background(), 1, 3)
So(err, ShouldBeNil)
})
}
func Test_DelPopupCache(t *testing.T) {
Convey("should return err be nil", t, func() {
err := d.DelPopupCache(context.Background(), 1)
So(err, ShouldBeNil)
})
}
func Test_RedPointCache(t *testing.T) {
Convey("should return err be nil", t, func() {
nid, err := d.RedPointCache(context.Background(), 1)
fmt.Printf("%+v\n", nid)
So(nid, ShouldNotBeNil)
So(nid, ShouldBeGreaterThanOrEqualTo, 0)
So(err, ShouldBeNil)
})
}
func Test_SetRedPointCache(t *testing.T) {
Convey("should return err be nil", t, func() {
err := d.SetRedPointCache(context.Background(), 1, 3)
So(err, ShouldBeNil)
})
}
func Test_DelRedPointCache(t *testing.T) {
Convey("should return err be nil", t, func() {
err := d.DelRedPointCache(context.Background(), 1)
So(err, ShouldBeNil)
})
}

View File

@@ -0,0 +1,177 @@
package dao
import (
"context"
"go-common/app/admin/main/usersuit/model"
"math/rand"
"testing"
. "github.com/smartystreets/goconvey/convey"
)
func TestDao_hit(t *testing.T) {
Convey("return someting", t, func() {
re := d.hit(1)
So(re, ShouldEqual, "1")
})
}
func TestDao_Medal(t *testing.T) {
Convey("return someting", t, func() {
res, err := d.Medal(context.Background())
So(err, ShouldBeNil)
So(res, ShouldNotBeNil)
})
}
func TestDao_MedalByID(t *testing.T) {
Convey("return someting", t, func() {
re, err := d.MedalByID(context.Background(), 1)
So(err, ShouldBeNil)
So(re, ShouldNotBeNil)
})
}
func TestDao_AddMedal(t *testing.T) {
Convey("return someting", t, func() {
pg := &model.Medal{
Name: "知名偶像",
Description: "红白出道,拯救高校",
Condition: "所有自制视频总播放数>=100万 ",
GID: 4,
Level: int8(3),
Sort: 3,
LevelRank: "100万",
IsOnline: 1,
Image: "/bfs/face/27a952195555e64508310e366b3e38bd4cd143fc.png",
ImageSmall: "/bfs/face/0497be49e08357bf05bca56e33a0637a273a7610.png",
}
id, err := d.AddMedal(context.Background(), pg)
So(err, ShouldBeNil)
So(id, ShouldNotBeNil)
})
}
func TestDao_UpMedal(t *testing.T) {
Convey("return someting", t, func() {
pg := &model.Medal{
Name: "test",
Description: "Description",
Condition: "Condition",
GID: 1,
Level: int8(3),
Sort: 1,
LevelRank: "LevelRank",
IsOnline: 1,
Image: "Image",
ImageSmall: "ImageSmall",
}
id, err := d.UpMedal(context.Background(), 1, pg)
So(err, ShouldBeNil)
So(id, ShouldNotBeNil)
})
}
func TestDao_MedalGroup(t *testing.T) {
Convey("return someting", t, func() {
res, err := d.MedalGroup(context.Background())
So(err, ShouldBeNil)
So(res, ShouldNotBeNil)
})
}
func TestDao_MedalGroupInfo(t *testing.T) {
Convey("return someting", t, func() {
res, err := d.MedalGroupInfo(context.Background())
So(err, ShouldBeNil)
So(res, ShouldNotBeNil)
})
}
func TestDao_MedalGroupParent(t *testing.T) {
Convey("return someting", t, func() {
res, err := d.MedalGroupParent(context.Background())
So(err, ShouldBeNil)
So(res, ShouldNotBeNil)
})
}
func TestDao_MedalGroupByID(t *testing.T) {
Convey("return someting", t, func() {
re, err := d.MedalGroupByID(context.Background(), 2)
So(err, ShouldBeNil)
So(re, ShouldNotBeNil)
})
}
func TestDao_MedalGroupAdd(t *testing.T) {
Convey("return someting", t, func() {
pg := &model.MedalGroup{
Name: "test",
PID: 1,
Rank: int8(1),
IsOnline: int8(1),
}
id, err := d.MedalGroupAdd(context.Background(), pg)
So(err, ShouldBeNil)
So(id, ShouldNotBeNil)
})
}
func TestDao_MedalGroupUp(t *testing.T) {
Convey("return someting", t, func() {
pg := &model.MedalGroup{
Name: "test111",
PID: 2,
Rank: 2,
IsOnline: 0,
}
id, err := d.MedalGroupUp(context.Background(), 37, pg)
So(err, ShouldBeNil)
So(id, ShouldNotBeNil)
})
}
func Test_MedalOwnerAdd(t *testing.T) {
mid := int64(rand.Int31())
Convey("return someting", t, func() {
id, err := d.MedalOwnerAdd(context.Background(), mid, 1)
So(err, ShouldBeNil)
So(id, ShouldNotBeNil)
})
Convey("return someting", t, func() {
_, err := d.MedalOwner(context.Background(), mid)
So(err, ShouldBeNil)
})
}
func TestDao_MedalAddList(t *testing.T) {
Convey("return someting", t, func() {
res, err := d.MedalAddList(context.Background(), 111)
So(err, ShouldBeNil)
So(res, ShouldNotBeNil)
})
}
func TestDao_MedalOwnerUpActivated(t *testing.T) {
Convey("return someting", t, func() {
id, err := d.MedalOwnerUpActivated(context.Background(), 1, 1)
So(err, ShouldBeNil)
So(id, ShouldNotBeNil)
})
}
func TestDao_MedalOwnerUpNotActivated(t *testing.T) {
Convey("return someting", t, func() {
id, err := d.MedalOwnerUpNotActivated(context.Background(), 1, 1)
So(err, ShouldBeNil)
So(id, ShouldNotBeNil)
})
}
func TestDao_MedalOwnerDel(t *testing.T) {
Convey("return someting", t, func() {
id, err := d.MedalOwnerDel(context.Background(), 1, 1, 1)
So(err, ShouldBeNil)
So(id, ShouldNotBeNil)
})
}

View File

@@ -0,0 +1,60 @@
package dao
import (
"context"
"net/url"
"go-common/library/ecode"
"go-common/library/xstr"
"github.com/pkg/errors"
)
// MutliSendSysMsg Mutli send sys msg.
func (d *Dao) MutliSendSysMsg(c context.Context, allUids []int64, title string, context string, ip string) (err error) {
var times int
ulen := len(allUids)
if ulen%100 == 0 {
times = ulen / 100
} else {
times = ulen/100 + 1
}
var uids []int64
for i := 0; i < times; i++ {
if i == times-1 {
uids = allUids[i*100:]
} else {
uids = allUids[i*100 : (i+1)*100]
}
if err = d.SendSysMsg(c, uids, title, context, ip); err != nil {
err = errors.Wrapf(err, "d.SendSysMsg(%+v,%s,%s,%s)", uids, title, context, ip)
continue
}
}
return
}
// SendSysMsg send sys msg.
func (d *Dao) SendSysMsg(c context.Context, uids []int64, title string, context string, ip string) (err error) {
params := url.Values{}
params.Set("mc", "2_1_13")
params.Set("title", title)
params.Set("data_type", "4")
params.Set("context", context)
params.Set("mid_list", xstr.JoinInts(uids))
var res struct {
Code int `json:"code"`
Data *struct {
Status int8 `json:"status"`
Remark string `json:"remark"`
} `json:"data"`
}
if err = d.client.Post(c, d.msgURL, ip, params, &res); err != nil {
err = errors.Wrapf(err, "SendSysMsg d.client.Post(%s)", d.msgURL+"?"+params.Encode())
return
}
if res.Code != 0 {
err = errors.Wrapf(ecode.Int(res.Code), "SendSysMsg d.client.Post(%s,%d)", d.msgURL+"?"+params.Encode(), res.Code)
}
return
}

View File

@@ -0,0 +1,27 @@
package dao
import (
"context"
"testing"
. "github.com/smartystreets/goconvey/convey"
gock "gopkg.in/h2non/gock.v1"
)
func Test_MutliSendSysMsg(t *testing.T) {
Convey("return someting", t, func() {
defer gock.OffAll()
httpMock("POST", d.msgURL).Reply(200).JSON(`{"code":0}`)
err := d.MutliSendSysMsg(context.Background(), []int64{22, 11}, "dasda", "dsadasd", "127.0.0.1")
So(err, ShouldBeNil)
})
}
func Test_SendSysMsg(t *testing.T) {
Convey("return someting", t, func() {
defer gock.OffAll()
httpMock("POST", d.msgURL).Reply(200).JSON(`{"code":0}`)
err := d.SendSysMsg(context.Background(), []int64{22, 11}, "dasda", "dsadasd", "127.0.0.1")
So(err, ShouldBeNil)
})
}

View File

@@ -0,0 +1,761 @@
package dao
import (
"bytes"
"context"
"database/sql"
"fmt"
"reflect"
"strconv"
"strings"
"sync"
"time"
"go-common/app/admin/main/usersuit/model"
xsql "go-common/library/database/sql"
"go-common/library/xstr"
"github.com/pkg/errors"
)
const (
_inPdGroupSQL = "INSERT INTO pendant_group(name,rank,status) VALUES (?,?,?)"
_inPdGroupRefSQL = "INSERT INTO pendant_group_ref(gid,pid) VALUES (?,?)"
_inPdInfoSQL = "INSERT INTO pendant_info(name,image,image_model,status,rank) VALUES (?,?,?,?,?)"
_inPdPriceSQL = "INSERT INTO pendant_price(pid,type,price) VALUES (?,?,?) ON DUPLICATE KEY UPDATE pid=?,type=?,price=?"
_inPdPKGSQL = "INSERT INTO user_pendant_pkg(mid,pid,expires,type,status) VALUES (?,?,?,4,1) ON DUPLICATE KEY UPDATE expires = ?, type = 4, status = 1"
_inPdPKGsSQL = "INSERT INTO user_pendant_pkg(mid,pid,expires,type,status) VALUES %s"
_inPdEquipSQL = "INSERT INTO user_pendant_equip(mid,pid,expires) VALUES (?,?,?) ON DUPLICATE KEY UPDATE pid = ? ,expires = ?"
_inPdOperationLogSQL = "INSERT INTO pendant_operation_log(oper_id,mid,pid,source_type,action) VALUES %s"
_upPdGroupRefSQL = "UPDATE pendant_group_ref SET gid = ? WHERE pid = ?"
_upPdPKGsSQL = "UPDATE user_pendant_pkg SET expires = CASE id %s END, type = 4, status = 1 WHERE id IN (%s)"
_upPdGroupSQL = "UPDATE pendant_group SET name=?,rank=?,status=? WHERE id=?"
_upPdGroupStatusSQL = "UPDATE pendant_group SET status=? WHERE id=?"
_upPdInfoSQL = "UPDATE pendant_info SET name=?,image=?,image_model=?,status=?,rank=? WHERE id=?"
_upPdInfoStatusSQL = "UPDATE pendant_info SET status=? WHERE id=?"
_pdInfoAllSQL = `SELECT i.id,i.name,i.image,i.image_model,i.status,i.rank,g.id,g.name,g.rank FROM pendant_info AS i INNER JOIN pendant_group_ref AS r
ON i.id = r.pid LEFT JOIN pendant_group AS g ON g.id = r.gid ORDER BY g.rank ,i.rank ASC,i.id DESC LIMIT ?,?`
_pdGroupInfoTotalSQL = "SELECT COUNT(*) FROM pendant_info INNER JOIN pendant_group_ref ON pendant_info.id = pendant_group_ref.pid"
_pdGroupsTotalSQL = "SELECT COUNT(*) FROM pendant_group"
_pdGroupRefsTotalSQL = "SELECT COUNT(*) FROM pendant_group_ref"
_pdGroupRefsGidTotalSQL = "SELECT COUNT(*) FROM pendant_group_ref WHERE gid = ?"
_pdGroupsSQL = "SELECT id,name,rank,status FROM pendant_group ORDER BY rank ASC LIMIT ?,?"
_pdGroupAllSQL = "SELECT id,name,rank,status FROM pendant_group ORDER BY rank ASC"
_pdGroupIDsSQL = "SELECT id,name,rank,status FROM pendant_group WHERE id IN (%s)"
_pdGroupIDSQL = "SELECT id,name,rank,status FROM pendant_group WHERE id = ?"
_pdInfoIDsSQL = "SELECT id,name,image,image_model,status,rank FROM pendant_info WHERE id IN (%s) ORDER BY rank ASC"
_pdPriceIDsSQL = "SELECT pid,type,price FROM pendant_price WHERE pid IN (%s)"
_pdGroupRefRanksSQL = "SELECT pr.gid,pr.pid FROM pendant_group_ref AS pr INNER JOIN pendant_group AS pg WHERE pr.gid = pg.id ORDER BY pg.rank ASC LIMIT ?,?"
_pdGroupRefsSQL = "SELECT pid FROM pendant_group_ref WHERE gid = ? LIMIT ?,?"
_pdInfoIDSQL = "SELECT id,name,image,image_model,status,rank FROM pendant_info WHERE id = ?"
_pdInfoAllNoPageSQL = "SELECT id,name,image,image_model,status,rank FROM pendant_info"
_maxOrderHistorysSQL = "SELECT MAX(id) FROM user_pendant_order"
_countOrderHistorysSQL = "SELECT COUNT(*) FROM user_pendant_order %s"
_orderHistorysSQL = "SELECT mid,order_id,pay_id,appid,status,pid,time_length,cost,buy_time,pay_type FROM user_pendant_order %s"
_pdPKGsUIDSQL = "SELECT mid,pid,expires,type,status,is_vip FROM user_pendant_pkg WHERE mid = ? ORDER BY mtime DESC"
_pdPKGUIDsSQL = "SELECT id,mid,pid,expires,type,status,is_vip FROM user_pendant_pkg WHERE mid IN (%s) AND pid = ?"
_pdPKGUIDSQL = "SELECT id,mid,pid,expires,type,status,is_vip FROM user_pendant_pkg WHERE mid = ? AND pid = ?"
_pdEquipUIDSQL = "SELECT pid,expires FROM user_pendant_equip WHERE mid = ? AND expires >= ?"
_pdOperationLogTotalSQL = "SELECT MAX(id) FROM pendant_operation_log"
_pdOperationLogSQL = "SELECT oper_id,action,mid,pid,source_type,ctime,mtime FROM pendant_operation_log ORDER BY mtime DESC LIMIT ?,?"
)
// AddPendantGroup insert pendant group .
func (d *Dao) AddPendantGroup(c context.Context, pg *model.PendantGroup) (gid int64, err error) {
var res sql.Result
if res, err = d.db.Exec(c, _inPdGroupSQL, pg.Name, pg.Rank, pg.Status); err != nil {
err = errors.Wrapf(err, "AddPendantGroup d.db.Exec(%s,%d)", pg.Name, pg.Rank)
return
}
return res.LastInsertId()
}
// TxAddPendantGroupRef tx insert pendant group ref.
func (d *Dao) TxAddPendantGroupRef(tx *xsql.Tx, pr *model.PendantGroupRef) (affected int64, err error) {
var res sql.Result
if res, err = tx.Exec(_inPdGroupRefSQL, pr.GID, pr.PID); err != nil {
err = errors.Wrapf(err, "TxAddPendantGroupRef itx.Exec(%d,%d)", pr.GID, pr.PID)
return
}
return res.RowsAffected()
}
// TxAddPendantInfo insert pendant info.
func (d *Dao) TxAddPendantInfo(tx *xsql.Tx, pi *model.PendantInfo) (pid int64, err error) {
var res sql.Result
if res, err = tx.Exec(_inPdInfoSQL, pi.Name, pi.Image, pi.ImageModel, pi.Status, pi.Rank); err != nil {
err = errors.Wrapf(err, "TxAddPendantInfo tx.Exec(%s,%s,%s,%d)", pi.Name, pi.Image, pi.ImageModel, pi.Rank)
return
}
return res.LastInsertId()
}
// TxAddPendantPrices insert pendant prices.
func (d *Dao) TxAddPendantPrices(tx *xsql.Tx, pp *model.PendantPrice) (affected int64, err error) {
var res sql.Result
if res, err = tx.Exec(_inPdPriceSQL, pp.PID, pp.TP, pp.Price, pp.PID, pp.TP, pp.Price); err != nil {
err = errors.Wrapf(err, "TxAddPendantPrices tx.Exec(%d,%d,%d)", pp.PID, pp.TP, pp.Price)
return
}
return res.RowsAffected()
}
// AddPendantPKG insert pendant pkg.
func (d *Dao) AddPendantPKG(c context.Context, pkg *model.PendantPKG) (affected int64, err error) {
var res sql.Result
if res, err = d.db.Exec(c, _inPdPKGSQL, pkg.UID, pkg.PID, pkg.Expires, pkg.Expires); err != nil {
err = errors.Wrapf(err, "AddPendantPKG d.db.Exec(%d,%d,%d)", pkg.UID, pkg.PID, pkg.Expires)
return
}
return res.RowsAffected()
}
// TxAddPendantPKGs multi insert pendant pkg.
func (d *Dao) TxAddPendantPKGs(tx *xsql.Tx, pkgs []*model.PendantPKG) (affected int64, err error) {
var (
uids []int64
pids map[int64]struct{}
)
l := len(pkgs)
valueStrings := make([]string, 0, l)
valueArgs := make([]interface{}, 0, l*3)
pids = make(map[int64]struct{})
for _, pkg := range pkgs {
valueStrings = append(valueStrings, "(?,?,?,4,1)")
valueArgs = append(valueArgs, strconv.FormatInt(pkg.UID, 10))
valueArgs = append(valueArgs, strconv.FormatInt(pkg.PID, 10))
valueArgs = append(valueArgs, strconv.FormatInt(pkg.Expires, 10))
uids = append(uids, pkg.UID)
pids[pkg.PID] = struct{}{}
}
stmt := fmt.Sprintf(_inPdPKGsSQL, strings.Join(valueStrings, ","))
_, err = tx.Exec(stmt, valueArgs...)
if err != nil {
err = errors.Wrapf(err, "TxAddPendantPKGs tx.Exec(%s,%+v)", xstr.JoinInts(uids), reflect.ValueOf(pids).MapKeys())
}
return
}
// AddPendantEquip insert pendant equip.
func (d *Dao) AddPendantEquip(c context.Context, pkg *model.PendantPKG) (affected int64, err error) {
var res sql.Result
if res, err = d.db.Exec(c, _inPdEquipSQL, pkg.UID, pkg.PID, pkg.Expires, pkg.PID, pkg.Expires); err != nil {
err = errors.Wrapf(err, "AddPendantEquip d.db.Exec(%d,%d,%d)", pkg.UID, pkg.PID, pkg.Expires)
return
}
return res.RowsAffected()
}
// AddPendantOperLog insert pendant operation log.
func (d *Dao) AddPendantOperLog(c context.Context, oid int64, uids []int64, pid int64, action string) (affected int64, err error) {
var res sql.Result
l := len(uids)
valueStrings := make([]string, 0, l)
valueArgs := make([]interface{}, 0, l*5)
for _, uid := range uids {
valueStrings = append(valueStrings, "(?,?,?,?,?)")
valueArgs = append(valueArgs, strconv.FormatInt(oid, 10))
valueArgs = append(valueArgs, strconv.FormatInt(uid, 10))
valueArgs = append(valueArgs, strconv.FormatInt(pid, 10))
valueArgs = append(valueArgs, strconv.FormatInt(int64(model.PendantSourceTypeAdmin), 10))
valueArgs = append(valueArgs, action)
}
stmt := fmt.Sprintf(_inPdOperationLogSQL, strings.Join(valueStrings, ","))
res, err = d.db.Exec(c, stmt, valueArgs...)
if err != nil {
err = errors.Errorf("AddPendantOperLog tx.Exec(%s,%d,%s) error(%+v)", xstr.JoinInts(uids), pid, action, err)
return
}
return res.RowsAffected()
}
// TxUpPendantGroupRef update pendant group ref.
func (d *Dao) TxUpPendantGroupRef(tx *xsql.Tx, gid, pid int64) (affected int64, err error) {
var res sql.Result
if res, err = tx.Exec(_upPdGroupRefSQL, gid, pid); err != nil {
err = errors.Wrapf(err, "UpPendantGroupRef tx.Exec(%d,%d)", gid, pid)
return
}
return res.RowsAffected()
}
// TxUpPendantPKGs multi update pendant pkg.
func (d *Dao) TxUpPendantPKGs(tx *xsql.Tx, pkgs []*model.PendantPKG) (affected int64, err error) {
var ids []int64
l := len(pkgs)
valueStrings := make([]string, 0, l)
valueArgs := make([]interface{}, 0, l*2)
for _, pkg := range pkgs {
valueStrings = append(valueStrings, "WHEN ? THEN ? ")
valueArgs = append(valueArgs, strconv.FormatInt(pkg.ID, 10))
valueArgs = append(valueArgs, strconv.FormatInt(pkg.Expires, 10))
ids = append(ids, pkg.ID)
}
stmt := fmt.Sprintf(_upPdPKGsSQL, strings.Join(valueStrings, " "), xstr.JoinInts(ids))
_, err = tx.Exec(stmt, valueArgs...)
if err != nil {
err = errors.Wrapf(err, "TxUpPendantPKGs tx.Exec(%s)", xstr.JoinInts(ids))
}
return
}
// UpPendantGroup update pendant group.
func (d *Dao) UpPendantGroup(c context.Context, pg *model.PendantGroup) (affected int64, err error) {
var res sql.Result
if res, err = d.db.Exec(c, _upPdGroupSQL, pg.Name, pg.Rank, pg.Status, pg.ID); err != nil {
err = errors.Wrapf(err, "UpPendantGroup tx.Exec(%s,%d,%d,%d)", pg.Name, pg.Rank, pg.Status, pg.ID)
return
}
return res.RowsAffected()
}
// UpPendantGroupStatus update pendant group status.
func (d *Dao) UpPendantGroupStatus(c context.Context, gid int64, status int8) (affected int64, err error) {
var res sql.Result
if res, err = d.db.Exec(c, _upPdGroupStatusSQL, status, gid); err != nil {
err = errors.Wrapf(err, "UpPendantGroupStatus tx.Exec(%d,%d)", status, gid)
return
}
return res.RowsAffected()
}
// TxUpPendantInfo update pendant info.
func (d *Dao) TxUpPendantInfo(tx *xsql.Tx, pi *model.PendantInfo) (affected int64, err error) {
var res sql.Result
if res, err = tx.Exec(_upPdInfoSQL, pi.Name, pi.Image, pi.ImageModel, pi.Status, pi.Rank, pi.ID); err != nil {
err = errors.Wrapf(err, "TxAddPendantPrices tx.Exec(%s,%s,%s,%d,%d,%d)", pi.Name, pi.Image, pi.ImageModel, pi.Status, pi.Rank, pi.ID)
return
}
return res.RowsAffected()
}
// UpPendantInfoStatus update pendant info status.
func (d *Dao) UpPendantInfoStatus(c context.Context, pid int64, status int8) (affected int64, err error) {
var res sql.Result
if res, err = d.db.Exec(c, _upPdInfoStatusSQL, status, pid); err != nil {
err = errors.Wrapf(err, "UpPendantGroupStatus tx.Exec(%d,%d)", status, pid)
return
}
return res.RowsAffected()
}
// PendantInfoAll pendant info all.
func (d *Dao) PendantInfoAll(c context.Context, pn, ps int) (pis []*model.PendantInfo, pids []int64, err error) {
var (
gid, groupRank sql.NullInt64
groupName sql.NullString
rows *xsql.Rows
offset = (pn - 1) * ps
)
if rows, err = d.db.Query(c, _pdInfoAllSQL, offset, ps); err != nil {
err = errors.Wrapf(err, "PendantInfoAll d.db.Query(%d,%d)", offset, ps)
return
}
defer rows.Close()
for rows.Next() {
pi := new(model.PendantInfo)
if err = rows.Scan(&pi.ID, &pi.Name, &pi.Image, &pi.ImageModel, &pi.Status, &pi.Rank, &gid, &groupName, &groupRank); err != nil {
err = errors.Wrap(err, "PendantInfoAll row.Scan()")
return
}
pi.GID = gid.Int64
pi.GroupName = groupName.String
pi.GroupRank = int16(groupRank.Int64)
pids = append(pids, pi.ID)
pis = append(pis, pi)
}
err = rows.Err()
return
}
// PendantGroupInfoTotal pendant group info total.
func (d *Dao) PendantGroupInfoTotal(c context.Context) (count int64, err error) {
row := d.db.QueryRow(c, _pdGroupInfoTotalSQL)
if err = row.Scan(&count); err != nil {
err = errors.Wrap(err, "d.dao.PendantGroupInfoTotal")
}
return
}
// PendantGroupsTotal pendant group total.
func (d *Dao) PendantGroupsTotal(c context.Context) (count int64, err error) {
row := d.db.QueryRow(c, _pdGroupsTotalSQL)
if err = row.Scan(&count); err != nil {
err = errors.Wrap(err, "d.dao.PendantGroupsTotal")
}
return
}
// PendantGroupRefsTotal pendant group refs total.
func (d *Dao) PendantGroupRefsTotal(c context.Context) (count int64, err error) {
row := d.db.QueryRow(c, _pdGroupRefsTotalSQL)
if err = row.Scan(&count); err != nil {
err = errors.Wrap(err, "d.dao.PendantGroupRefsTotal")
}
return
}
// PendantGroupRefsGidTotal pendant group refs total by gid.
func (d *Dao) PendantGroupRefsGidTotal(c context.Context, gid int64) (count int64, err error) {
row := d.db.QueryRow(c, _pdGroupRefsGidTotalSQL, gid)
if err = row.Scan(&count); err != nil {
err = errors.Wrap(err, "d.dao.PendantGroupRefsGidTotal")
}
return
}
// PendantGroups pendant group pagesize.
func (d *Dao) PendantGroups(c context.Context, pn, ps int) (pgs []*model.PendantGroup, err error) {
var (
rows *xsql.Rows
offset = (pn - 1) * ps
)
if rows, err = d.db.Query(c, _pdGroupsSQL, offset, ps); err != nil {
err = errors.Wrapf(err, "PendantGroups d.db.Query(%d,%d)", offset, ps)
return
}
defer rows.Close()
for rows.Next() {
pg := new(model.PendantGroup)
if err = rows.Scan(&pg.ID, &pg.Name, &pg.Rank, &pg.Status); err != nil {
err = errors.Wrap(err, "PendantGroups row.Scan()")
return
}
pgs = append(pgs, pg)
}
err = rows.Err()
return
}
// PendantGroupAll pendant all group .
func (d *Dao) PendantGroupAll(c context.Context) (pgs []*model.PendantGroup, err error) {
var rows *xsql.Rows
if rows, err = d.db.Query(c, _pdGroupAllSQL); err != nil {
err = errors.Wrap(err, "PendantGroupAll d.db.Query(%d,%d)")
return
}
defer rows.Close()
for rows.Next() {
pg := new(model.PendantGroup)
if err = rows.Scan(&pg.ID, &pg.Name, &pg.Rank, &pg.Status); err != nil {
err = errors.Wrap(err, "PendantGroupAll row.Scan()")
return
}
pgs = append(pgs, pg)
}
err = rows.Err()
return
}
// PendantGroupIDs pendant group in ids.
func (d *Dao) PendantGroupIDs(c context.Context, ids []int64) (pgs []*model.PendantGroup, err error) {
var rows *xsql.Rows
if rows, err = d.db.Query(c, fmt.Sprintf(_pdGroupIDsSQL, xstr.JoinInts(ids))); err != nil {
err = errors.Wrapf(err, "PendantGroupIDs d.db.Query(%s)", xstr.JoinInts(ids))
return
}
defer rows.Close()
for rows.Next() {
pg := new(model.PendantGroup)
if err = rows.Scan(&pg.ID, &pg.Name, &pg.Rank, &pg.Status); err != nil {
err = errors.Wrap(err, "PendantGroupIDs row.Scan()")
return
}
pgs = append(pgs, pg)
}
err = rows.Err()
return
}
// PendantGroupID pendant group by id.
func (d *Dao) PendantGroupID(c context.Context, id int64) (pg *model.PendantGroup, err error) {
row := d.db.QueryRow(c, _pdGroupIDSQL, id)
if err != nil {
err = errors.Wrapf(err, "PendantGroupID d.db.Query(%d)", id)
return
}
pg = &model.PendantGroup{}
if err = row.Scan(&pg.ID, &pg.Name, &pg.Rank, &pg.Status); err != nil {
if err == sql.ErrNoRows {
err = nil
pg = nil
return
}
err = errors.Wrap(err, "PendantGroupID row.Scan")
}
return
}
// PendantInfoIDs pendant info in ids.
func (d *Dao) PendantInfoIDs(c context.Context, ids []int64) (pis []*model.PendantInfo, pim map[int64]*model.PendantInfo, err error) {
var rows *xsql.Rows
if rows, err = d.db.Query(c, fmt.Sprintf(_pdInfoIDsSQL, xstr.JoinInts(ids))); err != nil {
err = errors.Wrapf(err, "PendantInfoIDs d.db.Query(%s)", xstr.JoinInts(ids))
return
}
defer rows.Close()
pim = make(map[int64]*model.PendantInfo, len(ids))
for rows.Next() {
pi := new(model.PendantInfo)
if err = rows.Scan(&pi.ID, &pi.Name, &pi.Image, &pi.ImageModel, &pi.Status, &pi.Rank); err != nil {
err = errors.Wrap(err, "PendantInfoIDs row.Scan()")
return
}
pis = append(pis, pi)
pim[pi.ID] = pi
}
err = rows.Err()
return
}
// PendantPriceIDs pendant price in ids.
func (d *Dao) PendantPriceIDs(c context.Context, ids []int64) (ppm map[int64][]*model.PendantPrice, err error) {
var rows *xsql.Rows
if rows, err = d.db.Query(c, fmt.Sprintf(_pdPriceIDsSQL, xstr.JoinInts(ids))); err != nil {
err = errors.Wrapf(err, "PendantPriceIDs d.db.Query(%s)", xstr.JoinInts(ids))
return
}
defer rows.Close()
ppm = make(map[int64][]*model.PendantPrice, len(ids))
for rows.Next() {
pp := new(model.PendantPrice)
if err = rows.Scan(&pp.PID, &pp.TP, &pp.Price); err != nil {
err = errors.Wrap(err, "PendantPriceIDs row.Scan()")
return
}
ppm[pp.PID] = append(ppm[pp.PID], pp)
}
err = rows.Err()
return
}
// PendantGroupRefRanks pendant group ref pagesize by rank.
func (d *Dao) PendantGroupRefRanks(c context.Context, pn, ps int) (prs []*model.PendantGroupRef, err error) {
var (
rows *xsql.Rows
offset = (pn - 1) * ps
)
if rows, err = d.db.Query(c, _pdGroupRefRanksSQL, offset, ps); err != nil {
err = errors.Wrapf(err, "PendantGroupRefRanks d.db.Query(%d,%d)", offset, ps)
return
}
defer rows.Close()
for rows.Next() {
pr := new(model.PendantGroupRef)
if err = rows.Scan(&pr.GID, &pr.PID); err != nil {
err = errors.Wrap(err, "PendantGroupRefRanks row.Scan()")
return
}
prs = append(prs, pr)
}
err = rows.Err()
return
}
// PendantGroupPIDs pendant group ref pagesize.
func (d *Dao) PendantGroupPIDs(c context.Context, gid int64, pn, ps int) (pids []int64, err error) {
var (
rows *xsql.Rows
offset = (pn - 1) * ps
)
if rows, err = d.db.Query(c, _pdGroupRefsSQL, gid, offset, ps); err != nil {
err = errors.Wrapf(err, "PendantGroupPIDs d.db.Query(%d,%d,%d)", gid, offset, ps)
return
}
defer rows.Close()
var pid int64
for rows.Next() {
if err = rows.Scan(&pid); err != nil {
err = errors.Wrap(err, "PendantGroupPIDs row.Scan()")
return
}
pids = append(pids, pid)
}
err = rows.Err()
return
}
// PendantInfoID pendant info.
func (d *Dao) PendantInfoID(c context.Context, id int64) (pi *model.PendantInfo, err error) {
row := d.db.QueryRow(c, _pdInfoIDSQL, id)
if err != nil {
err = errors.Wrapf(err, "PendantInfoID d.db.QueryRow(%d)", id)
return
}
pi = &model.PendantInfo{}
if err = row.Scan(&pi.ID, &pi.Name, &pi.Image, &pi.ImageModel, &pi.Status, &pi.Rank); err != nil {
if err == sql.ErrNoRows {
err = nil
pi = nil
return
}
err = errors.Wrap(err, "PendantInfoID row.Scan")
}
return
}
// PendantInfoAllNoPage pendant info no page.
func (d *Dao) PendantInfoAllNoPage(c context.Context) (pis []*model.PendantInfo, err error) {
var rows *xsql.Rows
if rows, err = d.db.Query(c, _pdInfoAllNoPageSQL); err != nil {
err = errors.Wrap(err, "PendantInfoAllOnSale d.db.Query()")
return
}
defer rows.Close()
for rows.Next() {
pi := new(model.PendantInfo)
if err = rows.Scan(&pi.ID, &pi.Name, &pi.Image, &pi.ImageModel, &pi.Status, &pi.Rank); err != nil {
err = errors.Wrap(err, "PendantInfoAllOnSale row.Scan()")
return
}
pis = append(pis, pi)
}
err = rows.Err()
return
}
// BuildOrderInfoSQL build a order sql string.
func (d *Dao) BuildOrderInfoSQL(c context.Context, arg *model.ArgPendantOrder, tp string) (sql string, values []interface{}) {
values = make([]interface{}, 0, 5)
var (
cond []string
condStr string
)
if arg.UID != 0 {
cond = append(cond, "mid = ?")
values = append(values, arg.UID)
}
if arg.PID != 0 {
cond = append(cond, "pid = ?")
values = append(values, arg.PID)
}
if arg.Status != 0 {
cond = append(cond, "status = ?")
values = append(values, arg.Status)
}
if arg.PayID != "" {
cond = append(cond, "pay_id = ?")
values = append(values, arg.PayID)
}
if arg.Start != 0 {
cond = append(cond, "mtime >= ?")
values = append(values, arg.Start)
}
if arg.End != 0 {
cond = append(cond, "mtime <= ?")
values = append(values, arg.End)
}
if tp == "info" {
condStr = d.joinStrings(cond)
if condStr != "" {
sql = fmt.Sprintf(_orderHistorysSQL+" %s %s ", "WHERE", condStr, "ORDER BY mtime DESC LIMIT ?,?")
} else {
sql = fmt.Sprintf(_orderHistorysSQL+" %s ", condStr, "ORDER BY mtime DESC LIMIT ?,?")
}
values = append(values, (arg.PN-1)*arg.PS, arg.PS)
} else if tp == "count" {
condStr = d.joinStrings(cond)
if condStr != "" {
sql = fmt.Sprintf(_countOrderHistorysSQL+" %s", "WHERE", condStr)
} else {
sql = fmt.Sprintf(_countOrderHistorysSQL, condStr)
}
}
return
}
func (d *Dao) joinStrings(is []string) string {
if len(is) == 0 {
return ""
}
if len(is) == 1 {
return is[0]
}
var bfPool = sync.Pool{
New: func() interface{} {
return bytes.NewBuffer([]byte{})
},
}
buf := bfPool.Get().(*bytes.Buffer)
for _, i := range is {
buf.WriteString(i)
buf.WriteString(" AND ")
}
if buf.Len() > 0 {
buf.Truncate(buf.Len() - 4)
}
s := buf.String()
buf.Reset()
bfPool.Put(buf)
return s
}
// MaxOrderHistory max order history.
func (d *Dao) MaxOrderHistory(c context.Context) (max int64, err error) {
row := d.db.QueryRow(c, _maxOrderHistorysSQL)
if err != nil {
err = errors.Wrap(err, "MaxOrderHistory d.db.QueryRow()")
return
}
if err = row.Scan(&max); err != nil {
if err == sql.ErrNoRows {
err = nil
max = 0
return
}
err = errors.Wrap(err, "MaxOrderHistory row.Scan")
}
return
}
// CountOrderHistory count order history.
func (d *Dao) CountOrderHistory(c context.Context, arg *model.ArgPendantOrder) (total int64, err error) {
sqlstr, values := d.BuildOrderInfoSQL(c, arg, "count")
row := d.db.QueryRow(c, sqlstr, values...)
if err != nil {
err = errors.Wrap(err, "CountOrderHistory d.db.QueryRow()")
return
}
if err = row.Scan(&total); err != nil {
if err == sql.ErrNoRows {
err = nil
total = 0
return
}
err = errors.Wrap(err, "CountOrderHistory row.Scan")
}
return
}
// OrderHistorys get order historys.
func (d *Dao) OrderHistorys(c context.Context, arg *model.ArgPendantOrder) (pos []*model.PendantOrder, pids []int64, err error) {
var rows *xsql.Rows
sqlstr, values := d.BuildOrderInfoSQL(c, arg, "info")
if rows, err = d.db.Query(c, sqlstr, values...); err != nil {
err = errors.Wrap(err, "OrderHistorys d.db.Query()")
return
}
defer rows.Close()
for rows.Next() {
po := new(model.PendantOrder)
if err = rows.Scan(&po.UID, &po.OrderID, &po.PayID, &po.AppID, &po.Status, &po.PID, &po.TimeLength, &po.Cost, &po.BuyTime, &po.PayType); err != nil {
err = errors.Wrap(err, "OrderHistorys row.Scan()")
return
}
pos = append(pos, po)
pids = append(pids, po.PID)
}
err = rows.Err()
return
}
// PendantPKGs get pendant pkgs.
func (d *Dao) PendantPKGs(c context.Context, uid int64) (pkgs []*model.PendantPKG, err error) {
var rows *xsql.Rows
if rows, err = d.db.Query(c, _pdPKGsUIDSQL, uid); err != nil {
err = errors.Wrapf(err, "PendantPKGs d.db.Query(%d)", uid)
return
}
defer rows.Close()
for rows.Next() {
pkg := new(model.PendantPKG)
if err = rows.Scan(&pkg.UID, &pkg.PID, &pkg.Expires, &pkg.TP, &pkg.Status, &pkg.IsVip); err != nil {
err = errors.Wrap(err, "PendantPKGs row.Scan()")
return
}
pkgs = append(pkgs, pkg)
}
err = rows.Err()
return
}
// PendantPKGUIDs get pendant pkgs by muilti uid.
func (d *Dao) PendantPKGUIDs(c context.Context, uids []int64, pid int64) (pkgs []*model.PendantPKG, err error) {
var rows *xsql.Rows
if rows, err = d.db.Query(c, fmt.Sprintf(_pdPKGUIDsSQL, xstr.JoinInts(uids)), pid); err != nil {
err = errors.Wrapf(err, "PendantPKGUIDs d.db.Query(%s,%d)", xstr.JoinInts(uids), pid)
return
}
defer rows.Close()
for rows.Next() {
pkg := new(model.PendantPKG)
if err = rows.Scan(&pkg.ID, &pkg.UID, &pkg.PID, &pkg.Expires, &pkg.TP, &pkg.Status, &pkg.IsVip); err != nil {
err = errors.Wrap(err, "PendantPKGUIDs row.Scan()")
return
}
pkgs = append(pkgs, pkg)
}
err = rows.Err()
return
}
// PendantPKG get pendant in pkg.
func (d *Dao) PendantPKG(c context.Context, uid, pid int64) (pkg *model.PendantPKG, err error) {
row := d.db.QueryRow(c, _pdPKGUIDSQL, uid, pid)
if err != nil {
err = errors.Wrapf(err, "PendantPKG d.db.QueryRow(%d,%d)", uid, pid)
return
}
pkg = &model.PendantPKG{}
if err = row.Scan(&pkg.ID, &pkg.UID, &pkg.PID, &pkg.Expires, &pkg.TP, &pkg.Status, &pkg.IsVip); err != nil {
if err == sql.ErrNoRows {
err = nil
pkg = nil
return
}
err = errors.Wrap(err, "PendantPKG row.Scan")
}
return
}
// PendantEquipUID pendant equip by uid.
func (d *Dao) PendantEquipUID(c context.Context, uid int64) (pkg *model.PendantPKG, err error) {
row := d.db.QueryRow(c, _pdEquipUIDSQL, uid, time.Now().Unix())
if err != nil {
err = errors.Wrapf(err, "PendantEquipUID d.db.QueryRow(%d)", uid)
return
}
pkg = &model.PendantPKG{}
if err = row.Scan(&pkg.PID, &pkg.Expires); err != nil {
if err == sql.ErrNoRows {
err = nil
pkg = nil
return
}
err = errors.Wrap(err, "PendantEquipUID row.Scan")
}
return
}
// PendantOperLog get pendant operation log.
func (d *Dao) PendantOperLog(c context.Context, pn, ps int) (opers []*model.PendantOperLog, uids []int64, err error) {
var (
rows *xsql.Rows
offset = (pn - 1) * ps
)
if rows, err = d.db.Query(c, _pdOperationLogSQL, offset, ps); err != nil {
err = errors.Wrapf(err, "PendantOperLog d.db.Query(%d,%d)", offset, ps)
return
}
defer rows.Close()
for rows.Next() {
oper := new(model.PendantOperLog)
if err = rows.Scan(&oper.OID, &oper.Action, &oper.UID, &oper.PID, &oper.SourceType, &oper.CTime, &oper.MTime); err != nil {
err = errors.Wrap(err, "PendantOperLog row.Scan()")
return
}
opers = append(opers, oper)
uids = append(uids, oper.UID)
}
err = rows.Err()
return
}
// PendantOperationLogTotal pendant operation log total.
func (d *Dao) PendantOperationLogTotal(c context.Context) (count int64, err error) {
row := d.db.QueryRow(c, _pdOperationLogTotalSQL)
if err = row.Scan(&count); err != nil {
err = errors.Wrap(err, "d.dao.PendantOperationLogTotal")
}
return
}

View File

@@ -0,0 +1,54 @@
package dao
import (
"context"
"fmt"
gmc "go-common/library/cache/memcache"
)
const (
_prefixRedPointFlag = "r_p_f_%d"
)
func redPointFlagKey(mid int64) string {
return fmt.Sprintf(_prefixRedPointFlag, mid)
}
// PendantPointCache get new pendant info red point cache.
func (d *Dao) PendantPointCache(c context.Context, mid int64) (pid int64, err error) {
conn := d.mc.Get(c)
defer conn.Close()
item, err := conn.Get(redPointFlagKey(mid))
if err != nil {
if err == gmc.ErrNotFound {
err = nil
}
return
}
err = conn.Scan(item, &pid)
return
}
// SetPendantPointCache set red point cache.
func (d *Dao) SetPendantPointCache(c context.Context, mid, pid int64) (err error) {
var (
item = &gmc.Item{Key: redPointFlagKey(mid), Object: pid, Expiration: d.pointExpire, Flags: gmc.FlagJSON}
conn = d.mc.Get(c)
)
defer conn.Close()
err = conn.Set(item)
return
}
// DelPendantPointCache delete new pendant info red point cache.
func (d *Dao) DelPendantPointCache(c context.Context, mid int64) (err error) {
conn := d.mc.Get(c)
defer conn.Close()
if err = conn.Delete(redPointFlagKey(mid)); err != nil {
if err == gmc.ErrNotFound {
err = nil
}
}
return
}

View File

@@ -0,0 +1,54 @@
package dao
import (
"context"
"strconv"
"go-common/library/cache/redis"
"go-common/library/log"
)
const (
_pendantPKG = "pkg_"
_pendantEquip = "pe_"
)
func keyPendantPKG(uid int64) string {
return _pendantPKG + strconv.FormatInt(uid, 10)
}
func keyEquip(uid int64) string {
return _pendantEquip + strconv.FormatInt(uid, 10)
}
// DelPKGCache del package cache
func (d *Dao) DelPKGCache(c context.Context, uids []int64) (err error) {
var (
args = redis.Args{}
conn = d.redis.Get(c)
)
defer conn.Close()
for _, v := range uids {
args = args.Add(keyPendantPKG(v))
}
if err = conn.Send("DEL", args...); err != nil {
log.Error("conn.Send(DEL, %s) error(%v)", args, err)
}
return
}
// DelEquipsCache del batch equip cache .
func (d *Dao) DelEquipsCache(c context.Context, uids []int64) (err error) {
var (
args = redis.Args{}
conn = d.redis.Get(c)
)
defer conn.Close()
for _, v := range uids {
args = args.Add(keyEquip(v))
}
if err = conn.Send("DEL", args...); err != nil {
log.Error("conn.Send(DEL, %s) error(%v)", args, err)
}
return
}

View File

@@ -0,0 +1,22 @@
package dao
import (
"context"
"testing"
. "github.com/smartystreets/goconvey/convey"
)
func Test_DelPKGCache(t *testing.T) {
Convey("return someting", t, func() {
err := d.DelPKGCache(context.Background(), []int64{22, 11})
So(err, ShouldBeNil)
})
}
func Test_DelEquipsCache(t *testing.T) {
Convey("return someting", t, func() {
err := d.DelEquipsCache(context.Background(), []int64{22, 11})
So(err, ShouldBeNil)
})
}

View File

@@ -0,0 +1,375 @@
package dao
import (
"context"
"math/rand"
"testing"
"go-common/app/admin/main/usersuit/model"
. "github.com/smartystreets/goconvey/convey"
)
func Test_AddPendantGroup(t *testing.T) {
Convey("return someting", t, func() {
pg := &model.PendantGroup{
Name: "dasdasd",
Rank: 22,
}
gid, err := d.AddPendantGroup(context.Background(), pg)
So(err, ShouldBeNil)
So(gid, ShouldNotBeNil)
})
}
func Test_TxAddPendantGroupRef(t *testing.T) {
Convey("return someting", t, func() {
pr := &model.PendantGroupRef{
GID: 11,
PID: int64(rand.Int31()),
}
tx, err := d.BeginTran(context.Background())
So(err, ShouldBeNil)
effect, err := d.TxAddPendantGroupRef(tx, pr)
So(err, ShouldBeNil)
defer func() {
if err != nil || effect == 0 {
tx.Rollback()
return
}
tx.Commit()
}()
So(err, ShouldBeNil)
})
}
func Test_TxAddPendantInfo(t *testing.T) {
Convey("return someting", t, func() {
pi := &model.PendantInfo{
Name: "dasdasdsads",
Image: "dasdds",
ImageModel: "xxsss",
Rank: 11,
}
tx, err := d.BeginTran(context.Background())
if err != nil {
So(err, ShouldBeNil)
}
id, err := d.TxAddPendantInfo(tx, pi)
if err != nil {
So(err, ShouldBeNil)
}
defer func() {
if err != nil || id == 0 {
tx.Rollback()
return
}
tx.Commit()
}()
So(err, ShouldBeNil)
})
}
func Test_TxAddPendantPrices(t *testing.T) {
Convey("return someting", t, func() {
pp := &model.PendantPrice{
PID: 22,
TP: 1,
Price: 22,
}
tx, err := d.BeginTran(context.Background())
if err != nil {
So(err, ShouldBeNil)
}
effect, err := d.TxAddPendantPrices(tx, pp)
if err != nil {
So(err, ShouldBeNil)
}
defer func() {
if err != nil || effect == 0 {
tx.Rollback()
return
}
tx.Commit()
}()
So(err, ShouldBeNil)
})
}
func Test_AddPendantPKG(t *testing.T) {
Convey("return someting", t, func() {
pkg := &model.PendantPKG{
UID: int64(rand.Int31()),
PID: 11,
Expires: 12312323,
}
_, err := d.AddPendantPKG(context.Background(), pkg)
So(err, ShouldBeNil)
})
}
func Test_TxAddPendantPKGs(t *testing.T) {
uid := int64(rand.Int31())
Convey("return someting", t, func() {
var pkgs []*model.PendantPKG
pkgs = append(pkgs, &model.PendantPKG{UID: uid, PID: 11, Expires: 12312323}, &model.PendantPKG{UID: uid, PID: 22, Expires: 12312323})
tx, err := d.BeginTran(context.Background())
if err != nil {
So(err, ShouldBeNil)
}
effect, err := d.TxAddPendantPKGs(tx, pkgs)
if err != nil {
So(err, ShouldBeNil)
}
defer func() {
if err != nil || effect == 0 {
tx.Rollback()
return
}
tx.Commit()
}()
So(err, ShouldBeNil)
})
}
func Test_AddPendantEquip(t *testing.T) {
Convey("return someting", t, func() {
pkg := &model.PendantPKG{
UID: 22,
PID: 11,
Expires: 12312323,
}
_, err := d.AddPendantEquip(context.Background(), pkg)
So(err, ShouldBeNil)
})
}
func Test_AddPendantOperLog(t *testing.T) {
Convey("return someting", t, func() {
_, err := d.AddPendantOperLog(context.Background(), 1, []int64{1}, 1, "sdsadasd")
So(err, ShouldBeNil)
})
}
func Test_TxUpPendantGroupRef(t *testing.T) {
Convey("return someting", t, func() {
tx, err := d.BeginTran(context.Background())
if err != nil {
So(err, ShouldBeNil)
}
effect, err := d.TxUpPendantGroupRef(tx, 22, 11)
if err != nil {
So(err, ShouldBeNil)
}
defer func() {
if err != nil || effect == 0 {
tx.Rollback()
return
}
tx.Commit()
}()
So(err, ShouldBeNil)
})
}
func Test_TxUpPendantPKGs(t *testing.T) {
Convey("return someting", t, func() {
var pkgs []*model.PendantPKG
pkgs = append(pkgs, &model.PendantPKG{UID: 22, PID: 11, Expires: 12312323}, &model.PendantPKG{UID: 11, PID: 22, Expires: 12312323})
tx, err := d.BeginTran(context.Background())
if err != nil {
So(err, ShouldBeNil)
}
effect, err := d.TxUpPendantPKGs(tx, pkgs)
if err != nil {
So(err, ShouldBeNil)
}
defer func() {
if err != nil || effect == 0 {
tx.Rollback()
return
}
tx.Commit()
}()
So(err, ShouldBeNil)
})
}
func Test_UpPendantGroup(t *testing.T) {
Convey("return someting", t, func() {
pg := &model.PendantGroup{
Name: "weqweqw",
Rank: 2,
Status: 1,
ID: 22,
}
_, err := d.UpPendantGroup(context.Background(), pg)
So(err, ShouldBeNil)
})
}
func Test_UpPendantGroupStatus(t *testing.T) {
Convey("return someting", t, func() {
_, err := d.UpPendantGroupStatus(context.Background(), 22, 1)
So(err, ShouldBeNil)
})
}
func Test_TxUpPendantInfo(t *testing.T) {
Convey("return someting", t, func() {
pi := &model.PendantInfo{
Name: "dasdasdsads",
Image: "dasdds",
ImageModel: "xxsss",
Rank: 11,
ID: 22,
}
tx, err := d.BeginTran(context.Background())
if err != nil {
So(err, ShouldBeNil)
}
effect, err := d.TxUpPendantInfo(tx, pi)
if err != nil {
So(err, ShouldBeNil)
}
defer func() {
if err != nil || effect == 0 {
tx.Rollback()
return
}
tx.Commit()
}()
So(err, ShouldBeNil)
})
}
func Test_UpPendantInfoStatus(t *testing.T) {
Convey("return someting", t, func() {
_, err := d.UpPendantInfoStatus(context.Background(), 22, 1)
So(err, ShouldBeNil)
})
}
func Test_PendantInfoAll(t *testing.T) {
Convey("return someting", t, func() {
_, _, err := d.PendantInfoAll(context.Background(), 1, 2)
So(err, ShouldBeNil)
})
}
func Test_PendantGroupIDs(t *testing.T) {
Convey("return someting", t, func() {
_, err := d.PendantGroupIDs(context.Background(), []int64{11, 22})
So(err, ShouldBeNil)
})
}
func Test_PendantGroupID(t *testing.T) {
Convey("return someting", t, func() {
_, err := d.PendantGroupID(context.Background(), 12)
So(err, ShouldBeNil)
})
}
func Test_PendantInfoIDs(t *testing.T) {
Convey("return someting", t, func() {
_, _, err := d.PendantInfoIDs(context.Background(), []int64{11, 22})
So(err, ShouldBeNil)
})
}
func Test_PendantPriceIDs(t *testing.T) {
Convey("return someting", t, func() {
ppm, err := d.PendantPriceIDs(context.Background(), []int64{11, 22})
So(err, ShouldBeNil)
So(ppm, ShouldNotBeNil)
})
}
func Test_PendantGroupRefRanks(t *testing.T) {
Convey("return someting", t, func() {
_, err := d.PendantGroupRefRanks(context.Background(), 1, 2)
So(err, ShouldBeNil)
})
}
func Test_PendantGroupPIDs(t *testing.T) {
Convey("return someting", t, func() {
_, err := d.PendantGroupPIDs(context.Background(), 11, 1, 2)
So(err, ShouldBeNil)
})
}
func Test_PendantInfoID(t *testing.T) {
Convey("return someting", t, func() {
pi, err := d.PendantInfoID(context.Background(), 11)
So(err, ShouldBeNil)
So(pi, ShouldNotBeNil)
})
}
func Test_PendantInfoAllOnSale(t *testing.T) {
Convey("return someting", t, func() {
_, err := d.PendantInfoAllNoPage(context.Background())
So(err, ShouldBeNil)
})
}
func Test_CountOrderHistory(t *testing.T) {
Convey("return someting", t, func() {
arg := &model.ArgPendantOrder{}
_, err := d.CountOrderHistory(context.Background(), arg)
So(err, ShouldBeNil)
})
}
func Test_OrderHistorys(t *testing.T) {
Convey("return someting", t, func() {
arg := &model.ArgPendantOrder{}
_, _, err := d.OrderHistorys(context.Background(), arg)
So(err, ShouldBeNil)
})
}
func Test_PendantPKGs(t *testing.T) {
Convey("return someting", t, func() {
_, err := d.PendantPKGs(context.Background(), 112)
So(err, ShouldBeNil)
})
}
func Test_PendantPKGUIDs(t *testing.T) {
Convey("return someting", t, func() {
_, err := d.PendantPKGUIDs(context.Background(), []int64{11, 22}, 112)
So(err, ShouldBeNil)
})
}
func Test_PendantPKG(t *testing.T) {
Convey("return someting", t, func() {
_, err := d.PendantPKG(context.Background(), 11, 112)
So(err, ShouldBeNil)
})
}
func Test_PendantEquipUID(t *testing.T) {
Convey("return someting", t, func() {
_, err := d.PendantEquipUID(context.Background(), 11)
So(err, ShouldBeNil)
})
}
func Test_PendantOperLog(t *testing.T) {
Convey("return someting", t, func() {
_, _, err := d.PendantOperLog(context.Background(), 1, 2)
So(err, ShouldBeNil)
})
}
func Test_PendantOperationLogTotal(t *testing.T) {
Convey("return someting", t, func() {
total, err := d.PendantOperationLogTotal(context.Background())
So(err, ShouldBeNil)
So(total, ShouldNotBeNil)
})
}

View File

@@ -0,0 +1,74 @@
package dao
import (
"context"
"crypto/hmac"
"crypto/sha1"
"encoding/base64"
"fmt"
"hash"
"io"
"net/http"
"strconv"
"go-common/library/log"
)
const (
_uploadURL = "/bfs/%s/%s"
_template = "%s\n%s\n%s\n%d\n"
_method = "PUT"
)
// Upload upload picture or log file to bfs
func (d *Dao) Upload(c context.Context, fileName, fileType string, expire int64, body io.Reader) (location string, err error) {
var (
url string
req *http.Request
resp *http.Response
code int
)
client := &http.Client{}
url = fmt.Sprintf(d.bfs+_uploadURL, d.bucket, fileName)
if req, err = http.NewRequest(_method, url, body); err != nil {
log.Error("http.NewRequest() Upload(%v) error(%v)", url, err)
return
}
authorization := authorize(d.key, d.secret, _method, d.bucket, fileName, expire)
req.Header.Set("Host", d.bfs)
req.Header.Add("Date", fmt.Sprint(expire))
req.Header.Add("Authorization", authorization)
req.Header.Add("Content-Type", fileType)
resp, err = client.Do(req)
if err != nil {
log.Error("resp.Do(%s) error(%v)", url, err)
return
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
err = fmt.Errorf("status code error:%v", resp.StatusCode)
return
}
code, err = strconv.Atoi(resp.Header.Get("code"))
if err != nil || code != http.StatusOK {
err = fmt.Errorf("response code error:%v", code)
return
}
location = resp.Header.Get("Location")
return
}
// authorize returns authorization for upload file to bfs
func authorize(key, secret, method, bucket, file string, expire int64) (authorization string) {
var (
content string
mac hash.Hash
signature string
)
content = fmt.Sprintf(_template, method, bucket, file, expire)
mac = hmac.New(sha1.New, []byte(secret))
mac.Write([]byte(content))
signature = base64.StdEncoding.EncodeToString(mac.Sum(nil))
authorization = fmt.Sprintf("%s:%s:%d", key, signature, expire)
return
}

View File

@@ -0,0 +1,56 @@
package(default_visibility = ["//visibility:public"])
load(
"@io_bazel_rules_go//go:def.bzl",
"go_test",
"go_library",
)
go_test(
name = "go_default_test",
srcs = ["invite_test.go"],
embed = [":go_default_library"],
rundir = ".",
tags = ["automanaged"],
deps = ["//vendor/github.com/smartystreets/goconvey/convey:go_default_library"],
)
go_library(
name = "go_default_library",
srcs = [
"common.go",
"http.go",
"invite.go",
"medal.go",
"pendant.go",
"upload.go",
],
importpath = "go-common/app/admin/main/usersuit/http",
tags = ["automanaged"],
visibility = ["//visibility:public"],
deps = [
"//app/admin/main/usersuit/conf:go_default_library",
"//app/admin/main/usersuit/model:go_default_library",
"//app/admin/main/usersuit/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/middleware/permit:go_default_library",
"//library/net/metadata:go_default_library",
"//library/xstr: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,29 @@
package http
import (
"go-common/app/admin/main/usersuit/model"
bm "go-common/library/net/http/blademaster"
)
func httpData(c *bm.Context, data interface{}, pager *model.Pager) {
res := make(map[string]interface{})
if data == nil {
data = struct{}{}
}
if pager == nil {
pager = &model.Pager{}
}
res["data"] = data
res["pager"] = &model.Pager{
Total: pager.Total,
PN: pager.PN,
PS: pager.PS,
Order: pager.Order,
Sort: pager.Sort,
}
c.JSONMap(res, nil)
}
func httpCode(c *bm.Context, err error) {
c.JSON(nil, err)
}

View File

@@ -0,0 +1,91 @@
package http
import (
"net/http"
"go-common/app/admin/main/usersuit/conf"
"go-common/app/admin/main/usersuit/service"
"go-common/library/log"
bm "go-common/library/net/http/blademaster"
"go-common/library/net/http/blademaster/middleware/permit"
)
var (
svc *service.Service
authSvc *permit.Permit
)
// Init fot init open service
func Init(c *conf.Config, s *service.Service) {
svc = s
authSvc = permit.New(c.Auth)
engine := bm.DefaultServer(c.BM)
innerRouter(engine)
// init internal server
if err := engine.Start(); err != nil {
log.Error("engine.Start error(%v)", err)
panic(err)
}
}
// innerRouter
func innerRouter(e *bm.Engine) {
// ping monitor
e.Ping(ping)
// internal api
bg := e.Group("/x/admin/usersuit")
{
// invite
bg.POST("/invite/generate", authSvc.Permit("INVITE_INFO_ADMIN"), generate)
bg.GET("/invite/list", authSvc.Permit("INVITE_INFO_SEARCH"), list)
// new pendant
bg.GET("/pendant/info/list", authSvc.Permit("PENDANT_INFO_LIST"), pendantInfoList) // 挂件列表(带分页)
bg.GET("/pendant/info/id", authSvc.Permit("PENDANT_INFO_ID"), pendantInfoID) // 挂件详情
bg.GET("/pendant/group/id", authSvc.Permit("PENDANT_GROUP_ID"), pendantGroupID) // 挂件分组详情
bg.GET("/pendant/group/list", authSvc.Permit("PENDANT_GROUP_LIST"), pendantGroupList) // 挂件分组列表(带分页)
bg.GET("/pendant/group/all", authSvc.Permit("PENDANT_GROUP_ALL"), pendantGroupAll) // 挂件分组列表(不带分页) 这个筛选列表可不加权限
bg.GET("/pendant/info/all/no/page", authSvc.Permit("PENDANT_INFO_ALL_NO_PAGE"), pendantInfoAllNoPage) // 在售挂件(不带分页) 这个筛选列表可不加权限
bg.POST("/pendant/add/info", authSvc.Permit("PENDANT_ADD_INFO"), addPendantInfo) // 添加挂件
bg.POST("/pendant/up/info", authSvc.Permit("PENDANT_UP_INFO"), upPendantInfo) // 更新挂件
bg.POST("/pendant/up/group/status", authSvc.Permit("PENDANT_UP_GROUP_STATUS"), upPendantGroupStatus) // 更新挂件分组状态
bg.POST("/pendant/up/info/status", authSvc.Permit("PENDANT_UP_INFO_STATUS"), upPendantInfoStatus) // 更新挂件状态
bg.POST("/pendant/add/group", authSvc.Permit("PENDANT_ADD_GROUP"), addPendantGroup) // 添加挂件分组
bg.POST("/pendant/up/group", authSvc.Permit("PENDANT_UP_GROUP"), upPendantGroup) // 更新挂件分组
bg.GET("/pendant/orders", authSvc.Permit("PENDANT_ORDERS"), pendantOrders) // 挂件订单列表
bg.POST("/pendant/equip", authSvc.Permit("PENDANT_EQUIP"), equipPendant) // 装备挂件
bg.GET("/user/pendant/pkg", authSvc.Permit("USER_PENDANT_PKG"), userPendantPKG) // 用户可用挂件背包列表
bg.GET("/user/pkg/details", authSvc.Permit("USER_PKG_DETAILS"), userPKGDetails) // 用户所属挂件详情
bg.POST("/pendant/up/pkg", authSvc.Permit("PENDANT_UP_PKG"), upPendantPKG) // 更新或激活用户挂件
bg.POST("/pendant/mutli/send", authSvc.Permit("PENDANT_MUTLI_SEND"), mutliSend) // 多用户发送挂件
bg.GET("/pendant/oper/log", authSvc.Permit("PENDANT_OPER_LOG"), pendantOperlog) // 发放挂件操作日志
bg.POST("/face/upload", upload) // 上传图片
//medal
bg.GET("/medal", authSvc.Permit("MEDAL_INFO_LIST"), medalList) // 勋章列表
bg.GET("/medal/id", authSvc.Permit("MEDAL_INFO_ID"), medalView) // 勋章查看
bg.POST("/medal/add", authSvc.Permit("MEDAL_INFO_ADD"), medalAdd) // 勋章添加
bg.POST("/medal/edit", authSvc.Permit("MEDAL_INFO_EDIT"), medalEdit) // 勋章编辑
bg.GET("/medal/group", authSvc.Permit("MEDAL_GROUP_LIST"), medalGroup) // 勋章分组列表
bg.GET("/medal/group/view", authSvc.Permit("MEDAL_GROUP_VIEW"), medalGroupView) // 勋章分组查看单个
bg.GET("/medal/group/parent", authSvc.Permit("MEDAL_GROUP_PARENT"), medalGroupParent) // 勋章父辈分组列表
bg.POST("/medal/group/add", authSvc.Permit("MEDAL_GROUP_ADD"), medalGroupAdd) // 勋章分组添加
bg.POST("/medal/group/edit", authSvc.Permit("MEDAL_GROUP_EDIT"), medalGroupEdit) // 勋章分组编辑
bg.GET("/medal/member/mid", authSvc.Permit("MEDAL_MEMBER_MID"), medalMemberMID) // 勋章会员管理
bg.POST("/medal/member/edit", authSvc.Permit("MEDAL_MEMBER_EDIT"), medalOwnerUpActivated) // 勋章会员编辑激活
bg.GET("/medal/member/add/list", authSvc.Permit("MEDAL_MEMBER_ADD_LIST"), medalMemberAddList) // 勋章会员可添加列表
bg.POST("/medal/member/add", authSvc.Permit("MEDAL_MEMBER_ADD"), medalMemberAdd) // 勋章会员添加
bg.POST("/medal/member/del", authSvc.Permit("MEDAL_MEMBER_DEL"), medalMemberDel) // 勋章会员删除
bg.POST("/medal/batch/add", authSvc.Permit("MEDAL_BATCH_ADD"), medalBatchAdd) // 勋章批量添加
bg.GET("/medal/oper/log", authSvc.Permit("MEDAL_OPER_LOG"), medalOperlog) // 勋章操作日志
}
}
// ping check server ok.
func ping(c *bm.Context) {
err := svc.Ping(c)
if err != nil {
log.Error("usersuit admin ping error")
c.AbortWithStatus(http.StatusServiceUnavailable)
}
}

View File

@@ -0,0 +1,132 @@
package http
import (
"strconv"
"time"
"go-common/library/ecode"
"go-common/library/log"
bm "go-common/library/net/http/blademaster"
)
const (
_format = "2006-01-02"
)
var (
_loc = time.Now().Location()
)
// generate generate invite code in batches.
func generate(c *bm.Context) {
var (
err error
params = c.Request.Form
)
numStr := params.Get("num")
if numStr == "" {
httpCode(c, ecode.RequestErr)
return
}
num, err := strconv.ParseInt(numStr, 10, 64)
if err != nil {
httpCode(c, ecode.RequestErr)
return
}
midStr := params.Get("mid")
if midStr == "" {
httpCode(c, ecode.RequestErr)
return
}
mid, err := strconv.ParseInt(midStr, 10, 64)
if err != nil {
httpCode(c, ecode.RequestErr)
return
}
expireDayStr := params.Get("expire")
if expireDayStr == "" {
httpCode(c, ecode.RequestErr)
return
}
expireDay, err := strconv.ParseInt(expireDayStr, 10, 64)
if err != nil {
httpCode(c, ecode.RequestErr)
return
}
invs, err := svc.Generate(c, mid, num, expireDay)
if err != nil {
log.Error("service.Generate(%d, %d, %d) error(%v)", mid, num, expireDay, err)
httpCode(c, err)
return
}
httpData(c, invs, nil)
}
// list get invite codes range from and to.
func list(c *bm.Context) {
params := c.Request.Form
midStr := params.Get("mid")
if midStr == "" {
httpCode(c, ecode.RequestErr)
return
}
mid, err := strconv.ParseInt(midStr, 10, 64)
if err != nil {
httpCode(c, ecode.RequestErr)
return
}
fromStr := params.Get("from")
toStr := params.Get("to")
if fromStr == "" || toStr == "" {
httpCode(c, ecode.RequestErr)
return
}
from, to, ok := rangeDate(fromStr, toStr)
if !ok {
httpCode(c, ecode.RequestErr)
return
}
fromTs := from.Unix()
toTs := to.Unix()
if fromTs < 0 || toTs < 0 || fromTs > toTs {
httpCode(c, ecode.RequestErr)
return
}
invs, err := svc.List(c, mid, fromTs, toTs)
if err != nil {
log.Error("service.List(%d, %d, %d) error(%v)", mid, from, to, err)
httpCode(c, err)
return
}
httpData(c, invs, nil)
}
func rangeDate(fromStr, toStr string) (from, to time.Time, ok bool) {
ok = true
if fromStr == "" || toStr == "" {
ok = false
return
}
fromDate, err := time.ParseInLocation(_format, fromStr, _loc)
if err != nil {
ok = false
return
}
toDate, err := time.ParseInLocation(_format, toStr, _loc)
if err != nil {
ok = false
return
}
from = time.Date(fromDate.Year(), fromDate.Month(), fromDate.Day(), 0, 0, 0, 0, fromDate.Location())
to = time.Date(toDate.Year(), toDate.Month(), toDate.Day(), 23, 59, 59, 0, toDate.Location())
return
}

View File

@@ -0,0 +1,23 @@
package http
import (
"testing"
. "github.com/smartystreets/goconvey/convey"
)
const (
_outFormat = "2006-01-02 15:04:05"
)
func TestInit(t *testing.T) {
Convey("range when from str equal to to str", t, func() {
fromStr := "2017-12-25"
toStr := "2017-12-25"
from, to, ok := rangeDate(fromStr, toStr)
So(ok, ShouldEqual, true)
So(from.Format(_outFormat), ShouldEqual, "2017-12-25 00:00:00")
So(to.Format(_outFormat), ShouldEqual, "2017-12-25 23:59:59")
So(to.Unix()-from.Unix(), ShouldEqual, 86399)
})
}

View File

@@ -0,0 +1,299 @@
package http
import (
"fmt"
"strconv"
"go-common/app/admin/main/usersuit/model"
"go-common/library/ecode"
"go-common/library/log"
bm "go-common/library/net/http/blademaster"
)
// medal.
func medalList(c *bm.Context) {
var (
err error
res []*model.MedalInfo
)
if res, err = svc.Medal(c); err != nil {
httpCode(c, err)
return
}
httpData(c, res, nil)
}
// medalView .
func medalView(c *bm.Context) {
arg := new(struct {
ID int64 `form:"id" validate:"required"`
})
if err := c.Bind(arg); err != nil {
return
}
var (
err error
np *model.MedalInfo
)
if np, err = svc.MedalView(c, arg.ID); err != nil {
httpCode(c, err)
return
}
np.Image = "http://i0.hdslb.com" + np.Image
np.ImageSmall = "http://i0.hdslb.com" + np.ImageSmall
httpData(c, np, nil)
}
// medalAdd add medal .
func medalAdd(c *bm.Context) {
var (
err error
)
arg := new(model.Medal)
if err = c.Bind(arg); err != nil {
return
}
if err = svc.AddMedal(c, arg); err != nil {
httpCode(c, err)
return
}
httpCode(c, nil)
}
func medalEdit(c *bm.Context) {
var (
err error
)
arg := new(model.Medal)
if err = c.Bind(arg); err != nil {
return
}
if err = svc.UpMedal(c, arg.ID, arg); err != nil {
httpCode(c, err)
return
}
httpCode(c, nil)
}
func medalGroup(c *bm.Context) {
var (
err error
res []*model.MedalGroup
)
if res, err = svc.MedalGroupInfo(c); err != nil {
httpCode(c, err)
return
}
httpData(c, res, nil)
}
func medalGroupView(c *bm.Context) {
arg := new(struct {
ID int64 `form:"id" validate:"required"`
})
if err := c.Bind(arg); err != nil {
return
}
var (
err error
res *model.MedalGroup
)
if res, err = svc.MedalGroupByGid(c, arg.ID); err != nil {
httpCode(c, err)
return
}
httpData(c, res, nil)
}
func medalGroupParent(c *bm.Context) {
var (
err error
res []*model.MedalGroup
)
if res, err = svc.MedalGroupParent(c); err != nil {
httpCode(c, err)
return
}
httpData(c, res, nil)
}
func medalGroupAdd(c *bm.Context) {
var (
err error
)
arg := new(model.MedalGroup)
if err = c.Bind(arg); err != nil {
return
}
if err = svc.MedalGroupAdd(c, arg); err != nil {
httpCode(c, err)
return
}
httpCode(c, nil)
}
func medalGroupEdit(c *bm.Context) {
var (
err error
)
arg := new(model.MedalGroup)
if err = c.Bind(arg); err != nil {
return
}
if err = svc.MedalGroupUp(c, arg.ID, arg); err != nil {
httpCode(c, err)
return
}
httpCode(c, nil)
}
func medalMemberMID(c *bm.Context) {
arg := new(struct {
MID int64 `form:"mid" validate:"required"`
})
if err := c.Bind(arg); err != nil {
return
}
var (
err error
res []*model.MedalMemberMID
)
if res, err = svc.MedalOwner(c, arg.MID); err != nil {
httpCode(c, err)
return
}
httpData(c, res, nil)
}
func medalOwnerUpActivated(c *bm.Context) {
arg := new(struct {
ID int64 `form:"id" validate:"required"`
MID int64 `form:"mid" validate:"required"`
})
if err := c.Bind(arg); err != nil {
return
}
var (
err error
)
if err = svc.MedalOwnerUpActivated(c, arg.MID, arg.ID); err != nil {
httpCode(c, err)
return
}
httpCode(c, nil)
}
func medalMemberAddList(c *bm.Context) {
arg := new(struct {
MID int64 `form:"mid" validate:"required"`
})
if err := c.Bind(arg); err != nil {
return
}
var (
err error
res []*model.MedalMemberAddList
)
if res, err = svc.MedalOwnerAddList(c, arg.MID); err != nil {
httpCode(c, err)
return
}
httpData(c, res, nil)
}
func medalMemberAdd(c *bm.Context) {
arg := new(struct {
MID int64 `form:"mid" validate:"required"`
NID int64 `form:"nid" validate:"required"`
Title string `form:"title"`
Message string `form:"message"`
OID int64 `form:"oper_id" validate:"required"`
})
if err := c.Bind(arg); err != nil {
return
}
var (
err error
)
if err = svc.MedalOwnerAdd(c, arg.MID, arg.NID, arg.Title, arg.Message, arg.OID); err != nil {
httpCode(c, err)
return
}
httpCode(c, nil)
}
func medalMemberDel(c *bm.Context) {
arg := new(struct {
MID int64 `form:"mid" validate:"required"`
NID int64 `form:"nid" validate:"required"`
IsDel int8 `form:"is_del"`
Title string `form:"title"`
Message string `form:"message"`
})
if err := c.Bind(arg); err != nil {
return
}
var (
err error
)
if err = svc.MedalOwnerDel(c, arg.MID, arg.NID, arg.IsDel, arg.Title, arg.Message); err != nil {
httpCode(c, err)
return
}
httpCode(c, nil)
}
func medalBatchAdd(c *bm.Context) {
var (
err error
nid int64
)
f, h, err := c.Request.FormFile("file")
if err != nil {
httpCode(c, ecode.RequestErr)
return
}
defer f.Close()
params := c.Request.Form
nidStr := params.Get("nid")
nid, err = strconv.ParseInt(nidStr, 10, 64)
if err != nil || nid <= 0 {
fmt.Printf("nid:%+v\n", nid)
httpCode(c, ecode.RequestErr)
return
}
msg, err := svc.BatchAdd(c, nid, f, h)
if err != nil || msg != "" {
log.Error("svc.BatchAdd error(%v), msg(%v)", err, msg)
httpCode(c, ecode.ServerErr)
return
}
res := new(struct {
Message string `form:"message"`
})
res.Message = msg
httpData(c, res, nil)
}
func medalOperlog(c *bm.Context) {
arg := new(struct {
PN int `form:"pn"`
PS int `form:"ps"`
MID int64 `form:"mid" validate:"required"`
})
arg.PN, arg.PS = 1, 20
if err := c.Bind(arg); err != nil {
return
}
opers, pager, err := svc.MedalOperlog(c, arg.MID, arg.PN, arg.PS)
if err != nil {
log.Error("svc.MedalOperlog(%+v) err(%v)", arg, err)
httpCode(c, err)
return
}
if len(opers) == 0 {
httpData(c, nil, pager)
return
}
httpData(c, opers, pager)
}

View File

@@ -0,0 +1,391 @@
package http
import (
"encoding/csv"
"io/ioutil"
"strconv"
"strings"
"go-common/app/admin/main/usersuit/model"
"go-common/library/ecode"
"go-common/library/log"
bm "go-common/library/net/http/blademaster"
"go-common/library/net/metadata"
"go-common/library/xstr"
)
func pendantInfoList(c *bm.Context) {
arg := new(model.ArgPendantGroupList)
arg.PN, arg.PS = 1, 20
if err := c.Bind(arg); err != nil {
return
}
pis, pager, err := svc.PendantInfoList(c, arg)
if err != nil {
log.Error("svc.PendantInfoList(%+v) err(%v)", arg, err)
return
}
if len(pis) == 0 {
httpData(c, nil, pager)
return
}
httpData(c, pis, pager)
}
func pendantInfoID(c *bm.Context) {
arg := new(struct {
PID int64 `form:"pid" validate:"required"`
GID int64 `form:"gid" validate:"required"`
})
if err := c.Bind(arg); err != nil {
return
}
pi, err := svc.PendantInfoID(c, arg.PID, arg.GID)
if err != nil {
log.Error("svc.PendantInfoID(%+v) err(%v)", arg, err)
httpCode(c, err)
return
}
httpData(c, pi, nil)
}
func pendantGroupID(c *bm.Context) {
arg := new(struct {
GID int64 `form:"gid" validate:"required"`
})
if err := c.Bind(arg); err != nil {
return
}
pg, err := svc.PendantGroupID(c, arg.GID)
if err != nil {
log.Error("svc.PendantGroupID(%+v) err(%v)", arg, err)
return
}
httpData(c, pg, nil)
}
func pendantGroupList(c *bm.Context) {
arg := new(model.ArgPendantGroupList)
arg.PN, arg.PS = 1, 20
if err := c.Bind(arg); err != nil {
return
}
pgs, pager, err := svc.PendantGroupList(c, arg)
if err != nil {
log.Error("svc.PendantGroupList(%+v) err(%v)", arg, err)
httpCode(c, err)
return
}
if len(pgs) == 0 {
httpData(c, nil, pager)
return
}
httpData(c, pgs, pager)
}
func pendantGroupAll(c *bm.Context) {
pgs, err := svc.PendantGroupAll(c)
if err != nil {
log.Error("svc.PendantGroupAll() err(%v)", err)
httpCode(c, err)
return
}
httpData(c, pgs, nil)
}
func pendantInfoAllNoPage(c *bm.Context) {
pis, err := svc.PendantInfoAllNoPage(c)
if err != nil {
log.Error("svc.pendantInfoAllNoPage() err(%v)", err)
httpCode(c, err)
return
}
httpData(c, pis, nil)
}
func addPendantInfo(c *bm.Context) {
arg := new(model.ArgPendantInfo)
if err := c.Bind(arg); err != nil {
return
}
err := svc.AddPendantInfo(c, arg)
if err != nil {
log.Error("svc.AddPendantInfo(%+v) err(%v)", arg, err)
httpCode(c, err)
return
}
httpCode(c, nil)
}
func upPendantInfo(c *bm.Context) {
arg := new(model.ArgPendantInfo)
if err := c.Bind(arg); err != nil {
return
}
err := svc.UpPendantInfo(c, arg)
if err != nil {
log.Error("svc.UpPendantInfo(%+v) err(%v)", arg, err)
httpCode(c, err)
return
}
httpCode(c, nil)
}
func upPendantGroupStatus(c *bm.Context) {
arg := new(struct {
GID int64 `form:"gid" validate:"required"`
Status int8 `form:"status"`
})
if err := c.Bind(arg); err != nil {
return
}
err := svc.UpPendantGroupStatus(c, arg.GID, arg.Status)
if err != nil {
log.Error("svc.UpPendantGroupStatus(%+v) err(%v)", arg, err)
httpCode(c, err)
return
}
httpCode(c, nil)
}
func upPendantInfoStatus(c *bm.Context) {
arg := new(struct {
PID int64 `form:"pid" validate:"required"`
Status int8 `form:"status"`
})
if err := c.Bind(arg); err != nil {
return
}
err := svc.UpPendantInfoStatus(c, arg.PID, arg.Status)
if err != nil {
log.Error("svc.UpPendantInfoStatus(%+v) err(%v)", arg, err)
httpCode(c, err)
return
}
httpCode(c, nil)
}
func addPendantGroup(c *bm.Context) {
arg := new(model.ArgPendantGroup)
if err := c.Bind(arg); err != nil {
return
}
err := svc.AddPendantGroup(c, arg)
if err != nil {
log.Error("svc.AddPendantGroup(%+v) err(%v)", arg, err)
httpCode(c, err)
return
}
httpCode(c, nil)
}
func upPendantGroup(c *bm.Context) {
arg := new(model.ArgPendantGroup)
if err := c.Bind(arg); err != nil {
return
}
err := svc.UpPendantGroup(c, arg)
if err != nil {
log.Error("svc.UpPendantGroup(%+v) err(%v)", arg, err)
httpCode(c, err)
return
}
httpCode(c, nil)
}
func pendantOrders(c *bm.Context) {
arg := new(model.ArgPendantOrder)
arg.PN, arg.PS = 1, 20
if err := c.Bind(arg); err != nil {
return
}
pos, pager, err := svc.PendantOrders(c, arg)
if err != nil {
log.Error("svc.PendantOrders(%+v) err(%v)", arg, err)
httpCode(c, err)
return
}
if len(pos) == 0 {
httpData(c, nil, pager)
return
}
httpData(c, pos, pager)
}
func equipPendant(c *bm.Context) {
arg := new(struct {
UID int64 `form:"uid" validate:"required"`
PID int64 `form:"pid" validate:"required"`
})
if err := c.Bind(arg); err != nil {
return
}
err := svc.EquipPendant(c, arg.UID, arg.PID)
if err != nil {
log.Error("svc.EquipPendant(%+v) err(%v)", arg, err)
httpCode(c, err)
return
}
httpCode(c, nil)
}
func userPendantPKG(c *bm.Context) {
arg := new(struct {
UID int64 `form:"uid" validate:"required"`
})
if err := c.Bind(arg); err != nil {
return
}
pkg, equip, err := svc.PendantPKG(c, arg.UID)
if err != nil {
log.Error("svc.PendantPKG(%+v) err(%v)", arg, err)
httpCode(c, err)
return
}
httpData(c, map[string]interface{}{
"pkg": pkg,
"equip": equip,
}, nil)
}
func userPKGDetails(c *bm.Context) {
arg := new(struct {
UID int64 `form:"uid" validate:"required"`
PID int64 `form:"pid" validate:"required"`
})
if err := c.Bind(arg); err != nil {
return
}
pkgs, err := svc.UserPKGDetails(c, arg.UID, arg.PID)
if err != nil {
log.Error("svc.UserPKGDetails(%+v) err(%v)", arg, err)
httpCode(c, err)
return
}
httpData(c, pkgs, nil)
}
func upPendantPKG(c *bm.Context) {
arg := new(model.ArgPendantPKG)
if err := c.Bind(arg); err != nil {
return
}
msg := &model.SysMsg{IsMsg: arg.IsMsg, Type: arg.Type, Title: arg.Title, Content: arg.Content, RemoteIP: metadata.String(c, metadata.RemoteIP)}
err := svc.UpPendantPKG(c, arg.UID, arg.PID, arg.Day, msg, arg.OID)
if err != nil {
log.Error("svc.UpPendantPKG(%+v) err(%v)", arg, err)
httpCode(c, err)
return
}
httpCode(c, nil)
}
// migrate old pedant info to new db.
func mutliSend(c *bm.Context) {
var (
err error
data []byte
uids []int64
)
file, _, err := c.Request.FormFile("file")
if err != nil {
log.Error("upload err(%v)", err)
httpCode(c, err)
return
}
defer file.Close()
data, err = ioutil.ReadAll(file)
if err != nil {
log.Error("ioutil.ReadAll err(%v)", err)
return
}
r := csv.NewReader(strings.NewReader(string(data)))
r.Comma = ','
records, err := r.ReadAll()
if err != nil {
log.Error("r.ReadAll() err(%v)", err)
}
var (
uid int64
muids = make(map[int64]struct{}, len(records))
)
for _, v := range records {
if v[0] == "" {
continue
}
if uid, err = strconv.ParseInt(v[0], 10, 64); err != nil {
log.Error("strconv.ParseInt err(%v)", err)
continue
}
if _, ok := muids[uid]; ok {
continue
}
muids[uid] = struct{}{}
uids = append(uids, uid)
}
if len(uids) == 0 {
log.Warn("uids is nothing to send pendant")
httpCode(c, ecode.RequestErr)
return
}
if len(uids) > 1000 {
httpCode(c, ecode.PendantAboveSendMaxLimit)
return
}
params := c.Request.Form
pidStr := params.Get("pid")
dayStr := params.Get("day")
isMsgStr := params.Get("is_msg")
title := params.Get("title")
content := params.Get("content")
operStr := params.Get("oper_id")
pid, err := strconv.ParseInt(pidStr, 10, 64)
if err != nil {
httpCode(c, ecode.RequestErr)
return
}
day, err := strconv.ParseInt(dayStr, 10, 64)
if err != nil {
httpCode(c, ecode.RequestErr)
return
}
isMsg, err := strconv.ParseBool(isMsgStr)
if err != nil {
httpCode(c, ecode.RequestErr)
return
}
oid, err := strconv.ParseInt(operStr, 10, 64)
if err != nil {
httpCode(c, ecode.RequestErr)
return
}
msg := &model.SysMsg{IsMsg: isMsg, Type: model.MsgTypeCustom, Title: title, Content: content, RemoteIP: metadata.String(c, metadata.RemoteIP)}
if err = svc.MutliSendPendant(c, uids, pid, day, msg, oid); err != nil {
log.Error("svc.MutliSendPendant(%s,%d,%d,%v,%d) err(%v)", xstr.JoinInts(uids), pid, day, msg, oid, err)
httpCode(c, err)
return
}
httpCode(c, nil)
}
func pendantOperlog(c *bm.Context) {
arg := new(struct {
PN int `form:"pn"`
PS int `form:"ps"`
})
arg.PN, arg.PS = 1, 20
if err := c.Bind(arg); err != nil {
return
}
opers, pager, err := svc.PendantOperlog(c, arg.PN, arg.PS)
if err != nil {
log.Error("svc.PendantOperlog(%+v) err(%v)", arg, err)
httpCode(c, err)
return
}
if len(opers) == 0 {
httpData(c, nil, pager)
return
}
httpData(c, opers, pager)
}

View File

@@ -0,0 +1,43 @@
package http
import (
"bytes"
"io/ioutil"
"net/http"
"time"
"go-common/library/log"
bm "go-common/library/net/http/blademaster"
)
func upload(c *bm.Context) {
imageFile, _, err := c.Request.FormFile("file")
if err != nil {
log.Error("upload err(%v)", err)
httpCode(c, err)
return
}
defer imageFile.Close()
bs, err := ioutil.ReadAll(imageFile)
if err != nil {
log.Error("ioutil.ReadAll err(%v)", err)
httpCode(c, err)
return
}
filetype := http.DetectContentType(bs)
// var extension string
switch filetype {
case "image/jpeg", "image/jpg", "image/gif", "image/png", "application/pdf":
default:
log.Warn("unknown filetype(%s) ", filetype)
return
}
//重新格式化文件名
local, err := svc.Upload(c, "", filetype, time.Now().Unix(), bytes.NewReader(bs))
if err != nil {
log.Error("svc.Upload error(%v)", err)
httpCode(c, err)
return
}
httpData(c, local, nil)
}

View File

@@ -0,0 +1,41 @@
package(default_visibility = ["//visibility:public"])
load(
"@io_bazel_rules_go//go:def.bzl",
"go_library",
)
go_library(
name = "go_default_library",
srcs = [
"invite.go",
"log.go",
"manager.go",
"medal.go",
"msg.go",
"notify.go",
"param.go",
"pendant.go",
],
importpath = "go-common/app/admin/main/usersuit/model",
tags = ["automanaged"],
visibility = ["//visibility:public"],
deps = [
"//app/service/main/account/model:go_default_library",
"//library/time: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,123 @@
package model
import (
"net"
"strconv"
accmdl "go-common/app/service/main/account/model"
xtime "go-common/library/time"
)
const (
// StatusOK status ok
StatusOK = 0
// StatusUsed status used
StatusUsed = 1
// StatusExpires status expires
StatusExpires = 2
)
// Invite invite.
type Invite struct {
Status int64 `json:"status"`
Mid int64 `json:"mid"`
Code string `json:"invite_code"`
IP uint32 `json:"-"` // legacy IP field
IPng []byte `json:"-"`
Ctime xtime.Time `json:"buy_time"`
Expires int64 `json:"expires"`
Imid int64 `json:"invited_mid,omitempty"`
UsedAt int64 `json:"used_at,omitempty"`
}
// BuyIPString is
func (inv *Invite) BuyIPString() string {
if inv.IP != 0 {
return inetNtoA(inv.IP)
}
return net.IP(inv.IPng).String()
}
func inetNtoA(sum uint32) string {
ip := make(net.IP, net.IPv4len)
ip[0] = byte((sum >> 24) & 0xFF)
ip[1] = byte((sum >> 16) & 0xFF)
ip[2] = byte((sum >> 8) & 0xFF)
ip[3] = byte(sum & 0xFF)
return ip.String()
}
// FillStatus fill status.
func (inv *Invite) FillStatus(now int64) {
if inv.Used() {
inv.Status = StatusUsed
return
}
if inv.Expired(now) {
inv.Status = StatusExpires
return
}
inv.Status = StatusOK
}
// Used check if used.
func (inv *Invite) Used() bool {
return inv.UsedAt > 0 && inv.Imid > 0
}
// Expired check if expired.
func (inv *Invite) Expired(now int64) bool {
return now > inv.Expires
}
// RichInvite rich invite with invitee info.
type RichInvite struct {
Status int64 `json:"status"`
Mid int64 `json:"mid"`
Code string `json:"invite_code"`
BuyIP string `json:"buy_ip"`
Ctime xtime.Time `json:"buy_time"`
Expires int64 `json:"expires"`
Invitee *Invitee `json:"invitee,omitempty"`
UsedAt int64 `json:"used_at,omitempty"`
}
// NewRichInvite new a rich invite.
func NewRichInvite(inv *Invite, info *accmdl.Info) *RichInvite {
if inv == nil {
return nil
}
var invt *Invitee
if inv.Used() {
if info != nil {
invt = &Invitee{
Mid: inv.Imid,
Uname: info.Name,
Face: info.Face,
}
} else {
invt = &Invitee{
Mid: inv.Imid,
Uname: "用户" + strconv.FormatInt(inv.Imid, 10),
Face: "http://static.hdslb.com/images/member/noface.gif",
}
}
}
return &RichInvite{
Status: inv.Status,
Mid: inv.Mid,
Code: inv.Code,
Ctime: inv.Ctime,
Expires: inv.Expires,
Invitee: invt,
UsedAt: inv.UsedAt,
BuyIP: inv.BuyIPString(),
}
}
// Invitee invited.
type Invitee struct {
Mid int64 `json:"mid"`
Uname string `json:"uname"`
Face string `json:"face"`
}

View File

@@ -0,0 +1,14 @@
package model
import (
xtime "go-common/library/time"
)
// OperationLog operation log .
type OperationLog struct {
ID int64 `json:"id"`
OID int64 `json:"oid"`
Action string `json:"action"`
CTime xtime.Time `json:"ctime"`
MTime xtime.Time `json:"mtime"`
}

View File

@@ -0,0 +1,7 @@
package model
// MangerInfo struct
type MangerInfo struct {
OID int64 `json:"id"`
Uname string `json:"username"`
}

View File

@@ -0,0 +1,90 @@
package model
import (
xtime "go-common/library/time"
)
const (
// OwnerActivated medal_owner is_activated=1 .
OwnerActivated = int8(1)
// OwnerNotActivated medal_owner is_activated=0 .
OwnerNotActivated = int8(0)
// MaxCount medal batch add max.
MaxCount = 2000
// MedalSourceTypeAdmin medal source type admin.
MedalSourceTypeAdmin = int8(1)
)
// Medal medal info .
type Medal struct {
ID int64 `form:"id" json:"id"`
GID int64 `form:"gid" validate:"required" json:"gid"`
Name string `form:"name" validate:"required" json:"name"`
Description string `form:"description" validate:"required" json:"description"`
Image string `form:"image" validate:"required" json:"image"`
ImageSmall string `form:"image_small" validate:"required" json:"image_small"`
Condition string `form:"condition" validate:"required" json:"condition"`
Level int8 `form:"level" validate:"min=1,max=3" json:"level"`
LevelRank string `form:"level_rank" validate:"required" json:"level_rank"`
Sort int `form:"sort" validate:"required" json:"sort"`
IsOnline int `form:"is_online" json:"is_online"`
CTime xtime.Time `json:"ctime,omitempty"`
MTime xtime.Time `json:"mtime,omitempty"`
}
// MedalGroup nameplate group .
type MedalGroup struct {
ID int64 `form:"id" json:"id"`
PID int64 `form:"pid" json:"pid"`
Rank int8 `form:"rank" validate:"required" json:"rank"`
IsOnline int8 `form:"is_online" json:"is_online"`
Name string `form:"name" validate:"required" json:"name"`
PName string `form:"pname" json:"pname,omitempty"`
CTime xtime.Time `json:"ctime,omitempty"`
MTime xtime.Time `json:"mtime,omitempty"`
}
// MedalOwner nameplate owner .
type MedalOwner struct {
ID int64 `json:"id"`
MID int64 `json:"mid"`
NID int64 `json:"nid"`
IsActivated int8 `json:"is_activated"`
IsDel int8 `json:"is_del"`
CTime xtime.Time `json:"ctime"`
MTime xtime.Time `json:"mtime"`
}
// MedalInfo struct.
type MedalInfo struct {
*Medal
GroupName string `json:"group_name"`
ParentGroupName string `json:"parent_group_name"`
}
// MedalMemberMID struct.
type MedalMemberMID struct {
ID int64 `json:"id"`
NID int64 `json:"nid"`
MedalName string `json:"medal_name"`
IsActivated int8 `json:"is_activated"`
IsDel int8 `json:"is_del"`
}
// MedalMemberAddList struct.
type MedalMemberAddList struct {
ID int64 `json:"id"`
MedalName string `json:"medal_name"`
}
// MedalOperLog struct.
type MedalOperLog struct {
OID int64 `json:"oper_id"`
Action string `json:"action"`
CTime xtime.Time `json:"ctime"`
MTime xtime.Time `json:"mtime"`
OperName string `json:"oper_name"`
MID int64 `json:"mid"`
MedalID int64 `json:"medal_id"`
SourceType int8 `json:"source_type"`
}

View File

@@ -0,0 +1,27 @@
package model
// const msg
const (
MsgTypeCustom = int8(1)
)
// SysMsg msg struct
type SysMsg struct {
IsMsg bool
Type int8
MID int64
Title string
Content string
RemoteIP string
}
// MsgInfo get msg info
func MsgInfo(msg *SysMsg) (title, content, ip string) {
switch msg.Type {
case MsgTypeCustom:
title = msg.Title
content = msg.Content
ip = msg.RemoteIP
}
return
}

View File

@@ -0,0 +1,14 @@
package model
//const
const (
AccountNotifyUpdatePendant = "updatePendant"
AccountNotifyUpdateMedal = "updateMedal"
)
// AccountNotify .
type AccountNotify struct {
UID int64 `json:"mid"`
Type string `json:"type"`
Action string `json:"action"`
}

View File

@@ -0,0 +1,79 @@
package model
import xtime "go-common/library/time"
// Pager .
type Pager struct {
Total int64 `json:"total"`
PN int `json:"page"`
PS int `json:"pagesize"`
Order string `json:"order"`
Sort string `json:"sort"`
}
// ArgPendantGroupList .
type ArgPendantGroupList struct {
GID int64 `form:"gid"`
PN int `form:"pn"`
PS int `form:"ps" validate:"max=100"`
}
// ArgPendantInfo .
type ArgPendantInfo struct {
PID int64 `form:"pid"`
GID int64 `form:"gid" validate:"required"`
Name string `form:"name" validate:"required"`
Image string `form:"image"`
ImageModel string `form:"image_model"`
Rank int16 `form:"rank"`
Status int8 `form:"status"`
IntegralPrice int `form:"integral_price"` // 积分
BcoinPrice int `form:"bcoin_price"` // B币
CoinPrice int `form:"coin_price"` // 硬币
}
// ArgPendantGroup .
type ArgPendantGroup struct {
GID int64 `form:"gid"`
Name string `form:"name" validate:"required"`
Rank int16 `form:"rank"`
Status int8 `form:"status"`
}
// ArgPendantOrder .
type ArgPendantOrder struct {
Start xtime.Time `form:"start_time"`
End xtime.Time `form:"end_time"`
Status int8 `form:"status"`
PID int64 `form:"pid"`
PayID string `form:"pay_id"`
UID int64 `form:"uid"`
PN int `form:"pn"`
PS int `form:"ps" validate:"max=100"`
}
// ArgPendantPKG .
type ArgPendantPKG struct {
UID int64 `form:"uid" validate:"required"`
PID int64 `form:"pid" validate:"required"`
Day int64 `form:"day" validate:"required"`
Type int8 `form:"type"`
IsMsg bool `form:"is_msg"`
Title string `form:"title"`
Content string `form:"content"`
OID int64 `form:"oper_id" validate:"required"`
}
// ArgMedal medal struct .
type ArgMedal struct {
GID int64 `json:"gid"`
Name string `json:"name"`
Description string `json:"description"`
Image string `json:"image"`
ImageSmall string `json:"image_small"`
Condition string `json:"condition"`
Level string `json:"level"`
LevelRank string `json:"level_rank"`
Sort int `json:"sort"`
IsOnline int `json:"is_online"`
}

View File

@@ -0,0 +1,131 @@
package model
import xtime "go-common/library/time"
// const .
const (
// pendant type
PendantCoinPrice = int8(0)
PendantBCoinPrice = int8(1)
PendantIntegralPrice = int8(2)
// order plat
PendantOrderPlatDefault = int8(-1)
PendantOrderPlatPCAndH5 = int8(0)
PendantOrderPlatPhone = int8(1)
// pkg status
PendantPKGInvalid = int8(0)
PendantPKGValid = int8(1)
PendantPKGOnEquip = int8(2)
// pendant add style
PendantAddStyleDay = int8(1)
PendantAddStyleDate = int8(2)
// sourceType
PendantSourceTypeAdmin = int8(1)
PendantSourceTypePGC = int8(2)
)
// var .
var (
PriceTypes = []int8{PendantCoinPrice, PendantBCoinPrice, PendantIntegralPrice}
)
// PendantGroup .
type PendantGroup struct {
ID int64 `json:"id"`
Name string `json:"name"`
Rank int16 `json:"rank"`
Status int8 `json:"status"`
}
// PendantPrice .
type PendantPrice struct {
PID int64 `json:"pid"`
TP int8 `json:"type"`
Price int `json:"price"`
}
// PendantInfo .
type PendantInfo struct {
ID int64 `json:"id"`
Name string `json:"name"`
Image string `json:"image"`
ImageModel string `json:"image_model"`
Status int8 `json:"status"`
Rank int16 `json:"rank"`
GID int64 `json:"gid"`
GroupName string `json:"group_name"`
GroupRank int16 `json:"group_rank"`
Prices []*PendantPrice `json:"prices"`
}
// PendantGroupRef .
type PendantGroupRef struct {
GID int64 `json:"gid"`
PID int64 `json:"pid"`
}
// PendantOrder .
type PendantOrder struct {
BuyTime int64 `json:"buy_time"`
OrderID string `json:"order_id"`
PayID string `json:"pay_id"`
UID int64 `json:"uid"`
PID int64 `json:"-"`
PName string `json:"pendant_name"`
TimeLength int64 `json:"time_length"`
Cost string `json:"cost"`
PayType int8 `json:"pay_type"`
Status int8 `json:"status"`
AppID int8 `json:"appid"`
Platform string `json:"platform"`
}
// CoverToPlatform .
func (p *PendantOrder) CoverToPlatform() {
switch p.AppID {
case PendantOrderPlatDefault:
p.Platform = "默认"
case PendantOrderPlatPCAndH5:
p.Platform = "PC/H5"
case PendantOrderPlatPhone:
p.Platform = "手机客户端"
}
}
// PendantPKG .
type PendantPKG struct {
ID int64 `json:"id"`
UID int64 `json:"uid"`
PID int64 `json:"pid"`
Expires int64 `json:"expires"`
TP int8 `json:"type"`
Status int8 `json:"status"`
IsVip int8 `json:"is_vip"`
}
// PendantOperLog .
type PendantOperLog struct {
OID int64 `json:"oper_id"`
Action string `json:"action"`
CTime xtime.Time `json:"ctime"`
MTime xtime.Time `json:"mtime"`
OperName string `json:"oper_name"`
UID int64 `json:"uid"`
PID int64 `json:"pid"`
SourceType int8 `json:"source_type"`
}
// BulidPendantPrice .
func (pp *PendantPrice) BulidPendantPrice(arg *ArgPendantInfo, tp int8) {
switch tp {
case PendantCoinPrice:
pp.Price = arg.CoinPrice
case PendantBCoinPrice:
pp.Price = arg.BcoinPrice
case PendantIntegralPrice:
pp.Price = arg.IntegralPrice
}
pp.TP = tp
pp.PID = arg.PID
}

View File

@@ -0,0 +1,71 @@
package(default_visibility = ["//visibility:public"])
load(
"@io_bazel_rules_go//go:def.bzl",
"go_test",
"go_library",
)
go_test(
name = "go_default_test",
srcs = [
"invite_test.go",
"medal_test.go",
"pendant_test.go",
"service_test.go",
],
embed = [":go_default_library"],
rundir = ".",
tags = ["automanaged"],
deps = [
"//app/admin/main/usersuit/conf:go_default_library",
"//app/admin/main/usersuit/model:go_default_library",
"//library/ecode:go_default_library",
"//vendor/github.com/smartystreets/goconvey/convey:go_default_library",
],
)
go_library(
name = "go_default_library",
srcs = [
"invite.go",
"medal.go",
"notify.go",
"pendant.go",
"service.go",
"upload.go",
],
importpath = "go-common/app/admin/main/usersuit/service",
tags = ["automanaged"],
visibility = ["//visibility:public"],
deps = [
"//app/admin/main/usersuit/conf:go_default_library",
"//app/admin/main/usersuit/dao:go_default_library",
"//app/admin/main/usersuit/model:go_default_library",
"//app/service/main/account/api:go_default_library",
"//app/service/main/account/model:go_default_library",
"//library/database/sql:go_default_library",
"//library/ecode:go_default_library",
"//library/log:go_default_library",
"//library/net/metadata:go_default_library",
"//library/queue/databus:go_default_library",
"//library/sync/errgroup:go_default_library",
"//library/time:go_default_library",
"//library/xstr:go_default_library",
"//vendor/github.com/pkg/errors: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,209 @@
package service
import (
"context"
"crypto/md5"
"encoding/hex"
"fmt"
"math/rand"
"net"
"sort"
"sync"
"time"
"go-common/app/admin/main/usersuit/model"
accmdl "go-common/app/service/main/account/api"
"go-common/library/ecode"
"go-common/library/log"
"go-common/library/net/metadata"
xtime "go-common/library/time"
"go-common/library/sync/errgroup"
)
const (
_geneMaxLimit = int64(1000)
_geneSubCount = 200
_batch = 50
_fetchInfoTimeout = time.Second * 5
)
var (
_emptyRichInvites = make([]*model.RichInvite, 0)
_emptyInfoMap = make(map[int64]*accmdl.Info)
)
// Generate generate invite codes in batch.
func (s *Service) Generate(c context.Context, mid, num, expireDay int64) (res []*model.RichInvite, err error) {
if num > _geneMaxLimit {
err = ecode.UsersuitInviteReachMaxGeneLimit
return
}
expireSeconds := expireDay * 86400
nowTs := time.Now().Unix()
cm, err1 := concurrentGenerateCode(mid, nowTs, int(num), _geneSubCount)
if err1 != nil {
log.Error("concurrentGenerateCode(%d, %d, %d, %d) error(%v)", mid, nowTs, num, _geneSubCount, err)
}
ginvs := make([]*model.Invite, 0, num)
buyIP := net.ParseIP(metadata.String(c, metadata.RemoteIP))
for code := range cm {
ginvs = append(ginvs, &model.Invite{
Mid: mid,
Code: code,
IP: IPv4toN(buyIP),
IPng: buyIP,
Expires: nowTs + expireSeconds,
Ctime: xtime.Time(nowTs),
})
}
invs := make([]*model.Invite, 0)
var rc int64
for _, inv := range ginvs {
if rc, err = s.d.AddIgnoreInvite(c, inv); err != nil {
err = nil
break
}
if rc == 0 {
log.Error("service.dao.AddIgnoreInvite(%s), duplicate entry for invite_code %s", inv.Code, inv.Code)
continue
}
invs = append(invs, inv)
}
res = s.fillStatusAndInviteeInfo(c, invs)
return
}
func concurrentGenerateCode(mid, ts int64, num, subCount int) (res map[string]int, err error) {
batches := num / subCount
eg, _ := errgroup.WithContext(context.TODO())
ims := make([]map[string]int, batches)
mu := sync.Mutex{}
for i := 0; i < batches; i++ {
idx := i
eg.Go(func() error {
im := make(map[string]int)
for len(im) < subCount {
im[geneInviteCode(mid, ts)] = 1
}
mu.Lock()
ims[idx] = im
mu.Unlock()
return nil
})
}
err = eg.Wait()
m := make(map[string]int)
for _, im := range ims {
for code := range im {
m[code] = 1
}
}
for len(m) < num {
m[geneInviteCode(mid, ts)] = 1
}
res = m
return
}
func geneInviteCode(mid int64, ts int64) string {
data := md5.Sum([]byte(fmt.Sprintf("%d,%d,%d", ts, mid, rand.Int63())))
h := hex.EncodeToString(data[:])
return h[8:24]
}
// List list one's invite codes range time start and end.
func (s *Service) List(c context.Context, mid, start, end int64) (res []*model.RichInvite, err error) {
if start > end {
res = _emptyRichInvites
return
}
var invs []*model.Invite
if invs, err = s.d.RangeInvites(c, mid, time.Unix(start, 0), time.Unix(end, 0)); err != nil {
return
}
sort.Slice(invs, func(i, j int) bool {
return int64(invs[i].Ctime) > int64(invs[j].Ctime)
})
res = s.fillStatusAndInviteeInfo(c, invs)
return
}
func (s *Service) fillStatusAndInviteeInfo(c context.Context, invs []*model.Invite) []*model.RichInvite {
if len(invs) == 0 {
return _emptyRichInvites
}
imidm := make(map[int64]struct{})
now := time.Now().Unix()
for _, inv := range invs {
inv.FillStatus(now)
if inv.Status == model.StatusUsed {
imidm[inv.Imid] = struct{}{}
}
}
infom := _emptyInfoMap
if len(imidm) > 0 {
imids := make([]int64, 0, len(imidm))
for imid := range imidm {
imids = append(imids, imid)
}
var err1 error
if infom, err1 = s.fetchInfos(c, imids, _fetchInfoTimeout); err1 != nil {
log.Error("service.fetchInfos(%v, %s) error(%v)", imids, _fetchInfoTimeout, err1)
}
}
rinvs := make([]*model.RichInvite, 0)
for _, inv := range invs {
rinvs = append(rinvs, model.NewRichInvite(inv, infom[inv.Imid]))
}
return rinvs
}
func (s *Service) fetchInfos(c context.Context, mids []int64, timeout time.Duration) (res map[int64]*accmdl.Info, err error) {
if len(mids) == 0 {
res = _emptyInfoMap
return
}
batches := len(mids)/_batch + 1
tc, cancel := context.WithTimeout(c, timeout)
defer cancel()
eg, errCtx := errgroup.WithContext(tc)
bms := make([]map[int64]*accmdl.Info, batches)
mu := sync.Mutex{}
for i := 0; i < batches; i++ {
idx := i
end := (idx + 1) * _batch
if idx == batches-1 {
end = len(mids)
}
ids := mids[idx*_batch : end]
eg.Go(func() error {
m, err1 := s.accountClient.Infos3(errCtx, &accmdl.MidsReq{Mids: ids})
mu.Lock()
bms[idx] = m.Infos
mu.Unlock()
return err1
})
}
err = eg.Wait()
res = make(map[int64]*accmdl.Info)
for _, bm := range bms {
for mid, info := range bm {
res[mid] = info
}
}
return
}
// IPv4toN is
func IPv4toN(ip net.IP) (sum uint32) {
v4 := ip.To4()
if v4 == nil {
return
}
sum += uint32(v4[0]) << 24
sum += uint32(v4[1]) << 16
sum += uint32(v4[2]) << 8
sum += uint32(v4[3])
return sum
}

View File

@@ -0,0 +1,60 @@
package service
import (
"context"
"testing"
"time"
"go-common/library/ecode"
. "github.com/smartystreets/goconvey/convey"
)
func TestService_Generate(t *testing.T) {
Convey("Generate 10 codes in batch", t, func() {
mid := int64(88888970)
num := int64(10)
expireDay := int64(30)
res, err := s.Generate(context.Background(), mid, num, expireDay)
So(err, ShouldBeNil)
So(len(res), ShouldEqual, num)
})
}
func TestService_List(t *testing.T) {
Convey("List when account's invite codes is not empty", t, func() {
mid := int64(88888970)
now := time.Now().Unix()
start, end := now-86400, now+86400
res, err := s.List(context.Background(), mid, start, end)
So(err, ShouldBeNil)
So(len(res), ShouldBeGreaterThan, 0)
})
}
func TestService_ConcurrentGeneInviteCode(t *testing.T) {
Convey("Generate 1000 codes in concurrency", t, func() {
num := 1000
mid := int64(88888970)
ts := time.Now().Unix()
m, err := concurrentGenerateCode(mid, ts, num, _geneSubCount)
So(err, ShouldBeNil)
So(len(m), ShouldEqual, num)
})
}
func TestService_FetchMultiInfo(t *testing.T) {
time.Sleep(time.Second * 2)
Convey("Fetch multi info", t, func() {
mids := []int64{88888970}
Convey("when not timeout", func() {
res, err := s.fetchInfos(context.Background(), mids, time.Second)
So(err, ShouldBeNil)
So(len(res), ShouldEqual, len(mids))
})
Convey("when timeout", func() {
_, err := s.fetchInfos(context.Background(), mids, time.Millisecond)
So(err, ShouldEqual, ecode.Deadline.Error())
})
})
}

View File

@@ -0,0 +1,328 @@
package service
import (
"context"
"encoding/csv"
"fmt"
"io"
"mime/multipart"
"net/url"
"strconv"
"strings"
"github.com/pkg/errors"
"go-common/app/admin/main/usersuit/model"
accmdl "go-common/app/service/main/account/model"
"go-common/library/ecode"
"go-common/library/log"
"go-common/library/xstr"
)
// Medal medal .
func (s *Service) Medal(c context.Context) (res []*model.MedalInfo, err error) {
nps, err := s.d.Medal(c)
if err != nil {
log.Error("s.d.Medal error(%v)", err)
}
mgs, err := s.d.MedalGroup(c)
if err != nil {
log.Error("s.d.MedalGroup error(%v)", err)
}
res = make([]*model.MedalInfo, 0)
for _, np := range nps {
re := &model.MedalInfo{}
re.Medal = np
if _, ok := mgs[np.GID]; ok {
re.GroupName = mgs[np.GID].Name
if mgs[np.GID].PID != 0 {
re.ParentGroupName = mgs[mgs[np.GID].PID].Name
}
}
res = append(res, re)
}
return
}
// MedalView .
func (s *Service) MedalView(c context.Context, id int64) (res *model.MedalInfo, err error) {
res = &model.MedalInfo{}
res.Medal, err = s.d.MedalByID(c, id)
if err != nil {
log.Error("s.d.MedalByID(%d) error(%v)", id, err)
return
}
mgs, err := s.d.MedalGroup(c)
if err != nil {
log.Error("s.d.MedalGroup error(%v)", err)
return
}
if _, ok := mgs[res.Medal.GID]; ok {
res.GroupName = mgs[res.Medal.GID].Name
if _, ok1 := mgs[mgs[res.Medal.GID].PID]; ok && ok1 {
res.ParentGroupName = mgs[mgs[res.Medal.GID].PID].Name
}
}
return
}
func getImagePath(raw string) string {
uri, err := url.Parse(raw)
if err != nil {
return raw
}
return uri.Path
}
// AddMedal add medal .
func (s *Service) AddMedal(c context.Context, np *model.Medal) (err error) {
np.Image = getImagePath(np.Image)
np.ImageSmall = getImagePath(np.ImageSmall)
if _, err := s.d.AddMedal(c, np); err != nil {
log.Error("s.d.AddMedal error(%v)", err)
}
return
}
// UpMedal update medal .
func (s *Service) UpMedal(c context.Context, id int64, np *model.Medal) (err error) {
np.Image = getImagePath(np.Image)
np.ImageSmall = getImagePath(np.ImageSmall)
if _, err := s.d.UpMedal(c, id, np); err != nil {
log.Error("s.d.UpMedal error(%v)", err)
}
return
}
// MedalGroup medal group .
func (s *Service) MedalGroup(c context.Context) (res map[int64]*model.MedalGroup, err error) {
res, err = s.d.MedalGroup(c)
if err != nil {
log.Error("s.MedalGroup error(%v)", err)
}
return
}
// MedalGroupInfo medal group all info include parent group name .
func (s *Service) MedalGroupInfo(c context.Context) (res []*model.MedalGroup, err error) {
res, err = s.d.MedalGroupInfo(c)
if err != nil {
log.Error("s.MedalGroupInfo error(%v)", err)
}
return
}
// MedalGroupParent medal group all info include parent group name .
func (s *Service) MedalGroupParent(c context.Context) (res []*model.MedalGroup, err error) {
res, err = s.d.MedalGroupParent(c)
if err != nil {
log.Error("s.MedalGroupParent error(%v)", err)
}
return
}
// MedalGroupByGid nameplate by gid .
func (s *Service) MedalGroupByGid(c context.Context, id int64) (ng *model.MedalGroup, err error) {
if ng, err = s.d.MedalGroupByID(c, id); err != nil {
log.Error("s.MedalGroupByID error(%v)", err)
}
return
}
// MedalGroupAdd add medal group.
func (s *Service) MedalGroupAdd(c context.Context, ng *model.MedalGroup) (err error) {
if _, err := s.d.MedalGroupAdd(c, ng); err != nil {
log.Error("s.MedalGroupAdd error(%v)", err)
}
return
}
// MedalGroupUp update medal group.
func (s *Service) MedalGroupUp(c context.Context, id int64, ng *model.MedalGroup) (err error) {
if _, err := s.d.MedalGroupUp(c, id, ng); err != nil {
log.Error("s.MedalGroupUp error(%v)", err)
}
return
}
// MedalOwner medal onwer .
func (s *Service) MedalOwner(c context.Context, mid int64) (no []*model.MedalMemberMID, err error) {
if no, err = s.d.MedalOwner(c, mid); err != nil {
log.Error("s.d.MedalOwner error(%+v)", err)
}
return
}
// MedalOwnerAdd medal owner add .
func (s *Service) MedalOwnerAdd(c context.Context, mid, nid int64, title, msg string, oid int64) (err error) {
count, err := s.d.CountOwnerBYNidMid(c, mid, nid)
if count > 0 || err != nil {
err = ecode.MedalHasGet
return
}
if _, err = s.d.MedalOwnerAdd(c, mid, nid); err != nil {
log.Error("s.MedalOwnerAdd(mid:%d nid:%d) error(%v)", mid, nid, err)
return
}
if err = s.d.DelMedalOwnersCache(c, mid); err != nil {
log.Error("s.DelMedalOwnersCache(mid:%d) error(%v)", mid, err)
err = nil
}
var (
mids []int64
ismsg bool
action string
)
mids = append(mids, mid)
log.Error("MedalOwnerAdd title(%+v) msg(%+v)", title, msg)
if title != "" && msg != "" {
ismsg = true
if err = s.d.SendSysMsg(c, mids, title, msg, ""); err != nil {
log.Error("MedalOwnerAdd(mid:%d nid:%d title:%s msg:%s) SendSysMsg error(%+v)", mid, nid, title, msg, err)
err = nil
}
}
if oid > 0 {
mi, err := s.d.MedalByID(c, nid)
if err != nil {
log.Error("MedalByID(id:%d) error(%+v)", nid, err)
err = nil
}
action = fmt.Sprintf("激活勋章:%s,", mi.Name)
log.Error("MedalOwnerAdd ismsg(id:%d %+v) error(%+v)", nid, ismsg, err)
if ismsg {
action += fmt.Sprintf("并发送消息title:%s msg:%s", title, msg)
} else {
action += fmt.Sprintf("并没有发送消息")
}
s.d.AddMedalOperLog(c, oid, mid, nid, action)
}
return
}
// MedalOwnerAddList .
func (s *Service) MedalOwnerAddList(c context.Context, mid int64) (res []*model.MedalMemberAddList, err error) {
if res, err = s.d.MedalAddList(c, mid); err != nil {
log.Error("s.d.MedalOwnerAddList(%d) error(%v)", mid, err)
}
return
}
// MedalOwnerUpActivated update medal owner is_activated.
func (s *Service) MedalOwnerUpActivated(c context.Context, mid, nid int64) (err error) {
if _, err = s.d.MedalOwnerUpActivated(c, mid, nid); err != nil {
log.Error("s.d.UpMedalOwnerActivated(mid:%d nid:%d) error(%v)", mid, nid, err)
}
if _, err = s.d.MedalOwnerUpNotActivated(c, mid, nid); err != nil {
log.Error("s.d.UpMedalOwnerNotActivated(mid:%d nid:%d) error(%v)", mid, nid, err)
}
if err = s.d.SetMedalActivatedCache(c, mid, nid); err != nil {
log.Error("s.d.DelMedalActivatedCache(mid:%d nid:%d) error(%v)", mid, nid, err)
err = nil
}
s.addAsyn(func() {
if err = s.accNotify(context.Background(), mid, model.AccountNotifyUpdateMedal); err != nil {
log.Error("s.accNotify(%d) error(%+v)", mid, err)
return
}
})
return
}
// MedalOwnerDel update medal owner is_del .
func (s *Service) MedalOwnerDel(c context.Context, mid, nid int64, isDel int8, title, msg string) (err error) {
if _, err = s.d.MedalOwnerDel(c, mid, nid, isDel); err != nil {
log.Error("s.d.MedalOwnerDel error(%v)", err)
}
if err = s.d.DelMedalOwnersCache(c, mid); err != nil {
log.Error("s.d.DelMedalOwnersCache(%d) error(%v)", mid, err)
err = nil
}
var mids []int64
mids = append(mids, mid)
if title != "" && msg != "" {
if err = s.d.SendSysMsg(c, mids, title, msg, ""); err != nil {
log.Error("MedalOwnerDel(mid:%d nid:%d title:%s msg:%s) SendSysMsg error(%+v)", mid, nid, title, msg, err)
err = nil
}
}
return
}
// ReadCsv read csv file
func (s *Service) ReadCsv(f multipart.File, h *multipart.FileHeader) (rs [][]string, err error) {
r := csv.NewReader(f)
for {
record, err := r.Read()
if err == io.EOF {
break
}
if err != nil {
fmt.Println(err)
log.Error("upload question ReadCsv error(%v)", err)
}
if len(record) == 1 {
rs = append(rs, record)
}
}
return
}
// BatchAdd medal bacth add.
func (s *Service) BatchAdd(c context.Context, nid int64, f multipart.File, h *multipart.FileHeader) (msg string, err error) {
if h != nil && !strings.HasSuffix(h.Filename, ".csv") {
msg = "not csv file."
return
}
rs, err := s.ReadCsv(f, h)
if len(rs) == 0 || len(rs) > model.MaxCount {
msg = "file size count is 0 or more than " + strconv.FormatInt(model.MaxCount, 10)
return
}
for _, r := range rs {
mid, err := strconv.ParseInt(r[0], 10, 64)
if err == nil {
if err = s.MedalOwnerAdd(c, mid, nid, "", "", 0); err != nil {
log.Error("s.d.MedalOwnerAdd(mid:%d nid:%d) error(%v)", mid, nid, err)
}
}
}
return
}
// MedalOperlog medal operactlog .
func (s *Service) MedalOperlog(c context.Context, mid int64, pn, ps int) (opers []*model.MedalOperLog, pager *model.Pager, err error) {
var total int64
pager = &model.Pager{
PN: pn,
PS: ps,
}
if total, err = s.d.MedalOperationLogTotal(c, mid); err != nil {
err = errors.Wrap(err, "s.d.MedalOperationLogTotal()")
return
}
if total <= 0 {
return
}
pager.Total = total
var uids []int64
if opers, uids, err = s.d.MedalOperLog(c, mid, pn, ps); err != nil {
err = errors.Wrapf(err, "s.d.MedalOperLog(%d,%d,%d)", mid, pn, ps)
return
}
var accInfoMap map[int64]*accmdl.Info
if accInfoMap, err = s.fetchInfos(c, uids, _fetchInfoTimeout); err != nil {
log.Error("service.fetchInfos(%v, %v) error(%v)", xstr.JoinInts(uids), _fetchInfoTimeout, err)
err = nil
}
for _, v := range opers {
if accInfo, ok := accInfoMap[v.MID]; ok {
v.Action = fmt.Sprintf("给用户(%s) %s", accInfo.Name, v.Action)
}
if operName, ok := s.Managers[v.OID]; ok {
v.OperName = operName
}
}
return
}

View File

@@ -0,0 +1,187 @@
package service
import (
"context"
"fmt"
"go-common/app/admin/main/usersuit/model"
"testing"
. "github.com/smartystreets/goconvey/convey"
)
func TestService_Medal(t *testing.T) {
Convey("return sth", t, func() {
res, err := s.Medal(context.Background())
for k, re := range res {
fmt.Printf("%d %+v \n", k, re)
}
So(err, ShouldBeNil)
So(res, ShouldNotBeNil)
})
}
func TestService_MedalView(t *testing.T) {
Convey("return sth", t, func() {
res, err := s.MedalView(context.Background(), 3)
fmt.Printf("%+v \n", res)
So(err, ShouldBeNil)
So(res, ShouldNotBeNil)
})
}
func TestService_AddMedal(t *testing.T) {
Convey("return sth", t, func() {
np := &model.Medal{
Name: "出道偶像",
Description: "播放五十万,准备发新单",
Condition: "所有自制视频总播放数>=50万",
GID: 4,
Level: int8(2),
Sort: 2,
LevelRank: "50万",
IsOnline: 1,
Image: "/bfs/face/3f2d64f048b39fb6c26f3db39df47e6080ec0f9c.png",
ImageSmall: "/bfs/face/90c35d41d8a19b19474d6bac672394c17b444ce8.png",
}
err := s.AddMedal(context.Background(), np)
fmt.Printf("%+v \n", err)
So(err, ShouldBeNil)
})
}
func TestService_UpMedal(t *testing.T) {
Convey("return sth", t, func() {
np := &model.Medal{
Name: "出道偶像111",
Description: "播放五十万,准备发新单",
Condition: "所有自制视频总播放数>=50万",
GID: 4,
Level: int8(2),
Sort: 2,
LevelRank: "50万",
IsOnline: 1,
Image: "/bfs/face/3f2d64f048b39fb6c26f3db39df47e6080ec0f9c.png",
ImageSmall: "/bfs/face/90c35d41d8a19b19474d6bac672394c17b444ce8.png",
}
err := s.UpMedal(context.Background(), 1, np)
fmt.Printf("%+v \n", err)
So(err, ShouldBeNil)
})
}
func TestService_MedalGroup(t *testing.T) {
Convey("return someting", t, func() {
res, err := s.MedalGroup(context.Background())
for k, re := range res {
fmt.Printf("%d %+v \n", k, re)
}
So(err, ShouldBeNil)
So(res, ShouldNotBeNil)
})
}
func TestService_MedalGroupInfo(t *testing.T) {
Convey("return someting", t, func() {
res, err := s.MedalGroupInfo(context.Background())
for k, re := range res {
fmt.Printf("%d %+v \n", k, re)
}
So(err, ShouldBeNil)
So(res, ShouldNotBeNil)
})
}
func TestService_MedalGroupParent(t *testing.T) {
Convey("return someting", t, func() {
res, err := s.MedalGroupParent(context.Background())
for k, re := range res {
fmt.Printf("%d %+v \n", k, re)
}
So(err, ShouldBeNil)
So(res, ShouldNotBeNil)
})
}
func TestService_MedalGroupByID(t *testing.T) {
Convey("return someting", t, func() {
re, err := s.MedalGroupByGid(context.Background(), 2)
So(err, ShouldBeNil)
So(re, ShouldNotBeNil)
fmt.Printf("%+v \n", re)
})
}
func TestService_MedalGroupAdd(t *testing.T) {
Convey("return someting", t, func() {
pg := &model.MedalGroup{
Name: "test",
PID: 1,
Rank: int8(1),
IsOnline: int8(1),
}
err := s.MedalGroupAdd(context.Background(), pg)
So(err, ShouldBeNil)
fmt.Printf("%+v \n", err)
})
}
func TestService_MedalGroupUp(t *testing.T) {
Convey("return someting", t, func() {
pg := &model.MedalGroup{
Name: "test222",
PID: 2,
Rank: 2,
IsOnline: 0,
}
err := s.MedalGroupUp(context.Background(), 37, pg)
So(err, ShouldBeNil)
fmt.Printf("%+v \n", err)
})
}
func TestService_MedalOwner(t *testing.T) {
Convey("return someting", t, func() {
res, err := s.MedalOwner(context.Background(), 111)
for k, re := range res {
fmt.Printf("%d %+v \n", k, re)
}
fmt.Printf("err:%+v \n", err)
So(err, ShouldBeNil)
So(res, ShouldNotBeNil)
})
}
func TestService_MedalOwnerAdd(t *testing.T) {
Convey("return someting", t, func() {
err := s.MedalOwnerAdd(context.Background(), 41, 1, "", "", 1)
fmt.Printf("%+v \n", err)
So(err, ShouldBeNil)
})
}
func TestService_MedalAddList(t *testing.T) {
Convey("return someting", t, func() {
res, err := s.MedalOwnerAddList(context.Background(), 1)
for k, re := range res {
fmt.Printf("%d %+v \n", k, re)
}
So(err, ShouldBeNil)
So(res, ShouldNotBeNil)
})
}
func TestService_MedalOwnerUpActivated(t *testing.T) {
Convey("return someting", t, func() {
err := s.MedalOwnerUpActivated(context.Background(), 1, 1)
fmt.Printf("%+v \n", err)
So(err, ShouldBeNil)
})
}
func TestService_MedalOwnerDel(t *testing.T) {
Convey("return someting", t, func() {
err := s.MedalOwnerDel(context.Background(), 1, 5, 0, "", "")
fmt.Printf("%+v \n", err)
So(err, ShouldBeNil)
})
}

View File

@@ -0,0 +1,17 @@
package service
import (
"context"
"strconv"
"go-common/app/admin/main/usersuit/model"
"go-common/library/log"
)
func (s *Service) accNotify(c context.Context, uid int64, action string) (err error) {
msg := &model.AccountNotify{UID: uid, Type: "update", Action: action}
if err = s.accountNotifyPub.Send(c, strconv.FormatInt(msg.UID, 10), msg); err != nil {
log.Error("mid(%d) s.accountNotifyPub.Send(%+v) error(%v)", msg.UID, msg, err)
}
return
}

View File

@@ -0,0 +1,643 @@
package service
import (
"context"
"fmt"
"time"
"go-common/app/admin/main/usersuit/model"
accmdl "go-common/app/service/main/account/model"
"go-common/library/database/sql"
"go-common/library/ecode"
"go-common/library/log"
xtime "go-common/library/time"
"go-common/library/xstr"
"github.com/pkg/errors"
)
// PendantInfoList pendant list by group rank.
func (s *Service) PendantInfoList(c context.Context, arg *model.ArgPendantGroupList) (pis []*model.PendantInfo, pager *model.Pager, err error) {
var (
total int64
pids []int64
ppm map[int64][]*model.PendantPrice
)
pager = &model.Pager{
PN: arg.PN,
PS: arg.PS,
}
// all group pendants
if arg.GID == 0 {
if total, err = s.d.PendantGroupInfoTotal(c); err != nil {
err = errors.Wrap(err, "s.d.PendantGroupInfoTotal()")
return
}
if total <= 0 {
return
}
pager.Total = total
if pis, pids, err = s.d.PendantInfoAll(c, arg.PN, arg.PS); err != nil {
err = errors.Wrapf(err, "s.d.PendantInfoAll(%d,%d)", arg.PN, arg.PS)
return
}
if len(pis) == 0 || len(pids) == 0 {
log.Warn("no pendant list")
return
}
if ppm, err = s.d.PendantPriceIDs(c, pids); err != nil {
err = errors.Wrapf(err, "s.d.PendantPriceIDs(%s)", xstr.JoinInts(pids))
return
}
for _, pi := range pis {
if pp, ok := ppm[pi.ID]; ok {
pi.Prices = pp
}
}
return
}
// one group pendants
if total, err = s.d.PendantGroupRefsGidTotal(c, arg.GID); err != nil {
err = errors.Wrap(err, "s.d.PendantGroupRefsGidTotal()")
return
}
if total <= 0 {
return
}
pager.Total = total
var pg *model.PendantGroup
if pids, err = s.d.PendantGroupPIDs(c, arg.GID, arg.PN, arg.PS); err != nil {
err = errors.Wrapf(err, "s.d.PendantGroupPIDs(%d,%d,%d)", arg.GID, arg.PN, arg.PS)
return
}
if pg, err = s.d.PendantGroupID(c, arg.GID); err != nil {
err = errors.Wrapf(err, "s.d.PendantGroupID(%d)", arg.GID)
return
}
if len(pids) == 0 {
log.Warn("no pendant group relation")
return
}
if pis, _, err = s.d.PendantInfoIDs(c, pids); err != nil {
err = errors.Wrapf(err, "s.d.PendantInfoIDs(%s)", xstr.JoinInts(pids))
return
}
if len(pis) == 0 {
log.Warn("no pendant list")
return
}
if ppm, err = s.d.PendantPriceIDs(c, pids); err != nil {
err = errors.Wrapf(err, "s.d.PendantPriceIDs(%s)", xstr.JoinInts(pids))
return
}
for _, pi := range pis {
if pp, ok := ppm[pi.ID]; ok {
pi.Prices = pp
}
pi.GID = arg.GID
pi.GroupName = pg.Name
pi.GroupRank = pg.Rank
}
return
}
// PendantInfoID pendant info by pid and gid.
func (s *Service) PendantInfoID(c context.Context, pid, gid int64) (pi *model.PendantInfo, err error) {
if pi, err = s.d.PendantInfoID(c, pid); err != nil {
err = errors.Wrapf(err, "s.d.PendantInfoID(%d)", pid)
return
}
if pi == nil {
err = ecode.PendantNotFound
return
}
var (
pg *model.PendantGroup
ppm map[int64][]*model.PendantPrice
)
if pg, err = s.d.PendantGroupID(c, gid); err != nil {
err = errors.Wrapf(err, "s.d.PendantGroupID(%d)", gid)
return
}
if ppm, err = s.d.PendantPriceIDs(c, []int64{pid}); err != nil {
err = errors.Wrapf(err, "s.d.PendantPriceIDs(%d)", pid)
return
}
pi.GID = gid
pi.GroupName = pg.Name
pi.GroupRank = pg.Rank
if pp, ok := ppm[pid]; ok {
pi.Prices = pp
}
return
}
// PendantGroupID pendant group by ID.
func (s *Service) PendantGroupID(c context.Context, gid int64) (pg *model.PendantGroup, err error) {
if pg, err = s.d.PendantGroupID(c, gid); err != nil {
err = errors.Wrapf(err, "s.d.PendantGroupID(%d)", gid)
}
return
}
// PendantGroupList group page.
func (s *Service) PendantGroupList(c context.Context, arg *model.ArgPendantGroupList) (pgs []*model.PendantGroup, pager *model.Pager, err error) {
var total int64
pager = &model.Pager{
PN: arg.PN,
PS: arg.PS,
}
if total, err = s.d.PendantGroupsTotal(c); err != nil {
err = errors.Wrap(err, "s.d.PendantGroupsTotal()")
return
}
if total <= 0 {
return
}
pager.Total = total
if pgs, err = s.d.PendantGroups(c, arg.PN, arg.PS); err != nil {
err = errors.Wrapf(err, "s.d.PendantGroups(%d,%d)", arg.PN, arg.PS)
}
return
}
// PendantGroupAll all groups.
func (s *Service) PendantGroupAll(c context.Context) (pgs []*model.PendantGroup, err error) {
if pgs, err = s.d.PendantGroupAll(c); err != nil {
err = errors.Wrap(err, "s.d.PendantGroupAll()")
return
}
return
}
// PendantInfoAllNoPage all info on no page.
func (s *Service) PendantInfoAllNoPage(c context.Context) (pis []*model.PendantInfo, err error) {
if pis, err = s.d.PendantInfoAllNoPage(c); err != nil {
err = errors.Wrap(err, "s.d.PendantInfoAllNoPage()")
return
}
return
}
// AddPendantInfo add pendantInfo .
func (s *Service) AddPendantInfo(c context.Context, arg *model.ArgPendantInfo) (err error) {
var pg *model.PendantGroup
if pg, err = s.d.PendantGroupID(c, arg.GID); err != nil {
err = errors.Wrapf(err, "s.d.PendantGroupID(%d)", arg.GID)
return
}
if pg == nil {
err = errors.New("group no exist")
return
}
// begin tran
var tx *sql.Tx
if tx, err = s.d.BeginTran(c); err != nil {
err = errors.Wrap(err, "s.arc.BeginTran()")
return
}
defer func() {
if err != nil {
tx.Rollback()
} else {
tx.Commit()
}
}()
pi := &model.PendantInfo{
Name: arg.Name,
Image: arg.Image,
ImageModel: arg.ImageModel,
Status: arg.Status,
Rank: arg.Rank,
}
var pid int64
if pid, err = s.d.TxAddPendantInfo(tx, pi); err != nil {
err = errors.Wrapf(err, "s.d.TxAddPendantInfo(%+v)", pi)
return
}
arg.PID = pid
pr := &model.PendantGroupRef{GID: arg.GID, PID: arg.PID}
if _, err = s.d.TxAddPendantGroupRef(tx, pr); err != nil {
err = errors.Wrapf(err, "s.d.TxAddPendantGroupRef(%+v)", pr)
return
}
pp := &model.PendantPrice{}
for _, tp := range model.PriceTypes {
pp.BulidPendantPrice(arg, tp)
if pp.Price != 0 {
if _, err = s.d.TxAddPendantPrices(tx, pp); err != nil {
err = errors.Wrapf(err, "s.d.TxAddPendantPrices(%+v)", pp)
return
}
}
}
return
}
// UpPendantInfo update pendant info .
func (s *Service) UpPendantInfo(c context.Context, arg *model.ArgPendantInfo) (err error) {
// begin tran
var tx *sql.Tx
if tx, err = s.d.BeginTran(c); err != nil {
err = errors.Wrap(err, "s.arc.BeginTran()")
return
}
defer func() {
if err != nil {
tx.Rollback()
} else {
tx.Commit()
}
}()
pi := &model.PendantInfo{
ID: arg.PID,
Name: arg.Name,
Image: arg.Image,
ImageModel: arg.ImageModel,
Status: arg.Status,
Rank: arg.Rank,
}
if _, err = s.d.TxUpPendantInfo(tx, pi); err != nil {
err = errors.Wrapf(err, "s.d.TxUpPendantInfo(%+v)", pi)
return
}
if _, err = s.d.TxUpPendantGroupRef(tx, arg.GID, arg.PID); err != nil {
err = errors.Wrapf(err, "s.d.TxUpPendantGroupRef(%d,%d)", arg.GID, arg.PID)
return
}
pp := &model.PendantPrice{}
for _, tp := range model.PriceTypes {
pp.BulidPendantPrice(arg, tp)
if pp.Price != 0 {
if _, err = s.d.TxAddPendantPrices(tx, pp); err != nil {
err = errors.Wrapf(err, "s.d.TxAddPendantPrices(%+v)", pp)
return
}
}
}
return
}
// UpPendantGroupStatus update pendant group status
func (s *Service) UpPendantGroupStatus(c context.Context, gid int64, status int8) (err error) {
if _, err = s.d.UpPendantGroupStatus(c, gid, status); err != nil {
err = errors.Wrapf(err, "s.d.UpPendantGroupStatus(%d,%d)", gid, status)
}
return
}
// UpPendantInfoStatus update pendant info status
func (s *Service) UpPendantInfoStatus(c context.Context, pid int64, status int8) (err error) {
if _, err = s.d.UpPendantInfoStatus(c, pid, status); err != nil {
err = errors.Wrapf(err, "s.d.UpPendantInfoStatus(%d,%d)", pid, status)
}
return
}
// AddPendantGroup update pendant group.
func (s *Service) AddPendantGroup(c context.Context, arg *model.ArgPendantGroup) (err error) {
pg := &model.PendantGroup{
Name: arg.Name,
Rank: arg.Rank,
Status: arg.Status,
}
if _, err = s.d.AddPendantGroup(c, pg); err != nil {
err = errors.Wrapf(err, "s.d.AddPendantGroup(%+v)", pg)
}
return
}
// UpPendantGroup update pendant group.
func (s *Service) UpPendantGroup(c context.Context, arg *model.ArgPendantGroup) (err error) {
if arg.GID == 0 {
err = ecode.PendantNotFound
return
}
pg := &model.PendantGroup{
ID: arg.GID,
Name: arg.Name,
Rank: arg.Rank,
Status: arg.Status,
}
if _, err = s.d.UpPendantGroup(c, pg); err != nil {
err = errors.Wrapf(err, "s.d.UpPendantGroup(%+v)", pg)
}
return
}
// PendantOrders get pendant order historys.
func (s *Service) PendantOrders(c context.Context, arg *model.ArgPendantOrder) (pos []*model.PendantOrder, pager *model.Pager, err error) {
var total int64
pager = &model.Pager{
PN: arg.PN,
PS: arg.PS,
}
if total, err = s.d.MaxOrderHistory(c); err != nil {
err = errors.Wrapf(err, "s.d.MaxOrderHistory(%+v)", arg)
return
}
if total <= 0 {
return
}
pager.Total = total
var pids []int64
if pos, pids, err = s.d.OrderHistorys(c, arg); err != nil {
err = errors.Wrapf(err, "s.d.OrderHistorys(%+v)", arg)
return
}
if len(pids) == 0 {
return
}
var pim map[int64]*model.PendantInfo
if _, pim, err = s.d.PendantInfoIDs(c, pids); err != nil {
err = errors.Wrapf(err, "s.d.PendantInfoIDs(%v)", xstr.JoinInts(pids))
return
}
for _, v := range pos {
if pi, ok := pim[v.PID]; ok {
v.PName = pi.Name
}
v.CoverToPlatform()
}
return
}
// PendantPKG get pendant in pkg.
func (s *Service) PendantPKG(c context.Context, uid int64) (pkgs []*model.PendantPKG, equip *model.PendantPKG, err error) {
if equip, err = s.d.PendantEquipUID(c, uid); err != nil {
err = errors.Wrapf(err, "s.d.PendantEquipUID(%d)", uid)
return
}
if pkgs, err = s.d.PendantPKGs(c, uid); err != nil {
err = errors.Wrapf(err, "s.d.PendantPKGs(%d)", uid)
return
}
if len(pkgs) == 0 {
return
}
var time = time.Now().Unix()
for _, pkg := range pkgs {
if equip != nil && pkg.PID == equip.PID {
pkg.Status = model.PendantPKGOnEquip
}
if pkg.Status == model.PendantPKGValid && pkg.Expires < time {
pkg.Status = model.PendantPKGInvalid
}
}
return
}
// UserPKGDetails get user pkg 's pendant details.
func (s *Service) UserPKGDetails(c context.Context, uid, pid int64) (pkg *model.PendantPKG, err error) {
if pkg, err = s.d.PendantPKG(c, uid, pid); err != nil {
err = errors.Wrapf(err, "s.d.PendantPKG(%d,%d)", uid, pid)
}
return
}
// EquipPendant equip pendant.
func (s *Service) EquipPendant(c context.Context, uid, pid int64) (err error) {
var pkg *model.PendantPKG
if pkg, err = s.d.PendantPKG(c, uid, pid); err != nil {
err = errors.Wrapf(err, "s.d.PendantPKG(%d,%d)", uid, pid)
return
}
if pkg == nil || pkg.Expires < time.Now().Unix() {
log.Warn("pid(%d) not exist or expires(%d) is failed", pid, time.Now().Unix())
return
}
if _, err = s.d.AddPendantEquip(c, pkg); err != nil {
err = errors.Wrapf(err, "s.d.AddPendantEquip(%+v)", pkg)
return
}
s.addAsyn(func() {
if err = s.d.DelEquipsCache(context.Background(), []int64{uid}); err != nil {
log.Error("s.d.DelEquipsCache(%d) error(%+v)", uid, err)
return
}
})
s.addAsyn(func() {
if err = s.accNotify(context.Background(), uid, model.AccountNotifyUpdatePendant); err != nil {
log.Error("s.accNotify(%d) error(%+v)", uid, err)
return
}
})
return
}
// UpPendantPKG update user pkg.
func (s *Service) UpPendantPKG(c context.Context, uid, pid int64, day int64, msg *model.SysMsg, oid int64) (err error) {
var (
pi *model.PendantInfo
pkg *model.PendantPKG
)
if pi, err = s.d.PendantInfoID(c, pid); err != nil {
err = errors.Wrapf(err, "s.d.PendantInfoID(%d)", pid)
return
}
if pi == nil {
err = ecode.PendantNotFound
return
}
if pkg, err = s.d.PendantPKG(c, uid, pid); err != nil {
err = errors.Wrapf(err, "s.d.PendantPKG(%d,%d)", uid, pid)
return
}
if pkg == nil {
pkg = &model.PendantPKG{}
}
var operAction string
switch msg.Type {
case model.PendantAddStyleDay:
if pkg.Expires < time.Now().Unix() {
pkg.Expires = time.Now().Unix() + day*86400
pkg.PID = pid
pkg.UID = uid
pkg.TP = model.PendantAddStyleDay
} else {
pkg.Expires = pkg.Expires + day*86400
}
operAction = fmt.Sprintf("新增%s挂件 %d天", pi.Name, day)
case model.PendantAddStyleDate:
if pkg.ID == 0 {
err = errors.New("no pkg")
return
}
oldExpires := pkg.Expires
pkg.Expires = day
operAction = fmt.Sprintf("修改%s挂件 到期时间从%s至%s", pi.Name,
xtime.Time(oldExpires).Time().Format("2006-01-02 15:04:05"),
xtime.Time(pkg.Expires).Time().Format("2006-01-02 15:04:05"))
}
if _, err = s.d.AddPendantPKG(c, pkg); err != nil {
err = errors.Wrapf(err, "s.d.AddPendantPKG(%+v)", pkg)
return
}
if msg.IsMsg {
s.addAsyn(func() {
msg.Type = model.MsgTypeCustom
title, content, ip := model.MsgInfo(msg)
if err = s.d.SendSysMsg(context.Background(), []int64{uid}, title, content, ip); err != nil {
log.Error("s.d.MutliSendSysMsg(%d,%s,%s,%s) error(%+v)", uid, title, content, ip, err)
}
})
}
s.addAsyn(func() {
if err = s.d.DelPKGCache(context.Background(), []int64{uid}); err != nil {
log.Error("s.d.DelPKGCache(%d) error(%+v)", uid, err)
}
if err = s.d.SetPendantPointCache(context.Background(), uid, pid); err != nil {
log.Error("s.d.SetPendantPointCache(%d,%d) error(%+v)", uid, pid, err)
}
if _, err = s.d.AddPendantOperLog(context.Background(), oid, []int64{uid}, pid, operAction); err != nil {
log.Error("s.d.AddPendantOperLog(%d,%s) error(%+v)", oid, operAction, err)
}
})
s.addAsyn(func() {
if err = s.accNotify(context.Background(), uid, model.AccountNotifyUpdatePendant); err != nil {
log.Error("s.accNotify(%d) error(%+v)", uid, err)
return
}
})
return
}
// MutliSendPendant mutli send pendant.
func (s *Service) MutliSendPendant(c context.Context, uids []int64, pid int64, day int64, msg *model.SysMsg, oid int64) (err error) {
var (
pi *model.PendantInfo
opkgs, npkgs []*model.PendantPKG
)
if pi, err = s.d.PendantInfoID(c, pid); err != nil {
err = errors.Wrapf(err, "s.d.PendantInfoID(%d)", pid)
return
}
if pi == nil {
err = ecode.PendantNotFound
return
}
if opkgs, err = s.d.PendantPKGUIDs(c, uids, pid); err != nil {
err = errors.Wrapf(err, "s.d.PendantPKGUIDs(%+v,%d)", uids, pid)
return
}
var ouids, nuids []int64
for _, pkg := range opkgs {
if pkg.Expires < time.Now().Unix() {
pkg.Expires = time.Now().Unix() + day*86400
} else {
pkg.Expires = pkg.Expires + day*86400
}
ouids = append(ouids, pkg.UID)
}
nuids = s.diffSlice(uids, ouids)
for _, nuid := range nuids {
npkgs = append(npkgs, &model.PendantPKG{PID: pid, UID: nuid, Expires: time.Now().Unix() + day*86400})
}
// begin tran
var tx *sql.Tx
if tx, err = s.d.BeginTran(c); err != nil {
err = errors.Wrap(err, "s.arc.BeginTran()")
return
}
defer func() {
if err != nil {
tx.Rollback()
} else {
tx.Commit()
}
}()
if len(npkgs) != 0 {
if _, err = s.d.TxAddPendantPKGs(tx, npkgs); err != nil {
err = errors.Wrapf(err, "s.d.TxAddPendantPKGs(%d,%s)", pid, xstr.JoinInts(nuids))
return
}
}
if len(opkgs) != 0 {
if _, err = s.d.TxUpPendantPKGs(tx, opkgs); err != nil {
err = errors.Wrapf(err, "s.d.TxUpPendantPKGs(%d,%s)", pid, xstr.JoinInts(ouids))
return
}
}
if msg.IsMsg {
s.addAsyn(func() {
title, content, ip := model.MsgInfo(msg)
if err = s.d.MutliSendSysMsg(context.Background(), uids, title, content, ip); err != nil {
log.Error("s.d.MutliSendSysMsg(%s,%s,%s,%s) error(%+v)", xstr.JoinInts(uids), title, content, ip, err)
}
})
}
s.addAsyn(func() {
if err = s.d.DelPKGCache(context.Background(), uids); err != nil {
log.Error("s.d.DelPKGCache(%s) error(%+v)", xstr.JoinInts(uids), err)
}
operAction := fmt.Sprintf("新增%s挂件 %d天", pi.Name, day)
if _, err = s.d.AddPendantOperLog(context.Background(), oid, uids, pid, operAction); err != nil {
log.Error("s.d.AddPendantOperLog(%d,%s,%s) error(%+v)", oid, xstr.JoinInts(uids), operAction, err)
}
})
for _, uid := range uids {
tid := uid
s.addAsyn(func() {
if err = s.accNotify(context.Background(), tid, model.AccountNotifyUpdatePendant); err != nil {
log.Error("s.accNotify(%d) error(%+v)", tid, err)
}
if err = s.d.SetPendantPointCache(context.Background(), tid, pid); err != nil {
log.Error("s.d.SetPendantPointCache(%d,%d) error(%+v)", tid, pid, err)
}
})
}
return
}
func (s *Service) diffSlice(sliceOne, sliceTwo []int64) (res []int64) {
for _, ov := range sliceOne {
inSlice := func(ov int64, sliceTwo []int64) bool {
for _, tv := range sliceTwo {
if tv == ov {
return true
}
}
return false
}(ov, sliceTwo)
if !inSlice {
res = append(res, ov)
}
}
return
}
// PendantOperlog pendant operactlog .
func (s *Service) PendantOperlog(c context.Context, pn, ps int) (opers []*model.PendantOperLog, pager *model.Pager, err error) {
var total int64
pager = &model.Pager{
PN: pn,
PS: ps,
}
if total, err = s.d.PendantOperationLogTotal(c); err != nil {
err = errors.Wrap(err, "s.d.PendantOperationLogTotal()")
return
}
if total <= 0 {
return
}
pager.Total = total
var uids []int64
if opers, uids, err = s.d.PendantOperLog(c, pn, ps); err != nil {
err = errors.Wrapf(err, "s.d.PendantOperLog(%d,%d)", pn, ps)
return
}
var accInfoMap map[int64]*accmdl.Info
if accInfoMap, err = s.fetchInfos(c, uids, _fetchInfoTimeout); err != nil {
log.Error("service.fetchInfos(%v, %v) error(%v)", xstr.JoinInts(uids), _fetchInfoTimeout, err)
err = nil
}
for _, v := range opers {
if accInfo, ok := accInfoMap[v.UID]; ok {
v.Action = fmt.Sprintf("给用户(%s) %s", accInfo.Name, v.Action)
}
if operName, ok := s.Managers[v.OID]; ok {
v.OperName = operName
}
}
return
}

View File

@@ -0,0 +1,146 @@
package service
import (
"context"
"testing"
"go-common/app/admin/main/usersuit/model"
. "github.com/smartystreets/goconvey/convey"
)
func Test_PendantInfoList(t *testing.T) {
Convey("return sth", t, func() {
arg := &model.ArgPendantGroupList{}
res, pager, err := s.PendantInfoList(context.Background(), arg)
So(err, ShouldBeNil)
So(res, ShouldNotBeNil)
So(pager, ShouldNotBeNil)
})
}
func Test_PendantInfoID(t *testing.T) {
Convey("return sth", t, func() {
pi, err := s.PendantInfoID(context.Background(), 11, 22)
So(err, ShouldBeNil)
So(pi, ShouldNotBeNil)
})
}
func Test_PendantGroupID(t *testing.T) {
Convey("return sth", t, func() {
pg, err := s.PendantGroupID(context.Background(), 11)
So(err, ShouldBeNil)
So(pg, ShouldNotBeNil)
})
}
func Test_PendantGroupList(t *testing.T) {
Convey("return sth", t, func() {
arg := &model.ArgPendantGroupList{}
pgs, pager, err := s.PendantGroupList(context.Background(), arg)
So(err, ShouldBeNil)
So(pgs, ShouldNotBeNil)
So(pager, ShouldNotBeNil)
})
}
func Test_PendantGroupAll(t *testing.T) {
Convey("return sth", t, func() {
pgs, err := s.PendantGroupAll(context.Background())
So(err, ShouldBeNil)
So(pgs, ShouldNotBeNil)
})
}
func Test_PendantInfoAllOnSale(t *testing.T) {
Convey("return sth", t, func() {
pis, err := s.PendantInfoAllNoPage(context.Background())
So(err, ShouldBeNil)
So(pis, ShouldNotBeNil)
})
}
func Test_AddPendantInfo(t *testing.T) {
Convey("return sth", t, func() {
arg := &model.ArgPendantInfo{
PID: 111,
GID: 22,
Name: "222",
Image: "sdada",
ImageModel: "dasdada",
Rank: 11,
Status: 1,
IntegralPrice: 22,
}
err := s.AddPendantInfo(context.Background(), arg)
So(err, ShouldBeNil)
})
}
func Test_UpPendantInfo(t *testing.T) {
Convey("return sth", t, func() {
arg := &model.ArgPendantInfo{
PID: 111,
GID: 22,
Name: "222",
Image: "sdada",
ImageModel: "dasdada",
Rank: 11,
Status: 1,
IntegralPrice: 22,
}
err := s.UpPendantInfo(context.Background(), arg)
So(err, ShouldBeNil)
})
}
func Test_UpPendantGroupStatus(t *testing.T) {
Convey("return sth", t, func() {
err := s.UpPendantGroupStatus(context.Background(), 1, 1)
So(err, ShouldBeNil)
})
}
func Test_UpPendantInfoStatus(t *testing.T) {
Convey("return sth", t, func() {
err := s.UpPendantInfoStatus(context.Background(), 1, 1)
So(err, ShouldBeNil)
})
}
func Test_AddPendantGroup(t *testing.T) {
Convey("return sth", t, func() {
arg := &model.ArgPendantGroup{
GID: 1,
Name: "2121",
Rank: 11,
Status: 1,
}
err := s.AddPendantGroup(context.Background(), arg)
So(err, ShouldBeNil)
})
}
func Test_UpPendantGroup(t *testing.T) {
Convey("return sth", t, func() {
arg := &model.ArgPendantGroup{
GID: 1,
Name: "2121",
Rank: 11,
Status: 1,
}
err := s.UpPendantGroup(context.Background(), arg)
So(err, ShouldBeNil)
})
}
func Test_PendantOrders(t *testing.T) {
Convey("return sth", t, func() {
arg := &model.ArgPendantOrder{}
pos, pager, err := s.PendantOrders(context.Background(), arg)
So(err, ShouldBeNil)
So(pos, ShouldNotBeNil)
So(pager, ShouldNotBeNil)
})
}

View File

@@ -0,0 +1,97 @@
package service
import (
"context"
"sync"
"time"
"go-common/app/admin/main/usersuit/conf"
"go-common/app/admin/main/usersuit/dao"
"go-common/library/log"
"go-common/library/queue/databus"
account "go-common/app/service/main/account/api"
)
// Service struct of service.
type Service struct {
d *dao.Dao
// wait group
wg sync.WaitGroup
// conf
c *conf.Config
accountClient account.AccountClient
// databus pub
accountNotifyPub *databus.Databus
Managers map[int64]string
asynch chan func()
}
// New create service instance and return.
func New(c *conf.Config) (s *Service) {
s = &Service{
c: c,
d: dao.New(c),
asynch: make(chan func(), 102400),
accountNotifyPub: databus.New(c.AccountNotify),
}
var err error
if s.accountClient, err = account.NewClient(c.AccountGRPC); err != nil {
panic(err)
}
s.loadManager()
s.wg.Add(1)
go s.asynproc()
go s.loadmanagerproc()
return
}
func (s *Service) loadmanagerproc() {
for {
time.Sleep(1 * time.Hour)
s.loadManager()
}
}
func (s *Service) loadManager() {
managers, err := s.d.Managers(context.TODO())
if err != nil {
log.Error("s.Managers error(%v)", err)
return
}
s.Managers = managers
}
// Close dao.
func (s *Service) Close() {
s.d.Close()
close(s.asynch)
time.Sleep(1 * time.Second)
s.wg.Wait()
}
// Ping check server ok.
func (s *Service) Ping(c context.Context) (err error) {
err = s.d.Ping(c)
return
}
func (s *Service) addAsyn(f func()) {
select {
case s.asynch <- f:
default:
log.Warn("asynproc chan full")
}
}
// cacheproc is a routine for executing closure.
func (s *Service) asynproc() {
defer s.wg.Done()
for {
f, ok := <-s.asynch
if !ok {
return
}
f()
}
}

View File

@@ -0,0 +1,19 @@
package service
import (
"flag"
"path/filepath"
"time"
"go-common/app/admin/main/usersuit/conf"
)
var s *Service
func init() {
dir, _ := filepath.Abs("../cmd/convey-test.toml")
flag.Set("conf", dir)
conf.Init()
s = New(conf.Conf)
time.Sleep(time.Second)
}

View File

@@ -0,0 +1,16 @@
package service
import (
"context"
"io"
"go-common/library/log"
)
// Upload http upload file.
func (s *Service) Upload(c context.Context, fileName, fileType string, expire int64, body io.Reader) (location string, err error) {
if location, err = s.d.Upload(c, fileName, fileType, expire, body); err != nil {
log.Error("s.upload.Upload() error(%v)", err)
}
return
}