Compare commits

...

27 Commits

Author SHA1 Message Date
Ted Unangst ef8b188fa9 raw sendmsg from command line 2023-08-02 18:49:28 -04:00
Ted Unangst 04cc94facd a little rework of the chonky bonk flow 2023-08-01 16:17:45 -04:00
Ted Unangst 2e82a931b9 some people are determined to fill my database with tombstones,
so only save zonk if we deleted something
2023-07-31 22:54:53 -04:00
Ted Unangst 592c189e8b need to demasto the mention 2023-07-31 20:46:43 -04:00
Ted Unangst 6cc464910d change notes 2023-07-31 20:45:56 -04:00
Ted Unangst c24f06b9f3 going forward, include tag in plain 2023-07-31 20:37:03 -04:00
Ted Unangst 14c9d31bd7 upgrade to backfill the plain text column 2023-07-31 20:36:15 -04:00
Ted Unangst a08e0d0cb8 create a plain column and use that for search 2023-07-31 19:46:55 -04:00
Ted Unangst 22d448fa5f strings are hard 2023-07-30 21:31:53 -04:00
Ted Unangst 8387dd4400 mixed case hashtag complicates things a bit 2023-07-30 21:01:45 -04:00
Ted Unangst c44af76356 better presentation for readded invisible content 2023-07-30 20:39:31 -04:00
Ted Unangst c57a52a90c allow tagging outside of content 2023-07-30 20:31:00 -04:00
Ted Unangst d3bf2b7bc8 retarget mention links to local profile 2023-07-30 17:03:46 -04:00
Ted Unangst a8aa306af4 simplify junk.get code 2023-07-30 16:49:34 -04:00
Ted Unangst 035f23eec0 m 2023-07-30 13:11:50 -04:00
Ted Unangst bed7d662bb clean up the one or many arrays a little 2023-07-30 13:08:53 -04:00
Ted Unangst bd80e1b4a8 search precis too 2023-07-29 21:56:45 -04:00
Ted Unangst a7adc79f20 handle announce of update like announce of create 2023-07-29 16:13:19 -04:00
Ted Unangst 92b1c61dc1 handle the case where the tag is just an object 2023-07-29 15:04:11 -04:00
Ted Unangst d5a2c8694c ::: spoiler markdown support 2023-07-29 14:45:01 -04:00
Ted Unangst 2c92593553 be mindful style for summary applies only to our details field 2023-07-29 14:36:30 -04:00
Ted Unangst fde9187832 let's just say http 400 is okie dokie 2023-07-27 20:51:19 -04:00
Ted Unangst c19490a802 donks for days. multiple images with api, adapted from benjojo 2023-07-24 14:28:24 -04:00
Ted Unangst b688f24e6d webs 63 with the cookie fix 2023-07-22 16:37:07 -04:00
Ted Unangst 3c0bce83f6 try lazy loading imgs. 2023-07-20 17:38:24 -04:00
Ted Unangst 7728080855 try simpler emu css from yonle 2023-07-20 17:32:30 -04:00
Ted Unangst 6d47ef0129 check again for the announce/create/page activity 2023-07-19 18:09:12 -04:00
14 changed files with 336 additions and 121 deletions

View File

@ -132,64 +132,31 @@ var flightdeck = gate.NewSerializer()
var signGets = true
func junkGet(userid int64, url string, args junk.GetArgs) (junk.Junk, error) {
func GetJunkTimeout(userid int64, url string, timeout time.Duration) (junk.Junk, error) {
client := http.DefaultClient
if args.Client != nil {
client = args.Client
}
req, err := http.NewRequest("GET", url, nil)
if err != nil {
return nil, err
}
if args.Accept != "" {
req.Header.Set("Accept", args.Accept)
}
if args.Agent != "" {
req.Header.Set("User-Agent", args.Agent)
}
if signGets {
sign := func(req *http.Request) error {
var ki *KeyInfo
ok := ziggies.Get(userid, &ki)
if ok {
httpsig.SignRequest(ki.keyname, ki.seckey, req, nil)
}
return nil
}
if args.Timeout != 0 {
ctx, cancel := context.WithTimeout(context.Background(), args.Timeout)
defer cancel()
req = req.WithContext(ctx)
}
resp, err := client.Do(req)
if err != nil {
return nil, err
}
defer resp.Body.Close()
switch resp.StatusCode {
case 200:
case 201:
case 202:
default:
return nil, fmt.Errorf("http get status: %d", resp.StatusCode)
}
return junk.Read(resp.Body)
}
func GetJunkTimeout(userid int64, url string, timeout time.Duration) (junk.Junk, error) {
client := http.DefaultClient
if develMode {
client = develClient
sign = nil
}
fn := func() (interface{}, error) {
at := thefakename
if strings.Contains(url, ".well-known/webfinger?resource") {
at = "application/jrd+json"
}
j, err := junkGet(userid, url, junk.GetArgs{
j, err := junk.Get(url, junk.GetArgs{
Accept: at,
Agent: "honksnonk/5.0; " + serverName,
Timeout: timeout,
Client: client,
Fixup: sign,
})
return j, err
}
@ -348,10 +315,10 @@ func eradicatexonk(userid int64, xid string) {
xonk := getxonk(userid, xid)
if xonk != nil {
deletehonk(xonk.ID)
}
_, err := stmtSaveZonker.Exec(userid, xid, "zonk")
if err != nil {
elog.Printf("error eradicating: %s", err)
_, err := stmtSaveZonker.Exec(userid, xid, "zonk")
if err != nil {
elog.Printf("error eradicating: %s", err)
}
}
}
@ -468,19 +435,12 @@ func newphone(a []string, obj junk.Junk) []string {
}
func extractattrto(obj junk.Junk) string {
who, _ := obj.GetString("attributedTo")
if who != "" {
return who
}
o, ok := obj.GetMap("attributedTo")
if ok {
id, ok := o.GetString("id")
if ok {
return id
}
}
arr, _ := obj.GetArray("attributedTo")
arr := oneforall(obj, "attributedTo")
for _, a := range arr {
s, ok := a.(string)
if ok {
return s
}
o, ok := a.(junk.Junk)
if ok {
t, _ := o.GetString("type")
@ -489,14 +449,21 @@ func extractattrto(obj junk.Junk) string {
return id
}
}
s, ok := a.(string)
if ok {
return s
}
}
return ""
}
func oneforall(obj junk.Junk, key string) []interface{} {
if val, ok := obj.GetMap(key); ok {
return []interface{}{val}
}
if str, ok := obj.GetString(key); ok {
return []interface{}{str}
}
arr, _ := obj.GetArray(key)
return arr
}
func firstofmany(obj junk.Junk, key string) string {
if val, _ := obj.GetString(key); val != "" {
return val
@ -523,7 +490,7 @@ func xonksaver(user *WhatAbout, item junk.Junk, origin string) *Honk {
maxdepth := 10
currenttid := ""
goingup := 0
var xonkxonkfn func(item junk.Junk, origin string, isUpdate bool) *Honk
var xonkxonkfn func(junk.Junk, string, bool, bool) *Honk
qutify := func(user *WhatAbout, content string) string {
if depth >= maxdepth {
@ -555,7 +522,7 @@ func xonksaver(user *WhatAbout, item junk.Junk, origin string) *Honk {
}
prevdepth := depth
depth = maxdepth
xonkxonkfn(j, originate(m), false)
xonkxonkfn(j, originate(m), false, false)
depth = prevdepth
}
}
@ -574,18 +541,22 @@ func xonksaver(user *WhatAbout, item junk.Junk, origin string) *Honk {
ilog.Printf("error getting onemore: %s: %s", xid, err)
return
}
depth++
xonkxonkfn(obj, originate(xid), false)
depth--
xonkxonkfn(obj, originate(xid), false, false)
}
xonkxonkfn = func(item junk.Junk, origin string, isUpdate bool) *Honk {
xonkxonkfn = func(item junk.Junk, origin string, isUpdate bool, isAnnounce bool) *Honk {
id, _ := item.GetString("id")
what := firstofmany(item, "type")
dt, ok := item.GetString("published")
if !ok {
dt = time.Now().Format(time.RFC3339)
}
if depth >= maxdepth+5 {
ilog.Printf("went too deep in xonkxonk")
return nil
}
depth++
defer func() { depth-- }()
var err error
var xid, rid, url, convoy string
@ -631,19 +602,26 @@ func xonksaver(user *WhatAbout, item junk.Junk, origin string) *Honk {
case "Announce":
obj, ok = item.GetMap("object")
if ok {
// peek ahead some
what, ok := obj.GetString("type")
if ok && what == "Create" {
obj, ok = obj.GetMap("object")
if !ok {
ilog.Printf("lost object inside create %s", id)
return nil
if ok && (what == "Create" || what == "Update") {
if what == "Update" {
isUpdate = true
}
inner, ok := obj.GetMap("object")
if ok {
obj = inner
} else {
xid, _ = obj.GetString("object")
}
}
xid, _ = obj.GetString("id")
if xid == "" {
xid, _ = obj.GetString("id")
}
} else {
xid, _ = item.GetString("object")
}
if !needbonkid(user, xid) {
if !isUpdate && !needbonkid(user, xid) {
return nil
}
origin = originate(xid)
@ -656,7 +634,7 @@ func xonksaver(user *WhatAbout, item junk.Junk, origin string) *Honk {
ilog.Printf("error getting bonk: %s: %s", xid, err)
}
}
what = "bonk"
return xonkxonkfn(obj, origin, isUpdate, true)
case "Update":
isUpdate = true
fallthrough
@ -678,7 +656,7 @@ func xonksaver(user *WhatAbout, item junk.Junk, origin string) *Honk {
ilog.Printf("no object for creation %s", id)
return nil
}
return xonkxonkfn(obj, origin, isUpdate)
return xonkxonkfn(obj, origin, isUpdate, isAnnounce)
case "Read":
xid, ok = item.GetString("object")
if ok {
@ -691,7 +669,7 @@ func xonksaver(user *WhatAbout, item junk.Junk, origin string) *Honk {
ilog.Printf("error getting read: %s", err)
return nil
}
return xonkxonkfn(obj, originate(xid), false)
return xonkxonkfn(obj, originate(xid), false, false)
}
return nil
case "Add":
@ -707,7 +685,7 @@ func xonksaver(user *WhatAbout, item junk.Junk, origin string) *Honk {
ilog.Printf("error getting add: %s", err)
return nil
}
return xonkxonkfn(obj, originate(xid), false)
return xonkxonkfn(obj, originate(xid), false, false)
}
return nil
case "Move":
@ -736,6 +714,7 @@ func xonksaver(user *WhatAbout, item junk.Junk, origin string) *Honk {
obj = item
what = "event"
case "ChatMessage":
isAnnounce = false
obj = item
what = "chonk"
default:
@ -743,6 +722,9 @@ func xonksaver(user *WhatAbout, item junk.Junk, origin string) *Honk {
dumpactivity(item)
return nil
}
if isAnnounce {
what = "bonk"
}
if obj != nil {
xid, _ = obj.GetString("id")
@ -950,7 +932,7 @@ func xonksaver(user *WhatAbout, item junk.Junk, origin string) *Honk {
}
}
if !preferorig {
atts, _ := obj.GetArray("attachment")
atts := oneforall(obj, "attachment")
for _, atti := range atts {
att, ok := atti.(junk.Junk)
if !ok {
@ -959,16 +941,8 @@ func xonksaver(user *WhatAbout, item junk.Junk, origin string) *Honk {
}
procatt(att)
}
if att, ok := obj.GetMap("attachment"); ok {
procatt(att)
}
}
tags, _ := obj.GetArray("tag")
for _, tagi := range tags {
tag, ok := tagi.(junk.Junk)
if !ok {
continue
}
proctag := func(tag junk.Junk) {
tt, _ := tag.GetString("type")
name, _ := tag.GetString("name")
desc, _ := tag.GetString("summary")
@ -1013,6 +987,14 @@ func xonksaver(user *WhatAbout, item junk.Junk, origin string) *Honk {
mentions = append(mentions, m)
}
}
tags := oneforall(obj, "tag")
for _, tagi := range tags {
tag, ok := tagi.(junk.Junk)
if !ok {
continue
}
proctag(tag)
}
if starttime, ok := obj.GetString("startTime"); ok {
if start, err := time.Parse(time.RFC3339, starttime); err == nil {
t := new(Time)
@ -1079,11 +1061,15 @@ func xonksaver(user *WhatAbout, item junk.Junk, origin string) *Honk {
imaginate(&xonk)
if what == "chonk" {
target, _ := obj.GetString("to")
if target == user.URL {
target = xonk.Honker
}
ch := Chonk{
UserID: xonk.UserID,
XID: xid,
Who: xonk.Honker,
Target: xonk.Honker,
Target: target,
Date: xonk.Date,
Noise: xonk.Noise,
Format: xonk.Format,
@ -1139,7 +1125,7 @@ func xonksaver(user *WhatAbout, item junk.Junk, origin string) *Honk {
return &xonk
}
return xonkxonkfn(item, origin, false)
return xonkxonkfn(item, origin, false, false)
}
func dumpactivity(item junk.Junk) {
@ -1267,6 +1253,7 @@ func jonkjonk(user *WhatAbout, h *Honk) (junk.Junk, junk.Junk) {
if !h.Public {
jo["directMessage"] = true
}
h.Noise = re_retag.ReplaceAllString(h.Noise, "")
translate(h)
redoimages(h)
if h.Precis != "" {

View File

@ -30,6 +30,7 @@ import (
"time"
"humungus.tedunangst.com/r/webs/cache"
"humungus.tedunangst.com/r/webs/htfilter"
"humungus.tedunangst.com/r/webs/httpsig"
"humungus.tedunangst.com/r/webs/login"
"humungus.tedunangst.com/r/webs/mz"
@ -342,7 +343,7 @@ func gethonksbysearch(userid int64, q string, wanted int64) []*Honk {
continue
}
t = "%" + t + "%"
queries = append(queries, "noise"+negate+"like ?")
queries = append(queries, negate+"(plain like ?)")
params = append(params, t)
}
@ -788,6 +789,30 @@ func loadchatter(userid int64) []*Chatter {
return chatter
}
func (honk *Honk) Plain() string {
var plain []string
var filt htfilter.Filter
filt.WithLinks = true
if honk.Precis != "" {
t, _ := filt.TextOnly(honk.Precis)
plain = append(plain, t)
}
if honk.Format == "html" {
t, _ := filt.TextOnly(honk.Noise)
plain = append(plain, t)
} else {
plain = append(plain, honk.Noise)
}
for _, d := range honk.Donks {
plain = append(plain, d.Name)
plain = append(plain, d.Desc)
}
for _, o := range honk.Onts {
plain = append(plain, o)
}
return strings.Join(plain, " ")
}
func savehonk(h *Honk) error {
dt := h.Date.UTC().Format(dbtimeformat)
aud := strings.Join(h.Audience, " ")
@ -798,10 +823,11 @@ func savehonk(h *Honk) error {
elog.Printf("can't begin tx: %s", err)
return err
}
plain := h.Plain()
res, err := tx.Stmt(stmtSaveHonk).Exec(h.UserID, h.What, h.Honker, h.XID, h.RID, dt, h.URL,
aud, h.Noise, h.Convoy, h.Whofore, h.Format, h.Precis,
h.Oonker, h.Flags)
h.Oonker, h.Flags, plain)
if err == nil {
h.ID, _ = res.LastInsertId()
err = saveextras(tx, h)
@ -832,10 +858,11 @@ func updatehonk(h *Honk) error {
elog.Printf("can't begin tx: %s", err)
return err
}
plain := h.Plain()
err = deleteextras(tx, h.ID, false)
if err == nil {
_, err = tx.Stmt(stmtUpdateHonk).Exec(h.Precis, h.Noise, h.Format, h.Whofore, dt, h.ID)
_, err = tx.Stmt(stmtUpdateHonk).Exec(h.Precis, h.Noise, h.Format, h.Whofore, dt, plain, h.ID)
}
if err == nil {
err = saveextras(tx, h)
@ -1170,9 +1197,9 @@ func prepareStatements(db *sql.DB) {
stmtDeleteAllMeta = preparetodie(db, "delete from honkmeta where honkid = ?")
stmtDeleteSomeMeta = preparetodie(db, "delete from honkmeta where honkid = ? and genus not in ('oldrev')")
stmtDeleteOneMeta = preparetodie(db, "delete from honkmeta where honkid = ? and genus = ?")
stmtSaveHonk = preparetodie(db, "insert into honks (userid, what, honker, xid, rid, dt, url, audience, noise, convoy, whofore, format, precis, oonker, flags) values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)")
stmtSaveHonk = preparetodie(db, "insert into honks (userid, what, honker, xid, rid, dt, url, audience, noise, convoy, whofore, format, precis, oonker, flags, plain) values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)")
stmtDeleteHonk = preparetodie(db, "delete from honks where honkid = ?")
stmtUpdateHonk = preparetodie(db, "update honks set precis = ?, noise = ?, format = ?, whofore = ?, dt = ? where honkid = ?")
stmtUpdateHonk = preparetodie(db, "update honks set precis = ?, noise = ?, format = ?, whofore = ?, dt = ?, plain = ? where honkid = ?")
stmtSaveOnt = preparetodie(db, "insert into onts (ontology, honkid) values (?, ?)")
stmtDeleteOnts = preparetodie(db, "delete from onts where honkid = ?")
stmtSaveDonk = preparetodie(db, "insert into donks (honkid, chonkid, fileid) values (?, ?, ?)")

View File

@ -69,6 +69,14 @@ func lethaldose(err error) int64 {
return 0
}
func letitslide(err error) bool {
str := err.Error()
if strings.Contains(str, "http post status: 400") {
return true
}
return false
}
var dqmtx sync.Mutex
func delinquent(userid int64, rcpt string, msg []byte) bool {
@ -144,6 +152,10 @@ func deliveration(doover Doover) {
if t := lethaldose(err); t > doover.Tries {
doover.Tries = t
}
if letitslide(err) {
dlog.Printf("whatever myever %s", inbox)
continue
}
doover.Msgs = doover.Msgs[i:]
sayitagain(doover)
return

View File

@ -2,6 +2,14 @@ changelog
=== next
+ More reliable search.
+ Secret tags.
+ Mention links locally.
+ ::: spoiler markdown
+ New threaded display order.
+ Improved search.

View File

@ -70,6 +70,13 @@ will be autolinked.
Exactly three dashes on a line,
.Dq --- ,
will become a horizontal rule.
.It spoilers
Hide blocks of text between triple colon delimted regions.
.Bd -literal
::: warning
text that should be hidden behind a warning
:::
.Ed
.El
.Pp
If the first line of a honk begins with

51
fun.go
View File

@ -82,6 +82,7 @@ func reverbolate(userid int64, honks []*Honk) {
local = true
}
if local && h.What != "bonked" {
h.Noise = re_retag.ReplaceAllString(h.Noise, "")
h.Noise = re_memes.ReplaceAllString(h.Noise, "")
}
h.Username, h.Handle = handles(h.Honker)
@ -124,11 +125,27 @@ func reverbolate(userid int64, honks []*Honk) {
h.Precis = demoji(h.Precis)
h.Noise = demoji(h.Noise)
h.Open = "open"
var misto string
for _, m := range h.Mentions {
if m.Where != h.Honker && !m.IsPresent(h.Noise) {
h.Noise = "(" + m.Who + ")" + h.Noise
misto += " " + m.Who
}
}
var mistag string
for _, o := range h.Onts {
if !OntIsPresent(o, h.Noise) {
mistag += " " + o
}
}
if len(misto) > 0 || len(mistag) > 0 {
if len(misto) > 0 {
misto = "(" + misto[1:] + ")<p>"
}
if len(mistag) > 0 {
mistag = "<p>(" + mistag[1:] + ")"
}
h.Noise = misto + h.Noise + mistag
}
zap := make(map[string]bool)
{
@ -159,6 +176,17 @@ func reverbolate(userid int64, honks []*Honk) {
data = re_emus.ReplaceAllStringFunc(data, emuxifier)
io.WriteString(w, data)
}
if user != nil {
htf.RetargetLink = func(href string) string {
h2 := strings.ReplaceAll(href, "/@", "/users/")
for _, m := range h.Mentions {
if h2 == m.Where || href == m.Where {
return "/h?xid=" + url.QueryEscape(m.Where)
}
}
return href
}
}
p, _ := htf.String(h.Precis)
n, _ := htf.String(h.Noise)
h.Precis = string(p)
@ -319,7 +347,7 @@ func translate(honk *Honk) {
noise = strings.TrimSpace(noise)
noise = marker.Mark(noise)
honk.Noise = noise
honk.Onts = oneofakind(marker.HashTags)
honk.Onts = oneofakind(append(honk.Onts, marker.HashTags...))
honk.Mentions = bunchofgrapes(marker.Mentions)
}
@ -428,6 +456,7 @@ 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_retag = regexp.MustCompile("tags: ?([^\n]+)")
var re_convalidate = regexp.MustCompile("^(https?|tag|data):")
func memetize(honk *Honk) {
@ -465,6 +494,24 @@ func memetize(honk *Honk) {
honk.Noise = re_memes.ReplaceAllStringFunc(honk.Noise, repl)
}
func recategorize(honk *Honk) {
repl := func(x string) string {
x = x[5:]
for _, t := range strings.Split(x, " ") {
if t == "" {
continue
}
if t[0] != '#' {
t = "#" + t
}
dlog.Printf("hashtag: %s", t)
honk.Onts = append(honk.Onts, t)
}
return ""
}
honk.Noise = re_retag.ReplaceAllStringFunc(honk.Noise, repl)
}
var re_quickmention = regexp.MustCompile("(^|[ \n])@[[:alnum:]_]+([ \n:;.,']|$)")
func quickrename(s string, userid int64) string {

2
go.mod
View File

@ -9,5 +9,5 @@ require (
golang.org/x/crypto v0.0.0-20220411220226-7b82a4e95df4
golang.org/x/net v0.0.0-20220425223048-2871e0cb64e4
humungus.tedunangst.com/r/go-sqlite3 v1.1.3
humungus.tedunangst.com/r/webs v0.6.62
humungus.tedunangst.com/r/webs v0.6.67
)

4
go.sum
View File

@ -25,5 +25,5 @@ golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
humungus.tedunangst.com/r/go-sqlite3 v1.1.3 h1:G2N4wzDS0NbuvrZtQJhh4F+3X+s7BF8b9ga8k38geUI=
humungus.tedunangst.com/r/go-sqlite3 v1.1.3/go.mod h1:FtEEmQM7U2Ey1TuEEOyY1BmphTZnmiEjPsNLEAkpf/M=
humungus.tedunangst.com/r/webs v0.6.62 h1:T/T0a2xWw1cYKTMqKXwP4GStRPUfOWYytN9zCMMlqpA=
humungus.tedunangst.com/r/webs v0.6.62/go.mod h1:03R0N9BcT49HB4TDd1YmarpbiPvPzVDm74Mk4h1hYPc=
humungus.tedunangst.com/r/webs v0.6.67 h1:OO5UkQa+bHeiIrZ5IGR9JGtgGPsKsYlRJEVk1bSt+Qo=
humungus.tedunangst.com/r/webs v0.6.67/go.mod h1:03R0N9BcT49HB4TDd1YmarpbiPvPzVDm74Mk4h1hYPc=

41
honk.go
View File

@ -144,6 +144,31 @@ func (mention *Mention) IsPresent(noise string) bool {
return strings.Contains(noise, ">@"+nick) || strings.Contains(noise, "@<span>"+nick)
}
func OntIsPresent(ont, noise string) bool {
ont = strings.ToLower(ont[1:])
idx := strings.IndexByte(noise, '#')
for idx >= 0 {
if strings.HasPrefix(noise[idx:], "#<span>") {
idx += 6
}
idx += 1
if idx+len(ont) >= len(noise) {
return false
}
test := noise[idx : idx+len(ont)]
test = strings.ToLower(test)
if test == ont {
return true
}
newidx := strings.IndexByte(noise[idx:], '#')
if newidx == -1 {
return false
}
idx += newidx
}
return false
}
type OldRevision struct {
Precis string
Noise string
@ -408,6 +433,22 @@ func main() {
return
}
unfollowyou(user, honkerid, true)
case "sendmsg":
if len(args) < 4 {
fmt.Printf("usage: honk send username filename rcpt\n")
return
}
user, err := butwhatabout(args[1])
if err != nil {
fmt.Printf("user not found\n")
return
}
data, err := os.ReadFile(args[2])
if err != nil {
fmt.Printf("can't read file\n")
return
}
deliverate(user.ID, args[3], data)
case "cleanup":
arg := "30"
if len(args) > 1 {

View File

@ -1,5 +1,4 @@
create table honks (honkid integer primary key, userid integer, what text, honker text, xid text, rid text, dt text, url text, audience text, noise text, convoy text, whofore integer, format text, precis text, oonker text, flags integer);
create table honks (honkid integer primary key, userid integer, what text, honker text, xid text, rid text, dt text, url text, audience text, noise text, convoy text, whofore integer, format text, precis text, oonker text, flags integer, plain text);
create table chonks (chonkid integer primary key, userid integer, xid text, who txt, target text, dt text, noise text, format text);
create table donks (honkid integer, chonkid integer, fileid integer);
create table filemeta (fileid integer primary key, xid text, name text, description text, url text, media text, local integer);

View File

@ -18,9 +18,12 @@ package main
import (
"database/sql"
"os"
"strings"
"humungus.tedunangst.com/r/webs/htfilter"
)
var myVersion = 43
var myVersion = 45
type dbexecer interface {
Exec(query string, args ...interface{}) (sql.Result, error)
@ -42,6 +45,22 @@ func upgradedb() {
if dbversion < 40 {
elog.Fatal("database is too old to upgrade")
}
var err error
var tx *sql.Tx
try := func(s string, args ...interface{}) {
if tx != nil {
_, err = tx.Exec(s, args...)
} else {
_, err = db.Exec(s, args...)
}
if err != nil {
elog.Fatalf("can't run %s: %s", s, err)
}
}
setV := func(ver int64) {
try("update config set value = ? where key = 'dbversion'", ver)
}
switch dbversion {
case 40:
doordie(db, "PRAGMA journal_mode=WAL")
@ -87,6 +106,72 @@ func upgradedb() {
doordie(db, "update config set value = 43 where key = 'dbversion'")
fallthrough
case 43:
try("alter table honks add column plain text")
try("update honks set plain = ''")
setV(44)
fallthrough
case 44:
makeplain := func(noise, precis, format string) []string {
var plain []string
var filt htfilter.Filter
filt.WithLinks = true
if precis != "" {
t, _ := filt.TextOnly(precis)
plain = append(plain, t)
}
if format == "html" {
t, _ := filt.TextOnly(noise)
plain = append(plain, t)
} else {
plain = append(plain, noise)
}
return plain
}
tx, err = db.Begin()
if err != nil {
elog.Fatal(err)
}
plainmap := make(map[int64][]string)
rows, err := tx.Query("select honkid, noise, precis, format from honks")
if err != nil {
elog.Fatal(err)
}
for rows.Next() {
var honkid int64
var noise, precis, format string
err = rows.Scan(&honkid, &noise, &precis, &format)
if err != nil {
elog.Fatal(err)
}
plainmap[honkid] = makeplain(noise, precis, format)
}
rows.Close()
rows, err = tx.Query("select honkid, name, description from donks join filemeta on donks.fileid = filemeta.fileid")
if err != nil {
elog.Fatal(err)
}
for rows.Next() {
var honkid int64
var name, desc string
err = rows.Scan(&honkid, &name, &desc)
if err != nil {
elog.Fatal(err)
}
plainmap[honkid] = append(plainmap[honkid], name)
plainmap[honkid] = append(plainmap[honkid], desc)
}
rows.Close()
for honkid, plain := range plainmap {
try("update honks set plain = ? where honkid = ?", strings.Join(plain, " "), honkid)
}
setV(45)
err = tx.Commit()
if err != nil {
elog.Fatal(err)
}
tx = nil
fallthrough
case 45:
default:
elog.Fatalf("can't upgrade unknown version %d", dbversion)

View File

@ -52,7 +52,7 @@ in reply to: <a href="{{ .RID }}" rel=noreferrer>{{ .RID }}</a>
</header>
<p>
<details class="noise" {{ .Open }} >
<summary>{{ .HTPrecis }}<p></summary>
<summary class="noise">{{ .HTPrecis }}<p></summary>
<p>{{ .HTPrecis }}
<p class="content">{{ .HTML }}
{{ with .Time }}
@ -72,7 +72,7 @@ in reply to: <a href="{{ .RID }}" rel=noreferrer>{{ .RID }}</a>
{{ if $omitimages }}
<p><a href="/d/{{ .XID }}">Image: {{ .Name }}</a>{{ if not (eq .Desc .Name) }} {{ .Desc }}{{ end }}
{{ else }}
<p><img src="/d/{{ .XID }}" title="{{ .Desc }}" alt="{{ .Desc }}">
<p><img src="/d/{{ .XID }}" loading=lazy title="{{ .Desc }}" alt="{{ .Desc }}">
{{ end }}
{{ end }}
{{ else }}

View File

@ -309,7 +309,7 @@ input[type=file] {
.limited details.actions summary {
color: var(--fg-limited);
}
details.noise[open] summary {
details.noise[open] summary.noise {
display: none;
}
h1, h2 {
@ -330,10 +330,8 @@ img, video {
display: block;
}
img.emu {
width: 2em;
height: 2em;
vertical-align: middle;
margin: -2px;
object-fit: contain;
}
.nophone {

34
web.go
View File

@ -1743,6 +1743,7 @@ func submithonk(w http.ResponseWriter, r *http.Request) *Honk {
honk.Noise = noise
precipitate(honk)
noise = honk.Noise
recategorize(honk)
translate(honk)
if rid != "" {
@ -1801,20 +1802,22 @@ func submithonk(w http.ResponseWriter, r *http.Request) *Honk {
donkxid = fmt.Sprintf("%s:%d", d.XID, d.FileID)
}
} else {
p := strings.Split(donkxid, ":")
xid := p[0]
url := fmt.Sprintf("https://%s/d/%s", serverName, xid)
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 {
ilog.Printf("can't find file: %s", xid)
for _, xid := range r.Form["donkxid"] {
p := strings.Split(xid, ":")
xid = p[0]
url := fmt.Sprintf("https://%s/d/%s", serverName, xid)
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 {
ilog.Printf("can't find file: %s", xid)
}
}
}
memetize(honk)
@ -2490,7 +2493,8 @@ func apihandler(w http.ResponseWriter, r *http.Request) {
http.Error(w, "missing donk", http.StatusBadRequest)
return
}
w.Write([]byte(d.XID))
donkxid := fmt.Sprintf("%s:%d", d.XID, d.FileID)
w.Write([]byte(donkxid))
case "zonkit":
zonkit(w, r)
case "gethonks":