diff --git a/activity.go b/activity.go index 5d1ce94..d94f304 100644 --- a/activity.go +++ b/activity.go @@ -607,6 +607,9 @@ func xonksaver(user *WhatAbout, item junk.Junk, origin string) *Honk { case "Event": obj = item what = "event" + case "ChatMessage": + obj = item + what = "chonk" default: log.Printf("unknown activity: %s", what) dumpactivity(item) @@ -876,6 +879,20 @@ func xonksaver(user *WhatAbout, item junk.Junk, origin string) *Honk { } imaginate(&xonk) + if what == "chonk" { + ch := Chonk{ + UserID: xonk.UserID, + XID: xid, + Who: xonk.Honker, + Target: xonk.Honker, + Date: xonk.Date, + Noise: xonk.Noise, + Format: xonk.Format, + } + savechonk(&ch) + return nil + } + if isUpdate { log.Printf("something has changed! %s", xonk.XID) prev := getxonk(user.ID, xonk.XID) @@ -1246,6 +1263,35 @@ func boxuprcpts(user *WhatAbout, addresses []string, useshared bool) map[string] return rcpts } +func sendchonk(user *WhatAbout, ch *Chonk) { + dt := ch.Date.Format(time.RFC3339) + aud := []string{ch.Target} + + jo := junk.New() + jo["id"] = ch.XID + jo["type"] = "ChatMessage" + jo["published"] = dt + jo["attributedTo"] = user.URL + jo["to"] = aud + jo["content"] = ch.Noise + + j := junk.New() + j["@context"] = itiswhatitis + j["id"] = user.URL + "/" + "honk" + "/" + shortxid(ch.XID) + j["type"] = "Create" + j["actor"] = user.URL + j["published"] = dt + j["to"] = aud + j["object"] = jo + + msg := j.ToBytes() + rcpts := make(map[string]bool) + rcpts[ch.Target] = true + for a := range rcpts { + go deliverate(0, user.ID, a, msg) + } +} + func honkworldwide(user *WhatAbout, honk *Honk) { jonk, _ := jonkjonk(user, honk) jonk["@context"] = itiswhatitis diff --git a/database.go b/database.go index 5648699..149b860 100644 --- a/database.go +++ b/database.go @@ -482,6 +482,37 @@ func finddonk(url string) *Donk { return nil } +func savechonk(ch *Chonk) error { + dt := ch.Date.UTC().Format(dbtimeformat) + res, err := stmtSaveChonk.Exec(ch.UserID, ch.XID, ch.Who, ch.Target, dt, ch.Noise, ch.Format) + if err == nil { + ch.ID, _ = res.LastInsertId() + } + return err +} + +func loadchatter(userid int64) map[string][]*Chonk { + rows, err := stmtLoadChonks.Query(userid) + if err != nil { + log.Printf("error loading chonks: %s", err) + return nil + } + defer rows.Close() + chonks := make(map[string][]*Chonk) + for rows.Next() { + ch := new(Chonk) + var dt string + err = rows.Scan(&ch.ID, &ch.UserID, &ch.XID, &ch.Who, &ch.Target, &dt, &ch.Noise, &ch.Format) + if err != nil { + log.Printf("error scanning chonk: %s", err) + continue + } + ch.Date, _ = time.Parse(dbtimeformat, dt) + chonks[ch.Target] = append(chonks[ch.Target], ch) + } + return chonks +} + func savehonk(h *Honk) error { dt := h.Date.UTC().Format(dbtimeformat) aud := strings.Join(h.Audience, " ") @@ -739,6 +770,7 @@ var stmtHonksForUserFirstClass *sql.Stmt var stmtSaveMeta, stmtDeleteAllMeta, stmtDeleteSomeMeta, stmtUpdateHonk *sql.Stmt var stmtHonksISaved, stmtGetFilters, stmtSaveFilter, stmtDeleteFilter *sql.Stmt var stmtGetTracks *sql.Stmt +var stmtSaveChonk, stmtLoadChonks *sql.Stmt func preparetodie(db *sql.DB, s string) *sql.Stmt { stmt, err := db.Prepare(s) @@ -816,4 +848,6 @@ func prepareStatements(db *sql.DB) { stmtSaveFilter = preparetodie(db, "insert into hfcs (userid, json) values (?, ?)") stmtDeleteFilter = preparetodie(db, "delete from hfcs where userid = ? and hfcsid = ?") stmtGetTracks = preparetodie(db, "select fetches from tracks where xid = ?") + stmtSaveChonk = preparetodie(db, "insert into chonks (userid, xid, who, target, dt, noise, format) values (?, ?, ?, ?, ?, ?, ?)") + stmtLoadChonks = preparetodie(db, "select chonkid, userid, xid, who, target, dt, noise, format from chonks where userid = ?") } diff --git a/docs/changelog.txt b/docs/changelog.txt index c2dae03..b6f4aa8 100644 --- a/docs/changelog.txt +++ b/docs/changelog.txt @@ -2,6 +2,8 @@ changelog === next +++ Boing boom tschak chonky chatter. + + Quote unquote reliability improvements. + Much better omit images handling. diff --git a/fun.go b/fun.go index 40ba38e..489adb5 100644 --- a/fun.go +++ b/fun.go @@ -178,6 +178,23 @@ func replaceimgsand(zap map[string]bool, absolute bool) func(node *html.Node) st } } +func filterchonk(ch *Chonk) { + var htf htfilter.Filter + htf.SpanClasses = allowedclasses + htf.BaseURL, _ = url.Parse(ch.XID) + ch.HTML, _ = htf.String(ch.Noise) + n := string(ch.HTML) + if strings.HasPrefix(n, "

") { + ch.HTML = template.HTML(n[3:]) + } + if short := shortname(ch.UserID, ch.Who); short != "" { + ch.Handle = short + } else { + _, ch.Handle = handles(ch.Who) + } + +} + func inlineimgsfor(honk *Honk) func(node *html.Node) string { return func(node *html.Node) string { src := htfilter.GetAttr(node, "src") diff --git a/honk.go b/honk.go index cad4862..7a454a0 100644 --- a/honk.go +++ b/honk.go @@ -94,6 +94,19 @@ type Honk struct { Mentions []Mention } +type Chonk struct { + ID int64 + UserID int64 + XID string + Who string + Target string + Date time.Time + Noise string + Format string + Handle string + HTML template.HTML +} + type Mention struct { Who string Where string diff --git a/schema.go b/schema.go index 1d430bd..d27b15f 100644 --- a/schema.go +++ b/schema.go @@ -3,6 +3,7 @@ package main var sqlSchema = ` 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 chonks (chonkid integer primary key, userid integer, xid text, who txt, target text, dt text, noise text, format text); create table donks (honkid integer, fileid integer); create table filemeta (fileid integer primary key, xid text, name text, description text, url text, media text, local integer); create table honkers (honkerid integer primary key, userid integer, name text, xid text, flavor text, combos text, owner text, meta text); diff --git a/schema.sql b/schema.sql index 8f501fd..f46f9a8 100644 --- a/schema.sql +++ b/schema.sql @@ -1,5 +1,6 @@ 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 chonks (chonkid integer primary key, userid integer, xid text, who txt, target text, dt text, noise text, format text); create table donks (honkid integer, fileid integer); create table filemeta (fileid integer primary key, xid text, name text, description text, url text, media text, local integer); create table honkers (honkerid integer primary key, userid integer, name text, xid text, flavor text, combos text, owner text, meta text); diff --git a/upgradedb.go b/upgradedb.go index 7026d0b..7db913a 100644 --- a/upgradedb.go +++ b/upgradedb.go @@ -24,7 +24,7 @@ import ( "time" ) -var myVersion = 34 +var myVersion = 35 func doordie(db *sql.DB, s string, args ...interface{}) { _, err := db.Exec(s, args...) @@ -366,6 +366,10 @@ func upgradedb() { doordie(db, "update config set value = 34 where key = 'dbversion'") fallthrough case 34: + doordie(db, "create table chonks (chonkid integer primary key, userid integer, xid text, who txt, target text, dt text, noise text, format text)") + doordie(db, "update config set value = 35 where key = 'dbversion'") + fallthrough + case 35: default: log.Fatalf("can't upgrade unknown version %d", dbversion) diff --git a/views/header.html b/views/header.html index b60df7d..3f07332 100644 --- a/views/header.html +++ b/views/header.html @@ -31,13 +31,13 @@ {{ end }} +

  • chatter
  • tags
  • events
  • saved
  • honkers
  • filters
  • my honks -
  • xzone
  • account
  • @@ -46,6 +46,7 @@
  • about
  • front
  • funzone +
  • xzone
  • help diff --git a/web.go b/web.go index 7cda832..3109d83 100644 --- a/web.go +++ b/web.go @@ -1770,6 +1770,56 @@ func showhonkers(w http.ResponseWriter, r *http.Request) { } } +func showchatter(w http.ResponseWriter, r *http.Request) { + u := login.GetUserInfo(r) + chatter := loadchatter(u.UserID) + for _, chonks := range chatter { + for _, ch := range chonks { + filterchonk(ch) + } + } + + templinfo := getInfo(r) + templinfo["Chatter"] = chatter + templinfo["ChonkCSRF"] = login.GetCSRF("sendchonk", r) + err := readviews.Execute(w, "chatter.html", templinfo) + if err != nil { + log.Print(err) + } +} + +func submitchonk(w http.ResponseWriter, r *http.Request) { + u := login.GetUserInfo(r) + user, _ := butwhatabout(u.Username) + noise := r.FormValue("noise") + target := r.FormValue("target") + format := "markdown" + dt := time.Now().UTC() + xid := fmt.Sprintf("%s/%s/%s", user.URL, "chonk", xfiltrate()) + + if !strings.HasPrefix(target, "https://") { + target = fullname(target, u.UserID) + } + if target == "" { + http.Error(w, "who is that?", http.StatusInternalServerError) + return + } + + ch := Chonk{ + UserID: u.UserID, + XID: xid, + Who: user.URL, + Target: target, + Date: dt, + Noise: noise, + Format: format, + } + savechonk(&ch) + go sendchonk(user, &ch) + + http.Redirect(w, r, "/chatter", http.StatusSeeOther) +} + var combocache = cache.New(cache.Options{Filler: func(userid int64) ([]string, bool) { honkers := gethonkers(userid) var combos []string @@ -2361,6 +2411,7 @@ func serve() { viewDir+"/views/honkpage.html", viewDir+"/views/honkfrags.html", viewDir+"/views/honkers.html", + viewDir+"/views/chatter.html", viewDir+"/views/hfcs.html", viewDir+"/views/combos.html", viewDir+"/views/honkform.html", @@ -2435,6 +2486,8 @@ func serve() { loggedin := mux.NewRoute().Subrouter() loggedin.Use(login.Required) loggedin.HandleFunc("/first", homepage) + loggedin.HandleFunc("/chatter", showchatter) + loggedin.Handle("/sendchonk", login.CSRFWrap("sendchonk", http.HandlerFunc(submitchonk))) loggedin.HandleFunc("/saved", homepage) loggedin.HandleFunc("/account", accountpage) loggedin.HandleFunc("/funzone", showfunzone)