mirror of
https://github.com/aljazceru/njump.git
synced 2026-01-31 03:34:37 +01:00
tmpl relay.html and replace LastNoteItem struct with a simpler EnhancedEvent with methods instead of hardcoded values.
This commit is contained in:
57
data.go
57
data.go
@@ -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
|
||||
|
||||
1
main.go
1
main.go
@@ -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",
|
||||
}
|
||||
|
||||
27
pages.go
27
pages.go
@@ -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
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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"> </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>
|
||||
|
||||
Reference in New Issue
Block a user