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:
parent
8e5449f636
commit
943c0f6221
13 changed files with 346 additions and 42 deletions
9
frontend/js/management/filebans.js
Normal file
9
frontend/js/management/filebans.js
Normal 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();
|
||||
});
|
|
@ -10,6 +10,7 @@ import $ from 'jquery';
|
|||
import { alertLightbox } from "../dom/lightbox";
|
||||
import { $topbar, TopBarButton } from '../dom/topbar';
|
||||
import "./sections";
|
||||
import "./filebans";
|
||||
|
||||
/**
|
||||
* @type {StaffInfo}
|
||||
|
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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
109
pkg/gcsql/filebans.go
Normal 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
|
||||
}
|
|
@ -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
|
||||
|
|
|
@ -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"`
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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,
|
||||
}
|
||||
|
|
68
templates/manage_filebans.html
Normal file
68
templates/manage_filebans.html
Normal 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>
|
|
@ -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>
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue