aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFChannel <>2021-07-22 13:50:11 -0700
committerFChannel <>2021-07-22 13:50:11 -0700
commit3b2c8a4c78ade9e819b61aa055039ae00e517a3e (patch)
tree1d52c2c44cf89d6aa53b7ff2fd1e034553e2157a
parent5592a8c898b45e1e97d91b2c0bb0ed21750a9959 (diff)
fixed quote bug and moved comment parsing server side without javascript
-rw-r--r--activityPubStruct.go11
-rw-r--r--client.go126
-rw-r--r--database.go42
-rw-r--r--main.go4
-rw-r--r--static/main.html9
-rw-r--r--static/ncatalog.html5
-rw-r--r--static/posts.html35
7 files changed, 174 insertions, 58 deletions
diff --git a/activityPubStruct.go b/activityPubStruct.go
index e790573..62fabe1 100644
--- a/activityPubStruct.go
+++ b/activityPubStruct.go
@@ -1,6 +1,9 @@
package main
-import "encoding/json"
+import (
+ "encoding/json"
+ "html/template"
+)
type AtContextRaw struct {
Context json.RawMessage `json:"@context,omitempty"`
@@ -111,7 +114,8 @@ type ObjectBase struct {
TripCode string `json:"tripcode,omitempty"`
Actor string `json:"actor,omitempty"`
Audience string `json:"audience,omitempty"`
- Content string `json:"content,omitempty"`
+ ContentHTML template.HTML `json:"contenthtml,omitempty"`
+ Content string `json:"content,omitempty"`
EndTime string `json:"endTime,omitempty"`
Generator string `json:"generator,omitempty"`
Icon string `json:"icon,omitempty"`
@@ -156,7 +160,8 @@ type NestedObjectBase struct {
TripCode string `json:"tripcode,omitempty"`
Actor string `json:"actor,omitempty"`
Audience string `json:"audience,omitempty"`
- Content string `json:"content,omitempty"`
+ ContentHTML template.HTML `json:"contenthtml,omitempty"`
+ Content string `json:"content,omitempty"`
EndTime string `json:"endTime,omitempty"`
Generator string `json:"generator,omitempty"`
Icon string `json:"icon,omitempty"`
diff --git a/client.go b/client.go
index af83a28..12e6147 100644
--- a/client.go
+++ b/client.go
@@ -1,14 +1,17 @@
package main
-import "net/http"
-import "html/template"
-import "database/sql"
-import _ "github.com/lib/pq"
-import "strings"
-import "strconv"
-import "sort"
-import "regexp"
-import "time"
+import (
+ "net/http"
+ "html/template"
+ "database/sql"
+ _ "github.com/lib/pq"
+ "strings"
+ "strconv"
+ "sort"
+ "regexp"
+ "time"
+ "fmt"
+)
var Key *string = new(string)
@@ -116,6 +119,7 @@ func IndexGet(w http.ResponseWriter, r *http.Request, db *sql.DB) {
if(len(data.BoardRemainer) == 3){
data.BoardRemainer = make([]int, 0)
}
+
data.InstanceIndex = GetCollectionFromReq("https://fchan.xyz/followers").Items
data.NewsItems = getNewsFromDB(db, 3)
@@ -184,6 +188,9 @@ func OutboxGet(w http.ResponseWriter, r *http.Request, db *sql.DB, collection Co
"proxy": func(url string) string {
return MediaProxy(url)
},
+ "short": func(actorName string, url string) string {
+ return shortURL(actorName, url)
+ },
"sub": func (i, j int) int { return i - j }}).ParseFiles("./static/main.html", "./static/nposts.html", "./static/top.html", "./static/bottom.html", "./static/posts.html"))
@@ -219,6 +226,14 @@ func OutboxGet(w http.ResponseWriter, r *http.Request, db *sql.DB, collection Co
returnData.Boards = Boards
returnData.Posts = collection.OrderedItems
+ for i, e := range returnData.Posts {
+ returnData.Posts[i].ContentHTML = ParseContent(db, returnData.Board.Actor, e.Id, e.Content, e)
+
+ for j, k := range e.Replies.OrderedItems {
+ returnData.Posts[i].Replies.OrderedItems[j].ContentHTML = ParseContent(db, returnData.Board.Actor, e.Id, k.Content, e)
+ }
+ }
+
var offset = 8
var pages []int
pageLimit := (float64(collection.TotalItems) / float64(offset))
@@ -236,7 +251,10 @@ func CatalogGet(w http.ResponseWriter, r *http.Request, db *sql.DB, collection C
t := template.Must(template.New("").Funcs(template.FuncMap{
"proxy": func(url string) string {
return MediaProxy(url)
- },
+ },
+ "short": func(actorName string, url string) string {
+ return shortURL(actorName, url)
+ },
"sub": func (i, j int) int { return i - j }}).ParseFiles("./static/main.html", "./static/ncatalog.html", "./static/top.html"))
actor := collection.Actor
@@ -273,7 +291,10 @@ func PostGet(w http.ResponseWriter, r *http.Request, db *sql.DB){
t := template.Must(template.New("").Funcs(template.FuncMap{
"proxy": func(url string) string {
return MediaProxy(url)
- },
+ },
+ "short": func(actorName string, url string) string {
+ return shortURL(actorName, url)
+ },
"sub": func (i, j int) int { return i - j }}).ParseFiles("./static/main.html", "./static/npost.html", "./static/top.html", "./static/bottom.html", "./static/posts.html"))
path := r.URL.Path
@@ -333,6 +354,14 @@ func PostGet(w http.ResponseWriter, r *http.Request, db *sql.DB){
if len(returnData.Posts) > 0 {
returnData.PostId = shortURL(returnData.Board.To, returnData.Posts[0].Id)
+
+ for i, e := range returnData.Posts {
+ returnData.Posts[i].ContentHTML = ParseContent(db, returnData.Board.Actor, e.Id, e.Content, e)
+
+ for j, k := range e.Replies.OrderedItems {
+ returnData.Posts[i].Replies.OrderedItems[j].ContentHTML = ParseContent(db, returnData.Board.Actor, e.Id, k.Content, e)
+ }
+ }
}
t.ExecuteTemplate(w, "layout", returnData)
@@ -596,7 +625,80 @@ func MediaProxy(url string) string {
if re.MatchString(url) {
return url
}
-
+
+ fmt.Println("")
MediaHashs[HashMedia(url)] = url
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)
+}
diff --git a/database.go b/database.go
index 1b2ec3d..3a20cb4 100644
--- a/database.go
+++ b/database.go
@@ -554,6 +554,48 @@ func GetObjectFromDB(db *sql.DB, id string) Collection {
return nColl
}
+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`
+
+ rows, err := db.Query(query, id)
+
+ CheckError(err, "error query object from db")
+
+ defer rows.Close()
+ for rows.Next(){
+ var post ObjectBase
+ var actor Actor
+ var attachID string
+ var previewID string
+
+ err = rows.Scan(&post.Id, &post.Name, &post.Content, &post.Type, &post.Published, &post.Updated, &post.AttributedTo, &attachID, &previewID, &actor.Id, &post.TripCode, &post.Sensitive)
+
+ CheckError(err, "error scan object into post struct")
+
+ post.Actor = actor.Id
+
+ var postCnt int
+ var imgCnt int
+ post.Replies, postCnt, imgCnt = GetObjectRepliesDB(db, post)
+
+ post.Replies.TotalItems = postCnt
+ post.Replies.TotalImgs = imgCnt
+
+ post.Attachment = GetObjectAttachment(db, attachID)
+
+ post.Preview = GetObjectPreview(db, previewID)
+
+ result = append(result, post)
+ }
+
+ nColl.OrderedItems = result
+
+ return nColl
+}
+
func GetObjectFromDBCatalog(db *sql.DB, id string) Collection {
var nColl Collection
var result []ObjectBase
diff --git a/main.go b/main.go
index 4327e44..601394f 100644
--- a/main.go
+++ b/main.go
@@ -1640,8 +1640,8 @@ func CreateAttachmentObject(file multipart.File, header *multipart.FileHeader) (
}
func ParseCommentForReplies(comment string) []ObjectBase {
-
- re := regexp.MustCompile("(>>)(https://|http://)?(www\\.)?.+\\/\\w+")
+
+ re := regexp.MustCompile(`(>>https?:\/\/[A-z.:0-9]+\/[A-z0-9]+\/\w+)`)
match := re.FindAllStringSubmatch(comment, -1)
var links []string
diff --git a/static/main.html b/static/main.html
index 3cb8555..9209ed9 100644
--- a/static/main.html
+++ b/static/main.html
@@ -53,14 +53,6 @@
color: #789922;
}
- .reply {
- {{ if .Board.Restricted }}
- color:#af0a0f;
- {{ else }}
- color:#000080;
- {{ end }}
- }
-
.post {
{{ if .Board.Restricted }}
background-color: #d5daf0;
@@ -85,6 +77,7 @@
<body>
<ul style="display: inline; padding:0;">
{{ $l := len .Boards }}
+ <li style="display: inline;">[<a href="/">Home</a>]</li>
{{range $i, $e := .Boards}}
{{ if eq (sub $l 1) 0 }}
<li style="display: inline;">[ <a href="{{.Location}}">{{$e.Name}} </a>]</li>
diff --git a/static/ncatalog.html b/static/ncatalog.html
index 68bb01a..d007d62 100644
--- a/static/ncatalog.html
+++ b/static/ncatalog.html
@@ -105,7 +105,7 @@
document.getElementById("{{ .Id }}-anchor").href = "/{{ $board.Name }}/" + shortURL("{{$board.Actor.Id}}", "{{ .Id }}")
</script>
{{ end }}
- <a id="{{ .Id }}-link" href="/{{ $board.Name }}/">
+ <a id="{{ .Id }}-link" href="/{{ $board.Name }}/{{ short $board.Actor.Outbox .Id }}">
<div>
{{ $replies := .Replies }}
{{ if $replies }}
@@ -121,9 +121,6 @@
</div>
</a>
</div>
- <script>
- document.getElementById("{{ .Id }}-link").href = "/{{ $board.Name }}/" + shortURL("{{$board.Actor.Id}}", "{{ .Id }}")
- </script>
{{ end }}
</div>
<hr>
diff --git a/static/posts.html b/static/posts.html
index d16f780..7552188 100644
--- a/static/posts.html
+++ b/static/posts.html
@@ -7,7 +7,7 @@
<hr>
{{ end }}
<div style="overflow: auto;">
- <div id="{{ .Id }}" style="overflow: visible; margin-bottom: 12px;">
+ <div id="{{ short $board.Actor.Outbox .Id }}" style="overflow: visible; margin-bottom: 12px;">
{{ if eq $board.ModCred $board.Domain $board.Actor.Id }}
<a href="/delete?id={{ .Id }}&board={{ $board.Actor.Name }}">[Delete Post]</a>
{{ end }}
@@ -22,7 +22,6 @@
<div id="media-{{ .Id }}"></div>
<script>
media = document.getElementById("media-{{ .Id }}")
-
if(({{ .Sensitive }} && {{ $board.Actor.Restricted }}) || (isOnion("{{ .Id }}") && !isOnion("{{ $board.Domain }}"))){
sensitive = document.getElementById("sensitive-{{ .Id }}")
hide = document.getElementById("hide-{{ .Id }}")
@@ -84,8 +83,8 @@
}
</script>
{{ end }}
- <span style="color: #0f0c5d;"><b>{{ .Name }}</b></span><span style="color: #117743;"><b>{{ if .AttributedTo }} {{.AttributedTo }} {{ else }} Anonymous {{ end }}</b></span><span class="tripcode"> {{ .TripCode }} </span><span>{{ .Published }} <a id="{{ .Id }}-anchor" href="/{{ $board.Name }}/">No.</a> <a id="{{ .Id }}-link" title="{{ .Id }}" href="javascript:quote('{{ $board.Actor.Id }}', '{{ $opId }}', '{{ .Id }}')">{{ .Id }}</a> {{ if ne .Type "Tombstone" }}<a href="javascript:report('{{ $board.Actor.Id }}', '{{ .Id }}')">[Report]</a>{{ end }}</span>
- <p id="{{ .Id }}-content" style="white-space: pre-wrap; margin: 10px 30px 10px 30px;">{{.Content}}</p>
+ <span style="color: #0f0c5d;"><b>{{ .Name }}</b></span><span style="color: #117743;"><b>{{ if .AttributedTo }} {{.AttributedTo }} {{ else }} Anonymous {{ end }}</b></span><span class="tripcode"> {{ .TripCode }} </span><span>{{ .Published }} <a id="{{ .Id }}-anchor" href="/{{ $board.Name }}/{{ short $board.Actor.Outbox $opId }}#{{ short $board.Actor.Outbox .Id }}">No.</a> <a id="{{ .Id }}-link" title="{{ .Id }}" href="javascript:quote('{{ $board.Actor.Id }}', '{{ $opId }}', '{{ .Id }}')">{{ short $board.Actor.Outbox .Id }}</a> {{ if ne .Type "Tombstone" }}<a href="javascript:report('{{ $board.Actor.Id }}', '{{ .Id }}')">[Report]</a>{{ end }}</span>
+ <p id="{{ .Id }}-content" style="white-space: pre-wrap; margin: 10px 30px 10px 30px;">{{.ContentHTML}}</p>
{{ if .Replies }}
{{ $replies := .Replies }}
{{ if gt $replies.TotalItems 5 }}
@@ -94,7 +93,7 @@
{{ end }}
{{ end }}
{{ range $replies.OrderedItems }}
- <div id="{{ .Id }}">
+ <div id="{{ short $board.Actor.Outbox .Id }}">
<div style="display: inline-block; overflow: auto;">
<div style="float: left; display: block; margin-right: 5px;">>></div>
<div class="post" style="overflow: auto; padding: 5px; margin-bottom: 2px;">
@@ -176,7 +175,7 @@
}
</script>
{{ end }}
- <span style="color: #0f0c5d;"><b>{{ .Name }}</b></span><span style="color: #117743;"><b>{{ if .AttributedTo }} {{.AttributedTo }} {{ else }} Anonymous {{ end }}</b></span><span class="tripcode"> {{ .TripCode }} </span><span>{{ .Published }} <a id="{{ .Id }}-anchor" href="/{{ $board.Name }}/post/{{ $opId }}#{{ .Id }}">No. </a><a id="{{ .Id }}-link" title="{{ .Id }}" href="javascript:quote('{{ $board.Actor.Id }}', '{{ $opId }}', '{{ .Id }}')">{{ .Id }}</a> {{ if ne .Type "Tombstone" }}<a href="javascript:report('{{ $board.Actor.Id }}', '{{ .Id }}')">[Report]</a>{{ end }}</span>
+ <span style="color: #0f0c5d;"><b>{{ .Name }}</b></span><span style="color: #117743;"><b>{{ if .AttributedTo }} {{.AttributedTo }} {{ else }} Anonymous {{ end }}</b></span><span class="tripcode"> {{ .TripCode }} </span><span>{{ .Published }} <a id="{{ .Id }}-anchor" href="/{{ $board.Name }}/{{ short $board.Actor.Outbox $opId }}#{{ short $board.Actor.Outbox .Id }}">No. </a><a id="{{ .Id }}-link" title="{{ .Id }}" href="javascript:quote('{{ $board.Actor.Id }}', '{{ $opId }}', '{{ .Id }}')">{{ short $board.Actor.Outbox .Id }}</a> {{ if ne .Type "Tombstone" }}<a href="javascript:report('{{ $board.Actor.Id }}', '{{ .Id }}')">[Report]</a>{{ end }}</span>
{{ $parentId := .Id }}
{{ if .Replies.OrderedItems }}
{{ range .Replies.OrderedItems }}
@@ -187,7 +186,7 @@
</script>
{{ end }}
{{ end }}
- <p id="{{ .Id }}-content" style="white-space: pre-wrap; margin: 10px 30px 10px 30px;">{{.Content}}</p>
+ <p id="{{ .Id }}-content" style="white-space: pre-wrap; margin: 10px 30px 10px 30px;">{{.ContentHTML}}</p>
</div>
</div>
</div>
@@ -196,17 +195,6 @@
document.getElementById("{{ .Id }}-size").innerText = " (" + convertSize({{ (index .Attachment 0).Size }}) + ")";
document.getElementById("{{ .Id }}-img").innerText = shortImg("{{ (index .Attachment 0).Name }}");
{{ end }}
-
- document.getElementById("{{ .Id }}-link").innerText = shortURL("{{ $board.Actor.Id }}", "{{ .Id }}");
-
- document.getElementById("{{ .Id }}-anchor").href = "/{{ $board.Name }}/" + shortURL("{{$board.Actor.Id}}", "{{ $opId }}") +
- "#" + shortURL("{{$board.Actor.Id}}", "{{ .Id }}");
- document.getElementById("{{ .Id }}").setAttribute("id", shortURL("{{$board.Actor.Id}}", "{{ .Id }}"));
-
- var content = document.getElementById("{{ .Id }}-content");
-
- content.innerHTML = convertContent('{{$board.Actor.Id}}', content.innerText, '{{ $opId }}')
-
</script>
{{ end }}
{{ end }}
@@ -217,17 +205,6 @@
document.getElementById("{{ .Id }}-size").innerText = " (" + convertSize({{ (index .Attachment 0).Size }}) + ")";
document.getElementById("{{ .Id }}-img").innerText = shortImg("{{ (index .Attachment 0).Name }}");
{{ end }}
-
- document.getElementById("{{ .Id }}-link").innerText = shortURL("{{ $board.Actor.Id }}", "{{ .Id }}");
-
- document.getElementById("{{ .Id }}").setAttribute("id", shortURL("{{ $board.Actor.Id }}", "{{ .Id }}"));
-
- document.getElementById("{{ .Id }}-anchor").href = "/{{ $board.Name }}/" + shortURL("{{$board.Actor.Id}}", "{{ $opId }}") +
- "#" + shortURL("{{$board.Actor.Id}}", "{{ .Id }}");
-
- var content = document.getElementById("{{ .Id }}-content");
-
- content.innerHTML = convertContent('{{$board.Actor.Id}}', content.innerText, '{{ $opId }}')
</script>
{{ end }}
{{ end }}