From 8c6e023e513dcf46a45dd201b1cdb048ecefc1c7 Mon Sep 17 00:00:00 2001 From: fade Date: Thu, 8 Sep 2022 08:26:25 -0400 Subject: [PATCH] add notification cleaning --- README.md | 22 +++++++------ bot.go | 63 ++++++++++++++++++++++--------------- cleaning.go | 36 ++++++++++++++++++++++ config.go | 22 +++++++------ config.json | 22 +++++++------ limits.go | 89 +++++++++++++++++++++++++++++++++++++---------------- logger.go | 2 +- main.go | 5 +++ utils.go | 13 ++++++++ 9 files changed, 192 insertions(+), 82 deletions(-) create mode 100644 cleaning.go create mode 100644 utils.go diff --git a/README.md b/README.md index c173bd4..8f67b74 100644 --- a/README.md +++ b/README.md @@ -17,16 +17,18 @@ This is a bot which implements group functionality in Mastodon. The bot is configured in a JSON file that looks like this: ``` { - "Server": "https://example.com", - "ClientID": "0000000000000000000000000000000000000000000", - "ClientSecret": "0000000000000000000000000000000000000000000", - "AccessToken": "0000000000000000000000000000000000000000000", - "WelcomeMessage": "We have a new member in our group. Please love and favor" - "Max_toots": 2, - "Toots_interval": 12, - "Duplicate_buf": 10, - "Order_limit": 1, - "Admins": ["admin@example.com"] + "Server": "https://example.com", + "ClientID": "0000000000000000000000000000000000000000000", + "ClientSecret": "0000000000000000000000000000000000000000000", + "AccessToken": "0000000000000000000000000000000000000000000", + "WelcomeMessage": "We have a new member in our group. Please love and favor", + "NotFollowedMessage": "you are not followed", + "Max_toots": 2, + "Toots_interval": 12, + "Duplicate_buf": 10, + "Order_limit": 1, + "Del_notices_interval": 30, + "Admins": ["admin@example.com"] } ``` diff --git a/bot.go b/bot.go index ccae133..e1f8e6c 100644 --- a/bot.go +++ b/bot.go @@ -10,26 +10,25 @@ import ( "github.com/mattn/go-mastodon" ) -func RunBot() { - logger_init() - - c := mastodon.NewClient(&mastodon.Config{ +var ( + c = mastodon.NewClient(&mastodon.Config{ Server: Conf.Server, ClientID: Conf.ClientID, ClientSecret: Conf.ClientSecret, AccessToken: Conf.AccessToken, }) - ctx := context.Background() + ctx = context.Background() + + my_account, _ = c.GetAccountCurrentUser(ctx) +) + +func RunBot() { events, err := c.StreamingUser(ctx) if err != nil { ErrorLogger.Println("Streaming") } - my_account, err := c.GetAccountCurrentUser(ctx) - if err != nil { - ErrorLogger.Println("Fetch account info") - } followers, err := c.GetAccountFollowers(ctx, my_account.ID, &mastodon.Pagination{Limit: 60}) if err != nil { ErrorLogger.Println("Fetch followers") @@ -43,28 +42,30 @@ func RunBot() { } notif := notifEvent.Notification + ntype := notif.Type + acct := notif.Status.Account.Acct + content := notif.Status.Content + tooturl := notif.Status.URL - // Posting function - postToot := func(toot string, vis string) error { + /*postToot := func(toot string, vis string) (*mastodon.Status, error) { conToot := mastodon.Toot{ Status: toot, Visibility: vis, } - _, err := c.PostStatus(ctx, &conToot) - return err - } + status, err := c.PostStatus(ctx, &conToot) + return status, err + }*/ // New follower - if notif.Type == "follow" { - acct := notif.Account.Acct - if !followed(acct) { // Add to db and post welcome message + if ntype == "follow" { + if !exist_in_database(acct) { // Add to db and post welcome message InfoLogger.Printf("%s followed", acct) add_to_db(acct) InfoLogger.Printf("%s added to database", acct) message := fmt.Sprintf("%s @%s", Conf.WelcomeMessage, acct) - err := postToot(message, "public") + _, err := postToot(message, "public") if err != nil { ErrorLogger.Println("Post welcome message") } @@ -73,11 +74,7 @@ func RunBot() { } // Read message - if notif.Type == "mention" { - acct := notif.Status.Account.Acct - content := notif.Status.Content - tooturl := notif.Status.URL - + if ntype == "mention" { for i := 0; i < len(followers); i++ { if acct == string(followers[i].Acct) { // Follow check if notif.Status.Visibility == "public" { // Reblog toot @@ -96,7 +93,7 @@ func RunBot() { } // Add to db if needed - if !followed(acct) { + if !exist_in_database(acct) { add_to_db(acct) InfoLogger.Printf("%s added to database", acct) } @@ -148,6 +145,24 @@ func RunBot() { break } } + if i == len(followers)-1 { // Notify user + if got_notice(acct) == 0 { + if !exist_in_database(acct) { + add_to_db(acct) + InfoLogger.Printf("%s added to database", acct) + } + + message := fmt.Sprintf("@%s %s", acct, Conf.NotFollowedMessage) + _, err := postToot(message, "direct") + if err != nil { + ErrorLogger.Printf("Notify %s", acct) + } + InfoLogger.Printf("%s has been notified", acct) + + mark_notice(acct) + InfoLogger.Printf("%s marked notification in database", acct) + } + } } } } diff --git a/cleaning.go b/cleaning.go new file mode 100644 index 0000000..26e8dea --- /dev/null +++ b/cleaning.go @@ -0,0 +1,36 @@ +package main + +import ( + "sync" + "time" + + "github.com/mattn/go-mastodon" +) + +var ( + wg sync.WaitGroup +) + +// Delete notices +func DeleteNotices() { + wg.Done() + + for { + statuses, err := c.GetAccountStatuses(ctx, my_account.ID, &mastodon.Pagination{Limit: 60}) + if err != nil { + ErrorLogger.Println("Get account statuses") + } + + time.Sleep(time.Duration(Conf.Del_notices_interval) * time.Second) + + for i := range statuses { + if statuses[i].Visibility == "direct" { + c.DeleteStatus(ctx, statuses[i].ID) + } + } + InfoLogger.Println("Cleaning notices") + + reset_notice_counter() + InfoLogger.Println("Reset notice counter") + } +} diff --git a/config.go b/config.go index f58e399..eb2d41a 100644 --- a/config.go +++ b/config.go @@ -16,16 +16,18 @@ var ( ) type Config struct { - Server string `json:"Server"` - ClientID string `json:"ClientID"` - ClientSecret string `json:"ClientSecret"` - AccessToken string `json:"AccessToken"` - WelcomeMessage string `json:"WelcomeMessage"` - Max_toots uint16 `json:"Max_toots"` - Toots_interval uint16 `json:"Toots_interval"` - Duplicate_buf uint16 `json:"Duplicate_buf"` - Order_limit uint16 `json:"Order_limit"` - Admins []string `json:"Admins"` + Server string `json:"Server"` + ClientID string `json:"ClientID"` + ClientSecret string `json:"ClientSecret"` + AccessToken string `json:"AccessToken"` + WelcomeMessage string `json:"WelcomeMessage"` + NotFollowedMessage string `json:"NotFollowedMessage"` + Max_toots uint `json:"Max_toots"` + Toots_interval uint `json:"Toots_interval"` + Duplicate_buf uint `json:"Duplicate_buf"` + Order_limit uint `json:"Order_limit"` + Del_notices_interval uint `json:"Del_notices_interval"` + Admins []string `json:"Admins"` } func ReadConfig() Config { diff --git a/config.json b/config.json index 878869c..1eec574 100644 --- a/config.json +++ b/config.json @@ -1,12 +1,14 @@ { - "Server": "https://example.com", - "ClientID": "0000000000000000000000000000000000000000000", - "ClientSecret": "0000000000000000000000000000000000000000000", - "AccessToken": "0000000000000000000000000000000000000000000", - "WelcomeMessage": "We have a new member in our group. Please love and favor", - "Max_toots": 2, - "Toots_interval": 12, - "Duplicate_buf": 10, - "Order_limit": 1, - "Admins": ["admin@example.com"] + "Server": "https://example.com", + "ClientID": "0000000000000000000000000000000000000000000", + "ClientSecret": "0000000000000000000000000000000000000000000", + "AccessToken": "0000000000000000000000000000000000000000000", + "WelcomeMessage": "We have a new member in our group. Please love and favor", + "NotFollowedMessage": "you are not followed", + "Max_toots": 2, + "Toots_interval": 12, + "Duplicate_buf": 10, + "Order_limit": 1, + "Del_notices_interval": 30, + "Admins": ["admin@example.com"] } \ No newline at end of file diff --git a/limits.go b/limits.go index 9b69748..e67c89c 100644 --- a/limits.go +++ b/limits.go @@ -9,6 +9,10 @@ import ( _ "github.com/mattn/go-sqlite3" ) +var ( + db = init_limit_db() +) + // Init database func init_limit_db() *sql.DB { db, err := sql.Open("sqlite3", *DBPath) @@ -16,7 +20,7 @@ func init_limit_db() *sql.DB { ErrorLogger.Println("Open database") } - cmd1 := `CREATE TABLE IF NOT EXISTS Limits (id INTEGER PRIMARY KEY AUTOINCREMENT, acct TEXT, ticket INTEGER, order_msg INTEGER, time TEXT)` + cmd1 := `CREATE TABLE IF NOT EXISTS Limits (id INTEGER PRIMARY KEY AUTOINCREMENT, acct TEXT, ticket INTEGER, order_msg INTEGER, got_notice INTEGER, posted TEXT)` cmd2 := `CREATE TABLE IF NOT EXISTS MsgHashs (message_hash TEXT)` stat1, err := db.Prepare(cmd1) @@ -36,18 +40,16 @@ func init_limit_db() *sql.DB { // Add account to database func add_to_db(acct string) { - db := init_limit_db() - cmd := `INSERT INTO Limits (acct, ticket, order_msg) VALUES (?, ?, ?)` + cmd := `INSERT INTO Limits (acct, ticket, order_msg, got_notice) VALUES (?, ?, ?, ?)` stat, err := db.Prepare(cmd) if err != nil { - ErrorLogger.Println("Add account to databse") + ErrorLogger.Println("Add account to database") } - stat.Exec(acct, Conf.Max_toots, 0) + stat.Exec(acct, Conf.Max_toots, 0, 0) } // Check followed once -func followed(acct string) bool { - db := init_limit_db() +func exist_in_database(acct string) bool { cmd := `SELECT acct FROM Limits WHERE acct = ?` err := db.QueryRow(cmd, acct).Scan(&acct) if err != nil { @@ -63,34 +65,32 @@ func followed(acct string) bool { // Take ticket for tooting func take_ticket(acct string) { - db := init_limit_db() cmd1 := `SELECT ticket FROM Limits WHERE acct = ?` - cmd2 := `UPDATE Limits SET ticket = ?, time = ? WHERE acct = ?` + cmd2 := `UPDATE Limits SET ticket = ?, posted = ? WHERE acct = ?` - var ticket uint16 + var ticket uint db.QueryRow(cmd1, acct).Scan(&ticket) if ticket > 0 { ticket = ticket - 1 } + now := time.Now() + last_toot_at := time.Date(now.Year(), now.Month(), now.Day(), now.Hour(), now.Minute(), now.Second(), 0, time.Local).Format("2006/01/02 15:04:05 MST") + stat, err := db.Prepare(cmd2) if err != nil { ErrorLogger.Println("Take ticket") } - now := time.Now() - last_toot_at := time.Date(now.Year(), now.Month(), now.Day(), now.Hour(), now.Minute(), now.Second(), 0, time.Local).Format("2006/01/02 15:04:05 MST") - stat.Exec(ticket, last_toot_at, acct) } // Check ticket availability -func check_ticket(acct string) uint16 { - db := init_limit_db() +func check_ticket(acct string) uint { cmd1 := `SELECT ticket FROM Limits WHERE acct = ?` - cmd2 := `SELECT time FROM Limits WHERE acct = ?` + cmd2 := `SELECT posted FROM Limits WHERE acct = ?` - var tickets uint16 + var tickets uint var lastS string db.QueryRow(cmd1, acct).Scan(&tickets) @@ -118,20 +118,18 @@ func check_ticket(acct string) uint16 { // Save message hash func save_msg_hash(hash string) { - db := init_limit_db() - cmd1 := `SELECT COUNT(*) FROM MsgHashs` cmd2 := `DELETE FROM MsgHashs WHERE ROWID IN (SELECT ROWID FROM MsgHashs LIMIT 1)` cmd3 := `INSERT INTO MsgHashs (message_hash) VALUES (?)` - var rows uint16 + var rows uint db.QueryRow(cmd1).Scan(&rows) if rows >= Conf.Duplicate_buf { superfluous := rows - Conf.Duplicate_buf - for i := uint16(0); i <= superfluous; i++ { + for i := uint(0); i <= superfluous; i++ { stat2, err := db.Prepare(cmd2) if err != nil { ErrorLogger.Println("Delete message hash from database") @@ -149,7 +147,6 @@ func save_msg_hash(hash string) { // Check message hash func check_msg_hash(hash string) bool { - db := init_limit_db() cmd := `SELECT message_hash FROM MsgHashs WHERE message_hash = ?` err := db.QueryRow(cmd, hash).Scan(&hash) if err != nil { @@ -165,7 +162,6 @@ func check_msg_hash(hash string) bool { // Count order func count_order(acct string) { - db := init_limit_db() cmd1 := `UPDATE Limits SET order_msg = ? WHERE acct != ?` cmd2 := `SELECT order_msg FROM Limits WHERE acct = ?` cmd3 := `UPDATE Limits SET order_msg = ? WHERE acct = ?` @@ -177,7 +173,7 @@ func count_order(acct string) { stat1.Exec(0, acct) - var order uint16 + var order uint db.QueryRow(cmd2, acct).Scan(&order) if order < Conf.Order_limit { order = order + 1 @@ -192,12 +188,51 @@ func count_order(acct string) { } // Check order -func check_order(acct string) uint16 { - db := init_limit_db() +func check_order(acct string) uint { cmd := `SELECT order_msg FROM Limits WHERE acct = ?` - var order uint16 + var order uint db.QueryRow(cmd, acct).Scan(&order) return order } + +// Mark notice +func mark_notice(acct string) { + cmd1 := `SELECT got_notice FROM Limits WHERE acct = ?` + cmd2 := `UPDATE Limits SET got_notice = ? WHERE acct = ?` + + var notice uint + db.QueryRow(cmd1, acct).Scan(¬ice) + + if notice == 0 { + notice = notice + 1 + } + + stat, err := db.Prepare(cmd2) + if err != nil { + ErrorLogger.Println("Mark notice") + } + stat.Exec(notice, acct) +} + +// Reset notice counter +func reset_notice_counter() { + cmd := `UPDATE Limits SET got_notice = ?` + + stat, err := db.Prepare(cmd) + if err != nil { + ErrorLogger.Println("Reset notice counter") + } + stat.Exec(0) +} + +// Check if got notification +func got_notice(acct string) uint { + cmd := `SELECT got_notice FROM Limits WHERE acct = ?` + + var notice uint + db.QueryRow(cmd, acct).Scan(¬ice) + + return notice +} diff --git a/logger.go b/logger.go index 60e785e..193bb04 100644 --- a/logger.go +++ b/logger.go @@ -11,7 +11,7 @@ var ( ErrorLogger *log.Logger ) -func logger_init() { +func LoggerInit() { file, err := os.OpenFile(*LogPath, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0600) if err != nil { log.Fatal("Failed to read log file") diff --git a/main.go b/main.go index c980332..53f8dbe 100644 --- a/main.go +++ b/main.go @@ -1,5 +1,10 @@ package main func main() { + LoggerInit() + + wg.Add(1) + + go DeleteNotices() RunBot() } diff --git a/utils.go b/utils.go new file mode 100644 index 0000000..11cdf4e --- /dev/null +++ b/utils.go @@ -0,0 +1,13 @@ +package main + +import "github.com/mattn/go-mastodon" + +// Posting function +func postToot(toot string, vis string) (*mastodon.Status, error) { + conToot := mastodon.Toot{ + Status: toot, + Visibility: vis, + } + status, err := c.PostStatus(ctx, &conToot) + return status, err +}