diff --git a/CHANGELOG b/CHANGELOG new file mode 100644 index 0000000..4cc48bc --- /dev/null +++ b/CHANGELOG @@ -0,0 +1,75 @@ +# Changelog + +All notable changes to this project will be documented in this file. + +The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), +and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). + +--- + +## [0.0.8] - 2023-10-17 (CHB-11) + +### Added + +- Added CORS permissions so local Angular can connect to local Go by [Arturo Vial](https://github.com/ratolibre1) + +## [0.0.7] - 2023-10-17 (CHB-9) + +### Added + +- Added new endpoint to get full list of chatrooms by [Arturo Vial](https://github.com/ratolibre1) + +## [0.0.6] - 2023-10-17 (CHB-7) + +### Added + +- Added new endpoints to validate login details and return a JWT token by [Arturo Vial](https://github.com/ratolibre1) +- Added Auth module by [Arturo Vial](https://github.com/ratolibre1) +- Added functions to find users by email, hash and validate passwords by [Arturo Vial](https://github.com/ratolibre1) + +## [0.0.5] - 2023-10-16 (CHB-6) + +### Added + +- Added new endpoints to enter and leave chatrooms by [Arturo Vial](https://github.com/ratolibre1) +- Added Chatrooms and Users modules by [Arturo Vial](https://github.com/ratolibre1) + +### Changed + +- Cleaned some English errors in original project by [Arturo Vial](https://github.com/ratolibre1) + +### Removed + +- Removed some calls to original User package (to be removed in the future) by [Arturo Vial](https://github.com/ratolibre1) + +## [0.0.4] - 2023-10-15 (CHB-3) + +### Added + +- Sending a command-like message gets its own workflow instead of storing it by [Arturo Vial](https://github.com/ratolibre1) + +### Changed + +- Renamed the module to "chat-hex" by [Arturo Vial](https://github.com/ratolibre1) + +## [0.0.3] - 2023-10-15 (CHB-2) + +### Added + +- Added new endpoint to list messages from a specific chatroom by [Arturo Vial](https://github.com/ratolibre1) + +## [0.0.2] - 2023-10-14 (CHB-1) + +### Added + +- Added Messages folders and endpoint to send a message by [Arturo Vial](https://github.com/ratolibre1) + +## [0.0.1] - 2023-10-14 + +### Added + +- Hexagonal Architecture scaffolding forked from [Github](https://github.com/favians/go-hexagonal) by [Arturo Vial](https://github.com/ratolibre1) + +### Changed + +- Cleaned some stuff, ensured connection with DB by [Arturo Vial](https://github.com/ratolibre1) diff --git a/README.md b/README.md index 0ca8cc6..727225b 100644 --- a/README.md +++ b/README.md @@ -1,55 +1,11 @@ -# Sample Golang API Server - -Sample REST API build using echo server. - -The code implementation was inspired by port and adapter pattern or known as [hexagonal](blog.octo.com/en/hexagonal-architecture-three-principles-and-an-implementation-example): - -- **Business**
Contains all the logic in domain business. Also called this as a service. All the interface of repository needed and the implementation of the service itself will be put here. -- **Modules**
Contains implementation of interfaces that defined at the business (also called as server-side adapters in hexagonal's term) -- **API**
API http handler or controller (also called user-side adapters in hexagonal's term) - -# Data initialization - -To describe about how port and adapter interaction (separation concerned), this example will have two databases supported. There are MySQL and MongoDB. - -MongoDB will become a default databaese in this example. If you want to change into MySQL, update the configuration inside -[config.yaml](https://raw.githubusercontent.com/muhsinshodiq/golang-sample-api/master/config/config.yaml) file. - ### MongoDB -Please execute script below to create a new collection called `items` including the index needed +Please execute script below to create the collections required to run the app ```mongodb -db.createCollection('items'); -db.items.createIndex({"tags": 1}); -db.items.createIndex({"modified_at": 1, "_id": 1}); -``` - -### MySQL - -Please execute script below to create `item` and `item_tag` table in your database - -```sql -CREATE TABLE `item` ( - `id` varchar(24) NOT NULL DEFAULT '', - `name` text NOT NULL, - `description` text NOT NULL, - `created_at` datetime NOT NULL, - `created_by` varchar(50) NOT NULL DEFAULT '', - `modified_at` datetime NOT NULL, - `modified_by` varchar(50) NOT NULL DEFAULT '', - `version` int(11) NOT NULL DEFAULT '1', - PRIMARY KEY (`id`), - KEY `modified_at` (`modified_at`,`id`) -) ENGINE=InnoDB DEFAULT CHARSET=latin1; - -CREATE TABLE `item_tag` ( - `item_id` varchar(24) NOT NULL DEFAULT '', - `tag` varchar(50) NOT NULL DEFAULT '', - PRIMARY KEY (`item_id`,`tag`), - KEY `tag` (`tag`), - CONSTRAINT `item_tag_ibfk_1` FOREIGN KEY (`item_id`) REFERENCES `item` (`id`) ON DELETE CASCADE ON UPDATE CASCADE -) ENGINE=InnoDB DEFAULT CHARSET=latin1; +db.createCollection('users'); +db.createCollection('messages'); +db.createCollection('chatrooms'); ``` # How To Run Server @@ -59,14 +15,3 @@ Just execute code below in your console ```console ./run.sh ``` - -# How To Consume The API - -There are 4 availables API that ready to use: - -- GET `/v1/items/:id` -- GET `/v1/items/[tag-name]` -- POST `/v1/items` -- PUT `/v1/items` - -To make it easier please download [Insomnia Core](https://insomnia.rest) app and import [this collection](https://raw.githubusercontent.com/muhsinshodiq/golang-sample-api/master/insomnia.json). diff --git a/api/common/error_business_response.go b/api/common/error_business_response.go index 3974228..cb03823 100644 --- a/api/common/error_business_response.go +++ b/api/common/error_business_response.go @@ -1,7 +1,7 @@ package common import ( - "go-hexagonal/business" + "chat-hex/business" "net/http" ) @@ -12,6 +12,7 @@ const ( errHasBeenModified errorBusinessResponseCode = "data_has_been modified" errNotFound errorBusinessResponseCode = "data_not_found" errInvalidSpec errorBusinessResponseCode = "invalid_spec" + ErrInvalidCommand errorBusinessResponseCode = "invalid_command" ) //BusinessResponse default payload response @@ -21,7 +22,7 @@ type BusinessResponse struct { Data interface{} `json:"data"` } -//NewErrorBusinessResponse Response return choosen http status like 400 bad request 422 unprocessable entity, ETC, based on responseCode +//NewErrorBusinessResponse Response return chosen http status like 400 bad request 422 unprocessable entity, ETC, based on responseCode func NewErrorBusinessResponse(err error) (int, BusinessResponse) { return errorMapping(err) } @@ -35,8 +36,10 @@ func errorMapping(err error) (int, BusinessResponse) { return newNotFoundResponse() case business.ErrInvalidSpec: return newValidationResponse(err.Error()) + case business.ErrInvalidCommand: + return newValidationResponse(err.Error()) case business.ErrHasBeenModified: - return newHasBeedModifiedResponse() + return newHasBeenModifiedResponse() } } @@ -49,8 +52,8 @@ func newInternalServerErrorResponse() (int, BusinessResponse) { } } -//newHasBeedModifiedResponse failed to validate request payload -func newHasBeedModifiedResponse() (int, BusinessResponse) { +//newHasBeenModifiedResponse failed to validate request payload +func newHasBeenModifiedResponse() (int, BusinessResponse) { return http.StatusBadRequest, BusinessResponse{ errHasBeenModified, "Data has been modified", diff --git a/api/insomnia.json b/api/insomnia.json deleted file mode 100644 index bb269cd..0000000 --- a/api/insomnia.json +++ /dev/null @@ -1 +0,0 @@ -{"_type":"export","__export_format":4,"__export_date":"2020-08-21T02:47:11.306Z","__export_source":"insomnia.desktop.app:v2020.3.3","resources":[{"_id":"req_1c9b323b350c4e7686691fec9a1c704a","authentication":{},"body":{},"created":1597464771713,"description":"","headers":[],"isPrivate":false,"metaSortKey":-1597464771714,"method":"GET","modified":1597977851048,"name":"Get Item By ID","parameters":[],"parentId":"fld_689377616fa049498b9dcaf20772b9e1","settingDisableRenderRequestBody":false,"settingEncodeUrl":true,"settingFollowRedirects":"global","settingRebuildPath":true,"settingSendCookies":true,"settingStoreCookies":true,"url":"{{ ITEM_TEST_HOST }}/v1/items/5f3f34f77611be3eb089e266","_type":"request"},{"_id":"fld_689377616fa049498b9dcaf20772b9e1","created":1597464693939,"description":"","environment":{},"environmentPropertyOrder":null,"metaSortKey":-1597464693939,"modified":1597978012668,"name":"Golang Sample API","parentId":"wrk_6fb5cf0f746044b2bdfe8bba6ba2ef73","_type":"request_group"},{"_id":"wrk_6fb5cf0f746044b2bdfe8bba6ba2ef73","created":1597464672977,"description":"","modified":1597464672977,"name":"Playground","parentId":null,"scope":null,"_type":"workspace"},{"_id":"req_f41a666217ea4bb2919066f9077f1618","authentication":{},"body":{},"created":1597464962599,"description":"","headers":[],"isPrivate":false,"metaSortKey":-1596770774963,"method":"GET","modified":1597486085313,"name":"Find Items By Tag","parameters":[],"parentId":"fld_689377616fa049498b9dcaf20772b9e1","settingDisableRenderRequestBody":false,"settingEncodeUrl":true,"settingFollowRedirects":"global","settingRebuildPath":true,"settingSendCookies":true,"settingStoreCookies":true,"url":"{{ ITEM_TEST_HOST }}/v1/items/tag/tag99","_type":"request"},{"_id":"req_713c323624964879a174a70a8fb0771f","authentication":{},"body":{"mimeType":"application/json","text":"{\n\t\"name\": \"New item\",\n\t\"description\": \"new\",\n\t\"tags\": []\n}"},"created":1597467138311,"description":"","headers":[{"id":"pair_0afa504b87d1493388d95ff4a4279953","name":"Content-Type","value":"application/json"}],"isPrivate":false,"metaSortKey":-1596423776587.5,"method":"POST","modified":1597467404785,"name":"Create New Item","parameters":[],"parentId":"fld_689377616fa049498b9dcaf20772b9e1","settingDisableRenderRequestBody":false,"settingEncodeUrl":true,"settingFollowRedirects":"global","settingRebuildPath":true,"settingSendCookies":true,"settingStoreCookies":true,"url":"{{ ITEM_TEST_HOST }}/v1/items","_type":"request"},{"_id":"req_504bc4a0d77a481c893169b7448025f7","authentication":{},"body":{"mimeType":"application/json","text":"{\n\t\"name\": \"New Item (updated2)\",\n\t\"description\": \"Description (updated)\",\n\t\"tags\": [\"tag99\"],\n\t\"version\": 1\n}"},"created":1597471472348,"description":"","headers":[{"id":"pair_0afa504b87d1493388d95ff4a4279953","name":"Content-Type","value":"application/json"}],"isPrivate":false,"metaSortKey":-1596250277399.75,"method":"PUT","modified":1597977860143,"name":"Update Item","parameters":[],"parentId":"fld_689377616fa049498b9dcaf20772b9e1","settingDisableRenderRequestBody":false,"settingEncodeUrl":true,"settingFollowRedirects":"global","settingRebuildPath":true,"settingSendCookies":true,"settingStoreCookies":true,"url":"{{ ITEM_TEST_HOST }}/v1/items/5f3f34f77611be3eb089e266","_type":"request"},{"_id":"env_78c71dbf04e35be6defe8946da09238e9868f15e","color":null,"created":1597464673272,"data":{"ITEM_TEST_HOST":"http://localhost:1323"},"dataPropertyOrder":{"&":["ITEM_TEST_HOST"]},"isPrivate":false,"metaSortKey":1597464673272,"modified":1597464735914,"name":"Base Environment","parentId":"wrk_6fb5cf0f746044b2bdfe8bba6ba2ef73","_type":"environment"},{"_id":"jar_78c71dbf04e35be6defe8946da09238e9868f15e","cookies":[],"created":1597464673277,"modified":1597464673277,"name":"Default Jar","parentId":"wrk_6fb5cf0f746044b2bdfe8bba6ba2ef73","_type":"cookie_jar"},{"_id":"spc_0200e9dc6d41429c82ff51946f56442c","contentType":"yaml","contents":"","created":1597464673003,"fileName":"Playground","modified":1597464673003,"parentId":"wrk_6fb5cf0f746044b2bdfe8bba6ba2ef73","_type":"api_spec"}]} \ No newline at end of file diff --git a/api/router.go b/api/router.go index ec8be04..7499980 100644 --- a/api/router.go +++ b/api/router.go @@ -1,23 +1,46 @@ package api import ( - "go-hexagonal/api/v1/user" + "chat-hex/api/v1/auth" + "chat-hex/api/v1/chatrooms" + "chat-hex/api/v1/messages" + "chat-hex/api/v1/users" + "chat-hex/middlewares" echo "github.com/labstack/echo/v4" ) -//RegisterPath Register all V1 API with routing path -func RegisterPath(e *echo.Echo, userController *user.Controller) { - if userController == nil { - panic("user controller cannot be nil") +//RegisterPaths Register all V1 API with routing path +func RegisterPaths(e *echo.Echo, authController *auth.Controller, usersController *users.Controller, chatroomsController *chatrooms.Controller, messagesController *messages.Controller) { + if authController == nil { + panic("auth controller cannot be nil") } - //user - userV1 := e.Group("v1/users") - userV1.GET("/:id", userController.FindUserByID) - userV1.GET("", userController.FindAllUserWithPagination) - userV1.POST("", userController.InsertUser) - userV1.PUT("/:id", userController.UpdateUser) + if usersController == nil { + panic("users controller cannot be nil") + } + + if messagesController == nil { + panic("messages controller cannot be nil") + } + + //auth + authV1 := e.Group("v1/auth") + authV1.POST("/token", authController.GenerateToken) + + //users + usersV1 := e.Group("v1/users") + usersV1.PATCH("/enter-chatroom", middlewares.Auth(usersController.EnterChatroom, authController.AuthError)) + usersV1.PATCH("/leave-chatroom", middlewares.Auth(usersController.LeaveChatroom, authController.AuthError)) + + //chatrooms + chatroomsV1 := e.Group("v1/chatrooms") + chatroomsV1.GET("", middlewares.Auth(chatroomsController.GetChatrooms, authController.AuthError)) + + //messages + messagesV1 := e.Group("v1/messages") + messagesV1.POST("", middlewares.Auth(messagesController.InsertMessage, authController.AuthError)) + messagesV1.GET("/:chatroom", middlewares.Auth(messagesController.GetMessagesByChatroom, authController.AuthError)) //health check e.GET("/health", func(c echo.Context) error { diff --git a/api/v1/auth/controller.go b/api/v1/auth/controller.go new file mode 100644 index 0000000..785ef55 --- /dev/null +++ b/api/v1/auth/controller.go @@ -0,0 +1,52 @@ +package auth + +import ( + "chat-hex/api/common" + "chat-hex/api/v1/auth/requests" + "chat-hex/business/auth" + "chat-hex/business/users" + + "github.com/labstack/echo/v4" +) + +type Controller struct { + service auth.Service + usersService users.Service +} + +func NewController(service auth.Service, usersService users.Service) *Controller { + return &Controller{ + service, + usersService, + } +} + +func (controller *Controller) GenerateToken(c echo.Context) error { + generateTokenRequest := new(requests.GenerateTokenRequest) + + err := c.Bind(generateTokenRequest) + if err != nil { + return c.JSON(common.NewBadRequestResponse()) + } + + user, err := controller.usersService.FindUserByEmail(generateTokenRequest.Email) + if err != nil { + return c.JSON(common.NewErrorBusinessResponse(err)) + } + + err = controller.usersService.CheckPassword(user.Password, generateTokenRequest.Password) + if err != nil { + return c.JSON(common.NewErrorBusinessResponse(err)) + } + + response, err := controller.service.GenerateJWT(*generateTokenRequest.ToGenerateTokenSpec()) + if err != nil { + return c.JSON(common.NewErrorBusinessResponse(err)) + } + + return c.JSON(common.NewSuccessResponse(response)) +} + +func (controller *Controller) AuthError(c echo.Context) error { + return c.JSON(common.NewForbiddenResponse()) +} \ No newline at end of file diff --git a/api/v1/auth/requests/generate_token.go b/api/v1/auth/requests/generate_token.go new file mode 100644 index 0000000..c87e5fa --- /dev/null +++ b/api/v1/auth/requests/generate_token.go @@ -0,0 +1,17 @@ +package requests + +import "chat-hex/business/auth" + +type GenerateTokenRequest struct { + Email string `json:"email"` + Password string `json:"password"` +} + +func (req *GenerateTokenRequest) ToGenerateTokenSpec() *auth.GenerateTokenSpec { + var generateTokenSpec auth.GenerateTokenSpec + + generateTokenSpec.Email = req.Email + generateTokenSpec.Password = req.Password + + return &generateTokenSpec +} \ No newline at end of file diff --git a/api/v1/chatrooms/controller.go b/api/v1/chatrooms/controller.go new file mode 100644 index 0000000..6f502d3 --- /dev/null +++ b/api/v1/chatrooms/controller.go @@ -0,0 +1,30 @@ +package chatrooms + +import ( + "chat-hex/api/common" + "chat-hex/api/v1/chatrooms/responses" + "chat-hex/business/chatrooms" + + "github.com/labstack/echo/v4" +) + +type Controller struct { + service chatrooms.Service +} + +func NewController(service chatrooms.Service) *Controller { + return &Controller{ + service, + } +} + +func (controller *Controller) GetChatrooms(c echo.Context) error { + chatrooms, err := controller.service.GetChatrooms() + if err != nil { + return c.JSON(common.NewErrorBusinessResponse(err)) + } + + response := responses.NewGetChatroomsResponse(chatrooms) + + return c.JSON(common.NewSuccessResponse(response)) +} \ No newline at end of file diff --git a/api/v1/chatrooms/responses/get_chatrooms.go b/api/v1/chatrooms/responses/get_chatrooms.go new file mode 100644 index 0000000..d9e230e --- /dev/null +++ b/api/v1/chatrooms/responses/get_chatrooms.go @@ -0,0 +1,33 @@ +package responses + +import "chat-hex/business/chatrooms" + +type chatroomResponse struct { + Name string `json:"name"` + Desc string `json:"desc"` + Code string `json:"code"` +} + +type getChatroomsResponse struct { + Chatrooms []chatroomResponse `json:"chatrooms"` +} + +func NewGetChatroomsResponse(chatrooms []chatrooms.Chatroom) getChatroomsResponse { + getChatroomsResponse := getChatroomsResponse{} + + for _, value := range chatrooms { + var chatroomResponse chatroomResponse + + chatroomResponse.Name = value.Name + chatroomResponse.Desc = value.Desc + chatroomResponse.Code = value.Code + + getChatroomsResponse.Chatrooms = append(getChatroomsResponse.Chatrooms, chatroomResponse) + } + + if getChatroomsResponse.Chatrooms == nil { + getChatroomsResponse.Chatrooms = []chatroomResponse{} + } + + return getChatroomsResponse +} \ No newline at end of file diff --git a/api/v1/messages/controller.go b/api/v1/messages/controller.go new file mode 100644 index 0000000..ed6caf8 --- /dev/null +++ b/api/v1/messages/controller.go @@ -0,0 +1,60 @@ +package messages + +import ( + "chat-hex/api/common" + "chat-hex/api/v1/messages/requests" + "chat-hex/api/v1/messages/responses" + "chat-hex/business/commands" + "chat-hex/business/messages" + + "github.com/labstack/echo/v4" +) + +type Controller struct { + service messages.Service + commandsService commands.Service +} + +func NewController(service messages.Service, commandsService commands.Service) *Controller { + return &Controller{ + service, + commandsService, + } +} + +func (controller *Controller) InsertMessage(c echo.Context) error { + insertMessageRequest := new(requests.InsertMessageRequest) + + err := c.Bind(insertMessageRequest) + if err != nil { + return c.JSON(common.NewBadRequestResponse()) + } + + messageHasCommandStructure := controller.service.MessageHasCommandStructure(*insertMessageRequest.ToInsertMessageSpec()) + if messageHasCommandStructure { + err = controller.commandsService.ProcessCommand(*insertMessageRequest.ToCommandSpec()) + if err != nil { + return c.JSON(common.NewErrorBusinessResponse(err)) + } + } else { + err = controller.service.InsertMessage(*insertMessageRequest.ToInsertMessageSpec()) + if err != nil { + return c.JSON(common.NewErrorBusinessResponse(err)) + } + } + + return c.JSON(common.NewSuccessResponseWithoutData()) +} + +func (controller *Controller) GetMessagesByChatroom(c echo.Context) error { + chatroom := c.Param("chatroom") + + messages, err := controller.service.GetMessagesByChatroom(chatroom) + if err != nil { + return c.JSON(common.NewErrorBusinessResponse(err)) + } + + response := responses.NewGetMessagesByChatroomResponse(messages) + + return c.JSON(common.NewSuccessResponse(response)) +} \ No newline at end of file diff --git a/api/v1/messages/requests/insert_message.go b/api/v1/messages/requests/insert_message.go new file mode 100644 index 0000000..833573e --- /dev/null +++ b/api/v1/messages/requests/insert_message.go @@ -0,0 +1,32 @@ +package requests + +import ( + "chat-hex/business/commands" + "chat-hex/business/messages" +) + +type InsertMessageRequest struct { + Content string `json:"content"` + Sender string `json:"sender"` + Chatroom string `json:"chatroom"` +} + +func (req *InsertMessageRequest) ToInsertMessageSpec() *messages.InsertMessageSpec { + var insertMessageSpec messages.InsertMessageSpec + + insertMessageSpec.Content = req.Content + insertMessageSpec.Sender = req.Sender + insertMessageSpec.Chatroom = req.Chatroom + + return &insertMessageSpec +} + +func (req *InsertMessageRequest) ToCommandSpec() *commands.CommandSpec { + var commandSpec commands.CommandSpec + + commandSpec.Content = req.Content + commandSpec.Sender = req.Sender + commandSpec.Chatroom = req.Chatroom + + return &commandSpec +} \ No newline at end of file diff --git a/api/v1/messages/responses/get_messages_by_chatroom.go b/api/v1/messages/responses/get_messages_by_chatroom.go new file mode 100644 index 0000000..a933a34 --- /dev/null +++ b/api/v1/messages/responses/get_messages_by_chatroom.go @@ -0,0 +1,38 @@ +package responses + +import ( + "chat-hex/business/messages" + "time" +) + +type getMessageResponse struct { + Id string `json:"id"` + Content string `json:"content"` + Sender string `json:"sender"` + Timestamp time.Time `json:"timestamp"` +} + +type getMessagesByChatroomResponse struct { + Messages []getMessageResponse `json:"messages"` +} + +func NewGetMessagesByChatroomResponse(messages []messages.Message) getMessagesByChatroomResponse { + getMessagesByChatroomResponse := getMessagesByChatroomResponse{} + + for _, value := range messages { + var getMessageResponse getMessageResponse + + getMessageResponse.Id = value.Id + getMessageResponse.Content = value.Content + getMessageResponse.Sender = value.Sender + getMessageResponse.Timestamp = value.Timestamp + + getMessagesByChatroomResponse.Messages = append(getMessagesByChatroomResponse.Messages, getMessageResponse) + } + + if getMessagesByChatroomResponse.Messages == nil { + getMessagesByChatroomResponse.Messages = []getMessageResponse{} + } + + return getMessagesByChatroomResponse +} \ No newline at end of file diff --git a/api/v1/user/controller.go b/api/v1/user/controller.go index 07d4a4b..b3f808d 100644 --- a/api/v1/user/controller.go +++ b/api/v1/user/controller.go @@ -1,10 +1,10 @@ package user import ( - "go-hexagonal/api/common" - "go-hexagonal/api/v1/user/request" - "go-hexagonal/api/v1/user/response" - "go-hexagonal/business/user" + "chat-hex/api/common" + "chat-hex/api/v1/user/request" + "chat-hex/api/v1/user/response" + "chat-hex/business/user" "strconv" echo "github.com/labstack/echo/v4" diff --git a/api/v1/user/request/insert_user.go b/api/v1/user/request/insert_user.go index e5a4643..5ac27b0 100644 --- a/api/v1/user/request/insert_user.go +++ b/api/v1/user/request/insert_user.go @@ -1,6 +1,6 @@ package request -import "go-hexagonal/business/user" +import "chat-hex/business/user" //InsertUserRequest create User request payload type InsertUserRequest struct { diff --git a/api/v1/user/response/get_all_user.go b/api/v1/user/response/get_all_user.go index 934df8a..87b399f 100644 --- a/api/v1/user/response/get_all_user.go +++ b/api/v1/user/response/get_all_user.go @@ -1,6 +1,6 @@ package response -import "go-hexagonal/business/user" +import "chat-hex/business/user" type getAllUserResponse struct { Meta meta `json:"meta"` diff --git a/api/v1/user/response/get_user.go b/api/v1/user/response/get_user.go index ec22c59..fd9581b 100644 --- a/api/v1/user/response/get_user.go +++ b/api/v1/user/response/get_user.go @@ -1,7 +1,7 @@ package response import ( - "go-hexagonal/business/user" + "chat-hex/business/user" "time" ) diff --git a/api/v1/users/controller.go b/api/v1/users/controller.go new file mode 100644 index 0000000..b79d1be --- /dev/null +++ b/api/v1/users/controller.go @@ -0,0 +1,51 @@ +package users + +import ( + "chat-hex/api/common" + "chat-hex/api/v1/users/requests" + "chat-hex/business/users" + + "github.com/labstack/echo/v4" +) + +type Controller struct { + service users.Service +} + +func NewController(service users.Service) *Controller { + return &Controller{ + service, + } +} + +func (controller *Controller) EnterChatroom(c echo.Context) error { + enterChatroomRequest := new(requests.EnterChatroomRequest) + + err := c.Bind(enterChatroomRequest) + if err != nil { + return c.JSON(common.NewBadRequestResponse()) + } + + err = controller.service.EnterChatroom(*enterChatroomRequest.ToEnterChatroomSpec()) + if err != nil { + return c.JSON(common.NewErrorBusinessResponse(err)) + } + + return nil +} + +func (controller *Controller) LeaveChatroom(c echo.Context) error { + leaveChatroomRequest := new(requests.LeaveChatroomRequest) + + err := c.Bind(leaveChatroomRequest) + if err != nil { + return c.JSON(common.NewBadRequestResponse()) + } + + err = controller.service.LeaveChatroom(*leaveChatroomRequest.ToLeaveChatroomSpec()) + if err != nil { + return c.JSON(common.NewErrorBusinessResponse(err)) + } + + return nil +} diff --git a/api/v1/users/requests/enter_chatroom.go b/api/v1/users/requests/enter_chatroom.go new file mode 100644 index 0000000..eed178f --- /dev/null +++ b/api/v1/users/requests/enter_chatroom.go @@ -0,0 +1,17 @@ +package requests + +import "chat-hex/business/users" + +type EnterChatroomRequest struct { + Email string `json:"email"` + Chatroom string `json:"chatroom"` +} + +func (req *EnterChatroomRequest) ToEnterChatroomSpec() *users.EnterChatroomSpec { + var enterChatroomSpec users.EnterChatroomSpec + + enterChatroomSpec.Email = req.Email + enterChatroomSpec.Chatroom = req.Chatroom + + return &enterChatroomSpec +} \ No newline at end of file diff --git a/api/v1/users/requests/leave_chatroom.go b/api/v1/users/requests/leave_chatroom.go new file mode 100644 index 0000000..3a90019 --- /dev/null +++ b/api/v1/users/requests/leave_chatroom.go @@ -0,0 +1,17 @@ +package requests + +import "chat-hex/business/users" + +type LeaveChatroomRequest struct { + Email string `json:"email"` + Chatroom string `json:"chatroom"` +} + +func (req *LeaveChatroomRequest) ToLeaveChatroomSpec() *users.LeaveChatroomSpec { + var leaveChatroomSpec users.LeaveChatroomSpec + + leaveChatroomSpec.Email = req.Email + leaveChatroomSpec.Chatroom = req.Chatroom + + return &leaveChatroomSpec +} \ No newline at end of file diff --git a/app/main.go b/app/main.go index 2ac3763..e169cd2 100644 --- a/app/main.go +++ b/app/main.go @@ -1,21 +1,31 @@ package main import ( + "chat-hex/config" + "chat-hex/modules/mongodb" "context" "fmt" - "go-hexagonal/config" - "go-hexagonal/modules/mongodb" - "go-hexagonal/api" - userController "go-hexagonal/api/v1/user" - userService "go-hexagonal/business/user" - userRepository "go-hexagonal/modules/user" + "chat-hex/api" + authController "chat-hex/api/v1/auth" + chatroomsController "chat-hex/api/v1/chatrooms" + messagesController "chat-hex/api/v1/messages" + usersController "chat-hex/api/v1/users" + authService "chat-hex/business/auth" + chatroomsService "chat-hex/business/chatrooms" + commandsService "chat-hex/business/commands" + messagesService "chat-hex/business/messages" + usersService "chat-hex/business/users" + chatroomsRepository "chat-hex/modules/chatrooms" + messagesRepository "chat-hex/modules/messages" + usersRepository "chat-hex/modules/users" "os" "os/signal" "time" echo "github.com/labstack/echo/v4" + "github.com/labstack/echo/v4/middleware" "github.com/labstack/gommon/log" "go.mongodb.org/mongo-driver/mongo" ) @@ -60,20 +70,37 @@ func main() { //initialize database connection based on given config dbConnection := newDatabaseConnection(config) - //initiate item repository - userRepo := userRepository.NewMongoDBRepository(dbConnection) - - //initiate item service - userService := userService.NewService(userRepo) - - //initiate item controller - userController := userController.NewController(userService) - //create echo http e := echo.New() - - //register API path and handler - api.RegisterPath(e, userController) + e.Use(middleware.CORSWithConfig(middleware.CORSConfig{ + AllowOrigins: []string{"*"}, + AllowHeaders: []string{echo.HeaderOrigin, echo.HeaderContentType, echo.HeaderAccept}, + })) + + //initiate chatrooms + chatroomsRepo := chatroomsRepository.NewMongoDBRepository(dbConnection) + chatroomsService := chatroomsService.NewService(chatroomsRepo) + chatroomsController := chatroomsController.NewController(chatroomsService) + + //initiate users + usersRepo := usersRepository.NewMongoDBRepository(dbConnection) + usersService := usersService.NewService(usersRepo, chatroomsService) + usersController := usersController.NewController(usersService) + + //initiate auth + authService := authService.NewService() + authController := authController.NewController(authService, usersService) + + //initiate commands + commandsService := commandsService.NewService() + + //initiate messages + messagesRepo := messagesRepository.NewMongoDBRepository(dbConnection) + messagesService := messagesService.NewService(messagesRepo) + messagesController := messagesController.NewController(messagesService, commandsService) + + //register paths + api.RegisterPaths(e, authController, usersController, chatroomsController, messagesController) // run server go func() { diff --git a/business/auth/interface.go b/business/auth/interface.go new file mode 100644 index 0000000..38b2a94 --- /dev/null +++ b/business/auth/interface.go @@ -0,0 +1,6 @@ +package auth + +type Service interface { + GenerateJWT(generateTokenSpec GenerateTokenSpec) (string, error) + ValidateToken(signedToken string) error +} \ No newline at end of file diff --git a/business/auth/service.go b/business/auth/service.go new file mode 100644 index 0000000..4753346 --- /dev/null +++ b/business/auth/service.go @@ -0,0 +1,63 @@ +package auth + +import ( + "errors" + "time" + + "github.com/dgrijalva/jwt-go" +) + +type GenerateTokenSpec struct { + Email string `validate:"required"` + Password string `validate:"required"` +} + +var jwtKey = []byte("chat-hex-key") + +type JWTClaim struct { + Email string `json:"email"` + jwt.StandardClaims +} + +type service struct{} + +func NewService() Service { + return &service{} +} + +func (s *service) GenerateJWT(generateTokenSpec GenerateTokenSpec) (string, error) { + expirationTime := time.Now().Add(1 * time.Hour) + claims := &JWTClaim{ + Email: generateTokenSpec.Email, + StandardClaims: jwt.StandardClaims{ + ExpiresAt: expirationTime.Unix(), + }, + } + + token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims) + return token.SignedString(jwtKey) +} + +func (s *service) ValidateToken(signedToken string) error { + token, err := jwt.ParseWithClaims( + signedToken, + &JWTClaim{}, + func(token *jwt.Token) (interface{}, error) { + return []byte(jwtKey), nil + }, + ) + if err != nil { + return err + } + + claims, ok := token.Claims.(*JWTClaim) + if !ok { + return errors.New("couldn't parse claims") + } + + if claims.ExpiresAt < time.Now().Local().Unix() { + return errors.New("token expired") + } + + return nil +} \ No newline at end of file diff --git a/business/chatrooms/chatroom.go b/business/chatrooms/chatroom.go new file mode 100644 index 0000000..1117068 --- /dev/null +++ b/business/chatrooms/chatroom.go @@ -0,0 +1,22 @@ +package chatrooms + +type Chatroom struct { + Id string + Name string + Desc string + Code string +} + +func NewChatroom( + id string, + name string, + desc string, + code string) Chatroom { + + return Chatroom{ + Id: id, + Name: name, + Desc: desc, + Code: code, + } +} \ No newline at end of file diff --git a/business/chatrooms/interface.go b/business/chatrooms/interface.go new file mode 100644 index 0000000..3b31dc9 --- /dev/null +++ b/business/chatrooms/interface.go @@ -0,0 +1,11 @@ +package chatrooms + +type Service interface { + FindChatroomByCode(code string) (*Chatroom, error) + GetChatrooms() ([]Chatroom, error) +} + +type Repository interface { + FindChatroomByCode(code string) (*Chatroom, error) + GetChatrooms() ([]Chatroom, error) +} \ No newline at end of file diff --git a/business/chatrooms/service.go b/business/chatrooms/service.go new file mode 100644 index 0000000..6c2c13c --- /dev/null +++ b/business/chatrooms/service.go @@ -0,0 +1,27 @@ +package chatrooms + +type service struct { + repository Repository +} + +func NewService(repository Repository) Service { + return &service{repository} +} + +func (s *service) FindChatroomByCode(code string) (*Chatroom, error) { + chatroom, err := s.repository.FindChatroomByCode(code) + if err != nil { + return nil, err + } + + return chatroom, nil +} + +func (s *service) GetChatrooms() ([]Chatroom, error) { + chatrooms, err := s.repository.GetChatrooms() + if err != nil { + return nil, err + } + + return chatrooms, nil +} \ No newline at end of file diff --git a/business/commands/command.go b/business/commands/command.go new file mode 100644 index 0000000..6940dd4 --- /dev/null +++ b/business/commands/command.go @@ -0,0 +1,5 @@ +package commands + +const ( + CommandStock = "/stock" +) \ No newline at end of file diff --git a/business/commands/interface.go b/business/commands/interface.go new file mode 100644 index 0000000..26e1609 --- /dev/null +++ b/business/commands/interface.go @@ -0,0 +1,5 @@ +package commands + +type Service interface { + ProcessCommand(commandSpec CommandSpec) error +} \ No newline at end of file diff --git a/business/commands/service.go b/business/commands/service.go new file mode 100644 index 0000000..b64a7ed --- /dev/null +++ b/business/commands/service.go @@ -0,0 +1,45 @@ +package commands + +import ( + "chat-hex/business" + "fmt" + "strings" +) + +type CommandSpec struct { + Content string `validate:"required"` + Sender string `validate:"required"` + Chatroom string `validate:"required"` +} + +type service struct{} + +func NewService() Service { + return &service{} +} + +func (s *service) ProcessCommand(commandSpec CommandSpec) error { + pieces := strings.Split(commandSpec.Content, "=") + + possibleCommand := strings.ToLower(pieces[0]) + if possibleCommand == CommandStock { + stockCode := strings.ToLower(pieces[1]) + if len(stockCode) <= 0 { + return business.ErrInvalidCommand + } + + err := s.AsyncStockCommand(stockCode, commandSpec.Chatroom) + if err != nil { + return business.ErrInvalidCommand + } + + return nil + } + + return business.ErrInvalidCommand +} + +func (s *service) AsyncStockCommand(stockCode string, chatroom string) error { + fmt.Println("STOCK CODE IS", stockCode, "CHATROOM IS", chatroom) + return nil +} \ No newline at end of file diff --git a/business/error.go b/business/error.go index 4261b18..5c5733e 100644 --- a/business/error.go +++ b/business/error.go @@ -4,14 +4,17 @@ import "errors" var ( //ErrInternalServerError Error caused by system error - ErrInternalServerError = errors.New("Internal Server Error") + ErrInternalServerError = errors.New("internal Server Error") //ErrHasBeenModified Error when update item that has been modified - ErrHasBeenModified = errors.New("Data has been modified") + ErrHasBeenModified = errors.New("data has been modified") //ErrNotFound Error when item is not found - ErrNotFound = errors.New("Data was not found") + ErrNotFound = errors.New("data was not found") //ErrInvalidSpec Error when data given is not valid on update or insert - ErrInvalidSpec = errors.New("Given spec is not valid") + ErrInvalidSpec = errors.New("given spec is not valid") + + //ErrInvalidCommand Error when the message is formatted like a command but it's not a valid one + ErrInvalidCommand = errors.New("this is not a valid command") ) diff --git a/business/messages/interface.go b/business/messages/interface.go new file mode 100644 index 0000000..aae7db1 --- /dev/null +++ b/business/messages/interface.go @@ -0,0 +1,12 @@ +package messages + +type Service interface { + InsertMessage(insertMessageSpec InsertMessageSpec) error + GetMessagesByChatroom(chatroom string) ([]Message, error) + MessageHasCommandStructure(insertMessageSpec InsertMessageSpec) bool +} + +type Repository interface { + InsertMessage(message Message) error + GetMessagesByChatroom(chatroom string) ([]Message, error) +} \ No newline at end of file diff --git a/business/messages/message.go b/business/messages/message.go new file mode 100644 index 0000000..a0957e5 --- /dev/null +++ b/business/messages/message.go @@ -0,0 +1,27 @@ +package messages + +import "time" + +type Message struct { + Id string + Content string + Sender string + Timestamp time.Time + ChatRoom string +} + +func NewMessage( + id string, + content string, + sender string, + timestamp time.Time, + chatroom string) Message { + + return Message{ + Id: id, + Content: content, + Sender: sender, + Timestamp: timestamp, + ChatRoom: chatroom, + } +} \ No newline at end of file diff --git a/business/messages/service.go b/business/messages/service.go new file mode 100644 index 0000000..e1b4ceb --- /dev/null +++ b/business/messages/service.go @@ -0,0 +1,64 @@ +package messages + +import ( + "chat-hex/business" + primitiveIDGenerator "chat-hex/util/primitiveIDGenerator" + "chat-hex/util/validator" + "time" +) + +type InsertMessageSpec struct { + Content string `validate:"required"` + Sender string `validate:"required"` + Chatroom string `validate:"required"` +} + +type service struct { + repository Repository +} + +func NewService(repository Repository) Service { + return &service{repository} +} + +func (s *service) InsertMessage(insertMessageSpec InsertMessageSpec) error { + err := validator.GetValidator().Struct(insertMessageSpec) + if err != nil { + return business.ErrInvalidSpec + } + + id := primitiveIDGenerator.GenerateID() + message := NewMessage( + id, + insertMessageSpec.Content, + insertMessageSpec.Sender, + time.Now(), + insertMessageSpec.Chatroom, + ) + + err = s.repository.InsertMessage(message) + if err != nil { + return err + } + + return nil +} + +func (s *service) GetMessagesByChatroom(chatroom string) ([]Message, error) { + messages, err := s.repository.GetMessagesByChatroom(chatroom) + if err != nil { + return []Message{}, err + } + + return messages, err +} + +func (s *service) MessageHasCommandStructure(insertMessageSpec InsertMessageSpec) bool { + err := validator.GetValidator().Struct(insertMessageSpec) + if err != nil { + return false + } + + firstCharacter:= insertMessageSpec.Content[0:1] + return firstCharacter == "/" +} \ No newline at end of file diff --git a/business/user/mocks/Repository.go b/business/user/mocks/Repository.go index 700f668..c91c08f 100644 --- a/business/user/mocks/Repository.go +++ b/business/user/mocks/Repository.go @@ -3,7 +3,7 @@ package mocks import ( - user "go-hexagonal/business/user" + user "chat-hex/business/user" mock "github.com/stretchr/testify/mock" ) diff --git a/business/user/mocks/Service.go b/business/user/mocks/Service.go index a5a656a..2e70a36 100644 --- a/business/user/mocks/Service.go +++ b/business/user/mocks/Service.go @@ -3,7 +3,7 @@ package mocks import ( - user "go-hexagonal/business/user" + user "chat-hex/business/user" mock "github.com/stretchr/testify/mock" ) diff --git a/business/user/service.go b/business/user/service.go index 1d58422..a54ca7a 100644 --- a/business/user/service.go +++ b/business/user/service.go @@ -1,9 +1,9 @@ package user import ( - "go-hexagonal/business" - "go-hexagonal/util/primiviteIDGenerator" - "go-hexagonal/util/validator" + "chat-hex/business" + "chat-hex/util/primitiveIDGenerator" + "chat-hex/util/validator" "time" ) @@ -49,7 +49,7 @@ func (s *service) InsertUser(insertUserSpec InsertUserSpec, createdBy string) er return business.ErrInvalidSpec } - id := primiviteIDGenerator.GenerateID() + id := primitiveIDGenerator.GenerateID() user := NewUser( id, insertUserSpec.Name, diff --git a/business/user/service_test.go b/business/user/service_test.go index 4b4fdd4..05cd3bc 100644 --- a/business/user/service_test.go +++ b/business/user/service_test.go @@ -1,9 +1,9 @@ package user_test import ( - "go-hexagonal/business" - "go-hexagonal/business/user" - userMock "go-hexagonal/business/user/mocks" + "chat-hex/business" + "chat-hex/business/user" + userMock "chat-hex/business/user/mocks" "os" "testing" diff --git a/business/users/interface.go b/business/users/interface.go new file mode 100644 index 0000000..5650e86 --- /dev/null +++ b/business/users/interface.go @@ -0,0 +1,15 @@ +package users + +type Service interface { + EnterChatroom(enterChatroomSpec EnterChatroomSpec) error + LeaveChatroom(leaveChatroomSpec LeaveChatroomSpec) error + HashPassword(password string) (*string, error) + FindUserByEmail(email string) (*User, error) + CheckPassword(hashedPassword string, clearPassword string) error +} + +type Repository interface { + FindUserByEmail(email string) (*User, error) + EnterChatroom(email string, chatroom string) error + LeaveChatroom(email string) error +} \ No newline at end of file diff --git a/business/users/service.go b/business/users/service.go new file mode 100644 index 0000000..2385355 --- /dev/null +++ b/business/users/service.go @@ -0,0 +1,90 @@ +package users + +import ( + "chat-hex/business" + "chat-hex/business/chatrooms" + "chat-hex/util/validator" + + "golang.org/x/crypto/bcrypt" +) + +type EnterChatroomSpec struct { + Email string `validate:"required"` + Chatroom string `validate:"required"` +} + +type LeaveChatroomSpec struct { + Email string `validate:"required"` + Chatroom string `validate:"required"` +} + +type service struct { + repository Repository + chatroomsService chatrooms.Service +} + +func NewService(repository Repository, chatroomsService chatrooms.Service) Service { + return &service{repository, chatroomsService} +} + +func (s *service) EnterChatroom(enterChatroomSpec EnterChatroomSpec) error { + err := validator.GetValidator().Struct(enterChatroomSpec) + if err != nil { + return business.ErrInvalidSpec + } + + _, err = s.chatroomsService.FindChatroomByCode(enterChatroomSpec.Chatroom) + if err != nil { + return business.ErrInvalidSpec + } + + err = s.repository.EnterChatroom(enterChatroomSpec.Email, enterChatroomSpec.Chatroom) + if err != nil { + return err + } + + return nil +} + +func (s *service) LeaveChatroom(leaveChatroomSpec LeaveChatroomSpec) error { + err := validator.GetValidator().Struct(leaveChatroomSpec) + if err != nil { + return business.ErrInvalidSpec + } + + err = s.repository.LeaveChatroom(leaveChatroomSpec.Email) + if err != nil { + return err + } + + return nil +} + +func (s *service) HashPassword(password string) (*string, error) { + bytes, err := bcrypt.GenerateFromPassword([]byte(password), 14) + if err != nil { + return nil, err + } + + preResult := string(bytes) + result := &preResult + return result, nil +} + +func (s *service) FindUserByEmail(email string) (*User, error){ + user, err := s.repository.FindUserByEmail(email) + if err != nil { + return nil, err + } + + return user, nil +} + +func (s *service) CheckPassword(passwordToCheck string, clearPassword string) error { + err := bcrypt.CompareHashAndPassword([]byte(passwordToCheck), []byte(clearPassword)) + if err != nil { + return err + } + + return nil +} \ No newline at end of file diff --git a/business/users/user.go b/business/users/user.go new file mode 100644 index 0000000..76827fd --- /dev/null +++ b/business/users/user.go @@ -0,0 +1,25 @@ +package users + +type User struct { + Id string + Email string + Password string + Name string + CurrentRoom string +} + +func NewUser( + id string, + email string, + password string, + name string, + currentRoom string) User { + + return User{ + Id: id, + Email: email, + Password: password, + Name: name, + CurrentRoom: currentRoom, + } +} \ No newline at end of file diff --git a/config/.env b/config/.env index dd9ea3c..b3d7e03 100644 --- a/config/.env +++ b/config/.env @@ -1,9 +1,9 @@ -GOHEXAGONAL_APP_PORT=8000 -GOHEXAGONAL_APP_ENVIRONMENT=dev +APP_PORT=3000 +APP_ENVIRONMENT=dev -GOHEXAGONAL_DB_DRIVER=mongodb -GOHEXAGONAL_DB_ADDRESS=localhost -GOHEXAGONAL_DB_PORT=27017 -GOHEXAGONAL_DB_USERNAME= -GOHEXAGONAL_DB_PASSWORD= -GOHEXAGONAL_DB_NAME=transaction \ No newline at end of file +DB_DRIVER=mongodb +DB_ADDRESS=localhost +DB_PORT=27017 +DB_USERNAME= +DB_PASSWORD= +DB_NAME=local \ No newline at end of file diff --git a/config/.env_local b/config/.env_local deleted file mode 100644 index 3525509..0000000 --- a/config/.env_local +++ /dev/null @@ -1,9 +0,0 @@ -export GOHEXAGONAL_APP_PORT=8000 -export GOHEXAGONAL_APP_ENVIRONMENT=dev - -export GOHEXAGONAL_DB_DRIVER=mongodb -export GOHEXAGONAL_DB_ADDRESS=localhost -export GOHEXAGONAL_DB_PORT=27017 -export GOHEXAGONAL_DB_USERNAME= -export GOHEXAGONAL_DB_PASSWORD= -export GOHEXAGONAL_DB_NAME=transaction \ No newline at end of file diff --git a/config/config.go b/config/config.go index a8cd69b..85c828b 100644 --- a/config/config.go +++ b/config/config.go @@ -2,9 +2,6 @@ package config import ( "sync" - - "github.com/labstack/gommon/log" - "github.com/spf13/viper" ) type ConfigIPForwarding struct { @@ -28,7 +25,7 @@ type AppConfig struct { var lock = &sync.Mutex{} var appConfig *AppConfig -//GetConfig Initiatilize config in singleton way +//GetConfig Initialize config in singleton way func GetConfig() *AppConfig { if appConfig != nil { return appConfig @@ -50,32 +47,14 @@ func GetConfig() *AppConfig { func initConfig() *AppConfig { var defaultConfig AppConfig - defaultConfig.AppPort = 8000 + defaultConfig.AppPort = 3000 defaultConfig.AppEnvironment = "" defaultConfig.DbDriver = "mongodb" defaultConfig.DbAddress = "localhost" defaultConfig.DbPort = 27017 defaultConfig.DbUsername = "" defaultConfig.DbPassword = "" - defaultConfig.DbName = "hexagonal" - - viper.AutomaticEnv() - viper.SetEnvPrefix("gohexagonal") - viper.BindEnv("app_port") - viper.BindEnv("app_environment") - viper.BindEnv("db_driver") - viper.BindEnv("db_address") - viper.BindEnv("db_port") - viper.BindEnv("db_username") - viper.BindEnv("db_password") - viper.BindEnv("db_name") - - var finalConfig AppConfig - err := viper.Unmarshal(&finalConfig) - if err != nil { - log.Info("failed to extract config, will use default value") - return &defaultConfig - } + defaultConfig.DbName = "local" - return &finalConfig + return &defaultConfig } diff --git a/go.mod b/go.mod index 50331fa..6bd1954 100644 --- a/go.mod +++ b/go.mod @@ -1,12 +1,15 @@ -module go-hexagonal +module chat-hex go 1.16 require ( - github.com/go-playground/validator/v10 v10.6.1 + github.com/dgrijalva/jwt-go v3.2.0+incompatible // indirect + github.com/gin-gonic/gin v1.9.1 + github.com/go-playground/validator/v10 v10.14.0 github.com/labstack/echo/v4 v4.3.0 github.com/labstack/gommon v0.3.0 github.com/spf13/viper v1.8.0 - github.com/stretchr/testify v1.7.0 // indirect + github.com/stretchr/testify v1.8.4 // indirect go.mongodb.org/mongo-driver v1.5.3 + golang.org/x/crypto v0.9.0 // indirect ) diff --git a/go.sum b/go.sum index acc147c..6d93abb 100644 --- a/go.sum +++ b/go.sum @@ -47,7 +47,13 @@ github.com/aws/aws-sdk-go v1.34.28 h1:sscPpn/Ns3i0F4HPEWAVcwdIRaZZCuL7llJ2/60yPI github.com/aws/aws-sdk-go v1.34.28/go.mod h1:H7NKnBqNVzoTJpGfLrQkkD+ytBA93eiDYi/+8rV9s48= github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= github.com/bketelsen/crypt v0.0.4/go.mod h1:aI6NrJ0pMGgvZKL1iVgXLnfIFJtfV+bKCoqOes/6LfM= +github.com/bytedance/sonic v1.5.0/go.mod h1:ED5hyg4y6t3/9Ku1R6dU/4KyJ48DZ4jPhfY1O2AihPM= +github.com/bytedance/sonic v1.9.1 h1:6iJ6NqdoxCDr6mbY8h18oSO+cShGSMRGCEo7F2h0x8s= +github.com/bytedance/sonic v1.9.1/go.mod h1:i736AoUSYt75HyZLoJW9ERYxcy6eaN6h4BZXU064P/U= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= +github.com/chenzhuoyu/base64x v0.0.0-20211019084208-fb5309c8db06/go.mod h1:DH46F32mSOjUmXrMHnKwZdA8wcEefY7UVqBKYGjpdQY= +github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311 h1:qSGYFH7+jGhDF8vLC+iwCD4WpbV1EBDSzWkJODFLams= +github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311/go.mod h1:b583jCggY9gE99b6G5LEC39OIiVsWj+R97kbl5odCEk= github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= @@ -60,6 +66,7 @@ github.com/coreos/go-systemd/v22 v22.3.2/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSV github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/dgrijalva/jwt-go v3.2.0+incompatible h1:7qlOGliEKZXTDg6OTjfoBKDXWrumCAMpl/TFQ4/5kLM= github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= @@ -71,18 +78,31 @@ github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7 github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4= github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= +github.com/gabriel-vasile/mimetype v1.4.2 h1:w5qFW6JKBz9Y393Y4q372O9A7cUSequkh1Q7OhCmWKU= +github.com/gabriel-vasile/mimetype v1.4.2/go.mod h1:zApsH/mKG4w07erKIaJPFiX0Tsq9BFQgN3qGY5GnNgA= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= +github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE= +github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI= +github.com/gin-gonic/gin v1.9.1 h1:4idEAncQnU5cB7BeOkPtxjfCSye0AAm1R0RVIqJ+Jmg= +github.com/gin-gonic/gin v1.9.1/go.mod h1:hPrL7YrpYKXt5YId3A/Tnip5kqbEAP+KLuI3SUcPTeU= github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= github.com/go-playground/assert/v2 v2.0.1 h1:MsBgLAaY856+nPRTKrp3/OZK38U/wa0CcBYNjji3q3A= github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4= +github.com/go-playground/assert/v2 v2.2.0/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4= github.com/go-playground/locales v0.13.0 h1:HyWk6mgj5qFqCT5fjGBuRArbVDfE4hi8+e8ceBS/t7Q= github.com/go-playground/locales v0.13.0/go.mod h1:taPMhCMXrRLJO55olJkUXHZBHCxTMfnGwq/HNwmWNS8= +github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA= +github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY= github.com/go-playground/universal-translator v0.17.0 h1:icxd5fm+REJzpZx7ZfpaD876Lmtgy7VtROAbHHXk8no= github.com/go-playground/universal-translator v0.17.0/go.mod h1:UkSxE5sNxxRwHyU+Scu5vgOQjsIJAF8j9muTVoKLVtA= +github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY= +github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY= github.com/go-playground/validator/v10 v10.6.1 h1:W6TRDXt4WcWp4c4nf/G+6BkGdhiIo0k417gfr+V6u4I= github.com/go-playground/validator/v10 v10.6.1/go.mod h1:xm76BBt941f7yWdGnI2DVPFFg1UK3YY04qifoXU3lOk= +github.com/go-playground/validator/v10 v10.14.0 h1:vgvQWe3XCz3gIeFDm/HnTIbj6UGmg/+t63MyGU2n5js= +github.com/go-playground/validator/v10 v10.14.0/go.mod h1:9iXMNT7sEkjXb0I+enO7QXmzG6QCsPWY4zveKFVRSyU= github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg= github.com/go-stack/stack v1.8.0 h1:5SgMzNM5HxrEjV0ww2lTmX6E2Izsfxas4+YHWRs3Lsk= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= @@ -110,6 +130,8 @@ github.com/gobuffalo/packd v0.1.0/go.mod h1:M2Juc+hhDXf/PnmBANFCqx4DM3wRbgDvnVWe github.com/gobuffalo/packr/v2 v2.0.9/go.mod h1:emmyGweYTm6Kdper+iywB6YK5YzuKchGtJQZ0Odn4pQ= github.com/gobuffalo/packr/v2 v2.2.0/go.mod h1:CaAwI0GPIAv+5wKLtv8Afwl+Cm78K/I/VCm/3ptBN+0= github.com/gobuffalo/syncx v0.0.0-20190224160051-33c29581e754/go.mod h1:HhnNqWY95UYwwW3uSASeV7vtgYkT2t16hJgV3AEPUpw= +github.com/goccy/go-json v0.10.2 h1:CrxCmQqYDkv1z7lO7Wbh2HN93uovUHgrECaO5ZrCXAU= +github.com/goccy/go-json v0.10.2/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I= github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= @@ -209,6 +231,8 @@ github.com/jmespath/go-jmespath/internal/testify v1.5.1 h1:shLQSRRSCCPj3f2gpwzGw github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfCI6z80xFu9LTZmf1ZRjMHUOPmWr69U= github.com/joho/godotenv v1.3.0/go.mod h1:7hK45KPybAkOC6peb+G5yklZfMxEjkZhHbwpqxOKXbg= github.com/json-iterator/go v1.1.11/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= +github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo= @@ -219,6 +243,9 @@ github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= github.com/klauspost/compress v1.9.5 h1:U+CaK85mrNNb4k8BNOfgJtJ/gr6kswUCFj6miSzVC6M= github.com/klauspost/compress v1.9.5/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A= +github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= +github.com/klauspost/cpuid/v2 v2.2.4 h1:acbojRNwl3o09bUq+yDCtZFc1aiwaAAxtcn8YkZXnvk= +github.com/klauspost/cpuid/v2 v2.2.4/go.mod h1:RVVoqg1df56z8g3pUjL/3lE5UfnlrJX8tyFgg4nqhuY= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg= @@ -233,6 +260,8 @@ github.com/labstack/gommon v0.3.0 h1:JEeO0bvc78PKdyHxloTKiF8BD5iGrH8T6MSeGvSgob0 github.com/labstack/gommon v0.3.0/go.mod h1:MULnywXg0yavhxWKc+lOruYdAhDwPK9wf0OL7NoOu+k= github.com/leodido/go-urn v1.2.0 h1:hpXL4XnriNwQ/ABnpepYM/1vCLWNDfUNts8dX3xTG6Y= github.com/leodido/go-urn v1.2.0/go.mod h1:+8+nEpDfqqsY+g338gtMEUOtuK+4dEMhiQEgxpxOKII= +github.com/leodido/go-urn v1.2.4 h1:XlAE/cm/ms7TE/VMVoduSpNBoyc2dOxHs5MZSwAN63Q= +github.com/leodido/go-urn v1.2.4/go.mod h1:7ZrI8mTSeBSHl/UaRyKQW1qZeMgak41ANeCNaVckg+4= github.com/magiconair/properties v1.8.5 h1:b6kJs+EmPFMYGkow9GiUyCyOvIwYetYJ3fSaWak/Gls= github.com/magiconair/properties v1.8.5/go.mod h1:y3VJvCyxH9uVvJTWEGAELF3aiYNyPKd5NZ3oSwXrF60= github.com/markbates/oncer v0.0.0-20181203154359-bf2de49a0be2/go.mod h1:Ld9puTsIW75CHf65OeIOkyKbteujpZVXDpWK6YGZbxE= @@ -246,6 +275,8 @@ github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hd github.com/mattn/go-isatty v0.0.9/go.mod h1:YNRxwqDuOph6SZLI9vUUz6OYw3QyUt7WiY2yME+cCiQ= github.com/mattn/go-isatty v0.0.12 h1:wuysRhFDzyxgEmMf5xjvJ2M9dZoWAXNNr5LSBS7uHXY= github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= +github.com/mattn/go-isatty v0.0.19 h1:JITubQf0MOLdlGRuRq+jtsDlekdYPia9ZFsB8h/APPA= +github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc= github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= @@ -257,13 +288,19 @@ github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh github.com/mitchellh/mapstructure v1.4.1 h1:CpVNEelQCZBooIPDn+AR3NpivK/TIKU8bDxdASFVQag= github.com/mitchellh/mapstructure v1.4.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= +github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= github.com/montanaflynn/stats v0.0.0-20171201202039-1bf9dbcd8cbe/go.mod h1:wL8QJuTMNUDYhXwkmfOly8iTdp5TEcJFWZD2D7SIkUc= github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= github.com/pelletier/go-toml v1.7.0/go.mod h1:vwGMzjaWMwyfHwgIBhI2YUM4fB6nL6lVAvS1LBMMhTE= github.com/pelletier/go-toml v1.9.3 h1:zeC5b1GviRUyKYd6OJPvBU/mcVDVoL1OhT17FCt5dSQ= github.com/pelletier/go-toml v1.9.3/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c= +github.com/pelletier/go-toml/v2 v2.0.8 h1:0ctb6s9mE31h0/lhu+J6OPmVeDxJn+kYnJc2jZR9tGQ= +github.com/pelletier/go-toml/v2 v2.0.8/go.mod h1:vuYfssBdrU2XDZ9bYydBu6t+6a6PYNcZljzZR9VXg+4= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= @@ -301,6 +338,9 @@ github.com/spf13/viper v1.8.0/go.mod h1:o0Pch8wJ9BVSWGQMbra6iw0oQ5oktSIBaujf1rJH github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.1 h1:2vfRuCMp5sSVIDSqO8oNnWJq7mPa6KVP3iPIwFBuy8A= github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= +github.com/stretchr/objx v0.5.0 h1:1zr/of2m5FGMsad5YfcqgdqdWrIhu+EBEJRhR1U7z/c= +github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= @@ -308,10 +348,21 @@ github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5 github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= +github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= +github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= +github.com/stretchr/testify v1.8.3/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= +github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= github.com/subosito/gotenv v1.2.0 h1:Slr1R9HxAlEKefgq5jn9U+DnETlIUa6HfgEzj0g5d7s= github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw= github.com/tidwall/pretty v1.0.0 h1:HsD+QiTn7sK6flMKIvNmpqz1qrpP3Ps6jOKIKMooyg4= github.com/tidwall/pretty v1.0.0/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk= +github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS4MhqMhdFk5YI= +github.com/twitchyliquid64/golang-asm v0.15.1/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2+aY1QWCk3Cedj/Gdt08= +github.com/ugorji/go/codec v1.2.11 h1:BMaWp1Bb6fHwEtbplGBGJ498wD+LKlNSl25MjdZY4dU= +github.com/ugorji/go/codec v1.2.11/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg= github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw= github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc= github.com/valyala/fasttemplate v1.0.1/go.mod h1:UQGH1tvbgY+Nz5t2n7tXsz52dQxojPUpymEIMZ47gx8= @@ -330,6 +381,7 @@ github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9de github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= +github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= go.etcd.io/etcd/api/v3 v3.5.0/go.mod h1:cbVKeC6lCfl7j/8jBhAK6aIYO9XOjdptoxU/nLQcPvs= go.etcd.io/etcd/client/pkg/v3 v3.5.0/go.mod h1:IJHfcCEKxYu1Os13ZdwCwIUTUVGYTSAM3YSwc9/Ac1g= go.etcd.io/etcd/client/v2 v2.305.0/go.mod h1:h9puh54ZTgAKtEbut2oe9P4L/oqKCVB6xsXlzd7alYQ= @@ -345,6 +397,9 @@ go.opencensus.io v0.23.0/go.mod h1:XItmlyltB5F7CS4xOC1DcqMoFqwtC6OG2xF7mCv7P7E= go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU= go.uber.org/zap v1.17.0/go.mod h1:MXVU+bhUf/A7Xi2HNOnopQOrmycQ5Ih87HtOu4q5SSo= +golang.org/x/arch v0.0.0-20210923205945-b76863e36670/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8= +golang.org/x/arch v0.3.0 h1:02VY4/ZcO/gBOH6PUaoiptASxtXU10jazRCP865E97k= +golang.org/x/arch v0.3.0/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8= golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= @@ -357,6 +412,10 @@ golang.org/x/crypto v0.0.0-20200302210943-78000ba7a073/go.mod h1:LzIPMQfyMNhhGPh golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2 h1:It14KIkyBFYkHkwZ7k45minvA9aorojkyjGk9KJ5B/w= golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= +golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= +golang.org/x/crypto v0.7.0/go.mod h1:pYwdfH91IfpZVANVyUOhSIPZaFoJGxTFbZhFTx+dXZU= +golang.org/x/crypto v0.9.0 h1:LF6fAI+IutBocDJ2OT0Q1g8plpYljMZ4+lty+dsqw3g= +golang.org/x/crypto v0.9.0/go.mod h1:yrmDGqONDYtNj3tH8X9dzUun2m2lzPa9ngI6/RUPGR0= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= @@ -392,6 +451,8 @@ golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= +golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181023162649-9b4f9f5ad519/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -429,6 +490,11 @@ golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v golang.org/x/net v0.0.0-20210316092652-d523dce5a7f4/go.mod h1:RBQZq4jEuRlivfhVLdyRGr576XBO4/greRjx4P4O3yc= golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4 h1:4nGaVu0QrbjT/AK2PRLuQfQuh6DJve+pELhqTdAj3x0= golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= +golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= +golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= +golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc= +golang.org/x/net v0.10.0 h1:X2//UzNDwYmtCLn7To6G58Wr6f5ahEAQgKNzv9Y951M= +golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= @@ -454,6 +520,9 @@ golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20210220032951-036812b2e83c h1:5KslGYwFpkhGh+Q16bwMP3cOontH8FOep7tGV86Y7SQ= golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.1.0 h1:wsuoTGHzEhffawBOhz5CYhcrV4IdKZbEyZjBMuTp12o= +golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -504,7 +573,19 @@ golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20210403161142-5e06dd20ab57/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210510120138-977fb7262007 h1:gG67DSER+11cZvqIMb8S8bt0vZtiN6xWYARwirrOSfE= golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220704084225-05e143d24a9e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.8.0 h1:EBmGv8NaZBZTWvrbjNoL6HVt+IVy3QDQpJs7VRIw3tU= +golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= +golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= +golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= +golang.org/x/term v0.6.0/go.mod h1:m6U89DPEgQRMq3DNkDClhWw02AUbt2daBVO4cn4Hv9U= +golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= @@ -514,9 +595,16 @@ golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6 h1:aRYxNxv6iGQlyVaZmk6ZgYEDa+Jg18DxebPSrd6bg1M= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= +golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ= +golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= +golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= +golang.org/x/text v0.9.0 h1:2sjJmO8cDvYveuX97RDLsxlyUxLl+GHoLxBiRdHllBE= +golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20201208040808-7e3f01d25324 h1:Hir2P/De0WpUhtrKGGjvSb2YxUgyZ7EFOSLIcSSpiwE= golang.org/x/time v0.0.0-20201208040808-7e3f01d25324/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= @@ -573,6 +661,8 @@ golang.org/x/tools v0.0.0-20210105154028-b0ab187a4818/go.mod h1:emZCQorbCU4vsT4f golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= golang.org/x/tools v0.1.2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= +golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= +golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= @@ -680,6 +770,8 @@ google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGj google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= +google.golang.org/protobuf v1.30.0 h1:kPPoIgf3TsEvrm0PFe15JQ+570QVxYzEvvHqChK+cng= +google.golang.org/protobuf v1.30.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= @@ -694,6 +786,8 @@ gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo= gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= @@ -702,5 +796,6 @@ honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= +rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4= rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= diff --git a/middlewares/auth.go b/middlewares/auth.go new file mode 100644 index 0000000..46fbc4f --- /dev/null +++ b/middlewares/auth.go @@ -0,0 +1,23 @@ +package middlewares + +import ( + "chat-hex/business/auth" + + "github.com/labstack/echo/v4" +) + +func Auth(next, stop echo.HandlerFunc) echo.HandlerFunc { + return func(c echo.Context) error { + tokenString := c.Request().Header.Get("Authorization") + if tokenString == "" { + return stop(c) + } + + err := auth.NewService().ValidateToken(tokenString) + if err != nil { + return stop(c) + } + + return next(c) + } +} \ No newline at end of file diff --git a/modules/chatrooms/mongo_repo.go b/modules/chatrooms/mongo_repo.go new file mode 100644 index 0000000..2fddc24 --- /dev/null +++ b/modules/chatrooms/mongo_repo.go @@ -0,0 +1,93 @@ +package mongodb + +import ( + "chat-hex/business" + "chat-hex/business/chatrooms" + "context" + + "go.mongodb.org/mongo-driver/bson" + "go.mongodb.org/mongo-driver/mongo" +) + +type MongoDBRepository struct { + collection *mongo.Collection +} + +type collection struct { + Id string `bson:"id"` + Name string `bson:"name"` + Desc string `bson:"desc"` + Code string `bson:"code"` +} + +func newCollection(chatroom chatrooms.Chatroom) *collection { + return &collection{ + chatroom.Id, + chatroom.Name, + chatroom.Desc, + chatroom.Code, + } +} + +func (col *collection) ToChatroom() chatrooms.Chatroom { + var chatroom chatrooms.Chatroom + + chatroom.Id = col.Id + chatroom.Name = col.Name + chatroom.Desc = col.Desc + chatroom.Code = col.Code + + return chatroom +} + +func NewMongoDBRepository(db *mongo.Database) *MongoDBRepository { + return &MongoDBRepository{ + db.Collection("chatrooms"), + } +} + +func (repo *MongoDBRepository) FindChatroomByCode(code string) (*chatrooms.Chatroom, error) { + var col collection + + filter := bson.M{"code": code} + + err := repo.collection.FindOne(context.TODO(), filter).Decode(&col) + if err != nil { + if err == mongo.ErrNoDocuments { + return nil, business.ErrNotFound + } + + return nil, err + } + + chatroom := col.ToChatroom() + + return &chatroom, nil +} + +func (repo *MongoDBRepository) GetChatrooms() ([]chatrooms.Chatroom, error) { + var chatrooms []chatrooms.Chatroom + + filter := bson.M{} + + cursor, err := repo.collection.Find(context.Background(), filter) + if err != nil { + return chatrooms, err + } + + defer cursor.Close(context.Background()) + + for cursor.Next(context.TODO()) { + var col collection + + err := cursor.Decode(&col) + if err != nil { + return chatrooms, err + } + + chatroom := col.ToChatroom() + chatrooms = append(chatrooms, chatroom) + } + + return chatrooms, nil +} \ No newline at end of file diff --git a/modules/messages/mongo_repo.go b/modules/messages/mongo_repo.go new file mode 100644 index 0000000..3cff70e --- /dev/null +++ b/modules/messages/mongo_repo.go @@ -0,0 +1,93 @@ +package mongodb + +import ( + "chat-hex/business/messages" + "context" + "time" + + "go.mongodb.org/mongo-driver/bson" + "go.mongodb.org/mongo-driver/mongo" + "go.mongodb.org/mongo-driver/mongo/options" +) + +type MongoDBRepository struct { + collection *mongo.Collection +} + +type collection struct { + Id string `bson:"_id"` + Content string `bson:"content"` + Sender string `bson:"sender"` + Timestamp time.Time `bson:"timestamp"` + ChatRoom string `bson:"chatroom"` +} + +func newCollection(message messages.Message) *collection { + return &collection{ + message.Id, + message.Content, + message.Sender, + message.Timestamp, + message.ChatRoom, + } +} + +func (col *collection) ToMessage() messages.Message { + var message messages.Message + + message.Id = col.Id + message.Content = col.Content + message.Sender = col.Sender + message.Timestamp = col.Timestamp + message.ChatRoom = col.ChatRoom + + return message +} + +func NewMongoDBRepository(db *mongo.Database) *MongoDBRepository { + return &MongoDBRepository{ + db.Collection("messages"), + } +} + +func (repo *MongoDBRepository) InsertMessage(message messages.Message) error { + col := newCollection(message) + + _, err := repo.collection.InsertOne(context.Background(), col) + if err != nil { + return err + } + + return nil +} + +func (repo *MongoDBRepository) GetMessagesByChatroom(chatroom string) ([]messages.Message, error) { + var messages []messages.Message + + filter := bson.M{"chatroom": chatroom} + + option := options.Find() + option.SetSort(bson.D{{Key: "timestamp", Value: -1}}) + option.SetLimit(50) + + cursor, err := repo.collection.Find(context.Background(), filter, option) + if err != nil { + return messages, err + } + + defer cursor.Close(context.Background()) + + for cursor.Next(context.TODO()) { + var col collection + + err := cursor.Decode(&col) + if err != nil { + return messages, err + } + + message := col.ToMessage() + messages = append(messages, message) + } + + return messages, nil +} \ No newline at end of file diff --git a/modules/user/mongo_repo.go b/modules/user/mongo_repo.go index 70212ab..9f02888 100644 --- a/modules/user/mongo_repo.go +++ b/modules/user/mongo_repo.go @@ -1,9 +1,9 @@ package item import ( + "chat-hex/business" + "chat-hex/business/user" "context" - "go-hexagonal/business" - "go-hexagonal/business/user" "time" "go.mongodb.org/mongo-driver/bson" @@ -63,7 +63,7 @@ func (col *collection) ToUser() user.User { //NewMongoDBRepository Generate mongo DB user repository func NewMongoDBRepository(db *mongo.Database) *MongoDBRepository { return &MongoDBRepository{ - db.Collection("user"), + db.Collection("users"), } } @@ -94,12 +94,12 @@ func (repo *MongoDBRepository) FindAllUserWithPagination(skip int, rowPerPage in var users []user.User - rowPageWithAddtion := rowPerPage + 1 + rowPageWithAddition := rowPerPage + 1 option := options.Find() option.SetSort(bson.D{{Key: "_id", Value: 1}}) option.SetSkip(int64(skip)) - option.SetLimit(int64(rowPageWithAddtion)) + option.SetLimit(int64(rowPageWithAddition)) cursor, err := repo.collection.Find(context.Background(), bson.M{}, option) if err != nil { diff --git a/modules/users/mongo_repo.go b/modules/users/mongo_repo.go new file mode 100644 index 0000000..6e25771 --- /dev/null +++ b/modules/users/mongo_repo.go @@ -0,0 +1,94 @@ +package mongodb + +import ( + "chat-hex/business" + "chat-hex/business/users" + "context" + + "go.mongodb.org/mongo-driver/bson" + "go.mongodb.org/mongo-driver/mongo" +) + +type MongoDBRepository struct { + collection *mongo.Collection +} + +type collection struct { + Id string `bson:"id"` + Email string `bson:"email"` + Password string `bson:"password"` + Name string `bson:"name"` + CurrentRoom string `bson:"currentRoom"` +} + +func newCollection(user users.User) *collection { + return &collection{ + user.Id, + user.Email, + user.Password, + user.Name, + user.CurrentRoom, + } +} + +func (col *collection) ToUser() users.User { + var user users.User + + user.Id = col.Id + user.Email = col.Email + user.Password = col.Password + user.Name = col.Name + user.CurrentRoom = col.CurrentRoom + + return user +} + +func NewMongoDBRepository(db *mongo.Database) *MongoDBRepository { + return &MongoDBRepository{ + db.Collection("users"), + } +} + +func (repo *MongoDBRepository) FindUserByEmail(email string) (*users.User, error) { + var col collection + + filter := bson.M{"email": email} + + if err := repo.collection.FindOne(context.TODO(), filter).Decode(&col); err != nil { + if err == mongo.ErrNoDocuments { + return nil, business.ErrNotFound + } + + return nil, err + } + + user := col.ToUser() + + return &user, nil +} + +func (repo *MongoDBRepository) EnterChatroom(email string, chatroom string) error { + filter := bson.M{"email": email} + + update := bson.M{"$set": bson.M{"currentRoom": chatroom}} + + _, err := repo.collection.UpdateOne(context.Background(), filter, update) + if err != nil { + return err + } + + return nil +} + +func (repo *MongoDBRepository) LeaveChatroom(email string) error { + filter := bson.M{"email": email} + + update := bson.M{"$set": bson.M{"currentRoom": nil}} + + _, err := repo.collection.UpdateOne(context.Background(), filter, update) + if err != nil { + return err + } + + return nil +} \ No newline at end of file diff --git a/util/primiviteIDGenerator/primiviteIDGenerator.go b/util/primitiveIDGenerator/primitiveIDGenerator.go similarity index 53% rename from util/primiviteIDGenerator/primiviteIDGenerator.go rename to util/primitiveIDGenerator/primitiveIDGenerator.go index 7054f0c..c844420 100644 --- a/util/primiviteIDGenerator/primiviteIDGenerator.go +++ b/util/primitiveIDGenerator/primitiveIDGenerator.go @@ -1,8 +1,8 @@ -package primiviteIDGenerator +package primitiveIDGenerator import "go.mongodb.org/mongo-driver/bson/primitive" -//GenerateID Generate 12 byte UUID. It will return 24 hexadimal characters +//GenerateID Generate 12 byte UUID. It will return 24 hexadecimal characters func GenerateID() string { return primitive.NewObjectID().Hex() }