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,96 @@
package(default_visibility = ["//visibility:public"])
load(
"@io_bazel_rules_go//go:def.bzl",
"go_test",
"go_library",
)
go_test(
name = "go_default_test",
srcs = [
"app_info_test.go",
"notice_test.go",
"remotelogin_test.go",
"reply_test.go",
"service_test.go",
"web_info_test.go",
],
embed = [":go_default_library"],
rundir = ".",
tags = ["automanaged"],
deps = [
"//app/interface/main/account/conf:go_default_library",
"//app/interface/main/account/model:go_default_library",
"//app/service/main/secure/model:go_default_library",
"//vendor/github.com/smartystreets/goconvey/convey:go_default_library",
],
)
go_library(
name = "go_default_library",
srcs = [
"app_info.go",
"medal.go",
"member.go",
"notice.go",
"remotelogin.go",
"reply.go",
"service.go",
"sudo.go",
"web_info.go",
],
importpath = "go-common/app/interface/main/account/service/member",
tags = ["automanaged"],
visibility = ["//visibility:public"],
deps = [
"//app/interface/main/account/conf:go_default_library",
"//app/interface/main/account/dao/account:go_default_library",
"//app/interface/main/account/dao/passport:go_default_library",
"//app/interface/main/account/dao/reply:go_default_library",
"//app/interface/main/account/model:go_default_library",
"//app/interface/openplatform/article/model:go_default_library",
"//app/interface/openplatform/article/rpc/client:go_default_library",
"//app/service/main/account/model:go_default_library",
"//app/service/main/account/rpc/client:go_default_library",
"//app/service/main/archive/api:go_default_library",
"//app/service/main/archive/api/gorpc:go_default_library",
"//app/service/main/archive/model/archive:go_default_library",
"//app/service/main/coin/api/gorpc:go_default_library",
"//app/service/main/coin/model:go_default_library",
"//app/service/main/filter/model/rpc:go_default_library",
"//app/service/main/filter/rpc/client:go_default_library",
"//app/service/main/location/model:go_default_library",
"//app/service/main/location/rpc/client:go_default_library",
"//app/service/main/member/api/gorpc:go_default_library",
"//app/service/main/member/model:go_default_library",
"//app/service/main/passport/model:go_default_library",
"//app/service/main/passport/rpc/client:go_default_library",
"//app/service/main/secure/model:go_default_library",
"//app/service/main/secure/rpc/client:go_default_library",
"//app/service/main/up/api/gorpc:go_default_library",
"//app/service/main/usersuit/model:go_default_library",
"//app/service/main/usersuit/rpc/client: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/queue/databus/report:go_default_library",
"//library/time: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,448 @@
package member
import (
"context"
"fmt"
"net/url"
"time"
"unicode/utf8"
"go-common/app/interface/main/account/model"
accModel "go-common/app/service/main/account/model"
coModel "go-common/app/service/main/coin/model"
ftModel "go-common/app/service/main/filter/model/rpc"
locModel "go-common/app/service/main/location/model"
meModel "go-common/app/service/main/member/model"
"go-common/library/ecode"
"go-common/library/log"
"go-common/library/net/metadata"
"go-common/library/queue/databus/report"
"github.com/pkg/errors"
)
var monitoredIPCountry = map[string]string{
"台湾": "台湾 IP",
"香港": "香港 IP",
"美国": "美国 IP",
"加拿大": "加拿大 IP",
}
var monitoredTelCountry = map[int64]string{
1: "美国/加拿大手机号",
}
var upNameCostCoins = 6.0
// Account get Account info.
func (s *Service) Account(c context.Context, mid int64, ip string) (acc *model.Account, err error) {
var (
nickFree *model.NickFree
mb *meModel.Member
)
marg := &meModel.ArgMemberMid{Mid: mid, RemoteIP: ip}
if mb, err = s.memRPC.Member(c, marg); err != nil {
log.Error("service.memberRPC.MyInfo(%v) error(%v)", marg, err)
return
}
if nickFree, err = s.NickFree(c, mid); err != nil {
return
}
acc = &model.Account{}
acc.Mid = mid
acc.Birthday = mb.Birthday.Time().Format("2006-01-02")
acc.Uname = mb.Name
acc.Face = mb.Face
acc.Sign = mb.Sign
acc.Sex = int8(mb.Sex)
acc.NickFree = nickFree.NickFree
return
}
// UpdateFace Update Face
func (s *Service) UpdateFace(c context.Context, mid int64, faceFile []byte, ftype string) (string, error) {
ip := metadata.String(c, metadata.RemoteIP)
// check
profile, err := s.accRPC.Profile3(c, &accModel.ArgMid{Mid: mid})
if err != nil {
return "", errors.WithStack(err)
}
//判断是否绑定手机号
if !s.validateTelStatus(profile.TelStatus) {
return "", ecode.MemberPhoneRequired
}
if profile.Silence != 0 {
return "", ecode.MemberBlocked
}
//Upload bfs
faceURL, err := s.accDao.UploadImage(c, ftype, faceFile, s.c.FaceBFS)
if err != nil {
log.Error("s.bfsDao.Upload(%d) error(%v)", mid, err)
return "", errors.WithStack(err)
}
URL, err := url.Parse(faceURL)
if err != nil {
return "", errors.WithStack(err)
}
inMonitor := s.ensureMonitor(c, mid, ip)
arg := &meModel.ArgAddPropertyReview{
Mid: mid,
New: URL.Path,
State: meModel.ReviewStateQueuing,
Property: meModel.ReviewPropertyFace,
}
if inMonitor {
arg.State = meModel.ReviewStateWait
return profile.Face, s.memRPC.AddPropertyReview(c, arg)
}
if err := s.memRPC.AddPropertyReview(c, arg); err != nil {
log.Error("s.memRPC.AddPropertyReview(%d,%s) error(%v)", mid, faceFile, err)
return "", errors.WithStack(err)
}
if err := s.memRPC.SetFace(c, &meModel.ArgUpdateFace{Mid: mid, Face: URL.Path}); err != nil {
log.Error("s.memRPC.SetFace(%d,%s) error(%v)", mid, faceURL, err)
return "", errors.WithStack(err)
}
return faceURL, nil
}
// UpdateName .
func (s *Service) UpdateName(c context.Context, mid int64, name, appkey string) error {
ip := metadata.String(c, metadata.RemoteIP)
_, inWhiteList := s.nickFreeAppKeys[appkey]
if inWhiteList {
return s.updateNameWithinWhiteList(c, mid, name, ip)
}
return s.updateName(c, mid, name, ip)
}
// updateNameWithinWhiteList 白名单 appkey 不扣硬币
func (s *Service) updateNameWithinWhiteList(c context.Context, mid int64, name, ip string) error {
if err := s.nameIsValid(c, mid, name, ip); err != nil {
return err
}
profile, err := s.accRPC.Profile3(c, &accModel.ArgMid{Mid: mid})
if err != nil {
return errors.WithStack(err)
}
if err := s.permitName(c, profile, ip); err != nil {
return err
}
if profile.Name == name {
log.Info("Update name is same to origin: mid: %d, name: %s, origin: %s", mid, name, profile.Name)
return nil
}
inMonitor := s.ensureMonitor(c, mid, ip)
remark := "appkey白名单修改昵称"
// 在监控列表里就加入添加审核列表
if inMonitor {
saveUpNameLog(mid, profile.Name, name, remark, inMonitor, ip)
return errors.WithStack(s.memRPC.AddPropertyReview(c, &meModel.ArgAddPropertyReview{
Mid: mid,
New: name,
State: meModel.ReviewStateWait,
Property: meModel.ReviewPropertyName,
Extra: map[string]interface{}{"nick_free": true},
}))
}
//修改昵称
if err := s.passDao.UpdateName(c, mid, name, ip); err != nil {
return errors.WithStack(err)
}
saveUpNameLog(mid, profile.Name, name, remark, inMonitor, ip)
return nil
}
//UpdateName update name.
func (s *Service) updateName(c context.Context, mid int64, name, ip string) error {
if err := s.nameIsValid(c, mid, name, ip); err != nil {
return err
}
profile, err := s.accRPC.Profile3(c, &accModel.ArgMid{Mid: mid})
if err != nil {
return errors.WithStack(err)
}
if err = s.permitName(c, profile, ip); err != nil {
return err
}
if profile.Name == name {
log.Info("Update name is same to origin: mid: %d, name: %s, origin: %s", mid, name, profile.Name)
return nil
}
// 判断是否改昵称免费
nickFree, err := s.NickFree(c, mid)
if err != nil {
return err
}
remark := "快速注册修改昵称"
if !nickFree.NickFree {
coins, coinErr := s.coinRPC.UserCoins(c, &coModel.ArgCoinInfo{Mid: mid, RealIP: ip})
if coinErr != nil {
return errors.WithStack(coinErr)
}
if coins < upNameCostCoins {
return ecode.UpdateUnameMoneyIsNot
}
remark = "修改昵称"
}
inMonitor := s.ensureMonitor(c, mid, ip)
// 在监控列表里就加入添加审核列表
if inMonitor {
saveUpNameLog(mid, profile.Name, name, remark, inMonitor, ip)
return errors.WithStack(s.memRPC.AddPropertyReview(c, &meModel.ArgAddPropertyReview{
Mid: mid,
New: name,
State: meModel.ReviewStateWait,
Property: meModel.ReviewPropertyName,
Extra: map[string]interface{}{"nick_free": nickFree.NickFree},
}))
}
//修改昵称
if err = s.passDao.UpdateName(c, mid, name, ip); err != nil {
return errors.WithStack(err)
}
saveUpNameLog(mid, profile.Name, name, remark, inMonitor, ip)
if nickFree.NickFree {
return errors.WithStack(s.memRPC.SetNickUpdated(c, &meModel.ArgMemberMid{Mid: mid}))
}
//扣除硬币
if _, err = s.coinRPC.ModifyCoin(c, &coModel.ArgModifyCoin{
Mid: mid,
Count: -upNameCostCoins,
Reason: fmt.Sprintf("UPDATE:NICK:%s=>%s", profile.Name, name),
IP: ip,
}); err != nil {
return errors.WithStack(err)
}
return nil
}
func (s *Service) monitorByIP(ctx context.Context, mid int64, ip string) (bool, string) {
IP, err := s.locRPC.Info(ctx, &locModel.ArgIP{IP: ip})
if err != nil || IP == nil {
log.Error("Failed to get ip info with ip: %s: %+v", ip, err)
return false, ""
}
descr, shouldMonitor := monitoredIPCountry[IP.Country]
if !shouldMonitor {
return false, ""
}
return true, descr
}
func (s *Service) monitorByTel(ctx context.Context, mid int64, ip string) (bool, string) {
p, err := s.passDao.QueryByMid(ctx, mid, ip)
if err != nil {
log.Error("Failed to query by mid form pasport: mid: %d: %+v", mid, err)
return false, ""
}
descr, shouldMonitor := monitoredTelCountry[p.CountryCode]
if !shouldMonitor {
return false, ""
}
return true, descr
}
func (s *Service) shouldMonitor(ctx context.Context, mid int64, ip string) (bool, string) {
should, descr := s.monitorByIP(ctx, mid, ip)
if should {
return true, descr
}
should, descr = s.monitorByTel(ctx, mid, ip)
if should {
return true, descr
}
return false, ""
}
func (s *Service) ensureMonitor(ctx context.Context, mid int64, ip string) bool {
inMonitor, _ := s.memRPC.IsInMonitor(ctx, &meModel.ArgMid{Mid: mid})
if inMonitor {
return true
}
should, descr := s.shouldMonitor(ctx, mid, ip)
if !should {
return false
}
if err := s.memRPC.AddUserMonitor(ctx, &meModel.ArgAddUserMonitor{
Mid: mid,
Operator: "system",
Remark: fmt.Sprintf("系统自动导入-%s", descr),
}); err != nil {
log.Error("Failed to add user moniter: mid: %d: %+v", mid, err)
}
return true
}
// UpdateSex update sex.
func (s *Service) UpdateSex(c context.Context, mid, sex int64) (err error) {
ip := metadata.String(c, metadata.RemoteIP)
return s.accDao.UpdateSex(c, mid, sex, ip)
}
//UpdateSign update sign.
func (s *Service) UpdateSign(c context.Context, mid int64, sign string) error {
ip := metadata.String(c, metadata.RemoteIP)
// 签名最长 70 个字符
if utf8.RuneCountInString(sign) > 70 {
return ecode.MemberSignOverLimit
}
// 签名不能包含 emoji
if model.HasEmoji(sign) {
return ecode.MemberSignHasEmoji
}
// 过滤敏感词
res, err := s.filterRPC.Filter(c, &ftModel.ArgFilter{Area: "sign", Message: sign})
if err != nil {
return err
}
// 大于 20 认为包含敏感词
if res.Level >= 20 {
return ecode.MemberSignSensitive
}
// 检查是否绑定手机
profile, err := s.accRPC.Profile3(c, &accModel.ArgMid{Mid: mid})
if err != nil {
return errors.WithStack(err)
}
if !s.validateTelStatus(profile.TelStatus) {
return ecode.MemberPhoneRequired
}
// 检查是否被禁言
if profile.Silence != 0 {
return ecode.MemberBlocked
}
// 如果和老的一模一样就没必要更新了
if profile.Sign == sign {
log.Info("Update sign is same to origin: mid: %d, sign: %s, origin: %s", mid, sign, profile.Sign)
return nil
}
inMonitor := s.ensureMonitor(c, mid, ip)
// 不在监控列表里就直接更新
if !inMonitor {
return errors.WithStack(s.memRPC.SetSign(c, &meModel.ArgUpdateSign{
Mid: mid,
Sign: sign,
RemoteIP: ip,
}))
}
// 否则就加入监控列表
return errors.WithStack(s.memRPC.AddPropertyReview(c, &meModel.ArgAddPropertyReview{
Mid: mid,
New: sign,
State: meModel.ReviewStateWait,
Property: meModel.ReviewPropertySign,
}))
}
// UpdateBirthday update birthday.
func (s *Service) UpdateBirthday(c context.Context, mid int64, birthday string) (err error) {
ip := metadata.String(c, metadata.RemoteIP)
return s.accDao.UpdateBirthday(c, mid, ip, birthday)
}
// NickFree .
func (s *Service) NickFree(c context.Context, mid int64) (nickFree *model.NickFree, err error) {
var (
isRegFast bool
nickUpdated bool
ip = metadata.String(c, metadata.RemoteIP)
)
sarg := &meModel.ArgMemberMid{Mid: mid}
if nickUpdated, err = s.memRPC.NickUpdated(c, sarg); err != nil {
log.Error("s.memRPC.IsUpNickFree(%v) error (%v)", sarg, err)
return
}
nickFree = &model.NickFree{}
if nickUpdated {
return
}
if isRegFast, err = s.passDao.FastReg(c, mid, ip); err != nil {
return
}
if isRegFast {
nickFree.NickFree = true
}
return
}
func saveUpNameLog(mid int64, oName, nName, remark string, isMonitor bool, ip string) {
report.User(&report.UserInfo{
Mid: mid,
Business: model.UpNameLogID,
Action: model.UpNameAction,
IP: ip,
Ctime: time.Now(),
Index: []interface{}{0, 0, 0, oName, nName, remark},
Content: map[string]interface{}{
"is_monitor": isMonitor,
"old_name": oName,
"new_name": nName,
"reason": fmt.Sprintf("修改昵称(原昵称:%s 新昵称:%s)", oName, nName),
"remark": remark,
},
})
}
func (s *Service) permitName(c context.Context, profile *accModel.Profile, ip string) error {
if !s.validateTelStatus(profile.TelStatus) {
return ecode.MemberPhoneRequired
}
// 检查是否被禁言
if profile.Silence != 0 {
return ecode.MemberBlocked
}
//昵称锁定,是否官方认证
if profile.Official.Role != 0 {
log.Info("update name fail, name is official, mid: %d", profile.Mid)
return ecode.UpdateUnameHadOfficial
}
pProfile, err := s.passDao.QueryByMid(c, profile.Mid, ip)
if err != nil {
return err
}
if pProfile.NickLock == 1 {
log.Info("update name fail, name is locked, mid: %d", profile.Mid)
return ecode.UpdateUnameHadLocked
}
return nil
}
func (s *Service) nameIsValid(c context.Context, mid int64, name, ip string) error {
if len(name) > 30 || utf8.RuneCountInString(name) > 16 {
return ecode.UpdateUnameTooLong
}
if utf8.RuneCountInString(name) < 3 {
return ecode.UpdateUnameTooShort
}
if !model.ValidName(name) {
return ecode.UpdateUnameFormat
}
// 判断昵称是否重复
if err := s.passDao.TestUserName(c, name, mid, ip); err != nil {
return err
}
// 过滤敏感词
res, err := s.filterRPC.Filter(c, &ftModel.ArgFilter{Area: "member", Message: name})
if err != nil {
return err
}
// 大于 20 认为包含敏感词
if res.Level >= 20 {
return ecode.UpdateUnameSensitive
}
return nil
}
func (s *Service) validateTelStatus(status int32) bool {
if s.c.Switch.UpdatePropertyPhoneRequired && status == 0 {
return false
}
return true
}

View File

@@ -0,0 +1,71 @@
package member
import (
"context"
"testing"
"time"
. "github.com/smartystreets/goconvey/convey"
)
func TestService_Account(t *testing.T) {
Convey("get account info", t, func() {
Convey("when not timeout", func() {
time.Sleep(time.Second * 2)
res, err := s.Account(context.TODO(), 1, "127.0.0.1")
So(err, ShouldBeNil)
So(res, ShouldNotBeNil)
})
})
}
func TestService_UpdateUname(t *testing.T) {
Convey("update uname", t, func() {
Convey("when not timeout", func() {
time.Sleep(time.Second * 2)
err := s.UpdateName(context.TODO(), 110001353, "127.0.0.1", "127.0.0.1")
So(err, ShouldBeNil)
})
})
}
func TestService_NickFree(t *testing.T) {
Convey("update uname", t, func() {
Convey("when not timeout", func() {
time.Sleep(time.Second * 2)
nick, err := s.NickFree(context.TODO(), 110001353)
So(err, ShouldBeNil)
So(nick, ShouldNotBeEmpty)
})
})
}
func TestService_UpdateSign(t *testing.T) {
Convey("update sign", t, func() {
Convey("when not timeout", func() {
err := s.UpdateSign(context.TODO(), 61, "1989-09-19")
So(err, ShouldBeNil)
})
})
}
func TestService_UpdateSex(t *testing.T) {
Convey("update sex", t, func() {
Convey("when not timeout", func() {
err := s.UpdateSex(context.TODO(), 110001353, 1)
So(err, ShouldBeNil)
})
})
}
func TestService_UpdateBirthday(t *testing.T) {
Convey("update sex", t, func() {
Convey("when not timeout", func() {
err := s.UpdateBirthday(context.TODO(), 61, "1989-09-19")
So(err, ShouldBeNil)
})
})
}

View File

@@ -0,0 +1,76 @@
package member
import (
"context"
"go-common/app/service/main/usersuit/model"
"go-common/library/log"
"go-common/library/net/metadata"
)
// MedalHomeInfo return user mdeal home info.
func (s *Service) MedalHomeInfo(c context.Context, mid int64) (res []*model.MedalHomeInfo, err error) {
var arg = &model.ArgMid{Mid: mid}
res, err = s.usRPC.MedalHomeInfo(c, arg)
if err != nil {
log.Error("s.medalRPC.MedalHomeInfo(%d) error (%v)", mid, err)
return
}
return
}
// MedalUserInfo return medal user info.
func (s *Service) MedalUserInfo(c context.Context, mid int64) (res *model.MedalUserInfo, err error) {
ip := metadata.String(c, metadata.RemoteIP)
var arg = &model.ArgMedalUserInfo{Mid: mid, IP: ip}
res, err = s.usRPC.MedalUserInfo(c, arg)
if err != nil {
log.Error("s.medalRPC.MedalUserInfo(%d) error (%v)", mid, err)
return
}
return
}
// MedalInstall install or uninstall medal.
func (s *Service) MedalInstall(c context.Context, mid, nid int64, isActivated int8) (err error) {
var arg = &model.ArgMedalInstall{Mid: mid, Nid: nid, IsActivated: isActivated}
err = s.usRPC.MedalInstall(c, arg)
if err != nil {
log.Error("s.medalRPC.MedalInstall(mid:%d nid:%d isActivated:%d) error (%v)", mid, nid, isActivated, err)
return
}
return
}
// MedalPopup return medal popup.
func (s *Service) MedalPopup(c context.Context, mid int64) (res *model.MedalPopup, err error) {
var arg = &model.ArgMid{Mid: mid}
res, err = s.usRPC.MedalPopup(c, arg)
if err != nil {
log.Error("s.medalRPC.MedalPopup(mid:%d) error (%v)", mid, err)
return
}
return
}
// MedalMyInfo return medal my info.
func (s *Service) MedalMyInfo(c context.Context, mid int64) (res []*model.MedalMyInfos, err error) {
var arg = &model.ArgMid{Mid: mid}
res, err = s.usRPC.MedalMyInfo(c, arg)
if err != nil {
log.Error("s.medalRPC.MedalMyInfo(mid:%d) error (%v)", mid, err)
return
}
return
}
// MedalAllInfo return medal all info.
func (s *Service) MedalAllInfo(c context.Context, mid int64) (res *model.MedalAllInfos, err error) {
var arg = &model.ArgMid{Mid: mid}
res, err = s.usRPC.MedalAllInfo(c, arg)
if err != nil {
log.Error("s.medalRPC.MedalAllInfo(mid:%d) error (%v)", mid, err)
return
}
return
}

View File

@@ -0,0 +1,267 @@
package member
import (
"context"
"go-common/app/interface/main/account/model"
accmdl "go-common/app/service/main/account/model"
arcmdl "go-common/app/service/main/archive/model/archive"
memmdl "go-common/app/service/main/member/model"
"go-common/library/ecode"
"go-common/library/log"
"go-common/library/net/metadata"
)
const (
_maxMonthlyOfficialSubmitTimes = 3
)
// IdentifyInfo get user identify info.
func (s *Service) IdentifyInfo(c context.Context, mid int64, ip string) (res *model.Identification, err error) {
var rid *model.IdentifyInfo
if rid, err = s.accDao.IdentifyInfo(c, mid, ip); err != nil {
log.Error("s.memRPC.IdentifyInfo(%d) err(%+v)", mid, err)
return
}
res = &model.Identification{}
switch rid.Identify {
case model.APIIdentifyOk:
res.Identification = model.IdentifyOK
case model.APIIdentifyNoInfo:
res.Identification = model.IdentifyNotOK
default:
log.Error("unknow mid(%d) identify(%d) status", mid, rid.Identify)
}
return
}
// SubmitOfficial is.
func (s *Service) SubmitOfficial(c context.Context, mid int64, apply *model.OfficialApply) error {
//ip := metadata.String(c, metadata.RemoteIP)
if apply.Role == memmdl.OfficialRoleUp || apply.Role == memmdl.OfficialRoleIdentify {
cons, err := s.OfficialConditions(c, mid)
if err != nil {
return err
}
if !cons.AllPass() {
log.Warn("Unexpected official apply submited: mid: %d conditons: %+v apply: %+v", mid, cons, apply)
return ecode.RequestErr
}
}
// 是否超出本月提交次数限制
times, err := s.accDao.GetMonthlyOfficialSubmittedTimes(c, mid)
if err != nil {
log.Error("Faield to get monthly official submitted times with mid %d: %+v", mid, err)
}
if times >= _maxMonthlyOfficialSubmitTimes {
log.Warn("User %d is exceed max monthly official submitted times")
return ecode.LimitExceed
}
ood, err := s.memRPC.OfficialDoc(c, &memmdl.ArgMid{Mid: mid})
// 是否已经存在审核中的申请
if err == nil && ood != nil && ood.State == memmdl.OfficialStateWait {
return nil
}
if apply.Telephone != "" {
if apply.TelVerifyCode == 0 {
log.Error("Invalid tel verify code: mid: %d code:%d", mid, apply.TelVerifyCode)
return ecode.RequestErr
}
vcode, verr := s.accDao.GetVerifyCode(c, mid, apply.Telephone)
if verr != nil {
log.Error("Failed to get verify code: %d, %s: %+v", mid, apply.Telephone, verr)
return ecode.CaptchaErr
}
if apply.TelVerifyCode != vcode {
log.Error("Failed to verify telephone verification code: %s, %d, %d", apply.Telephone, apply.TelVerifyCode, vcode)
return ecode.CaptchaErr
}
}
arg := &memmdl.ArgOfficialDoc{
Mid: mid,
Name: apply.Name,
Role: apply.Role,
Title: apply.Title,
Desc: apply.Desc,
Operator: apply.Operator,
Telephone: apply.Telephone,
Email: apply.Email,
Address: apply.Address,
Company: apply.Company,
CreditCode: apply.CreditCode,
Organization: apply.Organization,
OrganizationType: apply.OrganizationType,
BusinessLicense: apply.BusinessLicense,
BusinessScale: apply.BusinessScale,
BusinessLevel: apply.BusinessLevel,
BusinessAuth: apply.BusinessAuth,
Supplement: apply.Supplement,
Professional: apply.Professional,
Identification: apply.Identification,
OfficialSite: apply.OfficialSite,
RegisteredCapital: apply.RegisteredCapital,
SubmitSource: "user", // 来自 account-interface 的全部为 user
}
pros, err := s.accRPC.ProfileWithStat3(c, &accmdl.ArgMid{Mid: mid})
if err != nil {
log.Error("Failed to call ProfileWithStat3(%d): %+v", mid, err)
return err
}
arg.Realname = int8(pros.Identification)
if err := s.accDao.DelVerifyCode(c, mid, apply.Telephone); err != nil {
log.Error("Failed to delete verify code: mid: %d: mobile: %s: %+v", mid, apply.Telephone, err)
}
if _, err = s.accDao.IncreaseMonthlyOfficialSubmittedTimes(c, mid); err != nil {
log.Error("Failed to increase monthly official submitted times with mid: %d: %+v", mid, err)
}
return s.memRPC.SetOfficialDoc(c, arg)
}
// OfficialConditions is.
func (s *Service) OfficialConditions(c context.Context, mid int64) (*model.OfficialConditions, error) {
con := new(model.OfficialConditions)
pros, err := s.accRPC.ProfileWithStat3(c, &accmdl.ArgMid{Mid: mid})
if err != nil {
log.Error("Failed to call ProfileWithStat3(%d): %+v", mid, err)
return nil, err
}
if pros.Rank >= 10000 {
con.IsFormal = true
}
// 1 正常号码2 虚拟号码
if pros.TelStatus >= 1 {
con.BindTel = true
}
if pros.Identification == 1 {
con.Realname = true
}
if pros.Follower >= 100000 {
con.FollowerCount = true
}
arcCount, err := s.arcRPC.UpCount2(c, &arcmdl.ArgUpCount2{Mid: mid})
if err != nil {
log.Error("Failed to call s.arcRPC.UpCount2(%d): %+v", mid, err)
// return nil, err
}
if err == nil && arcCount >= 1 {
con.ArchiveCount = true
}
// 累计播放数
// upStat, err := s.upRPC.UpStatBase(c, &upmdl.ArgMidWithDate{Mid: mid})
// if err != nil {
// log.Error("Failed to call s.upRPC.UpStatBase(%d): %+v", mid, err)
// }
// if err == nil && upStat != nil && upStat.View >= 1000000 {
// con.ViewCount = true
// }
return con, nil
}
// UploadImage article upload cover.
func (s *Service) UploadImage(c context.Context, fileType string, body []byte) (url string, err error) {
if len(body) == 0 {
err = ecode.FileNotExists
return
}
if len(body) > s.c.BFS.MaxFileSize {
err = ecode.FileTooLarge
return
}
url, err = s.accDao.UploadImage(c, fileType, body, s.c.BFS)
if err != nil {
log.Error("account-interface: s.bfs.Upload error(%v)", err)
return
}
return
}
// MobileVerify is.
func (s *Service) MobileVerify(c context.Context, mid int64, mobile string, country int64) error {
ip := metadata.String(c, metadata.RemoteIP)
vcode, err := s.accDao.GenVerifyCode(c, mid, mobile)
if err != nil {
log.Error("Failed to generate verify code: %+v", err)
return err
}
return s.accDao.SendMobileVerify(c, vcode, country, mobile, ip)
}
// OfficialDoc is.
func (s *Service) OfficialDoc(c context.Context, mid int64) (*memmdl.OfficialDoc, error) {
ip := metadata.String(c, metadata.RemoteIP)
od, err := s.memRPC.OfficialDoc(c, &memmdl.ArgMid{Mid: mid, RealIP: ip})
if err != nil {
return nil, err
}
return od, nil
}
// MonthlyOfficialSubmittedTimes is
func (s *Service) MonthlyOfficialSubmittedTimes(c context.Context, mid int64) *model.OfficialSubmittedTimes {
result := &model.OfficialSubmittedTimes{
Submitted: 0,
Remain: _maxMonthlyOfficialSubmitTimes,
}
times, err := s.accDao.GetMonthlyOfficialSubmittedTimes(c, mid)
if err != nil {
log.Warn("Failed to get monthly official submitted times with mid: %d: %+v", mid, err)
return result
}
result.Submitted = times
if result.Submitted > _maxMonthlyOfficialSubmitTimes {
result.Submitted = _maxMonthlyOfficialSubmitTimes
}
result.Remain = _maxMonthlyOfficialSubmitTimes - result.Submitted
return result
}
// OfficialAutoFillDoc is
func (s *Service) OfficialAutoFillDoc(ctx context.Context, mid int64) (*memmdl.OfficialDoc, error) {
res := &memmdl.OfficialDoc{
Mid: mid,
}
// default name
info, err := s.accRPC.Info3(ctx, &accmdl.ArgMid{Mid: mid})
if err != nil {
return nil, err
}
res.Name = info.Name
// default from cm api
func() {
cminfo, err := s.accDao.BusinessAccountInfo(ctx, mid)
if err != nil {
log.Error("Failed to get cm business account info with mid: %d: %+v", mid, err)
return
}
if cminfo.Nickname != "" {
res.Name = cminfo.Nickname
}
if cminfo.CertificationTitle != "" {
res.Title = cminfo.CertificationTitle
}
if cminfo.CreditCode != "" {
res.CreditCode = cminfo.CreditCode
}
if cminfo.CompanyName != "" {
res.Company = cminfo.CompanyName
}
if cminfo.Organization != "" {
res.Organization = cminfo.Organization
}
if cminfo.OrganizationType != "" {
res.OrganizationType = cminfo.OrganizationType
}
}()
return res, nil
}

View File

@@ -0,0 +1,54 @@
package member
import (
"context"
"net"
"go-common/app/interface/main/account/model"
secmodel "go-common/app/service/main/secure/model"
"go-common/library/log"
)
// NoticeV2 notice v2.
func (s *Service) NoticeV2(c context.Context, mid int64, uuid string, pf string, b int64) (res *model.Notice2, err error) {
var msg *secmodel.Msg
if msg, err = s.secureRPC.Status(c, &secmodel.ArgSecure{Mid: mid, UUID: uuid}); err != nil {
log.Error("service.secureRPC.Status(%d) uuid(%s) error(%v)", mid, uuid, err)
return
}
if msg == nil || !msg.Notify {
log.Info("s.NoticeV2(%d) msg(%v) continue", mid, msg)
res = &model.Notice2{Status: model.NoticeStatusNotNotify}
return
}
res = &model.Notice2{
Status: model.NoticeStatusNotify,
Type: model.NoticeTypeSecurity,
Security: &model.Security{
Location: msg.Log.Location,
Time: msg.Log.Time,
IP: inetNtoA(msg.Log.IP),
Mid: msg.Log.Mid,
}}
return
}
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()
}
// CloseNoticeV2 close notice v2.
func (s *Service) CloseNoticeV2(c context.Context, mid int64, uuid string) (err error) {
arg := &secmodel.ArgSecure{Mid: mid, UUID: uuid}
if err = s.secureRPC.CloseNotify(c, arg); err != nil {
log.Error("service.secureRPC.CloseNotify(%v) error(%v)", arg, err)
return
}
return
}

View File

@@ -0,0 +1,38 @@
package member
import (
"context"
"testing"
"time"
. "github.com/smartystreets/goconvey/convey"
)
func TestService_NoticeV2(t *testing.T) {
Convey("TestService_NoticeV2", func() {
time.Sleep(time.Second * 2)
var (
mid = int64(1)
u = "foo"
//ip = "127.0.0.1"
pf = "ios"
build int64 = 123
)
res, err := s.NoticeV2(context.TODO(), mid, u, pf, build)
So(err, ShouldBeNil)
So(res, ShouldNotBeNil)
})
}
func TestService_CloseNoticeV2(t *testing.T) {
Convey("TestService_CloseNoticeV2", func() {
time.Sleep(time.Second * 2)
var (
mid = int64(1)
u = "foo"
//ip = "127.0.0.1"
)
err := s.CloseNoticeV2(context.TODO(), mid, u)
So(err, ShouldBeNil)
})
}

View File

@@ -0,0 +1,18 @@
package member
import (
"context"
secmodel "go-common/app/service/main/secure/model"
"go-common/library/log"
)
// Status query user's remote login status.
func (s *Service) Status(c context.Context, mid int64, uuid string) (res *secmodel.Msg, err error) {
arg := &secmodel.ArgSecure{Mid: mid, UUID: uuid}
if res, err = s.secureRPC.Status(c, arg); err != nil {
log.Error("s.secureRPC.Status(mid:%d) error (%v)", mid, err)
return
}
return
}

View File

@@ -0,0 +1,25 @@
package member
import (
"context"
"testing"
secmodel "go-common/app/service/main/secure/model"
. "github.com/smartystreets/goconvey/convey"
)
func TestService_Status(t *testing.T) {
var (
err error
c = context.TODO()
res *secmodel.Msg
)
Convey("TestService_Status", func() {
res, err = s.Status(c, 1, "xxxxx")
if err != nil {
t.Errorf("s.Status err(%v)", err)
}
t.Logf("s.Status result (%v)", res)
})
}

View File

@@ -0,0 +1,145 @@
package member
import (
"context"
"fmt"
"go-common/app/interface/main/account/model"
artMdl "go-common/app/interface/openplatform/article/model"
"go-common/app/service/main/archive/api"
arcMdl "go-common/app/service/main/archive/model/archive"
"go-common/library/log"
"go-common/library/net/metadata"
)
var (
_typeToURL = map[int64]string{
1: "https://www.bilibili.com/video/av%d/", // 稿件
2: "https://www.bilibili.com/topic/%d.html", // 话题
3: "https://h.bilibili.com/dy%d", // 画站
5: "https://vc.bilibili.com/video/%d", // 直播小视频
6: "https://www.bilibili.com/blackroom/ban/%d", // 封禁信息
7: "https://www.bilibili.com/blackroom/notice/%d", // 公告信息
10: "https://link.bilibili.com/p/eden/news#/newsdetail?id=%d", // 直播公告
11: "https://h.bilibili.com/%d", // 直播有文画
12: "https://www.bilibili.com/read/cv%d", // 专栏
13: "https://show.bilibili.com/platform/detail.html?id=%d", // 票务
15: "https://www.bilibili.com/judgement/case/%d", // 风纪委
}
)
// ReplyHistoryList reply history list
func (s *Service) ReplyHistoryList(c context.Context, mid int64, stime, etime, order, sort string, pn, ps int64, accessKey, cookie string) (rhl *model.ReplyHistory, err error) {
ip := metadata.String(c, metadata.RemoteIP)
if rhl, err = s.replyDao.ReplyHistoryList(c, mid, stime, etime, order, sort, pn, ps, accessKey, cookie, ip); err != nil {
log.Error("s.replyDao.ReplyHistoryList error(%v)", err)
return
}
idsMap := make(map[int64][]int64) // type -> ids
unique := make(map[int64]struct{})
for _, v := range rhl.Records {
if _, ok := unique[v.Oid]; !ok {
idsMap[v.Type] = append(idsMap[v.Type], v.Oid)
unique[v.Oid] = struct{}{}
}
}
rhlt, _ := s.fetchData(c, mid, idsMap, accessKey, cookie, ip)
for _, v := range rhl.Records {
if t, ok := rhlt[v.Type]; ok {
for _, b := range t {
if o, ok := b[v.Oid]; ok {
v.Title = o.Title
v.URL = o.URL
}
}
}
}
return
}
// fetchData
func (s *Service) fetchData(c context.Context, mid int64, idsMap map[int64][]int64, accessKey, cookie, ip string) (rhlt map[int64][]map[int64]*model.RecordAppend, err error) {
rhlt = make(map[int64][]map[int64]*model.RecordAppend) // type -> oid -> title/url
for t, v := range idsMap {
switch t {
case 1:
// 稿件
if len(v) > 0 {
var arcs map[int64]*api.Arc
arcArg := &arcMdl.ArgAids2{Aids: v, RealIP: ip}
if arcs, err = s.arcRPC.Archives3(c, arcArg); err != nil {
log.Error("s.arcRPC.Archives3 error(%v)", err)
return
}
for _, vv := range v {
if arc, ok := arcs[vv]; ok {
itu := &model.RecordAppend{
Title: arc.Title,
}
if arc.RedirectURL != "" {
itu.URL = arc.RedirectURL
} else {
itu.URL = fmt.Sprintf(_typeToURL[t], arc.Aid)
}
vitu := make(map[int64]*model.RecordAppend)
vitu[vv] = itu
rhlt[t] = append(rhlt[t], vitu)
}
}
}
case 4:
// 活动
if len(v) > 0 {
var aps map[int64]*model.RecordAppend
if aps, err = s.replyDao.ActivityPages(c, mid, v, accessKey, cookie, ip); err != nil {
log.Error("s.replyDao.ActivityPages error(%v)", err)
return
}
for _, vv := range v {
if ap, ok := aps[vv]; ok {
vitu := make(map[int64]*model.RecordAppend)
vitu[vv] = ap
rhlt[t] = append(rhlt[t], vitu)
}
}
}
case 12:
// 专栏
if len(v) > 0 {
var arts map[int64]*artMdl.Meta
artArg := &artMdl.ArgAids{Aids: v}
if arts, err = s.artRPC.ArticleMetas(c, artArg); err != nil {
log.Error("s.artRPC.ArticleMetas error(%v)", err)
return
}
for _, vv := range v {
if ap, ok := arts[vv]; ok {
itu := &model.RecordAppend{
Title: ap.Title,
URL: fmt.Sprintf(_typeToURL[t], ap.ID),
}
vitu := make(map[int64]*model.RecordAppend)
vitu[vv] = itu
rhlt[t] = append(rhlt[t], vitu)
}
}
}
default:
if len(v) > 0 {
for _, vv := range v {
itu := &model.RecordAppend{
Title: "",
URL: "",
}
if _, ok := _typeToURL[t]; ok {
itu.URL = fmt.Sprintf(_typeToURL[t], vv)
}
vitu := make(map[int64]*model.RecordAppend)
vitu[vv] = itu
rhlt[t] = append(rhlt[t], vitu)
}
}
}
}
return
}

View File

@@ -0,0 +1,36 @@
package member
import (
"context"
"testing"
"go-common/app/interface/main/account/model"
"github.com/smartystreets/goconvey/convey"
)
func TestService_ReplyHistoryList(t *testing.T) {
convey.Convey("ReplyHistoryList", t, func() {
var (
err error
//ip = ""
mid int64 = 88889069
stime = "1500805318"
etime = "1511237870"
order = "like"
sort = "desc"
pn int64 = 1
ps int64 = 100
accessKey = ""
cookie = ""
rhl *model.ReplyHistory
)
if rhl, err = s.ReplyHistoryList(context.TODO(), mid, stime, etime, order, sort, pn, ps, accessKey, cookie); err != nil {
convey.So(err, convey.ShouldBeNil)
t.Logf("err: %v", err)
}
for _, v := range rhl.Records {
t.Logf("title:%s, url:%s, id:%d, type: %d", v.Title, v.URL, v.ID, v.Type)
}
})
}

View File

@@ -0,0 +1,90 @@
package member
import (
"context"
"net"
"go-common/app/interface/main/account/conf"
"go-common/app/interface/main/account/dao/account"
"go-common/app/interface/main/account/dao/passport"
"go-common/app/interface/main/account/dao/reply"
artRPC "go-common/app/interface/openplatform/article/rpc/client"
accrpc "go-common/app/service/main/account/rpc/client"
arcRPC "go-common/app/service/main/archive/api/gorpc"
coinrpc "go-common/app/service/main/coin/api/gorpc"
filterrpc "go-common/app/service/main/filter/rpc/client"
locrpc "go-common/app/service/main/location/rpc/client"
memrpc "go-common/app/service/main/member/api/gorpc"
passRPC "go-common/app/service/main/passport/rpc/client"
securerpc "go-common/app/service/main/secure/rpc/client"
upRPC "go-common/app/service/main/up/api/gorpc"
usrpc "go-common/app/service/main/usersuit/rpc/client"
"go-common/library/queue/databus"
"github.com/pkg/errors"
)
// Service struct of service.
type Service struct {
// conf
c *conf.Config
accRPC *accrpc.Service3
memRPC *memrpc.Service
usRPC *usrpc.Service2
arcRPC *arcRPC.Service2
upRPC *upRPC.Service
artRPC *artRPC.Service
passRPC *passRPC.Client2
coinRPC *coinrpc.Service
locRPC *locrpc.Service
secureRPC *securerpc.Service
filterRPC *filterrpc.Service
accDao *account.Dao
replyDao *reply.Dao
passDao *passport.Dao
nickFreeAppKeys map[string]string
accountNotify *databus.Databus
removeLoginLogCIDR []*net.IPNet
}
// New create service instance and return.
func New(c *conf.Config) (s *Service) {
s = &Service{
c: c,
memRPC: memrpc.New(c.RPCClient2.Member),
accRPC: accrpc.New3(c.RPCClient2.Account),
usRPC: usrpc.New(c.RPCClient2.Usersuit),
arcRPC: arcRPC.New2(c.RPCClient2.Archive),
upRPC: upRPC.New(c.RPCClient2.UP),
artRPC: artRPC.New(c.RPCClient2.Article),
passRPC: passRPC.New(c.RPCClient2.PassPort),
coinRPC: coinrpc.New(c.RPCClient2.Coin),
locRPC: locrpc.New(c.RPCClient2.Location),
secureRPC: securerpc.New(c.RPCClient2.Secure),
filterRPC: filterrpc.New(c.RPCClient2.Filter),
accDao: account.New(c),
passDao: passport.New(c),
replyDao: reply.New(c),
nickFreeAppKeys: c.NickFreeAppKeys,
accountNotify: databus.New(c.AccountNotify),
}
cidrs := make([]*net.IPNet, 0, len(c.Account.RemoveLoginLogCIDR))
for _, raw := range c.Account.RemoveLoginLogCIDR {
_, inet, err := net.ParseCIDR(raw)
if err != nil {
panic(errors.Wrapf(err, "Invalid CIDR: %s", raw))
}
cidrs = append(cidrs, inet)
}
s.removeLoginLogCIDR = cidrs
return
}
// Ping check server ok.
func (s *Service) Ping(c context.Context) (err error) {
return
}
// Close dao.
func (s *Service) Close() {}

View File

@@ -0,0 +1,19 @@
package member
import (
"flag"
"go-common/app/interface/main/account/conf"
)
var (
s *Service
)
func init() {
flag.Set("conf", "../../cmd/account-interface-example.toml")
if err := conf.Init(); err != nil {
panic(err)
}
s = New(conf.Conf)
}

View File

@@ -0,0 +1,29 @@
package member
import (
"context"
"fmt"
)
func notifyKey(mid int64) string {
return fmt.Sprintf("AccountInterface-AccountNotify-T%d", mid)
}
// NotifyInfo notify info.
type NotifyInfo struct {
Uname string `json:"uname"`
Mid int64 `json:"mid"`
Type string `json:"type"`
NewName string `json:"newName"`
Action string `json:"action"`
}
// NotityPurgeCache is
func (s *Service) NotityPurgeCache(ctx context.Context, mid int64, action string) error {
msg := &NotifyInfo{
Mid: mid,
Action: action,
}
key := notifyKey(mid)
return s.accountNotify.Send(ctx, key, msg)
}

View File

@@ -0,0 +1,333 @@
package member
import (
"context"
"fmt"
"net"
"strconv"
"strings"
"go-common/app/interface/main/account/model"
cmodel "go-common/app/service/main/coin/model"
lmodel "go-common/app/service/main/location/model"
mmodel "go-common/app/service/main/member/model"
pmodel "go-common/app/service/main/passport/model"
smodel "go-common/app/service/main/secure/model"
"go-common/library/log"
"go-common/library/net/metadata"
"go-common/library/time"
)
// UpdateSettings Update Settings
func (s *Service) UpdateSettings(c context.Context, mid int64, settings *model.Settings) (err error) {
var (
mb *mmodel.Member
ip = metadata.String(c, metadata.RemoteIP)
)
if mb, err = s.memRPC.Member(c, &mmodel.ArgMemberMid{Mid: mid, RemoteIP: ip}); err != nil {
log.Error("s.Member(%d) error(%v)", mid, err)
return
}
if settings.Sex != sexName(mb.Sex) {
if err = s.accDao.UpdateSex(c, mid, sexID(settings.Sex), ip); err != nil {
return
}
}
if settings.Uname != mb.Name {
if err = s.updateName(c, mid, settings.Uname, ip); err != nil {
return
}
}
if settings.Sign != mb.Sign {
if err = s.UpdateSign(c, mid, settings.Sign); err != nil {
return
}
}
if settings.Birthday != mb.Birthday.Time().Format("2006-01-02") {
if err = s.accDao.UpdateBirthday(c, mid, ip, settings.Birthday); err != nil {
return
}
}
return
}
// SettingsInfo Settings Info
func (s *Service) SettingsInfo(c context.Context, mid int64) (user *model.User, err error) {
var (
mb *mmodel.Member
nickFree *model.NickFree
userID string
ip = metadata.String(c, metadata.RemoteIP)
)
user = &model.User{}
if mb, err = s.memRPC.Member(c, &mmodel.ArgMemberMid{Mid: mid, RemoteIP: ip}); err != nil {
log.Error("s.Member(%d) error(%v)", mid, err)
return
}
if nickFree, err = s.NickFree(c, mid); err != nil {
return
}
if userID, err = s.passDao.UserID(c, mid, ip); err != nil {
return
}
user.Userid = userID
user.Mid = mb.Mid
user.Uname = mb.Name
user.Birthday = mb.Birthday.Time().Format("2006-01-02")
user.NickFree = nickFree.NickFree
user.Sign = mb.Sign
user.Sex = sexName(mb.Sex)
// 尝试清理一次缓存减少用户反馈
s.NotityPurgeCache(c, mid, "updateUname")
return
}
// LogCoin Log Money
func (s *Service) LogCoin(c context.Context, mid int64) (logCoin *model.LogCoins, err error) {
var (
logs []*cmodel.Log
)
if logs, err = s.coinRPC.UserLog(c, &cmodel.ArgLog{Mid: mid, Recent: true, Translate: true}); err != nil {
return
}
logCoin = &model.LogCoins{}
logCoin.Count = len(logs)
logCoin.List = make([]*model.LogCoin, 0)
for _, l := range logs {
s := fmt.Sprintf("%0.1f", l.To-l.From)
delta, _ := strconv.ParseFloat(s, 64)
model := &model.LogCoin{Time: time.Time(l.TimeStamp).Time().Format("2006-01-02 15:04:05"), Reason: l.Desc, Delta: delta}
logCoin.List = append(logCoin.List, model)
}
return
}
// Coin coin.
func (s *Service) Coin(c context.Context, mid int64) (logCoin *model.Coin, err error) {
var (
coin float64
)
if coin, err = s.coinRPC.UserCoins(c, &cmodel.ArgCoinInfo{Mid: mid}); err != nil {
return
}
logCoin = &model.Coin{Money: coin}
return
}
// LogMoral Log Moral
func (s *Service) LogMoral(c context.Context, mid int64) (logMorals *model.LogMorals, err error) {
var (
logs []*mmodel.UserLog
moral *mmodel.Moral
toMoral, fromMoral, origin int64
)
if logs, err = s.memRPC.MoralLog(c, &mmodel.ArgMemberMid{Mid: mid}); err != nil {
log.Error("s.memRPC.MoralLog(%v) error(%v)", mid, err)
return
}
if moral, err = s.memRPC.Moral(c, &mmodel.ArgMemberMid{Mid: mid}); err != nil {
log.Error("s.memRPC.Moral(%v) error(%v)", mid, err)
return
}
logMorals = &model.LogMorals{Count: len(logs), Moral: moral.Moral / 100}
logMorals.List = make([]*model.LogMoral, 0)
for _, l := range logs {
ml := &model.LogMoral{}
ml.Reason = l.Content["reason"]
if origin, err = strconv.ParseInt(l.Content["origin"], 10, 64); err != nil {
log.Error("strconv.ParseInt(%v) error(%v)", l.Content["origin"], err)
continue
}
ml.Origin = model.Origin[origin]
ml.Time = time.Time(l.TS).Time().Format("2006-01-02 15:04:05")
if toMoral, err = strconv.ParseInt(l.Content["to_moral"], 10, 64); err != nil {
log.Error("strconv.ParseInt(%v) error(%v)", l.Content["to_moral"], err)
continue
}
if fromMoral, err = strconv.ParseInt(l.Content["from_moral"], 10, 64); err != nil {
log.Error("strconv.ParseInt(%v) error(%v)", l.Content["from_moral"], err)
continue
}
delta := float64(toMoral-fromMoral) / float64(100)
if ml.Delta, err = strconv.ParseFloat(fmt.Sprintf("%0.2f", delta), 64); err != nil {
log.Error("strconv.ParseFloat(%v) error(%v)", delta, err)
continue
}
logMorals.List = append(logMorals.List, ml)
}
return
}
// LogExp Log Exp
func (s *Service) LogExp(c context.Context, mid int64) (logExp *model.LogExps, err error) {
var (
logs []*mmodel.UserLog
toExp, fromExp float64
ip = metadata.String(c, metadata.RemoteIP)
)
logExp = &model.LogExps{}
if logs, err = s.memRPC.Log(c, &mmodel.ArgMid2{Mid: mid, RealIP: ip}); err != nil {
log.Error("s.memRPC.Log(%v) error(%v)", mid, err)
return
}
logExp.Count = len(logs)
logExp.List = make([]*model.LogExp, 0)
for _, l := range logs {
expLog := &model.LogExp{}
expLog.Time = time.Time(l.TS).Time().Format("2006-01-02 15:04:05")
expLog.Reason = l.Content["reason"]
if toExp, err = strconv.ParseFloat(l.Content["to_exp"], 10); err != nil {
log.Error("strconv.ParseFloat(%v) error(%v)", l.Content["to_exp"], err)
continue
}
if fromExp, err = strconv.ParseFloat(l.Content["from_exp"], 10); err != nil {
log.Error("strconv.ParseFloat(%v) error(%v)", l.Content["from_exp"], err)
continue
}
expLog.Delta = toExp - fromExp
logExp.List = append(logExp.List, expLog)
}
return
}
// LogLogin logLogin
func (s *Service) LogLogin(c context.Context, mid int64) (logLogins *model.LogLogins, err error) {
var (
logs []*pmodel.LoginLog
ips []string
locations map[string]*lmodel.Info
excLogs []*smodel.Expection
)
logLogins = &model.LogLogins{}
if logs, err = s.passRPC.LoginLogs(c, &pmodel.ArgLoginLogs{Mid: mid, Limit: 30}); err != nil {
log.Error("s.passRPC.LoginLogs(%v) error(%v)", mid, err)
return
}
if excLogs, err = s.secureRPC.ExpectionLoc(c, &smodel.ArgSecure{Mid: mid}); err != nil {
log.Error("s.secureRPC.ExpectionLoc(%v) error(%v)", mid, err)
return
}
logLogins.Count = len(logs)
logLogins.List = make([]*model.LogLogin, 0)
beRemoved := func(sip string) bool {
ip := net.ParseIP(sip)
for _, cidr := range s.removeLoginLogCIDR {
if cidr.Contains(ip) {
return true
}
}
lip, ierr := s.locRPC.Info(c, &lmodel.ArgIP{IP: sip})
if ierr != nil || lip == nil {
log.Error("Failed to get ip info with ip: %s: %+v", sip, ierr)
return false
}
// 过滤局域网登录
if lip.Country == "局域网" {
return true
}
return false
}
for _, l := range logs {
sip := string(int64ToIP(l.LoginIP).String())
if beRemoved(sip) {
continue
}
nl := &model.LogLogin{}
nl.Status = true
nl.Time = l.Timestamp
nl.TimeAt = time.Time(l.Timestamp).Time().Format("2006-01-02 15:04:05")
if len(excLogs) != 0 {
for _, e := range excLogs {
if int64(e.IP) == l.LoginIP && time.Time(l.Timestamp) == e.Time {
nl.Status = false
nl.Type = int64(e.FeedBack)
}
}
}
nl.IP = sip
ips = append(ips, nl.IP)
logLogins.List = append(logLogins.List, nl)
}
if locations, err = s.locRPC.Infos(c, ips); err != nil {
log.Error("s.locRPC.Infos(%v) error(%v)", ips, err)
return
}
for _, log := range logLogins.List {
if addr, ok := locations[log.IP]; ok {
log.Geo = addr.Country + addr.Province + addr.City + addr.ISP
}
log.IP = vagueIP(log.IP)
}
return
}
// Reward exp reward.
func (s *Service) Reward(c context.Context, mid int64) (reward *model.Reward, err error) {
var (
expStat *mmodel.ExpStat
todayExp int64
ip = metadata.String(c, metadata.RemoteIP)
)
if expStat, err = s.memRPC.Stat(c, &mmodel.ArgMid2{Mid: mid, RealIP: ip}); err != nil {
log.Error("s.s.memRPC.Stat(%d) error(%v)", mid, err)
return
}
if todayExp, err = s.coinRPC.TodayExp(c, &cmodel.ArgMid{Mid: mid, RealIP: ip}); err != nil {
log.Error("s.coinRPC.TodayExp(%d) error(%v)", mid, err)
return
}
if todayExp > 50 {
todayExp = 50
}
reward = &model.Reward{}
reward.Login = expStat.Login
reward.Share = expStat.Share
reward.Watch = expStat.Watch
reward.Coin = todayExp
return
}
func sexID(sex string) int64 {
switch sex {
case "男":
return 1
case "女":
return 2
default:
return 0
}
}
func sexName(sex int64) string {
switch sex {
case 1:
return "男"
case 2:
return "女"
default:
return "保密"
}
}
func vagueIP(ip string) string {
strs := strings.Split(ip, ".")
if len(strs) != 4 {
log.Error("error ip (%v)", ip)
return ""
}
strs[2] = "*"
strs[3] = "*"
return strs[0] + "." + strs[1] + "." + strs[2] + "." + strs[3]
}
func int64ToIP(ipnr int64) net.IP {
var bytes [4]byte
bytes[0] = byte(ipnr & 0xFF)
bytes[1] = byte((ipnr >> 8) & 0xFF)
bytes[2] = byte((ipnr >> 16) & 0xFF)
bytes[3] = byte((ipnr >> 24) & 0xFF)
return net.IPv4(bytes[3], bytes[2], bytes[1], bytes[0])
}

View File

@@ -0,0 +1,96 @@
package member
import (
"context"
. "github.com/smartystreets/goconvey/convey"
"go-common/app/interface/main/account/model"
"testing"
"time"
)
func TestService_SettingsInfo(t *testing.T) {
Convey("get settingsInfo info", t, func() {
Convey("when not timeout", func() {
time.Sleep(time.Second * 2)
res, err := s.SettingsInfo(context.TODO(), 110001260)
So(err, ShouldBeNil)
So(res, ShouldNotBeEmpty)
})
})
}
func TestService_LogLogin(t *testing.T) {
Convey("get settingsInfo info", t, func() {
Convey("when not timeout", func() {
time.Sleep(time.Second * 2)
res, err := s.LogLogin(context.TODO(), 110001260)
So(err, ShouldBeNil)
So(res, ShouldNotBeEmpty)
})
})
}
func TestService_LogCoin(t *testing.T) {
Convey("get settingsInfo info", t, func() {
Convey("when not timeout", func() {
time.Sleep(time.Second * 2)
res, err := s.LogCoin(context.TODO(), 1)
So(err, ShouldBeNil)
So(res, ShouldNotBeEmpty)
})
})
}
func TestService_LogExp(t *testing.T) {
Convey("get settingsInfo info", t, func() {
Convey("when not timeout", func() {
time.Sleep(time.Second * 2)
res, err := s.LogExp(context.TODO(), 110001260)
So(err, ShouldBeNil)
So(res, ShouldNotBeEmpty)
})
})
}
func TestService_LogMoral(t *testing.T) {
Convey("get settingsInfo info", t, func() {
Convey("when not timeout", func() {
time.Sleep(time.Second * 2)
res, err := s.LogMoral(context.TODO(), 110001260)
So(err, ShouldBeNil)
So(res, ShouldNotBeEmpty)
})
})
}
func TestService_Coin(t *testing.T) {
Convey("get settingsInfo info", t, func() {
Convey("when not timeout", func() {
time.Sleep(time.Second * 2)
res, err := s.Coin(context.TODO(), 1)
So(err, ShouldBeNil)
So(res, ShouldNotBeEmpty)
})
})
}
func TestService_UpdateSettings(t *testing.T) {
Convey("get settingsInfo info", t, func() {
Convey("when not timeout", func() {
time.Sleep(time.Second * 2)
err := s.UpdateSettings(context.TODO(), 110000092, &model.Settings{Uname: "test", Sex: "男"})
So(err, ShouldBeNil)
})
})
}
func TestService_Reward(t *testing.T) {
Convey("reward info", t, func() {
Convey("when not timeout", func() {
time.Sleep(time.Second * 2)
res, err := s.Reward(context.TODO(), 2)
So(err, ShouldBeNil)
So(res, ShouldNotBeEmpty)
})
})
}