1
0
Fork 0
mirror of https://github.com/Eggbertx/gochan.git synced 2025-09-04 10:06:24 -07:00

Add filebans staff action, related to issue #28

though currently it can only view, not add new bans
This commit is contained in:
Eggbertx 2022-09-15 21:37:56 -07:00
parent 8e5449f636
commit 943c0f6221
13 changed files with 346 additions and 42 deletions

View file

@ -0,0 +1,9 @@
import $ from "jquery";
import "jquery-ui/ui/widget";
import "jquery-ui/ui/unique-id";
import "jquery-ui/ui/widgets/tabs";
$(() => {
if(window.location.search.indexOf("?action=filebans") != 0)
return;
$("div#fileban-tabs").tabs();
});

View file

@ -10,6 +10,7 @@ import $ from 'jquery';
import { alertLightbox } from "../dom/lightbox";
import { $topbar, TopBarButton } from '../dom/topbar';
import "./sections";
import "./filebans";
/**
* @type {StaffInfo}

View file

@ -82,4 +82,19 @@ div.section-block {
select.post-actions {
margin-right: 4px;
margin-left: 4px;
}
.ui-tabs-nav {
list-style: none;
padding-left: 0px;
}
.ui-tabs-tab {
float: left;
text-decoration: none;
padding: 8px;
}
.ui-tabs-panel {
clear: both;
}

View file

@ -50,10 +50,24 @@ div#topbar {
.dropdown-menu {
background: $topbarcol!important;
// @include box-shadow(2px 2px 2px 3px $shadowcol);
@include shadow-filter(2px 2px 3px $shadowcol);
z-index: 0;
div:hover {
background: $bglight;
}
}
.ui-tabs-tab {
background: $topbarcol;
border: 1px solid $bglight;
}
.ui-tabs-active {
background: $bgcol;
}
.ui-tabs-panel {
background: $bgcol;
border: 1px solid $topbarcol;
padding: 8px;
}

View file

@ -562,3 +562,18 @@ select.post-actions {
margin-right: 4px;
margin-left: 4px;
}
.ui-tabs-nav {
list-style: none;
padding-left: 0px;
}
.ui-tabs-tab {
float: left;
text-decoration: none;
padding: 8px;
}
.ui-tabs-panel {
clear: both;
}

View file

@ -142,3 +142,18 @@ div#topbar li:hover {
.dropdown-menu div:hover {
background: #404040;
}
.ui-tabs-tab {
background: #202020;
border: 1px solid #404040;
}
.ui-tabs-active {
background: #363942;
}
.ui-tabs-panel {
background: #363942;
border: 1px solid #202020;
padding: 8px;
}

109
pkg/gcsql/filebans.go Normal file
View file

@ -0,0 +1,109 @@
package gcsql
import "database/sql"
// GetFilenameBans returns an array of filename bans. If matchFilename is a blank string, it returns all of them.
// If exactMatch is true, it returns an array of bans that = matchFilename, otherwise it treats matchFilename
// as a SQL wildcard query using LIKE
func GetFilenameBans(matchFilename string, exactMatch bool) ([]FilenameBan, error) {
query := `SELECT id,board_id,staff_id,staff_note,issued_at,filename,is_regex FROM DBPREFIXfilename_ban`
var rows *sql.Rows
var err error
if matchFilename != "" {
if exactMatch {
rows, err = QuerySQL(query+" WHERE filename = ?", matchFilename)
} else {
rows, err = QuerySQL(query+" WHERE filename LIKE ?", matchFilename)
}
} else {
rows, err = QuerySQL(query)
}
if err != nil {
return nil, err
}
var fnBans []FilenameBan
for rows.Next() {
var ban FilenameBan
if err = rows.Scan(
&ban.ID, &ban.BoardID, &ban.StaffID, &ban.StaffNote,
&ban.IssuedAt, &ban.Filename, &ban.IsRegex,
); err != nil {
return fnBans, err
}
fnBans = append(fnBans, ban)
}
return fnBans, err
}
// CreateFileNameBan creates a new ban on a filename. If boards is an empty string
// or the resulting query = nil, the ban is global, whether or not allBoards is set
func CreateFileNameBan(fileName string, isRegex bool, staffName string, permaban bool, staffNote, boardURI string) error {
const sql = `INSERT INTO DBPREFIXfilename_ban (board_id, staff_id, staff_note, filename, is_regex) VALUES board_id = ?, staff_id = ?, staff_note = ?, filename = ?, is_regex = ?`
staffID, err := getStaffID(staffName)
if err != nil {
return err
}
var boardID *int = nil
if boardURI != "" {
boardID = getBoardIDFromURIOrNil(boardURI)
}
_, err = ExecSQL(sql, boardID, staffID, staffNote, fileName, isRegex)
return err
}
func GetFileChecksumBans(matchChecksum string) ([]FileBan, error) {
query := `SELECT id,board_id,staff_id,staff_note,issued_at,checksum FROM DBPREFIXfile_ban`
if matchChecksum != "" {
query += " WHERE checksum = ?"
}
var rows *sql.Rows
var err error
if matchChecksum == "" {
rows, err = QuerySQL(query)
} else {
rows, err = QuerySQL(query, matchChecksum)
}
if err != nil {
return nil, err
}
var fileBans []FileBan
for rows.Next() {
var fileBan FileBan
if err = rows.Scan(
&fileBan.ID, &fileBan.BoardID, &fileBan.StaffID, &fileBan.StaffNote,
&fileBan.IssuedAt, &fileBan.Checksum,
); err != nil {
return fileBans, err
}
fileBans = append(fileBans, fileBan)
}
return fileBans, nil
}
// CreateFileBan creates a new ban on a file. If boards = nil, the ban is global.
func CreateFileBan(fileChecksum, staffName string, permaban bool, staffNote, boardURI string) error {
const sql = `INSERT INTO DBPREFIXfile_ban (board_id, staff_id, staff_note, checksum) VALUES board_id = ?, staff_id = ?, staff_note = ?, checksum = ?`
staffID, err := getStaffID(staffName)
if err != nil {
return err
}
boardID := getBoardIDFromURIOrNil(boardURI)
_, err = ExecSQL(sql, boardID, staffID, staffNote, fileChecksum)
return err
}
func checkFilenameBan(filename string) (*FilenameBan, error) {
const sql = `SELECT id, board_id, staff_id, staff_note, issued_at, filename, is_regex
FROM DBPREFIXfilename_ban WHERE filename = ?`
var ban = new(FilenameBan)
err := QueryRowSQL(sql, interfaceSlice(filename), interfaceSlice(&ban.ID, &ban.BoardID, &ban.StaffID, &ban.StaffNote, &ban.IssuedAt, &ban.Filename, &ban.IsRegex))
return ban, err
}
func checkFileBan(checksum string) (*FileBan, error) {
const sql = `SELECT id, board_id, staff_id, staff_note, issued_at, checksum
FROM DBPREFIXfile_ban WHERE checksum = ?`
var ban = new(FileBan)
err := QueryRowSQL(sql, interfaceSlice(checksum), interfaceSlice(&ban.ID, &ban.BoardID, &ban.StaffID, &ban.StaffNote, &ban.IssuedAt, &ban.Checksum))
return ban, err
}

View file

@ -187,30 +187,6 @@ func getBoardIDFromURIOrNil(URI string) *int {
return &ID
}
// CreateFileBan creates a new ban on a file. If boards = nil, the ban is global.
func CreateFileBan(fileChecksum, staffName string, permaban bool, staffNote, boardURI string) error {
const sql = `INSERT INTO DBPREFIXfile_ban (board_id, staff_id, staff_note, checksum) VALUES board_id = ?, staff_id = ?, staff_note = ?, checksum = ?`
staffID, err := getStaffID(staffName)
if err != nil {
return err
}
boardID := getBoardIDFromURIOrNil(boardURI)
_, err = ExecSQL(sql, boardID, staffID, staffNote, fileChecksum)
return err
}
// CreateFileNameBan creates a new ban on a filename. If boards = nil, the ban is global.
func CreateFileNameBan(fileName string, isRegex bool, staffName string, permaban bool, staffNote, boardURI string) error {
const sql = `INSERT INTO DBPREFIXfilename_ban (board_id, staff_id, staff_note, filename, is_regex) VALUES board_id = ?, staff_id = ?, staff_note = ?, filename = ?, is_regex = ?`
staffID, err := getStaffID(staffName)
if err != nil {
return err
}
boardID := getBoardIDFromURIOrNil(boardURI)
_, err = ExecSQL(sql, boardID, staffID, staffNote, fileName, isRegex)
return err
}
// CreateUserNameBan creates a new ban on a username. If boards = nil, the ban is global.
func CreateUserNameBan(userName string, isRegex bool, staffName string, permaban bool, staffNote, boardURI string) error {
const sql = `INSERT INTO DBPREFIXusername_ban (board_id, staff_id, staff_note, username, is_regex) VALUES board_id = ?, staff_id = ?, staff_note = ?, username = ?, is_regex = ?`
@ -370,22 +346,6 @@ func checkUsernameBan(name string) (*UsernameBan, error) {
return ban, err
}
func checkFilenameBan(filename string) (*FilenameBan, error) {
const sql = `SELECT id, board_id, staff_id, staff_note, issued_at, filename, is_regex
FROM DBPREFIXfilename_ban WHERE filename = ?`
var ban = new(FilenameBan)
err := QueryRowSQL(sql, interfaceSlice(filename), interfaceSlice(&ban.ID, &ban.BoardID, &ban.StaffID, &ban.StaffNote, &ban.IssuedAt, &ban.Filename, &ban.IsRegex))
return ban, err
}
func checkFileBan(checksum string) (*FileBan, error) {
const sql = `SELECT id, board_id, staff_id, staff_note, issued_at, checksum
FROM DBPREFIXfile_ban WHERE checksum = ?`
var ban = new(FileBan)
err := QueryRowSQL(sql, interfaceSlice(checksum), interfaceSlice(&ban.ID, &ban.BoardID, &ban.StaffID, &ban.StaffNote, &ban.IssuedAt, &ban.Checksum))
return ban, err
}
// GetMaxMessageLength returns the max message length on a board
func GetMaxMessageLength(boardID int) (length int, err error) {
const sql = `SELECT max_message_length FROM DBPREFIXboards

View file

@ -455,6 +455,26 @@ type FileBan struct {
Checksum string `json:"checksum"`
}
func (fb *FileBan) BoardURI() string {
if fb.BoardID == nil {
return ""
}
var uri string
err := QueryRowSQL(`SELECT uri FROM DBPREFIXboards WHERE id = ?`, interfaceSlice(fb.BoardID), interfaceSlice(&uri))
if err != nil {
return ""
}
return uri
}
func (fb *FileBan) StaffName() string {
staff, err := getStaffByID(fb.StaffID)
if err != nil {
return ""
}
return staff.Username
}
// FilenameBan contains the information associated with a specific filename ban
type FilenameBan struct {
ID int `json:"id"`
@ -466,6 +486,26 @@ type FilenameBan struct {
IsRegex bool `json:"is_regex"`
}
func (fnb *FilenameBan) BoardURI() string {
if fnb.BoardID == nil {
return ""
}
var uri string
err := QueryRowSQL(`SELECT uri FROM DBPREFIXboards WHERE id = ?`, interfaceSlice(fnb.BoardID), interfaceSlice(&uri))
if err != nil {
return ""
}
return uri
}
func (fnb *FilenameBan) StaffName() string {
staff, err := getStaffByID(fnb.StaffID)
if err != nil {
return ""
}
return staff.Username
}
// UsernameBan contains the information associated with a specific username ban
type UsernameBan struct {
ID int `json:"id"`

View file

@ -23,6 +23,7 @@ var (
ManageSections *template.Template
ManageConfig *template.Template
ManageDashboard *template.Template
ManageFileBans *template.Template
ManageIPSearch *template.Template
ManageRecentPosts *template.Template
ManageWordfilters *template.Template
@ -170,6 +171,12 @@ func templateLoading(t string, buildAll bool) error {
return templateError("manage_reports.html", err)
}
}
if buildAll || t == "managefilebans" {
ManageFileBans, err = loadTemplate("manage_filebans.html")
if err != nil {
return templateError("manage_filebans.html", err)
}
}
if buildAll || t == "manageipsearch" {
ManageIPSearch, err = loadTemplate("manage_ipsearch.html")
if err != nil {

View file

@ -197,6 +197,56 @@ var actions = []Action{
}
return manageRecentsBuffer.String(), nil
}},
{
ID: "filebans",
Title: "File bans",
Permissions: ModPerms,
JSONoutput: OptionalJSON,
Callback: func(writer http.ResponseWriter, request *http.Request, staff *gcsql.Staff, wantsJSON bool) (interface{}, error) {
filenameBans, err := gcsql.GetFilenameBans("", false)
if err != nil {
return "", err
}
checksumBans, err := gcsql.GetFileChecksumBans("")
if err != nil {
return "", err
}
if wantsJSON {
return map[string]interface{}{
"filenameBans": filenameBans,
"checksumBans": checksumBans,
}, nil
}
boardURIs, err := gcsql.GetBoardUris()
if err != nil {
return "", err
}
manageBansBuffer := bytes.NewBufferString("")
if err = serverutil.MinifyTemplate(gctemplates.ManageFileBans, map[string]interface{}{
"webroot": config.GetSystemCriticalConfig().WebRoot,
"filenameBans": filenameBans,
"checksumBans": checksumBans,
"boardURIs": boardURIs,
}, manageBansBuffer, "text/html"); err != nil {
gcutil.LogError(err).
Str("staff", staff.Username).
Str("action", "filebans").
Str("template", "manage_filebans.html").
Msg("failed executing file ban management page template")
return "", errors.New("failed executing file ban management page template: " + err.Error())
}
return manageBansBuffer.String(), nil
},
},
{
ID: "ipbans",
Title: "IP Bans",
Permissions: ModPerms,
JSONoutput: OptionalJSON,
Callback: func(writer http.ResponseWriter, request *http.Request, staff *gcsql.Staff, wantsJSON bool) (output interface{}, err error) {
return "", gcutil.ErrNotImplemented
},
},
{
ID: "bans",
Title: "Bans",
@ -1066,6 +1116,7 @@ var actions = []Action{
}
}
filterMap := map[string]interface{}{
"webroot": config.GetSystemCriticalConfig().WebRoot,
"wordfilters": wordfilters,
"edit": editFilter,
}

View file

@ -0,0 +1,68 @@
<div id="fileban-tabs">
<ul>
<li><a href="#filename-bans">Filename bans</a></li>
<li><a href="#checksum-bans">File checksum bans</a></li>
</ul>
<div id="filename-bans">
<h2>Create new filename ban</h2>
<form id="filenamebanform" action="{{.webroot}}manage?action=filebans" method="POST">
<input type="hidden" name="bantype" value="filename">
<table>
<tr><td>Filename</td><td><input type="text" name="filename" id="filename"></td></tr>
<tr><td>SQL wildcard<sup><a href="https://www.w3schools.com/sql/sql_wildcards.asp" target="_blank">?</a></sup></td><td><input type="checkbox" name="iswildcard" id="iswildcard"/></td></tr>
<tr><td>Board</td><td><select name="board">
<option value="">All boards (global ban)</option>
{{- range $b,$uri := .boardURIs -}}<option value="{{$uri}}">/{{$uri}}/</option>{{end -}}
</select></td></tr>
</table>
<input type="submit" name="dofilenameban" value="Create"/>
<input type="button" onclick="document.getElementById('filenamebanform').reset()" value="Cancel"/>
</form><hr/>
<h2>Current filename bans</h2>
{{- if eq 0 (len .filenameBans)}}<i>No filename bans</i>{{else -}}
<table border="1">
<tr><th>Filename</th><th>Wildcard</th><th>Board</th><th>Staff</th><th>Staff note</th><th>Action</th></tr>
{{range $b,$ban := .filenameBans}}
<tr>
<td>{{$ban.Filename}}</td>
<td>{{$ban.IsRegex}}</td>
<td>{{$uri := $ban.BoardURI}}{{if eq $uri ""}}<i>All boards</i>{{else}}/{{$uri}}/{{end}}</td>
<td>{{$staff := $ban.StaffName}}{{if eq $staff ""}}<i>?</i>{{else}}{{$staff}}{{end}}</td>
<td>{{$ban.StaffNote}}</td>
<td><a href="{{$.webroot}}manage?action=filebans&delfnb={{$ban.ID}}">Delete</a></td>
</tr>
{{end -}}
</table>
{{- end -}}
</div>
<div id="checksum-bans">
<h2>Create new file checksum ban</h2>
<form id="checksumbanform" action="{{.webroot}}manage?action=filebans" method="POST">
<input type="hidden" name="bantype" value="checksum">
<table>
<tr><td>Checksum</td><td><input type="text" name="filename" id="filename"></td></tr>
<tr><td>Board</td><td><select name="board">
<option value="">All boards (global ban)</option>
{{- range $b,$uri := .boardURIs -}}<option value="{{$uri}}">/{{$uri}}/</option>{{end -}}
</select></td></tr>
</table>
<input type="submit" name="dochecksumban" value="Create"/>
<input type="button" onclick="document.getElementById('checksumbanform').reset()" value="Cancel"/>
</form><hr/>
<h2>Current file checksum bans</h2>
{{- if eq 0 (len .checksumBans)}}<i>No file checksum bans</i>{{else -}}
<table border="1">
<tr><th>Checksum</th><th>Board</th><th>Staff</th><th>Staff note</th><th>Action</th></tr>
{{range $b,$ban := .checksumBans}}
<tr>
<td>{{$ban.Checksum}}</td>
<td>{{$uri := $ban.BoardURI}}{{if eq $uri ""}}<i>All boards</i>{{else}}/{{$uri}}/{{end}}</td>
<td>{{$staff := $ban.StaffName}}{{if eq $staff ""}}<i>?</i>{{else}}{{$staff}}{{end}}</td>
<td>{{$ban.StaffNote}}</td>
<td><a href="{{$.webroot}}manage?action=filebans&delfb={{$ban.ID}}">Delete</a></td>
</tr>
{{- end -}}
</table>
{{end}}
</div>
</div>

View file

@ -1,5 +1,5 @@
<div id="footer">
Powered by <a href="http://github.com/eggbertx/gochan/">Gochan {{version}}</a><br />
Powered by <a href="http://github.com/gochan-org/gochan/">Gochan {{version}}</a><br />
</div>
</div>
</body>