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

fix(account-service): fix concurrency issue and add real name info api #5103

Merged
merged 4 commits into from
Sep 25, 2024
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
34 changes: 34 additions & 0 deletions controllers/go.work.sum

Large diffs are not rendered by default.

30 changes: 30 additions & 0 deletions controllers/pkg/database/cockroach/accountv2.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ import (
"path/filepath"
"time"

"gorm.io/gorm/clause"

"gorm.io/gorm/logger"

gonanoid "github.com/matoous/go-nanoid/v2"
Expand Down Expand Up @@ -1070,6 +1072,17 @@ func (c *Cockroach) GetGiftCodeWithCode(code string) (*types.GiftCode, error) {

func (c *Cockroach) UseGiftCode(giftCode *types.GiftCode, userID string) error {
return c.DB.Transaction(func(tx *gorm.DB) error {
var lockedGiftCode types.GiftCode
// Lock the gift code record for update
if err := tx.Clauses(clause.Locking{Strength: "UPDATE", Options: "NOWAIT"}).
Where(&types.GiftCode{ID: giftCode.ID}).First(&lockedGiftCode).Error; err != nil {
return fmt.Errorf("failed to lock gift code: %w", err)
}

if lockedGiftCode.Used {
return fmt.Errorf("gift code has already been used")
}

ops := &types.UserQueryOpts{ID: userID}
// Update the user's balance
if err := c.updateBalance(tx, ops, giftCode.CreditAmount, false, true); err != nil {
Expand Down Expand Up @@ -1104,3 +1117,20 @@ func (c *Cockroach) UseGiftCode(giftCode *types.GiftCode, userID string) error {
return nil
})
}

func (c *Cockroach) GetUserRealNameInfoByUserID(userID string) (*types.UserRealNameInfo, error) {
// get user info
ops := &types.UserQueryOpts{ID: userID}
user, err := c.GetUserCr(ops)

if err != nil {
return nil, fmt.Errorf("failed to get user: %v", err)
}

// get user realname info
var userRealNameInfo types.UserRealNameInfo
if err := c.DB.Where(&types.UserRealNameInfo{UserUID: user.UserUID}).First(&userRealNameInfo).Error; err != nil {
return nil, fmt.Errorf("failed to get user real name info: %w", err)
}
return &userRealNameInfo, nil
}
18 changes: 18 additions & 0 deletions controllers/pkg/types/global.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
package types

import (
"encoding/json"
"time"

"github.com/google/uuid"
Expand Down Expand Up @@ -320,3 +321,20 @@ type AccountTransaction struct {
func (AccountTransaction) TableName() string {
return "AccountTransaction"
}

type UserRealNameInfo struct {
ID uuid.UUID `gorm:"column:id;type:uuid;default:gen_random_uuid();primary_key"`
UserUID uuid.UUID `gorm:"column:userUid;type:uuid;unique"`
RealName *string `gorm:"column:realName;type:text"`
IDCard *string `gorm:"column:idCard;type:text"`
Phone *string `gorm:"column:phone;type:text"`
IsVerified bool `gorm:"column:isVerified;type:boolean;default:false"`
IDVerifyFailedTimes int `gorm:"column:idVerifyFailedTimes;type:integer;default:0"`
CreatedAt time.Time `gorm:"column:createdAt;type:timestamp(3) with time zone;default:current_timestamp()"`
UpdatedAt time.Time `gorm:"column:updatedAt;type:timestamp(3) with time zone;autoUpdateTime"`
AdditionalInfo json.RawMessage `gorm:"column:additionalInfo;type:jsonb"`
}

func (UserRealNameInfo) TableName() string {
return "UserRealNameInfo"
}
9 changes: 9 additions & 0 deletions go.work.sum
Original file line number Diff line number Diff line change
Expand Up @@ -756,6 +756,7 @@ github.com/Azure/go-amqp v0.17.0/go.mod h1:9YJ3RhxRT1gquYnzpZO1vcYMMpAdJT+QEg6fw
github.com/Azure/go-amqp v0.18.1/go.mod h1:+bg0x3ce5+Q3ahCEXnCsGG3ETpDQe3MEVnOuT2ywPwc=
github.com/Azure/go-ansiterm v0.0.0-20210608223527-2377c96fe795/go.mod h1:LmzpDX56iTiv29bbRTIsUNlaFfuhWRQBWjQdVyAevI8=
github.com/Azure/go-autorest v12.0.0+incompatible/go.mod h1:r+4oMnoxhatjLLJ6zxSWATqVooLgysK6ZNox3g/xq24=
github.com/Azure/go-autorest v14.2.0+incompatible h1:V5VMDjClD3GiElqLWO7mz2MxNAK/vTfRHdAubSIPRgs=
github.com/Azure/go-autorest/autorest v0.11.24/go.mod h1:G6kyRlFnTuSbEYkQGawPfsCswgme4iYf6rfSKUDzbCc=
github.com/Azure/go-autorest/autorest v0.11.25/go.mod h1:7l8ybrIdUmGqZMTD0sRtAr8NvbHjfofbf8RSP2q7w7U=
github.com/Azure/go-autorest/autorest v0.11.28 h1:ndAExarwr5Y+GaHE6VCaY1kyS/HwwGGyuimVhWsHOEM=
Expand All @@ -772,11 +773,15 @@ github.com/Azure/go-autorest/autorest/azure/auth v0.5.12/go.mod h1:84w/uV8E37feW
github.com/Azure/go-autorest/autorest/azure/cli v0.4.5/go.mod h1:ADQAXrkgm7acgWVUNamOgh8YNrv4p27l3Wc55oVfpzg=
github.com/Azure/go-autorest/autorest/azure/cli v0.4.6 h1:w77/uPk80ZET2F+AfQExZyEWtn+0Rk/uw17m9fv5Ajc=
github.com/Azure/go-autorest/autorest/azure/cli v0.4.6/go.mod h1:piCfgPho7BiIDdEQ1+g4VmKyD5y+p/XtSNqE6Hc4QD0=
github.com/Azure/go-autorest/autorest/date v0.3.0 h1:7gUk1U5M/CQbp9WoqinNzJar+8KY+LPI6wiWrP/myHw=
github.com/Azure/go-autorest/autorest/mocks v0.4.2 h1:PGN4EDXnuQbojHbU0UWoNvmu9AGVwYHG9/fkDYhtAfw=
github.com/Azure/go-autorest/autorest/to v0.4.0 h1:oXVqrxakqqV1UZdSazDOPOLvOIz+XA683u8EctwboHk=
github.com/Azure/go-autorest/autorest/to v0.4.0/go.mod h1:fE8iZBn7LQR7zH/9XU2NcPR4o9jEImooCeWJcYV/zLE=
github.com/Azure/go-autorest/autorest/validation v0.1.0/go.mod h1:Ha3z/SqBeaalWQvokg3NZAlQTalVMtOIAs1aGK7G6u8=
github.com/Azure/go-autorest/autorest/validation v0.3.1 h1:AgyqjAd94fwNAoTjl/WQXg4VvFeRFpO+UhNyRXqF1ac=
github.com/Azure/go-autorest/autorest/validation v0.3.1/go.mod h1:yhLgjC0Wda5DYXl6JAsWyUe4KVNffhoDhG0zVzUMo3E=
github.com/Azure/go-autorest/logger v0.2.1 h1:IG7i4p/mDa2Ce4TRyAO8IHnVhAVF3RFU+ZtXWSmf4Tg=
github.com/Azure/go-autorest/tracing v0.6.0 h1:TYi4+3m5t6K48TGI9AUdb+IzbnSxvnvUMfuitfgcfuo=
github.com/AzureAD/microsoft-authentication-library-for-go v0.4.0/go.mod h1:Vt9sXTKwMyGcOxSmLDMnGPgqsUg7m8pe215qMLrDXw4=
github.com/AzureAD/microsoft-authentication-library-for-go v0.5.1/go.mod h1:Vt9sXTKwMyGcOxSmLDMnGPgqsUg7m8pe215qMLrDXw4=
github.com/AzureAD/microsoft-authentication-library-for-go v0.8.1/go.mod h1:4qFor3D/HDsvBME35Xy9rwW9DecL+M2sNw1ybjPtwA0=
Expand Down Expand Up @@ -835,6 +840,8 @@ github.com/PaesslerAG/jsonpath v0.1.1/go.mod h1:lVboNxFGal/VwW6d9JzIy56bUsYAP6tH
github.com/ProtonMail/go-crypto v0.0.0-20221026131551-cf6655e29de4/go.mod h1:UBYPn8k0D56RtnR8RFQMjmh4KrZzWJ5o7Z9SYjossQ8=
github.com/ProtonMail/go-crypto v0.0.0-20230217124315-7d5c6f04bbb8 h1:wPbRQzjjwFc0ih8puEVAOFGELsn1zoIIYdxvML7mDxA=
github.com/ProtonMail/go-crypto v0.0.0-20230217124315-7d5c6f04bbb8/go.mod h1:I0gYDMZ6Z5GRU7l58bNFSkPTFN6Yl12dsUlAZ8xy98g=
github.com/PuerkitoBio/purell v1.1.1 h1:WEQqlqaGbrPkxLJWfBwQmfEAE1Z7ONdDLqrN38tNFfI=
github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578 h1:d+Bc7a5rLufV/sSk/8dngufqelfh6jnri85riMAaF/M=
github.com/Shopify/goreferrer v0.0.0-20220729165902-8cddb4f5de06/go.mod h1:7erjKLwalezA0k99cWs5L11HWOAPNjdUZ6RxH1BXbbM=
github.com/Shopify/sarama v1.19.0/go.mod h1:FVkBWblsNy7DGZRfXLU0O9RCGt5g3g3yEuWXgklEdEo=
github.com/Shopify/toxiproxy v2.1.4+incompatible/go.mod h1:OXgGpZ6Cli1/URJOF1DMxUHB2q5Ap20/P/eIdh4G0pI=
Expand Down Expand Up @@ -2058,6 +2065,7 @@ github.com/nelsam/hel/v2 v2.3.3/go.mod h1:1ZTGfU2PFTOd5mx22i5O0Lc2GY933lQ2wb/ggy
github.com/networkplumbing/go-nft v0.2.0/go.mod h1:HnnM+tYvlGAsMU7yoYwXEVLLiDW9gdMmb5HoGcwpuQs=
github.com/networkplumbing/go-nft v0.3.0 h1:IIc6yHjN85KyJx21p3ZEsO0iBMYHNXux22rc9Q8TfFw=
github.com/networkplumbing/go-nft v0.3.0/go.mod h1:HnnM+tYvlGAsMU7yoYwXEVLLiDW9gdMmb5HoGcwpuQs=
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs=
github.com/nightlyone/lockfile v1.0.0/go.mod h1:rywoIealpdNse2r832aiD9jRk8ErCatROs6LzC841CI=
github.com/nishanths/predeclared v0.0.0-20190419143655-18a43bb90ffc/go.mod h1:62PewwiQTlm/7Rj+cxVYqZvDIUc+JjZq6GHAC1fsObQ=
github.com/nishanths/predeclared v0.0.0-20200524104333-86fad755b4d3/go.mod h1:nt3d53pc1VYcphSCIaYAJtnPYnr3Zyn8fMq2wvPGPso=
Expand All @@ -2071,6 +2079,7 @@ github.com/olekukonko/tablewriter v0.0.4/go.mod h1:zq6QwlOf5SlnkVbMSr5EoBv3636FW
github.com/olekukonko/tablewriter v0.0.5 h1:P2Ga83D34wi1o9J6Wh1mRuqd4mF/x/lgBS7N7AbDhec=
github.com/olekukonko/tablewriter v0.0.5/go.mod h1:hPp6KlRPjbx+hW8ykQs1w3UBbZlj6HuIJcUGPhkA7kY=
github.com/onsi/ginkgo v1.13.0/go.mod h1:+REjRxOmWfHCjfv9TTWB1jD1Frx4XydAD3zm1lskyM0=
github.com/onsi/ginkgo v1.16.5/go.mod h1:+E8gABHa3K6zRBolWtd+ROzc/U5bkGt0FwiG042wbpU=
github.com/onsi/ginkgo/v2 v2.3.0/go.mod h1:Eew0uilEqZmIEZr8JrvYlvOM7Rr6xzTmMV8AyFNU9d0=
github.com/onsi/ginkgo/v2 v2.4.0/go.mod h1:iHkDK1fKGcBoEHT5W7YBq4RFWaQulw+caOMkAt4OrFo=
github.com/onsi/ginkgo/v2 v2.5.0/go.mod h1:Luc4sArBICYCS8THh8v3i3i5CuSZO+RaQRaJoeNwomw=
Expand Down
52 changes: 52 additions & 0 deletions service/account/api/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -976,3 +976,55 @@ func UserUsage(c *gin.Context) {
"data": usage,
})
}

// GetUserRealNameInfo
// @Summary Get user real name information
// @Description Retrieve the real name information for a user
// @Tags GetUserRealNameInfo
// @Accept json
// @Produce json
// @Param request body helper.GetRealNameInfoReq true "Get real name info request"
// @Success 200 {object} helper.GetRealNameInfoResp "Successfully retrieved user real name info"
// @Failure 400 {object} helper.ErrorMessage "Failed to parse get real name info request"
// @Failure 401 {object} helper.ErrorMessage "Authentication error"
// @Failure 500 {object} helper.ErrorMessage "Failed to get user real name info or info not found/verified"
// @Router /account/v1alpha1/real-name-info [post]
func GetUserRealNameInfo(c *gin.Context) {
// Parse the get real name info request
req, err := helper.ParseGetRealNameInfoReq(c)
if err != nil {
c.JSON(http.StatusBadRequest, helper.ErrorMessage{Error: fmt.Sprintf("failed to parse get real name info request: %v", err)})
return
}

if err := authenticateRequest(c, req); err != nil {
c.JSON(http.StatusUnauthorized, helper.ErrorMessage{Error: fmt.Sprintf("authenticate error : %v", err)})
return
}

userRealNameInfo, err := dao.DBClient.GetUserRealNameInfo(req)

if err != nil {
c.JSON(http.StatusInternalServerError, helper.ErrorMessage{Error: fmt.Sprintf("failed to get user real name info: %v", err)})
return
}

if userRealNameInfo == nil {
c.JSON(http.StatusInternalServerError, helper.ErrorMessage{Error: "user real name info not found"})
return
}

if !userRealNameInfo.IsVerified {
c.JSON(http.StatusInternalServerError, helper.ErrorMessage{Error: "user real name info is not verified"})
return
}

// Return success response
c.JSON(http.StatusOK, helper.GetRealNameInfoResp{
Data: helper.GetRealNameInfoRespData{
UserID: req.UserID,
IsRealName: userRealNameInfo.IsVerified,
},
Message: "successfully get user real name info",
})
}
12 changes: 12 additions & 0 deletions service/account/dao/interface.go
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ type Interface interface {
GetRegions() ([]types.Region, error)
GetLocalRegion() types.Region
UseGiftCode(req *helper.UseGiftCodeReq) (*types.GiftCode, error)
GetUserRealNameInfo(req *helper.GetRealNameInfoReq) (*types.UserRealNameInfo, error)
}

type Account struct {
Expand Down Expand Up @@ -1444,3 +1445,14 @@ func (m *Account) UseGiftCode(req *helper.UseGiftCodeReq) (*types.GiftCode, erro

return giftCode, nil
}

func (m *Account) GetUserRealNameInfo(req *helper.GetRealNameInfoReq) (*types.UserRealNameInfo, error) {
// get user info
userRealNameInfo, err := m.ck.GetUserRealNameInfoByUserID(req.UserID)

if err != nil {
return nil, fmt.Errorf("failed to get user real name info: %v", err)
}

return userRealNameInfo, nil
}
26 changes: 24 additions & 2 deletions service/account/dao/interface_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -608,10 +608,10 @@ func TestAccount_UseGiftCode(t *testing.T) {
}

giftcode, err := db.UseGiftCode(&helper.UseGiftCodeReq{
Code: "DfxAffaeEf",
Code: "d-intl-TXERVADC3ASAGQJSx",
AuthBase: helper.AuthBase{
Auth: &helper.Auth{
Owner: "E1xAJ0fy4k",
UserID: "E1xAJ0fy4k",
},
},
})
Expand All @@ -623,6 +623,28 @@ func TestAccount_UseGiftCode(t *testing.T) {
t.Logf("giftcode = %+v", giftcode)
}

func TestAccount_GetUserRealNameInfo(t *testing.T) {
db, err := newAccountForTest("", os.Getenv("GLOBAL_COCKROACH_URI"), os.Getenv("LOCAL_COCKROACH_URI"))
if err != nil {
t.Fatalf("NewAccountInterface() error = %v", err)
return
}

userRealNameInfo, err := db.GetUserRealNameInfo(&helper.GetRealNameInfoReq{
AuthBase: helper.AuthBase{
Auth: &helper.Auth{
UserID: "E1xAJ0fy4k",
},
},
})

if err != nil {
t.Fatalf("GetUserRealNameInfo() error = %v", err)
return
}
t.Logf("userRealNameInfo = %+v", userRealNameInfo)
}

func init() {
// set env
os.Setenv("MONGO_URI", "")
Expand Down
97 changes: 97 additions & 0 deletions service/account/docs/docs.go
Original file line number Diff line number Diff line change
Expand Up @@ -1232,6 +1232,58 @@ const docTemplate = `{
}
}
},
"/account/v1alpha1/real-name-info": {
"post": {
"description": "Retrieve the real name information for a user",
"consumes": [
"application/json"
],
"produces": [
"application/json"
],
"tags": [
"GetUserRealNameInfo"
],
"summary": "Get user real name information",
"parameters": [
{
"description": "Get real name info request",
"name": "request",
"in": "body",
"required": true,
"schema": {
"$ref": "#/definitions/helper.GetRealNameInfoReq"
}
}
],
"responses": {
"200": {
"description": "Successfully retrieved user real name info",
"schema": {
"$ref": "#/definitions/helper.GetRealNameInfoResp"
}
},
"400": {
"description": "Failed to parse get real name info request",
"schema": {
"$ref": "#/definitions/helper.ErrorMessage"
}
},
"401": {
"description": "Authentication error",
"schema": {
"$ref": "#/definitions/helper.ErrorMessage"
}
},
"500": {
"description": "Failed to get user real name info or info not found/verified",
"schema": {
"$ref": "#/definitions/helper.ErrorMessage"
}
}
}
}
},
"/account/v1alpha1/regions": {
"post": {
"description": "Get regions",
Expand Down Expand Up @@ -1808,6 +1860,51 @@ const docTemplate = `{
}
}
},
"helper.GetRealNameInfoReq": {
"type": "object",
"properties": {
"kubeConfig": {
"type": "string"
},
"owner": {
"type": "string",
"example": "admin"
},
"token": {
"type": "string",
"example": "token"
},
"userID": {
"type": "string",
"example": "admin"
}
}
},
"helper.GetRealNameInfoResp": {
"type": "object",
"properties": {
"data": {
"$ref": "#/definitions/helper.GetRealNameInfoRespData"
},
"message": {
"type": "string",
"example": "Successfully retrieved real name information"
}
}
},
"helper.GetRealNameInfoRespData": {
"type": "object",
"properties": {
"isRealName": {
"type": "boolean",
"example": true
},
"userID": {
"type": "string",
"example": "user-123"
}
}
},
"helper.GetTransferRecordReq": {
"type": "object",
"properties": {
Expand Down
Loading
Loading