package backend import ( "fmt" "io" "log" "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) linkID := feed.AddLink(atom.NewLink(c.Link)) feed.Links[linkID].Rel = "self" feed.Generator = atom.NewGenerator("cpolis") feed.Generator.URI = "https://git.streifling.com/jason/cpolis" feed.Generator.Version = c.Version articles, err := db.GetCertainArticles("published", true) if err != nil { log.Printf("Error retrieving published articles for Atom feed: %v", err) return nil, fmt.Errorf("error getting published articles for Atom feed: %w", err) } for _, article := range articles { articleTitle, err := ConvertToPlain(article.Title) if err != nil { 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) } entry := atom.NewEntry(articleTitle) entry.ID = atom.NewID(fmt.Sprintf("urn:entry:%d", article.ID)) entry.Published = atom.NewDate(article.Created) entry.Content = atom.NewContent(atom.OutOfLine, "text/html", fmt.Sprintf("%s/article/serve/%s", c.Domain, article.UUID)) if article.AutoGenerated { entry.Summary = atom.NewText("text", "automatically generated") } else { articleSummary, err := ConvertToPlain(article.Summary) if err != nil { 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) } entry.Summary = atom.NewText("text", articleSummary) } if len(article.BannerLink) > 0 { linkID := entry.AddLink(atom.NewLink(fmt.Sprintf("%s/image/serve/%s", c.Domain, article.BannerLink))) entry.Links[linkID].Rel = "enclosure" entry.Links[linkID].Type = "image/webp" } authors, err := db.GetArticleAuthors(c, article.ID) if err != nil { 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) } for _, author := range authors { user, err := db.GetUser(c, author.ID) if err != nil { 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) } 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) } contributors, err := db.GetArticleContributors(c, article.ID) if err != nil { 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) } for _, contributor := range contributors { user, err := db.GetUser(c, contributor.ID) if err != nil { 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) } 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) } tags, err := db.GetArticleTags(article.ID) if err != nil { 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) } for _, tag := range tags { entry.AddCategory(atom.NewCategory(tag.Name)) } if article.IsInIssue || article.AutoGenerated { entry.AddCategory(atom.NewCategory(fmt.Sprintf("Orient Express %d", article.IssueID))) } if article.AutoGenerated { entry.AddCategory(atom.NewCategory("autogenerated")) } entry.Updated = atom.NewDate(article.Created) feed.AddEntry(entry) } if err = feed.Check(); err != nil { log.Printf("Error checking Atom feed: %v", err) return nil, fmt.Errorf("error checking Atom feed: %w", err) } atomXML, err := feed.ToXML("UTF-8") if err != nil { log.Printf("Error converting Atom feed to XML: %v", err) return nil, fmt.Errorf("error converting Atom feed to XML: %w", err) } return &atomXML, nil } func SaveAtomFeed(filename string, feed *string) error { file, err := os.Create(filename) if err != nil { log.Printf("Error creating file for Atom feed: %v", err) return fmt.Errorf("error creating file for Atom feed: %w", err) } defer func() { if cerr := file.Close(); cerr != nil { log.Printf("Error closing file for Atom feed: %v", cerr) } }() if err = file.Chmod(0644); err != nil { log.Printf("Error setting permissions for Atom file '%s': %v", filename, err) return fmt.Errorf("error setting permissions for Atom file: %w", err) } if _, err = io.WriteString(file, *feed); err != nil { log.Printf("Error writing to Atom file '%s': %v", filename, err) return fmt.Errorf("error writing to Atom file: %w", err) } return nil }