repos / pico

pico services - prose.sh, pastes.sh, imgs.sh, feeds.sh, pgs.sh
git clone https://github.com/picosh/pico.git

commit
b49c843
parent
7a2ff35
author
Eric Bower
date
2022-08-22 20:56:55 +0000 UTC
refactor(imgs): redesign blog page for imgs

After chatting with the pico members, it became clear that the photo
album direction I was heading in was not going to super useful.  Instead
we decided to revert the design back to how the other pico services
function.  So now it's just a stream of images not grouped by tags.
3 files changed,  +28, -312
M imgs/api.go
+23, -287
  1@@ -6,7 +6,6 @@ import (
  2 	"html/template"
  3 	"net/http"
  4 	"net/url"
  5-	"sort"
  6 	"strings"
  7 	"time"
  8 
  9@@ -23,32 +22,12 @@ type PageData struct {
 10 }
 11 
 12 type PostItemData struct {
 13-	URL            template.URL
 14-	BlogURL        template.URL
 15-	Username       string
 16-	Title          string
 17-	Description    string
 18-	PublishAtISO   string
 19-	PublishAt      string
 20-	UpdatedAtISO   string
 21-	UpdatedTimeAgo string
 22-	Tags           []string
 23-}
 24-
 25-type TagPageData struct {
 26-	BlogURL   template.URL
 27-	PageTitle string
 28-	Username  string
 29-	URL       template.URL
 30-	Site      shared.SitePageData
 31-	Tag       string
 32-	Posts     []TagPostData
 33-}
 34-
 35-type TagPostData struct {
 36-	URL     template.URL
 37-	ImgURL  template.URL
 38-	Caption string
 39+	BlogURL      template.URL
 40+	URL          template.URL
 41+	ImgURL       template.URL
 42+	PublishAtISO string
 43+	PublishAt    string
 44+	Caption      string
 45 }
 46 
 47 type BlogPageData struct {
 48@@ -59,7 +38,7 @@ type BlogPageData struct {
 49 	Username  string
 50 	Readme    *ReadmeTxt
 51 	Header    *HeaderTxt
 52-	Posts     []*PostTagData
 53+	Posts     []*PostItemData
 54 	HasFilter bool
 55 }
 56 
 57@@ -105,14 +84,6 @@ type ReadmeTxt struct {
 58 	Contents template.HTML
 59 }
 60 
 61-type MergePost struct {
 62-	Db     db.DB
 63-	UserID string
 64-	Space  string
 65-}
 66-
 67-var allTag = "all"
 68-
 69 func GetPostTitle(post *db.Post) string {
 70 	if post.Description == "" {
 71 		return post.Title
 72@@ -129,13 +100,6 @@ func isRequestTrackable(r *http.Request) bool {
 73 	return true
 74 }
 75 
 76-type PostTagData struct {
 77-	URL       template.URL
 78-	ImgURL    template.URL
 79-	Tag       string
 80-	PublishAt *time.Time
 81-}
 82-
 83 func blogHandler(w http.ResponseWriter, r *http.Request) {
 84 	username := shared.GetUsernameFromRequest(r)
 85 	dbpool := shared.GetDB(r)
 86@@ -149,7 +113,13 @@ func blogHandler(w http.ResponseWriter, r *http.Request) {
 87 		return
 88 	}
 89 
 90-	posts, err := dbpool.FindPostsForUser(user.ID, cfg.Space)
 91+	tag := r.URL.Query().Get("tag")
 92+	var posts []*db.Post
 93+	if tag == "" {
 94+		posts, err = dbpool.FindPostsForUser(user.ID, cfg.Space)
 95+	} else {
 96+		posts, err = dbpool.FindUserPostsByTag(tag, user.ID, cfg.Space)
 97+	}
 98 
 99 	if err != nil {
100 		logger.Error(err)
101@@ -179,46 +149,27 @@ func blogHandler(w http.ResponseWriter, r *http.Request) {
102 	}
103 	readmeTxt := &ReadmeTxt{}
104 
105-	tagMap := make(map[string]*db.Post, len(posts))
106+	postCollection := make([]*PostItemData, 0, len(posts))
107 	for _, post := range posts {
108-		if post.Hidden {
109-			continue
110-		}
111-
112-		for _, tag := range post.Tags {
113-			if tagMap[tag] == nil {
114-				tagMap[tag] = post
115-			}
116-		}
117-
118-		if tagMap[allTag] == nil {
119-			tagMap[allTag] = post
120-		}
121-	}
122-
123-	postCollection := make([]*PostTagData, 0, len(tagMap))
124-	for key, post := range tagMap {
125-		postCollection = append(postCollection, &PostTagData{
126-			Tag:       key,
127-			URL:       template.URL(cfg.TagURL(post.Username, key, onSubdomain, withUserName)),
128-			ImgURL:    template.URL(cfg.ImgURL(post.Username, post.Filename, onSubdomain, withUserName)),
129-			PublishAt: post.PublishAt,
130+		postCollection = append(postCollection, &PostItemData{
131+			ImgURL:       template.URL(cfg.ImgURL(post.Username, post.Filename, onSubdomain, withUserName)),
132+			URL:          template.URL(cfg.ImgURL(post.Username, post.Slug, onSubdomain, withUserName)),
133+			Caption:      post.Title,
134+			PublishAt:    post.PublishAt.Format("02 Jan, 2006"),
135+			PublishAtISO: post.PublishAt.Format(time.RFC3339),
136 		})
137 	}
138 
139-	sort.Slice(postCollection, func(i, j int) bool {
140-		return postCollection[i].PublishAt.After(*postCollection[j].PublishAt)
141-	})
142-
143 	data := BlogPageData{
144 		Site:      *cfg.GetSiteData(),
145 		PageTitle: headerTxt.Title,
146 		URL:       template.URL(cfg.FullBlogURL(username, onSubdomain, withUserName)),
147-		RSSURL:    template.URL(cfg.RssBlogURL(username, onSubdomain, withUserName, "")),
148+		RSSURL:    template.URL(cfg.RssBlogURL(username, onSubdomain, withUserName, tag)),
149 		Readme:    readmeTxt,
150 		Header:    headerTxt,
151 		Username:  username,
152 		Posts:     postCollection,
153+		HasFilter: tag != "",
154 	}
155 
156 	err = ts.Execute(w, data)
157@@ -286,219 +237,6 @@ func imgHandler(w http.ResponseWriter, r *http.Request) {
158 	}
159 }
160 
161-func tagHandler(w http.ResponseWriter, r *http.Request) {
162-	username := shared.GetUsernameFromRequest(r)
163-	subdomain := shared.GetSubdomain(r)
164-	cfg := shared.GetCfg(r)
165-
166-	tag := ""
167-	if !cfg.IsSubdomains() || subdomain == "" {
168-		tag, _ = url.PathUnescape(shared.GetField(r, 1))
169-	} else {
170-		tag, _ = url.PathUnescape(shared.GetField(r, 0))
171-	}
172-
173-	dbpool := shared.GetDB(r)
174-	logger := shared.GetLogger(r)
175-
176-	user, err := dbpool.FindUserForName(username)
177-	if err != nil {
178-		logger.Infof("blog not found: %s", username)
179-		http.Error(w, "blog not found", http.StatusNotFound)
180-		return
181-	}
182-
183-	hostDomain := strings.Split(r.Host, ":")[0]
184-	appDomain := strings.Split(cfg.ConfigCms.Domain, ":")[0]
185-
186-	onSubdomain := cfg.IsSubdomains() && strings.Contains(hostDomain, appDomain)
187-	withUserName := (!onSubdomain && hostDomain == appDomain) || !cfg.IsCustomdomains()
188-
189-	posts, err := dbpool.FindPostsForUser(user.ID, cfg.Space)
190-	if err != nil {
191-		logger.Infof("tag not found: %s/%s", username, tag)
192-		http.Error(w, "tag not found", http.StatusNotFound)
193-		return
194-	}
195-
196-	mergedPosts := make([]TagPostData, 0)
197-	for _, post := range posts {
198-		if post.Hidden {
199-			continue
200-		}
201-
202-		if tag != allTag && !slices.Contains(post.Tags, tag) {
203-			continue
204-		}
205-		mergedPosts = append(mergedPosts, TagPostData{
206-			URL:     template.URL(cfg.TagPostURL(username, tag, post.Slug, onSubdomain, withUserName)),
207-			ImgURL:  template.URL(cfg.ImgURL(username, post.Filename, onSubdomain, withUserName)),
208-			Caption: post.Title,
209-		})
210-	}
211-
212-	data := TagPageData{
213-		BlogURL:   template.URL(cfg.FullBlogURL(username, onSubdomain, withUserName)),
214-		Username:  username,
215-		PageTitle: fmt.Sprintf("%s -- %s", tag, username),
216-		Site:      *cfg.GetSiteData(),
217-		Tag:       tag,
218-		Posts:     mergedPosts,
219-		URL:       template.URL(cfg.TagURL(username, tag, onSubdomain, withUserName)),
220-	}
221-
222-	ts, err := shared.RenderTemplate(cfg, []string{
223-		cfg.StaticPath("html/tag.page.tmpl"),
224-	})
225-
226-	if err != nil {
227-		http.Error(w, err.Error(), http.StatusInternalServerError)
228-	}
229-
230-	err = ts.Execute(w, data)
231-	if err != nil {
232-		logger.Error(err)
233-		http.Error(w, err.Error(), http.StatusInternalServerError)
234-	}
235-}
236-
237-func tagPostHandler(w http.ResponseWriter, r *http.Request) {
238-	username := shared.GetUsernameFromRequest(r)
239-	subdomain := shared.GetSubdomain(r)
240-	cfg := shared.GetCfg(r)
241-
242-	tag := ""
243-	slug := ""
244-	if !cfg.IsSubdomains() || subdomain == "" {
245-		tag, _ = url.PathUnescape(shared.GetField(r, 1))
246-		slug, _ = url.PathUnescape(shared.GetField(r, 2))
247-	} else {
248-		tag, _ = url.PathUnescape(shared.GetField(r, 0))
249-		slug, _ = url.PathUnescape(shared.GetField(r, 1))
250-	}
251-
252-	dbpool := shared.GetDB(r)
253-	logger := shared.GetLogger(r)
254-
255-	user, err := dbpool.FindUserForName(username)
256-	if err != nil {
257-		logger.Infof("blog not found: %s", username)
258-		http.Error(w, "blog not found", http.StatusNotFound)
259-		return
260-	}
261-
262-	blogName := GetBlogName(username)
263-	hostDomain := strings.Split(r.Host, ":")[0]
264-	appDomain := strings.Split(cfg.ConfigCms.Domain, ":")[0]
265-
266-	onSubdomain := cfg.IsSubdomains() && strings.Contains(hostDomain, appDomain)
267-	withUserName := (!onSubdomain && hostDomain == appDomain) || !cfg.IsCustomdomains()
268-
269-	posts, err := dbpool.FindPostsForUser(user.ID, cfg.Space)
270-	if err != nil {
271-		logger.Infof("tag not found: %s/%s", username, tag)
272-		http.Error(w, "tag not found", http.StatusNotFound)
273-		return
274-	}
275-
276-	mergedPosts := make([]db.Post, 0)
277-	for _, post := range posts {
278-		if post.Hidden {
279-			continue
280-		}
281-
282-		if !slices.Contains(post.Tags, tag) {
283-			continue
284-		}
285-		mergedPosts = append(mergedPosts, *post)
286-	}
287-
288-	prevPage := ""
289-	nextPage := ""
290-	for i, post := range mergedPosts {
291-		if post.Slug != slug {
292-			continue
293-		}
294-
295-		if i+1 < len(mergedPosts) {
296-			nextPage = cfg.TagPostURL(
297-				username,
298-				tag,
299-				mergedPosts[i+1].Slug,
300-				onSubdomain,
301-				withUserName,
302-			)
303-		}
304-
305-		if i-1 >= 0 {
306-			prevPage = cfg.TagPostURL(
307-				username,
308-				tag,
309-				mergedPosts[i-1].Slug,
310-				onSubdomain,
311-				withUserName,
312-			)
313-		}
314-	}
315-
316-	post, err := dbpool.FindPostWithSlug(slug, user.ID, cfg.Space)
317-	if err != nil {
318-		logger.Infof("post not found: %s/%s", username, slug)
319-		http.Error(w, "post not found", http.StatusNotFound)
320-		return
321-	}
322-
323-	parsed, err := shared.ParseText(post.Text, cfg.ImgURL(username, "", true, false))
324-	if err != nil {
325-		logger.Error(err)
326-	}
327-	text := ""
328-	if parsed != nil {
329-		text = parsed.Html
330-	}
331-
332-	tagLinks := make([]Link, 0, len(post.Tags))
333-	for _, tag := range post.Tags {
334-		tagLinks = append(tagLinks, Link{
335-			URL:  template.URL(cfg.TagURL(username, tag, onSubdomain, withUserName)),
336-			Text: tag,
337-		})
338-	}
339-
340-	data := PostPageData{
341-		Site:         *cfg.GetSiteData(),
342-		PageTitle:    GetPostTitle(post),
343-		URL:          template.URL(cfg.FullPostURL(post.Username, post.Slug, onSubdomain, withUserName)),
344-		BlogURL:      template.URL(cfg.FullBlogURL(username, onSubdomain, withUserName)),
345-		Caption:      post.Description,
346-		Title:        post.Title,
347-		Slug:         post.Slug,
348-		PublishAt:    post.PublishAt.Format("02 Jan, 2006"),
349-		PublishAtISO: post.PublishAt.Format(time.RFC3339),
350-		Username:     username,
351-		BlogName:     blogName,
352-		Contents:     template.HTML(text),
353-		ImgURL:       template.URL(cfg.ImgURL(username, post.Filename, onSubdomain, withUserName)),
354-		Tags:         tagLinks,
355-		PrevPage:     template.URL(prevPage),
356-		NextPage:     template.URL(nextPage),
357-	}
358-
359-	ts, err := shared.RenderTemplate(cfg, []string{
360-		cfg.StaticPath("html/tag_post.page.tmpl"),
361-	})
362-
363-	if err != nil {
364-		http.Error(w, err.Error(), http.StatusInternalServerError)
365-	}
366-
367-	err = ts.Execute(w, data)
368-	if err != nil {
369-		logger.Error(err)
370-		http.Error(w, err.Error(), http.StatusInternalServerError)
371-	}
372-}
373-
374 func postHandler(w http.ResponseWriter, r *http.Request) {
375 	username := shared.GetUsernameFromRequest(r)
376 	subdomain := shared.GetSubdomain(r)
377@@ -864,8 +602,6 @@ func createSubdomainRoutes(staticRoutes []shared.Route) []shared.Route {
378 	routes = append(
379 		routes,
380 		shared.NewRoute("GET", "/([^/]+\\..+)", imgHandler),
381-		shared.NewRoute("GET", "/t/([^/]+)", tagHandler),
382-		shared.NewRoute("GET", "/([^/]+)/([^/]+)", tagPostHandler),
383 		shared.NewRoute("GET", "/([^/]+)", postHandler),
384 	)
385 
M imgs/html/blog.page.tmpl
+4, -3
 1@@ -47,13 +47,14 @@
 2     </section>
 3     {{end}}
 4 
 5+    {{if .HasFilter}}
 6+        <a href={{.URL}}>clear filters</a>
 7+    {{end}}
 8     <section class="albums">
 9         {{range .Posts}}
10         <article  class="thumbnail-container">
11             <a href="{{.URL}}" class="thumbnail-link">
12-                <div class="tag-overlay"></div>
13-                <div class="tag-text text-2xl">{{.Tag}}</div>
14-                <img class="thumbnail" src="{{.ImgURL}}" alt="{{.Tag}}" />
15+                <img class="thumbnail" src="{{.ImgURL}}" alt="{{.Caption}}" />
16             </a>
17         </article>
18         {{end}}
M shared/config.go
+1, -22
 1@@ -158,28 +158,7 @@ func (c *ConfigSite) ImgURL(username string, slug string, onSubdomain bool, with
 2 
 3 func (c *ConfigSite) TagURL(username, tag string, onSubdomain, withUserName bool) string {
 4 	tg := url.PathEscape(tag)
 5-	if c.IsSubdomains() && onSubdomain {
 6-		return fmt.Sprintf("%s://%s.%s/t/%s", c.Protocol, username, c.Domain, tg)
 7-	}
 8-
 9-	if withUserName {
10-		return fmt.Sprintf("/%s/t/%s", username, tg)
11-	}
12-
13-	return fmt.Sprintf("/t/%s", tg)
14-}
15-
16-func (c *ConfigSite) TagPostURL(username, tag, slug string, onSubdomain, withUserName bool) string {
17-	fname := url.PathEscape(strings.TrimLeft(slug, "/"))
18-	if c.IsSubdomains() && onSubdomain {
19-		return fmt.Sprintf("%s://%s.%s/%s/%s", c.Protocol, username, c.Domain, tag, fname)
20-	}
21-
22-	if withUserName {
23-		return fmt.Sprintf("/%s/%s/%s", username, tag, fname)
24-	}
25-
26-	return fmt.Sprintf("/%s/%s", tag, fname)
27+	return fmt.Sprintf("%s?tag=%s", c.FullBlogURL(username, onSubdomain, withUserName), tg)
28 }
29 
30 func CreateLogger() *zap.SugaredLogger {