mirror of
https://github.com/Eggbertx/gochan.git
synced 2025-08-02 19:16:23 -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()
|
return f.conditions, rows.Close()
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetConditions replaces all current conditions associated with the filter and applies the given conditions.
|
func (f *Filter) setConditionsContext(ctx context.Context, tx *sql.Tx, conditions ...FilterCondition) error {
|
||||||
// It returns an error if no conditions are provided
|
if f.ID == 0 {
|
||||||
func (f *Filter) SetConditions(conditions ...FilterCondition) error {
|
return ErrInvalidFilter
|
||||||
if len(conditions) < 1 {
|
}
|
||||||
|
if len(conditions) == 0 {
|
||||||
return ErrNoConditions
|
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 {
|
if err != nil {
|
||||||
return err
|
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 {
|
for c, condition := range conditions {
|
||||||
conditions[c].FilterID = f.ID
|
conditions[c].FilterID = f.ID
|
||||||
condition.FilterID = f.ID
|
condition.FilterID = f.ID
|
||||||
|
@ -213,19 +208,58 @@ func (f *Filter) SetConditions(conditions ...FilterCondition) error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if err = tx.Commit(); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
f.conditions = conditions
|
f.conditions = conditions
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f *Filter) UpdateDetails(staffNote string, matchAction string, matchDetail string) error {
|
// SetConditions replaces all current conditions associated with the filter and applies the given conditions.
|
||||||
_, err := ExecTimeoutSQL(nil,
|
// 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 = ?`,
|
`UPDATE DBPREFIXfilters SET staff_note = ?, issued_at = ?, match_action = ?, match_detail = ? WHERE id = ?`,
|
||||||
staffNote, time.Now(), matchAction, matchDetail, f.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
|
// BoardDirs returns an array of board directories associated with this filter
|
||||||
|
@ -307,6 +341,21 @@ func (f *Filter) BoardIDs() ([]int, error) {
|
||||||
return ids, nil
|
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,
|
// SetBoardIDs sets the board IDs to be associated with the filter. If no boards are used,
|
||||||
// the filter will be applied to all boards
|
// the filter will be applied to all boards
|
||||||
func (f *Filter) SetBoardIDs(ids ...int) error {
|
func (f *Filter) SetBoardIDs(ids ...int) error {
|
||||||
|
@ -318,17 +367,9 @@ func (f *Filter) SetBoardIDs(ids ...int) error {
|
||||||
}
|
}
|
||||||
defer tx.Rollback()
|
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
|
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()
|
return tx.Commit()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -487,6 +528,20 @@ func (fc *FilterCondition) testCondition(post *Post, upload *Upload, request *ht
|
||||||
return match, err
|
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
|
// 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
|
// 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) {
|
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 {
|
if err = QueryRowContextSQL(ctx, tx, `SELECT MAX(id) FROM DBPREFIXfilters`, nil, []any{&filter.ID}); err != nil {
|
||||||
return err
|
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
|
return err
|
||||||
}
|
}
|
||||||
if err = filter.SetConditions(conditions...); err != nil {
|
if err = filter.setBoardIDsContext(ctx, tx, boards...); err != nil {
|
||||||
return err
|
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")
|
errEv.Err(err).Caller().Int("filterID", filterID).Msg("Unable to get filter from ID")
|
||||||
return nil, err
|
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 {
|
for k, v := range request.PostForm {
|
||||||
|
@ -271,7 +268,6 @@ func filtersCallback(_ http.ResponseWriter, request *http.Request, staff *gcsql.
|
||||||
boardIDLogArr.Int(boardID)
|
boardIDLogArr.Int(boardID)
|
||||||
boards = append(boards, boardID)
|
boards = append(boards, boardID)
|
||||||
}
|
}
|
||||||
infoEv.Array("boardIDs", boardIDLogArr)
|
|
||||||
|
|
||||||
// set filter conditions
|
// set filter conditions
|
||||||
if strings.HasPrefix(k, "field") {
|
if strings.HasPrefix(k, "field") {
|
||||||
|
@ -319,8 +315,10 @@ func filtersCallback(_ http.ResponseWriter, request *http.Request, staff *gcsql.
|
||||||
Msg("Unable to submit filter")
|
Msg("Unable to submit filter")
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
infoEv.Msg("Filter submitted")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
data["filterBoards"] = make([]int, 0)
|
||||||
if editFilter := request.FormValue("edit"); editFilter != "" {
|
if editFilter := request.FormValue("edit"); editFilter != "" {
|
||||||
// user clicked on Edit link in filter row
|
// user clicked on Edit link in filter row
|
||||||
filterID, err := strconv.Atoi(editFilter)
|
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")
|
errEv.Err(err).Caller().Int("filterID", filterID).Msg("Unable to get filter conditions")
|
||||||
return nil, errors.New("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 {
|
} else {
|
||||||
// user loaded /manage/filters, populate single "default" condition
|
// user loaded /manage/filters, populate single "default" condition
|
||||||
data["filter"] = &gcsql.Filter{
|
data["filter"] = &gcsql.Filter{
|
||||||
|
|
|
@ -5,23 +5,23 @@
|
||||||
<th>Field/Condition:</th>
|
<th>Field/Condition:</th>
|
||||||
<td>
|
<td>
|
||||||
<select name="field{{.conditionNo}}" class="sel-field">
|
<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>
|
</select>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr class="search-cndtn">
|
<tr class="search-cndtn" {{if not .condition.HasSearchField}}style="display:none"{{end}}>
|
||||||
<th>Search:</th>
|
<th>Search:</th>
|
||||||
<td><input type="text" name="search{{.conditionNo}}" value="{{.condition.Search}}"></td>
|
<td><input type="text" name="search{{.conditionNo}}" value="{{.condition.Search}}"></td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr class="regex-cndtn">
|
<tr class="regex-cndtn" {{if not .condition.CanDoRegex}}style="display: none"{{end}}>
|
||||||
<th></th>
|
<th></th>
|
||||||
<td><label>Is regex <input type="checkbox" name="isregex{{.conditionNo}}" {{if .condition.IsRegex}}checked{{end}}/></label></td>
|
<td><label>Is regex <input type="checkbox" name="isregex{{.conditionNo}}" {{if .condition.IsRegex}}checked{{end}}/></label></td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr class="btns-cndtn">
|
<tr class="btns-cndtn">
|
||||||
<td></td>
|
<td></td>
|
||||||
<td>
|
<td><a href="#" class="rem-cndtn">Remove condition</a></td>
|
||||||
<a href="#" class="rem-cndtn">Remove condition</a>
|
|
||||||
</td>
|
|
||||||
</tr>
|
</tr>
|
||||||
</table>
|
</table>
|
||||||
</fieldset>
|
</fieldset>
|
||||||
|
@ -29,7 +29,7 @@
|
||||||
|
|
||||||
<h2>{{if gt $.filter.ID 0}}Edit filter{{else}}New filter{{end}}</h2>
|
<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">
|
<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>.
|
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 "!".
|
The filter action will be executed only if all conditions are met. Tripcode searches do not include the prefix "!".
|
||||||
<table>
|
<table>
|
||||||
|
@ -53,31 +53,37 @@
|
||||||
<th>Action</th>
|
<th>Action</th>
|
||||||
<td>
|
<td>
|
||||||
<select name="action" id="action">
|
<select name="action" id="action">
|
||||||
<option value="reject">Reject post</option>
|
<option value="reject" {{if eq $.filter.MatchAction `reject`}}selected{{end}}>Reject post</option>
|
||||||
<option value="ban">Ban IP</option>
|
<option value="ban" {{if eq $.filter.MatchAction `ban`}}selected{{end}}>Ban IP</option>
|
||||||
<option value="log">Log match</option>
|
<option value="log" {{if eq $.filter.MatchAction `log`}}selected{{end}}>Log match</option>
|
||||||
</select>
|
</select>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<th id="detail">Reason</th>
|
<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>
|
||||||
<tr>
|
<tr>
|
||||||
<th id="note">Staff Note</th>
|
<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>
|
||||||
<tr>
|
<tr>
|
||||||
<th>Board(s):</th>
|
<th>Board(s):</th>
|
||||||
<td id="boardslist">
|
<td id="boardslist">
|
||||||
If no boards are selected, the filter will be applied to all boards
|
If no boards are selected, the filter will be applied to all boards
|
||||||
{{- range $_,$board := .allBoards -}}
|
{{- 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 -}}
|
{{- end -}}
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
</table>
|
</table>
|
||||||
<input type="submit" name="dofilter{{if gt $.filter.ID 0}}edit{{else}}add{{end}}" value="Submit Filter">
|
<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>
|
</form>
|
||||||
<hr/>
|
<hr/>
|
||||||
<h2>Filter list</h2>
|
<h2>Filter list</h2>
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue