You've already forked nyx
mirror of
https://github.com/rls-moe/nyx
synced 2025-08-19 06:18:38 +00:00
Images/Non-images post work, several bug fixes, UI fixes
This commit is contained in:
21
http/admin/cleanup.go
Normal file
21
http/admin/cleanup.go
Normal file
@@ -0,0 +1,21 @@
|
||||
package admin
|
||||
|
||||
import (
|
||||
"github.com/tidwall/buntdb"
|
||||
"go.rls.moe/nyx/http/errw"
|
||||
"go.rls.moe/nyx/http/middle"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
func handleCleanup(w http.ResponseWriter, r *http.Request) {
|
||||
db := middle.GetDB(r)
|
||||
err := db.Update(func(tx *buntdb.Tx) error {
|
||||
/* Insert cleanup codes here */
|
||||
return nil
|
||||
})
|
||||
err = db.Shrink()
|
||||
if err != nil {
|
||||
errw.ErrorWriter(err, w, r)
|
||||
return
|
||||
}
|
||||
}
|
@@ -106,6 +106,8 @@ func handleDelPost(w http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
reply.Text = "[deleted]"
|
||||
reply.Metadata["deleted"] = "yes"
|
||||
reply.Image = nil
|
||||
reply.Thumbnail = nil
|
||||
err = resources.UpdateReply(tx, r.Host, board, reply)
|
||||
if err != nil {
|
||||
return err
|
||||
|
@@ -11,6 +11,7 @@ import (
|
||||
"go.rls.moe/nyx/resources"
|
||||
"html/template"
|
||||
"net/http"
|
||||
"strconv"
|
||||
"time"
|
||||
)
|
||||
|
||||
@@ -48,6 +49,10 @@ var (
|
||||
},
|
||||
"rateSpam": resources.SpamScore,
|
||||
"makeCaptcha": resources.MakeCaptcha,
|
||||
"dateFromID": resources.DateFromId,
|
||||
"formatDate": func(date time.Time) string {
|
||||
return date.Format("02 Jan 06 15:04:05")
|
||||
},
|
||||
}
|
||||
)
|
||||
|
||||
@@ -78,15 +83,74 @@ func Router(r chi.Router) {
|
||||
r.Get("/:board/board.html", serveBoard)
|
||||
r.Post("/:board/new_thread.sh", handleNewThread)
|
||||
r.Get("/:board/:thread/thread.html", serveThread)
|
||||
r.Get("/:board/:thread/:post/post.html", servePost)
|
||||
r.Get("/:board/:thread/:reply/:unused.png", serveFullImage)
|
||||
r.Get("/:board/:thread/:reply/thumb.png", serveThumb)
|
||||
r.Post("/:board/:thread/reply.sh", handleNewReply)
|
||||
r.Handle("/captcha/:captchaId.png", resources.ServeCaptcha)
|
||||
r.Handle("/captcha/:captchaId.wav", resources.ServeCaptcha)
|
||||
r.Handle("/captcha/download/:captchaId.wav", resources.ServeCaptcha)
|
||||
}
|
||||
|
||||
func servePost(w http.ResponseWriter, r *http.Request) {
|
||||
return
|
||||
func serveThumb(w http.ResponseWriter, r *http.Request) {
|
||||
dat := bytes.NewBuffer([]byte{})
|
||||
db := middle.GetDB(r)
|
||||
err := db.View(func(tx *buntdb.Tx) error {
|
||||
bName := chi.URLParam(r, "board")
|
||||
tid, err := strconv.Atoi(chi.URLParam(r, "thread"))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
rid, err := strconv.Atoi(chi.URLParam(r, "reply"))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
reply, err := resources.GetReply(tx, r.Host, bName, tid, rid)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
_, err = dat.Write(reply.Thumbnail)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
})
|
||||
if err != nil {
|
||||
errw.ErrorWriter(err, w, r)
|
||||
return
|
||||
}
|
||||
http.ServeContent(w, r, "thumb.png", time.Now(), bytes.NewReader(dat.Bytes()))
|
||||
}
|
||||
|
||||
func serveFullImage(w http.ResponseWriter, r *http.Request) {
|
||||
dat := bytes.NewBuffer([]byte{})
|
||||
db := middle.GetDB(r)
|
||||
err := db.View(func(tx *buntdb.Tx) error {
|
||||
bName := chi.URLParam(r, "board")
|
||||
tid, err := strconv.Atoi(chi.URLParam(r, "thread"))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
rid, err := strconv.Atoi(chi.URLParam(r, "reply"))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
reply, err := resources.GetReply(tx, r.Host, bName, tid, rid)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
_, err = dat.Write(reply.Image)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
})
|
||||
if err != nil {
|
||||
errw.ErrorWriter(err, w, r)
|
||||
return
|
||||
}
|
||||
http.ServeContent(w, r, "image.png", time.Now(), bytes.NewReader(dat.Bytes()))
|
||||
}
|
||||
|
||||
func serveDir(w http.ResponseWriter, r *http.Request) {
|
||||
|
@@ -1,12 +1,18 @@
|
||||
package board
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"github.com/nfnt/resize"
|
||||
"github.com/pressly/chi"
|
||||
"github.com/tidwall/buntdb"
|
||||
"go.rls.moe/nyx/http/errw"
|
||||
"go.rls.moe/nyx/http/middle"
|
||||
"go.rls.moe/nyx/resources"
|
||||
"image"
|
||||
_ "image/gif"
|
||||
_ "image/jpeg"
|
||||
"image/png"
|
||||
"net/http"
|
||||
"strconv"
|
||||
)
|
||||
@@ -17,6 +23,11 @@ func handleNewReply(w http.ResponseWriter, r *http.Request) {
|
||||
errw.ErrorWriter(err, w, r)
|
||||
return
|
||||
}
|
||||
err = r.ParseMultipartForm(10 * 1024 * 1024)
|
||||
if err != nil {
|
||||
errw.ErrorWriter(err, w, r)
|
||||
return
|
||||
}
|
||||
|
||||
if !resources.VerifyCaptcha(r) {
|
||||
http.Redirect(w, r,
|
||||
@@ -40,7 +51,7 @@ func handleNewReply(w http.ResponseWriter, r *http.Request) {
|
||||
errw.ErrorWriter(errw.MakeErrorWithTitle("I'm sorry but I can't do that", "These are too many characters"), w, r)
|
||||
return
|
||||
}
|
||||
if len(reply.Text) < 10 {
|
||||
if len(reply.Text) < 5 {
|
||||
errw.ErrorWriter(errw.MakeErrorWithTitle("I'm sorry but I can't do that", "These are not enough characters"), w, r)
|
||||
return
|
||||
}
|
||||
@@ -53,6 +64,36 @@ func handleNewReply(w http.ResponseWriter, r *http.Request) {
|
||||
return
|
||||
}
|
||||
|
||||
{
|
||||
file, _, err := r.FormFile("image")
|
||||
if err != nil && err != http.ErrMissingFile {
|
||||
errw.ErrorWriter(err, w, r)
|
||||
return
|
||||
} else if err != http.ErrMissingFile {
|
||||
img, _, err := image.Decode(file)
|
||||
if err != nil {
|
||||
errw.ErrorWriter(err, w, r)
|
||||
return
|
||||
}
|
||||
thumb := resize.Thumbnail(128, 128, img, resize.Lanczos3)
|
||||
imgBuf := bytes.NewBuffer([]byte{})
|
||||
err = png.Encode(imgBuf, img)
|
||||
if err != nil {
|
||||
errw.ErrorWriter(err, w, r)
|
||||
return
|
||||
}
|
||||
fmt.Println("Image has size ", len(imgBuf.Bytes()))
|
||||
reply.Image = imgBuf.Bytes()
|
||||
imgBuf = bytes.NewBuffer([]byte{})
|
||||
err = png.Encode(imgBuf, thumb)
|
||||
if err != nil {
|
||||
errw.ErrorWriter(err, w, r)
|
||||
return
|
||||
}
|
||||
reply.Thumbnail = imgBuf.Bytes()
|
||||
}
|
||||
}
|
||||
|
||||
reply.Metadata = map[string]string{}
|
||||
if r.FormValue("tripcode") != "" {
|
||||
reply.Metadata["trip"] = resources.CalcTripCode(r.FormValue("tripcode"))
|
||||
|
@@ -1,12 +1,16 @@
|
||||
package board
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"github.com/nfnt/resize"
|
||||
"github.com/pressly/chi"
|
||||
"github.com/tidwall/buntdb"
|
||||
"go.rls.moe/nyx/http/errw"
|
||||
"go.rls.moe/nyx/http/middle"
|
||||
"go.rls.moe/nyx/resources"
|
||||
"image"
|
||||
"image/png"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
@@ -16,6 +20,11 @@ func handleNewThread(w http.ResponseWriter, r *http.Request) {
|
||||
errw.ErrorWriter(err, w, r)
|
||||
return
|
||||
}
|
||||
err = r.ParseMultipartForm(10 * 1024 * 1024)
|
||||
if err != nil {
|
||||
errw.ErrorWriter(err, w, r)
|
||||
return
|
||||
}
|
||||
|
||||
if !resources.VerifyCaptcha(r) {
|
||||
http.Redirect(w, r,
|
||||
@@ -35,7 +44,7 @@ func handleNewThread(w http.ResponseWriter, r *http.Request) {
|
||||
errw.ErrorWriter(errw.MakeErrorWithTitle("I'm sorry but I can't do that", "These are too many characters"), w, r)
|
||||
return
|
||||
}
|
||||
if len(mainReply.Text) < 10 {
|
||||
if len(mainReply.Text) < 5 {
|
||||
errw.ErrorWriter(errw.MakeErrorWithTitle("I'm sorry but I can't do that", "These are not enough characters"), w, r)
|
||||
return
|
||||
}
|
||||
@@ -48,6 +57,36 @@ func handleNewThread(w http.ResponseWriter, r *http.Request) {
|
||||
return
|
||||
}
|
||||
|
||||
{
|
||||
file, _, err := r.FormFile("image")
|
||||
if err != nil && err != http.ErrMissingFile {
|
||||
errw.ErrorWriter(err, w, r)
|
||||
return
|
||||
} else if err != http.ErrMissingFile {
|
||||
img, _, err := image.Decode(file)
|
||||
if err != nil {
|
||||
errw.ErrorWriter(err, w, r)
|
||||
return
|
||||
}
|
||||
thumb := resize.Thumbnail(128, 128, img, resize.Lanczos3)
|
||||
imgBuf := bytes.NewBuffer([]byte{})
|
||||
err = png.Encode(imgBuf, img)
|
||||
if err != nil {
|
||||
errw.ErrorWriter(err, w, r)
|
||||
return
|
||||
}
|
||||
fmt.Println("Image has size ", len(imgBuf.Bytes()))
|
||||
mainReply.Image = imgBuf.Bytes()
|
||||
imgBuf = bytes.NewBuffer([]byte{})
|
||||
err = png.Encode(imgBuf, thumb)
|
||||
if err != nil {
|
||||
errw.ErrorWriter(err, w, r)
|
||||
return
|
||||
}
|
||||
mainReply.Thumbnail = imgBuf.Bytes()
|
||||
}
|
||||
}
|
||||
|
||||
mainReply.Metadata = map[string]string{}
|
||||
if r.FormValue("tripcode") != "" {
|
||||
mainReply.Metadata["trip"] = resources.CalcTripCode(r.FormValue("tripcode"))
|
||||
|
@@ -2,10 +2,14 @@
|
||||
<div class="postarea">
|
||||
{{ if .Thread }}
|
||||
<form id="postform"
|
||||
action="/{{.Board.ShortName}}/{{.Thread.ID}}/reply.sh" method="POST">
|
||||
action="/{{.Board.ShortName}}/{{.Thread.ID}}/reply.sh"
|
||||
method="POST"
|
||||
enctype="multipart/form-data">
|
||||
{{ else }}
|
||||
<form id="postform"
|
||||
action="/{{.Board.ShortName}}/new_thread.sh" method="POST">
|
||||
action="/{{.Board.ShortName}}/new_thread.sh"
|
||||
method="POST"
|
||||
enctype="multipart/form-data">
|
||||
{{ end }}
|
||||
<table>
|
||||
<tbody>
|
||||
@@ -41,7 +45,7 @@
|
||||
placeholder="your comment"
|
||||
rows="4"
|
||||
cols="48"
|
||||
minlength="10"
|
||||
minlength="5"
|
||||
required
|
||||
></textarea>
|
||||
</td>
|
||||
@@ -97,9 +101,7 @@
|
||||
Anonymous
|
||||
{{ end }}
|
||||
</span></label>
|
||||
<span class="reflink">
|
||||
<a href="/{{.Boardlink}}/{{.ThreadID}}/thread.html">No.{{.Reply.ID}}</a>
|
||||
</span>
|
||||
<span class="date">{{dateFromID .Reply.ID | formatDate}}</span>
|
||||
{{ if .Session }}
|
||||
{{ if eq (.Session.CAttr "mode") "admin" }}
|
||||
<form class="delform" action="/mod/del_reply.sh" method="POST">
|
||||
@@ -126,6 +128,18 @@
|
||||
<span>
|
||||
{{printf "[SpamScore: %f]" (rateSpam .Reply.Text) }}
|
||||
</span>
|
||||
<span class="reflink">
|
||||
<a href="/{{.Boardlink}}/{{.ThreadID}}/thread.html">No.{{.Reply.ID}}</a>
|
||||
</span>
|
||||
{{ if .Reply.Thumbnail }}
|
||||
<br />
|
||||
<a target="_blank" href="/{{.Boardlink}}/{{.ThreadID}}/{{.Reply.ID}}/{{.Reply.ID}}.png">
|
||||
<img
|
||||
src="/{{.Boardlink}}/{{.ThreadID}}/{{.Reply.ID}}/thumb.png"
|
||||
class="thumb"
|
||||
/>
|
||||
</a>
|
||||
{{ end }}
|
||||
{{ if .Reply.Metadata.deleted }}
|
||||
<blockquote><blockquote class="deleted">
|
||||
{{ renderText .Reply.Text }}
|
||||
@@ -152,7 +166,7 @@
|
||||
{{ end }}
|
||||
{{range .GetReplies}}
|
||||
{{ if ne .ID $threadrid }}
|
||||
<table><tbody><tr><td class="doubledash">>></td>
|
||||
<table class="reply-table"><tbody><tr><td class="doubledash">>></td>
|
||||
<td class="reply" id="reply{{.ID}}">
|
||||
{{ with dict "Reply" . "Boardlink" $boardlink "CSRF" $csrf "ThreadID" $threadid "Session" $session }}
|
||||
{{ template "thread/reply" . }}
|
||||
|
@@ -16,9 +16,17 @@ div {
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
blockquote blockquote { max-width: 80%; word-wrap: break-word; white-space: normal; }
|
||||
blockquote blockquote {
|
||||
word-wrap: break-word;
|
||||
word-break: break-all;
|
||||
white-space: normal;
|
||||
padding: 2px;
|
||||
margin-bottom: 1em;
|
||||
margin-top: 1em;
|
||||
margin-left: 40px;
|
||||
margin-right: 40px;
|
||||
}
|
||||
|
||||
.reply blockquote, blockquote :last-child { max-width: 80%; word-wrap: break-word; white-space: normal; }
|
||||
|
||||
.delform {
|
||||
display: inline;
|
||||
@@ -31,4 +39,12 @@ blockquote blockquote { max-width: 80%; word-wrap: break-word; white-space: norm
|
||||
|
||||
.deleted {
|
||||
color: #707070;
|
||||
}
|
||||
|
||||
.reply-table {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.reply {
|
||||
display: table;
|
||||
}
|
@@ -143,14 +143,13 @@ a:hover {
|
||||
|
||||
/* futaba_style.pl */
|
||||
|
||||
blockquote blockquote { margin-left: 0em; }
|
||||
form { margin-bottom: 0px }
|
||||
form .trap { display:none }
|
||||
.postarea { text-align: center }
|
||||
.postarea table { margin: 0px auto; text-align: left }
|
||||
.thumb { border: none; float: left; margin: 2px 20px }
|
||||
.nothumb { float: left; background: #eee; border: 2px dashed #aaa; text-align: center; margin: 2px 20px; padding: 1em 0.5em 1em 0.5em; }
|
||||
.reply blockquote, blockquote :last-child { margin-bottom: 0em; }
|
||||
|
||||
.reflink a { color: inherit; text-decoration: none }
|
||||
.reply .filesize { margin-left: 20px }
|
||||
.userdelete { float: right; text-align: center; white-space: nowrap }
|
||||
|
Reference in New Issue
Block a user