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,53 @@
package(default_visibility = ["//visibility:public"])
load(
"@io_bazel_rules_go//go:def.bzl",
"go_test",
"go_library",
)
go_test(
name = "go_default_test",
srcs = ["wechat_test.go"],
embed = [":go_default_library"],
rundir = ".",
tags = ["automanaged"],
deps = [
"//app/admin/ep/saga/conf:go_default_library",
"//app/admin/ep/saga/dao:go_default_library",
"//app/admin/ep/saga/model:go_default_library",
"//vendor/github.com/smartystreets/goconvey/convey:go_default_library",
],
)
go_library(
name = "go_default_library",
srcs = [
"contact.go",
"wechat.go",
],
importpath = "go-common/app/admin/ep/saga/service/wechat",
tags = ["automanaged"],
visibility = ["//visibility:public"],
deps = [
"//app/admin/ep/saga/conf:go_default_library",
"//app/admin/ep/saga/dao:go_default_library",
"//app/admin/ep/saga/model:go_default_library",
"//library/log: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,189 @@
package wechat
import (
"context"
"go-common/app/admin/ep/saga/model"
"go-common/library/log"
)
// Changes changes structure
type Changes struct {
Adds []*model.ContactInfo
Upts []*model.ContactInfo
Dels []*model.ContactInfo
}
// SyncContacts sync the contacts from wechat work 更新用户信息列表
func (w *Wechat) SyncContacts(c context.Context) (err error) {
//更新数据库用户列表 contact_infos
if err = w.AnalysisContacts(c); err != nil {
return
}
//更新用户saga信息
/*if err = w.UpdateVisible(c); err != nil {
return
}*/
return
}
// AnalysisContacts analysis the contact difference and save them 从企业微信更新用户列表最新
func (w *Wechat) AnalysisContacts(c context.Context) (err error) {
var (
contactsInDB []*model.ContactInfo
wechatContacts []*model.ContactInfo
changes = &Changes{}
)
//数据库里查询用户信息列表
if contactsInDB, err = w.dao.ContactInfos(); err != nil {
return
}
//企业微信接口查询用户列表
if wechatContacts, err = w.QueryWechatContacts(c); err != nil {
return
}
if changes, err = w.diffChanges(wechatContacts, contactsInDB); err != nil {
return
}
//saveChanges 更新用户信息
if err = w.saveChanges(changes); err != nil {
return
}
return
}
// QueryWechatContacts query wechat contacts with access token 获取用户信息列表
func (w *Wechat) QueryWechatContacts(c context.Context) (contacts []*model.ContactInfo, err error) {
var (
token string
)
if token, err = w.AccessToken(c, w.contact); err != nil {
return
}
if contacts, err = w.dao.WechatContacts(c, token); err != nil {
return
}
return
}
//saveChanges 保存企业微信与数据库用户信息的更新内容
func (w *Wechat) saveChanges(changes *Changes) (err error) {
var (
contact *model.ContactInfo
)
log.Info("saveChanges add(%d), upt(%d), del(%d)", len(changes.Adds), len(changes.Upts), len(changes.Dels))
for _, contact = range changes.Adds {
if err = w.dao.CreateContact(contact); err != nil {
return
}
log.Info("saveChanges add: %v", contact)
}
for _, contact = range changes.Upts {
if err = w.dao.UptContact(contact); err != nil {
return
}
log.Info("saveChanges upt: %v", contact)
}
for _, contact = range changes.Dels {
if err = w.dao.DelContact(contact); err != nil {
return
}
log.Info("saveChanges del: %v", contact)
}
return
}
//diffChanges 对比企业微信用户列表和数据库用户列表
func (w *Wechat) diffChanges(wechatContacts, contactsInDB []*model.ContactInfo) (changes *Changes, err error) {
var (
contact *model.ContactInfo
wechatContactsMap = make(map[string]*model.ContactInfo)
contactsInDBMap = make(map[string]*model.ContactInfo)
wechatContactIDs []string
dbContactsIDs []string
userID string
)
changes = new(Changes)
for _, contact = range wechatContacts {
wechatContactsMap[contact.UserID] = contact
wechatContactIDs = append(wechatContactIDs, contact.UserID)
}
for _, contact = range contactsInDB {
contactsInDBMap[contact.UserID] = contact
dbContactsIDs = append(dbContactsIDs, contact.UserID)
}
// 分析变化
for _, userID = range wechatContactIDs {
contact = wechatContactsMap[userID]
if w.inSlice(dbContactsIDs, userID) { // 企业微信联系人ID在数据库中能找到
if !contact.AlmostEqual(contactsInDBMap[userID]) { // 但是域不同
contact.ID = contactsInDBMap[userID].ID
changes.Upts = append(changes.Upts, contact)
}
} else {
changes.Adds = append(changes.Adds, contact) // 这个联系人是新增的
}
}
for _, userID = range dbContactsIDs {
if !w.inSlice(wechatContactIDs, userID) {
changes.Dels = append(changes.Dels, contactsInDBMap[userID])
}
}
return
}
func (w *Wechat) inSlice(slice []string, target string) bool {
for _, v := range slice {
if v == target {
return true
}
}
return false
}
// UpdateVisible update the visible property 更新用户saga信息
func (w *Wechat) UpdateVisible(c context.Context) (err error) {
var (
user *model.UserInfo
users []*model.UserInfo
contact *model.ContactInfo
)
//获取用户ID列表
if users, err = w.querySagaVisible(c); err != nil {
return
}
for _, user = range users {
//定义用户信息--saga是否可使用
contact = &model.ContactInfo{UserID: user.UserID, VisibleSaga: true}
if err = w.dao.UptContact(contact); err != nil {
return
}
}
return
}
//querySagaVisible 获取用户ID列表
func (w *Wechat) querySagaVisible(c context.Context) (users []*model.UserInfo, err error) {
var (
token string
)
if token, err = w.AccessToken(c, w.saga); err != nil {
return
}
if users, err = w.dao.WechatSagaVisible(c, token, w.saga.AppID); err != nil {
return
}
return
}

View File

@@ -0,0 +1,182 @@
package wechat
import (
"context"
"encoding/json"
"fmt"
"strings"
"go-common/app/admin/ep/saga/conf"
"go-common/app/admin/ep/saga/dao"
"go-common/app/admin/ep/saga/model"
"go-common/library/log"
"github.com/pkg/errors"
)
// Wechat 企业微信应用
type Wechat struct {
dao *dao.Dao
saga *model.AppConfig
contact *model.AppConfig
}
// New create an new wechat work
func New(d *dao.Dao) (w *Wechat) {
w = &Wechat{
dao: d,
saga: conf.Conf.Property.Wechat,
contact: conf.Conf.Property.Contact,
}
return w
}
// NewTxtNotify create wechat format text notification 从配置初始化企业微信TxtNotification
func (w *Wechat) NewTxtNotify(content string) (txtMsg *model.TxtNotification) {
return &model.TxtNotification{
Notification: model.Notification{
MsgType: "text",
AgentID: w.saga.AppID,
},
Body: model.Text{
Content: content,
},
Safe: 0,
}
}
// AccessToken get access_token from cache first, if not found, get it via wechat api.
func (w *Wechat) AccessToken(c context.Context, app *model.AppConfig) (token string, err error) {
var (
key string
expire int32
)
key = fmt.Sprintf("appid_%d", app.AppID)
if token, err = w.dao.AccessTokenRedis(c, key); err != nil {
log.Warn("AccessToken: failed to get access_token from cache, appId (%s), error (%s)", app.AppID, err.Error())
//企业微信api获取公司token
if token, expire, err = w.dao.WechatAccessToken(c, app.AppSecret); err != nil {
err = errors.Wrapf(err, "AccessToken: both mc and api can't provide access_token, appId(%s)", app.AppID)
return
}
// 通过API获取到了缓存一波
err = w.dao.SetAccessTokenRedis(c, key, token, expire)
return
}
if token == "" {
if token, expire, err = w.dao.WechatAccessToken(c, app.AppSecret); err != nil {
return
}
// 通过API获取到了缓存一波
err = w.dao.SetAccessTokenRedis(c, key, token, expire)
}
return
}
// PushMsg push text message via wechat notification api with access_token.推送企业微信
func (w *Wechat) PushMsg(c context.Context, userNames []string, content string) (err error) {
var (
token string
userIds string
invalidUser string
userNamesByte []byte
txtMsg = w.NewTxtNotify(content)
contentDB = content
)
//获取企业token
if token, err = w.AccessToken(c, w.saga); err != nil {
return
}
if token == "" {
err = errors.Errorf("PushMsg: get access token failed, it's empty. appid (%s), secret (%s)", w.saga.AppID, w.saga.AppSecret)
return
}
//员工编号以竖线分隔
if userIds, err = w.UserIds(userNames); err != nil {
return
}
txtMsg.ToUser = userIds
if invalidUser, err = w.dao.WechatPushMsg(c, token, txtMsg); err != nil {
if err = w.addRequireVisible(c, invalidUser); err != nil {
log.Error("PushMsg add userID (%s) in cache, error(%s)", invalidUser, err.Error())
}
return
}
if userNamesByte, err = json.Marshal(userNames); err != nil {
return
}
if len(contentDB) > model.MaxWechatLen {
contentDB = contentDB[:model.MaxWechatLen]
}
messageLog := &model.WechatMessageLog{
Touser: string(userNamesByte),
Content: contentDB,
Status: 1,
}
return w.dao.CreateMessageLog(messageLog)
}
// UserIds query user ids for user name list 查询员工编号
func (w *Wechat) UserIds(userNames []string) (ids string, err error) {
if ids, err = w.dao.UserIds(userNames); err != nil {
return
}
return
}
// addRequireVisible update wechat require visible users in memcache
func (w *Wechat) addRequireVisible(c context.Context, userIDs string) (err error) {
var (
contactInfo *model.ContactInfo
userID string
alreadyIn bool
)
users := strings.Split(userIDs, "|")
for _, userID = range users {
//查看是否缓存,缓存则继续
if alreadyIn, err = w.alreadyInCache(c, userID); err != nil || alreadyIn {
continue
}
//未缓存从数据库查询
if contactInfo, err = w.dao.QueryUserByID(userID); err != nil {
log.Error("no such userID (%s) in db, error(%s)", userID, err.Error())
return
}
//数据库查询结果缓存
if err = w.dao.SetRequireVisibleUsersRedis(c, contactInfo); err != nil {
log.Error("failed set to cache userID (%s) username (%s), err (%s)", userID, contactInfo.UserName, err.Error())
return
}
}
return
}
// alreadyInCache check user is or not in the memcache
func (w *Wechat) alreadyInCache(c context.Context, userID string) (alreadyIn bool, err error) {
var (
userMap = make(map[string]model.RequireVisibleUser)
)
//查询所有的值
if err = w.dao.RequireVisibleUsersRedis(c, &userMap); err != nil {
log.Error("get userID (%s) from cache error(%s)", userID, err.Error())
return
}
//匹配需要查询的用户id
for k, v := range userMap {
if userID == k {
log.Info("(%s) is already exist in cache, value(%v)", k, v)
alreadyIn = true
return
}
}
return
}

View File

@@ -0,0 +1,143 @@
package wechat
import (
"context"
"flag"
"os"
"testing"
"go-common/app/admin/ep/saga/conf"
"go-common/app/admin/ep/saga/dao"
"go-common/app/admin/ep/saga/model"
. "github.com/smartystreets/goconvey/convey"
)
var (
mydao *dao.Dao
wechat *Wechat
ctx = context.Background()
)
func TestMain(m *testing.M) {
var err error
flag.Set("conf", "../../cmd/saga-admin-test.toml")
if err = conf.Init(); err != nil {
panic(err)
}
mydao = dao.New()
defer mydao.Close()
wechat = New(mydao)
os.Exit(m.Run())
}
func TestAddRequireVisible(t *testing.T) {
var (
err error
userMap = make(map[string]model.RequireVisibleUser)
)
Convey("TEST addRequireVisible", t, func() {
err = wechat.addRequireVisible(ctx, "000000")
So(err, ShouldNotBeNil)
err = wechat.addRequireVisible(ctx, "001134")
So(err, ShouldBeNil)
err = mydao.RequireVisibleUsersRedis(ctx, &userMap)
So(err, ShouldBeNil)
So(userMap, ShouldContainKey, "001134")
})
}
func TestAlreadyInCache(t *testing.T) {
var (
err error
result bool
contactInfo model.ContactInfo
)
contactInfo = model.ContactInfo{
ID: "111",
UserName: "zhangsan",
UserID: "222",
NickName: "xiaolizi",
VisibleSaga: true,
}
Convey("TEST alreadyInCache", t, func() {
result, err = wechat.alreadyInCache(ctx, "000")
So(err, ShouldBeNil)
So(result, ShouldEqual, false)
So(mydao.SetRequireVisibleUsersRedis(ctx, &contactInfo), ShouldBeNil)
result, err = wechat.alreadyInCache(ctx, "222")
So(err, ShouldBeNil)
So(result, ShouldEqual, true)
})
}
func TestSyncContacts(t *testing.T) {
var (
err error
contactInfo = &model.ContactInfo{
UserID: "E10021",
UserName: "eyotang",
NickName: "ben大神点C",
}
modify = &model.ContactInfo{
UserID: "000328",
UserName: "eyotang",
NickName: "ben大神点C",
VisibleSaga: false,
}
target *model.ContactInfo
almostEqual bool
)
Convey("TEST sync after add incorrect", t, func() {
err = wechat.dao.CreateContact(contactInfo)
So(err, ShouldBeNil)
target, err = wechat.dao.QueryUserByID(contactInfo.UserID)
So(err, ShouldBeNil)
almostEqual = contactInfo.AlmostEqual(target)
So(almostEqual, ShouldBeTrue)
err = wechat.SyncContacts(ctx)
So(err, ShouldBeNil)
target, err = wechat.dao.QueryUserByID(contactInfo.UserID)
So(err, ShouldNotBeNil)
})
Convey("TEST aync after change", t, func() {
contactInfo, err = wechat.dao.QueryUserByID(modify.UserID)
So(err, ShouldBeNil)
modify.ID = contactInfo.ID
err = wechat.dao.UptContact(contactInfo)
So(err, ShouldBeNil)
err = wechat.SyncContacts(ctx)
So(err, ShouldBeNil)
target, err = wechat.dao.QueryUserByID(modify.UserID)
So(err, ShouldBeNil)
So(target.VisibleSaga, ShouldBeTrue)
So(target.UserName, ShouldNotEqual, "eyotang")
})
}
func TestPushMsg(t *testing.T) {
var err error
userName := []string{"wuwei"}
content := "测试发送企业微信"
Convey("TEST push message", t, func() {
err = wechat.PushMsg(ctx, userName, content)
So(err, ShouldBeNil)
})
}
func TestAnalysisContacts(t *testing.T) {
var err error
Convey("TEST analysis contacts", t, func() {
err = wechat.AnalysisContacts(ctx)
So(err, ShouldBeNil)
})
}