tmpl relay.html and replace LastNoteItem struct with a simpler EnhancedEvent with methods instead of hardcoded values.

This commit is contained in:
fiatjaf
2023-10-21 12:19:30 -03:00
parent 901b2b5d62
commit 65025d4967
6 changed files with 131 additions and 132 deletions

57
data.go
View File

@@ -14,18 +14,17 @@ import (
"github.com/nbd-wtf/go-nostr/nip19"
)
type LastNotesItem struct {
Npub string
NpubShort string
Nevent string
Content string
CreatedAt string
ModifiedAt string
IsReply bool
type EnhancedEvent struct {
event *nostr.Event
relays []string
}
func (i LastNotesItem) Preview() template.HTML {
lines := strings.Split(html.EscapeString(i.Content), "\n")
func (ee EnhancedEvent) IsReply() bool {
return nip10.GetImmediateReply(ee.event.Tags) != nil
}
func (ee EnhancedEvent) Preview() template.HTML {
lines := strings.Split(html.EscapeString(ee.event.Content), "\n")
var processedLines []string
for _, line := range lines {
if strings.TrimSpace(line) == "" {
@@ -38,6 +37,29 @@ func (i LastNotesItem) Preview() template.HTML {
return template.HTML(strings.Join(processedLines, "<br/>"))
}
func (ee EnhancedEvent) Npub() string {
npub, _ := nip19.EncodePublicKey(ee.event.PubKey)
return npub
}
func (ee EnhancedEvent) NpubShort() string {
npub := ee.Npub()
return npub[:8] + "…" + npub[len(npub)-4:]
}
func (ee EnhancedEvent) Nevent() string {
nevent, _ := nip19.EncodeEvent(ee.event.ID, ee.relays, ee.event.PubKey)
return nevent
}
func (ee EnhancedEvent) CreatedAtStr() string {
return time.Unix(int64(ee.event.CreatedAt), 0).Format("2006-01-02 15:04:05")
}
func (ee EnhancedEvent) ModifiedAtStr() string {
return time.Unix(int64(ee.event.CreatedAt), 0).Format("2006-01-02T15:04:05Z07:00")
}
type Data struct {
templateId TemplateID
typ string
@@ -54,7 +76,7 @@ type Data struct {
authorRelays []string
authorLong string
authorShort string
renderableLastNotes []LastNotesItem
renderableLastNotes []EnhancedEvent
kindDescription string
kindNIP string
video string
@@ -86,7 +108,7 @@ func grabData(ctx context.Context, code string, isProfileSitemap bool) (*Data, e
modifiedAt := time.Unix(int64(event.CreatedAt), 0).Format("2006-01-02T15:04:05Z07:00")
author := event
var renderableLastNotes []LastNotesItem
var renderableLastNotes []EnhancedEvent
parentNevent := ""
authorRelays := []string{}
var content string
@@ -148,16 +170,9 @@ func grabData(ctx context.Context, code string, isProfileSitemap bool) (*Data, e
}
}
renderableLastNotes = make([]LastNotesItem, len(lastNotes))
renderableLastNotes = make([]EnhancedEvent, len(lastNotes))
for i, levt := range lastNotes {
nevent, _ := nip19.EncodeEvent(levt.ID, []string{}, levt.PubKey)
renderableLastNotes[i] = LastNotesItem{
Nevent: nevent,
Content: levt.Content,
CreatedAt: time.Unix(int64(levt.CreatedAt), 0).Format("2006-01-02 15:04:05"),
ModifiedAt: time.Unix(int64(levt.CreatedAt), 0).Format("2006-01-02T15:04:05Z07:00"),
IsReply: nip10.GetImmediateReply(levt.Tags) != nil,
}
renderableLastNotes[i] = EnhancedEvent{levt, []string{}}
}
if err != nil {
return nil, err

View File

@@ -71,7 +71,6 @@ func main() {
// use a mapping to expressly link the templates and share them between more kinds/types
templateMapping = map[string]string{
"profile_sitemap": "sitemap.xml",
"relay": "relay.html",
"relay_sitemap": "sitemap.xml",
"archive_sitemap": "sitemap.xml",
}

View File

@@ -7,6 +7,7 @@ import (
"html/template"
"github.com/nbd-wtf/go-nostr"
"github.com/nbd-wtf/go-nostr/nip11"
"github.com/tylermmorton/tmpl"
)
@@ -244,7 +245,7 @@ type ProfilePage struct {
Content string
CreatedAt string
Domain string
LastNotes []LastNotesItem
LastNotes []EnhancedEvent
Metadata nostr.ProfileMetadata
NormalizedAuthorWebsiteURL string
RenderedAuthorAboutText template.HTML
@@ -258,3 +259,27 @@ type ProfilePage struct {
func (*ProfilePage) TemplateText() string {
return tmplProfile
}
var (
//go:embed templates/relay.html
tmplRelay string
RelayTemplate = tmpl.MustCompile(&RelayPage{})
)
type RelayPage struct {
HeadCommonPartial `tmpl:"head_common"`
TopPartial `tmpl:"top"`
ClientsPartial `tmpl:"clients"`
FooterPartial `tmpl:"footer"`
Type string
Info *nip11.RelayInformationDocument
Hostname string
Proxy string
LastNotes []EnhancedEvent
ModifiedAt string
}
func (*RelayPage) TemplateText() string {
return tmplRelay
}

View File

@@ -7,18 +7,19 @@ import (
"time"
"github.com/nbd-wtf/go-nostr"
"github.com/nbd-wtf/go-nostr/nip10"
"github.com/nbd-wtf/go-nostr/nip11"
"github.com/nbd-wtf/go-nostr/nip19"
)
func renderRelayPage(w http.ResponseWriter, r *http.Request) {
code := r.URL.Path[1:]
hostname := code[2:]
typ := "relay"
isSitemap := false
numResults := 1000
if strings.HasSuffix(hostname, ".xml") {
hostname = hostname[:len(hostname)-4]
typ = "relay_sitemap"
numResults = 5000
isSitemap = true
}
ctx, cancel := context.WithTimeout(r.Context(), time.Second*5)
@@ -33,48 +34,20 @@ func renderRelayPage(w http.ResponseWriter, r *http.Request) {
}
// last notes
events_num := 1000
if typ == "relay_sitemap" {
events_num = 5000
}
var lastNotes []*nostr.Event
if relay, err := pool.EnsureRelay(hostname); err == nil {
lastNotes, _ = relay.QuerySync(ctx, nostr.Filter{
Kinds: []int{1},
Limit: events_num,
Limit: numResults,
})
}
renderableLastNotes := make([]LastNotesItem, len(lastNotes))
renderableLastNotes := make([]EnhancedEvent, len(lastNotes))
lastEventAt := time.Now()
relay := []string{"wss://" + hostname}
for i, levt := range lastNotes {
nevent, _ := nip19.EncodeEvent(levt.ID, relay, levt.PubKey)
npub, _ := nip19.EncodePublicKey(levt.PubKey)
npubShort := npub[:8] + "…" + npub[len(npub)-4:]
renderableLastNotes[i] = LastNotesItem{
Npub: npub,
NpubShort: npubShort,
Nevent: nevent,
Content: levt.Content,
CreatedAt: time.Unix(int64(levt.CreatedAt), 0).Format("2006-01-02 15:04:05"),
ModifiedAt: time.Unix(int64(levt.CreatedAt), 0).Format("2006-01-02T15:04:05Z07:00"),
IsReply: nip10.GetImmediateReply(levt.Tags) != nil,
}
if i == 0 {
lastEventAt = time.Unix(int64(levt.CreatedAt), 0)
}
if len(lastNotes) > 0 {
lastEventAt = time.Unix(int64(lastNotes[0].CreatedAt), 0)
}
params := map[string]any{
"clients": []ClientReference{
{Name: "Coracle", URL: "https://coracle.social/relays/" + hostname},
},
"type": "relay",
"info": info,
"hostname": hostname,
"proxy": "https://" + hostname + "/njump/proxy?src=",
"lastNotes": renderableLastNotes,
"modifiedAt": lastEventAt.Format("2006-01-02T15:04:05Z07:00"),
for i, levt := range lastNotes {
renderableLastNotes[i] = EnhancedEvent{levt, []string{"wss://" + hostname}}
}
if len(renderableLastNotes) != 0 {
@@ -83,8 +56,23 @@ func renderRelayPage(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Cache-Control", "max-age=60")
}
if err := tmpls.ExecuteTemplate(w, templateMapping[typ], params); err != nil {
log.Error().Err(err).Msg("error rendering")
return
if !isSitemap {
RelayTemplate.Render(w, &RelayPage{
HeadCommonPartial: HeadCommonPartial{IsProfile: false},
ClientsPartial: ClientsPartial{
Clients: []ClientReference{
{Name: "Coracle", URL: "https://coracle.social/relays/" + hostname},
},
},
Type: "relay",
Info: info,
Hostname: hostname,
Proxy: "https://" + hostname + "/njump/proxy?src=",
LastNotes: renderableLastNotes,
ModifiedAt: lastEventAt.Format("2006-01-02T15:04:05Z07:00"),
})
} else {
// ArchiveSitemapTemplate.Render TODO
}
}

View File

@@ -109,15 +109,15 @@
<div class="field separator"></div>
<nav class="field last_notes">
<h2>Last Notes</h2>
{{range $i, $element := .LastNotes}}
<a href="/{{.Nevent}}" class="note">
{{range $i, $ee := .LastNotes}}
<a href="/{{$ee.Nevent}}" class="note">
<div class="header">
<div class="published_at">{{$element.CreatedAt}}</div>
{{if $element.IsReply}}
<div class="published_at">{{$ee.CreatedAtStr}}</div>
{{if $ee.IsReply}}
<div class="is_reply">- reply</div>
{{end}}
</div>
<div class="content">{{$element.Preview}}</div>
<div class="content">{{$ee.Preview}}</div>
</a>
{{end}}
</nav>

View File

@@ -1,123 +1,95 @@
<!doctype html>
<!DOCTYPE html>
<html class="theme--default">
<meta charset="UTF-8" />
<head>
<title>
Nostr Relay {{.hostname | escapeString}} - {{.info.Name | escapeString}}
</title>
<meta
property="og:title"
content="{{.hostname | escapeString}} - nostr relay"
/>
<meta
name="twitter:title"
content="{{.hostname | escapeString}} - nostr relay"
/>
<meta
property="og:site_name"
content="{{.hostname | escapeString}} - nostr relay"
/>
{{ if .info.Icon }}
<meta property="og:image" content="{{.info.Icon | escapeString}}" />
<meta
property="twitter:image"
content="{{.proxy}}{{.info.Icon | escapeString}}"
/>
{{end}} {{ if .info.Description }}
<meta
property="og:description"
content="{{.info.Description | escapeString}}"
/>
<meta
name="twitter:description"
content="{{.info.Description | escapeString}}"
/>
<title>Nostr Relay {{.Hostname}} - {{.Info.Name}}</title>
<meta property="og:title" content="{{.Hostname}} - nostr relay" />
<meta name="twitter:title" content="{{.Hostname}} - nostr relay" />
<meta property="og:site_name" content="{{.Hostname}} - nostr relay" />
{{ if not (eq "" .Info.Icon) }}
<meta property="og:image" content="{{.Info.Icon}}" />
<meta property="twitter:image" content="{{.Proxy}}{{.Info.Icon}}" />
{{end}} {{ if not (eq "" .Info.Description) }}
<meta property="og:description" content="{{.Info.Description}}" />
<meta name="twitter:description" content="{{.Info.Description}}" />
{{end}}
<meta property="twitter:card" content="summary" />
<link
rel="sitemap"
type="application/xml"
title="Sitemap for {{.hostname | escapeString}}"
href="/r/{{.hostname | escapeString}}.xml"
title="Sitemap for {{.Hostname}}"
href="/r/{{.Hostname}}.xml"
/>
{{template "head_common.html" .}}
{{template "head_common" .}}
</head>
<body class="profile">
{{template "top.html" .}}
{{template "top" .}}
<div class="container_wrapper">
<div class="container">
<div class="column columnA">
<div class="info-wrapper">
{{.info.Name | escapeString}}
{{.Info.Name}}
<span class="display">&nbsp;</span>
</div>
<div class="pic-wrapper">
<img class="pic" src="{{.info.Icon | escapeString}}" />
<img class="pic" src="{{.Info.Icon}}" />
</div>
</div>
<div class="column column_content">
<div class="field info-wrapper">
<h1 class="name">{{.info.Name | escapeString}}</h1>
<h1 class="name">{{.Info.Name}}</h1>
</div>
<div class="field separator long"></div>
<div class="field">wss://{{.hostname | escapeString}}</div>
<div class="field about">
{{.info.Description | escapeString | basicFormatting}}
</div>
<div class="field">wss://{{.Hostname}}</div>
<div class="field about">{{.Info.Description}}</div>
<div class="field separator long"></div>
{{if .info.PubKey}}
{{ if not (eq "" .Info.PubKey) }}
<div class="field">
<div class="label">Public Key</div>
{{.info.PubKey | escapeString}}
{{.Info.PubKey}}
</div>
{{end}} {{if .info.Contact}}
{{ end }}
<!---->
{{ if not (eq "" .Info.Contact) }}
<div class="field">
<div class="label">Contact</div>
<a href="{{.info.Contact | escapeString}}"
>{{.info.Contact | escapeString}}</a
>
<a href="{{.Info.Contact}}">{{.Info.Contact}}</a>
</div>
{{end}}
{{ end }}
<div class="field separator"></div>
<div class="field last_notes">
<h2>Last Notes</h2>
{{range .lastNotes}}
<a href="/{{.Nevent | escapeString}}" class="note">
{{range $i, $ee := .LastNotes}}
<a href="/{{$ee.Nevent}}" class="note">
<div class="header">
<div class="published_at">{{.CreatedAt | escapeString}}</div>
<div class="published_at">{{$ee.CreatedAtStr}}</div>
<br />
{{if not (eq .ParentNevent "")}}
{{if $ee.IsReply}}
<div class="is_reply">- reply</div>
{{end}}
<div class="npub">
by <span href="/{{.Npub}}">{{.NpubShort}}</span>
by <span href="/{{$ee.Npub}}">{{$ee.NpubShort}}</span>
</div>
</div>
<div class="content">
{{.Content | escapeString | previewNotesFormatting}}
</div>
<div class="content">{{$ee.Preview}}</div>
</a>
{{end}}
</div>
</div>
{{template "column_clients.html" .}}
{{template "clients" .ClientsPartial}}
</div>
</div>
{{template "footer.html"}}
<script>
{{template "scripts.js"}}
</script>
{{template "footer" .}}
</body>
</html>