github.com/ngocphuongnb/tetua@v0.0.7-alpha/app/web/topic.go (about) 1 package web 2 3 import ( 4 "net/http" 5 "strconv" 6 "sync" 7 8 "github.com/gorilla/feeds" 9 "github.com/ngocphuongnb/tetua/app/cache" 10 "github.com/ngocphuongnb/tetua/app/config" 11 "github.com/ngocphuongnb/tetua/app/entities" 12 "github.com/ngocphuongnb/tetua/app/repositories" 13 "github.com/ngocphuongnb/tetua/app/server" 14 "github.com/ngocphuongnb/tetua/app/utils" 15 "github.com/ngocphuongnb/tetua/views" 16 ) 17 18 func TopicView(c server.Context) (err error) { 19 topicSlug := c.Param("slug") 20 topics := utils.SliceFilter(cache.Topics, func(t *entities.Topic) bool { 21 return t.Slug == topicSlug 22 }) 23 24 if len(topics) == 0 { 25 c.Meta().Title = "Topic not found" 26 return c.Status(http.StatusNotFound).Render(views.Error("Topic not found")) 27 } 28 29 topic := topics[0] 30 c.Meta().Title = topic.Name 31 var wg sync.WaitGroup 32 var paginate *entities.Paginate[entities.Post] 33 var topPosts []*entities.Post 34 35 wg.Add(2) 36 go func(wg *sync.WaitGroup) { 37 defer wg.Done() 38 paginate, err = repositories.Post.Paginate(c.Context(), &entities.PostFilter{ 39 Filter: &entities.Filter{ 40 Page: c.QueryInt("page"), 41 IgnoreUrlParams: []string{"topic"}, 42 }, 43 TopicIDs: []int{topic.ID}, 44 }) 45 }(&wg) 46 go func(wg *sync.WaitGroup) { 47 defer wg.Done() 48 var topPostErr error 49 topPosts, topPostErr = repositories.Post.Find(c.Context(), &entities.PostFilter{ 50 Filter: &entities.Filter{ 51 Limit: 8, 52 Sorts: []*entities.Sort{{ 53 Field: "view_count", 54 Order: "desc", 55 }}, 56 }, 57 TopicIDs: []int{topic.ID}, 58 }) 59 60 if topPostErr != nil { 61 c.Logger().Error(topPostErr) 62 } 63 }(&wg) 64 65 wg.Wait() 66 67 if err != nil { 68 c.Logger().Error(err) 69 return c.Status(http.StatusBadGateway).Render(views.Error("Something went wrong")) 70 } 71 72 return c.Render(views.TopicView(cache.Topics, topic, paginate, topPosts)) 73 } 74 75 func TopicFeed(c server.Context) error { 76 topics := utils.SliceFilter(cache.Topics, func(t *entities.Topic) bool { 77 return t.Slug == c.Param("slug") 78 }) 79 80 if len(topics) == 0 { 81 c.Meta().Title = "Topic not found" 82 return c.Status(http.StatusNotFound).SendString("Topic not found") 83 } 84 85 topic := topics[0] 86 posts, err := repositories.Post.Find(c.Context(), &entities.PostFilter{ 87 Filter: &entities.Filter{ 88 Limit: 50, 89 }, 90 TopicIDs: []int{topic.ID}, 91 }) 92 93 if err != nil { 94 c.Logger().Error(err) 95 return c.Status(http.StatusNotFound).SendString("Topic not found") 96 } 97 98 feed := &feeds.Feed{ 99 Title: topic.Name, 100 Link: &feeds.Link{Href: topic.Url()}, 101 Description: topic.Description, 102 Author: &feeds.Author{Name: config.Setting("contact_name"), Email: config.Setting("contact_email")}, 103 } 104 105 feed.Items = utils.SliceMap(posts, func(post *entities.Post) *feeds.Item { 106 return &feeds.Item{ 107 Id: strconv.Itoa(post.ID), 108 Title: post.Name, 109 Description: post.Description, 110 Content: post.ContentHTML, 111 Author: &feeds.Author{Name: post.User.Name(), Email: post.User.Email}, 112 Link: &feeds.Link{Href: post.Url()}, 113 Created: *post.CreatedAt, 114 Updated: *post.UpdatedAt, 115 } 116 }) 117 118 rss, err := feed.ToRss() 119 if err != nil { 120 c.Logger().Error(err) 121 return c.Status(http.StatusInternalServerError).SendString("Error") 122 } 123 124 c.Response().Header("content-type", "application/xml; charset=utf-8") 125 return c.SendString(rss) 126 }