mirror of
https://github.com/Eggbertx/gochan.git
synced 2025-08-02 23:26:23 -07:00
Add filter enabling/disabling
This commit is contained in:
parent
e3a4efd9c0
commit
fa56d500b8
5 changed files with 147 additions and 30 deletions
|
@ -25,8 +25,12 @@ h1, h2 {
|
||||||
table.mgmt-table {
|
table.mgmt-table {
|
||||||
margin-top: 4px;
|
margin-top: 4px;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
td.table-actions {
|
td.table-actions,col.row-actions,col.row-staff {
|
||||||
text-align: center;
|
text-align: center;
|
||||||
|
width: 7%;
|
||||||
|
}
|
||||||
|
col.row-date {
|
||||||
|
width: 20%;
|
||||||
}
|
}
|
||||||
th {
|
th {
|
||||||
padding: 4px;
|
padding: 4px;
|
||||||
|
|
|
@ -324,8 +324,12 @@ table.mgmt-table {
|
||||||
margin-top: 4px;
|
margin-top: 4px;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
}
|
}
|
||||||
table.mgmt-table td.table-actions {
|
table.mgmt-table td.table-actions, table.mgmt-table col.row-actions, table.mgmt-table col.row-staff {
|
||||||
text-align: center;
|
text-align: center;
|
||||||
|
width: 7%;
|
||||||
|
}
|
||||||
|
table.mgmt-table col.row-date {
|
||||||
|
width: 20%;
|
||||||
}
|
}
|
||||||
table.mgmt-table th {
|
table.mgmt-table th {
|
||||||
padding: 4px;
|
padding: 4px;
|
||||||
|
|
|
@ -5,26 +5,43 @@ import (
|
||||||
"errors"
|
"errors"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
AllFilters ShowFilters = iota
|
||||||
|
OnlyActiveFilters
|
||||||
|
OnlyInactiveFilters
|
||||||
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
ErrInvalidConditionField = errors.New("unrecognized conditional field")
|
ErrInvalidConditionField = errors.New("unrecognized conditional field")
|
||||||
ErrInvalidMatchAction = errors.New("unrecognized filter action")
|
ErrInvalidMatchAction = errors.New("unrecognized filter action")
|
||||||
|
ErrInvalidFilter = errors.New("unrecognized filter id")
|
||||||
)
|
)
|
||||||
|
|
||||||
|
type ShowFilters int
|
||||||
|
|
||||||
func GetFilterByID(id int) (*Filter, error) {
|
func GetFilterByID(id int) (*Filter, error) {
|
||||||
var filter Filter
|
var filter Filter
|
||||||
err := QueryRowTimeoutSQL(nil,
|
err := QueryRowTimeoutSQL(nil,
|
||||||
`SELECT id, staff_id, staff_note, issued_at, match_action, match_detail, is_active FROM DBPREFIXfilters WHERE id = ?`,
|
`SELECT id, staff_id, staff_note, issued_at, match_action, match_detail, is_active FROM DBPREFIXfilters WHERE id = ?`,
|
||||||
[]any{id}, []any{&filter.ID, &filter.StaffID, &filter.StaffNote, &filter.IssuedAt, &filter.MatchAction, &filter.MatchDetail, &filter.IsActive},
|
[]any{id}, []any{&filter.ID, &filter.StaffID, &filter.StaffNote, &filter.IssuedAt, &filter.MatchAction, &filter.MatchDetail, &filter.IsActive},
|
||||||
)
|
)
|
||||||
if err != nil {
|
if errors.Is(err, sql.ErrNoRows) {
|
||||||
|
return nil, ErrInvalidFilter
|
||||||
|
} else if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return &filter, nil
|
return &filter, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetAllFilters returns an array of all post filters, and an error if one occured
|
// GetAllFilters returns an array of all post filters, and an error if one occured. It can optionally return only the active or
|
||||||
func GetAllFilters() ([]Filter, error) {
|
// only the inactive filters (or return all)
|
||||||
|
func GetAllFilters(show ShowFilters) ([]Filter, error) {
|
||||||
query := `SELECT id, staff_id, staff_note, issued_at, match_action, match_detail, is_active FROM DBPREFIXfilters`
|
query := `SELECT id, staff_id, staff_note, issued_at, match_action, match_detail, is_active FROM DBPREFIXfilters`
|
||||||
|
if show == OnlyActiveFilters {
|
||||||
|
query += " WHERE is_active = TRUE"
|
||||||
|
} else if show == OnlyInactiveFilters {
|
||||||
|
query += " WHERE is_active = FALSE"
|
||||||
|
}
|
||||||
rows, cancel, err := QueryTimeoutSQL(nil, query)
|
rows, cancel, err := QueryTimeoutSQL(nil, query)
|
||||||
if errors.Is(err, sql.ErrNoRows) {
|
if errors.Is(err, sql.ErrNoRows) {
|
||||||
return nil, nil
|
return nil, nil
|
||||||
|
@ -133,7 +150,9 @@ func (f *Filter) BoardDirs() ([]string, error) {
|
||||||
|
|
||||||
func (f *Filter) BoardIDs() ([]int, error) {
|
func (f *Filter) BoardIDs() ([]int, error) {
|
||||||
rows, cancel, err := QueryTimeoutSQL(nil, `SELECT board_id FROM DBPREFIXfilter_boards WHERE filter_id = ?`, f.ID)
|
rows, cancel, err := QueryTimeoutSQL(nil, `SELECT board_id FROM DBPREFIXfilter_boards WHERE filter_id = ?`, f.ID)
|
||||||
if err != nil {
|
if errors.Is(err, sql.ErrNoRows) {
|
||||||
|
return nil, nil
|
||||||
|
} else if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
defer func() {
|
defer func() {
|
||||||
|
@ -150,3 +169,14 @@ func (f *Filter) BoardIDs() ([]int, error) {
|
||||||
}
|
}
|
||||||
return ids, nil
|
return ids, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SetFilterActive updates the filter with the given id, setting its active status and returning an error if one occured
|
||||||
|
func SetFilterActive(id int, active bool) error {
|
||||||
|
_, err := ExecTimeoutSQL(nil, `UPDATE DBPREFIXfilters SET is_active = ? WHERE id = ?`, active, id)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func DeleteFilter(id int) error {
|
||||||
|
_, err := ExecTimeoutSQL(nil, `DELETE FROM DBPREFIXfilters WHERE id = ?`, id)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
|
@ -9,6 +9,7 @@ import (
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/url"
|
"net/url"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
|
||||||
"github.com/gochan-org/gochan/pkg/building"
|
"github.com/gochan-org/gochan/pkg/building"
|
||||||
"github.com/gochan-org/gochan/pkg/config"
|
"github.com/gochan-org/gochan/pkg/config"
|
||||||
|
@ -36,10 +37,15 @@ var (
|
||||||
{Value: "hasfile", Text: "Has file"},
|
{Value: "hasfile", Text: "Has file"},
|
||||||
{Value: "nofile", Text: "No file"},
|
{Value: "nofile", Text: "No file"},
|
||||||
{Value: "filename", Text: "Filename"},
|
{Value: "filename", Text: "Filename"},
|
||||||
{Value: "filechecksum", Text: "File checksum"},
|
{Value: "checksum", Text: "File checksum"},
|
||||||
{Value: "imgfingerprint", Text: "Image fingerprint"},
|
{Value: "ahash", Text: "Image fingerprint"},
|
||||||
{Value: "useragent", Text: "User agent"},
|
{Value: "useragent", Text: "User agent"},
|
||||||
}
|
}
|
||||||
|
filterActionsMap = map[string]string{
|
||||||
|
"reject": "Reject post",
|
||||||
|
"ban": "Ban IP",
|
||||||
|
"log": "Log match",
|
||||||
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
func bansCallback(_ http.ResponseWriter, request *http.Request, staff *gcsql.Staff, _ bool, infoEv *zerolog.Event, errEv *zerolog.Event) (output interface{}, err error) {
|
func bansCallback(_ http.ResponseWriter, request *http.Request, staff *gcsql.Staff, _ bool, infoEv *zerolog.Event, errEv *zerolog.Event) (output interface{}, err error) {
|
||||||
|
@ -354,12 +360,82 @@ func filtersCallback(_ http.ResponseWriter, request *http.Request, staff *gcsql.
|
||||||
// doFilterAdd = request.PostFormValue("dofilteradd")
|
// doFilterAdd = request.PostFormValue("dofilteradd")
|
||||||
// filterID := request.FormValue("filterid")
|
// filterID := request.FormValue("filterid")
|
||||||
// editFilter := request.FormValue("editfilter")
|
// editFilter := request.FormValue("editfilter")
|
||||||
// delFilter := request.FormValue("delfilter")
|
disableFilterIDStr := request.FormValue("disable")
|
||||||
|
enableFilterIDStr := request.FormValue("enable")
|
||||||
|
if disableFilterIDStr != "" {
|
||||||
|
disableFilterID, err := strconv.Atoi(disableFilterIDStr)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
gcsql.SetFilterActive(disableFilterID, false)
|
||||||
|
} else if enableFilterIDStr != "" {
|
||||||
|
enableFilterID, err := strconv.Atoi(enableFilterIDStr)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
gcsql.SetFilterActive(enableFilterID, true)
|
||||||
|
}
|
||||||
|
|
||||||
|
showStr := request.FormValue("show")
|
||||||
|
var show gcsql.ShowFilters
|
||||||
|
switch showStr {
|
||||||
|
case "active":
|
||||||
|
show = gcsql.OnlyActiveFilters
|
||||||
|
case "inactive":
|
||||||
|
show = gcsql.OnlyInactiveFilters
|
||||||
|
default:
|
||||||
|
show = gcsql.AllFilters
|
||||||
|
}
|
||||||
|
|
||||||
|
filters, err := gcsql.GetAllFilters(show)
|
||||||
|
if err != nil {
|
||||||
|
errEv.Err(err).Caller().Msg("Unable to get filter list")
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
fieldsMap := make(map[string]string)
|
||||||
|
for _, ff := range filterFields {
|
||||||
|
fieldsMap[ff.Value] = ff.Text
|
||||||
|
}
|
||||||
|
var staffUsernames []string
|
||||||
|
|
||||||
|
var conditionsText []string
|
||||||
|
for _, filter := range filters {
|
||||||
|
if _, ok := filterActionsMap[filter.MatchAction]; !ok {
|
||||||
|
return nil, gcsql.ErrInvalidMatchAction
|
||||||
|
}
|
||||||
|
conditions, err := filter.Conditions()
|
||||||
|
if err != nil {
|
||||||
|
errEv.Err(err).Caller().Int("filterID", filter.ID).Msg("Unable to get filter conditions")
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var filterConditionsText string
|
||||||
|
for _, condition := range conditions {
|
||||||
|
text, ok := fieldsMap[condition.Field]
|
||||||
|
if !ok {
|
||||||
|
return nil, gcsql.ErrInvalidConditionField
|
||||||
|
}
|
||||||
|
filterConditionsText += text + ","
|
||||||
|
}
|
||||||
|
filterConditionsText = strings.TrimRight(filterConditionsText, ",")
|
||||||
|
conditionsText = append(conditionsText, filterConditionsText)
|
||||||
|
|
||||||
|
username, err := gcsql.GetStaffUsernameFromID(*filter.StaffID)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
staffUsernames = append(staffUsernames, username)
|
||||||
|
}
|
||||||
|
|
||||||
var buf bytes.Buffer
|
var buf bytes.Buffer
|
||||||
if err = serverutil.MinifyTemplate(gctemplates.ManageFilters, map[string]any{
|
if err = serverutil.MinifyTemplate(gctemplates.ManageFilters, map[string]any{
|
||||||
"allBoards": gcsql.AllBoards,
|
"allBoards": gcsql.AllBoards,
|
||||||
"fields": filterFields,
|
"fields": filterFields,
|
||||||
|
"filters": filters,
|
||||||
|
"conditions": conditionsText,
|
||||||
|
"actions": filterActionsMap,
|
||||||
|
"staff": staffUsernames,
|
||||||
|
"show": showStr,
|
||||||
}, &buf, "text/html"); err != nil {
|
}, &buf, "text/html"); err != nil {
|
||||||
errEv.Err(err).Caller().Str("template", gctemplates.ManageFilters).Send()
|
errEv.Err(err).Caller().Str("template", gctemplates.ManageFilters).Send()
|
||||||
return "", errors.New("Unable to execute filter management template: " + err.Error())
|
return "", errors.New("Unable to execute filter management template: " + err.Error())
|
||||||
|
|
|
@ -66,34 +66,37 @@
|
||||||
</form>
|
</form>
|
||||||
<hr/>
|
<hr/>
|
||||||
<h2>Filter list</h2>
|
<h2>Filter list</h2>
|
||||||
|
<form action="{{webPath `/manage/filters`}}" method="GET">
|
||||||
|
<select name="show" id="">
|
||||||
|
<option value="all" {{if or (eq $.show `all`) (eq $.show ``)}}selected{{end}}>All filters</option>
|
||||||
|
<option value="active" {{if eq $.show `active`}}selected{{end}}>Only active</option>
|
||||||
|
<option value="inactive" {{if eq $.show `inactive`}}selected{{end}}>Only inactive</option>
|
||||||
|
</select>
|
||||||
|
<input type="submit" value="Show">
|
||||||
|
</form>
|
||||||
|
</form>
|
||||||
<table class="mgmt-table filterlist">
|
<table class="mgmt-table filterlist">
|
||||||
<colgroup>
|
<colgroup>
|
||||||
<col class="row-actions">
|
<col class="row-actions">
|
||||||
<col class="filter-action">
|
<col class="filter-action">
|
||||||
<col class="filter-conditions">
|
<col class="filter-conditions">
|
||||||
|
<col class="staff-note">
|
||||||
|
<col class="row-staff">
|
||||||
|
<col class="is-active">
|
||||||
<col class="row-date">
|
<col class="row-date">
|
||||||
</colgroup>
|
</colgroup>
|
||||||
<tr>
|
<tr>
|
||||||
<th>Actions</th><th>Filter action</th><th>Conditions</th><th>Staff</th><th>Last modified</th>
|
<th>Actions</th><th>Filter action</th><th>Conditions</th><th>Staff note</th><th>Staff</th><th>Is active</th><th>Last modified</th>
|
||||||
</tr>
|
</tr>
|
||||||
<!-- TODO: replace dummy data with actual data -->
|
{{- range $f, $filter := $.filters -}}
|
||||||
<tr>
|
<tr>
|
||||||
<td>
|
<td><a href="{{webPath `/manage/filters`}}?edit={{$filter.ID}}">Edit</a> | <a href="{{webPath `/manage/filters`}}?{{if $filter.IsActive}}disable{{else}}enable{{end}}={{$filter.ID}}">{{if $filter.IsActive}}Disable{{else}}Enable{{end}}</a></td>
|
||||||
<a href="{{webPath `/manage/filters?edit=1`}}">Edit</a> | <a href="{{webPath `/manage/filters?delete=1`}}">Delete</a>
|
<td>{{index $.actions $filter.MatchAction}}</td>
|
||||||
</td>
|
<td>{{index $.conditions $f}}</td>
|
||||||
<td>Ban IP</td>
|
<td>{{$filter.StaffNote}}</td>
|
||||||
<td>User agent, Name, Tripcode, First time poster</td>
|
<td>{{index $.staff $f}}</td>
|
||||||
<td>admin</td>
|
<td>{{$filter.IsActive}}</td>
|
||||||
<td>2024-07-01 12:00:00</td>
|
<td>{{formatTimestamp $filter.IssuedAt}}</td>
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td>
|
|
||||||
<a href="{{webPath `/manage/filters?edit=2`}}">Edit</a> |
|
|
||||||
<a href="{{webPath `/manage/filters?delete=2`}}">Delete</a>
|
|
||||||
</td>
|
|
||||||
<td>Reject post</td>
|
|
||||||
<td>Name, Tripcode, Email, Subject, Message body, First time poster, Not a first time poster, Is OP, Is reply, Has file, No file, Filename, File checksum, Image fingerprint, User agent</td>
|
|
||||||
<td>admin</td>
|
|
||||||
<td>2024-07-01 12:00:00</td>
|
|
||||||
</tr>
|
</tr>
|
||||||
|
{{- end -}}
|
||||||
</table>
|
</table>
|
Loading…
Add table
Add a link
Reference in a new issue