Merge 391969f6fc
into e92c33aae4
This commit is contained in:
commit
d0514596ad
|
@ -59,9 +59,17 @@ type (
|
|||
|
||||
Monetization string `json:"monetization_pointer,omitempty"`
|
||||
|
||||
UnlockProtocol *UnlockProtocol `json:"unlock_protocol,omitempty"`
|
||||
|
||||
db *datastore
|
||||
hostName string
|
||||
}
|
||||
|
||||
UnlockProtocol struct {
|
||||
RPCEndpoint string `json:"rpc_endpoint" schema:"rpc_endpoint"`
|
||||
ChainId int `json:"chain_id" schema:"chain_id"`
|
||||
LockAddress string `json:"lock_address" schema:"lock_address"`
|
||||
}
|
||||
CollectionObj struct {
|
||||
Collection
|
||||
TotalPosts int `json:"total_posts"`
|
||||
|
@ -99,6 +107,8 @@ type (
|
|||
Monetization *string `schema:"monetization_pointer" json:"monetization_pointer"`
|
||||
Visibility *int `schema:"visibility" json:"public"`
|
||||
Format *sql.NullString `schema:"format" json:"format"`
|
||||
|
||||
UnlockProtocol *UnlockProtocol `schema:"unlock_protocol" json:"unlock_protocol"`
|
||||
}
|
||||
CollectionFormat struct {
|
||||
Format string
|
||||
|
|
49
database.go
49
database.go
|
@ -14,12 +14,14 @@ import (
|
|||
"context"
|
||||
"database/sql"
|
||||
"fmt"
|
||||
"github.com/writeas/web-core/silobridge"
|
||||
wf_db "github.com/writefreely/writefreely/db"
|
||||
"net/http"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/writeas/web-core/silobridge"
|
||||
wf_db "github.com/writefreely/writefreely/db"
|
||||
|
||||
"github.com/guregu/null"
|
||||
"github.com/guregu/null/zero"
|
||||
uuid "github.com/nu7hatch/gouuid"
|
||||
|
@ -815,6 +817,18 @@ func (db *datastore) GetCollectionBy(condition string, value interface{}) (*Coll
|
|||
c.Public = c.IsPublic()
|
||||
c.Monetization = db.GetCollectionAttribute(c.ID, "monetization_pointer")
|
||||
|
||||
RPCEndpoint := db.GetCollectionAttribute(c.ID, "unlock_protocol.rpc_endpoint")
|
||||
if RPCEndpoint != "" {
|
||||
c.UnlockProtocol = &UnlockProtocol{
|
||||
RPCEndpoint: RPCEndpoint,
|
||||
}
|
||||
chainIdStr := db.GetCollectionAttribute(c.ID, "unlock_protocol.chain_id")
|
||||
c.UnlockProtocol.ChainId, err = strconv.Atoi(chainIdStr)
|
||||
c.UnlockProtocol.LockAddress = db.GetCollectionAttribute(c.ID, "unlock_protocol.lock_address")
|
||||
|
||||
}
|
||||
|
||||
|
||||
c.db = db
|
||||
|
||||
return c, nil
|
||||
|
@ -932,6 +946,37 @@ func (db *datastore) UpdateCollection(c *SubmittedCollection, alias string) erro
|
|||
}
|
||||
}
|
||||
|
||||
// Update Unlock Protocol value
|
||||
if c.UnlockProtocol != nil {
|
||||
skipUpdate := false
|
||||
if c.UnlockProtocol.RPCEndpoint != "" {
|
||||
// Strip away any excess spaces
|
||||
c.UnlockProtocol.RPCEndpoint = strings.TrimSpace(c.UnlockProtocol.RPCEndpoint)
|
||||
}
|
||||
if c.UnlockProtocol.LockAddress != "" {
|
||||
// Strip away any excess spaces
|
||||
c.UnlockProtocol.LockAddress = strings.TrimSpace(c.UnlockProtocol.LockAddress)
|
||||
}
|
||||
if !skipUpdate {
|
||||
_, err = db.Exec("INSERT INTO collectionattributes (collection_id, attribute, value) VALUES (?, ?, ?) "+db.upsert("collection_id", "attribute")+" value = ?", collID, "unlock_protocol.rpc_endpoint", c.UnlockProtocol.RPCEndpoint, c.UnlockProtocol.RPCEndpoint)
|
||||
if err != nil {
|
||||
log.Error("Unable to insert unlock_protocol.rpc_endpoint value: %v", err)
|
||||
return err
|
||||
}
|
||||
_, err = db.Exec("INSERT INTO collectionattributes (collection_id, attribute, value) VALUES (?, ?, ?) "+db.upsert("collection_id", "attribute")+" value = ?", collID, "unlock_protocol.chain_id", c.UnlockProtocol.ChainId, c.UnlockProtocol.ChainId)
|
||||
if err != nil {
|
||||
log.Error("Unable to insert unlock_protocol.chain_id value: %v", err)
|
||||
return err
|
||||
}
|
||||
_, err = db.Exec("INSERT INTO collectionattributes (collection_id, attribute, value) VALUES (?, ?, ?) "+db.upsert("collection_id", "attribute")+" value = ?", collID, "unlock_protocol.lock_address", c.UnlockProtocol.LockAddress, c.UnlockProtocol.LockAddress)
|
||||
if err != nil {
|
||||
log.Error("Unable to insert unlock_protocol.lock_address value: %v", err)
|
||||
return err
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
// Update rest of the collection data
|
||||
if q.Updates != "" {
|
||||
res, err = db.Exec("UPDATE collections SET "+q.Updates+" WHERE "+q.Conditions, q.Params...)
|
||||
|
|
2
go.mod
2
go.mod
|
@ -16,6 +16,7 @@ require (
|
|||
github.com/guregu/null v3.5.0+incompatible
|
||||
github.com/hashicorp/go-multierror v1.1.1
|
||||
github.com/ikeikeikeike/go-sitemap-generator/v2 v2.0.2
|
||||
github.com/jteeuwen/go-bindata v3.0.7+incompatible // indirect
|
||||
github.com/jtolds/gls v4.2.1+incompatible // indirect
|
||||
github.com/kylemcc/twitter-text-go v0.0.0-20180726194232-7f582f6736ec
|
||||
github.com/lunixbochs/vtclean v1.0.0 // indirect
|
||||
|
@ -43,6 +44,7 @@ require (
|
|||
github.com/writefreely/go-nodeinfo v1.2.0
|
||||
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9
|
||||
golang.org/x/net v0.0.0-20200707034311-ab3426394381
|
||||
golang.org/x/sys v0.0.0-20220319134239-a9b59b0215f8 // indirect
|
||||
gopkg.in/ini.v1 v1.62.0
|
||||
)
|
||||
|
||||
|
|
4
go.sum
4
go.sum
|
@ -70,6 +70,8 @@ github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+l
|
|||
github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM=
|
||||
github.com/ikeikeikeike/go-sitemap-generator/v2 v2.0.2 h1:wIdDEle9HEy7vBPjC6oKz6ejs3Ut+jmsYvuOoAW2pSM=
|
||||
github.com/ikeikeikeike/go-sitemap-generator/v2 v2.0.2/go.mod h1:WtaVKD9TeruTED9ydiaOJU08qGoEPP/LyzTKiD3jEsw=
|
||||
github.com/jteeuwen/go-bindata v3.0.7+incompatible h1:91Uy4d9SYVr1kyTJ15wJsog+esAZZl7JmEfTkwmhJts=
|
||||
github.com/jteeuwen/go-bindata v3.0.7+incompatible/go.mod h1:JVvhzYOiGBnFSYRyV00iY8q7/0PThjIYav1p9h5dmKs=
|
||||
github.com/jtolds/gls v4.2.1+incompatible h1:fSuqC+Gmlu6l/ZYAoZzx2pyucC8Xza35fpRVWLVmUEE=
|
||||
github.com/jtolds/gls v4.2.1+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
|
||||
github.com/juju/ansiterm v0.0.0-20180109212912-720a0952cc2a h1:FaWFmfWdAUKbSCtOU2QjDaorUexogfaMgbipgYATUMU=
|
||||
|
@ -169,6 +171,8 @@ golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7w
|
|||
golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd h1:xhmwyvizuTgC2qz7ZlMluP20uW+C3Rm0FD/WLDX8884=
|
||||
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20220319134239-a9b59b0215f8 h1:OH54vjqzRWmbJ62fjuhxy7AxFFgoHN0/DPc/UrL8cAs=
|
||||
golang.org/x/sys v0.0.0-20220319134239-a9b59b0215f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
|
|
|
@ -43,7 +43,7 @@ var (
|
|||
mentionReg = regexp.MustCompile(`@([A-Za-z0-9._%+-]+)(@[A-Za-z0-9.-]+\.[A-Za-z]+)\b`)
|
||||
)
|
||||
|
||||
func (p *Post) handlePremiumContent(c *Collection, isOwner, postPage bool, cfg *config.Config) {
|
||||
func (p *Post) handleWebmonetizationPremiumContent(c *Collection, isOwner, postPage bool, cfg *config.Config) {
|
||||
if c.Monetization != "" {
|
||||
// User has Web Monetization enabled, so split content if it exists
|
||||
spl := strings.Index(p.Content, shortCodePaid)
|
||||
|
@ -73,6 +73,43 @@ func (p *Post) handlePremiumContent(c *Collection, isOwner, postPage bool, cfg *
|
|||
}
|
||||
}
|
||||
|
||||
func (p *Post) handleUnlockProtocolPremiumContent(c *Collection, isOwner, postPage bool, cfg *config.Config) {
|
||||
if c.UnlockProtocol != nil {
|
||||
// Let's see if the user is logged in (2 options: query string include `code`, or cookie includes `code`)
|
||||
// the `code` object includes the signed message + signature. Signed message includes timestamp
|
||||
// Ethereum includes a "signer recovery" mechamism to "trust" the address
|
||||
// if not, split and render login button
|
||||
// if so, check if the user has a valid membership thru rpc endpoint
|
||||
// For this we just call the right function on contract hasValidMembership(useraddress)
|
||||
// if not, split and render purchase button
|
||||
// if so, don't split and render full content (maybe show a "thank you for being a member")
|
||||
spl := strings.Index(p.Content, shortCodePaid)
|
||||
p.IsPaid = spl > -1
|
||||
if postPage {
|
||||
// We're viewing the individual post
|
||||
if isOwner {
|
||||
p.Content = strings.Replace(p.Content, shortCodePaid, "\n\n"+`<p class="split">Your subscriber content begins here.</p>`+"\n\n", 1)
|
||||
} else {
|
||||
if spl > -1 {
|
||||
p.Content = p.Content[:spl+len(shortCodePaid)]
|
||||
p.Content = strings.Replace(p.Content, shortCodePaid, "\n\n"+`<p class="split">Continue reading with a <strong>Coil</strong> membership.</p>`+"\n\n", 1)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// We've viewing the post on the collection landing
|
||||
if spl > -1 {
|
||||
baseURL := c.CanonicalURL()
|
||||
if isOwner {
|
||||
baseURL = "/" + c.Alias + "/"
|
||||
}
|
||||
|
||||
p.Content = p.Content[:spl+len(shortCodePaid)]
|
||||
p.HTMLExcerpt = template.HTML(applyMarkdown([]byte(p.Content[:spl]), baseURL, cfg))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (p *Post) formatContent(cfg *config.Config, c *Collection, isOwner bool, isPostPage bool) {
|
||||
baseURL := c.CanonicalURL()
|
||||
// TODO: redundant
|
||||
|
@ -80,7 +117,8 @@ func (p *Post) formatContent(cfg *config.Config, c *Collection, isOwner bool, is
|
|||
baseURL = "/" + c.Alias + "/"
|
||||
}
|
||||
|
||||
p.handlePremiumContent(c, isOwner, isPostPage, cfg)
|
||||
p.handleWebmonetizationPremiumContent(c, isOwner, isPostPage, cfg)
|
||||
p.handleUnlockProtocolPremiumContent(c, isOwner, isPostPage, cfg)
|
||||
p.Content = strings.Replace(p.Content, "<!--paid-->", "<!--paid-->", 1)
|
||||
|
||||
p.HTMLTitle = template.HTML(applyBasicMarkdown([]byte(p.Title.String)))
|
||||
|
|
File diff suppressed because it is too large
Load Diff
3
read.go
3
read.go
|
@ -115,7 +115,8 @@ func (app *App) FetchPublicPosts() (interface{}, error) {
|
|||
}
|
||||
|
||||
p.extractData()
|
||||
p.handlePremiumContent(c, false, false, app.cfg)
|
||||
p.handleWebmonetizationPremiumContent(c, false, false, app.cfg)
|
||||
p.handleUnlockProtocolPremiumContent(c, false, false, app.cfg)
|
||||
p.HTMLContent = template.HTML(applyMarkdown([]byte(p.Content), "", app.cfg))
|
||||
fp := p.processPost()
|
||||
if isCollectionPost {
|
||||
|
|
|
@ -161,6 +161,26 @@ textarea.section.norm {
|
|||
<input type="text" name="monetization_pointer" style="width:100%" value="{{.Collection.Monetization}}" placeholder="$wallet.example.com/alice" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="option">
|
||||
<h2>Unlock Protocol</h2>
|
||||
<div class="section">
|
||||
<p class="explain">Blah! Provide some info aboit Unlock...</p>
|
||||
<label>
|
||||
RPC Endpoint:
|
||||
<input type="text" name="unlock_protocol.rpc_endpoint" style="width:100%" value="{{.Collection.UnlockProtocol.RPCEndpoint}}" placeholder="https://rpc..." />
|
||||
</label>
|
||||
<label>
|
||||
Chain ID:
|
||||
<input type="text" name="unlock_protocol.chain_id" style="width:100%" value="{{.Collection.UnlockProtocol.ChainId}}" placeholder="4" />
|
||||
</label>
|
||||
<label>
|
||||
Lock Address:
|
||||
<input type="text" name="unlock_protocol.lock_address" style="width:100%" value="{{.Collection.UnlockProtocol.LockAddress}}" placeholder="0x...." />
|
||||
</Label>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{{end}}
|
||||
|
||||
<div class="option" style="text-align: center; margin-top: 4em;">
|
||||
|
|
Loading…
Reference in New Issue