Skip to content

Instantly share code, notes, and snippets.

@stek29
Last active October 29, 2019 16:06
Show Gist options
  • Save stek29/7da818858713b7d82c1567800a478399 to your computer and use it in GitHub Desktop.
Save stek29/7da818858713b7d82c1567800a478399 to your computer and use it in GitHub Desktop.
package main
import (
"context"
"errors"
"log"
"os"
"os/signal"
"regexp"
"strconv"
"strings"
"github.com/jinzhu/configor"
"github.com/spf13/pflag"
"github.com/stek29/vk"
"github.com/stek29/vk/vkapi"
"github.com/stek29/vk/vkbot"
)
var vkClient vk.API
var cyrilRegex = regexp.MustCompile(`(?i)[а-яёй]`)
type extConfig struct {
VKToken string
Groups []vkbot.CallbackGroupConfig
}
func getNameForUID(userID int) (string, error) {
users, err := vkapi.Users{vkClient}.Get(vkapi.UsersGetParams{
UserIDs: []string{strconv.Itoa(userID)},
})
if err != nil {
return "", err
}
if len(users) < 1 || users[0].ID != userID {
return "", errors.New("VK didn't return user we wanted")
}
return users[0].FirstName, nil
}
func getNameForGID(groupID int) (string, error) {
groups, err := vkapi.Groups{vkClient}.GetByID(vkapi.GroupsGetByIDParams{
GroupID: strconv.Itoa(groupID),
})
if err != nil {
return "", err
}
if len(groups) < 1 || groups[0].ID != groupID {
return "", errors.New("VK didn't return group we wanted")
}
return groups[0].Name, nil
}
func getNameForID(ID int) (string, error) {
switch {
case ID > 0:
return getNameForUID(ID)
case ID < 0:
return getNameForGID(-ID)
default:
return "", errors.New("ID cant be 0!")
}
}
type commentDeleter func(client vk.API, ownerID int, commentID int) error
func handleComment(ownerID int, comment vk.Comment, deleter commentDeleter) {
commentText := comment.Text
log.Printf("Handling Comment: %d_%d (%q)", ownerID, comment.ID, commentText)
if replyTo := comment.ReplyToUser; replyTo != 0 {
name, err := getNameForID(replyTo)
if err != nil {
log.Printf("Cant get first name for id%d: %v", replyTo, err)
}
commentText = strings.Replace(commentText, name, "", -1)
}
if cyrilRegex.MatchString(commentText) {
if err := deleter(vkClient, ownerID, comment.ID); err != nil {
log.Printf("Cant delete comment %d_%d: %v", ownerID, comment.ID, err)
}
log.Printf("Deleted Comment: %d_%d", ownerID, comment.ID)
}
}
func handleDeleteComment(ok bool, err error) error {
if err != nil {
return err
}
if ok != true {
return errors.New("deleteComment returned false")
}
return nil
}
func wallCommentDeleter(client vk.API, ownerID int, commentID int) error {
return handleDeleteComment(vkapi.Wall{vkClient}.DeleteComment(vkapi.WallDeleteCommentParams{
OwnerID: ownerID,
CommentID: commentID,
}))
}
func photoCommentDeleter(client vk.API, ownerID int, commentID int) error {
return handleDeleteComment(vkapi.Photos{vkClient}.DeleteComment(vkapi.PhotosDeleteCommentParams{
OwnerID: ownerID,
CommentID: commentID,
}))
}
func videoCommentDeleter(client vk.API, ownerID int, commentID int) error {
return handleDeleteComment(vkapi.Video{vkClient}.DeleteComment(vkapi.VideoDeleteCommentParams{
OwnerID: ownerID,
CommentID: commentID,
}))
}
func marketCommentDeleter(client vk.API, ownerID int, commentID int) error {
return handleDeleteComment(vkapi.Market{vkClient}.DeleteComment(vkapi.MarketDeleteCommentParams{
OwnerID: ownerID,
CommentID: commentID,
}))
}
func handleEvent(event vk.CallbackEvent) {
log.Printf("Got event: GroupID=%v Secret=%v Event=%T", event.GroupID, event.Secret, event.Event)
switch v := event.Event.(type) {
case vk.WallReplyNew:
go handleComment(v.PostOwnerID, v.Comment, wallCommentDeleter)
case vk.WallReplyEdit:
go handleComment(v.PostOwnerID, v.Comment, wallCommentDeleter)
case vk.WallReplyRestore:
go handleComment(v.PostOwnerID, v.Comment, wallCommentDeleter)
case vk.PhotoCommentNew:
go handleComment(v.PhotoOwnerID, v.Comment, photoCommentDeleter)
case vk.PhotoCommentEdit:
go handleComment(v.PhotoOwnerID, v.Comment, photoCommentDeleter)
case vk.PhotoCommentRestore:
go handleComment(v.PhotoOwnerID, v.Comment, photoCommentDeleter)
case vk.VideoCommentNew:
go handleComment(v.VideoOwnerID, v.Comment, videoCommentDeleter)
case vk.VideoCommentEdit:
go handleComment(v.VideoOwnerID, v.Comment, videoCommentDeleter)
case vk.VideoCommentRestore:
go handleComment(v.VideoOwnerID, v.Comment, videoCommentDeleter)
case vk.MarketCommentNew:
go handleComment(v.MarketOwnerID, v.Comment, marketCommentDeleter)
case vk.MarketCommentEdit:
go handleComment(v.MarketOwnerID, v.Comment, marketCommentDeleter)
case vk.MarketCommentRestore:
go handleComment(v.MarketOwnerID, v.Comment, marketCommentDeleter)
}
}
func main() {
lAddr := pflag.StringP("listen", "l", "127.0.0.1:8081", "host:port to listen")
confPath := pflag.StringP("conf", "c", "nocyril.yaml", "Path to config file")
pflag.Parse()
var config extConfig
if err := configor.Load(&config, *confPath); err != nil {
log.Fatalf("Failed to load config: %v", err)
}
vkToken := config.VKToken
if vkToken == "" {
log.Fatal("vk token is required (check config file)")
}
if client, err := vk.NewBaseAPI(vk.BaseAPIConfig{AccessToken: vkToken}); err != nil {
log.Fatalf("Failed to create vkClient: %v", err)
} else {
vkClient = client
}
if len(config.Groups) == 0 {
log.Fatalf("At least one group config is required")
}
bot, err := vkbot.NewBot(vkClient, vkbot.BotConfig{
GroupID: config.Groups[0].GroupID,
Poller: &vkbot.CallbackPoller{
Listen: *lAddr,
GroupConfigs: config.Groups,
},
})
if err != nil {
log.Fatalf("Failed to create bot: %v", err)
}
ctx, cancel := context.WithCancel(context.Background())
go func(cancel context.CancelFunc) {
sigint := make(chan os.Signal, 1)
signal.Notify(sigint, os.Interrupt)
<-sigint
cancel()
}(cancel)
events, err := bot.StartPolling(ctx, 0)
if err != nil {
log.Fatal("Cat start polling:", err)
}
for e := range events {
handleEvent(e)
}
log.Printf("Bye!")
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment