2025-01-11 18:44:55 +01:00
package handlers
import (
"context"
"net/http"
2025-03-09 21:16:42 +01:00
"github.com/go-pkgz/routegroup"
2025-02-28 08:29:40 +01:00
2025-03-09 21:16:42 +01:00
"github.com/h44z/wg-portal/internal/app/api/core/request"
"github.com/h44z/wg-portal/internal/app/api/core/respond"
2025-01-11 18:44:55 +01:00
"github.com/h44z/wg-portal/internal/app/api/v1/models"
"github.com/h44z/wg-portal/internal/domain"
)
type InterfaceEndpointInterfaceService interface {
GetAll ( context . Context ) ( [ ] domain . Interface , [ ] [ ] domain . Peer , error )
GetById ( context . Context , domain . InterfaceIdentifier ) ( * domain . Interface , [ ] domain . Peer , error )
2025-05-09 16:19:36 +02:00
Prepare ( context . Context ) ( * domain . Interface , error )
2025-01-11 18:44:55 +01:00
Create ( context . Context , * domain . Interface ) ( * domain . Interface , error )
Update ( context . Context , domain . InterfaceIdentifier , * domain . Interface ) ( * domain . Interface , [ ] domain . Peer , error )
Delete ( context . Context , domain . InterfaceIdentifier ) error
}
type InterfaceEndpoint struct {
2025-03-09 21:16:42 +01:00
interfaces InterfaceEndpointInterfaceService
authenticator Authenticator
validator Validator
2025-01-11 18:44:55 +01:00
}
2025-03-09 21:16:42 +01:00
func NewInterfaceEndpoint (
authenticator Authenticator ,
validator Validator ,
interfaceService InterfaceEndpointInterfaceService ,
) * InterfaceEndpoint {
2025-01-11 18:44:55 +01:00
return & InterfaceEndpoint {
2025-03-09 21:16:42 +01:00
authenticator : authenticator ,
validator : validator ,
interfaces : interfaceService ,
2025-01-11 18:44:55 +01:00
}
}
func ( e InterfaceEndpoint ) GetName ( ) string {
return "InterfaceEndpoint"
}
2025-03-09 21:16:42 +01:00
func ( e InterfaceEndpoint ) RegisterRoutes ( g * routegroup . Bundle ) {
apiGroup := g . Mount ( "/interface" )
apiGroup . Use ( e . authenticator . LoggedIn ( ScopeAdmin ) )
2025-01-11 18:44:55 +01:00
2025-03-09 21:16:42 +01:00
apiGroup . HandleFunc ( "GET /all" , e . handleAllGet ( ) )
apiGroup . HandleFunc ( "GET /by-id/{id}" , e . handleByIdGet ( ) )
2025-01-11 18:44:55 +01:00
2025-05-09 16:19:36 +02:00
apiGroup . HandleFunc ( "GET /prepare" , e . handlePrepareGet ( ) )
2025-03-09 21:16:42 +01:00
apiGroup . HandleFunc ( "POST /new" , e . handleCreatePost ( ) )
apiGroup . HandleFunc ( "PUT /by-id/{id}" , e . handleUpdatePut ( ) )
apiGroup . HandleFunc ( "DELETE /by-id/{id}" , e . handleDelete ( ) )
2025-01-11 18:44:55 +01:00
}
// handleAllGet returns a gorm Handler function.
//
// @ID interface_handleAllGet
// @Tags Interfaces
// @Summary Get all interface records.
// @Produce json
// @Success 200 {object} []models.Interface
// @Failure 401 {object} models.Error
// @Failure 500 {object} models.Error
// @Router /interface/all [get]
// @Security BasicAuth
2025-03-09 21:16:42 +01:00
func ( e InterfaceEndpoint ) handleAllGet ( ) http . HandlerFunc {
return func ( w http . ResponseWriter , r * http . Request ) {
allInterfaces , allPeersPerInterface , err := e . interfaces . GetAll ( r . Context ( ) )
2025-01-11 18:44:55 +01:00
if err != nil {
2025-03-09 21:16:42 +01:00
status , model := ParseServiceError ( err )
respond . JSON ( w , status , model )
2025-01-11 18:44:55 +01:00
return
}
2025-03-09 21:16:42 +01:00
respond . JSON ( w , http . StatusOK , models . NewInterfaces ( allInterfaces , allPeersPerInterface ) )
2025-01-11 18:44:55 +01:00
}
}
// handleByIdGet returns a gorm Handler function.
//
// @ID interfaces_handleByIdGet
// @Tags Interfaces
// @Summary Get a specific interface record by its identifier.
// @Param id path string true "The interface identifier."
// @Produce json
// @Success 200 {object} models.Interface
// @Failure 401 {object} models.Error
// @Failure 403 {object} models.Error
// @Failure 404 {object} models.Error
// @Failure 500 {object} models.Error
// @Router /interface/by-id/{id} [get]
// @Security BasicAuth
2025-03-09 21:16:42 +01:00
func ( e InterfaceEndpoint ) handleByIdGet ( ) http . HandlerFunc {
return func ( w http . ResponseWriter , r * http . Request ) {
id := request . Path ( r , "id" )
2025-01-11 18:44:55 +01:00
if id == "" {
2025-03-09 21:16:42 +01:00
respond . JSON ( w , http . StatusBadRequest ,
models . Error { Code : http . StatusBadRequest , Message : "missing interface id" } )
2025-01-11 18:44:55 +01:00
return
}
2025-03-09 21:16:42 +01:00
iface , interfacePeers , err := e . interfaces . GetById ( r . Context ( ) , domain . InterfaceIdentifier ( id ) )
2025-01-11 18:44:55 +01:00
if err != nil {
2025-03-09 21:16:42 +01:00
status , model := ParseServiceError ( err )
respond . JSON ( w , status , model )
2025-01-11 18:44:55 +01:00
return
}
2025-03-09 21:16:42 +01:00
respond . JSON ( w , http . StatusOK , models . NewInterface ( iface , interfacePeers ) )
2025-01-11 18:44:55 +01:00
}
}
2025-05-09 16:19:36 +02:00
// handlePrepareGet returns a gorm handler function.
//
// @ID interfaces_handlePrepareGet
// @Tags Interfaces
// @Summary Prepare a new interface record.
// @Description This endpoint returns a new interface with default values (fresh key pair, valid name, new IP address pool, ...).
// @Produce json
// @Success 200 {object} models.Interface
// @Failure 401 {object} models.Error
// @Failure 403 {object} models.Error
// @Failure 500 {object} models.Error
// @Router /interface/prepare [get]
// @Security BasicAuth
func ( e InterfaceEndpoint ) handlePrepareGet ( ) http . HandlerFunc {
return func ( w http . ResponseWriter , r * http . Request ) {
iface , err := e . interfaces . Prepare ( r . Context ( ) )
if err != nil {
status , model := ParseServiceError ( err )
respond . JSON ( w , status , model )
return
}
respond . JSON ( w , http . StatusOK , models . NewInterface ( iface , nil ) )
}
}
2025-01-11 18:44:55 +01:00
// handleCreatePost returns a gorm handler function.
//
// @ID interfaces_handleCreatePost
// @Tags Interfaces
// @Summary Create a new interface record.
2025-05-09 16:19:36 +02:00
// @Description This endpoint creates a new interface with the provided data. All required fields must be filled (e.g. name, private key, public key, ...).
2025-01-11 18:44:55 +01:00
// @Param request body models.Interface true "The interface data."
// @Produce json
// @Success 200 {object} models.Interface
// @Failure 400 {object} models.Error
// @Failure 401 {object} models.Error
// @Failure 403 {object} models.Error
// @Failure 409 {object} models.Error
// @Failure 500 {object} models.Error
// @Router /interface/new [post]
// @Security BasicAuth
2025-03-09 21:16:42 +01:00
func ( e InterfaceEndpoint ) handleCreatePost ( ) http . HandlerFunc {
return func ( w http . ResponseWriter , r * http . Request ) {
2025-01-11 18:44:55 +01:00
var iface models . Interface
2025-03-09 21:16:42 +01:00
if err := request . BodyJson ( r , & iface ) ; err != nil {
respond . JSON ( w , http . StatusBadRequest , models . Error { Code : http . StatusBadRequest , Message : err . Error ( ) } )
return
}
if err := e . validator . Struct ( iface ) ; err != nil {
respond . JSON ( w , http . StatusBadRequest , models . Error { Code : http . StatusBadRequest , Message : err . Error ( ) } )
2025-01-11 18:44:55 +01:00
return
}
2025-03-09 21:16:42 +01:00
newInterface , err := e . interfaces . Create ( r . Context ( ) , models . NewDomainInterface ( & iface ) )
2025-01-11 18:44:55 +01:00
if err != nil {
2025-03-09 21:16:42 +01:00
status , model := ParseServiceError ( err )
respond . JSON ( w , status , model )
2025-01-11 18:44:55 +01:00
return
}
2025-03-09 21:16:42 +01:00
respond . JSON ( w , http . StatusOK , models . NewInterface ( newInterface , nil ) )
2025-01-11 18:44:55 +01:00
}
}
// handleUpdatePut returns a gorm handler function.
//
// @ID interfaces_handleUpdatePut
// @Tags Interfaces
// @Summary Update an interface record.
2025-05-09 16:19:36 +02:00
// @Description This endpoint updates an existing interface with the provided data. All required fields must be filled (e.g. name, private key, public key, ...).
2025-01-11 18:44:55 +01:00
// @Param id path string true "The interface identifier."
// @Param request body models.Interface true "The interface data."
// @Produce json
// @Success 200 {object} models.Interface
// @Failure 400 {object} models.Error
// @Failure 401 {object} models.Error
// @Failure 403 {object} models.Error
// @Failure 404 {object} models.Error
// @Failure 500 {object} models.Error
// @Router /interface/by-id/{id} [put]
// @Security BasicAuth
2025-03-09 21:16:42 +01:00
func ( e InterfaceEndpoint ) handleUpdatePut ( ) http . HandlerFunc {
return func ( w http . ResponseWriter , r * http . Request ) {
id := request . Path ( r , "id" )
2025-01-11 18:44:55 +01:00
if id == "" {
2025-03-09 21:16:42 +01:00
respond . JSON ( w , http . StatusBadRequest ,
models . Error { Code : http . StatusBadRequest , Message : "missing interface id" } )
2025-01-11 18:44:55 +01:00
return
}
var iface models . Interface
2025-03-09 21:16:42 +01:00
if err := request . BodyJson ( r , & iface ) ; err != nil {
respond . JSON ( w , http . StatusBadRequest , models . Error { Code : http . StatusBadRequest , Message : err . Error ( ) } )
return
}
if err := e . validator . Struct ( iface ) ; err != nil {
respond . JSON ( w , http . StatusBadRequest , models . Error { Code : http . StatusBadRequest , Message : err . Error ( ) } )
return
}
if id != iface . Identifier {
respond . JSON ( w , http . StatusBadRequest ,
models . Error { Code : http . StatusBadRequest , Message : "interface id mismatch" } )
2025-01-11 18:44:55 +01:00
return
}
updatedInterface , updatedInterfacePeers , err := e . interfaces . Update (
2025-03-09 21:16:42 +01:00
r . Context ( ) ,
2025-01-11 18:44:55 +01:00
domain . InterfaceIdentifier ( id ) ,
models . NewDomainInterface ( & iface ) ,
)
if err != nil {
2025-03-09 21:16:42 +01:00
status , model := ParseServiceError ( err )
respond . JSON ( w , status , model )
2025-01-11 18:44:55 +01:00
return
}
2025-03-09 21:16:42 +01:00
respond . JSON ( w , http . StatusOK , models . NewInterface ( updatedInterface , updatedInterfacePeers ) )
2025-01-11 18:44:55 +01:00
}
}
// handleDelete returns a gorm handler function.
//
// @ID interfaces_handleDelete
// @Tags Interfaces
// @Summary Delete the interface record.
// @Param id path string true "The interface identifier."
// @Produce json
// @Success 204 "No content if deletion was successful."
// @Failure 400 {object} models.Error
// @Failure 401 {object} models.Error
// @Failure 403 {object} models.Error
// @Failure 404 {object} models.Error
// @Failure 500 {object} models.Error
// @Router /interface/by-id/{id} [delete]
// @Security BasicAuth
2025-03-09 21:16:42 +01:00
func ( e InterfaceEndpoint ) handleDelete ( ) http . HandlerFunc {
return func ( w http . ResponseWriter , r * http . Request ) {
id := request . Path ( r , "id" )
2025-01-11 18:44:55 +01:00
if id == "" {
2025-03-09 21:16:42 +01:00
respond . JSON ( w , http . StatusBadRequest ,
models . Error { Code : http . StatusBadRequest , Message : "missing interface id" } )
2025-01-11 18:44:55 +01:00
return
}
2025-03-09 21:16:42 +01:00
err := e . interfaces . Delete ( r . Context ( ) , domain . InterfaceIdentifier ( id ) )
2025-01-11 18:44:55 +01:00
if err != nil {
2025-03-09 21:16:42 +01:00
status , model := ParseServiceError ( err )
respond . JSON ( w , status , model )
2025-01-11 18:44:55 +01:00
return
}
2025-03-09 21:16:42 +01:00
respond . Status ( w , http . StatusNoContent )
2025-01-11 18:44:55 +01:00
}
}