diff --git a/account.go b/account.go
index ba013c2..fb1550d 100644
--- a/account.go
+++ b/account.go
@@ -826,6 +826,9 @@ func viewEditCollection(app *App, u *User, w http.ResponseWriter, r *http.Reques
return ErrCollectionNotFound
}
+ // Add collection properties
+ c.MonetizationPointer = app.db.GetCollectionAttribute(c.ID, "monetization_pointer")
+
silenced, err := app.db.IsUserSilenced(u.ID)
if err != nil {
log.Error("view edit collection %v", err)
diff --git a/admin.go b/admin.go
index 457b384..a0d10eb 100644
--- a/admin.go
+++ b/admin.go
@@ -529,6 +529,7 @@ func handleAdminUpdateConfig(apper Apper, u *User, w http.ResponseWriter, r *htt
}
apper.App().cfg.App.Federation = r.FormValue("federation") == "on"
apper.App().cfg.App.PublicStats = r.FormValue("public_stats") == "on"
+ apper.App().cfg.App.Monetization = r.FormValue("monetization") == "on"
apper.App().cfg.App.Private = r.FormValue("private") == "on"
apper.App().cfg.App.LocalTimeline = r.FormValue("local_timeline") == "on"
if apper.App().cfg.App.LocalTimeline && apper.App().timeline == nil {
diff --git a/collections.go b/collections.go
index 2295837..e1ebe48 100644
--- a/collections.go
+++ b/collections.go
@@ -56,6 +56,8 @@ type (
PublicOwner bool `datastore:"public_owner" json:"-"`
URL string `json:"url,omitempty"`
+ MonetizationPointer string `json:"monetization_pointer,omitempty"`
+
db *datastore
hostName string
}
@@ -87,14 +89,15 @@ type (
Handle string `schema:"handle" json:"handle"`
// Actual collection values updated in the DB
- Alias *string `schema:"alias" json:"alias"`
- Title *string `schema:"title" json:"title"`
- 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"`
+ Alias *string `schema:"alias" json:"alias"`
+ Title *string `schema:"title" json:"title"`
+ 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"`
+ Monetization *string `schema:"monetization_pointer" json:"monetization_pointer"`
+ Visibility *int `schema:"visibility" json:"public"`
+ Format *sql.NullString `schema:"format" json:"format"`
}
CollectionFormat struct {
Format string
@@ -552,6 +555,7 @@ type CollectionPage struct {
IsOwner bool
CanPin bool
Username string
+ Monetization string
Collections *[]Collection
PinnedPosts *[]PublicPost
IsAdmin bool
@@ -829,6 +833,7 @@ func handleViewCollection(app *App, w http.ResponseWriter, r *http.Request) erro
// Add more data
// TODO: fix this mess of collections inside collections
displayPage.PinnedPosts, _ = app.db.GetPinnedPosts(coll.CollectionObj, isOwner)
+ displayPage.Monetization = app.db.GetCollectionAttribute(coll.ID, "monetization_pointer")
collTmpl := "collection"
if app.cfg.App.Chorus {
@@ -947,6 +952,7 @@ func handleViewCollectionTag(app *App, w http.ResponseWriter, r *http.Request) e
// Add more data
// TODO: fix this mess of collections inside collections
displayPage.PinnedPosts, _ = app.db.GetPinnedPosts(coll.CollectionObj, isOwner)
+ displayPage.Monetization = app.db.GetCollectionAttribute(coll.ID, "monetization_pointer")
err = templates["collection-tags"].ExecuteTemplate(w, "collection-tags", displayPage)
if err != nil {
diff --git a/config/config.go b/config/config.go
index 7b64e02..faf73fb 100644
--- a/config/config.go
+++ b/config/config.go
@@ -1,5 +1,5 @@
/*
- * Copyright © 2018-2019 A Bunch Tell LLC.
+ * Copyright © 2018-2020 A Bunch Tell LLC.
*
* This file is part of WriteFreely.
*
@@ -137,9 +137,11 @@ type (
MinUsernameLen int `ini:"min_username_len"`
MaxBlogs int `ini:"max_blogs"`
+ // Options for public instances
// Federation
- Federation bool `ini:"federation"`
- PublicStats bool `ini:"public_stats"`
+ Federation bool `ini:"federation"`
+ PublicStats bool `ini:"public_stats"`
+ Monetization bool `ini:"monetization"`
// Access
Private bool `ini:"private"`
diff --git a/database.go b/database.go
index 8237e41..54939fe 100644
--- a/database.go
+++ b/database.go
@@ -905,6 +905,29 @@ func (db *datastore) UpdateCollection(c *SubmittedCollection, alias string) erro
}
}
+ // Update Monetization value
+ if c.Monetization != nil {
+ skipUpdate := false
+ if *c.Monetization != "" {
+ // Strip away any excess spaces
+ trimmed := strings.TrimSpace(*c.Monetization)
+ // Only update value when it starts with "$", per spec: https://paymentpointers.org
+ if strings.HasPrefix(trimmed, "$") {
+ c.Monetization = &trimmed
+ } else {
+ // Value appears invalid, so don't update
+ skipUpdate = true
+ }
+ }
+ if !skipUpdate {
+ _, err = db.Exec("INSERT INTO collectionattributes (collection_id, attribute, value) VALUES (?, ?, ?) ON DUPLICATE KEY UPDATE value = ?", collID, "monetization_pointer", *c.Monetization, *c.Monetization)
+ if err != nil {
+ log.Error("Unable to insert monetization_pointer value: %v", err)
+ return err
+ }
+ }
+ }
+
// Update rest of the collection data
res, err = db.Exec("UPDATE collections SET "+q.Updates+" WHERE "+q.Conditions, q.Params...)
if err != nil {
@@ -2162,6 +2185,28 @@ func (db *datastore) CollectionHasAttribute(id int64, attr string) bool {
return true
}
+func (db *datastore) GetCollectionAttribute(id int64, attr string) string {
+ var v string
+ err := db.QueryRow("SELECT value FROM collectionattributes WHERE collection_id = ? AND attribute = ?", id, attr).Scan(&v)
+ switch {
+ case err == sql.ErrNoRows:
+ return ""
+ case err != nil:
+ log.Error("Couldn't SELECT value in getCollectionAttribute for attribute '%s': %v", attr, err)
+ return ""
+ }
+ return v
+}
+
+func (db *datastore) SetCollectionAttribute(id int64, attr, v string) error {
+ _, err := db.Exec("INSERT INTO collectionattributes (collection_id, attribute, value) VALUES (?, ?, ?)", id, attr, v)
+ if err != nil {
+ log.Error("Unable to INSERT into collectionattributes: %v", err)
+ return err
+ }
+ return nil
+}
+
// DeleteAccount will delete the entire account for userID
func (db *datastore) DeleteAccount(userID int64) error {
// Get all collections
diff --git a/posts.go b/posts.go
index 4c8c76e..8d60650 100644
--- a/posts.go
+++ b/posts.go
@@ -1476,6 +1476,7 @@ Are you sure it was ever here?`,
IsOwner bool
IsPinned bool
IsCustomDomain bool
+ Monetization string
PinnedPosts *[]PublicPost
IsFound bool
IsAdmin bool
@@ -1493,6 +1494,7 @@ Are you sure it was ever here?`,
tp.CanInvite = canUserInvite(app.cfg, tp.IsAdmin)
tp.PinnedPosts, _ = app.db.GetPinnedPosts(coll, p.IsOwner)
tp.IsPinned = len(*tp.PinnedPosts) > 0 && PostsContains(tp.PinnedPosts, p)
+ tp.Monetization = app.db.GetCollectionAttribute(coll.ID, "monetization_pointer")
if !postFound {
w.WriteHeader(http.StatusNotFound)
diff --git a/templates/chorus-collection-post.tmpl b/templates/chorus-collection-post.tmpl
index dcea457..22f2d8f 100644
--- a/templates/chorus-collection-post.tmpl
+++ b/templates/chorus-collection-post.tmpl
@@ -29,6 +29,7 @@
{{range .Images}}{{else}}{{end}}
+ {{template "collection-meta" .}}
{{if .Collection.StyleSheet}}{{end}}
{{end}}
{{end}}
{{if .Collection.RenderMathJax}}
diff --git a/templates/collection-tags.tmpl b/templates/collection-tags.tmpl
index b7c92c8..e2f8962 100644
--- a/templates/collection-tags.tmpl
+++ b/templates/collection-tags.tmpl
@@ -29,6 +29,7 @@
+ {{template "collection-meta" .}}
{{if .Collection.StyleSheet}}{{end}}
{{if .Collection.RenderMathJax}}
diff --git a/templates/collection.tmpl b/templates/collection.tmpl
index d39c58c..42664e7 100644
--- a/templates/collection.tmpl
+++ b/templates/collection.tmpl
@@ -27,6 +27,7 @@
+ {{template "collection-meta" .}}
{{if .StyleSheet}}{{end}}
{{if .RenderMathJax}}
diff --git a/templates/include/post-render.tmpl b/templates/include/post-render.tmpl
index 81fd33e..c4ed082 100644
--- a/templates/include/post-render.tmpl
+++ b/templates/include/post-render.tmpl
@@ -1,4 +1,10 @@
+{{define "collection-meta"}}
+ {{if .Monetization -}}
+
+ {{- end}}
+{{end}}
+
{{define "highlighting"}}