api,frontend: add Akismet spam flagging integration
This commit is contained in:
parent
d1318daaca
commit
9fcf67d667
9
api/Gopkg.lock
generated
9
api/Gopkg.lock
generated
@ -9,6 +9,14 @@
|
|||||||
revision = "64a2037ec6be8a4b0c1d1f706ed35b428b989239"
|
revision = "64a2037ec6be8a4b0c1d1f706ed35b428b989239"
|
||||||
version = "v0.26.0"
|
version = "v0.26.0"
|
||||||
|
|
||||||
|
[[projects]]
|
||||||
|
branch = "master"
|
||||||
|
digest = "1:9769b231d8f5ff406a012aa7f293e45ed69d11617832a1c3c7b8c6ce1558a2a1"
|
||||||
|
name = "github.com/adtac/go-akismet"
|
||||||
|
packages = ["akismet"]
|
||||||
|
pruneopts = "UT"
|
||||||
|
revision = "0ca9e1023047c869ecd4bd3c20780511597a4a77"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
digest = "1:15042ad3498153684d09f393bbaec6b216c8eec6d61f63dff711de7d64ed8861"
|
digest = "1:15042ad3498153684d09f393bbaec6b216c8eec6d61f63dff711de7d64ed8861"
|
||||||
name = "github.com/golang/protobuf"
|
name = "github.com/golang/protobuf"
|
||||||
@ -143,6 +151,7 @@
|
|||||||
analyzer-name = "dep"
|
analyzer-name = "dep"
|
||||||
analyzer-version = 1
|
analyzer-version = 1
|
||||||
input-imports = [
|
input-imports = [
|
||||||
|
"github.com/adtac/go-akismet/akismet",
|
||||||
"github.com/gorilla/handlers",
|
"github.com/gorilla/handlers",
|
||||||
"github.com/gorilla/mux",
|
"github.com/gorilla/mux",
|
||||||
"github.com/lib/pq",
|
"github.com/lib/pq",
|
||||||
|
31
api/akismet.go
Normal file
31
api/akismet.go
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/adtac/go-akismet/akismet"
|
||||||
|
"os"
|
||||||
|
)
|
||||||
|
|
||||||
|
func isSpam(domain string, userIp string, userAgent string, name string, email string, url string, markdown string) bool {
|
||||||
|
akismetKey := os.Getenv("AKISMET_KEY")
|
||||||
|
if akismetKey == "" {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
res, err := akismet.Check(&akismet.Comment{
|
||||||
|
Blog: domain,
|
||||||
|
UserIP: userIp,
|
||||||
|
UserAgent: userAgent,
|
||||||
|
CommentType: "comment",
|
||||||
|
CommentAuthor: name,
|
||||||
|
CommentAuthorEmail: email,
|
||||||
|
CommentAuthorURL: url,
|
||||||
|
CommentContent: markdown,
|
||||||
|
}, akismetKey)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
logger.Errorf("error: cannot validate commenet using Akismet: %v", err)
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
return res
|
||||||
|
}
|
@ -89,8 +89,12 @@ func commentNewHandler(w http.ResponseWriter, r *http.Request) {
|
|||||||
var state string
|
var state string
|
||||||
|
|
||||||
if *x.CommenterToken == "anonymous" {
|
if *x.CommenterToken == "anonymous" {
|
||||||
state = "unapproved"
|
|
||||||
commenterHex = "anonymous"
|
commenterHex = "anonymous"
|
||||||
|
if isSpam(*x.Domain, getIp(r), getUserAgent(r), "Anonymous", "", "", *x.Markdown) {
|
||||||
|
state = "flagged"
|
||||||
|
} else {
|
||||||
|
state = "unapproved"
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
c, err := commenterGetByCommenterToken(*x.CommenterToken)
|
c, err := commenterGetByCommenterToken(*x.CommenterToken)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -112,10 +116,14 @@ func commentNewHandler(w http.ResponseWriter, r *http.Request) {
|
|||||||
if isModerator {
|
if isModerator {
|
||||||
state = "approved"
|
state = "approved"
|
||||||
} else {
|
} else {
|
||||||
if d.RequireModeration {
|
if isSpam(*x.Domain, getIp(r), getUserAgent(r), c.Name, c.Email, c.Link, *x.Markdown) {
|
||||||
state = "unapproved"
|
state = "flagged"
|
||||||
} else {
|
} else {
|
||||||
state = "approved"
|
if d.RequireModeration {
|
||||||
|
state = "unapproved"
|
||||||
|
} else {
|
||||||
|
state = "approved"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -126,5 +134,5 @@ func commentNewHandler(w http.ResponseWriter, r *http.Request) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
bodyMarshal(w, response{"success": true, "commentHex": commentHex, "approved": state == "approved"})
|
bodyMarshal(w, response{"success": true, "commentHex": commentHex, "state": state})
|
||||||
}
|
}
|
||||||
|
@ -43,6 +43,8 @@ func configParse() error {
|
|||||||
"SMTP_PORT": "",
|
"SMTP_PORT": "",
|
||||||
"SMTP_FROM_ADDRESS": "",
|
"SMTP_FROM_ADDRESS": "",
|
||||||
|
|
||||||
|
"AKISMET_KEY": "",
|
||||||
|
|
||||||
"GOOGLE_KEY": "",
|
"GOOGLE_KEY": "",
|
||||||
"GOOGLE_SECRET": "",
|
"GOOGLE_SECRET": "",
|
||||||
}
|
}
|
||||||
|
@ -3,9 +3,9 @@ package main
|
|||||||
import ()
|
import ()
|
||||||
|
|
||||||
type page struct {
|
type page struct {
|
||||||
Domain string `json:"domain"`
|
Domain string `json:"domain"`
|
||||||
Path string `json:"path"`
|
Path string `json:"path"`
|
||||||
IsLocked bool `json:"isLocked"`
|
IsLocked bool `json:"isLocked"`
|
||||||
CommentCount int `json:"commentCount"`
|
CommentCount int `json:"commentCount"`
|
||||||
StickyCommentHex string `json:"stickyCommentHex"`
|
StickyCommentHex string `json:"stickyCommentHex"`
|
||||||
}
|
}
|
||||||
|
@ -43,3 +43,16 @@ func bodyMarshal(w http.ResponseWriter, x map[string]interface{}) error {
|
|||||||
w.Write(resp)
|
w.Write(resp)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func getIp(r *http.Request) string {
|
||||||
|
ip := r.RemoteAddr
|
||||||
|
if r.Header.Get("X-Forwarded-For") != "" {
|
||||||
|
ip = r.Header.Get("X-Forwarded-For")
|
||||||
|
}
|
||||||
|
|
||||||
|
return ip
|
||||||
|
}
|
||||||
|
|
||||||
|
func getUserAgent(r *http.Request) string {
|
||||||
|
return r.Header.Get("User-Agent")
|
||||||
|
}
|
||||||
|
@ -51,6 +51,7 @@
|
|||||||
var ID_REMOVE = "commento-comment-remove-";
|
var ID_REMOVE = "commento-comment-remove-";
|
||||||
var ID_STICKY = "commento-comment-sticky-";
|
var ID_STICKY = "commento-comment-sticky-";
|
||||||
var ID_CONTENTS = "commento-comment-contents-";
|
var ID_CONTENTS = "commento-comment-contents-";
|
||||||
|
var ID_NAME = "commento-comment-name-";
|
||||||
var ID_SUBMIT_BUTTON = "commento-submit-button-";
|
var ID_SUBMIT_BUTTON = "commento-submit-button-";
|
||||||
var ID_FOOTER = "commento-footer";
|
var ID_FOOTER = "commento-footer";
|
||||||
|
|
||||||
@ -519,14 +520,17 @@
|
|||||||
$(ID_COMMENTS_AREA).innerHTML = "";
|
$(ID_COMMENTS_AREA).innerHTML = "";
|
||||||
commentsRender();
|
commentsRender();
|
||||||
|
|
||||||
if (!resp.approved) {
|
var message = "";
|
||||||
if (id == "root") {
|
if (resp.state == "unapproved")
|
||||||
var body = $(ID_SUPER_CONTAINER + id);
|
message = "Your comment is under moderation.";
|
||||||
prepend(body, messageCreate("Your comment is under moderation."));
|
else if (resp.state == "flagged")
|
||||||
} else {
|
message = "Your comment was flagged as spam and is under moderation.";
|
||||||
var body = $(ID_BODY + id);
|
|
||||||
append(body, messageCreate("Your comment is under moderation."));
|
if (message != "") {
|
||||||
}
|
if (id == "root")
|
||||||
|
prepend($(ID_SUPER_CONTAINER + id), messageCreate(message));
|
||||||
|
else
|
||||||
|
append($(ID_BODY + id), messageCreate(message));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@ -652,6 +656,7 @@
|
|||||||
remove.id = ID_REMOVE + comment.commentHex;
|
remove.id = ID_REMOVE + comment.commentHex;
|
||||||
sticky.id = ID_STICKY + comment.commentHex;
|
sticky.id = ID_STICKY + comment.commentHex;
|
||||||
contents.id = ID_CONTENTS + comment.commentHex;
|
contents.id = ID_CONTENTS + comment.commentHex;
|
||||||
|
name.id = ID_NAME + comment.commentHex;
|
||||||
|
|
||||||
collapse.title = "Collapse";
|
collapse.title = "Collapse";
|
||||||
upvote.title = "Upvote";
|
upvote.title = "Upvote";
|
||||||
@ -692,8 +697,10 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
classAdd(card, "card");
|
classAdd(card, "card");
|
||||||
if (isModerator && comment.state == "unapproved")
|
if (isModerator && comment.state != "approved")
|
||||||
classAdd(card, "dark-card");
|
classAdd(card, "dark-card");
|
||||||
|
if (comment.state == "flagged")
|
||||||
|
classAdd(name, "flagged");
|
||||||
classAdd(header, "header");
|
classAdd(header, "header");
|
||||||
classAdd(name, "name");
|
classAdd(name, "name");
|
||||||
classAdd(subtitle, "subtitle");
|
classAdd(subtitle, "subtitle");
|
||||||
@ -773,7 +780,7 @@
|
|||||||
if (parentHex == "root")
|
if (parentHex == "root")
|
||||||
append(options, sticky);
|
append(options, sticky);
|
||||||
append(options, remove);
|
append(options, remove);
|
||||||
if (comment.state == "unapproved")
|
if (comment.state != "approved")
|
||||||
append(options, approve);
|
append(options, approve);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
@ -823,10 +830,12 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
var card = $(ID_CARD + commentHex);
|
var card = $(ID_CARD + commentHex);
|
||||||
|
var name = $(ID_NAME + commentHex);
|
||||||
var options = $(ID_OPTIONS + commentHex);
|
var options = $(ID_OPTIONS + commentHex);
|
||||||
var tick = $(ID_APPROVE + commentHex);
|
var tick = $(ID_APPROVE + commentHex);
|
||||||
|
|
||||||
classRemove(card, "dark-card");
|
classRemove(card, "dark-card");
|
||||||
|
classRemove(name, "flagged");
|
||||||
remove(tick);
|
remove(tick);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -124,6 +124,17 @@
|
|||||||
width: fit-content;
|
width: fit-content;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.commento-flagged::after {
|
||||||
|
content: "Flagged";
|
||||||
|
text-transform: uppercase;
|
||||||
|
font-size: 10px;
|
||||||
|
background: $red-7;
|
||||||
|
color: white;
|
||||||
|
margin-left: 8px;
|
||||||
|
padding: 2px 6px 2px 6px;
|
||||||
|
border-radius: 100px;
|
||||||
|
}
|
||||||
|
|
||||||
.commento-subtitle {
|
.commento-subtitle {
|
||||||
display: block;
|
display: block;
|
||||||
color: #999;
|
color: #999;
|
||||||
|
Loading…
Reference in New Issue
Block a user