1
0
Fork 0
mirror of https://github.com/Eggbertx/gochan.git synced 2025-08-24 08:46:24 -07:00

Make template for recent posts page

Also make manage page h1 headers automatic
This commit is contained in:
Eggbertx 2022-01-29 23:47:13 -08:00
parent 33388612d7
commit 8e706a313c
15 changed files with 128 additions and 113 deletions

View file

@ -534,6 +534,11 @@ div.section-block div.section-body {
padding: 8px;
}
.centered {
display: block;
text-align: center;
}
#footer {
bottom: 0px;
clear: both;

View file

@ -206,25 +206,22 @@ func getSpecificPostStringDecorated(ID string, onlyNotDeleted bool) (Post, error
// getRecentPostsInternal returns the most recent N posts, on a specific board if specified, only with files if specified
// Deprecated: This method was created to support old functionality during the database refactor of april 2020
// The code should be changed to reflect the new database design
// TODO: rework so it uses all features/better sql
// get recent posts
func getRecentPostsInternal(amount int, onlyWithFile bool, boardID int, onSpecificBoard bool) ([]RecentPost, error) {
//TODO: rework so it uses all features/better sql
//get recent posts
recentQueryStr := `
/*
recentposts = join all non-deleted posts with the post id of their thread and the board it belongs on, sort by date and grab top x posts
singlefiles = the top file per post id
Left join singlefiles on recentposts where recentposts.selfid = singlefiles.post_id
Coalesce filenames to "" (if filename = null -> "" else filename)
Query might benefit from [filter on posts with at least one file -> ] filter N most recent -> manually loop N results for file/board/parentthreadid
*/
Select
// recentposts = join all non-deleted posts with the post id of their thread and the board it belongs on, sort by date and grab top x posts
// singlefiles = the top file per post id
// Left join singlefiles on recentposts where recentposts.selfid = singlefiles.post_id
// Coalesce filenames to "" (if filename = null -> "" else filename)
// Query might benefit from [filter on posts with at least one file -> ] filter N most recent -> manually loop N results for file/board/parentthreadid
recentQueryStr := `SELECT
recentposts.selfid AS id,
recentposts.toppostid AS parentid,
recentposts.boardname,
recentposts.boardid,
recentposts.ip,
recentposts.name,
recentposts.tripcode,
recentposts.message,
@ -237,11 +234,12 @@ func getRecentPostsInternal(amount int, onlyWithFile bool, boardID int, onSpecif
topposts.id AS toppostid,
boards.dir AS boardname,
boards.id AS boardid,
posts.ip,
posts.name,
posts.tripcode,
posts.message,
posts.email,
posts.created_on
posts.created_on
FROM
DBPREFIXposts AS posts
JOIN DBPREFIXthreads AS threads
@ -252,7 +250,6 @@ func getRecentPostsInternal(amount int, onlyWithFile bool, boardID int, onSpecif
ON threads.board_id = boards.id
WHERE
topposts.is_top_post = TRUE AND posts.is_deleted = FALSE
) as recentposts
LEFT JOIN
(SELECT files.post_id, filename, files.thumbnail_width, files.thumbnail_height
@ -299,7 +296,8 @@ func getRecentPostsInternal(amount int, onlyWithFile bool, boardID int, onSpecif
var formattedHTML template.HTML
if err = rows.Scan(
&recentPost.PostID, &recentPost.ParentID, &recentPost.BoardName, &recentPost.BoardID,
&recentPost.Name, &recentPost.Tripcode, &formattedHTML, &recentPost.Filename, &recentPost.ThumbW, &recentPost.ThumbH,
&recentPost.IP, &recentPost.Name, &recentPost.Tripcode, &formattedHTML, &recentPost.Filename,
&recentPost.ThumbW, &recentPost.ThumbH,
); err != nil {
return nil, err
}

View file

@ -13,7 +13,6 @@ import (
"github.com/gochan-org/gochan/pkg/config"
"github.com/gochan-org/gochan/pkg/gcsql"
"github.com/gochan-org/gochan/pkg/gcutil"
x_html "golang.org/x/net/html"
)
var (
@ -63,7 +62,6 @@ var funcMap = template.FuncMap{
},
// String functions
// "arrToString": arrToString,
"intToString": strconv.Itoa,
"escapeString": html.EscapeString,
"formatFilesize": func(sizeInt int) string {
@ -128,19 +126,7 @@ var funcMap = template.FuncMap{
},
"truncateHTMLMessage": truncateHTML,
"stripHTML": func(htmlStr template.HTML) string {
dom := x_html.NewTokenizer(strings.NewReader(string(htmlStr)))
for tokenType := dom.Next(); tokenType != x_html.ErrorToken; {
if tokenType != x_html.TextToken {
tokenType = dom.Next()
continue
}
txtContent := strings.TrimSpace(x_html.UnescapeString(string(dom.Text())))
if len(txtContent) > 0 {
return x_html.EscapeString(txtContent)
}
tokenType = dom.Next()
}
return ""
return gcutil.StripHTML(string(htmlStr))
},
"truncateString": func(msg string, limit int, ellipsis bool) string {
if len(msg) > limit {

View file

@ -11,23 +11,24 @@ import (
)
var (
Banpage *template.Template
Captcha *template.Template
Catalog *template.Template
ErrorPage *template.Template
FrontPage *template.Template
BoardPage *template.Template
JsConsts *template.Template
ManageBans *template.Template
ManageBoards *template.Template
ManageConfig *template.Template
ManageDashboard *template.Template
ManageLogin *template.Template
ManageStaff *template.Template
PageHeader *template.Template
PageFooter *template.Template
PostEdit *template.Template
ThreadPage *template.Template
Banpage *template.Template
Captcha *template.Template
Catalog *template.Template
ErrorPage *template.Template
FrontPage *template.Template
BoardPage *template.Template
JsConsts *template.Template
ManageBans *template.Template
ManageBoards *template.Template
ManageConfig *template.Template
ManageDashboard *template.Template
ManageRecentPosts *template.Template
ManageLogin *template.Template
ManageStaff *template.Template
PageHeader *template.Template
PageFooter *template.Template
PostEdit *template.Template
ThreadPage *template.Template
)
func loadTemplate(files ...string) (*template.Template, error) {
@ -153,6 +154,12 @@ func templateLoading(t string, buildAll bool) error {
return templateError("manage_login.html", err)
}
}
if buildAll || t == "managerecents" {
ManageRecentPosts, err = loadTemplate("manage_recentposts.html")
if err != nil {
return templateError("manage_recentposts.html", err)
}
}
if buildAll || t == "managestaff" {
ManageStaff, err = loadTemplate("manage_staff.html")
if err != nil {

View file

@ -21,6 +21,7 @@ import (
"github.com/aquilax/tripcode"
"golang.org/x/crypto/bcrypt"
x_html "golang.org/x/net/html"
)
const (
@ -258,6 +259,22 @@ func RandomString(length int) string {
return str
}
func StripHTML(htmlIn string) string {
dom := x_html.NewTokenizer(strings.NewReader(htmlIn))
for tokenType := dom.Next(); tokenType != x_html.ErrorToken; {
if tokenType != x_html.TextToken {
tokenType = dom.Next()
continue
}
txtContent := strings.TrimSpace(x_html.UnescapeString(string(dom.Text())))
if len(txtContent) > 0 {
return x_html.EscapeString(txtContent)
}
tokenType = dom.Next()
}
return ""
}
func ThumbnailExtension(filename string) string {
ext := filepath.Ext(strings.ToLower(filename))
switch ext {

View file

@ -85,7 +85,7 @@ var actions = []Action{
Title: "Cleanup",
Permissions: AdminPerms,
Callback: func(writer http.ResponseWriter, request *http.Request, wantsJSON bool) (output interface{}, err error) {
outputStr := `<h2>Cleanup</h2><br />`
outputStr := ""
if request.FormValue("run") == "Run Cleanup" {
outputStr += "Removing deleted posts from the database.<hr />"
if err = gcsql.PermanentlyRemoveDeletedPosts(); err != nil {
@ -117,46 +117,25 @@ var actions = []Action{
Permissions: JanitorPerms,
JSONoutput: OptionalJSON,
Callback: func(writer http.ResponseWriter, request *http.Request, wantsJSON bool) (output interface{}, err error) {
var outputStr string
systemCritical := config.GetSystemCriticalConfig()
limit := gcutil.HackyStringToInt(request.FormValue("limit"))
if limit == 0 {
limit = 50
}
output = `<h1 class="manage-header">Recent posts</h1>` +
`Limit by: <select id="limit">` +
`<option>25</option><option>50</option><option>100</option><option>200</option>` +
`</select><br /><table width="100%%d" border="1">` +
`<colgroup><col width="25%%" /><col width="50%%" /><col width="17%%" /></colgroup>` +
`<tr><th></th><th>Message</th><th>Time</th></tr>`
recentposts, err := gcsql.GetRecentPostsGlobal(limit, false) //only uses boardname, boardid, postid, parentid, message, ip and timestamp
if wantsJSON {
if wantsJSON || err != nil {
return recentposts, err
}
if err != nil {
errMsg := gclog.Println(gclog.LErrorLog, "Error getting recent posts:", err.Error())
err = errors.New(errMsg)
if wantsJSON {
return ErrStaffAction{
ErrorField: "recentpostserror",
Action: "recentposts",
Message: errMsg,
}, err
}
return errMsg, err
manageRecentsBuffer := bytes.NewBufferString("")
if err = serverutil.MinifyTemplate(gctemplates.ManageRecentPosts,
map[string]interface{}{
"recentposts": recentposts,
"webroot": config.GetSystemCriticalConfig().WebRoot,
},
manageRecentsBuffer, "text/html"); err != nil {
return "", errors.New(gclog.Print(gclog.LErrorLog,
"Error executing ban management page template: "+err.Error()))
}
for _, recentpost := range recentposts {
outputStr += fmt.Sprintf(
`<tr><td><b>Post:</b> <a href="%s">%s/%d</a><br /><b>IP:</b> %s</td><td>%s</td><td>%s</td></tr>`,
path.Join(systemCritical.WebRoot, recentpost.BoardName, "/res/", strconv.Itoa(recentpost.ParentID)+".html#"+strconv.Itoa(recentpost.PostID)),
recentpost.BoardName, recentpost.PostID, recentpost.IP, string(recentpost.Message),
recentpost.Timestamp.Format("01/02/06, 15:04"),
)
}
outputStr += "</table>"
return
return manageRecentsBuffer.String(), nil
}},
{
ID: "bans",
@ -457,7 +436,7 @@ var actions = []Action{
"front": "Built front page successfully",
}, err
}
return "<h2>Build front page</h2>Built front page successfully", err
return "Built front page successfully", err
}},
{
ID: "rebuildall",
@ -513,33 +492,32 @@ var actions = []Action{
if wantsJSON {
return buildMap, nil
}
buildStr := "<h2>Rebuilding everything</h2>"
buildStr := ""
for _, msg := range buildMap {
buildStr += fmt.Sprintln(msg, "<hr />")
}
return buildStr, nil
}},
{
ID: "rebuildboard",
Title: "Rebuild board",
Permissions: AdminPerms,
Callback: func(writer http.ResponseWriter, request *http.Request, wantsJSON bool) (output interface{}, err error) {
return "Not implemented (yet)", gcutil.ErrNotImplemented
// if err = gctemplates.InitTemplates(); err != nil {
// return "", err
// }
// {
// ID: "rebuildboard",
// Title: "Rebuild board",
// Permissions: AdminPerms,
// Callback: func(writer http.ResponseWriter, request *http.Request, wantsJSON bool) (output interface{}, err error) {
// if err = gctemplates.InitTemplates(); err != nil {
// return "", err
// }
// for b, board := range request.Form {
// if b == "board" {
// return board[0], nil
// }
// }
// return "", &ErrStaffAction{
// ErrorField: "staffaction",
// Action: "rebuildboard",
// Message: fmt.Sprintf("/%s/ is not a board"),
// }
}},
// for b, board := range request.Form {
// if b == "board" {
// return board[0], nil
// }
// }
// return "", &ErrStaffAction{
// ErrorField: "staffaction",
// Action: "rebuildboard",
// Message: fmt.Sprintf("/%s/ is not a board"),
// }
// }},
{
ID: "rebuildboards",
Title: "Rebuild boards",
@ -555,7 +533,7 @@ var actions = []Action{
"message": "Boards built successfully",
}, building.BuildBoards(false)
}
return "<h2>Rebuild boards</h2>Boards built successfully", building.BuildBoards(false)
return "Boards built successfully", building.BuildBoards(false)
}},
{
ID: "reparsehtml",
@ -607,7 +585,7 @@ var actions = []Action{
Title: "Temporary posts lists",
Permissions: AdminPerms,
Callback: func(writer http.ResponseWriter, request *http.Request, wantsJSON bool) (output interface{}, err error) {
outputStr := `<h1>Temporary posts</h1>`
outputStr := ""
if len(gcsql.TempPosts) == 0 {
outputStr += "No temporary posts<br />"
return

View file

@ -64,6 +64,11 @@ div.section-block {
}
}
.centered {
display: block;
text-align: center;
}
#footer {
bottom:0px;
clear:both;

View file

@ -1,4 +1,3 @@
<h1>Ban user</h1>
<form method="POST" action="/manage?action=bans">
<input type="hidden" name="do" value="add" />
<b>User filter:</b><br />

View file

@ -1,4 +1,3 @@
<h2>Manage Boards</h2>
<form action="{{$.webroot}}manage?action=boards" method="GET">
<input type="hidden" name="action" value="boards">
{{with $.boards}}{{else}}

View file

@ -1,4 +1,3 @@
<h1>Config editor</h1>
{{if ne .status ""}}{{.status}}<hr />{{end}}
Some fields omitted because they can not be (safely) edited from the web interface while Gochan is running.
Edit these directly in gochan.json, then restart Gochan.<br />

View file

@ -1,4 +1,3 @@
<h2>Dashboard</h2>
<fieldset><legend>Announcements</legend>
{{range $a, $announcement := $.announcements}}
<div class="announcement">

View file

@ -1,4 +1,3 @@
<h1>Login</h1><br />
<form method="POST" action="{{.webroot}}manage?action=login" id="login-box" class="staff-form">
<input type="hidden" name="redirect" value="{{.redirect}}" />
<table>

View file

@ -0,0 +1,24 @@
<!-- Limit by: <select id="limitby">
<option>25</option>
<option>50</option>
<option>100</option>
<option>200</option>
</select><br /><br /> -->
<table width="100%" border="1">
<colgroup><col width="5%"><col width="15%"><col width="60%"><col width="15%"></colgroup>
<tr><th></th><th>Name</th><th>Message</th><th>Thumb</th></tr>
{{range $rp, $post := $.recentposts}}
<tr><td><a href="{{$post.BoardName}}/res/{{if eq $post.ParentID 0}}{{$post.ID}}{{else}}{{$post.ParentID}}{{end}}.html#{{$post.PostID}}" class="centered">Post</a></td>
<td><b>Name: </b> {{- if and (eq $post.Name "") (eq $post.Tripcode "")}}<span class="postername">Anonymous</span>{{end}}
{{- if ne $post.Name ""}}<span class="postername">{{$post.Name}}</span>{{end -}}
{{- if ne $post.Tripcode ""}}!<span class="tripcode">{{$post.Tripcode}}</span>{{end -}}<br />
<b>IP: </b> {{$post.IP}}</td>
<td>{{truncateMessage (stripHTML $post.Message) 300 16}}</td><td>
{{- if eq $post.Filename "deleted" -}}
<div class="file-deleted-box centered" style="text-align:center;">File removed</div>
{{- else if ne $post.Filename "" -}}
{{- $thumbURL := stringAppend $.webroot $post.BoardName "/thumb/" (getThreadThumbnail $post.Filename) -}}
{{- $uploadURL := stringAppend $.webroot $post.BoardName "/src/" $post.Filename -}}
<a href="{{$uploadURL}}" target="_blank" class="centered"><img src="{{$thumbURL}}"></a>
{{end}}</td></tr>{{end}}
</table>

View file

@ -1,4 +1,3 @@
<h1 class="manage-header">Staff</h1><br />
<table id="stafftable" border="1">
<tr>
<td><b>Username</b></td>

View file

@ -20,4 +20,5 @@
<div id="topbar">
<a href="{{$.webroot}}" class="topbar-item">home</a>
{{range $i, $board := .boards}}<a href="{{$.webroot}}{{$board.Dir}}/" class="topbar-item" title="{{$board.Title}}">/{{$board.Dir}}/</a>{{end}}
</div>
</div>
{{with $.page_title}}<br /><h1>{{$.page_title}}</h1>{{end}}