1
0
Fork 0
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:
Eggbertx 2024-08-19 16:34:48 -07:00
parent a7744d6d88
commit 38c4107b15
3 changed files with 112 additions and 46 deletions

View file

@ -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()
}

View file

@ -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{

View file

@ -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>