From 530439772d1da5e6a263d4a6253d44994052409f Mon Sep 17 00:00:00 2001 From: Donald Feury Date: Wed, 24 Feb 2021 23:00:21 -0500 Subject: [PATCH 01/96] Add Pagination to Tags Collection Mostly copied the logic for pagination from non tag collection --- collections.go | 9 +++++++++ routes.go | 1 + templates/collection-tags.tmpl | 11 +++++++++++ 3 files changed, 21 insertions(+) diff --git a/collections.go b/collections.go index e1ebe48..898b730 100644 --- a/collections.go +++ b/collections.go @@ -901,6 +901,15 @@ func handleViewCollectionTag(app *App, w http.ResponseWriter, r *http.Request) e coll := newDisplayCollection(c, cr, page) + coll.TotalPages = int(math.Ceil(float64(coll.TotalPosts) / float64(coll.Format.PostsPerPage()))) + if coll.TotalPages > 0 && page > coll.TotalPages { + redirURL := fmt.Sprintf("/page/%d", coll.TotalPages) + if !app.cfg.App.SingleUser { + redirURL = fmt.Sprintf("/%s%s%s", cr.prefix, coll.Alias, redirURL) + } + return impart.HTTPError{http.StatusFound, redirURL} + } + coll.Posts, _ = app.db.GetPostsTagged(app.cfg, c, tag, page, cr.isCollOwner) if coll.Posts != nil && len(*coll.Posts) == 0 { return ErrCollectionPageNotFound diff --git a/routes.go b/routes.go index bb1785f..6595949 100644 --- a/routes.go +++ b/routes.go @@ -206,6 +206,7 @@ func InitRoutes(apper Apper, r *mux.Router) *mux.Router { func RouteCollections(handler *Handler, r *mux.Router) { r.HandleFunc("/page/{page:[0-9]+}", handler.Web(handleViewCollection, UserLevelReader)) r.HandleFunc("/tag:{tag}", handler.Web(handleViewCollectionTag, UserLevelReader)) + r.HandleFunc("/tag:{tag}/page/{page:[0-9]+}", handler.Web(handleViewCollectionTag, UserLevelReader)) r.HandleFunc("/tag:{tag}/feed/", handler.Web(ViewFeed, UserLevelReader)) r.HandleFunc("/sitemap.xml", handler.AllReader(handleViewSitemap)) r.HandleFunc("/feed/", handler.AllReader(ViewFeed)) diff --git a/templates/collection-tags.tmpl b/templates/collection-tags.tmpl index e2f8962..9fb130a 100644 --- a/templates/collection-tags.tmpl +++ b/templates/collection-tags.tmpl @@ -60,6 +60,17 @@ {{if .Posts}}
{{else}}
{{end}}

{{.Tag}}

{{template "posts" .}} + + {{if gt .TotalPages 1}}{{end}} + {{if .Posts}}
{{else}}{{end}} {{ if .Collection.ShowFooterBranding }} From 9ed268754318db276236ba71ff42c69dd5eedb70 Mon Sep 17 00:00:00 2001 From: Donald Feury Date: Wed, 24 Feb 2021 23:49:15 -0500 Subject: [PATCH 02/96] Added TagCollectionPage * Implements PrevPageURL and NextPageURL * This allows the collection-tag template to get proper urls for paginating using tags. --- collections.go | 29 +++++++++++++++++++++++++---- 1 file changed, 25 insertions(+), 4 deletions(-) diff --git a/collections.go b/collections.go index 898b730..c926295 100644 --- a/collections.go +++ b/collections.go @@ -562,6 +562,30 @@ type CollectionPage struct { CanInvite bool } +type TagCollectionPage struct { + CollectionPage + Tag string +} + +func (tcp TagCollectionPage) PrevPageURL(prefix string, n int, tl bool) string { + u := fmt.Sprintf("/tag:%s", tcp.Tag) + if n > 2 { + u += fmt.Sprintf("/page/%d", n-1) + } + if tl { + return u + } + return "/" + prefix + tcp.Alias + u + +} + +func (tcp TagCollectionPage) NextPageURL(prefix string, n int, tl bool) string { + if tl { + return fmt.Sprintf("/tag:%s/page/%d", tcp.Tag, n+1) + } + return fmt.Sprintf("/%s%s/tag:%s/page/%d", prefix, tcp.Alias, tcp.Tag, n+1) +} + func NewCollectionObj(c *Collection) *CollectionObj { return &CollectionObj{ Collection: *c, @@ -916,10 +940,7 @@ func handleViewCollectionTag(app *App, w http.ResponseWriter, r *http.Request) e } // Serve collection - displayPage := struct { - CollectionPage - Tag string - }{ + displayPage := TagCollectionPage{ CollectionPage: CollectionPage{ DisplayCollection: coll, StaticPage: pageForReq(app, r), From 4c0fcdf7c69be84933453ebe43aef4dbe5595d31 Mon Sep 17 00:00:00 2001 From: Donald Feury Date: Wed, 24 Feb 2021 23:55:56 -0500 Subject: [PATCH 03/96] Setting activitypub.go back to master version --- activitypub.go | 23 +++-------------------- 1 file changed, 3 insertions(+), 20 deletions(-) diff --git a/activitypub.go b/activitypub.go index 18307de..db42726 100644 --- a/activitypub.go +++ b/activitypub.go @@ -397,9 +397,7 @@ func handleFetchCollectionInbox(app *App, w http.ResponseWriter, r *http.Request go func() { if to == nil { - if debugging { - log.Error("No `to` value!") - } + log.Error("No to! %v", err) return } @@ -494,7 +492,7 @@ func makeActivityPost(hostName string, p *activitystreams.Person, url string, m r, _ := http.NewRequest("POST", url, bytes.NewBuffer(b)) r.Header.Add("Content-Type", "application/activity+json") - r.Header.Set("User-Agent", ServerUserAgent(hostName)) + r.Header.Set("User-Agent", "Go ("+serverSoftware+"/"+softwareVer+"; +"+hostName+")") h := sha256.New() h.Write(b) r.Header.Add("Digest", "SHA-256="+base64.StdEncoding.EncodeToString(h.Sum(nil))) @@ -544,7 +542,7 @@ func resolveIRI(hostName, url string) ([]byte, error) { r, _ := http.NewRequest("GET", url, nil) r.Header.Add("Accept", "application/activity+json") - r.Header.Set("User-Agent", ServerUserAgent(hostName)) + r.Header.Set("User-Agent", "Go ("+serverSoftware+"/"+softwareVer+"; +"+hostName+")") if debugging { dump, err := httputil.DumpRequestOut(r, true) @@ -631,17 +629,6 @@ func federatePost(app *App, p *PublicPost, collID int64, isUpdate bool) error { log.Info("Federating new post!") } } - - // If app is private, do not federate - if app.cfg.App.Private { - return nil - } - - // Do not federate posts from private or protected blogs - if p.Collection.Visibility == CollPrivate || p.Collection.Visibility == CollProtected { - return nil - } - actor := p.Collection.PersonObject(collID) na := p.ActivityObject(app) @@ -710,10 +697,6 @@ func federatePost(app *App, p *PublicPost, collID int64, isUpdate bool) error { // I don't believe we'd ever have too many mentions in a single post that this // could become a burden. remoteUser, err := getRemoteUser(app, tag.HRef) - if err != nil { - log.Error("Unable to find remote user %s. Skipping: %v", tag.HRef, err) - continue - } err = makeActivityPost(app.cfg.App.Host, actor, remoteUser.Inbox, activity) if err != nil { log.Error("Couldn't post! %v", err) From ebdb9320903f30dd85ed2f65d4ae65c9f0ce5a20 Mon Sep 17 00:00:00 2001 From: Donald Feury Date: Wed, 24 Feb 2021 23:57:35 -0500 Subject: [PATCH 04/96] I meant develop, not master --- activitypub.go | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/activitypub.go b/activitypub.go index db42726..0e69075 100644 --- a/activitypub.go +++ b/activitypub.go @@ -397,7 +397,9 @@ func handleFetchCollectionInbox(app *App, w http.ResponseWriter, r *http.Request go func() { if to == nil { - log.Error("No to! %v", err) + if debugging { + log.Error("No `to` value!") + } return } @@ -492,7 +494,7 @@ func makeActivityPost(hostName string, p *activitystreams.Person, url string, m r, _ := http.NewRequest("POST", url, bytes.NewBuffer(b)) r.Header.Add("Content-Type", "application/activity+json") - r.Header.Set("User-Agent", "Go ("+serverSoftware+"/"+softwareVer+"; +"+hostName+")") + r.Header.Set("User-Agent", ServerUserAgent(hostName)) h := sha256.New() h.Write(b) r.Header.Add("Digest", "SHA-256="+base64.StdEncoding.EncodeToString(h.Sum(nil))) @@ -542,7 +544,7 @@ func resolveIRI(hostName, url string) ([]byte, error) { r, _ := http.NewRequest("GET", url, nil) r.Header.Add("Accept", "application/activity+json") - r.Header.Set("User-Agent", "Go ("+serverSoftware+"/"+softwareVer+"; +"+hostName+")") + r.Header.Set("User-Agent", ServerUserAgent(hostName)) if debugging { dump, err := httputil.DumpRequestOut(r, true) @@ -697,6 +699,10 @@ func federatePost(app *App, p *PublicPost, collID int64, isUpdate bool) error { // I don't believe we'd ever have too many mentions in a single post that this // could become a burden. remoteUser, err := getRemoteUser(app, tag.HRef) + if err != nil { + log.Error("Unable to find remote user %s. Skipping: %v", tag.HRef, err) + continue + } err = makeActivityPost(app.cfg.App.Host, actor, remoteUser.Inbox, activity) if err != nil { log.Error("Couldn't post! %v", err) From 276304d5b8614863d3f40f3fae3b053d6163380c Mon Sep 17 00:00:00 2001 From: Matt Baer Date: Sun, 27 Jun 2021 10:35:36 -0400 Subject: [PATCH 05/96] Rearrange applyMarkdownSpecial parameters --- postrender.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/postrender.go b/postrender.go index 8e71109..1e265fa 100644 --- a/postrender.go +++ b/postrender.go @@ -119,7 +119,7 @@ func (p *PublicPost) augmentReadingDestination() { } func applyMarkdown(data []byte, baseURL string, cfg *config.Config) string { - return applyMarkdownSpecial(data, false, baseURL, cfg) + return applyMarkdownSpecial(data, baseURL, cfg, false) } func disableYoutubeAutoplay(outHTML string) string { @@ -141,7 +141,7 @@ func disableYoutubeAutoplay(outHTML string) string { return outHTML } -func applyMarkdownSpecial(data []byte, skipNoFollow bool, baseURL string, cfg *config.Config) string { +func applyMarkdownSpecial(data []byte, baseURL string, cfg *config.Config, skipNoFollow bool) string { mdExtensions := 0 | blackfriday.EXTENSION_TABLES | blackfriday.EXTENSION_FENCED_CODE | From cbc24274753454e6af486f8a8f532ab4228fda41 Mon Sep 17 00:00:00 2001 From: Matt Baer Date: Sun, 27 Jun 2021 10:51:53 -0400 Subject: [PATCH 06/96] Don't apply "nofollow" to links on single-user instances --- postrender.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/postrender.go b/postrender.go index 1e265fa..4d1a24d 100644 --- a/postrender.go +++ b/postrender.go @@ -119,7 +119,7 @@ func (p *PublicPost) augmentReadingDestination() { } func applyMarkdown(data []byte, baseURL string, cfg *config.Config) string { - return applyMarkdownSpecial(data, baseURL, cfg, false) + return applyMarkdownSpecial(data, baseURL, cfg, cfg.App.SingleUser) } func disableYoutubeAutoplay(outHTML string) string { From 6b336e22aacea2a8b6d335557cc292352621b404 Mon Sep 17 00:00:00 2001 From: Matt Baer Date: Sun, 27 Jun 2021 17:57:07 -0400 Subject: [PATCH 07/96] Log user out when authenticated as deleted user Now when we check for the user at certain times and find that the user doesn't exist in the database, we log them out and send them back to the home page. --- account.go | 17 ++++++++++++++++- database.go | 2 +- handle.go | 10 ++++++++-- invites.go | 3 +++ pad.go | 3 +++ session.go | 9 +++++---- 6 files changed, 36 insertions(+), 8 deletions(-) diff --git a/account.go b/account.go index 72d12ee..eaf3eaf 100644 --- a/account.go +++ b/account.go @@ -787,6 +787,9 @@ func viewArticles(app *App, u *User, w http.ResponseWriter, r *http.Request) err silenced, err := app.db.IsUserSilenced(u.ID) if err != nil { + if err == ErrUserNotFound { + return err + } log.Error("view articles: %v", err) } d := struct { @@ -822,7 +825,10 @@ func viewCollections(app *App, u *User, w http.ResponseWriter, r *http.Request) silenced, err := app.db.IsUserSilenced(u.ID) if err != nil { - log.Error("view collections %v", err) + if err == ErrUserNotFound { + return err + } + log.Error("view collections: %v", err) return fmt.Errorf("view collections: %v", err) } d := struct { @@ -861,6 +867,9 @@ func viewEditCollection(app *App, u *User, w http.ResponseWriter, r *http.Reques silenced, err := app.db.IsUserSilenced(u.ID) if err != nil { + if err == ErrUserNotFound { + return err + } log.Error("view edit collection %v", err) return fmt.Errorf("view edit collection: %v", err) } @@ -1037,6 +1046,9 @@ func viewStats(app *App, u *User, w http.ResponseWriter, r *http.Request) error silenced, err := app.db.IsUserSilenced(u.ID) if err != nil { + if err == ErrUserNotFound { + return err + } log.Error("view stats: %v", err) return err } @@ -1070,6 +1082,9 @@ func viewStats(app *App, u *User, w http.ResponseWriter, r *http.Request) error func viewSettings(app *App, u *User, w http.ResponseWriter, r *http.Request) error { fullUser, err := app.db.GetUserByID(u.ID) if err != nil { + if err == ErrUserNotFound { + return err + } log.Error("Unable to get user for settings: %s", err) return impart.HTTPError{http.StatusInternalServerError, "Unable to retrieve user data. The humans have been alerted."} } diff --git a/database.go b/database.go index fefc3c1..5c3a84f 100644 --- a/database.go +++ b/database.go @@ -332,7 +332,7 @@ func (db *datastore) IsUserSilenced(id int64) (bool, error) { err := db.QueryRow("SELECT status FROM users WHERE id = ?", id).Scan(&u.Status) switch { case err == sql.ErrNoRows: - return false, fmt.Errorf("is user silenced: %v", ErrUserNotFound) + return false, ErrUserNotFound case err != nil: log.Error("Couldn't SELECT user status: %v", err) return false, fmt.Errorf("is user silenced: %v", err) diff --git a/handle.go b/handle.go index 1cbf114..9e9821c 100644 --- a/handle.go +++ b/handle.go @@ -155,8 +155,14 @@ func (h *Handler) User(f userHandlerFunc) http.HandlerFunc { err := f(h.app.App(), u, w, r) if err == nil { status = http.StatusOK - } else if err, ok := err.(impart.HTTPError); ok { - status = err.Status + } else if impErr, ok := err.(impart.HTTPError); ok { + status = impErr.Status + if impErr == ErrUserNotFound { + log.Info("Logged-in user not found. Logging out.") + sendRedirect(w, http.StatusFound, "/me/logout?to="+h.app.App().cfg.App.LandingPath()) + // Reset err so handleHTTPError does nothing + err = nil + } } else { status = http.StatusInternalServerError } diff --git a/invites.go b/invites.go index 4024634..70eaa42 100644 --- a/invites.go +++ b/invites.go @@ -78,6 +78,9 @@ func handleViewUserInvites(app *App, u *User, w http.ResponseWriter, r *http.Req p.Silenced, err = app.db.IsUserSilenced(u.ID) if err != nil { + if err == ErrUserNotFound { + return err + } log.Error("view invites: %v", err) } diff --git a/pad.go b/pad.go index d150334..695d5d2 100644 --- a/pad.go +++ b/pad.go @@ -55,6 +55,9 @@ func handleViewPad(app *App, w http.ResponseWriter, r *http.Request) error { } appData.Silenced, err = app.db.IsUserSilenced(appData.User.ID) if err != nil { + if err == ErrUserNotFound { + return err + } log.Error("Unable to get user status for Pad: %v", err) } } diff --git a/session.go b/session.go index 81d628f..5584565 100644 --- a/session.go +++ b/session.go @@ -130,12 +130,13 @@ func saveUserSession(app *App, r *http.Request, w http.ResponseWriter) error { return err } -func getFullUserSession(app *App, r *http.Request) *User { +func getFullUserSession(app *App, r *http.Request) (*User, error) { u := getUserSession(app, r) if u == nil { - return nil + return nil, nil } - u, _ = app.db.GetUserByID(u.ID) - return u + var err error + u, err = app.db.GetUserByID(u.ID) + return u, err } From 5be1938a8aca2f1a30531355d4f25dcc5839468e Mon Sep 17 00:00:00 2001 From: mnlg Date: Thu, 5 Aug 2021 16:53:20 +0200 Subject: [PATCH 08/96] Fix Gopher collections query --- database.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/database.go b/database.go index f474ae9..3af063d 100644 --- a/database.go +++ b/database.go @@ -1688,7 +1688,7 @@ func (db *datastore) GetPublicCollections(hostName string) (*[]Collection, error FROM collections c LEFT JOIN users u ON u.id = c.owner_id WHERE c.privacy = 1 AND u.status = 0 - ORDER BY id ASC`) + ORDER BY title ASC`) if err != nil { log.Error("Failed selecting public collections: %v", err) return nil, impart.HTTPError{http.StatusInternalServerError, "Couldn't retrieve public collections."} From ae7e42e24e2d66142298bd4bdd3145b3619a0cc2 Mon Sep 17 00:00:00 2001 From: mnlg Date: Thu, 12 Aug 2021 20:23:44 +0200 Subject: [PATCH 09/96] Fix date format in anonymous posts --- database.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/database.go b/database.go index f474ae9..f441c46 100644 --- a/database.go +++ b/database.go @@ -1833,7 +1833,7 @@ func (db *datastore) GetAnonymousPosts(u *User, page int) (*[]PublicPost, error) if page > 0 { limitStr = fmt.Sprintf(" LIMIT %d, %d", start, pagePosts) } - rows, err := db.Query("SELECT id, view_count, title, created, updated, content FROM posts WHERE owner_id = ? AND collection_id IS NULL ORDER BY created DESC"+limitStr, u.ID) + rows, err := db.Query("SELECT id, view_count, title, language, created, updated, content FROM posts WHERE owner_id = ? AND collection_id IS NULL ORDER BY created DESC"+limitStr, u.ID) if err != nil { log.Error("Failed selecting from posts: %v", err) return nil, impart.HTTPError{http.StatusInternalServerError, "Couldn't retrieve user anonymous posts."} @@ -1843,7 +1843,7 @@ func (db *datastore) GetAnonymousPosts(u *User, page int) (*[]PublicPost, error) posts := []PublicPost{} for rows.Next() { p := Post{} - err = rows.Scan(&p.ID, &p.ViewCount, &p.Title, &p.Created, &p.Updated, &p.Content) + err = rows.Scan(&p.ID, &p.ViewCount, &p.Title, &p.Language, &p.Created, &p.Updated, &p.Content) if err != nil { log.Error("Failed scanning row: %v", err) break From cc69f9f2f1d69fdf7ea0159d7b7f3c43bd463a07 Mon Sep 17 00:00:00 2001 From: HeartDev <88726114+lt3Dev@users.noreply.github.com> Date: Sat, 21 Aug 2021 08:57:25 +0000 Subject: [PATCH 10/96] Templates: use relative URLs for static assets I noticed most asset links use relative URLs, except for a few. This commit remedies this inconsistency. OpenGraph embeds were not changed, because in my experience, some embed scrapers require absolute URLs. Motivation: The site I use has an onion and a clearnet version, and currently, visiting the onion loads fonts, styles, and the favicon over the clearnet. --- templates/base.tmpl | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/templates/base.tmpl b/templates/base.tmpl index 604d0ff..389f303 100644 --- a/templates/base.tmpl +++ b/templates/base.tmpl @@ -2,8 +2,8 @@ {{ template "head" . }} - - + + @@ -86,7 +86,7 @@ {{end}} {{else}} - {{if .WebFonts}}{{end}} + {{if .WebFonts}}{{end}} {{end}} {{end}} From 44bfd4573e2f1e6c20686b68cd336f321b836f4f Mon Sep 17 00:00:00 2001 From: Matt Baer Date: Mon, 23 Aug 2021 14:07:25 -0400 Subject: [PATCH 11/96] Support keyboard navigation on pad publish target dropdown --- templates/pad.tmpl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/templates/pad.tmpl b/templates/pad.tmpl index 8da063e..aff281d 100644 --- a/templates/pad.tmpl +++ b/templates/pad.tmpl @@ -24,7 +24,7 @@ {{if not .SingleUser}}

{{end}}