Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(identifier): add create and get identifier #5

Merged
merged 2 commits into from
Jan 30, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 16 additions & 2 deletions cmd/daemon/daemon.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,9 @@ import (
"github.com/dezh-tech/panda/infrastructures/redis"
"github.com/dezh-tech/panda/pkg/logger"
"github.com/dezh-tech/panda/repositories"
service "github.com/dezh-tech/panda/services/domain"
domainService "github.com/dezh-tech/panda/services/domain"
identifierService "github.com/dezh-tech/panda/services/identifier"
userService "github.com/dezh-tech/panda/services/user"
)

type Daemon struct {
Expand All @@ -38,10 +40,22 @@ func New(cfg *config.Config) (*Daemon, error) {
return nil, err
}

// repo
domainRepo := repositories.NewDomainRepository(db.Client, cfg.Database.DBName,
time.Duration(cfg.Database.QueryTimeout)*time.Millisecond)

hs := http.New(cfg.HTTPServer, service.NewDomainService(domainRepo))
userRepo := repositories.NewUserRepository(db.Client, cfg.Database.DBName,
time.Duration(cfg.Database.QueryTimeout)*time.Millisecond)

identifierRepo := repositories.NewIdentifierRepository(db.Client, cfg.Database.DBName,
time.Duration(cfg.Database.QueryTimeout)*time.Millisecond)

// services
domainSrv := domainService.NewDomainService(domainRepo)
userSrv := userService.NewUserService(userRepo)
identifierSrv := identifierService.NewIdentifierService(identifierRepo, domainSrv, userSrv)

hs := http.New(cfg.HTTPServer, domainSrv, userSrv, identifierSrv)
gs := grpc.New(&cfg.GRPCServer, r, db, time.Now())

return &Daemon{
Expand Down
1 change: 1 addition & 0 deletions deliveries/http/handlers/domain/domain_get.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ func (dh Domain) getAll(c echo.Context) error {
domainsRes := make([]DomainGetResponse, 0)
for _, d := range *domains {
domainsRes = append(domainsRes, DomainGetResponse{
ID: d.ID,
Domain: d.Domain,
BasePricePerIdentifier: d.BasePricePerIdentifier,
DefaultTTL: d.DefaultTTL,
Expand Down
9 changes: 5 additions & 4 deletions deliveries/http/handlers/domain/domain_response.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,9 @@ type DomainCreateResponse struct {
}

type DomainGetResponse struct {
Domain string `json:"domain"`
BasePricePerIdentifier uint `json:"base_price_per_identifier"`
DefaultTTL uint32 `json:"default_ttl"`
Status string `json:"status"`
ID interface{} `json:"id"`
Domain string `json:"domain"`
BasePricePerIdentifier uint `json:"base_price_per_identifier"`
DefaultTTL uint32 `json:"default_ttl"`
Status string `json:"status"`
}
65 changes: 65 additions & 0 deletions deliveries/http/handlers/identifier/identifier_create.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
package handlers

import (
"errors"
"net/http"

"github.com/dezh-tech/panda/pkg"
"github.com/dezh-tech/panda/pkg/validator"
domainService "github.com/dezh-tech/panda/services/domain"
identifierService "github.com/dezh-tech/panda/services/identifier"
userService "github.com/dezh-tech/panda/services/user"
"github.com/labstack/echo/v4"
)

// CreateIdentifier creates a new identifier.
//
// @Summary Create a new identifier
// @Description Creates a new identifier with the specified attributes. Returns success if the identifier is created successfully or relevant error messages if the creation fails.
// @Tags identifiers
// @Accept json
// @Produce json
// @Param identifier body IdentifierCreateRequest true "Identifier creation payload"
// @Success 200 {object} pkg.ResponseDto "Identifier created successfully"
// @Failure 400 {object} pkg.ResponseDto{error=validator.Varror} "Bad Request - Validation error or invalid input"
// @Failure 409 {object} pkg.ResponseDto{error=validator.Varror} "Conflict - Identifier already exists"
// @Failure 500 {object} pkg.ResponseDto{error=validator.Varror} "Internal Server Error - Unexpected server error"
// @Router /identifiers [post]
func (dh Identifier) create(c echo.Context) error {
req := new(IdentifierCreateRequest)
if err := c.Bind(req); err != nil {
return echo.NewHTTPError(http.StatusBadRequest, pkg.ResponseDto{
Success: false,
Error: validator.Varror{Error: "invalid input"},
})
}

// Validate the request payload
v := validator.NewValidator()
validationErrors := v.Validate(req)
if validationErrors != nil {
return echo.NewHTTPError(http.StatusBadRequest, pkg.ResponseDto{
Success: false,
Error: validator.Varror{ValidationErrors: validationErrors},
})
}

// Call the domain service to create the domain
ctx := c.Request().Context()
_, err := dh.service.Create(ctx, req.Name, req.DomainID, req.Pubkey)
if err != nil {
if errors.Is(err, domainService.ErrNotFound) || errors.Is(err, userService.ErrNotFound) || errors.Is(err, identifierService.ErrIsExist) || errors.Is(err, identifierService.Err) {
return echo.NewHTTPError(http.StatusConflict, pkg.ResponseDto{
Success: false,
Error: validator.Varror{Error: err.Error()},
})
}

return echo.NewHTTPError(http.StatusInternalServerError, pkg.ResponseDto{
Success: false,
Error: validator.Varror{Error: echo.ErrInternalServerError.Error()},
})
}

return c.JSON(http.StatusOK, pkg.ResponseDto{Success: true})
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
package handlers

import (
"net/http"

"github.com/dezh-tech/panda/pkg"
"github.com/dezh-tech/panda/pkg/validator"
"github.com/labstack/echo/v4"
)

// IdentifierGetAllByPubkey retrieves all identifiers.
//
// @Summary Retrieve all identifiers
// @Description Get a list of all identifiers associated with the provided public key.
// @Tags identifiers
// @Accept json
// @Produce json
// @Param Authorization header string true "Authorization"
// @Success 200 {object} pkg.ResponseDto{data=[]IdentifierGetResponse} "identifiers retrieved successfully"
// @Failure 500 {object} pkg.ResponseDto[string] "Internal Server Error"
// @Router /identifiers [get]
func (dh Identifier) getAllByPubkey(c echo.Context) error {
ctx := c.Request().Context()
idns, err := dh.service.GetAllByPubKey(ctx, c.Get("pubkey").(string))
if err != nil {
return echo.NewHTTPError(http.StatusInternalServerError, pkg.ResponseDto{
Success: false,
Error: validator.Varror{Error: echo.ErrInternalServerError.Error()},
})
}

idnRes := make([]IdentifierGetResponse, 0)
for _, d := range *idns {

Check failure on line 33 in deliveries/http/handlers/identifier/identifier_get_all_by_pubkey.go

View workflow job for this annotation

GitHub Actions / lint

rangeValCopy: each iteration copies 152 bytes (consider pointers or indexing) (gocritic)
idnRes = append(idnRes, IdentifierGetResponse{
Name: d.Name,
Pubkey: d.Pubkey,
DomainID: d.DomainID,
FullIdentifier: d.FullIdentifier,
ExpiresAt: d.ExpiresAt,
})
}

// Respond with the created domain's ID
return c.JSON(http.StatusOK, pkg.ResponseDto{Success: true, Data: idnRes})
}
13 changes: 13 additions & 0 deletions deliveries/http/handlers/identifier/identifier_handler.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package handlers

import service "github.com/dezh-tech/panda/services/identifier"

type Identifier struct {
service service.Identifier
}

func NewIdentifierService(identifierSvc service.Identifier) Identifier {
return Identifier{
service: identifierSvc,
}
}
7 changes: 7 additions & 0 deletions deliveries/http/handlers/identifier/identifier_request.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package handlers

type IdentifierCreateRequest struct {
DomainID string `json:"domain_id" validate:"required"`

Check failure on line 4 in deliveries/http/handlers/identifier/identifier_request.go

View workflow job for this annotation

GitHub Actions / lint

tag is not aligned, should be: json:"domain_id" validate:"required" (tagalign)
Pubkey string `json:"pubkey" validate:"required"`
Name string `json:"name" validate:"required"`
}
11 changes: 11 additions & 0 deletions deliveries/http/handlers/identifier/identifier_response.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package handlers

import "time"

type IdentifierGetResponse struct {
Name string `json:"name"`
Pubkey string `json:"pubkey"`
DomainID string `json:"domain_id"`
ExpiresAt time.Time `json:"expires_at"`
FullIdentifier string `json:"full_identifier"`
}
13 changes: 13 additions & 0 deletions deliveries/http/handlers/identifier/identifier_routes.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package handlers

import (
middleware "github.com/dezh-tech/panda/deliveries/http/middlewares"
"github.com/labstack/echo/v4"
)

func (dh Identifier) SetIdentifierRoutes(e *echo.Echo) {
userGroup := e.Group("/identifiers")

userGroup.POST("", dh.create)
userGroup.GET("", dh.getAllByPubkey, middleware.Auth("a"))
}
63 changes: 63 additions & 0 deletions deliveries/http/handlers/user/user_create.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
package handlers

import (
"errors"
"net/http"

"github.com/dezh-tech/panda/pkg"
"github.com/dezh-tech/panda/pkg/validator"
userService "github.com/dezh-tech/panda/services/user"
"github.com/labstack/echo/v4"
)

// CreateUser creates a new user.
//
// @Summary Create a new user
// @Description Creates a new user using the provided public key. The request payload must include a valid public key for successful user creation.
// @Tags users
// @Accept json
// @Produce json
// @Param user body UserCreateRequest true "Payload containing the public key for user creation"
// @Success 200 {object} pkg.ResponseDto "User created successfully"
// @Failure 400 {object} pkg.ResponseDto[validator.Varror] "Bad Request - Invalid input or validation errors"
// @Failure 409 {object} pkg.ResponseDto[validator.Varror] "Conflict - User with the specified public key already exists"
// @Failure 500 {object} pkg.ResponseDto[string] "Internal Server Error - An unexpected error occurred"
// @Router /users [post]
func (uh User) create(c echo.Context) error {
req := new(UserCreateRequest)
if err := c.Bind(req); err != nil {
return echo.NewHTTPError(http.StatusBadRequest, pkg.ResponseDto{
Success: false,
Error: validator.Varror{Error: "invalid input"},
})
}

// Validate the request payload
v := validator.NewValidator()
validationErrors := v.Validate(req)
if validationErrors != nil {
return echo.NewHTTPError(http.StatusBadRequest, pkg.ResponseDto{
Success: false,
Error: validator.Varror{ValidationErrors: validationErrors},
})
}

// Call the domain service to create the domain
ctx := c.Request().Context()
_, err := uh.service.Create(ctx, req.Pubkey)
if err != nil {
if errors.Is(err, userService.ErrIsExist) {
return echo.NewHTTPError(http.StatusConflict, pkg.ResponseDto{
Success: false,
Error: validator.Varror{Error: err.Error()},
})
}

return echo.NewHTTPError(http.StatusInternalServerError, pkg.ResponseDto{
Success: false,
Error: validator.Varror{Error: echo.ErrInternalServerError.Error()},
})
}

return c.JSON(http.StatusOK, pkg.ResponseDto{Success: true, Data: nil})
}
5 changes: 5 additions & 0 deletions deliveries/http/handlers/user/user_request.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package handlers

type UserCreateRequest struct {
Pubkey string `json:"pubKey" validate:"required"`

Check failure on line 4 in deliveries/http/handlers/user/user_request.go

View workflow job for this annotation

GitHub Actions / lint

tag is not aligned , should be: json:"pubKey" validate:"required" (tagalign)
}
11 changes: 11 additions & 0 deletions deliveries/http/handlers/user/user_routes.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package handlers

import (
"github.com/labstack/echo/v4"
)

func (dh User) SetUserRoutes(e *echo.Echo) {
userGroup := e.Group("/users")

userGroup.POST("", dh.create)
}
10 changes: 8 additions & 2 deletions deliveries/http/http_handlers.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
package http

import (
handlers "github.com/dezh-tech/panda/deliveries/http/handlers/domain"
domainHandlers "github.com/dezh-tech/panda/deliveries/http/handlers/domain"
identifierHandlers "github.com/dezh-tech/panda/deliveries/http/handlers/identifier"
userHandlers "github.com/dezh-tech/panda/deliveries/http/handlers/user"
_ "github.com/dezh-tech/panda/docs" // revive:disable-line:blank-imports Justification: Required for Swagger documentation
"github.com/labstack/echo/v4"
echoSwagger "github.com/swaggo/echo-swagger"
Expand All @@ -23,11 +25,15 @@ import (
// @BasePath /

type Handlers struct {
domain handlers.Domain
domain domainHandlers.Domain
user userHandlers.User
identifier identifierHandlers.Identifier
}

func (h *Handlers) Start(r *echo.Echo) {
h.domain.SetDomainRoutes(r)
h.user.SetUserRoutes(r)
h.identifier.SetIdentifierRoutes(r)

r.GET("/swagger/*", echoSwagger.WrapHandler)
}
14 changes: 10 additions & 4 deletions deliveries/http/http_server.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,12 @@
import (
"fmt"

handlers "github.com/dezh-tech/panda/deliveries/http/handlers/domain"
service "github.com/dezh-tech/panda/services/domain"
domain "github.com/dezh-tech/panda/deliveries/http/handlers/domain"
identifier "github.com/dezh-tech/panda/deliveries/http/handlers/identifier"
user "github.com/dezh-tech/panda/deliveries/http/handlers/user"
domainService "github.com/dezh-tech/panda/services/domain"
identifierService "github.com/dezh-tech/panda/services/identifier"
userService "github.com/dezh-tech/panda/services/user"
"github.com/labstack/echo/v4"
)

Expand All @@ -14,18 +18,20 @@
handlers Handlers
}

func New(config Config, userSvc service.Domain) Server {
func New(config Config, domainService domainService.Domain, userService userService.User, identifierService identifierService.Identifier) Server {

Check failure on line 21 in deliveries/http/http_server.go

View workflow job for this annotation

GitHub Actions / lint

importShadow: shadow of imported from 'github.com/dezh-tech/panda/services/domain' package 'domainService' (gocritic)
return Server{
Router: echo.New(),
config: config,

handlers: Handlers{
domain: handlers.NewDomainService(userSvc),
domain: domain.NewDomainService(domainService),
user: user.NewUserService(userService),
identifier: identifier.NewIdentifierService(identifierService),
},
}
}

func (s Server) Start() error {

Check failure on line 34 in deliveries/http/http_server.go

View workflow job for this annotation

GitHub Actions / lint

hugeParam: s is heavy (112 bytes); consider passing it by pointer (gocritic)
s.handlers.Start(s.Router)

address := fmt.Sprintf(":%d", s.config.Port)
Expand All @@ -36,7 +42,7 @@
return nil
}

func (s Server) Stop() error {

Check failure on line 45 in deliveries/http/http_server.go

View workflow job for this annotation

GitHub Actions / lint

hugeParam: s is heavy (112 bytes); consider passing it by pointer (gocritic)
if err := s.Router.Close(); err != nil {
return err
}
Expand Down
Loading
Loading