2024-10-27 07:20:23 +01:00
|
|
|
package backend
|
|
|
|
|
|
|
|
import (
|
|
|
|
"fmt"
|
|
|
|
"io"
|
2025-01-22 22:10:34 +01:00
|
|
|
"log"
|
2024-10-27 07:20:23 +01:00
|
|
|
"os"
|
|
|
|
|
|
|
|
"git.streifling.com/jason/atom"
|
|
|
|
)
|
|
|
|
|
|
|
|
func GenerateAtomFeed(c *Config, db *DB) (*string, error) {
|
|
|
|
feed := atom.NewFeed(c.Title)
|
|
|
|
feed.ID = atom.NewID("urn:feed:1")
|
|
|
|
feed.Subtitle = atom.NewText("text", c.Description)
|
2024-11-01 16:22:31 +01:00
|
|
|
|
|
|
|
linkID := feed.AddLink(atom.NewLink(c.Link))
|
|
|
|
feed.Links[linkID].Rel = "self"
|
2024-10-27 07:20:23 +01:00
|
|
|
|
|
|
|
feed.Generator = atom.NewGenerator("cpolis")
|
|
|
|
feed.Generator.URI = "https://git.streifling.com/jason/cpolis"
|
2024-10-27 13:58:19 +01:00
|
|
|
feed.Generator.Version = c.Version
|
2024-10-27 07:20:23 +01:00
|
|
|
|
|
|
|
articles, err := db.GetCertainArticles("published", true)
|
|
|
|
if err != nil {
|
2025-01-22 22:10:34 +01:00
|
|
|
log.Printf("Error retrieving published articles for Atom feed: %v", err)
|
|
|
|
return nil, fmt.Errorf("error getting published articles for Atom feed: %w", err)
|
2024-10-27 07:20:23 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
for _, article := range articles {
|
|
|
|
articleTitle, err := ConvertToPlain(article.Title)
|
|
|
|
if err != nil {
|
2025-01-22 22:10:34 +01:00
|
|
|
log.Printf("Error converting article title to plain text for Atom feed: %v", err)
|
|
|
|
return nil, fmt.Errorf("error converting title to plain text for Atom feed: %w", err)
|
2024-10-27 07:20:23 +01:00
|
|
|
}
|
|
|
|
entry := atom.NewEntry(articleTitle)
|
2025-01-22 22:10:34 +01:00
|
|
|
entry.ID = atom.NewID(fmt.Sprintf("urn:entry:%d", article.ID))
|
2024-10-27 07:20:23 +01:00
|
|
|
entry.Published = atom.NewDate(article.Created)
|
2025-01-22 22:10:34 +01:00
|
|
|
entry.Content = atom.NewContent(atom.OutOfLine, "text/html", fmt.Sprintf("%s/article/serve/%s", c.Domain, article.UUID))
|
2024-10-27 07:20:23 +01:00
|
|
|
|
2024-10-30 02:12:53 +01:00
|
|
|
if article.AutoGenerated {
|
2024-10-30 03:23:59 +01:00
|
|
|
entry.Summary = atom.NewText("text", "automatically generated")
|
2024-10-30 02:12:53 +01:00
|
|
|
} else {
|
|
|
|
articleSummary, err := ConvertToPlain(article.Summary)
|
|
|
|
if err != nil {
|
2025-01-22 22:10:34 +01:00
|
|
|
log.Printf("Error converting article summary to plain text for Atom feed: %v", err)
|
|
|
|
return nil, fmt.Errorf("error converting description to plain text for Atom feed: %w", err)
|
2024-10-30 02:12:53 +01:00
|
|
|
}
|
|
|
|
entry.Summary = atom.NewText("text", articleSummary)
|
|
|
|
}
|
|
|
|
|
|
|
|
if len(article.BannerLink) > 0 {
|
2025-01-22 22:10:34 +01:00
|
|
|
linkID := entry.AddLink(atom.NewLink(fmt.Sprintf("%s/image/serve/%s", c.Domain, article.BannerLink)))
|
2024-10-30 02:12:53 +01:00
|
|
|
entry.Links[linkID].Rel = "enclosure"
|
|
|
|
entry.Links[linkID].Type = "image/webp"
|
|
|
|
}
|
2024-10-27 07:20:23 +01:00
|
|
|
|
2024-12-01 09:59:39 +01:00
|
|
|
authors, err := db.GetArticleAuthors(c, article.ID)
|
2024-10-27 07:20:23 +01:00
|
|
|
if err != nil {
|
2025-01-22 22:10:34 +01:00
|
|
|
log.Printf("Error retrieving authors for article ID %d for Atom feed: %v", article.ID, err)
|
|
|
|
return nil, fmt.Errorf("error getting article's authors for Atom feed: %w", err)
|
2024-12-01 09:59:39 +01:00
|
|
|
}
|
|
|
|
for _, author := range authors {
|
|
|
|
user, err := db.GetUser(c, author.ID)
|
|
|
|
if err != nil {
|
2025-01-22 22:10:34 +01:00
|
|
|
log.Printf("Error retrieving user info for author ID %d for Atom feed: %v", author.ID, err)
|
|
|
|
return nil, fmt.Errorf("error getting user info for Atom feed: %w", err)
|
2024-12-01 09:59:39 +01:00
|
|
|
}
|
2024-12-27 10:30:15 +01:00
|
|
|
|
2025-01-22 22:10:34 +01:00
|
|
|
authorID := entry.AddAuthor(atom.NewPerson(fmt.Sprintf("%s %s", user.FirstName, user.LastName)))
|
|
|
|
entry.Authors[authorID].URI = fmt.Sprintf("%s/image/serve/%s", c.Domain, user.ProfilePicLink)
|
2024-10-27 07:20:23 +01:00
|
|
|
}
|
|
|
|
|
2024-12-27 10:30:15 +01:00
|
|
|
contributors, err := db.GetArticleContributors(c, article.ID)
|
|
|
|
if err != nil {
|
2025-01-22 22:10:34 +01:00
|
|
|
log.Printf("Error retrieving contributors for article ID %d for Atom feed: %v", article.ID, err)
|
|
|
|
return nil, fmt.Errorf("error getting article's contributors for Atom feed: %w", err)
|
2024-12-27 10:30:15 +01:00
|
|
|
}
|
|
|
|
for _, contributor := range contributors {
|
|
|
|
user, err := db.GetUser(c, contributor.ID)
|
|
|
|
if err != nil {
|
2025-01-22 22:10:34 +01:00
|
|
|
log.Printf("Error retrieving user info for contributor ID %d for Atom feed: %v", contributor.ID, err)
|
|
|
|
return nil, fmt.Errorf("error getting user info for Atom feed: %w", err)
|
2024-12-27 10:30:15 +01:00
|
|
|
}
|
|
|
|
|
2025-01-22 22:10:34 +01:00
|
|
|
contributorID := entry.AddContributor(atom.NewPerson(fmt.Sprintf("%s %s", user.FirstName, user.LastName)))
|
|
|
|
entry.Contributors[contributorID].URI = fmt.Sprintf("%s/image/serve/%s", c.Domain, user.ProfilePicLink)
|
2024-12-27 10:30:15 +01:00
|
|
|
}
|
|
|
|
|
2024-10-27 07:20:23 +01:00
|
|
|
tags, err := db.GetArticleTags(article.ID)
|
|
|
|
if err != nil {
|
2025-01-22 22:10:34 +01:00
|
|
|
log.Printf("Error retrieving tags for article ID %d for Atom feed: %v", article.ID, err)
|
|
|
|
return nil, fmt.Errorf("error getting tags for articles for Atom feed: %w", err)
|
2024-10-27 07:20:23 +01:00
|
|
|
}
|
|
|
|
for _, tag := range tags {
|
|
|
|
entry.AddCategory(atom.NewCategory(tag.Name))
|
|
|
|
}
|
|
|
|
|
|
|
|
if article.IsInIssue || article.AutoGenerated {
|
2025-01-22 22:10:34 +01:00
|
|
|
entry.AddCategory(atom.NewCategory(fmt.Sprintf("Orient Express %d", article.IssueID)))
|
2024-10-27 07:20:23 +01:00
|
|
|
}
|
|
|
|
if article.AutoGenerated {
|
|
|
|
entry.AddCategory(atom.NewCategory("autogenerated"))
|
|
|
|
}
|
|
|
|
|
|
|
|
entry.Updated = atom.NewDate(article.Created)
|
|
|
|
feed.AddEntry(entry)
|
|
|
|
}
|
|
|
|
|
|
|
|
if err = feed.Check(); err != nil {
|
2025-01-22 22:10:34 +01:00
|
|
|
log.Printf("Error checking Atom feed: %v", err)
|
|
|
|
return nil, fmt.Errorf("error checking Atom feed: %w", err)
|
2024-10-27 07:20:23 +01:00
|
|
|
}
|
|
|
|
|
2025-01-22 22:10:34 +01:00
|
|
|
atomXML, err := feed.ToXML("UTF-8")
|
2024-10-27 07:20:23 +01:00
|
|
|
if err != nil {
|
2025-01-22 22:10:34 +01:00
|
|
|
log.Printf("Error converting Atom feed to XML: %v", err)
|
|
|
|
return nil, fmt.Errorf("error converting Atom feed to XML: %w", err)
|
2024-10-27 07:20:23 +01:00
|
|
|
}
|
|
|
|
|
2025-01-22 22:10:34 +01:00
|
|
|
return &atomXML, nil
|
2024-10-27 07:20:23 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
func SaveAtomFeed(filename string, feed *string) error {
|
|
|
|
file, err := os.Create(filename)
|
|
|
|
if err != nil {
|
2025-01-22 22:10:34 +01:00
|
|
|
log.Printf("Error creating file for Atom feed: %v", err)
|
|
|
|
return fmt.Errorf("error creating file for Atom feed: %w", err)
|
2024-10-27 07:20:23 +01:00
|
|
|
}
|
2025-01-22 22:10:34 +01:00
|
|
|
defer func() {
|
|
|
|
if cerr := file.Close(); cerr != nil {
|
|
|
|
log.Printf("Error closing file for Atom feed: %v", cerr)
|
|
|
|
}
|
|
|
|
}()
|
|
|
|
|
2024-10-27 07:20:23 +01:00
|
|
|
if err = file.Chmod(0644); err != nil {
|
2025-01-22 22:10:34 +01:00
|
|
|
log.Printf("Error setting permissions for Atom file '%s': %v", filename, err)
|
|
|
|
return fmt.Errorf("error setting permissions for Atom file: %w", err)
|
2024-10-27 07:20:23 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
if _, err = io.WriteString(file, *feed); err != nil {
|
2025-01-22 22:10:34 +01:00
|
|
|
log.Printf("Error writing to Atom file '%s': %v", filename, err)
|
|
|
|
return fmt.Errorf("error writing to Atom file: %w", err)
|
2024-10-27 07:20:23 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|