mirror of
https://github.com/Eggbertx/gochan.git
synced 2025-08-02 10:56:25 -07:00
Fix condition double-sending
This commit is contained in:
parent
a7744d6d88
commit
38c4107b15
3 changed files with 112 additions and 46 deletions
|
@ -188,24 +188,19 @@ func (f *Filter) Conditions() ([]FilterCondition, error) {
|
|||
return f.conditions, rows.Close()
|
||||
}
|
||||
|
||||
// SetConditions replaces all current conditions associated with the filter and applies the given conditions.
|
||||
// It returns an error if no conditions are provided
|
||||
func (f *Filter) SetConditions(conditions ...FilterCondition) error {
|
||||
if len(conditions) < 1 {
|
||||
func (f *Filter) setConditionsContext(ctx context.Context, tx *sql.Tx, conditions ...FilterCondition) error {
|
||||
if f.ID == 0 {
|
||||
return ErrInvalidFilter
|
||||
}
|
||||
if len(conditions) == 0 {
|
||||
return ErrNoConditions
|
||||
}
|
||||
ctx, cancel := context.WithTimeout(context.Background(), gcdb.defaultTimeout)
|
||||
defer cancel()
|
||||
|
||||
tx, err := BeginContextTx(ctx)
|
||||
_, err := ExecContextSQL(ctx, tx, `DELETE FROM DBPREFIXfilter_conditions WHERE filter_id = ?`, f.ID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer tx.Rollback()
|
||||
|
||||
if _, err = ExecContextSQL(ctx, tx, `DELETE FROM DBPREFIXfilter_conditions WHERE filter_id = ?`, f.ID); err != nil {
|
||||
return err
|
||||
}
|
||||
for c, condition := range conditions {
|
||||
conditions[c].FilterID = f.ID
|
||||
condition.FilterID = f.ID
|
||||
|
@ -213,19 +208,58 @@ func (f *Filter) SetConditions(conditions ...FilterCondition) error {
|
|||
return err
|
||||
}
|
||||
}
|
||||
if err = tx.Commit(); err != nil {
|
||||
return err
|
||||
}
|
||||
f.conditions = conditions
|
||||
return nil
|
||||
}
|
||||
|
||||
func (f *Filter) UpdateDetails(staffNote string, matchAction string, matchDetail string) error {
|
||||
_, err := ExecTimeoutSQL(nil,
|
||||
// SetConditions replaces all current conditions associated with the filter and applies the given conditions.
|
||||
// It returns an error if no conditions are provided
|
||||
func (f *Filter) SetConditions(conditions ...FilterCondition) error {
|
||||
ctx, cancel := context.WithTimeout(context.Background(), gcdb.defaultTimeout)
|
||||
defer cancel()
|
||||
tx, err := BeginContextTx(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer tx.Rollback()
|
||||
|
||||
if err = f.setConditionsContext(ctx, tx, conditions...); err != nil {
|
||||
return err
|
||||
}
|
||||
return tx.Commit()
|
||||
}
|
||||
|
||||
func (f *Filter) updateDetailsContext(ctx context.Context, tx *sql.Tx, staffNote string, matchAction string, matchDetail string) error {
|
||||
_, err := ExecContextSQL(ctx, tx,
|
||||
`UPDATE DBPREFIXfilters SET staff_note = ?, issued_at = ?, match_action = ?, match_detail = ? WHERE id = ?`,
|
||||
staffNote, time.Now(), matchAction, matchDetail, f.ID,
|
||||
)
|
||||
return err
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
f.StaffNote = staffNote
|
||||
f.MatchAction = matchAction
|
||||
f.MatchDetail = matchDetail
|
||||
return nil
|
||||
}
|
||||
|
||||
// UpdateDetails updates the filter's staff note, match action, and match detail (ban message, reject reason, etc)
|
||||
func (f *Filter) UpdateDetails(staffNote string, matchAction string, matchDetail string) error {
|
||||
if f.ID == 0 {
|
||||
return ErrInvalidFilter
|
||||
}
|
||||
ctx, cancel := context.WithTimeout(context.Background(), gcdb.defaultTimeout)
|
||||
defer cancel()
|
||||
tx, err := BeginContextTx(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer tx.Rollback()
|
||||
|
||||
if err = f.updateDetailsContext(ctx, tx, staffNote, matchAction, matchDetail); err != nil {
|
||||
return err
|
||||
}
|
||||
return tx.Commit()
|
||||
}
|
||||
|
||||
// BoardDirs returns an array of board directories associated with this filter
|
||||
|
@ -307,6 +341,21 @@ func (f *Filter) BoardIDs() ([]int, error) {
|
|||
return ids, nil
|
||||
}
|
||||
|
||||
func (f *Filter) setBoardIDsContext(ctx context.Context, tx *sql.Tx, ids ...int) error {
|
||||
_, err := ExecContextSQL(ctx, tx, `DELETE FROM DBPREFIXfilter_boards WHERE filter_id = ?`, f.ID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for _, boardID := range ids {
|
||||
if _, err = ExecContextSQL(ctx, tx,
|
||||
`INSERT INTO DBPREFIXfilter_boards(filter_id, board_id) VALUES (?,?)`, f.ID, boardID,
|
||||
); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// SetBoardIDs sets the board IDs to be associated with the filter. If no boards are used,
|
||||
// the filter will be applied to all boards
|
||||
func (f *Filter) SetBoardIDs(ids ...int) error {
|
||||
|
@ -318,17 +367,9 @@ func (f *Filter) SetBoardIDs(ids ...int) error {
|
|||
}
|
||||
defer tx.Rollback()
|
||||
|
||||
if _, err = ExecContextSQL(ctx, tx, `DELETE FROM DBPREFIXfilter_boards WHERE filter_id = ?`, f.ID); err != nil {
|
||||
if err = f.setBoardIDsContext(ctx, tx, ids...); err != nil {
|
||||
return err
|
||||
}
|
||||
for _, boardID := range ids {
|
||||
if _, err = ExecContextSQL(ctx, tx,
|
||||
`INSERT INTO DBPREFIXfilter_boards(filter_id, board_id) VALUES (?,?)`,
|
||||
f.ID, boardID,
|
||||
); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return tx.Commit()
|
||||
}
|
||||
|
||||
|
@ -487,6 +528,20 @@ func (fc *FilterCondition) testCondition(post *Post, upload *Upload, request *ht
|
|||
return match, err
|
||||
}
|
||||
|
||||
// CanDoRegex is a convenience function for templates. It returns true if the filter condition should show a regular expression
|
||||
// checkbox
|
||||
func (fc FilterCondition) CanDoRegex() bool {
|
||||
return fc.HasSearchField() && (fc.Field == "name" || fc.Field == "trip" || fc.Field == "email" || fc.Field == "subject" ||
|
||||
fc.Field == "body" || fc.Field == "filename" || fc.Field == "useragent")
|
||||
}
|
||||
|
||||
// HasSearchField is a convenience function for templates. It returns true if the filter condition should show a search box
|
||||
func (fc FilterCondition) HasSearchField() bool {
|
||||
return fc.Field != "firsttimeboard" && fc.Field != "notfirsttimeboard" && fc.Field != "firsttimesite" &&
|
||||
fc.Field != "notfirsttimesite" && fc.Field != "isop" && fc.Field != "notop" && fc.Field != "hasfile" &&
|
||||
fc.Field != "nofile"
|
||||
}
|
||||
|
||||
// DoPostFiltering checks the filters against the given post. If a match is found, its respective action is taken and the filter
|
||||
// is returned. It logs any errors it receives and returns a sanitized error (if one occured) that can be shown to the end user
|
||||
func DoPostFiltering(post *Post, upload *Upload, boardID int, request *http.Request, errEv *zerolog.Event) (*Filter, error) {
|
||||
|
@ -555,12 +610,15 @@ func ApplyFilter(filter *Filter, conditions []FilterCondition, boards []int) err
|
|||
if err = QueryRowContextSQL(ctx, tx, `SELECT MAX(id) FROM DBPREFIXfilters`, nil, []any{&filter.ID}); err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
filter.updateDetailsContext(ctx, tx, filter.StaffNote, filter.MatchAction, filter.MatchDetail)
|
||||
}
|
||||
if err = tx.Commit(); err != nil {
|
||||
|
||||
if err = filter.setConditionsContext(ctx, tx, conditions...); err != nil {
|
||||
return err
|
||||
}
|
||||
if err = filter.SetConditions(conditions...); err != nil {
|
||||
if err = filter.setBoardIDsContext(ctx, tx, boards...); err != nil {
|
||||
return err
|
||||
}
|
||||
return filter.SetBoardIDs(boards...)
|
||||
return tx.Commit()
|
||||
}
|
||||
|
|
|
@ -252,9 +252,6 @@ func filtersCallback(_ http.ResponseWriter, request *http.Request, staff *gcsql.
|
|||
errEv.Err(err).Caller().Int("filterID", filterID).Msg("Unable to get filter from ID")
|
||||
return nil, err
|
||||
}
|
||||
if conditions, err = filter.Conditions(); err != nil {
|
||||
errEv.Err(err).Caller().Int("filterID", filterID).Msg("Unable to get filter conditions list")
|
||||
}
|
||||
}
|
||||
|
||||
for k, v := range request.PostForm {
|
||||
|
@ -271,7 +268,6 @@ func filtersCallback(_ http.ResponseWriter, request *http.Request, staff *gcsql.
|
|||
boardIDLogArr.Int(boardID)
|
||||
boards = append(boards, boardID)
|
||||
}
|
||||
infoEv.Array("boardIDs", boardIDLogArr)
|
||||
|
||||
// set filter conditions
|
||||
if strings.HasPrefix(k, "field") {
|
||||
|
@ -319,8 +315,10 @@ func filtersCallback(_ http.ResponseWriter, request *http.Request, staff *gcsql.
|
|||
Msg("Unable to submit filter")
|
||||
return nil, err
|
||||
}
|
||||
infoEv.Msg("Filter submitted")
|
||||
}
|
||||
|
||||
data["filterBoards"] = make([]int, 0)
|
||||
if editFilter := request.FormValue("edit"); editFilter != "" {
|
||||
// user clicked on Edit link in filter row
|
||||
filterID, err := strconv.Atoi(editFilter)
|
||||
|
@ -338,6 +336,10 @@ func filtersCallback(_ http.ResponseWriter, request *http.Request, staff *gcsql.
|
|||
errEv.Err(err).Caller().Int("filterID", filterID).Msg("Unable to get filter conditions")
|
||||
return nil, errors.New("unable to get filter conditions")
|
||||
}
|
||||
if data["filterBoards"], err = filter.BoardIDs(); err != nil {
|
||||
errEv.Err(err).Caller().Msg("Unable to get filter board IDs")
|
||||
return nil, errors.New("unable to get filter board IDs")
|
||||
}
|
||||
} else {
|
||||
// user loaded /manage/filters, populate single "default" condition
|
||||
data["filter"] = &gcsql.Filter{
|
||||
|
|
|
@ -5,23 +5,23 @@
|
|||
<th>Field/Condition:</th>
|
||||
<td>
|
||||
<select name="field{{.conditionNo}}" class="sel-field">
|
||||
{{- range $_,$field := .fields}}<option value="{{$field.Value}}" {{if eq $field.Value $.condition.Field}}selected{{end}}>{{$field.Text}}</option>{{end -}}
|
||||
{{- range $_,$field := .fields -}}
|
||||
<option value="{{$field.Value}}" {{if eq $field.Value $.condition.Field}}selected{{end}}>{{$field.Text}}</option>
|
||||
{{- end -}}
|
||||
</select>
|
||||
</td>
|
||||
</tr>
|
||||
<tr class="search-cndtn">
|
||||
<tr class="search-cndtn" {{if not .condition.HasSearchField}}style="display:none"{{end}}>
|
||||
<th>Search:</th>
|
||||
<td><input type="text" name="search{{.conditionNo}}" value="{{.condition.Search}}"></td>
|
||||
</tr>
|
||||
<tr class="regex-cndtn">
|
||||
<tr class="regex-cndtn" {{if not .condition.CanDoRegex}}style="display: none"{{end}}>
|
||||
<th></th>
|
||||
<td><label>Is regex <input type="checkbox" name="isregex{{.conditionNo}}" {{if .condition.IsRegex}}checked{{end}}/></label></td>
|
||||
</tr>
|
||||
<tr class="btns-cndtn">
|
||||
<td></td>
|
||||
<td>
|
||||
<a href="#" class="rem-cndtn">Remove condition</a>
|
||||
</td>
|
||||
<td><a href="#" class="rem-cndtn">Remove condition</a></td>
|
||||
</tr>
|
||||
</table>
|
||||
</fieldset>
|
||||
|
@ -29,7 +29,7 @@
|
|||
|
||||
<h2>{{if gt $.filter.ID 0}}Edit filter{{else}}New filter{{end}}</h2>
|
||||
<form id="filterform" action="{{webPath `/manage/filters`}}{{if gt $.filter.ID 0}}?edit={{.ID}}{{end}}" method="POST">
|
||||
{{- if gt $.filter.ID 0}}<input type="hidden" name="filterid" value="{{.ID}}">{{end -}}
|
||||
{{- if gt $.filter.ID 0}}<input type="hidden" name="filterid" value="{{$.filter.ID}}">{{end -}}
|
||||
Filter conditions are checked against a post after the IP is checked against the <a href="{{webPath `/manage/bans`}}">ban list</a>.
|
||||
The filter action will be executed only if all conditions are met. Tripcode searches do not include the prefix "!".
|
||||
<table>
|
||||
|
@ -53,31 +53,37 @@
|
|||
<th>Action</th>
|
||||
<td>
|
||||
<select name="action" id="action">
|
||||
<option value="reject">Reject post</option>
|
||||
<option value="ban">Ban IP</option>
|
||||
<option value="log">Log match</option>
|
||||
<option value="reject" {{if eq $.filter.MatchAction `reject`}}selected{{end}}>Reject post</option>
|
||||
<option value="ban" {{if eq $.filter.MatchAction `ban`}}selected{{end}}>Ban IP</option>
|
||||
<option value="log" {{if eq $.filter.MatchAction `log`}}selected{{end}}>Log match</option>
|
||||
</select>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th id="detail">Reason</th>
|
||||
<td><textarea name="detail" rows="5" cols="35">{{if gt $.filter.ID 0}}{{.MatchDetail}}{{end}}</textarea></td>
|
||||
<td><textarea name="detail" rows="5" cols="35">{{$.filter.MatchDetail}}</textarea></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th id="note">Staff Note</th>
|
||||
<td><textarea name="note" rows="5" cols="35">{{if gt $.filter.ID 0}}{{.StaffNote}}{{end}}</textarea></td>
|
||||
<td><textarea name="note" rows="5" cols="35">{{$.filter.StaffNote}}</textarea></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>Board(s):</th>
|
||||
<td id="boardslist">
|
||||
If no boards are selected, the filter will be applied to all boards
|
||||
{{- range $_,$board := .allBoards -}}
|
||||
<label for="applyboard{{$board.ID}}">/{{$board.Dir}}/ - {{$board.Title}} <input type="checkbox" name="applyboard{{$board.ID}}" id="applyboard{{$board.ID}}"></label>
|
||||
<label for="applyboard{{$board.ID}}">/{{$board.Dir}}/ - {{$board.Title}} <input type="checkbox" name="applyboard{{$board.ID}}" id="applyboard{{$board.ID}}"
|
||||
{{- range $_,$boardID := $.filterBoards -}}
|
||||
{{if eq $boardID $board.ID}}checked{{end}}
|
||||
{{- end}}></label>
|
||||
{{- end -}}
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
<input type="submit" name="dofilter{{if gt $.filter.ID 0}}edit{{else}}add{{end}}" value="Submit Filter">
|
||||
{{- if gt $.filter.ID 0 -}}
|
||||
<input type="button" onclick="window.location='{{webPath `manage/filters`}}'" value="Cancel"/>
|
||||
{{- end -}}
|
||||
</form>
|
||||
<hr/>
|
||||
<h2>Filter list</h2>
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue