init project
This commit is contained in:
@@ -0,0 +1,5 @@
|
||||
package database
|
||||
|
||||
type Config interface {
|
||||
ConnString() string
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
package db
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
_ "github.com/lib/pq"
|
||||
"go.uber.org/zap"
|
||||
_ "gopkg.in/yaml.v3"
|
||||
"gorm.io/driver/postgres"
|
||||
"gorm.io/gorm"
|
||||
|
||||
"furtuna-be/config"
|
||||
)
|
||||
|
||||
func NewPostgres(c config.Database) (*gorm.DB, error) {
|
||||
dialector := postgres.New(postgres.Config{
|
||||
DSN: c.DSN(),
|
||||
})
|
||||
|
||||
db, err := gorm.Open(dialector, &gorm.Config{})
|
||||
|
||||
//db, err := gorm.Open(dialector, &gorm.Config{
|
||||
// Logger: logger.Default.LogMode(logger.Info), // Enable GORM logging
|
||||
//})
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
zapCfg := zap.NewProductionConfig()
|
||||
zapCfg.Level = zap.NewAtomicLevelAt(zap.DebugLevel) // whatever minimum level
|
||||
zapCfg.DisableCaller = true
|
||||
// logger, _ := zapCfg.Build()
|
||||
// db = gorm.Open(sqldblogger.New(logger), db)
|
||||
|
||||
// ping the database to test the connection
|
||||
sqlDB, err := db.DB()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := sqlDB.Ping(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
sqlDB.SetMaxIdleConns(c.MaxIdleConnectionsInSecond)
|
||||
sqlDB.SetMaxOpenConns(c.MaxOpenConnectionsInSecond)
|
||||
sqlDB.SetConnMaxLifetime(c.ConnectionMaxLifetime())
|
||||
|
||||
fmt.Println("Successfully connected to PostgreSQL database")
|
||||
|
||||
return db, nil
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
package errors
|
||||
|
||||
import "net/http"
|
||||
|
||||
const (
|
||||
Success Code = "20000"
|
||||
ServerError Code = "50000"
|
||||
BadRequest Code = "40000"
|
||||
InvalidRequest Code = "40001"
|
||||
Unauthorized Code = "40100"
|
||||
Forbidden Code = "40300"
|
||||
Timeout Code = "50400"
|
||||
)
|
||||
|
||||
type Code string
|
||||
|
||||
var (
|
||||
codeMap = map[Code]string{
|
||||
Success: "Success",
|
||||
BadRequest: "Bad or invalid request",
|
||||
Unauthorized: "Unauthorized Token",
|
||||
Timeout: "Gateway Timeout",
|
||||
ServerError: "Internal Server Error",
|
||||
Forbidden: "Forbidden",
|
||||
InvalidRequest: "Invalid Request",
|
||||
}
|
||||
|
||||
codeHTTPMap = map[Code]int{
|
||||
Success: http.StatusOK,
|
||||
BadRequest: http.StatusBadRequest,
|
||||
Unauthorized: http.StatusUnauthorized,
|
||||
Timeout: http.StatusGatewayTimeout,
|
||||
ServerError: http.StatusInternalServerError,
|
||||
Forbidden: http.StatusForbidden,
|
||||
InvalidRequest: http.StatusUnprocessableEntity,
|
||||
}
|
||||
)
|
||||
|
||||
func (c Code) GetMessage() string {
|
||||
return codeMap[c]
|
||||
}
|
||||
|
||||
func (c Code) GetHTTPCode() int {
|
||||
return codeHTTPMap[c]
|
||||
}
|
||||
|
||||
func (c Code) GetCode() string {
|
||||
return string(c)
|
||||
}
|
||||
@@ -0,0 +1,95 @@
|
||||
package errors
|
||||
|
||||
import "net/http"
|
||||
|
||||
type ErrType string
|
||||
|
||||
const (
|
||||
errRequestTimeOut ErrType = "Request Timeout to 3rd Party"
|
||||
errConnectTimeOut ErrType = "Connect Timeout to 3rd Party"
|
||||
errFailedExternalCall ErrType = "Failed response from 3rd Party call"
|
||||
errExternalCall ErrType = "error on 3rd Party call"
|
||||
errInvalidRequest ErrType = "Invalid Request"
|
||||
errBadRequest ErrType = "Bad Request"
|
||||
errOrderNotFound ErrType = "Astria order is not found"
|
||||
errCheckoutIDNotDefined ErrType = "Checkout client id not found"
|
||||
errInternalServer ErrType = "Internal Server error"
|
||||
errUserIsNotFound ErrType = "User is not found"
|
||||
errInvalidLogin ErrType = "User email or password is invalid"
|
||||
errUnauthorized ErrType = "Unauthorized"
|
||||
)
|
||||
|
||||
var (
|
||||
ErrorBadRequest = NewServiceException(errBadRequest)
|
||||
ErrorInvalidRequest = NewServiceException(errInvalidRequest)
|
||||
ErrorUnauthorized = NewServiceException(errUnauthorized)
|
||||
ErrorOrderNotFound = NewServiceException(errOrderNotFound)
|
||||
ErrorClientIDNotDefined = NewServiceException(errCheckoutIDNotDefined)
|
||||
ErrorRequestTimeout = NewServiceException(errRequestTimeOut)
|
||||
ErrorExternalCall = NewServiceException(errExternalCall)
|
||||
ErrorFailedExternalCall = NewServiceException(errFailedExternalCall)
|
||||
ErrorConnectionTimeOut = NewServiceException(errConnectTimeOut)
|
||||
ErrorInternalServer = NewServiceException(errInternalServer)
|
||||
ErrorUserIsNotFound = NewServiceException(errUserIsNotFound)
|
||||
ErrorUserInvalidLogin = NewServiceException(errInvalidLogin)
|
||||
)
|
||||
|
||||
type Error interface {
|
||||
ErrorType() ErrType
|
||||
MapErrorsToHTTPCode() int
|
||||
MapErrorsToCode() Code
|
||||
error
|
||||
}
|
||||
|
||||
type ServiceException struct {
|
||||
errorType ErrType
|
||||
message string
|
||||
}
|
||||
|
||||
func NewServiceException(errType ErrType) *ServiceException {
|
||||
return &ServiceException{
|
||||
errorType: errType,
|
||||
message: string(errType),
|
||||
}
|
||||
}
|
||||
|
||||
func (s *ServiceException) ErrorType() ErrType {
|
||||
return s.errorType
|
||||
}
|
||||
|
||||
func (s *ServiceException) Error() string {
|
||||
return s.message
|
||||
}
|
||||
|
||||
func (s *ServiceException) MapErrorsToHTTPCode() int {
|
||||
switch s.ErrorType() {
|
||||
case errBadRequest:
|
||||
return http.StatusBadRequest
|
||||
|
||||
case errInvalidRequest:
|
||||
return http.StatusBadRequest
|
||||
|
||||
case errInvalidLogin:
|
||||
return http.StatusBadRequest
|
||||
|
||||
default:
|
||||
return http.StatusInternalServerError
|
||||
}
|
||||
}
|
||||
|
||||
func (s *ServiceException) MapErrorsToCode() Code {
|
||||
switch s.ErrorType() {
|
||||
|
||||
case errUnauthorized:
|
||||
return Unauthorized
|
||||
|
||||
case errConnectTimeOut:
|
||||
return Timeout
|
||||
|
||||
case errBadRequest:
|
||||
return BadRequest
|
||||
|
||||
default:
|
||||
return ServerError
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
package http
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"time"
|
||||
|
||||
"go.uber.org/zap"
|
||||
|
||||
"furtuna-be/internal/common/logger"
|
||||
)
|
||||
|
||||
type HttpClient struct {
|
||||
Client *http.Client
|
||||
}
|
||||
|
||||
func NewHttpClient() *HttpClient {
|
||||
return &HttpClient{
|
||||
Client: &http.Client{},
|
||||
}
|
||||
}
|
||||
|
||||
func (c *HttpClient) Do(ctx context.Context, req *http.Request) (int, []byte, error) {
|
||||
start := time.Now()
|
||||
logger.ContextLogger(ctx).Info(fmt.Sprintf("Sending request: %v %v", req.Method, req.URL))
|
||||
resp, err := c.Client.Do(req)
|
||||
if err != nil {
|
||||
logger.ContextLogger(ctx).Error(" Failed to send request:", zap.Error(err))
|
||||
return 0, nil, err
|
||||
}
|
||||
|
||||
logger.ContextLogger(ctx).Info(fmt.Sprintf("Received Response: : %v", resp.StatusCode))
|
||||
|
||||
defer resp.Body.Close()
|
||||
body, err := ioutil.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
logger.ContextLogger(ctx).Error(" Failed to read response:", zap.Error(err))
|
||||
return 0, nil, err
|
||||
}
|
||||
|
||||
logger.ContextLogger(ctx).Info(fmt.Sprintf("Latency : %v", time.Since(start)))
|
||||
|
||||
return resp.StatusCode, body, nil
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
package logger
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"furtuna-be/internal/constants"
|
||||
"sync"
|
||||
|
||||
"go.uber.org/zap"
|
||||
)
|
||||
|
||||
var mainLogger *zap.Logger = nil
|
||||
|
||||
var mainLoggerInit sync.Once
|
||||
|
||||
func NewMainLoggerSingleton() *zap.Logger {
|
||||
mainLoggerInit.Do(func() {
|
||||
logger, err := zap.NewProduction()
|
||||
if err != nil {
|
||||
logger.Error("logger initialization failed", zap.Any("error", err))
|
||||
panic(fmt.Sprintf("logger initialization failed %v", err))
|
||||
}
|
||||
logger.Info("logger started")
|
||||
mainLogger = logger
|
||||
})
|
||||
|
||||
return mainLogger
|
||||
}
|
||||
|
||||
func NewMainNoOpLoggerSingleton() *zap.Logger {
|
||||
mainLoggerInit.Do(func() {
|
||||
logger := zap.NewNop()
|
||||
logger.Info("logger started")
|
||||
mainLogger = logger
|
||||
})
|
||||
|
||||
return mainLogger
|
||||
}
|
||||
|
||||
func NewNoOp() *zap.Logger {
|
||||
return zap.NewNop()
|
||||
}
|
||||
|
||||
func GetLogger() *zap.Logger {
|
||||
return mainLogger
|
||||
}
|
||||
|
||||
func ContextLogger(ctx context.Context) *zap.Logger {
|
||||
logger := GetLogger()
|
||||
|
||||
if ctxRqID, ok := ctx.Value(constants.ContextRequestID).(string); ok {
|
||||
return logger.With(zap.String(constants.ContextRequestID, ctxRqID))
|
||||
}
|
||||
|
||||
return logger
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
package mycontext
|
||||
|
||||
import (
|
||||
"context"
|
||||
"furtuna-be/internal/constants/role"
|
||||
"furtuna-be/internal/entity"
|
||||
)
|
||||
|
||||
type ContextKey string
|
||||
|
||||
type Context interface {
|
||||
context.Context
|
||||
|
||||
RequestedBy() int64
|
||||
IsSuperAdmin() bool
|
||||
}
|
||||
|
||||
type MyContextImpl struct {
|
||||
context.Context
|
||||
|
||||
requestedBy int64
|
||||
requestID string
|
||||
branchID int64
|
||||
roleID int
|
||||
}
|
||||
|
||||
func (m *MyContextImpl) RequestedBy() int64 {
|
||||
return m.requestedBy
|
||||
}
|
||||
|
||||
func (m *MyContextImpl) IsSuperAdmin() bool {
|
||||
return m.roleID == int(role.SuperAdmin)
|
||||
}
|
||||
|
||||
func NewMyContext(parent context.Context, claims *entity.JWTAuthClaims) (*MyContextImpl, error) {
|
||||
return &MyContextImpl{
|
||||
Context: parent,
|
||||
requestedBy: claims.UserID,
|
||||
branchID: claims.BranchID,
|
||||
roleID: claims.Role,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func NewContext(parent context.Context) *MyContextImpl {
|
||||
return &MyContextImpl{
|
||||
Context: parent,
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
package request
|
||||
|
||||
import (
|
||||
"context"
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
const (
|
||||
ReqInfoKey reqInfoKeyType = "request-info"
|
||||
)
|
||||
|
||||
func SetTraceId(c *gin.Context, traceId string) {
|
||||
info, exists := c.Get(ReqInfoKey)
|
||||
if exists {
|
||||
parsedInfo := info.(RequestInfo)
|
||||
parsedInfo.TraceId = traceId
|
||||
|
||||
c.Set(ReqInfoKey, parsedInfo)
|
||||
|
||||
return
|
||||
}
|
||||
c.Set(ReqInfoKey, RequestInfo{TraceId: traceId})
|
||||
}
|
||||
|
||||
func SetUserId(c *gin.Context, userId int64) {
|
||||
info, exists := c.Get(ReqInfoKey)
|
||||
if exists {
|
||||
parsedInfo := info.(RequestInfo)
|
||||
parsedInfo.UserId = userId
|
||||
|
||||
c.Set(ReqInfoKey, parsedInfo)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
c.Set(ReqInfoKey, RequestInfo{UserId: userId})
|
||||
}
|
||||
|
||||
func SetUserContext(c *gin.Context, payload map[string]interface{}) {
|
||||
c.Set(ReqInfoKey, RequestInfo{
|
||||
UserId: int64(payload["userId"].(float64)),
|
||||
Role: payload["role"].(string),
|
||||
})
|
||||
}
|
||||
|
||||
func ContextWithReqInfo(c *gin.Context) context.Context {
|
||||
info, ok := c.Get(ReqInfoKey)
|
||||
if ok {
|
||||
return WithRequestInfo(c, info.(RequestInfo))
|
||||
}
|
||||
|
||||
return WithRequestInfo(c, RequestInfo{})
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
package request
|
||||
|
||||
import "context"
|
||||
|
||||
type requestInfoKey int
|
||||
|
||||
const (
|
||||
key requestInfoKey = iota
|
||||
)
|
||||
|
||||
type RequestInfo struct {
|
||||
UserId int64
|
||||
TraceId string
|
||||
Permissions map[string]bool
|
||||
Role string
|
||||
}
|
||||
|
||||
func WithRequestInfo(ctx context.Context, info RequestInfo) context.Context {
|
||||
return context.WithValue(ctx, key, info)
|
||||
}
|
||||
|
||||
func GetRequestInfo(ctx context.Context) (requestInfo RequestInfo, ok bool) {
|
||||
requestInfo, ok = ctx.Value(key).(RequestInfo)
|
||||
return
|
||||
}
|
||||
|
||||
type reqInfoKeyType = string
|
||||
|
||||
const (
|
||||
reqInfoKey reqInfoKeyType = "request-info"
|
||||
)
|
||||
|
||||
func GetReqInfo(c context.Context) RequestInfo {
|
||||
info := c.Value(reqInfoKey)
|
||||
if info != nil {
|
||||
return info.(RequestInfo)
|
||||
}
|
||||
|
||||
return RequestInfo{}
|
||||
}
|
||||
Reference in New Issue
Block a user