Compare commits
43 Commits
50524cade2
...
10bca44dc5
Author | SHA1 | Date |
---|---|---|
Ted Unangst | 10bca44dc5 | |
Ted Unangst | fc567f7f69 | |
Ted Unangst | 353a3b27f6 | |
Ted Unangst | b5470175c7 | |
Ted Unangst | 9e43ccbb88 | |
Ted Unangst | 67c2d983bd | |
Ted Unangst | 2a8f20feff | |
Ted Unangst | ae8d1909d8 | |
Ted Unangst | deec523437 | |
Ted Unangst | 4f8a33eb2b | |
Ted Unangst | 7058ecd1d0 | |
Ted Unangst | 31a9ea6a08 | |
Ted Unangst | 2eb5b9d3c0 | |
Ted Unangst | 858ce2f291 | |
Ted Unangst | af2deab137 | |
Ted Unangst | a857fdd06c | |
Ted Unangst | dab8de6670 | |
Ted Unangst | b261f73c49 | |
Ted Unangst | bf9e65d699 | |
Ted Unangst | 7f8d2068fd | |
Ted Unangst | 2559b0cf16 | |
Ted Unangst | ff5b731644 | |
Ted Unangst | ba9d745efa | |
Ted Unangst | e965f7090f | |
Ted Unangst | e8d1d64f1c | |
Ted Unangst | 5e481273df | |
Ted Unangst | e9813defe2 | |
Ted Unangst | 23117ad450 | |
Ted Unangst | 108cd4fff3 | |
Ted Unangst | 55ece74faa | |
Ted Unangst | 5eb2821d10 | |
Ted Unangst | 65face4f35 | |
Ted Unangst | ed13b68989 | |
Ted Unangst | b6efa7d4bd | |
Ted Unangst | ca9f48106c | |
Ted Unangst | 65a27bf359 | |
Ted Unangst | 4ed4ae3186 | |
Ted Unangst | 398d430e97 | |
Ted Unangst | e08c21228c | |
Ted Unangst | ad5a149f64 | |
Ted Unangst | 9b8018ff26 | |
Ted Unangst | 6d52b4f492 | |
Ted Unangst | 628fc34ae4 |
2
.hgtags
2
.hgtags
|
@ -36,3 +36,5 @@ dac64bc6a93cedeb6ae618cba8f8647af96d2ece v0.9.3
|
|||
6a522536238fe25b6d048543f52ed406ccf720b2 v0.9.6
|
||||
bc1bcfb9c0cc86b3c63325b07e13a36b9d4500f0 v0.9.7
|
||||
916cefdc24363b6e7e193dbde82632c17f58adfd v0.9.8
|
||||
4b8cf31560b7d1e1696af109b158766c4ce823ab v0.9.9
|
||||
d7c3a01e7aaef67c40920bbc4e8507350fc33e31 v0.9.91
|
||||
|
|
96
activity.go
96
activity.go
|
@ -511,7 +511,8 @@ var re_mast0link = regexp.MustCompile(`https://[[:alnum:].]+/users/[[:alnum:]]+/
|
|||
var re_masto1ink = regexp.MustCompile(`https://[[:alnum:].]+/@[[:alnum:]]+/[[:digit:]]+`)
|
||||
var re_misslink = regexp.MustCompile(`https://[[:alnum:].]+/notes/[[:alnum:]]+`)
|
||||
var re_honklink = regexp.MustCompile(`https://[[:alnum:].]+/u/[[:alnum:]]+/h/[[:alnum:]]+`)
|
||||
var re_romalink = regexp.MustCompile(`https://[[:alnum:].]+/objects/[[:alnum:]-]+`)
|
||||
var re_r0malink = regexp.MustCompile(`https://[[:alnum:].]+/objects/[[:alnum:]-]+`)
|
||||
var re_roma1ink = regexp.MustCompile(`https://[[:alnum:].]+/notice/[[:alnum:]]+`)
|
||||
var re_qtlinks = regexp.MustCompile(`>https://[^\s<]+<`)
|
||||
|
||||
func qutify(user *WhatAbout, content string) string {
|
||||
|
@ -521,14 +522,11 @@ func qutify(user *WhatAbout, content string) string {
|
|||
mlinks := re_qtlinks.FindAllString(malcontent, -1)
|
||||
for _, m := range mlinks {
|
||||
m = m[1 : len(m)-1]
|
||||
dlog.Printf("consider qt: %s", m)
|
||||
if re_mast0link.MatchString(m) ||
|
||||
re_masto1ink.MatchString(m) ||
|
||||
if re_mast0link.MatchString(m) || re_masto1ink.MatchString(m) ||
|
||||
re_misslink.MatchString(m) ||
|
||||
re_honklink.MatchString(m) ||
|
||||
re_romalink.MatchString(m) {
|
||||
re_r0malink.MatchString(m) || re_roma1ink.MatchString(m) {
|
||||
j, err := GetJunk(user.ID, m)
|
||||
dlog.Printf("fetched %s: %s", m, err)
|
||||
if err == nil {
|
||||
q, ok := j.GetString("content")
|
||||
if ok {
|
||||
|
@ -576,6 +574,7 @@ func xonksaver(user *WhatAbout, item junk.Junk, origin string) *Honk {
|
|||
var replies []string
|
||||
var obj junk.Junk
|
||||
waspage := false
|
||||
preferorig := false
|
||||
switch what {
|
||||
case "Delete":
|
||||
obj, ok = item.GetMap("object")
|
||||
|
@ -687,11 +686,10 @@ func xonksaver(user *WhatAbout, item junk.Junk, origin string) *Honk {
|
|||
case "Page":
|
||||
waspage = true
|
||||
fallthrough
|
||||
case "GuessWord": // dealt with below
|
||||
fallthrough
|
||||
case "Audio":
|
||||
fallthrough
|
||||
case "Image":
|
||||
preferorig = true
|
||||
fallthrough
|
||||
case "Video":
|
||||
fallthrough
|
||||
|
@ -820,12 +818,6 @@ func xonksaver(user *WhatAbout, item junk.Junk, origin string) *Honk {
|
|||
targ, _ := obj.GetString("target")
|
||||
content += string(templates.Sprintf(`<p>Moved to <a href="%s">%s</a>`, targ, targ))
|
||||
}
|
||||
if ot == "GuessWord" {
|
||||
what = "wonk"
|
||||
content, _ = obj.GetString("content")
|
||||
xonk.Wonkles, _ = obj.GetString("wordlist")
|
||||
go savewonkles(xonk.Wonkles)
|
||||
}
|
||||
if what == "honk" && rid != "" {
|
||||
what = "tonk"
|
||||
}
|
||||
|
@ -846,6 +838,9 @@ func xonksaver(user *WhatAbout, item junk.Junk, origin string) *Honk {
|
|||
at, _ := att.GetString("type")
|
||||
mt, _ := att.GetString("mediaType")
|
||||
u, ok := att.GetString("url")
|
||||
if !ok {
|
||||
u, ok = att.GetString("href")
|
||||
}
|
||||
if !ok {
|
||||
if ua, ok := att.GetArray("url"); ok && len(ua) > 0 {
|
||||
u, ok = ua[0].(string)
|
||||
|
@ -873,7 +868,7 @@ func xonksaver(user *WhatAbout, item junk.Junk, origin string) *Honk {
|
|||
localize := false
|
||||
if numatts > 4 {
|
||||
ilog.Printf("excessive attachment: %s", at)
|
||||
} else if at == "Document" || at == "Image" {
|
||||
} else if at == "Document" || at == "Image" || (preferorig && at == "Link") {
|
||||
mt = strings.ToLower(mt)
|
||||
dlog.Printf("attachment: %s %s", mt, u)
|
||||
if mt == "text/plain" || mt == "application/pdf" ||
|
||||
|
@ -886,23 +881,42 @@ func xonksaver(user *WhatAbout, item junk.Junk, origin string) *Honk {
|
|||
if skipMedia(&xonk) {
|
||||
localize = false
|
||||
}
|
||||
if preferorig && !localize {
|
||||
return
|
||||
}
|
||||
donk := savedonk(u, name, desc, mt, localize)
|
||||
if donk != nil {
|
||||
xonk.Donks = append(xonk.Donks, donk)
|
||||
}
|
||||
numatts++
|
||||
}
|
||||
atts, _ := obj.GetArray("attachment")
|
||||
for _, atti := range atts {
|
||||
att, ok := atti.(junk.Junk)
|
||||
if !ok {
|
||||
ilog.Printf("attachment that wasn't map?")
|
||||
continue
|
||||
if preferorig {
|
||||
atts, _ := obj.GetArray("url")
|
||||
for _, atti := range atts {
|
||||
att, ok := atti.(junk.Junk)
|
||||
if !ok {
|
||||
ilog.Printf("attachment that wasn't map?")
|
||||
continue
|
||||
}
|
||||
procatt(att)
|
||||
}
|
||||
if numatts == 0 {
|
||||
preferorig = false
|
||||
}
|
||||
procatt(att)
|
||||
}
|
||||
if att, ok := obj.GetMap("attachment"); ok {
|
||||
procatt(att)
|
||||
if !preferorig {
|
||||
atts, _ := obj.GetArray("attachment")
|
||||
for _, atti := range atts {
|
||||
att, ok := atti.(junk.Junk)
|
||||
if !ok {
|
||||
ilog.Printf("attachment that wasn't map?")
|
||||
continue
|
||||
}
|
||||
procatt(att)
|
||||
}
|
||||
if att, ok := obj.GetMap("attachment"); ok {
|
||||
procatt(att)
|
||||
}
|
||||
}
|
||||
tags, _ := obj.GetArray("tag")
|
||||
for _, tagi := range tags {
|
||||
|
@ -1181,8 +1195,6 @@ func jonkjonk(user *WhatAbout, h *Honk) (junk.Junk, junk.Junk) {
|
|||
fallthrough
|
||||
case "event":
|
||||
fallthrough
|
||||
case "wonk":
|
||||
fallthrough
|
||||
case "honk":
|
||||
j["type"] = "Create"
|
||||
jo = junk.New()
|
||||
|
@ -1190,8 +1202,6 @@ func jonkjonk(user *WhatAbout, h *Honk) (junk.Junk, junk.Junk) {
|
|||
jo["type"] = "Note"
|
||||
if h.What == "event" {
|
||||
jo["type"] = "Event"
|
||||
} else if h.What == "wonk" {
|
||||
jo["type"] = "GuessWord"
|
||||
}
|
||||
if h.What == "update" {
|
||||
j["type"] = "Update"
|
||||
|
@ -1298,14 +1308,11 @@ func jonkjonk(user *WhatAbout, h *Honk) (junk.Junk, junk.Junk) {
|
|||
jo["duration"] = "PT" + strings.ToUpper(t.Duration.String())
|
||||
}
|
||||
}
|
||||
if w := h.Wonkles; w != "" {
|
||||
jo["wordlist"] = w
|
||||
}
|
||||
atts := activatedonks(h.Donks)
|
||||
if len(atts) > 0 {
|
||||
jo["attachment"] = atts
|
||||
}
|
||||
jo["summary"] = html.EscapeString(h.Precis)
|
||||
jo["summary"] = h.Precis
|
||||
jo["content"] = h.Noise
|
||||
j["object"] = jo
|
||||
case "bonk":
|
||||
|
@ -1899,7 +1906,7 @@ func unfollowme(user *WhatAbout, who string, name string, j junk.Junk) {
|
|||
}
|
||||
}
|
||||
|
||||
func followyou(user *WhatAbout, honkerid int64) {
|
||||
func followyou(user *WhatAbout, honkerid int64, sync bool) {
|
||||
var url, owner string
|
||||
db := opendatabase()
|
||||
row := db.QueryRow("select xid, owner from honkers where honkerid = ? and userid = ? and flavor in ('unsub', 'peep', 'presub', 'sub')",
|
||||
|
@ -1916,26 +1923,37 @@ func followyou(user *WhatAbout, honkerid int64) {
|
|||
elog.Printf("error updating honker: %s", err)
|
||||
return
|
||||
}
|
||||
go subsub(user, url, owner, folxid)
|
||||
if sync {
|
||||
subsub(user, url, owner, folxid)
|
||||
} else {
|
||||
go subsub(user, url, owner, folxid)
|
||||
}
|
||||
|
||||
}
|
||||
func unfollowyou(user *WhatAbout, honkerid int64) {
|
||||
func unfollowyou(user *WhatAbout, honkerid int64, sync bool) {
|
||||
db := opendatabase()
|
||||
row := db.QueryRow("select xid, owner, folxid from honkers where honkerid = ? and userid = ? and flavor in ('sub')",
|
||||
row := db.QueryRow("select xid, owner, folxid, flavor from honkers where honkerid = ? and userid = ? and flavor in ('unsub', 'peep', 'presub', 'sub')",
|
||||
honkerid, user.ID)
|
||||
var url, owner, folxid string
|
||||
err := row.Scan(&url, &owner, &folxid)
|
||||
var url, owner, folxid, flavor string
|
||||
err := row.Scan(&url, &owner, &folxid, &flavor)
|
||||
if err != nil {
|
||||
elog.Printf("can't get honker xid: %s", err)
|
||||
return
|
||||
}
|
||||
if flavor == "peep" {
|
||||
return
|
||||
}
|
||||
ilog.Printf("unsubscribing from %s", url)
|
||||
_, err = db.Exec("update honkers set flavor = ? where honkerid = ?", "unsub", honkerid)
|
||||
if err != nil {
|
||||
elog.Printf("error updating honker: %s", err)
|
||||
return
|
||||
}
|
||||
go itakeitallback(user, url, owner, folxid)
|
||||
if sync {
|
||||
itakeitallback(user, url, owner, folxid)
|
||||
} else {
|
||||
go itakeitallback(user, url, owner, folxid)
|
||||
}
|
||||
}
|
||||
|
||||
func followyou2(user *WhatAbout, j junk.Junk) {
|
||||
|
|
51
bloat.go
51
bloat.go
|
@ -14,54 +14,3 @@
|
|||
// OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"strings"
|
||||
|
||||
"humungus.tedunangst.com/r/webs/junk"
|
||||
)
|
||||
|
||||
func servewonkles(w http.ResponseWriter, r *http.Request) {
|
||||
url := r.FormValue("w")
|
||||
dlog.Printf("getting wordlist: %s", url)
|
||||
wonkles := getxonker(url, "wonkles")
|
||||
if wonkles == "" {
|
||||
wonkles = savewonkles(url)
|
||||
if wonkles == "" {
|
||||
http.NotFound(w, r)
|
||||
return
|
||||
}
|
||||
}
|
||||
var words []string
|
||||
for _, l := range strings.Split(wonkles, "\n") {
|
||||
words = append(words, l)
|
||||
}
|
||||
if !develMode {
|
||||
w.Header().Set("Cache-Control", "max-age=7776000")
|
||||
}
|
||||
|
||||
j := junk.New()
|
||||
j["wordlist"] = words
|
||||
j.Write(w)
|
||||
}
|
||||
|
||||
func savewonkles(url string) string {
|
||||
w := getxonker(url, "wonkles")
|
||||
if w != "" {
|
||||
return w
|
||||
}
|
||||
ilog.Printf("fetching wonkles: %s", url)
|
||||
res, err := fetchsome(url)
|
||||
if err != nil {
|
||||
ilog.Printf("error fetching wonkles: %s", err)
|
||||
return ""
|
||||
}
|
||||
w = getxonker(url, "wonkles")
|
||||
if w != "" {
|
||||
return w
|
||||
}
|
||||
w = string(res)
|
||||
savexonker(url, w, "wonkles", "")
|
||||
return w
|
||||
}
|
||||
|
|
46
database.go
46
database.go
|
@ -485,9 +485,7 @@ func donksforhonks(honks []*Honk) {
|
|||
continue
|
||||
}
|
||||
case "wonkles":
|
||||
h.Wonkles = j
|
||||
case "guesses":
|
||||
h.Guesses = template.HTML(j)
|
||||
case "oldrev":
|
||||
default:
|
||||
elog.Printf("unknown meta genus: %s", genus)
|
||||
|
@ -576,6 +574,20 @@ func savefileandxid(name string, desc string, url string, media string, local bo
|
|||
return fileid, xid, nil
|
||||
}
|
||||
|
||||
func finddonkid(fileid int64, url string) *Donk {
|
||||
donk := new(Donk)
|
||||
row := stmtFindFileId.QueryRow(fileid, url)
|
||||
err := row.Scan(&donk.XID, &donk.Local, &donk.Desc)
|
||||
if err == nil {
|
||||
donk.FileID = fileid
|
||||
return donk
|
||||
}
|
||||
if err != sql.ErrNoRows {
|
||||
elog.Printf("error finding file: %s", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func finddonk(url string) *Donk {
|
||||
donk := new(Donk)
|
||||
row := stmtFindFile.QueryRow(url)
|
||||
|
@ -897,20 +909,6 @@ func saveextras(tx *sql.Tx, h *Honk) error {
|
|||
return err
|
||||
}
|
||||
}
|
||||
if w := h.Wonkles; w != "" {
|
||||
_, err := tx.Stmt(stmtSaveMeta).Exec(h.ID, "wonkles", w)
|
||||
if err != nil {
|
||||
elog.Printf("error saving wonkles: %s", err)
|
||||
return err
|
||||
}
|
||||
}
|
||||
if g := h.Guesses; g != "" {
|
||||
_, err := tx.Stmt(stmtSaveMeta).Exec(h.ID, "guesses", g)
|
||||
if err != nil {
|
||||
elog.Printf("error saving guesses: %s", err)
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
|
@ -978,7 +976,7 @@ func savexonker(what, value, flav, when string) {
|
|||
stmtSaveXonker.Exec(what, value, flav, when)
|
||||
}
|
||||
|
||||
func savehonker(user *WhatAbout, url, name, flavor, combos, mj string) error {
|
||||
func savehonker(user *WhatAbout, url, name, flavor, combos, mj string) (int64, error) {
|
||||
var owner string
|
||||
if url[0] == '#' {
|
||||
flavor = "peep"
|
||||
|
@ -990,7 +988,7 @@ func savehonker(user *WhatAbout, url, name, flavor, combos, mj string) error {
|
|||
info, err := investigate(url)
|
||||
if err != nil {
|
||||
ilog.Printf("failed to investigate honker: %s", err)
|
||||
return err
|
||||
return 0, err
|
||||
}
|
||||
url = info.XID
|
||||
if name == "" {
|
||||
|
@ -1009,19 +1007,16 @@ func savehonker(user *WhatAbout, url, name, flavor, combos, mj string) error {
|
|||
} else {
|
||||
err = fmt.Errorf("it seems you are already subscribed to them")
|
||||
}
|
||||
return err
|
||||
return 0, err
|
||||
}
|
||||
|
||||
res, err := stmtSaveHonker.Exec(user.ID, name, url, flavor, combos, owner, mj)
|
||||
if err != nil {
|
||||
elog.Print(err)
|
||||
return err
|
||||
return 0, err
|
||||
}
|
||||
honkerid, _ := res.LastInsertId()
|
||||
if flavor == "presub" {
|
||||
followyou(user, honkerid)
|
||||
}
|
||||
return nil
|
||||
return honkerid, nil
|
||||
}
|
||||
|
||||
func cleanupdb(arg string) {
|
||||
|
@ -1098,7 +1093,7 @@ var stmtHonksByOntology, stmtHonksForUser, stmtHonksForMe, stmtSaveDub, stmtHonk
|
|||
var stmtHonksFromLongAgo *sql.Stmt
|
||||
var stmtHonksByHonker, stmtSaveHonk, stmtUserByName, stmtUserByNumber *sql.Stmt
|
||||
var stmtEventHonks, stmtOneBonk, stmtFindZonk, stmtFindXonk, stmtSaveDonk *sql.Stmt
|
||||
var stmtFindFile, stmtGetFileData, stmtSaveFileData, stmtSaveFile *sql.Stmt
|
||||
var stmtFindFile, stmtFindFileId, stmtGetFileData, stmtSaveFileData, stmtSaveFile *sql.Stmt
|
||||
var stmtCheckFileData *sql.Stmt
|
||||
var stmtAddDoover, stmtGetDoovers, stmtLoadDoover, stmtZapDoover, stmtOneHonker *sql.Stmt
|
||||
var stmtUntagged, stmtDeleteHonk, stmtDeleteDonks, stmtDeleteOnts, stmtSaveZonker *sql.Stmt
|
||||
|
@ -1168,6 +1163,7 @@ func prepareStatements(db *sql.DB) {
|
|||
stmtGetFileData = preparetodie(blobdb, "select media, content from filedata where xid = ?")
|
||||
stmtFindXonk = preparetodie(db, "select honkid from honks where userid = ? and xid = ?")
|
||||
stmtFindFile = preparetodie(db, "select fileid, xid from filemeta where url = ? and local = 1")
|
||||
stmtFindFileId = preparetodie(db, "select xid, local, description from filemeta where fileid = ? and url = ? and local = 1")
|
||||
stmtUserByName = preparetodie(db, "select userid, username, displayname, about, pubkey, seckey, options from users where username = ? and userid > 0")
|
||||
stmtUserByNumber = preparetodie(db, "select userid, username, displayname, about, pubkey, seckey, options from users where userid = ?")
|
||||
stmtSaveDub = preparetodie(db, "insert into honkers (userid, name, xid, flavor, combos, owner, meta, folxid) values (?, ?, ?, ?, '', '', '', ?)")
|
||||
|
|
|
@ -54,13 +54,6 @@ activities are ignored.
|
|||
Limited support.
|
||||
.It Vt Audio
|
||||
Limited Support.
|
||||
.It Vt GuessWord
|
||||
Guess the word game.
|
||||
(Unofficial extension.)
|
||||
The solution is stored in
|
||||
.Fa content
|
||||
with the possible words, one per line, in a file located at
|
||||
.Fa wordlist .
|
||||
.El
|
||||
.Pp
|
||||
Honk primarily supports HTML content, not markdown or other formats,
|
||||
|
|
|
@ -1,6 +1,18 @@
|
|||
changelog
|
||||
|
||||
=== next
|
||||
=== 0.9.91 One More Time
|
||||
|
||||
+ Swallow a follow bug.
|
||||
|
||||
=== 0.9.9 Eat the Bugs
|
||||
|
||||
+ Some fixes for image descriptions.
|
||||
|
||||
+ Fix double htmlization of subject lines.
|
||||
|
||||
+ Remove the wonk support. Fun's over, back to work.
|
||||
|
||||
+ All inclusive danger zone spoiler alerts.
|
||||
|
||||
+ Emu peeker
|
||||
|
||||
|
|
|
@ -52,6 +52,8 @@ fields as well.
|
|||
Regular expression match against the post
|
||||
.Fa content .
|
||||
The special value of "." will match any post with a summary only.
|
||||
.It Ar is reply
|
||||
A reply to another post.
|
||||
.It Ar is announce
|
||||
Is announced (shared).
|
||||
.It Ar announce of
|
||||
|
|
21
docs/honk.3
21
docs/honk.3
|
@ -158,6 +158,27 @@ Delete this honk.
|
|||
Mute this thread.
|
||||
What should identify a convoy.
|
||||
.El
|
||||
.Ss gethonkers
|
||||
Returns a list of current honkers in json format.
|
||||
.Ss savehonker
|
||||
Save a new honker, or update an existing one.
|
||||
The following fields are used.
|
||||
.Bl -tag -width honkerid
|
||||
.It Fa honkerid
|
||||
The numeric ID of an existing honker to update.
|
||||
.It Fa name
|
||||
The preferred short name.
|
||||
.It Fa url
|
||||
The ActivityPub actor url.
|
||||
.It Fa combos
|
||||
Space separated list of combos.
|
||||
.It Fa notes
|
||||
Some notes.
|
||||
.El
|
||||
.Pp
|
||||
The honker numeric ID will be returned for success.
|
||||
To delete, unsub, or sub, include a form value with name and value equal.
|
||||
As in, a form value named delete with the value delete, or unsub=unsub, etc.
|
||||
.Ss sendactivity
|
||||
Send anything.
|
||||
No limits, no error checking.
|
||||
|
|
|
@ -74,7 +74,8 @@ will become a horizontal rule.
|
|||
.Pp
|
||||
If the first line of a honk begins with
|
||||
.Dq DZ:
|
||||
(danger zone) it will be used a summary and the post marked sensitive.
|
||||
(danger zone) or any other combination of two letters and a colon,
|
||||
it will be used a summary and the post marked sensitive.
|
||||
.Pp
|
||||
Mentioning a specfic user such as
|
||||
.Pq @user@example.social
|
||||
|
@ -121,7 +122,7 @@ A description, or caption, is encouraged.
|
|||
Text files and PDFs are also supported as attachments.
|
||||
Other formats are not supported.
|
||||
.Pp
|
||||
One may also check in to a location.
|
||||
One may also live dangerously by posting assassination coordinates.
|
||||
The available fields, all optional, are
|
||||
.Ar name ,
|
||||
.Ar url ,
|
||||
|
|
|
@ -142,6 +142,11 @@ command.
|
|||
Users may be deleted with the
|
||||
.Ic deluser Ar username
|
||||
command.
|
||||
.Pp
|
||||
Follow and unfollow requests can be sent via command line with
|
||||
.Ic follow Ar username Ar url
|
||||
and
|
||||
.Ic unfollow Ar username Ar url .
|
||||
.Ss Maintenance
|
||||
The database may grow large over time.
|
||||
The
|
||||
|
|
24
fun.go
24
fun.go
|
@ -181,9 +181,6 @@ func reverbolate(userid int64, honks []*Honk) {
|
|||
|
||||
h.HTPrecis = template.HTML(h.Precis)
|
||||
h.HTML = template.HTML(h.Noise)
|
||||
if h.What == "wonked" {
|
||||
h.HTML = "? wonk ?"
|
||||
}
|
||||
if redo := relingo[h.What]; redo != "" {
|
||||
h.What = redo
|
||||
}
|
||||
|
@ -290,12 +287,11 @@ func imaginate(honk *Honk) {
|
|||
htf.String(honk.Noise)
|
||||
}
|
||||
|
||||
func translate(honk *Honk) {
|
||||
if honk.Format == "html" {
|
||||
return
|
||||
}
|
||||
var re_dangerous = regexp.MustCompile("^[a-zA-Z]{2}:")
|
||||
|
||||
func precipitate(honk *Honk) {
|
||||
noise := honk.Noise
|
||||
if strings.HasPrefix(noise, "DZ:") {
|
||||
if re_dangerous.MatchString(noise) {
|
||||
idx := strings.Index(noise, "\n")
|
||||
if idx == -1 {
|
||||
honk.Precis = noise
|
||||
|
@ -304,8 +300,16 @@ func translate(honk *Honk) {
|
|||
honk.Precis = noise[:idx]
|
||||
noise = noise[idx+1:]
|
||||
}
|
||||
honk.Precis = markitzero(strings.TrimSpace(honk.Precis))
|
||||
honk.Noise = noise
|
||||
}
|
||||
honk.Precis = markitzero(strings.TrimSpace(honk.Precis))
|
||||
}
|
||||
|
||||
func translate(honk *Honk) {
|
||||
if honk.Format == "html" {
|
||||
return
|
||||
}
|
||||
noise := honk.Noise
|
||||
|
||||
var marker mz.Marker
|
||||
marker.HashLinker = ontoreplacer
|
||||
|
@ -421,6 +425,8 @@ func herdofemus(noise string) []Emu {
|
|||
var re_memes = regexp.MustCompile("meme: ?([^\n]+)")
|
||||
var re_avatar = regexp.MustCompile("avatar: ?([^\n]+)")
|
||||
var re_banner = regexp.MustCompile("banner: ?([^\n]+)")
|
||||
var re_convoy = regexp.MustCompile("convoy: ?([^\n]+)")
|
||||
var re_convalidate = regexp.MustCompile("^(https?|tag|data):")
|
||||
|
||||
func memetize(honk *Honk) {
|
||||
repl := func(x string) string {
|
||||
|
|
|
@ -1,6 +0,0 @@
|
|||
echo "package main" > schema.go
|
||||
echo "var sqlSchema = \`" >> schema.go
|
||||
cat schema.sql >> schema.go
|
||||
echo "\`" >> schema.go
|
||||
go fmt schema.go
|
||||
|
14
hfcs.go
14
hfcs.go
|
@ -33,6 +33,7 @@ type Filter struct {
|
|||
IncludeAudience bool `json:",omitempty"`
|
||||
Text string `json:",omitempty"`
|
||||
re_text *regexp.Regexp
|
||||
IsReply bool `json:",omitempty"`
|
||||
IsAnnounce bool `json:",omitempty"`
|
||||
AnnounceOf string `json:",omitempty"`
|
||||
Reject bool `json:",omitempty"`
|
||||
|
@ -306,6 +307,13 @@ func matchfilterX(h *Honk, f *Filter) string {
|
|||
}
|
||||
}
|
||||
}
|
||||
if match && f.IsReply {
|
||||
match = false
|
||||
if h.RID != "" {
|
||||
match = true
|
||||
rv += " reply"
|
||||
}
|
||||
}
|
||||
if match && f.IsAnnounce {
|
||||
match = false
|
||||
if (f.AnnounceOf == "" && h.Oonker != "") || f.AnnounceOf == h.Oonker ||
|
||||
|
@ -407,6 +415,12 @@ func unsee(honks []*Honk, userid int64) {
|
|||
h.Open = ""
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for _, h := range honks {
|
||||
if h.Precis != "" {
|
||||
h.Open = ""
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
42
honk.go
42
honk.go
|
@ -104,8 +104,6 @@ type Honk struct {
|
|||
Time *Time
|
||||
Mentions []Mention
|
||||
Badonks []Badonk
|
||||
Wonkles string
|
||||
Guesses template.HTML
|
||||
}
|
||||
|
||||
type Badonk struct {
|
||||
|
@ -180,10 +178,6 @@ func (honk *Honk) IsReacted() bool {
|
|||
return honk.Flags&flagIsReacted != 0
|
||||
}
|
||||
|
||||
func (honk *Honk) IsWonked() bool {
|
||||
return honk.Flags&flagIsWonked != 0
|
||||
}
|
||||
|
||||
type Donk struct {
|
||||
FileID int64
|
||||
XID string
|
||||
|
@ -379,6 +373,42 @@ func main() {
|
|||
return
|
||||
}
|
||||
chpass(args[1])
|
||||
case "follow":
|
||||
if len(args) < 3 {
|
||||
fmt.Printf("usage: honk follow username url\n")
|
||||
return
|
||||
}
|
||||
user, err := butwhatabout(args[1])
|
||||
if err != nil {
|
||||
fmt.Printf("user not found\n")
|
||||
return
|
||||
}
|
||||
var meta HonkerMeta
|
||||
mj, _ := jsonify(&meta)
|
||||
honkerid, err := savehonker(user, args[2], "", "presub", "", mj)
|
||||
if err != nil {
|
||||
fmt.Printf("had some trouble with that: %s\n", err)
|
||||
return
|
||||
}
|
||||
followyou(user, honkerid, true)
|
||||
case "unfollow":
|
||||
if len(args) < 3 {
|
||||
fmt.Printf("usage: honk unfollow username url\n")
|
||||
return
|
||||
}
|
||||
user, err := butwhatabout(args[1])
|
||||
if err != nil {
|
||||
fmt.Printf("user not found\n")
|
||||
return
|
||||
}
|
||||
row := db.QueryRow("select honkerid from honkers where xid = ? and userid = ? and flavor in ('sub')", args[2], user.ID)
|
||||
var honkerid int64
|
||||
err = row.Scan(&honkerid)
|
||||
if err != nil {
|
||||
fmt.Printf("sorry couldn't find them\n")
|
||||
return
|
||||
}
|
||||
unfollowyou(user, honkerid, true)
|
||||
case "cleanup":
|
||||
arg := "30"
|
||||
if len(args) > 1 {
|
||||
|
|
53
hoot.go
53
hoot.go
|
@ -26,6 +26,7 @@ import (
|
|||
"github.com/andybalholm/cascadia"
|
||||
"golang.org/x/net/html"
|
||||
"humungus.tedunangst.com/r/webs/htfilter"
|
||||
"humungus.tedunangst.com/r/webs/templates"
|
||||
)
|
||||
|
||||
var tweetsel = cascadia.MustCompile("div[data-testid=tweetText]")
|
||||
|
@ -54,10 +55,11 @@ func hootextractor(r io.Reader, url string, seen map[string]bool) string {
|
|||
var htf htfilter.Filter
|
||||
htf.Imager = func(node *html.Node) string {
|
||||
alt := htfilter.GetAttr(node, "alt")
|
||||
if htfilter.HasClass(node, "Emoji") && alt != "" {
|
||||
src := htfilter.GetAttr(node, "src")
|
||||
if htfilter.HasClass(node, "Emoji") || strings.HasSuffix(src, ".svg") {
|
||||
return alt
|
||||
}
|
||||
return fmt.Sprintf(" <img src='%s'>", htfilter.GetAttr(node, "src"))
|
||||
return string(templates.Sprintf(" <img src='%s' alt='%s'>", src, alt))
|
||||
}
|
||||
|
||||
var buf strings.Builder
|
||||
|
@ -65,41 +67,6 @@ func hootextractor(r io.Reader, url string, seen map[string]bool) string {
|
|||
|
||||
divs := tweetsel.MatchAll(root)
|
||||
for i, div := range divs {
|
||||
{
|
||||
twp := div.Parent.Parent.Parent.Parent.Parent
|
||||
link := url
|
||||
alink := linksel.MatchFirst(twp)
|
||||
if alink == nil {
|
||||
if i != 0 {
|
||||
dlog.Printf("missing link")
|
||||
continue
|
||||
}
|
||||
} else {
|
||||
alink = alink.Parent
|
||||
link = "https://twitter.com" + htfilter.GetAttr(alink, "href")
|
||||
}
|
||||
authormatch := authorregex.FindStringSubmatch(link)
|
||||
if len(authormatch) < 2 {
|
||||
dlog.Printf("no author?: %s", link)
|
||||
continue
|
||||
}
|
||||
author := authormatch[1]
|
||||
if wanted == "" {
|
||||
wanted = author
|
||||
}
|
||||
if author != wanted {
|
||||
continue
|
||||
}
|
||||
for _, img := range imgsel.MatchAll(twp) {
|
||||
img.Parent.RemoveChild(img)
|
||||
div.AppendChild(img)
|
||||
}
|
||||
text := htf.NodeText(div)
|
||||
text = strings.Replace(text, "\n", " ", -1)
|
||||
fmt.Fprintf(&buf, "> @%s: %s\n", author, text)
|
||||
continue
|
||||
}
|
||||
|
||||
twp := div.Parent.Parent.Parent.Parent.Parent
|
||||
link := url
|
||||
alink := linksel.MatchFirst(twp)
|
||||
|
@ -109,12 +76,9 @@ func hootextractor(r io.Reader, url string, seen map[string]bool) string {
|
|||
continue
|
||||
}
|
||||
} else {
|
||||
alink = alink.Parent
|
||||
link = "https://twitter.com" + htfilter.GetAttr(alink, "href")
|
||||
}
|
||||
replto := replyingto.MatchFirst(twp)
|
||||
if replto != nil {
|
||||
continue
|
||||
}
|
||||
authormatch := authorregex.FindStringSubmatch(link)
|
||||
if len(authormatch) < 2 {
|
||||
dlog.Printf("no author?: %s", link)
|
||||
|
@ -133,14 +97,7 @@ func hootextractor(r io.Reader, url string, seen map[string]bool) string {
|
|||
}
|
||||
text := htf.NodeText(div)
|
||||
text = strings.Replace(text, "\n", " ", -1)
|
||||
text = re_removepics.ReplaceAllString(text, "")
|
||||
|
||||
if seen[text] {
|
||||
continue
|
||||
}
|
||||
|
||||
fmt.Fprintf(&buf, "> @%s: %s\n", author, text)
|
||||
seen[text] = true
|
||||
}
|
||||
return buf.String()
|
||||
}
|
||||
|
|
|
@ -210,7 +210,7 @@ func importMastotooters(user *WhatAbout, source string) {
|
|||
name := ""
|
||||
flavor := "peep"
|
||||
combos := ""
|
||||
err := savehonker(user, url, name, flavor, combos, mj)
|
||||
_, err := savehonker(user, url, name, flavor, combos, mj)
|
||||
if err != nil {
|
||||
elog.Printf("trouble with a honker: %s", err)
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
|
||||
PROGS=autobonker gettoken saytheday sprayandpray wonkawonk youvegothonks
|
||||
PROGS=autobonker gettoken saytheday sprayandpray youvegothonks
|
||||
|
||||
all: $(PROGS)
|
||||
|
||||
|
@ -18,8 +18,5 @@ saytheday: saytheday.go
|
|||
sprayandpray: sprayandpray.go
|
||||
go build sprayandpray.go
|
||||
|
||||
wonkawonk: wonkawonk.go fetch.go
|
||||
go build wonkawonk.go fetch.go
|
||||
|
||||
youvegothonks: youvegothonks.go
|
||||
go build youvegothonks.go
|
||||
|
|
|
@ -1,79 +0,0 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"crypto/rand"
|
||||
"flag"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"math/big"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"os"
|
||||
"strings"
|
||||
)
|
||||
|
||||
var debugMode = false
|
||||
|
||||
func honkahonk(server, token, wonk, wonkles string) {
|
||||
form := make(url.Values)
|
||||
form.Add("token", token)
|
||||
form.Add("action", "honk")
|
||||
form.Add("noise", wonk)
|
||||
form.Add("wonkles", wonkles)
|
||||
apiurl := fmt.Sprintf("https://%s/api", server)
|
||||
req, err := http.NewRequest("POST", apiurl, strings.NewReader(form.Encode()))
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
req.Header.Add("Content-Type", "application/x-www-form-urlencoded")
|
||||
client := http.DefaultClient
|
||||
if debugMode {
|
||||
client = debugClient
|
||||
}
|
||||
|
||||
resp, err := client.Do(req)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
answer, err := ioutil.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
if resp.StatusCode != 200 {
|
||||
log.Fatalf("status: %d: %s", resp.StatusCode, answer)
|
||||
}
|
||||
}
|
||||
|
||||
func main() {
|
||||
server := ""
|
||||
token := ""
|
||||
wonkles := ""
|
||||
flag.StringVar(&server, "server", server, "server to connnect")
|
||||
flag.StringVar(&token, "token", token, "auth token to use")
|
||||
flag.StringVar(&wonkles, "wonkles", wonkles, "wordlist to use")
|
||||
flag.BoolVar(&debugMode, "debug", debugMode, "debug mode")
|
||||
flag.Parse()
|
||||
|
||||
if server == "" || token == "" || wonkles == "" {
|
||||
flag.Usage()
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
wordlist, err := fetchsome(wonkles)
|
||||
if err != nil {
|
||||
log.Printf("error fetching wonkles: %s", err)
|
||||
}
|
||||
var words []string
|
||||
for _, w := range strings.Split(string(wordlist), "\n") {
|
||||
words = append(words, w)
|
||||
}
|
||||
max := big.NewInt(int64(len(words)))
|
||||
i, _ := rand.Int(rand.Reader, max)
|
||||
wonk := words[i.Int64()]
|
||||
|
||||
log.Printf("picking: %s", wonk)
|
||||
|
||||
honkahonk(server, token, wonk, wonkles)
|
||||
}
|
34
upgradedb.go
34
upgradedb.go
|
@ -22,7 +22,7 @@ import (
|
|||
"time"
|
||||
)
|
||||
|
||||
var myVersion = 41
|
||||
var myVersion = 42
|
||||
|
||||
type dbexecer interface {
|
||||
Exec(query string, args ...interface{}) (sql.Result, error)
|
||||
|
@ -206,6 +206,38 @@ func upgradedb() {
|
|||
doordie(db, "update config set value = 41 where key = 'dbversion'")
|
||||
fallthrough
|
||||
case 41:
|
||||
tx, err := db.Begin()
|
||||
if err != nil {
|
||||
elog.Fatal(err)
|
||||
}
|
||||
rows, err := tx.Query("select honkid, noise from honks where format = 'markdown' and precis <> ''")
|
||||
if err != nil {
|
||||
elog.Fatal(err)
|
||||
}
|
||||
m := make(map[int64]string)
|
||||
var dummy Honk
|
||||
for rows.Next() {
|
||||
err = rows.Scan(&dummy.ID, &dummy.Noise)
|
||||
if err != nil {
|
||||
elog.Fatal(err)
|
||||
}
|
||||
precipitate(&dummy)
|
||||
m[dummy.ID] = dummy.Noise
|
||||
}
|
||||
rows.Close()
|
||||
for id, noise := range m {
|
||||
_, err = tx.Exec("update honks set noise = ? where honkid = ?", noise, id)
|
||||
if err != nil {
|
||||
elog.Fatal(err)
|
||||
}
|
||||
}
|
||||
err = tx.Commit()
|
||||
if err != nil {
|
||||
elog.Fatal(err)
|
||||
}
|
||||
doordie(db, "update config set value = 42 where key = 'dbversion'")
|
||||
fallthrough
|
||||
case 42:
|
||||
|
||||
default:
|
||||
elog.Fatalf("can't upgrade unknown version %d", dbversion)
|
||||
|
|
|
@ -21,20 +21,14 @@
|
|||
<p><label class="button" for="reaction">reaction:</label>
|
||||
<select tabindex=1 name="reaction">
|
||||
<option {{ and (eq .User.Options.Reaction "none") "selected" }}>none</option>
|
||||
<option {{ and (eq .User.Options.Reaction "\U0001F61E") "selected" }}>{{ "\U0001F61E" }}</option>
|
||||
<option {{ and (eq .User.Options.Reaction "\U0001F937") "selected" }}>{{ "\U0001F937" }}</option>
|
||||
<option {{ and (eq .User.Options.Reaction "\U0001F596") "selected" }}>{{ "\U0001F596" }}</option>
|
||||
<option {{ and (eq .User.Options.Reaction "\U0001F648") "selected" }}>{{ "\U0001F648" }}</option>
|
||||
<option {{ and (eq .User.Options.Reaction "\U0001F9BE") "selected" }}>{{ "\U0001F9BE" }}</option>
|
||||
<option {{ and (eq .User.Options.Reaction "\U0001F346") "selected" }}>{{ "\U0001F346" }}</option>
|
||||
<option {{ and (eq .User.Options.Reaction "\U0001F351") "selected" }}>{{ "\U0001F351" }}</option>
|
||||
<option {{ and (eq .User.Options.Reaction "\U0001F32E") "selected" }}>{{ "\U0001F32E" }}</option>
|
||||
<option {{ and (eq .User.Options.Reaction "\U0001F951") "selected" }}>{{ "\U0001F951" }}</option>
|
||||
<option {{ and (eq .User.Options.Reaction "\U0001F5FF") "selected" }}>{{ "\U0001F5FF" }}</option>
|
||||
<option {{ and (eq .User.Options.Reaction "\U0001F99A") "selected" }}>{{ "\U0001F99A" }}</option>
|
||||
<option {{ and (eq .User.Options.Reaction "\U0001F3BB") "selected" }}>{{ "\U0001F3BB" }}</option>
|
||||
<option {{ and (eq .User.Options.Reaction "\U0001FA93") "selected" }}>{{ "\U0001FA93" }}</option>
|
||||
<option {{ and (eq .User.Options.Reaction "\U0001F1EB") "selected" }}>{{ "\U0001F1EB" }}</option>
|
||||
<option {{ and (eq .User.Options.Reaction "\U0001F1FD") "selected" }}>{{ "\U0001F1FD" }}</option>
|
||||
<option {{ and (eq .User.Options.Reaction "\U0001F9EF") "selected" }}>{{ "\U0001F9EF" }}</option>
|
||||
</select>
|
||||
<p><button>update settings</button>
|
||||
</form>
|
||||
|
|
|
@ -20,6 +20,8 @@ Honk Filtering and Censorship System
|
|||
<input tabindex=1 type="checkbox" id="incaud" name="incaud" value="yes"><span></span></label></span>
|
||||
<p><label for="filttext">text matches:</label><br>
|
||||
<input tabindex=1 type="text" name="filttext" value="" autocomplete=off>
|
||||
<p><span><label class=button for="isreply">is reply:
|
||||
<input tabindex=1 type="checkbox" id="isreply" name="isreply" value="yes"><span></span></label></span>
|
||||
<p><span><label class=button for="isannounce">is announce:
|
||||
<input tabindex=1 type="checkbox" id="isannounce" name="isannounce" value="yes"><span></span></label></span>
|
||||
<p><label for="announceof">announce of:</label><br>
|
||||
|
@ -54,6 +56,7 @@ Honk Filtering and Censorship System
|
|||
{{ with .Notes }}<p>Notes: {{ . }}{{ end }}
|
||||
<p>Date: {{ .Date.Format "2006-01-02" }}
|
||||
{{ with .Actor }}<p>Who: {{ . }}{{ end }} {{ with .IncludeAudience }} (inclusive) {{ end }}
|
||||
{{ if .IsReply }}<p>Reply: y{{ end }}
|
||||
{{ if .IsAnnounce }}<p>Announce: {{ .AnnounceOf }}{{ end }}
|
||||
{{ with .Text }}<p>Text: {{ . }}{{ end }}
|
||||
<p>Actions: {{ range .Actions }} {{ . }} {{ end }}
|
||||
|
|
|
@ -52,7 +52,7 @@ in reply to: <a href="{{ .RID }}" rel=noreferrer>{{ .RID }}</a>
|
|||
</header>
|
||||
<p>
|
||||
<details class="noise" {{ .Open }} >
|
||||
<summary>{{ .HTPrecis }}</summary>
|
||||
<summary>{{ .HTPrecis }}<p></summary>
|
||||
<p>{{ .HTPrecis }}
|
||||
<p class="content">{{ .HTML }}
|
||||
{{ with .Time }}
|
||||
|
@ -89,15 +89,6 @@ in reply to: <a href="{{ .RID }}" rel=noreferrer>{{ .RID }}</a>
|
|||
{{ end }}
|
||||
</details>
|
||||
{{ end }}
|
||||
{{ if eq .Honk.What "wonked" }}
|
||||
<p>
|
||||
{{ if and $bonkcsrf .Honk.IsWonked }}
|
||||
{{ .Honk.Guesses }}
|
||||
<p>{{ .Honk.Noise }}
|
||||
{{ else }}
|
||||
<button class="playit" data-noise="{{ .Honk.Noise }}" data-wonk="{{ .Honk.Wonkles }}">it's play time!</button>
|
||||
{{ end }}
|
||||
{{ end }}
|
||||
{{ if and $bonkcsrf (not $IsPreview) }}
|
||||
<p>
|
||||
<details class="actions">
|
||||
|
|
|
@ -14,7 +14,7 @@
|
|||
<p id="donkdescriptor"><label for=donkdesc>description:</label><br>
|
||||
<input type="text" name="donkdesc" value="{{ .DonkDesc }}" autocomplete=off>
|
||||
{{ with .SavedPlace }}
|
||||
<p><button id=checkinbutton type=button>checkin</button>
|
||||
<p><button id=checkinbutton type=button>assassination coordinates</button>
|
||||
<div id=placedescriptor>
|
||||
<p><label>name:</label><br><input type="text" name="placename" id=placenameinput value="{{ .Name }}">
|
||||
<p><label>url:</label><br><input type="text" name="placeurl" id=placeurlinput value="{{ .Url }}">
|
||||
|
@ -22,7 +22,7 @@
|
|||
<label>lon: </label><input type="text" size=9 name="placelong" id=placelonginput value="{{ .Longitude }}">
|
||||
</div>
|
||||
{{ else }}
|
||||
<p><button id=checkinbutton type=button>checkin</button>
|
||||
<p><button id=checkinbutton type=button>assassination coordinates</button>
|
||||
<div id=placedescriptor class="hide">
|
||||
<p><label>name:</label><br><input type="text" name="placename" id=placenameinput value="">
|
||||
<p><label>url:</label><br><input type="text" name="placeurl" id=placeurlinput value="">
|
||||
|
|
|
@ -139,7 +139,6 @@ function fillinhonks(xhr, glowit) {
|
|||
} else {
|
||||
holder.append(h)
|
||||
}
|
||||
|
||||
}
|
||||
relinklinks()
|
||||
return lenhonks
|
||||
|
@ -212,7 +211,7 @@ function switchtopage(name, arg) {
|
|||
curpagestate.name = name
|
||||
curpagestate.arg = arg
|
||||
// get the holder for the target page
|
||||
var stash = name + ":" + arg
|
||||
stash = name + ":" + arg
|
||||
holder = honksforpage[stash]
|
||||
if (holder) {
|
||||
honksonpage.prepend(holder)
|
||||
|
@ -226,7 +225,7 @@ function switchtopage(name, arg) {
|
|||
var args = hydrargs()
|
||||
get("/hydra?" + encode(args), function(xhr) {
|
||||
if (xhr.status == 200) {
|
||||
var lenhonks = fillinhonks(xhr, false)
|
||||
fillinhonks(xhr, false)
|
||||
} else {
|
||||
refreshupdate(" status: " + xhr.status)
|
||||
}
|
||||
|
@ -337,12 +336,6 @@ function relinklinks() {
|
|||
el.onclick = function() {
|
||||
flogit(el, "react", xid);
|
||||
}
|
||||
} else if (el.classList.contains("playit")) {
|
||||
var noise = el.dataset.noise
|
||||
var wonk = el.dataset.wonk
|
||||
el.onclick = function() {
|
||||
playit(el, noise, wonk, xid)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
@ -358,6 +351,7 @@ function showhonkform(elem, rid, hname) {
|
|||
elem.insertAdjacentElement('afterend', form)
|
||||
}
|
||||
var ridinput = document.getElementById("ridinput")
|
||||
var honknoise = document.getElementById("honknoise")
|
||||
if (rid) {
|
||||
ridinput.value = rid
|
||||
if (hname) {
|
||||
|
@ -371,7 +365,7 @@ function showhonkform(elem, rid, hname) {
|
|||
}
|
||||
var updateinput = document.getElementById("updatexidinput")
|
||||
updateinput.value = ""
|
||||
document.getElementById("honknoise").focus()
|
||||
honknoise.focus()
|
||||
return false
|
||||
}
|
||||
function cancelhonking() {
|
||||
|
@ -393,9 +387,9 @@ function hideelement(el) {
|
|||
function updatedonker() {
|
||||
var el = document.getElementById("donker")
|
||||
el.children[1].textContent = el.children[0].value.slice(-20)
|
||||
var el = document.getElementById("donkdescriptor")
|
||||
el = document.getElementById("donkdescriptor")
|
||||
el.style.display = ""
|
||||
var el = document.getElementById("saveddonkxid")
|
||||
el = document.getElementById("saveddonkxid")
|
||||
el.value = ""
|
||||
}
|
||||
var checkinprec = 100.0
|
||||
|
@ -417,25 +411,19 @@ function fillcheckin() {
|
|||
gpsoptions.timeout = 2000
|
||||
}, function(err) {
|
||||
showelement("placedescriptor")
|
||||
el = document.getElementById("placenameinput")
|
||||
var el = document.getElementById("placenameinput")
|
||||
el.value = err.message
|
||||
}, gpsoptions)
|
||||
}
|
||||
}
|
||||
function playit(elem, word, wordlist, xid) {
|
||||
import('/wonk.js').then(module => {
|
||||
makeaguess = module.makeaguess
|
||||
module.addguesscontrols(elem, word, wordlist, xid)
|
||||
})
|
||||
}
|
||||
function addemu(elem) {
|
||||
const data = elem.alt
|
||||
const box = document.getElementById("honknoise");
|
||||
box.value += data;
|
||||
}
|
||||
function loademus() {
|
||||
div = document.getElementById("emupicker")
|
||||
request = new XMLHttpRequest()
|
||||
var div = document.getElementById("emupicker")
|
||||
var request = new XMLHttpRequest()
|
||||
request.open('GET', '/emus')
|
||||
request.onload = function() {
|
||||
div.innerHTML = request.responseText
|
||||
|
|
|
@ -1,89 +0,0 @@
|
|||
export function addguesscontrols(elem, word, wordlist, xid) {
|
||||
var host = elem.parentElement
|
||||
elem.innerHTML = "loading..."
|
||||
|
||||
host.correctAnswer = word
|
||||
host.guesses = []
|
||||
host.xid = xid
|
||||
var xhr = new XMLHttpRequest()
|
||||
xhr.open("GET", "/bloat/wonkles?w=" + encodeURIComponent(wordlist))
|
||||
xhr.responseType = "json"
|
||||
xhr.onload = function() {
|
||||
var wordlist = xhr.response.wordlist
|
||||
var validguesses = {}
|
||||
console.log("valid " + wordlist.length)
|
||||
for (var i = 0; i < wordlist.length; i++) {
|
||||
validguesses[wordlist[i]] = true
|
||||
}
|
||||
host.validGuesses = validguesses
|
||||
var div = document.createElement( 'div' );
|
||||
div.innerHTML = "<p><input> <button>guess</button>"
|
||||
div.querySelector('button').onclick = function() {
|
||||
makeaguess(this)
|
||||
}
|
||||
host.append(div)
|
||||
elem.remove()
|
||||
}
|
||||
xhr.send()
|
||||
}
|
||||
export function makeaguess(btn) {
|
||||
var host = btn.parentElement.parentElement.parentElement
|
||||
var correct = host.correctAnswer
|
||||
var valid = host.validGuesses
|
||||
var inp = btn.previousElementSibling
|
||||
var g = inp.value.toLowerCase()
|
||||
var res = ""
|
||||
if (valid[g]) {
|
||||
var letters = {}
|
||||
var obfu = ""
|
||||
for (var i = 0; i < correct.length; i++) {
|
||||
var l = correct[i]
|
||||
letters[l] = (letters[l] | 0) + 1
|
||||
}
|
||||
for (var i = 0; i < g.length && i < correct.length; i++) {
|
||||
if (g[i] == correct[i]) {
|
||||
letters[g[i]] = letters[g[i]] - 1
|
||||
}
|
||||
}
|
||||
for (var i = 0; i < g.length; i++) {
|
||||
if (i < correct.length && g[i] == correct[i]) {
|
||||
res += g[i].toUpperCase()
|
||||
obfu += "🟩"
|
||||
} else if (letters[g[i]] > 0) {
|
||||
res += g[i]
|
||||
obfu += "🟨"
|
||||
letters[g[i]] = letters[g[i]] - 1
|
||||
} else {
|
||||
obfu += "⬛"
|
||||
res += "."
|
||||
}
|
||||
}
|
||||
|
||||
var div = document.createElement( 'div' );
|
||||
div.innerHTML = "<p class='fontmonospace'>" + res
|
||||
host.append(div)
|
||||
host.guesses.push(obfu)
|
||||
} else {
|
||||
var div = document.createElement( 'div' );
|
||||
div.innerHTML = "<p> invalid guess"
|
||||
host.append(div)
|
||||
}
|
||||
var div = document.createElement( 'div' );
|
||||
if (res == correct.toUpperCase()) {
|
||||
var mess = "<p>you are very smart!"
|
||||
mess += "<p>" + host.xid
|
||||
for (var i = 0; i < host.guesses.length; i++) {
|
||||
mess += "<p>" + host.guesses[i]
|
||||
}
|
||||
div.innerHTML = mess
|
||||
if (typeof(csrftoken) != "undefined")
|
||||
post("/zonkit", encode({"CSRF": csrftoken, "wherefore": "wonk", "guesses": host.guesses.join("<p>"), "what": host.xid}))
|
||||
} else {
|
||||
div.innerHTML = "<p><input> <button>guess</button>"
|
||||
div.querySelector('button').onclick = function() {
|
||||
makeaguess(this)
|
||||
}
|
||||
}
|
||||
host.append(div)
|
||||
btn.parentElement.remove()
|
||||
}
|
148
web.go
148
web.go
|
@ -381,8 +381,6 @@ func inbox(w http.ResponseWriter, r *http.Request) {
|
|||
ilog.Printf("inbox message failed signature for %s from %s: %s", keyname, r.Header.Get("X-Forwarded-For"), err)
|
||||
if keyname != "" {
|
||||
ilog.Printf("bad signature from %s", keyname)
|
||||
ilog.Writer().Write(payload)
|
||||
ilog.Writer().Write([]byte{'\n'})
|
||||
}
|
||||
http.Error(w, "what did you call me?", http.StatusTeapot)
|
||||
return
|
||||
|
@ -421,13 +419,9 @@ func inbox(w http.ResponseWriter, r *http.Request) {
|
|||
return
|
||||
case "Question":
|
||||
return
|
||||
case "Note":
|
||||
go xonksaver(user, j, origin)
|
||||
return
|
||||
}
|
||||
}
|
||||
ilog.Printf("unknown Update activity")
|
||||
dumpactivity(j)
|
||||
go xonksaver(user, j, origin)
|
||||
case "Undo":
|
||||
obj, ok := j.GetMap("object")
|
||||
if !ok {
|
||||
|
@ -487,8 +481,6 @@ func serverinbox(w http.ResponseWriter, r *http.Request) {
|
|||
ilog.Printf("inbox message failed signature for %s from %s: %s", keyname, r.Header.Get("X-Forwarded-For"), err)
|
||||
if keyname != "" {
|
||||
ilog.Printf("bad signature from %s", keyname)
|
||||
ilog.Writer().Write(payload)
|
||||
ilog.Writer().Write([]byte{'\n'})
|
||||
}
|
||||
http.Error(w, "what did you call me?", http.StatusTeapot)
|
||||
return
|
||||
|
@ -1330,21 +1322,6 @@ func zonkit(w http.ResponseWriter, r *http.Request) {
|
|||
return
|
||||
}
|
||||
|
||||
if wherefore == "wonk" {
|
||||
xonk := getxonk(userinfo.UserID, what)
|
||||
if xonk != nil {
|
||||
_, err := stmtUpdateFlags.Exec(flagIsWonked, xonk.ID)
|
||||
if err == nil {
|
||||
guesses := r.FormValue("guesses")
|
||||
_, err = stmtSaveMeta.Exec(xonk.ID, "guesses", guesses)
|
||||
}
|
||||
if err != nil {
|
||||
elog.Printf("error saving: %s", err)
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// my hammer is too big, oh well
|
||||
defer oldjonks.Flush()
|
||||
|
||||
|
@ -1578,7 +1555,7 @@ func submitdonk(w http.ResponseWriter, r *http.Request) (*Donk, error) {
|
|||
return d, nil
|
||||
}
|
||||
|
||||
func submitwebhonk(w http.ResponseWriter, r *http.Request) {
|
||||
func websubmithonk(w http.ResponseWriter, r *http.Request) {
|
||||
h := submithonk(w, r)
|
||||
if h == nil {
|
||||
return
|
||||
|
@ -1620,10 +1597,6 @@ func submithonk(w http.ResponseWriter, r *http.Request) *Honk {
|
|||
if rid != "" {
|
||||
what = "tonk"
|
||||
}
|
||||
wonkles := r.FormValue("wonkles")
|
||||
if wonkles != "" {
|
||||
what = "wonk"
|
||||
}
|
||||
honk = &Honk{
|
||||
UserID: userinfo.UserID,
|
||||
Username: userinfo.Username,
|
||||
|
@ -1632,17 +1605,28 @@ func submithonk(w http.ResponseWriter, r *http.Request) *Honk {
|
|||
XID: xid,
|
||||
Date: dt,
|
||||
Format: format,
|
||||
Wonkles: wonkles,
|
||||
}
|
||||
}
|
||||
|
||||
var convoy string
|
||||
noise = strings.Replace(noise, "\r", "", -1)
|
||||
if updatexid == "" && rid == "" {
|
||||
noise = re_convoy.ReplaceAllStringFunc(noise, func(m string) string {
|
||||
convoy = m[7:]
|
||||
convoy = strings.TrimSpace(convoy)
|
||||
if !re_convalidate.MatchString(convoy) {
|
||||
convoy = ""
|
||||
}
|
||||
return ""
|
||||
})
|
||||
}
|
||||
noise = quickrename(noise, userinfo.UserID)
|
||||
noise = hooterize(noise)
|
||||
honk.Noise = noise
|
||||
precipitate(honk)
|
||||
noise = honk.Noise
|
||||
translate(honk)
|
||||
|
||||
var convoy string
|
||||
if rid != "" {
|
||||
xonk := getxonk(userinfo.UserID, rid)
|
||||
if xonk == nil {
|
||||
|
@ -1662,7 +1646,7 @@ func submithonk(w http.ResponseWriter, r *http.Request) *Honk {
|
|||
honk.RID = rid
|
||||
if xonk.Precis != "" && honk.Precis == "" {
|
||||
honk.Precis = xonk.Precis
|
||||
if !(strings.HasPrefix(honk.Precis, "DZ:") || strings.HasPrefix(honk.Precis, "re: re: re: ")) {
|
||||
if !re_dangerous.MatchString(honk.Precis) {
|
||||
honk.Precis = "re: " + honk.Precis
|
||||
}
|
||||
}
|
||||
|
@ -1696,12 +1680,19 @@ func submithonk(w http.ResponseWriter, r *http.Request) *Honk {
|
|||
}
|
||||
if d != nil {
|
||||
honk.Donks = append(honk.Donks, d)
|
||||
donkxid = d.XID
|
||||
donkxid = fmt.Sprintf("%s:%d", d.XID, d.FileID)
|
||||
}
|
||||
} else {
|
||||
xid := donkxid
|
||||
p := strings.Split(donkxid, ":")
|
||||
xid := p[0]
|
||||
url := fmt.Sprintf("https://%s/d/%s", serverName, xid)
|
||||
donk := finddonk(url)
|
||||
var donk *Donk
|
||||
if len(p) > 1 {
|
||||
fileid, _ := strconv.ParseInt(p[1], 10, 0)
|
||||
donk = finddonkid(fileid, url)
|
||||
} else {
|
||||
donk = finddonk(url)
|
||||
}
|
||||
if donk != nil {
|
||||
honk.Donks = append(honk.Donks, donk)
|
||||
} else {
|
||||
|
@ -1904,7 +1895,15 @@ func showcombos(w http.ResponseWriter, r *http.Request) {
|
|||
}
|
||||
}
|
||||
|
||||
func submithonker(w http.ResponseWriter, r *http.Request) {
|
||||
func websubmithonker(w http.ResponseWriter, r *http.Request) {
|
||||
h := submithonker(w, r)
|
||||
if h == nil {
|
||||
return
|
||||
}
|
||||
http.Redirect(w, r, "/honkers", http.StatusSeeOther)
|
||||
}
|
||||
|
||||
func submithonker(w http.ResponseWriter, r *http.Request) *Honker {
|
||||
u := login.GetUserInfo(r)
|
||||
user, _ := butwhatabout(u.Username)
|
||||
name := strings.TrimSpace(r.FormValue("name"))
|
||||
|
@ -1914,10 +1913,10 @@ func submithonker(w http.ResponseWriter, r *http.Request) {
|
|||
combos = " " + combos + " "
|
||||
honkerid, _ := strconv.ParseInt(r.FormValue("honkerid"), 10, 0)
|
||||
|
||||
re_namecheck := regexp.MustCompile("[\\pL[:digit:]_.-]+")
|
||||
re_namecheck := regexp.MustCompile("^[\\pL[:digit:]_.-]+$")
|
||||
if name != "" && !re_namecheck.MatchString(name) {
|
||||
http.Error(w, "please use a plainer name", http.StatusInternalServerError)
|
||||
return
|
||||
return nil
|
||||
}
|
||||
|
||||
var meta HonkerMeta
|
||||
|
@ -1926,31 +1925,34 @@ func submithonker(w http.ResponseWriter, r *http.Request) {
|
|||
|
||||
defer honkerinvalidator.Clear(u.UserID)
|
||||
|
||||
// mostly dummy, fill in later...
|
||||
h := &Honker{
|
||||
ID: honkerid,
|
||||
}
|
||||
|
||||
if honkerid > 0 {
|
||||
if r.FormValue("delete") == "delete" {
|
||||
unfollowyou(user, honkerid)
|
||||
unfollowyou(user, honkerid, false)
|
||||
stmtDeleteHonker.Exec(honkerid)
|
||||
http.Redirect(w, r, "/honkers", http.StatusSeeOther)
|
||||
return
|
||||
return h
|
||||
}
|
||||
if r.FormValue("unsub") == "unsub" {
|
||||
unfollowyou(user, honkerid)
|
||||
unfollowyou(user, honkerid, false)
|
||||
}
|
||||
if r.FormValue("sub") == "sub" {
|
||||
followyou(user, honkerid)
|
||||
followyou(user, honkerid, false)
|
||||
}
|
||||
_, err := stmtUpdateHonker.Exec(name, combos, mj, honkerid, u.UserID)
|
||||
if err != nil {
|
||||
elog.Printf("update honker err: %s", err)
|
||||
return
|
||||
return nil
|
||||
}
|
||||
http.Redirect(w, r, "/honkers", http.StatusSeeOther)
|
||||
return
|
||||
return h
|
||||
}
|
||||
|
||||
if url == "" {
|
||||
http.Error(w, "subscribing to nothing?", http.StatusInternalServerError)
|
||||
return
|
||||
return nil
|
||||
}
|
||||
|
||||
flavor := "presub"
|
||||
|
@ -1958,13 +1960,17 @@ func submithonker(w http.ResponseWriter, r *http.Request) {
|
|||
flavor = "peep"
|
||||
}
|
||||
|
||||
err := savehonker(user, url, name, flavor, combos, mj)
|
||||
var err error
|
||||
honkerid, err = savehonker(user, url, name, flavor, combos, mj)
|
||||
if err != nil {
|
||||
http.Error(w, "had some trouble with that: "+err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
return nil
|
||||
}
|
||||
|
||||
http.Redirect(w, r, "/honkers", http.StatusSeeOther)
|
||||
if flavor == "presub" {
|
||||
followyou(user, honkerid, false)
|
||||
}
|
||||
h.ID = honkerid
|
||||
return h
|
||||
}
|
||||
|
||||
func hfcspage(w http.ResponseWriter, r *http.Request) {
|
||||
|
@ -2001,6 +2007,7 @@ func savehfcs(w http.ResponseWriter, r *http.Request) {
|
|||
filt.Actor = strings.TrimSpace(r.FormValue("actor"))
|
||||
filt.IncludeAudience = r.FormValue("incaud") == "yes"
|
||||
filt.Text = strings.TrimSpace(r.FormValue("filttext"))
|
||||
filt.IsReply = r.FormValue("isreply") == "yes"
|
||||
filt.IsAnnounce = r.FormValue("isannounce") == "yes"
|
||||
filt.AnnounceOf = strings.TrimSpace(r.FormValue("announceof"))
|
||||
filt.Reject = r.FormValue("doreject") == "yes"
|
||||
|
@ -2116,11 +2123,29 @@ func somedays() string {
|
|||
return fmt.Sprintf("%d", secs)
|
||||
}
|
||||
|
||||
func lookatme(ava string) string {
|
||||
if strings.Contains(ava, serverName+"/"+userSep) {
|
||||
idx := strings.LastIndexByte(ava, '/')
|
||||
if idx < len(ava) {
|
||||
name := ava[idx+1:]
|
||||
user, _ := butwhatabout(name)
|
||||
if user != nil && user.URL == ava {
|
||||
return user.Options.Avatar
|
||||
}
|
||||
}
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func avatate(w http.ResponseWriter, r *http.Request) {
|
||||
if develMode {
|
||||
loadAvatarColors()
|
||||
}
|
||||
n := r.FormValue("a")
|
||||
if redir := lookatme(n); redir != "" {
|
||||
http.Redirect(w, r, redir, http.StatusSeeOther)
|
||||
return
|
||||
}
|
||||
a := genAvatar(n)
|
||||
if !develMode {
|
||||
w.Header().Set("Cache-Control", "max-age="+somedays())
|
||||
|
@ -2331,7 +2356,7 @@ func apihandler(w http.ResponseWriter, r *http.Request) {
|
|||
if h == nil {
|
||||
return
|
||||
}
|
||||
w.Write([]byte(h.XID))
|
||||
fmt.Fprintf(w, "%s", h.XID)
|
||||
case "donk":
|
||||
d, err := submitdonk(w, r)
|
||||
if err != nil {
|
||||
|
@ -2391,6 +2416,16 @@ func apihandler(w http.ResponseWriter, r *http.Request) {
|
|||
for rcpt := range rcpts {
|
||||
go deliverate(0, userid, rcpt, msg, true)
|
||||
}
|
||||
case "gethonkers":
|
||||
j := junk.New()
|
||||
j["honkers"] = gethonkers(u.UserID)
|
||||
j.Write(w)
|
||||
case "savehonker":
|
||||
h := submithonker(w, r)
|
||||
if h == nil {
|
||||
return
|
||||
}
|
||||
fmt.Fprintf(w, "%d", h.ID)
|
||||
default:
|
||||
http.Error(w, "unknown action", http.StatusNotFound)
|
||||
return
|
||||
|
@ -2433,7 +2468,7 @@ func bgmonitor() {
|
|||
|
||||
func addcspheaders(next http.Handler) http.Handler {
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
w.Header().Set("Content-Security-Policy", "default-src 'none'; script-src 'self'; connect-src 'self'; style-src 'self'; img-src 'self'; report-uri /csp-violation")
|
||||
w.Header().Set("Content-Security-Policy", "default-src 'none'; script-src 'self'; connect-src 'self'; style-src 'self'; img-src 'self'; media-src 'self'; report-uri /csp-violation")
|
||||
next.ServeHTTP(w, r)
|
||||
})
|
||||
}
|
||||
|
@ -2553,7 +2588,6 @@ func serve() {
|
|||
|
||||
getters.HandleFunc("/style.css", serveviewasset)
|
||||
getters.HandleFunc("/honkpage.js", serveviewasset)
|
||||
getters.HandleFunc("/wonk.js", serveviewasset)
|
||||
getters.HandleFunc("/misc.js", serveviewasset)
|
||||
getters.HandleFunc("/local.css", servedataasset)
|
||||
getters.HandleFunc("/local.js", servedataasset)
|
||||
|
@ -2566,8 +2600,6 @@ func serve() {
|
|||
getters.HandleFunc("/logout", login.LogoutFunc)
|
||||
getters.HandleFunc("/help/{name:[\\pL[:digit:]_.-]+}", servehelp)
|
||||
|
||||
getters.HandleFunc("/bloat/wonkles", servewonkles)
|
||||
|
||||
loggedin := mux.NewRoute().Subrouter()
|
||||
loggedin.Use(login.Required)
|
||||
loggedin.HandleFunc("/first", homepage)
|
||||
|
@ -2583,7 +2615,7 @@ func serve() {
|
|||
loggedin.HandleFunc("/xzone", xzone)
|
||||
loggedin.HandleFunc("/newhonk", newhonkpage)
|
||||
loggedin.HandleFunc("/edit", edithonkpage)
|
||||
loggedin.Handle("/honk", login.CSRFWrap("honkhonk", http.HandlerFunc(submitwebhonk)))
|
||||
loggedin.Handle("/honk", login.CSRFWrap("honkhonk", http.HandlerFunc(websubmithonk)))
|
||||
loggedin.Handle("/bonk", login.CSRFWrap("honkhonk", http.HandlerFunc(submitbonk)))
|
||||
loggedin.Handle("/zonkit", login.CSRFWrap("honkhonk", http.HandlerFunc(zonkit)))
|
||||
loggedin.Handle("/savehfcs", login.CSRFWrap("filter", http.HandlerFunc(savehfcs)))
|
||||
|
@ -2598,7 +2630,7 @@ func serve() {
|
|||
loggedin.HandleFunc("/q", showsearch)
|
||||
loggedin.HandleFunc("/hydra", webhydra)
|
||||
loggedin.HandleFunc("/emus", showemus)
|
||||
loggedin.Handle("/submithonker", login.CSRFWrap("submithonker", http.HandlerFunc(submithonker)))
|
||||
loggedin.Handle("/submithonker", login.CSRFWrap("submithonker", http.HandlerFunc(websubmithonker)))
|
||||
|
||||
err = http.Serve(listener, mux)
|
||||
if err != nil {
|
||||
|
|
Loading…
Reference in New Issue