src

Go monorepo.
git clone git://code.dwrz.net/src
Log | Files | Refs

entry.go (3076B)


      1 package entry
      2 
      3 import (
      4 	"embed"
      5 	"encoding/json"
      6 	"fmt"
      7 	"html/template"
      8 	"io/fs"
      9 	"path/filepath"
     10 	"sort"
     11 	"time"
     12 
     13 	"code.dwrz.net/src/pkg/log"
     14 )
     15 
     16 //go:embed static/*
     17 var static embed.FS
     18 
     19 const (
     20 	YearFormat   = "2006"
     21 	DateFormat   = "2006-01-02"
     22 	metadataFile = "metadata.json"
     23 )
     24 
     25 type Entry struct {
     26 	Cover     string        `json:"cover"`
     27 	Content   template.HTML `json:"content"`
     28 	Date      time.Time     `json:"date"`
     29 	Link      string        `json:"link"`
     30 	Next      *Entry        `json:"next"`
     31 	Previous  *Entry        `json:"previous"`
     32 	Published bool          `json:"published"`
     33 	Title     string        `json:"title"`
     34 }
     35 
     36 type Year struct {
     37 	Entries []*Entry
     38 	Text    string
     39 }
     40 
     41 type LoadParams struct {
     42 	Log *log.Logger
     43 }
     44 
     45 func Load(p LoadParams) ([]*Entry, error) {
     46 	var entries []*Entry
     47 
     48 	parseFS := func(path string, d fs.DirEntry, err error) error {
     49 		if err != nil {
     50 			return err
     51 		}
     52 		if !d.IsDir() || d.Name() == "static" {
     53 			return nil
     54 		}
     55 
     56 		// Open the entry metadata file.
     57 		data, err := static.ReadFile(
     58 			filepath.Join("static", d.Name(), metadataFile),
     59 		)
     60 		if err != nil {
     61 			p.Log.Error.Printf("ignoring %s: %v", d.Name(), err)
     62 			return nil
     63 		}
     64 
     65 		var entry = &Entry{}
     66 		if err := json.Unmarshal(data, entry); err != nil {
     67 			p.Log.Error.Printf("ignoring %s: %v", d.Name(), err)
     68 			return nil
     69 		}
     70 
     71 		// Ignore unpublished entries.
     72 		if !entry.Published {
     73 			p.Log.Debug.Printf(
     74 				"ignoring %s: not published", d.Name(),
     75 			)
     76 			return nil
     77 		}
     78 
     79 		// Get the entry content.
     80 		entryFile := d.Name() + ".html"
     81 		content, err := static.ReadFile(
     82 			filepath.Join("static", d.Name(), entryFile),
     83 		)
     84 		if err != nil {
     85 			p.Log.Error.Printf("ignoring %s: %v", d.Name(), err)
     86 			return nil
     87 		}
     88 
     89 		// Set entry values.
     90 		entry.Content = template.HTML(string(content))
     91 		entry.Link = fmt.Sprintf("%s", entry.Date.Format(DateFormat))
     92 
     93 		entries = append(entries, entry)
     94 
     95 		return nil
     96 	}
     97 
     98 	if err := fs.WalkDir(static, "static", parseFS); err != nil {
     99 		return nil, fmt.Errorf("failed to parse templates: %v", err)
    100 	}
    101 
    102 	// Sort the entries.
    103 	sort.Slice(entries, func(i, j int) bool {
    104 		return entries[i].Date.Before(entries[j].Date)
    105 	})
    106 
    107 	// Set the previous and next entry.
    108 	for i, e := range entries {
    109 		if i-1 >= 0 {
    110 			e.Previous = entries[i-1]
    111 		}
    112 		if i+1 < len(entries) {
    113 			e.Next = entries[i+1]
    114 		}
    115 	}
    116 
    117 	return entries, nil
    118 }
    119 
    120 func SortYear(entries []*Entry) []Year {
    121 	var yearEntries = map[string]*Year{}
    122 	for _, e := range entries {
    123 		year := e.Date.Format(YearFormat)
    124 		if _, exists := yearEntries[year]; !exists {
    125 			yearEntries[year] = &Year{
    126 				Entries: []*Entry{e},
    127 				Text:    year,
    128 			}
    129 			continue
    130 		}
    131 
    132 		yearEntries[year].Entries = append(yearEntries[year].Entries, e)
    133 	}
    134 
    135 	// Sort each year's entries, then sort the years.
    136 	var years = []Year{}
    137 	for _, year := range yearEntries {
    138 		sort.Slice(year.Entries, func(i, j int) bool {
    139 			return year.Entries[i].Date.After(year.Entries[j].Date)
    140 		})
    141 
    142 		years = append(years, *year)
    143 	}
    144 	sort.Slice(years, func(i, j int) bool {
    145 		return years[i].Text > years[j].Text
    146 	})
    147 
    148 	return years
    149 }