Skip to content

Commit

Permalink
Feat: app metadata (#570)
Browse files Browse the repository at this point in the history
* chore: wg.Add() before go (#559)

* chore: code cleanup (#558)

* Update README.md

Add command to make the install script executable in the instructions.

* feat: add migration card in wallet screen (#555)

* feat: add migration card in wallet screen

* chore: transfer funds if channel exists

* chore: typo

* chore: improve copy

* chore: add transfer funds button

* fix: remove duplicate icon

---------

Co-authored-by: Roland Bewick <roland.bewick@gmail.com>

* chore: run extra workflows on PR (#563)

* chore: run extra workflows on PR

* fix: pull request workflows

* build(deps): bump github.com/nbd-wtf/go-nostr from 0.34.5 to 0.34.10 (#551)

Bumps [github.com/nbd-wtf/go-nostr](https://github.com/nbd-wtf/go-nostr) from 0.34.5 to 0.34.10.
- [Commits](nbd-wtf/go-nostr@v0.34.5...v0.34.10)

---
updated-dependencies:
- dependency-name: github.com/nbd-wtf/go-nostr
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* build(deps): bump gopkg.in/DataDog/dd-trace-go.v1 from 1.66.0 to 1.67.0 (#552)

Bumps gopkg.in/DataDog/dd-trace-go.v1 from 1.66.0 to 1.67.0.

---
updated-dependencies:
- dependency-name: gopkg.in/DataDog/dd-trace-go.v1
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* fix: do not render 0 on withdraw onchain funds page when reserve balance is 0 (#549)

* chore: update fly default kill timeout to ensure app gracefully shuts down (#547)

* feat: app metadata

* fix(wails): parse max length in log output endpoint (#568)

* fix: alby account image and name on transaction list

* fix: vertically center transaction item content

* fix: use slashed zero on wallet balance

* chore: align app image with app name in transaction list

* fix: ensure auth with correct user if refresh token expires (#572)

* fix: do not allow editing name of Alby Account connection

* fix: change "Create Wallet" to "Create Subaccount"

* fix: subaccount copy

* chore: update friends and family app icon

* fix: update app store images (#574)

* fix: update app store images

* chore: update paper scissors hodl and zapplanner icons

* chore: update lume and habla news icons

* chore: resize and compress zapplanner and rps logos

---------

Co-authored-by: Roland Bewick <roland.bewick@gmail.com>

* feat: add new auto channel flow that works with existing channels (#556)

* feat: add new auto channel flow that works with existing channels

* chore: remove "first" from auto channel copy

* feat: new transaction list item design

---------

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: Matjaž Lipuš <matjazl@gmail.com>
Co-authored-by: BtcPins <pardus79@gmail.com>
Co-authored-by: Michael Bumann <hello@michaelbumann.com>
Co-authored-by: Adithya Vardhan <imadithyavardhan@gmail.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
  • Loading branch information
6 people authored Sep 2, 2024
1 parent 1291974 commit 4a9a311
Show file tree
Hide file tree
Showing 61 changed files with 758 additions and 140 deletions.
4 changes: 4 additions & 0 deletions .github/workflows/http.yml
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
name: HTTP build - Linux and MacOS
on:
push:
branches:
- master
pull_request:
types: [opened, synchronize]
workflow_call:
inputs:
build-release:
Expand Down
4 changes: 4 additions & 0 deletions .github/workflows/wails.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@ name: Wails build - all platforms

on:
push:
branches:
- master
pull_request:
types: [opened, synchronize]

workflow_call:
inputs:
Expand Down
1 change: 1 addition & 0 deletions alby/alby_oauth_service.go
Original file line number Diff line number Diff line change
Expand Up @@ -439,6 +439,7 @@ func (svc *albyOAuthService) LinkAccount(ctx context.Context, lnClient lnclient.
nil,
scopes,
false,
nil,
)

if err != nil {
Expand Down
25 changes: 24 additions & 1 deletion api/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,8 @@ func (api *api) CreateApp(createAppRequest *CreateAppRequest) (*CreateAppRespons
createAppRequest.BudgetRenewal,
expiresAt,
createAppRequest.Scopes,
createAppRequest.Isolated)
createAppRequest.Isolated,
createAppRequest.Metadata)

if err != nil {
return nil, err
Expand Down Expand Up @@ -220,6 +221,16 @@ func (api *api) GetApp(dbApp *db.App) *App {
maxAmount := uint64(paySpecificPermission.MaxAmountSat)
budgetUsage = queries.GetBudgetUsageSat(api.db, &paySpecificPermission)

var metadata Metadata
if dbApp.Metadata != nil {
jsonErr := json.Unmarshal(dbApp.Metadata, &metadata)
if jsonErr != nil {
logger.Logger.WithError(jsonErr).WithFields(logrus.Fields{
"app_id": dbApp.ID,
}).Error("Failed to deserialize app metadata")
}
}

response := App{
ID: dbApp.ID,
Name: dbApp.Name,
Expand All @@ -233,6 +244,7 @@ func (api *api) GetApp(dbApp *db.App) *App {
BudgetUsage: budgetUsage,
BudgetRenewal: paySpecificPermission.BudgetRenewal,
Isolated: dbApp.Isolated,
Metadata: metadata,
}

if dbApp.Isolated {
Expand Down Expand Up @@ -300,6 +312,17 @@ func (api *api) ListApps() ([]App, error) {
apiApp.LastEventAt = &lastEvent.CreatedAt
}

var metadata Metadata
if dbApp.Metadata != nil {
jsonErr := json.Unmarshal(dbApp.Metadata, &metadata)
if jsonErr != nil {
logger.Logger.WithError(jsonErr).WithFields(logrus.Fields{
"app_id": dbApp.ID,
}).Error("Failed to deserialize app metadata")
}
apiApp.Metadata = metadata
}

apiApps = append(apiApps, apiApp)
}
return apiApps, nil
Expand Down
2 changes: 2 additions & 0 deletions api/models.go
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ type App struct {
BudgetRenewal string `json:"budgetRenewal"`
Isolated bool `json:"isolated"`
Balance uint64 `json:"balance"`
Metadata Metadata `json:"metadata,omitempty"`
}

type ListAppsResponse struct {
Expand All @@ -93,6 +94,7 @@ type CreateAppRequest struct {
Scopes []string `json:"scopes"`
ReturnTo string `json:"returnTo"`
Isolated bool `json:"isolated"`
Metadata Metadata `json:"metadata,omitempty"`
}

type StartRequest struct {
Expand Down
2 changes: 1 addition & 1 deletion cmd/http/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ import (
)

func main() {
log.Info("NWC Starting in HTTP mode")
log.Info("AlbyHub Starting in HTTP mode")

// Create a channel to receive OS signals.
osSignalChannel := make(chan os.Signal, 1)
Expand Down
16 changes: 14 additions & 2 deletions db/db_service.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package db

import (
"encoding/hex"
"encoding/json"
"errors"
"fmt"
"slices"
Expand All @@ -11,6 +12,7 @@ import (
"github.com/getAlby/hub/events"
"github.com/getAlby/hub/logger"
"github.com/nbd-wtf/go-nostr"
"gorm.io/datatypes"
"gorm.io/gorm"
)

Expand All @@ -26,7 +28,7 @@ func NewDBService(db *gorm.DB, eventPublisher events.EventPublisher) *dbService
}
}

func (svc *dbService) CreateApp(name string, pubkey string, maxAmountSat uint64, budgetRenewal string, expiresAt *time.Time, scopes []string, isolated bool) (*App, string, error) {
func (svc *dbService) CreateApp(name string, pubkey string, maxAmountSat uint64, budgetRenewal string, expiresAt *time.Time, scopes []string, isolated bool, metadata map[string]interface{}) (*App, string, error) {
if isolated && (slices.Contains(scopes, constants.SIGN_MESSAGE_SCOPE)) {
// cannot sign messages because the isolated app is a custodial subaccount
return nil, "", errors.New("isolated app cannot have sign_message scope")
Expand All @@ -47,7 +49,17 @@ func (svc *dbService) CreateApp(name string, pubkey string, maxAmountSat uint64,
}
}

app := App{Name: name, NostrPubkey: pairingPublicKey, Isolated: isolated}
var metadataBytes []byte
if metadata != nil {
var err error
metadataBytes, err = json.Marshal(metadata)
if err != nil {
logger.Logger.WithError(err).Error("Failed to serialize metadata")
return nil, "", err
}
}

app := App{Name: name, NostrPubkey: pairingPublicKey, Isolated: isolated, Metadata: datatypes.JSON(metadataBytes)}

err := svc.db.Transaction(func(tx *gorm.DB) error {
err := tx.Save(&app).Error
Expand Down
25 changes: 25 additions & 0 deletions db/migrations/202408291715_app_metadata.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package migrations

import (
_ "embed"

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

var _202408291715_app_metadata = &gormigrate.Migration{
ID: "202408291715_app_metadata",
Migrate: func(tx *gorm.DB) error {

if err := tx.Exec(`
ALTER TABLE apps ADD COLUMN metadata JSON;
`).Error; err != nil {
return err
}

return nil
},
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 @@ -21,6 +21,7 @@ func Migrate(gormDB *gorm.DB) error {
_202407262257_remove_invalid_scopes,
_202408061737_add_boostagrams_and_use_json,
_202408191242_transaction_failure_reason,
_202408291715_app_metadata,
})

return m.Migrate()
Expand Down
3 changes: 2 additions & 1 deletion db/models.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ type App struct {
CreatedAt time.Time
UpdatedAt time.Time
Isolated bool
Metadata datatypes.JSON
}

type AppPermission struct {
Expand Down Expand Up @@ -86,7 +87,7 @@ type Transaction struct {
}

type DBService interface {
CreateApp(name string, pubkey string, maxAmountSat uint64, budgetRenewal string, expiresAt *time.Time, scopes []string, isolated bool) (*App, string, error)
CreateApp(name string, pubkey string, maxAmountSat uint64, budgetRenewal string, expiresAt *time.Time, scopes []string, isolated bool, metadata map[string]interface{}) (*App, string, error)
}

const (
Expand Down
1 change: 1 addition & 0 deletions fly.toml
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
app = 'nwc'
primary_region = 'lax'
swap_size_mb = 2048
kill_timeout = 120

[build]
image = 'ghcr.io/getalby/hub:latest'
Expand Down
Binary file modified frontend/src/assets/suggested-apps/alby.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified frontend/src/assets/suggested-apps/amethyst.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified frontend/src/assets/suggested-apps/damus.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified frontend/src/assets/suggested-apps/habla-news.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified frontend/src/assets/suggested-apps/kiwi.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified frontend/src/assets/suggested-apps/lume.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified frontend/src/assets/suggested-apps/nostrudel.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified frontend/src/assets/suggested-apps/nostur.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified frontend/src/assets/suggested-apps/paper-scissors-hodl.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified frontend/src/assets/suggested-apps/primal.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified frontend/src/assets/suggested-apps/snort.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file removed frontend/src/assets/suggested-apps/stackernews.png
Binary file not shown.
Binary file modified frontend/src/assets/suggested-apps/uncle-jim.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file removed frontend/src/assets/suggested-apps/wavelake.png
Binary file not shown.
Binary file added frontend/src/assets/suggested-apps/wavlake.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified frontend/src/assets/suggested-apps/wherostr.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified frontend/src/assets/suggested-apps/yakihonne.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified frontend/src/assets/suggested-apps/zap-stream.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified frontend/src/assets/suggested-apps/zapplanner.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified frontend/src/assets/suggested-apps/zapple-pay.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified frontend/src/assets/suggested-apps/zappy-bird.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
37 changes: 29 additions & 8 deletions frontend/src/components/AppAvatar.tsx
Original file line number Diff line number Diff line change
@@ -1,27 +1,48 @@
import { suggestedApps } from "src/components/SuggestedAppData";
import UserAvatar from "src/components/UserAvatar";
import { cn } from "src/lib/utils";
import { App } from "src/types";

type Props = {
appName: string;
app: App;
className?: string;
};

export default function AppAvatar({ appName, className }: Props) {
export default function AppAvatar({ app, className }: Props) {
if (app.name === "getalby.com") {
return <UserAvatar className={className} />;
}
const appStoreApp = app?.metadata?.app_store_app_id
? suggestedApps.find(
(suggestedApp) => suggestedApp.id === app.metadata?.app_store_app_id
)
: undefined;
const image = appStoreApp?.logo;

const gradient =
appName
app.name
.split("")
.map((c) => c.charCodeAt(0))
.reduce((a, b) => a + b, 0) % 10;
return (
<div
className={cn(
"rounded-lg border relative",
`avatar-gradient-${gradient}`,
"rounded-lg border relative overflow-hidden",
!image && `avatar-gradient-${gradient}`,
className
)}
>
<span className="absolute top-1/2 left-1/2 transform -translate-x-1/2 -translate-y-1/2 text-white text-xl font-medium capitalize">
{appName.charAt(0)}
</span>
{image && (
<img
src={image}
className={cn("absolute w-full h-full rounded-lg", className)}
/>
)}
{!image && (
<span className="absolute top-1/2 left-1/2 transform -translate-x-1/2 -translate-y-1/2 text-white text-xl font-medium capitalize">
{app.name.charAt(0)}
</span>
)}
</div>
);
}
6 changes: 3 additions & 3 deletions frontend/src/components/SuggestedAppData.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,9 @@ import nostur from "src/assets/suggested-apps/nostur.png";
import paperScissorsHodl from "src/assets/suggested-apps/paper-scissors-hodl.png";
import primal from "src/assets/suggested-apps/primal.png";
import snort from "src/assets/suggested-apps/snort.png";
import stackernews from "src/assets/suggested-apps/stackernews.png";
import stackernews from "src/assets/suggested-apps/stacker-news.png";
import uncleJim from "src/assets/suggested-apps/uncle-jim.png";
import wavelake from "src/assets/suggested-apps/wavelake.png";
import wavlake from "src/assets/suggested-apps/wavlake.png";
import wherostr from "src/assets/suggested-apps/wherostr.png";
import yakihonne from "src/assets/suggested-apps/yakihonne.png";
import zapstream from "src/assets/suggested-apps/zap-stream.png";
Expand Down Expand Up @@ -85,7 +85,7 @@ export const suggestedApps: SuggestedApp[] = [
title: "Wavlake",
description: "Creators platform",
webLink: "https://www.wavlake.com/",
logo: wavelake,
logo: wavlake,
},
{
id: "snort",
Expand Down
4 changes: 2 additions & 2 deletions frontend/src/components/SuggestedApps.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Globe } from "lucide-react";
import { ExternalLinkIcon, Globe } from "lucide-react";
import { Link } from "react-router-dom";
import ExternalLink from "src/components/ExternalLink";
import { AppleIcon } from "src/components/icons/Apple";
Expand Down Expand Up @@ -84,7 +84,7 @@ function InternalAppCard({ id, title, description, logo }: SuggestedApp) {
<CardFooter className="flex flex-row justify-end">
<Link to={`/internal-apps/${id}`}>
<Button variant="outline">
<NostrWalletConnectIcon className="w-4 h-4 mr-2" />
<ExternalLinkIcon className="w-4 h-4 mr-2" />
Open
</Button>
</Link>
Expand Down
Loading

0 comments on commit 4a9a311

Please sign in to comment.