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(bux-399): Confirm contact #497

Merged
merged 6 commits into from
Mar 13, 2024
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
15 changes: 14 additions & 1 deletion actions/contacts/models.go
Original file line number Diff line number Diff line change
@@ -1,8 +1,21 @@
package contacts

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

// CreateContact is the model for creating a contact
type CreateContact struct {
Metadata engine.Metadata `json:"metadata"`
}

// UpdateContact is the model for updating a contact
type UpdateContact struct {
XPubID string `json:"xpub_id"`
FullName string `json:"full_name"`
Paymail string `json:"paymail"`
chris-4chain marked this conversation as resolved.
Show resolved Hide resolved
PubKey string `json:"pubKey"`
chris-4chain marked this conversation as resolved.
Show resolved Hide resolved
Status models.ContactStatus `json:"status"`
chris-4chain marked this conversation as resolved.
Show resolved Hide resolved
Metadata engine.Metadata `json:"metadata"`
}
2 changes: 2 additions & 0 deletions actions/contacts/routes.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,11 @@ func NewHandler(appConfig *config.AppConfig, services *config.AppServices) route
apiEndpoints := routes.APIEndpointsFunc(func(router *gin.RouterGroup) {
contactGroup := router.Group("/contact")
contactGroup.POST("", action.create)
contactGroup.PATCH("", action.update)
chris-4chain marked this conversation as resolved.
Show resolved Hide resolved

contactsGroup := router.Group("/contacts")
contactsGroup.GET("", action.search)

})

return apiEndpoints
Expand Down
47 changes: 47 additions & 0 deletions actions/contacts/update.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
package contacts

import (
"net/http"

"github.com/bitcoin-sv/spv-wallet/engine"
"github.com/bitcoin-sv/spv-wallet/mappings"
"github.com/bitcoin-sv/spv-wallet/server/auth"
"github.com/gin-gonic/gin"
)

// update will update an existing model
// Update Contact godoc
// @Summary Update contact
// @Description Update contact
// @Tags Contacts
// @Produce json
// @Param metadata body string true "Contacts Metadata"
// @Success 200
// @Router /v1/contact [patch]
// @Security x-auth-xpub
func (a *Action) update(c *gin.Context) {
reqXPubID := c.GetString(auth.ParamXPubHashKey)

var requestBody UpdateContact
chris-4chain marked this conversation as resolved.
Show resolved Hide resolved

if err := c.ShouldBindJSON(&requestBody); err != nil {
c.JSON(http.StatusBadRequest, err.Error())
return
}

if requestBody.XPubID == "" {
c.JSON(http.StatusBadRequest, "Id is missing")
}

contact, err := a.Services.SpvWalletEngine.UpdateContact(c.Request.Context(), requestBody.FullName, requestBody.PubKey, reqXPubID, requestBody.Paymail, engine.ContactStatus(requestBody.Status), engine.WithMetadatas(requestBody.Metadata))

if err != nil {
c.JSON(http.StatusExpectationFailed, err.Error())
return
}

contract := mappings.MapToContactContract(contact)

c.JSON(http.StatusOK, contract)

}
34 changes: 34 additions & 0 deletions engine/action_contact.go
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,40 @@ func (c *Client) NewContact(ctx context.Context, fullName, paymail, senderPubKey
return contact, nil
}

func (c *Client) UpdateContact(ctx context.Context, fullName, pubKey, xPubID, paymailAddr string, status ContactStatus, opts ...ModelOps) (*Contact, error) {
contact, err := getContactByXPubIdAndRequesterPubKey(ctx, xPubID, paymailAddr, opts...)

if err != nil {
return nil, fmt.Errorf("failed to get contact: %w", err)
}

if contact == nil {
return nil, fmt.Errorf("contact not found")
}

if fullName != "" {
contact.FullName = fullName
}

if pubKey != "" {
contact.PubKey = pubKey
}

if status != "" {
contact.Status = status
}

if paymailAddr != "" {
contact.Paymail = paymailAddr
}
chris-4chain marked this conversation as resolved.
Show resolved Hide resolved

if err = contact.Save(ctx); err != nil {
return nil, err
}

return contact, nil
}

func (c *Client) GetPubKeyFromPki(pkiUrl, paymailAddress string) (string, error) {
if pkiUrl == "" {
return "", errors.New("pkiUrl should not be empty")
Expand Down
7 changes: 5 additions & 2 deletions engine/definitions.go
Original file line number Diff line number Diff line change
Expand Up @@ -94,8 +94,11 @@ const (
bumpField = "bump"
fullNameField = "full_name"
paymailField = "paymail"
senderXPubField = "pub_key"
contactStatus = "status"

// TODO: check
xPubKeyField = "pub_key"
senderXPubField = "pub_key"
contactStatus = "status"

// Universal statuses
statusCanceled = "canceled"
Expand Down
3 changes: 3 additions & 0 deletions engine/interface.go
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,9 @@ type ClientService interface {

type ContactService interface {
NewContact(ctx context.Context, fullName, paymail, pubKey string, opts ...ModelOps) (*Contact, error)

UpdateContact(ctx context.Context, fullName, pubKey, xPubID, paymail string, status ContactStatus, opts ...ModelOps) (*Contact, error)

GetContacts(ctx context.Context, metadata *Metadata, conditions *map[string]interface{}, queryParams *datastore.QueryParams, opts ...ModelOps) ([]*Contact, error)
}

Expand Down
34 changes: 34 additions & 0 deletions engine/model_contact.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ package engine
import (
"context"
"errors"
"fmt"

"github.com/bitcoin-sv/go-paymail"
"github.com/bitcoin-sv/spv-wallet/engine/utils"
"github.com/mrz1836/go-datastore"
Expand Down Expand Up @@ -75,6 +77,37 @@ func getContact(ctx context.Context, fullName, paymailAddress, senderPubKey stri
return contact, nil
}

func getContactByXPubIdAndRequesterPubKey(ctx context.Context, xPubId, paymailAddr string, opts ...ModelOps) (*Contact, error) {

if xPubId == "" {
return nil, fmt.Errorf("xpub_id is empty")
}

if paymailAddr == "" {
return nil, fmt.Errorf("paymail address is empty")
}
contact := &Contact{
XpubID: xPubId,
Paymail: paymailAddr,
}

contact.enrich(ModelContact, opts...)

conditions := map[string]interface{}{
xPubIDField: xPubId,
paymailField: paymailAddr,
}

if err := Get(ctx, contact, conditions, false, defaultDatabaseReadTimeout, false); err != nil {
if errors.Is(err, datastore.ErrNoResults) {
return nil, nil
}
return nil, err
}

return contact, nil
}

func getContacts(ctx context.Context, metadata *Metadata, conditions *map[string]interface{}, queryParams *datastore.QueryParams, opts ...ModelOps) ([]*Contact, error) {
contacts := make([]*Contact, 0)

Expand All @@ -83,6 +116,7 @@ func getContacts(ctx context.Context, metadata *Metadata, conditions *map[string
}

return contacts, nil

}

func (c *Contact) GetModelName() string {
Expand Down
77 changes: 75 additions & 2 deletions engine/model_contact_test.go
Original file line number Diff line number Diff line change
@@ -1,18 +1,24 @@
package engine

import (
"testing"

"github.com/bitcoin-sv/spv-wallet/engine/utils"
"github.com/mrz1836/go-datastore"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"testing"
)

const (
fullName = "John Doe"
paymailTest = "test@paymail.com"
senderPubKey = "senderPubKey"
xPubID = "62910a1ecbc7728afad563ab3f8aa70568ed934d1e0383cb1bbbfb1bc8f2afe5"

xpubKey = "xpub661MyMwAqRbcEp7YgDpGXquSF2NW3GBAU3SXTikFT1nkxHGbxjG9RgGxr9X3D4AYsJ6ZqYjMGcdUsPDQZoeibKECs5d56f1w9rfF3QrAAu9"
xPubId = "62910a1ecbc7728afad563ab3f8aa70568ed934d1e0383cb1bbbfb1bc8f2afe5"
paymailAddr = "test.test@mail.test"

xPubID = "62910a1ecbc7728afad563ab3f8aa70568ed934d1e0383cb1bbbfb1bc8f2afe5"
)

func Test_newContact(t *testing.T) {
Expand Down Expand Up @@ -97,6 +103,72 @@ func Test_getContact(t *testing.T) {
})
}

func Test_getContactByXPubIdAndPubKey(t *testing.T) {
t.Run("valid xPubId and paymailAddr", func(t *testing.T) {
ctx, client, deferMe := CreateTestSQLiteClient(t, false, false, withTaskManagerMockup())
defer deferMe()
var opts []ModelOps
createdContact, err := newContact(
fullName,
paymailAddr,
xpubKey,
append(opts, client.DefaultModelOptions(
New(),
)...)...,
)
createdContact.PubKey = "testPubKey"
err = createdContact.Save(ctx)

contact, err := getContactByXPubIdAndRequesterPubKey(ctx, createdContact.XpubID, createdContact.Paymail, client.DefaultModelOptions()...)

require.NotNil(t, contact)
require.NoError(t, err)
})

t.Run("empty xPubId", func(t *testing.T) {
ctx, client, deferMe := CreateTestSQLiteClient(t, false, false, withTaskManagerMockup())
defer deferMe()

var opts []ModelOps
createdContact, err := newContact(
fullName,
paymailAddr,
xpubKey,
append(opts, client.DefaultModelOptions(
New(),
)...)...,
)
createdContact.PubKey = "testPubKey"
err = createdContact.Save(ctx)

contact, err := getContactByXPubIdAndRequesterPubKey(ctx, "", createdContact.Paymail, client.DefaultModelOptions()...)

require.Nil(t, contact)
require.Error(t, err)
})

t.Run("empty paymailAddr", func(t *testing.T) {
ctx, client, deferMe := CreateTestSQLiteClient(t, false, false, withTaskManagerMockup())
defer deferMe()

var opts []ModelOps
createdContact, err := newContact(
fullName,
paymailAddr,
xpubKey,
append(opts, client.DefaultModelOptions(
New(),
)...)...,
)
createdContact.PubKey = "testPubKey"
err = createdContact.Save(ctx)

contact, err := getContactByXPubIdAndRequesterPubKey(ctx, createdContact.XpubID, "", client.DefaultModelOptions()...)

require.Nil(t, contact)
require.Error(t, err)
})
}
func Test_getContacts(t *testing.T) {
t.Run("status 'not confirmed'", func(t *testing.T) {
ctx, client, deferMe := CreateTestSQLiteClient(t, false, false, withTaskManagerMockup())
Expand Down Expand Up @@ -153,5 +225,6 @@ func Test_getContacts(t *testing.T) {

require.NoError(t, err)
assert.Equal(t, 0, len(contacts))

})
}
Loading