diff --git a/collections.go b/collections.go index 9688ad9..edde677 100644 --- a/collections.go +++ b/collections.go @@ -47,6 +47,7 @@ type ( Language string `schema:"lang" json:"lang,omitempty"` StyleSheet string `datastore:"style_sheet" schema:"style_sheet" json:"style_sheet"` Script string `datastore:"script" schema:"script" json:"script,omitempty"` + Signature string `datastore:"post_signature" schema:"signature" json:"-"` Public bool `datastore:"public" json:"public"` Visibility collVisibility `datastore:"private" json:"-"` Format string `datastore:"format" json:"format,omitempty"` @@ -91,6 +92,7 @@ type ( Description *string `schema:"description" json:"description"` StyleSheet *sql.NullString `schema:"style_sheet" json:"style_sheet"` Script *sql.NullString `schema:"script" json:"script"` + Signature *sql.NullString `schema:"signature" json:"signature"` Visibility *int `schema:"visibility" json:"public"` Format *sql.NullString `schema:"format" json:"format"` } diff --git a/database.go b/database.go index 000d62c..6f97d8c 100644 --- a/database.go +++ b/database.go @@ -791,10 +791,10 @@ func (db *datastore) GetCollectionBy(condition string, value interface{}) (*Coll c := &Collection{} // FIXME: change Collection to reflect database values. Add helper functions to get actual values - var styleSheet, script, format zero.String - row := db.QueryRow("SELECT id, alias, title, description, style_sheet, script, format, owner_id, privacy, view_count FROM collections WHERE "+condition, value) + var styleSheet, script, signature, format zero.String + row := db.QueryRow("SELECT id, alias, title, description, style_sheet, script, post_signature, format, owner_id, privacy, view_count FROM collections WHERE "+condition, value) - err := row.Scan(&c.ID, &c.Alias, &c.Title, &c.Description, &styleSheet, &script, &format, &c.OwnerID, &c.Visibility, &c.Views) + err := row.Scan(&c.ID, &c.Alias, &c.Title, &c.Description, &styleSheet, &script, &signature, &format, &c.OwnerID, &c.Visibility, &c.Views) switch { case err == sql.ErrNoRows: return nil, impart.HTTPError{http.StatusNotFound, "Collection doesn't exist."} @@ -806,6 +806,7 @@ func (db *datastore) GetCollectionBy(condition string, value interface{}) (*Coll } c.StyleSheet = styleSheet.String c.Script = script.String + c.Signature = signature.String c.Format = format.String c.Public = c.IsPublic() @@ -849,7 +850,8 @@ func (db *datastore) UpdateCollection(c *SubmittedCollection, alias string) erro SetStringPtr(c.Title, "title"). SetStringPtr(c.Description, "description"). SetNullString(c.StyleSheet, "style_sheet"). - SetNullString(c.Script, "script") + SetNullString(c.Script, "script"). + SetNullString(c.Signature, "post_signature") if c.Format != nil { cf := &CollectionFormat{Format: c.Format.String} @@ -1150,6 +1152,7 @@ func (db *datastore) GetPosts(cfg *config.Config, c *Collection, page int, inclu break } p.extractData() + p.augmentContent(c) p.formatContent(cfg, c, includeFuture) posts = append(posts, p.processPost()) @@ -1214,6 +1217,7 @@ func (db *datastore) GetPostsTagged(cfg *config.Config, c *Collection, tag strin break } p.extractData() + p.augmentContent(c) p.formatContent(cfg, c, includeFuture) posts = append(posts, p.processPost()) @@ -1590,6 +1594,7 @@ func (db *datastore) GetPinnedPosts(coll *CollectionObj, includeFuture bool) (*[ break } p.extractData() + p.augmentContent(&coll.Collection) pp := p.processPost() pp.Collection = coll diff --git a/migrations/drivers.go b/migrations/drivers.go index 59fe16f..1399411 100644 --- a/migrations/drivers.go +++ b/migrations/drivers.go @@ -78,3 +78,10 @@ func (db *datastore) engine() string { } return " ENGINE = InnoDB" } + +func (db *datastore) after(colName string) string { + if db.driverName == driverSQLite { + return "" + } + return " AFTER " + colName +} diff --git a/migrations/migrations.go b/migrations/migrations.go index 6810bff..88897fd 100644 --- a/migrations/migrations.go +++ b/migrations/migrations.go @@ -65,6 +65,7 @@ var migrations = []Migration{ New("support oauth attach", oauthAttach), // V6 -> V7 New("support oauth via invite", oauthInvites), // V7 -> V8 (v0.12.0) New("optimize drafts retrieval", optimizeDrafts), // V8 -> V9 + New("support post signatures", supportPostSignatures), // V9 -> V10 } // CurrentVer returns the current migration version the application is on diff --git a/migrations/v10.go b/migrations/v10.go new file mode 100644 index 0000000..9c84a01 --- /dev/null +++ b/migrations/v10.go @@ -0,0 +1,33 @@ +/* + * Copyright © 2020 A Bunch Tell LLC. + * + * This file is part of WriteFreely. + * + * WriteFreely is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License, included + * in the LICENSE file in this source code package. + */ + +package migrations + +func supportPostSignatures(db *datastore) error { + t, err := db.Begin() + if err != nil { + t.Rollback() + return err + } + + _, err = t.Exec(`ALTER TABLE collections ADD COLUMN post_signature ` + db.typeText() + db.collateMultiByte() + ` NULL` + db.after("script")) + if err != nil { + t.Rollback() + return err + } + + err = t.Commit() + if err != nil { + t.Rollback() + return err + } + + return nil +} diff --git a/postrender.go b/postrender.go index 84aa9a9..f917b6e 100644 --- a/postrender.go +++ b/postrender.go @@ -58,6 +58,17 @@ func (p *PublicPost) formatContent(cfg *config.Config, isOwner bool) { p.Post.formatContent(cfg, &p.Collection.Collection, isOwner) } +func (p *Post) augmentContent(c *Collection) { + // Add post signatures + if c.Signature != "" { + p.Content += "\n\n" + c.Signature + } +} + +func (p *PublicPost) augmentContent() { + p.Post.augmentContent(&p.Collection.Collection) +} + func applyMarkdown(data []byte, baseURL string, cfg *config.Config) string { return applyMarkdownSpecial(data, false, baseURL, cfg) } diff --git a/posts.go b/posts.go index 5c69659..4c8c76e 100644 --- a/posts.go +++ b/posts.go @@ -1141,6 +1141,7 @@ func (p *PublicPost) ActivityObject(app *App) *activitystreams.Object { p.Collection.FederatedAccount() + "/followers", } o.Name = p.DisplayTitle() + p.augmentContent() if p.HTMLContent == template.HTML("") { p.formatContent(cfg, false) } @@ -1432,6 +1433,8 @@ Are you sure it was ever here?`, return impart.HTTPError{http.StatusGone, "Post was unpublished."} } + p.augmentContent() + // Serve collection post if isRaw { contentType := "text/plain" diff --git a/templates/user/collection.tmpl b/templates/user/collection.tmpl index 5afe421..14114e6 100644 --- a/templates/user/collection.tmpl +++ b/templates/user/collection.tmpl @@ -5,6 +5,15 @@ {{define "collection"}} {{template "header" .}} + +
This content will be added to the end of every post on this blog, as if it were part of the post itself. Markdown, HTML, and shortcodes are allowed.
+ +