aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFChannel <>2021-07-23 22:45:44 -0700
committerFChannel <>2021-07-23 22:45:44 -0700
commit8f7386f2906716d40099fb50f029d48796dd1bbd (patch)
tree790b290434220a94e384eb8970d26dea1967e6f9
parentc5eff11c39d0a07f5cb7401835d04ba4df9edcbf (diff)
added cross post support. could blow up if referencing a link that is not local to the database or cache.
-rw-r--r--client.go209
-rw-r--r--database.go12
-rw-r--r--main.go61
-rw-r--r--outboxPost.go2
-rw-r--r--static/posts.html4
5 files changed, 205 insertions, 83 deletions
diff --git a/client.go b/client.go
index 002fc40..4f2fd70 100644
--- a/client.go
+++ b/client.go
@@ -638,78 +638,6 @@ func MediaProxy(url string) string {
return "/api/media?hash=" + HashMedia(url)
}
-func ParseContent(db *sql.DB, board Actor, op string, content string, thread ObjectBase) template.HTML {
- var nContent = content
-
- re := regexp.MustCompile(`(>>https?://[A-Za-z0-9_.:\-~]+\/[A-Za-z0-9_.\-~]+\/\w+)`)
- match := re.FindAllStringSubmatch(nContent, -1)
-
- //add url to each matched reply
- for i, _ := range match {
- link := strings.Replace(match[i][0], ">>", "", 1)
- isOP := ""
-
- if link == op {
- isOP = " (OP)"
- }
-
- //formate the hover title text
- var quoteTitle string
-
- // if the quoted content is local get it
- // else get it from the database
- if thread.Id == link {
- quoteTitle = thread.Content
- } else {
- for _, e := range thread.Replies.OrderedItems {
- if e.Id == link {
- quoteTitle = e.Content
- break
- }
- }
-
- if quoteTitle == "" {
- obj := GetObjectFromDBFromID(db, link)
- if len(obj.OrderedItems) > 0 {
- quoteTitle = obj.OrderedItems[0].Content
- }
- }
- }
-
- quoteTitle = strings.ReplaceAll(quoteTitle, ">", `/\&lt;`)
- quoteTitle = strings.ReplaceAll(quoteTitle, "\"", "")
- quoteTitle = strings.ReplaceAll(quoteTitle, "'", "")
-
-
- var style string
- if board.Restricted {
- style = "color: #af0a0f;"
- }
-
- //replace link with quote format
- nContent = strings.Replace(nContent, match[i][0], "<a class=\"reply\" style=\"" + style + "\" title=\"" + quoteTitle + "\" href=\"/" + board.Name + "/" + shortURL(board.Outbox, op) + "#" + shortURL(board.Outbox, link) + "\"> &gt;&gt;" + shortURL(board.Outbox, link) + isOP + "</a>", -1)
- }
-
- // replace quotes
- re = regexp.MustCompile(`((\r\n|^)>(.+)?[^\r\n])`)
- match = re.FindAllStringSubmatch(nContent, -1)
-
- for i, _ := range match {
- quote := strings.Replace(match[i][0], ">", "&gt;", 1)
- line := re.ReplaceAllString(match[i][0], "<span class=\"quote\">" + quote + "</span>")
- nContent = strings.Replace(nContent, match[i][0], line, 1)
- }
-
- //replace isolated greater than symboles
- re = regexp.MustCompile(`(\r\n)>`)
-
- nContent = re.ReplaceAllString(nContent, "\r\n<span class=\"quote\">&gt;</span>")
-
- nContent = strings.ReplaceAll(nContent, `/\&lt;`, ">")
-
- return template.HTML(nContent)
-}
-
func ParseAttachment(obj ObjectBase, catalog bool) template.HTML {
if len(obj.Attachment) < 1 {
@@ -784,3 +712,140 @@ func ParseAttachment(obj ObjectBase, catalog bool) template.HTML {
return template.HTML(media)
}
+
+func ParseContent(db *sql.DB, board Actor, op string, content string, thread ObjectBase) template.HTML {
+
+ nContent := ParseLinkComments(db, board, op, content, thread)
+
+ nContent = ParseCommentQuotes(nContent)
+
+ nContent = strings.ReplaceAll(nContent, `/\&lt;`, ">")
+
+ return template.HTML(nContent)
+};
+
+func ParseLinkComments(db *sql.DB, board Actor, op string, content string, thread ObjectBase) string {
+ re := regexp.MustCompile(`(>>(https?://[A-Za-z0-9_.:\-~]+\/[A-Za-z0-9_.\-~]+\/)(f[A-Za-z0-9_.\-~]+-)?([A-Za-z0-9_.\-~]+)?#?([A-Za-z0-9_.\-~]+)?)`)
+ match := re.FindAllStringSubmatch(content, -1)
+
+ //add url to each matched reply
+ for i, _ := range match {
+ link := strings.Replace(match[i][0], ">>", "", 1)
+ isOP := ""
+
+ domain := match[i][2]
+
+ if link == op {
+ isOP = " (OP)"
+ }
+
+ parsedLink := ConvertHashLink(domain, link)
+
+ //formate the hover title text
+ var quoteTitle string
+
+ // if the quoted content is local get it
+ // else get it from the database
+ if thread.Id == link {
+ quoteTitle = thread.Content
+ } else {
+ for _, e := range thread.Replies.OrderedItems {
+ if e.Id == parsedLink {
+ quoteTitle = ParseLinkTitle(board.Outbox, op, e.Content)
+ break
+ }
+ }
+
+ if quoteTitle == "" {
+ obj := GetObjectFromDBFromID(db, parsedLink)
+ if len(obj.OrderedItems) > 0 {
+ quoteTitle = ParseLinkTitle(board.Outbox, op, obj.OrderedItems[0].Content)
+ } else {
+ quoteTitle = ParseLinkTitle(board.Outbox, op, parsedLink)
+ }
+ }
+ }
+
+ var style string
+ if board.Restricted {
+ style = "color: #af0a0f;"
+ }
+
+ //replace link with quote format
+ replyID, isReply := IsReplyToOP(db, op, parsedLink)
+ if isReply {
+ id := shortURL(board.Outbox, replyID)
+
+ content = strings.Replace(content, match[i][0], "<a class=\"reply\" style=\"" + style + "\" title=\"" + quoteTitle + "\" href=\"/" + board.Name + "/" + shortURL(board.Outbox, op) + "#" + id + "\">&gt;&gt;" + id + "" + isOP + "</a>", -1)
+
+ } else {
+
+ //this is a cross post
+ parsedOP := GetReplyOP(db, parsedLink)
+
+ if parsedOP != "" {
+ link = parsedOP + "#" + shortURL(parsedOP, parsedLink)
+ }
+
+ content = strings.Replace(content, match[i][0], "<a class=\"reply\" style=\"" + style + "\" title=\"" + quoteTitle + "\" href=\"" + link + "\">&gt;&gt;" + shortURL(board.Outbox, parsedLink) + isOP + " →</a>", -1)
+ }
+ }
+
+ return content
+}
+
+func ParseLinkTitle(actorName string, op string, content string) string {
+ re := regexp.MustCompile(`(>>(https?://[A-Za-z0-9_.:\-~]+\/[A-Za-z0-9_.\-~]+\/)\w+(#.+)?)`)
+ match := re.FindAllStringSubmatch(content, -1)
+
+ for i, _ := range match {
+ link := strings.Replace(match[i][0], ">>", "", 1)
+ isOP := ""
+
+ domain := match[i][2]
+
+ if link == op {
+ isOP = " (OP)"
+ }
+
+ link = ConvertHashLink(domain, link)
+ content = strings.Replace(content, match[i][0], ">>" + shortURL(actorName, link) + isOP , 1)
+ }
+
+ content = strings.ReplaceAll(content, "'", "")
+ content = strings.ReplaceAll(content, "\"", "")
+ content = strings.ReplaceAll(content, ">", `/\&lt;`)
+
+ return content
+}
+
+func ParseCommentQuotes(content string) string {
+ // replace quotes
+ re := regexp.MustCompile(`((\r\n|\r|\n|^)>(.+)?[^\r\n])`)
+ match := re.FindAllStringSubmatch(content, -1)
+
+ for i, _ := range match {
+ quote := strings.Replace(match[i][0], ">", "&gt;", 1)
+ line := re.ReplaceAllString(match[i][0], "<span class=\"quote\">" + quote + "</span>")
+ content = strings.Replace(content, match[i][0], line, 1)
+ }
+
+ //replace isolated greater than symboles
+ re = regexp.MustCompile(`(\r\n|\n|\r)>`)
+
+ return re.ReplaceAllString(content, "\r\n<span class=\"quote\">&gt;</span>")
+}
+
+func ConvertHashLink(domain string, link string) string {
+ re := regexp.MustCompile(`(#.+)`)
+ parsedLink := re.FindString(link)
+
+ if parsedLink != "" {
+ parsedLink = domain + "" + strings.Replace(parsedLink, "#", "", 1)
+ parsedLink = strings.Replace(parsedLink, "\r", "", -1)
+ } else {
+ parsedLink = link
+ }
+
+ return parsedLink
+}
diff --git a/database.go b/database.go
index 3a20cb4..3d3f9ff 100644
--- a/database.go
+++ b/database.go
@@ -6,6 +6,7 @@ import (
"os"
"sort"
"strings"
+ "regexp"
"time"
"html/template"
@@ -558,7 +559,16 @@ func GetObjectFromDBFromID(db *sql.DB, id string) Collection {
var nColl Collection
var result []ObjectBase
- query := `select x.id, x.name, x.content, x.type, x.published, x.updated, x.attributedto, x.attachment, x.preview, x.actor, x.tripcode, x.sensitive from (select id, name, content, type, published, updated, attributedto, attachment, preview, actor, tripcode, sensitive from activitystream where id=$1 and type='Note' union select id, name, content, type, published, updated, attributedto, attachment, preview, actor, tripcode, sensitive from cacheactivitystream where id=$1 and type='Note') as x order by x.updated`
+ query := `select x.id, x.name, x.content, x.type, x.published, x.updated, x.attributedto, x.attachment, x.preview, x.actor, x.tripcode, x.sensitive from (select id, name, content, type, published, updated, attributedto, attachment, preview, actor, tripcode, sensitive from activitystream where id like $1 and type='Note' union select id, name, content, type, published, updated, attributedto, attachment, preview, actor, tripcode, sensitive from cacheactivitystream where id like $1 and type='Note') as x order by x.updated`
+
+ re := regexp.MustCompile(`f(\w+)\-`)
+ match := re.FindStringSubmatch(id)
+
+ if len(match) > 0 {
+ re := regexp.MustCompile(`(.+)\-`)
+ id = re.ReplaceAllString(id, "")
+ id = "%" + match[1] + "/" + id
+ }
rows, err := db.Query(query, id)
diff --git a/main.go b/main.go
index f219a2d..dc9370b 100644
--- a/main.go
+++ b/main.go
@@ -1730,7 +1730,7 @@ func CreateAttachmentObject(file multipart.File, header *multipart.FileHeader) (
return nAttachment, tempFile
}
-func ParseCommentForReplies(comment string) []ObjectBase {
+func ParseCommentForReplies(db *sql.DB, comment string, op string) []ObjectBase {
re := regexp.MustCompile(`(>>https?://[A-Za-z0-9_.\-~]+\/[A-Za-z0-9_.\-~]+\/\w+)`)
match := re.FindAllStringSubmatch(comment, -1)
@@ -1743,7 +1743,8 @@ func ParseCommentForReplies(comment string) []ObjectBase {
str = strings.Replace(str, "http://", "", 1)
str = strings.Replace(str, "https://", "", 1)
str = TP + "" + str
- if !IsInStringArray(links, str) {
+ _ , isReply := IsReplyToOP(db, op, str)
+ if !IsInStringArray(links, str) && isReply {
links = append(links, str)
}
}
@@ -1864,7 +1865,6 @@ func GetActorCollection(collection string) Collection {
return nCollection
}
-
defer resp.Body.Close()
if resp.StatusCode == 200 {
@@ -2405,7 +2405,7 @@ func ParseCommentForReply(comment string) string {
re := regexp.MustCompile("(>>)(https://|http://)?(www\\.)?.+\\/\\w+")
match := re.FindAllStringSubmatch(comment, -1)
-
+
var links []string
for i:= 0; i < len(match); i++ {
@@ -2414,7 +2414,7 @@ func ParseCommentForReply(comment string) string {
}
if(len(links) > 0){
- _, isValid := CheckValidActivity(links[0])
+ _, isValid := CheckValidActivity(strings.ReplaceAll(links[0], ">", ""))
if(isValid) {
return links[0]
@@ -2843,3 +2843,54 @@ func HasValidation(w http.ResponseWriter, r *http.Request, actor Actor) bool {
return true
}
+
+func IsReplyToOP(db *sql.DB, op string, link string) (string, bool) {
+
+ if op == link {
+ return link, true
+ }
+
+ re := regexp.MustCompile(`f(\w+)\-`)
+ match := re.FindStringSubmatch(link)
+
+ if len(match) > 0 {
+ re := regexp.MustCompile(`(.+)\-`)
+ link = re.ReplaceAllString(link, "")
+ link = "%" + match[1] + "/" + link
+ }
+
+ query := `select id from replies where id like $1 and inreplyto=$2`
+
+ rows, err := db.Query(query, link, op)
+
+ CheckError(err, "error selecting in reply to op from db")
+
+ var id string
+ defer rows.Close()
+ rows.Next()
+ rows.Scan(&id)
+
+ if id != "" {
+
+ return id, true
+ }
+
+ return "", false
+}
+
+func GetReplyOP(db *sql.DB, link string) string {
+
+ query := `select id from replies where id in (select inreplyto from replies where id=$1) and inreplyto=''`
+
+ rows, err := db.Query(query, link)
+
+ CheckError(err, "could not get reply OP from db ")
+
+ var id string
+
+ defer rows.Close()
+ rows.Next()
+ rows.Scan(&id)
+
+ return id
+}
diff --git a/outboxPost.go b/outboxPost.go
index b3a8baf..1d658ea 100644
--- a/outboxPost.go
+++ b/outboxPost.go
@@ -381,7 +381,7 @@ func ObjectFromForm(r *http.Request, db *sql.DB, obj ObjectBase) ObjectBase {
}
}
- replyingTo := ParseCommentForReplies(r.FormValue("comment"))
+ replyingTo := ParseCommentForReplies(db, r.FormValue("comment"), originalPost.Id)
for _, e := range replyingTo {
diff --git a/static/posts.html b/static/posts.html
index d7f46b9..5810348 100644
--- a/static/posts.html
+++ b/static/posts.html
@@ -101,10 +101,6 @@
{{ if .Replies.OrderedItems }}
{{ range .Replies.OrderedItems }}
<span id="{{$parentId}}-replyto-{{.Id}}"></span>
- <script>
- var content = convertContentNoLink('{{$board.Actor.Id}}', '{{ .Content }}', '{{ $opId }}')
- document.getElementById("{{ $parentId }}-replyto-{{.Id}}").innerHTML = "<a title='" + content +"' href='/{{ $board.Name }}/" + shortURL("{{ $board.Actor.Id }}", "{{ $opId }}") + "#" + shortURL("{{ $board.Actor.Id }}", "{{ .Id }}") + "'>>>" + shortURL("{{ $board.Actor.Id }}", "{{ .Id }}") + "</a>";
- </script>
{{ end }}
{{ end }}
<p id="{{ .Id }}-content" style="white-space: pre-wrap; margin: 10px 30px 10px 30px;">{{.ContentHTML}}</p>