Skip to content
New issue

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

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

Already on GitHub? # to your account

feat(SPV-1478): migrate existing admin v2 endpoints to openapi3 #899

Merged
merged 20 commits into from
Feb 14, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
700a9d3
feat(SPV-1478): migrate existing admin users endpoint to openapi3 imp…
pawellewandowski98 Feb 8, 2025
7b9f9bc
chore(SPV-1478): fix linter errors
pawellewandowski98 Feb 8, 2025
cab6e35
chore: require fields in models
pawellewandowski98 Feb 9, 2025
2730aec
chore: regenerate models
pawellewandowski98 Feb 9, 2025
e35b2ea
chore: update response description
pawellewandowski98 Feb 9, 2025
c62bc88
feat: change the way of creating servers
pawellewandowski98 Feb 10, 2025
95b327a
Merge branch 'main' into feat/SPV-1478-migrate-admin-endpoints
pawellewandowski98 Feb 10, 2025
6ff6a5a
chore: regenerate api
pawellewandowski98 Feb 10, 2025
a96c3e2
chore: update api structures
pawellewandowski98 Feb 11, 2025
71ed788
chore: regenerate api
pawellewandowski98 Feb 11, 2025
c0398d5
Merge remote-tracking branch 'origin/main' into feat/SPV-1478-migrate…
dorzepowski Feb 12, 2025
958fbc6
fix: fixes after merge of main
dorzepowski Feb 13, 2025
8ff6321
feat: use operation ids
dorzepowski Feb 13, 2025
3fdc27f
feat: shorten names of generated models
dorzepowski Feb 13, 2025
986df03
feat: use generated models in endpoint handlers
dorzepowski Feb 13, 2025
0230ff4
Merge remote-tracking branch 'origin/main' into feat/SPV-1478-migrate…
dorzepowski Feb 13, 2025
423dfcc
chore: fix linter
dorzepowski Feb 13, 2025
4ba8a7c
adjust error on admin create user
dorzepowski Feb 14, 2025
a4b742b
remove user endpoints tag from shared config
dorzepowski Feb 14, 2025
0b22239
Merge remote-tracking branch 'origin/main' into feat/SPV-1478-migrate…
dorzepowski Feb 14, 2025
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
8 changes: 4 additions & 4 deletions actions/v2/admin/internal/mapping/paymail.go
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
package mapping

import (
"github.com/bitcoin-sv/spv-wallet/api"
"github.com/bitcoin-sv/spv-wallet/engine/v2/paymails/paymailsmodels"
"github.com/bitcoin-sv/spv-wallet/models/response/adminresponse"
)

// PaymailToAdminResponse maps a paymail to a response
func PaymailToAdminResponse(p *paymailsmodels.Paymail) adminresponse.Paymail {
return adminresponse.Paymail{
ID: p.ID,
func PaymailToAdminResponse(p *paymailsmodels.Paymail) api.ModelsPaymail {
return api.ModelsPaymail{
Id: p.ID,
Alias: p.Alias,
Domain: p.Domain,
Paymail: p.Alias + "@" + p.Domain,
Expand Down
14 changes: 7 additions & 7 deletions actions/v2/admin/internal/mapping/user.go
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
package mapping

import (
"github.com/bitcoin-sv/spv-wallet/api"
"github.com/bitcoin-sv/spv-wallet/engine/v2/users/usersmodels"
"github.com/bitcoin-sv/spv-wallet/lox"
"github.com/bitcoin-sv/spv-wallet/models/response/adminresponse"
"github.com/samber/lo"
)

// UserToResponse maps a user to a response
func UserToResponse(u *usersmodels.User) adminresponse.User {
return adminresponse.User{
ID: u.ID,
func UserToResponse(u *usersmodels.User) api.ModelsUser {
return api.ModelsUser{
Id: u.ID,
CreatedAt: u.CreatedAt,
UpdatedAt: u.UpdatedAt,
PublicKey: u.PublicKey,
Expand All @@ -19,9 +19,9 @@ func UserToResponse(u *usersmodels.User) adminresponse.User {
}

// UsersPaymailToResponse maps a user's paymail to a response
func UsersPaymailToResponse(p *usersmodels.Paymail) adminresponse.Paymail {
return adminresponse.Paymail{
ID: p.ID,
func UsersPaymailToResponse(p *usersmodels.Paymail) api.ModelsPaymail {
return api.ModelsPaymail{
Id: p.ID,
Alias: p.Alias,
Domain: p.Domain,
Paymail: p.Alias + "@" + p.Domain,
Expand Down
11 changes: 0 additions & 11 deletions actions/v2/admin/register.go

This file was deleted.

18 changes: 14 additions & 4 deletions actions/v2/admin/server.go
Original file line number Diff line number Diff line change
@@ -1,9 +1,19 @@
package admin

// APIAdmin represents server with admin API endpoints
type APIAdmin struct{}
import (
"github.com/bitcoin-sv/spv-wallet/actions/v2/admin/users"
"github.com/bitcoin-sv/spv-wallet/engine"
"github.com/rs/zerolog"
)

// APIAdmin represents server with API endpoints
type APIAdmin struct {
users.APIAdminUsers
}

// NewAPIAdmin creates a new APIAdmin
func NewAPIAdmin() *APIAdmin {
return &APIAdmin{}
func NewAPIAdmin(spvWalletEngine engine.ClientInterface, logger *zerolog.Logger) APIAdmin {
return APIAdmin{
users.NewAPIAdminUsers(spvWalletEngine, logger),
}
}
4 changes: 2 additions & 2 deletions actions/v2/admin/status.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import (
"github.com/gin-gonic/gin"
)

// GetApiV2AdminStatus return the status of the server only after admin authentication
func (s *APIAdmin) GetApiV2AdminStatus(c *gin.Context) {
// AdminStatus return the status of the server only after admin authentication
func (s *APIAdmin) AdminStatus(c *gin.Context) {
c.Status(http.StatusOK)
}
40 changes: 26 additions & 14 deletions actions/v2/admin/users/create.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,35 +6,35 @@ import (
primitives "github.com/bitcoin-sv/go-sdk/primitives/ec"
adminerrors "github.com/bitcoin-sv/spv-wallet/actions/v2/admin/errors"
"github.com/bitcoin-sv/spv-wallet/actions/v2/admin/internal/mapping"
"github.com/bitcoin-sv/spv-wallet/api"
configerrors "github.com/bitcoin-sv/spv-wallet/config/errors"
"github.com/bitcoin-sv/spv-wallet/engine/spverrors"
"github.com/bitcoin-sv/spv-wallet/engine/v2/users/usersmodels"
"github.com/bitcoin-sv/spv-wallet/models/request/adminrequest"
"github.com/bitcoin-sv/spv-wallet/server/reqctx"
"github.com/gin-gonic/gin"
)

func create(c *gin.Context, _ *reqctx.AdminContext) {
logger := reqctx.Logger(c)

var requestBody adminrequest.CreateUser
if err := c.Bind(&requestBody); err != nil {
spverrors.ErrorResponse(c, spverrors.ErrCannotBindRequest.Wrap(err), logger)
// CreateUser creates a new user
func (s *APIAdminUsers) CreateUser(c *gin.Context) {
var request api.RequestsCreateUser
if err := c.Bind(&request); err != nil {
spverrors.ErrorResponse(c, spverrors.ErrCannotBindRequest.Wrap(err), s.logger)
return
}

requestBody := &createUserRequest{&request}

if err := validatePubKey(requestBody.PublicKey); err != nil {
spverrors.ErrorResponse(c, err, logger)
spverrors.ErrorResponse(c, err, s.logger)
return
}

newUser := &usersmodels.NewUser{
PublicKey: requestBody.PublicKey,
}
if requestBody.PaymailDefined() {
alias, domain, err := parsePaymail(requestBody.Paymail)
alias, domain, err := parsePaymail(requestBody.PaymailRequestBody())
if err != nil {
spverrors.ErrorResponse(c, err, logger)
spverrors.ErrorResponse(c, err, s.logger)
return
}

Expand All @@ -43,13 +43,13 @@ func create(c *gin.Context, _ *reqctx.AdminContext) {
Domain: domain,

PublicName: requestBody.Paymail.PublicName,
Avatar: requestBody.Paymail.Avatar,
Avatar: requestBody.Paymail.AvatarURL,
}
}

createdUser, err := reqctx.Engine(c).UsersService().Create(c, newUser)
createdUser, err := s.engine.UsersService().Create(c, newUser)
if err != nil {
spverrors.MapResponse(c, err, logger).
spverrors.MapResponse(c, err, s.logger).
If(configerrors.ErrUnsupportedDomain).Then(adminerrors.ErrInvalidDomain).
Else(adminerrors.ErrCreatingUser)
return
Expand All @@ -65,3 +65,15 @@ func validatePubKey(pubKey string) error {
}
return nil
}

type createUserRequest struct {
*api.RequestsCreateUser
}

func (r *createUserRequest) PaymailDefined() bool {
return r.RequestsCreateUser.Paymail != nil
}

func (r *createUserRequest) PaymailRequestBody() *addPaymailRequest {
return &addPaymailRequest{r.RequestsCreateUser.Paymail}
}
10 changes: 4 additions & 6 deletions actions/v2/admin/users/get.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,16 +5,14 @@ import (

"github.com/bitcoin-sv/spv-wallet/actions/v2/admin/internal/mapping"
"github.com/bitcoin-sv/spv-wallet/engine/spverrors"
"github.com/bitcoin-sv/spv-wallet/server/reqctx"
"github.com/gin-gonic/gin"
)

func get(c *gin.Context, _ *reqctx.AdminContext) {
userID := c.Param("id")

user, err := reqctx.Engine(c).UsersService().GetByID(c, userID)
// UserById returns a user by ID
func (s *APIAdminUsers) UserById(c *gin.Context, id string) {
user, err := s.engine.UsersService().GetByID(c, id)
if err != nil {
spverrors.ErrorResponse(c, err, reqctx.Logger(c))
spverrors.ErrorResponse(c, err, s.logger)
return
}

Expand Down
51 changes: 36 additions & 15 deletions actions/v2/admin/users/paymail_add.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,41 +6,39 @@ import (
"github.com/bitcoin-sv/go-paymail"
adminerrors "github.com/bitcoin-sv/spv-wallet/actions/v2/admin/errors"
"github.com/bitcoin-sv/spv-wallet/actions/v2/admin/internal/mapping"
"github.com/bitcoin-sv/spv-wallet/api"
configerrors "github.com/bitcoin-sv/spv-wallet/config/errors"
"github.com/bitcoin-sv/spv-wallet/engine/spverrors"
"github.com/bitcoin-sv/spv-wallet/engine/v2/paymails/paymailsmodels"
"github.com/bitcoin-sv/spv-wallet/models/request/adminrequest"
"github.com/bitcoin-sv/spv-wallet/server/reqctx"
"github.com/gin-gonic/gin"
)

func addPaymail(c *gin.Context, _ *reqctx.AdminContext) {
logger := reqctx.Logger(c)

var requestBody adminrequest.AddPaymail
if err := c.Bind(&requestBody); err != nil {
spverrors.ErrorResponse(c, spverrors.ErrCannotBindRequest.Wrap(err), logger)
// AddPaymailToUser add paymails to the user
func (s *APIAdminUsers) AddPaymailToUser(c *gin.Context, id string) {
var request api.RequestsAddPaymail
if err := c.Bind(&request); err != nil {
spverrors.ErrorResponse(c, spverrors.ErrCannotBindRequest.Wrap(err), s.logger)
return
}

userID := c.Param("id")
requestBody := addPaymailRequest{&request}

alias, domain, err := parsePaymail(&requestBody)
if err != nil {
spverrors.ErrorResponse(c, err, logger)
spverrors.ErrorResponse(c, err, s.logger)
return
}

newPaymail := &paymailsmodels.NewPaymail{
Alias: alias,
Domain: domain,
PublicName: requestBody.PublicName,
Avatar: requestBody.Avatar,
UserID: userID,
Avatar: requestBody.AvatarURL,
UserID: id,
}
createdPaymail, err := reqctx.Engine(c).PaymailsService().Create(c, newPaymail)
createdPaymail, err := s.engine.PaymailsService().Create(c, newPaymail)
if err != nil {
spverrors.MapResponse(c, err, logger).
spverrors.MapResponse(c, err, s.logger).
If(configerrors.ErrUnsupportedDomain).Then(adminerrors.ErrInvalidDomain).
Else(adminerrors.ErrAddingPaymail)
return
Expand All @@ -52,7 +50,7 @@ func addPaymail(c *gin.Context, _ *reqctx.AdminContext) {
// parsePaymail parses the paymail address from the request body.
// Uses either Alias + Domain or the whole paymail Address field
// If both Alias + Domain and Address are set, and they are inconsistent, an error is returned.
func parsePaymail(request *adminrequest.AddPaymail) (string, string, error) {
func parsePaymail(request *addPaymailRequest) (string, string, error) {
if request.HasAddress() &&
(request.HasAlias() || request.HasDomain()) &&
!request.AddressEqualsTo(request.Alias+"@"+request.Domain) {
Expand All @@ -67,3 +65,26 @@ func parsePaymail(request *adminrequest.AddPaymail) (string, string, error) {
}
return alias, domain, nil
}

type addPaymailRequest struct {
*api.RequestsAddPaymail
}

func (a addPaymailRequest) HasAddress() bool {
return a.Address != ""
}

// HasAlias returns true if the paymail alias is set
func (a addPaymailRequest) HasAlias() bool {
return a.Alias != ""
}

// HasDomain returns true if the paymail domain is set
func (a addPaymailRequest) HasDomain() bool {
return a.Domain != ""
}

// AddressEqualsTo returns true if the paymail address is equal to the given string
func (a addPaymailRequest) AddressEqualsTo(s string) bool {
return a.Address == s
}
15 changes: 0 additions & 15 deletions actions/v2/admin/users/routes.go

This file was deleted.

20 changes: 20 additions & 0 deletions actions/v2/admin/users/server.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package users

import (
"github.com/bitcoin-sv/spv-wallet/engine"
"github.com/rs/zerolog"
)

// APIAdminUsers represents server with admin API endpoints
type APIAdminUsers struct {
engine engine.ClientInterface
logger *zerolog.Logger
}

// NewAPIAdminUsers creates a new APIAdminUsers
func NewAPIAdminUsers(engine engine.ClientInterface, logger *zerolog.Logger) APIAdminUsers {
return APIAdminUsers{
engine: engine,
logger: logger,
}
}
4 changes: 2 additions & 2 deletions actions/v2/base/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,6 @@ type APIBase struct {
}

// NewAPIBase creates a new APIBase with config
func NewAPIBase(config *config.AppConfig) *APIBase {
return &APIBase{config}
func NewAPIBase(config *config.AppConfig) APIBase {
return APIBase{config}
}
9 changes: 5 additions & 4 deletions actions/v2/base/shared_config.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,17 +3,18 @@ package base
import (
"net/http"

"github.com/bitcoin-sv/spv-wallet/models/response"
"github.com/bitcoin-sv/spv-wallet/api"
"github.com/gin-gonic/gin"
)

// GetApiV2ConfigsShared is the handler for SharedConfig which can be obtained by both admin and user
func (s *APIBase) GetApiV2ConfigsShared(c *gin.Context) {
sharedConfig := response.SharedConfig{
// SharedConfig is the handler for SharedConfig which can be obtained by both admin and user
func (s *APIBase) SharedConfig(c *gin.Context) {
sharedConfig := api.ResponsesSharedConfig{
PaymailDomains: s.config.Paymail.Domains,
ExperimentalFeatures: map[string]bool{
"pikeContactsEnabled": s.config.ExperimentalFeatures.PikeContactsEnabled,
"pikePaymentEnabled": s.config.ExperimentalFeatures.PikePaymentEnabled,
"v2": s.config.ExperimentalFeatures.V2,
},
}

Expand Down
6 changes: 4 additions & 2 deletions actions/v2/base/shared_config_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,8 @@ func TestGETConfigsShared(t *testing.T) {
"paymailDomains": ["example.com"],
"experimentalFeatures": {
"pikeContactsEnabled": true,
"pikePaymentEnabled": true
"pikePaymentEnabled": true,
"v2": true
}
}`)
})
Expand All @@ -52,7 +53,8 @@ func TestGETConfigsShared(t *testing.T) {
"paymailDomains": ["example.com"],
"experimentalFeatures": {
"pikeContactsEnabled": true,
"pikePaymentEnabled": true
"pikePaymentEnabled": true,
"v2": true
}
}`)

Expand Down
Loading
Loading