reviewer-basic/basic.go (179 lines of code) (raw):
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package basic
import (
"embed"
"encoding/json"
"fmt"
"strings"
"github.com/apache/answer-plugins/reviewer-basic/i18n"
"github.com/apache/answer-plugins/util"
"github.com/apache/answer/plugin"
myI18n "github.com/segmentfault/pacman/i18n"
)
//go:embed info.yaml
var Info embed.FS
type Reviewer struct {
Config *ReviewerConfig
}
const (
OptionNone = "none"
OptionAll = "all"
OptionFirst = "first"
)
type ReviewerConfig struct {
PostAllNeedReview bool `json:"review_post_all"`
PostNeedReview bool `json:"review_post"`
PostReviewOption string `json:"review_post_option"`
PostReviewKeywords string `json:"review_post_keywords"`
PostDisallowedKeywords string `json:"disallowed_keywords"`
}
func init() {
plugin.Register(&Reviewer{
Config: &ReviewerConfig{},
})
}
func (r *Reviewer) Info() plugin.Info {
info := &util.Info{}
info.GetInfo(Info)
return plugin.Info{
Name: plugin.MakeTranslator(i18n.InfoName),
SlugName: info.SlugName,
Description: plugin.MakeTranslator(i18n.InfoDescription),
Author: info.Author,
Version: info.Version,
Link: info.Link,
}
}
func (r *Reviewer) Review(content *plugin.ReviewContent) (result *plugin.ReviewResult) {
result = &plugin.ReviewResult{Approved: true, ReviewStatus: plugin.ReviewStatusApproved}
// If the author is admin, no need to review
if content.Author.Role > 1 {
return result
}
if r.Config.PostReviewOption == OptionAll || (r.Config.PostReviewOption == "" && r.Config.PostAllNeedReview) {
result = &plugin.ReviewResult{
Approved: false,
ReviewStatus: plugin.ReviewStatusNeedReview,
Reason: plugin.TranslateWithData(myI18n.Language(content.Language), i18n.CommentNeedReview, nil),
}
return result
}
if (r.Config.PostReviewOption == OptionFirst || (r.Config.PostReviewOption == "" && r.Config.PostNeedReview)) && content.Author.ApprovedQuestionAmount+content.Author.ApprovedAnswerAmount == 0 {
result = &plugin.ReviewResult{
Approved: false,
ReviewStatus: plugin.ReviewStatusNeedReview,
Reason: plugin.TranslateWithData(myI18n.Language(content.Language), i18n.CommentNeedReview, nil),
}
return result
}
keywords := strings.Split(r.Config.PostReviewKeywords, "\n")
disallowedKeywords := strings.Split(r.Config.PostDisallowedKeywords, "\n")
// Check if the post contains the keywords that need review
for _, keyword := range keywords {
keyword = strings.TrimSpace(keyword)
if len(keyword) == 0 {
continue
}
keyword = strings.ToLower(keyword)
if strings.Contains(strings.ToLower(content.Title), keyword) ||
strings.Contains(strings.ToLower(content.Content), keyword) ||
strings.Contains(content.IP, keyword) ||
strings.Contains(content.UserAgent, keyword) ||
r.checkTags(content.Tags, keyword) {
return &plugin.ReviewResult{
Approved: false,
ReviewStatus: plugin.ReviewStatusNeedReview,
Reason: fmt.Sprintf(plugin.TranslateWithData(myI18n.Language(content.Language), i18n.CommentMatchWordReview, nil), keyword),
}
}
}
// If the post contains the disallowed keywords
for _, disallowedKeyword := range disallowedKeywords {
disallowedKeyword = strings.TrimSpace(disallowedKeyword)
if len(disallowedKeyword) == 0 {
continue
}
disallowedKeyword = strings.ToLower(disallowedKeyword)
if strings.Contains(strings.ToLower(content.Title), disallowedKeyword) ||
strings.Contains(strings.ToLower(content.Content), disallowedKeyword) ||
strings.Contains(content.IP, disallowedKeyword) ||
strings.Contains(content.UserAgent, disallowedKeyword) ||
r.checkTags(content.Tags, disallowedKeyword) {
return &plugin.ReviewResult{
Approved: false,
ReviewStatus: plugin.ReviewStatusDeleteDirectly,
Reason: fmt.Sprintf(plugin.TranslateWithData(myI18n.Language(content.Language), i18n.CommentMatchWordReview, nil), disallowedKeyword),
}
}
}
return result
}
func (r *Reviewer) ConfigFields() []plugin.ConfigField {
defaultOption := OptionNone
if r.Config.PostReviewOption == "" {
if r.Config.PostAllNeedReview {
defaultOption = OptionAll
} else if r.Config.PostNeedReview {
defaultOption = OptionFirst
}
} else {
defaultOption = r.Config.PostReviewOption
}
return []plugin.ConfigField{
{
Name: "review_post_option",
Type: plugin.ConfigTypeSelect,
Title: plugin.MakeTranslator(i18n.ConfigReviewPostTitle),
Required: false,
UIOptions: plugin.ConfigFieldUIOptions{},
Value: defaultOption,
Options: []plugin.ConfigFieldOption{
{
Value: OptionNone,
Label: plugin.MakeTranslator(i18n.ConfigSelectOption),
},
{
Value: OptionAll,
Label: plugin.MakeTranslator(i18n.ConfigReviewPostLabelAll),
},
{
Value: OptionFirst,
Label: plugin.MakeTranslator(i18n.ConfigReviewPostLabelFirst),
},
},
},
{
Name: "review_post_keywords",
Type: plugin.ConfigTypeTextarea,
Title: plugin.MakeTranslator(i18n.ConfigReviewPostKeywordsTitle),
Description: plugin.MakeTranslator(i18n.ConfigReviewPostKeywordsDescription),
Value: r.Config.PostReviewKeywords,
},
{
Name: "disallowed_keywords",
Type: plugin.ConfigTypeTextarea,
Title: plugin.MakeTranslator(i18n.ConfigDisallowedKeywordsTitle),
Description: plugin.MakeTranslator(i18n.ConfigDisallowedKeywordsDescription),
Value: r.Config.PostDisallowedKeywords,
},
}
}
func (r *Reviewer) ConfigReceiver(config []byte) error {
c := &ReviewerConfig{}
_ = json.Unmarshal(config, c)
if c.PostReviewOption == OptionAll {
c.PostAllNeedReview = true
c.PostNeedReview = false
} else if c.PostReviewOption == OptionFirst {
c.PostAllNeedReview = false
c.PostNeedReview = true
} else if c.PostReviewOption == OptionNone {
c.PostAllNeedReview = false
c.PostNeedReview = false
}
r.Config = c
return nil
}
func (r *Reviewer) checkTags(tags []string, keyword string) bool {
for _, tag := range tags {
if strings.Contains(strings.ToLower(tag), keyword) {
return true
}
}
return false
}