From c803e63c594a1bfe71ac896b7b34eb232a434b10 Mon Sep 17 00:00:00 2001 From: Roland Bewick Date: Wed, 27 Dec 2023 13:24:35 +0700 Subject: [PATCH] feat: add api models --- echo_handlers.go | 100 +++++++++------------ frontend/src/hooks/useApp.ts | 4 +- frontend/src/hooks/useApps.ts | 4 +- frontend/src/screens/apps/AppsList.tsx | 56 +++++------- frontend/src/screens/apps/ShowApp.tsx | 60 ++++++------- frontend/src/types.ts | 37 ++++---- models.go | 115 ++++++++----------------- models/api/api.go | 57 ++++++++++++ 8 files changed, 208 insertions(+), 225 deletions(-) create mode 100644 models/api/api.go diff --git a/echo_handlers.go b/echo_handlers.go index bc5c91fe..997a7ffc 100644 --- a/echo_handlers.go +++ b/echo_handlers.go @@ -17,6 +17,7 @@ import ( echologrus "github.com/davrux/echo-logrus/v4" // "github.com/getAlby/lndhub.go/lib/responses" "github.com/getAlby/nostr-wallet-connect/frontend" + "github.com/getAlby/nostr-wallet-connect/models/api" "github.com/gorilla/sessions" "github.com/labstack/echo-contrib/session" "github.com/labstack/echo/v4" @@ -116,25 +117,31 @@ func (svc *Service) AppsListHandler(c echo.Context) error { return c.NoContent(http.StatusUnauthorized) } - apps := user.Apps + apps := []api.App{} + + for _, app := range user.Apps { + apiApp := api.App{ + // ID: app.ID, + Name: app.Name, + Description: app.Description, + CreatedAt: app.CreatedAt, + UpdatedAt: app.UpdatedAt, + NostrPubkey: app.NostrPubkey, + } - lastEvents := make(map[uint]*NostrEvent) - for _, app := range apps { var lastEvent NostrEvent result := svc.db.Where("app_id = ?", app.ID).Order("id desc").Limit(1).Find(&lastEvent) if result.RowsAffected > 0 { - lastEvents[app.ID] = &lastEvent + apiApp.LastEventAt = &lastEvent.CreatedAt } + apps = append(apps, apiApp) } - return c.JSON(http.StatusOK, ListAppsResponse{ - Apps: apps, - LastEvents: lastEvents, - }) + return c.JSON(http.StatusOK, apps) } func (svc *Service) AppsShowHandler(c echo.Context) error { - csrf, _ := c.Get(middleware.DefaultCSRFConfig.ContextKey).(string) + // csrf, _ := c.Get(middleware.DefaultCSRFConfig.ContextKey).(string) user, err := svc.GetUser(c) if err != nil { return c.JSON(http.StatusBadRequest, ErrorResponse{ @@ -165,18 +172,18 @@ func (svc *Service) AppsShowHandler(c echo.Context) error { var lastEvent NostrEvent lastEventResult := svc.db.Where("app_id = ?", app.ID).Order("id desc").Limit(1).Find(&lastEvent) - var eventsCount int64 - svc.db.Model(&NostrEvent{}).Where("app_id = ?", app.ID).Count(&eventsCount) + //var eventsCount int64 + //svc.db.Model(&NostrEvent{}).Where("app_id = ?", app.ID).Count(&eventsCount) paySpecificPermission := AppPermission{} appPermissions := []AppPermission{} - var expiresAt int64 + var expiresAt *time.Time svc.db.Where("app_id = ?", app.ID).Find(&appPermissions) requestMethods := []string{} for _, appPerm := range appPermissions { if !appPerm.ExpiresAt.IsZero() { - expiresAt = appPerm.ExpiresAt.Unix() + expiresAt = &appPerm.ExpiresAt } if appPerm.RequestMethod == NIP_47_PAY_INVOICE_METHOD { //find the pay_invoice-specific permissions @@ -185,65 +192,36 @@ func (svc *Service) AppsShowHandler(c echo.Context) error { requestMethods = append(requestMethods, appPerm.RequestMethod) } - renewsIn := "" + //renewsIn := "" budgetUsage := int64(0) maxAmount := paySpecificPermission.MaxAmount if maxAmount > 0 { budgetUsage = svc.GetBudgetUsage(&paySpecificPermission) - endOfBudget := GetEndOfBudget(paySpecificPermission.BudgetRenewal, app.CreatedAt) - renewsIn = getEndOfBudgetString(endOfBudget) } - response := ShowAppResponse{ - App: app, - PaySpecificPermission: paySpecificPermission, - RequestMethods: requestMethods, - EventsCount: eventsCount, - BudgetUsage: budgetUsage, - RenewsIn: renewsIn, - Csrf: csrf, + response := api.App{ + Name: app.Name, + Description: app.Description, + CreatedAt: app.CreatedAt, + UpdatedAt: app.UpdatedAt, + NostrPubkey: app.NostrPubkey, + ExpiresAt: expiresAt, + MaxAmount: maxAmount, + RequestMethods: requestMethods, + BudgetUsage: budgetUsage, + BudgetRenewal: paySpecificPermission.BudgetRenewal, } if lastEventResult.RowsAffected > 0 { - response.LastEvent = &lastEvent - } - if expiresAt != 0 { - response.ExpiresAt = &expiresAt + response.LastEventAt = &lastEvent.CreatedAt } return c.JSON(http.StatusOK, response) } -// TODO: remove this function, should be done in React! -func getEndOfBudgetString(endOfBudget time.Time) (result string) { - if endOfBudget.IsZero() { - return "--" - } - endOfBudgetDuration := endOfBudget.Sub(time.Now()) - - //less than a day - if endOfBudgetDuration.Hours() < 24 { - hours := int(endOfBudgetDuration.Hours()) - minutes := int(endOfBudgetDuration.Minutes()) % 60 - return fmt.Sprintf("%d hours and %d minutes", hours, minutes) - } - //less than a month - if endOfBudgetDuration.Hours() < 24*30 { - days := int(endOfBudgetDuration.Hours() / 24) - return fmt.Sprintf("%d days", days) - } - //more than a month - months := int(endOfBudgetDuration.Hours() / 24 / 30) - days := int(endOfBudgetDuration.Hours()/24) % 30 - if days > 0 { - return fmt.Sprintf("%d months %d days", months, days) - } - return fmt.Sprintf("%d months", months) -} - func (svc *Service) CSRFHandler(c echo.Context) error { csrf, _ := c.Get(middleware.DefaultCSRFConfig.ContextKey).(string) - return c.JSON(http.StatusOK, &CSRFResponse{ + return c.JSON(http.StatusOK, &api.CSRFResponse{ Csrf: csrf, }) } @@ -356,7 +334,7 @@ func (svc *Service) AppsCreateHandler(c echo.Context) error { publicRelayUrl = svc.cfg.Relay } - responseBody := &CreateAppResponse{} + responseBody := &api.CreateAppResponse{} responseBody.Name = name responseBody.Pubkey = pairingPublicKey responseBody.PairingSecret = pairingSecretKey @@ -417,9 +395,13 @@ func (svc *Service) InfoHandler(c echo.Context) error { if err != nil { return err } - responseBody := &InfoResponse{} + responseBody := &api.InfoResponse{} responseBody.BackendType = svc.cfg.LNBackendType - responseBody.User = user + if user != nil { + responseBody.User = &api.User{ + Email: user.Email, + } + } responseBody.Csrf = csrf return c.JSON(http.StatusOK, responseBody) } diff --git a/frontend/src/hooks/useApp.ts b/frontend/src/hooks/useApp.ts index e910a381..6d2c24d7 100644 --- a/frontend/src/hooks/useApp.ts +++ b/frontend/src/hooks/useApp.ts @@ -1,7 +1,7 @@ import useSWR from "swr"; -import { ShowAppResponse } from "../types"; +import { App } from "../types"; import { swrFetcher } from "../swr"; export function useApp(pubkey: string | undefined) { - return useSWR(pubkey && `/api/apps/${pubkey}`, swrFetcher); + return useSWR(pubkey && `/api/apps/${pubkey}`, swrFetcher); } diff --git a/frontend/src/hooks/useApps.ts b/frontend/src/hooks/useApps.ts index b213f1dd..0273799a 100644 --- a/frontend/src/hooks/useApps.ts +++ b/frontend/src/hooks/useApps.ts @@ -1,7 +1,7 @@ import useSWR from "swr"; -import { ListAppsResponse } from "../types"; +import { App } from "../types"; import { swrFetcher } from "../swr"; export function useApps() { - return useSWR("/api/apps", swrFetcher); + return useSWR("/api/apps", swrFetcher); } diff --git a/frontend/src/screens/apps/AppsList.tsx b/frontend/src/screens/apps/AppsList.tsx index 02e26d84..925f33cb 100644 --- a/frontend/src/screens/apps/AppsList.tsx +++ b/frontend/src/screens/apps/AppsList.tsx @@ -1,17 +1,12 @@ -import { useNavigate } from "react-router-dom"; - import Loading from "../../components/Loading"; -import { App } from "../../types"; import { useApps } from "../../hooks/useApps"; import { PlusIcon } from "../../components/icons/PlusIcon"; +import { useNavigate } from "react-router-dom"; function AppsList() { const { data: apps } = useApps(); - const navigate = useNavigate(); - const handleRowClick = (appId: App["nostrPubkey"]) => { - navigate(`/apps/${appId}`); - }; + const navigate = useNavigate(); if (!apps) { return ; @@ -46,7 +41,7 @@ function AppsList() { - {!apps.apps.length && ( + {!apps.length && ( )} - {apps.apps.length && ( - <> - {apps.apps.map((app, index) => ( - handleRowClick(app.nostrPubkey)} - key={index} - className="bg-white dark:bg-surface-02dp cursor-pointer hover:bg-purple-50 dark:hover:bg-surface-16dp" - > - {/* onClick="window.location='/apps/{{.NostrPubkey}}'"*/} - - {app.name} - - - {apps.lastEvents[app.id] - ? new Date( - apps.lastEvents[app.id].createdAt - ).toLocaleDateString() - : "-"} - - - Details - - - ))} - - )} + {apps.map((app, index) => ( + navigate(`/apps/${app.nostrPubkey}`)} + className="bg-white dark:bg-surface-02dp cursor-pointer hover:bg-purple-50 dark:hover:bg-surface-16dp" + > + + {app.name} + + + {app.lastEventAt + ? new Date(app.lastEventAt).toLocaleDateString() + : "-"} + + + Details + + + ))} diff --git a/frontend/src/screens/apps/ShowApp.tsx b/frontend/src/screens/apps/ShowApp.tsx index d06f79bc..1074532c 100644 --- a/frontend/src/screens/apps/ShowApp.tsx +++ b/frontend/src/screens/apps/ShowApp.tsx @@ -6,16 +6,16 @@ import { useApp } from "../../hooks/useApp"; function ShowApp() { const { data: info } = useInfo(); const { pubkey } = useParams() as { pubkey: string }; - const { data: appData } = useApp(pubkey); + const { data: app } = useApp(pubkey); const navigate = useNavigate(); - if (!appData || !info) { + if (!app || !info) { return ; } const handleDelete = async (event: React.FormEvent) => { event.preventDefault(); try { - await fetch(`/api/apps/${appData.app.nostrPubkey}`, { + await fetch(`/api/apps/${app.nostrPubkey}`, { method: "DELETE", headers: { "Content-Type": "application/json", @@ -31,10 +31,10 @@ function ShowApp() { return (

- {appData ? appData.app.name : "Fetching app..."} + {app ? app.name : "Fetching app..."}

- {appData ? appData.app.description : ""} + {app ? app.description : ""}

{"<"} Back to overview @@ -49,7 +49,7 @@ function ShowApp() { Public Key - {appData.app.nostrPubkey} + {app.nostrPubkey} @@ -57,8 +57,8 @@ function ShowApp() { Last used - {appData.eventsCount && appData.lastEvent - ? appData.lastEvent.createdAt + {app.lastEventAt + ? new Date(app.lastEventAt).toLocaleDateString() : "never"} @@ -67,8 +67,8 @@ function ShowApp() { Expires at - {appData.expiresAt - ? new Date(appData.expiresAt * 1000).toLocaleDateString() + {app.expiresAt + ? new Date(app.expiresAt).toLocaleDateString() : "never"} @@ -80,34 +80,29 @@ function ShowApp() { Permissions
    - {appData.requestMethods.map((method, index) => ( + {app.requestMethods.map((method, index) => (
  • {method}
  • ))}
- {appData.paySpecificPermission && - appData.paySpecificPermission.maxAmount > 0 && ( -
- - - - - - - - - -
Budget - {appData.paySpecificPermission.maxAmount} sats ( - {appData.budgetUsage} sats used) -
Renews in - {appData.renewsIn} (set to{" "} - {appData.paySpecificPermission.budgetRenewal}) -
-
- )} + {app.maxAmount > 0 && ( +
+ + + + + + + + + +
Budget + {app.maxAmount} sats ({app.budgetUsage} sats used) +
Renews{app.budgetRenewal}
+
+ )}
@@ -122,7 +117,6 @@ function ShowApp() {
-