├── proto-gen.sh ├── services ├── auth.service.go ├── user.service.go ├── post.service.go ├── auth.service.impl.go ├── user.service.impl.go └── post.service.impl.go ├── proto ├── rpc_create_post.proto ├── user_service.proto ├── rpc_update_post.proto ├── rpc_signin_user.proto ├── rpc_signup_user.proto ├── post.proto ├── user.proto ├── auth_service.proto └── post_service.proto ├── utils ├── helper.go ├── encode.go ├── password.go ├── token.go └── email.go ├── Makefile ├── .gitignore ├── docker-compose.yml ├── tmp └── build-errors.log ├── gapi ├── post-server.go ├── rpc_delete_post.go ├── user-server.go ├── rpc_get_me.go ├── auth-server.go ├── rpc_list_posts.go ├── rpc_get_post.go ├── rpc_verify_user.go ├── rpc_create_post.go ├── rpc_update_post.go ├── rpc_signin_user.go └── rpc_signup_user.go ├── controllers ├── user.controller.go ├── post.controller.go └── auth.controller.go ├── routes ├── user.routes.go ├── post.routes.go └── auth.routes.go ├── client ├── geMe_client.go ├── getPost_client.go ├── signin_client.go ├── createPost_client.go ├── updatePost_client.go ├── signup_client.go ├── deletePost_client.go └── listPosts_client.go ├── .air.toml ├── templates ├── base.html ├── verificationCode.html ├── resetPassword.html └── styles.html ├── middleware └── deserialize-user.go ├── config └── default.go ├── models ├── post.model.go └── user.model.go ├── example.env ├── go.mod ├── cmd ├── client │ └── main.go └── server │ └── main.go ├── pb ├── user_service_grpc.pb.go ├── user_service.pb.go ├── rpc_create_post.pb.go ├── rpc_update_post.pb.go ├── auth_service_grpc.pb.go ├── auth_service.pb.go ├── rpc_signin_user.pb.go ├── rpc_signup_user.pb.go ├── post.pb.go ├── post_service_grpc.pb.go ├── user.pb.go └── post_service.pb.go └── readMe.md /proto-gen.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | rm -rf pb/*.go 4 | protoc --proto_path=proto --go_out=pb --go_opt=paths=source_relative \ 5 | --go-grpc_out=pb --go-grpc_opt=paths=source_relative \ 6 | proto/*.proto -------------------------------------------------------------------------------- /services/auth.service.go: -------------------------------------------------------------------------------- 1 | package services 2 | 3 | import "github.com/wpcodevo/golang-mongodb/models" 4 | 5 | type AuthService interface { 6 | SignUpUser(*models.SignUpInput) (*models.DBResponse, error) 7 | SignInUser(*models.SignInInput) (*models.DBResponse, error) 8 | } 9 | -------------------------------------------------------------------------------- /proto/rpc_create_post.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | package pb; 4 | 5 | option go_package = "github.com/wpcodevo/golang-mongodb/pb"; 6 | 7 | message CreatePostRequest { 8 | string Title = 1; 9 | string Content = 2; 10 | string Image = 3; 11 | string User = 4; 12 | } 13 | -------------------------------------------------------------------------------- /utils/helper.go: -------------------------------------------------------------------------------- 1 | package utils 2 | 3 | import "go.mongodb.org/mongo-driver/bson" 4 | 5 | func ToDoc(v interface{}) (doc *bson.D, err error) { 6 | data, err := bson.Marshal(v) 7 | if err != nil { 8 | return 9 | } 10 | 11 | err = bson.Unmarshal(data, &doc) 12 | return 13 | } 14 | -------------------------------------------------------------------------------- /proto/user_service.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | package pb; 4 | 5 | import "user.proto"; 6 | 7 | option go_package = "github.com/wpcodevo/golang-mongodb/pb"; 8 | 9 | service UserService { 10 | rpc GetMe(GetMeRequest) returns (UserResponse) {} 11 | } 12 | 13 | message GetMeRequest { string Id = 1; } 14 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | .PHONY: dev dev-down go proto 2 | 3 | dev: 4 | docker-compose up -d 5 | 6 | dev-down: 7 | docker-compose down 8 | 9 | go: 10 | air 11 | 12 | proto: 13 | protoc --proto_path=proto --go_out=pb --go_opt=paths=source_relative \ 14 | --go-grpc_out=pb --go-grpc_opt=paths=source_relative \ 15 | proto/*.proto -------------------------------------------------------------------------------- /proto/rpc_update_post.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | package pb; 4 | 5 | option go_package = "github.com/wpcodevo/golang-mongodb/pb"; 6 | 7 | message UpdatePostRequest { 8 | string Id = 1; 9 | optional string Title = 2; 10 | optional string Content = 3; 11 | optional string Image = 4; 12 | optional string User = 5; 13 | } 14 | -------------------------------------------------------------------------------- /services/user.service.go: -------------------------------------------------------------------------------- 1 | package services 2 | 3 | import "github.com/wpcodevo/golang-mongodb/models" 4 | 5 | type UserService interface { 6 | FindUserById(id string) (*models.DBResponse, error) 7 | FindUserByEmail(email string) (*models.DBResponse, error) 8 | UpdateUserById(id string, data *models.UpdateInput) (*models.DBResponse, error) 9 | } 10 | -------------------------------------------------------------------------------- /proto/rpc_signin_user.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | package pb; 4 | 5 | option go_package = "github.com/wpcodevo/golang-mongodb/pb"; 6 | 7 | message SignInUserInput { 8 | string email = 1; 9 | string password = 2; 10 | } 11 | 12 | message SignInUserResponse { 13 | string status = 1; 14 | string access_token = 2; 15 | string refresh_token = 3; 16 | } -------------------------------------------------------------------------------- /proto/rpc_signup_user.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | package pb; 4 | 5 | option go_package = "github.com/wpcodevo/golang-mongodb/pb"; 6 | 7 | import "user.proto"; 8 | 9 | message SignUpUserInput { 10 | string name = 1; 11 | string email = 2; 12 | string password = 3; 13 | string passwordConfirm = 4; 14 | } 15 | 16 | message SignUpUserResponse { User user = 1; } 17 | -------------------------------------------------------------------------------- /utils/encode.go: -------------------------------------------------------------------------------- 1 | package utils 2 | 3 | import "encoding/base64" 4 | 5 | func Encode(s string) string { 6 | data := base64.StdEncoding.EncodeToString([]byte(s)) 7 | return string(data) 8 | } 9 | 10 | func Decode(s string) (string, error) { 11 | data, err := base64.StdEncoding.DecodeString(s) 12 | if err != nil { 13 | return "", err 14 | } 15 | 16 | return string(data), nil 17 | } 18 | -------------------------------------------------------------------------------- /services/post.service.go: -------------------------------------------------------------------------------- 1 | package services 2 | 3 | import "github.com/wpcodevo/golang-mongodb/models" 4 | 5 | type PostService interface { 6 | CreatePost(*models.CreatePostRequest) (*models.DBPost, error) 7 | UpdatePost(string, *models.UpdatePost) (*models.DBPost, error) 8 | FindPostById(string) (*models.DBPost, error) 9 | FindPosts(page int, limit int) ([]*models.DBPost, error) 10 | DeletePost(string) error 11 | } 12 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Binaries for programs and plugins 2 | *.exe 3 | *.exe~ 4 | *.dll 5 | *.so 6 | *.dylib 7 | 8 | # Test binary, built with `go test -c` 9 | *.test 10 | 11 | # Output of the go coverage tool, specifically when used with LiteIDE 12 | *.out 13 | 14 | # Dependency directories (remove the comment below to include it) 15 | # vendor/ 16 | .DS_Store 17 | TODO.md 18 | logs.txt 19 | .idea/ 20 | secret.md 21 | app.env 22 | /temp 23 | temp/ -------------------------------------------------------------------------------- /proto/post.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | package pb; 4 | 5 | option go_package = "github.com/wpcodevo/golang-mongodb/pb"; 6 | import "google/protobuf/timestamp.proto"; 7 | 8 | message Post { 9 | string Id = 1; 10 | string Title = 2; 11 | string Content = 3; 12 | string Image = 4; 13 | string User = 5; 14 | google.protobuf.Timestamp created_at = 6; 15 | google.protobuf.Timestamp updated_at = 7; 16 | } 17 | 18 | message PostResponse { Post post = 1; } 19 | -------------------------------------------------------------------------------- /docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: '3' 2 | services: 3 | mongodb: 4 | image: mongo 5 | container_name: mongodb 6 | restart: always 7 | env_file: 8 | - ./app.env 9 | 10 | ports: 11 | - '6000:27017' 12 | volumes: 13 | - mongodb:/data/db 14 | 15 | redis: 16 | image: redis:alpine 17 | container_name: redis 18 | ports: 19 | - '6379:6379' 20 | volumes: 21 | - redisDB:/data 22 | volumes: 23 | mongodb: 24 | redisDB: 25 | -------------------------------------------------------------------------------- /tmp/build-errors.log: -------------------------------------------------------------------------------- 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 -------------------------------------------------------------------------------- /proto/user.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | package pb; 4 | 5 | import "google/protobuf/timestamp.proto"; 6 | option go_package = "github.com/wpcodevo/golang-mongodb/pb"; 7 | 8 | message User { 9 | string id = 1; 10 | string name = 2; 11 | string email = 3; 12 | string role = 4; 13 | google.protobuf.Timestamp created_at = 5; 14 | google.protobuf.Timestamp updated_at = 6; 15 | } 16 | 17 | message UserResponse { User user = 1; } 18 | 19 | message GenericResponse { 20 | string status = 1; 21 | string message = 2; 22 | } -------------------------------------------------------------------------------- /proto/auth_service.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | package pb; 4 | 5 | import "rpc_signin_user.proto"; 6 | import "rpc_signup_user.proto"; 7 | import "user.proto"; 8 | 9 | option go_package = "github.com/wpcodevo/golang-mongodb/pb"; 10 | 11 | service AuthService { 12 | rpc SignUpUser(SignUpUserInput) returns (GenericResponse) {} 13 | rpc SignInUser(SignInUserInput) returns (SignInUserResponse) {} 14 | rpc VerifyEmail(VerifyEmailRequest) returns (GenericResponse) {} 15 | } 16 | 17 | message VerifyEmailRequest { string verificationCode = 1; } -------------------------------------------------------------------------------- /utils/password.go: -------------------------------------------------------------------------------- 1 | package utils 2 | 3 | import ( 4 | "fmt" 5 | 6 | "golang.org/x/crypto/bcrypt" 7 | ) 8 | 9 | func HashPassword(password string) (string, error) { 10 | hashedPassword, err := bcrypt.GenerateFromPassword([]byte(password), bcrypt.DefaultCost) 11 | 12 | if err != nil { 13 | return "", fmt.Errorf("could not hash password %w", err) 14 | } 15 | return string(hashedPassword), nil 16 | } 17 | 18 | func VerifyPassword(hashedPassword string, candidatePassword string) error { 19 | return bcrypt.CompareHashAndPassword([]byte(hashedPassword), []byte(candidatePassword)) 20 | } 21 | -------------------------------------------------------------------------------- /gapi/post-server.go: -------------------------------------------------------------------------------- 1 | package gapi 2 | 3 | import ( 4 | "github.com/wpcodevo/golang-mongodb/pb" 5 | "github.com/wpcodevo/golang-mongodb/services" 6 | "go.mongodb.org/mongo-driver/mongo" 7 | ) 8 | 9 | type PostServer struct { 10 | pb.UnimplementedPostServiceServer 11 | postCollection *mongo.Collection 12 | postService services.PostService 13 | } 14 | 15 | func NewGrpcPostServer(postCollection *mongo.Collection, postService services.PostService) (*PostServer, error) { 16 | postServer := &PostServer{ 17 | postCollection: postCollection, 18 | postService: postService, 19 | } 20 | 21 | return postServer, nil 22 | } 23 | -------------------------------------------------------------------------------- /controllers/user.controller.go: -------------------------------------------------------------------------------- 1 | package controllers 2 | 3 | import ( 4 | "net/http" 5 | 6 | "github.com/gin-gonic/gin" 7 | "github.com/wpcodevo/golang-mongodb/models" 8 | "github.com/wpcodevo/golang-mongodb/services" 9 | ) 10 | 11 | type UserController struct { 12 | userService services.UserService 13 | } 14 | 15 | func NewUserController(userService services.UserService) UserController { 16 | return UserController{userService} 17 | } 18 | 19 | func (uc *UserController) GetMe(ctx *gin.Context) { 20 | currentUser := ctx.MustGet("currentUser").(*models.DBResponse) 21 | 22 | ctx.JSON(http.StatusOK, gin.H{"status": "success", "data": gin.H{"user": models.FilteredResponse(currentUser)}}) 23 | } 24 | -------------------------------------------------------------------------------- /gapi/rpc_delete_post.go: -------------------------------------------------------------------------------- 1 | package gapi 2 | 3 | import ( 4 | "context" 5 | "strings" 6 | 7 | "github.com/wpcodevo/golang-mongodb/pb" 8 | "google.golang.org/grpc/codes" 9 | "google.golang.org/grpc/status" 10 | ) 11 | 12 | func (postServer *PostServer) DeletePost(ctx context.Context, req *pb.PostRequest) (*pb.DeletePostResponse, error) { 13 | postId := req.GetId() 14 | 15 | if err := postServer.postService.DeletePost(postId); err != nil { 16 | if strings.Contains(err.Error(), "Id exists") { 17 | return nil, status.Errorf(codes.NotFound, err.Error()) 18 | } 19 | return nil, status.Errorf(codes.Internal, err.Error()) 20 | } 21 | 22 | res := &pb.DeletePostResponse{ 23 | Success: true, 24 | } 25 | 26 | return res, nil 27 | } 28 | -------------------------------------------------------------------------------- /routes/user.routes.go: -------------------------------------------------------------------------------- 1 | package routes 2 | 3 | import ( 4 | "github.com/gin-gonic/gin" 5 | "github.com/wpcodevo/golang-mongodb/controllers" 6 | "github.com/wpcodevo/golang-mongodb/middleware" 7 | "github.com/wpcodevo/golang-mongodb/services" 8 | ) 9 | 10 | type UserRouteController struct { 11 | userController controllers.UserController 12 | } 13 | 14 | func NewRouteUserController(userController controllers.UserController) UserRouteController { 15 | return UserRouteController{userController} 16 | } 17 | 18 | func (uc *UserRouteController) UserRoute(rg *gin.RouterGroup, userService services.UserService) { 19 | 20 | router := rg.Group("users") 21 | router.Use(middleware.DeserializeUser(userService)) 22 | router.GET("/me", uc.userController.GetMe) 23 | } 24 | -------------------------------------------------------------------------------- /gapi/user-server.go: -------------------------------------------------------------------------------- 1 | package gapi 2 | 3 | import ( 4 | "github.com/wpcodevo/golang-mongodb/config" 5 | "github.com/wpcodevo/golang-mongodb/pb" 6 | "github.com/wpcodevo/golang-mongodb/services" 7 | "go.mongodb.org/mongo-driver/mongo" 8 | ) 9 | 10 | type UserServer struct { 11 | pb.UnimplementedUserServiceServer 12 | config config.Config 13 | userService services.UserService 14 | userCollection *mongo.Collection 15 | } 16 | 17 | func NewGrpcUserServer(config config.Config, userService services.UserService, userCollection *mongo.Collection) (*UserServer, error) { 18 | userServer := &UserServer{ 19 | config: config, 20 | userService: userService, 21 | userCollection: userCollection, 22 | } 23 | 24 | return userServer, nil 25 | } 26 | -------------------------------------------------------------------------------- /proto/post_service.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | package pb; 4 | 5 | option go_package = "github.com/wpcodevo/golang-mongodb/pb"; 6 | import "post.proto"; 7 | import "rpc_create_post.proto"; 8 | import "rpc_update_post.proto"; 9 | 10 | service PostService { 11 | rpc CreatePost(CreatePostRequest) returns (PostResponse) {} 12 | rpc GetPost(PostRequest) returns (PostResponse) {} 13 | rpc GetPosts(GetPostsRequest) returns (stream Post) {} 14 | rpc UpdatePost(UpdatePostRequest) returns (PostResponse) {} 15 | rpc DeletePost(PostRequest) returns (DeletePostResponse) {} 16 | } 17 | 18 | message GetPostsRequest { 19 | optional int64 page = 1; 20 | optional int64 limit = 2; 21 | } 22 | 23 | message PostRequest { string Id = 1; } 24 | 25 | message DeletePostResponse { bool success = 1; } -------------------------------------------------------------------------------- /routes/post.routes.go: -------------------------------------------------------------------------------- 1 | package routes 2 | 3 | import ( 4 | "github.com/gin-gonic/gin" 5 | "github.com/wpcodevo/golang-mongodb/controllers" 6 | ) 7 | 8 | type PostRouteController struct { 9 | postController controllers.PostController 10 | } 11 | 12 | func NewPostControllerRoute(postController controllers.PostController) PostRouteController { 13 | return PostRouteController{postController} 14 | } 15 | 16 | func (r *PostRouteController) PostRoute(rg *gin.RouterGroup) { 17 | router := rg.Group("/posts") 18 | 19 | router.GET("/", r.postController.FindPosts) 20 | router.GET("/:postId", r.postController.FindPostById) 21 | router.POST("/", r.postController.CreatePost) 22 | router.PATCH("/:postId", r.postController.UpdatePost) 23 | router.DELETE("/:postId", r.postController.DeletePost) 24 | } 25 | -------------------------------------------------------------------------------- /client/geMe_client.go: -------------------------------------------------------------------------------- 1 | package client 2 | 3 | import ( 4 | "context" 5 | "fmt" 6 | "log" 7 | "time" 8 | 9 | "github.com/wpcodevo/golang-mongodb/pb" 10 | "google.golang.org/grpc" 11 | ) 12 | 13 | type GetMeClient struct { 14 | service pb.UserServiceClient 15 | } 16 | 17 | func NewGetMeClient(conn *grpc.ClientConn) *GetMeClient { 18 | service := pb.NewUserServiceClient(conn) 19 | 20 | return &GetMeClient{service} 21 | } 22 | 23 | func (getMeClient *GetMeClient) GetMeUser(credentials *pb.GetMeRequest) { 24 | 25 | ctx, cancel := context.WithTimeout(context.Background(), time.Duration(time.Millisecond*5000)) 26 | defer cancel() 27 | 28 | res, err := getMeClient.service.GetMe(ctx, credentials) 29 | 30 | if err != nil { 31 | log.Fatalf("GeMe: %v", err) 32 | } 33 | 34 | fmt.Println(res) 35 | } 36 | -------------------------------------------------------------------------------- /client/getPost_client.go: -------------------------------------------------------------------------------- 1 | package client 2 | 3 | import ( 4 | "context" 5 | "fmt" 6 | "log" 7 | "time" 8 | 9 | "github.com/wpcodevo/golang-mongodb/pb" 10 | "google.golang.org/grpc" 11 | ) 12 | 13 | type GetPostClient struct { 14 | service pb.PostServiceClient 15 | } 16 | 17 | func NewGetPostClient(conn *grpc.ClientConn) *GetPostClient { 18 | service := pb.NewPostServiceClient(conn) 19 | 20 | return &GetPostClient{service} 21 | } 22 | 23 | func (getPostClient *GetPostClient) GetPost(args *pb.PostRequest) { 24 | 25 | ctx, cancel := context.WithTimeout(context.Background(), time.Duration(time.Millisecond*5000)) 26 | defer cancel() 27 | 28 | res, err := getPostClient.service.GetPost(ctx, args) 29 | 30 | if err != nil { 31 | log.Fatalf("GetPost: %v", err) 32 | } 33 | 34 | fmt.Println(res) 35 | } 36 | -------------------------------------------------------------------------------- /client/signin_client.go: -------------------------------------------------------------------------------- 1 | package client 2 | 3 | import ( 4 | "context" 5 | "fmt" 6 | "log" 7 | "time" 8 | 9 | "github.com/wpcodevo/golang-mongodb/pb" 10 | "google.golang.org/grpc" 11 | ) 12 | 13 | type SignInUserClient struct { 14 | service pb.AuthServiceClient 15 | } 16 | 17 | func NewSignInUserClient(conn *grpc.ClientConn) *SignInUserClient { 18 | service := pb.NewAuthServiceClient(conn) 19 | 20 | return &SignInUserClient{service} 21 | } 22 | 23 | func (signInUserClient *SignInUserClient) SignInUser(credentials *pb.SignInUserInput) { 24 | 25 | ctx, cancel := context.WithTimeout(context.Background(), time.Second) 26 | defer cancel() 27 | 28 | res, err := signInUserClient.service.SignInUser(ctx, credentials) 29 | 30 | if err != nil { 31 | log.Fatalf("SignInUser: %v", err) 32 | } 33 | 34 | fmt.Println(res) 35 | } 36 | -------------------------------------------------------------------------------- /.air.toml: -------------------------------------------------------------------------------- 1 | root = "." 2 | testdata_dir = "testdata" 3 | tmp_dir = "tmp" 4 | 5 | [build] 6 | bin = "tmp\\main.exe" 7 | cmd = "go build -o ./tmp/main.exe ./cmd/server/main.go" 8 | delay = 1000 9 | exclude_dir = ["assets", "tmp", "vendor", "testdata"] 10 | exclude_file = [] 11 | exclude_regex = ["_test.go"] 12 | exclude_unchanged = false 13 | follow_symlink = false 14 | full_bin = "" 15 | include_dir = [] 16 | include_ext = ["go", "tpl", "tmpl", "html"] 17 | kill_delay = "0s" 18 | log = "build-errors.log" 19 | send_interrupt = false 20 | stop_on_error = true 21 | 22 | [color] 23 | app = "" 24 | build = "yellow" 25 | main = "magenta" 26 | runner = "green" 27 | watcher = "cyan" 28 | 29 | [log] 30 | time = false 31 | 32 | [misc] 33 | clean_on_exit = false 34 | 35 | [screen] 36 | clear_on_rebuild = false 37 | -------------------------------------------------------------------------------- /client/createPost_client.go: -------------------------------------------------------------------------------- 1 | package client 2 | 3 | import ( 4 | "context" 5 | "fmt" 6 | "log" 7 | "time" 8 | 9 | "github.com/wpcodevo/golang-mongodb/pb" 10 | "google.golang.org/grpc" 11 | ) 12 | 13 | type CreatePostClient struct { 14 | service pb.PostServiceClient 15 | } 16 | 17 | func NewCreatePostClient(conn *grpc.ClientConn) *CreatePostClient { 18 | service := pb.NewPostServiceClient(conn) 19 | 20 | return &CreatePostClient{service} 21 | } 22 | 23 | func (createPostClient *CreatePostClient) CreatePost(args *pb.CreatePostRequest) { 24 | 25 | ctx, cancel := context.WithTimeout(context.Background(), time.Duration(time.Millisecond*5000)) 26 | defer cancel() 27 | 28 | res, err := createPostClient.service.CreatePost(ctx, args) 29 | 30 | if err != nil { 31 | log.Fatalf("CreatePost: %v", err) 32 | } 33 | 34 | fmt.Println(res) 35 | } 36 | -------------------------------------------------------------------------------- /client/updatePost_client.go: -------------------------------------------------------------------------------- 1 | package client 2 | 3 | import ( 4 | "context" 5 | "fmt" 6 | "log" 7 | "time" 8 | 9 | "github.com/wpcodevo/golang-mongodb/pb" 10 | "google.golang.org/grpc" 11 | ) 12 | 13 | type UpdatePostClient struct { 14 | service pb.PostServiceClient 15 | } 16 | 17 | func NewUpdatePostClient(conn *grpc.ClientConn) *UpdatePostClient { 18 | service := pb.NewPostServiceClient(conn) 19 | 20 | return &UpdatePostClient{service} 21 | } 22 | 23 | func (updatePostClient *UpdatePostClient) UpdatePost(args *pb.UpdatePostRequest) { 24 | 25 | ctx, cancel := context.WithTimeout(context.Background(), time.Duration(time.Millisecond*5000)) 26 | defer cancel() 27 | 28 | res, err := updatePostClient.service.UpdatePost(ctx, args) 29 | 30 | if err != nil { 31 | log.Fatalf("UpdatePost: %v", err) 32 | } 33 | 34 | fmt.Println(res) 35 | } 36 | -------------------------------------------------------------------------------- /client/signup_client.go: -------------------------------------------------------------------------------- 1 | package client 2 | 3 | import ( 4 | "context" 5 | "fmt" 6 | "log" 7 | "time" 8 | 9 | "github.com/wpcodevo/golang-mongodb/pb" 10 | "google.golang.org/grpc" 11 | ) 12 | 13 | type SignUpUserClient struct { 14 | service pb.AuthServiceClient 15 | } 16 | 17 | func NewSignUpUserClient(conn *grpc.ClientConn) *SignUpUserClient { 18 | service := pb.NewAuthServiceClient(conn) 19 | 20 | return &SignUpUserClient{service} 21 | } 22 | 23 | func (signUpUserClient *SignUpUserClient) SignUpUser(credentials *pb.SignUpUserInput) { 24 | 25 | ctx, cancel := context.WithTimeout(context.Background(), time.Duration(time.Millisecond*5000)) 26 | defer cancel() 27 | 28 | res, err := signUpUserClient.service.SignUpUser(ctx, credentials) 29 | 30 | if err != nil { 31 | log.Fatalf("SignUpUser: %v", err) 32 | } 33 | 34 | fmt.Println(res) 35 | } 36 | -------------------------------------------------------------------------------- /client/deletePost_client.go: -------------------------------------------------------------------------------- 1 | package client 2 | 3 | import ( 4 | "context" 5 | "fmt" 6 | "log" 7 | "time" 8 | 9 | "github.com/wpcodevo/golang-mongodb/pb" 10 | "google.golang.org/grpc" 11 | ) 12 | 13 | type DeletePostClient struct { 14 | service pb.PostServiceClient 15 | } 16 | 17 | func NewDeletePostClient(conn *grpc.ClientConn) *DeletePostClient { 18 | service := pb.NewPostServiceClient(conn) 19 | 20 | return &DeletePostClient{service} 21 | } 22 | 23 | func (deletePostClient *DeletePostClient) DeletePost(args *pb.PostRequest) { 24 | 25 | ctx, cancel := context.WithTimeout(context.Background(), time.Duration(time.Millisecond*5000)) 26 | defer cancel() 27 | 28 | _, err := deletePostClient.service.DeletePost(ctx, args) 29 | 30 | if err != nil { 31 | log.Fatalf("DeletePost: %v", err) 32 | } 33 | 34 | fmt.Println("Post deleted successfully") 35 | } 36 | -------------------------------------------------------------------------------- /gapi/rpc_get_me.go: -------------------------------------------------------------------------------- 1 | package gapi 2 | 3 | import ( 4 | "context" 5 | 6 | "github.com/wpcodevo/golang-mongodb/pb" 7 | "google.golang.org/grpc/codes" 8 | "google.golang.org/grpc/status" 9 | "google.golang.org/protobuf/types/known/timestamppb" 10 | ) 11 | 12 | func (userServer *UserServer) GetMe(ctx context.Context, req *pb.GetMeRequest) (*pb.UserResponse, error) { 13 | id := req.GetId() 14 | user, err := userServer.userService.FindUserById(id) 15 | 16 | if err != nil { 17 | return nil, status.Errorf(codes.Unimplemented, err.Error()) 18 | } 19 | 20 | res := &pb.UserResponse{ 21 | User: &pb.User{ 22 | Id: user.ID.Hex(), 23 | Name: user.Name, 24 | Email: user.Email, 25 | Role: user.Role, 26 | CreatedAt: timestamppb.New(user.CreatedAt), 27 | UpdatedAt: timestamppb.New(user.UpdatedAt), 28 | }, 29 | } 30 | return res, nil 31 | } 32 | -------------------------------------------------------------------------------- /gapi/auth-server.go: -------------------------------------------------------------------------------- 1 | package gapi 2 | 3 | import ( 4 | "github.com/wpcodevo/golang-mongodb/config" 5 | "github.com/wpcodevo/golang-mongodb/pb" 6 | "github.com/wpcodevo/golang-mongodb/services" 7 | "go.mongodb.org/mongo-driver/mongo" 8 | ) 9 | 10 | type AuthServer struct { 11 | pb.UnimplementedAuthServiceServer 12 | config config.Config 13 | authService services.AuthService 14 | userService services.UserService 15 | userCollection *mongo.Collection 16 | } 17 | 18 | func NewGrpcAuthServer(config config.Config, authService services.AuthService, 19 | userService services.UserService, userCollection *mongo.Collection) (*AuthServer, error) { 20 | 21 | authServer := &AuthServer{ 22 | config: config, 23 | authService: authService, 24 | userService: userService, 25 | userCollection: userCollection, 26 | } 27 | 28 | return authServer, nil 29 | } 30 | -------------------------------------------------------------------------------- /templates/base.html: -------------------------------------------------------------------------------- 1 | {{define "base"}} 2 | 3 | 4 | 5 | 6 | 7 | {{template "styles" .}} 8 | {{ .Subject}} 9 | 10 | 11 | 18 | 19 | 20 | 27 | 28 | 29 | 30 | 31 | 32 | {{end}} 33 | -------------------------------------------------------------------------------- /gapi/rpc_list_posts.go: -------------------------------------------------------------------------------- 1 | package gapi 2 | 3 | import ( 4 | "github.com/wpcodevo/golang-mongodb/pb" 5 | "google.golang.org/grpc/codes" 6 | "google.golang.org/grpc/status" 7 | "google.golang.org/protobuf/types/known/timestamppb" 8 | ) 9 | 10 | func (postServer *PostServer) GetPosts(req *pb.GetPostsRequest, stream pb.PostService_GetPostsServer) error { 11 | var page = req.GetPage() 12 | var limit = req.GetLimit() 13 | 14 | posts, err := postServer.postService.FindPosts(int(page), int(limit)) 15 | if err != nil { 16 | return status.Errorf(codes.Internal, err.Error()) 17 | } 18 | 19 | for _, post := range posts { 20 | stream.Send(&pb.Post{ 21 | Id: post.Id.Hex(), 22 | Title: post.Title, 23 | Content: post.Content, 24 | Image: post.Image, 25 | CreatedAt: timestamppb.New(post.CreateAt), 26 | UpdatedAt: timestamppb.New(post.UpdatedAt), 27 | }) 28 | } 29 | 30 | return nil 31 | } 32 | -------------------------------------------------------------------------------- /client/listPosts_client.go: -------------------------------------------------------------------------------- 1 | package client 2 | 3 | import ( 4 | "context" 5 | "fmt" 6 | "io" 7 | "log" 8 | "time" 9 | 10 | "github.com/wpcodevo/golang-mongodb/pb" 11 | "google.golang.org/grpc" 12 | ) 13 | 14 | type ListPostsClient struct { 15 | service pb.PostServiceClient 16 | } 17 | 18 | func NewListPostsClient(conn *grpc.ClientConn) *ListPostsClient { 19 | service := pb.NewPostServiceClient(conn) 20 | 21 | return &ListPostsClient{service} 22 | } 23 | 24 | func (listPostsClient *ListPostsClient) ListPosts(args *pb.GetPostsRequest) { 25 | ctx, cancel := context.WithTimeout(context.Background(), time.Duration(time.Millisecond*5000)) 26 | defer cancel() 27 | 28 | stream, err := listPostsClient.service.GetPosts(ctx, args) 29 | if err != nil { 30 | log.Fatalf("ListPosts: %v", err) 31 | } 32 | 33 | for { 34 | res, err := stream.Recv() 35 | 36 | if err == io.EOF { 37 | break 38 | } 39 | 40 | if err != nil { 41 | log.Fatalf("ListPosts: %v", err) 42 | } 43 | 44 | fmt.Println(res) 45 | } 46 | 47 | } 48 | -------------------------------------------------------------------------------- /gapi/rpc_get_post.go: -------------------------------------------------------------------------------- 1 | package gapi 2 | 3 | import ( 4 | "context" 5 | "strings" 6 | 7 | "github.com/wpcodevo/golang-mongodb/pb" 8 | "google.golang.org/grpc/codes" 9 | "google.golang.org/grpc/status" 10 | "google.golang.org/protobuf/types/known/timestamppb" 11 | ) 12 | 13 | func (postServer *PostServer) GetPost(ctx context.Context, req *pb.PostRequest) (*pb.PostResponse, error) { 14 | postId := req.GetId() 15 | 16 | post, err := postServer.postService.FindPostById(postId) 17 | if err != nil { 18 | if strings.Contains(err.Error(), "Id exists") { 19 | return nil, status.Errorf(codes.NotFound, err.Error()) 20 | 21 | } 22 | return nil, status.Errorf(codes.Internal, err.Error()) 23 | } 24 | 25 | res := &pb.PostResponse{ 26 | Post: &pb.Post{ 27 | Id: post.Id.Hex(), 28 | Title: post.Title, 29 | Content: post.Content, 30 | Image: post.Image, 31 | User: post.User, 32 | CreatedAt: timestamppb.New(post.CreateAt), 33 | UpdatedAt: timestamppb.New(post.UpdatedAt), 34 | }, 35 | } 36 | return res, nil 37 | } 38 | -------------------------------------------------------------------------------- /routes/auth.routes.go: -------------------------------------------------------------------------------- 1 | package routes 2 | 3 | import ( 4 | "github.com/gin-gonic/gin" 5 | "github.com/wpcodevo/golang-mongodb/controllers" 6 | "github.com/wpcodevo/golang-mongodb/middleware" 7 | "github.com/wpcodevo/golang-mongodb/services" 8 | ) 9 | 10 | type AuthRouteController struct { 11 | authController controllers.AuthController 12 | } 13 | 14 | func NewAuthRouteController(authController controllers.AuthController) AuthRouteController { 15 | return AuthRouteController{authController} 16 | } 17 | 18 | func (rc *AuthRouteController) AuthRoute(rg *gin.RouterGroup, userService services.UserService) { 19 | router := rg.Group("/auth") 20 | 21 | router.POST("/register", rc.authController.SignUpUser) 22 | router.POST("/login", rc.authController.SignInUser) 23 | router.GET("/refresh", rc.authController.RefreshAccessToken) 24 | router.GET("/logout", middleware.DeserializeUser(userService), rc.authController.LogoutUser) 25 | router.GET("/verifyemail/:verificationCode", rc.authController.VerifyEmail) 26 | router.POST("/forgotPassword", rc.authController.ForgotPassword) 27 | } 28 | -------------------------------------------------------------------------------- /gapi/rpc_verify_user.go: -------------------------------------------------------------------------------- 1 | package gapi 2 | 3 | import ( 4 | "context" 5 | "time" 6 | 7 | "github.com/wpcodevo/golang-mongodb/pb" 8 | "github.com/wpcodevo/golang-mongodb/utils" 9 | "go.mongodb.org/mongo-driver/bson" 10 | "google.golang.org/grpc/codes" 11 | "google.golang.org/grpc/status" 12 | ) 13 | 14 | func (authServer *AuthServer) VerifyEmail(ctx context.Context, req *pb.VerifyEmailRequest) (*pb.GenericResponse, error) { 15 | code := req.GetVerificationCode() 16 | 17 | verificationCode := utils.Encode(code) 18 | 19 | query := bson.D{{Key: "verificationCode", Value: verificationCode}} 20 | 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: ""}}}} 21 | result, err := authServer.userCollection.UpdateOne(ctx, query, update) 22 | if err != nil { 23 | return nil, status.Errorf(codes.Internal, err.Error()) 24 | } 25 | 26 | if result.MatchedCount == 0 { 27 | return nil, status.Errorf(codes.PermissionDenied, "Could not verify email address") 28 | } 29 | 30 | res := &pb.GenericResponse{ 31 | Status: "success", 32 | Message: "Email verified successfully", 33 | } 34 | return res, nil 35 | } 36 | -------------------------------------------------------------------------------- /gapi/rpc_create_post.go: -------------------------------------------------------------------------------- 1 | package gapi 2 | 3 | import ( 4 | "context" 5 | "strings" 6 | 7 | "github.com/wpcodevo/golang-mongodb/models" 8 | "github.com/wpcodevo/golang-mongodb/pb" 9 | "google.golang.org/grpc/codes" 10 | "google.golang.org/grpc/status" 11 | "google.golang.org/protobuf/types/known/timestamppb" 12 | ) 13 | 14 | func (postServer *PostServer) CreatePost(ctx context.Context, req *pb.CreatePostRequest) (*pb.PostResponse, error) { 15 | 16 | post := &models.CreatePostRequest{ 17 | Title: req.GetTitle(), 18 | Content: req.GetContent(), 19 | Image: req.GetImage(), 20 | User: req.GetUser(), 21 | } 22 | 23 | newPost, err := postServer.postService.CreatePost(post) 24 | 25 | if err != nil { 26 | if strings.Contains(err.Error(), "title already exists") { 27 | return nil, status.Errorf(codes.AlreadyExists, err.Error()) 28 | } 29 | 30 | return nil, status.Errorf(codes.Internal, err.Error()) 31 | } 32 | 33 | res := &pb.PostResponse{ 34 | Post: &pb.Post{ 35 | Id: newPost.Id.Hex(), 36 | Title: newPost.Title, 37 | Content: newPost.Content, 38 | User: newPost.User, 39 | CreatedAt: timestamppb.New(newPost.CreateAt), 40 | UpdatedAt: timestamppb.New(newPost.UpdatedAt), 41 | }, 42 | } 43 | return res, nil 44 | } 45 | -------------------------------------------------------------------------------- /gapi/rpc_update_post.go: -------------------------------------------------------------------------------- 1 | package gapi 2 | 3 | import ( 4 | "context" 5 | "strings" 6 | "time" 7 | 8 | "github.com/wpcodevo/golang-mongodb/models" 9 | "github.com/wpcodevo/golang-mongodb/pb" 10 | "google.golang.org/grpc/codes" 11 | "google.golang.org/grpc/status" 12 | "google.golang.org/protobuf/types/known/timestamppb" 13 | ) 14 | 15 | func (postServer *PostServer) UpdatePost(ctx context.Context, req *pb.UpdatePostRequest) (*pb.PostResponse, error) { 16 | postId := req.GetId() 17 | 18 | post := &models.UpdatePost{ 19 | Title: req.GetTitle(), 20 | Content: req.GetContent(), 21 | Image: req.GetImage(), 22 | User: req.GetUser(), 23 | UpdatedAt: time.Now(), 24 | } 25 | 26 | updatedPost, err := postServer.postService.UpdatePost(postId, post) 27 | 28 | if err != nil { 29 | if strings.Contains(err.Error(), "Id exists") { 30 | return nil, status.Errorf(codes.NotFound, err.Error()) 31 | } 32 | return nil, status.Errorf(codes.Internal, err.Error()) 33 | } 34 | 35 | res := &pb.PostResponse{ 36 | Post: &pb.Post{ 37 | Id: updatedPost.Id.Hex(), 38 | Title: updatedPost.Title, 39 | Content: updatedPost.Content, 40 | Image: updatedPost.Image, 41 | User: updatedPost.User, 42 | CreatedAt: timestamppb.New(updatedPost.CreateAt), 43 | UpdatedAt: timestamppb.New(updatedPost.UpdatedAt), 44 | }, 45 | } 46 | return res, nil 47 | } 48 | -------------------------------------------------------------------------------- /middleware/deserialize-user.go: -------------------------------------------------------------------------------- 1 | package middleware 2 | 3 | import ( 4 | "fmt" 5 | "net/http" 6 | "strings" 7 | 8 | "github.com/gin-gonic/gin" 9 | "github.com/wpcodevo/golang-mongodb/config" 10 | "github.com/wpcodevo/golang-mongodb/services" 11 | "github.com/wpcodevo/golang-mongodb/utils" 12 | ) 13 | 14 | func DeserializeUser(userService services.UserService) gin.HandlerFunc { 15 | return func(ctx *gin.Context) { 16 | var access_token string 17 | cookie, err := ctx.Cookie("access_token") 18 | 19 | authorizationHeader := ctx.Request.Header.Get("Authorization") 20 | fields := strings.Fields(authorizationHeader) 21 | 22 | if len(fields) != 0 && fields[0] == "Bearer" { 23 | access_token = fields[1] 24 | } else if err == nil { 25 | access_token = cookie 26 | } 27 | 28 | if access_token == "" { 29 | ctx.AbortWithStatusJSON(http.StatusUnauthorized, gin.H{"status": "fail", "message": "You are not logged in"}) 30 | return 31 | } 32 | 33 | config, _ := config.LoadConfig(".") 34 | sub, err := utils.ValidateToken(access_token, config.AccessTokenPublicKey) 35 | if err != nil { 36 | ctx.AbortWithStatusJSON(http.StatusUnauthorized, gin.H{"status": "fail", "message": err.Error()}) 37 | return 38 | } 39 | 40 | user, err := userService.FindUserById(fmt.Sprint(sub)) 41 | if err != nil { 42 | ctx.AbortWithStatusJSON(http.StatusUnauthorized, gin.H{"status": "fail", "message": "The user belonging to this token no logger exists"}) 43 | return 44 | } 45 | 46 | ctx.Set("currentUser", user) 47 | ctx.Next() 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /config/default.go: -------------------------------------------------------------------------------- 1 | package config 2 | 3 | import ( 4 | "time" 5 | 6 | "github.com/spf13/viper" 7 | ) 8 | 9 | type Config struct { 10 | DBUri string `mapstructure:"MONGODB_LOCAL_URI"` 11 | RedisUri string `mapstructure:"REDIS_URL"` 12 | Port string `mapstructure:"PORT"` 13 | 14 | GrpcServerAddress string `mapstructure:"GRPC_SERVER_ADDRESS"` 15 | 16 | AccessTokenPrivateKey string `mapstructure:"ACCESS_TOKEN_PRIVATE_KEY"` 17 | AccessTokenPublicKey string `mapstructure:"ACCESS_TOKEN_PUBLIC_KEY"` 18 | RefreshTokenPrivateKey string `mapstructure:"REFRESH_TOKEN_PRIVATE_KEY"` 19 | RefreshTokenPublicKey string `mapstructure:"REFRESH_TOKEN_PUBLIC_KEY"` 20 | AccessTokenExpiresIn time.Duration `mapstructure:"ACCESS_TOKEN_EXPIRED_IN"` 21 | RefreshTokenExpiresIn time.Duration `mapstructure:"REFRESH_TOKEN_EXPIRED_IN"` 22 | AccessTokenMaxAge int `mapstructure:"ACCESS_TOKEN_MAXAGE"` 23 | RefreshTokenMaxAge int `mapstructure:"REFRESH_TOKEN_MAXAGE"` 24 | 25 | Origin string `mapstructure:"CLIENT_ORIGIN"` 26 | 27 | EmailFrom string `mapstructure:"EMAIL_FROM"` 28 | SMTPHost string `mapstructure:"SMTP_HOST"` 29 | SMTPPass string `mapstructure:"SMTP_PASS"` 30 | SMTPPort int `mapstructure:"SMTP_PORT"` 31 | SMTPUser string `mapstructure:"SMTP_USER"` 32 | } 33 | 34 | func LoadConfig(path string) (config Config, err error) { 35 | viper.AddConfigPath(path) 36 | viper.SetConfigType("env") 37 | viper.SetConfigName("app") 38 | 39 | viper.AutomaticEnv() 40 | 41 | err = viper.ReadInConfig() 42 | if err != nil { 43 | return 44 | } 45 | 46 | err = viper.Unmarshal(&config) 47 | return 48 | } 49 | -------------------------------------------------------------------------------- /templates/verificationCode.html: -------------------------------------------------------------------------------- 1 | {{template "base" .}} {{define "content"}} 2 | 3 | 4 | 5 | 46 | 47 | 48 | 49 | 50 | {{end}} 51 | -------------------------------------------------------------------------------- /models/post.model.go: -------------------------------------------------------------------------------- 1 | package models 2 | 3 | import ( 4 | "time" 5 | 6 | "go.mongodb.org/mongo-driver/bson/primitive" 7 | ) 8 | 9 | type CreatePostRequest struct { 10 | Title string `json:"title" bson:"title" binding:"required"` 11 | Content string `json:"content" bson:"content" binding:"required"` 12 | Image string `json:"image,omitempty" bson:"image,omitempty"` 13 | User string `json:"user" bson:"user" binding:"required"` 14 | CreateAt time.Time `json:"created_at,omitempty" bson:"created_at,omitempty"` 15 | UpdatedAt time.Time `json:"updated_at,omitempty" bson:"updated_at,omitempty"` 16 | } 17 | 18 | type DBPost struct { 19 | Id primitive.ObjectID `json:"id,omitempty" bson:"_id,omitempty"` 20 | Title string `json:"title,omitempty" bson:"title,omitempty"` 21 | Content string `json:"content,omitempty" bson:"content,omitempty"` 22 | Image string `json:"image,omitempty" bson:"image,omitempty"` 23 | User string `json:"user,omitempty" bson:"user,omitempty"` 24 | CreateAt time.Time `json:"created_at,omitempty" bson:"created_at,omitempty"` 25 | UpdatedAt time.Time `json:"updated_at,omitempty" bson:"updated_at,omitempty"` 26 | } 27 | 28 | type UpdatePost struct { 29 | Title string `json:"title,omitempty" bson:"title,omitempty"` 30 | Content string `json:"content,omitempty" bson:"content,omitempty"` 31 | Image string `json:"image,omitempty" bson:"image,omitempty"` 32 | User string `json:"user,omitempty" bson:"user,omitempty"` 33 | CreateAt time.Time `json:"created_at,omitempty" bson:"created_at,omitempty"` 34 | UpdatedAt time.Time `json:"updated_at,omitempty" bson:"updated_at,omitempty"` 35 | } 36 | -------------------------------------------------------------------------------- /gapi/rpc_signin_user.go: -------------------------------------------------------------------------------- 1 | package gapi 2 | 3 | import ( 4 | "context" 5 | 6 | "github.com/wpcodevo/golang-mongodb/pb" 7 | "github.com/wpcodevo/golang-mongodb/utils" 8 | "go.mongodb.org/mongo-driver/mongo" 9 | "google.golang.org/grpc/codes" 10 | "google.golang.org/grpc/status" 11 | ) 12 | 13 | func (authServer *AuthServer) SignInUser(ctx context.Context, req *pb.SignInUserInput) (*pb.SignInUserResponse, error) { 14 | user, err := authServer.userService.FindUserByEmail(req.GetEmail()) 15 | if err != nil { 16 | if err == mongo.ErrNoDocuments { 17 | 18 | return nil, status.Errorf(codes.InvalidArgument, "Invalid email or password") 19 | 20 | } 21 | 22 | return nil, status.Errorf(codes.Internal, err.Error()) 23 | 24 | } 25 | 26 | if !user.Verified { 27 | 28 | return nil, status.Errorf(codes.PermissionDenied, "You are not verified, please verify your email to login") 29 | 30 | } 31 | 32 | if err := utils.VerifyPassword(user.Password, req.GetPassword()); err != nil { 33 | 34 | return nil, status.Errorf(codes.InvalidArgument, "Invalid email or Password") 35 | 36 | } 37 | 38 | // Generate Tokens 39 | access_token, err := utils.CreateToken(authServer.config.AccessTokenExpiresIn, user.ID, authServer.config.AccessTokenPrivateKey) 40 | if err != nil { 41 | 42 | return nil, status.Errorf(codes.PermissionDenied, err.Error()) 43 | 44 | } 45 | 46 | refresh_token, err := utils.CreateToken(authServer.config.RefreshTokenExpiresIn, user.ID, authServer.config.RefreshTokenPrivateKey) 47 | if err != nil { 48 | return nil, status.Errorf(codes.PermissionDenied, err.Error()) 49 | } 50 | 51 | res := &pb.SignInUserResponse{ 52 | Status: "success", 53 | AccessToken: access_token, 54 | RefreshToken: refresh_token, 55 | } 56 | 57 | return res, nil 58 | } 59 | -------------------------------------------------------------------------------- /templates/resetPassword.html: -------------------------------------------------------------------------------- 1 | {{template "base" .}} {{define "content"}} 2 | 3 | 4 | 5 | 50 | 51 | 52 | 53 | 54 | {{end}} 55 | -------------------------------------------------------------------------------- /utils/token.go: -------------------------------------------------------------------------------- 1 | package utils 2 | 3 | import ( 4 | "encoding/base64" 5 | "fmt" 6 | "time" 7 | 8 | "github.com/golang-jwt/jwt" 9 | ) 10 | 11 | func CreateToken(ttl time.Duration, payload interface{}, privateKey string) (string, error) { 12 | decodedPrivateKey, err := base64.StdEncoding.DecodeString(privateKey) 13 | if err != nil { 14 | return "", fmt.Errorf("could not decode key: %w", err) 15 | } 16 | key, err := jwt.ParseRSAPrivateKeyFromPEM(decodedPrivateKey) 17 | 18 | if err != nil { 19 | return "", fmt.Errorf("create: parse key: %w", err) 20 | } 21 | 22 | now := time.Now().UTC() 23 | 24 | claims := make(jwt.MapClaims) 25 | claims["sub"] = payload 26 | claims["exp"] = now.Add(ttl).Unix() 27 | claims["iat"] = now.Unix() 28 | claims["nbf"] = now.Unix() 29 | 30 | token, err := jwt.NewWithClaims(jwt.SigningMethodRS256, claims).SignedString(key) 31 | 32 | if err != nil { 33 | return "", fmt.Errorf("create: sign token: %w", err) 34 | } 35 | 36 | return token, nil 37 | } 38 | 39 | func ValidateToken(token string, publicKey string) (interface{}, error) { 40 | decodedPublicKey, err := base64.StdEncoding.DecodeString(publicKey) 41 | if err != nil { 42 | return nil, fmt.Errorf("could not decode: %w", err) 43 | } 44 | 45 | key, err := jwt.ParseRSAPublicKeyFromPEM(decodedPublicKey) 46 | 47 | if err != nil { 48 | return "", fmt.Errorf("validate: parse key: %w", err) 49 | } 50 | 51 | parsedToken, err := jwt.Parse(token, func(t *jwt.Token) (interface{}, error) { 52 | if _, ok := t.Method.(*jwt.SigningMethodRSA); !ok { 53 | return nil, fmt.Errorf("unexpected method: %s", t.Header["alg"]) 54 | } 55 | return key, nil 56 | }) 57 | 58 | if err != nil { 59 | return nil, fmt.Errorf("validate: %w", err) 60 | } 61 | 62 | claims, ok := parsedToken.Claims.(jwt.MapClaims) 63 | if !ok || !parsedToken.Valid { 64 | return nil, fmt.Errorf("validate: invalid token") 65 | } 66 | 67 | return claims["sub"], nil 68 | } 69 | -------------------------------------------------------------------------------- /services/auth.service.impl.go: -------------------------------------------------------------------------------- 1 | package services 2 | 3 | import ( 4 | "context" 5 | "errors" 6 | "strings" 7 | "time" 8 | 9 | "github.com/wpcodevo/golang-mongodb/models" 10 | "github.com/wpcodevo/golang-mongodb/utils" 11 | "go.mongodb.org/mongo-driver/bson" 12 | "go.mongodb.org/mongo-driver/mongo" 13 | "go.mongodb.org/mongo-driver/mongo/options" 14 | ) 15 | 16 | type AuthServiceImpl struct { 17 | collection *mongo.Collection 18 | ctx context.Context 19 | } 20 | 21 | func NewAuthService(collection *mongo.Collection, ctx context.Context) AuthService { 22 | return &AuthServiceImpl{collection, ctx} 23 | } 24 | 25 | func (uc *AuthServiceImpl) SignUpUser(user *models.SignUpInput) (*models.DBResponse, error) { 26 | user.CreatedAt = time.Now() 27 | user.UpdatedAt = user.CreatedAt 28 | user.Email = strings.ToLower(user.Email) 29 | user.PasswordConfirm = "" 30 | user.Verified = false 31 | user.Role = "user" 32 | 33 | hashedPassword, _ := utils.HashPassword(user.Password) 34 | user.Password = hashedPassword 35 | res, err := uc.collection.InsertOne(uc.ctx, &user) 36 | 37 | if err != nil { 38 | if er, ok := err.(mongo.WriteException); ok && er.WriteErrors[0].Code == 11000 { 39 | return nil, errors.New("user with that email already exist") 40 | } 41 | return nil, err 42 | } 43 | 44 | // Create a unique index for the email field 45 | opt := options.Index() 46 | opt.SetUnique(true) 47 | index := mongo.IndexModel{Keys: bson.M{"email": 1}, Options: opt} 48 | 49 | if _, err := uc.collection.Indexes().CreateOne(uc.ctx, index); err != nil { 50 | return nil, errors.New("could not create index for email") 51 | } 52 | 53 | var newUser *models.DBResponse 54 | query := bson.M{"_id": res.InsertedID} 55 | 56 | err = uc.collection.FindOne(uc.ctx, query).Decode(&newUser) 57 | if err != nil { 58 | return nil, err 59 | } 60 | 61 | return newUser, nil 62 | } 63 | 64 | func (uc *AuthServiceImpl) SignInUser(*models.SignInInput) (*models.DBResponse, error) { 65 | return nil, nil 66 | } 67 | -------------------------------------------------------------------------------- /utils/email.go: -------------------------------------------------------------------------------- 1 | package utils 2 | 3 | import ( 4 | "bytes" 5 | "crypto/tls" 6 | "fmt" 7 | "log" 8 | "os" 9 | "path/filepath" 10 | "text/template" 11 | 12 | "github.com/k3a/html2text" 13 | "github.com/wpcodevo/golang-mongodb/config" 14 | "github.com/wpcodevo/golang-mongodb/models" 15 | "gopkg.in/gomail.v2" 16 | ) 17 | 18 | type EmailData struct { 19 | URL string 20 | FirstName string 21 | Subject string 22 | } 23 | 24 | // 👇 Email template parser 25 | 26 | func ParseTemplateDir(dir string) (*template.Template, error) { 27 | var paths []string 28 | err := filepath.Walk(dir, func(path string, info os.FileInfo, err error) error { 29 | if err != nil { 30 | return err 31 | } 32 | if !info.IsDir() { 33 | paths = append(paths, path) 34 | } 35 | return nil 36 | }) 37 | 38 | fmt.Println("Am parsing templates...") 39 | 40 | if err != nil { 41 | return nil, err 42 | } 43 | 44 | return template.ParseFiles(paths...) 45 | } 46 | 47 | func SendEmail(user *models.DBResponse, data *EmailData, templateName string) error { 48 | config, err := config.LoadConfig(".") 49 | 50 | if err != nil { 51 | log.Fatal("could not load config", err) 52 | } 53 | 54 | // Sender data. 55 | from := config.EmailFrom 56 | smtpPass := config.SMTPPass 57 | smtpUser := config.SMTPUser 58 | to := user.Email 59 | smtpHost := config.SMTPHost 60 | smtpPort := config.SMTPPort 61 | 62 | var body bytes.Buffer 63 | 64 | template, err := ParseTemplateDir("templates") 65 | if err != nil { 66 | log.Fatal("Could not parse template", err) 67 | } 68 | 69 | template = template.Lookup(templateName) 70 | template.Execute(&body, &data) 71 | fmt.Println(template.Name()) 72 | 73 | m := gomail.NewMessage() 74 | 75 | m.SetHeader("From", from) 76 | m.SetHeader("To", to) 77 | m.SetHeader("Subject", data.Subject) 78 | m.SetBody("text/html", body.String()) 79 | m.AddAlternative("text/plain", html2text.HTML2Text(body.String())) 80 | 81 | d := gomail.NewDialer(smtpHost, smtpPort, smtpUser, smtpPass) 82 | d.TLSConfig = &tls.Config{InsecureSkipVerify: true} 83 | 84 | // Send Email 85 | if err := d.DialAndSend(m); err != nil { 86 | return err 87 | } 88 | return nil 89 | } 90 | -------------------------------------------------------------------------------- /gapi/rpc_signup_user.go: -------------------------------------------------------------------------------- 1 | package gapi 2 | 3 | import ( 4 | "context" 5 | "strings" 6 | 7 | "github.com/thanhpk/randstr" 8 | "github.com/wpcodevo/golang-mongodb/models" 9 | "github.com/wpcodevo/golang-mongodb/pb" 10 | "github.com/wpcodevo/golang-mongodb/utils" 11 | "google.golang.org/grpc/codes" 12 | "google.golang.org/grpc/status" 13 | ) 14 | 15 | func (authServer *AuthServer) SignUpUser(ctx context.Context, req *pb.SignUpUserInput) (*pb.GenericResponse, error) { 16 | if req.GetPassword() != req.GetPasswordConfirm() { 17 | return nil, status.Errorf(codes.InvalidArgument, "passwords do not match") 18 | } 19 | 20 | user := models.SignUpInput{ 21 | Name: req.GetName(), 22 | Email: req.GetEmail(), 23 | Password: req.GetPassword(), 24 | PasswordConfirm: req.GetPasswordConfirm(), 25 | } 26 | 27 | newUser, err := authServer.authService.SignUpUser(&user) 28 | 29 | if err != nil { 30 | if strings.Contains(err.Error(), "email already exist") { 31 | return nil, status.Errorf(codes.AlreadyExists, "%s", err.Error()) 32 | 33 | } 34 | return nil, status.Errorf(codes.Internal, "%s", err.Error()) 35 | } 36 | 37 | // Generate Verification Code 38 | code := randstr.String(20) 39 | 40 | verificationCode := utils.Encode(code) 41 | 42 | updateData := &models.UpdateInput{ 43 | VerificationCode: verificationCode, 44 | } 45 | 46 | // Update User in Database 47 | authServer.userService.UpdateUserById(newUser.ID.Hex(), updateData) 48 | 49 | var firstName = newUser.Name 50 | 51 | if strings.Contains(firstName, " ") { 52 | firstName = strings.Split(firstName, " ")[0] 53 | } 54 | 55 | // 👇 Send Email 56 | emailData := utils.EmailData{ 57 | URL: authServer.config.Origin + "/verifyemail/" + code, 58 | FirstName: firstName, 59 | Subject: "Your account verification code", 60 | } 61 | 62 | err = utils.SendEmail(newUser, &emailData, "verificationCode.html") 63 | if err != nil { 64 | return nil, status.Errorf(codes.Internal, "There was an error sending email: %s", err.Error()) 65 | 66 | } 67 | 68 | message := "We sent an email with a verification code to " + newUser.Email 69 | 70 | res := &pb.GenericResponse{ 71 | Status: "success", 72 | Message: message, 73 | } 74 | return res, nil 75 | } 76 | -------------------------------------------------------------------------------- /services/user.service.impl.go: -------------------------------------------------------------------------------- 1 | package services 2 | 3 | import ( 4 | "context" 5 | "errors" 6 | "fmt" 7 | "strings" 8 | 9 | "github.com/wpcodevo/golang-mongodb/models" 10 | "github.com/wpcodevo/golang-mongodb/utils" 11 | "go.mongodb.org/mongo-driver/bson" 12 | "go.mongodb.org/mongo-driver/bson/primitive" 13 | "go.mongodb.org/mongo-driver/mongo" 14 | "go.mongodb.org/mongo-driver/mongo/options" 15 | ) 16 | 17 | type UserServiceImpl struct { 18 | collection *mongo.Collection 19 | ctx context.Context 20 | } 21 | 22 | func NewUserServiceImpl(collection *mongo.Collection, ctx context.Context) UserService { 23 | return &UserServiceImpl{collection, ctx} 24 | } 25 | 26 | func (us *UserServiceImpl) FindUserById(id string) (*models.DBResponse, error) { 27 | oid, _ := primitive.ObjectIDFromHex(id) 28 | 29 | var user *models.DBResponse 30 | 31 | query := bson.M{"_id": oid} 32 | err := us.collection.FindOne(us.ctx, query).Decode(&user) 33 | 34 | if err != nil { 35 | if err == mongo.ErrNoDocuments { 36 | return &models.DBResponse{}, err 37 | } 38 | return nil, err 39 | } 40 | 41 | return user, nil 42 | } 43 | 44 | func (us *UserServiceImpl) FindUserByEmail(email string) (*models.DBResponse, error) { 45 | var user *models.DBResponse 46 | 47 | query := bson.M{"email": strings.ToLower(email)} 48 | err := us.collection.FindOne(us.ctx, query).Decode(&user) 49 | 50 | if err != nil { 51 | if err == mongo.ErrNoDocuments { 52 | return &models.DBResponse{}, err 53 | } 54 | return nil, err 55 | } 56 | 57 | return user, nil 58 | } 59 | 60 | func (uc *UserServiceImpl) UpdateUserById(id string, data *models.UpdateInput) (*models.DBResponse, error) { 61 | doc, err := utils.ToDoc(data) 62 | if err != nil { 63 | return &models.DBResponse{}, err 64 | } 65 | 66 | fmt.Println(data) 67 | 68 | obId, _ := primitive.ObjectIDFromHex(id) 69 | 70 | query := bson.D{{Key: "_id", Value: obId}} 71 | update := bson.D{{Key: "$set", Value: doc}} 72 | result := uc.collection.FindOneAndUpdate(uc.ctx, query, update, options.FindOneAndUpdate().SetReturnDocument(1)) 73 | 74 | var updatedUser *models.DBResponse 75 | if err := result.Decode(&updatedUser); err != nil { 76 | return nil, errors.New("no document with that id exists") 77 | } 78 | 79 | return updatedUser, nil 80 | } 81 | -------------------------------------------------------------------------------- /example.env: -------------------------------------------------------------------------------- 1 | PORT=8000 2 | 3 | GRPC_SERVER_ADDRESS=0.0.0.0:8080 4 | 5 | MONGO_INITDB_ROOT_USERNAME=root 6 | MONGO_INITDB_ROOT_PASSWORD=password123 7 | 8 | MONGODB_LOCAL_URI=mongodb://root:password123@localhost:6000 9 | 10 | REDIS_URL=localhost:6379 11 | 12 | CLIENT_ORIGIN=http://localhost:3000 13 | 14 | EMAIL_FROM=admin@admin.com 15 | SMTP_HOST=smtp.mailtrap.io 16 | SMTP_USER= 17 | SMTP_PASS= 18 | SMTP_PORT=587 19 | 20 | 21 | ACCESS_TOKEN_PRIVATE_KEY=LS0tLS1CRUdJTiBSU0EgUFJJVkFURSBLRVktLS0tLQpNSUlCUEFJQkFBSkJBTzVIKytVM0xrWC91SlRvRHhWN01CUURXSTdGU0l0VXNjbGFFKzlaUUg5Q2VpOGIxcUVmCnJxR0hSVDVWUis4c3UxVWtCUVpZTER3MnN3RTVWbjg5c0ZVQ0F3RUFBUUpCQUw4ZjRBMUlDSWEvQ2ZmdWR3TGMKNzRCdCtwOXg0TEZaZXMwdHdtV3Vha3hub3NaV0w4eVpSTUJpRmI4a25VL0hwb3piTnNxMmN1ZU9wKzVWdGRXNApiTlVDSVFENm9JdWxqcHdrZTFGY1VPaldnaXRQSjNnbFBma3NHVFBhdFYwYnJJVVI5d0loQVBOanJ1enB4ckhsCkUxRmJxeGtUNFZ5bWhCOU1HazU0Wk1jWnVjSmZOcjBUQWlFQWhML3UxOVZPdlVBWVd6Wjc3Y3JxMTdWSFBTcXoKUlhsZjd2TnJpdEg1ZGdjQ0lRRHR5QmFPdUxuNDlIOFIvZ2ZEZ1V1cjg3YWl5UHZ1YStxeEpXMzQrb0tFNXdJZwpQbG1KYXZsbW9jUG4rTkVRdGhLcTZuZFVYRGpXTTlTbktQQTVlUDZSUEs0PQotLS0tLUVORCBSU0EgUFJJVkFURSBLRVktLS0tLQ== 22 | 23 | ACCESS_TOKEN_PUBLIC_KEY=LS0tLS1CRUdJTiBQVUJMSUMgS0VZLS0tLS0KTUZ3d0RRWUpLb1pJaHZjTkFRRUJCUUFEU3dBd1NBSkJBTzVIKytVM0xrWC91SlRvRHhWN01CUURXSTdGU0l0VQpzY2xhRSs5WlFIOUNlaThiMXFFZnJxR0hSVDVWUis4c3UxVWtCUVpZTER3MnN3RTVWbjg5c0ZVQ0F3RUFBUT09Ci0tLS0tRU5EIFBVQkxJQyBLRVktLS0tLQ== 24 | ACCESS_TOKEN_EXPIRED_IN=15m 25 | ACCESS_TOKEN_MAXAGE=15 26 | 27 | 28 | REFRESH_TOKEN_PRIVATE_KEY=LS0tLS1CRUdJTiBSU0EgUFJJVkFURSBLRVktLS0tLQpNSUlCT1FJQkFBSkJBSWFJcXZXeldCSndnYjR1SEhFQ01RdHFZMTI5b2F5RzVZMGlGcG51a0J1VHpRZVlQWkE4Cmx4OC9lTUh3Rys1MlJGR3VxMmE2N084d2s3TDR5dnY5dVY4Q0F3RUFBUUpBRUZ6aEJqOUk3LzAxR285N01CZUgKSlk5TUJLUEMzVHdQQVdwcSswL3p3UmE2ZkZtbXQ5NXNrN21qT3czRzNEZ3M5T2RTeWdsbTlVdndNWXh6SXFERAplUUloQVA5UStrMTBQbGxNd2ZJbDZtdjdTMFRYOGJDUlRaZVI1ZFZZb3FTeW40YmpBaUVBaHVUa2JtZ1NobFlZCnRyclNWZjN0QWZJcWNVUjZ3aDdMOXR5MVlvalZVRlVDSUhzOENlVHkwOWxrbkVTV0dvV09ZUEZVemhyc3Q2Z08KU3dKa2F2VFdKdndEQWlBdWhnVU8yeEFBaXZNdEdwUHVtb3hDam8zNjBMNXg4d012bWdGcEFYNW9uUUlnQzEvSwpNWG1heWtsaFRDeWtXRnpHMHBMWVdkNGRGdTI5M1M2ZUxJUlNIS009Ci0tLS0tRU5EIFJTQSBQUklWQVRFIEtFWS0tLS0t 29 | 30 | REFRESH_TOKEN_PUBLIC_KEY=LS0tLS1CRUdJTiBQVUJMSUMgS0VZLS0tLS0KTUZ3d0RRWUpLb1pJaHZjTkFRRUJCUUFEU3dBd1NBSkJBSWFJcXZXeldCSndnYjR1SEhFQ01RdHFZMTI5b2F5Rwo1WTBpRnBudWtCdVR6UWVZUFpBOGx4OC9lTUh3Rys1MlJGR3VxMmE2N084d2s3TDR5dnY5dVY4Q0F3RUFBUT09Ci0tLS0tRU5EIFBVQkxJQyBLRVktLS0tLQ== 31 | 32 | REFRESH_TOKEN_EXPIRED_IN=60m 33 | REFRESH_TOKEN_MAXAGE=60 34 | -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module github.com/wpcodevo/golang-mongodb 2 | 3 | go 1.18 4 | 5 | require ( 6 | github.com/gin-contrib/cors v1.3.1 7 | github.com/gin-gonic/gin v1.7.7 8 | github.com/go-redis/redis/v8 v8.11.5 9 | github.com/golang-jwt/jwt v3.2.2+incompatible 10 | github.com/k3a/html2text v1.0.8 11 | github.com/spf13/viper v1.11.0 12 | github.com/thanhpk/randstr v1.0.4 13 | go.mongodb.org/mongo-driver v1.9.1 14 | golang.org/x/crypto v0.0.0-20220513210258-46612604a0f9 15 | google.golang.org/grpc v1.45.0 16 | google.golang.org/protobuf v1.28.0 17 | gopkg.in/gomail.v2 v2.0.0-20160411212932-81ebce5c23df 18 | ) 19 | 20 | require ( 21 | github.com/cespare/xxhash/v2 v2.1.2 // indirect 22 | github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect 23 | github.com/fsnotify/fsnotify v1.5.1 // indirect 24 | github.com/gin-contrib/sse v0.1.0 // indirect 25 | github.com/go-playground/locales v0.14.0 // indirect 26 | github.com/go-playground/universal-translator v0.18.0 // indirect 27 | github.com/go-playground/validator/v10 v10.11.0 // indirect 28 | github.com/go-stack/stack v1.8.0 // indirect 29 | github.com/golang/protobuf v1.5.2 // indirect 30 | github.com/golang/snappy v0.0.1 // indirect 31 | github.com/hashicorp/hcl v1.0.0 // indirect 32 | github.com/json-iterator/go v1.1.12 // indirect 33 | github.com/klauspost/compress v1.13.6 // indirect 34 | github.com/leodido/go-urn v1.2.1 // indirect 35 | github.com/magiconair/properties v1.8.6 // indirect 36 | github.com/mattn/go-isatty v0.0.14 // indirect 37 | github.com/mitchellh/mapstructure v1.4.3 // indirect 38 | github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect 39 | github.com/modern-go/reflect2 v1.0.2 // indirect 40 | github.com/pelletier/go-toml v1.9.4 // indirect 41 | github.com/pelletier/go-toml/v2 v2.0.0-beta.8 // indirect 42 | github.com/pkg/errors v0.9.1 // indirect 43 | github.com/spf13/afero v1.8.2 // indirect 44 | github.com/spf13/cast v1.4.1 // indirect 45 | github.com/spf13/jwalterweatherman v1.1.0 // indirect 46 | github.com/spf13/pflag v1.0.5 // indirect 47 | github.com/subosito/gotenv v1.2.0 // indirect 48 | github.com/ugorji/go/codec v1.2.7 // indirect 49 | github.com/xdg-go/pbkdf2 v1.0.0 // indirect 50 | github.com/xdg-go/scram v1.0.2 // indirect 51 | github.com/xdg-go/stringprep v1.0.2 // indirect 52 | github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d // indirect 53 | golang.org/x/net v0.0.0-20220412020605-290c469a71a5 // indirect 54 | golang.org/x/sync v0.0.0-20201207232520-09787c993a3a // indirect 55 | golang.org/x/sys v0.0.0-20220513210249-45d2b4557a2a // indirect 56 | golang.org/x/text v0.3.7 // indirect 57 | google.golang.org/genproto v0.0.0-20220407144326-9054f6ed7bac // indirect 58 | gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc // indirect 59 | gopkg.in/ini.v1 v1.66.4 // indirect 60 | gopkg.in/yaml.v2 v2.4.0 // indirect 61 | gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b // indirect 62 | ) 63 | -------------------------------------------------------------------------------- /cmd/client/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "log" 5 | 6 | "github.com/wpcodevo/golang-mongodb/client" 7 | "github.com/wpcodevo/golang-mongodb/pb" 8 | "google.golang.org/grpc" 9 | "google.golang.org/grpc/credentials/insecure" 10 | ) 11 | 12 | const ( 13 | address = "0.0.0.0:8080" 14 | ) 15 | 16 | func main() { 17 | conn, err := grpc.Dial(address, grpc.WithTransportCredentials(insecure.NewCredentials()), grpc.WithBlock()) 18 | 19 | if err != nil { 20 | log.Fatalf("failed to connect: %v", err) 21 | } 22 | 23 | defer conn.Close() 24 | 25 | // Sign Up 26 | if false { 27 | signUpUserClient := client.NewSignUpUserClient(conn) 28 | newUser := &pb.SignUpUserInput{ 29 | Name: "Jane Smith", 30 | Email: "janesmith@gmail.com", 31 | Password: "password123", 32 | PasswordConfirm: "password123", 33 | } 34 | signUpUserClient.SignUpUser(newUser) 35 | } 36 | 37 | // Sign In 38 | if false { 39 | signInUserClient := client.NewSignInUserClient(conn) 40 | 41 | credentials := &pb.SignInUserInput{ 42 | Email: "janesmith@gmail.com", 43 | Password: "password123", 44 | } 45 | signInUserClient.SignInUser(credentials) 46 | } 47 | 48 | // Get Me 49 | if false { 50 | 51 | getMeClient := client.NewGetMeClient(conn) 52 | id := &pb.GetMeRequest{ 53 | Id: "628cffb91e50302d360c1a2c", 54 | } 55 | getMeClient.GetMeUser(id) 56 | 57 | } 58 | 59 | // List Posts 60 | if false { 61 | listPostsClient := client.NewListPostsClient(conn) 62 | 63 | var page int64 = 1 64 | var limit int64 = 10 65 | args := &pb.GetPostsRequest{ 66 | Page: &page, 67 | Limit: &limit, 68 | } 69 | 70 | listPostsClient.ListPosts(args) 71 | } 72 | 73 | // Create Post 74 | if false { 75 | createPostClient := client.NewCreatePostClient(conn) 76 | 77 | args := &pb.CreatePostRequest{ 78 | Title: "My second gRPC post with joy", 79 | Content: "It's always good to learn new technologies", 80 | User: "62908e0a42a608d5aeae2f64", 81 | Image: "default.png", 82 | } 83 | 84 | createPostClient.CreatePost(args) 85 | } 86 | 87 | // Update Post 88 | if false { 89 | updatePostClient := client.NewUpdatePostClient(conn) 90 | 91 | title := "My new updated title for my blog" 92 | args := &pb.UpdatePostRequest{ 93 | Id: "629169e00a6c7cfd24e2129d", 94 | Title: &title, 95 | } 96 | 97 | updatePostClient.UpdatePost(args) 98 | } 99 | 100 | // Get Post 101 | if false { 102 | getPostClient := client.NewGetPostClient(conn) 103 | 104 | args := &pb.PostRequest{ 105 | Id: "629169e00a6c7cfd24e2129d", 106 | } 107 | 108 | getPostClient.GetPost(args) 109 | } 110 | 111 | // Delete Post 112 | if false { 113 | deletePostClient := client.NewDeletePostClient(conn) 114 | 115 | args := &pb.PostRequest{ 116 | Id: "629147ff3c92aed11d49394b", 117 | } 118 | 119 | deletePostClient.DeletePost(args) 120 | } 121 | } 122 | -------------------------------------------------------------------------------- /controllers/post.controller.go: -------------------------------------------------------------------------------- 1 | package controllers 2 | 3 | import ( 4 | "net/http" 5 | "strconv" 6 | "strings" 7 | 8 | "github.com/gin-gonic/gin" 9 | "github.com/wpcodevo/golang-mongodb/models" 10 | "github.com/wpcodevo/golang-mongodb/services" 11 | ) 12 | 13 | type PostController struct { 14 | postService services.PostService 15 | } 16 | 17 | func NewPostController(postService services.PostService) PostController { 18 | return PostController{postService} 19 | } 20 | 21 | func (pc *PostController) CreatePost(ctx *gin.Context) { 22 | var post *models.CreatePostRequest 23 | 24 | if err := ctx.ShouldBindJSON(&post); err != nil { 25 | ctx.JSON(http.StatusBadRequest, err.Error()) 26 | return 27 | } 28 | 29 | newPost, err := pc.postService.CreatePost(post) 30 | 31 | if err != nil { 32 | if strings.Contains(err.Error(), "title already exists") { 33 | ctx.JSON(http.StatusConflict, gin.H{"status": "fail", "message": err.Error()}) 34 | return 35 | } 36 | 37 | ctx.JSON(http.StatusBadGateway, gin.H{"status": "fail", "message": err.Error()}) 38 | return 39 | } 40 | 41 | ctx.JSON(http.StatusCreated, gin.H{"status": "success", "data": newPost}) 42 | } 43 | 44 | func (pc *PostController) UpdatePost(ctx *gin.Context) { 45 | postId := ctx.Param("postId") 46 | 47 | var post *models.UpdatePost 48 | if err := ctx.ShouldBindJSON(&post); err != nil { 49 | ctx.JSON(http.StatusBadGateway, gin.H{"status": "fail", "message": err.Error()}) 50 | return 51 | } 52 | 53 | updatedPost, err := pc.postService.UpdatePost(postId, post) 54 | if err != nil { 55 | if strings.Contains(err.Error(), "Id exists") { 56 | ctx.JSON(http.StatusNotFound, gin.H{"status": "fail", "message": err.Error()}) 57 | return 58 | } 59 | ctx.JSON(http.StatusBadGateway, gin.H{"status": "fail", "message": err.Error()}) 60 | return 61 | } 62 | 63 | ctx.JSON(http.StatusOK, gin.H{"status": "success", "data": updatedPost}) 64 | } 65 | 66 | func (pc *PostController) FindPostById(ctx *gin.Context) { 67 | postId := ctx.Param("postId") 68 | 69 | post, err := pc.postService.FindPostById(postId) 70 | 71 | if err != nil { 72 | ctx.JSON(http.StatusBadGateway, gin.H{"status": "fail", "message": err.Error()}) 73 | return 74 | } 75 | 76 | ctx.JSON(http.StatusOK, gin.H{"status": "success", "data": post}) 77 | } 78 | 79 | func (pc *PostController) FindPosts(ctx *gin.Context) { 80 | var page = ctx.DefaultQuery("page", "1") 81 | var limit = ctx.DefaultQuery("limit", "10") 82 | 83 | intPage, err := strconv.Atoi(page) 84 | if err != nil { 85 | ctx.JSON(http.StatusBadGateway, gin.H{"status": "fail", "message": err.Error()}) 86 | return 87 | } 88 | 89 | intLimit, err := strconv.Atoi(limit) 90 | if err != nil { 91 | ctx.JSON(http.StatusBadGateway, gin.H{"status": "fail", "message": err.Error()}) 92 | return 93 | } 94 | 95 | posts, err := pc.postService.FindPosts(intPage, intLimit) 96 | if err != nil { 97 | ctx.JSON(http.StatusBadGateway, gin.H{"status": "fail", "message": err.Error()}) 98 | return 99 | } 100 | 101 | ctx.JSON(http.StatusOK, gin.H{"status": "success", "results": len(posts), "data": posts}) 102 | } 103 | 104 | func (pc *PostController) DeletePost(ctx *gin.Context) { 105 | postId := ctx.Param("postId") 106 | 107 | err := pc.postService.DeletePost(postId) 108 | 109 | if err != nil { 110 | if strings.Contains(err.Error(), "Id exists") { 111 | ctx.JSON(http.StatusNotFound, gin.H{"status": "fail", "message": err.Error()}) 112 | return 113 | } 114 | ctx.JSON(http.StatusBadGateway, gin.H{"status": "fail", "message": err.Error()}) 115 | return 116 | } 117 | 118 | ctx.JSON(http.StatusNoContent, nil) 119 | } 120 | -------------------------------------------------------------------------------- /pb/user_service_grpc.pb.go: -------------------------------------------------------------------------------- 1 | // Code generated by protoc-gen-go-grpc. DO NOT EDIT. 2 | // versions: 3 | // - protoc-gen-go-grpc v1.2.0 4 | // - protoc v3.20.1 5 | // source: user_service.proto 6 | 7 | package pb 8 | 9 | import ( 10 | context "context" 11 | grpc "google.golang.org/grpc" 12 | codes "google.golang.org/grpc/codes" 13 | status "google.golang.org/grpc/status" 14 | ) 15 | 16 | // This is a compile-time assertion to ensure that this generated file 17 | // is compatible with the grpc package it is being compiled against. 18 | // Requires gRPC-Go v1.32.0 or later. 19 | const _ = grpc.SupportPackageIsVersion7 20 | 21 | // UserServiceClient is the client API for UserService service. 22 | // 23 | // 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. 24 | type UserServiceClient interface { 25 | GetMe(ctx context.Context, in *GetMeRequest, opts ...grpc.CallOption) (*UserResponse, error) 26 | } 27 | 28 | type userServiceClient struct { 29 | cc grpc.ClientConnInterface 30 | } 31 | 32 | func NewUserServiceClient(cc grpc.ClientConnInterface) UserServiceClient { 33 | return &userServiceClient{cc} 34 | } 35 | 36 | func (c *userServiceClient) GetMe(ctx context.Context, in *GetMeRequest, opts ...grpc.CallOption) (*UserResponse, error) { 37 | out := new(UserResponse) 38 | err := c.cc.Invoke(ctx, "/pb.UserService/GetMe", in, out, opts...) 39 | if err != nil { 40 | return nil, err 41 | } 42 | return out, nil 43 | } 44 | 45 | // UserServiceServer is the server API for UserService service. 46 | // All implementations must embed UnimplementedUserServiceServer 47 | // for forward compatibility 48 | type UserServiceServer interface { 49 | GetMe(context.Context, *GetMeRequest) (*UserResponse, error) 50 | mustEmbedUnimplementedUserServiceServer() 51 | } 52 | 53 | // UnimplementedUserServiceServer must be embedded to have forward compatible implementations. 54 | type UnimplementedUserServiceServer struct { 55 | } 56 | 57 | func (UnimplementedUserServiceServer) GetMe(context.Context, *GetMeRequest) (*UserResponse, error) { 58 | return nil, status.Errorf(codes.Unimplemented, "method GetMe not implemented") 59 | } 60 | func (UnimplementedUserServiceServer) mustEmbedUnimplementedUserServiceServer() {} 61 | 62 | // UnsafeUserServiceServer may be embedded to opt out of forward compatibility for this service. 63 | // Use of this interface is not recommended, as added methods to UserServiceServer will 64 | // result in compilation errors. 65 | type UnsafeUserServiceServer interface { 66 | mustEmbedUnimplementedUserServiceServer() 67 | } 68 | 69 | func RegisterUserServiceServer(s grpc.ServiceRegistrar, srv UserServiceServer) { 70 | s.RegisterService(&UserService_ServiceDesc, srv) 71 | } 72 | 73 | func _UserService_GetMe_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { 74 | in := new(GetMeRequest) 75 | if err := dec(in); err != nil { 76 | return nil, err 77 | } 78 | if interceptor == nil { 79 | return srv.(UserServiceServer).GetMe(ctx, in) 80 | } 81 | info := &grpc.UnaryServerInfo{ 82 | Server: srv, 83 | FullMethod: "/pb.UserService/GetMe", 84 | } 85 | handler := func(ctx context.Context, req interface{}) (interface{}, error) { 86 | return srv.(UserServiceServer).GetMe(ctx, req.(*GetMeRequest)) 87 | } 88 | return interceptor(ctx, in, info, handler) 89 | } 90 | 91 | // UserService_ServiceDesc is the grpc.ServiceDesc for UserService service. 92 | // It's only intended for direct use with grpc.RegisterService, 93 | // and not to be introspected or modified (even as a copy) 94 | var UserService_ServiceDesc = grpc.ServiceDesc{ 95 | ServiceName: "pb.UserService", 96 | HandlerType: (*UserServiceServer)(nil), 97 | Methods: []grpc.MethodDesc{ 98 | { 99 | MethodName: "GetMe", 100 | Handler: _UserService_GetMe_Handler, 101 | }, 102 | }, 103 | Streams: []grpc.StreamDesc{}, 104 | Metadata: "user_service.proto", 105 | } 106 | -------------------------------------------------------------------------------- /services/post.service.impl.go: -------------------------------------------------------------------------------- 1 | package services 2 | 3 | import ( 4 | "context" 5 | "errors" 6 | "time" 7 | 8 | "github.com/wpcodevo/golang-mongodb/models" 9 | "github.com/wpcodevo/golang-mongodb/utils" 10 | "go.mongodb.org/mongo-driver/bson" 11 | "go.mongodb.org/mongo-driver/bson/primitive" 12 | "go.mongodb.org/mongo-driver/mongo" 13 | "go.mongodb.org/mongo-driver/mongo/options" 14 | ) 15 | 16 | type PostServiceImpl struct { 17 | postCollection *mongo.Collection 18 | ctx context.Context 19 | } 20 | 21 | func NewPostService(postCollection *mongo.Collection, ctx context.Context) PostService { 22 | return &PostServiceImpl{postCollection, ctx} 23 | } 24 | 25 | func (p *PostServiceImpl) CreatePost(post *models.CreatePostRequest) (*models.DBPost, error) { 26 | post.CreateAt = time.Now() 27 | post.UpdatedAt = post.CreateAt 28 | res, err := p.postCollection.InsertOne(p.ctx, post) 29 | 30 | if err != nil { 31 | if er, ok := err.(mongo.WriteException); ok && er.WriteErrors[0].Code == 11000 { 32 | return nil, errors.New("post with that title already exists") 33 | } 34 | return nil, err 35 | } 36 | 37 | opt := options.Index() 38 | opt.SetUnique(true) 39 | 40 | index := mongo.IndexModel{Keys: bson.M{"title": 1}, Options: opt} 41 | 42 | if _, err := p.postCollection.Indexes().CreateOne(p.ctx, index); err != nil { 43 | return nil, errors.New("could not create index for title") 44 | } 45 | 46 | var newPost *models.DBPost 47 | query := bson.M{"_id": res.InsertedID} 48 | if err = p.postCollection.FindOne(p.ctx, query).Decode(&newPost); err != nil { 49 | return nil, err 50 | } 51 | 52 | return newPost, nil 53 | } 54 | 55 | func (p *PostServiceImpl) UpdatePost(id string, data *models.UpdatePost) (*models.DBPost, error) { 56 | doc, err := utils.ToDoc(data) 57 | if err != nil { 58 | return nil, err 59 | } 60 | 61 | obId, _ := primitive.ObjectIDFromHex(id) 62 | query := bson.D{{Key: "_id", Value: obId}} 63 | update := bson.D{{Key: "$set", Value: doc}} 64 | res := p.postCollection.FindOneAndUpdate(p.ctx, query, update, options.FindOneAndUpdate().SetReturnDocument(1)) 65 | 66 | var updatedPost *models.DBPost 67 | if err := res.Decode(&updatedPost); err != nil { 68 | return nil, errors.New("no post with that Id exists") 69 | } 70 | 71 | return updatedPost, nil 72 | } 73 | 74 | func (p *PostServiceImpl) FindPostById(id string) (*models.DBPost, error) { 75 | obId, _ := primitive.ObjectIDFromHex(id) 76 | 77 | query := bson.M{"_id": obId} 78 | 79 | var post *models.DBPost 80 | 81 | if err := p.postCollection.FindOne(p.ctx, query).Decode(&post); err != nil { 82 | if err == mongo.ErrNoDocuments { 83 | return nil, errors.New("no document with that Id exists") 84 | } 85 | 86 | return nil, err 87 | } 88 | 89 | return post, nil 90 | } 91 | 92 | func (p *PostServiceImpl) FindPosts(page int, limit int) ([]*models.DBPost, error) { 93 | if page == 0 { 94 | page = 1 95 | } 96 | 97 | if limit == 0 { 98 | limit = 10 99 | } 100 | 101 | skip := (page - 1) * limit 102 | 103 | opt := options.FindOptions{} 104 | opt.SetLimit(int64(limit)) 105 | opt.SetSkip(int64(skip)) 106 | opt.SetSort(bson.M{"created_at": -1}) 107 | 108 | query := bson.M{} 109 | 110 | cursor, err := p.postCollection.Find(p.ctx, query, &opt) 111 | if err != nil { 112 | return nil, err 113 | } 114 | 115 | defer cursor.Close(p.ctx) 116 | 117 | var posts []*models.DBPost 118 | 119 | for cursor.Next(p.ctx) { 120 | post := &models.DBPost{} 121 | err := cursor.Decode(post) 122 | 123 | if err != nil { 124 | return nil, err 125 | } 126 | 127 | posts = append(posts, post) 128 | } 129 | 130 | if err := cursor.Err(); err != nil { 131 | return nil, err 132 | } 133 | 134 | if len(posts) == 0 { 135 | return []*models.DBPost{}, nil 136 | } 137 | 138 | return posts, nil 139 | } 140 | 141 | func (p *PostServiceImpl) DeletePost(id string) error { 142 | obId, _ := primitive.ObjectIDFromHex(id) 143 | query := bson.M{"_id": obId} 144 | 145 | res, err := p.postCollection.DeleteOne(p.ctx, query) 146 | if err != nil { 147 | return err 148 | } 149 | 150 | if res.DeletedCount == 0 { 151 | return errors.New("no document with that Id exists") 152 | } 153 | 154 | return nil 155 | } 156 | -------------------------------------------------------------------------------- /models/user.model.go: -------------------------------------------------------------------------------- 1 | package models 2 | 3 | import ( 4 | "time" 5 | 6 | "go.mongodb.org/mongo-driver/bson/primitive" 7 | ) 8 | 9 | // 👈 SignUpInput struct 10 | type SignUpInput struct { 11 | Name string `json:"name" bson:"name" binding:"required"` 12 | Email string `json:"email" bson:"email" binding:"required"` 13 | Password string `json:"password" bson:"password" binding:"required,min=8"` 14 | PasswordConfirm string `json:"passwordConfirm" bson:"passwordConfirm,omitempty" binding:"required"` 15 | Role string `json:"role" bson:"role"` 16 | VerificationCode string `json:"verificationCode,omitempty" bson:"verificationCode,omitempty"` 17 | ResetPasswordToken string `json:"resetPasswordToken,omitempty" bson:"resetPasswordToken,omitempty"` 18 | ResetPasswordAt time.Time `json:"resetPasswordAt,omitempty" bson:"resetPasswordAt,omitempty"` 19 | Verified bool `json:"verified" bson:"verified"` 20 | CreatedAt time.Time `json:"created_at" bson:"created_at"` 21 | UpdatedAt time.Time `json:"updated_at" bson:"updated_at"` 22 | } 23 | 24 | // 👈 SignInInput struct 25 | type SignInInput struct { 26 | Email string `json:"email" bson:"email" binding:"required"` 27 | Password string `json:"password" bson:"password" binding:"required"` 28 | } 29 | 30 | // 👈 DBResponse struct 31 | type DBResponse struct { 32 | ID primitive.ObjectID `json:"id" bson:"_id"` 33 | Name string `json:"name" bson:"name"` 34 | Email string `json:"email" bson:"email"` 35 | Password string `json:"password" bson:"password"` 36 | PasswordConfirm string `json:"passwordConfirm,omitempty" bson:"passwordConfirm,omitempty"` 37 | Role string `json:"role" bson:"role"` 38 | VerificationCode string `json:"verificationCode,omitempty" bson:"verificationCode"` 39 | ResetPasswordToken string `json:"resetPasswordToken,omitempty" bson:"resetPasswordToken,omitempty"` 40 | ResetPasswordAt time.Time `json:"resetPasswordAt,omitempty" bson:"resetPasswordAt,omitempty"` 41 | Verified bool `json:"verified" bson:"verified"` 42 | CreatedAt time.Time `json:"created_at" bson:"created_at"` 43 | UpdatedAt time.Time `json:"updated_at" bson:"updated_at"` 44 | } 45 | 46 | type UpdateInput struct { 47 | Name string `json:"name,omitempty" bson:"name,omitempty"` 48 | Email string `json:"email,omitempty" bson:"email,omitempty"` 49 | Password string `json:"password,omitempty" bson:"password,omitempty"` 50 | Role string `json:"role,omitempty" bson:"role,omitempty"` 51 | VerificationCode string `json:"verificationCode,omitempty" bson:"verificationCode,omitempty"` 52 | ResetPasswordToken string `json:"resetPasswordToken,omitempty" bson:"resetPasswordToken,omitempty"` 53 | ResetPasswordAt time.Time `json:"resetPasswordAt,omitempty" bson:"resetPasswordAt,omitempty"` 54 | Verified bool `json:"verified,omitempty" bson:"verified,omitempty"` 55 | CreatedAt time.Time `json:"created_at,omitempty" bson:"created_at,omitempty"` 56 | UpdatedAt time.Time `json:"updated_at,omitempty" bson:"updated_at,omitempty"` 57 | } 58 | 59 | // 👈 UserResponse struct 60 | type UserResponse struct { 61 | ID primitive.ObjectID `json:"id,omitempty" bson:"_id,omitempty"` 62 | Name string `json:"name,omitempty" bson:"name,omitempty"` 63 | Email string `json:"email,omitempty" bson:"email,omitempty"` 64 | Role string `json:"role,omitempty" bson:"role,omitempty"` 65 | CreatedAt time.Time `json:"created_at" bson:"created_at"` 66 | UpdatedAt time.Time `json:"updated_at" bson:"updated_at"` 67 | } 68 | 69 | // 👈 ForgotPasswordInput struct 70 | type ForgotPasswordInput struct { 71 | Email string `json:"email" bson:"email" binding:"required"` 72 | } 73 | 74 | // 👈 ResetPasswordInput struct 75 | type ResetPasswordInput struct { 76 | Password string `json:"password" bson:"password"` 77 | PasswordConfirm string `json:"passwordConfirm,omitempty" bson:"passwordConfirm,omitempty"` 78 | } 79 | 80 | func FilteredResponse(user *DBResponse) UserResponse { 81 | return UserResponse{ 82 | ID: user.ID, 83 | Email: user.Email, 84 | Name: user.Name, 85 | Role: user.Role, 86 | CreatedAt: user.CreatedAt, 87 | UpdatedAt: user.UpdatedAt, 88 | } 89 | } 90 | -------------------------------------------------------------------------------- /pb/user_service.pb.go: -------------------------------------------------------------------------------- 1 | // Code generated by protoc-gen-go. DO NOT EDIT. 2 | // versions: 3 | // protoc-gen-go v1.28.0 4 | // protoc v3.20.1 5 | // source: user_service.proto 6 | 7 | package pb 8 | 9 | import ( 10 | protoreflect "google.golang.org/protobuf/reflect/protoreflect" 11 | protoimpl "google.golang.org/protobuf/runtime/protoimpl" 12 | reflect "reflect" 13 | sync "sync" 14 | ) 15 | 16 | const ( 17 | // Verify that this generated code is sufficiently up-to-date. 18 | _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) 19 | // Verify that runtime/protoimpl is sufficiently up-to-date. 20 | _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) 21 | ) 22 | 23 | type GetMeRequest struct { 24 | state protoimpl.MessageState 25 | sizeCache protoimpl.SizeCache 26 | unknownFields protoimpl.UnknownFields 27 | 28 | Id string `protobuf:"bytes,1,opt,name=Id,proto3" json:"Id,omitempty"` 29 | } 30 | 31 | func (x *GetMeRequest) Reset() { 32 | *x = GetMeRequest{} 33 | if protoimpl.UnsafeEnabled { 34 | mi := &file_user_service_proto_msgTypes[0] 35 | ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) 36 | ms.StoreMessageInfo(mi) 37 | } 38 | } 39 | 40 | func (x *GetMeRequest) String() string { 41 | return protoimpl.X.MessageStringOf(x) 42 | } 43 | 44 | func (*GetMeRequest) ProtoMessage() {} 45 | 46 | func (x *GetMeRequest) ProtoReflect() protoreflect.Message { 47 | mi := &file_user_service_proto_msgTypes[0] 48 | if protoimpl.UnsafeEnabled && x != nil { 49 | ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) 50 | if ms.LoadMessageInfo() == nil { 51 | ms.StoreMessageInfo(mi) 52 | } 53 | return ms 54 | } 55 | return mi.MessageOf(x) 56 | } 57 | 58 | // Deprecated: Use GetMeRequest.ProtoReflect.Descriptor instead. 59 | func (*GetMeRequest) Descriptor() ([]byte, []int) { 60 | return file_user_service_proto_rawDescGZIP(), []int{0} 61 | } 62 | 63 | func (x *GetMeRequest) GetId() string { 64 | if x != nil { 65 | return x.Id 66 | } 67 | return "" 68 | } 69 | 70 | var File_user_service_proto protoreflect.FileDescriptor 71 | 72 | var file_user_service_proto_rawDesc = []byte{ 73 | 0x0a, 0x12, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x70, 74 | 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x02, 0x70, 0x62, 0x1a, 0x0a, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x70, 75 | 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x1e, 0x0a, 0x0c, 0x47, 0x65, 0x74, 0x4d, 0x65, 0x52, 0x65, 0x71, 76 | 0x75, 0x65, 0x73, 0x74, 0x12, 0x0e, 0x0a, 0x02, 0x49, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 77 | 0x52, 0x02, 0x49, 0x64, 0x32, 0x3c, 0x0a, 0x0b, 0x55, 0x73, 0x65, 0x72, 0x53, 0x65, 0x72, 0x76, 78 | 0x69, 0x63, 0x65, 0x12, 0x2d, 0x0a, 0x05, 0x47, 0x65, 0x74, 0x4d, 0x65, 0x12, 0x10, 0x2e, 0x70, 79 | 0x62, 0x2e, 0x47, 0x65, 0x74, 0x4d, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x10, 80 | 0x2e, 0x70, 0x62, 0x2e, 0x55, 0x73, 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 81 | 0x22, 0x00, 0x42, 0x27, 0x5a, 0x25, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 82 | 0x2f, 0x77, 0x70, 0x63, 0x6f, 0x64, 0x65, 0x76, 0x6f, 0x2f, 0x67, 0x6f, 0x6c, 0x61, 0x6e, 0x67, 83 | 0x2d, 0x6d, 0x6f, 0x6e, 0x67, 0x6f, 0x64, 0x62, 0x2f, 0x70, 0x62, 0x62, 0x06, 0x70, 0x72, 0x6f, 84 | 0x74, 0x6f, 0x33, 85 | } 86 | 87 | var ( 88 | file_user_service_proto_rawDescOnce sync.Once 89 | file_user_service_proto_rawDescData = file_user_service_proto_rawDesc 90 | ) 91 | 92 | func file_user_service_proto_rawDescGZIP() []byte { 93 | file_user_service_proto_rawDescOnce.Do(func() { 94 | file_user_service_proto_rawDescData = protoimpl.X.CompressGZIP(file_user_service_proto_rawDescData) 95 | }) 96 | return file_user_service_proto_rawDescData 97 | } 98 | 99 | var file_user_service_proto_msgTypes = make([]protoimpl.MessageInfo, 1) 100 | var file_user_service_proto_goTypes = []interface{}{ 101 | (*GetMeRequest)(nil), // 0: pb.GetMeRequest 102 | (*UserResponse)(nil), // 1: pb.UserResponse 103 | } 104 | var file_user_service_proto_depIdxs = []int32{ 105 | 0, // 0: pb.UserService.GetMe:input_type -> pb.GetMeRequest 106 | 1, // 1: pb.UserService.GetMe:output_type -> pb.UserResponse 107 | 1, // [1:2] is the sub-list for method output_type 108 | 0, // [0:1] is the sub-list for method input_type 109 | 0, // [0:0] is the sub-list for extension type_name 110 | 0, // [0:0] is the sub-list for extension extendee 111 | 0, // [0:0] is the sub-list for field type_name 112 | } 113 | 114 | func init() { file_user_service_proto_init() } 115 | func file_user_service_proto_init() { 116 | if File_user_service_proto != nil { 117 | return 118 | } 119 | file_user_proto_init() 120 | if !protoimpl.UnsafeEnabled { 121 | file_user_service_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { 122 | switch v := v.(*GetMeRequest); i { 123 | case 0: 124 | return &v.state 125 | case 1: 126 | return &v.sizeCache 127 | case 2: 128 | return &v.unknownFields 129 | default: 130 | return nil 131 | } 132 | } 133 | } 134 | type x struct{} 135 | out := protoimpl.TypeBuilder{ 136 | File: protoimpl.DescBuilder{ 137 | GoPackagePath: reflect.TypeOf(x{}).PkgPath(), 138 | RawDescriptor: file_user_service_proto_rawDesc, 139 | NumEnums: 0, 140 | NumMessages: 1, 141 | NumExtensions: 0, 142 | NumServices: 1, 143 | }, 144 | GoTypes: file_user_service_proto_goTypes, 145 | DependencyIndexes: file_user_service_proto_depIdxs, 146 | MessageInfos: file_user_service_proto_msgTypes, 147 | }.Build() 148 | File_user_service_proto = out.File 149 | file_user_service_proto_rawDesc = nil 150 | file_user_service_proto_goTypes = nil 151 | file_user_service_proto_depIdxs = nil 152 | } 153 | -------------------------------------------------------------------------------- /cmd/server/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "context" 5 | "fmt" 6 | "log" 7 | "net" 8 | "net/http" 9 | 10 | "github.com/gin-contrib/cors" 11 | "github.com/gin-gonic/gin" 12 | "github.com/go-redis/redis/v8" 13 | "github.com/wpcodevo/golang-mongodb/config" 14 | "github.com/wpcodevo/golang-mongodb/controllers" 15 | "github.com/wpcodevo/golang-mongodb/gapi" 16 | "github.com/wpcodevo/golang-mongodb/pb" 17 | "github.com/wpcodevo/golang-mongodb/routes" 18 | "github.com/wpcodevo/golang-mongodb/services" 19 | "go.mongodb.org/mongo-driver/mongo" 20 | "go.mongodb.org/mongo-driver/mongo/options" 21 | "go.mongodb.org/mongo-driver/mongo/readpref" 22 | "google.golang.org/grpc" 23 | "google.golang.org/grpc/reflection" 24 | ) 25 | 26 | var ( 27 | server *gin.Engine 28 | ctx context.Context 29 | mongoclient *mongo.Client 30 | redisclient *redis.Client 31 | 32 | userService services.UserService 33 | UserController controllers.UserController 34 | UserRouteController routes.UserRouteController 35 | 36 | authCollection *mongo.Collection 37 | authService services.AuthService 38 | AuthController controllers.AuthController 39 | AuthRouteController routes.AuthRouteController 40 | 41 | // 👇 Create the Post Variables 42 | postService services.PostService 43 | PostController controllers.PostController 44 | postCollection *mongo.Collection 45 | PostRouteController routes.PostRouteController 46 | ) 47 | 48 | func init() { 49 | config, err := config.LoadConfig(".") 50 | if err != nil { 51 | log.Fatal("Could not load environment variables", err) 52 | } 53 | 54 | ctx = context.TODO() 55 | 56 | // Connect to MongoDB 57 | mongoconn := options.Client().ApplyURI(config.DBUri) 58 | mongoclient, err := mongo.Connect(ctx, mongoconn) 59 | 60 | if err != nil { 61 | panic(err) 62 | } 63 | 64 | if err := mongoclient.Ping(ctx, readpref.Primary()); err != nil { 65 | panic(err) 66 | } 67 | 68 | fmt.Println("MongoDB successfully connected...") 69 | 70 | // Connect to Redis 71 | redisclient = redis.NewClient(&redis.Options{ 72 | Addr: config.RedisUri, 73 | }) 74 | 75 | if _, err := redisclient.Ping(ctx).Result(); err != nil { 76 | panic(err) 77 | } 78 | 79 | err = redisclient.Set(ctx, "test", "Welcome to Golang with Redis and MongoDB", 0).Err() 80 | if err != nil { 81 | panic(err) 82 | } 83 | 84 | fmt.Println("Redis client connected successfully...") 85 | 86 | // Collections 87 | authCollection = mongoclient.Database("golang_mongodb").Collection("users") 88 | userService = services.NewUserServiceImpl(authCollection, ctx) 89 | authService = services.NewAuthService(authCollection, ctx) 90 | AuthController = controllers.NewAuthController(authService, userService, ctx, authCollection) 91 | AuthRouteController = routes.NewAuthRouteController(AuthController) 92 | 93 | UserController = controllers.NewUserController(userService) 94 | UserRouteController = routes.NewRouteUserController(UserController) 95 | 96 | // 👇 Instantiate the Constructors 97 | postCollection = mongoclient.Database("golang_mongodb").Collection("posts") 98 | postService = services.NewPostService(postCollection, ctx) 99 | PostController = controllers.NewPostController(postService) 100 | PostRouteController = routes.NewPostControllerRoute(PostController) 101 | 102 | server = gin.Default() 103 | } 104 | 105 | func main() { 106 | config, err := config.LoadConfig(".") 107 | 108 | if err != nil { 109 | log.Fatal("Could not load config", err) 110 | } 111 | 112 | defer mongoclient.Disconnect(ctx) 113 | 114 | // startGinServer(config) 115 | startGrpcServer(config) 116 | } 117 | 118 | func startGrpcServer(config config.Config) { 119 | authServer, err := gapi.NewGrpcAuthServer(config, authService, userService, authCollection) 120 | if err != nil { 121 | log.Fatal("cannot create grpc authServer: ", err) 122 | } 123 | 124 | userServer, err := gapi.NewGrpcUserServer(config, userService, authCollection) 125 | if err != nil { 126 | log.Fatal("cannot create grpc userServer: ", err) 127 | } 128 | 129 | postServer, err := gapi.NewGrpcPostServer(postCollection, postService) 130 | if err != nil { 131 | log.Fatal("cannot create grpc postServer: ", err) 132 | } 133 | 134 | grpcServer := grpc.NewServer() 135 | 136 | pb.RegisterAuthServiceServer(grpcServer, authServer) 137 | pb.RegisterUserServiceServer(grpcServer, userServer) 138 | // 👇 Register the Post gRPC service 139 | pb.RegisterPostServiceServer(grpcServer, postServer) 140 | reflection.Register(grpcServer) 141 | 142 | listener, err := net.Listen("tcp", config.GrpcServerAddress) 143 | if err != nil { 144 | log.Fatal("cannot create grpc server: ", err) 145 | } 146 | 147 | log.Printf("start gRPC server on %s", listener.Addr().String()) 148 | err = grpcServer.Serve(listener) 149 | if err != nil { 150 | log.Fatal("cannot create grpc server: ", err) 151 | } 152 | } 153 | 154 | func startGinServer(config config.Config) { 155 | value, err := redisclient.Get(ctx, "test").Result() 156 | 157 | if err == redis.Nil { 158 | fmt.Println("key: test does not exist") 159 | } else if err != nil { 160 | panic(err) 161 | } 162 | 163 | corsConfig := cors.DefaultConfig() 164 | corsConfig.AllowOrigins = []string{config.Origin} 165 | corsConfig.AllowCredentials = true 166 | 167 | server.Use(cors.New(corsConfig)) 168 | 169 | router := server.Group("/api") 170 | router.GET("/healthchecker", func(ctx *gin.Context) { 171 | ctx.JSON(http.StatusOK, gin.H{"status": "success", "message": value}) 172 | }) 173 | 174 | AuthRouteController.AuthRoute(router, userService) 175 | UserRouteController.UserRoute(router, userService) 176 | // 👇 Post Route 177 | PostRouteController.PostRoute(router) 178 | log.Fatal(server.Run(":" + config.Port)) 179 | } 180 | -------------------------------------------------------------------------------- /pb/rpc_create_post.pb.go: -------------------------------------------------------------------------------- 1 | // Code generated by protoc-gen-go. DO NOT EDIT. 2 | // versions: 3 | // protoc-gen-go v1.28.0 4 | // protoc v3.20.1 5 | // source: rpc_create_post.proto 6 | 7 | package pb 8 | 9 | import ( 10 | protoreflect "google.golang.org/protobuf/reflect/protoreflect" 11 | protoimpl "google.golang.org/protobuf/runtime/protoimpl" 12 | reflect "reflect" 13 | sync "sync" 14 | ) 15 | 16 | const ( 17 | // Verify that this generated code is sufficiently up-to-date. 18 | _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) 19 | // Verify that runtime/protoimpl is sufficiently up-to-date. 20 | _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) 21 | ) 22 | 23 | type CreatePostRequest struct { 24 | state protoimpl.MessageState 25 | sizeCache protoimpl.SizeCache 26 | unknownFields protoimpl.UnknownFields 27 | 28 | Title string `protobuf:"bytes,1,opt,name=Title,proto3" json:"Title,omitempty"` 29 | Content string `protobuf:"bytes,2,opt,name=Content,proto3" json:"Content,omitempty"` 30 | Image string `protobuf:"bytes,3,opt,name=Image,proto3" json:"Image,omitempty"` 31 | User string `protobuf:"bytes,4,opt,name=User,proto3" json:"User,omitempty"` 32 | } 33 | 34 | func (x *CreatePostRequest) Reset() { 35 | *x = CreatePostRequest{} 36 | if protoimpl.UnsafeEnabled { 37 | mi := &file_rpc_create_post_proto_msgTypes[0] 38 | ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) 39 | ms.StoreMessageInfo(mi) 40 | } 41 | } 42 | 43 | func (x *CreatePostRequest) String() string { 44 | return protoimpl.X.MessageStringOf(x) 45 | } 46 | 47 | func (*CreatePostRequest) ProtoMessage() {} 48 | 49 | func (x *CreatePostRequest) ProtoReflect() protoreflect.Message { 50 | mi := &file_rpc_create_post_proto_msgTypes[0] 51 | if protoimpl.UnsafeEnabled && x != nil { 52 | ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) 53 | if ms.LoadMessageInfo() == nil { 54 | ms.StoreMessageInfo(mi) 55 | } 56 | return ms 57 | } 58 | return mi.MessageOf(x) 59 | } 60 | 61 | // Deprecated: Use CreatePostRequest.ProtoReflect.Descriptor instead. 62 | func (*CreatePostRequest) Descriptor() ([]byte, []int) { 63 | return file_rpc_create_post_proto_rawDescGZIP(), []int{0} 64 | } 65 | 66 | func (x *CreatePostRequest) GetTitle() string { 67 | if x != nil { 68 | return x.Title 69 | } 70 | return "" 71 | } 72 | 73 | func (x *CreatePostRequest) GetContent() string { 74 | if x != nil { 75 | return x.Content 76 | } 77 | return "" 78 | } 79 | 80 | func (x *CreatePostRequest) GetImage() string { 81 | if x != nil { 82 | return x.Image 83 | } 84 | return "" 85 | } 86 | 87 | func (x *CreatePostRequest) GetUser() string { 88 | if x != nil { 89 | return x.User 90 | } 91 | return "" 92 | } 93 | 94 | var File_rpc_create_post_proto protoreflect.FileDescriptor 95 | 96 | var file_rpc_create_post_proto_rawDesc = []byte{ 97 | 0x0a, 0x15, 0x72, 0x70, 0x63, 0x5f, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x5f, 0x70, 0x6f, 0x73, 98 | 0x74, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x02, 0x70, 0x62, 0x22, 0x6d, 0x0a, 0x11, 0x43, 99 | 0x72, 0x65, 0x61, 0x74, 0x65, 0x50, 0x6f, 0x73, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 100 | 0x12, 0x14, 0x0a, 0x05, 0x54, 0x69, 0x74, 0x6c, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 101 | 0x05, 0x54, 0x69, 0x74, 0x6c, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 102 | 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 103 | 0x12, 0x14, 0x0a, 0x05, 0x49, 0x6d, 0x61, 0x67, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 104 | 0x05, 0x49, 0x6d, 0x61, 0x67, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x55, 0x73, 0x65, 0x72, 0x18, 0x04, 105 | 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x55, 0x73, 0x65, 0x72, 0x42, 0x27, 0x5a, 0x25, 0x67, 0x69, 106 | 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x77, 0x70, 0x63, 0x6f, 0x64, 0x65, 0x76, 107 | 0x6f, 0x2f, 0x67, 0x6f, 0x6c, 0x61, 0x6e, 0x67, 0x2d, 0x6d, 0x6f, 0x6e, 0x67, 0x6f, 0x64, 0x62, 108 | 0x2f, 0x70, 0x62, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, 109 | } 110 | 111 | var ( 112 | file_rpc_create_post_proto_rawDescOnce sync.Once 113 | file_rpc_create_post_proto_rawDescData = file_rpc_create_post_proto_rawDesc 114 | ) 115 | 116 | func file_rpc_create_post_proto_rawDescGZIP() []byte { 117 | file_rpc_create_post_proto_rawDescOnce.Do(func() { 118 | file_rpc_create_post_proto_rawDescData = protoimpl.X.CompressGZIP(file_rpc_create_post_proto_rawDescData) 119 | }) 120 | return file_rpc_create_post_proto_rawDescData 121 | } 122 | 123 | var file_rpc_create_post_proto_msgTypes = make([]protoimpl.MessageInfo, 1) 124 | var file_rpc_create_post_proto_goTypes = []interface{}{ 125 | (*CreatePostRequest)(nil), // 0: pb.CreatePostRequest 126 | } 127 | var file_rpc_create_post_proto_depIdxs = []int32{ 128 | 0, // [0:0] is the sub-list for method output_type 129 | 0, // [0:0] is the sub-list for method input_type 130 | 0, // [0:0] is the sub-list for extension type_name 131 | 0, // [0:0] is the sub-list for extension extendee 132 | 0, // [0:0] is the sub-list for field type_name 133 | } 134 | 135 | func init() { file_rpc_create_post_proto_init() } 136 | func file_rpc_create_post_proto_init() { 137 | if File_rpc_create_post_proto != nil { 138 | return 139 | } 140 | if !protoimpl.UnsafeEnabled { 141 | file_rpc_create_post_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { 142 | switch v := v.(*CreatePostRequest); i { 143 | case 0: 144 | return &v.state 145 | case 1: 146 | return &v.sizeCache 147 | case 2: 148 | return &v.unknownFields 149 | default: 150 | return nil 151 | } 152 | } 153 | } 154 | type x struct{} 155 | out := protoimpl.TypeBuilder{ 156 | File: protoimpl.DescBuilder{ 157 | GoPackagePath: reflect.TypeOf(x{}).PkgPath(), 158 | RawDescriptor: file_rpc_create_post_proto_rawDesc, 159 | NumEnums: 0, 160 | NumMessages: 1, 161 | NumExtensions: 0, 162 | NumServices: 0, 163 | }, 164 | GoTypes: file_rpc_create_post_proto_goTypes, 165 | DependencyIndexes: file_rpc_create_post_proto_depIdxs, 166 | MessageInfos: file_rpc_create_post_proto_msgTypes, 167 | }.Build() 168 | File_rpc_create_post_proto = out.File 169 | file_rpc_create_post_proto_rawDesc = nil 170 | file_rpc_create_post_proto_goTypes = nil 171 | file_rpc_create_post_proto_depIdxs = nil 172 | } 173 | -------------------------------------------------------------------------------- /pb/rpc_update_post.pb.go: -------------------------------------------------------------------------------- 1 | // Code generated by protoc-gen-go. DO NOT EDIT. 2 | // versions: 3 | // protoc-gen-go v1.28.0 4 | // protoc v3.20.1 5 | // source: rpc_update_post.proto 6 | 7 | package pb 8 | 9 | import ( 10 | protoreflect "google.golang.org/protobuf/reflect/protoreflect" 11 | protoimpl "google.golang.org/protobuf/runtime/protoimpl" 12 | reflect "reflect" 13 | sync "sync" 14 | ) 15 | 16 | const ( 17 | // Verify that this generated code is sufficiently up-to-date. 18 | _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) 19 | // Verify that runtime/protoimpl is sufficiently up-to-date. 20 | _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) 21 | ) 22 | 23 | type UpdatePostRequest struct { 24 | state protoimpl.MessageState 25 | sizeCache protoimpl.SizeCache 26 | unknownFields protoimpl.UnknownFields 27 | 28 | Id string `protobuf:"bytes,1,opt,name=Id,proto3" json:"Id,omitempty"` 29 | Title *string `protobuf:"bytes,2,opt,name=Title,proto3,oneof" json:"Title,omitempty"` 30 | Content *string `protobuf:"bytes,3,opt,name=Content,proto3,oneof" json:"Content,omitempty"` 31 | Image *string `protobuf:"bytes,4,opt,name=Image,proto3,oneof" json:"Image,omitempty"` 32 | User *string `protobuf:"bytes,5,opt,name=User,proto3,oneof" json:"User,omitempty"` 33 | } 34 | 35 | func (x *UpdatePostRequest) Reset() { 36 | *x = UpdatePostRequest{} 37 | if protoimpl.UnsafeEnabled { 38 | mi := &file_rpc_update_post_proto_msgTypes[0] 39 | ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) 40 | ms.StoreMessageInfo(mi) 41 | } 42 | } 43 | 44 | func (x *UpdatePostRequest) String() string { 45 | return protoimpl.X.MessageStringOf(x) 46 | } 47 | 48 | func (*UpdatePostRequest) ProtoMessage() {} 49 | 50 | func (x *UpdatePostRequest) ProtoReflect() protoreflect.Message { 51 | mi := &file_rpc_update_post_proto_msgTypes[0] 52 | if protoimpl.UnsafeEnabled && x != nil { 53 | ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) 54 | if ms.LoadMessageInfo() == nil { 55 | ms.StoreMessageInfo(mi) 56 | } 57 | return ms 58 | } 59 | return mi.MessageOf(x) 60 | } 61 | 62 | // Deprecated: Use UpdatePostRequest.ProtoReflect.Descriptor instead. 63 | func (*UpdatePostRequest) Descriptor() ([]byte, []int) { 64 | return file_rpc_update_post_proto_rawDescGZIP(), []int{0} 65 | } 66 | 67 | func (x *UpdatePostRequest) GetId() string { 68 | if x != nil { 69 | return x.Id 70 | } 71 | return "" 72 | } 73 | 74 | func (x *UpdatePostRequest) GetTitle() string { 75 | if x != nil && x.Title != nil { 76 | return *x.Title 77 | } 78 | return "" 79 | } 80 | 81 | func (x *UpdatePostRequest) GetContent() string { 82 | if x != nil && x.Content != nil { 83 | return *x.Content 84 | } 85 | return "" 86 | } 87 | 88 | func (x *UpdatePostRequest) GetImage() string { 89 | if x != nil && x.Image != nil { 90 | return *x.Image 91 | } 92 | return "" 93 | } 94 | 95 | func (x *UpdatePostRequest) GetUser() string { 96 | if x != nil && x.User != nil { 97 | return *x.User 98 | } 99 | return "" 100 | } 101 | 102 | var File_rpc_update_post_proto protoreflect.FileDescriptor 103 | 104 | var file_rpc_update_post_proto_rawDesc = []byte{ 105 | 0x0a, 0x15, 0x72, 0x70, 0x63, 0x5f, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x5f, 0x70, 0x6f, 0x73, 106 | 0x74, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x02, 0x70, 0x62, 0x22, 0xba, 0x01, 0x0a, 0x11, 107 | 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x50, 0x6f, 0x73, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 108 | 0x74, 0x12, 0x0e, 0x0a, 0x02, 0x49, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x49, 109 | 0x64, 0x12, 0x19, 0x0a, 0x05, 0x54, 0x69, 0x74, 0x6c, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 110 | 0x48, 0x00, 0x52, 0x05, 0x54, 0x69, 0x74, 0x6c, 0x65, 0x88, 0x01, 0x01, 0x12, 0x1d, 0x0a, 0x07, 111 | 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x48, 0x01, 0x52, 112 | 0x07, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x88, 0x01, 0x01, 0x12, 0x19, 0x0a, 0x05, 0x49, 113 | 0x6d, 0x61, 0x67, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x48, 0x02, 0x52, 0x05, 0x49, 0x6d, 114 | 0x61, 0x67, 0x65, 0x88, 0x01, 0x01, 0x12, 0x17, 0x0a, 0x04, 0x55, 0x73, 0x65, 0x72, 0x18, 0x05, 115 | 0x20, 0x01, 0x28, 0x09, 0x48, 0x03, 0x52, 0x04, 0x55, 0x73, 0x65, 0x72, 0x88, 0x01, 0x01, 0x42, 116 | 0x08, 0x0a, 0x06, 0x5f, 0x54, 0x69, 0x74, 0x6c, 0x65, 0x42, 0x0a, 0x0a, 0x08, 0x5f, 0x43, 0x6f, 117 | 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x42, 0x08, 0x0a, 0x06, 0x5f, 0x49, 0x6d, 0x61, 0x67, 0x65, 0x42, 118 | 0x07, 0x0a, 0x05, 0x5f, 0x55, 0x73, 0x65, 0x72, 0x42, 0x27, 0x5a, 0x25, 0x67, 0x69, 0x74, 0x68, 119 | 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x77, 0x70, 0x63, 0x6f, 0x64, 0x65, 0x76, 0x6f, 0x2f, 120 | 0x67, 0x6f, 0x6c, 0x61, 0x6e, 0x67, 0x2d, 0x6d, 0x6f, 0x6e, 0x67, 0x6f, 0x64, 0x62, 0x2f, 0x70, 121 | 0x62, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, 122 | } 123 | 124 | var ( 125 | file_rpc_update_post_proto_rawDescOnce sync.Once 126 | file_rpc_update_post_proto_rawDescData = file_rpc_update_post_proto_rawDesc 127 | ) 128 | 129 | func file_rpc_update_post_proto_rawDescGZIP() []byte { 130 | file_rpc_update_post_proto_rawDescOnce.Do(func() { 131 | file_rpc_update_post_proto_rawDescData = protoimpl.X.CompressGZIP(file_rpc_update_post_proto_rawDescData) 132 | }) 133 | return file_rpc_update_post_proto_rawDescData 134 | } 135 | 136 | var file_rpc_update_post_proto_msgTypes = make([]protoimpl.MessageInfo, 1) 137 | var file_rpc_update_post_proto_goTypes = []interface{}{ 138 | (*UpdatePostRequest)(nil), // 0: pb.UpdatePostRequest 139 | } 140 | var file_rpc_update_post_proto_depIdxs = []int32{ 141 | 0, // [0:0] is the sub-list for method output_type 142 | 0, // [0:0] is the sub-list for method input_type 143 | 0, // [0:0] is the sub-list for extension type_name 144 | 0, // [0:0] is the sub-list for extension extendee 145 | 0, // [0:0] is the sub-list for field type_name 146 | } 147 | 148 | func init() { file_rpc_update_post_proto_init() } 149 | func file_rpc_update_post_proto_init() { 150 | if File_rpc_update_post_proto != nil { 151 | return 152 | } 153 | if !protoimpl.UnsafeEnabled { 154 | file_rpc_update_post_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { 155 | switch v := v.(*UpdatePostRequest); i { 156 | case 0: 157 | return &v.state 158 | case 1: 159 | return &v.sizeCache 160 | case 2: 161 | return &v.unknownFields 162 | default: 163 | return nil 164 | } 165 | } 166 | } 167 | file_rpc_update_post_proto_msgTypes[0].OneofWrappers = []interface{}{} 168 | type x struct{} 169 | out := protoimpl.TypeBuilder{ 170 | File: protoimpl.DescBuilder{ 171 | GoPackagePath: reflect.TypeOf(x{}).PkgPath(), 172 | RawDescriptor: file_rpc_update_post_proto_rawDesc, 173 | NumEnums: 0, 174 | NumMessages: 1, 175 | NumExtensions: 0, 176 | NumServices: 0, 177 | }, 178 | GoTypes: file_rpc_update_post_proto_goTypes, 179 | DependencyIndexes: file_rpc_update_post_proto_depIdxs, 180 | MessageInfos: file_rpc_update_post_proto_msgTypes, 181 | }.Build() 182 | File_rpc_update_post_proto = out.File 183 | file_rpc_update_post_proto_rawDesc = nil 184 | file_rpc_update_post_proto_goTypes = nil 185 | file_rpc_update_post_proto_depIdxs = nil 186 | } 187 | -------------------------------------------------------------------------------- /pb/auth_service_grpc.pb.go: -------------------------------------------------------------------------------- 1 | // Code generated by protoc-gen-go-grpc. DO NOT EDIT. 2 | // versions: 3 | // - protoc-gen-go-grpc v1.2.0 4 | // - protoc v3.20.1 5 | // source: auth_service.proto 6 | 7 | package pb 8 | 9 | import ( 10 | context "context" 11 | grpc "google.golang.org/grpc" 12 | codes "google.golang.org/grpc/codes" 13 | status "google.golang.org/grpc/status" 14 | ) 15 | 16 | // This is a compile-time assertion to ensure that this generated file 17 | // is compatible with the grpc package it is being compiled against. 18 | // Requires gRPC-Go v1.32.0 or later. 19 | const _ = grpc.SupportPackageIsVersion7 20 | 21 | // AuthServiceClient is the client API for AuthService service. 22 | // 23 | // 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. 24 | type AuthServiceClient interface { 25 | SignUpUser(ctx context.Context, in *SignUpUserInput, opts ...grpc.CallOption) (*GenericResponse, error) 26 | SignInUser(ctx context.Context, in *SignInUserInput, opts ...grpc.CallOption) (*SignInUserResponse, error) 27 | VerifyEmail(ctx context.Context, in *VerifyEmailRequest, opts ...grpc.CallOption) (*GenericResponse, error) 28 | } 29 | 30 | type authServiceClient struct { 31 | cc grpc.ClientConnInterface 32 | } 33 | 34 | func NewAuthServiceClient(cc grpc.ClientConnInterface) AuthServiceClient { 35 | return &authServiceClient{cc} 36 | } 37 | 38 | func (c *authServiceClient) SignUpUser(ctx context.Context, in *SignUpUserInput, opts ...grpc.CallOption) (*GenericResponse, error) { 39 | out := new(GenericResponse) 40 | err := c.cc.Invoke(ctx, "/pb.AuthService/SignUpUser", in, out, opts...) 41 | if err != nil { 42 | return nil, err 43 | } 44 | return out, nil 45 | } 46 | 47 | func (c *authServiceClient) SignInUser(ctx context.Context, in *SignInUserInput, opts ...grpc.CallOption) (*SignInUserResponse, error) { 48 | out := new(SignInUserResponse) 49 | err := c.cc.Invoke(ctx, "/pb.AuthService/SignInUser", in, out, opts...) 50 | if err != nil { 51 | return nil, err 52 | } 53 | return out, nil 54 | } 55 | 56 | func (c *authServiceClient) VerifyEmail(ctx context.Context, in *VerifyEmailRequest, opts ...grpc.CallOption) (*GenericResponse, error) { 57 | out := new(GenericResponse) 58 | err := c.cc.Invoke(ctx, "/pb.AuthService/VerifyEmail", in, out, opts...) 59 | if err != nil { 60 | return nil, err 61 | } 62 | return out, nil 63 | } 64 | 65 | // AuthServiceServer is the server API for AuthService service. 66 | // All implementations must embed UnimplementedAuthServiceServer 67 | // for forward compatibility 68 | type AuthServiceServer interface { 69 | SignUpUser(context.Context, *SignUpUserInput) (*GenericResponse, error) 70 | SignInUser(context.Context, *SignInUserInput) (*SignInUserResponse, error) 71 | VerifyEmail(context.Context, *VerifyEmailRequest) (*GenericResponse, error) 72 | mustEmbedUnimplementedAuthServiceServer() 73 | } 74 | 75 | // UnimplementedAuthServiceServer must be embedded to have forward compatible implementations. 76 | type UnimplementedAuthServiceServer struct { 77 | } 78 | 79 | func (UnimplementedAuthServiceServer) SignUpUser(context.Context, *SignUpUserInput) (*GenericResponse, error) { 80 | return nil, status.Errorf(codes.Unimplemented, "method SignUpUser not implemented") 81 | } 82 | func (UnimplementedAuthServiceServer) SignInUser(context.Context, *SignInUserInput) (*SignInUserResponse, error) { 83 | return nil, status.Errorf(codes.Unimplemented, "method SignInUser not implemented") 84 | } 85 | func (UnimplementedAuthServiceServer) VerifyEmail(context.Context, *VerifyEmailRequest) (*GenericResponse, error) { 86 | return nil, status.Errorf(codes.Unimplemented, "method VerifyEmail not implemented") 87 | } 88 | func (UnimplementedAuthServiceServer) mustEmbedUnimplementedAuthServiceServer() {} 89 | 90 | // UnsafeAuthServiceServer may be embedded to opt out of forward compatibility for this service. 91 | // Use of this interface is not recommended, as added methods to AuthServiceServer will 92 | // result in compilation errors. 93 | type UnsafeAuthServiceServer interface { 94 | mustEmbedUnimplementedAuthServiceServer() 95 | } 96 | 97 | func RegisterAuthServiceServer(s grpc.ServiceRegistrar, srv AuthServiceServer) { 98 | s.RegisterService(&AuthService_ServiceDesc, srv) 99 | } 100 | 101 | func _AuthService_SignUpUser_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { 102 | in := new(SignUpUserInput) 103 | if err := dec(in); err != nil { 104 | return nil, err 105 | } 106 | if interceptor == nil { 107 | return srv.(AuthServiceServer).SignUpUser(ctx, in) 108 | } 109 | info := &grpc.UnaryServerInfo{ 110 | Server: srv, 111 | FullMethod: "/pb.AuthService/SignUpUser", 112 | } 113 | handler := func(ctx context.Context, req interface{}) (interface{}, error) { 114 | return srv.(AuthServiceServer).SignUpUser(ctx, req.(*SignUpUserInput)) 115 | } 116 | return interceptor(ctx, in, info, handler) 117 | } 118 | 119 | func _AuthService_SignInUser_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { 120 | in := new(SignInUserInput) 121 | if err := dec(in); err != nil { 122 | return nil, err 123 | } 124 | if interceptor == nil { 125 | return srv.(AuthServiceServer).SignInUser(ctx, in) 126 | } 127 | info := &grpc.UnaryServerInfo{ 128 | Server: srv, 129 | FullMethod: "/pb.AuthService/SignInUser", 130 | } 131 | handler := func(ctx context.Context, req interface{}) (interface{}, error) { 132 | return srv.(AuthServiceServer).SignInUser(ctx, req.(*SignInUserInput)) 133 | } 134 | return interceptor(ctx, in, info, handler) 135 | } 136 | 137 | func _AuthService_VerifyEmail_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { 138 | in := new(VerifyEmailRequest) 139 | if err := dec(in); err != nil { 140 | return nil, err 141 | } 142 | if interceptor == nil { 143 | return srv.(AuthServiceServer).VerifyEmail(ctx, in) 144 | } 145 | info := &grpc.UnaryServerInfo{ 146 | Server: srv, 147 | FullMethod: "/pb.AuthService/VerifyEmail", 148 | } 149 | handler := func(ctx context.Context, req interface{}) (interface{}, error) { 150 | return srv.(AuthServiceServer).VerifyEmail(ctx, req.(*VerifyEmailRequest)) 151 | } 152 | return interceptor(ctx, in, info, handler) 153 | } 154 | 155 | // AuthService_ServiceDesc is the grpc.ServiceDesc for AuthService service. 156 | // It's only intended for direct use with grpc.RegisterService, 157 | // and not to be introspected or modified (even as a copy) 158 | var AuthService_ServiceDesc = grpc.ServiceDesc{ 159 | ServiceName: "pb.AuthService", 160 | HandlerType: (*AuthServiceServer)(nil), 161 | Methods: []grpc.MethodDesc{ 162 | { 163 | MethodName: "SignUpUser", 164 | Handler: _AuthService_SignUpUser_Handler, 165 | }, 166 | { 167 | MethodName: "SignInUser", 168 | Handler: _AuthService_SignInUser_Handler, 169 | }, 170 | { 171 | MethodName: "VerifyEmail", 172 | Handler: _AuthService_VerifyEmail_Handler, 173 | }, 174 | }, 175 | Streams: []grpc.StreamDesc{}, 176 | Metadata: "auth_service.proto", 177 | } 178 | -------------------------------------------------------------------------------- /pb/auth_service.pb.go: -------------------------------------------------------------------------------- 1 | // Code generated by protoc-gen-go. DO NOT EDIT. 2 | // versions: 3 | // protoc-gen-go v1.28.0 4 | // protoc v3.20.1 5 | // source: auth_service.proto 6 | 7 | package pb 8 | 9 | import ( 10 | protoreflect "google.golang.org/protobuf/reflect/protoreflect" 11 | protoimpl "google.golang.org/protobuf/runtime/protoimpl" 12 | reflect "reflect" 13 | sync "sync" 14 | ) 15 | 16 | const ( 17 | // Verify that this generated code is sufficiently up-to-date. 18 | _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) 19 | // Verify that runtime/protoimpl is sufficiently up-to-date. 20 | _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) 21 | ) 22 | 23 | type VerifyEmailRequest struct { 24 | state protoimpl.MessageState 25 | sizeCache protoimpl.SizeCache 26 | unknownFields protoimpl.UnknownFields 27 | 28 | VerificationCode string `protobuf:"bytes,1,opt,name=verificationCode,proto3" json:"verificationCode,omitempty"` 29 | } 30 | 31 | func (x *VerifyEmailRequest) Reset() { 32 | *x = VerifyEmailRequest{} 33 | if protoimpl.UnsafeEnabled { 34 | mi := &file_auth_service_proto_msgTypes[0] 35 | ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) 36 | ms.StoreMessageInfo(mi) 37 | } 38 | } 39 | 40 | func (x *VerifyEmailRequest) String() string { 41 | return protoimpl.X.MessageStringOf(x) 42 | } 43 | 44 | func (*VerifyEmailRequest) ProtoMessage() {} 45 | 46 | func (x *VerifyEmailRequest) ProtoReflect() protoreflect.Message { 47 | mi := &file_auth_service_proto_msgTypes[0] 48 | if protoimpl.UnsafeEnabled && x != nil { 49 | ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) 50 | if ms.LoadMessageInfo() == nil { 51 | ms.StoreMessageInfo(mi) 52 | } 53 | return ms 54 | } 55 | return mi.MessageOf(x) 56 | } 57 | 58 | // Deprecated: Use VerifyEmailRequest.ProtoReflect.Descriptor instead. 59 | func (*VerifyEmailRequest) Descriptor() ([]byte, []int) { 60 | return file_auth_service_proto_rawDescGZIP(), []int{0} 61 | } 62 | 63 | func (x *VerifyEmailRequest) GetVerificationCode() string { 64 | if x != nil { 65 | return x.VerificationCode 66 | } 67 | return "" 68 | } 69 | 70 | var File_auth_service_proto protoreflect.FileDescriptor 71 | 72 | var file_auth_service_proto_rawDesc = []byte{ 73 | 0x0a, 0x12, 0x61, 0x75, 0x74, 0x68, 0x5f, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x70, 74 | 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x02, 0x70, 0x62, 0x1a, 0x15, 0x72, 0x70, 0x63, 0x5f, 0x73, 0x69, 75 | 0x67, 0x6e, 0x69, 0x6e, 0x5f, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 76 | 0x15, 0x72, 0x70, 0x63, 0x5f, 0x73, 0x69, 0x67, 0x6e, 0x75, 0x70, 0x5f, 0x75, 0x73, 0x65, 0x72, 77 | 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x0a, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x70, 0x72, 0x6f, 78 | 0x74, 0x6f, 0x22, 0x40, 0x0a, 0x12, 0x56, 0x65, 0x72, 0x69, 0x66, 0x79, 0x45, 0x6d, 0x61, 0x69, 79 | 0x6c, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x2a, 0x0a, 0x10, 0x76, 0x65, 0x72, 0x69, 80 | 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x43, 0x6f, 0x64, 0x65, 0x18, 0x01, 0x20, 0x01, 81 | 0x28, 0x09, 0x52, 0x10, 0x76, 0x65, 0x72, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 82 | 0x43, 0x6f, 0x64, 0x65, 0x32, 0xc2, 0x01, 0x0a, 0x0b, 0x41, 0x75, 0x74, 0x68, 0x53, 0x65, 0x72, 83 | 0x76, 0x69, 0x63, 0x65, 0x12, 0x38, 0x0a, 0x0a, 0x53, 0x69, 0x67, 0x6e, 0x55, 0x70, 0x55, 0x73, 84 | 0x65, 0x72, 0x12, 0x13, 0x2e, 0x70, 0x62, 0x2e, 0x53, 0x69, 0x67, 0x6e, 0x55, 0x70, 0x55, 0x73, 85 | 0x65, 0x72, 0x49, 0x6e, 0x70, 0x75, 0x74, 0x1a, 0x13, 0x2e, 0x70, 0x62, 0x2e, 0x47, 0x65, 0x6e, 86 | 0x65, 0x72, 0x69, 0x63, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x3b, 87 | 0x0a, 0x0a, 0x53, 0x69, 0x67, 0x6e, 0x49, 0x6e, 0x55, 0x73, 0x65, 0x72, 0x12, 0x13, 0x2e, 0x70, 88 | 0x62, 0x2e, 0x53, 0x69, 0x67, 0x6e, 0x49, 0x6e, 0x55, 0x73, 0x65, 0x72, 0x49, 0x6e, 0x70, 0x75, 89 | 0x74, 0x1a, 0x16, 0x2e, 0x70, 0x62, 0x2e, 0x53, 0x69, 0x67, 0x6e, 0x49, 0x6e, 0x55, 0x73, 0x65, 90 | 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x3c, 0x0a, 0x0b, 0x56, 91 | 0x65, 0x72, 0x69, 0x66, 0x79, 0x45, 0x6d, 0x61, 0x69, 0x6c, 0x12, 0x16, 0x2e, 0x70, 0x62, 0x2e, 92 | 0x56, 0x65, 0x72, 0x69, 0x66, 0x79, 0x45, 0x6d, 0x61, 0x69, 0x6c, 0x52, 0x65, 0x71, 0x75, 0x65, 93 | 0x73, 0x74, 0x1a, 0x13, 0x2e, 0x70, 0x62, 0x2e, 0x47, 0x65, 0x6e, 0x65, 0x72, 0x69, 0x63, 0x52, 94 | 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x42, 0x27, 0x5a, 0x25, 0x67, 0x69, 0x74, 95 | 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x77, 0x70, 0x63, 0x6f, 0x64, 0x65, 0x76, 0x6f, 96 | 0x2f, 0x67, 0x6f, 0x6c, 0x61, 0x6e, 0x67, 0x2d, 0x6d, 0x6f, 0x6e, 0x67, 0x6f, 0x64, 0x62, 0x2f, 97 | 0x70, 0x62, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, 98 | } 99 | 100 | var ( 101 | file_auth_service_proto_rawDescOnce sync.Once 102 | file_auth_service_proto_rawDescData = file_auth_service_proto_rawDesc 103 | ) 104 | 105 | func file_auth_service_proto_rawDescGZIP() []byte { 106 | file_auth_service_proto_rawDescOnce.Do(func() { 107 | file_auth_service_proto_rawDescData = protoimpl.X.CompressGZIP(file_auth_service_proto_rawDescData) 108 | }) 109 | return file_auth_service_proto_rawDescData 110 | } 111 | 112 | var file_auth_service_proto_msgTypes = make([]protoimpl.MessageInfo, 1) 113 | var file_auth_service_proto_goTypes = []interface{}{ 114 | (*VerifyEmailRequest)(nil), // 0: pb.VerifyEmailRequest 115 | (*SignUpUserInput)(nil), // 1: pb.SignUpUserInput 116 | (*SignInUserInput)(nil), // 2: pb.SignInUserInput 117 | (*GenericResponse)(nil), // 3: pb.GenericResponse 118 | (*SignInUserResponse)(nil), // 4: pb.SignInUserResponse 119 | } 120 | var file_auth_service_proto_depIdxs = []int32{ 121 | 1, // 0: pb.AuthService.SignUpUser:input_type -> pb.SignUpUserInput 122 | 2, // 1: pb.AuthService.SignInUser:input_type -> pb.SignInUserInput 123 | 0, // 2: pb.AuthService.VerifyEmail:input_type -> pb.VerifyEmailRequest 124 | 3, // 3: pb.AuthService.SignUpUser:output_type -> pb.GenericResponse 125 | 4, // 4: pb.AuthService.SignInUser:output_type -> pb.SignInUserResponse 126 | 3, // 5: pb.AuthService.VerifyEmail:output_type -> pb.GenericResponse 127 | 3, // [3:6] is the sub-list for method output_type 128 | 0, // [0:3] is the sub-list for method input_type 129 | 0, // [0:0] is the sub-list for extension type_name 130 | 0, // [0:0] is the sub-list for extension extendee 131 | 0, // [0:0] is the sub-list for field type_name 132 | } 133 | 134 | func init() { file_auth_service_proto_init() } 135 | func file_auth_service_proto_init() { 136 | if File_auth_service_proto != nil { 137 | return 138 | } 139 | file_rpc_signin_user_proto_init() 140 | file_rpc_signup_user_proto_init() 141 | file_user_proto_init() 142 | if !protoimpl.UnsafeEnabled { 143 | file_auth_service_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { 144 | switch v := v.(*VerifyEmailRequest); i { 145 | case 0: 146 | return &v.state 147 | case 1: 148 | return &v.sizeCache 149 | case 2: 150 | return &v.unknownFields 151 | default: 152 | return nil 153 | } 154 | } 155 | } 156 | type x struct{} 157 | out := protoimpl.TypeBuilder{ 158 | File: protoimpl.DescBuilder{ 159 | GoPackagePath: reflect.TypeOf(x{}).PkgPath(), 160 | RawDescriptor: file_auth_service_proto_rawDesc, 161 | NumEnums: 0, 162 | NumMessages: 1, 163 | NumExtensions: 0, 164 | NumServices: 1, 165 | }, 166 | GoTypes: file_auth_service_proto_goTypes, 167 | DependencyIndexes: file_auth_service_proto_depIdxs, 168 | MessageInfos: file_auth_service_proto_msgTypes, 169 | }.Build() 170 | File_auth_service_proto = out.File 171 | file_auth_service_proto_rawDesc = nil 172 | file_auth_service_proto_goTypes = nil 173 | file_auth_service_proto_depIdxs = nil 174 | } 175 | -------------------------------------------------------------------------------- /templates/styles.html: -------------------------------------------------------------------------------- 1 | {{define "styles"}} 2 | 331 | {{end}} 332 | -------------------------------------------------------------------------------- /pb/rpc_signin_user.pb.go: -------------------------------------------------------------------------------- 1 | // Code generated by protoc-gen-go. DO NOT EDIT. 2 | // versions: 3 | // protoc-gen-go v1.28.0 4 | // protoc v3.20.1 5 | // source: rpc_signin_user.proto 6 | 7 | package pb 8 | 9 | import ( 10 | protoreflect "google.golang.org/protobuf/reflect/protoreflect" 11 | protoimpl "google.golang.org/protobuf/runtime/protoimpl" 12 | reflect "reflect" 13 | sync "sync" 14 | ) 15 | 16 | const ( 17 | // Verify that this generated code is sufficiently up-to-date. 18 | _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) 19 | // Verify that runtime/protoimpl is sufficiently up-to-date. 20 | _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) 21 | ) 22 | 23 | type SignInUserInput struct { 24 | state protoimpl.MessageState 25 | sizeCache protoimpl.SizeCache 26 | unknownFields protoimpl.UnknownFields 27 | 28 | Email string `protobuf:"bytes,1,opt,name=email,proto3" json:"email,omitempty"` 29 | Password string `protobuf:"bytes,2,opt,name=password,proto3" json:"password,omitempty"` 30 | } 31 | 32 | func (x *SignInUserInput) Reset() { 33 | *x = SignInUserInput{} 34 | if protoimpl.UnsafeEnabled { 35 | mi := &file_rpc_signin_user_proto_msgTypes[0] 36 | ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) 37 | ms.StoreMessageInfo(mi) 38 | } 39 | } 40 | 41 | func (x *SignInUserInput) String() string { 42 | return protoimpl.X.MessageStringOf(x) 43 | } 44 | 45 | func (*SignInUserInput) ProtoMessage() {} 46 | 47 | func (x *SignInUserInput) ProtoReflect() protoreflect.Message { 48 | mi := &file_rpc_signin_user_proto_msgTypes[0] 49 | if protoimpl.UnsafeEnabled && x != nil { 50 | ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) 51 | if ms.LoadMessageInfo() == nil { 52 | ms.StoreMessageInfo(mi) 53 | } 54 | return ms 55 | } 56 | return mi.MessageOf(x) 57 | } 58 | 59 | // Deprecated: Use SignInUserInput.ProtoReflect.Descriptor instead. 60 | func (*SignInUserInput) Descriptor() ([]byte, []int) { 61 | return file_rpc_signin_user_proto_rawDescGZIP(), []int{0} 62 | } 63 | 64 | func (x *SignInUserInput) GetEmail() string { 65 | if x != nil { 66 | return x.Email 67 | } 68 | return "" 69 | } 70 | 71 | func (x *SignInUserInput) GetPassword() string { 72 | if x != nil { 73 | return x.Password 74 | } 75 | return "" 76 | } 77 | 78 | type SignInUserResponse struct { 79 | state protoimpl.MessageState 80 | sizeCache protoimpl.SizeCache 81 | unknownFields protoimpl.UnknownFields 82 | 83 | Status string `protobuf:"bytes,1,opt,name=status,proto3" json:"status,omitempty"` 84 | AccessToken string `protobuf:"bytes,2,opt,name=access_token,json=accessToken,proto3" json:"access_token,omitempty"` 85 | RefreshToken string `protobuf:"bytes,3,opt,name=refresh_token,json=refreshToken,proto3" json:"refresh_token,omitempty"` 86 | } 87 | 88 | func (x *SignInUserResponse) Reset() { 89 | *x = SignInUserResponse{} 90 | if protoimpl.UnsafeEnabled { 91 | mi := &file_rpc_signin_user_proto_msgTypes[1] 92 | ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) 93 | ms.StoreMessageInfo(mi) 94 | } 95 | } 96 | 97 | func (x *SignInUserResponse) String() string { 98 | return protoimpl.X.MessageStringOf(x) 99 | } 100 | 101 | func (*SignInUserResponse) ProtoMessage() {} 102 | 103 | func (x *SignInUserResponse) ProtoReflect() protoreflect.Message { 104 | mi := &file_rpc_signin_user_proto_msgTypes[1] 105 | if protoimpl.UnsafeEnabled && x != nil { 106 | ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) 107 | if ms.LoadMessageInfo() == nil { 108 | ms.StoreMessageInfo(mi) 109 | } 110 | return ms 111 | } 112 | return mi.MessageOf(x) 113 | } 114 | 115 | // Deprecated: Use SignInUserResponse.ProtoReflect.Descriptor instead. 116 | func (*SignInUserResponse) Descriptor() ([]byte, []int) { 117 | return file_rpc_signin_user_proto_rawDescGZIP(), []int{1} 118 | } 119 | 120 | func (x *SignInUserResponse) GetStatus() string { 121 | if x != nil { 122 | return x.Status 123 | } 124 | return "" 125 | } 126 | 127 | func (x *SignInUserResponse) GetAccessToken() string { 128 | if x != nil { 129 | return x.AccessToken 130 | } 131 | return "" 132 | } 133 | 134 | func (x *SignInUserResponse) GetRefreshToken() string { 135 | if x != nil { 136 | return x.RefreshToken 137 | } 138 | return "" 139 | } 140 | 141 | var File_rpc_signin_user_proto protoreflect.FileDescriptor 142 | 143 | var file_rpc_signin_user_proto_rawDesc = []byte{ 144 | 0x0a, 0x15, 0x72, 0x70, 0x63, 0x5f, 0x73, 0x69, 0x67, 0x6e, 0x69, 0x6e, 0x5f, 0x75, 0x73, 0x65, 145 | 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x02, 0x70, 0x62, 0x22, 0x43, 0x0a, 0x0f, 0x53, 146 | 0x69, 0x67, 0x6e, 0x49, 0x6e, 0x55, 0x73, 0x65, 0x72, 0x49, 0x6e, 0x70, 0x75, 0x74, 0x12, 0x14, 147 | 0x0a, 0x05, 0x65, 0x6d, 0x61, 0x69, 0x6c, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x65, 148 | 0x6d, 0x61, 0x69, 0x6c, 0x12, 0x1a, 0x0a, 0x08, 0x70, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 149 | 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x70, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 150 | 0x22, 0x74, 0x0a, 0x12, 0x53, 0x69, 0x67, 0x6e, 0x49, 0x6e, 0x55, 0x73, 0x65, 0x72, 0x52, 0x65, 151 | 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 152 | 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x21, 153 | 0x0a, 0x0c, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x5f, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x18, 0x02, 154 | 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x54, 0x6f, 0x6b, 0x65, 155 | 0x6e, 0x12, 0x23, 0x0a, 0x0d, 0x72, 0x65, 0x66, 0x72, 0x65, 0x73, 0x68, 0x5f, 0x74, 0x6f, 0x6b, 156 | 0x65, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x72, 0x65, 0x66, 0x72, 0x65, 0x73, 157 | 0x68, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x42, 0x27, 0x5a, 0x25, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 158 | 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x77, 0x70, 0x63, 0x6f, 0x64, 0x65, 0x76, 0x6f, 0x2f, 0x67, 0x6f, 159 | 0x6c, 0x61, 0x6e, 0x67, 0x2d, 0x6d, 0x6f, 0x6e, 0x67, 0x6f, 0x64, 0x62, 0x2f, 0x70, 0x62, 0x62, 160 | 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, 161 | } 162 | 163 | var ( 164 | file_rpc_signin_user_proto_rawDescOnce sync.Once 165 | file_rpc_signin_user_proto_rawDescData = file_rpc_signin_user_proto_rawDesc 166 | ) 167 | 168 | func file_rpc_signin_user_proto_rawDescGZIP() []byte { 169 | file_rpc_signin_user_proto_rawDescOnce.Do(func() { 170 | file_rpc_signin_user_proto_rawDescData = protoimpl.X.CompressGZIP(file_rpc_signin_user_proto_rawDescData) 171 | }) 172 | return file_rpc_signin_user_proto_rawDescData 173 | } 174 | 175 | var file_rpc_signin_user_proto_msgTypes = make([]protoimpl.MessageInfo, 2) 176 | var file_rpc_signin_user_proto_goTypes = []interface{}{ 177 | (*SignInUserInput)(nil), // 0: pb.SignInUserInput 178 | (*SignInUserResponse)(nil), // 1: pb.SignInUserResponse 179 | } 180 | var file_rpc_signin_user_proto_depIdxs = []int32{ 181 | 0, // [0:0] is the sub-list for method output_type 182 | 0, // [0:0] is the sub-list for method input_type 183 | 0, // [0:0] is the sub-list for extension type_name 184 | 0, // [0:0] is the sub-list for extension extendee 185 | 0, // [0:0] is the sub-list for field type_name 186 | } 187 | 188 | func init() { file_rpc_signin_user_proto_init() } 189 | func file_rpc_signin_user_proto_init() { 190 | if File_rpc_signin_user_proto != nil { 191 | return 192 | } 193 | if !protoimpl.UnsafeEnabled { 194 | file_rpc_signin_user_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { 195 | switch v := v.(*SignInUserInput); i { 196 | case 0: 197 | return &v.state 198 | case 1: 199 | return &v.sizeCache 200 | case 2: 201 | return &v.unknownFields 202 | default: 203 | return nil 204 | } 205 | } 206 | file_rpc_signin_user_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { 207 | switch v := v.(*SignInUserResponse); i { 208 | case 0: 209 | return &v.state 210 | case 1: 211 | return &v.sizeCache 212 | case 2: 213 | return &v.unknownFields 214 | default: 215 | return nil 216 | } 217 | } 218 | } 219 | type x struct{} 220 | out := protoimpl.TypeBuilder{ 221 | File: protoimpl.DescBuilder{ 222 | GoPackagePath: reflect.TypeOf(x{}).PkgPath(), 223 | RawDescriptor: file_rpc_signin_user_proto_rawDesc, 224 | NumEnums: 0, 225 | NumMessages: 2, 226 | NumExtensions: 0, 227 | NumServices: 0, 228 | }, 229 | GoTypes: file_rpc_signin_user_proto_goTypes, 230 | DependencyIndexes: file_rpc_signin_user_proto_depIdxs, 231 | MessageInfos: file_rpc_signin_user_proto_msgTypes, 232 | }.Build() 233 | File_rpc_signin_user_proto = out.File 234 | file_rpc_signin_user_proto_rawDesc = nil 235 | file_rpc_signin_user_proto_goTypes = nil 236 | file_rpc_signin_user_proto_depIdxs = nil 237 | } 238 | -------------------------------------------------------------------------------- /pb/rpc_signup_user.pb.go: -------------------------------------------------------------------------------- 1 | // Code generated by protoc-gen-go. DO NOT EDIT. 2 | // versions: 3 | // protoc-gen-go v1.28.0 4 | // protoc v3.20.1 5 | // source: rpc_signup_user.proto 6 | 7 | package pb 8 | 9 | import ( 10 | protoreflect "google.golang.org/protobuf/reflect/protoreflect" 11 | protoimpl "google.golang.org/protobuf/runtime/protoimpl" 12 | reflect "reflect" 13 | sync "sync" 14 | ) 15 | 16 | const ( 17 | // Verify that this generated code is sufficiently up-to-date. 18 | _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) 19 | // Verify that runtime/protoimpl is sufficiently up-to-date. 20 | _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) 21 | ) 22 | 23 | type SignUpUserInput struct { 24 | state protoimpl.MessageState 25 | sizeCache protoimpl.SizeCache 26 | unknownFields protoimpl.UnknownFields 27 | 28 | Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"` 29 | Email string `protobuf:"bytes,2,opt,name=email,proto3" json:"email,omitempty"` 30 | Password string `protobuf:"bytes,3,opt,name=password,proto3" json:"password,omitempty"` 31 | PasswordConfirm string `protobuf:"bytes,4,opt,name=passwordConfirm,proto3" json:"passwordConfirm,omitempty"` 32 | } 33 | 34 | func (x *SignUpUserInput) Reset() { 35 | *x = SignUpUserInput{} 36 | if protoimpl.UnsafeEnabled { 37 | mi := &file_rpc_signup_user_proto_msgTypes[0] 38 | ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) 39 | ms.StoreMessageInfo(mi) 40 | } 41 | } 42 | 43 | func (x *SignUpUserInput) String() string { 44 | return protoimpl.X.MessageStringOf(x) 45 | } 46 | 47 | func (*SignUpUserInput) ProtoMessage() {} 48 | 49 | func (x *SignUpUserInput) ProtoReflect() protoreflect.Message { 50 | mi := &file_rpc_signup_user_proto_msgTypes[0] 51 | if protoimpl.UnsafeEnabled && x != nil { 52 | ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) 53 | if ms.LoadMessageInfo() == nil { 54 | ms.StoreMessageInfo(mi) 55 | } 56 | return ms 57 | } 58 | return mi.MessageOf(x) 59 | } 60 | 61 | // Deprecated: Use SignUpUserInput.ProtoReflect.Descriptor instead. 62 | func (*SignUpUserInput) Descriptor() ([]byte, []int) { 63 | return file_rpc_signup_user_proto_rawDescGZIP(), []int{0} 64 | } 65 | 66 | func (x *SignUpUserInput) GetName() string { 67 | if x != nil { 68 | return x.Name 69 | } 70 | return "" 71 | } 72 | 73 | func (x *SignUpUserInput) GetEmail() string { 74 | if x != nil { 75 | return x.Email 76 | } 77 | return "" 78 | } 79 | 80 | func (x *SignUpUserInput) GetPassword() string { 81 | if x != nil { 82 | return x.Password 83 | } 84 | return "" 85 | } 86 | 87 | func (x *SignUpUserInput) GetPasswordConfirm() string { 88 | if x != nil { 89 | return x.PasswordConfirm 90 | } 91 | return "" 92 | } 93 | 94 | type SignUpUserResponse struct { 95 | state protoimpl.MessageState 96 | sizeCache protoimpl.SizeCache 97 | unknownFields protoimpl.UnknownFields 98 | 99 | User *User `protobuf:"bytes,1,opt,name=user,proto3" json:"user,omitempty"` 100 | } 101 | 102 | func (x *SignUpUserResponse) Reset() { 103 | *x = SignUpUserResponse{} 104 | if protoimpl.UnsafeEnabled { 105 | mi := &file_rpc_signup_user_proto_msgTypes[1] 106 | ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) 107 | ms.StoreMessageInfo(mi) 108 | } 109 | } 110 | 111 | func (x *SignUpUserResponse) String() string { 112 | return protoimpl.X.MessageStringOf(x) 113 | } 114 | 115 | func (*SignUpUserResponse) ProtoMessage() {} 116 | 117 | func (x *SignUpUserResponse) ProtoReflect() protoreflect.Message { 118 | mi := &file_rpc_signup_user_proto_msgTypes[1] 119 | if protoimpl.UnsafeEnabled && x != nil { 120 | ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) 121 | if ms.LoadMessageInfo() == nil { 122 | ms.StoreMessageInfo(mi) 123 | } 124 | return ms 125 | } 126 | return mi.MessageOf(x) 127 | } 128 | 129 | // Deprecated: Use SignUpUserResponse.ProtoReflect.Descriptor instead. 130 | func (*SignUpUserResponse) Descriptor() ([]byte, []int) { 131 | return file_rpc_signup_user_proto_rawDescGZIP(), []int{1} 132 | } 133 | 134 | func (x *SignUpUserResponse) GetUser() *User { 135 | if x != nil { 136 | return x.User 137 | } 138 | return nil 139 | } 140 | 141 | var File_rpc_signup_user_proto protoreflect.FileDescriptor 142 | 143 | var file_rpc_signup_user_proto_rawDesc = []byte{ 144 | 0x0a, 0x15, 0x72, 0x70, 0x63, 0x5f, 0x73, 0x69, 0x67, 0x6e, 0x75, 0x70, 0x5f, 0x75, 0x73, 0x65, 145 | 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x02, 0x70, 0x62, 0x1a, 0x0a, 0x75, 0x73, 0x65, 146 | 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x81, 0x01, 0x0a, 0x0f, 0x53, 0x69, 0x67, 0x6e, 147 | 0x55, 0x70, 0x55, 0x73, 0x65, 0x72, 0x49, 0x6e, 0x70, 0x75, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x6e, 148 | 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 149 | 0x14, 0x0a, 0x05, 0x65, 0x6d, 0x61, 0x69, 0x6c, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 150 | 0x65, 0x6d, 0x61, 0x69, 0x6c, 0x12, 0x1a, 0x0a, 0x08, 0x70, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 151 | 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x70, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 152 | 0x64, 0x12, 0x28, 0x0a, 0x0f, 0x70, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x43, 0x6f, 0x6e, 153 | 0x66, 0x69, 0x72, 0x6d, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0f, 0x70, 0x61, 0x73, 0x73, 154 | 0x77, 0x6f, 0x72, 0x64, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x72, 0x6d, 0x22, 0x32, 0x0a, 0x12, 0x53, 155 | 0x69, 0x67, 0x6e, 0x55, 0x70, 0x55, 0x73, 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 156 | 0x65, 0x12, 0x1c, 0x0a, 0x04, 0x75, 0x73, 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 157 | 0x08, 0x2e, 0x70, 0x62, 0x2e, 0x55, 0x73, 0x65, 0x72, 0x52, 0x04, 0x75, 0x73, 0x65, 0x72, 0x42, 158 | 0x27, 0x5a, 0x25, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x77, 0x70, 159 | 0x63, 0x6f, 0x64, 0x65, 0x76, 0x6f, 0x2f, 0x67, 0x6f, 0x6c, 0x61, 0x6e, 0x67, 0x2d, 0x6d, 0x6f, 160 | 0x6e, 0x67, 0x6f, 0x64, 0x62, 0x2f, 0x70, 0x62, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, 161 | } 162 | 163 | var ( 164 | file_rpc_signup_user_proto_rawDescOnce sync.Once 165 | file_rpc_signup_user_proto_rawDescData = file_rpc_signup_user_proto_rawDesc 166 | ) 167 | 168 | func file_rpc_signup_user_proto_rawDescGZIP() []byte { 169 | file_rpc_signup_user_proto_rawDescOnce.Do(func() { 170 | file_rpc_signup_user_proto_rawDescData = protoimpl.X.CompressGZIP(file_rpc_signup_user_proto_rawDescData) 171 | }) 172 | return file_rpc_signup_user_proto_rawDescData 173 | } 174 | 175 | var file_rpc_signup_user_proto_msgTypes = make([]protoimpl.MessageInfo, 2) 176 | var file_rpc_signup_user_proto_goTypes = []interface{}{ 177 | (*SignUpUserInput)(nil), // 0: pb.SignUpUserInput 178 | (*SignUpUserResponse)(nil), // 1: pb.SignUpUserResponse 179 | (*User)(nil), // 2: pb.User 180 | } 181 | var file_rpc_signup_user_proto_depIdxs = []int32{ 182 | 2, // 0: pb.SignUpUserResponse.user:type_name -> pb.User 183 | 1, // [1:1] is the sub-list for method output_type 184 | 1, // [1:1] is the sub-list for method input_type 185 | 1, // [1:1] is the sub-list for extension type_name 186 | 1, // [1:1] is the sub-list for extension extendee 187 | 0, // [0:1] is the sub-list for field type_name 188 | } 189 | 190 | func init() { file_rpc_signup_user_proto_init() } 191 | func file_rpc_signup_user_proto_init() { 192 | if File_rpc_signup_user_proto != nil { 193 | return 194 | } 195 | file_user_proto_init() 196 | if !protoimpl.UnsafeEnabled { 197 | file_rpc_signup_user_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { 198 | switch v := v.(*SignUpUserInput); i { 199 | case 0: 200 | return &v.state 201 | case 1: 202 | return &v.sizeCache 203 | case 2: 204 | return &v.unknownFields 205 | default: 206 | return nil 207 | } 208 | } 209 | file_rpc_signup_user_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { 210 | switch v := v.(*SignUpUserResponse); i { 211 | case 0: 212 | return &v.state 213 | case 1: 214 | return &v.sizeCache 215 | case 2: 216 | return &v.unknownFields 217 | default: 218 | return nil 219 | } 220 | } 221 | } 222 | type x struct{} 223 | out := protoimpl.TypeBuilder{ 224 | File: protoimpl.DescBuilder{ 225 | GoPackagePath: reflect.TypeOf(x{}).PkgPath(), 226 | RawDescriptor: file_rpc_signup_user_proto_rawDesc, 227 | NumEnums: 0, 228 | NumMessages: 2, 229 | NumExtensions: 0, 230 | NumServices: 0, 231 | }, 232 | GoTypes: file_rpc_signup_user_proto_goTypes, 233 | DependencyIndexes: file_rpc_signup_user_proto_depIdxs, 234 | MessageInfos: file_rpc_signup_user_proto_msgTypes, 235 | }.Build() 236 | File_rpc_signup_user_proto = out.File 237 | file_rpc_signup_user_proto_rawDesc = nil 238 | file_rpc_signup_user_proto_goTypes = nil 239 | file_rpc_signup_user_proto_depIdxs = nil 240 | } 241 | -------------------------------------------------------------------------------- /pb/post.pb.go: -------------------------------------------------------------------------------- 1 | // Code generated by protoc-gen-go. DO NOT EDIT. 2 | // versions: 3 | // protoc-gen-go v1.28.0 4 | // protoc v3.20.1 5 | // source: post.proto 6 | 7 | package pb 8 | 9 | import ( 10 | protoreflect "google.golang.org/protobuf/reflect/protoreflect" 11 | protoimpl "google.golang.org/protobuf/runtime/protoimpl" 12 | timestamppb "google.golang.org/protobuf/types/known/timestamppb" 13 | reflect "reflect" 14 | sync "sync" 15 | ) 16 | 17 | const ( 18 | // Verify that this generated code is sufficiently up-to-date. 19 | _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) 20 | // Verify that runtime/protoimpl is sufficiently up-to-date. 21 | _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) 22 | ) 23 | 24 | type Post struct { 25 | state protoimpl.MessageState 26 | sizeCache protoimpl.SizeCache 27 | unknownFields protoimpl.UnknownFields 28 | 29 | Id string `protobuf:"bytes,1,opt,name=Id,proto3" json:"Id,omitempty"` 30 | Title string `protobuf:"bytes,2,opt,name=Title,proto3" json:"Title,omitempty"` 31 | Content string `protobuf:"bytes,3,opt,name=Content,proto3" json:"Content,omitempty"` 32 | Image string `protobuf:"bytes,4,opt,name=Image,proto3" json:"Image,omitempty"` 33 | User string `protobuf:"bytes,5,opt,name=User,proto3" json:"User,omitempty"` 34 | CreatedAt *timestamppb.Timestamp `protobuf:"bytes,6,opt,name=created_at,json=createdAt,proto3" json:"created_at,omitempty"` 35 | UpdatedAt *timestamppb.Timestamp `protobuf:"bytes,7,opt,name=updated_at,json=updatedAt,proto3" json:"updated_at,omitempty"` 36 | } 37 | 38 | func (x *Post) Reset() { 39 | *x = Post{} 40 | if protoimpl.UnsafeEnabled { 41 | mi := &file_post_proto_msgTypes[0] 42 | ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) 43 | ms.StoreMessageInfo(mi) 44 | } 45 | } 46 | 47 | func (x *Post) String() string { 48 | return protoimpl.X.MessageStringOf(x) 49 | } 50 | 51 | func (*Post) ProtoMessage() {} 52 | 53 | func (x *Post) ProtoReflect() protoreflect.Message { 54 | mi := &file_post_proto_msgTypes[0] 55 | if protoimpl.UnsafeEnabled && x != nil { 56 | ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) 57 | if ms.LoadMessageInfo() == nil { 58 | ms.StoreMessageInfo(mi) 59 | } 60 | return ms 61 | } 62 | return mi.MessageOf(x) 63 | } 64 | 65 | // Deprecated: Use Post.ProtoReflect.Descriptor instead. 66 | func (*Post) Descriptor() ([]byte, []int) { 67 | return file_post_proto_rawDescGZIP(), []int{0} 68 | } 69 | 70 | func (x *Post) GetId() string { 71 | if x != nil { 72 | return x.Id 73 | } 74 | return "" 75 | } 76 | 77 | func (x *Post) GetTitle() string { 78 | if x != nil { 79 | return x.Title 80 | } 81 | return "" 82 | } 83 | 84 | func (x *Post) GetContent() string { 85 | if x != nil { 86 | return x.Content 87 | } 88 | return "" 89 | } 90 | 91 | func (x *Post) GetImage() string { 92 | if x != nil { 93 | return x.Image 94 | } 95 | return "" 96 | } 97 | 98 | func (x *Post) GetUser() string { 99 | if x != nil { 100 | return x.User 101 | } 102 | return "" 103 | } 104 | 105 | func (x *Post) GetCreatedAt() *timestamppb.Timestamp { 106 | if x != nil { 107 | return x.CreatedAt 108 | } 109 | return nil 110 | } 111 | 112 | func (x *Post) GetUpdatedAt() *timestamppb.Timestamp { 113 | if x != nil { 114 | return x.UpdatedAt 115 | } 116 | return nil 117 | } 118 | 119 | type PostResponse struct { 120 | state protoimpl.MessageState 121 | sizeCache protoimpl.SizeCache 122 | unknownFields protoimpl.UnknownFields 123 | 124 | Post *Post `protobuf:"bytes,1,opt,name=post,proto3" json:"post,omitempty"` 125 | } 126 | 127 | func (x *PostResponse) Reset() { 128 | *x = PostResponse{} 129 | if protoimpl.UnsafeEnabled { 130 | mi := &file_post_proto_msgTypes[1] 131 | ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) 132 | ms.StoreMessageInfo(mi) 133 | } 134 | } 135 | 136 | func (x *PostResponse) String() string { 137 | return protoimpl.X.MessageStringOf(x) 138 | } 139 | 140 | func (*PostResponse) ProtoMessage() {} 141 | 142 | func (x *PostResponse) ProtoReflect() protoreflect.Message { 143 | mi := &file_post_proto_msgTypes[1] 144 | if protoimpl.UnsafeEnabled && x != nil { 145 | ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) 146 | if ms.LoadMessageInfo() == nil { 147 | ms.StoreMessageInfo(mi) 148 | } 149 | return ms 150 | } 151 | return mi.MessageOf(x) 152 | } 153 | 154 | // Deprecated: Use PostResponse.ProtoReflect.Descriptor instead. 155 | func (*PostResponse) Descriptor() ([]byte, []int) { 156 | return file_post_proto_rawDescGZIP(), []int{1} 157 | } 158 | 159 | func (x *PostResponse) GetPost() *Post { 160 | if x != nil { 161 | return x.Post 162 | } 163 | return nil 164 | } 165 | 166 | var File_post_proto protoreflect.FileDescriptor 167 | 168 | var file_post_proto_rawDesc = []byte{ 169 | 0x0a, 0x0a, 0x70, 0x6f, 0x73, 0x74, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x02, 0x70, 0x62, 170 | 0x1a, 0x1f, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 171 | 0x66, 0x2f, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x2e, 0x70, 0x72, 0x6f, 0x74, 172 | 0x6f, 0x22, 0xe6, 0x01, 0x0a, 0x04, 0x50, 0x6f, 0x73, 0x74, 0x12, 0x0e, 0x0a, 0x02, 0x49, 0x64, 173 | 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x49, 0x64, 0x12, 0x14, 0x0a, 0x05, 0x54, 0x69, 174 | 0x74, 0x6c, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x54, 0x69, 0x74, 0x6c, 0x65, 175 | 0x12, 0x18, 0x0a, 0x07, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 176 | 0x09, 0x52, 0x07, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x12, 0x14, 0x0a, 0x05, 0x49, 0x6d, 177 | 0x61, 0x67, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x49, 0x6d, 0x61, 0x67, 0x65, 178 | 0x12, 0x12, 0x0a, 0x04, 0x55, 0x73, 0x65, 0x72, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 179 | 0x55, 0x73, 0x65, 0x72, 0x12, 0x39, 0x0a, 0x0a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x5f, 180 | 0x61, 0x74, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 181 | 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 182 | 0x74, 0x61, 0x6d, 0x70, 0x52, 0x09, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x41, 0x74, 0x12, 183 | 0x39, 0x0a, 0x0a, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x64, 0x5f, 0x61, 0x74, 0x18, 0x07, 0x20, 184 | 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 185 | 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 186 | 0x09, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x64, 0x41, 0x74, 0x22, 0x2c, 0x0a, 0x0c, 0x50, 0x6f, 187 | 0x73, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x1c, 0x0a, 0x04, 0x70, 0x6f, 188 | 0x73, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x08, 0x2e, 0x70, 0x62, 0x2e, 0x50, 0x6f, 189 | 0x73, 0x74, 0x52, 0x04, 0x70, 0x6f, 0x73, 0x74, 0x42, 0x27, 0x5a, 0x25, 0x67, 0x69, 0x74, 0x68, 190 | 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x77, 0x70, 0x63, 0x6f, 0x64, 0x65, 0x76, 0x6f, 0x2f, 191 | 0x67, 0x6f, 0x6c, 0x61, 0x6e, 0x67, 0x2d, 0x6d, 0x6f, 0x6e, 0x67, 0x6f, 0x64, 0x62, 0x2f, 0x70, 192 | 0x62, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, 193 | } 194 | 195 | var ( 196 | file_post_proto_rawDescOnce sync.Once 197 | file_post_proto_rawDescData = file_post_proto_rawDesc 198 | ) 199 | 200 | func file_post_proto_rawDescGZIP() []byte { 201 | file_post_proto_rawDescOnce.Do(func() { 202 | file_post_proto_rawDescData = protoimpl.X.CompressGZIP(file_post_proto_rawDescData) 203 | }) 204 | return file_post_proto_rawDescData 205 | } 206 | 207 | var file_post_proto_msgTypes = make([]protoimpl.MessageInfo, 2) 208 | var file_post_proto_goTypes = []interface{}{ 209 | (*Post)(nil), // 0: pb.Post 210 | (*PostResponse)(nil), // 1: pb.PostResponse 211 | (*timestamppb.Timestamp)(nil), // 2: google.protobuf.Timestamp 212 | } 213 | var file_post_proto_depIdxs = []int32{ 214 | 2, // 0: pb.Post.created_at:type_name -> google.protobuf.Timestamp 215 | 2, // 1: pb.Post.updated_at:type_name -> google.protobuf.Timestamp 216 | 0, // 2: pb.PostResponse.post:type_name -> pb.Post 217 | 3, // [3:3] is the sub-list for method output_type 218 | 3, // [3:3] is the sub-list for method input_type 219 | 3, // [3:3] is the sub-list for extension type_name 220 | 3, // [3:3] is the sub-list for extension extendee 221 | 0, // [0:3] is the sub-list for field type_name 222 | } 223 | 224 | func init() { file_post_proto_init() } 225 | func file_post_proto_init() { 226 | if File_post_proto != nil { 227 | return 228 | } 229 | if !protoimpl.UnsafeEnabled { 230 | file_post_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { 231 | switch v := v.(*Post); i { 232 | case 0: 233 | return &v.state 234 | case 1: 235 | return &v.sizeCache 236 | case 2: 237 | return &v.unknownFields 238 | default: 239 | return nil 240 | } 241 | } 242 | file_post_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { 243 | switch v := v.(*PostResponse); i { 244 | case 0: 245 | return &v.state 246 | case 1: 247 | return &v.sizeCache 248 | case 2: 249 | return &v.unknownFields 250 | default: 251 | return nil 252 | } 253 | } 254 | } 255 | type x struct{} 256 | out := protoimpl.TypeBuilder{ 257 | File: protoimpl.DescBuilder{ 258 | GoPackagePath: reflect.TypeOf(x{}).PkgPath(), 259 | RawDescriptor: file_post_proto_rawDesc, 260 | NumEnums: 0, 261 | NumMessages: 2, 262 | NumExtensions: 0, 263 | NumServices: 0, 264 | }, 265 | GoTypes: file_post_proto_goTypes, 266 | DependencyIndexes: file_post_proto_depIdxs, 267 | MessageInfos: file_post_proto_msgTypes, 268 | }.Build() 269 | File_post_proto = out.File 270 | file_post_proto_rawDesc = nil 271 | file_post_proto_goTypes = nil 272 | file_post_proto_depIdxs = nil 273 | } 274 | -------------------------------------------------------------------------------- /controllers/auth.controller.go: -------------------------------------------------------------------------------- 1 | package controllers 2 | 3 | import ( 4 | "context" 5 | "fmt" 6 | "log" 7 | "net/http" 8 | "strings" 9 | "time" 10 | 11 | "github.com/gin-gonic/gin" 12 | "github.com/thanhpk/randstr" 13 | "github.com/wpcodevo/golang-mongodb/config" 14 | "github.com/wpcodevo/golang-mongodb/models" 15 | "github.com/wpcodevo/golang-mongodb/services" 16 | "github.com/wpcodevo/golang-mongodb/utils" 17 | "go.mongodb.org/mongo-driver/bson" 18 | "go.mongodb.org/mongo-driver/mongo" 19 | ) 20 | 21 | type AuthController struct { 22 | authService services.AuthService 23 | userService services.UserService 24 | ctx context.Context 25 | collection *mongo.Collection 26 | } 27 | 28 | func NewAuthController(authService services.AuthService, userService services.UserService, ctx context.Context, collection *mongo.Collection) AuthController { 29 | return AuthController{authService, userService, ctx, collection} 30 | } 31 | 32 | func (ac *AuthController) SignUpUser(ctx *gin.Context) { 33 | var user *models.SignUpInput 34 | 35 | if err := ctx.ShouldBindJSON(&user); err != nil { 36 | ctx.JSON(http.StatusBadRequest, gin.H{"status": "fail", "message": err.Error()}) 37 | return 38 | } 39 | 40 | if user.Password != user.PasswordConfirm { 41 | ctx.JSON(http.StatusBadRequest, gin.H{"status": "fail", "message": "Passwords do not match"}) 42 | return 43 | } 44 | 45 | newUser, err := ac.authService.SignUpUser(user) 46 | 47 | if err != nil { 48 | if strings.Contains(err.Error(), "email already exist") { 49 | ctx.JSON(http.StatusConflict, gin.H{"status": "error", "message": err.Error()}) 50 | return 51 | } 52 | ctx.JSON(http.StatusBadGateway, gin.H{"status": "error", "message": err.Error()}) 53 | return 54 | } 55 | 56 | config, err := config.LoadConfig(".") 57 | if err != nil { 58 | log.Fatal("Could not load config", err) 59 | } 60 | 61 | // Generate Verification Code 62 | code := randstr.String(20) 63 | 64 | verificationCode := utils.Encode(code) 65 | 66 | updateData := &models.UpdateInput{ 67 | VerificationCode: verificationCode, 68 | } 69 | 70 | // Update User in Database 71 | ac.userService.UpdateUserById(newUser.ID.Hex(), updateData) 72 | 73 | var firstName = newUser.Name 74 | 75 | if strings.Contains(firstName, " ") { 76 | firstName = strings.Split(firstName, " ")[1] 77 | } 78 | 79 | // 👇 Send Email 80 | emailData := utils.EmailData{ 81 | URL: config.Origin + "/verifyemail/" + code, 82 | FirstName: firstName, 83 | Subject: "Your account verification code", 84 | } 85 | 86 | err = utils.SendEmail(newUser, &emailData, "verificationCode.html") 87 | if err != nil { 88 | ctx.JSON(http.StatusBadGateway, gin.H{"status": "success", "message": "There was an error sending email"}) 89 | return 90 | } 91 | 92 | message := "We sent an email with a verification code to " + user.Email 93 | ctx.JSON(http.StatusCreated, gin.H{"status": "success", "message": message}) 94 | } 95 | 96 | func (ac *AuthController) SignInUser(ctx *gin.Context) { 97 | var credentials *models.SignInInput 98 | 99 | if err := ctx.ShouldBindJSON(&credentials); err != nil { 100 | ctx.JSON(http.StatusBadRequest, gin.H{"status": "fail", "message": err.Error()}) 101 | return 102 | } 103 | 104 | user, err := ac.userService.FindUserByEmail(credentials.Email) 105 | if err != nil { 106 | if err == mongo.ErrNoDocuments { 107 | ctx.JSON(http.StatusBadRequest, gin.H{"status": "fail", "message": "Invalid email or password"}) 108 | return 109 | } 110 | ctx.JSON(http.StatusBadRequest, gin.H{"status": "fail", "message": err.Error()}) 111 | return 112 | } 113 | 114 | if !user.Verified { 115 | ctx.JSON(http.StatusUnauthorized, gin.H{"status": "fail", "message": "You are not verified, please verify your email to login"}) 116 | return 117 | } 118 | 119 | if err := utils.VerifyPassword(user.Password, credentials.Password); err != nil { 120 | ctx.JSON(http.StatusBadRequest, gin.H{"status": "fail", "message": "Invalid email or Password"}) 121 | return 122 | } 123 | 124 | config, _ := config.LoadConfig(".") 125 | 126 | // Generate Tokens 127 | access_token, err := utils.CreateToken(config.AccessTokenExpiresIn, user.ID, config.AccessTokenPrivateKey) 128 | if err != nil { 129 | ctx.JSON(http.StatusBadRequest, gin.H{"status": "fail", "message": err.Error()}) 130 | return 131 | } 132 | 133 | refresh_token, err := utils.CreateToken(config.RefreshTokenExpiresIn, user.ID, config.RefreshTokenPrivateKey) 134 | if err != nil { 135 | ctx.JSON(http.StatusBadRequest, gin.H{"status": "fail", "message": err.Error()}) 136 | return 137 | } 138 | 139 | ctx.SetCookie("access_token", access_token, config.AccessTokenMaxAge*60, "/", "localhost", false, true) 140 | ctx.SetCookie("refresh_token", refresh_token, config.RefreshTokenMaxAge*60, "/", "localhost", false, true) 141 | ctx.SetCookie("logged_in", "true", config.AccessTokenMaxAge*60, "/", "localhost", false, false) 142 | 143 | ctx.JSON(http.StatusOK, gin.H{"status": "success", "access_token": access_token}) 144 | } 145 | 146 | func (ac *AuthController) RefreshAccessToken(ctx *gin.Context) { 147 | message := "could not refresh access token" 148 | 149 | cookie, err := ctx.Cookie("refresh_token") 150 | 151 | if err != nil { 152 | ctx.AbortWithStatusJSON(http.StatusForbidden, gin.H{"status": "fail", "message": message}) 153 | return 154 | } 155 | 156 | config, _ := config.LoadConfig(".") 157 | 158 | sub, err := utils.ValidateToken(cookie, config.RefreshTokenPublicKey) 159 | if err != nil { 160 | ctx.AbortWithStatusJSON(http.StatusForbidden, gin.H{"status": "fail", "message": err.Error()}) 161 | return 162 | } 163 | 164 | user, err := ac.userService.FindUserById(fmt.Sprint(sub)) 165 | if err != nil { 166 | ctx.AbortWithStatusJSON(http.StatusForbidden, gin.H{"status": "fail", "message": "the user belonging to this token no logger exists"}) 167 | return 168 | } 169 | 170 | access_token, err := utils.CreateToken(config.AccessTokenExpiresIn, user.ID, config.AccessTokenPrivateKey) 171 | if err != nil { 172 | ctx.AbortWithStatusJSON(http.StatusForbidden, gin.H{"status": "fail", "message": err.Error()}) 173 | return 174 | } 175 | 176 | ctx.SetCookie("access_token", access_token, config.AccessTokenMaxAge*60, "/", "localhost", false, true) 177 | ctx.SetCookie("logged_in", "true", config.AccessTokenMaxAge*60, "/", "localhost", false, false) 178 | 179 | ctx.JSON(http.StatusOK, gin.H{"status": "success", "access_token": access_token}) 180 | } 181 | 182 | func (ac *AuthController) LogoutUser(ctx *gin.Context) { 183 | ctx.SetCookie("access_token", "", -1, "/", "localhost", false, true) 184 | ctx.SetCookie("refresh_token", "", -1, "/", "localhost", false, true) 185 | ctx.SetCookie("logged_in", "", -1, "/", "localhost", false, true) 186 | 187 | ctx.JSON(http.StatusOK, gin.H{"status": "success"}) 188 | } 189 | 190 | func (ac *AuthController) VerifyEmail(ctx *gin.Context) { 191 | 192 | code := ctx.Params.ByName("verificationCode") 193 | verificationCode := utils.Encode(code) 194 | 195 | query := bson.D{{Key: "verificationCode", Value: verificationCode}} 196 | update := bson.D{{Key: "$set", Value: bson.D{{Key: "verified", Value: true}}}, {Key: "$unset", Value: bson.D{{Key: "verificationCode", Value: ""}}}} 197 | result, err := ac.collection.UpdateOne(ac.ctx, query, update) 198 | if err != nil { 199 | ctx.JSON(http.StatusForbidden, gin.H{"status": "success", "message": err.Error()}) 200 | return 201 | } 202 | 203 | if result.MatchedCount == 0 { 204 | ctx.JSON(http.StatusForbidden, gin.H{"status": "success", "message": "Could not verify email address"}) 205 | return 206 | } 207 | 208 | fmt.Println(result) 209 | 210 | ctx.JSON(http.StatusOK, gin.H{"status": "success", "message": "Email verified successfully"}) 211 | 212 | } 213 | 214 | func (ac *AuthController) ForgotPassword(ctx *gin.Context) { 215 | var userCredential *models.ForgotPasswordInput 216 | 217 | if err := ctx.ShouldBindJSON(&userCredential); err != nil { 218 | ctx.JSON(http.StatusBadRequest, gin.H{"status": "fail", "message": err.Error()}) 219 | return 220 | } 221 | 222 | message := "You will receive a reset email if user with that email exist" 223 | 224 | user, err := ac.userService.FindUserByEmail(userCredential.Email) 225 | if err != nil { 226 | if err == mongo.ErrNoDocuments { 227 | ctx.JSON(http.StatusOK, gin.H{"status": "fail", "message": message}) 228 | return 229 | } 230 | ctx.JSON(http.StatusBadGateway, gin.H{"status": "error", "message": err.Error()}) 231 | return 232 | } 233 | 234 | if !user.Verified { 235 | ctx.JSON(http.StatusUnauthorized, gin.H{"status": "error", "message": "Account not verified"}) 236 | return 237 | } 238 | 239 | config, err := config.LoadConfig(".") 240 | if err != nil { 241 | log.Fatal("Could not load config", err) 242 | } 243 | 244 | // Generate Verification Code 245 | resetToken := randstr.String(20) 246 | 247 | passwordResetToken := utils.Encode(resetToken) 248 | 249 | // Update User in Database 250 | query := bson.D{{Key: "email", Value: strings.ToLower(userCredential.Email)}} 251 | update := bson.D{{Key: "$set", Value: bson.D{{Key: "passwordResetToken", Value: passwordResetToken}, {Key: "passwordResetAt", Value: time.Now().Add(time.Minute * 15)}}}} 252 | result, err := ac.collection.UpdateOne(ac.ctx, query, update) 253 | 254 | if result.MatchedCount == 0 { 255 | ctx.JSON(http.StatusBadGateway, gin.H{"status": "success", "message": "There was an error sending email"}) 256 | return 257 | } 258 | 259 | if err != nil { 260 | ctx.JSON(http.StatusForbidden, gin.H{"status": "success", "message": err.Error()}) 261 | return 262 | } 263 | var firstName = user.Name 264 | 265 | if strings.Contains(firstName, " ") { 266 | firstName = strings.Split(firstName, " ")[1] 267 | } 268 | 269 | // 👇 Send Email 270 | emailData := utils.EmailData{ 271 | URL: config.Origin + "/forgotPassword/" + resetToken, 272 | FirstName: firstName, 273 | Subject: "Your password reset token (valid for 10min)", 274 | } 275 | 276 | err = utils.SendEmail(user, &emailData, "resetPassword.html") 277 | if err != nil { 278 | ctx.JSON(http.StatusBadGateway, gin.H{"status": "success", "message": "There was an error sending email"}) 279 | return 280 | } 281 | ctx.JSON(http.StatusOK, gin.H{"status": "success", "message": message}) 282 | } 283 | -------------------------------------------------------------------------------- /readMe.md: -------------------------------------------------------------------------------- 1 | # Build gRPC Server API & Client with Golang and MongoDB 2 | 3 | ## 1. API with Golang + MongoDB + Redis + Gin Gonic: Project Setup 4 | 5 | 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. 6 | 7 | ![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) 8 | 9 | ### Topics Covered 10 | 11 | - Setup Golang with MongoDB and Redis 12 | - Creating MongoDB and Redis Database with Docker-compose 13 | - Setup Environment Variables 14 | - How to Connect Golang App to Redis and MongoDB 15 | - Test the Golang API 16 | - How to Connect to MongoDB and Redis Servers in VS Code 17 | 18 | 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) 19 | 20 | 21 | ## 2. Golang & MongoDB: JWT Authentication and Authorization 22 | 23 | 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. 24 | 25 | ![Golang & MongoDB: JWT Authentication and Authorization](https://codevoweb.com/wp-content/uploads/2022/05/Golang-and-MongoDB-JWT-Authentication-and-Authorization.webp) 26 | 27 | ### Topics Covered 28 | 29 | - Golang & MongoDB JWT Authentication Overview 30 | - JWT Authentication Example with Golang and MongoDB 31 | - How to Generate Public and Private Keys 32 | - Update Environment Variables with Viper 33 | - Creating the User models with structs 34 | - Creating an Auth and User Interfaces 35 | - Authentication Interface 36 | - User Interface 37 | - Create utility functions to hash and verify password 38 | - Create services that interact with the database 39 | - Auth interface implementation 40 | - User interface implementation 41 | - Create a utility function to sign and verify JWT tokens 42 | - Create Json Web Token 43 | - Verify JSON Web Token 44 | - Create the authentication controllers 45 | - Signup user controller 46 | - Login user controller 47 | - Refresh access token controller 48 | - Logout user controller 49 | - Authentication Middleware Guard 50 | - Create the user controllers 51 | - Create API Routes with Gin 52 | - Auth Routes 53 | - User Routes 54 | - Add the Routes to the Gin Middleware Pipeline 55 | 56 | Read the entire article here: [https://codevoweb.com/golang-mongodb-jwt-authentication-authorization](https://codevoweb.com/golang-mongodb-jwt-authentication-authorization) 57 | 58 | ## 3. API with Golang + MongoDB: Send HTML Emails with Gomail 59 | 60 | 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. 61 | 62 | ![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) 63 | 64 | ### Topics Covered 65 | 66 | - Send Emails with Golang, MongoDB, and Gomail Overview 67 | - Creating the HTML Email Templates with Golang 68 | - Create an SMTP Provider Account 69 | - Load and Validate Environment Variables Viper 70 | - Create a Utility Function to Send the Emails 71 | - Update the SignUp Controller 72 | 73 | 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) 74 | 75 | 76 | ## 4. API with Golang, Gin Gonic & MongoDB: Forget/Reset Password 77 | 78 | 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. 79 | 80 | ![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) 81 | 82 | ### Topics Covered 83 | 84 | - Forget/Reset Password with Golang, Gin, and MongoDB 85 | - Create the MongoDB Model Structs 86 | - Create the HTML Email Templates with Golang 87 | - Define a Utility Function to Parse the HTML Templates 88 | - Create a Function to Send the HTML Emails 89 | - Add the Forgot Password Controller 90 | - Add the Reset Password Controller 91 | - Register the Gin API Routes 92 | 93 | 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) 94 | 95 | 96 | ## 5. Build Golang gRPC Server and Client: SignUp User & Verify Email 97 | 98 | 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. 99 | 100 | ![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) 101 | 102 | ### Topics Covered 103 | 104 | - gRPC Project setup in Golang 105 | - Create the gRPC Request and Response Messages 106 | - Define the gRPC User messages 107 | - Define the gRPC Request and Response Message to SignUp User 108 | - Create the gRPC Service Methods 109 | - Generate the gRPC client and server interfaces 110 | - Start the gRPC Server 111 | - Test the gRPC API Server with Golang Evans 112 | - Create the gRPC API Controllers 113 | - Register User gRPC Controller 114 | - Verify User gRPC Controller 115 | - Create the gRPC Client to Register a User 116 | 117 | 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) 118 | 119 | ## 6. Build Golang gRPC Server and Client: Access & Refresh Tokens 120 | 121 | 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. 122 | 123 | ![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) 124 | 125 | ### Topics Covered 126 | 127 | - Create the gRPC Request and Response Messages 128 | - Create the gRPC User messages 129 | - Define the gRPC Request and Response Message to Login User 130 | - Update the Authentication gRPC Service 131 | - Create a gRPC User Service 132 | - Create the gRPC Controllers 133 | - Create the gRPC Servers 134 | - Register the gRPC Servers 135 | - Create the gRPC Clients in Golang 136 | - Connect the gRPC Client to the gRPC Server 137 | 138 | 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) 139 | 140 | ## 7. Build CRUD RESTful API Server with Golang, Gin, and MongoDB 141 | 142 | 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. 143 | 144 | ![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) 145 | 146 | ### Topics Covered 147 | 148 | - Golang, Gin Gonic, MongoDB CRUD RESTful API Overview 149 | - Create the Models with Structs 150 | - Create the Service Interface 151 | - Create Methods to Implement the Interface 152 | - Initialize the Service Struct 153 | - Define a Service to Create a Post 154 | - Define a Service to Update Post 155 | - Define a Service to Delete Post 156 | - Define a Service to Get Single Post 157 | - Define a Service to Get All Posts 158 | - Create Controllers to Perform the CRUD Operations 159 | - Initialize the Controller Struct 160 | - Define a Controller to Create a Post 161 | - Define a Controller to Update a Post 162 | - Define a Controller to Delete a Post 163 | - Define a Controller to Get a Single Post 164 | - Define a Controller to Get All Posts 165 | - Create the Routes for the Controllers 166 | - Initialize the Constructors and Start the Gin Server 167 | 168 | 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) 169 | 170 | 171 | ## 8. Build CRUD gRPC Server API & Client with Golang and MongoDB 172 | 173 | 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. 174 | 175 | ![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) 176 | 177 | ### Topics Covered 178 | 179 | - Define the Models with Structs 180 | - Create the ProtoBuf Messages 181 | - Define the gRPC Service and RPC Methods 182 | - Define a Custom Service Interface 183 | - Create Methods to Implement the Service Interface 184 | - Create a Constructor to Implement the Service Interface 185 | - Create a new Post 186 | - Update a Post 187 | - Find a Post 188 | - Retrieve All Posts 189 | - Delete a Post 190 | - Define the gRPC Controllers 191 | - Register the gRPC Services and Start the gRPC Server 192 | - Test the gRPC API Server with Evans CLI 193 | - Create the gRPC API Handlers in Golang 194 | - CreatePost gRPC Handler 195 | - UpdatePost gRPC Service Handler 196 | - GetPost gRPC Service Handler 197 | - DeletePost gRPC Service Handler 198 | - GetPosts gRPC Service Handler 199 | - Testing the gRPC Services with Evans Cli 200 | - Create the gRPC Clients 201 | - gRPC Client to Create a Post 202 | - gRPC Client to Update a Post 203 | - gRPC Client to Get a Single Post 204 | - gRPC Client to Get All Posts 205 | - gRPC Client to Delete a Post 206 | - Register the gRPC Services 207 | 208 | 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) 209 | -------------------------------------------------------------------------------- /pb/post_service_grpc.pb.go: -------------------------------------------------------------------------------- 1 | // Code generated by protoc-gen-go-grpc. DO NOT EDIT. 2 | // versions: 3 | // - protoc-gen-go-grpc v1.2.0 4 | // - protoc v3.20.1 5 | // source: post_service.proto 6 | 7 | package pb 8 | 9 | import ( 10 | context "context" 11 | grpc "google.golang.org/grpc" 12 | codes "google.golang.org/grpc/codes" 13 | status "google.golang.org/grpc/status" 14 | ) 15 | 16 | // This is a compile-time assertion to ensure that this generated file 17 | // is compatible with the grpc package it is being compiled against. 18 | // Requires gRPC-Go v1.32.0 or later. 19 | const _ = grpc.SupportPackageIsVersion7 20 | 21 | // PostServiceClient is the client API for PostService service. 22 | // 23 | // 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. 24 | type PostServiceClient interface { 25 | CreatePost(ctx context.Context, in *CreatePostRequest, opts ...grpc.CallOption) (*PostResponse, error) 26 | GetPost(ctx context.Context, in *PostRequest, opts ...grpc.CallOption) (*PostResponse, error) 27 | GetPosts(ctx context.Context, in *GetPostsRequest, opts ...grpc.CallOption) (PostService_GetPostsClient, error) 28 | UpdatePost(ctx context.Context, in *UpdatePostRequest, opts ...grpc.CallOption) (*PostResponse, error) 29 | DeletePost(ctx context.Context, in *PostRequest, opts ...grpc.CallOption) (*DeletePostResponse, error) 30 | } 31 | 32 | type postServiceClient struct { 33 | cc grpc.ClientConnInterface 34 | } 35 | 36 | func NewPostServiceClient(cc grpc.ClientConnInterface) PostServiceClient { 37 | return &postServiceClient{cc} 38 | } 39 | 40 | func (c *postServiceClient) CreatePost(ctx context.Context, in *CreatePostRequest, opts ...grpc.CallOption) (*PostResponse, error) { 41 | out := new(PostResponse) 42 | err := c.cc.Invoke(ctx, "/pb.PostService/CreatePost", in, out, opts...) 43 | if err != nil { 44 | return nil, err 45 | } 46 | return out, nil 47 | } 48 | 49 | func (c *postServiceClient) GetPost(ctx context.Context, in *PostRequest, opts ...grpc.CallOption) (*PostResponse, error) { 50 | out := new(PostResponse) 51 | err := c.cc.Invoke(ctx, "/pb.PostService/GetPost", in, out, opts...) 52 | if err != nil { 53 | return nil, err 54 | } 55 | return out, nil 56 | } 57 | 58 | func (c *postServiceClient) GetPosts(ctx context.Context, in *GetPostsRequest, opts ...grpc.CallOption) (PostService_GetPostsClient, error) { 59 | stream, err := c.cc.NewStream(ctx, &PostService_ServiceDesc.Streams[0], "/pb.PostService/GetPosts", opts...) 60 | if err != nil { 61 | return nil, err 62 | } 63 | x := &postServiceGetPostsClient{stream} 64 | if err := x.ClientStream.SendMsg(in); err != nil { 65 | return nil, err 66 | } 67 | if err := x.ClientStream.CloseSend(); err != nil { 68 | return nil, err 69 | } 70 | return x, nil 71 | } 72 | 73 | type PostService_GetPostsClient interface { 74 | Recv() (*Post, error) 75 | grpc.ClientStream 76 | } 77 | 78 | type postServiceGetPostsClient struct { 79 | grpc.ClientStream 80 | } 81 | 82 | func (x *postServiceGetPostsClient) Recv() (*Post, error) { 83 | m := new(Post) 84 | if err := x.ClientStream.RecvMsg(m); err != nil { 85 | return nil, err 86 | } 87 | return m, nil 88 | } 89 | 90 | func (c *postServiceClient) UpdatePost(ctx context.Context, in *UpdatePostRequest, opts ...grpc.CallOption) (*PostResponse, error) { 91 | out := new(PostResponse) 92 | err := c.cc.Invoke(ctx, "/pb.PostService/UpdatePost", in, out, opts...) 93 | if err != nil { 94 | return nil, err 95 | } 96 | return out, nil 97 | } 98 | 99 | func (c *postServiceClient) DeletePost(ctx context.Context, in *PostRequest, opts ...grpc.CallOption) (*DeletePostResponse, error) { 100 | out := new(DeletePostResponse) 101 | err := c.cc.Invoke(ctx, "/pb.PostService/DeletePost", in, out, opts...) 102 | if err != nil { 103 | return nil, err 104 | } 105 | return out, nil 106 | } 107 | 108 | // PostServiceServer is the server API for PostService service. 109 | // All implementations must embed UnimplementedPostServiceServer 110 | // for forward compatibility 111 | type PostServiceServer interface { 112 | CreatePost(context.Context, *CreatePostRequest) (*PostResponse, error) 113 | GetPost(context.Context, *PostRequest) (*PostResponse, error) 114 | GetPosts(*GetPostsRequest, PostService_GetPostsServer) error 115 | UpdatePost(context.Context, *UpdatePostRequest) (*PostResponse, error) 116 | DeletePost(context.Context, *PostRequest) (*DeletePostResponse, error) 117 | mustEmbedUnimplementedPostServiceServer() 118 | } 119 | 120 | // UnimplementedPostServiceServer must be embedded to have forward compatible implementations. 121 | type UnimplementedPostServiceServer struct { 122 | } 123 | 124 | func (UnimplementedPostServiceServer) CreatePost(context.Context, *CreatePostRequest) (*PostResponse, error) { 125 | return nil, status.Errorf(codes.Unimplemented, "method CreatePost not implemented") 126 | } 127 | func (UnimplementedPostServiceServer) GetPost(context.Context, *PostRequest) (*PostResponse, error) { 128 | return nil, status.Errorf(codes.Unimplemented, "method GetPost not implemented") 129 | } 130 | func (UnimplementedPostServiceServer) GetPosts(*GetPostsRequest, PostService_GetPostsServer) error { 131 | return status.Errorf(codes.Unimplemented, "method GetPosts not implemented") 132 | } 133 | func (UnimplementedPostServiceServer) UpdatePost(context.Context, *UpdatePostRequest) (*PostResponse, error) { 134 | return nil, status.Errorf(codes.Unimplemented, "method UpdatePost not implemented") 135 | } 136 | func (UnimplementedPostServiceServer) DeletePost(context.Context, *PostRequest) (*DeletePostResponse, error) { 137 | return nil, status.Errorf(codes.Unimplemented, "method DeletePost not implemented") 138 | } 139 | func (UnimplementedPostServiceServer) mustEmbedUnimplementedPostServiceServer() {} 140 | 141 | // UnsafePostServiceServer may be embedded to opt out of forward compatibility for this service. 142 | // Use of this interface is not recommended, as added methods to PostServiceServer will 143 | // result in compilation errors. 144 | type UnsafePostServiceServer interface { 145 | mustEmbedUnimplementedPostServiceServer() 146 | } 147 | 148 | func RegisterPostServiceServer(s grpc.ServiceRegistrar, srv PostServiceServer) { 149 | s.RegisterService(&PostService_ServiceDesc, srv) 150 | } 151 | 152 | func _PostService_CreatePost_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { 153 | in := new(CreatePostRequest) 154 | if err := dec(in); err != nil { 155 | return nil, err 156 | } 157 | if interceptor == nil { 158 | return srv.(PostServiceServer).CreatePost(ctx, in) 159 | } 160 | info := &grpc.UnaryServerInfo{ 161 | Server: srv, 162 | FullMethod: "/pb.PostService/CreatePost", 163 | } 164 | handler := func(ctx context.Context, req interface{}) (interface{}, error) { 165 | return srv.(PostServiceServer).CreatePost(ctx, req.(*CreatePostRequest)) 166 | } 167 | return interceptor(ctx, in, info, handler) 168 | } 169 | 170 | func _PostService_GetPost_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { 171 | in := new(PostRequest) 172 | if err := dec(in); err != nil { 173 | return nil, err 174 | } 175 | if interceptor == nil { 176 | return srv.(PostServiceServer).GetPost(ctx, in) 177 | } 178 | info := &grpc.UnaryServerInfo{ 179 | Server: srv, 180 | FullMethod: "/pb.PostService/GetPost", 181 | } 182 | handler := func(ctx context.Context, req interface{}) (interface{}, error) { 183 | return srv.(PostServiceServer).GetPost(ctx, req.(*PostRequest)) 184 | } 185 | return interceptor(ctx, in, info, handler) 186 | } 187 | 188 | func _PostService_GetPosts_Handler(srv interface{}, stream grpc.ServerStream) error { 189 | m := new(GetPostsRequest) 190 | if err := stream.RecvMsg(m); err != nil { 191 | return err 192 | } 193 | return srv.(PostServiceServer).GetPosts(m, &postServiceGetPostsServer{stream}) 194 | } 195 | 196 | type PostService_GetPostsServer interface { 197 | Send(*Post) error 198 | grpc.ServerStream 199 | } 200 | 201 | type postServiceGetPostsServer struct { 202 | grpc.ServerStream 203 | } 204 | 205 | func (x *postServiceGetPostsServer) Send(m *Post) error { 206 | return x.ServerStream.SendMsg(m) 207 | } 208 | 209 | func _PostService_UpdatePost_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { 210 | in := new(UpdatePostRequest) 211 | if err := dec(in); err != nil { 212 | return nil, err 213 | } 214 | if interceptor == nil { 215 | return srv.(PostServiceServer).UpdatePost(ctx, in) 216 | } 217 | info := &grpc.UnaryServerInfo{ 218 | Server: srv, 219 | FullMethod: "/pb.PostService/UpdatePost", 220 | } 221 | handler := func(ctx context.Context, req interface{}) (interface{}, error) { 222 | return srv.(PostServiceServer).UpdatePost(ctx, req.(*UpdatePostRequest)) 223 | } 224 | return interceptor(ctx, in, info, handler) 225 | } 226 | 227 | func _PostService_DeletePost_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { 228 | in := new(PostRequest) 229 | if err := dec(in); err != nil { 230 | return nil, err 231 | } 232 | if interceptor == nil { 233 | return srv.(PostServiceServer).DeletePost(ctx, in) 234 | } 235 | info := &grpc.UnaryServerInfo{ 236 | Server: srv, 237 | FullMethod: "/pb.PostService/DeletePost", 238 | } 239 | handler := func(ctx context.Context, req interface{}) (interface{}, error) { 240 | return srv.(PostServiceServer).DeletePost(ctx, req.(*PostRequest)) 241 | } 242 | return interceptor(ctx, in, info, handler) 243 | } 244 | 245 | // PostService_ServiceDesc is the grpc.ServiceDesc for PostService service. 246 | // It's only intended for direct use with grpc.RegisterService, 247 | // and not to be introspected or modified (even as a copy) 248 | var PostService_ServiceDesc = grpc.ServiceDesc{ 249 | ServiceName: "pb.PostService", 250 | HandlerType: (*PostServiceServer)(nil), 251 | Methods: []grpc.MethodDesc{ 252 | { 253 | MethodName: "CreatePost", 254 | Handler: _PostService_CreatePost_Handler, 255 | }, 256 | { 257 | MethodName: "GetPost", 258 | Handler: _PostService_GetPost_Handler, 259 | }, 260 | { 261 | MethodName: "UpdatePost", 262 | Handler: _PostService_UpdatePost_Handler, 263 | }, 264 | { 265 | MethodName: "DeletePost", 266 | Handler: _PostService_DeletePost_Handler, 267 | }, 268 | }, 269 | Streams: []grpc.StreamDesc{ 270 | { 271 | StreamName: "GetPosts", 272 | Handler: _PostService_GetPosts_Handler, 273 | ServerStreams: true, 274 | }, 275 | }, 276 | Metadata: "post_service.proto", 277 | } 278 | -------------------------------------------------------------------------------- /pb/user.pb.go: -------------------------------------------------------------------------------- 1 | // Code generated by protoc-gen-go. DO NOT EDIT. 2 | // versions: 3 | // protoc-gen-go v1.28.0 4 | // protoc v3.20.1 5 | // source: user.proto 6 | 7 | package pb 8 | 9 | import ( 10 | protoreflect "google.golang.org/protobuf/reflect/protoreflect" 11 | protoimpl "google.golang.org/protobuf/runtime/protoimpl" 12 | timestamppb "google.golang.org/protobuf/types/known/timestamppb" 13 | reflect "reflect" 14 | sync "sync" 15 | ) 16 | 17 | const ( 18 | // Verify that this generated code is sufficiently up-to-date. 19 | _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) 20 | // Verify that runtime/protoimpl is sufficiently up-to-date. 21 | _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) 22 | ) 23 | 24 | type User struct { 25 | state protoimpl.MessageState 26 | sizeCache protoimpl.SizeCache 27 | unknownFields protoimpl.UnknownFields 28 | 29 | Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` 30 | Name string `protobuf:"bytes,2,opt,name=name,proto3" json:"name,omitempty"` 31 | Email string `protobuf:"bytes,3,opt,name=email,proto3" json:"email,omitempty"` 32 | Role string `protobuf:"bytes,4,opt,name=role,proto3" json:"role,omitempty"` 33 | CreatedAt *timestamppb.Timestamp `protobuf:"bytes,5,opt,name=created_at,json=createdAt,proto3" json:"created_at,omitempty"` 34 | UpdatedAt *timestamppb.Timestamp `protobuf:"bytes,6,opt,name=updated_at,json=updatedAt,proto3" json:"updated_at,omitempty"` 35 | } 36 | 37 | func (x *User) Reset() { 38 | *x = User{} 39 | if protoimpl.UnsafeEnabled { 40 | mi := &file_user_proto_msgTypes[0] 41 | ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) 42 | ms.StoreMessageInfo(mi) 43 | } 44 | } 45 | 46 | func (x *User) String() string { 47 | return protoimpl.X.MessageStringOf(x) 48 | } 49 | 50 | func (*User) ProtoMessage() {} 51 | 52 | func (x *User) ProtoReflect() protoreflect.Message { 53 | mi := &file_user_proto_msgTypes[0] 54 | if protoimpl.UnsafeEnabled && x != nil { 55 | ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) 56 | if ms.LoadMessageInfo() == nil { 57 | ms.StoreMessageInfo(mi) 58 | } 59 | return ms 60 | } 61 | return mi.MessageOf(x) 62 | } 63 | 64 | // Deprecated: Use User.ProtoReflect.Descriptor instead. 65 | func (*User) Descriptor() ([]byte, []int) { 66 | return file_user_proto_rawDescGZIP(), []int{0} 67 | } 68 | 69 | func (x *User) GetId() string { 70 | if x != nil { 71 | return x.Id 72 | } 73 | return "" 74 | } 75 | 76 | func (x *User) GetName() string { 77 | if x != nil { 78 | return x.Name 79 | } 80 | return "" 81 | } 82 | 83 | func (x *User) GetEmail() string { 84 | if x != nil { 85 | return x.Email 86 | } 87 | return "" 88 | } 89 | 90 | func (x *User) GetRole() string { 91 | if x != nil { 92 | return x.Role 93 | } 94 | return "" 95 | } 96 | 97 | func (x *User) GetCreatedAt() *timestamppb.Timestamp { 98 | if x != nil { 99 | return x.CreatedAt 100 | } 101 | return nil 102 | } 103 | 104 | func (x *User) GetUpdatedAt() *timestamppb.Timestamp { 105 | if x != nil { 106 | return x.UpdatedAt 107 | } 108 | return nil 109 | } 110 | 111 | type UserResponse struct { 112 | state protoimpl.MessageState 113 | sizeCache protoimpl.SizeCache 114 | unknownFields protoimpl.UnknownFields 115 | 116 | User *User `protobuf:"bytes,1,opt,name=user,proto3" json:"user,omitempty"` 117 | } 118 | 119 | func (x *UserResponse) Reset() { 120 | *x = UserResponse{} 121 | if protoimpl.UnsafeEnabled { 122 | mi := &file_user_proto_msgTypes[1] 123 | ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) 124 | ms.StoreMessageInfo(mi) 125 | } 126 | } 127 | 128 | func (x *UserResponse) String() string { 129 | return protoimpl.X.MessageStringOf(x) 130 | } 131 | 132 | func (*UserResponse) ProtoMessage() {} 133 | 134 | func (x *UserResponse) ProtoReflect() protoreflect.Message { 135 | mi := &file_user_proto_msgTypes[1] 136 | if protoimpl.UnsafeEnabled && x != nil { 137 | ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) 138 | if ms.LoadMessageInfo() == nil { 139 | ms.StoreMessageInfo(mi) 140 | } 141 | return ms 142 | } 143 | return mi.MessageOf(x) 144 | } 145 | 146 | // Deprecated: Use UserResponse.ProtoReflect.Descriptor instead. 147 | func (*UserResponse) Descriptor() ([]byte, []int) { 148 | return file_user_proto_rawDescGZIP(), []int{1} 149 | } 150 | 151 | func (x *UserResponse) GetUser() *User { 152 | if x != nil { 153 | return x.User 154 | } 155 | return nil 156 | } 157 | 158 | type GenericResponse struct { 159 | state protoimpl.MessageState 160 | sizeCache protoimpl.SizeCache 161 | unknownFields protoimpl.UnknownFields 162 | 163 | Status string `protobuf:"bytes,1,opt,name=status,proto3" json:"status,omitempty"` 164 | Message string `protobuf:"bytes,2,opt,name=message,proto3" json:"message,omitempty"` 165 | } 166 | 167 | func (x *GenericResponse) Reset() { 168 | *x = GenericResponse{} 169 | if protoimpl.UnsafeEnabled { 170 | mi := &file_user_proto_msgTypes[2] 171 | ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) 172 | ms.StoreMessageInfo(mi) 173 | } 174 | } 175 | 176 | func (x *GenericResponse) String() string { 177 | return protoimpl.X.MessageStringOf(x) 178 | } 179 | 180 | func (*GenericResponse) ProtoMessage() {} 181 | 182 | func (x *GenericResponse) ProtoReflect() protoreflect.Message { 183 | mi := &file_user_proto_msgTypes[2] 184 | if protoimpl.UnsafeEnabled && x != nil { 185 | ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) 186 | if ms.LoadMessageInfo() == nil { 187 | ms.StoreMessageInfo(mi) 188 | } 189 | return ms 190 | } 191 | return mi.MessageOf(x) 192 | } 193 | 194 | // Deprecated: Use GenericResponse.ProtoReflect.Descriptor instead. 195 | func (*GenericResponse) Descriptor() ([]byte, []int) { 196 | return file_user_proto_rawDescGZIP(), []int{2} 197 | } 198 | 199 | func (x *GenericResponse) GetStatus() string { 200 | if x != nil { 201 | return x.Status 202 | } 203 | return "" 204 | } 205 | 206 | func (x *GenericResponse) GetMessage() string { 207 | if x != nil { 208 | return x.Message 209 | } 210 | return "" 211 | } 212 | 213 | var File_user_proto protoreflect.FileDescriptor 214 | 215 | var file_user_proto_rawDesc = []byte{ 216 | 0x0a, 0x0a, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x02, 0x70, 0x62, 217 | 0x1a, 0x1f, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 218 | 0x66, 0x2f, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x2e, 0x70, 0x72, 0x6f, 0x74, 219 | 0x6f, 0x22, 0xca, 0x01, 0x0a, 0x04, 0x55, 0x73, 0x65, 0x72, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 220 | 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 221 | 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x14, 222 | 0x0a, 0x05, 0x65, 0x6d, 0x61, 0x69, 0x6c, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x65, 223 | 0x6d, 0x61, 0x69, 0x6c, 0x12, 0x12, 0x0a, 0x04, 0x72, 0x6f, 0x6c, 0x65, 0x18, 0x04, 0x20, 0x01, 224 | 0x28, 0x09, 0x52, 0x04, 0x72, 0x6f, 0x6c, 0x65, 0x12, 0x39, 0x0a, 0x0a, 0x63, 0x72, 0x65, 0x61, 225 | 0x74, 0x65, 0x64, 0x5f, 0x61, 0x74, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 226 | 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 227 | 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x09, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 228 | 0x64, 0x41, 0x74, 0x12, 0x39, 0x0a, 0x0a, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x64, 0x5f, 0x61, 229 | 0x74, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 230 | 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 231 | 0x61, 0x6d, 0x70, 0x52, 0x09, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x64, 0x41, 0x74, 0x22, 0x2c, 232 | 0x0a, 0x0c, 0x55, 0x73, 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x1c, 233 | 0x0a, 0x04, 0x75, 0x73, 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x08, 0x2e, 0x70, 234 | 0x62, 0x2e, 0x55, 0x73, 0x65, 0x72, 0x52, 0x04, 0x75, 0x73, 0x65, 0x72, 0x22, 0x43, 0x0a, 0x0f, 235 | 0x47, 0x65, 0x6e, 0x65, 0x72, 0x69, 0x63, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 236 | 0x16, 0x0a, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 237 | 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x18, 0x0a, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 238 | 0x67, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 239 | 0x65, 0x42, 0x27, 0x5a, 0x25, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 240 | 0x77, 0x70, 0x63, 0x6f, 0x64, 0x65, 0x76, 0x6f, 0x2f, 0x67, 0x6f, 0x6c, 0x61, 0x6e, 0x67, 0x2d, 241 | 0x6d, 0x6f, 0x6e, 0x67, 0x6f, 0x64, 0x62, 0x2f, 0x70, 0x62, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 242 | 0x6f, 0x33, 243 | } 244 | 245 | var ( 246 | file_user_proto_rawDescOnce sync.Once 247 | file_user_proto_rawDescData = file_user_proto_rawDesc 248 | ) 249 | 250 | func file_user_proto_rawDescGZIP() []byte { 251 | file_user_proto_rawDescOnce.Do(func() { 252 | file_user_proto_rawDescData = protoimpl.X.CompressGZIP(file_user_proto_rawDescData) 253 | }) 254 | return file_user_proto_rawDescData 255 | } 256 | 257 | var file_user_proto_msgTypes = make([]protoimpl.MessageInfo, 3) 258 | var file_user_proto_goTypes = []interface{}{ 259 | (*User)(nil), // 0: pb.User 260 | (*UserResponse)(nil), // 1: pb.UserResponse 261 | (*GenericResponse)(nil), // 2: pb.GenericResponse 262 | (*timestamppb.Timestamp)(nil), // 3: google.protobuf.Timestamp 263 | } 264 | var file_user_proto_depIdxs = []int32{ 265 | 3, // 0: pb.User.created_at:type_name -> google.protobuf.Timestamp 266 | 3, // 1: pb.User.updated_at:type_name -> google.protobuf.Timestamp 267 | 0, // 2: pb.UserResponse.user:type_name -> pb.User 268 | 3, // [3:3] is the sub-list for method output_type 269 | 3, // [3:3] is the sub-list for method input_type 270 | 3, // [3:3] is the sub-list for extension type_name 271 | 3, // [3:3] is the sub-list for extension extendee 272 | 0, // [0:3] is the sub-list for field type_name 273 | } 274 | 275 | func init() { file_user_proto_init() } 276 | func file_user_proto_init() { 277 | if File_user_proto != nil { 278 | return 279 | } 280 | if !protoimpl.UnsafeEnabled { 281 | file_user_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { 282 | switch v := v.(*User); i { 283 | case 0: 284 | return &v.state 285 | case 1: 286 | return &v.sizeCache 287 | case 2: 288 | return &v.unknownFields 289 | default: 290 | return nil 291 | } 292 | } 293 | file_user_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { 294 | switch v := v.(*UserResponse); i { 295 | case 0: 296 | return &v.state 297 | case 1: 298 | return &v.sizeCache 299 | case 2: 300 | return &v.unknownFields 301 | default: 302 | return nil 303 | } 304 | } 305 | file_user_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} { 306 | switch v := v.(*GenericResponse); i { 307 | case 0: 308 | return &v.state 309 | case 1: 310 | return &v.sizeCache 311 | case 2: 312 | return &v.unknownFields 313 | default: 314 | return nil 315 | } 316 | } 317 | } 318 | type x struct{} 319 | out := protoimpl.TypeBuilder{ 320 | File: protoimpl.DescBuilder{ 321 | GoPackagePath: reflect.TypeOf(x{}).PkgPath(), 322 | RawDescriptor: file_user_proto_rawDesc, 323 | NumEnums: 0, 324 | NumMessages: 3, 325 | NumExtensions: 0, 326 | NumServices: 0, 327 | }, 328 | GoTypes: file_user_proto_goTypes, 329 | DependencyIndexes: file_user_proto_depIdxs, 330 | MessageInfos: file_user_proto_msgTypes, 331 | }.Build() 332 | File_user_proto = out.File 333 | file_user_proto_rawDesc = nil 334 | file_user_proto_goTypes = nil 335 | file_user_proto_depIdxs = nil 336 | } 337 | -------------------------------------------------------------------------------- /pb/post_service.pb.go: -------------------------------------------------------------------------------- 1 | // Code generated by protoc-gen-go. DO NOT EDIT. 2 | // versions: 3 | // protoc-gen-go v1.28.0 4 | // protoc v3.20.1 5 | // source: post_service.proto 6 | 7 | package pb 8 | 9 | import ( 10 | protoreflect "google.golang.org/protobuf/reflect/protoreflect" 11 | protoimpl "google.golang.org/protobuf/runtime/protoimpl" 12 | reflect "reflect" 13 | sync "sync" 14 | ) 15 | 16 | const ( 17 | // Verify that this generated code is sufficiently up-to-date. 18 | _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) 19 | // Verify that runtime/protoimpl is sufficiently up-to-date. 20 | _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) 21 | ) 22 | 23 | type GetPostsRequest struct { 24 | state protoimpl.MessageState 25 | sizeCache protoimpl.SizeCache 26 | unknownFields protoimpl.UnknownFields 27 | 28 | Page *int64 `protobuf:"varint,1,opt,name=page,proto3,oneof" json:"page,omitempty"` 29 | Limit *int64 `protobuf:"varint,2,opt,name=limit,proto3,oneof" json:"limit,omitempty"` 30 | } 31 | 32 | func (x *GetPostsRequest) Reset() { 33 | *x = GetPostsRequest{} 34 | if protoimpl.UnsafeEnabled { 35 | mi := &file_post_service_proto_msgTypes[0] 36 | ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) 37 | ms.StoreMessageInfo(mi) 38 | } 39 | } 40 | 41 | func (x *GetPostsRequest) String() string { 42 | return protoimpl.X.MessageStringOf(x) 43 | } 44 | 45 | func (*GetPostsRequest) ProtoMessage() {} 46 | 47 | func (x *GetPostsRequest) ProtoReflect() protoreflect.Message { 48 | mi := &file_post_service_proto_msgTypes[0] 49 | if protoimpl.UnsafeEnabled && x != nil { 50 | ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) 51 | if ms.LoadMessageInfo() == nil { 52 | ms.StoreMessageInfo(mi) 53 | } 54 | return ms 55 | } 56 | return mi.MessageOf(x) 57 | } 58 | 59 | // Deprecated: Use GetPostsRequest.ProtoReflect.Descriptor instead. 60 | func (*GetPostsRequest) Descriptor() ([]byte, []int) { 61 | return file_post_service_proto_rawDescGZIP(), []int{0} 62 | } 63 | 64 | func (x *GetPostsRequest) GetPage() int64 { 65 | if x != nil && x.Page != nil { 66 | return *x.Page 67 | } 68 | return 0 69 | } 70 | 71 | func (x *GetPostsRequest) GetLimit() int64 { 72 | if x != nil && x.Limit != nil { 73 | return *x.Limit 74 | } 75 | return 0 76 | } 77 | 78 | type PostRequest struct { 79 | state protoimpl.MessageState 80 | sizeCache protoimpl.SizeCache 81 | unknownFields protoimpl.UnknownFields 82 | 83 | Id string `protobuf:"bytes,1,opt,name=Id,proto3" json:"Id,omitempty"` 84 | } 85 | 86 | func (x *PostRequest) Reset() { 87 | *x = PostRequest{} 88 | if protoimpl.UnsafeEnabled { 89 | mi := &file_post_service_proto_msgTypes[1] 90 | ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) 91 | ms.StoreMessageInfo(mi) 92 | } 93 | } 94 | 95 | func (x *PostRequest) String() string { 96 | return protoimpl.X.MessageStringOf(x) 97 | } 98 | 99 | func (*PostRequest) ProtoMessage() {} 100 | 101 | func (x *PostRequest) ProtoReflect() protoreflect.Message { 102 | mi := &file_post_service_proto_msgTypes[1] 103 | if protoimpl.UnsafeEnabled && x != nil { 104 | ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) 105 | if ms.LoadMessageInfo() == nil { 106 | ms.StoreMessageInfo(mi) 107 | } 108 | return ms 109 | } 110 | return mi.MessageOf(x) 111 | } 112 | 113 | // Deprecated: Use PostRequest.ProtoReflect.Descriptor instead. 114 | func (*PostRequest) Descriptor() ([]byte, []int) { 115 | return file_post_service_proto_rawDescGZIP(), []int{1} 116 | } 117 | 118 | func (x *PostRequest) GetId() string { 119 | if x != nil { 120 | return x.Id 121 | } 122 | return "" 123 | } 124 | 125 | type DeletePostResponse struct { 126 | state protoimpl.MessageState 127 | sizeCache protoimpl.SizeCache 128 | unknownFields protoimpl.UnknownFields 129 | 130 | Success bool `protobuf:"varint,1,opt,name=success,proto3" json:"success,omitempty"` 131 | } 132 | 133 | func (x *DeletePostResponse) Reset() { 134 | *x = DeletePostResponse{} 135 | if protoimpl.UnsafeEnabled { 136 | mi := &file_post_service_proto_msgTypes[2] 137 | ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) 138 | ms.StoreMessageInfo(mi) 139 | } 140 | } 141 | 142 | func (x *DeletePostResponse) String() string { 143 | return protoimpl.X.MessageStringOf(x) 144 | } 145 | 146 | func (*DeletePostResponse) ProtoMessage() {} 147 | 148 | func (x *DeletePostResponse) ProtoReflect() protoreflect.Message { 149 | mi := &file_post_service_proto_msgTypes[2] 150 | if protoimpl.UnsafeEnabled && x != nil { 151 | ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) 152 | if ms.LoadMessageInfo() == nil { 153 | ms.StoreMessageInfo(mi) 154 | } 155 | return ms 156 | } 157 | return mi.MessageOf(x) 158 | } 159 | 160 | // Deprecated: Use DeletePostResponse.ProtoReflect.Descriptor instead. 161 | func (*DeletePostResponse) Descriptor() ([]byte, []int) { 162 | return file_post_service_proto_rawDescGZIP(), []int{2} 163 | } 164 | 165 | func (x *DeletePostResponse) GetSuccess() bool { 166 | if x != nil { 167 | return x.Success 168 | } 169 | return false 170 | } 171 | 172 | var File_post_service_proto protoreflect.FileDescriptor 173 | 174 | var file_post_service_proto_rawDesc = []byte{ 175 | 0x0a, 0x12, 0x70, 0x6f, 0x73, 0x74, 0x5f, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x70, 176 | 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x02, 0x70, 0x62, 0x1a, 0x0a, 0x70, 0x6f, 0x73, 0x74, 0x2e, 0x70, 177 | 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x15, 0x72, 0x70, 0x63, 0x5f, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 178 | 0x5f, 0x70, 0x6f, 0x73, 0x74, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x15, 0x72, 0x70, 0x63, 179 | 0x5f, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x5f, 0x70, 0x6f, 0x73, 0x74, 0x2e, 0x70, 0x72, 0x6f, 180 | 0x74, 0x6f, 0x22, 0x58, 0x0a, 0x0f, 0x47, 0x65, 0x74, 0x50, 0x6f, 0x73, 0x74, 0x73, 0x52, 0x65, 181 | 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x17, 0x0a, 0x04, 0x70, 0x61, 0x67, 0x65, 0x18, 0x01, 0x20, 182 | 0x01, 0x28, 0x03, 0x48, 0x00, 0x52, 0x04, 0x70, 0x61, 0x67, 0x65, 0x88, 0x01, 0x01, 0x12, 0x19, 183 | 0x0a, 0x05, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x48, 0x01, 0x52, 184 | 0x05, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x88, 0x01, 0x01, 0x42, 0x07, 0x0a, 0x05, 0x5f, 0x70, 0x61, 185 | 0x67, 0x65, 0x42, 0x08, 0x0a, 0x06, 0x5f, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x22, 0x1d, 0x0a, 0x0b, 186 | 0x50, 0x6f, 0x73, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x0e, 0x0a, 0x02, 0x49, 187 | 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x49, 0x64, 0x22, 0x2e, 0x0a, 0x12, 0x44, 188 | 0x65, 0x6c, 0x65, 0x74, 0x65, 0x50, 0x6f, 0x73, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 189 | 0x65, 0x12, 0x18, 0x0a, 0x07, 0x73, 0x75, 0x63, 0x63, 0x65, 0x73, 0x73, 0x18, 0x01, 0x20, 0x01, 190 | 0x28, 0x08, 0x52, 0x07, 0x73, 0x75, 0x63, 0x63, 0x65, 0x73, 0x73, 0x32, 0x97, 0x02, 0x0a, 0x0b, 191 | 0x50, 0x6f, 0x73, 0x74, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x37, 0x0a, 0x0a, 0x43, 192 | 0x72, 0x65, 0x61, 0x74, 0x65, 0x50, 0x6f, 0x73, 0x74, 0x12, 0x15, 0x2e, 0x70, 0x62, 0x2e, 0x43, 193 | 0x72, 0x65, 0x61, 0x74, 0x65, 0x50, 0x6f, 0x73, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 194 | 0x1a, 0x10, 0x2e, 0x70, 0x62, 0x2e, 0x50, 0x6f, 0x73, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 195 | 0x73, 0x65, 0x22, 0x00, 0x12, 0x2e, 0x0a, 0x07, 0x47, 0x65, 0x74, 0x50, 0x6f, 0x73, 0x74, 0x12, 196 | 0x0f, 0x2e, 0x70, 0x62, 0x2e, 0x50, 0x6f, 0x73, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 197 | 0x1a, 0x10, 0x2e, 0x70, 0x62, 0x2e, 0x50, 0x6f, 0x73, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 198 | 0x73, 0x65, 0x22, 0x00, 0x12, 0x2d, 0x0a, 0x08, 0x47, 0x65, 0x74, 0x50, 0x6f, 0x73, 0x74, 0x73, 199 | 0x12, 0x13, 0x2e, 0x70, 0x62, 0x2e, 0x47, 0x65, 0x74, 0x50, 0x6f, 0x73, 0x74, 0x73, 0x52, 0x65, 200 | 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x08, 0x2e, 0x70, 0x62, 0x2e, 0x50, 0x6f, 0x73, 0x74, 0x22, 201 | 0x00, 0x30, 0x01, 0x12, 0x37, 0x0a, 0x0a, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x50, 0x6f, 0x73, 202 | 0x74, 0x12, 0x15, 0x2e, 0x70, 0x62, 0x2e, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x50, 0x6f, 0x73, 203 | 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x10, 0x2e, 0x70, 0x62, 0x2e, 0x50, 0x6f, 204 | 0x73, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x37, 0x0a, 0x0a, 205 | 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x50, 0x6f, 0x73, 0x74, 0x12, 0x0f, 0x2e, 0x70, 0x62, 0x2e, 206 | 0x50, 0x6f, 0x73, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x16, 0x2e, 0x70, 0x62, 207 | 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x50, 0x6f, 0x73, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 208 | 0x6e, 0x73, 0x65, 0x22, 0x00, 0x42, 0x27, 0x5a, 0x25, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 209 | 0x63, 0x6f, 0x6d, 0x2f, 0x77, 0x70, 0x63, 0x6f, 0x64, 0x65, 0x76, 0x6f, 0x2f, 0x67, 0x6f, 0x6c, 210 | 0x61, 0x6e, 0x67, 0x2d, 0x6d, 0x6f, 0x6e, 0x67, 0x6f, 0x64, 0x62, 0x2f, 0x70, 0x62, 0x62, 0x06, 211 | 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, 212 | } 213 | 214 | var ( 215 | file_post_service_proto_rawDescOnce sync.Once 216 | file_post_service_proto_rawDescData = file_post_service_proto_rawDesc 217 | ) 218 | 219 | func file_post_service_proto_rawDescGZIP() []byte { 220 | file_post_service_proto_rawDescOnce.Do(func() { 221 | file_post_service_proto_rawDescData = protoimpl.X.CompressGZIP(file_post_service_proto_rawDescData) 222 | }) 223 | return file_post_service_proto_rawDescData 224 | } 225 | 226 | var file_post_service_proto_msgTypes = make([]protoimpl.MessageInfo, 3) 227 | var file_post_service_proto_goTypes = []interface{}{ 228 | (*GetPostsRequest)(nil), // 0: pb.GetPostsRequest 229 | (*PostRequest)(nil), // 1: pb.PostRequest 230 | (*DeletePostResponse)(nil), // 2: pb.DeletePostResponse 231 | (*CreatePostRequest)(nil), // 3: pb.CreatePostRequest 232 | (*UpdatePostRequest)(nil), // 4: pb.UpdatePostRequest 233 | (*PostResponse)(nil), // 5: pb.PostResponse 234 | (*Post)(nil), // 6: pb.Post 235 | } 236 | var file_post_service_proto_depIdxs = []int32{ 237 | 3, // 0: pb.PostService.CreatePost:input_type -> pb.CreatePostRequest 238 | 1, // 1: pb.PostService.GetPost:input_type -> pb.PostRequest 239 | 0, // 2: pb.PostService.GetPosts:input_type -> pb.GetPostsRequest 240 | 4, // 3: pb.PostService.UpdatePost:input_type -> pb.UpdatePostRequest 241 | 1, // 4: pb.PostService.DeletePost:input_type -> pb.PostRequest 242 | 5, // 5: pb.PostService.CreatePost:output_type -> pb.PostResponse 243 | 5, // 6: pb.PostService.GetPost:output_type -> pb.PostResponse 244 | 6, // 7: pb.PostService.GetPosts:output_type -> pb.Post 245 | 5, // 8: pb.PostService.UpdatePost:output_type -> pb.PostResponse 246 | 2, // 9: pb.PostService.DeletePost:output_type -> pb.DeletePostResponse 247 | 5, // [5:10] is the sub-list for method output_type 248 | 0, // [0:5] is the sub-list for method input_type 249 | 0, // [0:0] is the sub-list for extension type_name 250 | 0, // [0:0] is the sub-list for extension extendee 251 | 0, // [0:0] is the sub-list for field type_name 252 | } 253 | 254 | func init() { file_post_service_proto_init() } 255 | func file_post_service_proto_init() { 256 | if File_post_service_proto != nil { 257 | return 258 | } 259 | file_post_proto_init() 260 | file_rpc_create_post_proto_init() 261 | file_rpc_update_post_proto_init() 262 | if !protoimpl.UnsafeEnabled { 263 | file_post_service_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { 264 | switch v := v.(*GetPostsRequest); i { 265 | case 0: 266 | return &v.state 267 | case 1: 268 | return &v.sizeCache 269 | case 2: 270 | return &v.unknownFields 271 | default: 272 | return nil 273 | } 274 | } 275 | file_post_service_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { 276 | switch v := v.(*PostRequest); i { 277 | case 0: 278 | return &v.state 279 | case 1: 280 | return &v.sizeCache 281 | case 2: 282 | return &v.unknownFields 283 | default: 284 | return nil 285 | } 286 | } 287 | file_post_service_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} { 288 | switch v := v.(*DeletePostResponse); i { 289 | case 0: 290 | return &v.state 291 | case 1: 292 | return &v.sizeCache 293 | case 2: 294 | return &v.unknownFields 295 | default: 296 | return nil 297 | } 298 | } 299 | } 300 | file_post_service_proto_msgTypes[0].OneofWrappers = []interface{}{} 301 | type x struct{} 302 | out := protoimpl.TypeBuilder{ 303 | File: protoimpl.DescBuilder{ 304 | GoPackagePath: reflect.TypeOf(x{}).PkgPath(), 305 | RawDescriptor: file_post_service_proto_rawDesc, 306 | NumEnums: 0, 307 | NumMessages: 3, 308 | NumExtensions: 0, 309 | NumServices: 1, 310 | }, 311 | GoTypes: file_post_service_proto_goTypes, 312 | DependencyIndexes: file_post_service_proto_depIdxs, 313 | MessageInfos: file_post_service_proto_msgTypes, 314 | }.Build() 315 | File_post_service_proto = out.File 316 | file_post_service_proto_rawDesc = nil 317 | file_post_service_proto_goTypes = nil 318 | file_post_service_proto_depIdxs = nil 319 | } 320 | --------------------------------------------------------------------------------