Skip to content

Commit

Permalink
feat: add api models
Browse files Browse the repository at this point in the history
  • Loading branch information
rolznz committed Dec 27, 2023
1 parent 292d49e commit c803e63
Show file tree
Hide file tree
Showing 8 changed files with 208 additions and 225 deletions.
100 changes: 41 additions & 59 deletions echo_handlers.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -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{
Expand Down Expand Up @@ -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
Expand All @@ -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,
})
}
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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)
}
4 changes: 2 additions & 2 deletions frontend/src/hooks/useApp.ts
Original file line number Diff line number Diff line change
@@ -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<ShowAppResponse>(pubkey && `/api/apps/${pubkey}`, swrFetcher);
return useSWR<App>(pubkey && `/api/apps/${pubkey}`, swrFetcher);
}
4 changes: 2 additions & 2 deletions frontend/src/hooks/useApps.ts
Original file line number Diff line number Diff line change
@@ -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<ListAppsResponse>("/api/apps", swrFetcher);
return useSWR<App[]>("/api/apps", swrFetcher);
}
56 changes: 22 additions & 34 deletions frontend/src/screens/apps/AppsList.tsx
Original file line number Diff line number Diff line change
@@ -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 <Loading />;
Expand Down Expand Up @@ -46,7 +41,7 @@ function AppsList() {
</tr>
</thead>
<tbody className="divide-y dark:divide-white/10">
{!apps.apps.length && (
{!apps.length && (
<tr className="bg-white dark:bg-surface-02dp">
<td
colSpan={3}
Expand All @@ -57,32 +52,25 @@ function AppsList() {
</tr>
)}

{apps.apps.length && (
<>
{apps.apps.map((app, index) => (
<tr
onClick={() => 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}}'"*/}
<td className="px-6 py-4 text-gray-500 dark:text-white">
{app.name}
</td>
<td className="px-6 py-4 text-gray-500 dark:text-neutral-400 hidden md:table-cell">
{apps.lastEvents[app.id]
? new Date(
apps.lastEvents[app.id].createdAt
).toLocaleDateString()
: "-"}
</td>
<td className="px-6 py-4 text-purple-700 dark:text-purple-400 text-right">
Details
</td>
</tr>
))}
</>
)}
{apps.map((app, index) => (
<tr
key={index}
onClick={() => navigate(`/apps/${app.nostrPubkey}`)}
className="bg-white dark:bg-surface-02dp cursor-pointer hover:bg-purple-50 dark:hover:bg-surface-16dp"
>
<td className="px-6 py-4 text-gray-500 dark:text-white">
{app.name}
</td>
<td className="px-6 py-4 text-gray-500 dark:text-neutral-400 hidden md:table-cell">
{app.lastEventAt
? new Date(app.lastEventAt).toLocaleDateString()
: "-"}
</td>
<td className="px-6 py-4 text-purple-700 dark:text-purple-400 text-right">
<a href={`/apps/${app.nostrPubkey}`}>Details</a>
</td>
</tr>
))}
</tbody>
</table>
</div>
Expand Down
Loading

0 comments on commit c803e63

Please sign in to comment.