0
0
mirror of https://github.com/rls-moe/nyx synced 2025-08-19 06:18:38 +00:00

MVP, no mod tools or anything but it works

This commit is contained in:
Tim Schuster
2017-03-12 20:37:53 +01:00
parent 70b12c516a
commit 69b0d20825
186 changed files with 44200 additions and 0 deletions

52
http/board/board.go Normal file
View File

@@ -0,0 +1,52 @@
package board
import (
"bytes"
"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"
"log"
"net/http"
"time"
)
func serveBoard(w http.ResponseWriter, r *http.Request) {
dat := bytes.NewBuffer([]byte{})
db := middle.GetDB(r)
ctx := middle.GetBaseCtx(r)
err := db.View(func(tx *buntdb.Tx) error {
bName := chi.URLParam(r, "board")
b, err := resources.GetBoard(tx, r.Host, bName)
if err != nil {
return err
}
ctx["Board"] = b
threads, err := resources.ListThreads(tx, r.Host, bName)
if err != nil {
return err
}
log.Println("Number of Thread on board: ", len(threads))
for k := range threads {
err := resources.FillReplies(tx, r.Host, threads[k])
if err != nil {
return err
}
}
ctx["Threads"] = threads
return nil
})
if err != nil {
errw.ErrorWriter(err, w, r)
return
}
err = boardTmpl.Execute(dat, ctx)
if err != nil {
errw.ErrorWriter(err, w, r)
return
}
http.ServeContent(w, r, "board.html", time.Now(), bytes.NewReader(dat.Bytes()))
}

88
http/board/handler.go Normal file
View File

@@ -0,0 +1,88 @@
package board
import (
"bytes"
"github.com/GeertJohan/go.rice"
"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"
"html/template"
"net/http"
"time"
)
var riceConf = rice.Config{
LocateOrder: []rice.LocateMethod{
rice.LocateWorkingDirectory,
rice.LocateEmbedded,
rice.LocateAppended,
},
}
var box = riceConf.MustFindBox("http/board/res/")
var (
dirTmpl = template.New("board/dir")
boardTmpl = template.New("board/board")
threadTmpl = template.New("board/thread")
hdlFMap = template.FuncMap{
"renderText": resources.OperateReplyText,
}
)
func init() {
var err error
dirTmpl, err = dirTmpl.Parse(box.MustString("dir.html"))
if err != nil {
panic(err)
}
boardTmpl, err = boardTmpl.Funcs(hdlFMap).Parse(box.MustString("board.html"))
if err != nil {
panic(err)
}
threadTmpl, err = threadTmpl.Funcs(hdlFMap).Parse(box.MustString("thread.html"))
if err != nil {
panic(err)
}
}
func Router(r chi.Router) {
r.Get("/", serveDir)
r.Get("/dir.html", serveDir)
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.Post("/:board/:thread/reply.sh", handleNewReply)
}
func servePost(w http.ResponseWriter, r *http.Request) {
return
}
func serveDir(w http.ResponseWriter, r *http.Request) {
dat := bytes.NewBuffer([]byte{})
db := middle.GetDB(r)
ctx := middle.GetBaseCtx(r)
err := db.View(func(tx *buntdb.Tx) error {
bList, err := resources.ListBoards(tx, r.Host)
if err != nil {
return err
}
ctx["Boards"] = bList
return nil
})
if err != nil {
errw.ErrorWriter(err, w, r)
return
}
err = dirTmpl.Execute(dat, ctx)
if err != nil {
errw.ErrorWriter(err, w, r)
return
}
http.ServeContent(w, r, "dir.html", time.Now(), bytes.NewReader(dat.Bytes()))
}

59
http/board/newreply.go Normal file
View File

@@ -0,0 +1,59 @@
package board
import (
"fmt"
"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"
"net/http"
"strconv"
)
func handleNewReply(w http.ResponseWriter, r *http.Request) {
err := r.ParseForm()
if err != nil {
errw.ErrorWriter(err, w, r)
return
}
var reply = &resources.Reply{}
reply.Board = chi.URLParam(r, "board")
tid, err := strconv.Atoi(chi.URLParam(r, "thread"))
if err != nil {
errw.ErrorWriter(err, w, r)
return
}
reply.Thread = int64(tid)
reply.Text = r.FormValue("text")
if len(reply.Text) > 1000 {
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 {
errw.ErrorWriter(errw.MakeErrorWithTitle("I'm sorry but I can't do that", "These are not enough characters"), w, r)
return
}
reply.Metadata = map[string]string{}
if r.FormValue("tripcode") != "" {
reply.Metadata["trip"] = resources.CalcTripCode(r.FormValue("tripcode"))
} else {
reply.Metadata["trip"] = "Anonymous"
}
db := middle.GetDB(r)
if err = db.Update(func(tx *buntdb.Tx) error {
thread, err := resources.GetThread(tx, r.Host, reply.Board, reply.Thread)
if err != nil {
return err
}
return resources.NewReply(tx, r.Host, reply.Board, thread, reply, false)
}); err != nil {
errw.ErrorWriter(err, w, r)
return
}
http.Redirect(w, r, fmt.Sprintf("/%s/%d/thread.html", chi.URLParam(r, "board"), reply.Thread), http.StatusSeeOther)
}

48
http/board/newthread.go Normal file
View File

@@ -0,0 +1,48 @@
package board
import (
"fmt"
"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"
"net/http"
)
func handleNewThread(w http.ResponseWriter, r *http.Request) {
err := r.ParseForm()
if err != nil {
errw.ErrorWriter(err, w, r)
return
}
var thread = &resources.Thread{}
var mainReply = &resources.Reply{}
mainReply.Board = chi.URLParam(r, "board")
thread.Board = chi.URLParam(r, "board")
mainReply.Text = r.FormValue("text")
if len(mainReply.Text) > 1000 {
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 {
errw.ErrorWriter(errw.MakeErrorWithTitle("I'm sorry but I can't do that", "These are not enough characters"), w, r)
return
}
mainReply.Metadata = map[string]string{}
if r.FormValue("tripcode") != "" {
mainReply.Metadata["trip"] = resources.CalcTripCode(r.FormValue("tripcode"))
}
db := middle.GetDB(r)
if err = db.Update(func(tx *buntdb.Tx) error {
return resources.NewThread(tx, r.Host, mainReply.Board, thread, mainReply)
}); err != nil {
errw.ErrorWriter(err, w, r)
return
}
http.Redirect(w, r, fmt.Sprintf("/%s/%d/thread.html", chi.URLParam(r, "board"), thread.ID), http.StatusSeeOther)
}

119
http/board/res/board.html Normal file
View File

@@ -0,0 +1,119 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>{{.Config.Site.Title}} - /{{.Board.ShortName}}/</title>
<link rel="stylesheet" href="/@/style.css">
<link rel="stylesheet" href="/@/custom.css">
</head>
<body>
<div class="banner logo">
<div class="site title"><h1><span class="reflink"><a href="/{{.Board.ShortName}}/board.html">/{{.Board.ShortName}}/</a></span></h1></div>
<div class="site description"><h2>{{.Board.LongName}}</h2></div>
</div>
{{ $boardlink := .Board.ShortName }}
<div class="postarea">
<form id="postform" action="/{{$boardlink}}/new_thread.sh" method="POST">
<table>
<tbody>
<tr>
<td class="postblock">
TripCode
</td>
<td>
<input type="text" name="tripcode" size=48 placeholder="Anonymous"/>
<input
type="hidden"
name="csrf_token"
value="{{ .CSRFToken }}" />
</td>
</tr>
<tr>
<td class="postblock">
Comment
</td>
<td>
<textarea
name="text"
placeholder="your comment"
rows="4"
cols="48"
minlength="10"
required
></textarea>
</td>
</tr>
<tr>
<td class="postblock">
Image File
</td>
<td>
<input type="file" name="image" />
</td>
</tr>
{{ if ne .Config.Captcha.Mode "disabled" }}
<tr>
<td class="postblock">
Captcha
</td>
<td>
<input type="text" name="captcha" size=48 />
<input type="hidden"
value="{{.CaptchaToken}}"/>
<img alt=""
src="{{.CaptchaImage}}" />
</td>
</tr>
{{ end }}
<tr>
<td class="postblock">
</td>
<td>
<input type="submit" value="Post" />
</td>
</tr>
</tbody>
</table>
</form>
</div>
<hr />
<div class="postlists">
{{range .Threads}}
{{ $threadrid := .GetReply.ID }}
<label><span class="postertrip">
{{ if .GetReply.Metadata.trip }}
{{.GetReply.Metadata.trip}}
{{ else }}
Anonymous
{{ end }}
</span></label>
<span class="reflink"><a href="/{{$boardlink}}/{{.ID}}/thread.html">No.{{.ID}}</a></span>
<blockquote><blockquote>
{{ renderText .GetReply.Text}}
</blockquote></blockquote>
{{range .GetReplies}}
{{ if ne .ID $threadrid }}
<table><tbody><tr><td class="doubledash">&gt;&gt;</td>
<td class="reply" id="reply{{.ID}}">
<label><span class="postertrip">
{{ if .Metadata.trip }}
{{.Metadata.trip}}
{{ else }}
Anonymous
{{ end }}
</span></label>
<span class="reflink"><a href="/{{$boardlink}}/{{.Thread}}/thread.html">No.{{.ID}}</a></span>
<blockquote><blockquote>
{{ renderText .Text}}
</blockquote></blockquote>
</td>
</tr></tbody></table>
{{end}}
{{end}}
<br clear="left" /><hr />
{{end}}
</div>
</body>
</html>

30
http/board/res/dir.html Normal file
View File

@@ -0,0 +1,30 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>{{.Config.Site.Title}} Boards</title>
<link rel="stylesheet" href="/@/style.css">
<link rel="stylesheet" href="/@/custom.css">
</head>
<body>
<div class="banner logo">
<div class="site title"><h1>{{.Config.Site.Title}}</h1></div>
<div class="site description"><h2>{{.Config.Site.Description}}</h2></div>
</div>
<div class="boardlist">
<div class="boardtitle">
<h3>Boards</h3>
</div>
<div class="boardlist">
<ul>
{{range .Boards}}
<li>
<a class="boardlink" href="/{{ .ShortName}}/board.html">{{.ShortName}}: {{.LongName}}</a>
</li>
{{end}}
</ul>
</div>
</div>
</body>
</html>

129
http/board/res/thread.html Normal file
View File

@@ -0,0 +1,129 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>{{.Config.Site.Title}} - /{{.Board.ShortName}}/</title>
<link rel="stylesheet" href="/@/style.css">
<link rel="stylesheet" href="/@/custom.css">
</head>
<body>
<div class="banner logo">
<div class="site title"><h1><span class="reflink"><a href="/{{.Board.ShortName}}/board.html">/{{.Board.ShortName}}/</a></span></h1></div>
<div class="site description"><h2>{{.Board.LongName}}</h2></div>
</div>
{{ $boardlink := .Board.ShortName }}
<hr />
<div class="postarea">
<form id="postform" action="/{{.Board.ShortName}}/{{.Thread.ID}}/reply.sh" method="POST">
<table>
<tbody>
<tr>
<td class="postblock">
TripCode
</td>
<td>
<input type="text" name="tripcode" size=48 placeholder="Anonymous"/>
<input
type="hidden"
name="csrf_token"
value="{{ .CSRFToken }}" />
</td>
</tr>
<tr>
<td class="postblock">
Comment
</td>
<td>
<textarea
name="text"
placeholder="your comment"
rows="4"
cols="48"
minlength="10"
required
></textarea>
</td>
</tr>
<tr>
<td class="postblock">
Image File
</td>
<td>
<input type="file" name="image" />
</td>
</tr>
{{ if ne .Config.Captcha.Mode "disabled" }}
<tr>
<td class="postblock">
Captcha
</td>
<td>
<input type="text" name="captcha" size=48 />
<input type="hidden"
value="{{.CaptchaToken}}"/>
<img alt=""
src="{{.CaptchaImage}}" />
</td>
</tr>
{{ end }}
<tr>
<td class="postblock">
</td>
<td>
<input type="submit" value="Post" />
</td>
</tr>
{{ if .Board.Metadata.rules }}
<tr>
<td class="postblock">
Rules
</td>
<td>
{{ .Board.Metadata.rules }}
</td>
</tr>
{{ end }}
</tbody>
</table>
</form>
</div>
<div class="postlists">
{{with .Thread }}
{{ $threadrid := .GetReply.ID }}
<label><span class="postertrip">
{{ if .GetReply.Metadata.trip }}
{{.GetReply.Metadata.trip}}
{{ else }}
Anonymous
{{ end }}
</span></label>
<span class="reflink"><a href="/{{$boardlink}}/{{.ID}}/thread.html">No.{{.ID}}</a></span>
<blockquote><blockquote>
{{ renderText .GetReply.Text}}
</blockquote></blockquote>
{{range .GetReplies}}
{{ if ne .ID $threadrid }}
<table><tbody><tr><td class="doubledash">&gt;&gt;</td>
<td class="reply" id="reply{{.ID}}">
<label><span class="postertrip">
{{ if .Metadata.trip }}
{{.Metadata.trip}}
{{ else }}
Anonymous
{{ end }}
</span></label>
<span class="reflink"><a href="/{{$boardlink}}/{{.Thread}}/thread.html">No.{{.ID}}</a></span>
<blockquote><blockquote>
{{ renderText .Text}}
</blockquote></blockquote>
</td>
</tr></tbody></table>
{{end}}
{{end}}
<br clear="left" /><hr />
{{end}}
</div>
</body>
</html>

57
http/board/thread.go Normal file
View File

@@ -0,0 +1,57 @@
package board
import (
"bytes"
"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"
"net/http"
"strconv"
"time"
)
func serveThread(w http.ResponseWriter, r *http.Request) {
dat := bytes.NewBuffer([]byte{})
db := middle.GetDB(r)
ctx := middle.GetBaseCtx(r)
err := db.View(func(tx *buntdb.Tx) error {
bName := chi.URLParam(r, "board")
b, err := resources.GetBoard(tx, r.Host, bName)
if err != nil {
return err
}
ctx["Board"] = b
id, err := strconv.Atoi(chi.URLParam(r, "thread"))
if err != nil {
return err
}
thread, err := resources.GetThread(tx, r.Host, bName, int64(id))
if err != nil {
return err
}
err = resources.FillReplies(tx, r.Host, thread)
if err != nil {
return err
}
if err != nil {
return err
}
ctx["Thread"] = thread
return nil
})
if err != nil {
errw.ErrorWriter(err, w, r)
return
}
err = threadTmpl.Execute(dat, ctx)
if err != nil {
errw.ErrorWriter(err, w, r)
return
}
http.ServeContent(w, r, "board.html", time.Now(), bytes.NewReader(dat.Bytes()))
}