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: show tlv records in transaction popup #365

Merged
merged 23 commits into from
Aug 9, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
33a5714
feat: show tlv records in transaction popup
im-adithya Jul 29, 2024
832bbf4
chore: add podcastinginfo component
im-adithya Jul 30, 2024
10afe14
chore: remove ? in podcasting info component
im-adithya Jul 30, 2024
65e6752
Merge branch 'master' into task-tlv-records
im-adithya Aug 5, 2024
308e4ff
chore: decode tlv record values in backend
im-adithya Aug 6, 2024
185895f
chore: add backup for tx description
im-adithya Aug 6, 2024
eb84d63
feat: add boostagram column and use jsonb in metadata
im-adithya Aug 6, 2024
a6406a8
chore: do not modify metadata while parsing
im-adithya Aug 7, 2024
25064af
chore: combine boostagram and metadata migration
im-adithya Aug 7, 2024
d9d99c0
feat: extract description from custom records
im-adithya Aug 8, 2024
178410f
chore: fix keysend tests
im-adithya Aug 8, 2024
4ee56dc
chore: change metadata param type in makeinvoice
im-adithya Aug 8, 2024
41c290b
chore: fix make invoice tests
im-adithya Aug 8, 2024
e12433e
chore: metadata fixes
im-adithya Aug 8, 2024
168d7cf
Merge remote-tracking branch 'origin/master' into task-tlv-records
rolznz Aug 8, 2024
3b96728
fix: boostragram and metadata migration
rolznz Aug 8, 2024
7c29b25
chore: set metadata json column to null if empty
im-adithya Aug 8, 2024
8760830
fix: remove jsonb from migration
im-adithya Aug 8, 2024
fe59323
chore: code cleanup, rename api models, fix metadata usage
rolznz Aug 9, 2024
662c01d
fix: metadata format
rolznz Aug 9, 2024
fb30ae6
chore: remove unused contant
rolznz Aug 9, 2024
e6d9930
fix: tests
rolznz Aug 9, 2024
268b69a
chore: improve tests
rolznz Aug 9, 2024
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
34 changes: 27 additions & 7 deletions api/models.go
Original file line number Diff line number Diff line change
Expand Up @@ -200,15 +200,35 @@ type Transaction struct {
Type string `json:"type"`
Invoice string `json:"invoice"`
Description string `json:"description"`
DescriptionHash string `json:"description_hash"`
DescriptionHash string `json:"descriptionHash"`
Preimage *string `json:"preimage"`
PaymentHash string `json:"payment_hash"`
PaymentHash string `json:"paymentHash"`
Amount uint64 `json:"amount"`
FeesPaid uint64 `json:"fees_paid"`
CreatedAt string `json:"created_at"`
SettledAt *string `json:"settled_at"`
AppId *uint `json:"app_id"`
Metadata interface{} `json:"metadata,omitempty"`
FeesPaid uint64 `json:"feesPaid"`
CreatedAt string `json:"createdAt"`
SettledAt *string `json:"settledAt"`
AppId *uint `json:"appId"`
Metadata Metadata `json:"metadata,omitempty"`
Boostagram *Boostagram `json:"boostagram,omitempty"`
}

type Metadata = map[string]interface{}

type Boostagram struct {
AppName string `json:"appName"`
Name string `json:"name"`
Podcast string `json:"podcast"`
URL string `json:"url"`
Episode string `json:"episode,omitempty"`
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@im-adithya why do some have omitempty others not? is it required?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I took this from LBE repo here, whereever we have ?: in the Boostagram type there, I've omitted

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

but it looks completely arbitrary and doesn't seem to follow the spec - https://github.com/lightning/blips/blob/master/blip-0010.md#fields

FeedId string `json:"feedId,omitempty"`
ItemId string `json:"itemId,omitempty"`
Timestamp int64 `json:"ts,omitempty"`
Message string `json:"message,omitempty"`
SenderId string `json:"senderId"`
SenderName string `json:"senderName"`
Time string `json:"time"`
Action string `json:"action"`
ValueMsatTotal int64 `json:"valueMsatTotal"`
}

// debug api
Expand Down
43 changes: 38 additions & 5 deletions api/transactions.go
Original file line number Diff line number Diff line change
Expand Up @@ -73,17 +73,30 @@ func toApiTransaction(transaction *transactions.Transaction) *Transaction {
preimage = transaction.Preimage
}

var metadata interface{}
if transaction.Metadata != "" {
jsonErr := json.Unmarshal([]byte(transaction.Metadata), &metadata)
var metadata Metadata
if transaction.Metadata != nil {
jsonErr := json.Unmarshal(transaction.Metadata, &metadata)
if jsonErr != nil {
logger.Logger.WithError(jsonErr).WithFields(logrus.Fields{
"id": transaction.ID,
"metadata": transaction.Metadata,
"payment_hash": transaction.PaymentHash,
"metadata": transaction.Metadata,
}).Error("Failed to deserialize transaction metadata")
}
}

var boostagram *Boostagram
rolznz marked this conversation as resolved.
Show resolved Hide resolved
if transaction.Boostagram != nil {
var txBoostagram transactions.Boostagram
jsonErr := json.Unmarshal(transaction.Boostagram, &txBoostagram)
if jsonErr != nil {
logger.Logger.WithError(jsonErr).WithFields(logrus.Fields{
"payment_hash": transaction.PaymentHash,
"boostagram": transaction.Boostagram,
}).Error("Failed to deserialize transaction boostagram info")
}
boostagram = toApiBoostagram(&txBoostagram)
}

return &Transaction{
Type: transaction.Type,
Invoice: transaction.PaymentRequest,
Expand All @@ -97,5 +110,25 @@ func toApiTransaction(transaction *transactions.Transaction) *Transaction {
CreatedAt: createdAt,
SettledAt: settledAt,
Metadata: metadata,
Boostagram: boostagram,
}
}

func toApiBoostagram(boostagram *transactions.Boostagram) *Boostagram {
return &Boostagram{
AppName: boostagram.AppName,
Name: boostagram.Name,
Podcast: boostagram.Podcast,
URL: boostagram.URL,
Episode: boostagram.Episode,
FeedId: boostagram.FeedId,
ItemId: boostagram.ItemId,
Timestamp: boostagram.Timestamp,
Message: boostagram.Message,
SenderId: boostagram.SenderId,
SenderName: boostagram.SenderName,
Time: boostagram.Time,
Action: boostagram.Action,
ValueMsatTotal: boostagram.ValueMsatTotal,
}
}
29 changes: 29 additions & 0 deletions db/migrations/202408061737_add_boostagrams_and_use_json.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
package migrations

import (
_ "embed"

"github.com/go-gormigrate/gormigrate/v2"
"gorm.io/gorm"
)

// This migration adds boostagram column to transactions
var _202408061737_add_boostagrams_and_use_json = &gormigrate.Migration{
ID: "202408061737_add_boostagrams_and_use_json",
Migrate: func(db *gorm.DB) error {
err := db.Transaction(func(tx *gorm.DB) error {
return tx.Exec(`
ALTER TABLE transactions ADD COLUMN boostagram JSON;
ALTER TABLE transactions ADD COLUMN metadata_temp JSON;
UPDATE transactions SET metadata_temp = json(metadata) where metadata != "";
rolznz marked this conversation as resolved.
Show resolved Hide resolved
im-adithya marked this conversation as resolved.
Show resolved Hide resolved
ALTER TABLE transactions DROP COLUMN metadata;
ALTER TABLE transactions RENAME COLUMN metadata_temp TO metadata;
`).Error
})

return err
},
Rollback: func(tx *gorm.DB) error {
return nil
},
}
1 change: 1 addition & 0 deletions db/migrations/migrate.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ func Migrate(gormDB *gorm.DB) error {
_202407151352_autoincrement,
_202407201604_transactions_indexes,
_202407262257_remove_invalid_scopes,
_202408061737_add_boostagrams_and_use_json,
})

return m.Migrate()
Expand Down
9 changes: 7 additions & 2 deletions db/models.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
package db

import "time"
import (
"time"

"gorm.io/datatypes"
)

type UserConfig struct {
ID uint
Expand Down Expand Up @@ -75,8 +79,9 @@ type Transaction struct {
ExpiresAt *time.Time
UpdatedAt time.Time
SettledAt *time.Time
Metadata string
Metadata datatypes.JSON
SelfPayment bool
Boostagram datatypes.JSON
}

type DBService interface {
Expand Down
63 changes: 63 additions & 0 deletions frontend/src/components/PodcastingInfo.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
import { Boostagram } from "src/types";

function PodcastingInfo({ boost }: { boost: Boostagram }) {
return (
<>
{boost.message && (
<div className="mt-6">
<p>Message</p>
<p className="text-muted-foreground break-all">{boost.message}</p>
</div>
)}
{boost.podcast && (
<div className="mt-6">
<p>Podcast</p>
<p className="text-muted-foreground break-all">{boost.podcast}</p>
</div>
)}
{boost.episode && (
<div className="mt-6">
<p>Episode</p>
<p className="text-muted-foreground break-all">{boost.episode}</p>
</div>
)}
{boost.action && (
<div className="mt-6">
<p>Action</p>
<p className="text-muted-foreground break-all">{boost.action}</p>
</div>
)}
{boost.ts && (
<div className="mt-6">
<p>Timestamp</p>
<p className="text-muted-foreground break-all">{boost.ts}</p>
</div>
)}
{boost.valueMsatTotal && (
<div className="mt-6">
<p>Total amount</p>
<p className="text-muted-foreground break-all">
{new Intl.NumberFormat(undefined, {}).format(
Math.floor(boost.valueMsatTotal / 1000)
)}{" "}
{Math.floor(boost.valueMsatTotal / 1000) == 1 ? "sat" : "sats"}
</p>
</div>
)}
{boost.senderName && (
<div className="mt-6">
<p>Sender</p>
<p className="text-muted-foreground break-all">{boost.senderName}</p>
</div>
)}
{boost.appName && (
<div className="mt-6">
<p>App</p>
<p className="text-muted-foreground break-all">{boost.appName}</p>
</div>
)}
</>
);
}

export default PodcastingInfo;
102 changes: 53 additions & 49 deletions frontend/src/components/TransactionItem.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import {
} from "lucide-react";
import React from "react";
import AppAvatar from "src/components/AppAvatar";
import PodcastingInfo from "src/components/PodcastingInfo";
import {
Credenza,
CredenzaBody,
Expand Down Expand Up @@ -38,7 +39,7 @@ function TransactionItem({ tx }: Props) {
const [showDetails, setShowDetails] = React.useState(false);
const type = tx.type;
const Icon = tx.type == "outgoing" ? ArrowUpIcon : ArrowDownIcon;
const app = tx.app_id && apps?.find((app) => app.id === tx.app_id);
const app = tx.appId && apps?.find((app) => app.id === tx.appId);

const copy = (text: string) => {
copyToClipboard(text);
Expand Down Expand Up @@ -92,7 +93,7 @@ function TransactionItem({ tx }: Props) {
{app ? app.name : type == "incoming" ? "Received" : "Sent"}
</p>
<p className="text-sm md:text-base truncate text-muted-foreground">
{dayjs(tx.settled_at).fromNow()}
{dayjs(tx.settledAt).fromNow()}
</p>
</div>
<p className="text-sm md:text-base text-muted-foreground break-all">
Expand Down Expand Up @@ -166,7 +167,7 @@ function TransactionItem({ tx }: Props) {
<div className="mt-8">
<p>Date & Time</p>
<p className="text-muted-foreground">
{dayjs(tx.settled_at)
{dayjs(tx.settledAt)
.tz(dayjs.tz.guess())
.format("D MMMM YYYY, HH:mm")}
</p>
Expand All @@ -176,9 +177,9 @@ function TransactionItem({ tx }: Props) {
<p>Fee</p>
<p className="text-muted-foreground">
{new Intl.NumberFormat(undefined, {}).format(
Math.floor(tx.fees_paid / 1000)
Math.floor(tx.feesPaid / 1000)
)}{" "}
{Math.floor(tx.fees_paid / 1000) == 1 ? "sat" : "sats"}
{Math.floor(tx.feesPaid / 1000) == 1 ? "sat" : "sats"}
</p>
</div>
)}
Expand All @@ -191,52 +192,55 @@ function TransactionItem({ tx }: Props) {
</div>
)}
</CredenzaBody>
<CredenzaFooter className="!justify-start mt-4 !flex-col">
<div
className="flex items-center gap-2 cursor-pointer"
onClick={() => setShowDetails(!showDetails)}
>
Details
{showDetails ? (
<ChevronUp className="w-4 h-4" />
) : (
<ChevronDown className="w-4 h-4" />
)}
</div>
{showDetails && (
<>
<div className="mt-6 !ml-0">
<p>Preimage</p>
<div className="flex items-center gap-4">
<p className="text-muted-foreground break-all">
{tx.preimage}
</p>
<CopyIcon
className="cursor-pointer text-muted-foreground w-6 h-6"
onClick={() => {
if (tx.preimage) {
copy(tx.preimage);
}
}}
/>
<CredenzaFooter>
<div className="mt-4 w-full">
<div
className="flex items-center gap-2 cursor-pointer"
onClick={() => setShowDetails(!showDetails)}
>
Details
{showDetails ? (
<ChevronUp className="w-4 h-4" />
) : (
<ChevronDown className="w-4 h-4" />
)}
</div>
{showDetails && (
<>
{tx.boostagram && <PodcastingInfo boost={tx.boostagram} />}
<div className="mt-6">
<p>Preimage</p>
<div className="flex items-center gap-4">
<p className="text-muted-foreground break-all">
{tx.preimage}
</p>
<CopyIcon
className="cursor-pointer text-muted-foreground w-6 h-6"
onClick={() => {
if (tx.preimage) {
copy(tx.preimage);
}
}}
/>
</div>
</div>
</div>
<div className="mt-6 !ml-0">
<p>Hash</p>
<div className="flex items-center gap-4">
<p className="text-muted-foreground break-all">
{tx.payment_hash}
</p>
<CopyIcon
className="cursor-pointer text-muted-foreground w-6 h-6"
onClick={() => {
copy(tx.payment_hash);
}}
/>
<div className="mt-6">
<p>Hash</p>
<div className="flex items-center gap-4">
<p className="text-muted-foreground break-all">
{tx.paymentHash}
</p>
<CopyIcon
className="cursor-pointer text-muted-foreground w-6 h-6"
onClick={() => {
copy(tx.paymentHash);
}}
/>
</div>
</div>
</div>
</>
)}
</>
)}
</div>
</CredenzaFooter>
</CredenzaContent>
</Credenza>
Expand Down
2 changes: 1 addition & 1 deletion frontend/src/components/TransactionsList.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ function TransactionsList() {
) : (
<>
{transactions?.map((tx) => {
return <TransactionItem key={tx.payment_hash + tx.type} tx={tx} />;
return <TransactionItem key={tx.paymentHash + tx.type} tx={tx} />;
})}
</>
)}
Expand Down
Loading
Loading