fix social network server
This commit is contained in:
parent
350bbf086c
commit
e352f006b0
|
@ -2,4 +2,4 @@
|
||||||
CREATE DATABASE relation;
|
CREATE DATABASE relation;
|
||||||
|
|
||||||
// 創建 User 節點 UID 是唯一鍵
|
// 創建 User 節點 UID 是唯一鍵
|
||||||
CREATE CONSTRAINT FOR (u:User) REQUIRE u.UID IS UNIQUE
|
CREATE CONSTRAINT FOR (u:User) REQUIRE u.uid IS UNIQUE
|
|
@ -251,7 +251,48 @@ message AddUserToNetworkReq
|
||||||
string uid = 1;
|
string uid = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
message DoFollowerRelationReq
|
||||||
|
{
|
||||||
|
string follower_uid = 1;
|
||||||
|
string followee_uid = 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
message FollowReq
|
||||||
|
{
|
||||||
|
string uid = 1;
|
||||||
|
int64 page_size = 2;
|
||||||
|
int64 page_index = 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
message FollowResp
|
||||||
|
{
|
||||||
|
repeated string uid = 1;
|
||||||
|
Pager page = 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
message FollowCountReq
|
||||||
|
{
|
||||||
|
string uid = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
message FollowCountResp
|
||||||
|
{
|
||||||
|
string uid = 1;
|
||||||
|
int64 total = 2;
|
||||||
|
}
|
||||||
|
|
||||||
service SocialNetworkService
|
service SocialNetworkService
|
||||||
{
|
{
|
||||||
rpc AddUserToNetwork(AddUserToNetworkReq) returns (OKResp);
|
// MarkFollowRelation 關注
|
||||||
|
rpc MarkFollowRelation(DoFollowerRelationReq) returns (OKResp);
|
||||||
|
// RemoveFollowRelation 取消關注
|
||||||
|
rpc RemoveFollowRelation(DoFollowerRelationReq) returns (OKResp);
|
||||||
|
// GetFollower 取得跟隨者名單
|
||||||
|
rpc GetFollower(FollowReq) returns (FollowResp);
|
||||||
|
// GetFollowee 取得我跟隨的名單
|
||||||
|
rpc GetFollowee(FollowReq) returns (FollowResp);
|
||||||
|
// GetFollowerCount 取得跟隨者數量
|
||||||
|
rpc GetFollowerCount(FollowCountReq) returns (FollowCountResp);
|
||||||
|
// GetFolloweeCount 取得我跟隨的數量
|
||||||
|
rpc GetFolloweeCount(FollowCountReq) returns (FollowCountResp);
|
||||||
}
|
}
|
|
@ -41,6 +41,15 @@ const (
|
||||||
SetNoMoreDataErrorCode
|
SetNoMoreDataErrorCode
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
MarkRelationErrorCode ErrorCode = iota + 30
|
||||||
|
GetFollowerErrorCode
|
||||||
|
GetFollowerCountErrorCode
|
||||||
|
GetFolloweeErrorCode
|
||||||
|
GetFolloweeCountErrorCode
|
||||||
|
RemoveRelationErrorCode
|
||||||
|
)
|
||||||
|
|
||||||
func CommentError(ec ErrorCode, s ...string) *ers.LibError {
|
func CommentError(ec ErrorCode, s ...string) *ers.LibError {
|
||||||
return ers.NewError(code.CloudEPTweeting, code.DBError,
|
return ers.NewError(code.CloudEPTweeting, code.DBError,
|
||||||
ec.ToUint32(),
|
ec.ToUint32(),
|
||||||
|
|
|
@ -4,4 +4,23 @@ import "context"
|
||||||
|
|
||||||
type SocialNetworkRepository interface {
|
type SocialNetworkRepository interface {
|
||||||
CreateUserNode(ctx context.Context, uid string) error
|
CreateUserNode(ctx context.Context, uid string) error
|
||||||
|
MarkFollowerRelation(ctx context.Context, fromUID, toUID string) error
|
||||||
|
RemoveFollowerRelation(ctx context.Context, fromUID, toUID string) error
|
||||||
|
GetFollower(ctx context.Context, req FollowReq) (FollowResp, error)
|
||||||
|
GetFollowee(ctx context.Context, req FollowReq) (FollowResp, error)
|
||||||
|
GetFollowerCount(ctx context.Context, uid string) (int64, error)
|
||||||
|
GetFolloweeCount(ctx context.Context, uid string) (int64, error)
|
||||||
|
GetDegreeBetweenUsers(ctx context.Context, uid1, uid2 string) (int64, error)
|
||||||
|
GetUIDsWithinNDegrees(ctx context.Context, uid string, degrees, pageSize, pageIndex int64) ([]string, int64, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
type FollowReq struct {
|
||||||
|
UID string
|
||||||
|
PageSize int64
|
||||||
|
PageIndex int64
|
||||||
|
}
|
||||||
|
|
||||||
|
type FollowResp struct {
|
||||||
|
UIDs []string
|
||||||
|
Total int64
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,37 +0,0 @@
|
||||||
package socialnetworkservicelogic
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"fmt"
|
|
||||||
|
|
||||||
"app-cloudep-tweeting-service/gen_result/pb/tweeting"
|
|
||||||
"app-cloudep-tweeting-service/internal/svc"
|
|
||||||
|
|
||||||
"github.com/zeromicro/go-zero/core/logx"
|
|
||||||
)
|
|
||||||
|
|
||||||
type AddUserToNetworkLogic struct {
|
|
||||||
ctx context.Context
|
|
||||||
svcCtx *svc.ServiceContext
|
|
||||||
logx.Logger
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewAddUserToNetworkLogic(ctx context.Context, svcCtx *svc.ServiceContext) *AddUserToNetworkLogic {
|
|
||||||
return &AddUserToNetworkLogic{
|
|
||||||
ctx: ctx,
|
|
||||||
svcCtx: svcCtx,
|
|
||||||
Logger: logx.WithContext(ctx),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (l *AddUserToNetworkLogic) AddUserToNetwork(in *tweeting.AddUserToNetworkReq) (*tweeting.OKResp, error) {
|
|
||||||
// todo: add your logic here and delete this line
|
|
||||||
err := l.svcCtx.SocialNetworkRepository.CreateUserNode(l.ctx, in.GetUid())
|
|
||||||
if err != nil {
|
|
||||||
fmt.Println("gg88g88g8", err)
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
fmt.Println(err)
|
|
||||||
|
|
||||||
return &tweeting.OKResp{}, nil
|
|
||||||
}
|
|
|
@ -0,0 +1,58 @@
|
||||||
|
package socialnetworkservicelogic
|
||||||
|
|
||||||
|
import (
|
||||||
|
"app-cloudep-tweeting-service/internal/domain"
|
||||||
|
ers "code.30cm.net/digimon/library-go/errs"
|
||||||
|
"context"
|
||||||
|
|
||||||
|
"app-cloudep-tweeting-service/gen_result/pb/tweeting"
|
||||||
|
"app-cloudep-tweeting-service/internal/svc"
|
||||||
|
|
||||||
|
"github.com/zeromicro/go-zero/core/logx"
|
||||||
|
)
|
||||||
|
|
||||||
|
type GetFolloweeCountLogic struct {
|
||||||
|
ctx context.Context
|
||||||
|
svcCtx *svc.ServiceContext
|
||||||
|
logx.Logger
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewGetFolloweeCountLogic(ctx context.Context, svcCtx *svc.ServiceContext) *GetFolloweeCountLogic {
|
||||||
|
return &GetFolloweeCountLogic{
|
||||||
|
ctx: ctx,
|
||||||
|
svcCtx: svcCtx,
|
||||||
|
Logger: logx.WithContext(ctx),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetFolloweeCount 取得我跟隨的數量
|
||||||
|
func (l *GetFolloweeCountLogic) GetFolloweeCount(in *tweeting.FollowCountReq) (*tweeting.FollowCountResp, error) {
|
||||||
|
// 驗證資料
|
||||||
|
if err := l.svcCtx.Validate.ValidateAll(&getFollowCountReq{
|
||||||
|
UID: in.Uid,
|
||||||
|
}); err != nil {
|
||||||
|
// 錯誤代碼 05-011-00
|
||||||
|
return nil, ers.InvalidFormat(err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
followeeCount, err := l.svcCtx.SocialNetworkRepository.GetFolloweeCount(l.ctx, in.GetUid())
|
||||||
|
if err != nil {
|
||||||
|
// 錯誤代碼 05-021-34
|
||||||
|
e := domain.CommentErrorL(
|
||||||
|
domain.GetFolloweeCountErrorCode,
|
||||||
|
logx.WithContext(l.ctx),
|
||||||
|
[]logx.LogField{
|
||||||
|
{Key: "req", Value: in},
|
||||||
|
{Key: "func", Value: "SocialNetworkRepository.GetFolloweeCount"},
|
||||||
|
{Key: "err", Value: err},
|
||||||
|
},
|
||||||
|
"failed to count follower").Wrap(err)
|
||||||
|
|
||||||
|
return nil, e
|
||||||
|
}
|
||||||
|
|
||||||
|
return &tweeting.FollowCountResp{
|
||||||
|
Uid: in.GetUid(),
|
||||||
|
Total: followeeCount,
|
||||||
|
}, nil
|
||||||
|
}
|
|
@ -0,0 +1,69 @@
|
||||||
|
package socialnetworkservicelogic
|
||||||
|
|
||||||
|
import (
|
||||||
|
"app-cloudep-tweeting-service/internal/domain"
|
||||||
|
"app-cloudep-tweeting-service/internal/domain/repository"
|
||||||
|
ers "code.30cm.net/digimon/library-go/errs"
|
||||||
|
"context"
|
||||||
|
|
||||||
|
"app-cloudep-tweeting-service/gen_result/pb/tweeting"
|
||||||
|
"app-cloudep-tweeting-service/internal/svc"
|
||||||
|
|
||||||
|
"github.com/zeromicro/go-zero/core/logx"
|
||||||
|
)
|
||||||
|
|
||||||
|
type GetFolloweeLogic struct {
|
||||||
|
ctx context.Context
|
||||||
|
svcCtx *svc.ServiceContext
|
||||||
|
logx.Logger
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewGetFolloweeLogic(ctx context.Context, svcCtx *svc.ServiceContext) *GetFolloweeLogic {
|
||||||
|
return &GetFolloweeLogic{
|
||||||
|
ctx: ctx,
|
||||||
|
svcCtx: svcCtx,
|
||||||
|
Logger: logx.WithContext(ctx),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetFollowee 取得我跟隨的名單
|
||||||
|
func (l *GetFolloweeLogic) GetFollowee(in *tweeting.FollowReq) (*tweeting.FollowResp, error) {
|
||||||
|
// 驗證資料
|
||||||
|
if err := l.svcCtx.Validate.ValidateAll(&getFollowReq{
|
||||||
|
UID: in.Uid,
|
||||||
|
PageSize: in.PageSize,
|
||||||
|
PageIndex: in.PageIndex,
|
||||||
|
}); err != nil {
|
||||||
|
// 錯誤代碼 05-011-00
|
||||||
|
return nil, ers.InvalidFormat(err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
followee, err := l.svcCtx.SocialNetworkRepository.GetFollowee(l.ctx, repository.FollowReq{
|
||||||
|
UID: in.GetUid(),
|
||||||
|
PageIndex: in.GetPageIndex(),
|
||||||
|
PageSize: in.GetPageSize(),
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
// 錯誤代碼 05-021-33
|
||||||
|
e := domain.CommentErrorL(
|
||||||
|
domain.GetFolloweeErrorCode,
|
||||||
|
logx.WithContext(l.ctx),
|
||||||
|
[]logx.LogField{
|
||||||
|
{Key: "req", Value: in},
|
||||||
|
{Key: "func", Value: "SocialNetworkRepository.GetFollowee"},
|
||||||
|
{Key: "err", Value: err},
|
||||||
|
},
|
||||||
|
"failed to get relation: ", in.GetUid()).Wrap(err)
|
||||||
|
|
||||||
|
return nil, e
|
||||||
|
}
|
||||||
|
|
||||||
|
return &tweeting.FollowResp{
|
||||||
|
Uid: followee.UIDs,
|
||||||
|
Page: &tweeting.Pager{
|
||||||
|
Total: followee.Total,
|
||||||
|
Index: in.GetPageIndex(),
|
||||||
|
Size: in.GetPageSize(),
|
||||||
|
},
|
||||||
|
}, nil
|
||||||
|
}
|
|
@ -0,0 +1,62 @@
|
||||||
|
package socialnetworkservicelogic
|
||||||
|
|
||||||
|
import (
|
||||||
|
"app-cloudep-tweeting-service/internal/domain"
|
||||||
|
ers "code.30cm.net/digimon/library-go/errs"
|
||||||
|
"context"
|
||||||
|
|
||||||
|
"app-cloudep-tweeting-service/gen_result/pb/tweeting"
|
||||||
|
"app-cloudep-tweeting-service/internal/svc"
|
||||||
|
|
||||||
|
"github.com/zeromicro/go-zero/core/logx"
|
||||||
|
)
|
||||||
|
|
||||||
|
type GetFollowerCountLogic struct {
|
||||||
|
ctx context.Context
|
||||||
|
svcCtx *svc.ServiceContext
|
||||||
|
logx.Logger
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewGetFollowerCountLogic(ctx context.Context, svcCtx *svc.ServiceContext) *GetFollowerCountLogic {
|
||||||
|
return &GetFollowerCountLogic{
|
||||||
|
ctx: ctx,
|
||||||
|
svcCtx: svcCtx,
|
||||||
|
Logger: logx.WithContext(ctx),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type getFollowCountReq struct {
|
||||||
|
UID string `validate:"required"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetFollowerCount 取得跟隨者數量
|
||||||
|
func (l *GetFollowerCountLogic) GetFollowerCount(in *tweeting.FollowCountReq) (*tweeting.FollowCountResp, error) {
|
||||||
|
// 驗證資料
|
||||||
|
if err := l.svcCtx.Validate.ValidateAll(&getFollowCountReq{
|
||||||
|
UID: in.Uid,
|
||||||
|
}); err != nil {
|
||||||
|
// 錯誤代碼 05-011-00
|
||||||
|
return nil, ers.InvalidFormat(err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
followerCount, err := l.svcCtx.SocialNetworkRepository.GetFollowerCount(l.ctx, in.GetUid())
|
||||||
|
if err != nil {
|
||||||
|
// 錯誤代碼 05-021-32
|
||||||
|
e := domain.CommentErrorL(
|
||||||
|
domain.GetFollowerCountErrorCode,
|
||||||
|
logx.WithContext(l.ctx),
|
||||||
|
[]logx.LogField{
|
||||||
|
{Key: "req", Value: in},
|
||||||
|
{Key: "func", Value: "SocialNetworkRepository.GetFollowerCount"},
|
||||||
|
{Key: "err", Value: err},
|
||||||
|
},
|
||||||
|
"failed to count follower").Wrap(err)
|
||||||
|
|
||||||
|
return nil, e
|
||||||
|
}
|
||||||
|
|
||||||
|
return &tweeting.FollowCountResp{
|
||||||
|
Uid: in.GetUid(),
|
||||||
|
Total: followerCount,
|
||||||
|
}, nil
|
||||||
|
}
|
|
@ -0,0 +1,75 @@
|
||||||
|
package socialnetworkservicelogic
|
||||||
|
|
||||||
|
import (
|
||||||
|
"app-cloudep-tweeting-service/internal/domain"
|
||||||
|
"app-cloudep-tweeting-service/internal/domain/repository"
|
||||||
|
ers "code.30cm.net/digimon/library-go/errs"
|
||||||
|
"context"
|
||||||
|
|
||||||
|
"app-cloudep-tweeting-service/gen_result/pb/tweeting"
|
||||||
|
"app-cloudep-tweeting-service/internal/svc"
|
||||||
|
|
||||||
|
"github.com/zeromicro/go-zero/core/logx"
|
||||||
|
)
|
||||||
|
|
||||||
|
type GetFollowerLogic struct {
|
||||||
|
ctx context.Context
|
||||||
|
svcCtx *svc.ServiceContext
|
||||||
|
logx.Logger
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewGetFollowerLogic(ctx context.Context, svcCtx *svc.ServiceContext) *GetFollowerLogic {
|
||||||
|
return &GetFollowerLogic{
|
||||||
|
ctx: ctx,
|
||||||
|
svcCtx: svcCtx,
|
||||||
|
Logger: logx.WithContext(ctx),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type getFollowReq struct {
|
||||||
|
UID string `validate:"required"`
|
||||||
|
PageSize int64 `validate:"required"`
|
||||||
|
PageIndex int64 `validate:"required"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetFollower 取得跟隨者名單
|
||||||
|
func (l *GetFollowerLogic) GetFollower(in *tweeting.FollowReq) (*tweeting.FollowResp, error) {
|
||||||
|
// 驗證資料
|
||||||
|
if err := l.svcCtx.Validate.ValidateAll(&getFollowReq{
|
||||||
|
UID: in.Uid,
|
||||||
|
PageSize: in.PageSize,
|
||||||
|
PageIndex: in.PageIndex,
|
||||||
|
}); err != nil {
|
||||||
|
// 錯誤代碼 05-011-00
|
||||||
|
return nil, ers.InvalidFormat(err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
follower, err := l.svcCtx.SocialNetworkRepository.GetFollower(l.ctx, repository.FollowReq{
|
||||||
|
UID: in.GetUid(),
|
||||||
|
PageIndex: in.GetPageIndex(),
|
||||||
|
PageSize: in.GetPageSize(),
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
// 錯誤代碼 05-021-31
|
||||||
|
e := domain.CommentErrorL(
|
||||||
|
domain.GetFollowerErrorCode,
|
||||||
|
logx.WithContext(l.ctx),
|
||||||
|
[]logx.LogField{
|
||||||
|
{Key: "req", Value: in},
|
||||||
|
{Key: "func", Value: "SocialNetworkRepository.GetFollower"},
|
||||||
|
{Key: "err", Value: err},
|
||||||
|
},
|
||||||
|
"failed to get relation: ", in.GetUid()).Wrap(err)
|
||||||
|
|
||||||
|
return nil, e
|
||||||
|
}
|
||||||
|
|
||||||
|
return &tweeting.FollowResp{
|
||||||
|
Uid: follower.UIDs,
|
||||||
|
Page: &tweeting.Pager{
|
||||||
|
Total: follower.Total,
|
||||||
|
Index: in.GetPageIndex(),
|
||||||
|
Size: in.GetPageSize(),
|
||||||
|
},
|
||||||
|
}, nil
|
||||||
|
}
|
|
@ -0,0 +1,62 @@
|
||||||
|
package socialnetworkservicelogic
|
||||||
|
|
||||||
|
import (
|
||||||
|
"app-cloudep-tweeting-service/internal/domain"
|
||||||
|
ers "code.30cm.net/digimon/library-go/errs"
|
||||||
|
"context"
|
||||||
|
|
||||||
|
"app-cloudep-tweeting-service/gen_result/pb/tweeting"
|
||||||
|
"app-cloudep-tweeting-service/internal/svc"
|
||||||
|
|
||||||
|
"github.com/zeromicro/go-zero/core/logx"
|
||||||
|
)
|
||||||
|
|
||||||
|
type MarkFollowRelationLogic struct {
|
||||||
|
ctx context.Context
|
||||||
|
svcCtx *svc.ServiceContext
|
||||||
|
logx.Logger
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewMarkFollowRelationLogic(ctx context.Context, svcCtx *svc.ServiceContext) *MarkFollowRelationLogic {
|
||||||
|
return &MarkFollowRelationLogic{
|
||||||
|
ctx: ctx,
|
||||||
|
svcCtx: svcCtx,
|
||||||
|
Logger: logx.WithContext(ctx),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type doFollowReq struct {
|
||||||
|
FollowerUID string `json:"follower_uid" validate:"required"` // 追隨者,跟隨你的人(別人關注你)
|
||||||
|
FolloweeUID string `json:"followee_uid" validate:"required"` // 追蹤者,你跟隨的人(你關注別)
|
||||||
|
}
|
||||||
|
|
||||||
|
// MarkFollowRelation 關注
|
||||||
|
func (l *MarkFollowRelationLogic) MarkFollowRelation(in *tweeting.DoFollowerRelationReq) (*tweeting.OKResp, error) {
|
||||||
|
// 驗證資料
|
||||||
|
if err := l.svcCtx.Validate.ValidateAll(&doFollowReq{
|
||||||
|
FollowerUID: in.GetFollowerUid(),
|
||||||
|
FolloweeUID: in.GetFolloweeUid(),
|
||||||
|
}); err != nil {
|
||||||
|
// 錯誤代碼 05-011-00
|
||||||
|
return nil, ers.InvalidFormat(err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
// 這裡要幫建立關係, follower 追蹤 -> followee
|
||||||
|
err := l.svcCtx.SocialNetworkRepository.MarkFollowerRelation(l.ctx, in.GetFollowerUid(), in.GetFolloweeUid())
|
||||||
|
if err != nil {
|
||||||
|
// 錯誤代碼 05-021-30
|
||||||
|
e := domain.CommentErrorL(
|
||||||
|
domain.MarkRelationErrorCode,
|
||||||
|
logx.WithContext(l.ctx),
|
||||||
|
[]logx.LogField{
|
||||||
|
{Key: "req", Value: in},
|
||||||
|
{Key: "func", Value: "SocialNetworkRepository.MarkFollowerRelationBetweenUsers"},
|
||||||
|
{Key: "err", Value: err},
|
||||||
|
},
|
||||||
|
"failed to mark relation form -> to", in.GetFollowerUid(), in.GetFolloweeUid()).Wrap(err)
|
||||||
|
|
||||||
|
return nil, e
|
||||||
|
}
|
||||||
|
|
||||||
|
return &tweeting.OKResp{}, nil
|
||||||
|
}
|
|
@ -0,0 +1,57 @@
|
||||||
|
package socialnetworkservicelogic
|
||||||
|
|
||||||
|
import (
|
||||||
|
"app-cloudep-tweeting-service/internal/domain"
|
||||||
|
ers "code.30cm.net/digimon/library-go/errs"
|
||||||
|
"context"
|
||||||
|
|
||||||
|
"app-cloudep-tweeting-service/gen_result/pb/tweeting"
|
||||||
|
"app-cloudep-tweeting-service/internal/svc"
|
||||||
|
|
||||||
|
"github.com/zeromicro/go-zero/core/logx"
|
||||||
|
)
|
||||||
|
|
||||||
|
type RemoveFollowRelationLogic struct {
|
||||||
|
ctx context.Context
|
||||||
|
svcCtx *svc.ServiceContext
|
||||||
|
logx.Logger
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewRemoveFollowRelationLogic(ctx context.Context, svcCtx *svc.ServiceContext) *RemoveFollowRelationLogic {
|
||||||
|
return &RemoveFollowRelationLogic{
|
||||||
|
ctx: ctx,
|
||||||
|
svcCtx: svcCtx,
|
||||||
|
Logger: logx.WithContext(ctx),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// RemoveFollowRelation 取消關注
|
||||||
|
func (l *RemoveFollowRelationLogic) RemoveFollowRelation(in *tweeting.DoFollowerRelationReq) (*tweeting.OKResp, error) {
|
||||||
|
// 驗證資料
|
||||||
|
if err := l.svcCtx.Validate.ValidateAll(&doFollowReq{
|
||||||
|
FollowerUID: in.GetFollowerUid(),
|
||||||
|
FolloweeUID: in.GetFolloweeUid(),
|
||||||
|
}); err != nil {
|
||||||
|
// 錯誤代碼 05-011-00
|
||||||
|
return nil, ers.InvalidFormat(err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
// 這裡要幫刪除關係, follower 追蹤 -> followee
|
||||||
|
err := l.svcCtx.SocialNetworkRepository.RemoveFollowerRelation(l.ctx, in.GetFollowerUid(), in.GetFolloweeUid())
|
||||||
|
if err != nil {
|
||||||
|
// 錯誤代碼 05-021-35
|
||||||
|
e := domain.CommentErrorL(
|
||||||
|
domain.RemoveRelationErrorCode,
|
||||||
|
logx.WithContext(l.ctx),
|
||||||
|
[]logx.LogField{
|
||||||
|
{Key: "req", Value: in},
|
||||||
|
{Key: "func", Value: "SocialNetworkRepository.RemoveFollowerRelation"},
|
||||||
|
{Key: "err", Value: err},
|
||||||
|
},
|
||||||
|
"failed to remove relation form -> to", in.GetFollowerUid(), in.GetFolloweeUid()).Wrap(err)
|
||||||
|
|
||||||
|
return nil, e
|
||||||
|
}
|
||||||
|
|
||||||
|
return &tweeting.OKResp{}, nil
|
||||||
|
}
|
|
@ -5,6 +5,7 @@ import (
|
||||||
"app-cloudep-tweeting-service/internal/domain/repository"
|
"app-cloudep-tweeting-service/internal/domain/repository"
|
||||||
client4J "app-cloudep-tweeting-service/internal/lib/neo4j"
|
client4J "app-cloudep-tweeting-service/internal/lib/neo4j"
|
||||||
"context"
|
"context"
|
||||||
|
"fmt"
|
||||||
"github.com/neo4j/neo4j-go-driver/v5/neo4j"
|
"github.com/neo4j/neo4j-go-driver/v5/neo4j"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -25,7 +26,7 @@ func MustSocialNetworkRepository(param SocialNetworkParam) repository.SocialNetw
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s SocialNetworkRepository) CreateUserNode(ctx context.Context, uid string) error {
|
func (s *SocialNetworkRepository) CreateUserNode(ctx context.Context, uid string) error {
|
||||||
session, err := s.neo4jClient.Conn()
|
session, err := s.neo4jClient.Conn()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -36,18 +37,356 @@ func (s SocialNetworkRepository) CreateUserNode(ctx context.Context, uid string)
|
||||||
"uid": uid,
|
"uid": uid,
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err = session.NewSession(ctx, neo4j.SessionConfig{
|
run, err := session.NewSession(ctx, neo4j.SessionConfig{
|
||||||
AccessMode: neo4j.AccessModeWrite,
|
AccessMode: neo4j.AccessModeWrite,
|
||||||
}).Run(ctx, "CREATE (n:User {uid: $uid}) RETURN n", params)
|
}).Run(ctx, "CREATE (n:User {uid: $uid}) RETURN n", params)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// // 處理結果
|
// 處理結果
|
||||||
// if run.Next(ctx) {
|
if run.Next(ctx) {
|
||||||
// node := run.Record().AsMap()
|
_ = run.Record().AsMap()
|
||||||
// fmt.Printf("Created Node: %v\n", node)
|
}
|
||||||
// }
|
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *SocialNetworkRepository) MarkFollowerRelation(ctx context.Context, fromUID, toUID string) error {
|
||||||
|
session, err := s.neo4jClient.Conn()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer session.Close(ctx)
|
||||||
|
|
||||||
|
params := map[string]interface{}{
|
||||||
|
"fromUID": fromUID,
|
||||||
|
"toUID": toUID,
|
||||||
|
}
|
||||||
|
|
||||||
|
// 這是有向的關係 form -> to
|
||||||
|
query := `
|
||||||
|
MERGE (from:User {uid: $fromUID})
|
||||||
|
MERGE (to:User {uid: $toUID})
|
||||||
|
MERGE (from)-[:FRIENDS_WITH]->(to)
|
||||||
|
RETURN from, to
|
||||||
|
`
|
||||||
|
|
||||||
|
run, err := session.NewSession(ctx, neo4j.SessionConfig{
|
||||||
|
AccessMode: neo4j.AccessModeWrite,
|
||||||
|
}).Run(ctx, query, params)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// 處理結果
|
||||||
|
if run.Next(ctx) {
|
||||||
|
_ = run.Record().AsMap()
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *SocialNetworkRepository) GetFollower(ctx context.Context, req repository.FollowReq) (repository.FollowResp, error) {
|
||||||
|
session, err := s.neo4jClient.Conn()
|
||||||
|
if err != nil {
|
||||||
|
return repository.FollowResp{}, err
|
||||||
|
}
|
||||||
|
defer session.Close(ctx)
|
||||||
|
|
||||||
|
params := map[string]interface{}{
|
||||||
|
"uid": req.UID,
|
||||||
|
"skip": (req.PageIndex - 1) * req.PageSize,
|
||||||
|
"limit": req.PageSize,
|
||||||
|
}
|
||||||
|
|
||||||
|
query := `
|
||||||
|
MATCH (follower:User)-[:FRIENDS_WITH]->(user:User {uid: $uid})
|
||||||
|
RETURN follower.uid AS uid
|
||||||
|
SKIP $skip LIMIT $limit
|
||||||
|
`
|
||||||
|
|
||||||
|
run, err := session.NewSession(ctx, neo4j.SessionConfig{
|
||||||
|
AccessMode: neo4j.AccessModeRead,
|
||||||
|
}).Run(ctx, query, params)
|
||||||
|
if err != nil {
|
||||||
|
return repository.FollowResp{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var uids []string
|
||||||
|
for run.Next(ctx) {
|
||||||
|
record := run.Record()
|
||||||
|
if uid, ok := record.Get("uid"); ok {
|
||||||
|
uids = append(uids, uid.(string))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
total, err := s.GetFollowerCount(ctx, req.UID)
|
||||||
|
if err != nil {
|
||||||
|
return repository.FollowResp{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return repository.FollowResp{
|
||||||
|
UIDs: uids,
|
||||||
|
Total: total,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *SocialNetworkRepository) GetFollowee(ctx context.Context, req repository.FollowReq) (repository.FollowResp, error) {
|
||||||
|
session, err := s.neo4jClient.Conn()
|
||||||
|
if err != nil {
|
||||||
|
return repository.FollowResp{}, err
|
||||||
|
}
|
||||||
|
defer session.Close(ctx)
|
||||||
|
|
||||||
|
params := map[string]interface{}{
|
||||||
|
"uid": req.UID,
|
||||||
|
"skip": (req.PageIndex - 1) * req.PageSize,
|
||||||
|
"limit": req.PageSize,
|
||||||
|
}
|
||||||
|
|
||||||
|
query := `
|
||||||
|
MATCH (user:User {uid: $uid})-[:FRIENDS_WITH]->(followee:User)
|
||||||
|
RETURN followee.uid AS uid
|
||||||
|
SKIP $skip LIMIT $limit
|
||||||
|
`
|
||||||
|
|
||||||
|
run, err := session.NewSession(ctx, neo4j.SessionConfig{
|
||||||
|
AccessMode: neo4j.AccessModeRead,
|
||||||
|
}).Run(ctx, query, params)
|
||||||
|
if err != nil {
|
||||||
|
return repository.FollowResp{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var uids []string
|
||||||
|
for run.Next(ctx) {
|
||||||
|
record := run.Record()
|
||||||
|
if uid, ok := record.Get("uid"); ok {
|
||||||
|
uids = append(uids, uid.(string))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
total, err := s.GetFolloweeCount(ctx, req.UID)
|
||||||
|
if err != nil {
|
||||||
|
return repository.FollowResp{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return repository.FollowResp{
|
||||||
|
UIDs: uids,
|
||||||
|
Total: total,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *SocialNetworkRepository) GetFollowerCount(ctx context.Context, uid string) (int64, error) {
|
||||||
|
session, err := s.neo4jClient.Conn()
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
defer session.Close(ctx)
|
||||||
|
|
||||||
|
params := map[string]interface{}{
|
||||||
|
"uid": uid,
|
||||||
|
}
|
||||||
|
|
||||||
|
query := `
|
||||||
|
MATCH (:User)-[:FRIENDS_WITH]->(user:User {uid: $uid})
|
||||||
|
RETURN count(*) AS followerCount
|
||||||
|
`
|
||||||
|
|
||||||
|
run, err := session.NewSession(ctx, neo4j.SessionConfig{
|
||||||
|
AccessMode: neo4j.AccessModeRead,
|
||||||
|
}).Run(ctx, query, params)
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var count int64
|
||||||
|
if run.Next(ctx) {
|
||||||
|
record := run.Record()
|
||||||
|
if followerCount, ok := record.Get("followerCount"); ok {
|
||||||
|
count = followerCount.(int64)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return count, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *SocialNetworkRepository) GetFolloweeCount(ctx context.Context, uid string) (int64, error) {
|
||||||
|
session, err := s.neo4jClient.Conn()
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
defer session.Close(ctx)
|
||||||
|
|
||||||
|
params := map[string]interface{}{
|
||||||
|
"uid": uid,
|
||||||
|
}
|
||||||
|
|
||||||
|
query := `
|
||||||
|
MATCH (user:User {uid: $uid})-[:FRIENDS_WITH]->(:User)
|
||||||
|
RETURN count(*) AS followeeCount
|
||||||
|
`
|
||||||
|
|
||||||
|
run, err := session.NewSession(ctx, neo4j.SessionConfig{
|
||||||
|
AccessMode: neo4j.AccessModeRead,
|
||||||
|
}).Run(ctx, query, params)
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var count int64
|
||||||
|
if run.Next(ctx) {
|
||||||
|
record := run.Record()
|
||||||
|
if followeeCount, ok := record.Get("followeeCount"); ok {
|
||||||
|
count = followeeCount.(int64)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return count, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *SocialNetworkRepository) RemoveFollowerRelation(ctx context.Context, fromUID, toUID string) error {
|
||||||
|
session, err := s.neo4jClient.Conn()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer session.Close(ctx)
|
||||||
|
|
||||||
|
params := map[string]interface{}{
|
||||||
|
"fromUID": fromUID,
|
||||||
|
"toUID": toUID,
|
||||||
|
}
|
||||||
|
|
||||||
|
query := `
|
||||||
|
MATCH (from:User {uid: $fromUID})-[r:FRIENDS_WITH]->(to:User {uid: $toUID})
|
||||||
|
DELETE r
|
||||||
|
`
|
||||||
|
|
||||||
|
_, err = session.NewSession(ctx, neo4j.SessionConfig{
|
||||||
|
AccessMode: neo4j.AccessModeWrite,
|
||||||
|
}).Run(ctx, query, params)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed to remove follower relation: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetDegreeBetweenUsers 取得這兩個點之間的度數 (最短路徑長度)
|
||||||
|
func (s *SocialNetworkRepository) GetDegreeBetweenUsers(ctx context.Context, uid1, uid2 string) (int64, error) {
|
||||||
|
session, err := s.neo4jClient.Conn()
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
defer session.Close(ctx)
|
||||||
|
|
||||||
|
params := map[string]interface{}{
|
||||||
|
"uid1": uid1,
|
||||||
|
"uid2": uid2,
|
||||||
|
}
|
||||||
|
|
||||||
|
query := `
|
||||||
|
MATCH (user1:User {uid: $uid1}), (user2:User {uid: $uid2})
|
||||||
|
MATCH p = shortestPath((user1)-[*]-(user2))
|
||||||
|
RETURN length(p) AS degree
|
||||||
|
`
|
||||||
|
|
||||||
|
run, err := session.NewSession(ctx, neo4j.SessionConfig{
|
||||||
|
AccessMode: neo4j.AccessModeRead,
|
||||||
|
}).Run(ctx, query, params)
|
||||||
|
if err != nil {
|
||||||
|
return 0, fmt.Errorf("failed to get degree between users: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
var degree int64
|
||||||
|
if run.Next(ctx) {
|
||||||
|
record := run.Record()
|
||||||
|
if deg, ok := record.Get("degree"); ok {
|
||||||
|
degree = deg.(int64)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return degree, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetUIDsWithinNDegrees 取得某個節點在 n 度內關係所有 UID
|
||||||
|
func (s *SocialNetworkRepository) GetUIDsWithinNDegrees(ctx context.Context, uid string, degrees, pageSize, pageIndex int64) ([]string, int64, error) {
|
||||||
|
session, err := s.neo4jClient.Conn()
|
||||||
|
if err != nil {
|
||||||
|
return nil, 0, err
|
||||||
|
}
|
||||||
|
defer session.Close(ctx)
|
||||||
|
|
||||||
|
params := map[string]interface{}{
|
||||||
|
"uid": uid,
|
||||||
|
"degrees": degrees,
|
||||||
|
"skip": (pageIndex - 1) * pageSize,
|
||||||
|
"limit": pageSize,
|
||||||
|
}
|
||||||
|
|
||||||
|
// 查詢結果帶分頁
|
||||||
|
query := `
|
||||||
|
MATCH (user:User {uid: $uid})-[:FRIENDS_WITH*1..$degrees]-(related:User)
|
||||||
|
WITH DISTINCT related.uid AS uid
|
||||||
|
SKIP $skip LIMIT $limit
|
||||||
|
RETURN uid
|
||||||
|
`
|
||||||
|
|
||||||
|
run, err := session.NewSession(ctx, neo4j.SessionConfig{
|
||||||
|
AccessMode: neo4j.AccessModeRead,
|
||||||
|
}).Run(ctx, query, params)
|
||||||
|
if err != nil {
|
||||||
|
return nil, 0, fmt.Errorf("failed to get uids within %d degrees of user: %w", degrees, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
var uids []string
|
||||||
|
for run.Next(ctx) {
|
||||||
|
record := run.Record()
|
||||||
|
if uid, ok := record.Get("uid"); ok {
|
||||||
|
uids = append(uids, uid.(string))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 計算總數
|
||||||
|
totalCount, err := s.getTotalUIDsWithinNDegrees(ctx, uid, degrees)
|
||||||
|
if err != nil {
|
||||||
|
return nil, 0, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return uids, totalCount, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *SocialNetworkRepository) getTotalUIDsWithinNDegrees(ctx context.Context, uid string, degrees int64) (int64, error) {
|
||||||
|
session, err := s.neo4jClient.Conn()
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
defer session.Close(ctx)
|
||||||
|
|
||||||
|
params := map[string]interface{}{
|
||||||
|
"uid": uid,
|
||||||
|
"degrees": degrees,
|
||||||
|
}
|
||||||
|
|
||||||
|
query := `
|
||||||
|
MATCH (user:User {uid: $uid})-[:FRIENDS_WITH*1..$degrees]-(related:User)
|
||||||
|
RETURN count(DISTINCT related.uid) AS totalCount
|
||||||
|
`
|
||||||
|
|
||||||
|
run, err := session.NewSession(ctx, neo4j.SessionConfig{
|
||||||
|
AccessMode: neo4j.AccessModeRead,
|
||||||
|
}).Run(ctx, query, params)
|
||||||
|
if err != nil {
|
||||||
|
return 0, fmt.Errorf("failed to get total uids within %d degrees of user: %w", degrees, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
var totalCount int64
|
||||||
|
if run.Next(ctx) {
|
||||||
|
record := run.Record()
|
||||||
|
if count, ok := record.Get("totalCount"); ok {
|
||||||
|
totalCount = count.(int64)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return totalCount, nil
|
||||||
|
}
|
||||||
|
|
|
@ -22,7 +22,38 @@ func NewSocialNetworkServiceServer(svcCtx *svc.ServiceContext) *SocialNetworkSer
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *SocialNetworkServiceServer) AddUserToNetwork(ctx context.Context, in *tweeting.AddUserToNetworkReq) (*tweeting.OKResp, error) {
|
// MarkFollowRelation 關注
|
||||||
l := socialnetworkservicelogic.NewAddUserToNetworkLogic(ctx, s.svcCtx)
|
func (s *SocialNetworkServiceServer) MarkFollowRelation(ctx context.Context, in *tweeting.DoFollowerRelationReq) (*tweeting.OKResp, error) {
|
||||||
return l.AddUserToNetwork(in)
|
l := socialnetworkservicelogic.NewMarkFollowRelationLogic(ctx, s.svcCtx)
|
||||||
|
return l.MarkFollowRelation(in)
|
||||||
|
}
|
||||||
|
|
||||||
|
// RemoveFollowRelation 取消關注
|
||||||
|
func (s *SocialNetworkServiceServer) RemoveFollowRelation(ctx context.Context, in *tweeting.DoFollowerRelationReq) (*tweeting.OKResp, error) {
|
||||||
|
l := socialnetworkservicelogic.NewRemoveFollowRelationLogic(ctx, s.svcCtx)
|
||||||
|
return l.RemoveFollowRelation(in)
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetFollower 取得跟隨者名單
|
||||||
|
func (s *SocialNetworkServiceServer) GetFollower(ctx context.Context, in *tweeting.FollowReq) (*tweeting.FollowResp, error) {
|
||||||
|
l := socialnetworkservicelogic.NewGetFollowerLogic(ctx, s.svcCtx)
|
||||||
|
return l.GetFollower(in)
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetFollowee 取得我跟隨的名單
|
||||||
|
func (s *SocialNetworkServiceServer) GetFollowee(ctx context.Context, in *tweeting.FollowReq) (*tweeting.FollowResp, error) {
|
||||||
|
l := socialnetworkservicelogic.NewGetFolloweeLogic(ctx, s.svcCtx)
|
||||||
|
return l.GetFollowee(in)
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetFollowerCount 取得跟隨者數量
|
||||||
|
func (s *SocialNetworkServiceServer) GetFollowerCount(ctx context.Context, in *tweeting.FollowCountReq) (*tweeting.FollowCountResp, error) {
|
||||||
|
l := socialnetworkservicelogic.NewGetFollowerCountLogic(ctx, s.svcCtx)
|
||||||
|
return l.GetFollowerCount(in)
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetFolloweeCount 取得我跟隨的數量
|
||||||
|
func (s *SocialNetworkServiceServer) GetFolloweeCount(ctx context.Context, in *tweeting.FollowCountReq) (*tweeting.FollowCountResp, error) {
|
||||||
|
l := socialnetworkservicelogic.NewGetFolloweeCountLogic(ctx, s.svcCtx)
|
||||||
|
return l.GetFolloweeCount(in)
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue