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(SPV-736) adding admin contacts methods #223

Merged
merged 7 commits into from
May 10, 2024
Merged
Show file tree
Hide file tree
Changes from 4 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
29 changes: 29 additions & 0 deletions admin_contacts.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
package walletclient

import (
"context"

"github.com/bitcoin-sv/spv-wallet/models"

"github.com/bitcoin-sv/spv-wallet-go-client/transports"
)

func (wc *WalletClient) AdminGetContacts(ctx context.Context, conditions map[string]interface{}, metadata *models.Metadata, queryParams *transports.QueryParams) ([]*models.Contact, transports.ResponseError) {
ac4ch marked this conversation as resolved.
Show resolved Hide resolved
return wc.transport.AdminGetContacts(ctx, conditions, metadata, queryParams)
}

func (wc *WalletClient) AdminUpdateContact(ctx context.Context, id, fullName string, metadata *models.Metadata) (*models.Contact, transports.ResponseError) {
return wc.transport.AdminUpdateContact(ctx, id, fullName, metadata)
}

func (wc *WalletClient) AdminDeleteContact(ctx context.Context, id string) transports.ResponseError {
return wc.transport.AdminDeleteContact(ctx, id)
}

func (wc *WalletClient) AdminAcceptContact(ctx context.Context, id string) (*models.Contact, transports.ResponseError) {
return wc.transport.AdminAcceptContact(ctx, id)
}

func (wc *WalletClient) AdminRejectContact(ctx context.Context, id string) (*models.Contact, transports.ResponseError) {
return wc.transport.AdminRejectContact(ctx, id)
}
3 changes: 2 additions & 1 deletion contacts.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,9 @@ import (
"errors"
"fmt"

"github.com/bitcoin-sv/spv-wallet-go-client/transports"
"github.com/bitcoin-sv/spv-wallet/models"

"github.com/bitcoin-sv/spv-wallet-go-client/transports"
)

// UpsertContact add or update contact. When adding a new contact, the system utilizes Paymail's PIKE capability to dispatch an invitation request, asking the counterparty to include the current user in their contacts.
Expand Down
3 changes: 2 additions & 1 deletion contacts_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,10 @@ import (
"strings"
"testing"

"github.com/bitcoin-sv/spv-wallet-go-client/fixtures"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"

"github.com/bitcoin-sv/spv-wallet-go-client/fixtures"
)

// TestContactActionsRouting will test routing
Expand Down
158 changes: 158 additions & 0 deletions examples/http_admin/http_admin.go
ac4ch marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
@@ -0,0 +1,158 @@
package main

import (
"context"
"fmt"
"log"
"time"

"github.com/bitcoin-sv/spv-wallet/models"

walletclient "github.com/bitcoin-sv/spv-wallet-go-client"
"github.com/bitcoin-sv/spv-wallet-go-client/transports"
"github.com/bitcoin-sv/spv-wallet-go-client/xpriv"
)

const serverURL = "http://localhost:3003/v1"
const adminKey = "you can get admin key from spv-wallet default settings"

func main() {

// Create a clientAdmin
clientAdmin, _ := walletclient.New(
walletclient.WithXPriv(adminKey),
walletclient.WithAdminKey(adminKey),
walletclient.WithHTTP(serverURL),
walletclient.WithSignRequest(true),
)
log.Println("is sign req: ", clientAdmin.IsSignRequest())
ctx := context.Background()

aliceName := "alice"
bobName := "bob"
aliceClient, _ := createUser(ctx, aliceName)
bobClient, bobPaymail := createUser(ctx, bobName)

if _, err := aliceClient.UpsertContact(ctx, bobPaymail, bobName, nil); err != nil {
panic(err)
}

fmt.Println()
log.Println(" **** Admin Get Contacts ****")
c, err := clientAdmin.AdminGetContacts(ctx, nil, nil, &transports.QueryParams{})
if err != nil {
log.Printf("admin error for get contacts - %v", err)
}
if len(c) == 0 {
log.Printf("empty list of contacts")
return
}
log.Printf("admin got contacts: %#v\n", c)

fmt.Println()
log.Println(" **** Admin Update Contact ****")
bobToUpdate := c[0]
log.Printf("Bob before update [%v]", c[0].FullName)
updatedContact, err := clientAdmin.AdminUpdateContact(ctx, bobToUpdate.ID, fmt.Sprintf("%s %s", bobName, time.Now().Local().String()), nil)
if err != nil {
log.Panicf("error updating contact id: [%s] name: [%s] - %s", bobToUpdate.ID, bobToUpdate.FullName, err)
}
log.Printf("updated contact full name [%v]", updatedContact.FullName)

fmt.Println()
log.Println(" **** Admin Reject Contact ****")
aliceContacts, err := bobClient.GetContacts(ctx, nil, nil, nil)
if err != nil {
log.Printf("admin error for get contacts - %v", err)
}
if len(aliceContacts) == 0 {
log.Printf("empty list of contacts")
return
}
log.Printf("status should be awaiting == [%v]", aliceContacts[0].Status)

rejectAliceContact, err := clientAdmin.AdminRejectContact(ctx, aliceContacts[0].ID)
if err != nil {
log.Panicf("contact not accepted id: %v - %s", aliceContacts[0].ID, err)
}
log.Printf("status should change to rejected == [%v]", rejectAliceContact.Status)

fmt.Println()
log.Println(" **** Admin Accept Contact ****")
if _, err := aliceClient.UpsertContact(ctx, bobPaymail, bobName, nil); err != nil {
panic(err)
}

aliceContacts, err = bobClient.GetContacts(ctx, nil, nil, nil)
if err != nil {
log.Printf("admin error for get contacts - %v", err)
}
if len(aliceContacts) == 0 {
log.Printf("empty list of contacts")
return
}

log.Printf("status should be awaiting == [%v]", aliceContacts[0].Status)
acceptAliceContact, err := clientAdmin.AdminAcceptContact(ctx, aliceContacts[0].ID)
if err != nil {
log.Panicf("contact not accepted id: %v - %s", aliceContacts[0].ID, err)
}
log.Printf("status should change to unconfirmed == [%v]", acceptAliceContact.Status)

fmt.Println()
log.Println(" **** Admin Delete Contact ****")

err = clientAdmin.AdminDeleteContact(ctx, aliceContacts[0].ID)
if err != nil {
log.Panicf("contact not accepted id: %v - %s", aliceContacts[0].ID, err)
}
if len(aliceContacts) > 0 {
log.Println("removed id:", aliceContacts[0].ID)
} else {
log.Println("alice contacts are empty")
}
aliceContacts, err = bobClient.GetContacts(ctx, nil, nil, nil)
if err != nil {
log.Printf("admin error for get contacts - %v", err)
}
if len(aliceContacts) == 0 {
log.Printf("empty list of contacts")
}
for _, c := range aliceContacts {
log.Println("alice contacts id:", c.ID, c.FullName, c.DeletedAt)
}
}

func createUser(ctx context.Context, name string) (*walletclient.WalletClient, string) {
keys, _ := xpriv.Generate()

timestamp := time.Now().UnixMicro()
examplePaymail := fmt.Sprintf("contacttest_%d_%[email protected]", timestamp, name)

adminClient, _ := walletclient.New(
walletclient.WithXPriv(adminKey),
walletclient.WithAdminKey(adminKey),
walletclient.WithHTTP(serverURL),
walletclient.WithSignRequest(true),
)

metadata := make(models.Metadata)
metadata["name"] = name

err := adminClient.AdminNewXpub(ctx, keys.XPub().String(), &metadata)
if err != nil {
panic(err)
}
_, err = adminClient.AdminCreatePaymail(context.Background(), keys.XPub().String(), examplePaymail, name, "")
if err != nil {
panic(err)
}

userClient, _ := walletclient.New(
walletclient.WithXPriv(keys.XPriv()),
walletclient.WithHTTP(serverURL),
walletclient.WithSignRequest(true),
)

return userClient, examplePaymail
}
46 changes: 46 additions & 0 deletions transports/http_admin.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package transports
import (
"context"
"encoding/json"
"fmt"
"net/http"

"github.com/bitcoin-sv/spv-wallet/models"
Expand Down Expand Up @@ -316,3 +317,48 @@ func (h *TransportHTTP) AdminGetSharedConfig(ctx context.Context) (*models.Share

return model, nil
}

func (h *TransportHTTP) AdminGetContacts(ctx context.Context, conditions map[string]interface{}, metadata *models.Metadata, queryParams *QueryParams) ([]*models.Contact, ResponseError) {
jsonStr, err := json.Marshal(map[string]interface{}{
FieldConditions: conditions,
FieldMetadata: processMetadata(metadata),
FieldQueryParams: queryParams,
})
dorzepowski marked this conversation as resolved.
Show resolved Hide resolved
if err != nil {
return nil, WrapError(err)
}

var contacts []*models.Contact
err = h.doHTTPRequest(ctx, http.MethodPost, "/admin/contact/search", jsonStr, h.adminXPriv, true, &contacts)
return contacts, WrapError(err)
}

func (h *TransportHTTP) AdminUpdateContact(ctx context.Context, id, fullName string, metadata *models.Metadata) (*models.Contact, ResponseError) {
jsonStr, err := json.Marshal(map[string]interface{}{
"fullName": fullName,
FieldMetadata: processMetadata(metadata),
})
if err != nil {
return nil, WrapError(err)
}
var contact *models.Contact
err = h.doHTTPRequest(ctx, http.MethodPatch, fmt.Sprintf("/admin/contact/%s", id), jsonStr, h.adminXPriv, true, &contact)
ac4ch marked this conversation as resolved.
Show resolved Hide resolved
return contact, WrapError(err)
}

func (h *TransportHTTP) AdminDeleteContact(ctx context.Context, id string) ResponseError {
err := h.doHTTPRequest(ctx, http.MethodDelete, fmt.Sprintf("/admin/contact/%s", id), nil, h.adminXPriv, true, nil)
return WrapError(err)
}

func (h *TransportHTTP) AdminAcceptContact(ctx context.Context, id string) (*models.Contact, ResponseError) {
var contact *models.Contact
err := h.doHTTPRequest(ctx, http.MethodPatch, fmt.Sprintf("/admin/contact/accepted/%s", id), nil, h.adminXPriv, true, &contact)
return contact, WrapError(err)
}

func (h *TransportHTTP) AdminRejectContact(ctx context.Context, id string) (*models.Contact, ResponseError) {
var contact *models.Contact
err := h.doHTTPRequest(ctx, http.MethodPatch, fmt.Sprintf("/admin/contact/rejected/%s", id), nil, h.adminXPriv, true, &contact)
return contact, WrapError(err)
}
5 changes: 5 additions & 0 deletions transports/interface.go
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,11 @@ type AdminService interface {
AdminGetXPubsCount(ctx context.Context, conditions map[string]interface{}, metadata *models.Metadata) (int64, ResponseError)
AdminRecordTransaction(ctx context.Context, hex string) (*models.Transaction, ResponseError)
AdminGetSharedConfig(ctx context.Context) (*models.SharedConfig, ResponseError)
AdminGetContacts(ctx context.Context, conditions map[string]interface{}, metadata *models.Metadata, queryParams *QueryParams) ([]*models.Contact, ResponseError)
AdminUpdateContact(ctx context.Context, id, fullName string, metadata *models.Metadata) (*models.Contact, ResponseError)
AdminDeleteContact(ctx context.Context, id string) ResponseError
AdminAcceptContact(ctx context.Context, id string) (*models.Contact, ResponseError)
AdminRejectContact(ctx context.Context, id string) (*models.Contact, ResponseError)
}

// TransportService the transport service interface
Expand Down
Loading