142 lines
3.7 KiB
Go
142 lines
3.7 KiB
Go
package models_pages
|
|
|
|
import (
|
|
"bytes"
|
|
"fmt"
|
|
"html/template"
|
|
"log"
|
|
"main/tools"
|
|
"os"
|
|
"path/filepath"
|
|
"sort"
|
|
"strconv"
|
|
"strings"
|
|
"time"
|
|
)
|
|
|
|
const (
|
|
// Имя соответствующего шаблона
|
|
PostsPageTmplName = "posts.gohtml"
|
|
)
|
|
|
|
type PostsMap map[PostLink]*Post
|
|
type PostsPage struct {
|
|
PostsListOnPage []*Post // список постов на странице
|
|
PageNumber int // номер страницы
|
|
PagesCount int // общее количество страниц
|
|
}
|
|
|
|
func LoadPosts(dir string) (PostsMap, error) {
|
|
|
|
posts := PostsMap{}
|
|
|
|
err := filepath.Walk(dir, func(path string, f os.FileInfo, err error) error {
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if !f.IsDir() && strings.HasSuffix(f.Name(), ".md") {
|
|
|
|
md, err := os.ReadFile(path)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
html := tools.MdToHTML(md)
|
|
|
|
name := filepath.Base(path)
|
|
lowLineIndex := strings.Index(name, "_")
|
|
|
|
if lowLineIndex == -1 {
|
|
// Обработка случая, если "_" нет в имени
|
|
log.Fatal(`post name parse error`)
|
|
}
|
|
|
|
timestampStr := name[:lowLineIndex]
|
|
timestamp, err := strconv.ParseInt(timestampStr, 10, 64)
|
|
if err != nil {
|
|
// Ошибка парсинга timestamp
|
|
log.Fatal(`post name parse error`)
|
|
}
|
|
link := fmt.Sprintf("/%s", strings.TrimSuffix(name[lowLineIndex+1:], ".md"))
|
|
posts[PostLink(link)] = createPost(link, html, timestamp)
|
|
}
|
|
return nil
|
|
})
|
|
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return posts, nil
|
|
}
|
|
|
|
// Получение из мапы постов списка постов, отсортированного по ModTimestamp (новые сначала)
|
|
func (p *PostsMap) PostsList() []*Post {
|
|
postsSlice := make([]*Post, 0, len(*p))
|
|
for _, post := range *p {
|
|
postsSlice = append(postsSlice, post)
|
|
}
|
|
|
|
sort.Slice(postsSlice, func(i, j int) bool {
|
|
return postsSlice[i].Timestamp > postsSlice[j].Timestamp
|
|
})
|
|
|
|
return postsSlice
|
|
}
|
|
|
|
func CreatePage(postsList []*Post, pageNumber, postsMaxCountOnPage int) *PostsPage {
|
|
// Общее количество страниц
|
|
pagesCount := (len(postsList) + postsMaxCountOnPage - 1) / postsMaxCountOnPage
|
|
|
|
// Ошибки тут быть не может, так как этот обработчик настроен
|
|
// на только существующие реально pageNumber и в случае
|
|
// какого то не существующего номера страницы он просто
|
|
// не сработает (в главном main настроены маршруты)
|
|
|
|
startIndex := pageNumber * postsMaxCountOnPage
|
|
endIndex := startIndex + postsMaxCountOnPage
|
|
endIndex = min(endIndex, len(postsList))
|
|
postsSublistForPageNumber := postsList[startIndex:endIndex]
|
|
|
|
return &PostsPage{
|
|
PostsListOnPage: postsSublistForPageNumber,
|
|
PageNumber: pageNumber,
|
|
PagesCount: pagesCount,
|
|
}
|
|
}
|
|
|
|
func (p *PostsPage) RenderPostsPage(templates *template.Template, version int64) ([]byte, error) {
|
|
var pageData bytes.Buffer
|
|
|
|
var prevPageNumber, nextPageNumber int
|
|
|
|
if p.PageNumber == 0 {
|
|
prevPageNumber = p.PagesCount - 1
|
|
} else {
|
|
prevPageNumber = p.PageNumber - 1
|
|
}
|
|
|
|
nextPageNumber = (p.PageNumber + 1) % p.PagesCount
|
|
|
|
pagi := fmt.Sprintf(
|
|
`<a href="/posts/%d"><-</a> %d/%d <a href="/posts/%d">-></a>`,
|
|
prevPageNumber,
|
|
p.PageNumber+1,
|
|
p.PagesCount,
|
|
nextPageNumber,
|
|
)
|
|
|
|
context := map[string]any{
|
|
"pagi": template.HTML(pagi),
|
|
"version": version,
|
|
"renderingTimestamp": time.Now().Unix(),
|
|
"posts": p.PostsListOnPage,
|
|
}
|
|
|
|
if err := templates.ExecuteTemplate(&pageData, PostsPageTmplName, context); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return pageData.Bytes(), nil
|
|
}
|