Refactor HTML creation

This commit is contained in:
Joakim Hellsén 2024-02-14 01:56:47 +01:00
commit 5da1cf0bd5
3 changed files with 70 additions and 104 deletions

View file

@ -2,6 +2,7 @@ package html
import ( import (
"fmt" "fmt"
"log"
"math/rand" "math/rand"
"strings" "strings"
@ -79,69 +80,31 @@ textarea {
} }
` `
func FullHTML(h HTMLData) string { const (
var sb strings.Builder // errorListItem is shown after adding a feed. It shows if error or success.
var errorBuilder strings.Builder errorListItem = `<li class="%s"><a href="%s">%s</a> - %s</li>`
FeedCount := 0 // htmlTemplate is the HTML template for the entire page.
DatabaseSize := stats.GetDBSize() htmlTemplate = `<!DOCTYPE html>
<html lang="en">
// This is the error message that will be displayed if there are any errors <head>
if len(h.ParseResult) > 0 { <meta charset="UTF-8">
errorBuilder.WriteString("<ul>") <meta name="viewport" content="width=device-width, initial-scale=1.0">
for _, result := range h.ParseResult { <meta name="description" content="%s">
var listItemClass, statusMsg string <meta name="keywords" content="%s">
if result.IsError { <meta name="author" content="%s">
listItemClass = "error" <link rel="canonical" href="%s">
statusMsg = result.Msg <title>%s</title>
} else { <style>%s</style>
listItemClass = "success" </head>
statusMsg = result.Msg <body>
} %s
errorBuilder.WriteString(fmt.Sprintf(`<li class="%s"><a href="%s">%s</a> - %s</li>`, listItemClass, result.FeedURL, result.FeedURL, statusMsg))
}
errorBuilder.WriteString("</ul>")
}
StatusMsg := errorBuilder.String()
sb.WriteString(`
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
`)
if h.Description != "" {
sb.WriteString(`<meta name="description" content="` + h.Description + `">`)
}
if h.Keywords != "" {
sb.WriteString(`<meta name="keywords" content="` + h.Keywords + `">`)
}
if h.Author != "" {
sb.WriteString(`<meta name="author" content="` + h.Author + `">`)
}
if h.CanonicalURL != "" {
sb.WriteString(`<link rel="canonical" href="` + h.CanonicalURL + `">`)
}
sb.WriteString(`
<title>` + h.Title + `</title>
<style>` + style + `</style>
</head>
<body>
` + StatusMsg + `
<span class="title"><h1><a href="/">FeedVault</a></h1></span> <span class="title"><h1><a href="/">FeedVault</a></h1></span>
<div class="leftright"> <div class="leftright">
<div class="left"> <div class="left">
<small>Archive of <a href="https://en.wikipedia.org/wiki/Web_feed">web feeds</a>. ` + fmt.Sprintf("%d", FeedCount) + ` feeds. ~` + DatabaseSize + `.</small> <small>Archive of <a href="https://en.wikipedia.org/wiki/Web_feed">web feeds</a>. %d feeds. ~%s.</small>
</div> </div>
<div class="right"> <div class="right">
<!-- Search -->
<form action="#" method="get"> <form action="#" method="get">
<input type="text" name="q" placeholder="Search"> <input type="text" name="q" placeholder="Search">
<button type="submit">Search</button> <button type="submit">Search</button>
@ -152,7 +115,7 @@ func FullHTML(h HTMLData) string {
<small> <small>
<div class="leftright"> <div class="leftright">
<div class="left"> <div class="left">
<a href="/">Home</a> | <a href="/feeds">Feeds</a> | <a href="/api">API</a> <a href="/">Home</a> | <a href="/feeds">Feeds</a> | <a href="/api">API</a>
</div> </div>
<div class="right"> <div class="right">
<a href="https://github.com/TheLovinator1/FeedVault">GitHub</a> | <a href="https://github.com/sponsors/TheLovinator1">Donate</a> <a href="https://github.com/TheLovinator1/FeedVault">GitHub</a> | <a href="https://github.com/sponsors/TheLovinator1">Donate</a>
@ -161,10 +124,10 @@ func FullHTML(h HTMLData) string {
</small> </small>
</nav> </nav>
<hr> <hr>
<main> <main>
` + h.Content + ` %s
</main> </main>
<hr> <hr>
<footer> <footer>
<small> <small>
<div class="leftright"> <div class="leftright">
@ -178,14 +141,41 @@ func FullHTML(h HTMLData) string {
<a href="mailto:hello@feedvault.se">hello@feedvault.se</a> <a href="mailto:hello@feedvault.se">hello@feedvault.se</a>
</div> </div>
<div class="right"> <div class="right">
` + quotes.FunMsg[rand.Intn(len(quotes.FunMsg))] + ` %s
</div> </div>
</div> </div>
</small> </small>
</footer> </footer>
</body> </body>
</html>`) </html>`
)
return sb.String()
func buildErrorList(parseResults []models.ParseResult) string {
var errorBuilder strings.Builder
if len(parseResults) > 0 {
errorBuilder.WriteString("<ul>")
for _, result := range parseResults {
// CSS class for the list item. Green for success, red for error.
listItemClass := "success"
if result.IsError {
listItemClass = "error"
}
errorBuilder.WriteString(fmt.Sprintf(errorListItem, listItemClass, result.FeedURL, result.FeedURL, result.Msg))
}
errorBuilder.WriteString("</ul>")
}
return errorBuilder.String()
}
func FullHTML(h HTMLData) string {
statusMsg := buildErrorList(h.ParseResult)
feedCount := 0
databaseSize, err := stats.GetDBSize()
if err != nil {
databaseSize = "0 KiB"
log.Println("Error getting database size:", err)
}
funMsg := quotes.FunMsg[rand.Intn(len(quotes.FunMsg))]
return fmt.Sprintf(htmlTemplate, h.Description, h.Keywords, h.Author, h.CanonicalURL, h.Title, style, statusMsg, feedCount, databaseSize, h.Content, funMsg)
} }

View file

@ -1,32 +1,7 @@
package models package models
import (
"net/http"
"github.com/TheLovinator1/FeedVault/pkg/stats"
)
type TemplateData struct {
Title string
Description string
Keywords string
Author string
CanonicalURL string
FeedCount int
DatabaseSize string
Request *http.Request
ParseErrors []ParseResult
}
type ParseResult struct { type ParseResult struct {
FeedURL string FeedURL string
Msg string Msg string
IsError bool IsError bool
} }
func (d *TemplateData) GetDatabaseSizeAndFeedCount() {
// TODO: Get the feed count from the database
// TODO: Add amount of entries
// TODO: Add amount of users
d.DatabaseSize = stats.GetDBSize()
}

View file

@ -2,7 +2,6 @@ package stats
import ( import (
"fmt" "fmt"
"log"
"os" "os"
"time" "time"
) )
@ -14,20 +13,16 @@ type Cache struct {
var cache Cache var cache Cache
// Get the size of the database and return as nearest human readable size. func GetDBSize() (string, error) {
//
// e.g. 1.23 KiB, 4.56 MiB, 7.89 GiB, 0.12 TiB
// The size is cached for 10 minutes
func GetDBSize() string {
// If cache is less than 10 minutes old, return cached data // If cache is less than 10 minutes old, return cached data
if time.Since(cache.timestamp).Minutes() < 10 { if time.Since(cache.timestamp).Minutes() < 10 {
return cache.data return cache.data, nil
} }
// TODO: This should be read from the environment
fileInfo, err := os.Stat("feedvault.db") fileInfo, err := os.Stat("feedvault.db")
if err != nil { if err != nil {
log.Println("Error getting file info:", err) return "", err
return "0 B"
} }
// Get the file size in bytes // Get the file size in bytes
@ -35,16 +30,23 @@ func GetDBSize() string {
// Convert to human readable size and append the unit (KiB, MiB, GiB, TiB) // Convert to human readable size and append the unit (KiB, MiB, GiB, TiB)
var size float64 var size float64
if fileSize < 1024*1024 { if fileSize < 1024*1024 {
// If the file size is less than 1 KiB, return the size in bytes
size = float64(fileSize) / 1024 size = float64(fileSize) / 1024
cache.data = fmt.Sprintf("%.2f KiB", size) cache.data = fmt.Sprintf("%.2f KiB", size)
} else if fileSize < 1024*1024*1024 { } else if fileSize < 1024*1024*1024 {
// If the file size is less than 1 MiB, return the size in KiB
size = float64(fileSize) / (1024 * 1024) size = float64(fileSize) / (1024 * 1024)
cache.data = fmt.Sprintf("%.2f MiB", size) cache.data = fmt.Sprintf("%.2f MiB", size)
} else if fileSize < 1024*1024*1024*1024 { } else if fileSize < 1024*1024*1024*1024 {
// If the file size is less than 1 GiB, return the size in MiB
size = float64(fileSize) / (1024 * 1024 * 1024) size = float64(fileSize) / (1024 * 1024 * 1024)
cache.data = fmt.Sprintf("%.2f GiB", size) cache.data = fmt.Sprintf("%.2f GiB", size)
} else { } else {
// If the file size is 1 GiB or more, return the size in TiB
size = float64(fileSize) / (1024 * 1024 * 1024 * 1024) size = float64(fileSize) / (1024 * 1024 * 1024 * 1024)
cache.data = fmt.Sprintf("%.2f TiB", size) cache.data = fmt.Sprintf("%.2f TiB", size)
} }
@ -52,7 +54,6 @@ func GetDBSize() string {
// Update cache timestamp // Update cache timestamp
cache.timestamp = time.Now() cache.timestamp = time.Now()
log.Println("Returning database size, it is", cache.data) // Return the human readable size
return cache.data, nil
return cache.data
} }