package export import ( "fmt" "log" "os" "path/filepath" "strings" "time" "git.blob42.xyz/blob42/hugobot/v3/config" "git.blob42.xyz/blob42/hugobot/v3/encoder" "git.blob42.xyz/blob42/hugobot/v3/feeds" "git.blob42.xyz/blob42/hugobot/v3/filters" "git.blob42.xyz/blob42/hugobot/v3/posts" "git.blob42.xyz/blob42/hugobot/v3/types" "git.blob42.xyz/blob42/hugobot/v3/utils" ) var PostMappers []PostMapper var FeedMappers []FeedMapper type Map map[string]interface{} type PostMapper func(Map, feeds.Feed, posts.Post) error type FeedMapper func(Map, feeds.Feed) error // Exported version of a post type PostExport struct { ID int64 `json:"id"` Title string `json:"title"` Link string `json:"link"` Published time.Time `json:"published"` Content string `json:"content"` } type PostMap map[int64]Map type FeedExport struct { Name string `json:"name"` Section string `json:"section"` Categories types.StringList `json:"categories"` Posts PostMap `json:"posts"` } type HugoExporter struct{} func (he HugoExporter) Handle(feed feeds.Feed) error { return he.export(feed) } func (he HugoExporter) export(feed feeds.Feed) error { log.Printf("Exporting %s to %s", feed.Name, config.HugoData()) posts, err := posts.GetPostsByFeedId(feed.FeedID) if err != nil { return err } if len(posts) == 0 { log.Printf("nothing to export") return nil } // Run filters on posts for _, p := range posts { filters.RunPostFilterHooks(feed, p) } // Dir and filename dirPath := filepath.Join(config.HugoData(), feed.Section) cleanFeedName := strings.Replace(feed.Name, "/", "-", -1) filePath := filepath.Join(dirPath, cleanFeedName+".json") err = utils.Mkdir(dirPath) if err != nil { return err } feedExp := Map{ "name": feed.Name, "section": feed.Section, "categories": feed.Categories, } runFeedMappers(feedExp, feed) postsMap := make(PostMap) for _, p := range posts { exp := Map{ "id": p.PostID, "title": p.Title, "link": p.Link, "published": p.Published, "updated": p.Updated, //"content": p.Content, } runPostMappers(exp, feed, *p) postsMap[p.PostID] = exp } feedExp["posts"] = postsMap outputFile, err := os.Create(filePath) defer outputFile.Close() if err != nil { return err } exportEncoder := encoder.NewExportEncoder(outputFile, encoder.JSON) exportEncoder.Encode(feedExp) //jsonEnc.Encode(feedExp) // Handle feeds which export posts individually as hugo posts // Like bulletin if feed.ExportPosts { for _, p := range posts { exp := map[string]interface{}{ "id": p.PostID, "title": p.Title, "name": feed.Name, "author": p.Author, "description": p.PostDescription, "externalLink": feed.UseExternalLink, "display_name": feed.DisplayName, "publishdate": p.Published, "date": p.Updated, "issuedate": utils.NextThursday(p.Updated), "use_data": true, "slug": p.ShortID, "link": p.Link, // Content is written in the post "content": p.Content, "categories": feed.Categories, "tags": strings.Split(p.Tags, ","), } if feed.Publications != "" { exp["publications"] = strings.Split(feed.Publications, ",") } runPostMappers(exp, feed, *p) dirPath := filepath.Join(config.HugoContent(), feed.Section) cleanFeedName := strings.Replace(feed.Name, "/", "-", -1) fileName := fmt.Sprintf("%s-%s.md", cleanFeedName, p.ShortID) filePath := filepath.Join(dirPath, fileName) outputFile, err := os.Create(filePath) defer outputFile.Close() if err != nil { return err } exportEncoder := encoder.NewExportEncoder(outputFile, encoder.TOML) exportEncoder.Encode(exp) } } return nil } // Runs in goroutine func (he HugoExporter) Export(feed feeds.Feed) { err := he.export(feed) if err != nil { log.Fatal(err) } } func NewHugoExporter() HugoExporter { // Make sure path exists err := utils.Mkdir(config.HugoData()) if err != nil { log.Fatal(err) } return HugoExporter{} } func runPostMappers(e Map, f feeds.Feed, p posts.Post) { for _, fn := range PostMappers { err := fn(e, f, p) if err != nil { log.Print(err) } } } func runFeedMappers(e Map, f feeds.Feed) { for _, fn := range FeedMappers { err := fn(e, f) if err != nil { log.Print(err) } } } func RegisterPostMapper(mapper PostMapper) { PostMappers = append(PostMappers, mapper) } func RegisterFeedMapper(mapper FeedMapper) { FeedMappers = append(FeedMappers, mapper) } func init() { RegisterPostMapper(BulletinExport) RegisterPostMapper(NewsletterPostLayout) RegisterPostMapper(RFCExport) RegisterPostMapper(ReleaseExport) }