From 3d6339bc50a4b2cf452f0408a74029832239250b Mon Sep 17 00:00:00 2001 From: Edem Date: Sun, 15 May 2022 13:17:01 +0000 Subject: [PATCH 01/16] updated --- readMe.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 readMe.md diff --git a/readMe.md b/readMe.md new file mode 100644 index 0000000..02c3878 --- /dev/null +++ b/readMe.md @@ -0,0 +1,5 @@ +# API with Golang + MongoDB + Redis + Gin Gonic + +## API with Golang + MongoDB + Redis + Gin Gonic: Project Setup + +1.[Project Setup](https://codevoweb.com/api-golang-mongodb-gin-gonic-project-setup) From e48e2775843eb8223dc130216a4ae84009225f91 Mon Sep 17 00:00:00 2001 From: Edem Date: Thu, 19 May 2022 10:43:06 +0000 Subject: [PATCH 02/16] updated --- readMe.md | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/readMe.md b/readMe.md index 02c3878..6740f14 100644 --- a/readMe.md +++ b/readMe.md @@ -1,5 +1,10 @@ # API with Golang + MongoDB + Redis + Gin Gonic -## API with Golang + MongoDB + Redis + Gin Gonic: Project Setup +### 1. API with Golang + MongoDB + Redis + Gin Gonic: Project Setup -1.[Project Setup](https://codevoweb.com/api-golang-mongodb-gin-gonic-project-setup) +[API with Golang + MongoDB + Redis + Gin Gonic: Project Setup](https://codevoweb.com/api-golang-mongodb-gin-gonic-project-setup) + +### 2. Golang & MongoDB: JWT Authentication and Authorization + +1.[Golang & MongoDB: JWT Authentication and Authorization +](https://codevoweb.com/golang-mongodb-jwt-authentication-authorization) From bbba676144b9271b28d3119187157bd20c11bf82 Mon Sep 17 00:00:00 2001 From: Edem Date: Thu, 19 May 2022 10:45:21 +0000 Subject: [PATCH 03/16] updated --- readMe.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/readMe.md b/readMe.md index 6740f14..f2ea9a4 100644 --- a/readMe.md +++ b/readMe.md @@ -6,5 +6,4 @@ ### 2. Golang & MongoDB: JWT Authentication and Authorization -1.[Golang & MongoDB: JWT Authentication and Authorization -](https://codevoweb.com/golang-mongodb-jwt-authentication-authorization) +[Golang & MongoDB: JWT Authentication and Authorization](https://codevoweb.com/golang-mongodb-jwt-authentication-authorization) From 1d3b8070c915592c7ac1ff3f0535d468f864f069 Mon Sep 17 00:00:00 2001 From: Edem Date: Sat, 21 May 2022 11:50:26 +0000 Subject: [PATCH 04/16] updated --- readMe.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/readMe.md b/readMe.md index f2ea9a4..3ab3782 100644 --- a/readMe.md +++ b/readMe.md @@ -7,3 +7,7 @@ ### 2. Golang & MongoDB: JWT Authentication and Authorization [Golang & MongoDB: JWT Authentication and Authorization](https://codevoweb.com/golang-mongodb-jwt-authentication-authorization) + +### 3. API with Golang + MongoDB: Send HTML Emails with Gomail + +[API with Golang + MongoDB: Send HTML Emails with Gomail](https://codevoweb.com/api-golang-mongodb-send-html-emails-gomail) From e20eaab7d4b939c573e129a92db37731fe333cb2 Mon Sep 17 00:00:00 2001 From: Edem Date: Wed, 25 May 2022 18:40:26 +0000 Subject: [PATCH 05/16] updated --- readMe.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/readMe.md b/readMe.md index 3ab3782..ab77422 100644 --- a/readMe.md +++ b/readMe.md @@ -11,3 +11,7 @@ ### 3. API with Golang + MongoDB: Send HTML Emails with Gomail [API with Golang + MongoDB: Send HTML Emails with Gomail](https://codevoweb.com/api-golang-mongodb-send-html-emails-gomail) + +### 4. API with Golang, Gin Gonic & MongoDB: Forget/Reset Password + +[API with Golang, Gin Gonic & MongoDB: Forget/Reset Password](https://codevoweb.com/api-golang-gin-gonic-mongodb-forget-reset-password) From 06f41c1c311ebdcbf53c16a9ed751e8dcbec42b9 Mon Sep 17 00:00:00 2001 From: Edem Date: Thu, 26 May 2022 15:40:35 +0000 Subject: [PATCH 06/16] updated --- readMe.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/readMe.md b/readMe.md index ab77422..56a6138 100644 --- a/readMe.md +++ b/readMe.md @@ -15,3 +15,7 @@ ### 4. API with Golang, Gin Gonic & MongoDB: Forget/Reset Password [API with Golang, Gin Gonic & MongoDB: Forget/Reset Password](https://codevoweb.com/api-golang-gin-gonic-mongodb-forget-reset-password) + +### 5. Build Golang gRPC Server and Client: SignUp User & Verify Email + +[Build Golang gRPC Server and Client: SignUp User & Verify Email](https://codevoweb.com/golang-grpc-server-and-client-signup-user-verify-email) From 6f79d9da252685c15792e0de58faad46a142fa38 Mon Sep 17 00:00:00 2001 From: Edem Date: Sat, 28 May 2022 16:25:04 +0000 Subject: [PATCH 07/16] updated --- readMe.md | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/readMe.md b/readMe.md index 56a6138..da96030 100644 --- a/readMe.md +++ b/readMe.md @@ -1,4 +1,4 @@ -# API with Golang + MongoDB + Redis + Gin Gonic +# CRUD RESTful API with Golang + MongoDB + Redis + Gin Gonic ### 1. API with Golang + MongoDB + Redis + Gin Gonic: Project Setup @@ -19,3 +19,11 @@ ### 5. Build Golang gRPC Server and Client: SignUp User & Verify Email [Build Golang gRPC Server and Client: SignUp User & Verify Email](https://codevoweb.com/golang-grpc-server-and-client-signup-user-verify-email) + +### 6. Build Golang gRPC Server and Client: Access & Refresh Tokens + +[Build Golang gRPC Server and Client: Access & Refresh Tokens](https://codevoweb.com/golang-grpc-server-and-client-access-refresh-tokens) + +### 7. Build CRUD RESTful API Server with Golang, Gin, and MongoDB + +[Build CRUD RESTful API Server with Golang, Gin, and MongoDB](https://codevoweb.com/crud-restful-api-server-with-golang-and-mongodb) From e307f42b93c50fbcfd41b1dff0aed3e270b032d8 Mon Sep 17 00:00:00 2001 From: Edem Date: Wed, 1 Jun 2022 22:56:31 +0000 Subject: [PATCH 08/16] updated --- readMe.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/readMe.md b/readMe.md index da96030..224cc58 100644 --- a/readMe.md +++ b/readMe.md @@ -27,3 +27,7 @@ ### 7. Build CRUD RESTful API Server with Golang, Gin, and MongoDB [Build CRUD RESTful API Server with Golang, Gin, and MongoDB](https://codevoweb.com/crud-restful-api-server-with-golang-and-mongodb) + +### 8. Build CRUD gRPC Server API & Client with Golang and MongoDB + +[Build CRUD gRPC Server API & Client with Golang and MongoDB](https://codevoweb.com/crud-grpc-server-api-client-with-golang-and-mongodb) From 79024d5799905d4e78c24fc31320d3d97fa04c28 Mon Sep 17 00:00:00 2001 From: Edem Date: Wed, 8 Jun 2022 21:08:27 +0000 Subject: [PATCH 09/16] added google oauth --- config/default.go | 13 +++- controllers/auth.controller.go | 50 +++++++++++++ main.go | 11 +-- routes/session.routes.go | 20 ++++++ tmp/build-errors.log | 1 + utils/googleOAuth.go | 128 +++++++++++++++++++++++++++++++++ 6 files changed, 216 insertions(+), 7 deletions(-) create mode 100644 routes/session.routes.go create mode 100644 tmp/build-errors.log create mode 100644 utils/googleOAuth.go diff --git a/config/default.go b/config/default.go index 3b6b820..e7a2c39 100644 --- a/config/default.go +++ b/config/default.go @@ -7,9 +7,12 @@ import ( ) type Config struct { - DBUri string `mapstructure:"MONGODB_LOCAL_URI"` - RedisUri string `mapstructure:"REDIS_URL"` - Port string `mapstructure:"PORT"` + DBUri string `mapstructure:"MONGODB_LOCAL_URI"` + RedisUri string `mapstructure:"REDIS_URL"` + Port string `mapstructure:"PORT"` + + ClientOrigin string `mapstructure:"CLIENT_ORIGIN"` + AccessTokenPrivateKey string `mapstructure:"ACCESS_TOKEN_PRIVATE_KEY"` AccessTokenPublicKey string `mapstructure:"ACCESS_TOKEN_PUBLIC_KEY"` RefreshTokenPrivateKey string `mapstructure:"REFRESH_TOKEN_PRIVATE_KEY"` @@ -18,6 +21,10 @@ type Config struct { RefreshTokenExpiresIn time.Duration `mapstructure:"REFRESH_TOKEN_EXPIRED_IN"` AccessTokenMaxAge int `mapstructure:"ACCESS_TOKEN_MAXAGE"` RefreshTokenMaxAge int `mapstructure:"REFRESH_TOKEN_MAXAGE"` + + GoogleClientID string `mapstructure:"GOOGLE_OAUTH_CLIENT_ID"` + GoogleClientSecret string `mapstructure:"GOOGLE_OAUTH_CLIENT_SECRET"` + GoogleOAuthRedirectUrl string `mapstructure:"GOOGLE_OAUTH_REDIRECT_URL"` } func LoadConfig(path string) (config Config, err error) { diff --git a/controllers/auth.controller.go b/controllers/auth.controller.go index dc8c356..1c8b6fb 100644 --- a/controllers/auth.controller.go +++ b/controllers/auth.controller.go @@ -124,3 +124,53 @@ func (ac *AuthController) RefreshAccessToken(ctx *gin.Context) { ctx.JSON(http.StatusOK, gin.H{"status": "success", "access_token": access_token}) } + +func (ac *AuthController) GoogleOAuth(ctx *gin.Context) { + code := ctx.Query("code") + var pathUrl string = "/" + + if ctx.Query("state") != "" { + pathUrl = ctx.Query("state") + } + + if code == "" { + ctx.JSON(http.StatusUnauthorized, gin.H{"status": "fail", "message": "Authorization code not provided!"}) + return + } + + // Use the code to get the id and access tokens + tokenRes, err := utils.GetGoogleOauthToken(code) + + if err != nil { + ctx.JSON(http.StatusBadGateway, gin.H{"status": "fail", "message": err.Error()}) + } + + user, err := utils.GetGoogleUser(tokenRes.Access_token, tokenRes.Id_token) + + if err != nil { + ctx.JSON(http.StatusBadGateway, gin.H{"status": "fail", "message": err.Error()}) + } + + fmt.Println(user.Email) + + config, _ := config.LoadConfig(".") + + // Generate Tokens + access_token, err := utils.CreateToken(config.AccessTokenExpiresIn, user.Id, config.AccessTokenPrivateKey) + if err != nil { + ctx.JSON(http.StatusBadRequest, gin.H{"status": "fail", "message": err.Error()}) + return + } + + refresh_token, err := utils.CreateToken(config.RefreshTokenExpiresIn, user.Id, config.RefreshTokenPrivateKey) + if err != nil { + ctx.JSON(http.StatusBadRequest, gin.H{"status": "fail", "message": err.Error()}) + return + } + + ctx.SetCookie("access_token", access_token, config.AccessTokenMaxAge*60, "/", "localhost", false, true) + ctx.SetCookie("refresh_token", refresh_token, config.RefreshTokenMaxAge*60, "/", "localhost", false, true) + ctx.SetCookie("logged_in", "true", config.AccessTokenMaxAge*60, "/", "localhost", false, false) + + ctx.Redirect(http.StatusTemporaryRedirect, fmt.Sprint(config.ClientOrigin, pathUrl)) +} diff --git a/main.go b/main.go index e1e6699..74b7bc3 100644 --- a/main.go +++ b/main.go @@ -27,10 +27,11 @@ var ( UserController controllers.UserController UserRouteController routes.UserRouteController - authCollection *mongo.Collection - authService services.AuthService - AuthController controllers.AuthController - AuthRouteController routes.AuthRouteController + authCollection *mongo.Collection + authService services.AuthService + AuthController controllers.AuthController + AuthRouteController routes.AuthRouteController + SessionRouteController routes.SessionRouteController ) func init() { @@ -77,6 +78,7 @@ func init() { authService = services.NewAuthService(authCollection, ctx) AuthController = controllers.NewAuthController(authService, userService) AuthRouteController = routes.NewAuthRouteController(AuthController) + SessionRouteController = routes.NewSessionRouteController(AuthController) UserController = controllers.NewUserController(userService) UserRouteController = routes.NewRouteUserController(UserController) @@ -108,5 +110,6 @@ func main() { AuthRouteController.AuthRoute(router) UserRouteController.UserRoute(router, userService) + SessionRouteController.SessionRoute(router) log.Fatal(server.Run(":" + config.Port)) } diff --git a/routes/session.routes.go b/routes/session.routes.go new file mode 100644 index 0000000..0d5ce4f --- /dev/null +++ b/routes/session.routes.go @@ -0,0 +1,20 @@ +package routes + +import ( + "github.com/gin-gonic/gin" + "github.com/wpcodevo/golang-mongodb/controllers" +) + +type SessionRouteController struct { + authController controllers.AuthController +} + +func NewSessionRouteController(authController controllers.AuthController) SessionRouteController { + return SessionRouteController{authController} +} + +func (rc *SessionRouteController) SessionRoute(rg *gin.RouterGroup) { + router := rg.Group("/sessions/oauth") + + router.GET("/google", rc.authController.GoogleOAuth) +} diff --git a/tmp/build-errors.log b/tmp/build-errors.log new file mode 100644 index 0000000..0427d98 --- /dev/null +++ b/tmp/build-errors.log @@ -0,0 +1 @@ +exit status 2exit status 2exit status 2exit status 2 \ No newline at end of file diff --git a/utils/googleOAuth.go b/utils/googleOAuth.go new file mode 100644 index 0000000..9089b54 --- /dev/null +++ b/utils/googleOAuth.go @@ -0,0 +1,128 @@ +package utils + +import ( + "bytes" + "encoding/json" + "errors" + "fmt" + "io/ioutil" + "net/http" + "net/url" + "time" + + "github.com/wpcodevo/golang-mongodb/config" +) + +type GoogleOauthToken struct { + Access_token string + Id_token string +} + +type GoogleUserResult struct { + Id string + Email string + Verified_email bool + Name string + Given_name string + Family_name string + Picture string + Locale string +} + +func GetGoogleOauthToken(code string) (*GoogleOauthToken, error) { + const rootURl = "https://oauth2.googleapis.com/token" + + config, _ := config.LoadConfig(".") + values := url.Values{} + values.Add("grant_type", "authorization_code") + values.Add("code", code) + values.Add("client_id", config.GoogleClientID) + values.Add("client_secret", config.GoogleClientSecret) + values.Add("redirect_uri", config.GoogleOAuthRedirectUrl) + + query := values.Encode() + + req, err := http.NewRequest("POST", rootURl, bytes.NewBufferString(query)) + if err != nil { + return nil, err + } + + req.Header.Set("Content-Type", "application/x-www-form-urlencoded") + client := http.Client{ + Timeout: time.Second * 30, + } + + res, err := client.Do(req) + if err != nil { + return nil, err + } + + if res.StatusCode != http.StatusOK { + return nil, errors.New("could not retrieve token") + } + + resBody, err := ioutil.ReadAll(res.Body) + if err != nil { + return nil, err + } + + var GoogleOauthTokenRes map[string]interface{} + + if err := json.Unmarshal(resBody, &GoogleOauthTokenRes); err != nil { + return nil, err + } + + tokenBody := &GoogleOauthToken{ + Access_token: GoogleOauthTokenRes["access_token"].(string), + Id_token: GoogleOauthTokenRes["id_token"].(string), + } + + return tokenBody, nil +} + +func GetGoogleUser(access_token string, id_token string) (*GoogleUserResult, error) { + rootUrl := fmt.Sprintf("https://www.googleapis.com/oauth2/v1/userinfo?alt=json&access_token=%s", access_token) + + req, err := http.NewRequest("GET", rootUrl, nil) + if err != nil { + return nil, err + } + + req.Header.Set("Authorization", fmt.Sprintf("Bearer %s", id_token)) + + client := http.Client{ + Timeout: time.Second * 30, + } + + res, err := client.Do(req) + if err != nil { + return nil, err + } + + if res.StatusCode != http.StatusOK { + return nil, errors.New("could not retrieve user") + } + + resBody, err := ioutil.ReadAll(res.Body) + if err != nil { + return nil, err + } + + var GoogleUserRes map[string]interface{} + + if err := json.Unmarshal(resBody, &GoogleUserRes); err != nil { + return nil, err + } + + userBody := &GoogleUserResult{ + Id: GoogleUserRes["id"].(string), + Email: GoogleUserRes["email"].(string), + Verified_email: GoogleUserRes["verified_email"].(bool), + Name: GoogleUserRes["name"].(string), + Given_name: GoogleUserRes["given_name"].(string), + Picture: GoogleUserRes["picture"].(string), + Locale: GoogleUserRes["locale"].(string), + } + + return userBody, nil +} From a70ac49721320132481f6991d494f249db9bec5e Mon Sep 17 00:00:00 2001 From: Edem Date: Wed, 8 Jun 2022 21:16:13 +0000 Subject: [PATCH 10/16] update --- models/user.model.go | 17 +++++++++++++++++ services/user.service.impl.go | 22 ++++++++++++++++++++++ 2 files changed, 39 insertions(+) diff --git a/models/user.model.go b/models/user.model.go index e28e2a3..a0ed1e4 100644 --- a/models/user.model.go +++ b/models/user.model.go @@ -12,6 +12,7 @@ type SignUpInput struct { Password string `json:"password" bson:"password" binding:"required,min=8"` PasswordConfirm string `json:"passwordConfirm" bson:"passwordConfirm,omitempty" binding:"required"` Role string `json:"role" bson:"role"` + Provider string `json:"provider" bson:"provider"` Verified bool `json:"verified" bson:"verified"` CreatedAt time.Time `json:"created_at" bson:"created_at"` UpdatedAt time.Time `json:"updated_at" bson:"updated_at"` @@ -28,6 +29,7 @@ type DBResponse struct { Email string `json:"email" bson:"email"` Password string `json:"password" bson:"password"` PasswordConfirm string `json:"passwordConfirm,omitempty" bson:"passwordConfirm,omitempty"` + Provider string `json:"provider" bson:"provider"` Role string `json:"role" bson:"role"` Verified bool `json:"verified" bson:"verified"` CreatedAt time.Time `json:"created_at" bson:"created_at"` @@ -39,16 +41,31 @@ type UserResponse struct { Name string `json:"name,omitempty" bson:"name,omitempty"` Email string `json:"email,omitempty" bson:"email,omitempty"` Role string `json:"role,omitempty" bson:"role,omitempty"` + Provider string `json:"provider" bson:"provider"` CreatedAt time.Time `json:"created_at" bson:"created_at"` UpdatedAt time.Time `json:"updated_at" bson:"updated_at"` } +type UpdateDBUser struct { + ID primitive.ObjectID `json:"id,omitempty" bson:"_id,omitempty"` + Name string `json:"name,omitempty" bson:"name,omitempty"` + Email string `json:"email,omitempty" bson:"email,omitempty"` + Password string `json:"password,omitempty" bson:"password,omitempty"` + PasswordConfirm string `json:"passwordConfirm,omitempty" bson:"passwordConfirm,omitempty"` + Role string `json:"role,omitempty" bson:"role,omitempty"` + Provider string `json:"provider" bson:"provider"` + Verified bool `json:"verified,omitempty" bson:"verified,omitempty"` + CreatedAt time.Time `json:"created_at,omitempty" bson:"created_at,omitempty"` + UpdatedAt time.Time `json:"updated_at,omitempty" bson:"updated_at,omitempty"` +} + func FilteredResponse(user *DBResponse) UserResponse { return UserResponse{ ID: user.ID, Email: user.Email, Name: user.Name, Role: user.Role, + Provider: user.Provider, CreatedAt: user.CreatedAt, UpdatedAt: user.UpdatedAt, } diff --git a/services/user.service.impl.go b/services/user.service.impl.go index b3bbb46..71a9a78 100644 --- a/services/user.service.impl.go +++ b/services/user.service.impl.go @@ -2,12 +2,14 @@ package services import ( "context" + "errors" "strings" "github.com/wpcodevo/golang-mongodb/models" "go.mongodb.org/mongo-driver/bson" "go.mongodb.org/mongo-driver/bson/primitive" "go.mongodb.org/mongo-driver/mongo" + "go.mongodb.org/mongo-driver/mongo/options" ) type UserServiceImpl struct { @@ -52,3 +54,23 @@ func (us *UserServiceImpl) FindUserByEmail(email string) (*models.DBResponse, er return user, nil } + +func (uc *UserServiceImpl) UpdateUser(id string, data *models.UpdateDBUser) (*models.DBResponse, error) { + doc, err := utils.ToDoc(data) + if err != nil { + return nil, err + } + + obId, _ := primitive.ObjectIDFromHex(id) + query := bson.D{{Key: "_id", Value: obId}} + update := bson.D{{Key: "$set", Value: doc}} + res := uc.collection.FindOneAndUpdate(uc.ctx, query, update, options.FindOneAndUpdate().SetReturnDocument(1)) + + var updatedPost *models.DBResponse + + if err := res.Decode(&updatedPost); err != nil { + return nil, errors.New("no post with that Id exists") + } + + return updatedPost, nil +} From d53c096cac2a8f3ac93843d53455562fce00bcaf Mon Sep 17 00:00:00 2001 From: Edem Date: Thu, 9 Jun 2022 10:07:54 +0000 Subject: [PATCH 11/16] updated --- controllers/auth.controller.go | 18 ++++++++++++++++++ models/user.model.go | 7 ++++++- services/auth.service.impl.go | 2 ++ services/user.service.go | 1 + services/user.service.impl.go | 9 +++++---- tmp/build-errors.log | 2 +- utils/helper.go | 13 +++++++++++++ 7 files changed, 46 insertions(+), 6 deletions(-) create mode 100644 utils/helper.go diff --git a/controllers/auth.controller.go b/controllers/auth.controller.go index 1c8b6fb..ce8a418 100644 --- a/controllers/auth.controller.go +++ b/controllers/auth.controller.go @@ -3,6 +3,7 @@ package controllers import ( "fmt" "net/http" + "time" "github.com/gin-gonic/gin" "github.com/wpcodevo/golang-mongodb/config" @@ -151,6 +152,23 @@ func (ac *AuthController) GoogleOAuth(ctx *gin.Context) { ctx.JSON(http.StatusBadGateway, gin.H{"status": "fail", "message": err.Error()}) } + createdAt := time.Now() + resBody := &models.UpdateDBUser{ + Email: user.Email, + Name: user.Name, + Photo: user.Picture, + Provider: "google", + Role: "user", + Verified: true, + CreatedAt: createdAt, + UpdatedAt: createdAt, + } + + _, err = ac.userService.UpsertUser(user.Email, resBody) + if err != nil { + ctx.JSON(http.StatusBadGateway, gin.H{"status": "fail", "message": err.Error()}) + } + fmt.Println(user.Email) config, _ := config.LoadConfig(".") diff --git a/models/user.model.go b/models/user.model.go index a0ed1e4..84da905 100644 --- a/models/user.model.go +++ b/models/user.model.go @@ -12,7 +12,8 @@ type SignUpInput struct { Password string `json:"password" bson:"password" binding:"required,min=8"` PasswordConfirm string `json:"passwordConfirm" bson:"passwordConfirm,omitempty" binding:"required"` Role string `json:"role" bson:"role"` - Provider string `json:"provider" bson:"provider"` + Provider string `json:"provider,omitempty" bson:"provider,omitempty"` + Photo string `json:"photo,omitempty" bson:"photo,omitempty"` Verified bool `json:"verified" bson:"verified"` CreatedAt time.Time `json:"created_at" bson:"created_at"` UpdatedAt time.Time `json:"updated_at" bson:"updated_at"` @@ -30,6 +31,7 @@ type DBResponse struct { Password string `json:"password" bson:"password"` PasswordConfirm string `json:"passwordConfirm,omitempty" bson:"passwordConfirm,omitempty"` Provider string `json:"provider" bson:"provider"` + Photo string `json:"photo,omitempty" bson:"photo,omitempty"` Role string `json:"role" bson:"role"` Verified bool `json:"verified" bson:"verified"` CreatedAt time.Time `json:"created_at" bson:"created_at"` @@ -41,6 +43,7 @@ type UserResponse struct { Name string `json:"name,omitempty" bson:"name,omitempty"` Email string `json:"email,omitempty" bson:"email,omitempty"` Role string `json:"role,omitempty" bson:"role,omitempty"` + Photo string `json:"photo,omitempty" bson:"photo,omitempty"` Provider string `json:"provider" bson:"provider"` CreatedAt time.Time `json:"created_at" bson:"created_at"` UpdatedAt time.Time `json:"updated_at" bson:"updated_at"` @@ -54,6 +57,7 @@ type UpdateDBUser struct { PasswordConfirm string `json:"passwordConfirm,omitempty" bson:"passwordConfirm,omitempty"` Role string `json:"role,omitempty" bson:"role,omitempty"` Provider string `json:"provider" bson:"provider"` + Photo string `json:"photo,omitempty" bson:"photo,omitempty"` Verified bool `json:"verified,omitempty" bson:"verified,omitempty"` CreatedAt time.Time `json:"created_at,omitempty" bson:"created_at,omitempty"` UpdatedAt time.Time `json:"updated_at,omitempty" bson:"updated_at,omitempty"` @@ -66,6 +70,7 @@ func FilteredResponse(user *DBResponse) UserResponse { Name: user.Name, Role: user.Role, Provider: user.Provider, + Photo: user.Photo, CreatedAt: user.CreatedAt, UpdatedAt: user.UpdatedAt, } diff --git a/services/auth.service.impl.go b/services/auth.service.impl.go index 191f28f..10914c8 100644 --- a/services/auth.service.impl.go +++ b/services/auth.service.impl.go @@ -29,6 +29,8 @@ func (uc *AuthServiceImpl) SignUpUser(user *models.SignUpInput) (*models.DBRespo user.PasswordConfirm = "" user.Verified = true user.Role = "user" + user.Photo = "default.png" + user.Provider = "local" hashedPassword, _ := utils.HashPassword(user.Password) user.Password = hashedPassword diff --git a/services/user.service.go b/services/user.service.go index a43c1a8..0b40c2d 100644 --- a/services/user.service.go +++ b/services/user.service.go @@ -5,4 +5,5 @@ import "github.com/wpcodevo/golang-mongodb/models" type UserService interface { FindUserById(string) (*models.DBResponse, error) FindUserByEmail(string) (*models.DBResponse, error) + UpsertUser(string, *models.UpdateDBUser) (*models.DBResponse, error) } diff --git a/services/user.service.impl.go b/services/user.service.impl.go index 71a9a78..2511f19 100644 --- a/services/user.service.impl.go +++ b/services/user.service.impl.go @@ -6,6 +6,7 @@ import ( "strings" "github.com/wpcodevo/golang-mongodb/models" + "github.com/wpcodevo/golang-mongodb/utils" "go.mongodb.org/mongo-driver/bson" "go.mongodb.org/mongo-driver/bson/primitive" "go.mongodb.org/mongo-driver/mongo" @@ -55,16 +56,16 @@ func (us *UserServiceImpl) FindUserByEmail(email string) (*models.DBResponse, er return user, nil } -func (uc *UserServiceImpl) UpdateUser(id string, data *models.UpdateDBUser) (*models.DBResponse, error) { +func (uc *UserServiceImpl) UpsertUser(email string, data *models.UpdateDBUser) (*models.DBResponse, error) { doc, err := utils.ToDoc(data) if err != nil { return nil, err } - obId, _ := primitive.ObjectIDFromHex(id) - query := bson.D{{Key: "_id", Value: obId}} + opts := options.FindOneAndUpdate().SetUpsert(true).SetReturnDocument(1) + query := bson.D{{Key: "email", Value: email}} update := bson.D{{Key: "$set", Value: doc}} - res := uc.collection.FindOneAndUpdate(uc.ctx, query, update, options.FindOneAndUpdate().SetReturnDocument(1)) + res := uc.collection.FindOneAndUpdate(uc.ctx, query, update, opts) var updatedPost *models.DBResponse diff --git a/tmp/build-errors.log b/tmp/build-errors.log index 0427d98..0e06a41 100644 --- a/tmp/build-errors.log +++ b/tmp/build-errors.log @@ -1 +1 @@ -exit status 2exit status 2exit status 2exit status 2 \ No newline at end of file +exit status 2exit status 2exit status 2exit status 2exit status 2 \ No newline at end of file diff --git a/utils/helper.go b/utils/helper.go new file mode 100644 index 0000000..3cd5674 --- /dev/null +++ b/utils/helper.go @@ -0,0 +1,13 @@ +package utils + +import "go.mongodb.org/mongo-driver/bson" + +func ToDoc(v interface{}) (doc *bson.D, err error) { + data, err := bson.Marshal(v) + if err != nil { + return + } + + err = bson.Unmarshal(data, &doc) + return +} From d70dec02e5cd99f1830801c0af3a51731421dec9 Mon Sep 17 00:00:00 2001 From: Edem Date: Thu, 9 Jun 2022 15:51:06 +0000 Subject: [PATCH 12/16] updated --- controllers/auth.controller.go | 11 ++++++----- go.mod | 2 +- go.sum | 13 +++++++++++-- main.go | 7 +++++++ services/user.service.impl.go | 3 +++ 5 files changed, 28 insertions(+), 8 deletions(-) diff --git a/controllers/auth.controller.go b/controllers/auth.controller.go index ce8a418..c520076 100644 --- a/controllers/auth.controller.go +++ b/controllers/auth.controller.go @@ -22,6 +22,7 @@ func NewAuthController(authService services.AuthService, userService services.Us return AuthController{authService, userService} } +// SignUp User func (ac *AuthController) SignUpUser(ctx *gin.Context) { var user *models.SignUpInput @@ -45,6 +46,7 @@ func (ac *AuthController) SignUpUser(ctx *gin.Context) { ctx.JSON(http.StatusCreated, gin.H{"status": "success", "data": gin.H{"user": models.FilteredResponse(newUser)}}) } +// SignIn User func (ac *AuthController) SignInUser(ctx *gin.Context) { var credentials *models.SignInInput @@ -90,6 +92,7 @@ func (ac *AuthController) SignInUser(ctx *gin.Context) { ctx.JSON(http.StatusOK, gin.H{"status": "success", "access_token": access_token}) } +// Refresh Access Token func (ac *AuthController) RefreshAccessToken(ctx *gin.Context) { message := "could not refresh access token" @@ -164,23 +167,21 @@ func (ac *AuthController) GoogleOAuth(ctx *gin.Context) { UpdatedAt: createdAt, } - _, err = ac.userService.UpsertUser(user.Email, resBody) + updatedUser, err := ac.userService.UpsertUser(user.Email, resBody) if err != nil { ctx.JSON(http.StatusBadGateway, gin.H{"status": "fail", "message": err.Error()}) } - fmt.Println(user.Email) - config, _ := config.LoadConfig(".") // Generate Tokens - access_token, err := utils.CreateToken(config.AccessTokenExpiresIn, user.Id, config.AccessTokenPrivateKey) + access_token, err := utils.CreateToken(config.AccessTokenExpiresIn, updatedUser.ID.Hex(), config.AccessTokenPrivateKey) if err != nil { ctx.JSON(http.StatusBadRequest, gin.H{"status": "fail", "message": err.Error()}) return } - refresh_token, err := utils.CreateToken(config.RefreshTokenExpiresIn, user.Id, config.RefreshTokenPrivateKey) + refresh_token, err := utils.CreateToken(config.RefreshTokenExpiresIn, updatedUser.ID.Hex(), config.RefreshTokenPrivateKey) if err != nil { ctx.JSON(http.StatusBadRequest, gin.H{"status": "fail", "message": err.Error()}) return diff --git a/go.mod b/go.mod index beee686..57bb926 100644 --- a/go.mod +++ b/go.mod @@ -3,8 +3,8 @@ module github.com/wpcodevo/golang-mongodb go 1.18 require ( + github.com/gin-contrib/cors v1.3.1 github.com/gin-gonic/gin v1.7.7 - github.com/go-redis/redis v6.15.9+incompatible github.com/go-redis/redis/v8 v8.11.5 github.com/golang-jwt/jwt v3.2.2+incompatible github.com/spf13/viper v1.11.0 diff --git a/go.sum b/go.sum index 9442763..6a98943 100644 --- a/go.sum +++ b/go.sum @@ -62,8 +62,11 @@ github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.m github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= github.com/fsnotify/fsnotify v1.5.1 h1:mZcQUHVQUQWoPXXtuf9yuEXKudkV2sx1E06UadKWpgI= github.com/fsnotify/fsnotify v1.5.1/go.mod h1:T3375wBYaZdLLcVNkcVbzGHY7f1l/uK5T5Ai1i3InKU= +github.com/gin-contrib/cors v1.3.1 h1:doAsuITavI4IOcd0Y19U4B+O0dNWihRyX//nn4sEmgA= +github.com/gin-contrib/cors v1.3.1/go.mod h1:jjEJ4268OPZUcU7k9Pm653S7lXUGcqMADzFA61xsmDk= github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE= github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI= +github.com/gin-gonic/gin v1.5.0/go.mod h1:Nd6IXA8m5kNZdNEHMBd93KT+mdY3+bewLgRvmCsR2Do= github.com/gin-gonic/gin v1.7.7 h1:3DoBmSbJbZAWqXJC3SLjAPfutPJJRN1U5pALB7EeTTs= github.com/gin-gonic/gin v1.7.7/go.mod h1:axIBovoeJpVj8S3BwE0uPMTeReE4+AfFtqpqaZ1qq1U= github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= @@ -71,17 +74,17 @@ github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2 github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= github.com/go-playground/assert/v2 v2.0.1 h1:MsBgLAaY856+nPRTKrp3/OZK38U/wa0CcBYNjji3q3A= github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4= +github.com/go-playground/locales v0.12.1/go.mod h1:IUMDtCfWo/w/mtMfIE/IG2K+Ey3ygWanZIBtBW0W2TM= github.com/go-playground/locales v0.13.0/go.mod h1:taPMhCMXrRLJO55olJkUXHZBHCxTMfnGwq/HNwmWNS8= github.com/go-playground/locales v0.14.0 h1:u50s323jtVGugKlcYeyzC0etD1HifMjqmJqb8WugfUU= github.com/go-playground/locales v0.14.0/go.mod h1:sawfccIbzZTqEDETgFXqTho0QybSa7l++s0DH+LDiLs= +github.com/go-playground/universal-translator v0.16.0/go.mod h1:1AnU7NaIRDWWzGEKwgtJRd2xk99HeFyHw3yid4rvQIY= github.com/go-playground/universal-translator v0.17.0/go.mod h1:UkSxE5sNxxRwHyU+Scu5vgOQjsIJAF8j9muTVoKLVtA= github.com/go-playground/universal-translator v0.18.0 h1:82dyy6p4OuJq4/CByFNOn/jYrnRPArHwAcmLoJZxyho= github.com/go-playground/universal-translator v0.18.0/go.mod h1:UvRDBj+xPUEGrFYl+lu/H90nyDXpg0fqeB/AQUGNTVA= github.com/go-playground/validator/v10 v10.4.1/go.mod h1:nlOn6nFhuKACm19sB/8EGNn9GlaMV7XkbRSipzJ0Ii4= github.com/go-playground/validator/v10 v10.11.0 h1:0W+xRM511GY47Yy3bZUbJVitCNg2BOGlCyvTqsp/xIw= github.com/go-playground/validator/v10 v10.11.0/go.mod h1:i+3WkQ1FvaUjjxh1kSvIA4dMGDBiPU55YFDl0WbKdWU= -github.com/go-redis/redis v6.15.9+incompatible h1:K0pv1D7EQUjfyoMql+r/jZqCLizCGKFlFgcHWWmHQjg= -github.com/go-redis/redis v6.15.9+incompatible/go.mod h1:NAIEuMOZ/fxfXJIrKDQDz8wamY7mA7PouImQ2Jvg6kA= github.com/go-redis/redis/v8 v8.11.5 h1:AcZZR7igkdvfVmQTPnu9WE37LRrO/YrBH5zWyjDC0oI= github.com/go-redis/redis/v8 v8.11.5/go.mod h1:gREzHqY1hg6oD9ngVRbLStwAWKhA0FEgq8Jd4h5lpwo= github.com/go-stack/stack v1.8.0 h1:5SgMzNM5HxrEjV0ww2lTmX6E2Izsfxas4+YHWRs3Lsk= @@ -156,6 +159,7 @@ github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4= github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= +github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= @@ -173,11 +177,13 @@ github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= +github.com/leodido/go-urn v1.1.0/go.mod h1:+cyI34gQWZcE1eQU7NVgKkkzdXDQHr1dBMtdAPozLkw= github.com/leodido/go-urn v1.2.0/go.mod h1:+8+nEpDfqqsY+g338gtMEUOtuK+4dEMhiQEgxpxOKII= github.com/leodido/go-urn v1.2.1 h1:BqpAaACuzVSgi/VLzGZIobT2z4v53pjosyNd9Yv6n/w= github.com/leodido/go-urn v1.2.1/go.mod h1:zt4jvISO2HfUBqxjfIshjdMTYS56ZS/qv49ictyFfxY= github.com/magiconair/properties v1.8.6 h1:5ibWZ6iY0NctNGWo87LalDlEZ6R41TqbbDamhfG/Qzo= github.com/magiconair/properties v1.8.6/go.mod h1:y3VJvCyxH9uVvJTWEGAELF3aiYNyPKd5NZ3oSwXrF60= +github.com/mattn/go-isatty v0.0.9/go.mod h1:YNRxwqDuOph6SZLI9vUUz6OYw3QyUt7WiY2yME+cCiQ= github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= github.com/mattn/go-isatty v0.0.14 h1:yVuAays6BHfxijgZPzw+3Zlu5yQgKGP2/hcQbHb7S9Y= github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= @@ -362,6 +368,7 @@ golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -559,6 +566,8 @@ gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8 gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= +gopkg.in/go-playground/assert.v1 v1.2.1/go.mod h1:9RXL0bg/zibRAgZUYszZSwO/z8Y/a8bDuhia5mkpMnE= +gopkg.in/go-playground/validator.v9 v9.29.1/go.mod h1:+c9/zcJMFNgbLvly1L1V+PpxWdVbfP1avr/N00E2vyQ= gopkg.in/ini.v1 v1.66.4 h1:SsAcf+mM7mRZo2nJNGt8mZCjG8ZRaNGMURJw7BsIST4= gopkg.in/ini.v1 v1.66.4/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= diff --git a/main.go b/main.go index 74b7bc3..6701a6e 100644 --- a/main.go +++ b/main.go @@ -6,6 +6,7 @@ import ( "log" "net/http" + "github.com/gin-contrib/cors" "github.com/gin-gonic/gin" "github.com/go-redis/redis/v8" "github.com/wpcodevo/golang-mongodb/config" @@ -103,6 +104,12 @@ func main() { panic(err) } + corsConfig := cors.DefaultConfig() + corsConfig.AllowOrigins = []string{"http://localhost:8000", "http://localhost:3000"} + corsConfig.AllowCredentials = true + + server.Use(cors.New(corsConfig)) + router := server.Group("/api") router.GET("/healthchecker", func(ctx *gin.Context) { ctx.JSON(http.StatusOK, gin.H{"status": "success", "message": value}) diff --git a/services/user.service.impl.go b/services/user.service.impl.go index 2511f19..ec8a63c 100644 --- a/services/user.service.impl.go +++ b/services/user.service.impl.go @@ -22,6 +22,7 @@ func NewUserServiceImpl(collection *mongo.Collection, ctx context.Context) UserS return &UserServiceImpl{collection, ctx} } +// FindUserByID func (us *UserServiceImpl) FindUserById(id string) (*models.DBResponse, error) { oid, _ := primitive.ObjectIDFromHex(id) @@ -40,6 +41,7 @@ func (us *UserServiceImpl) FindUserById(id string) (*models.DBResponse, error) { return user, nil } +// FindUserByEmail func (us *UserServiceImpl) FindUserByEmail(email string) (*models.DBResponse, error) { var user *models.DBResponse @@ -56,6 +58,7 @@ func (us *UserServiceImpl) FindUserByEmail(email string) (*models.DBResponse, er return user, nil } +// UpsertUser func (uc *UserServiceImpl) UpsertUser(email string, data *models.UpdateDBUser) (*models.DBResponse, error) { doc, err := utils.ToDoc(data) if err != nil { From abb73e8112d3fa0af862865a3467274a003974b9 Mon Sep 17 00:00:00 2001 From: Edem Date: Thu, 9 Jun 2022 15:54:06 +0000 Subject: [PATCH 13/16] updated --- readMe.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/readMe.md b/readMe.md index 224cc58..38b625d 100644 --- a/readMe.md +++ b/readMe.md @@ -31,3 +31,7 @@ ### 8. Build CRUD gRPC Server API & Client with Golang and MongoDB [Build CRUD gRPC Server API & Client with Golang and MongoDB](https://codevoweb.com/crud-grpc-server-api-client-with-golang-and-mongodb) + +### 9. Google OAuth Authentication React.js, MongoDB and Golang + +[Google OAuth Authentication React.js, MongoDB and Golang](https://codevoweb.com/google-oauth-authentication-react-mongodb-and-golang) From 62584cf79e3244e7a59bd0fd7ee775030ecadf35 Mon Sep 17 00:00:00 2001 From: Edem Ziddah Date: Sun, 2 Oct 2022 19:20:16 +0000 Subject: [PATCH 14/16] updated --- .air.toml | 36 ++ .gitignore | 23 ++ Makefile | 15 + client/createPost_client.go | 35 ++ client/deletePost_client.go | 35 ++ client/geMe_client.go | 35 ++ client/getPost_client.go | 35 ++ client/listPosts_client.go | 47 +++ client/signin_client.go | 35 ++ client/signup_client.go | 35 ++ client/updatePost_client.go | 35 ++ cmd/client/main.go | 121 ++++++ cmd/server/main.go | 179 +++++++++ config/default.go | 48 +++ controllers/auth.controller.go | 282 ++++++++++++++ controllers/post.controller.go | 119 ++++++ controllers/user.controller.go | 23 ++ docker-compose.yml | 24 ++ example.env | 33 ++ gapi/auth-server.go | 29 ++ gapi/post-server.go | 22 ++ gapi/rpc_create_post.go | 44 +++ gapi/rpc_delete_post.go | 27 ++ gapi/rpc_get_me.go | 31 ++ gapi/rpc_get_post.go | 37 ++ gapi/rpc_list_posts.go | 31 ++ gapi/rpc_signin_user.go | 58 +++ gapi/rpc_signup_user.go | 75 ++++ gapi/rpc_update_post.go | 47 +++ gapi/rpc_verify_user.go | 35 ++ gapi/user-server.go | 25 ++ go.mod | 62 ++++ go.sum | 630 ++++++++++++++++++++++++++++++++ middleware/deserialize-user.go | 49 +++ models/post.model.go | 35 ++ models/user.model.go | 89 +++++ pb/auth_service.pb.go | 174 +++++++++ pb/auth_service_grpc.pb.go | 177 +++++++++ pb/post.pb.go | 273 ++++++++++++++ pb/post_service.pb.go | 319 ++++++++++++++++ pb/post_service_grpc.pb.go | 277 ++++++++++++++ pb/rpc_create_post.pb.go | 172 +++++++++ pb/rpc_signin_user.pb.go | 237 ++++++++++++ pb/rpc_signup_user.pb.go | 240 ++++++++++++ pb/rpc_update_post.pb.go | 186 ++++++++++ pb/user.pb.go | 336 +++++++++++++++++ pb/user_service.pb.go | 152 ++++++++ pb/user_service_grpc.pb.go | 105 ++++++ proto-gen.sh | 6 + proto/auth_service.proto | 17 + proto/post.proto | 18 + proto/post_service.proto | 25 ++ proto/rpc_create_post.proto | 12 + proto/rpc_signin_user.proto | 16 + proto/rpc_signup_user.proto | 16 + proto/rpc_update_post.proto | 13 + proto/user.proto | 22 ++ proto/user_service.proto | 13 + readMe.md | 1 + routes/auth.routes.go | 27 ++ routes/post.routes.go | 24 ++ routes/user.routes.go | 23 ++ services/auth.service.go | 8 + services/auth.service.impl.go | 66 ++++ services/post.service.go | 11 + services/post.service.impl.go | 155 ++++++++ services/user.service.go | 9 + services/user.service.impl.go | 80 ++++ templates/base.html | 32 ++ templates/resetPassword.html | 54 +++ templates/styles.html | 331 +++++++++++++++++ templates/verificationCode.html | 50 +++ tmp/build-errors.log | 1 + utils/email.go | 89 +++++ utils/encode.go | 17 + utils/helper.go | 13 + utils/password.go | 20 + utils/token.go | 68 ++++ 78 files changed, 6406 insertions(+) create mode 100644 .air.toml create mode 100644 .gitignore create mode 100644 Makefile create mode 100644 client/createPost_client.go create mode 100644 client/deletePost_client.go create mode 100644 client/geMe_client.go create mode 100644 client/getPost_client.go create mode 100644 client/listPosts_client.go create mode 100644 client/signin_client.go create mode 100644 client/signup_client.go create mode 100644 client/updatePost_client.go create mode 100644 cmd/client/main.go create mode 100644 cmd/server/main.go create mode 100644 config/default.go create mode 100644 controllers/auth.controller.go create mode 100644 controllers/post.controller.go create mode 100644 controllers/user.controller.go create mode 100644 docker-compose.yml create mode 100644 example.env create mode 100644 gapi/auth-server.go create mode 100644 gapi/post-server.go create mode 100644 gapi/rpc_create_post.go create mode 100644 gapi/rpc_delete_post.go create mode 100644 gapi/rpc_get_me.go create mode 100644 gapi/rpc_get_post.go create mode 100644 gapi/rpc_list_posts.go create mode 100644 gapi/rpc_signin_user.go create mode 100644 gapi/rpc_signup_user.go create mode 100644 gapi/rpc_update_post.go create mode 100644 gapi/rpc_verify_user.go create mode 100644 gapi/user-server.go create mode 100644 go.mod create mode 100644 go.sum create mode 100644 middleware/deserialize-user.go create mode 100644 models/post.model.go create mode 100644 models/user.model.go create mode 100644 pb/auth_service.pb.go create mode 100644 pb/auth_service_grpc.pb.go create mode 100644 pb/post.pb.go create mode 100644 pb/post_service.pb.go create mode 100644 pb/post_service_grpc.pb.go create mode 100644 pb/rpc_create_post.pb.go create mode 100644 pb/rpc_signin_user.pb.go create mode 100644 pb/rpc_signup_user.pb.go create mode 100644 pb/rpc_update_post.pb.go create mode 100644 pb/user.pb.go create mode 100644 pb/user_service.pb.go create mode 100644 pb/user_service_grpc.pb.go create mode 100644 proto-gen.sh create mode 100644 proto/auth_service.proto create mode 100644 proto/post.proto create mode 100644 proto/post_service.proto create mode 100644 proto/rpc_create_post.proto create mode 100644 proto/rpc_signin_user.proto create mode 100644 proto/rpc_signup_user.proto create mode 100644 proto/rpc_update_post.proto create mode 100644 proto/user.proto create mode 100644 proto/user_service.proto create mode 100644 readMe.md create mode 100644 routes/auth.routes.go create mode 100644 routes/post.routes.go create mode 100644 routes/user.routes.go create mode 100644 services/auth.service.go create mode 100644 services/auth.service.impl.go create mode 100644 services/post.service.go create mode 100644 services/post.service.impl.go create mode 100644 services/user.service.go create mode 100644 services/user.service.impl.go create mode 100644 templates/base.html create mode 100644 templates/resetPassword.html create mode 100644 templates/styles.html create mode 100644 templates/verificationCode.html create mode 100644 tmp/build-errors.log create mode 100644 utils/email.go create mode 100644 utils/encode.go create mode 100644 utils/helper.go create mode 100644 utils/password.go create mode 100644 utils/token.go diff --git a/.air.toml b/.air.toml new file mode 100644 index 0000000..162718c --- /dev/null +++ b/.air.toml @@ -0,0 +1,36 @@ +root = "." +testdata_dir = "testdata" +tmp_dir = "tmp" + +[build] + bin = "tmp\\main.exe" + cmd = "go build -o ./tmp/main.exe ./cmd/server/main.go" + delay = 1000 + exclude_dir = ["assets", "tmp", "vendor", "testdata"] + exclude_file = [] + exclude_regex = ["_test.go"] + exclude_unchanged = false + follow_symlink = false + full_bin = "" + include_dir = [] + include_ext = ["go", "tpl", "tmpl", "html"] + kill_delay = "0s" + log = "build-errors.log" + send_interrupt = false + stop_on_error = true + +[color] + app = "" + build = "yellow" + main = "magenta" + runner = "green" + watcher = "cyan" + +[log] + time = false + +[misc] + clean_on_exit = false + +[screen] + clear_on_rebuild = false diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..8ab3927 --- /dev/null +++ b/.gitignore @@ -0,0 +1,23 @@ +# Binaries for programs and plugins +*.exe +*.exe~ +*.dll +*.so +*.dylib + +# Test binary, built with `go test -c` +*.test + +# Output of the go coverage tool, specifically when used with LiteIDE +*.out + +# Dependency directories (remove the comment below to include it) +# vendor/ +.DS_Store +TODO.md +logs.txt +.idea/ +secret.md +app.env +/temp +temp/ \ No newline at end of file diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..a7630b9 --- /dev/null +++ b/Makefile @@ -0,0 +1,15 @@ +.PHONY: dev dev-down go proto + +dev: + docker-compose up -d + +dev-down: + docker-compose down + +go: + air + +proto: + protoc --proto_path=proto --go_out=pb --go_opt=paths=source_relative \ + --go-grpc_out=pb --go-grpc_opt=paths=source_relative \ + proto/*.proto \ No newline at end of file diff --git a/client/createPost_client.go b/client/createPost_client.go new file mode 100644 index 0000000..102eef0 --- /dev/null +++ b/client/createPost_client.go @@ -0,0 +1,35 @@ +package client + +import ( + "context" + "fmt" + "log" + "time" + + "github.com/wpcodevo/golang-mongodb/pb" + "google.golang.org/grpc" +) + +type CreatePostClient struct { + service pb.PostServiceClient +} + +func NewCreatePostClient(conn *grpc.ClientConn) *CreatePostClient { + service := pb.NewPostServiceClient(conn) + + return &CreatePostClient{service} +} + +func (createPostClient *CreatePostClient) CreatePost(args *pb.CreatePostRequest) { + + ctx, cancel := context.WithTimeout(context.Background(), time.Duration(time.Millisecond*5000)) + defer cancel() + + res, err := createPostClient.service.CreatePost(ctx, args) + + if err != nil { + log.Fatalf("CreatePost: %v", err) + } + + fmt.Println(res) +} diff --git a/client/deletePost_client.go b/client/deletePost_client.go new file mode 100644 index 0000000..ee54bba --- /dev/null +++ b/client/deletePost_client.go @@ -0,0 +1,35 @@ +package client + +import ( + "context" + "fmt" + "log" + "time" + + "github.com/wpcodevo/golang-mongodb/pb" + "google.golang.org/grpc" +) + +type DeletePostClient struct { + service pb.PostServiceClient +} + +func NewDeletePostClient(conn *grpc.ClientConn) *DeletePostClient { + service := pb.NewPostServiceClient(conn) + + return &DeletePostClient{service} +} + +func (deletePostClient *DeletePostClient) DeletePost(args *pb.PostRequest) { + + ctx, cancel := context.WithTimeout(context.Background(), time.Duration(time.Millisecond*5000)) + defer cancel() + + _, err := deletePostClient.service.DeletePost(ctx, args) + + if err != nil { + log.Fatalf("DeletePost: %v", err) + } + + fmt.Println("Post deleted successfully") +} diff --git a/client/geMe_client.go b/client/geMe_client.go new file mode 100644 index 0000000..c7deb02 --- /dev/null +++ b/client/geMe_client.go @@ -0,0 +1,35 @@ +package client + +import ( + "context" + "fmt" + "log" + "time" + + "github.com/wpcodevo/golang-mongodb/pb" + "google.golang.org/grpc" +) + +type GetMeClient struct { + service pb.UserServiceClient +} + +func NewGetMeClient(conn *grpc.ClientConn) *GetMeClient { + service := pb.NewUserServiceClient(conn) + + return &GetMeClient{service} +} + +func (getMeClient *GetMeClient) GetMeUser(credentials *pb.GetMeRequest) { + + ctx, cancel := context.WithTimeout(context.Background(), time.Duration(time.Millisecond*5000)) + defer cancel() + + res, err := getMeClient.service.GetMe(ctx, credentials) + + if err != nil { + log.Fatalf("GeMe: %v", err) + } + + fmt.Println(res) +} diff --git a/client/getPost_client.go b/client/getPost_client.go new file mode 100644 index 0000000..cb33323 --- /dev/null +++ b/client/getPost_client.go @@ -0,0 +1,35 @@ +package client + +import ( + "context" + "fmt" + "log" + "time" + + "github.com/wpcodevo/golang-mongodb/pb" + "google.golang.org/grpc" +) + +type GetPostClient struct { + service pb.PostServiceClient +} + +func NewGetPostClient(conn *grpc.ClientConn) *GetPostClient { + service := pb.NewPostServiceClient(conn) + + return &GetPostClient{service} +} + +func (getPostClient *GetPostClient) GetPost(args *pb.PostRequest) { + + ctx, cancel := context.WithTimeout(context.Background(), time.Duration(time.Millisecond*5000)) + defer cancel() + + res, err := getPostClient.service.GetPost(ctx, args) + + if err != nil { + log.Fatalf("GetPost: %v", err) + } + + fmt.Println(res) +} diff --git a/client/listPosts_client.go b/client/listPosts_client.go new file mode 100644 index 0000000..a34e39f --- /dev/null +++ b/client/listPosts_client.go @@ -0,0 +1,47 @@ +package client + +import ( + "context" + "fmt" + "io" + "log" + "time" + + "github.com/wpcodevo/golang-mongodb/pb" + "google.golang.org/grpc" +) + +type ListPostsClient struct { + service pb.PostServiceClient +} + +func NewListPostsClient(conn *grpc.ClientConn) *ListPostsClient { + service := pb.NewPostServiceClient(conn) + + return &ListPostsClient{service} +} + +func (listPostsClient *ListPostsClient) ListPosts(args *pb.GetPostsRequest) { + ctx, cancel := context.WithTimeout(context.Background(), time.Duration(time.Millisecond*5000)) + defer cancel() + + stream, err := listPostsClient.service.GetPosts(ctx, args) + if err != nil { + log.Fatalf("ListPosts: %v", err) + } + + for { + res, err := stream.Recv() + + if err == io.EOF { + break + } + + if err != nil { + log.Fatalf("ListPosts: %v", err) + } + + fmt.Println(res) + } + +} diff --git a/client/signin_client.go b/client/signin_client.go new file mode 100644 index 0000000..c65709e --- /dev/null +++ b/client/signin_client.go @@ -0,0 +1,35 @@ +package client + +import ( + "context" + "fmt" + "log" + "time" + + "github.com/wpcodevo/golang-mongodb/pb" + "google.golang.org/grpc" +) + +type SignInUserClient struct { + service pb.AuthServiceClient +} + +func NewSignInUserClient(conn *grpc.ClientConn) *SignInUserClient { + service := pb.NewAuthServiceClient(conn) + + return &SignInUserClient{service} +} + +func (signInUserClient *SignInUserClient) SignInUser(credentials *pb.SignInUserInput) { + + ctx, cancel := context.WithTimeout(context.Background(), time.Second) + defer cancel() + + res, err := signInUserClient.service.SignInUser(ctx, credentials) + + if err != nil { + log.Fatalf("SignInUser: %v", err) + } + + fmt.Println(res) +} diff --git a/client/signup_client.go b/client/signup_client.go new file mode 100644 index 0000000..29a9867 --- /dev/null +++ b/client/signup_client.go @@ -0,0 +1,35 @@ +package client + +import ( + "context" + "fmt" + "log" + "time" + + "github.com/wpcodevo/golang-mongodb/pb" + "google.golang.org/grpc" +) + +type SignUpUserClient struct { + service pb.AuthServiceClient +} + +func NewSignUpUserClient(conn *grpc.ClientConn) *SignUpUserClient { + service := pb.NewAuthServiceClient(conn) + + return &SignUpUserClient{service} +} + +func (signUpUserClient *SignUpUserClient) SignUpUser(credentials *pb.SignUpUserInput) { + + ctx, cancel := context.WithTimeout(context.Background(), time.Duration(time.Millisecond*5000)) + defer cancel() + + res, err := signUpUserClient.service.SignUpUser(ctx, credentials) + + if err != nil { + log.Fatalf("SignUpUser: %v", err) + } + + fmt.Println(res) +} diff --git a/client/updatePost_client.go b/client/updatePost_client.go new file mode 100644 index 0000000..eeb1185 --- /dev/null +++ b/client/updatePost_client.go @@ -0,0 +1,35 @@ +package client + +import ( + "context" + "fmt" + "log" + "time" + + "github.com/wpcodevo/golang-mongodb/pb" + "google.golang.org/grpc" +) + +type UpdatePostClient struct { + service pb.PostServiceClient +} + +func NewUpdatePostClient(conn *grpc.ClientConn) *UpdatePostClient { + service := pb.NewPostServiceClient(conn) + + return &UpdatePostClient{service} +} + +func (updatePostClient *UpdatePostClient) UpdatePost(args *pb.UpdatePostRequest) { + + ctx, cancel := context.WithTimeout(context.Background(), time.Duration(time.Millisecond*5000)) + defer cancel() + + res, err := updatePostClient.service.UpdatePost(ctx, args) + + if err != nil { + log.Fatalf("UpdatePost: %v", err) + } + + fmt.Println(res) +} diff --git a/cmd/client/main.go b/cmd/client/main.go new file mode 100644 index 0000000..049fa45 --- /dev/null +++ b/cmd/client/main.go @@ -0,0 +1,121 @@ +package main + +import ( + "log" + + "github.com/wpcodevo/golang-mongodb/client" + "github.com/wpcodevo/golang-mongodb/pb" + "google.golang.org/grpc" + "google.golang.org/grpc/credentials/insecure" +) + +const ( + address = "0.0.0.0:8080" +) + +func main() { + conn, err := grpc.Dial(address, grpc.WithTransportCredentials(insecure.NewCredentials()), grpc.WithBlock()) + + if err != nil { + log.Fatalf("failed to connect: %v", err) + } + + defer conn.Close() + + // Sign Up + if false { + signUpUserClient := client.NewSignUpUserClient(conn) + newUser := &pb.SignUpUserInput{ + Name: "Jane Smith", + Email: "janesmith@gmail.com", + Password: "password123", + PasswordConfirm: "password123", + } + signUpUserClient.SignUpUser(newUser) + } + + // Sign In + if false { + signInUserClient := client.NewSignInUserClient(conn) + + credentials := &pb.SignInUserInput{ + Email: "janesmith@gmail.com", + Password: "password123", + } + signInUserClient.SignInUser(credentials) + } + + // Get Me + if false { + + getMeClient := client.NewGetMeClient(conn) + id := &pb.GetMeRequest{ + Id: "628cffb91e50302d360c1a2c", + } + getMeClient.GetMeUser(id) + + } + + // List Posts + if false { + listPostsClient := client.NewListPostsClient(conn) + + var page int64 = 1 + var limit int64 = 10 + args := &pb.GetPostsRequest{ + Page: &page, + Limit: &limit, + } + + listPostsClient.ListPosts(args) + } + + // Create Post + if false { + createPostClient := client.NewCreatePostClient(conn) + + args := &pb.CreatePostRequest{ + Title: "My second gRPC post with joy", + Content: "It's always good to learn new technologies", + User: "62908e0a42a608d5aeae2f64", + Image: "default.png", + } + + createPostClient.CreatePost(args) + } + + // Update Post + if false { + updatePostClient := client.NewUpdatePostClient(conn) + + title := "My new updated title for my blog" + args := &pb.UpdatePostRequest{ + Id: "629169e00a6c7cfd24e2129d", + Title: &title, + } + + updatePostClient.UpdatePost(args) + } + + // Get Post + if false { + getPostClient := client.NewGetPostClient(conn) + + args := &pb.PostRequest{ + Id: "629169e00a6c7cfd24e2129d", + } + + getPostClient.GetPost(args) + } + + // Delete Post + if false { + deletePostClient := client.NewDeletePostClient(conn) + + args := &pb.PostRequest{ + Id: "629147ff3c92aed11d49394b", + } + + deletePostClient.DeletePost(args) + } +} diff --git a/cmd/server/main.go b/cmd/server/main.go new file mode 100644 index 0000000..d6fdb20 --- /dev/null +++ b/cmd/server/main.go @@ -0,0 +1,179 @@ +package main + +import ( + "context" + "fmt" + "log" + "net" + "net/http" + + "github.com/gin-contrib/cors" + "github.com/gin-gonic/gin" + "github.com/go-redis/redis/v8" + "github.com/wpcodevo/golang-mongodb/config" + "github.com/wpcodevo/golang-mongodb/controllers" + "github.com/wpcodevo/golang-mongodb/gapi" + "github.com/wpcodevo/golang-mongodb/pb" + "github.com/wpcodevo/golang-mongodb/routes" + "github.com/wpcodevo/golang-mongodb/services" + "go.mongodb.org/mongo-driver/mongo" + "go.mongodb.org/mongo-driver/mongo/options" + "go.mongodb.org/mongo-driver/mongo/readpref" + "google.golang.org/grpc" + "google.golang.org/grpc/reflection" +) + +var ( + server *gin.Engine + ctx context.Context + mongoclient *mongo.Client + redisclient *redis.Client + + userService services.UserService + UserController controllers.UserController + UserRouteController routes.UserRouteController + + authCollection *mongo.Collection + authService services.AuthService + AuthController controllers.AuthController + AuthRouteController routes.AuthRouteController + + // 👇 Create the Post Variables + postService services.PostService + PostController controllers.PostController + postCollection *mongo.Collection + PostRouteController routes.PostRouteController +) + +func init() { + config, err := config.LoadConfig(".") + if err != nil { + log.Fatal("Could not load environment variables", err) + } + + ctx = context.TODO() + + // Connect to MongoDB + mongoconn := options.Client().ApplyURI(config.DBUri) + mongoclient, err := mongo.Connect(ctx, mongoconn) + + if err != nil { + panic(err) + } + + if err := mongoclient.Ping(ctx, readpref.Primary()); err != nil { + panic(err) + } + + fmt.Println("MongoDB successfully connected...") + + // Connect to Redis + redisclient = redis.NewClient(&redis.Options{ + Addr: config.RedisUri, + }) + + if _, err := redisclient.Ping(ctx).Result(); err != nil { + panic(err) + } + + err = redisclient.Set(ctx, "test", "Welcome to Golang with Redis and MongoDB", 0).Err() + if err != nil { + panic(err) + } + + fmt.Println("Redis client connected successfully...") + + // Collections + authCollection = mongoclient.Database("golang_mongodb").Collection("users") + userService = services.NewUserServiceImpl(authCollection, ctx) + authService = services.NewAuthService(authCollection, ctx) + AuthController = controllers.NewAuthController(authService, userService, ctx, authCollection) + AuthRouteController = routes.NewAuthRouteController(AuthController) + + UserController = controllers.NewUserController(userService) + UserRouteController = routes.NewRouteUserController(UserController) + + // 👇 Instantiate the Constructors + postCollection = mongoclient.Database("golang_mongodb").Collection("posts") + postService = services.NewPostService(postCollection, ctx) + PostController = controllers.NewPostController(postService) + PostRouteController = routes.NewPostControllerRoute(PostController) + + server = gin.Default() +} + +func main() { + config, err := config.LoadConfig(".") + + if err != nil { + log.Fatal("Could not load config", err) + } + + defer mongoclient.Disconnect(ctx) + + // startGinServer(config) + startGrpcServer(config) +} + +func startGrpcServer(config config.Config) { + authServer, err := gapi.NewGrpcAuthServer(config, authService, userService, authCollection) + if err != nil { + log.Fatal("cannot create grpc authServer: ", err) + } + + userServer, err := gapi.NewGrpcUserServer(config, userService, authCollection) + if err != nil { + log.Fatal("cannot create grpc userServer: ", err) + } + + postServer, err := gapi.NewGrpcPostServer(postCollection, postService) + if err != nil { + log.Fatal("cannot create grpc postServer: ", err) + } + + grpcServer := grpc.NewServer() + + pb.RegisterAuthServiceServer(grpcServer, authServer) + pb.RegisterUserServiceServer(grpcServer, userServer) + // 👇 Register the Post gRPC service + pb.RegisterPostServiceServer(grpcServer, postServer) + reflection.Register(grpcServer) + + listener, err := net.Listen("tcp", config.GrpcServerAddress) + if err != nil { + log.Fatal("cannot create grpc server: ", err) + } + + log.Printf("start gRPC server on %s", listener.Addr().String()) + err = grpcServer.Serve(listener) + if err != nil { + log.Fatal("cannot create grpc server: ", err) + } +} + +func startGinServer(config config.Config) { + value, err := redisclient.Get(ctx, "test").Result() + + if err == redis.Nil { + fmt.Println("key: test does not exist") + } else if err != nil { + panic(err) + } + + corsConfig := cors.DefaultConfig() + corsConfig.AllowOrigins = []string{config.Origin} + corsConfig.AllowCredentials = true + + server.Use(cors.New(corsConfig)) + + router := server.Group("/api") + router.GET("/healthchecker", func(ctx *gin.Context) { + ctx.JSON(http.StatusOK, gin.H{"status": "success", "message": value}) + }) + + AuthRouteController.AuthRoute(router, userService) + UserRouteController.UserRoute(router, userService) + // 👇 Post Route + PostRouteController.PostRoute(router) + log.Fatal(server.Run(":" + config.Port)) +} diff --git a/config/default.go b/config/default.go new file mode 100644 index 0000000..c8f9257 --- /dev/null +++ b/config/default.go @@ -0,0 +1,48 @@ +package config + +import ( + "time" + + "github.com/spf13/viper" +) + +type Config struct { + DBUri string `mapstructure:"MONGODB_LOCAL_URI"` + RedisUri string `mapstructure:"REDIS_URL"` + Port string `mapstructure:"PORT"` + + GrpcServerAddress string `mapstructure:"GRPC_SERVER_ADDRESS"` + + AccessTokenPrivateKey string `mapstructure:"ACCESS_TOKEN_PRIVATE_KEY"` + AccessTokenPublicKey string `mapstructure:"ACCESS_TOKEN_PUBLIC_KEY"` + RefreshTokenPrivateKey string `mapstructure:"REFRESH_TOKEN_PRIVATE_KEY"` + RefreshTokenPublicKey string `mapstructure:"REFRESH_TOKEN_PUBLIC_KEY"` + AccessTokenExpiresIn time.Duration `mapstructure:"ACCESS_TOKEN_EXPIRED_IN"` + RefreshTokenExpiresIn time.Duration `mapstructure:"REFRESH_TOKEN_EXPIRED_IN"` + AccessTokenMaxAge int `mapstructure:"ACCESS_TOKEN_MAXAGE"` + RefreshTokenMaxAge int `mapstructure:"REFRESH_TOKEN_MAXAGE"` + + Origin string `mapstructure:"CLIENT_ORIGIN"` + + EmailFrom string `mapstructure:"EMAIL_FROM"` + SMTPHost string `mapstructure:"SMTP_HOST"` + SMTPPass string `mapstructure:"SMTP_PASS"` + SMTPPort int `mapstructure:"SMTP_PORT"` + SMTPUser string `mapstructure:"SMTP_USER"` +} + +func LoadConfig(path string) (config Config, err error) { + viper.AddConfigPath(path) + viper.SetConfigType("env") + viper.SetConfigName("app") + + viper.AutomaticEnv() + + err = viper.ReadInConfig() + if err != nil { + return + } + + err = viper.Unmarshal(&config) + return +} diff --git a/controllers/auth.controller.go b/controllers/auth.controller.go new file mode 100644 index 0000000..ea3c8c2 --- /dev/null +++ b/controllers/auth.controller.go @@ -0,0 +1,282 @@ +package controllers + +import ( + "context" + "fmt" + "log" + "net/http" + "strings" + "time" + + "github.com/gin-gonic/gin" + "github.com/thanhpk/randstr" + "github.com/wpcodevo/golang-mongodb/config" + "github.com/wpcodevo/golang-mongodb/models" + "github.com/wpcodevo/golang-mongodb/services" + "github.com/wpcodevo/golang-mongodb/utils" + "go.mongodb.org/mongo-driver/bson" + "go.mongodb.org/mongo-driver/mongo" +) + +type AuthController struct { + authService services.AuthService + userService services.UserService + ctx context.Context + collection *mongo.Collection +} + +func NewAuthController(authService services.AuthService, userService services.UserService, ctx context.Context, collection *mongo.Collection) AuthController { + return AuthController{authService, userService, ctx, collection} +} + +func (ac *AuthController) SignUpUser(ctx *gin.Context) { + var user *models.SignUpInput + + if err := ctx.ShouldBindJSON(&user); err != nil { + ctx.JSON(http.StatusBadRequest, gin.H{"status": "fail", "message": err.Error()}) + return + } + + if user.Password != user.PasswordConfirm { + ctx.JSON(http.StatusBadRequest, gin.H{"status": "fail", "message": "Passwords do not match"}) + return + } + + newUser, err := ac.authService.SignUpUser(user) + + if err != nil { + if strings.Contains(err.Error(), "email already exist") { + ctx.JSON(http.StatusConflict, gin.H{"status": "error", "message": err.Error()}) + return + } + ctx.JSON(http.StatusBadGateway, gin.H{"status": "error", "message": err.Error()}) + return + } + + config, err := config.LoadConfig(".") + if err != nil { + log.Fatal("Could not load config", err) + } + + // Generate Verification Code + code := randstr.String(20) + + verificationCode := utils.Encode(code) + + updateData := &models.UpdateInput{ + VerificationCode: verificationCode, + } + + // Update User in Database + ac.userService.UpdateUserById(newUser.ID.Hex(), updateData) + + var firstName = newUser.Name + + if strings.Contains(firstName, " ") { + firstName = strings.Split(firstName, " ")[1] + } + + // 👇 Send Email + emailData := utils.EmailData{ + URL: config.Origin + "/verifyemail/" + code, + FirstName: firstName, + Subject: "Your account verification code", + } + + err = utils.SendEmail(newUser, &emailData, "verificationCode.html") + if err != nil { + ctx.JSON(http.StatusBadGateway, gin.H{"status": "success", "message": "There was an error sending email"}) + return + } + + message := "We sent an email with a verification code to " + user.Email + ctx.JSON(http.StatusCreated, gin.H{"status": "success", "message": message}) +} + +func (ac *AuthController) SignInUser(ctx *gin.Context) { + var credentials *models.SignInInput + + if err := ctx.ShouldBindJSON(&credentials); err != nil { + ctx.JSON(http.StatusBadRequest, gin.H{"status": "fail", "message": err.Error()}) + return + } + + user, err := ac.userService.FindUserByEmail(credentials.Email) + if err != nil { + if err == mongo.ErrNoDocuments { + ctx.JSON(http.StatusBadRequest, gin.H{"status": "fail", "message": "Invalid email or password"}) + return + } + ctx.JSON(http.StatusBadRequest, gin.H{"status": "fail", "message": err.Error()}) + return + } + + if !user.Verified { + ctx.JSON(http.StatusUnauthorized, gin.H{"status": "fail", "message": "You are not verified, please verify your email to login"}) + return + } + + if err := utils.VerifyPassword(user.Password, credentials.Password); err != nil { + ctx.JSON(http.StatusBadRequest, gin.H{"status": "fail", "message": "Invalid email or Password"}) + return + } + + config, _ := config.LoadConfig(".") + + // Generate Tokens + access_token, err := utils.CreateToken(config.AccessTokenExpiresIn, user.ID, config.AccessTokenPrivateKey) + if err != nil { + ctx.JSON(http.StatusBadRequest, gin.H{"status": "fail", "message": err.Error()}) + return + } + + refresh_token, err := utils.CreateToken(config.RefreshTokenExpiresIn, user.ID, config.RefreshTokenPrivateKey) + if err != nil { + ctx.JSON(http.StatusBadRequest, gin.H{"status": "fail", "message": err.Error()}) + return + } + + ctx.SetCookie("access_token", access_token, config.AccessTokenMaxAge*60, "/", "localhost", false, true) + ctx.SetCookie("refresh_token", refresh_token, config.RefreshTokenMaxAge*60, "/", "localhost", false, true) + ctx.SetCookie("logged_in", "true", config.AccessTokenMaxAge*60, "/", "localhost", false, false) + + ctx.JSON(http.StatusOK, gin.H{"status": "success", "access_token": access_token}) +} + +func (ac *AuthController) RefreshAccessToken(ctx *gin.Context) { + message := "could not refresh access token" + + cookie, err := ctx.Cookie("refresh_token") + + if err != nil { + ctx.AbortWithStatusJSON(http.StatusForbidden, gin.H{"status": "fail", "message": message}) + return + } + + config, _ := config.LoadConfig(".") + + sub, err := utils.ValidateToken(cookie, config.RefreshTokenPublicKey) + if err != nil { + ctx.AbortWithStatusJSON(http.StatusForbidden, gin.H{"status": "fail", "message": err.Error()}) + return + } + + user, err := ac.userService.FindUserById(fmt.Sprint(sub)) + if err != nil { + ctx.AbortWithStatusJSON(http.StatusForbidden, gin.H{"status": "fail", "message": "the user belonging to this token no logger exists"}) + return + } + + access_token, err := utils.CreateToken(config.AccessTokenExpiresIn, user.ID, config.AccessTokenPrivateKey) + if err != nil { + ctx.AbortWithStatusJSON(http.StatusForbidden, gin.H{"status": "fail", "message": err.Error()}) + return + } + + ctx.SetCookie("access_token", access_token, config.AccessTokenMaxAge*60, "/", "localhost", false, true) + ctx.SetCookie("logged_in", "true", config.AccessTokenMaxAge*60, "/", "localhost", false, false) + + ctx.JSON(http.StatusOK, gin.H{"status": "success", "access_token": access_token}) +} + +func (ac *AuthController) LogoutUser(ctx *gin.Context) { + ctx.SetCookie("access_token", "", -1, "/", "localhost", false, true) + ctx.SetCookie("refresh_token", "", -1, "/", "localhost", false, true) + ctx.SetCookie("logged_in", "", -1, "/", "localhost", false, true) + + ctx.JSON(http.StatusOK, gin.H{"status": "success"}) +} + +func (ac *AuthController) VerifyEmail(ctx *gin.Context) { + + code := ctx.Params.ByName("verificationCode") + verificationCode := utils.Encode(code) + + query := bson.D{{Key: "verificationCode", Value: verificationCode}} + update := bson.D{{Key: "$set", Value: bson.D{{Key: "verified", Value: true}}}, {Key: "$unset", Value: bson.D{{Key: "verificationCode", Value: ""}}}} + result, err := ac.collection.UpdateOne(ac.ctx, query, update) + if err != nil { + ctx.JSON(http.StatusForbidden, gin.H{"status": "success", "message": err.Error()}) + return + } + + if result.MatchedCount == 0 { + ctx.JSON(http.StatusForbidden, gin.H{"status": "success", "message": "Could not verify email address"}) + return + } + + fmt.Println(result) + + ctx.JSON(http.StatusOK, gin.H{"status": "success", "message": "Email verified successfully"}) + +} + +func (ac *AuthController) ForgotPassword(ctx *gin.Context) { + var userCredential *models.ForgotPasswordInput + + if err := ctx.ShouldBindJSON(&userCredential); err != nil { + ctx.JSON(http.StatusBadRequest, gin.H{"status": "fail", "message": err.Error()}) + return + } + + message := "You will receive a reset email if user with that email exist" + + user, err := ac.userService.FindUserByEmail(userCredential.Email) + if err != nil { + if err == mongo.ErrNoDocuments { + ctx.JSON(http.StatusOK, gin.H{"status": "fail", "message": message}) + return + } + ctx.JSON(http.StatusBadGateway, gin.H{"status": "error", "message": err.Error()}) + return + } + + if !user.Verified { + ctx.JSON(http.StatusUnauthorized, gin.H{"status": "error", "message": "Account not verified"}) + return + } + + config, err := config.LoadConfig(".") + if err != nil { + log.Fatal("Could not load config", err) + } + + // Generate Verification Code + resetToken := randstr.String(20) + + passwordResetToken := utils.Encode(resetToken) + + // Update User in Database + query := bson.D{{Key: "email", Value: strings.ToLower(userCredential.Email)}} + update := bson.D{{Key: "$set", Value: bson.D{{Key: "passwordResetToken", Value: passwordResetToken}, {Key: "passwordResetAt", Value: time.Now().Add(time.Minute * 15)}}}} + result, err := ac.collection.UpdateOne(ac.ctx, query, update) + + if result.MatchedCount == 0 { + ctx.JSON(http.StatusBadGateway, gin.H{"status": "success", "message": "There was an error sending email"}) + return + } + + if err != nil { + ctx.JSON(http.StatusForbidden, gin.H{"status": "success", "message": err.Error()}) + return + } + var firstName = user.Name + + if strings.Contains(firstName, " ") { + firstName = strings.Split(firstName, " ")[1] + } + + // 👇 Send Email + emailData := utils.EmailData{ + URL: config.Origin + "/forgotPassword/" + resetToken, + FirstName: firstName, + Subject: "Your password reset token (valid for 10min)", + } + + err = utils.SendEmail(user, &emailData, "resetPassword.html") + if err != nil { + ctx.JSON(http.StatusBadGateway, gin.H{"status": "success", "message": "There was an error sending email"}) + return + } + ctx.JSON(http.StatusOK, gin.H{"status": "success", "message": message}) +} diff --git a/controllers/post.controller.go b/controllers/post.controller.go new file mode 100644 index 0000000..0ce8253 --- /dev/null +++ b/controllers/post.controller.go @@ -0,0 +1,119 @@ +package controllers + +import ( + "net/http" + "strconv" + "strings" + + "github.com/gin-gonic/gin" + "github.com/wpcodevo/golang-mongodb/models" + "github.com/wpcodevo/golang-mongodb/services" +) + +type PostController struct { + postService services.PostService +} + +func NewPostController(postService services.PostService) PostController { + return PostController{postService} +} + +func (pc *PostController) CreatePost(ctx *gin.Context) { + var post *models.CreatePostRequest + + if err := ctx.ShouldBindJSON(&post); err != nil { + ctx.JSON(http.StatusBadRequest, err.Error()) + return + } + + newPost, err := pc.postService.CreatePost(post) + + if err != nil { + if strings.Contains(err.Error(), "title already exists") { + ctx.JSON(http.StatusConflict, gin.H{"status": "fail", "message": err.Error()}) + return + } + + ctx.JSON(http.StatusBadGateway, gin.H{"status": "fail", "message": err.Error()}) + return + } + + ctx.JSON(http.StatusCreated, gin.H{"status": "success", "data": newPost}) +} + +func (pc *PostController) UpdatePost(ctx *gin.Context) { + postId := ctx.Param("postId") + + var post *models.UpdatePost + if err := ctx.ShouldBindJSON(&post); err != nil { + ctx.JSON(http.StatusBadGateway, gin.H{"status": "fail", "message": err.Error()}) + return + } + + updatedPost, err := pc.postService.UpdatePost(postId, post) + if err != nil { + if strings.Contains(err.Error(), "Id exists") { + ctx.JSON(http.StatusNotFound, gin.H{"status": "fail", "message": err.Error()}) + return + } + ctx.JSON(http.StatusBadGateway, gin.H{"status": "fail", "message": err.Error()}) + return + } + + ctx.JSON(http.StatusOK, gin.H{"status": "success", "data": updatedPost}) +} + +func (pc *PostController) FindPostById(ctx *gin.Context) { + postId := ctx.Param("postId") + + post, err := pc.postService.FindPostById(postId) + + if err != nil { + ctx.JSON(http.StatusBadGateway, gin.H{"status": "fail", "message": err.Error()}) + return + } + + ctx.JSON(http.StatusOK, gin.H{"status": "success", "data": post}) +} + +func (pc *PostController) FindPosts(ctx *gin.Context) { + var page = ctx.DefaultQuery("page", "1") + var limit = ctx.DefaultQuery("limit", "10") + + intPage, err := strconv.Atoi(page) + if err != nil { + ctx.JSON(http.StatusBadGateway, gin.H{"status": "fail", "message": err.Error()}) + return + } + + intLimit, err := strconv.Atoi(limit) + if err != nil { + ctx.JSON(http.StatusBadGateway, gin.H{"status": "fail", "message": err.Error()}) + return + } + + posts, err := pc.postService.FindPosts(intPage, intLimit) + if err != nil { + ctx.JSON(http.StatusBadGateway, gin.H{"status": "fail", "message": err.Error()}) + return + } + + ctx.JSON(http.StatusOK, gin.H{"status": "success", "results": len(posts), "data": posts}) +} + +func (pc *PostController) DeletePost(ctx *gin.Context) { + postId := ctx.Param("postId") + + err := pc.postService.DeletePost(postId) + + if err != nil { + if strings.Contains(err.Error(), "Id exists") { + ctx.JSON(http.StatusNotFound, gin.H{"status": "fail", "message": err.Error()}) + return + } + ctx.JSON(http.StatusBadGateway, gin.H{"status": "fail", "message": err.Error()}) + return + } + + ctx.JSON(http.StatusNoContent, nil) +} diff --git a/controllers/user.controller.go b/controllers/user.controller.go new file mode 100644 index 0000000..f57fd3b --- /dev/null +++ b/controllers/user.controller.go @@ -0,0 +1,23 @@ +package controllers + +import ( + "net/http" + + "github.com/gin-gonic/gin" + "github.com/wpcodevo/golang-mongodb/models" + "github.com/wpcodevo/golang-mongodb/services" +) + +type UserController struct { + userService services.UserService +} + +func NewUserController(userService services.UserService) UserController { + return UserController{userService} +} + +func (uc *UserController) GetMe(ctx *gin.Context) { + currentUser := ctx.MustGet("currentUser").(*models.DBResponse) + + ctx.JSON(http.StatusOK, gin.H{"status": "success", "data": gin.H{"user": models.FilteredResponse(currentUser)}}) +} diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..9ce3bec --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,24 @@ +version: '3' +services: + mongodb: + image: mongo + container_name: mongodb + restart: always + env_file: + - ./app.env + + ports: + - '6000:27017' + volumes: + - mongodb:/data/db + + redis: + image: redis:alpine + container_name: redis + ports: + - '6379:6379' + volumes: + - redisDB:/data +volumes: + mongodb: + redisDB: diff --git a/example.env b/example.env new file mode 100644 index 0000000..cd74f71 --- /dev/null +++ b/example.env @@ -0,0 +1,33 @@ +PORT=8000 + +GRPC_SERVER_ADDRESS=0.0.0.0:8080 + +MONGO_INITDB_ROOT_USERNAME=root +MONGO_INITDB_ROOT_PASSWORD=password123 + +MONGODB_LOCAL_URI=mongodb://root:password123@localhost:6000 + +REDIS_URL=localhost:6379 + +CLIENT_ORIGIN=http://localhost:3000 + +EMAIL_FROM=admin@admin.com +SMTP_HOST=smtp.mailtrap.io +SMTP_USER= +SMTP_PASS= +SMTP_PORT=587 + + +ACCESS_TOKEN_PRIVATE_KEY=LS0tLS1CRUdJTiBSU0EgUFJJVkFURSBLRVktLS0tLQpNSUlCUEFJQkFBSkJBTzVIKytVM0xrWC91SlRvRHhWN01CUURXSTdGU0l0VXNjbGFFKzlaUUg5Q2VpOGIxcUVmCnJxR0hSVDVWUis4c3UxVWtCUVpZTER3MnN3RTVWbjg5c0ZVQ0F3RUFBUUpCQUw4ZjRBMUlDSWEvQ2ZmdWR3TGMKNzRCdCtwOXg0TEZaZXMwdHdtV3Vha3hub3NaV0w4eVpSTUJpRmI4a25VL0hwb3piTnNxMmN1ZU9wKzVWdGRXNApiTlVDSVFENm9JdWxqcHdrZTFGY1VPaldnaXRQSjNnbFBma3NHVFBhdFYwYnJJVVI5d0loQVBOanJ1enB4ckhsCkUxRmJxeGtUNFZ5bWhCOU1HazU0Wk1jWnVjSmZOcjBUQWlFQWhML3UxOVZPdlVBWVd6Wjc3Y3JxMTdWSFBTcXoKUlhsZjd2TnJpdEg1ZGdjQ0lRRHR5QmFPdUxuNDlIOFIvZ2ZEZ1V1cjg3YWl5UHZ1YStxeEpXMzQrb0tFNXdJZwpQbG1KYXZsbW9jUG4rTkVRdGhLcTZuZFVYRGpXTTlTbktQQTVlUDZSUEs0PQotLS0tLUVORCBSU0EgUFJJVkFURSBLRVktLS0tLQ== + +ACCESS_TOKEN_PUBLIC_KEY=LS0tLS1CRUdJTiBQVUJMSUMgS0VZLS0tLS0KTUZ3d0RRWUpLb1pJaHZjTkFRRUJCUUFEU3dBd1NBSkJBTzVIKytVM0xrWC91SlRvRHhWN01CUURXSTdGU0l0VQpzY2xhRSs5WlFIOUNlaThiMXFFZnJxR0hSVDVWUis4c3UxVWtCUVpZTER3MnN3RTVWbjg5c0ZVQ0F3RUFBUT09Ci0tLS0tRU5EIFBVQkxJQyBLRVktLS0tLQ== +ACCESS_TOKEN_EXPIRED_IN=15m +ACCESS_TOKEN_MAXAGE=15 + + +REFRESH_TOKEN_PRIVATE_KEY=LS0tLS1CRUdJTiBSU0EgUFJJVkFURSBLRVktLS0tLQpNSUlCT1FJQkFBSkJBSWFJcXZXeldCSndnYjR1SEhFQ01RdHFZMTI5b2F5RzVZMGlGcG51a0J1VHpRZVlQWkE4Cmx4OC9lTUh3Rys1MlJGR3VxMmE2N084d2s3TDR5dnY5dVY4Q0F3RUFBUUpBRUZ6aEJqOUk3LzAxR285N01CZUgKSlk5TUJLUEMzVHdQQVdwcSswL3p3UmE2ZkZtbXQ5NXNrN21qT3czRzNEZ3M5T2RTeWdsbTlVdndNWXh6SXFERAplUUloQVA5UStrMTBQbGxNd2ZJbDZtdjdTMFRYOGJDUlRaZVI1ZFZZb3FTeW40YmpBaUVBaHVUa2JtZ1NobFlZCnRyclNWZjN0QWZJcWNVUjZ3aDdMOXR5MVlvalZVRlVDSUhzOENlVHkwOWxrbkVTV0dvV09ZUEZVemhyc3Q2Z08KU3dKa2F2VFdKdndEQWlBdWhnVU8yeEFBaXZNdEdwUHVtb3hDam8zNjBMNXg4d012bWdGcEFYNW9uUUlnQzEvSwpNWG1heWtsaFRDeWtXRnpHMHBMWVdkNGRGdTI5M1M2ZUxJUlNIS009Ci0tLS0tRU5EIFJTQSBQUklWQVRFIEtFWS0tLS0t + +REFRESH_TOKEN_PUBLIC_KEY=LS0tLS1CRUdJTiBQVUJMSUMgS0VZLS0tLS0KTUZ3d0RRWUpLb1pJaHZjTkFRRUJCUUFEU3dBd1NBSkJBSWFJcXZXeldCSndnYjR1SEhFQ01RdHFZMTI5b2F5Rwo1WTBpRnBudWtCdVR6UWVZUFpBOGx4OC9lTUh3Rys1MlJGR3VxMmE2N084d2s3TDR5dnY5dVY4Q0F3RUFBUT09Ci0tLS0tRU5EIFBVQkxJQyBLRVktLS0tLQ== + +REFRESH_TOKEN_EXPIRED_IN=60m +REFRESH_TOKEN_MAXAGE=60 diff --git a/gapi/auth-server.go b/gapi/auth-server.go new file mode 100644 index 0000000..1e85879 --- /dev/null +++ b/gapi/auth-server.go @@ -0,0 +1,29 @@ +package gapi + +import ( + "github.com/wpcodevo/golang-mongodb/config" + "github.com/wpcodevo/golang-mongodb/pb" + "github.com/wpcodevo/golang-mongodb/services" + "go.mongodb.org/mongo-driver/mongo" +) + +type AuthServer struct { + pb.UnimplementedAuthServiceServer + config config.Config + authService services.AuthService + userService services.UserService + userCollection *mongo.Collection +} + +func NewGrpcAuthServer(config config.Config, authService services.AuthService, + userService services.UserService, userCollection *mongo.Collection) (*AuthServer, error) { + + authServer := &AuthServer{ + config: config, + authService: authService, + userService: userService, + userCollection: userCollection, + } + + return authServer, nil +} diff --git a/gapi/post-server.go b/gapi/post-server.go new file mode 100644 index 0000000..5aab520 --- /dev/null +++ b/gapi/post-server.go @@ -0,0 +1,22 @@ +package gapi + +import ( + "github.com/wpcodevo/golang-mongodb/pb" + "github.com/wpcodevo/golang-mongodb/services" + "go.mongodb.org/mongo-driver/mongo" +) + +type PostServer struct { + pb.UnimplementedPostServiceServer + postCollection *mongo.Collection + postService services.PostService +} + +func NewGrpcPostServer(postCollection *mongo.Collection, postService services.PostService) (*PostServer, error) { + postServer := &PostServer{ + postCollection: postCollection, + postService: postService, + } + + return postServer, nil +} diff --git a/gapi/rpc_create_post.go b/gapi/rpc_create_post.go new file mode 100644 index 0000000..5f461b2 --- /dev/null +++ b/gapi/rpc_create_post.go @@ -0,0 +1,44 @@ +package gapi + +import ( + "context" + "strings" + + "github.com/wpcodevo/golang-mongodb/models" + "github.com/wpcodevo/golang-mongodb/pb" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/status" + "google.golang.org/protobuf/types/known/timestamppb" +) + +func (postServer *PostServer) CreatePost(ctx context.Context, req *pb.CreatePostRequest) (*pb.PostResponse, error) { + + post := &models.CreatePostRequest{ + Title: req.GetTitle(), + Content: req.GetContent(), + Image: req.GetImage(), + User: req.GetUser(), + } + + newPost, err := postServer.postService.CreatePost(post) + + if err != nil { + if strings.Contains(err.Error(), "title already exists") { + return nil, status.Errorf(codes.AlreadyExists, err.Error()) + } + + return nil, status.Errorf(codes.Internal, err.Error()) + } + + res := &pb.PostResponse{ + Post: &pb.Post{ + Id: newPost.Id.Hex(), + Title: newPost.Title, + Content: newPost.Content, + User: newPost.User, + CreatedAt: timestamppb.New(newPost.CreateAt), + UpdatedAt: timestamppb.New(newPost.UpdatedAt), + }, + } + return res, nil +} diff --git a/gapi/rpc_delete_post.go b/gapi/rpc_delete_post.go new file mode 100644 index 0000000..aa59a35 --- /dev/null +++ b/gapi/rpc_delete_post.go @@ -0,0 +1,27 @@ +package gapi + +import ( + "context" + "strings" + + "github.com/wpcodevo/golang-mongodb/pb" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/status" +) + +func (postServer *PostServer) DeletePost(ctx context.Context, req *pb.PostRequest) (*pb.DeletePostResponse, error) { + postId := req.GetId() + + if err := postServer.postService.DeletePost(postId); err != nil { + if strings.Contains(err.Error(), "Id exists") { + return nil, status.Errorf(codes.NotFound, err.Error()) + } + return nil, status.Errorf(codes.Internal, err.Error()) + } + + res := &pb.DeletePostResponse{ + Success: true, + } + + return res, nil +} diff --git a/gapi/rpc_get_me.go b/gapi/rpc_get_me.go new file mode 100644 index 0000000..c6cbd02 --- /dev/null +++ b/gapi/rpc_get_me.go @@ -0,0 +1,31 @@ +package gapi + +import ( + "context" + + "github.com/wpcodevo/golang-mongodb/pb" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/status" + "google.golang.org/protobuf/types/known/timestamppb" +) + +func (userServer *UserServer) GetMe(ctx context.Context, req *pb.GetMeRequest) (*pb.UserResponse, error) { + id := req.GetId() + user, err := userServer.userService.FindUserById(id) + + if err != nil { + return nil, status.Errorf(codes.Unimplemented, err.Error()) + } + + res := &pb.UserResponse{ + User: &pb.User{ + Id: user.ID.Hex(), + Name: user.Name, + Email: user.Email, + Role: user.Role, + CreatedAt: timestamppb.New(user.CreatedAt), + UpdatedAt: timestamppb.New(user.UpdatedAt), + }, + } + return res, nil +} diff --git a/gapi/rpc_get_post.go b/gapi/rpc_get_post.go new file mode 100644 index 0000000..6eac59d --- /dev/null +++ b/gapi/rpc_get_post.go @@ -0,0 +1,37 @@ +package gapi + +import ( + "context" + "strings" + + "github.com/wpcodevo/golang-mongodb/pb" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/status" + "google.golang.org/protobuf/types/known/timestamppb" +) + +func (postServer *PostServer) GetPost(ctx context.Context, req *pb.PostRequest) (*pb.PostResponse, error) { + postId := req.GetId() + + post, err := postServer.postService.FindPostById(postId) + if err != nil { + if strings.Contains(err.Error(), "Id exists") { + return nil, status.Errorf(codes.NotFound, err.Error()) + + } + return nil, status.Errorf(codes.Internal, err.Error()) + } + + res := &pb.PostResponse{ + Post: &pb.Post{ + Id: post.Id.Hex(), + Title: post.Title, + Content: post.Content, + Image: post.Image, + User: post.User, + CreatedAt: timestamppb.New(post.CreateAt), + UpdatedAt: timestamppb.New(post.UpdatedAt), + }, + } + return res, nil +} diff --git a/gapi/rpc_list_posts.go b/gapi/rpc_list_posts.go new file mode 100644 index 0000000..a3636a0 --- /dev/null +++ b/gapi/rpc_list_posts.go @@ -0,0 +1,31 @@ +package gapi + +import ( + "github.com/wpcodevo/golang-mongodb/pb" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/status" + "google.golang.org/protobuf/types/known/timestamppb" +) + +func (postServer *PostServer) GetPosts(req *pb.GetPostsRequest, stream pb.PostService_GetPostsServer) error { + var page = req.GetPage() + var limit = req.GetLimit() + + posts, err := postServer.postService.FindPosts(int(page), int(limit)) + if err != nil { + return status.Errorf(codes.Internal, err.Error()) + } + + for _, post := range posts { + stream.Send(&pb.Post{ + Id: post.Id.Hex(), + Title: post.Title, + Content: post.Content, + Image: post.Image, + CreatedAt: timestamppb.New(post.CreateAt), + UpdatedAt: timestamppb.New(post.UpdatedAt), + }) + } + + return nil +} diff --git a/gapi/rpc_signin_user.go b/gapi/rpc_signin_user.go new file mode 100644 index 0000000..a5b6d09 --- /dev/null +++ b/gapi/rpc_signin_user.go @@ -0,0 +1,58 @@ +package gapi + +import ( + "context" + + "github.com/wpcodevo/golang-mongodb/pb" + "github.com/wpcodevo/golang-mongodb/utils" + "go.mongodb.org/mongo-driver/mongo" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/status" +) + +func (authServer *AuthServer) SignInUser(ctx context.Context, req *pb.SignInUserInput) (*pb.SignInUserResponse, error) { + user, err := authServer.userService.FindUserByEmail(req.GetEmail()) + if err != nil { + if err == mongo.ErrNoDocuments { + + return nil, status.Errorf(codes.InvalidArgument, "Invalid email or password") + + } + + return nil, status.Errorf(codes.Internal, err.Error()) + + } + + if !user.Verified { + + return nil, status.Errorf(codes.PermissionDenied, "You are not verified, please verify your email to login") + + } + + if err := utils.VerifyPassword(user.Password, req.GetPassword()); err != nil { + + return nil, status.Errorf(codes.InvalidArgument, "Invalid email or Password") + + } + + // Generate Tokens + access_token, err := utils.CreateToken(authServer.config.AccessTokenExpiresIn, user.ID, authServer.config.AccessTokenPrivateKey) + if err != nil { + + return nil, status.Errorf(codes.PermissionDenied, err.Error()) + + } + + refresh_token, err := utils.CreateToken(authServer.config.RefreshTokenExpiresIn, user.ID, authServer.config.RefreshTokenPrivateKey) + if err != nil { + return nil, status.Errorf(codes.PermissionDenied, err.Error()) + } + + res := &pb.SignInUserResponse{ + Status: "success", + AccessToken: access_token, + RefreshToken: refresh_token, + } + + return res, nil +} diff --git a/gapi/rpc_signup_user.go b/gapi/rpc_signup_user.go new file mode 100644 index 0000000..1682d7b --- /dev/null +++ b/gapi/rpc_signup_user.go @@ -0,0 +1,75 @@ +package gapi + +import ( + "context" + "strings" + + "github.com/thanhpk/randstr" + "github.com/wpcodevo/golang-mongodb/models" + "github.com/wpcodevo/golang-mongodb/pb" + "github.com/wpcodevo/golang-mongodb/utils" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/status" +) + +func (authServer *AuthServer) SignUpUser(ctx context.Context, req *pb.SignUpUserInput) (*pb.GenericResponse, error) { + if req.GetPassword() != req.GetPasswordConfirm() { + return nil, status.Errorf(codes.InvalidArgument, "passwords do not match") + } + + user := models.SignUpInput{ + Name: req.GetName(), + Email: req.GetEmail(), + Password: req.GetPassword(), + PasswordConfirm: req.GetPasswordConfirm(), + } + + newUser, err := authServer.authService.SignUpUser(&user) + + if err != nil { + if strings.Contains(err.Error(), "email already exist") { + return nil, status.Errorf(codes.AlreadyExists, "%s", err.Error()) + + } + return nil, status.Errorf(codes.Internal, "%s", err.Error()) + } + + // Generate Verification Code + code := randstr.String(20) + + verificationCode := utils.Encode(code) + + updateData := &models.UpdateInput{ + VerificationCode: verificationCode, + } + + // Update User in Database + authServer.userService.UpdateUserById(newUser.ID.Hex(), updateData) + + var firstName = newUser.Name + + if strings.Contains(firstName, " ") { + firstName = strings.Split(firstName, " ")[0] + } + + // 👇 Send Email + emailData := utils.EmailData{ + URL: authServer.config.Origin + "/verifyemail/" + code, + FirstName: firstName, + Subject: "Your account verification code", + } + + err = utils.SendEmail(newUser, &emailData, "verificationCode.html") + if err != nil { + return nil, status.Errorf(codes.Internal, "There was an error sending email: %s", err.Error()) + + } + + message := "We sent an email with a verification code to " + newUser.Email + + res := &pb.GenericResponse{ + Status: "success", + Message: message, + } + return res, nil +} diff --git a/gapi/rpc_update_post.go b/gapi/rpc_update_post.go new file mode 100644 index 0000000..cdca9ae --- /dev/null +++ b/gapi/rpc_update_post.go @@ -0,0 +1,47 @@ +package gapi + +import ( + "context" + "strings" + "time" + + "github.com/wpcodevo/golang-mongodb/models" + "github.com/wpcodevo/golang-mongodb/pb" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/status" + "google.golang.org/protobuf/types/known/timestamppb" +) + +func (postServer *PostServer) UpdatePost(ctx context.Context, req *pb.UpdatePostRequest) (*pb.PostResponse, error) { + postId := req.GetId() + + post := &models.UpdatePost{ + Title: req.GetTitle(), + Content: req.GetContent(), + Image: req.GetImage(), + User: req.GetUser(), + UpdatedAt: time.Now(), + } + + updatedPost, err := postServer.postService.UpdatePost(postId, post) + + if err != nil { + if strings.Contains(err.Error(), "Id exists") { + return nil, status.Errorf(codes.NotFound, err.Error()) + } + return nil, status.Errorf(codes.Internal, err.Error()) + } + + res := &pb.PostResponse{ + Post: &pb.Post{ + Id: updatedPost.Id.Hex(), + Title: updatedPost.Title, + Content: updatedPost.Content, + Image: updatedPost.Image, + User: updatedPost.User, + CreatedAt: timestamppb.New(updatedPost.CreateAt), + UpdatedAt: timestamppb.New(updatedPost.UpdatedAt), + }, + } + return res, nil +} diff --git a/gapi/rpc_verify_user.go b/gapi/rpc_verify_user.go new file mode 100644 index 0000000..75f675f --- /dev/null +++ b/gapi/rpc_verify_user.go @@ -0,0 +1,35 @@ +package gapi + +import ( + "context" + "time" + + "github.com/wpcodevo/golang-mongodb/pb" + "github.com/wpcodevo/golang-mongodb/utils" + "go.mongodb.org/mongo-driver/bson" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/status" +) + +func (authServer *AuthServer) VerifyEmail(ctx context.Context, req *pb.VerifyEmailRequest) (*pb.GenericResponse, error) { + code := req.GetVerificationCode() + + verificationCode := utils.Encode(code) + + query := bson.D{{Key: "verificationCode", Value: verificationCode}} + update := bson.D{{Key: "$set", Value: bson.D{{Key: "verified", Value: true}, {Key: "updated_at", Value: time.Now()}}}, {Key: "$unset", Value: bson.D{{Key: "verificationCode", Value: ""}}}} + result, err := authServer.userCollection.UpdateOne(ctx, query, update) + if err != nil { + return nil, status.Errorf(codes.Internal, err.Error()) + } + + if result.MatchedCount == 0 { + return nil, status.Errorf(codes.PermissionDenied, "Could not verify email address") + } + + res := &pb.GenericResponse{ + Status: "success", + Message: "Email verified successfully", + } + return res, nil +} diff --git a/gapi/user-server.go b/gapi/user-server.go new file mode 100644 index 0000000..3f4b3c3 --- /dev/null +++ b/gapi/user-server.go @@ -0,0 +1,25 @@ +package gapi + +import ( + "github.com/wpcodevo/golang-mongodb/config" + "github.com/wpcodevo/golang-mongodb/pb" + "github.com/wpcodevo/golang-mongodb/services" + "go.mongodb.org/mongo-driver/mongo" +) + +type UserServer struct { + pb.UnimplementedUserServiceServer + config config.Config + userService services.UserService + userCollection *mongo.Collection +} + +func NewGrpcUserServer(config config.Config, userService services.UserService, userCollection *mongo.Collection) (*UserServer, error) { + userServer := &UserServer{ + config: config, + userService: userService, + userCollection: userCollection, + } + + return userServer, nil +} diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..18ea677 --- /dev/null +++ b/go.mod @@ -0,0 +1,62 @@ +module github.com/wpcodevo/golang-mongodb + +go 1.18 + +require ( + github.com/gin-contrib/cors v1.3.1 + github.com/gin-gonic/gin v1.7.7 + github.com/go-redis/redis/v8 v8.11.5 + github.com/golang-jwt/jwt v3.2.2+incompatible + github.com/k3a/html2text v1.0.8 + github.com/spf13/viper v1.11.0 + github.com/thanhpk/randstr v1.0.4 + go.mongodb.org/mongo-driver v1.9.1 + golang.org/x/crypto v0.0.0-20220513210258-46612604a0f9 + google.golang.org/grpc v1.45.0 + google.golang.org/protobuf v1.28.0 + gopkg.in/gomail.v2 v2.0.0-20160411212932-81ebce5c23df +) + +require ( + github.com/cespare/xxhash/v2 v2.1.2 // indirect + github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect + github.com/fsnotify/fsnotify v1.5.1 // indirect + github.com/gin-contrib/sse v0.1.0 // indirect + github.com/go-playground/locales v0.14.0 // indirect + github.com/go-playground/universal-translator v0.18.0 // indirect + github.com/go-playground/validator/v10 v10.11.0 // indirect + github.com/go-stack/stack v1.8.0 // indirect + github.com/golang/protobuf v1.5.2 // indirect + github.com/golang/snappy v0.0.1 // indirect + github.com/hashicorp/hcl v1.0.0 // indirect + github.com/json-iterator/go v1.1.12 // indirect + github.com/klauspost/compress v1.13.6 // indirect + github.com/leodido/go-urn v1.2.1 // indirect + github.com/magiconair/properties v1.8.6 // indirect + github.com/mattn/go-isatty v0.0.14 // indirect + github.com/mitchellh/mapstructure v1.4.3 // indirect + github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect + github.com/modern-go/reflect2 v1.0.2 // indirect + github.com/pelletier/go-toml v1.9.4 // indirect + github.com/pelletier/go-toml/v2 v2.0.0-beta.8 // indirect + github.com/pkg/errors v0.9.1 // indirect + github.com/spf13/afero v1.8.2 // indirect + github.com/spf13/cast v1.4.1 // indirect + github.com/spf13/jwalterweatherman v1.1.0 // indirect + github.com/spf13/pflag v1.0.5 // indirect + github.com/subosito/gotenv v1.2.0 // indirect + github.com/ugorji/go/codec v1.2.7 // indirect + github.com/xdg-go/pbkdf2 v1.0.0 // indirect + github.com/xdg-go/scram v1.0.2 // indirect + github.com/xdg-go/stringprep v1.0.2 // indirect + github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d // indirect + golang.org/x/net v0.0.0-20220412020605-290c469a71a5 // indirect + golang.org/x/sync v0.0.0-20201207232520-09787c993a3a // indirect + golang.org/x/sys v0.0.0-20220513210249-45d2b4557a2a // indirect + golang.org/x/text v0.3.7 // indirect + google.golang.org/genproto v0.0.0-20220407144326-9054f6ed7bac // indirect + gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc // indirect + gopkg.in/ini.v1 v1.66.4 // indirect + gopkg.in/yaml.v2 v2.4.0 // indirect + gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b // indirect +) diff --git a/go.sum b/go.sum new file mode 100644 index 0000000..74e1f1f --- /dev/null +++ b/go.sum @@ -0,0 +1,630 @@ +cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU= +cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU= +cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY= +cloud.google.com/go v0.44.3/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY= +cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc= +cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0= +cloud.google.com/go v0.50.0/go.mod h1:r9sluTvynVuxRIOHXQEHMFffphuXHOMZMycpNR5e6To= +cloud.google.com/go v0.52.0/go.mod h1:pXajvRH/6o3+F9jDHZWQ5PbGhn+o8w9qiu/CffaVdO4= +cloud.google.com/go v0.53.0/go.mod h1:fp/UouUEsRkN6ryDKNW/Upv/JBKnv6WDthjR6+vze6M= +cloud.google.com/go v0.54.0/go.mod h1:1rq2OEkV3YMf6n/9ZvGWI3GWw0VoqH/1x2nd8Is/bPc= +cloud.google.com/go v0.56.0/go.mod h1:jr7tqZxxKOVYizybht9+26Z/gUq7tiRzu+ACVAMbKVk= +cloud.google.com/go v0.57.0/go.mod h1:oXiQ6Rzq3RAkkY7N6t3TcE6jE+CIBBbA36lwQ1JyzZs= +cloud.google.com/go v0.62.0/go.mod h1:jmCYTdRCQuc1PHIIJ/maLInMho30T/Y0M4hTdTShOYc= +cloud.google.com/go v0.65.0/go.mod h1:O5N8zS7uWy9vkA9vayVHs65eM1ubvY4h553ofrNHObY= +cloud.google.com/go v0.72.0/go.mod h1:M+5Vjvlc2wnp6tjzE102Dw08nGShTscUx2nZMufOKPI= +cloud.google.com/go v0.74.0/go.mod h1:VV1xSbzvo+9QJOxLDaJfTjx5e+MePCpCWwvftOeQmWk= +cloud.google.com/go v0.75.0/go.mod h1:VGuuCn7PG0dwsd5XPVm2Mm3wlh3EL55/79EKB6hlPTY= +cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o= +cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE= +cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc= +cloud.google.com/go/bigquery v1.5.0/go.mod h1:snEHRnqQbz117VIFhE8bmtwIDY80NLUZUMb4Nv6dBIg= +cloud.google.com/go/bigquery v1.7.0/go.mod h1://okPTzCYNXSlb24MZs83e2Do+h+VXtc4gLoIoXIAPc= +cloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM77hZzJN/fQ= +cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE= +cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk= +cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I= +cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw= +cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA= +cloud.google.com/go/pubsub v1.3.1/go.mod h1:i+ucay31+CNRpDW4Lu78I4xXG+O1r/MAHgjpRVR+TSU= +cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw= +cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos= +cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk= +cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs= +cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0= +cloud.google.com/go/storage v1.14.0/go.mod h1:GrKmX003DSIwi9o29oFT7YDnHYwZoctc3fOKtUw0Xmo= +dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= +github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= +github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= +github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY= +github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= +github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/cespare/xxhash/v2 v2.1.2 h1:YRXhKfTDauu4ajMg1TPgFO5jnlC2HCbmLXMcTG5cbYE= +github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= +github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= +github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= +github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= +github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= +github.com/cncf/udpa/go v0.0.0-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= +github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= +github.com/cncf/udpa/go v0.0.0-20210930031921-04548b0d99d4/go.mod h1:6pvJx4me5XPnfI9Z40ddWsdw2W/uZgQLFXToKeRcDiI= +github.com/cncf/xds/go v0.0.0-20210805033703-aa0b78936158/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/cncf/xds/go v0.0.0-20210922020428-25de7278fc84/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/cncf/xds/go v0.0.0-20211011173535-cb28da3451f1/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f h1:lO4WD4F/rVNCu3HqELle0jiPLLBs70cWOduZpkS1E78= +github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc= +github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= +github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= +github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= +github.com/envoyproxy/go-control-plane v0.9.7/go.mod h1:cwu0lG7PUMfa9snN8LXBig5ynNVH9qI8YYLbd1fK2po= +github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= +github.com/envoyproxy/go-control-plane v0.9.10-0.20210907150352-cf90f659a021/go.mod h1:AFq3mo9L8Lqqiid3OhADV3RfLJnjiw63cSpi+fDTRC0= +github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= +github.com/fsnotify/fsnotify v1.5.1 h1:mZcQUHVQUQWoPXXtuf9yuEXKudkV2sx1E06UadKWpgI= +github.com/fsnotify/fsnotify v1.5.1/go.mod h1:T3375wBYaZdLLcVNkcVbzGHY7f1l/uK5T5Ai1i3InKU= +github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= +github.com/gin-contrib/cors v1.3.1 h1:doAsuITavI4IOcd0Y19U4B+O0dNWihRyX//nn4sEmgA= +github.com/gin-contrib/cors v1.3.1/go.mod h1:jjEJ4268OPZUcU7k9Pm653S7lXUGcqMADzFA61xsmDk= +github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE= +github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI= +github.com/gin-gonic/gin v1.5.0/go.mod h1:Nd6IXA8m5kNZdNEHMBd93KT+mdY3+bewLgRvmCsR2Do= +github.com/gin-gonic/gin v1.7.7 h1:3DoBmSbJbZAWqXJC3SLjAPfutPJJRN1U5pALB7EeTTs= +github.com/gin-gonic/gin v1.7.7/go.mod h1:axIBovoeJpVj8S3BwE0uPMTeReE4+AfFtqpqaZ1qq1U= +github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= +github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= +github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= +github.com/go-playground/assert/v2 v2.0.1 h1:MsBgLAaY856+nPRTKrp3/OZK38U/wa0CcBYNjji3q3A= +github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4= +github.com/go-playground/locales v0.12.1/go.mod h1:IUMDtCfWo/w/mtMfIE/IG2K+Ey3ygWanZIBtBW0W2TM= +github.com/go-playground/locales v0.13.0/go.mod h1:taPMhCMXrRLJO55olJkUXHZBHCxTMfnGwq/HNwmWNS8= +github.com/go-playground/locales v0.14.0 h1:u50s323jtVGugKlcYeyzC0etD1HifMjqmJqb8WugfUU= +github.com/go-playground/locales v0.14.0/go.mod h1:sawfccIbzZTqEDETgFXqTho0QybSa7l++s0DH+LDiLs= +github.com/go-playground/universal-translator v0.16.0/go.mod h1:1AnU7NaIRDWWzGEKwgtJRd2xk99HeFyHw3yid4rvQIY= +github.com/go-playground/universal-translator v0.17.0/go.mod h1:UkSxE5sNxxRwHyU+Scu5vgOQjsIJAF8j9muTVoKLVtA= +github.com/go-playground/universal-translator v0.18.0 h1:82dyy6p4OuJq4/CByFNOn/jYrnRPArHwAcmLoJZxyho= +github.com/go-playground/universal-translator v0.18.0/go.mod h1:UvRDBj+xPUEGrFYl+lu/H90nyDXpg0fqeB/AQUGNTVA= +github.com/go-playground/validator/v10 v10.4.1/go.mod h1:nlOn6nFhuKACm19sB/8EGNn9GlaMV7XkbRSipzJ0Ii4= +github.com/go-playground/validator/v10 v10.11.0 h1:0W+xRM511GY47Yy3bZUbJVitCNg2BOGlCyvTqsp/xIw= +github.com/go-playground/validator/v10 v10.11.0/go.mod h1:i+3WkQ1FvaUjjxh1kSvIA4dMGDBiPU55YFDl0WbKdWU= +github.com/go-redis/redis/v8 v8.11.5 h1:AcZZR7igkdvfVmQTPnu9WE37LRrO/YrBH5zWyjDC0oI= +github.com/go-redis/redis/v8 v8.11.5/go.mod h1:gREzHqY1hg6oD9ngVRbLStwAWKhA0FEgq8Jd4h5lpwo= +github.com/go-stack/stack v1.8.0 h1:5SgMzNM5HxrEjV0ww2lTmX6E2Izsfxas4+YHWRs3Lsk= +github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= +github.com/golang-jwt/jwt v3.2.2+incompatible h1:IfV12K8xAKAnZqdXVzCZ+TOjboZ2keLg81eXfW3O+oY= +github.com/golang-jwt/jwt v3.2.2+incompatible/go.mod h1:8pz2t5EyA70fFQQSrl6XZXzqecmYZeUEB8OUGHkxJ+I= +github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= +github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= +github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= +github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y= +github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= +github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= +github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= +github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4= +github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= +github.com/golang/protobuf v1.3.4/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= +github.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk= +github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= +github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= +github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= +github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= +github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= +github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8= +github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= +github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= +github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= +github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw= +github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= +github.com/golang/snappy v0.0.1 h1:Qgr9rKW7uDUkrbSmQeiDsGa8SjGyCOGtuasMWwvp2P4= +github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= +github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= +github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= +github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.7 h1:81/ik6ipDQS2aGcBfIN5dHDB36BwrStyeAQquSYCV4o= +github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= +github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= +github.com/google/martian/v3 v3.1.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= +github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= +github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= +github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20201023163331-3e6fc7fc9c4c/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20201203190320-1bf35d6f28c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20201218002935-b9804c9f04c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= +github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= +github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= +github.com/googleapis/google-cloud-go-testing v0.0.0-20200911160855-bcd43fbb19e8/go.mod h1:dvDLG8qkwmyD9a/MJJN3XJcT3xFxOKAvTZGvuZmac9g= +github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1 h1:EGx4pi6eqNxGaHF6qqu48+N2wcFQ5qg5FXgOdqsJ5d8= +github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= +github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw= +github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4= +github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= +github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= +github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= +github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= +github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= +github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= +github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= +github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo= +github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= +github.com/k3a/html2text v1.0.8 h1:rVanLhKilpnJUJs/CNKWzMC4YaQINGxK0rSG8ssmnV0= +github.com/k3a/html2text v1.0.8/go.mod h1:ieEXykM67iT8lTvEWBh6fhpH4B23kB9OMKPdIBmgUqA= +github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= +github.com/klauspost/compress v1.13.6 h1:P76CopJELS0TiO2mebmnzgWaajssP/EszplttgQxcgc= +github.com/klauspost/compress v1.13.6/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk= +github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg= +github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= +github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0= +github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= +github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= +github.com/leodido/go-urn v1.1.0/go.mod h1:+cyI34gQWZcE1eQU7NVgKkkzdXDQHr1dBMtdAPozLkw= +github.com/leodido/go-urn v1.2.0/go.mod h1:+8+nEpDfqqsY+g338gtMEUOtuK+4dEMhiQEgxpxOKII= +github.com/leodido/go-urn v1.2.1 h1:BqpAaACuzVSgi/VLzGZIobT2z4v53pjosyNd9Yv6n/w= +github.com/leodido/go-urn v1.2.1/go.mod h1:zt4jvISO2HfUBqxjfIshjdMTYS56ZS/qv49ictyFfxY= +github.com/magiconair/properties v1.8.6 h1:5ibWZ6iY0NctNGWo87LalDlEZ6R41TqbbDamhfG/Qzo= +github.com/magiconair/properties v1.8.6/go.mod h1:y3VJvCyxH9uVvJTWEGAELF3aiYNyPKd5NZ3oSwXrF60= +github.com/mattn/go-isatty v0.0.9/go.mod h1:YNRxwqDuOph6SZLI9vUUz6OYw3QyUt7WiY2yME+cCiQ= +github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= +github.com/mattn/go-isatty v0.0.14 h1:yVuAays6BHfxijgZPzw+3Zlu5yQgKGP2/hcQbHb7S9Y= +github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= +github.com/mitchellh/mapstructure v1.4.3 h1:OVowDSCllw/YjdLkam3/sm7wEtOy59d8ndGgCcyj8cs= +github.com/mitchellh/mapstructure v1.4.3/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= +github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= +github.com/montanaflynn/stats v0.0.0-20171201202039-1bf9dbcd8cbe/go.mod h1:wL8QJuTMNUDYhXwkmfOly8iTdp5TEcJFWZD2D7SIkUc= +github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE= +github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE= +github.com/onsi/gomega v1.18.1 h1:M1GfJqGRrBrrGGsbxzV5dqM2U2ApXefZCQpkukxYRLE= +github.com/pelletier/go-toml v1.9.4 h1:tjENF6MfZAg8e4ZmZTeWaWiT2vXtsoO6+iuOjFhECwM= +github.com/pelletier/go-toml v1.9.4/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c= +github.com/pelletier/go-toml/v2 v2.0.0-beta.8 h1:dy81yyLYJDwMTifq24Oi/IslOslRrDSb3jwDggjz3Z0= +github.com/pelletier/go-toml/v2 v2.0.0-beta.8/go.mod h1:r9LEWfGN8R5k0VXJ+0BkIe7MYkRdwZOjgMj2KwnJFUo= +github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA= +github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= +github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/sftp v1.13.1/go.mod h1:3HaPG6Dq1ILlpPZRO0HVMrsydcdLt6HRDccSgb87qRg= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ= +github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= +github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc= +github.com/rogpeppe/go-internal v1.8.0 h1:FCbCCtXNOY3UtUuHUYaghJg4y7Fd14rXifAYUAtL9R8= +github.com/rogpeppe/go-internal v1.8.0/go.mod h1:WmiCO8CzOY8rg0OYDC4/i/2WRWAB6poM+XZ2dLUbcbE= +github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d h1:zE9ykElWQ6/NYmHa3jpm/yHnI4xSofP+UP6SpjHcSeM= +github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= +github.com/smartystreets/goconvey v1.6.4 h1:fv0U8FUIMPNf1L9lnHLvLhgicrIVChEkdzIKYqbNC9s= +github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= +github.com/spf13/afero v1.8.2 h1:xehSyVa0YnHWsJ49JFljMpg1HX19V6NDZ1fkm1Xznbo= +github.com/spf13/afero v1.8.2/go.mod h1:CtAatgMJh6bJEIs48Ay/FOnkljP3WeGUG0MC1RfAqwo= +github.com/spf13/cast v1.4.1 h1:s0hze+J0196ZfEMTs80N7UlFt0BDuQ7Q+JDnHiMWKdA= +github.com/spf13/cast v1.4.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= +github.com/spf13/jwalterweatherman v1.1.0 h1:ue6voC5bR5F8YxI5S67j9i582FU4Qvo2bmqnqMYADFk= +github.com/spf13/jwalterweatherman v1.1.0/go.mod h1:aNWZUN0dPAAO/Ljvb5BEdw96iTZ0EXowPYD95IqWIGo= +github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= +github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= +github.com/spf13/viper v1.11.0 h1:7OX/1FS6n7jHD1zGrZTM7WtY13ZELRyosK4k93oPr44= +github.com/spf13/viper v1.11.0/go.mod h1:djo0X/bA5+tYVoCn+C7cAYJGcVn/qYLFTG8gdUsX7Zk= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= +github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= +github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.1 h1:5TQK59W5E3v0r2duFAb7P95B6hEeOyEnHRa8MjYSMTY= +github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/subosito/gotenv v1.2.0 h1:Slr1R9HxAlEKefgq5jn9U+DnETlIUa6HfgEzj0g5d7s= +github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw= +github.com/thanhpk/randstr v1.0.4 h1:IN78qu/bR+My+gHCvMEXhR/i5oriVHcTB/BJJIRTsNo= +github.com/thanhpk/randstr v1.0.4/go.mod h1:M/H2P1eNLZzlDwAzpkkkUvoyNNMbzRGhESZuEQk3r0U= +github.com/tidwall/pretty v1.0.0 h1:HsD+QiTn7sK6flMKIvNmpqz1qrpP3Ps6jOKIKMooyg4= +github.com/tidwall/pretty v1.0.0/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk= +github.com/ugorji/go v1.1.7/go.mod h1:kZn38zHttfInRq0xu/PH0az30d+z6vm202qpg1oXVMw= +github.com/ugorji/go v1.2.7/go.mod h1:nF9osbDWLy6bDVv/Rtoh6QgnvNDpmCalQV5urGCCS6M= +github.com/ugorji/go/codec v1.1.7/go.mod h1:Ax+UKWsSmolVDwsd+7N3ZtXu+yMGCf907BLYF3GoBXY= +github.com/ugorji/go/codec v1.2.7 h1:YPXUKf7fYbp/y8xloBqZOw2qaVggbfwMlI8WM3wZUJ0= +github.com/ugorji/go/codec v1.2.7/go.mod h1:WGN1fab3R1fzQlVQTkfxVtIBhWDRqOviHU95kRgeqEY= +github.com/xdg-go/pbkdf2 v1.0.0 h1:Su7DPu48wXMwC3bs7MCNG+z4FhcyEuz5dlvchbq0B0c= +github.com/xdg-go/pbkdf2 v1.0.0/go.mod h1:jrpuAogTd400dnrH08LKmI/xc1MbPOebTwRqcT5RDeI= +github.com/xdg-go/scram v1.0.2 h1:akYIkZ28e6A96dkWNJQu3nmCzH3YfwMPQExUYDaRv7w= +github.com/xdg-go/scram v1.0.2/go.mod h1:1WAq6h33pAW+iRreB34OORO2Nf7qel3VV3fjBj+hCSs= +github.com/xdg-go/stringprep v1.0.2 h1:6iq84/ryjjeRmMJwxutI51F2GIPlP5BfTvXHeYjyhBc= +github.com/xdg-go/stringprep v1.0.2/go.mod h1:8F9zXuvzgwmyT5DUm4GUfZGDdT3W+LCvS6+da4O5kxM= +github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d h1:splanxYIlg+5LfHAM6xpdFEAYOk8iySO56hMFq6uLyA= +github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d/go.mod h1:rHwXgn7JulP+udvsHwJoVG1YGAP6VLg4y9I5dyZdqmA= +github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +go.mongodb.org/mongo-driver v1.9.1 h1:m078y9v7sBItkt1aaoe2YlvWEXcD263e1a4E1fBrJ1c= +go.mongodb.org/mongo-driver v1.9.1/go.mod h1:0sQWfOeY63QTntERDJJ/0SuKK0T1uVSgKCuAROlKEPY= +go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= +go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= +go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= +go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= +go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= +go.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk= +go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20201216223049-8b5274cf687f/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I= +golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= +golang.org/x/crypto v0.0.0-20211108221036-ceb1ce70b4fa/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= +golang.org/x/crypto v0.0.0-20211215153901-e495a2d5b3d3/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= +golang.org/x/crypto v0.0.0-20220513210258-46612604a0f9 h1:NUzdAbFtCJSXU20AOXgeqaUwg8Ypg4MPYmL+d+rsB5c= +golang.org/x/crypto v0.0.0-20220513210258-46612604a0f9/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= +golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= +golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek= +golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY= +golang.org/x/exp v0.0.0-20191129062945-2f5052295587/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= +golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= +golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= +golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM= +golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU= +golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= +golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= +golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= +golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= +golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= +golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs= +golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= +golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= +golang.org/x/lint v0.0.0-20201208152925-83fdc39ff7b5/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= +golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE= +golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o= +golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= +golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY= +golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= +golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= +golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= +golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200222125558-5a598a2470a0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200501053045-e0ff5e5a1de5/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200506145744-7e3656a0809f/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200513185701-a91f0712d120/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= +golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= +golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= +golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20201031054903-ff519b6c9102/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20201209123823-ac852fbbde11/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20201224014010-6772e930b67b/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= +golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20220412020605-290c469a71a5 h1:bRb386wvrE+oBNdF1d/Xh9mQrfQ4ecYhW5qJ5GvTGT4= +golang.org/x/net v0.0.0-20220412020605-290c469a71a5/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= +golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= +golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20200902213428-5d25da1a8d43/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20201109201403-9fd604954f58/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20201208152858-08078c50e5b5/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210218202405-ba52d332ba99/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20201207232520-09787c993a3a h1:DcqTD9SDLc+1P/r1EmRBwnVsrOwW+kk2vWf9n+1sGhs= +golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200331124033-c3d80250170d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200501052902-10377860bb8e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200511232937-7e40ca221e25/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200905004654-be1d3432aa8f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201201145000-ef89a241ccb3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210104204734-6f8348627aad/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210225134936-a50acf3fe073/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210423185535-09eb48e85fd7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210806184541-e5e7981a1069/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220513210249-45d2b4557a2a h1:N2T1jUrTQE9Re6TFF5PhvEHXHCguynGhKjWVsIUt5cY= +golang.org/x/sys v0.0.0-20220513210249-45d2b4557a2a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= +golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= +golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= +golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk= +golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= +golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= +golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190531172133-b3315ee88b7d/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191130070609-6e064ea0cf2d/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200117161641-43d50277825c/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200122220014-bf1340f18c4a/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200204074204-1cc6d1ef6c74/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200207183749-b753a1ba74fa/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200212150539-ea181f53ac56/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200224181240-023911ca70b2/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200227222343-706bc42d1f0d/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200304193943-95d2e580d8eb/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= +golang.org/x/tools v0.0.0-20200312045724-11d5b4c81c7d/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= +golang.org/x/tools v0.0.0-20200331025713-a30bf2db82d4/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8= +golang.org/x/tools v0.0.0-20200501065659-ab2804fb9c9d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200512131952-2bc93b1c0c88/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200515010526-7d3b6ebf133d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200618134242-20370b0cb4b2/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200729194436-6467de6f59a7/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= +golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= +golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= +golang.org/x/tools v0.0.0-20200904185747-39188db58858/go.mod h1:Cj7w3i3Rnn0Xh82ur9kSqwfTHTeVxaDqrfMjpcNT6bE= +golang.org/x/tools v0.0.0-20201110124207-079ba7bd75cd/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20201201161351-ac6f37ff4c2a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20201208233053-a543418bbed2/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20210105154028-b0ab187a4818/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20210108195828-e2f9c7f1fc8e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= +golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20220411194840-2f41105eb62f h1:GGU+dLjvlC3qDwqYgL6UgRmHXhOOgns0bZu2Ty5mm6U= +google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= +google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M= +google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= +google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= +google.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= +google.golang.org/api v0.14.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= +google.golang.org/api v0.15.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= +google.golang.org/api v0.17.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.18.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.19.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.20.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.22.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.24.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= +google.golang.org/api v0.28.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= +google.golang.org/api v0.29.0/go.mod h1:Lcubydp8VUV7KeIHD9z2Bys/sm/vGKnG1UHuDBSrHWM= +google.golang.org/api v0.30.0/go.mod h1:QGmEvQ87FHZNiUVJkT14jQNYJ4ZJjdRF23ZXz5138Fc= +google.golang.org/api v0.35.0/go.mod h1:/XrVsuzM0rZmrsbjJutiuftIzeuTQcEeaYcSk/mQ1dg= +google.golang.org/api v0.36.0/go.mod h1:+z5ficQTmoYpPn8LCUNVpK5I7hwkpjbcgqA7I34qYtE= +google.golang.org/api v0.40.0/go.mod h1:fYKFpnQN0DsDSKRVRcQSDQNtqWPfM9i+zNPxepjRCQ8= +google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= +google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= +google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= +google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= +google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= +google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= +google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= +google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= +google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= +google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= +google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8= +google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20191115194625-c23dd37a84c9/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20191216164720-4f79533eabd1/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20191230161307-f3c370f40bfb/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20200115191322-ca5a22157cba/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20200122232147-0452cf42e150/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20200204135345-fa8e72b47b90/go.mod h1:GmwEX6Z4W5gMy59cAlVYjN9JhxgbQH6Gn+gFDQe2lzA= +google.golang.org/genproto v0.0.0-20200212174721-66ed5ce911ce/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200224152610-e50cd9704f63/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200228133532-8c2c7df3a383/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200305110556-506484158171/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200312145019-da6875a35672/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200331122359-1ee6d9798940/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200430143042-b979b6f78d84/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200511104702-f5ebc3bea380/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200513103714-09dca8ec2884/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200515170657-fc4c6c6a6587/go.mod h1:YsZOwe1myG/8QRHRsmBRE1LrgQY60beZKjly0O1fX9U= +google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= +google.golang.org/genproto v0.0.0-20200618031413-b414f8b61790/go.mod h1:jDfRM7FcilCzHH/e9qn6dsT145K34l5v+OpcnNgKAAA= +google.golang.org/genproto v0.0.0-20200729003335-053ba62fc06f/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20200804131852-c06518451d9c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20200904004341-0bd0a958aa1d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20201109203340-2640f1f9cdfb/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20201201144952-b05cb90ed32e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20201210142538-e3217bee35cc/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20201214200347-8c77b98c765d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210108203827-ffc7fda8c3d7/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210226172003-ab064af71705/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20220407144326-9054f6ed7bac h1:qSNTkEN+L2mvWcLgJOR+8bdHX9rN/IdU3A1Ghpfb1Rg= +google.golang.org/genproto v0.0.0-20220407144326-9054f6ed7bac/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo= +google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= +google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= +google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= +google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= +google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= +google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/grpc v1.28.0/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKal+60= +google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk= +google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= +google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= +google.golang.org/grpc v1.31.1/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= +google.golang.org/grpc v1.33.1/go.mod h1:fr5YgcSWrqhRRxogOsw7RzIpsmvOZ6IcH4kBYTpR3n0= +google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc= +google.golang.org/grpc v1.34.0/go.mod h1:WotjhfgOW/POjDeRt8vscBtXq+2VjORFy659qA51WJ8= +google.golang.org/grpc v1.35.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= +google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= +google.golang.org/grpc v1.45.0 h1:NEpgUqV3Z+ZjkqMsxMg11IaDrXY4RY6CQukSGK0uI1M= +google.golang.org/grpc v1.45.0/go.mod h1:lN7owxKUQEqMfSyQikvvk5tf/6zMPsrK+ONuO11+0rQ= +google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= +google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= +google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= +google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= +google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= +google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4= +google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= +google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= +google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= +google.golang.org/protobuf v1.28.0 h1:w43yiav+6bVFTBQFZX0r7ipe9JQ1QsbMgHwbBziscLw= +google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc h1:2gGKlE2+asNV9m7xrywl36YYNnBG5ZQ0r/BOOxqPpmk= +gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc/go.mod h1:m7x9LTH6d71AHyAX77c9yqWCCa3UKHcVEj9y7hAtKDk= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= +gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= +gopkg.in/go-playground/assert.v1 v1.2.1/go.mod h1:9RXL0bg/zibRAgZUYszZSwO/z8Y/a8bDuhia5mkpMnE= +gopkg.in/go-playground/validator.v9 v9.29.1/go.mod h1:+c9/zcJMFNgbLvly1L1V+PpxWdVbfP1avr/N00E2vyQ= +gopkg.in/gomail.v2 v2.0.0-20160411212932-81ebce5c23df h1:n7WqCuqOuCbNr617RXOY0AWRXxgwEyPp2z+p0+hgMuE= +gopkg.in/gomail.v2 v2.0.0-20160411212932-81ebce5c23df/go.mod h1:LRQQ+SO6ZHR7tOkpBDuZnXENFzX8qRjMDMyPD6BRkCw= +gopkg.in/ini.v1 v1.66.4 h1:SsAcf+mM7mRZo2nJNGt8mZCjG8ZRaNGMURJw7BsIST4= +gopkg.in/ini.v1 v1.66.4/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= +gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= +gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo= +gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= +honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= +honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= +rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= +rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= +rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= diff --git a/middleware/deserialize-user.go b/middleware/deserialize-user.go new file mode 100644 index 0000000..77c6602 --- /dev/null +++ b/middleware/deserialize-user.go @@ -0,0 +1,49 @@ +package middleware + +import ( + "fmt" + "net/http" + "strings" + + "github.com/gin-gonic/gin" + "github.com/wpcodevo/golang-mongodb/config" + "github.com/wpcodevo/golang-mongodb/services" + "github.com/wpcodevo/golang-mongodb/utils" +) + +func DeserializeUser(userService services.UserService) gin.HandlerFunc { + return func(ctx *gin.Context) { + var access_token string + cookie, err := ctx.Cookie("access_token") + + authorizationHeader := ctx.Request.Header.Get("Authorization") + fields := strings.Fields(authorizationHeader) + + if len(fields) != 0 && fields[0] == "Bearer" { + access_token = fields[1] + } else if err == nil { + access_token = cookie + } + + if access_token == "" { + ctx.AbortWithStatusJSON(http.StatusUnauthorized, gin.H{"status": "fail", "message": "You are not logged in"}) + return + } + + config, _ := config.LoadConfig(".") + sub, err := utils.ValidateToken(access_token, config.AccessTokenPublicKey) + if err != nil { + ctx.AbortWithStatusJSON(http.StatusUnauthorized, gin.H{"status": "fail", "message": err.Error()}) + return + } + + user, err := userService.FindUserById(fmt.Sprint(sub)) + if err != nil { + ctx.AbortWithStatusJSON(http.StatusUnauthorized, gin.H{"status": "fail", "message": "The user belonging to this token no logger exists"}) + return + } + + ctx.Set("currentUser", user) + ctx.Next() + } +} diff --git a/models/post.model.go b/models/post.model.go new file mode 100644 index 0000000..3bf6e6a --- /dev/null +++ b/models/post.model.go @@ -0,0 +1,35 @@ +package models + +import ( + "time" + + "go.mongodb.org/mongo-driver/bson/primitive" +) + +type CreatePostRequest struct { + Title string `json:"title" bson:"title" binding:"required"` + Content string `json:"content" bson:"content" binding:"required"` + Image string `json:"image,omitempty" bson:"image,omitempty"` + User string `json:"user" bson:"user" binding:"required"` + CreateAt time.Time `json:"created_at,omitempty" bson:"created_at,omitempty"` + UpdatedAt time.Time `json:"updated_at,omitempty" bson:"updated_at,omitempty"` +} + +type DBPost struct { + Id primitive.ObjectID `json:"id,omitempty" bson:"_id,omitempty"` + Title string `json:"title,omitempty" bson:"title,omitempty"` + Content string `json:"content,omitempty" bson:"content,omitempty"` + Image string `json:"image,omitempty" bson:"image,omitempty"` + User string `json:"user,omitempty" bson:"user,omitempty"` + CreateAt time.Time `json:"created_at,omitempty" bson:"created_at,omitempty"` + UpdatedAt time.Time `json:"updated_at,omitempty" bson:"updated_at,omitempty"` +} + +type UpdatePost struct { + Title string `json:"title,omitempty" bson:"title,omitempty"` + Content string `json:"content,omitempty" bson:"content,omitempty"` + Image string `json:"image,omitempty" bson:"image,omitempty"` + User string `json:"user,omitempty" bson:"user,omitempty"` + CreateAt time.Time `json:"created_at,omitempty" bson:"created_at,omitempty"` + UpdatedAt time.Time `json:"updated_at,omitempty" bson:"updated_at,omitempty"` +} diff --git a/models/user.model.go b/models/user.model.go new file mode 100644 index 0000000..690f287 --- /dev/null +++ b/models/user.model.go @@ -0,0 +1,89 @@ +package models + +import ( + "time" + + "go.mongodb.org/mongo-driver/bson/primitive" +) + +// 👈 SignUpInput struct +type SignUpInput struct { + Name string `json:"name" bson:"name" binding:"required"` + Email string `json:"email" bson:"email" binding:"required"` + Password string `json:"password" bson:"password" binding:"required,min=8"` + PasswordConfirm string `json:"passwordConfirm" bson:"passwordConfirm,omitempty" binding:"required"` + Role string `json:"role" bson:"role"` + VerificationCode string `json:"verificationCode,omitempty" bson:"verificationCode,omitempty"` + ResetPasswordToken string `json:"resetPasswordToken,omitempty" bson:"resetPasswordToken,omitempty"` + ResetPasswordAt time.Time `json:"resetPasswordAt,omitempty" bson:"resetPasswordAt,omitempty"` + Verified bool `json:"verified" bson:"verified"` + CreatedAt time.Time `json:"created_at" bson:"created_at"` + UpdatedAt time.Time `json:"updated_at" bson:"updated_at"` +} + +// 👈 SignInInput struct +type SignInInput struct { + Email string `json:"email" bson:"email" binding:"required"` + Password string `json:"password" bson:"password" binding:"required"` +} + +// 👈 DBResponse struct +type DBResponse struct { + ID primitive.ObjectID `json:"id" bson:"_id"` + Name string `json:"name" bson:"name"` + Email string `json:"email" bson:"email"` + Password string `json:"password" bson:"password"` + PasswordConfirm string `json:"passwordConfirm,omitempty" bson:"passwordConfirm,omitempty"` + Role string `json:"role" bson:"role"` + VerificationCode string `json:"verificationCode,omitempty" bson:"verificationCode"` + ResetPasswordToken string `json:"resetPasswordToken,omitempty" bson:"resetPasswordToken,omitempty"` + ResetPasswordAt time.Time `json:"resetPasswordAt,omitempty" bson:"resetPasswordAt,omitempty"` + Verified bool `json:"verified" bson:"verified"` + CreatedAt time.Time `json:"created_at" bson:"created_at"` + UpdatedAt time.Time `json:"updated_at" bson:"updated_at"` +} + +type UpdateInput struct { + Name string `json:"name,omitempty" bson:"name,omitempty"` + Email string `json:"email,omitempty" bson:"email,omitempty"` + Password string `json:"password,omitempty" bson:"password,omitempty"` + Role string `json:"role,omitempty" bson:"role,omitempty"` + VerificationCode string `json:"verificationCode,omitempty" bson:"verificationCode,omitempty"` + ResetPasswordToken string `json:"resetPasswordToken,omitempty" bson:"resetPasswordToken,omitempty"` + ResetPasswordAt time.Time `json:"resetPasswordAt,omitempty" bson:"resetPasswordAt,omitempty"` + Verified bool `json:"verified,omitempty" bson:"verified,omitempty"` + CreatedAt time.Time `json:"created_at,omitempty" bson:"created_at,omitempty"` + UpdatedAt time.Time `json:"updated_at,omitempty" bson:"updated_at,omitempty"` +} + +// 👈 UserResponse struct +type UserResponse struct { + ID primitive.ObjectID `json:"id,omitempty" bson:"_id,omitempty"` + Name string `json:"name,omitempty" bson:"name,omitempty"` + Email string `json:"email,omitempty" bson:"email,omitempty"` + Role string `json:"role,omitempty" bson:"role,omitempty"` + CreatedAt time.Time `json:"created_at" bson:"created_at"` + UpdatedAt time.Time `json:"updated_at" bson:"updated_at"` +} + +// 👈 ForgotPasswordInput struct +type ForgotPasswordInput struct { + Email string `json:"email" bson:"email" binding:"required"` +} + +// 👈 ResetPasswordInput struct +type ResetPasswordInput struct { + Password string `json:"password" bson:"password"` + PasswordConfirm string `json:"passwordConfirm,omitempty" bson:"passwordConfirm,omitempty"` +} + +func FilteredResponse(user *DBResponse) UserResponse { + return UserResponse{ + ID: user.ID, + Email: user.Email, + Name: user.Name, + Role: user.Role, + CreatedAt: user.CreatedAt, + UpdatedAt: user.UpdatedAt, + } +} diff --git a/pb/auth_service.pb.go b/pb/auth_service.pb.go new file mode 100644 index 0000000..4a5a984 --- /dev/null +++ b/pb/auth_service.pb.go @@ -0,0 +1,174 @@ +// Code generated by protoc-gen-go. DO NOT EDIT. +// versions: +// protoc-gen-go v1.28.0 +// protoc v3.20.1 +// source: auth_service.proto + +package pb + +import ( + protoreflect "google.golang.org/protobuf/reflect/protoreflect" + protoimpl "google.golang.org/protobuf/runtime/protoimpl" + reflect "reflect" + sync "sync" +) + +const ( + // Verify that this generated code is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) + // Verify that runtime/protoimpl is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) +) + +type VerifyEmailRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + VerificationCode string `protobuf:"bytes,1,opt,name=verificationCode,proto3" json:"verificationCode,omitempty"` +} + +func (x *VerifyEmailRequest) Reset() { + *x = VerifyEmailRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_auth_service_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *VerifyEmailRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*VerifyEmailRequest) ProtoMessage() {} + +func (x *VerifyEmailRequest) ProtoReflect() protoreflect.Message { + mi := &file_auth_service_proto_msgTypes[0] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use VerifyEmailRequest.ProtoReflect.Descriptor instead. +func (*VerifyEmailRequest) Descriptor() ([]byte, []int) { + return file_auth_service_proto_rawDescGZIP(), []int{0} +} + +func (x *VerifyEmailRequest) GetVerificationCode() string { + if x != nil { + return x.VerificationCode + } + return "" +} + +var File_auth_service_proto protoreflect.FileDescriptor + +var file_auth_service_proto_rawDesc = []byte{ + 0x0a, 0x12, 0x61, 0x75, 0x74, 0x68, 0x5f, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x70, + 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x02, 0x70, 0x62, 0x1a, 0x15, 0x72, 0x70, 0x63, 0x5f, 0x73, 0x69, + 0x67, 0x6e, 0x69, 0x6e, 0x5f, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, + 0x15, 0x72, 0x70, 0x63, 0x5f, 0x73, 0x69, 0x67, 0x6e, 0x75, 0x70, 0x5f, 0x75, 0x73, 0x65, 0x72, + 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x0a, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x70, 0x72, 0x6f, + 0x74, 0x6f, 0x22, 0x40, 0x0a, 0x12, 0x56, 0x65, 0x72, 0x69, 0x66, 0x79, 0x45, 0x6d, 0x61, 0x69, + 0x6c, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x2a, 0x0a, 0x10, 0x76, 0x65, 0x72, 0x69, + 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x43, 0x6f, 0x64, 0x65, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x10, 0x76, 0x65, 0x72, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, + 0x43, 0x6f, 0x64, 0x65, 0x32, 0xc2, 0x01, 0x0a, 0x0b, 0x41, 0x75, 0x74, 0x68, 0x53, 0x65, 0x72, + 0x76, 0x69, 0x63, 0x65, 0x12, 0x38, 0x0a, 0x0a, 0x53, 0x69, 0x67, 0x6e, 0x55, 0x70, 0x55, 0x73, + 0x65, 0x72, 0x12, 0x13, 0x2e, 0x70, 0x62, 0x2e, 0x53, 0x69, 0x67, 0x6e, 0x55, 0x70, 0x55, 0x73, + 0x65, 0x72, 0x49, 0x6e, 0x70, 0x75, 0x74, 0x1a, 0x13, 0x2e, 0x70, 0x62, 0x2e, 0x47, 0x65, 0x6e, + 0x65, 0x72, 0x69, 0x63, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x3b, + 0x0a, 0x0a, 0x53, 0x69, 0x67, 0x6e, 0x49, 0x6e, 0x55, 0x73, 0x65, 0x72, 0x12, 0x13, 0x2e, 0x70, + 0x62, 0x2e, 0x53, 0x69, 0x67, 0x6e, 0x49, 0x6e, 0x55, 0x73, 0x65, 0x72, 0x49, 0x6e, 0x70, 0x75, + 0x74, 0x1a, 0x16, 0x2e, 0x70, 0x62, 0x2e, 0x53, 0x69, 0x67, 0x6e, 0x49, 0x6e, 0x55, 0x73, 0x65, + 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x3c, 0x0a, 0x0b, 0x56, + 0x65, 0x72, 0x69, 0x66, 0x79, 0x45, 0x6d, 0x61, 0x69, 0x6c, 0x12, 0x16, 0x2e, 0x70, 0x62, 0x2e, + 0x56, 0x65, 0x72, 0x69, 0x66, 0x79, 0x45, 0x6d, 0x61, 0x69, 0x6c, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x1a, 0x13, 0x2e, 0x70, 0x62, 0x2e, 0x47, 0x65, 0x6e, 0x65, 0x72, 0x69, 0x63, 0x52, + 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x42, 0x27, 0x5a, 0x25, 0x67, 0x69, 0x74, + 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x77, 0x70, 0x63, 0x6f, 0x64, 0x65, 0x76, 0x6f, + 0x2f, 0x67, 0x6f, 0x6c, 0x61, 0x6e, 0x67, 0x2d, 0x6d, 0x6f, 0x6e, 0x67, 0x6f, 0x64, 0x62, 0x2f, + 0x70, 0x62, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, +} + +var ( + file_auth_service_proto_rawDescOnce sync.Once + file_auth_service_proto_rawDescData = file_auth_service_proto_rawDesc +) + +func file_auth_service_proto_rawDescGZIP() []byte { + file_auth_service_proto_rawDescOnce.Do(func() { + file_auth_service_proto_rawDescData = protoimpl.X.CompressGZIP(file_auth_service_proto_rawDescData) + }) + return file_auth_service_proto_rawDescData +} + +var file_auth_service_proto_msgTypes = make([]protoimpl.MessageInfo, 1) +var file_auth_service_proto_goTypes = []interface{}{ + (*VerifyEmailRequest)(nil), // 0: pb.VerifyEmailRequest + (*SignUpUserInput)(nil), // 1: pb.SignUpUserInput + (*SignInUserInput)(nil), // 2: pb.SignInUserInput + (*GenericResponse)(nil), // 3: pb.GenericResponse + (*SignInUserResponse)(nil), // 4: pb.SignInUserResponse +} +var file_auth_service_proto_depIdxs = []int32{ + 1, // 0: pb.AuthService.SignUpUser:input_type -> pb.SignUpUserInput + 2, // 1: pb.AuthService.SignInUser:input_type -> pb.SignInUserInput + 0, // 2: pb.AuthService.VerifyEmail:input_type -> pb.VerifyEmailRequest + 3, // 3: pb.AuthService.SignUpUser:output_type -> pb.GenericResponse + 4, // 4: pb.AuthService.SignInUser:output_type -> pb.SignInUserResponse + 3, // 5: pb.AuthService.VerifyEmail:output_type -> pb.GenericResponse + 3, // [3:6] is the sub-list for method output_type + 0, // [0:3] is the sub-list for method input_type + 0, // [0:0] is the sub-list for extension type_name + 0, // [0:0] is the sub-list for extension extendee + 0, // [0:0] is the sub-list for field type_name +} + +func init() { file_auth_service_proto_init() } +func file_auth_service_proto_init() { + if File_auth_service_proto != nil { + return + } + file_rpc_signin_user_proto_init() + file_rpc_signup_user_proto_init() + file_user_proto_init() + if !protoimpl.UnsafeEnabled { + file_auth_service_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*VerifyEmailRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + } + type x struct{} + out := protoimpl.TypeBuilder{ + File: protoimpl.DescBuilder{ + GoPackagePath: reflect.TypeOf(x{}).PkgPath(), + RawDescriptor: file_auth_service_proto_rawDesc, + NumEnums: 0, + NumMessages: 1, + NumExtensions: 0, + NumServices: 1, + }, + GoTypes: file_auth_service_proto_goTypes, + DependencyIndexes: file_auth_service_proto_depIdxs, + MessageInfos: file_auth_service_proto_msgTypes, + }.Build() + File_auth_service_proto = out.File + file_auth_service_proto_rawDesc = nil + file_auth_service_proto_goTypes = nil + file_auth_service_proto_depIdxs = nil +} diff --git a/pb/auth_service_grpc.pb.go b/pb/auth_service_grpc.pb.go new file mode 100644 index 0000000..32facb3 --- /dev/null +++ b/pb/auth_service_grpc.pb.go @@ -0,0 +1,177 @@ +// Code generated by protoc-gen-go-grpc. DO NOT EDIT. +// versions: +// - protoc-gen-go-grpc v1.2.0 +// - protoc v3.20.1 +// source: auth_service.proto + +package pb + +import ( + context "context" + grpc "google.golang.org/grpc" + codes "google.golang.org/grpc/codes" + status "google.golang.org/grpc/status" +) + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the grpc package it is being compiled against. +// Requires gRPC-Go v1.32.0 or later. +const _ = grpc.SupportPackageIsVersion7 + +// AuthServiceClient is the client API for AuthService service. +// +// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream. +type AuthServiceClient interface { + SignUpUser(ctx context.Context, in *SignUpUserInput, opts ...grpc.CallOption) (*GenericResponse, error) + SignInUser(ctx context.Context, in *SignInUserInput, opts ...grpc.CallOption) (*SignInUserResponse, error) + VerifyEmail(ctx context.Context, in *VerifyEmailRequest, opts ...grpc.CallOption) (*GenericResponse, error) +} + +type authServiceClient struct { + cc grpc.ClientConnInterface +} + +func NewAuthServiceClient(cc grpc.ClientConnInterface) AuthServiceClient { + return &authServiceClient{cc} +} + +func (c *authServiceClient) SignUpUser(ctx context.Context, in *SignUpUserInput, opts ...grpc.CallOption) (*GenericResponse, error) { + out := new(GenericResponse) + err := c.cc.Invoke(ctx, "/pb.AuthService/SignUpUser", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *authServiceClient) SignInUser(ctx context.Context, in *SignInUserInput, opts ...grpc.CallOption) (*SignInUserResponse, error) { + out := new(SignInUserResponse) + err := c.cc.Invoke(ctx, "/pb.AuthService/SignInUser", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *authServiceClient) VerifyEmail(ctx context.Context, in *VerifyEmailRequest, opts ...grpc.CallOption) (*GenericResponse, error) { + out := new(GenericResponse) + err := c.cc.Invoke(ctx, "/pb.AuthService/VerifyEmail", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +// AuthServiceServer is the server API for AuthService service. +// All implementations must embed UnimplementedAuthServiceServer +// for forward compatibility +type AuthServiceServer interface { + SignUpUser(context.Context, *SignUpUserInput) (*GenericResponse, error) + SignInUser(context.Context, *SignInUserInput) (*SignInUserResponse, error) + VerifyEmail(context.Context, *VerifyEmailRequest) (*GenericResponse, error) + mustEmbedUnimplementedAuthServiceServer() +} + +// UnimplementedAuthServiceServer must be embedded to have forward compatible implementations. +type UnimplementedAuthServiceServer struct { +} + +func (UnimplementedAuthServiceServer) SignUpUser(context.Context, *SignUpUserInput) (*GenericResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method SignUpUser not implemented") +} +func (UnimplementedAuthServiceServer) SignInUser(context.Context, *SignInUserInput) (*SignInUserResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method SignInUser not implemented") +} +func (UnimplementedAuthServiceServer) VerifyEmail(context.Context, *VerifyEmailRequest) (*GenericResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method VerifyEmail not implemented") +} +func (UnimplementedAuthServiceServer) mustEmbedUnimplementedAuthServiceServer() {} + +// UnsafeAuthServiceServer may be embedded to opt out of forward compatibility for this service. +// Use of this interface is not recommended, as added methods to AuthServiceServer will +// result in compilation errors. +type UnsafeAuthServiceServer interface { + mustEmbedUnimplementedAuthServiceServer() +} + +func RegisterAuthServiceServer(s grpc.ServiceRegistrar, srv AuthServiceServer) { + s.RegisterService(&AuthService_ServiceDesc, srv) +} + +func _AuthService_SignUpUser_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(SignUpUserInput) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(AuthServiceServer).SignUpUser(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/pb.AuthService/SignUpUser", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(AuthServiceServer).SignUpUser(ctx, req.(*SignUpUserInput)) + } + return interceptor(ctx, in, info, handler) +} + +func _AuthService_SignInUser_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(SignInUserInput) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(AuthServiceServer).SignInUser(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/pb.AuthService/SignInUser", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(AuthServiceServer).SignInUser(ctx, req.(*SignInUserInput)) + } + return interceptor(ctx, in, info, handler) +} + +func _AuthService_VerifyEmail_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(VerifyEmailRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(AuthServiceServer).VerifyEmail(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/pb.AuthService/VerifyEmail", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(AuthServiceServer).VerifyEmail(ctx, req.(*VerifyEmailRequest)) + } + return interceptor(ctx, in, info, handler) +} + +// AuthService_ServiceDesc is the grpc.ServiceDesc for AuthService service. +// It's only intended for direct use with grpc.RegisterService, +// and not to be introspected or modified (even as a copy) +var AuthService_ServiceDesc = grpc.ServiceDesc{ + ServiceName: "pb.AuthService", + HandlerType: (*AuthServiceServer)(nil), + Methods: []grpc.MethodDesc{ + { + MethodName: "SignUpUser", + Handler: _AuthService_SignUpUser_Handler, + }, + { + MethodName: "SignInUser", + Handler: _AuthService_SignInUser_Handler, + }, + { + MethodName: "VerifyEmail", + Handler: _AuthService_VerifyEmail_Handler, + }, + }, + Streams: []grpc.StreamDesc{}, + Metadata: "auth_service.proto", +} diff --git a/pb/post.pb.go b/pb/post.pb.go new file mode 100644 index 0000000..48d7ca4 --- /dev/null +++ b/pb/post.pb.go @@ -0,0 +1,273 @@ +// Code generated by protoc-gen-go. DO NOT EDIT. +// versions: +// protoc-gen-go v1.28.0 +// protoc v3.20.1 +// source: post.proto + +package pb + +import ( + protoreflect "google.golang.org/protobuf/reflect/protoreflect" + protoimpl "google.golang.org/protobuf/runtime/protoimpl" + timestamppb "google.golang.org/protobuf/types/known/timestamppb" + reflect "reflect" + sync "sync" +) + +const ( + // Verify that this generated code is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) + // Verify that runtime/protoimpl is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) +) + +type Post struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Id string `protobuf:"bytes,1,opt,name=Id,proto3" json:"Id,omitempty"` + Title string `protobuf:"bytes,2,opt,name=Title,proto3" json:"Title,omitempty"` + Content string `protobuf:"bytes,3,opt,name=Content,proto3" json:"Content,omitempty"` + Image string `protobuf:"bytes,4,opt,name=Image,proto3" json:"Image,omitempty"` + User string `protobuf:"bytes,5,opt,name=User,proto3" json:"User,omitempty"` + CreatedAt *timestamppb.Timestamp `protobuf:"bytes,6,opt,name=created_at,json=createdAt,proto3" json:"created_at,omitempty"` + UpdatedAt *timestamppb.Timestamp `protobuf:"bytes,7,opt,name=updated_at,json=updatedAt,proto3" json:"updated_at,omitempty"` +} + +func (x *Post) Reset() { + *x = Post{} + if protoimpl.UnsafeEnabled { + mi := &file_post_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *Post) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Post) ProtoMessage() {} + +func (x *Post) ProtoReflect() protoreflect.Message { + mi := &file_post_proto_msgTypes[0] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use Post.ProtoReflect.Descriptor instead. +func (*Post) Descriptor() ([]byte, []int) { + return file_post_proto_rawDescGZIP(), []int{0} +} + +func (x *Post) GetId() string { + if x != nil { + return x.Id + } + return "" +} + +func (x *Post) GetTitle() string { + if x != nil { + return x.Title + } + return "" +} + +func (x *Post) GetContent() string { + if x != nil { + return x.Content + } + return "" +} + +func (x *Post) GetImage() string { + if x != nil { + return x.Image + } + return "" +} + +func (x *Post) GetUser() string { + if x != nil { + return x.User + } + return "" +} + +func (x *Post) GetCreatedAt() *timestamppb.Timestamp { + if x != nil { + return x.CreatedAt + } + return nil +} + +func (x *Post) GetUpdatedAt() *timestamppb.Timestamp { + if x != nil { + return x.UpdatedAt + } + return nil +} + +type PostResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Post *Post `protobuf:"bytes,1,opt,name=post,proto3" json:"post,omitempty"` +} + +func (x *PostResponse) Reset() { + *x = PostResponse{} + if protoimpl.UnsafeEnabled { + mi := &file_post_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *PostResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*PostResponse) ProtoMessage() {} + +func (x *PostResponse) ProtoReflect() protoreflect.Message { + mi := &file_post_proto_msgTypes[1] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use PostResponse.ProtoReflect.Descriptor instead. +func (*PostResponse) Descriptor() ([]byte, []int) { + return file_post_proto_rawDescGZIP(), []int{1} +} + +func (x *PostResponse) GetPost() *Post { + if x != nil { + return x.Post + } + return nil +} + +var File_post_proto protoreflect.FileDescriptor + +var file_post_proto_rawDesc = []byte{ + 0x0a, 0x0a, 0x70, 0x6f, 0x73, 0x74, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x02, 0x70, 0x62, + 0x1a, 0x1f, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, + 0x66, 0x2f, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x2e, 0x70, 0x72, 0x6f, 0x74, + 0x6f, 0x22, 0xe6, 0x01, 0x0a, 0x04, 0x50, 0x6f, 0x73, 0x74, 0x12, 0x0e, 0x0a, 0x02, 0x49, 0x64, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x49, 0x64, 0x12, 0x14, 0x0a, 0x05, 0x54, 0x69, + 0x74, 0x6c, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x54, 0x69, 0x74, 0x6c, 0x65, + 0x12, 0x18, 0x0a, 0x07, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x07, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x12, 0x14, 0x0a, 0x05, 0x49, 0x6d, + 0x61, 0x67, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x49, 0x6d, 0x61, 0x67, 0x65, + 0x12, 0x12, 0x0a, 0x04, 0x55, 0x73, 0x65, 0x72, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, + 0x55, 0x73, 0x65, 0x72, 0x12, 0x39, 0x0a, 0x0a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x5f, + 0x61, 0x74, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, + 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, + 0x74, 0x61, 0x6d, 0x70, 0x52, 0x09, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x41, 0x74, 0x12, + 0x39, 0x0a, 0x0a, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x64, 0x5f, 0x61, 0x74, 0x18, 0x07, 0x20, + 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, + 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, + 0x09, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x64, 0x41, 0x74, 0x22, 0x2c, 0x0a, 0x0c, 0x50, 0x6f, + 0x73, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x1c, 0x0a, 0x04, 0x70, 0x6f, + 0x73, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x08, 0x2e, 0x70, 0x62, 0x2e, 0x50, 0x6f, + 0x73, 0x74, 0x52, 0x04, 0x70, 0x6f, 0x73, 0x74, 0x42, 0x27, 0x5a, 0x25, 0x67, 0x69, 0x74, 0x68, + 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x77, 0x70, 0x63, 0x6f, 0x64, 0x65, 0x76, 0x6f, 0x2f, + 0x67, 0x6f, 0x6c, 0x61, 0x6e, 0x67, 0x2d, 0x6d, 0x6f, 0x6e, 0x67, 0x6f, 0x64, 0x62, 0x2f, 0x70, + 0x62, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, +} + +var ( + file_post_proto_rawDescOnce sync.Once + file_post_proto_rawDescData = file_post_proto_rawDesc +) + +func file_post_proto_rawDescGZIP() []byte { + file_post_proto_rawDescOnce.Do(func() { + file_post_proto_rawDescData = protoimpl.X.CompressGZIP(file_post_proto_rawDescData) + }) + return file_post_proto_rawDescData +} + +var file_post_proto_msgTypes = make([]protoimpl.MessageInfo, 2) +var file_post_proto_goTypes = []interface{}{ + (*Post)(nil), // 0: pb.Post + (*PostResponse)(nil), // 1: pb.PostResponse + (*timestamppb.Timestamp)(nil), // 2: google.protobuf.Timestamp +} +var file_post_proto_depIdxs = []int32{ + 2, // 0: pb.Post.created_at:type_name -> google.protobuf.Timestamp + 2, // 1: pb.Post.updated_at:type_name -> google.protobuf.Timestamp + 0, // 2: pb.PostResponse.post:type_name -> pb.Post + 3, // [3:3] is the sub-list for method output_type + 3, // [3:3] is the sub-list for method input_type + 3, // [3:3] is the sub-list for extension type_name + 3, // [3:3] is the sub-list for extension extendee + 0, // [0:3] is the sub-list for field type_name +} + +func init() { file_post_proto_init() } +func file_post_proto_init() { + if File_post_proto != nil { + return + } + if !protoimpl.UnsafeEnabled { + file_post_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*Post); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_post_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*PostResponse); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + } + type x struct{} + out := protoimpl.TypeBuilder{ + File: protoimpl.DescBuilder{ + GoPackagePath: reflect.TypeOf(x{}).PkgPath(), + RawDescriptor: file_post_proto_rawDesc, + NumEnums: 0, + NumMessages: 2, + NumExtensions: 0, + NumServices: 0, + }, + GoTypes: file_post_proto_goTypes, + DependencyIndexes: file_post_proto_depIdxs, + MessageInfos: file_post_proto_msgTypes, + }.Build() + File_post_proto = out.File + file_post_proto_rawDesc = nil + file_post_proto_goTypes = nil + file_post_proto_depIdxs = nil +} diff --git a/pb/post_service.pb.go b/pb/post_service.pb.go new file mode 100644 index 0000000..e338e2e --- /dev/null +++ b/pb/post_service.pb.go @@ -0,0 +1,319 @@ +// Code generated by protoc-gen-go. DO NOT EDIT. +// versions: +// protoc-gen-go v1.28.0 +// protoc v3.20.1 +// source: post_service.proto + +package pb + +import ( + protoreflect "google.golang.org/protobuf/reflect/protoreflect" + protoimpl "google.golang.org/protobuf/runtime/protoimpl" + reflect "reflect" + sync "sync" +) + +const ( + // Verify that this generated code is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) + // Verify that runtime/protoimpl is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) +) + +type GetPostsRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Page *int64 `protobuf:"varint,1,opt,name=page,proto3,oneof" json:"page,omitempty"` + Limit *int64 `protobuf:"varint,2,opt,name=limit,proto3,oneof" json:"limit,omitempty"` +} + +func (x *GetPostsRequest) Reset() { + *x = GetPostsRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_post_service_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *GetPostsRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetPostsRequest) ProtoMessage() {} + +func (x *GetPostsRequest) ProtoReflect() protoreflect.Message { + mi := &file_post_service_proto_msgTypes[0] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GetPostsRequest.ProtoReflect.Descriptor instead. +func (*GetPostsRequest) Descriptor() ([]byte, []int) { + return file_post_service_proto_rawDescGZIP(), []int{0} +} + +func (x *GetPostsRequest) GetPage() int64 { + if x != nil && x.Page != nil { + return *x.Page + } + return 0 +} + +func (x *GetPostsRequest) GetLimit() int64 { + if x != nil && x.Limit != nil { + return *x.Limit + } + return 0 +} + +type PostRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Id string `protobuf:"bytes,1,opt,name=Id,proto3" json:"Id,omitempty"` +} + +func (x *PostRequest) Reset() { + *x = PostRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_post_service_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *PostRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*PostRequest) ProtoMessage() {} + +func (x *PostRequest) ProtoReflect() protoreflect.Message { + mi := &file_post_service_proto_msgTypes[1] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use PostRequest.ProtoReflect.Descriptor instead. +func (*PostRequest) Descriptor() ([]byte, []int) { + return file_post_service_proto_rawDescGZIP(), []int{1} +} + +func (x *PostRequest) GetId() string { + if x != nil { + return x.Id + } + return "" +} + +type DeletePostResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Success bool `protobuf:"varint,1,opt,name=success,proto3" json:"success,omitempty"` +} + +func (x *DeletePostResponse) Reset() { + *x = DeletePostResponse{} + if protoimpl.UnsafeEnabled { + mi := &file_post_service_proto_msgTypes[2] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *DeletePostResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*DeletePostResponse) ProtoMessage() {} + +func (x *DeletePostResponse) ProtoReflect() protoreflect.Message { + mi := &file_post_service_proto_msgTypes[2] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use DeletePostResponse.ProtoReflect.Descriptor instead. +func (*DeletePostResponse) Descriptor() ([]byte, []int) { + return file_post_service_proto_rawDescGZIP(), []int{2} +} + +func (x *DeletePostResponse) GetSuccess() bool { + if x != nil { + return x.Success + } + return false +} + +var File_post_service_proto protoreflect.FileDescriptor + +var file_post_service_proto_rawDesc = []byte{ + 0x0a, 0x12, 0x70, 0x6f, 0x73, 0x74, 0x5f, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x70, + 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x02, 0x70, 0x62, 0x1a, 0x0a, 0x70, 0x6f, 0x73, 0x74, 0x2e, 0x70, + 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x15, 0x72, 0x70, 0x63, 0x5f, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, + 0x5f, 0x70, 0x6f, 0x73, 0x74, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x15, 0x72, 0x70, 0x63, + 0x5f, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x5f, 0x70, 0x6f, 0x73, 0x74, 0x2e, 0x70, 0x72, 0x6f, + 0x74, 0x6f, 0x22, 0x58, 0x0a, 0x0f, 0x47, 0x65, 0x74, 0x50, 0x6f, 0x73, 0x74, 0x73, 0x52, 0x65, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x17, 0x0a, 0x04, 0x70, 0x61, 0x67, 0x65, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x03, 0x48, 0x00, 0x52, 0x04, 0x70, 0x61, 0x67, 0x65, 0x88, 0x01, 0x01, 0x12, 0x19, + 0x0a, 0x05, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x48, 0x01, 0x52, + 0x05, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x88, 0x01, 0x01, 0x42, 0x07, 0x0a, 0x05, 0x5f, 0x70, 0x61, + 0x67, 0x65, 0x42, 0x08, 0x0a, 0x06, 0x5f, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x22, 0x1d, 0x0a, 0x0b, + 0x50, 0x6f, 0x73, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x0e, 0x0a, 0x02, 0x49, + 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x49, 0x64, 0x22, 0x2e, 0x0a, 0x12, 0x44, + 0x65, 0x6c, 0x65, 0x74, 0x65, 0x50, 0x6f, 0x73, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, + 0x65, 0x12, 0x18, 0x0a, 0x07, 0x73, 0x75, 0x63, 0x63, 0x65, 0x73, 0x73, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x08, 0x52, 0x07, 0x73, 0x75, 0x63, 0x63, 0x65, 0x73, 0x73, 0x32, 0x97, 0x02, 0x0a, 0x0b, + 0x50, 0x6f, 0x73, 0x74, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x37, 0x0a, 0x0a, 0x43, + 0x72, 0x65, 0x61, 0x74, 0x65, 0x50, 0x6f, 0x73, 0x74, 0x12, 0x15, 0x2e, 0x70, 0x62, 0x2e, 0x43, + 0x72, 0x65, 0x61, 0x74, 0x65, 0x50, 0x6f, 0x73, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x1a, 0x10, 0x2e, 0x70, 0x62, 0x2e, 0x50, 0x6f, 0x73, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, + 0x73, 0x65, 0x22, 0x00, 0x12, 0x2e, 0x0a, 0x07, 0x47, 0x65, 0x74, 0x50, 0x6f, 0x73, 0x74, 0x12, + 0x0f, 0x2e, 0x70, 0x62, 0x2e, 0x50, 0x6f, 0x73, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x1a, 0x10, 0x2e, 0x70, 0x62, 0x2e, 0x50, 0x6f, 0x73, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, + 0x73, 0x65, 0x22, 0x00, 0x12, 0x2d, 0x0a, 0x08, 0x47, 0x65, 0x74, 0x50, 0x6f, 0x73, 0x74, 0x73, + 0x12, 0x13, 0x2e, 0x70, 0x62, 0x2e, 0x47, 0x65, 0x74, 0x50, 0x6f, 0x73, 0x74, 0x73, 0x52, 0x65, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x08, 0x2e, 0x70, 0x62, 0x2e, 0x50, 0x6f, 0x73, 0x74, 0x22, + 0x00, 0x30, 0x01, 0x12, 0x37, 0x0a, 0x0a, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x50, 0x6f, 0x73, + 0x74, 0x12, 0x15, 0x2e, 0x70, 0x62, 0x2e, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x50, 0x6f, 0x73, + 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x10, 0x2e, 0x70, 0x62, 0x2e, 0x50, 0x6f, + 0x73, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x37, 0x0a, 0x0a, + 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x50, 0x6f, 0x73, 0x74, 0x12, 0x0f, 0x2e, 0x70, 0x62, 0x2e, + 0x50, 0x6f, 0x73, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x16, 0x2e, 0x70, 0x62, + 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x50, 0x6f, 0x73, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, + 0x6e, 0x73, 0x65, 0x22, 0x00, 0x42, 0x27, 0x5a, 0x25, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, + 0x63, 0x6f, 0x6d, 0x2f, 0x77, 0x70, 0x63, 0x6f, 0x64, 0x65, 0x76, 0x6f, 0x2f, 0x67, 0x6f, 0x6c, + 0x61, 0x6e, 0x67, 0x2d, 0x6d, 0x6f, 0x6e, 0x67, 0x6f, 0x64, 0x62, 0x2f, 0x70, 0x62, 0x62, 0x06, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, +} + +var ( + file_post_service_proto_rawDescOnce sync.Once + file_post_service_proto_rawDescData = file_post_service_proto_rawDesc +) + +func file_post_service_proto_rawDescGZIP() []byte { + file_post_service_proto_rawDescOnce.Do(func() { + file_post_service_proto_rawDescData = protoimpl.X.CompressGZIP(file_post_service_proto_rawDescData) + }) + return file_post_service_proto_rawDescData +} + +var file_post_service_proto_msgTypes = make([]protoimpl.MessageInfo, 3) +var file_post_service_proto_goTypes = []interface{}{ + (*GetPostsRequest)(nil), // 0: pb.GetPostsRequest + (*PostRequest)(nil), // 1: pb.PostRequest + (*DeletePostResponse)(nil), // 2: pb.DeletePostResponse + (*CreatePostRequest)(nil), // 3: pb.CreatePostRequest + (*UpdatePostRequest)(nil), // 4: pb.UpdatePostRequest + (*PostResponse)(nil), // 5: pb.PostResponse + (*Post)(nil), // 6: pb.Post +} +var file_post_service_proto_depIdxs = []int32{ + 3, // 0: pb.PostService.CreatePost:input_type -> pb.CreatePostRequest + 1, // 1: pb.PostService.GetPost:input_type -> pb.PostRequest + 0, // 2: pb.PostService.GetPosts:input_type -> pb.GetPostsRequest + 4, // 3: pb.PostService.UpdatePost:input_type -> pb.UpdatePostRequest + 1, // 4: pb.PostService.DeletePost:input_type -> pb.PostRequest + 5, // 5: pb.PostService.CreatePost:output_type -> pb.PostResponse + 5, // 6: pb.PostService.GetPost:output_type -> pb.PostResponse + 6, // 7: pb.PostService.GetPosts:output_type -> pb.Post + 5, // 8: pb.PostService.UpdatePost:output_type -> pb.PostResponse + 2, // 9: pb.PostService.DeletePost:output_type -> pb.DeletePostResponse + 5, // [5:10] is the sub-list for method output_type + 0, // [0:5] is the sub-list for method input_type + 0, // [0:0] is the sub-list for extension type_name + 0, // [0:0] is the sub-list for extension extendee + 0, // [0:0] is the sub-list for field type_name +} + +func init() { file_post_service_proto_init() } +func file_post_service_proto_init() { + if File_post_service_proto != nil { + return + } + file_post_proto_init() + file_rpc_create_post_proto_init() + file_rpc_update_post_proto_init() + if !protoimpl.UnsafeEnabled { + file_post_service_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*GetPostsRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_post_service_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*PostRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_post_service_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*DeletePostResponse); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + } + file_post_service_proto_msgTypes[0].OneofWrappers = []interface{}{} + type x struct{} + out := protoimpl.TypeBuilder{ + File: protoimpl.DescBuilder{ + GoPackagePath: reflect.TypeOf(x{}).PkgPath(), + RawDescriptor: file_post_service_proto_rawDesc, + NumEnums: 0, + NumMessages: 3, + NumExtensions: 0, + NumServices: 1, + }, + GoTypes: file_post_service_proto_goTypes, + DependencyIndexes: file_post_service_proto_depIdxs, + MessageInfos: file_post_service_proto_msgTypes, + }.Build() + File_post_service_proto = out.File + file_post_service_proto_rawDesc = nil + file_post_service_proto_goTypes = nil + file_post_service_proto_depIdxs = nil +} diff --git a/pb/post_service_grpc.pb.go b/pb/post_service_grpc.pb.go new file mode 100644 index 0000000..9821284 --- /dev/null +++ b/pb/post_service_grpc.pb.go @@ -0,0 +1,277 @@ +// Code generated by protoc-gen-go-grpc. DO NOT EDIT. +// versions: +// - protoc-gen-go-grpc v1.2.0 +// - protoc v3.20.1 +// source: post_service.proto + +package pb + +import ( + context "context" + grpc "google.golang.org/grpc" + codes "google.golang.org/grpc/codes" + status "google.golang.org/grpc/status" +) + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the grpc package it is being compiled against. +// Requires gRPC-Go v1.32.0 or later. +const _ = grpc.SupportPackageIsVersion7 + +// PostServiceClient is the client API for PostService service. +// +// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream. +type PostServiceClient interface { + CreatePost(ctx context.Context, in *CreatePostRequest, opts ...grpc.CallOption) (*PostResponse, error) + GetPost(ctx context.Context, in *PostRequest, opts ...grpc.CallOption) (*PostResponse, error) + GetPosts(ctx context.Context, in *GetPostsRequest, opts ...grpc.CallOption) (PostService_GetPostsClient, error) + UpdatePost(ctx context.Context, in *UpdatePostRequest, opts ...grpc.CallOption) (*PostResponse, error) + DeletePost(ctx context.Context, in *PostRequest, opts ...grpc.CallOption) (*DeletePostResponse, error) +} + +type postServiceClient struct { + cc grpc.ClientConnInterface +} + +func NewPostServiceClient(cc grpc.ClientConnInterface) PostServiceClient { + return &postServiceClient{cc} +} + +func (c *postServiceClient) CreatePost(ctx context.Context, in *CreatePostRequest, opts ...grpc.CallOption) (*PostResponse, error) { + out := new(PostResponse) + err := c.cc.Invoke(ctx, "/pb.PostService/CreatePost", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *postServiceClient) GetPost(ctx context.Context, in *PostRequest, opts ...grpc.CallOption) (*PostResponse, error) { + out := new(PostResponse) + err := c.cc.Invoke(ctx, "/pb.PostService/GetPost", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *postServiceClient) GetPosts(ctx context.Context, in *GetPostsRequest, opts ...grpc.CallOption) (PostService_GetPostsClient, error) { + stream, err := c.cc.NewStream(ctx, &PostService_ServiceDesc.Streams[0], "/pb.PostService/GetPosts", opts...) + if err != nil { + return nil, err + } + x := &postServiceGetPostsClient{stream} + if err := x.ClientStream.SendMsg(in); err != nil { + return nil, err + } + if err := x.ClientStream.CloseSend(); err != nil { + return nil, err + } + return x, nil +} + +type PostService_GetPostsClient interface { + Recv() (*Post, error) + grpc.ClientStream +} + +type postServiceGetPostsClient struct { + grpc.ClientStream +} + +func (x *postServiceGetPostsClient) Recv() (*Post, error) { + m := new(Post) + if err := x.ClientStream.RecvMsg(m); err != nil { + return nil, err + } + return m, nil +} + +func (c *postServiceClient) UpdatePost(ctx context.Context, in *UpdatePostRequest, opts ...grpc.CallOption) (*PostResponse, error) { + out := new(PostResponse) + err := c.cc.Invoke(ctx, "/pb.PostService/UpdatePost", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *postServiceClient) DeletePost(ctx context.Context, in *PostRequest, opts ...grpc.CallOption) (*DeletePostResponse, error) { + out := new(DeletePostResponse) + err := c.cc.Invoke(ctx, "/pb.PostService/DeletePost", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +// PostServiceServer is the server API for PostService service. +// All implementations must embed UnimplementedPostServiceServer +// for forward compatibility +type PostServiceServer interface { + CreatePost(context.Context, *CreatePostRequest) (*PostResponse, error) + GetPost(context.Context, *PostRequest) (*PostResponse, error) + GetPosts(*GetPostsRequest, PostService_GetPostsServer) error + UpdatePost(context.Context, *UpdatePostRequest) (*PostResponse, error) + DeletePost(context.Context, *PostRequest) (*DeletePostResponse, error) + mustEmbedUnimplementedPostServiceServer() +} + +// UnimplementedPostServiceServer must be embedded to have forward compatible implementations. +type UnimplementedPostServiceServer struct { +} + +func (UnimplementedPostServiceServer) CreatePost(context.Context, *CreatePostRequest) (*PostResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method CreatePost not implemented") +} +func (UnimplementedPostServiceServer) GetPost(context.Context, *PostRequest) (*PostResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method GetPost not implemented") +} +func (UnimplementedPostServiceServer) GetPosts(*GetPostsRequest, PostService_GetPostsServer) error { + return status.Errorf(codes.Unimplemented, "method GetPosts not implemented") +} +func (UnimplementedPostServiceServer) UpdatePost(context.Context, *UpdatePostRequest) (*PostResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method UpdatePost not implemented") +} +func (UnimplementedPostServiceServer) DeletePost(context.Context, *PostRequest) (*DeletePostResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method DeletePost not implemented") +} +func (UnimplementedPostServiceServer) mustEmbedUnimplementedPostServiceServer() {} + +// UnsafePostServiceServer may be embedded to opt out of forward compatibility for this service. +// Use of this interface is not recommended, as added methods to PostServiceServer will +// result in compilation errors. +type UnsafePostServiceServer interface { + mustEmbedUnimplementedPostServiceServer() +} + +func RegisterPostServiceServer(s grpc.ServiceRegistrar, srv PostServiceServer) { + s.RegisterService(&PostService_ServiceDesc, srv) +} + +func _PostService_CreatePost_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(CreatePostRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(PostServiceServer).CreatePost(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/pb.PostService/CreatePost", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(PostServiceServer).CreatePost(ctx, req.(*CreatePostRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _PostService_GetPost_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(PostRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(PostServiceServer).GetPost(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/pb.PostService/GetPost", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(PostServiceServer).GetPost(ctx, req.(*PostRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _PostService_GetPosts_Handler(srv interface{}, stream grpc.ServerStream) error { + m := new(GetPostsRequest) + if err := stream.RecvMsg(m); err != nil { + return err + } + return srv.(PostServiceServer).GetPosts(m, &postServiceGetPostsServer{stream}) +} + +type PostService_GetPostsServer interface { + Send(*Post) error + grpc.ServerStream +} + +type postServiceGetPostsServer struct { + grpc.ServerStream +} + +func (x *postServiceGetPostsServer) Send(m *Post) error { + return x.ServerStream.SendMsg(m) +} + +func _PostService_UpdatePost_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(UpdatePostRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(PostServiceServer).UpdatePost(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/pb.PostService/UpdatePost", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(PostServiceServer).UpdatePost(ctx, req.(*UpdatePostRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _PostService_DeletePost_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(PostRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(PostServiceServer).DeletePost(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/pb.PostService/DeletePost", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(PostServiceServer).DeletePost(ctx, req.(*PostRequest)) + } + return interceptor(ctx, in, info, handler) +} + +// PostService_ServiceDesc is the grpc.ServiceDesc for PostService service. +// It's only intended for direct use with grpc.RegisterService, +// and not to be introspected or modified (even as a copy) +var PostService_ServiceDesc = grpc.ServiceDesc{ + ServiceName: "pb.PostService", + HandlerType: (*PostServiceServer)(nil), + Methods: []grpc.MethodDesc{ + { + MethodName: "CreatePost", + Handler: _PostService_CreatePost_Handler, + }, + { + MethodName: "GetPost", + Handler: _PostService_GetPost_Handler, + }, + { + MethodName: "UpdatePost", + Handler: _PostService_UpdatePost_Handler, + }, + { + MethodName: "DeletePost", + Handler: _PostService_DeletePost_Handler, + }, + }, + Streams: []grpc.StreamDesc{ + { + StreamName: "GetPosts", + Handler: _PostService_GetPosts_Handler, + ServerStreams: true, + }, + }, + Metadata: "post_service.proto", +} diff --git a/pb/rpc_create_post.pb.go b/pb/rpc_create_post.pb.go new file mode 100644 index 0000000..8718d71 --- /dev/null +++ b/pb/rpc_create_post.pb.go @@ -0,0 +1,172 @@ +// Code generated by protoc-gen-go. DO NOT EDIT. +// versions: +// protoc-gen-go v1.28.0 +// protoc v3.20.1 +// source: rpc_create_post.proto + +package pb + +import ( + protoreflect "google.golang.org/protobuf/reflect/protoreflect" + protoimpl "google.golang.org/protobuf/runtime/protoimpl" + reflect "reflect" + sync "sync" +) + +const ( + // Verify that this generated code is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) + // Verify that runtime/protoimpl is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) +) + +type CreatePostRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Title string `protobuf:"bytes,1,opt,name=Title,proto3" json:"Title,omitempty"` + Content string `protobuf:"bytes,2,opt,name=Content,proto3" json:"Content,omitempty"` + Image string `protobuf:"bytes,3,opt,name=Image,proto3" json:"Image,omitempty"` + User string `protobuf:"bytes,4,opt,name=User,proto3" json:"User,omitempty"` +} + +func (x *CreatePostRequest) Reset() { + *x = CreatePostRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_rpc_create_post_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *CreatePostRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*CreatePostRequest) ProtoMessage() {} + +func (x *CreatePostRequest) ProtoReflect() protoreflect.Message { + mi := &file_rpc_create_post_proto_msgTypes[0] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use CreatePostRequest.ProtoReflect.Descriptor instead. +func (*CreatePostRequest) Descriptor() ([]byte, []int) { + return file_rpc_create_post_proto_rawDescGZIP(), []int{0} +} + +func (x *CreatePostRequest) GetTitle() string { + if x != nil { + return x.Title + } + return "" +} + +func (x *CreatePostRequest) GetContent() string { + if x != nil { + return x.Content + } + return "" +} + +func (x *CreatePostRequest) GetImage() string { + if x != nil { + return x.Image + } + return "" +} + +func (x *CreatePostRequest) GetUser() string { + if x != nil { + return x.User + } + return "" +} + +var File_rpc_create_post_proto protoreflect.FileDescriptor + +var file_rpc_create_post_proto_rawDesc = []byte{ + 0x0a, 0x15, 0x72, 0x70, 0x63, 0x5f, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x5f, 0x70, 0x6f, 0x73, + 0x74, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x02, 0x70, 0x62, 0x22, 0x6d, 0x0a, 0x11, 0x43, + 0x72, 0x65, 0x61, 0x74, 0x65, 0x50, 0x6f, 0x73, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x12, 0x14, 0x0a, 0x05, 0x54, 0x69, 0x74, 0x6c, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x05, 0x54, 0x69, 0x74, 0x6c, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, + 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, + 0x12, 0x14, 0x0a, 0x05, 0x49, 0x6d, 0x61, 0x67, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x05, 0x49, 0x6d, 0x61, 0x67, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x55, 0x73, 0x65, 0x72, 0x18, 0x04, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x55, 0x73, 0x65, 0x72, 0x42, 0x27, 0x5a, 0x25, 0x67, 0x69, + 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x77, 0x70, 0x63, 0x6f, 0x64, 0x65, 0x76, + 0x6f, 0x2f, 0x67, 0x6f, 0x6c, 0x61, 0x6e, 0x67, 0x2d, 0x6d, 0x6f, 0x6e, 0x67, 0x6f, 0x64, 0x62, + 0x2f, 0x70, 0x62, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, +} + +var ( + file_rpc_create_post_proto_rawDescOnce sync.Once + file_rpc_create_post_proto_rawDescData = file_rpc_create_post_proto_rawDesc +) + +func file_rpc_create_post_proto_rawDescGZIP() []byte { + file_rpc_create_post_proto_rawDescOnce.Do(func() { + file_rpc_create_post_proto_rawDescData = protoimpl.X.CompressGZIP(file_rpc_create_post_proto_rawDescData) + }) + return file_rpc_create_post_proto_rawDescData +} + +var file_rpc_create_post_proto_msgTypes = make([]protoimpl.MessageInfo, 1) +var file_rpc_create_post_proto_goTypes = []interface{}{ + (*CreatePostRequest)(nil), // 0: pb.CreatePostRequest +} +var file_rpc_create_post_proto_depIdxs = []int32{ + 0, // [0:0] is the sub-list for method output_type + 0, // [0:0] is the sub-list for method input_type + 0, // [0:0] is the sub-list for extension type_name + 0, // [0:0] is the sub-list for extension extendee + 0, // [0:0] is the sub-list for field type_name +} + +func init() { file_rpc_create_post_proto_init() } +func file_rpc_create_post_proto_init() { + if File_rpc_create_post_proto != nil { + return + } + if !protoimpl.UnsafeEnabled { + file_rpc_create_post_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*CreatePostRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + } + type x struct{} + out := protoimpl.TypeBuilder{ + File: protoimpl.DescBuilder{ + GoPackagePath: reflect.TypeOf(x{}).PkgPath(), + RawDescriptor: file_rpc_create_post_proto_rawDesc, + NumEnums: 0, + NumMessages: 1, + NumExtensions: 0, + NumServices: 0, + }, + GoTypes: file_rpc_create_post_proto_goTypes, + DependencyIndexes: file_rpc_create_post_proto_depIdxs, + MessageInfos: file_rpc_create_post_proto_msgTypes, + }.Build() + File_rpc_create_post_proto = out.File + file_rpc_create_post_proto_rawDesc = nil + file_rpc_create_post_proto_goTypes = nil + file_rpc_create_post_proto_depIdxs = nil +} diff --git a/pb/rpc_signin_user.pb.go b/pb/rpc_signin_user.pb.go new file mode 100644 index 0000000..7c14645 --- /dev/null +++ b/pb/rpc_signin_user.pb.go @@ -0,0 +1,237 @@ +// Code generated by protoc-gen-go. DO NOT EDIT. +// versions: +// protoc-gen-go v1.28.0 +// protoc v3.20.1 +// source: rpc_signin_user.proto + +package pb + +import ( + protoreflect "google.golang.org/protobuf/reflect/protoreflect" + protoimpl "google.golang.org/protobuf/runtime/protoimpl" + reflect "reflect" + sync "sync" +) + +const ( + // Verify that this generated code is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) + // Verify that runtime/protoimpl is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) +) + +type SignInUserInput struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Email string `protobuf:"bytes,1,opt,name=email,proto3" json:"email,omitempty"` + Password string `protobuf:"bytes,2,opt,name=password,proto3" json:"password,omitempty"` +} + +func (x *SignInUserInput) Reset() { + *x = SignInUserInput{} + if protoimpl.UnsafeEnabled { + mi := &file_rpc_signin_user_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *SignInUserInput) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*SignInUserInput) ProtoMessage() {} + +func (x *SignInUserInput) ProtoReflect() protoreflect.Message { + mi := &file_rpc_signin_user_proto_msgTypes[0] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use SignInUserInput.ProtoReflect.Descriptor instead. +func (*SignInUserInput) Descriptor() ([]byte, []int) { + return file_rpc_signin_user_proto_rawDescGZIP(), []int{0} +} + +func (x *SignInUserInput) GetEmail() string { + if x != nil { + return x.Email + } + return "" +} + +func (x *SignInUserInput) GetPassword() string { + if x != nil { + return x.Password + } + return "" +} + +type SignInUserResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Status string `protobuf:"bytes,1,opt,name=status,proto3" json:"status,omitempty"` + AccessToken string `protobuf:"bytes,2,opt,name=access_token,json=accessToken,proto3" json:"access_token,omitempty"` + RefreshToken string `protobuf:"bytes,3,opt,name=refresh_token,json=refreshToken,proto3" json:"refresh_token,omitempty"` +} + +func (x *SignInUserResponse) Reset() { + *x = SignInUserResponse{} + if protoimpl.UnsafeEnabled { + mi := &file_rpc_signin_user_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *SignInUserResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*SignInUserResponse) ProtoMessage() {} + +func (x *SignInUserResponse) ProtoReflect() protoreflect.Message { + mi := &file_rpc_signin_user_proto_msgTypes[1] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use SignInUserResponse.ProtoReflect.Descriptor instead. +func (*SignInUserResponse) Descriptor() ([]byte, []int) { + return file_rpc_signin_user_proto_rawDescGZIP(), []int{1} +} + +func (x *SignInUserResponse) GetStatus() string { + if x != nil { + return x.Status + } + return "" +} + +func (x *SignInUserResponse) GetAccessToken() string { + if x != nil { + return x.AccessToken + } + return "" +} + +func (x *SignInUserResponse) GetRefreshToken() string { + if x != nil { + return x.RefreshToken + } + return "" +} + +var File_rpc_signin_user_proto protoreflect.FileDescriptor + +var file_rpc_signin_user_proto_rawDesc = []byte{ + 0x0a, 0x15, 0x72, 0x70, 0x63, 0x5f, 0x73, 0x69, 0x67, 0x6e, 0x69, 0x6e, 0x5f, 0x75, 0x73, 0x65, + 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x02, 0x70, 0x62, 0x22, 0x43, 0x0a, 0x0f, 0x53, + 0x69, 0x67, 0x6e, 0x49, 0x6e, 0x55, 0x73, 0x65, 0x72, 0x49, 0x6e, 0x70, 0x75, 0x74, 0x12, 0x14, + 0x0a, 0x05, 0x65, 0x6d, 0x61, 0x69, 0x6c, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x65, + 0x6d, 0x61, 0x69, 0x6c, 0x12, 0x1a, 0x0a, 0x08, 0x70, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, + 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x70, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, + 0x22, 0x74, 0x0a, 0x12, 0x53, 0x69, 0x67, 0x6e, 0x49, 0x6e, 0x55, 0x73, 0x65, 0x72, 0x52, 0x65, + 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x21, + 0x0a, 0x0c, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x5f, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x18, 0x02, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x54, 0x6f, 0x6b, 0x65, + 0x6e, 0x12, 0x23, 0x0a, 0x0d, 0x72, 0x65, 0x66, 0x72, 0x65, 0x73, 0x68, 0x5f, 0x74, 0x6f, 0x6b, + 0x65, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x72, 0x65, 0x66, 0x72, 0x65, 0x73, + 0x68, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x42, 0x27, 0x5a, 0x25, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, + 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x77, 0x70, 0x63, 0x6f, 0x64, 0x65, 0x76, 0x6f, 0x2f, 0x67, 0x6f, + 0x6c, 0x61, 0x6e, 0x67, 0x2d, 0x6d, 0x6f, 0x6e, 0x67, 0x6f, 0x64, 0x62, 0x2f, 0x70, 0x62, 0x62, + 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, +} + +var ( + file_rpc_signin_user_proto_rawDescOnce sync.Once + file_rpc_signin_user_proto_rawDescData = file_rpc_signin_user_proto_rawDesc +) + +func file_rpc_signin_user_proto_rawDescGZIP() []byte { + file_rpc_signin_user_proto_rawDescOnce.Do(func() { + file_rpc_signin_user_proto_rawDescData = protoimpl.X.CompressGZIP(file_rpc_signin_user_proto_rawDescData) + }) + return file_rpc_signin_user_proto_rawDescData +} + +var file_rpc_signin_user_proto_msgTypes = make([]protoimpl.MessageInfo, 2) +var file_rpc_signin_user_proto_goTypes = []interface{}{ + (*SignInUserInput)(nil), // 0: pb.SignInUserInput + (*SignInUserResponse)(nil), // 1: pb.SignInUserResponse +} +var file_rpc_signin_user_proto_depIdxs = []int32{ + 0, // [0:0] is the sub-list for method output_type + 0, // [0:0] is the sub-list for method input_type + 0, // [0:0] is the sub-list for extension type_name + 0, // [0:0] is the sub-list for extension extendee + 0, // [0:0] is the sub-list for field type_name +} + +func init() { file_rpc_signin_user_proto_init() } +func file_rpc_signin_user_proto_init() { + if File_rpc_signin_user_proto != nil { + return + } + if !protoimpl.UnsafeEnabled { + file_rpc_signin_user_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*SignInUserInput); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_rpc_signin_user_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*SignInUserResponse); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + } + type x struct{} + out := protoimpl.TypeBuilder{ + File: protoimpl.DescBuilder{ + GoPackagePath: reflect.TypeOf(x{}).PkgPath(), + RawDescriptor: file_rpc_signin_user_proto_rawDesc, + NumEnums: 0, + NumMessages: 2, + NumExtensions: 0, + NumServices: 0, + }, + GoTypes: file_rpc_signin_user_proto_goTypes, + DependencyIndexes: file_rpc_signin_user_proto_depIdxs, + MessageInfos: file_rpc_signin_user_proto_msgTypes, + }.Build() + File_rpc_signin_user_proto = out.File + file_rpc_signin_user_proto_rawDesc = nil + file_rpc_signin_user_proto_goTypes = nil + file_rpc_signin_user_proto_depIdxs = nil +} diff --git a/pb/rpc_signup_user.pb.go b/pb/rpc_signup_user.pb.go new file mode 100644 index 0000000..8657f75 --- /dev/null +++ b/pb/rpc_signup_user.pb.go @@ -0,0 +1,240 @@ +// Code generated by protoc-gen-go. DO NOT EDIT. +// versions: +// protoc-gen-go v1.28.0 +// protoc v3.20.1 +// source: rpc_signup_user.proto + +package pb + +import ( + protoreflect "google.golang.org/protobuf/reflect/protoreflect" + protoimpl "google.golang.org/protobuf/runtime/protoimpl" + reflect "reflect" + sync "sync" +) + +const ( + // Verify that this generated code is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) + // Verify that runtime/protoimpl is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) +) + +type SignUpUserInput struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"` + Email string `protobuf:"bytes,2,opt,name=email,proto3" json:"email,omitempty"` + Password string `protobuf:"bytes,3,opt,name=password,proto3" json:"password,omitempty"` + PasswordConfirm string `protobuf:"bytes,4,opt,name=passwordConfirm,proto3" json:"passwordConfirm,omitempty"` +} + +func (x *SignUpUserInput) Reset() { + *x = SignUpUserInput{} + if protoimpl.UnsafeEnabled { + mi := &file_rpc_signup_user_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *SignUpUserInput) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*SignUpUserInput) ProtoMessage() {} + +func (x *SignUpUserInput) ProtoReflect() protoreflect.Message { + mi := &file_rpc_signup_user_proto_msgTypes[0] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use SignUpUserInput.ProtoReflect.Descriptor instead. +func (*SignUpUserInput) Descriptor() ([]byte, []int) { + return file_rpc_signup_user_proto_rawDescGZIP(), []int{0} +} + +func (x *SignUpUserInput) GetName() string { + if x != nil { + return x.Name + } + return "" +} + +func (x *SignUpUserInput) GetEmail() string { + if x != nil { + return x.Email + } + return "" +} + +func (x *SignUpUserInput) GetPassword() string { + if x != nil { + return x.Password + } + return "" +} + +func (x *SignUpUserInput) GetPasswordConfirm() string { + if x != nil { + return x.PasswordConfirm + } + return "" +} + +type SignUpUserResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + User *User `protobuf:"bytes,1,opt,name=user,proto3" json:"user,omitempty"` +} + +func (x *SignUpUserResponse) Reset() { + *x = SignUpUserResponse{} + if protoimpl.UnsafeEnabled { + mi := &file_rpc_signup_user_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *SignUpUserResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*SignUpUserResponse) ProtoMessage() {} + +func (x *SignUpUserResponse) ProtoReflect() protoreflect.Message { + mi := &file_rpc_signup_user_proto_msgTypes[1] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use SignUpUserResponse.ProtoReflect.Descriptor instead. +func (*SignUpUserResponse) Descriptor() ([]byte, []int) { + return file_rpc_signup_user_proto_rawDescGZIP(), []int{1} +} + +func (x *SignUpUserResponse) GetUser() *User { + if x != nil { + return x.User + } + return nil +} + +var File_rpc_signup_user_proto protoreflect.FileDescriptor + +var file_rpc_signup_user_proto_rawDesc = []byte{ + 0x0a, 0x15, 0x72, 0x70, 0x63, 0x5f, 0x73, 0x69, 0x67, 0x6e, 0x75, 0x70, 0x5f, 0x75, 0x73, 0x65, + 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x02, 0x70, 0x62, 0x1a, 0x0a, 0x75, 0x73, 0x65, + 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x81, 0x01, 0x0a, 0x0f, 0x53, 0x69, 0x67, 0x6e, + 0x55, 0x70, 0x55, 0x73, 0x65, 0x72, 0x49, 0x6e, 0x70, 0x75, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x6e, + 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, + 0x14, 0x0a, 0x05, 0x65, 0x6d, 0x61, 0x69, 0x6c, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, + 0x65, 0x6d, 0x61, 0x69, 0x6c, 0x12, 0x1a, 0x0a, 0x08, 0x70, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, + 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x70, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, + 0x64, 0x12, 0x28, 0x0a, 0x0f, 0x70, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x43, 0x6f, 0x6e, + 0x66, 0x69, 0x72, 0x6d, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0f, 0x70, 0x61, 0x73, 0x73, + 0x77, 0x6f, 0x72, 0x64, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x72, 0x6d, 0x22, 0x32, 0x0a, 0x12, 0x53, + 0x69, 0x67, 0x6e, 0x55, 0x70, 0x55, 0x73, 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, + 0x65, 0x12, 0x1c, 0x0a, 0x04, 0x75, 0x73, 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, + 0x08, 0x2e, 0x70, 0x62, 0x2e, 0x55, 0x73, 0x65, 0x72, 0x52, 0x04, 0x75, 0x73, 0x65, 0x72, 0x42, + 0x27, 0x5a, 0x25, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x77, 0x70, + 0x63, 0x6f, 0x64, 0x65, 0x76, 0x6f, 0x2f, 0x67, 0x6f, 0x6c, 0x61, 0x6e, 0x67, 0x2d, 0x6d, 0x6f, + 0x6e, 0x67, 0x6f, 0x64, 0x62, 0x2f, 0x70, 0x62, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, +} + +var ( + file_rpc_signup_user_proto_rawDescOnce sync.Once + file_rpc_signup_user_proto_rawDescData = file_rpc_signup_user_proto_rawDesc +) + +func file_rpc_signup_user_proto_rawDescGZIP() []byte { + file_rpc_signup_user_proto_rawDescOnce.Do(func() { + file_rpc_signup_user_proto_rawDescData = protoimpl.X.CompressGZIP(file_rpc_signup_user_proto_rawDescData) + }) + return file_rpc_signup_user_proto_rawDescData +} + +var file_rpc_signup_user_proto_msgTypes = make([]protoimpl.MessageInfo, 2) +var file_rpc_signup_user_proto_goTypes = []interface{}{ + (*SignUpUserInput)(nil), // 0: pb.SignUpUserInput + (*SignUpUserResponse)(nil), // 1: pb.SignUpUserResponse + (*User)(nil), // 2: pb.User +} +var file_rpc_signup_user_proto_depIdxs = []int32{ + 2, // 0: pb.SignUpUserResponse.user:type_name -> pb.User + 1, // [1:1] is the sub-list for method output_type + 1, // [1:1] is the sub-list for method input_type + 1, // [1:1] is the sub-list for extension type_name + 1, // [1:1] is the sub-list for extension extendee + 0, // [0:1] is the sub-list for field type_name +} + +func init() { file_rpc_signup_user_proto_init() } +func file_rpc_signup_user_proto_init() { + if File_rpc_signup_user_proto != nil { + return + } + file_user_proto_init() + if !protoimpl.UnsafeEnabled { + file_rpc_signup_user_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*SignUpUserInput); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_rpc_signup_user_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*SignUpUserResponse); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + } + type x struct{} + out := protoimpl.TypeBuilder{ + File: protoimpl.DescBuilder{ + GoPackagePath: reflect.TypeOf(x{}).PkgPath(), + RawDescriptor: file_rpc_signup_user_proto_rawDesc, + NumEnums: 0, + NumMessages: 2, + NumExtensions: 0, + NumServices: 0, + }, + GoTypes: file_rpc_signup_user_proto_goTypes, + DependencyIndexes: file_rpc_signup_user_proto_depIdxs, + MessageInfos: file_rpc_signup_user_proto_msgTypes, + }.Build() + File_rpc_signup_user_proto = out.File + file_rpc_signup_user_proto_rawDesc = nil + file_rpc_signup_user_proto_goTypes = nil + file_rpc_signup_user_proto_depIdxs = nil +} diff --git a/pb/rpc_update_post.pb.go b/pb/rpc_update_post.pb.go new file mode 100644 index 0000000..db3fbbf --- /dev/null +++ b/pb/rpc_update_post.pb.go @@ -0,0 +1,186 @@ +// Code generated by protoc-gen-go. DO NOT EDIT. +// versions: +// protoc-gen-go v1.28.0 +// protoc v3.20.1 +// source: rpc_update_post.proto + +package pb + +import ( + protoreflect "google.golang.org/protobuf/reflect/protoreflect" + protoimpl "google.golang.org/protobuf/runtime/protoimpl" + reflect "reflect" + sync "sync" +) + +const ( + // Verify that this generated code is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) + // Verify that runtime/protoimpl is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) +) + +type UpdatePostRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Id string `protobuf:"bytes,1,opt,name=Id,proto3" json:"Id,omitempty"` + Title *string `protobuf:"bytes,2,opt,name=Title,proto3,oneof" json:"Title,omitempty"` + Content *string `protobuf:"bytes,3,opt,name=Content,proto3,oneof" json:"Content,omitempty"` + Image *string `protobuf:"bytes,4,opt,name=Image,proto3,oneof" json:"Image,omitempty"` + User *string `protobuf:"bytes,5,opt,name=User,proto3,oneof" json:"User,omitempty"` +} + +func (x *UpdatePostRequest) Reset() { + *x = UpdatePostRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_rpc_update_post_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *UpdatePostRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*UpdatePostRequest) ProtoMessage() {} + +func (x *UpdatePostRequest) ProtoReflect() protoreflect.Message { + mi := &file_rpc_update_post_proto_msgTypes[0] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use UpdatePostRequest.ProtoReflect.Descriptor instead. +func (*UpdatePostRequest) Descriptor() ([]byte, []int) { + return file_rpc_update_post_proto_rawDescGZIP(), []int{0} +} + +func (x *UpdatePostRequest) GetId() string { + if x != nil { + return x.Id + } + return "" +} + +func (x *UpdatePostRequest) GetTitle() string { + if x != nil && x.Title != nil { + return *x.Title + } + return "" +} + +func (x *UpdatePostRequest) GetContent() string { + if x != nil && x.Content != nil { + return *x.Content + } + return "" +} + +func (x *UpdatePostRequest) GetImage() string { + if x != nil && x.Image != nil { + return *x.Image + } + return "" +} + +func (x *UpdatePostRequest) GetUser() string { + if x != nil && x.User != nil { + return *x.User + } + return "" +} + +var File_rpc_update_post_proto protoreflect.FileDescriptor + +var file_rpc_update_post_proto_rawDesc = []byte{ + 0x0a, 0x15, 0x72, 0x70, 0x63, 0x5f, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x5f, 0x70, 0x6f, 0x73, + 0x74, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x02, 0x70, 0x62, 0x22, 0xba, 0x01, 0x0a, 0x11, + 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x50, 0x6f, 0x73, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x12, 0x0e, 0x0a, 0x02, 0x49, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x49, + 0x64, 0x12, 0x19, 0x0a, 0x05, 0x54, 0x69, 0x74, 0x6c, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, + 0x48, 0x00, 0x52, 0x05, 0x54, 0x69, 0x74, 0x6c, 0x65, 0x88, 0x01, 0x01, 0x12, 0x1d, 0x0a, 0x07, + 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x48, 0x01, 0x52, + 0x07, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x88, 0x01, 0x01, 0x12, 0x19, 0x0a, 0x05, 0x49, + 0x6d, 0x61, 0x67, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x48, 0x02, 0x52, 0x05, 0x49, 0x6d, + 0x61, 0x67, 0x65, 0x88, 0x01, 0x01, 0x12, 0x17, 0x0a, 0x04, 0x55, 0x73, 0x65, 0x72, 0x18, 0x05, + 0x20, 0x01, 0x28, 0x09, 0x48, 0x03, 0x52, 0x04, 0x55, 0x73, 0x65, 0x72, 0x88, 0x01, 0x01, 0x42, + 0x08, 0x0a, 0x06, 0x5f, 0x54, 0x69, 0x74, 0x6c, 0x65, 0x42, 0x0a, 0x0a, 0x08, 0x5f, 0x43, 0x6f, + 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x42, 0x08, 0x0a, 0x06, 0x5f, 0x49, 0x6d, 0x61, 0x67, 0x65, 0x42, + 0x07, 0x0a, 0x05, 0x5f, 0x55, 0x73, 0x65, 0x72, 0x42, 0x27, 0x5a, 0x25, 0x67, 0x69, 0x74, 0x68, + 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x77, 0x70, 0x63, 0x6f, 0x64, 0x65, 0x76, 0x6f, 0x2f, + 0x67, 0x6f, 0x6c, 0x61, 0x6e, 0x67, 0x2d, 0x6d, 0x6f, 0x6e, 0x67, 0x6f, 0x64, 0x62, 0x2f, 0x70, + 0x62, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, +} + +var ( + file_rpc_update_post_proto_rawDescOnce sync.Once + file_rpc_update_post_proto_rawDescData = file_rpc_update_post_proto_rawDesc +) + +func file_rpc_update_post_proto_rawDescGZIP() []byte { + file_rpc_update_post_proto_rawDescOnce.Do(func() { + file_rpc_update_post_proto_rawDescData = protoimpl.X.CompressGZIP(file_rpc_update_post_proto_rawDescData) + }) + return file_rpc_update_post_proto_rawDescData +} + +var file_rpc_update_post_proto_msgTypes = make([]protoimpl.MessageInfo, 1) +var file_rpc_update_post_proto_goTypes = []interface{}{ + (*UpdatePostRequest)(nil), // 0: pb.UpdatePostRequest +} +var file_rpc_update_post_proto_depIdxs = []int32{ + 0, // [0:0] is the sub-list for method output_type + 0, // [0:0] is the sub-list for method input_type + 0, // [0:0] is the sub-list for extension type_name + 0, // [0:0] is the sub-list for extension extendee + 0, // [0:0] is the sub-list for field type_name +} + +func init() { file_rpc_update_post_proto_init() } +func file_rpc_update_post_proto_init() { + if File_rpc_update_post_proto != nil { + return + } + if !protoimpl.UnsafeEnabled { + file_rpc_update_post_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*UpdatePostRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + } + file_rpc_update_post_proto_msgTypes[0].OneofWrappers = []interface{}{} + type x struct{} + out := protoimpl.TypeBuilder{ + File: protoimpl.DescBuilder{ + GoPackagePath: reflect.TypeOf(x{}).PkgPath(), + RawDescriptor: file_rpc_update_post_proto_rawDesc, + NumEnums: 0, + NumMessages: 1, + NumExtensions: 0, + NumServices: 0, + }, + GoTypes: file_rpc_update_post_proto_goTypes, + DependencyIndexes: file_rpc_update_post_proto_depIdxs, + MessageInfos: file_rpc_update_post_proto_msgTypes, + }.Build() + File_rpc_update_post_proto = out.File + file_rpc_update_post_proto_rawDesc = nil + file_rpc_update_post_proto_goTypes = nil + file_rpc_update_post_proto_depIdxs = nil +} diff --git a/pb/user.pb.go b/pb/user.pb.go new file mode 100644 index 0000000..4d32386 --- /dev/null +++ b/pb/user.pb.go @@ -0,0 +1,336 @@ +// Code generated by protoc-gen-go. DO NOT EDIT. +// versions: +// protoc-gen-go v1.28.0 +// protoc v3.20.1 +// source: user.proto + +package pb + +import ( + protoreflect "google.golang.org/protobuf/reflect/protoreflect" + protoimpl "google.golang.org/protobuf/runtime/protoimpl" + timestamppb "google.golang.org/protobuf/types/known/timestamppb" + reflect "reflect" + sync "sync" +) + +const ( + // Verify that this generated code is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) + // Verify that runtime/protoimpl is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) +) + +type User struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` + Name string `protobuf:"bytes,2,opt,name=name,proto3" json:"name,omitempty"` + Email string `protobuf:"bytes,3,opt,name=email,proto3" json:"email,omitempty"` + Role string `protobuf:"bytes,4,opt,name=role,proto3" json:"role,omitempty"` + CreatedAt *timestamppb.Timestamp `protobuf:"bytes,5,opt,name=created_at,json=createdAt,proto3" json:"created_at,omitempty"` + UpdatedAt *timestamppb.Timestamp `protobuf:"bytes,6,opt,name=updated_at,json=updatedAt,proto3" json:"updated_at,omitempty"` +} + +func (x *User) Reset() { + *x = User{} + if protoimpl.UnsafeEnabled { + mi := &file_user_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *User) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*User) ProtoMessage() {} + +func (x *User) ProtoReflect() protoreflect.Message { + mi := &file_user_proto_msgTypes[0] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use User.ProtoReflect.Descriptor instead. +func (*User) Descriptor() ([]byte, []int) { + return file_user_proto_rawDescGZIP(), []int{0} +} + +func (x *User) GetId() string { + if x != nil { + return x.Id + } + return "" +} + +func (x *User) GetName() string { + if x != nil { + return x.Name + } + return "" +} + +func (x *User) GetEmail() string { + if x != nil { + return x.Email + } + return "" +} + +func (x *User) GetRole() string { + if x != nil { + return x.Role + } + return "" +} + +func (x *User) GetCreatedAt() *timestamppb.Timestamp { + if x != nil { + return x.CreatedAt + } + return nil +} + +func (x *User) GetUpdatedAt() *timestamppb.Timestamp { + if x != nil { + return x.UpdatedAt + } + return nil +} + +type UserResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + User *User `protobuf:"bytes,1,opt,name=user,proto3" json:"user,omitempty"` +} + +func (x *UserResponse) Reset() { + *x = UserResponse{} + if protoimpl.UnsafeEnabled { + mi := &file_user_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *UserResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*UserResponse) ProtoMessage() {} + +func (x *UserResponse) ProtoReflect() protoreflect.Message { + mi := &file_user_proto_msgTypes[1] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use UserResponse.ProtoReflect.Descriptor instead. +func (*UserResponse) Descriptor() ([]byte, []int) { + return file_user_proto_rawDescGZIP(), []int{1} +} + +func (x *UserResponse) GetUser() *User { + if x != nil { + return x.User + } + return nil +} + +type GenericResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Status string `protobuf:"bytes,1,opt,name=status,proto3" json:"status,omitempty"` + Message string `protobuf:"bytes,2,opt,name=message,proto3" json:"message,omitempty"` +} + +func (x *GenericResponse) Reset() { + *x = GenericResponse{} + if protoimpl.UnsafeEnabled { + mi := &file_user_proto_msgTypes[2] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *GenericResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GenericResponse) ProtoMessage() {} + +func (x *GenericResponse) ProtoReflect() protoreflect.Message { + mi := &file_user_proto_msgTypes[2] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GenericResponse.ProtoReflect.Descriptor instead. +func (*GenericResponse) Descriptor() ([]byte, []int) { + return file_user_proto_rawDescGZIP(), []int{2} +} + +func (x *GenericResponse) GetStatus() string { + if x != nil { + return x.Status + } + return "" +} + +func (x *GenericResponse) GetMessage() string { + if x != nil { + return x.Message + } + return "" +} + +var File_user_proto protoreflect.FileDescriptor + +var file_user_proto_rawDesc = []byte{ + 0x0a, 0x0a, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x02, 0x70, 0x62, + 0x1a, 0x1f, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, + 0x66, 0x2f, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x2e, 0x70, 0x72, 0x6f, 0x74, + 0x6f, 0x22, 0xca, 0x01, 0x0a, 0x04, 0x55, 0x73, 0x65, 0x72, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, + 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x14, + 0x0a, 0x05, 0x65, 0x6d, 0x61, 0x69, 0x6c, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x65, + 0x6d, 0x61, 0x69, 0x6c, 0x12, 0x12, 0x0a, 0x04, 0x72, 0x6f, 0x6c, 0x65, 0x18, 0x04, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x04, 0x72, 0x6f, 0x6c, 0x65, 0x12, 0x39, 0x0a, 0x0a, 0x63, 0x72, 0x65, 0x61, + 0x74, 0x65, 0x64, 0x5f, 0x61, 0x74, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, + 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, + 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x09, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, + 0x64, 0x41, 0x74, 0x12, 0x39, 0x0a, 0x0a, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x64, 0x5f, 0x61, + 0x74, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, + 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, + 0x61, 0x6d, 0x70, 0x52, 0x09, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x64, 0x41, 0x74, 0x22, 0x2c, + 0x0a, 0x0c, 0x55, 0x73, 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x1c, + 0x0a, 0x04, 0x75, 0x73, 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x08, 0x2e, 0x70, + 0x62, 0x2e, 0x55, 0x73, 0x65, 0x72, 0x52, 0x04, 0x75, 0x73, 0x65, 0x72, 0x22, 0x43, 0x0a, 0x0f, + 0x47, 0x65, 0x6e, 0x65, 0x72, 0x69, 0x63, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, + 0x16, 0x0a, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x18, 0x0a, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, + 0x67, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, + 0x65, 0x42, 0x27, 0x5a, 0x25, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, + 0x77, 0x70, 0x63, 0x6f, 0x64, 0x65, 0x76, 0x6f, 0x2f, 0x67, 0x6f, 0x6c, 0x61, 0x6e, 0x67, 0x2d, + 0x6d, 0x6f, 0x6e, 0x67, 0x6f, 0x64, 0x62, 0x2f, 0x70, 0x62, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, + 0x6f, 0x33, +} + +var ( + file_user_proto_rawDescOnce sync.Once + file_user_proto_rawDescData = file_user_proto_rawDesc +) + +func file_user_proto_rawDescGZIP() []byte { + file_user_proto_rawDescOnce.Do(func() { + file_user_proto_rawDescData = protoimpl.X.CompressGZIP(file_user_proto_rawDescData) + }) + return file_user_proto_rawDescData +} + +var file_user_proto_msgTypes = make([]protoimpl.MessageInfo, 3) +var file_user_proto_goTypes = []interface{}{ + (*User)(nil), // 0: pb.User + (*UserResponse)(nil), // 1: pb.UserResponse + (*GenericResponse)(nil), // 2: pb.GenericResponse + (*timestamppb.Timestamp)(nil), // 3: google.protobuf.Timestamp +} +var file_user_proto_depIdxs = []int32{ + 3, // 0: pb.User.created_at:type_name -> google.protobuf.Timestamp + 3, // 1: pb.User.updated_at:type_name -> google.protobuf.Timestamp + 0, // 2: pb.UserResponse.user:type_name -> pb.User + 3, // [3:3] is the sub-list for method output_type + 3, // [3:3] is the sub-list for method input_type + 3, // [3:3] is the sub-list for extension type_name + 3, // [3:3] is the sub-list for extension extendee + 0, // [0:3] is the sub-list for field type_name +} + +func init() { file_user_proto_init() } +func file_user_proto_init() { + if File_user_proto != nil { + return + } + if !protoimpl.UnsafeEnabled { + file_user_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*User); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_user_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*UserResponse); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_user_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*GenericResponse); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + } + type x struct{} + out := protoimpl.TypeBuilder{ + File: protoimpl.DescBuilder{ + GoPackagePath: reflect.TypeOf(x{}).PkgPath(), + RawDescriptor: file_user_proto_rawDesc, + NumEnums: 0, + NumMessages: 3, + NumExtensions: 0, + NumServices: 0, + }, + GoTypes: file_user_proto_goTypes, + DependencyIndexes: file_user_proto_depIdxs, + MessageInfos: file_user_proto_msgTypes, + }.Build() + File_user_proto = out.File + file_user_proto_rawDesc = nil + file_user_proto_goTypes = nil + file_user_proto_depIdxs = nil +} diff --git a/pb/user_service.pb.go b/pb/user_service.pb.go new file mode 100644 index 0000000..a69182e --- /dev/null +++ b/pb/user_service.pb.go @@ -0,0 +1,152 @@ +// Code generated by protoc-gen-go. DO NOT EDIT. +// versions: +// protoc-gen-go v1.28.0 +// protoc v3.20.1 +// source: user_service.proto + +package pb + +import ( + protoreflect "google.golang.org/protobuf/reflect/protoreflect" + protoimpl "google.golang.org/protobuf/runtime/protoimpl" + reflect "reflect" + sync "sync" +) + +const ( + // Verify that this generated code is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) + // Verify that runtime/protoimpl is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) +) + +type GetMeRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Id string `protobuf:"bytes,1,opt,name=Id,proto3" json:"Id,omitempty"` +} + +func (x *GetMeRequest) Reset() { + *x = GetMeRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_user_service_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *GetMeRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetMeRequest) ProtoMessage() {} + +func (x *GetMeRequest) ProtoReflect() protoreflect.Message { + mi := &file_user_service_proto_msgTypes[0] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GetMeRequest.ProtoReflect.Descriptor instead. +func (*GetMeRequest) Descriptor() ([]byte, []int) { + return file_user_service_proto_rawDescGZIP(), []int{0} +} + +func (x *GetMeRequest) GetId() string { + if x != nil { + return x.Id + } + return "" +} + +var File_user_service_proto protoreflect.FileDescriptor + +var file_user_service_proto_rawDesc = []byte{ + 0x0a, 0x12, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x70, + 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x02, 0x70, 0x62, 0x1a, 0x0a, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x70, + 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x1e, 0x0a, 0x0c, 0x47, 0x65, 0x74, 0x4d, 0x65, 0x52, 0x65, 0x71, + 0x75, 0x65, 0x73, 0x74, 0x12, 0x0e, 0x0a, 0x02, 0x49, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x02, 0x49, 0x64, 0x32, 0x3c, 0x0a, 0x0b, 0x55, 0x73, 0x65, 0x72, 0x53, 0x65, 0x72, 0x76, + 0x69, 0x63, 0x65, 0x12, 0x2d, 0x0a, 0x05, 0x47, 0x65, 0x74, 0x4d, 0x65, 0x12, 0x10, 0x2e, 0x70, + 0x62, 0x2e, 0x47, 0x65, 0x74, 0x4d, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x10, + 0x2e, 0x70, 0x62, 0x2e, 0x55, 0x73, 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, + 0x22, 0x00, 0x42, 0x27, 0x5a, 0x25, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, + 0x2f, 0x77, 0x70, 0x63, 0x6f, 0x64, 0x65, 0x76, 0x6f, 0x2f, 0x67, 0x6f, 0x6c, 0x61, 0x6e, 0x67, + 0x2d, 0x6d, 0x6f, 0x6e, 0x67, 0x6f, 0x64, 0x62, 0x2f, 0x70, 0x62, 0x62, 0x06, 0x70, 0x72, 0x6f, + 0x74, 0x6f, 0x33, +} + +var ( + file_user_service_proto_rawDescOnce sync.Once + file_user_service_proto_rawDescData = file_user_service_proto_rawDesc +) + +func file_user_service_proto_rawDescGZIP() []byte { + file_user_service_proto_rawDescOnce.Do(func() { + file_user_service_proto_rawDescData = protoimpl.X.CompressGZIP(file_user_service_proto_rawDescData) + }) + return file_user_service_proto_rawDescData +} + +var file_user_service_proto_msgTypes = make([]protoimpl.MessageInfo, 1) +var file_user_service_proto_goTypes = []interface{}{ + (*GetMeRequest)(nil), // 0: pb.GetMeRequest + (*UserResponse)(nil), // 1: pb.UserResponse +} +var file_user_service_proto_depIdxs = []int32{ + 0, // 0: pb.UserService.GetMe:input_type -> pb.GetMeRequest + 1, // 1: pb.UserService.GetMe:output_type -> pb.UserResponse + 1, // [1:2] is the sub-list for method output_type + 0, // [0:1] is the sub-list for method input_type + 0, // [0:0] is the sub-list for extension type_name + 0, // [0:0] is the sub-list for extension extendee + 0, // [0:0] is the sub-list for field type_name +} + +func init() { file_user_service_proto_init() } +func file_user_service_proto_init() { + if File_user_service_proto != nil { + return + } + file_user_proto_init() + if !protoimpl.UnsafeEnabled { + file_user_service_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*GetMeRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + } + type x struct{} + out := protoimpl.TypeBuilder{ + File: protoimpl.DescBuilder{ + GoPackagePath: reflect.TypeOf(x{}).PkgPath(), + RawDescriptor: file_user_service_proto_rawDesc, + NumEnums: 0, + NumMessages: 1, + NumExtensions: 0, + NumServices: 1, + }, + GoTypes: file_user_service_proto_goTypes, + DependencyIndexes: file_user_service_proto_depIdxs, + MessageInfos: file_user_service_proto_msgTypes, + }.Build() + File_user_service_proto = out.File + file_user_service_proto_rawDesc = nil + file_user_service_proto_goTypes = nil + file_user_service_proto_depIdxs = nil +} diff --git a/pb/user_service_grpc.pb.go b/pb/user_service_grpc.pb.go new file mode 100644 index 0000000..e31a561 --- /dev/null +++ b/pb/user_service_grpc.pb.go @@ -0,0 +1,105 @@ +// Code generated by protoc-gen-go-grpc. DO NOT EDIT. +// versions: +// - protoc-gen-go-grpc v1.2.0 +// - protoc v3.20.1 +// source: user_service.proto + +package pb + +import ( + context "context" + grpc "google.golang.org/grpc" + codes "google.golang.org/grpc/codes" + status "google.golang.org/grpc/status" +) + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the grpc package it is being compiled against. +// Requires gRPC-Go v1.32.0 or later. +const _ = grpc.SupportPackageIsVersion7 + +// UserServiceClient is the client API for UserService service. +// +// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream. +type UserServiceClient interface { + GetMe(ctx context.Context, in *GetMeRequest, opts ...grpc.CallOption) (*UserResponse, error) +} + +type userServiceClient struct { + cc grpc.ClientConnInterface +} + +func NewUserServiceClient(cc grpc.ClientConnInterface) UserServiceClient { + return &userServiceClient{cc} +} + +func (c *userServiceClient) GetMe(ctx context.Context, in *GetMeRequest, opts ...grpc.CallOption) (*UserResponse, error) { + out := new(UserResponse) + err := c.cc.Invoke(ctx, "/pb.UserService/GetMe", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +// UserServiceServer is the server API for UserService service. +// All implementations must embed UnimplementedUserServiceServer +// for forward compatibility +type UserServiceServer interface { + GetMe(context.Context, *GetMeRequest) (*UserResponse, error) + mustEmbedUnimplementedUserServiceServer() +} + +// UnimplementedUserServiceServer must be embedded to have forward compatible implementations. +type UnimplementedUserServiceServer struct { +} + +func (UnimplementedUserServiceServer) GetMe(context.Context, *GetMeRequest) (*UserResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method GetMe not implemented") +} +func (UnimplementedUserServiceServer) mustEmbedUnimplementedUserServiceServer() {} + +// UnsafeUserServiceServer may be embedded to opt out of forward compatibility for this service. +// Use of this interface is not recommended, as added methods to UserServiceServer will +// result in compilation errors. +type UnsafeUserServiceServer interface { + mustEmbedUnimplementedUserServiceServer() +} + +func RegisterUserServiceServer(s grpc.ServiceRegistrar, srv UserServiceServer) { + s.RegisterService(&UserService_ServiceDesc, srv) +} + +func _UserService_GetMe_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(GetMeRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(UserServiceServer).GetMe(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/pb.UserService/GetMe", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(UserServiceServer).GetMe(ctx, req.(*GetMeRequest)) + } + return interceptor(ctx, in, info, handler) +} + +// UserService_ServiceDesc is the grpc.ServiceDesc for UserService service. +// It's only intended for direct use with grpc.RegisterService, +// and not to be introspected or modified (even as a copy) +var UserService_ServiceDesc = grpc.ServiceDesc{ + ServiceName: "pb.UserService", + HandlerType: (*UserServiceServer)(nil), + Methods: []grpc.MethodDesc{ + { + MethodName: "GetMe", + Handler: _UserService_GetMe_Handler, + }, + }, + Streams: []grpc.StreamDesc{}, + Metadata: "user_service.proto", +} diff --git a/proto-gen.sh b/proto-gen.sh new file mode 100644 index 0000000..1140d54 --- /dev/null +++ b/proto-gen.sh @@ -0,0 +1,6 @@ +#!/bin/bash + +rm -rf pb/*.go +protoc --proto_path=proto --go_out=pb --go_opt=paths=source_relative \ + --go-grpc_out=pb --go-grpc_opt=paths=source_relative \ + proto/*.proto \ No newline at end of file diff --git a/proto/auth_service.proto b/proto/auth_service.proto new file mode 100644 index 0000000..8afdc3f --- /dev/null +++ b/proto/auth_service.proto @@ -0,0 +1,17 @@ +syntax = "proto3"; + +package pb; + +import "rpc_signin_user.proto"; +import "rpc_signup_user.proto"; +import "user.proto"; + +option go_package = "github.com/wpcodevo/golang-mongodb/pb"; + +service AuthService { + rpc SignUpUser(SignUpUserInput) returns (GenericResponse) {} + rpc SignInUser(SignInUserInput) returns (SignInUserResponse) {} + rpc VerifyEmail(VerifyEmailRequest) returns (GenericResponse) {} +} + +message VerifyEmailRequest { string verificationCode = 1; } \ No newline at end of file diff --git a/proto/post.proto b/proto/post.proto new file mode 100644 index 0000000..b626870 --- /dev/null +++ b/proto/post.proto @@ -0,0 +1,18 @@ +syntax = "proto3"; + +package pb; + +option go_package = "github.com/wpcodevo/golang-mongodb/pb"; +import "google/protobuf/timestamp.proto"; + +message Post { + string Id = 1; + string Title = 2; + string Content = 3; + string Image = 4; + string User = 5; + google.protobuf.Timestamp created_at = 6; + google.protobuf.Timestamp updated_at = 7; +} + +message PostResponse { Post post = 1; } diff --git a/proto/post_service.proto b/proto/post_service.proto new file mode 100644 index 0000000..6eb14ea --- /dev/null +++ b/proto/post_service.proto @@ -0,0 +1,25 @@ +syntax = "proto3"; + +package pb; + +option go_package = "github.com/wpcodevo/golang-mongodb/pb"; +import "post.proto"; +import "rpc_create_post.proto"; +import "rpc_update_post.proto"; + +service PostService { + rpc CreatePost(CreatePostRequest) returns (PostResponse) {} + rpc GetPost(PostRequest) returns (PostResponse) {} + rpc GetPosts(GetPostsRequest) returns (stream Post) {} + rpc UpdatePost(UpdatePostRequest) returns (PostResponse) {} + rpc DeletePost(PostRequest) returns (DeletePostResponse) {} +} + +message GetPostsRequest { + optional int64 page = 1; + optional int64 limit = 2; +} + +message PostRequest { string Id = 1; } + +message DeletePostResponse { bool success = 1; } \ No newline at end of file diff --git a/proto/rpc_create_post.proto b/proto/rpc_create_post.proto new file mode 100644 index 0000000..03b9c1a --- /dev/null +++ b/proto/rpc_create_post.proto @@ -0,0 +1,12 @@ +syntax = "proto3"; + +package pb; + +option go_package = "github.com/wpcodevo/golang-mongodb/pb"; + +message CreatePostRequest { + string Title = 1; + string Content = 2; + string Image = 3; + string User = 4; +} diff --git a/proto/rpc_signin_user.proto b/proto/rpc_signin_user.proto new file mode 100644 index 0000000..f9b2621 --- /dev/null +++ b/proto/rpc_signin_user.proto @@ -0,0 +1,16 @@ +syntax = "proto3"; + +package pb; + +option go_package = "github.com/wpcodevo/golang-mongodb/pb"; + +message SignInUserInput { + string email = 1; + string password = 2; +} + +message SignInUserResponse { + string status = 1; + string access_token = 2; + string refresh_token = 3; +} \ No newline at end of file diff --git a/proto/rpc_signup_user.proto b/proto/rpc_signup_user.proto new file mode 100644 index 0000000..9d70037 --- /dev/null +++ b/proto/rpc_signup_user.proto @@ -0,0 +1,16 @@ +syntax = "proto3"; + +package pb; + +option go_package = "github.com/wpcodevo/golang-mongodb/pb"; + +import "user.proto"; + +message SignUpUserInput { + string name = 1; + string email = 2; + string password = 3; + string passwordConfirm = 4; +} + +message SignUpUserResponse { User user = 1; } diff --git a/proto/rpc_update_post.proto b/proto/rpc_update_post.proto new file mode 100644 index 0000000..a20aa0a --- /dev/null +++ b/proto/rpc_update_post.proto @@ -0,0 +1,13 @@ +syntax = "proto3"; + +package pb; + +option go_package = "github.com/wpcodevo/golang-mongodb/pb"; + +message UpdatePostRequest { + string Id = 1; + optional string Title = 2; + optional string Content = 3; + optional string Image = 4; + optional string User = 5; +} diff --git a/proto/user.proto b/proto/user.proto new file mode 100644 index 0000000..4962dde --- /dev/null +++ b/proto/user.proto @@ -0,0 +1,22 @@ +syntax = "proto3"; + +package pb; + +import "google/protobuf/timestamp.proto"; +option go_package = "github.com/wpcodevo/golang-mongodb/pb"; + +message User { + string id = 1; + string name = 2; + string email = 3; + string role = 4; + google.protobuf.Timestamp created_at = 5; + google.protobuf.Timestamp updated_at = 6; +} + +message UserResponse { User user = 1; } + +message GenericResponse { + string status = 1; + string message = 2; +} \ No newline at end of file diff --git a/proto/user_service.proto b/proto/user_service.proto new file mode 100644 index 0000000..5c6f965 --- /dev/null +++ b/proto/user_service.proto @@ -0,0 +1,13 @@ +syntax = "proto3"; + +package pb; + +import "user.proto"; + +option go_package = "github.com/wpcodevo/golang-mongodb/pb"; + +service UserService { + rpc GetMe(GetMeRequest) returns (UserResponse) {} +} + +message GetMeRequest { string Id = 1; } diff --git a/readMe.md b/readMe.md new file mode 100644 index 0000000..5888896 --- /dev/null +++ b/readMe.md @@ -0,0 +1 @@ +# Build gRPC Server API & Client with Golang and MongoDB diff --git a/routes/auth.routes.go b/routes/auth.routes.go new file mode 100644 index 0000000..d480c8b --- /dev/null +++ b/routes/auth.routes.go @@ -0,0 +1,27 @@ +package routes + +import ( + "github.com/gin-gonic/gin" + "github.com/wpcodevo/golang-mongodb/controllers" + "github.com/wpcodevo/golang-mongodb/middleware" + "github.com/wpcodevo/golang-mongodb/services" +) + +type AuthRouteController struct { + authController controllers.AuthController +} + +func NewAuthRouteController(authController controllers.AuthController) AuthRouteController { + return AuthRouteController{authController} +} + +func (rc *AuthRouteController) AuthRoute(rg *gin.RouterGroup, userService services.UserService) { + router := rg.Group("/auth") + + router.POST("/register", rc.authController.SignUpUser) + router.POST("/login", rc.authController.SignInUser) + router.GET("/refresh", rc.authController.RefreshAccessToken) + router.GET("/logout", middleware.DeserializeUser(userService), rc.authController.LogoutUser) + router.GET("/verifyemail/:verificationCode", rc.authController.VerifyEmail) + router.POST("/forgotPassword", rc.authController.ForgotPassword) +} diff --git a/routes/post.routes.go b/routes/post.routes.go new file mode 100644 index 0000000..3507517 --- /dev/null +++ b/routes/post.routes.go @@ -0,0 +1,24 @@ +package routes + +import ( + "github.com/gin-gonic/gin" + "github.com/wpcodevo/golang-mongodb/controllers" +) + +type PostRouteController struct { + postController controllers.PostController +} + +func NewPostControllerRoute(postController controllers.PostController) PostRouteController { + return PostRouteController{postController} +} + +func (r *PostRouteController) PostRoute(rg *gin.RouterGroup) { + router := rg.Group("/posts") + + router.GET("/", r.postController.FindPosts) + router.GET("/:postId", r.postController.FindPostById) + router.POST("/", r.postController.CreatePost) + router.PATCH("/:postId", r.postController.UpdatePost) + router.DELETE("/:postId", r.postController.DeletePost) +} diff --git a/routes/user.routes.go b/routes/user.routes.go new file mode 100644 index 0000000..0bd770b --- /dev/null +++ b/routes/user.routes.go @@ -0,0 +1,23 @@ +package routes + +import ( + "github.com/gin-gonic/gin" + "github.com/wpcodevo/golang-mongodb/controllers" + "github.com/wpcodevo/golang-mongodb/middleware" + "github.com/wpcodevo/golang-mongodb/services" +) + +type UserRouteController struct { + userController controllers.UserController +} + +func NewRouteUserController(userController controllers.UserController) UserRouteController { + return UserRouteController{userController} +} + +func (uc *UserRouteController) UserRoute(rg *gin.RouterGroup, userService services.UserService) { + + router := rg.Group("users") + router.Use(middleware.DeserializeUser(userService)) + router.GET("/me", uc.userController.GetMe) +} diff --git a/services/auth.service.go b/services/auth.service.go new file mode 100644 index 0000000..eaa9afe --- /dev/null +++ b/services/auth.service.go @@ -0,0 +1,8 @@ +package services + +import "github.com/wpcodevo/golang-mongodb/models" + +type AuthService interface { + SignUpUser(*models.SignUpInput) (*models.DBResponse, error) + SignInUser(*models.SignInInput) (*models.DBResponse, error) +} diff --git a/services/auth.service.impl.go b/services/auth.service.impl.go new file mode 100644 index 0000000..d144fb4 --- /dev/null +++ b/services/auth.service.impl.go @@ -0,0 +1,66 @@ +package services + +import ( + "context" + "errors" + "strings" + "time" + + "github.com/wpcodevo/golang-mongodb/models" + "github.com/wpcodevo/golang-mongodb/utils" + "go.mongodb.org/mongo-driver/bson" + "go.mongodb.org/mongo-driver/mongo" + "go.mongodb.org/mongo-driver/mongo/options" +) + +type AuthServiceImpl struct { + collection *mongo.Collection + ctx context.Context +} + +func NewAuthService(collection *mongo.Collection, ctx context.Context) AuthService { + return &AuthServiceImpl{collection, ctx} +} + +func (uc *AuthServiceImpl) SignUpUser(user *models.SignUpInput) (*models.DBResponse, error) { + user.CreatedAt = time.Now() + user.UpdatedAt = user.CreatedAt + user.Email = strings.ToLower(user.Email) + user.PasswordConfirm = "" + user.Verified = false + user.Role = "user" + + hashedPassword, _ := utils.HashPassword(user.Password) + user.Password = hashedPassword + res, err := uc.collection.InsertOne(uc.ctx, &user) + + if err != nil { + if er, ok := err.(mongo.WriteException); ok && er.WriteErrors[0].Code == 11000 { + return nil, errors.New("user with that email already exist") + } + return nil, err + } + + // Create a unique index for the email field + opt := options.Index() + opt.SetUnique(true) + index := mongo.IndexModel{Keys: bson.M{"email": 1}, Options: opt} + + if _, err := uc.collection.Indexes().CreateOne(uc.ctx, index); err != nil { + return nil, errors.New("could not create index for email") + } + + var newUser *models.DBResponse + query := bson.M{"_id": res.InsertedID} + + err = uc.collection.FindOne(uc.ctx, query).Decode(&newUser) + if err != nil { + return nil, err + } + + return newUser, nil +} + +func (uc *AuthServiceImpl) SignInUser(*models.SignInInput) (*models.DBResponse, error) { + return nil, nil +} diff --git a/services/post.service.go b/services/post.service.go new file mode 100644 index 0000000..24010cc --- /dev/null +++ b/services/post.service.go @@ -0,0 +1,11 @@ +package services + +import "github.com/wpcodevo/golang-mongodb/models" + +type PostService interface { + CreatePost(*models.CreatePostRequest) (*models.DBPost, error) + UpdatePost(string, *models.UpdatePost) (*models.DBPost, error) + FindPostById(string) (*models.DBPost, error) + FindPosts(page int, limit int) ([]*models.DBPost, error) + DeletePost(string) error +} diff --git a/services/post.service.impl.go b/services/post.service.impl.go new file mode 100644 index 0000000..320751a --- /dev/null +++ b/services/post.service.impl.go @@ -0,0 +1,155 @@ +package services + +import ( + "context" + "errors" + "time" + + "github.com/wpcodevo/golang-mongodb/models" + "github.com/wpcodevo/golang-mongodb/utils" + "go.mongodb.org/mongo-driver/bson" + "go.mongodb.org/mongo-driver/bson/primitive" + "go.mongodb.org/mongo-driver/mongo" + "go.mongodb.org/mongo-driver/mongo/options" +) + +type PostServiceImpl struct { + postCollection *mongo.Collection + ctx context.Context +} + +func NewPostService(postCollection *mongo.Collection, ctx context.Context) PostService { + return &PostServiceImpl{postCollection, ctx} +} + +func (p *PostServiceImpl) CreatePost(post *models.CreatePostRequest) (*models.DBPost, error) { + post.CreateAt = time.Now() + post.UpdatedAt = post.CreateAt + res, err := p.postCollection.InsertOne(p.ctx, post) + + if err != nil { + if er, ok := err.(mongo.WriteException); ok && er.WriteErrors[0].Code == 11000 { + return nil, errors.New("post with that title already exists") + } + return nil, err + } + + opt := options.Index() + opt.SetUnique(true) + + index := mongo.IndexModel{Keys: bson.M{"title": 1}, Options: opt} + + if _, err := p.postCollection.Indexes().CreateOne(p.ctx, index); err != nil { + return nil, errors.New("could not create index for title") + } + + var newPost *models.DBPost + query := bson.M{"_id": res.InsertedID} + if err = p.postCollection.FindOne(p.ctx, query).Decode(&newPost); err != nil { + return nil, err + } + + return newPost, nil +} + +func (p *PostServiceImpl) UpdatePost(id string, data *models.UpdatePost) (*models.DBPost, error) { + doc, err := utils.ToDoc(data) + if err != nil { + return nil, err + } + + obId, _ := primitive.ObjectIDFromHex(id) + query := bson.D{{Key: "_id", Value: obId}} + update := bson.D{{Key: "$set", Value: doc}} + res := p.postCollection.FindOneAndUpdate(p.ctx, query, update, options.FindOneAndUpdate().SetReturnDocument(1)) + + var updatedPost *models.DBPost + if err := res.Decode(&updatedPost); err != nil { + return nil, errors.New("no post with that Id exists") + } + + return updatedPost, nil +} + +func (p *PostServiceImpl) FindPostById(id string) (*models.DBPost, error) { + obId, _ := primitive.ObjectIDFromHex(id) + + query := bson.M{"_id": obId} + + var post *models.DBPost + + if err := p.postCollection.FindOne(p.ctx, query).Decode(&post); err != nil { + if err == mongo.ErrNoDocuments { + return nil, errors.New("no document with that Id exists") + } + + return nil, err + } + + return post, nil +} + +func (p *PostServiceImpl) FindPosts(page int, limit int) ([]*models.DBPost, error) { + if page == 0 { + page = 1 + } + + if limit == 0 { + limit = 10 + } + + skip := (page - 1) * limit + + opt := options.FindOptions{} + opt.SetLimit(int64(limit)) + opt.SetSkip(int64(skip)) + opt.SetSort(bson.M{"created_at": -1}) + + query := bson.M{} + + cursor, err := p.postCollection.Find(p.ctx, query, &opt) + if err != nil { + return nil, err + } + + defer cursor.Close(p.ctx) + + var posts []*models.DBPost + + for cursor.Next(p.ctx) { + post := &models.DBPost{} + err := cursor.Decode(post) + + if err != nil { + return nil, err + } + + posts = append(posts, post) + } + + if err := cursor.Err(); err != nil { + return nil, err + } + + if len(posts) == 0 { + return []*models.DBPost{}, nil + } + + return posts, nil +} + +func (p *PostServiceImpl) DeletePost(id string) error { + obId, _ := primitive.ObjectIDFromHex(id) + query := bson.M{"_id": obId} + + res, err := p.postCollection.DeleteOne(p.ctx, query) + if err != nil { + return err + } + + if res.DeletedCount == 0 { + return errors.New("no document with that Id exists") + } + + return nil +} diff --git a/services/user.service.go b/services/user.service.go new file mode 100644 index 0000000..cc428ad --- /dev/null +++ b/services/user.service.go @@ -0,0 +1,9 @@ +package services + +import "github.com/wpcodevo/golang-mongodb/models" + +type UserService interface { + FindUserById(id string) (*models.DBResponse, error) + FindUserByEmail(email string) (*models.DBResponse, error) + UpdateUserById(id string, data *models.UpdateInput) (*models.DBResponse, error) +} diff --git a/services/user.service.impl.go b/services/user.service.impl.go new file mode 100644 index 0000000..a3e6504 --- /dev/null +++ b/services/user.service.impl.go @@ -0,0 +1,80 @@ +package services + +import ( + "context" + "errors" + "fmt" + "strings" + + "github.com/wpcodevo/golang-mongodb/models" + "github.com/wpcodevo/golang-mongodb/utils" + "go.mongodb.org/mongo-driver/bson" + "go.mongodb.org/mongo-driver/bson/primitive" + "go.mongodb.org/mongo-driver/mongo" + "go.mongodb.org/mongo-driver/mongo/options" +) + +type UserServiceImpl struct { + collection *mongo.Collection + ctx context.Context +} + +func NewUserServiceImpl(collection *mongo.Collection, ctx context.Context) UserService { + return &UserServiceImpl{collection, ctx} +} + +func (us *UserServiceImpl) FindUserById(id string) (*models.DBResponse, error) { + oid, _ := primitive.ObjectIDFromHex(id) + + var user *models.DBResponse + + query := bson.M{"_id": oid} + err := us.collection.FindOne(us.ctx, query).Decode(&user) + + if err != nil { + if err == mongo.ErrNoDocuments { + return &models.DBResponse{}, err + } + return nil, err + } + + return user, nil +} + +func (us *UserServiceImpl) FindUserByEmail(email string) (*models.DBResponse, error) { + var user *models.DBResponse + + query := bson.M{"email": strings.ToLower(email)} + err := us.collection.FindOne(us.ctx, query).Decode(&user) + + if err != nil { + if err == mongo.ErrNoDocuments { + return &models.DBResponse{}, err + } + return nil, err + } + + return user, nil +} + +func (uc *UserServiceImpl) UpdateUserById(id string, data *models.UpdateInput) (*models.DBResponse, error) { + doc, err := utils.ToDoc(data) + if err != nil { + return &models.DBResponse{}, err + } + + fmt.Println(data) + + obId, _ := primitive.ObjectIDFromHex(id) + + query := bson.D{{Key: "_id", Value: obId}} + update := bson.D{{Key: "$set", Value: doc}} + result := uc.collection.FindOneAndUpdate(uc.ctx, query, update, options.FindOneAndUpdate().SetReturnDocument(1)) + + var updatedUser *models.DBResponse + if err := result.Decode(&updatedUser); err != nil { + return nil, errors.New("no document with that id exists") + } + + return updatedUser, nil +} diff --git a/templates/base.html b/templates/base.html new file mode 100644 index 0000000..314c963 --- /dev/null +++ b/templates/base.html @@ -0,0 +1,32 @@ +{{define "base"}} + + + + + + {{template "styles" .}} + {{ .Subject}} + + + + + + + + + + + +{{end}} diff --git a/templates/resetPassword.html b/templates/resetPassword.html new file mode 100644 index 0000000..b067c03 --- /dev/null +++ b/templates/resetPassword.html @@ -0,0 +1,54 @@ +{{template "base" .}} {{define "content"}} + + + + + + + + +{{end}} diff --git a/templates/styles.html b/templates/styles.html new file mode 100644 index 0000000..3a51224 --- /dev/null +++ b/templates/styles.html @@ -0,0 +1,331 @@ +{{define "styles"}} + +{{end}} diff --git a/templates/verificationCode.html b/templates/verificationCode.html new file mode 100644 index 0000000..093b541 --- /dev/null +++ b/templates/verificationCode.html @@ -0,0 +1,50 @@ +{{template "base" .}} {{define "content"}} + + + + + + + + +{{end}} diff --git a/tmp/build-errors.log b/tmp/build-errors.log new file mode 100644 index 0000000..b9a46ca --- /dev/null +++ b/tmp/build-errors.log @@ -0,0 +1 @@ +exit status 1exit status 0xc000013aexit status 1exit status 1exit status 2exit status 2exit status 2exit status 2exit status 2exit status 2exit status 2exit status 2exit status 2exit status 2exit status 2exit status 2exit status 2exit status 2exit status 2exit status 2exit status 2exit status 1exit status 1exit status 2exit status 1exit status 1exit status 2exit status 1exit status 2exit status 1exit status 2exit status 1exit status 1exit status 2exit status 2exit status 0xc000013aexit status 2 \ No newline at end of file diff --git a/utils/email.go b/utils/email.go new file mode 100644 index 0000000..4fabae8 --- /dev/null +++ b/utils/email.go @@ -0,0 +1,89 @@ +package utils + +import ( + "bytes" + "crypto/tls" + "fmt" + "log" + "os" + "path/filepath" + "text/template" + + "github.com/k3a/html2text" + "github.com/wpcodevo/golang-mongodb/config" + "github.com/wpcodevo/golang-mongodb/models" + "gopkg.in/gomail.v2" +) + +type EmailData struct { + URL string + FirstName string + Subject string +} + +// 👇 Email template parser + +func ParseTemplateDir(dir string) (*template.Template, error) { + var paths []string + err := filepath.Walk(dir, func(path string, info os.FileInfo, err error) error { + if err != nil { + return err + } + if !info.IsDir() { + paths = append(paths, path) + } + return nil + }) + + fmt.Println("Am parsing templates...") + + if err != nil { + return nil, err + } + + return template.ParseFiles(paths...) +} + +func SendEmail(user *models.DBResponse, data *EmailData, templateName string) error { + config, err := config.LoadConfig(".") + + if err != nil { + log.Fatal("could not load config", err) + } + + // Sender data. + from := config.EmailFrom + smtpPass := config.SMTPPass + smtpUser := config.SMTPUser + to := user.Email + smtpHost := config.SMTPHost + smtpPort := config.SMTPPort + + var body bytes.Buffer + + template, err := ParseTemplateDir("templates") + if err != nil { + log.Fatal("Could not parse template", err) + } + + template = template.Lookup(templateName) + template.Execute(&body, &data) + fmt.Println(template.Name()) + + m := gomail.NewMessage() + + m.SetHeader("From", from) + m.SetHeader("To", to) + m.SetHeader("Subject", data.Subject) + m.SetBody("text/html", body.String()) + m.AddAlternative("text/plain", html2text.HTML2Text(body.String())) + + d := gomail.NewDialer(smtpHost, smtpPort, smtpUser, smtpPass) + d.TLSConfig = &tls.Config{InsecureSkipVerify: true} + + // Send Email + if err := d.DialAndSend(m); err != nil { + return err + } + return nil +} diff --git a/utils/encode.go b/utils/encode.go new file mode 100644 index 0000000..22a2cd7 --- /dev/null +++ b/utils/encode.go @@ -0,0 +1,17 @@ +package utils + +import "encoding/base64" + +func Encode(s string) string { + data := base64.StdEncoding.EncodeToString([]byte(s)) + return string(data) +} + +func Decode(s string) (string, error) { + data, err := base64.StdEncoding.DecodeString(s) + if err != nil { + return "", err + } + + return string(data), nil +} diff --git a/utils/helper.go b/utils/helper.go new file mode 100644 index 0000000..3cd5674 --- /dev/null +++ b/utils/helper.go @@ -0,0 +1,13 @@ +package utils + +import "go.mongodb.org/mongo-driver/bson" + +func ToDoc(v interface{}) (doc *bson.D, err error) { + data, err := bson.Marshal(v) + if err != nil { + return + } + + err = bson.Unmarshal(data, &doc) + return +} diff --git a/utils/password.go b/utils/password.go new file mode 100644 index 0000000..f255eb7 --- /dev/null +++ b/utils/password.go @@ -0,0 +1,20 @@ +package utils + +import ( + "fmt" + + "golang.org/x/crypto/bcrypt" +) + +func HashPassword(password string) (string, error) { + hashedPassword, err := bcrypt.GenerateFromPassword([]byte(password), bcrypt.DefaultCost) + + if err != nil { + return "", fmt.Errorf("could not hash password %w", err) + } + return string(hashedPassword), nil +} + +func VerifyPassword(hashedPassword string, candidatePassword string) error { + return bcrypt.CompareHashAndPassword([]byte(hashedPassword), []byte(candidatePassword)) +} diff --git a/utils/token.go b/utils/token.go new file mode 100644 index 0000000..20c9756 --- /dev/null +++ b/utils/token.go @@ -0,0 +1,68 @@ +package utils + +import ( + "encoding/base64" + "fmt" + "time" + + "github.com/golang-jwt/jwt" +) + +func CreateToken(ttl time.Duration, payload interface{}, privateKey string) (string, error) { + decodedPrivateKey, err := base64.StdEncoding.DecodeString(privateKey) + if err != nil { + return "", fmt.Errorf("could not decode key: %w", err) + } + key, err := jwt.ParseRSAPrivateKeyFromPEM(decodedPrivateKey) + + if err != nil { + return "", fmt.Errorf("create: parse key: %w", err) + } + + now := time.Now().UTC() + + claims := make(jwt.MapClaims) + claims["sub"] = payload + claims["exp"] = now.Add(ttl).Unix() + claims["iat"] = now.Unix() + claims["nbf"] = now.Unix() + + token, err := jwt.NewWithClaims(jwt.SigningMethodRS256, claims).SignedString(key) + + if err != nil { + return "", fmt.Errorf("create: sign token: %w", err) + } + + return token, nil +} + +func ValidateToken(token string, publicKey string) (interface{}, error) { + decodedPublicKey, err := base64.StdEncoding.DecodeString(publicKey) + if err != nil { + return nil, fmt.Errorf("could not decode: %w", err) + } + + key, err := jwt.ParseRSAPublicKeyFromPEM(decodedPublicKey) + + if err != nil { + return "", fmt.Errorf("validate: parse key: %w", err) + } + + parsedToken, err := jwt.Parse(token, func(t *jwt.Token) (interface{}, error) { + if _, ok := t.Method.(*jwt.SigningMethodRSA); !ok { + return nil, fmt.Errorf("unexpected method: %s", t.Header["alg"]) + } + return key, nil + }) + + if err != nil { + return nil, fmt.Errorf("validate: %w", err) + } + + claims, ok := parsedToken.Claims.(jwt.MapClaims) + if !ok || !parsedToken.Valid { + return nil, fmt.Errorf("validate: invalid token") + } + + return claims["sub"], nil +} From 04a949d04412ddde56f959885055dbd039f697f2 Mon Sep 17 00:00:00 2001 From: CODEVO Date: Sun, 2 Oct 2022 19:30:20 +0000 Subject: [PATCH 15/16] Update readMe.md --- readMe.md | 207 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 207 insertions(+) diff --git a/readMe.md b/readMe.md index 5888896..e0befc5 100644 --- a/readMe.md +++ b/readMe.md @@ -1 +1,208 @@ # Build gRPC Server API & Client with Golang and MongoDB + +## 1. API with Golang + MongoDB + Redis + Gin Gonic: Project Setup + +In this article, you'll learn how to set up a Golang application with MongoDB-Go-driver, Gin Gonic, and Go Redis. Later, we'll access both the Redis and MongoDB databases directly in VS Code using a MySQL VS Code extension. + +![API with Golang + MongoDB + Redis + Gin Gonic: Project Setup](https://codevoweb.com/wp-content/uploads/2022/05/API-with-Golang-MongoDB-Redis-and-Gin-Gonic-Project-Setup.webp) + +### Topics Covered + +- Setup Golang with MongoDB and Redis +- Creating MongoDB and Redis Database with Docker-compose +- Setup Environment Variables +- How to Connect Golang App to Redis and MongoDB +- Test the Golang API +- How to Connect to MongoDB and Redis Servers in VS Code + +Read the entire article here: [https://codevoweb.com/api-golang-mongodb-gin-gonic-project-setup](https://codevoweb.com/api-golang-mongodb-gin-gonic-project-setup) + + +## 2. Golang & MongoDB: JWT Authentication and Authorization + +In this article, you'll learn how to implement RS256 JWT (JSON Web Token) Authentication and Authorization with Golang, Gin Gonic, MongoDB-Go-driver, and Docker-compose. + +![Golang & MongoDB: JWT Authentication and Authorization](https://codevoweb.com/wp-content/uploads/2022/05/Golang-and-MongoDB-JWT-Authentication-and-Authorization.webp) + +### Topics Covered + +- Golang & MongoDB JWT Authentication Overview +- JWT Authentication Example with Golang and MongoDB +- How to Generate Public and Private Keys +- Update Environment Variables with Viper +- Creating the User models with structs +- Creating an Auth and User Interfaces + - Authentication Interface + - User Interface +- Create utility functions to hash and verify password +- Create services that interact with the database + - Auth interface implementation + - User interface implementation +- Create a utility function to sign and verify JWT tokens + - Create Json Web Token + - Verify JSON Web Token +- Create the authentication controllers + - Signup user controller + - Login user controller + - Refresh access token controller + - Logout user controller +- Authentication Middleware Guard +- Create the user controllers +- Create API Routes with Gin + - Auth Routes + - User Routes +- Add the Routes to the Gin Middleware Pipeline + +Read the entire article here: [https://codevoweb.com/golang-mongodb-jwt-authentication-authorization](https://codevoweb.com/golang-mongodb-jwt-authentication-authorization) + +## 3. API with Golang + MongoDB: Send HTML Emails with Gomail + +In this article, you'll learn how to send HTML emails with Golang, Gomail, MongoDB-Go-Driver, Redis, and Docker-compose. Also, you'll learn how to generate HTML templates with the standard Golang html/template package. + +![API with Golang + MongoDB: Send HTML Emails with Gomail](https://codevoweb.com/wp-content/uploads/2022/05/API-with-Golang-MongoDB-Send-HTML-Emails-with-Gomail.webp) + +### Topics Covered + +- Send Emails with Golang, MongoDB, and Gomail Overview +- Creating the HTML Email Templates with Golang +- Create an SMTP Provider Account +- Load and Validate Environment Variables Viper +- Create a Utility Function to Send the Emails +- Update the SignUp Controller + +Read the entire article here: [https://codevoweb.com/api-golang-mongodb-send-html-emails-gomail](https://codevoweb.com/api-golang-mongodb-send-html-emails-gomail) + + +## 4. API with Golang, Gin Gonic & MongoDB: Forget/Reset Password + +In this article, you'll learn how to implement forget/reset password functionality with Golang, Gin Gonic, Gomail, MongoDB-Go-driver, Redis, and Docker-compose. + +![API with Golang, Gin Gonic & MongoDB: Forget/Reset Password](https://codevoweb.com/wp-content/uploads/2022/05/API-with-Golang-Gin-Gonic-MongoDB-Forget-Reset-Password.webp) + +### Topics Covered + +- Forget/Reset Password with Golang, Gin, and MongoDB +- Create the MongoDB Model Structs +- Create the HTML Email Templates with Golang +- Define a Utility Function to Parse the HTML Templates +- Create a Function to Send the HTML Emails +- Add the Forgot Password Controller +- Add the Reset Password Controller +- Register the Gin API Routes + +Read the entire article here: [https://codevoweb.com/api-golang-gin-gonic-mongodb-forget-reset-password](https://codevoweb.com/api-golang-gin-gonic-mongodb-forget-reset-password) + + +## 5. Build Golang gRPC Server and Client: SignUp User & Verify Email + +In this article, you'll learn how to create a gRPC server to register a user and verify their email address using Golang, MongoDB-Go-driver, Gomail, and Docker-compose. + +![Build Golang gRPC Server and Client: SignUp User & Verify Email](https://codevoweb.com/wp-content/uploads/2022/05/Build-Golang-gRPC-Server-and-Client-SignUp-User-Verify-Email.webp) + +### Topics Covered + +- gRPC Project setup in Golang +- Create the gRPC Request and Response Messages + - Define the gRPC User messages + - Define the gRPC Request and Response Message to SignUp User +- Create the gRPC Service Methods +- Generate the gRPC client and server interfaces +- Start the gRPC Server +- Test the gRPC API Server with Golang Evans +- Create the gRPC API Controllers + - Register User gRPC Controller + - Verify User gRPC Controller +- Create the gRPC Client to Register a User + +Read the entire article here: [https://codevoweb.com/golang-grpc-server-and-client-signup-user-verify-email](https://codevoweb.com/golang-grpc-server-and-client-signup-user-verify-email) + +## 6. Build Golang gRPC Server and Client: Access & Refresh Tokens + +In this article, you'll learn how to implement JWT access and refresh tokens with gRPC using Golang, MongoDB-Go-driver, Gomail, Docker, and Docker-compose. + +![Build Golang gRPC Server and Client: Access & Refresh Tokens](https://codevoweb.com/wp-content/uploads/2022/05/Build-Golang-gRPC-Server-and-Client-Access-Refresh-Tokens.webp) + +### Topics Covered + +- Create the gRPC Request and Response Messages + - Create the gRPC User messages + - Define the gRPC Request and Response Message to Login User + - Update the Authentication gRPC Service + - Create a gRPC User Service +- Create the gRPC Controllers +- Create the gRPC Servers +- Register the gRPC Servers +- Create the gRPC Clients in Golang +- Connect the gRPC Client to the gRPC Server + +Read the entire article here: [https://codevoweb.com/golang-grpc-server-and-client-access-refresh-tokens](https://codevoweb.com/golang-grpc-server-and-client-access-refresh-tokens) + +## 7. Build CRUD RESTful API Server with Golang, Gin, and MongoDB + +In this article, you'll learn how to build a CRUD RESTful API server with Golang, Gin Gonic, MongoDB-Go-driver, Docker, and Docker-compose. + +![Build CRUD RESTful API Server with Golang, Gin, and MongoDB](https://codevoweb.com/wp-content/uploads/2022/05/Build-CRUD-RESTful-API-Server-with-Golang-Gin-and-MongoDB.webp) + +### Topics Covered + +- Golang, Gin Gonic, MongoDB CRUD RESTful API Overview +- Create the Models with Structs +- Create the Service Interface +- Create Methods to Implement the Interface + - Initialize the Service Struct + - Define a Service to Create a Post + - Define a Service to Update Post + - Define a Service to Delete Post + - Define a Service to Get Single Post + - Define a Service to Get All Posts +- Create Controllers to Perform the CRUD Operations + - Initialize the Controller Struct + - Define a Controller to Create a Post + - Define a Controller to Update a Post + - Define a Controller to Delete a Post + - Define a Controller to Get a Single Post + - Define a Controller to Get All Posts +- Create the Routes for the Controllers +- Initialize the Constructors and Start the Gin Server + +Read the entire article here: [https://codevoweb.com/crud-restful-api-server-with-golang-and-mongodb](https://codevoweb.com/crud-restful-api-server-with-golang-and-mongodb) + + +## 8. Build CRUD gRPC Server API & Client with Golang and MongoDB + +In this article, you'll learn how to build a CRUD gRPC API server with Golang, MongoDB-Go-driver, and Docker-compose. You'll also build a gRPC client to interact with the gRPC API. + +![Build CRUD gRPC Server API & Client with Golang and MongoDB](https://codevoweb.com/wp-content/uploads/2022/06/Build-CRUD-gRPC-Server-API-Client-with-Golang-and-MongoDB.webp) + +### Topics Covered + +- Define the Models with Structs +- Create the ProtoBuf Messages +- Define the gRPC Service and RPC Methods +- Define a Custom Service Interface +- Create Methods to Implement the Service Interface + - Create a Constructor to Implement the Service Interface + - Create a new Post + - Update a Post + - Find a Post + - Retrieve All Posts + - Delete a Post +- Define the gRPC Controllers +- Register the gRPC Services and Start the gRPC Server +- Test the gRPC API Server with Evans CLI +- Create the gRPC API Handlers in Golang + - CreatePost gRPC Handler + - UpdatePost gRPC Service Handler + - GetPost gRPC Service Handler + - DeletePost gRPC Service Handler + - GetPosts gRPC Service Handler +- Testing the gRPC Services with Evans Cli +- Create the gRPC Clients + - gRPC Client to Create a Post + - gRPC Client to Update a Post + - gRPC Client to Get a Single Post + - gRPC Client to Get All Posts + - gRPC Client to Delete a Post +- Register the gRPC Services + +Read the entire article here: [https://codevoweb.com/crud-grpc-server-api-client-with-golang-and-mongodb](https://codevoweb.com/crud-grpc-server-api-client-with-golang-and-mongodb) From c57ad9aa6ced19053fb749e943457d215ba5fc44 Mon Sep 17 00:00:00 2001 From: Edem Date: Sat, 30 Mar 2024 11:35:29 +0000 Subject: [PATCH 16/16] run both gin and grpc in parallel --- .air.toml | 2 +- Golang_API.postman_collection.json | 309 +++++++++++++++++++++++++++++ cmd/client/main.go | 2 +- cmd/server/main.go | 8 +- tmp/build-errors.log | 1 - 5 files changed, 317 insertions(+), 5 deletions(-) create mode 100644 Golang_API.postman_collection.json delete mode 100644 tmp/build-errors.log diff --git a/.air.toml b/.air.toml index 162718c..e7575f9 100644 --- a/.air.toml +++ b/.air.toml @@ -3,7 +3,7 @@ testdata_dir = "testdata" tmp_dir = "tmp" [build] - bin = "tmp\\main.exe" + bin = "./tmp/main.exe" cmd = "go build -o ./tmp/main.exe ./cmd/server/main.go" delay = 1000 exclude_dir = ["assets", "tmp", "vendor", "testdata"] diff --git a/Golang_API.postman_collection.json b/Golang_API.postman_collection.json new file mode 100644 index 0000000..5d299b6 --- /dev/null +++ b/Golang_API.postman_collection.json @@ -0,0 +1,309 @@ +{ + "info": { + "_postman_id": "112e818d-eb80-4ac7-bd1f-181e32484495", + "name": "Golang_API", + "schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json", + "_exporter_id": "14791724" + }, + "item": [ + { + "name": "Auth", + "item": [ + { + "name": "Register", + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\r\n \"email\": \"admin@admin.com\",\r\n \"name\": \"Admin\",\r\n \"photo\": \"default.png\",\r\n \"password\": \"password123\",\r\n \"passwordConfirm\": \"password123\"\r\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "localhost:8000/api/auth/register", + "host": [ + "localhost" + ], + "port": "8000", + "path": [ + "api", + "auth", + "register" + ] + } + }, + "response": [] + }, + { + "name": "Refresh Token", + "request": { + "method": "GET", + "header": [], + "url": { + "raw": "localhost:8000/api/auth/refresh", + "host": [ + "localhost" + ], + "port": "8000", + "path": [ + "api", + "auth", + "refresh" + ] + } + }, + "response": [] + }, + { + "name": "Logout", + "request": { + "method": "GET", + "header": [], + "url": { + "raw": "localhost:8000/api/auth/logout", + "host": [ + "localhost" + ], + "port": "8000", + "path": [ + "api", + "auth", + "logout" + ] + } + }, + "response": [] + }, + { + "name": "Login", + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\r\n \"email\": \"admin@admin.com\",\r\n \"password\": \"password123\"\r\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "localhost:8000/api/auth/login", + "host": [ + "localhost" + ], + "port": "8000", + "path": [ + "api", + "auth", + "login" + ] + } + }, + "response": [] + }, + { + "name": "Verify Email Address", + "request": { + "method": "GET", + "header": [], + "url": { + "raw": "{{host}}/api/auth/verifyemail/M3ypLxqQMEMgRgWHwxee", + "host": [ + "{{host}}" + ], + "path": [ + "api", + "auth", + "verifyemail", + "M3ypLxqQMEMgRgWHwxee" + ] + } + }, + "response": [] + } + ] + }, + { + "name": "User", + "item": [ + { + "name": "Get Me", + "request": { + "method": "GET", + "header": [], + "url": { + "raw": "localhost:8000/api/users/me", + "host": [ + "localhost" + ], + "port": "8000", + "path": [ + "api", + "users", + "me" + ] + } + }, + "response": [] + } + ] + }, + { + "name": "Post", + "item": [ + { + "name": "Create Post", + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\r\n \"title\": \"My first Python FASTAPI app project\",\r\n \"category\": \"Python\",\r\n \"content\": \"My content haha My content haha\",\r\n \"image\": \"default.png\"\r\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "localhost:8000/api/posts", + "host": [ + "localhost" + ], + "port": "8000", + "path": [ + "api", + "posts" + ] + } + }, + "response": [] + }, + { + "name": "Get Post", + "request": { + "method": "GET", + "header": [], + "url": { + "raw": "localhost:8000/api/posts/328cd0be-eeac-4be4-b764-7d3dc95695b2", + "host": [ + "localhost" + ], + "port": "8000", + "path": [ + "api", + "posts", + "328cd0be-eeac-4be4-b764-7d3dc95695b2" + ] + } + }, + "response": [] + }, + { + "name": "Update Post", + "request": { + "method": "PATCH", + "header": [], + "body": { + "mode": "raw", + "raw": "{\r\n \"title\": \"Updated My first golang GORM app project\",\r\n \"category\": \"Golang\"\r\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "localhost:8000/api/posts/e891ac2e-5371-45e3-a0d4-781e8c365905", + "host": [ + "localhost" + ], + "port": "8000", + "path": [ + "api", + "posts", + "e891ac2e-5371-45e3-a0d4-781e8c365905" + ] + } + }, + "response": [] + }, + { + "name": "Delete Post", + "request": { + "method": "DELETE", + "header": [], + "url": { + "raw": "localhost:8000/api/posts/66e1374e-d1f5-4e70-ad61-1a014ba8309b", + "host": [ + "localhost" + ], + "port": "8000", + "path": [ + "api", + "posts", + "66e1374e-d1f5-4e70-ad61-1a014ba8309b" + ] + } + }, + "response": [] + }, + { + "name": "Get All Posts", + "request": { + "method": "GET", + "header": [], + "url": { + "raw": "localhost:8000/api/posts?page=1&limit=10", + "host": [ + "localhost" + ], + "port": "8000", + "path": [ + "api", + "posts" + ], + "query": [ + { + "key": "page", + "value": "1" + }, + { + "key": "limit", + "value": "10" + } + ] + } + }, + "response": [] + }, + { + "name": "Health Checker", + "request": { + "method": "GET", + "header": [], + "url": { + "raw": "http://localhost:8000/api/healthchecker", + "protocol": "http", + "host": [ + "localhost" + ], + "port": "8000", + "path": [ + "api", + "healthchecker" + ] + } + }, + "response": [] + } + ] + } + ] +} \ No newline at end of file diff --git a/cmd/client/main.go b/cmd/client/main.go index 049fa45..07d7cb9 100644 --- a/cmd/client/main.go +++ b/cmd/client/main.go @@ -71,7 +71,7 @@ func main() { } // Create Post - if false { + if true { createPostClient := client.NewCreatePostClient(conn) args := &pb.CreatePostRequest{ diff --git a/cmd/server/main.go b/cmd/server/main.go index d6fdb20..e31da03 100644 --- a/cmd/server/main.go +++ b/cmd/server/main.go @@ -111,8 +111,12 @@ func main() { defer mongoclient.Disconnect(ctx) - // startGinServer(config) - startGrpcServer(config) + // Start gRPC server in a separate goroutine + go startGrpcServer(config) + + // Start Gin server in the main goroutine + startGinServer(config) + } func startGrpcServer(config config.Config) { diff --git a/tmp/build-errors.log b/tmp/build-errors.log deleted file mode 100644 index b9a46ca..0000000 --- a/tmp/build-errors.log +++ /dev/null @@ -1 +0,0 @@ -exit status 1exit status 0xc000013aexit status 1exit status 1exit status 2exit status 2exit status 2exit status 2exit status 2exit status 2exit status 2exit status 2exit status 2exit status 2exit status 2exit status 2exit status 2exit status 2exit status 2exit status 2exit status 2exit status 1exit status 1exit status 2exit status 1exit status 1exit status 2exit status 1exit status 2exit status 1exit status 2exit status 1exit status 1exit status 2exit status 2exit status 0xc000013aexit status 2 \ No newline at end of file