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

Add thread attributes manage page

This commit is contained in:
Eggbertx 2023-01-28 15:23:44 -08:00
parent 39fdb320c9
commit 0f0c9362eb
7 changed files with 161 additions and 23 deletions

View file

@ -100,11 +100,10 @@ func GetBoardDirFromPostID(postID int) (string, error) {
return boardURI, err
}
// GetBoardFromID returns the board corresponding to a given id
func GetBoardFromID(id int) (*Board, error) {
const query = selectBoardsBaseSQL + "WHERE DBPREFIXboards.id = ?"
func getBoardBase(where string, whereParameters []interface{}) (*Board, error) {
query := selectBoardsBaseSQL + where
board := new(Board)
err := QueryRowSQL(query, interfaceSlice(id), interfaceSlice(
err := QueryRowSQL(query, whereParameters, interfaceSlice(
&board.ID, &board.SectionID, &board.URI, &board.Dir, &board.NavbarPosition, &board.Title, &board.Subtitle,
&board.Description, &board.MaxFilesize, &board.MaxThreads, &board.DefaultStyle, &board.Locked,
&board.CreatedAt, &board.AnonymousName, &board.ForceAnonymous, &board.AutosageAfter, &board.NoImagesAfter,
@ -114,6 +113,23 @@ func GetBoardFromID(id int) (*Board, error) {
return board, err
}
// GetBoardFromID returns the board corresponding to a given id
func GetBoardFromID(id int) (*Board, error) {
return getBoardBase("WHERE DBPREFIXboards.id = ?", interfaceSlice(id))
}
// GetBoardFromDir returns the board corresponding to a given dir
func GetBoardFromDir(dir string) (*Board, error) {
return getBoardBase("WHERE DBPREFIXboards.dir = ?", interfaceSlice(dir))
}
// GetIDFromDir returns the id of the board with the given dir value
func GetBoardIDFromDir(dir string) (id int, err error) {
const query = `SELECT id FROM DBPREFIXboards WHERE dir = ?`
err = QueryRowSQL(query, interfaceSlice(dir), interfaceSlice(&id))
return id, err
}
// GetBoardURIs gets a list of all existing board URIs
func GetBoardURIs() (URIS []string, err error) {
const sql = `SELECT uri FROM DBPREFIXboards`

View file

@ -86,6 +86,25 @@ func GetTopPostInThread(postID int) (int, error) {
return id, err
}
func GetTopPostIDsInThreadIDs(threads ...interface{}) ([]int, error) {
params := createArrayPlaceholder(threads)
query := `SELECT id FROM DBPREFIXposts WHERE thread_id in ` + params
rows, err := QuerySQL(query, threads...)
if err != nil {
return nil, err
}
defer rows.Close()
var ids []int
for rows.Next() {
var id int
if err = rows.Scan(&id); err != nil {
return nil, err
}
ids = append(ids, id)
}
return ids, nil
}
func GetThreadTopPost(threadID int) (*Post, error) {
const query = selectPostsBaseSQL + "WHERE thread_id = ? AND is_top_post = TRUE LIMIT 1"
post := new(Post)

View file

@ -81,10 +81,11 @@ func GetThreadsWithBoardID(boardID int, onlyNotDeleted bool) ([]Thread, error) {
var thread Thread
if err = rows.Scan(
&thread.ID, &thread.BoardID, &thread.Locked, &thread.Stickied, &thread.Anchored,
&thread.Cyclical, &thread.LastBump,
&thread.Cyclical, &thread.LastBump, &thread.DeletedAt, &thread.IsDeleted,
); err != nil {
return threads, err
}
threads = append(threads, thread)
}
return threads, nil
}

View file

@ -21,6 +21,7 @@ var (
ManageAppeals *template.Template
ManageBans *template.Template
ManageBoards *template.Template
ManageThreadAttrs *template.Template
ManageSections *template.Template
ManageConfig *template.Template
ManageDashboard *template.Template
@ -154,6 +155,12 @@ func templateLoading(t string, buildAll bool) error {
return templateError("manage_boards.html", err)
}
}
if buildAll || t == "managethreadattrs" {
ManageThreadAttrs, err = LoadTemplate("manage_threadattrs.html")
if err != nil {
return templateError("manage_threadattrs.html", err)
}
}
if buildAll || t == "managesections" {
ManageSections, err = LoadTemplate("manage_sections.html")
if err != nil {

View file

@ -741,6 +741,78 @@ var actions = []Action{
outputStr += staffBuffer.String()
return outputStr, nil
}},
{
ID: "threadattrs",
Title: "View/Update Thread Attributes",
Permissions: ModPerms,
JSONoutput: OptionalJSON,
Callback: func(writer http.ResponseWriter, request *http.Request, staff *gcsql.Staff, wantsJSON bool, infoEv, errEv *zerolog.Event) (output interface{}, err error) {
boardDir := request.FormValue("board")
attrBuffer := bytes.NewBufferString("")
if boardDir == "" {
if wantsJSON {
return nil, errors.New(`missing required field "board"`)
}
if err = serverutil.MinifyTemplate(gctemplates.ManageThreadAttrs, map[string]interface{}{
"action": "threadattrs",
"boards": gcsql.AllBoards,
}, attrBuffer, "text/html"); err != nil {
errEv.Err(err).Caller().Send()
return "", err
}
return attrBuffer.String(), nil
}
errEv.Str("boardDir", boardDir)
boardID, err := gcsql.GetBoardIDFromDir(boardDir)
if err != nil {
errEv.Err(err).Caller().Send()
return "", err
}
var updateID int
for name, val := range request.Form {
if len(val) > 0 && val[0] == "Update attributes" {
if _, err = fmt.Sscanf(name, "update-%d", &updateID); err != nil {
return "", fmt.Errorf("invalid input name %q: %s", name, err.Error())
}
}
}
threads, err := gcsql.GetThreadsWithBoardID(boardID, true)
var threadIDs []interface{}
for _, thread := range threads {
threadIDs = append(threadIDs, thread.ID)
}
if err != nil {
errEv.Err(err).Caller().
Int("boardID", boardID).Send()
return "", err
}
if wantsJSON {
return threads, nil
}
board := gcsql.Board{
ID: boardID,
Dir: boardDir,
}
opIDs, err := gcsql.GetTopPostIDsInThreadIDs(threadIDs...)
if err != nil {
errEv.Err(err).Caller().Send()
return "", err
}
if err = serverutil.MinifyTemplate(gctemplates.ManageThreadAttrs, map[string]interface{}{
"action": "threadattrs",
"boards": gcsql.AllBoards,
"board": board,
"threads": threads,
"opIDs": opIDs,
}, attrBuffer, "text/html"); err != nil {
errEv.Err(err).Caller().Send()
return "", err
}
return attrBuffer.String(), nil
}},
{
ID: "login",
Title: "Login",
@ -1192,22 +1264,6 @@ var actions = []Action{
}
return postInfo, nil
}},
// {
// may end up deleting this
// ID: "tempposts",
// Title: "Temporary posts lists",
// Permissions: AdminPerms,
// Callback: func(writer http.ResponseWriter, request *http.Request, wantsJSON bool) (output interface{}, err error) {
// outputStr := ""
// if len(gcsql.TempPosts) == 0 {
// outputStr += "No temporary posts"
// return
// }
// for p, post := range gcsql.TempPosts {
// outputStr += fmt.Sprintf("Post[%d]: %#v<br />", p, post)
// }
// return outputStr, nil
// }},
{
ID: "wordfilters",
Title: "Wordfilters",

View file

@ -86,7 +86,7 @@ func CallManageFunction(writer http.ResponseWriter, request *http.Request) {
}
if staff.Rank < action.Permissions {
writer.WriteHeader(403)
writer.WriteHeader(http.StatusForbidden)
errEv.
Int("rank", staff.Rank).
Int("requiredRank", action.Permissions).
@ -107,7 +107,7 @@ func CallManageFunction(writer http.ResponseWriter, request *http.Request) {
output, err = action.Callback(writer, request, staff, wantsJSON, infoEv, errEv)
}
if err != nil {
// writer.WriteHeader(500)
writer.WriteHeader(http.StatusInternalServerError)
serveError(writer, "actionerror", actionID, err.Error(), wantsJSON || (action.JSONoutput == AlwaysJSON))
return
}

View file

@ -0,0 +1,39 @@
<form method="GET" action="{{webPath "manage" $.action}}" class="staff-form">
{{with $.boards -}}
<select name="board">
{{range $_, $board := $.boards}}
<option value="{{$board.Dir}}" {{with $.board}}{{if eq $.board.Dir $board.Dir}}selected="selected"{{end}}{{end}}>/{{$board.Dir}}/ - {{$board.Title}}</option>
{{else}}
<i>No boards</i>
{{end}}
</select>
<input type="submit" name="show-threads" value="Show threads" /><br />
{{else}}
<i>No boards</i>
{{end}}
{{with $.board}}
Threads on /{{.Dir}}/ (board ID is {{.ID}})<br/>
{{if (lt (len $.threads) 1)}}
<i>No threads on </i>
{{else -}}
<table>
<tr>
<th>Thread ID</th><th>OP</th><th>Locked</th><th>Stickied</th><th>Anchored</th><th>Cyclical</th>
</tr>
{{- range $t, $thread := $.threads}}
<tr>
{{- with $opIDstr := (print (index $.opIDs $t)) -}}
<td>{{$thread.ID}}</td>
<td><a href="{{webPath $.board.Dir "res" $opIDstr}}.html">&gt;&gt;/{{$.board.Dir}}/{{$opIDstr}}</a></td>
<td><input type="checkbox" name="locked" {{if $thread.Locked}}checked="checked"{{end}} />{{$thread.Locked}}</td>
<td><input type="checkbox" name="stickied" {{if $thread.Stickied}}checked="checked"{{end}} />{{$thread.Stickied}}</td>
<td><input type="checkbox" name="anchored" {{if $thread.Anchored}}checked="checked"{{end}} />{{$thread.Anchored}}</td>
<td><input type="checkbox" name="cyclical" {{if $thread.Cyclical}}checked="checked"{{end}} />{{$thread.Cyclical}}</td>
<td><input type="submit" name="update-{{$thread.ID}}" value="Update attributes"></td>
{{- end}}
</tr>
{{end -}}
</table>
{{- end}}
{{end}}
</form>