Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add payment #135

Merged
merged 1 commit into from
Apr 22, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions server/cmd/api/biz/handler/user/user_service.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 5 additions & 0 deletions server/cmd/trip/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ type ServerConfig struct {
OtelInfo OtelConfig `mapstructure:"otel" json:"otel"`
CarSrvInfo CarSrvConfig `mapstructure:"car_srv" json:"car_srv"`
ProfileSrvInfo ProfileSrvConfig `mapstructure:"profile_srv" json:"profile_srv"`
UserSrvInfo UserSrvConfig `mapstructure:"user_srv" json:"user_srv"`
}

type CarSrvConfig struct {
Expand All @@ -35,3 +36,7 @@ type CarSrvConfig struct {
type ProfileSrvConfig struct {
Name string `mapstructure:"name" json:"name"`
}

type UserSrvConfig struct {
Name string `mapstructure:"name" json:"name"`
}
2 changes: 2 additions & 0 deletions server/cmd/trip/config/global.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package config
import (
"github.com/CyanAsterisk/FreeCar/server/shared/kitex_gen/car/carservice"
"github.com/CyanAsterisk/FreeCar/server/shared/kitex_gen/profile/profileservice"
"github.com/CyanAsterisk/FreeCar/server/shared/kitex_gen/user/userservice"
)

var (
Expand All @@ -11,4 +12,5 @@ var (

CarClient carservice.Client
ProfileClient profileservice.Client
UserClient userservice.Client
)
12 changes: 12 additions & 0 deletions server/cmd/trip/handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,12 @@ type TripServiceImpl struct {
CarManager CarManager
POIManager POIManager
MongoManager MongoManager
PayManager PayManager
}

// PayManager defines the ACL for payment.
type PayManager interface {
Pay(ctx context.Context, aid id.AccountID, feeCent int32) error
}

// ProfileManager defines the ACL(Anti Corruption Layer)
Expand Down Expand Up @@ -194,6 +200,12 @@ func (s *TripServiceImpl) UpdateTrip(ctx context.Context, req *trip.UpdateTripRe
resp.BaseResp = tools.BuildBaseResp(errno.CarSrvErr.WithMessage("lock car err"))
return resp, nil
}

if err = s.PayManager.Pay(ctx, aid, tr.Trip.End.FeeCent); err != nil {
klog.Error("pay err", err)
resp.BaseResp = tools.BuildBaseResp(errno.ServiceErr.WithMessage("pay err"))
return resp, nil
}
}
err = s.MongoManager.UpdateTrip(ctx, tid, aid, tr.UpdatedAt, tr.Trip)
if err != nil {
Expand Down
45 changes: 45 additions & 0 deletions server/cmd/trip/initialize/user_service.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
package initialize

import (
"fmt"

"github.com/CyanAsterisk/FreeCar/server/cmd/trip/config"
"github.com/CyanAsterisk/FreeCar/server/shared/kitex_gen/user/userservice"
"github.com/cloudwego/kitex/client"
"github.com/cloudwego/kitex/pkg/klog"
"github.com/cloudwego/kitex/pkg/loadbalance"
"github.com/cloudwego/kitex/pkg/rpcinfo"
"github.com/kitex-contrib/obs-opentelemetry/provider"
"github.com/kitex-contrib/obs-opentelemetry/tracing"
consul "github.com/kitex-contrib/registry-consul"
)

func InitUser() {
// init resolver
r, err := consul.NewConsulResolver(fmt.Sprintf("%s:%d",
config.GlobalConsulConfig.Host,
config.GlobalConsulConfig.Port))
if err != nil {
klog.Fatalf("new consul client failed: %s", err.Error())
}
// init OpenTelemetry
provider.NewOpenTelemetryProvider(
provider.WithServiceName(config.GlobalServerConfig.UserSrvInfo.Name),
provider.WithExportEndpoint(config.GlobalServerConfig.OtelInfo.EndPoint),
provider.WithInsecure(),
)

// create a new client
c, err := userservice.NewClient(
config.GlobalServerConfig.UserSrvInfo.Name,
client.WithResolver(r), // service discovery
client.WithLoadBalancer(loadbalance.NewWeightedBalancer()), // load balance
client.WithMuxConnection(1), // multiplexing
client.WithSuite(tracing.NewClientSuite()),
client.WithClientBasicInfo(&rpcinfo.EndpointBasicInfo{ServiceName: config.GlobalServerConfig.UserSrvInfo.Name}),
)
if err != nil {
klog.Fatalf("ERROR: cannot init client: %v\n", err)
}
config.UserClient = c
}
4 changes: 4 additions & 0 deletions server/cmd/trip/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import (
"github.com/CyanAsterisk/FreeCar/server/cmd/trip/initialize"
"github.com/CyanAsterisk/FreeCar/server/cmd/trip/pkg/car"
"github.com/CyanAsterisk/FreeCar/server/cmd/trip/pkg/mongo"
"github.com/CyanAsterisk/FreeCar/server/cmd/trip/pkg/pay"
"github.com/CyanAsterisk/FreeCar/server/cmd/trip/pkg/poi"
"github.com/CyanAsterisk/FreeCar/server/cmd/trip/pkg/profile"
"github.com/CyanAsterisk/FreeCar/server/shared/consts"
Expand Down Expand Up @@ -37,8 +38,11 @@ func main() {
defer p.Shutdown(context.Background())
initialize.InitCar()
initialize.InitProfile()
initialize.InitUser()

impl := new(TripServiceImpl)
impl.PayManager = pay.NewManager(config.UserClient)

impl.CarManager = &car.Manager{
CarService: config.CarClient,
}
Expand Down
35 changes: 35 additions & 0 deletions server/cmd/trip/pkg/pay/pay.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
package pay

import (
"context"
"github.com/CyanAsterisk/FreeCar/server/shared/errno"
"github.com/CyanAsterisk/FreeCar/server/shared/kitex_gen/user"
"github.com/CyanAsterisk/FreeCar/server/shared/tools"

"github.com/CyanAsterisk/FreeCar/server/shared/id"
"github.com/CyanAsterisk/FreeCar/server/shared/kitex_gen/user/userservice"
)

// Manager defines a car manager.
type Manager struct {
UserClient userservice.Client
}

// NewManager creates a new pay manager.
func NewManager(c userservice.Client) *Manager {
return &Manager{
UserClient: c,
}
}

// Pay pays for the trip.
func (m *Manager) Pay(ctx context.Context, aid id.AccountID, feeCent int32) error {
resp, err := m.UserClient.Pay(ctx, &user.PayRequest{
AccountId: aid.String(),
FeeCent: feeCent,
})
if err != nil {
return errno.RPCUserSrvErr
}
return tools.ParseBaseResp(resp.BaseResp)
}
24 changes: 24 additions & 0 deletions server/cmd/user/handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -239,6 +239,7 @@ func (s *UserServiceImpl) GetUser(ctx context.Context, req *user.GetUserRequest)
Username: u.Username,
PhoneNumber: u.PhoneNumber,
AvatarUrl: "",
Balance: u.Balance,
}
if u.AvatarBlobId != "" {
res, err := s.BlobManager.GetBlobURL(ctx, &blob.GetBlobURLRequest{
Expand Down Expand Up @@ -342,3 +343,26 @@ func (s *UserServiceImpl) GetAllUsers(ctx context.Context, req *user.GetAllUsers
resp.Users = uInfos
return resp, nil
}

// Pay implements the UserServiceImpl interface.
func (s *UserServiceImpl) Pay(ctx context.Context, req *user.PayRequest) (resp *user.PayResponse, err error) {
resp = new(user.PayResponse)
var u *mysql.User
if u, err = s.UserMysqlManager.GetUserByAccountId(req.AccountId); err != nil {
if err == errno.RecordNotFound {
resp.BaseResp = tools.BuildBaseResp(errno.RecordNotFound)
} else {
klog.Error("get user error", err)
resp.BaseResp = tools.BuildBaseResp(errno.UserSrvErr.WithMessage("get user error"))
}
return resp, nil
}
u.Balance -= req.FeeCent
if err = s.UserMysqlManager.UpdateUser(u); err != nil {
klog.Error("update user error", err)
resp.BaseResp = tools.BuildBaseResp(errno.UserSrvErr.WithMessage("update user error"))
return resp, nil
}
resp.BaseResp = tools.BuildBaseResp(nil)
return resp, nil
}
4 changes: 4 additions & 0 deletions server/cmd/user/pkg/mysql/user.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ type User struct {
AvatarBlobId string
Username string `gorm:"type:varchar(40)"`
OpenID string `gorm:"column:openid;type:varchar(100);uniqueIndex"`
Balance int32 `gorm:"column:balance"`
Deleted gorm.DeletedAt
}

Expand Down Expand Up @@ -105,6 +106,9 @@ func (m *UserManager) UpdateUser(user *User) error {
if user.AvatarBlobId != "" {
u["avatar_blob_id"] = user.AvatarBlobId
}
if user.Balance != 0 {
u["balance"] = user.Balance
}
err := m.db.Model(&User{ID: user.ID}).Updates(u).Error
if err == gorm.ErrRecordNotFound {
return errno.RecordNotFound
Expand Down
16 changes: 9 additions & 7 deletions server/cmd/user/pkg/mysql/user_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ func TestUserLifecycle(t *testing.T) {
AvatarBlobId: "1001",
Username: "username1",
OpenID: "openID-1",
Balance: 1000,
}
manager := NewUserManager(db, salt)
cases := []struct {
Expand All @@ -36,7 +37,7 @@ func TestUserLifecycle(t *testing.T) {
resp, err := manager.CreateUser(&u)
return fmt.Sprintf("[err = %+v][resp = %+v]", err, resp)
},
want: "[err = <nil>][resp = &{ID:1234 PhoneNumber:10086 AvatarBlobId:1001 Username:username1 OpenID:5cc2876d40c14dcabe891399c4a0422a Deleted:{Time:0001-01-01 00:00:00 +0000 UTC Valid:false}}]",
want: `[err = <nil>][resp = &{ID:1234 PhoneNumber:10086 AvatarBlobId:1001 Username:username1 OpenID:5cc2876d40c14dcabe891399c4a0422a Balance:1000 Deleted:{Time:0001-01-01 00:00:00 +0000 UTC Valid:false}}]`,
},
{
name: "Duplicate create user",
Expand All @@ -53,15 +54,15 @@ func TestUserLifecycle(t *testing.T) {
resp, err := manager.GetUserByAccountId(user.ID)
return fmt.Sprintf("[err = %+v][resp = %+v]", err, resp)
},
want: "[err = <nil>][resp = &{ID:1234 PhoneNumber:10086 AvatarBlobId:1001 Username:username1 OpenID:5cc2876d40c14dcabe891399c4a0422a Deleted:{Time:0001-01-01 00:00:00 +0000 UTC Valid:false}}]",
want: `[err = <nil>][resp = &{ID:1234 PhoneNumber:10086 AvatarBlobId:1001 Username:username1 OpenID:5cc2876d40c14dcabe891399c4a0422a Balance:1000 Deleted:{Time:0001-01-01 00:00:00 +0000 UTC Valid:false}}]`,
},
{
name: "get user by openId",
op: func() string {
resp, err := manager.GetUserByOpenId(user.OpenID)
return fmt.Sprintf("[err = %+v][resp = %+v]", err, resp)
},
want: "[err = <nil>][resp = &{ID:1234 PhoneNumber:10086 AvatarBlobId:1001 Username:username1 OpenID:5cc2876d40c14dcabe891399c4a0422a Deleted:{Time:0001-01-01 00:00:00 +0000 UTC Valid:false}}]",
want: `[err = <nil>][resp = &{ID:1234 PhoneNumber:10086 AvatarBlobId:1001 Username:username1 OpenID:5cc2876d40c14dcabe891399c4a0422a Balance:1000 Deleted:{Time:0001-01-01 00:00:00 +0000 UTC Valid:false}}]`,
},
{
name: "update user info",
Expand All @@ -71,6 +72,7 @@ func TestUserLifecycle(t *testing.T) {
PhoneNumber: "8888888888",
AvatarBlobId: "10100101001",
Username: "new-username",
Balance: 2000,
}
err = manager.UpdateUser(&newUserInfo)
if err != nil {
Expand All @@ -79,7 +81,7 @@ func TestUserLifecycle(t *testing.T) {
resp, err := manager.GetUserByAccountId(user.ID)
return fmt.Sprintf("[err = %+v][resp = %+v]", err, resp)
},
want: "[err = <nil>][resp = &{ID:1234 PhoneNumber:8888888888 AvatarBlobId:10100101001 Username:new-username OpenID:5cc2876d40c14dcabe891399c4a0422a Deleted:{Time:0001-01-01 00:00:00 +0000 UTC Valid:false}}]",
want: `[err = <nil>][resp = &{ID:1234 PhoneNumber:8888888888 AvatarBlobId:10100101001 Username:new-username OpenID:5cc2876d40c14dcabe891399c4a0422a Balance:2000 Deleted:{Time:0001-01-01 00:00:00 +0000 UTC Valid:false}}]`,
},
{
name: "get some users",
Expand All @@ -105,7 +107,7 @@ func TestUserLifecycle(t *testing.T) {
}
return fmt.Sprintf("[err = %+v][resp = %+v]", err, string(resp))
},
want: `[err = <nil>][resp = [{"ID":"1234","PhoneNumber":"8888888888","AvatarBlobId":"10100101001","Username":"new-username","OpenID":"5cc2876d40c14dcabe891399c4a0422a","Deleted":null},{"ID":"1235","PhoneNumber":"10086","AvatarBlobId":"1001","Username":"username2","OpenID":"dcd63116db07e44a16e3f0015f965a53","Deleted":null},{"ID":"1236","PhoneNumber":"10086","AvatarBlobId":"1001","Username":"username3","OpenID":"72e38afb76dc1022c1c78b2429024d80","Deleted":null}]]`,
want: `[err = <nil>][resp = [{"ID":"1234","PhoneNumber":"8888888888","AvatarBlobId":"10100101001","Username":"new-username","OpenID":"5cc2876d40c14dcabe891399c4a0422a","Balance":2000,"Deleted":null},{"ID":"1235","PhoneNumber":"10086","AvatarBlobId":"1001","Username":"username2","OpenID":"dcd63116db07e44a16e3f0015f965a53","Balance":0,"Deleted":null},{"ID":"1236","PhoneNumber":"10086","AvatarBlobId":"1001","Username":"username3","OpenID":"72e38afb76dc1022c1c78b2429024d80","Balance":0,"Deleted":null}]]`,
},
{
name: "get all users",
Expand All @@ -117,7 +119,7 @@ func TestUserLifecycle(t *testing.T) {
}
return fmt.Sprintf("[err = %+v][resp = %+v]", err, string(resp))
},
want: `[err = <nil>][resp = [{"ID":"1234","PhoneNumber":"8888888888","AvatarBlobId":"10100101001","Username":"new-username","OpenID":"5cc2876d40c14dcabe891399c4a0422a","Deleted":null},{"ID":"1235","PhoneNumber":"10086","AvatarBlobId":"1001","Username":"username2","OpenID":"dcd63116db07e44a16e3f0015f965a53","Deleted":null},{"ID":"1236","PhoneNumber":"10086","AvatarBlobId":"1001","Username":"username3","OpenID":"72e38afb76dc1022c1c78b2429024d80","Deleted":null}]]`,
want: `[err = <nil>][resp = [{"ID":"1234","PhoneNumber":"8888888888","AvatarBlobId":"10100101001","Username":"new-username","OpenID":"5cc2876d40c14dcabe891399c4a0422a","Balance":2000,"Deleted":null},{"ID":"1235","PhoneNumber":"10086","AvatarBlobId":"1001","Username":"username2","OpenID":"dcd63116db07e44a16e3f0015f965a53","Balance":0,"Deleted":null},{"ID":"1236","PhoneNumber":"10086","AvatarBlobId":"1001","Username":"username3","OpenID":"72e38afb76dc1022c1c78b2429024d80","Balance":0,"Deleted":null}]]`,
},
{
name: "delete user",
Expand Down Expand Up @@ -147,7 +149,7 @@ func TestUserLifecycle(t *testing.T) {
}
return fmt.Sprintf("[err = %+v][resp = %+v]", err, string(resp))
},
want: `[err = <nil>][resp = [{"ID":"1234","PhoneNumber":"8888888888","AvatarBlobId":"10100101001","Username":"new-username","OpenID":"5cc2876d40c14dcabe891399c4a0422a","Deleted":null},{"ID":"1236","PhoneNumber":"10086","AvatarBlobId":"1001","Username":"username3","OpenID":"72e38afb76dc1022c1c78b2429024d80","Deleted":null}]]`,
want: `[err = <nil>][resp = [{"ID":"1234","PhoneNumber":"8888888888","AvatarBlobId":"10100101001","Username":"new-username","OpenID":"5cc2876d40c14dcabe891399c4a0422a","Balance":2000,"Deleted":null},{"ID":"1236","PhoneNumber":"10086","AvatarBlobId":"1001","Username":"username3","OpenID":"72e38afb76dc1022c1c78b2429024d80","Balance":0,"Deleted":null}]]`,
},
}

Expand Down
2 changes: 2 additions & 0 deletions server/idl/base/user.thrift
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,13 @@ struct User{
3: string phone_number;
4: string avatar_blob_id;
5: string open_id;
6: i32 balance;
}

struct UserInfo{
1: string account_id;
2: string username;
3: string phone_number;
4: string avatar_url;
5: i32 balance;
}
10 changes: 10 additions & 0 deletions server/idl/rpc/user.thrift
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,15 @@ struct GetAllUsersResponse {
2: list<user.User> users
}

struct PayRequest{
1: string account_id
2: i32 fee_cent
}

struct PayResponse{
1: common.BaseResponse base_resp
}

service UserService {
LoginResponse Login(1: LoginRequest req)
AdminLoginResponse AdminLogin(1: AdminLoginRequest req)
Expand All @@ -106,6 +115,7 @@ service UserService {
AddUserResponse AddUser(1: AddUserRequest req)
DeleteUserResponse DeleteUser(1: DeleteUserRequest req)
UpdateUserResponse UpdateUser(1: UpdateUserRequest req)
PayResponse Pay(1: PayRequest req)
GetSomeUsersResponse GetSomeUsers(1: GetSomeUsersRequest req)
GetAllUsersResponse GetAllUsers(1: GetAllUsersRequest req)
}
Loading