diff --git a/cmd/apiserver/main.go b/cmd/apiserver/main.go index f35c82e6..19b11a72 100644 --- a/cmd/apiserver/main.go +++ b/cmd/apiserver/main.go @@ -154,6 +154,12 @@ func main() { panic(err) } + // setup DS chat API client + err = sdk.InitDsChatClient(cfg.DsChatConfig.BaseUrl, cfg.DsChatConfig.AuthKey) + if err != nil { + panic(err) + } + // Setup zerolog zerolog.TimeFieldFormat = zerolog.TimeFormatUnix zerolog.ErrorStackMarshaler = pkgerrors.MarshalStack diff --git a/config.yml.example b/config.yml.example index 42ba86fe..288e19d4 100644 --- a/config.yml.example +++ b/config.yml.example @@ -66,3 +66,7 @@ snsInvite: entityId: 2 entityName: 新手公会 applicant: 0x4564d5a8Bb409272F1FB4ae4c8b45fC0eaFd709D + +dsChatConfig: + baseUrl: http://localhost:3000 + authKey: TyUcDRDCAKvPkeEMNYEdbVZNA7fwEUCu diff --git a/internal/config/config.go b/internal/config/config.go index a7df1c0c..415e624f 100644 --- a/internal/config/config.go +++ b/internal/config/config.go @@ -29,6 +29,7 @@ type Config struct { Admin adminData `json:"admin" yaml:"admin"` QuickAccounting QuickAccounting `json:"quickAccounting" yaml:"quickAccounting"` SnsInvite SnsInvite `json:"snsInvite" yaml:"snsInvite"` + DsChatConfig DsChatConfig `json:"dsChatConfig" yaml:"dsChatConfig"` } type ( @@ -122,6 +123,11 @@ type ( EntityName string `json:"entityName" yaml:"entityName"` Applicant string `json:"applicant" yaml:"applicant"` } + + DsChatConfig struct { + BaseUrl string `json:"baseUrl" yaml:"baseUrl"` + AuthKey string `json:"authKey" yaml:"authKey"` + } ) func LoadConfig(configPath string) *Config { diff --git a/internal/sdk/ds_chat_client.go b/internal/sdk/ds_chat_client.go new file mode 100644 index 00000000..7e44e0a5 --- /dev/null +++ b/internal/sdk/ds_chat_client.go @@ -0,0 +1,91 @@ +package sdk + +import ( + "encoding/json" + "fmt" + "net/http" + + "github.com/rs/zerolog/log" + "github.com/theseed-labs/os-backend/internal/common" +) + +type DsChatResponse struct { + ApiKey string `json:"apiKey"` +} + +type DsChatClient struct { + ApiBase string `json:"api_base"` + AuthKey string `json:"auth_key"` +} + +var dsChatClient *DsChatClient + +func InitDsChatClient(apiBase string, authKey string) error { + dsChatClient = &DsChatClient{ + ApiBase: apiBase, + AuthKey: authKey, + } + return nil +} + +func GetDsChatClient() *DsChatClient { + return dsChatClient +} + +func (c *DsChatClient) Auth(wallet string) (*DsChatResponse, error) { + _wallet := common.FormatUserWallet(wallet) + endpoint := fmt.Sprintf("%s/os/auth/%s", c.ApiBase, _wallet) + log.Debug().Msgf("update spp profile, endpoint %s", endpoint) + + req, err := http.NewRequest("POST", endpoint, nil) + if err != nil { + return nil, err + } + + req.Header.Set("Authorization", fmt.Sprintf("Bearer %s", c.AuthKey)) + req.Header.Set("Content-Type", "application/json") + + client := &http.Client{} + resp, err := client.Do(req) + if err != nil { + return nil, err + } + defer resp.Body.Close() + + res := DsChatResponse{} + err = json.NewDecoder(resp.Body).Decode(&res) + if err != nil { + return nil, err + } + + return &res, nil +} + +func (c *DsChatClient) Refersh(wallet string) (*DsChatResponse, error) { + _wallet := common.FormatUserWallet(wallet) + endpoint := fmt.Sprintf("%s/os/refresh/%s", c.ApiBase, _wallet) + log.Debug().Msgf("update spp profile, endpoint %s", endpoint) + + req, err := http.NewRequest("POST", endpoint, nil) + if err != nil { + return nil, err + } + + req.Header.Set("Authorization", fmt.Sprintf("Bearer %s", c.AuthKey)) + req.Header.Set("Content-Type", "application/json") + + client := &http.Client{} + resp, err := client.Do(req) + if err != nil { + return nil, err + } + defer resp.Body.Close() + + res := DsChatResponse{} + err = json.NewDecoder(resp.Body).Decode(&res) + if err != nil { + return nil, err + } + + return &res, nil +} diff --git a/internal/sdk/spp_client.go b/internal/sdk/spp_client.go index 5830d55a..20efa118 100644 --- a/internal/sdk/spp_client.go +++ b/internal/sdk/spp_client.go @@ -52,6 +52,8 @@ type SeepassResponse struct { } `json:"sbt"` SocialAccounts []interface{} `json:"social_accounts"` + + DsApiKey string `json:"ds_api_key"` } type ProfileSocialAccount struct { diff --git a/internal_inject/user/user.controller.go b/internal_inject/user/user.controller.go index 02217c6e..f8e30390 100644 --- a/internal_inject/user/user.controller.go +++ b/internal_inject/user/user.controller.go @@ -77,6 +77,79 @@ func Register(fatherGroup *gin.RouterGroup) { userAuthGroup.POST("/leave_metaforo_group", user.LeaveMetaforoGroup) userAuthGroup.POST("/prepare_metaforo", user.PrepareMetaforoData) userAuthGroup.GET("/level", user.UserLvl) + userAuthGroup.POST("/refresh/dsapikey", user.RefreshDsApiKey) + userAuthGroup.POST("/auth/dschat", user.AuthDsChat) +} + +func findString(slice []string, target string) (int, bool) { + for i, s := range slice { + if s == target { + return i, true // 返回索引和存在标记 + } + } + return -1, false // 未找到 +} + +func (ctrl *UserController) AuthDsChat(ctx *gin.Context) { + user, _ := api.ForContextUserAndDB(ctx) + if user == nil { + ctx.JSON(http.StatusInternalServerError, api.ServerError(errors.New("user need to login"))) + return + } + sppClient := sdk.GetSppClient() + seepassResp, err := api.GetCachedSeepassData(sppClient, user.Wallet, false) + if err != nil { + sdk.LogServerErrorToSentry(ctx, err) + ctx.JSON(http.StatusInternalServerError, api.ServerError(errors.New("you need become seedao member"))) + return + } + + _, ok := findString(seepassResp.Roles, "SEEDAO_MEMBER") + if ok { + dsChatClient := sdk.GetDsChatClient() + res, err := dsChatClient.Auth(user.Wallet) + if err != nil { + sdk.LogServerErrorToSentry(ctx, err) + ctx.JSON(http.StatusInternalServerError, api.ServerError(errors.New("dschat auth error"))) + return + } + ctx.JSON(http.StatusOK, api.Success(res)) + return + } else { + ctx.JSON(http.StatusInternalServerError, api.ServerError(errors.New("you need become seedao member"))) + return + } +} + +func (ctrl *UserController) RefreshDsApiKey(ctx *gin.Context) { + user, _ := api.ForContextUserAndDB(ctx) + if user == nil { + ctx.JSON(http.StatusInternalServerError, api.ServerError(errors.New("user need to login"))) + return + } + sppClient := sdk.GetSppClient() + seepassResp, err := api.GetCachedSeepassData(sppClient, user.Wallet, false) + if err != nil { + sdk.LogServerErrorToSentry(ctx, err) + ctx.JSON(http.StatusInternalServerError, api.ServerError(errors.New("you need become seedao member"))) + return + } + + _, ok := findString(seepassResp.Roles, "SEEDAO_MEMBER") + if ok { + dsChatClient := sdk.GetDsChatClient() + res, err := dsChatClient.Refersh(user.Wallet) + if err != nil { + sdk.LogServerErrorToSentry(ctx, err) + ctx.JSON(http.StatusInternalServerError, api.ServerError(errors.New("dschat refresh error"))) + return + } + ctx.JSON(http.StatusOK, api.Success(res)) + return + } else { + ctx.JSON(http.StatusInternalServerError, api.ServerError(errors.New("you need become seedao member"))) + return + } } func (ctrl *UserController) RefreshNonce(ctx *gin.Context) { @@ -336,6 +409,15 @@ func (ctrl *UserController) Detail(ctx *gin.Context) { sppClient := sdk.GetSppClient() seepassResp, err := api.GetCachedSeepassData(sppClient, user.Wallet, false) if err == nil { + _, ok := findString(seepassResp.Roles, "SEEDAO_MEMBER") + if ok { + dsChatClient := sdk.GetDsChatClient() + res, err := dsChatClient.Auth(user.Wallet) + if err == nil { + seepassResp.DsApiKey = res.ApiKey + } + } + ctx.JSON(http.StatusOK, api.Success(seepassResp)) return }