This commit is contained in:
Julien Genestoux 2022-03-24 02:11:47 +00:00 committed by GitHub
commit d0514596ad
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 137 additions and 283 deletions

View File

@ -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

View File

@ -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
View File

@ -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
View File

@ -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=

View File

@ -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, "&lt;!--paid-->", "<!--paid-->", 1)
p.HTMLTitle = template.HTML(applyBasicMarkdown([]byte(p.Title.String)))

290
prose/package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -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 {

View File

@ -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;">