diff options
-rw-r--r-- | client.go | 93 | ||||
-rw-r--r-- | database.go | 194 | ||||
-rw-r--r-- | main.go | 24 | ||||
-rw-r--r-- | outboxGet.go | 28 | ||||
-rw-r--r-- | outboxPost.go | 6 | ||||
-rw-r--r-- | static/archive.html | 81 | ||||
-rw-r--r-- | static/main.html | 32 | ||||
-rw-r--r-- | static/ncatalog.html | 24 | ||||
-rw-r--r-- | static/npost.html | 18 | ||||
-rw-r--r-- | static/nposts.html | 5 | ||||
-rw-r--r-- | static/posts.html | 6 | ||||
-rw-r--r-- | static/top.html | 55 |
12 files changed, 504 insertions, 62 deletions
@@ -277,6 +277,7 @@ func CatalogGet(w http.ResponseWriter, r *http.Request, db *sql.DB, collection C return ParseAttachment(obj, catalog) }, "sub": func (i, j int) int { return i - j }}).ParseFiles("./static/main.html", "./static/ncatalog.html", "./static/top.html")) + actor := collection.Actor var returnData PageData @@ -308,6 +309,54 @@ func CatalogGet(w http.ResponseWriter, r *http.Request, db *sql.DB, collection C t.ExecuteTemplate(w, "layout", returnData) } +func ArchiveGet(w http.ResponseWriter, r *http.Request, db *sql.DB, collection Collection){ + 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) + }, + "shortExcerpt": func(post ObjectBase) template.HTML { + return template.HTML(ShortExcerpt(post)) + }, + "parseAttachment": func(obj ObjectBase, catalog bool) template.HTML { + return ParseAttachment(obj, catalog) + }, + "mod": func(i, j int) bool { return i % j == 0 }, + "sub": func (i, j int) int { return i - j }}).ParseFiles("./static/main.html", "./static/archive.html", "./static/bottom.html")) + + actor := collection.Actor + + var returnData PageData + returnData.Board.Name = actor.Name + returnData.Board.PrefName = actor.PreferredUsername + returnData.Board.InReplyTo = "" + returnData.Board.To = actor.Outbox + returnData.Board.Actor = *actor + returnData.Board.Summary = actor.Summary + returnData.Board.ModCred, _ = GetPasswordFromSession(r) + returnData.Board.Domain = Domain + returnData.Board.Restricted = actor.Restricted + returnData.Key = *Key + returnData.ReturnTo = "archive" + + returnData.Board.Post.Actor = actor.Id + + returnData.Instance = GetActorFromDB(db, Domain) + + returnData.Board.Captcha = Domain + "/" + GetRandomCaptcha(db) + returnData.Board.CaptchaCode = GetCaptchaCode(returnData.Board.Captcha) + + returnData.Title = "/" + actor.Name + "/ - " + actor.PreferredUsername + + returnData.Boards = Boards + + returnData.Posts = collection.OrderedItems + + t.ExecuteTemplate(w, "layout", returnData) +} + func PostGet(w http.ResponseWriter, r *http.Request, db *sql.DB){ t := template.Must(template.New("").Funcs(template.FuncMap{ "proxy": func(url string) string { @@ -455,6 +504,22 @@ func WantToServeCatalog(db *sql.DB, actorName string) (Collection, bool) { return collection, serve } +func WantToServeArchive(db *sql.DB, actorName string) (Collection, bool) { + + var collection Collection + serve := false + + actor := GetActorByNameFromDB(db, actorName) + + if actor.Id != "" { + collection = GetActorCollectionDBType(db, actor.Id, "Archive") + collection.Actor = &actor + return collection, true + } + + return collection, serve +} + func StripTransferProtocol(value string) string { re := regexp.MustCompile("(http://|https://)?(www.)?") @@ -924,3 +989,31 @@ func ConvertSize(size int64) string { return rValue; } + +func ShortExcerpt(post ObjectBase) string { + var returnString string + + if post.Name != "" { + returnString = post.Name + ": " + post.Content; + } else { + returnString = post.Content; + } + + re := regexp.MustCompile(`(^.{100})`) + + match := re.FindStringSubmatch(returnString) + + if len(match) > 0 { + returnString = match[0] + "..." + } + + re = regexp.MustCompile(`(^.+:)`) + + match = re.FindStringSubmatch(returnString) + + if len(match) > 0 { + returnString = strings.Replace(returnString, match[0], "<b>" + match[0] + "</b>", 1) + } + + return returnString +} diff --git a/database.go b/database.go index f0601ce..e3f4050 100644 --- a/database.go +++ b/database.go @@ -250,7 +250,17 @@ func WriteObjectReplyToLocalDB(db *sql.DB, id string, replyto string) { } func WriteObjectReplyToDB(db *sql.DB, obj ObjectBase) { - for _, e := range obj.InReplyTo { + for i, e := range obj.InReplyTo { + + if !CheckIfObjectOP(db, obj.Id) && i == 0 { + nType := GetObjectTypeDB(db, e.Id) + + if nType == "Archive" { + UpdateObjectTypeDB(db, obj.Id, "Archive") + } + } + + query := `select id from replies where id=$1 and inreplyto=$2` rows, err := db.Query(query, obj.Id, e.Id) @@ -268,7 +278,6 @@ func WriteObjectReplyToDB(db *sql.DB, obj ObjectBase) { _, err := db.Exec(query, obj.Id, e.Id) - CheckError(err, "error inserting replies db") } @@ -513,12 +522,54 @@ func GetObjectFromDBPage(db *sql.DB, id string, page int) Collection { return nColl } -func GetObjectFromDB(db *sql.DB, id string) Collection { +func GetActorObjectCollectionFromDB(db *sql.DB, actorId string) Collection { var nColl Collection var result []ObjectBase query := `select id, name, content, type, published, updated, attributedto, attachment, preview, actor, tripcode, sensitive from activitystream where actor=$1 and id in (select id from replies where inreplyto='') and type='Note' order by updated desc` + rows, err := db.Query(query, actorId) + + 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 GetObjectFromDB(db *sql.DB, id string) Collection { + var nColl Collection + var result []ObjectBase + + query := `select id, name, content, type, published, updated, attributedto, attachment, preview, actor, tripcode, sensitive from activitystream where id=$1 order by updated desc` + rows, err := db.Query(query, id) CheckError(err, "error query object from db") @@ -651,7 +702,7 @@ func GetObjectByIDFromDB(db *sql.DB, postID 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` + 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' or type='Archive') union select id, name, content, type, published, updated, attributedto, attachment, preview, actor, tripcode, sensitive from cacheactivitystream where id=$1 and (type='Note' or type='Archive')) as x` rows, err := db.Query(query, postID) @@ -770,7 +821,7 @@ func GetObjectRepliesDB(db *sql.DB, parent ObjectBase) (*CollectionBase, int, in var nColl CollectionBase var result []ObjectBase - query := `select count(x.id) over(), sum(case when RTRIM(x.attachment) = '' then 0 else 1 end) over(), x.id, x.name, x.content, x.type, x.published, x.attributedto, x.attachment, x.preview, x.actor, x.tripcode, x.sensitive from (select * from activitystream where id in (select id from replies where inreplyto=$1) and type='Note' union select * from cacheactivitystream where id in (select id from replies where inreplyto=$1) and type='Note') as x order by x.published asc` + query := `select count(x.id) over(), sum(case when RTRIM(x.attachment) = '' then 0 else 1 end) over(), x.id, x.name, x.content, x.type, x.published, x.attributedto, x.attachment, x.preview, x.actor, x.tripcode, x.sensitive from (select * from activitystream where id in (select id from replies where inreplyto=$1) and (type='Note' or type='Archive') union select * from cacheactivitystream where id in (select id from replies where inreplyto=$1) and (type='Note' or type='Archive')) as x order by x.published asc` rows, err := db.Query(query, parent.Id) @@ -819,7 +870,7 @@ func GetObjectRepliesReplies(db *sql.DB, parent ObjectBase) (*CollectionBase, in var nColl CollectionBase var result []ObjectBase - query := `select id, name, content, type, published, attributedto, attachment, preview, actor, tripcode, sensitive from activitystream where id in (select id from replies where inreplyto=$1) and type='Note' order by updated asc` + query := `select id, name, content, type, published, attributedto, attachment, preview, actor, tripcode, sensitive from activitystream where id in (select id from replies where inreplyto=$1) and (type='Note' or type='Archive') order by updated asc` rows, err := db.Query(query, parent.Id) @@ -1781,3 +1832,134 @@ func IsInactiveTimestamp(db *sql.DB, timeStamp string) bool { return false } + +func ArchivePosts(db *sql.DB, actor Actor) { + if actor.Id != "" { + col := GetAllActorArchiveDB(db, actor.Id, 165) + for _, e := range col.OrderedItems { + for _, k := range e.Replies.OrderedItems { + UpdateObjectTypeDB(db, k.Id, "Archive") + } + UpdateObjectTypeDB(db, e.Id, "Archive") + } + } +} + +func GetAllActorArchiveDB(db *sql.DB, id string, offset int) Collection { + var nColl Collection + var result []ObjectBase + + query := `select x.id, x.updated from (select id, updated from activitystream where actor=$1 and id in (select id from replies where inreplyto='') and type='Note' union select id, updated from activitystream where actor in (select following from following where id=$1) and id in (select id from replies where inreplyto='') and type='Note' union select id, updated from cacheactivitystream where actor in (select following from following where id=$1) and id in (select id from replies where inreplyto='') and type='Note') as x order by x.updated desc offset $2` + + rows, err := db.Query(query, id, offset) + + CheckError(err, "error query object from db") + + defer rows.Close() + for rows.Next(){ + var post ObjectBase + + err = rows.Scan(&post.Id, &post.Updated) + + CheckError(err, "error scan object into post struct for archive") + + post.Replies, _, _ = GetObjectRepliesDB(db, post) + + result = append(result, post) + } + + nColl.OrderedItems = result + + return nColl +} + +func GetActorCollectionDBType(db *sql.DB, actorId string, nType 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 actor=$1 and id in (select id from replies where inreplyto='') and type=$2 union select id, name, content, type, published, updated, attributedto, attachment, preview, actor, tripcode, sensitive from activitystream where actor in (select following from following where id=$1) and id in (select id from replies where inreplyto='') and type=$2 union select id, name, content, type, published, updated, attributedto, attachment, preview, actor, tripcode, sensitive from cacheactivitystream where actor in (select following from following where id=$1) and id in (select id from replies where inreplyto='') and type=$2) as x order by x.updated desc` + + rows, err := db.Query(query, actorId, nType) + + CheckError(err, "error query object from db archive") + + 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 archive") + + post.Actor = actor.Id + + var replies CollectionBase + + post.Replies = &replies + + post.Replies.TotalItems, post.Replies.TotalImgs = GetObjectRepliesCount(db, post) + + post.Attachment = GetObjectAttachment(db, attachID) + + post.Preview = GetObjectPreview(db, previewID) + + result = append(result, post) + } + + nColl.OrderedItems = result + + return nColl +} + +func UpdateObjectTypeDB(db *sql.DB, id string, nType string) { + query := `update activitystream set type=$2 where id=$1 and type !='Tombstone'` + + _, err := db.Exec(query, id, nType) + + CheckError(err, "error updating activitystream reply type to archive") + + query = `update cacheactivitystream set type=$2 where id=$1 and type !='Tombstone'` + + _, err = db.Exec(query, id, nType) + + CheckError(err, "error updating cache reply type to archive") +} + +func UnArchiveLast(db *sql.DB) { + query := `select id, updated from activitystream where type='Archive' union select id, updated from cacheactivitystream where type='Archive' order by updated desc limit 1` + + rows, err := db.Query(query) + + CheckError(err, "error with unarchive last") + + var id, updated string + defer rows.Close() + rows.Next() + rows.Scan(&id, &updated) + + col := GetObjectFromDB(db, id) + + for _, e := range col.OrderedItems { + for _, k := range e.Replies.OrderedItems { + UpdateObjectTypeDB(db, k.Id, "Note") + } + UpdateObjectTypeDB(db, e.Id, "Note") + } +} + +func GetObjectTypeDB(db *sql.DB, id string) string { + query := `select type from activitystream where id=$1 union select type from cacheactivitystream where id=$1` + + rows, err := db.Query(query, id) + CheckError(err, "error with getting object type from db") + + var nType string + defer rows.Close() + rows.Next() + rows.Scan(&nType) + + return nType +} @@ -69,6 +69,8 @@ func main() { FollowingBoards = GetActorFollowingDB(db, Domain) + StartupArchive(db) + Boards = GetBoardCollection(db) // root actor is used to follow remote feeds that are not local @@ -113,6 +115,7 @@ func main() { var actorReported bool var actorVerification bool var actorMainPage bool + var actorArchive bool var accept = r.Header.Get("Accept") @@ -135,6 +138,7 @@ func main() { actorFollowers = (path == "/" + actor.Name + "/followers") actorReported = (path == "/" + actor.Name + "/reported") actorVerification = (path == "/" + actor.Name + "/verification") + actorArchive = (path == "/" + actor.Name + "/archive") escapedActorName := strings.Replace(actor.Name, "*", "\\*", -1) escapedActorName = strings.Replace(escapedActorName, "^", "\\^", -1) @@ -253,6 +257,14 @@ func main() { return } + if actorArchive { + collection, valid := WantToServeArchive(db, actor.Name) + if valid { + ArchiveGet(w, r, db, collection) + } + return + } + if actorReported { GetActorReported(w, r, db, actor.Id) return @@ -843,6 +855,7 @@ func main() { go DeleteObjectRequest(db, id) } + UnArchiveLast(db) if !isOP { if (!IsIDLocal(db, id)){ @@ -890,6 +903,9 @@ func main() { TombstoneObjectAndReplies(db, id) } + UnArchiveLast(db) + + if(manage == "t"){ http.Redirect(w, r, "/" + *Key + "/" + board , http.StatusSeeOther) return @@ -928,6 +944,8 @@ func main() { go DeleteObjectRequest(db, id) } + UnArchiveLast(db) + if(manage == "t"){ http.Redirect(w, r, "/" + *Key + "/" + board , http.StatusSeeOther) return @@ -2898,3 +2916,9 @@ func GetReplyOP(db *sql.DB, link string) string { return id } + +func StartupArchive(db *sql.DB) { + for _, e := range FollowingBoards { + ArchivePosts(db, GetActorFromDB(db, e.Id)) + } +} diff --git a/outboxGet.go b/outboxGet.go index 4064f0b..f656b3e 100644 --- a/outboxGet.go +++ b/outboxGet.go @@ -9,7 +9,7 @@ func GetActorOutbox(w http.ResponseWriter, r *http.Request, db *sql.DB) { actor := GetActorFromPath(db, r.URL.Path, "/") var collection Collection - collection.OrderedItems = GetObjectFromDB(db, actor.Id).OrderedItems + collection.OrderedItems = GetActorObjectCollectionFromDB(db, actor.Id).OrderedItems collection.AtContext.Context = "https://www.w3.org/ns/activitystreams" collection.Actor = &actor @@ -32,17 +32,17 @@ func GetCollectionFromPath(db *sql.DB, path string) Collection { rows, err := db.Query(query, path) CheckError(err, "error query collection path from db") - + defer rows.Close() for rows.Next(){ var actor Actor var post ObjectBase var attachID string - var previewID string - + var previewID string + err = rows.Scan(&post.Id, &post.Name, &post.Content, &post.Type, &post.Published, &post.AttributedTo, &attachID, &previewID, &actor.Id) - + CheckError(err, "error scan object into post struct from path") post.Actor = actor.Id @@ -50,13 +50,13 @@ func GetCollectionFromPath(db *sql.DB, path string) Collection { post.InReplyTo = GetInReplyToDB(db, post) var postCnt int - var imgCnt int + var imgCnt int post.Replies, postCnt, imgCnt = GetObjectRepliesDB(db, post) post.Replies.TotalItems, post.Replies.TotalImgs = GetObjectRepliesCount(db, post) post.Replies.TotalItems = post.Replies.TotalItems + postCnt - post.Replies.TotalImgs = post.Replies.TotalImgs + imgCnt + post.Replies.TotalImgs = post.Replies.TotalImgs + imgCnt post.Attachment = GetObjectAttachment(db, attachID) @@ -65,11 +65,11 @@ func GetCollectionFromPath(db *sql.DB, path string) Collection { result = append(result, post) } - nColl.AtContext.Context = "https://www.w3.org/ns/activitystreams" + nColl.AtContext.Context = "https://www.w3.org/ns/activitystreams" nColl.OrderedItems = result - return nColl + return nColl } func GetObjectFromPath(db *sql.DB, path string) ObjectBase{ @@ -81,7 +81,7 @@ func GetObjectFromPath(db *sql.DB, path string) ObjectBase{ rows, err := db.Query(query, path) CheckError(err, "error query collection path from db") - + defer rows.Close() rows.Next() var attachID string @@ -89,9 +89,9 @@ func GetObjectFromPath(db *sql.DB, path string) ObjectBase{ var nActor Actor nObj.Actor = nActor.Id - + err = rows.Scan(&nObj.Id, &nObj.Name, &nObj.Content, &nObj.Type, &nObj.Published, &nObj.AttributedTo, &attachID, &previewID, &nObj.Actor) - + CheckError(err, "error scan object into post struct from path") var postCnt int @@ -102,11 +102,11 @@ func GetObjectFromPath(db *sql.DB, path string) ObjectBase{ nObj.Replies.TotalItems, nObj.Replies.TotalImgs = GetObjectRepliesCount(db, nObj) nObj.Replies.TotalItems = nObj.Replies.TotalItems + postCnt - nObj.Replies.TotalImgs = nObj.Replies.TotalImgs + imgCnt + nObj.Replies.TotalImgs = nObj.Replies.TotalImgs + imgCnt nObj.Attachment = GetObjectAttachment(db, attachID) nObj.Preview = GetObjectPreview(db, previewID) - return nObj + return nObj } diff --git a/outboxPost.go b/outboxPost.go index beb49fb..d54dd8e 100644 --- a/outboxPost.go +++ b/outboxPost.go @@ -55,6 +55,11 @@ func ParseOutboxRequest(w http.ResponseWriter, r *http.Request, db *sql.DB) { nObj.Actor = Domain + "/" + actor.Name nObj = WriteObjectToDB(db, nObj) + + if len(nObj.To) == 0 { + ArchivePosts(db, actor) + } + activity := CreateActivity("Create", nObj) activity = AddFollowersToActivity(db, activity) go MakeActivityRequest(db, activity) @@ -536,6 +541,7 @@ func ParseInboxRequest(w http.ResponseWriter, r *http.Request, db *sql.DB) { if IsActorLocal(db, e) { if !IsActorLocal(db, activity.Actor.Id) { WriteObjectToCache(db, *activity.Object) + ArchivePosts(db, GetActorFromDB(db, e)) } } } diff --git a/static/archive.html b/static/archive.html new file mode 100644 index 0000000..2b7d69a --- /dev/null +++ b/static/archive.html @@ -0,0 +1,81 @@ +{{ define "header" }} +<title>/{{ .Board.Name }}/ - Archive</title> +<meta name="description" content="{{ (index .Posts 0).Content }}"> +<meta property="og:url" content="{{ (index .Posts 0).Id }}"> +<meta property="og:site_name" content="{{ .Instance.PreferredUsername }}" /> + +<meta property="og:title" content="{{ (index .Posts 0).Name }}"> +<meta property="og:description" content="{{ (index .Posts 0).Content }}"> + +<meta name="twitter:title" content="{{ (index .Posts 0).Name }}"> +<meta name="twitter:description" content="{{ (index .Posts 0).Content }}"> +<meta name="twitter:card" content="summary_large_image"> + +{{ if (index .Posts 0).Preview }} +<meta property="og:image" content="{{ (index .Posts 0).Preview.Href }}" /> +<meta name="twitter:image" content="{{ (index .Posts 0).Preview.Href }}" /> +{{ end }} + +<script src="/static/js/posts.js"></script> +{{ end }} + +{{ define "top" }} +<h1 style="text-align: center; color: #af0a0f;">/{{ .Board.Name }}/ - {{ .Board.PrefName }}</h1> +<p style="text-align: center;">{{ .Board.Summary }}</p> +<h1 style="text-align: center;">Archived Posts</h1> +{{ end }} + +{{ define "content" }} +{{ $board := .Board }} + +<hr> +<ul style="margin: 0; padding: 0; display: inline;"> + <li style="display: inline"><a href="/{{ $board.Name }}">[Return]</a></li> + <li style="display: inline"><a href="/{{ $board.Name }}/catalog">[Catalog]</a></li> + <li style="display: inline"><a href="#bottom">[Bottom]</a></li> + <li style="display: inline"><a href="javascript:location.reload()">[Refresh]</a></li> +</ul> +<hr> + +<table align="center" style="width: 900px;"> + <tr> + <th style="width: 100px">No.</th> + <th>Excerpt</th> + <th style="width: 100px;"></th> + </tr> + {{ range $i, $e := .Posts }} + {{ if mod $i 2 }} + <tr class="box-alt"> + <td>{{ short $board.Actor.Outbox $e.Id }}</td> + <td>{{ shortExcerpt $e }}</td> + <td style="text-align: center;"><a href="/{{ $board.Actor.Name }}/{{ short $board.Actor.Outbox $e.Id }}">[View]</a></td> + </tr> + {{ else }} + <tr class="box"> + <td>{{ short $board.Actor.Outbox $e.Id }}</td> + <td>{{ shortExcerpt $e }}</td> + <td style="text-align: center;"><a href="/{{ $board.Actor.Name }}/{{ short $board.Actor.Outbox $e.Id }}">[View]</a></td> + </tr> + {{ end }} + {{ end }} +</table> + +<hr> +<div style="height: 22px;"> + <ul style="position: absolute; left: 5px; margin: 0; padding: 0; display: inline;"> + <li style="display: inline"><a href="/{{ $board.Name }}">[Return]</a></li> + <li style="display: inline"><a href="/{{ $board.Name }}/catalog">[Catalog]</a></li> + <li style="display: inline"><a id="bottom" href="#top">[Top]</a></li> + <li style="display: inline"><a href="javascript:location.reload()">[Refresh]</a></li> + </ul> +</div> +<hr> + +{{ end }} + +{{ define "script" }} +<script src="/static/js/footerscript.js"></script> +<script> + viewLink("{{ .Board.Name }}", "{{ .Board.Actor.Id }}") +</script> +{{ end }} diff --git a/static/main.html b/static/main.html index 9209ed9..362b7b3 100644 --- a/static/main.html +++ b/static/main.html @@ -2,9 +2,9 @@ <!DOCTYPE html> <html> <head> - <meta charset="UTF-8"> + <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1"> - <meta name="keywords" content="Federated Imageboard based on Activtypub"> + <meta name="keywords" content="Federated Imageboard based on Activtypub"> <meta property="og:locale" content="en_US" /> <meta property="og:type" content="website" /> <link rel="icon" type="image/png" href="/static/favicon.png"> @@ -30,7 +30,7 @@ color: #820404 {{ end }} } - + .popup-box { {{ if .Board.Restricted }} border: 4px solid #d3caf0; @@ -47,8 +47,16 @@ {{ else }} background-color: #f9f9e0; {{ end }} - } - + } + + .box-alt { + {{ if .Board.Restricted }} + background-color: #d3caf0; + {{ else }} + background-color: #f0e2d9; + {{ end }} + } + .quote { color: #789922; } @@ -60,7 +68,7 @@ background-color: #f0e0d6; {{ end }} } - + :target > div > .post { {{ if .Board.Restricted }} background-color: #d6bad0; @@ -72,21 +80,21 @@ color: #117743; } </style> - {{ template "header" . }} + {{ template "header" . }} </head> <body> <ul style="display: inline; padding:0;"> {{ $l := len .Boards }} - <li style="display: inline;">[<a href="/">Home</a>]</li> + <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> + <li style="display: inline;">[ <a href="{{.Location}}">{{$e.Name}} </a>]</li> {{ else if eq $i 0 }} <li style="display: inline;">[<a href="{{.Location}}">{{$e.Name}} </a>/</li> {{ else if eq $i (sub $l 1) }} <li style="display: inline;"><a href="{{.Location}}">{{$e.Name}}</a>]</li> {{ else }} - <li style="display: inline;"><a href="{{.Location}}">{{$e.Name}} </a>/</li> + <li style="display: inline;"><a href="{{.Location}}">{{$e.Name}} </a>/</li> {{ end }} {{end}} </ul> @@ -96,9 +104,9 @@ {{ end }} {{ end }} {{ template "top" . }} - + {{ template "content" . }} - + {{ template "bottom" . }} <div align="center" style="width: 500px; margin:0 auto; margin-top: 50px;"> <a href="/">[Home]</a><a href="/static/rules.html">[Rules]</a><a href="/static/faq.html">[FAQ]</a> diff --git a/static/ncatalog.html b/static/ncatalog.html index c7f5b30..8ce418a 100644 --- a/static/ncatalog.html +++ b/static/ncatalog.html @@ -19,25 +19,26 @@ <hr> <ul style="margin: 0; padding: 0; display: inline"> <li style="display: inline"><a href="/{{ $board.Name }}">[Return]</a></li> + <li style="display: inline"><a href="/{{ $board.Name }}/archive">[Archive]</a></li> <li style="display: inline"><a href="#bottom">[Bottom]</a></li> <li style="display: inline"><a href="javascript:location.reload()">[Refresh]</a></li> -</ul> +</ul> <hr> <div style="padding: 10px; text-align: center;"> {{ range .Posts }} <div style="overflow: hidden; vertical-align: top; padding-right: 24px; padding-bottom: 24px; display: inline-block; width: 180px; max-height: 320px; margin-bottom: 10px;"> - {{ if eq $board.ModCred $board.Domain $board.Actor.Id }} + {{ if eq $board.ModCred $board.Domain $board.Actor.Id }} <a href="/delete?id={{ .Id }}&board={{ $board.Actor.Name }}">[Delete Post]</a> {{ end }} {{ if .Attachment }} - {{ if eq $board.ModCred $board.Domain $board.Actor.Id }} + {{ if eq $board.ModCred $board.Domain $board.Actor.Id }} <a href="/deleteattach?id={{ .Id }}&board={{ $board.Actor.Name }}">[Delete Attachment]</a> - <a href="/marksensitive?id={{ .Id }}&board={{ $board.Actor.Name }}">[Mark Sensitive]</a> - {{ end }} + <a href="/marksensitive?id={{ .Id }}&board={{ $board.Actor.Name }}">[Mark Sensitive]</a> + {{ end }} <div id="hide-{{ .Id }}" style="display: none;">[Hide]</div> - <div id="sensitive-{{ .Id }}" style="display: none;"><div style="position: relative; text-align: center;"><img id="sensitive-img-{{ .Id }}" style="float: left; margin-right: 10px; margin-bottom: 10px; max-width: 180px; max-height: 180px;" src="/static/sensitive.png"><div id="sensitive-text-{{ .Id }}" style="width: 170px; position: absolute; margin-top: 75px; padding: 5px; background-color: black; color: white; cursor: default; ">NSFW Content</div></div></div> - <a id="{{ .Id }}-anchor" href="/{{ $board.Name }}/{{ short $board.Actor.Outbox .Id}}"> + <div id="sensitive-{{ .Id }}" style="display: none;"><div style="position: relative; text-align: center;"><img id="sensitive-img-{{ .Id }}" style="float: left; margin-right: 10px; margin-bottom: 10px; max-width: 180px; max-height: 180px;" src="/static/sensitive.png"><div id="sensitive-text-{{ .Id }}" style="width: 170px; position: absolute; margin-top: 75px; padding: 5px; background-color: black; color: white; cursor: default; ">NSFW Content</div></div></div> + <a id="{{ .Id }}-anchor" href="/{{ $board.Name }}/{{ short $board.Actor.Outbox .Id}}"> <div id="media-{{ .Id }}" style="width:180px;"> {{ parseAttachment . true }}</div> </a> <script> @@ -59,9 +60,9 @@ sensitive.onclick = function(){document.getElementById("media-{{ .Id }}").style="display: block;"; document.getElementById("sensitive-{{ .Id }}").style="display: none;"; document.getElementById("hide-{{ .Id }}").style="display: block; cursor: pointer;"} hide.onclick = function(){document.getElementById("media-{{ .Id }}").style="display: none;"; document.getElementById("sensitive-{{ .Id }}").style="display: block;"; document.getElementById("hide-{{ .Id }}").style="display: none;"} sensitive.style = "display: block" - media.style = "display: none;" - } - </script> + media.style = "display: none;" + } + </script> {{ end }} <a id="{{ .Id }}-link" href="/{{ $board.Name }}/{{ short $board.Actor.Outbox .Id }}"> <div> @@ -84,10 +85,11 @@ <hr> <ul style="margin: 0; padding: 0; display: inline"> <li style="display: inline"><a href="/{{ $board.Name }}">[Return]</a></li> + <li style="display: inline"><a href="/{{ $board.Name }}/archive">[Archive]</a></li> <li style="display: inline"><a id="bottom" href="#top">[Top]</a></li> <li style="display: inline"><a href="javascript:location.reload()">[Refresh]</a></li> </ul> -<hr> +<hr> {{ end }} {{ define "bottom" }} {{ end }} diff --git a/static/npost.html b/static/npost.html index 419a1a9..2f0778f 100644 --- a/static/npost.html +++ b/static/npost.html @@ -15,8 +15,6 @@ <meta property="og:image" content="{{ (index .Posts 0).Preview.Href }}" /> <meta name="twitter:image" content="{{ (index .Posts 0).Preview.Href }}" /> {{ end }} - -<script src="/static/js/posts.js"></script> {{ end }} {{ define "content" }} @@ -25,7 +23,6 @@ <hr> <ul style="margin: 0; padding: 0; display: inline"> <li style="display: inline"><a href="/{{ $board.Name }}">[Return]</a></li> - <li style="display: inline"><a href="/{{ $board.Name }}/catalog">[Catalog]</a></li> <li style="display: inline"><a href="#bottom">[Bottom]</a></li> <li style="display: inline"><a href="javascript:location.reload()">[Refresh]</a></li> </ul> @@ -36,23 +33,24 @@ <hr> <ul style="position: absolute; left: 5px; margin: 0; padding: 0; display: inline"> <li style="display: inline"><a href="/{{ $board.Name }}">[Return]</a></li> - <li style="display: inline"><a href="/{{ $board.Name }}/catalog">[Catalog]</a></li> <li style="display: inline"><a id="bottom" href="#top">[Top]</a></li> <li style="display: inline"><a href="javascript:location.reload()">[Refresh]</a></li> <li style="display: inline"><input id="autoreload-checkbox" type="checkbox" onclick="autoTimer()"> Auto refresh <span id="autoreload-countdown" style="visibility: hidden;">0</span></li> </ul> -{{ $replies := (index .Posts 0).Replies }} +{{ $replies := (index .Posts 0).Replies }} <span style="float: right;">{{ $replies.TotalItems }} / {{ $replies.TotalImgs }}</span> -<div style="width: 500px; margin: 0 auto; text-align: center;"> - <span ><a id="reply-content" href="javascript:quote('{{ $board.Actor.Id }}', '{{ (index .Posts 0).Id }}', 'reply')">[Post a Reply]</a></span> + +<div style="width: 500px; height: 22px; margin: 0 auto; text-align: center;"> +{{ if eq (index .Posts 0).Type "Note" }} +<span ><a id="reply-content" href="javascript:quote('{{ $board.Actor.Id }}', '{{ (index .Posts 0).Id }}', 'reply')">[Post a Reply]</a></span> +{{ end }} </div> + <hr> {{ end }} {{ define "script" }} +<script src="/static/js/posts.js"></script> <script src="/static/js/footerscript.js"></script> <script src="/static/js/timer.js"></script> -<script> - viewLink("{{ .Board.Name }}", "{{ .Board.Actor.Id }}") -</script> {{ end }} diff --git a/static/nposts.html b/static/nposts.html index 2b05b66..e70b982 100644 --- a/static/nposts.html +++ b/static/nposts.html @@ -10,15 +10,14 @@ <meta name="twitter:title" content="{{ .Title }}"> <meta name="twitter:description" content="{{ .Board.Summary }}"> <meta name="twitter:card" content="summary_large_image"> -<script src="/static/js/posts.js"></script> {{ end }} - {{ define "content" }} {{ $board := .Board }} <hr> <ul style="margin: 0; padding: 0; display: inline"> <li style="display: inline"><a href="/{{ $board.Name }}/catalog">[Catalog]</a></li> + <li style="display: inline"><a href="/{{ $board.Name }}/archive">[Archive]</a></li> <li style="display: inline"><a href="#bottom">[Bottom]</a></li> <li style="display: inline"><a href="javascript:location.reload()">[Refresh]</a></li> </ul> @@ -28,6 +27,7 @@ <hr> <ul style="margin: 0; padding: 0; display: inline"> <li style="display: inline"><a href="/{{ $board.Name }}/catalog">[Catalog]</a></li> + <li style="display: inline"><a href="/{{ $board.Name }}/archive">[Archive]</a></li> <li style="display: inline"><a id="bottom" href="#top">[Top]</a></li> <li style="display: inline"><a href="javascript:location.reload()">[Refresh]</a></li> </ul> @@ -54,5 +54,6 @@ {{ end }} {{ define "script" }} +<script src="/static/js/posts.js"></script> <script src="/static/js/footerscript.js"></script> {{ end }} diff --git a/static/posts.html b/static/posts.html index 8ee3844..0349ebb 100644 --- a/static/posts.html +++ b/static/posts.html @@ -45,7 +45,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 }}/{{ 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> + <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 }}" {{ if eq .Type "Note" }} href="javascript:quote('{{ $board.Actor.Id }}', '{{ $opId }}', '{{ .Id }}')" {{ end }}>{{ 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;">{{ parseContent $board.Actor $opId .Content $thread }}</p> {{ if .Replies }} {{ $replies := .Replies }} @@ -68,7 +68,7 @@ <a href="/deleteattach?id={{ .Id }}&board={{ $board.Actor.Name }}">[Delete Attachment]</a> <a href="/marksensitive?id={{ .Id }}&board={{ $board.Actor.Name }}">[Mark Sensitive]</a> {{ end }} - <span style="display: block;">File <a id="{{ .Id }}-img" href="{{ proxy (index .Attachment 0).Href}}">{{ shortImg (index .Attachment 0).Name }}</a> <span id="{{ .Id }}-size"> ({{ convertSize (index .Attachment 0).Size }})</span></span> + <span style="display: block;">File <a id="{{ .Id }}-img" href="{{ proxy (index .Attachment 0).Href}}">{{ shortImg (index .Attachment 0).Name }}</a> <span id="{{ .Id }}-size">({{ convertSize (index .Attachment 0).Size }})</span></span> <div id="hide-{{ .Id }}" style="display: none;">[Hide]</div> <div id="sensitive-{{ .Id }}" style="display: none;"><div style="position: relative; text-align: center;"><img id="sensitive-img-{{ .Id }}" style="float: left; margin-right: 10px; margin-bottom: 10px; max-width: 250px; max-height: 250px;" src="/static/sensitive.png"><div id="sensitive-text-{{ .Id }}" style="width: 240px; position: absolute; margin-top: 110px; padding: 5px; background-color: black; color: white; cursor: default; ">NSFW Content</div></div></div> <div> </div> @@ -97,7 +97,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 }}/{{ 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> + <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 }}" {{ if eq .Type "Note" }} href="javascript:quote('{{ $board.Actor.Id }}', '{{ $opId }}', '{{ .Id }}')" {{ end }}>{{ 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 }} diff --git a/static/top.html b/static/top.html index 952feb0..0081fc7 100644 --- a/static/top.html +++ b/static/top.html @@ -3,11 +3,12 @@ <h1 style="text-align: center; color: #af0a0f;">/{{ .Board.Name }}/ - {{ .Board.PrefName }}</h1> <p style="text-align: center;">{{ .Board.Summary }}</p> {{ $len := len .Posts }} + {{ if eq $len 0 }} {{ if .Board.InReplyTo }} <h3 id="newpostbtn" state="0" style="text-align: center; margin-top: 80px; display: none;"><a href="javascript:newpost()">[Post a Reply]</a></h3> - {{ else }} + {{ else }} <h3 id="newpostbtn" state="0" style="text-align: center; margin-top: 80px; display: none;"><a href="javascript:newpost()">[Start a New Thread]</a></h3> - {{ end }} + {{ end }} <!-- end if inreplyto--> <div id="newpost"> <form onsubmit="sessionStorage.setItem('element-closed-reply', true)" id="new-post" action="/post" method="post" enctype="multipart/form-data" style="margin-left: 180px;"> <label for="name">Name:</label><br> @@ -35,9 +36,55 @@ </div> </form> </div> + + {{ else }} <!-- special case to distinquish Notes and Archived formatting --> + + {{ if eq (index .Posts 0).Type "Note" }} + {{ if .Board.InReplyTo }} + <h3 id="newpostbtn" state="0" style="text-align: center; margin-top: 80px; display: none;"><a href="javascript:newpost()">[Post a Reply]</a></h3> + {{ else }} + <h3 id="newpostbtn" state="0" style="text-align: center; margin-top: 80px; display: none;"><a href="javascript:newpost()">[Start a New Thread]</a></h3> + {{ end }} <!-- end if inreplyto--> + {{ $len := len .Posts }} + <div id="newpost"> + <form onsubmit="sessionStorage.setItem('element-closed-reply', true)" id="new-post" action="/post" method="post" enctype="multipart/form-data" style="margin-left: 180px;"> + <label for="name">Name:</label><br> + <input type="text" id="name" name="name" placeholder="Anonymous" maxlength="100"><br> + <label for="options">Options:</label><br> + <input type="text" id="options" name="options" maxlength="100" style="margin-right:10px">{{ if .Board.InReplyTo }}<input type="submit" value="Post">{{ end }}<br> + {{ if eq .Board.InReplyTo "" }} + <label for="subject">Subject:</label><br> + <input type="text" id="subject" name="subject" maxlength="100" style="margin-right:10px"><input type="submit" value="Post"><br> + {{ end }} + <label for="comment">Comment:</label><br> + <textarea rows="10" cols="50" id="comment" name="comment" maxlength="2000"></textarea><br> + <input type="hidden" id="inReplyTo" name="inReplyTo" value="{{ .Board.InReplyTo }}"> + <input type="hidden" id="sendTo" name="sendTo" value="{{ .Board.To }}"> + <input type="hidden" id="boardName" name="boardName" value="{{ .Board.Name }}"> + <input type="hidden" id="captchaCode" name="captchaCode" value="{{ .Board.CaptchaCode }}"> + <input type="hidden" id="returnTo" name="returnTo" value="{{ .ReturnTo }}"> + <input type="file" id="file" name="file" {{ if gt $len 1 }} required {{ else }} {{ if eq $len 0 }} required {{ end }} {{ end }} ><br><br> + <input type="checkbox" name="sensitive"><span>Mark attachment as sensitive</span><br><br> + <label stye="display: inline-block;" for="captcha">Captcha:</label> + <br> + <input style="display: inline-block;" type="text" id="captcha" name="captcha" autocomplete="off"><br> + <div style="height: 65px;"> + <img src="{{ .Board.Captcha }}"> + </div> + </form> + </div> + {{ else }} + <h1 style="text-align: center;">Archived Post</h1> + {{ end }} + {{ end }} <!-- end of len eq 0--> </div> <script> - document.getElementById("newpostbtn").style.display = "block"; - document.getElementById("newpost").style.display = "none"; + newpostbtn = document.getElementById("newpostbtn"); + newpost = document.getElementById("newpost"); + + if(newpostbtn) + newpostbtn.style.display = "block"; + if(newpost) + newpost.style.display = "none"; </script> {{ end }} |