From 90421cccd6c9e7b589fbf1e02146fb18924dd500 Mon Sep 17 00:00:00 2001 From: Chuck Findlay Date: Thu, 23 May 2024 20:33:32 -0300 Subject: [PATCH] subscribe and unsubscribe endpoints now work, and finished subscription package tests --- bruno/POST Privmsg Subscription Removal.bru | 19 ++++++ bruno/POST Privmsg Subscription.bru | 2 +- main.go | 3 +- requesthandlers/http.go | 27 ++++++++ webhook/subscription.go | 53 +++++++++++++-- webhook/subscription_test.go | 75 +++++++++++++++------ 6 files changed, 151 insertions(+), 28 deletions(-) create mode 100644 bruno/POST Privmsg Subscription Removal.bru diff --git a/bruno/POST Privmsg Subscription Removal.bru b/bruno/POST Privmsg Subscription Removal.bru new file mode 100644 index 0000000..382b58d --- /dev/null +++ b/bruno/POST Privmsg Subscription Removal.bru @@ -0,0 +1,19 @@ +meta { + name: POST Privmsg Subscription Removal + type: http + seq: 4 +} + +post { + url: http://localhost:8080/unsubscribe + body: json + auth: none +} + +body:json { + { + "Target": "Test", + "URL": "http://localhost/404", + "Password": "{{WMB_PASSWORD}}" + } +} diff --git a/bruno/POST Privmsg Subscription.bru b/bruno/POST Privmsg Subscription.bru index 62f987d..528a7ab 100644 --- a/bruno/POST Privmsg Subscription.bru +++ b/bruno/POST Privmsg Subscription.bru @@ -5,7 +5,7 @@ meta { } post { - url: http://localhost:8080/subscription + url: http://localhost:8080/subscribe body: json auth: none } diff --git a/main.go b/main.go index 5408e01..ceeb614 100644 --- a/main.go +++ b/main.go @@ -27,7 +27,8 @@ func main() { router.POST("/message", requesthandlers.PostMessage) router.GET("/message", requesthandlers.QueryMessage) router.POST("/directedMessage", requesthandlers.PostDirectedMessage) - router.POST("/subscription", requesthandlers.PostSubscribePrivmsg) + router.POST("/subscribe", requesthandlers.PostSubscribePrivmsg) + router.POST("/unsubscribe", requesthandlers.PostUnsubscribePrivmsg) err := router.Run(listenAddress) diff --git a/requesthandlers/http.go b/requesthandlers/http.go index 80c7439..ecd6ab3 100644 --- a/requesthandlers/http.go +++ b/requesthandlers/http.go @@ -122,3 +122,30 @@ func PostSubscribePrivmsg(c *gin.Context) { }) } } + +func PostUnsubscribePrivmsg(c *gin.Context) { + var subscription model.PrivmsgSubscription + + if err := c.BindJSON(&subscription); err != nil { + c.String(http.StatusBadRequest, "Invalid query parameters") + return + } + + if !validatePassword(subscription.Password, c) { + return + } + + success := webhook.UnsubscribePrivmsg(subscription.Target, subscription.URL) + + if success { + c.JSON(http.StatusOK, gin.H{ + "status": "success", + "message": "Subscription removal successful", + }) + } else { + c.JSON(http.StatusBadRequest, gin.H{ + "status": "failure", + "message": "Subscription removal failed", + }) + } +} diff --git a/webhook/subscription.go b/webhook/subscription.go index 2e83426..641e450 100644 --- a/webhook/subscription.go +++ b/webhook/subscription.go @@ -11,12 +11,53 @@ import ( func SubscribePrivmsg(target string, url string) bool { db := database.DB.GetDB() - // Create the table if it doesn't exist - _, err := db.Exec("CREATE TABLE IF NOT EXISTS PrivmsgSubscriptions (Target TEXT, URL TEXT, FailureCount INTEGER DEFAULT 0, Timestamp DATETIME DEFAULT CURRENT_TIMESTAMP, PRIMARY KEY (Target, URL))") + // Begin a transaction + tx, err := db.Begin() + if err != nil { + log.Printf("Error beginning transaction: %v", err) + return false + } + defer tx.Rollback() // Rollback the transaction if it's not committed + + // Check if the data already exists + row := tx.QueryRow("SELECT 1 FROM PrivmsgSubscriptions WHERE Target = ? AND URL = ?", target, url) + var exists bool + err = row.Scan(&exists) + if err != nil && err != sql.ErrNoRows { + log.Printf("Error checking existence: %v", err) + return false + } + if exists { + return false + } + + // Prepare the statement + stmt, err := tx.Prepare("INSERT OR IGNORE INTO PrivmsgSubscriptions (Target, URL, FailureCount) VALUES (?, ?, 0)") if err != nil { - log.Printf("Error creating table: %v", err) + log.Printf("Error preparing statement: %v", err) return false } + defer stmt.Close() // Close the statement when it's no longer needed + + // Execute the statement + _, err = stmt.Exec(target, url) + if err != nil { + log.Printf("Error executing statement: %v", err) + return false + } + + // Commit the transaction + err = tx.Commit() + if err != nil { + log.Printf("Error committing transaction: %v", err) + return false + } + + return true +} + +func UnsubscribePrivmsg(target string, url string) bool { + db := database.DB.GetDB() // Begin a transaction tx, err := db.Begin() @@ -24,6 +65,7 @@ func SubscribePrivmsg(target string, url string) bool { log.Printf("Error beginning transaction: %v", err) return false } + defer tx.Rollback() // Rollback the transaction if it's not committed // Check if the data already exists row := tx.QueryRow("SELECT 1 FROM PrivmsgSubscriptions WHERE Target = ? AND URL = ?", target, url) @@ -33,16 +75,17 @@ func SubscribePrivmsg(target string, url string) bool { log.Printf("Error checking existence: %v", err) return false } - if exists { + if !exists { return false } // Prepare the statement - stmt, err := tx.Prepare("INSERT OR IGNORE INTO PrivmsgSubscriptions (Target, URL, FailureCount) VALUES (?, ?, 0)") + stmt, err := tx.Prepare("DELETE FROM PrivmsgSubscriptions WHERE Target = ? AND URL = ?") if err != nil { log.Printf("Error preparing statement: %v", err) return false } + defer stmt.Close() // Close the statement when it's no longer needed // Execute the statement _, err = stmt.Exec(target, url) diff --git a/webhook/subscription_test.go b/webhook/subscription_test.go index 21d158a..e102a0d 100644 --- a/webhook/subscription_test.go +++ b/webhook/subscription_test.go @@ -19,26 +19,27 @@ func TestSubscribePrivmsg(t *testing.T) { database.DB.SetDB(db) // Expectations - mock.ExpectExec("CREATE TABLE IF NOT EXISTS PrivmsgSubscriptions \\(Target TEXT, URL TEXT, FailureCount INTEGER DEFAULT 0, Timestamp DATETIME DEFAULT CURRENT_TIMESTAMP, PRIMARY KEY \\(Target, URL\\)\\)").WillReturnResult(sqlmock.NewResult(1, 1)) mock.ExpectBegin() - - // Expect the SELECT query mock.ExpectQuery("^SELECT 1 FROM PrivmsgSubscriptions WHERE Target = \\? AND URL = \\?$"). WithArgs("target", "url"). WillReturnRows(sqlmock.NewRows([]string{"exists"}).AddRow(false)) - - mock.ExpectPrepare("INSERT OR IGNORE INTO PrivmsgSubscriptions") - mock.ExpectExec("INSERT OR IGNORE INTO PrivmsgSubscriptions").WithArgs("target", "url").WillReturnResult(sqlmock.NewResult(1, 1)) + mock.ExpectPrepare("^INSERT OR IGNORE INTO PrivmsgSubscriptions \\(Target, URL, FailureCount\\) VALUES \\(\\?, \\?, 0\\)$") + mock.ExpectExec("^INSERT OR IGNORE INTO PrivmsgSubscriptions \\(Target, URL, FailureCount\\) VALUES \\(\\?, \\?, 0\\)$"). + WithArgs("target", "url"). + WillReturnResult(sqlmock.NewResult(1, 1)) mock.ExpectCommit() // Call the function - webhook.SubscribePrivmsg("target", "url") + result := webhook.SubscribePrivmsg("target", "url") // Make sure all expectations were met require.NoError(t, mock.ExpectationsWereMet(), "There were unfulfilled expectations") + + // Check the result + require.True(t, result, "Expected true") } -func TestSubscribePrivmsgExistsAndDoesnt(t *testing.T) { +func TestSubscribePrivmsgExists(t *testing.T) { // Create a mock database db, mock, err := sqlmock.New() require.NoError(t, err, "An error was not expected when opening a stub database connection") @@ -47,14 +48,12 @@ func TestSubscribePrivmsgExistsAndDoesnt(t *testing.T) { // Set the mock database in the DB object database.DB.SetDB(db) - // Expectations for the first call - mock.ExpectExec("CREATE TABLE IF NOT EXISTS PrivmsgSubscriptions \\(Target TEXT, URL TEXT, FailureCount INTEGER DEFAULT 0, Timestamp DATETIME DEFAULT CURRENT_TIMESTAMP, PRIMARY KEY \\(Target, URL\\)\\)").WillReturnResult(sqlmock.NewResult(1, 1)) + // Expectations mock.ExpectBegin() - - // Expect the SELECT query mock.ExpectQuery("^SELECT 1 FROM PrivmsgSubscriptions WHERE Target = \\? AND URL = \\?$"). WithArgs("target", "url"). WillReturnRows(sqlmock.NewRows([]string{"exists"}).AddRow(true)) + mock.ExpectRollback() // Call the function result := webhook.SubscribePrivmsg("target", "url") @@ -64,22 +63,30 @@ func TestSubscribePrivmsgExistsAndDoesnt(t *testing.T) { // Check the result require.False(t, result, "Expected false") +} - // Expectations for the second call - mock.ExpectExec("CREATE TABLE IF NOT EXISTS PrivmsgSubscriptions \\(Target TEXT, URL TEXT, FailureCount INTEGER DEFAULT 0, Timestamp DATETIME DEFAULT CURRENT_TIMESTAMP, PRIMARY KEY \\(Target, URL\\)\\)").WillReturnResult(sqlmock.NewResult(1, 1)) - mock.ExpectBegin() +func TestUnsubscribePrivmsg(t *testing.T) { + // Create a mock database + db, mock, err := sqlmock.New() + require.NoError(t, err, "An error was not expected when opening a stub database connection") + defer db.Close() + + // Set the mock database in the DB object + database.DB.SetDB(db) - // Expect the SELECT query + // Expectations + mock.ExpectBegin() mock.ExpectQuery("^SELECT 1 FROM PrivmsgSubscriptions WHERE Target = \\? AND URL = \\?$"). WithArgs("target", "url"). - WillReturnRows(sqlmock.NewRows([]string{"exists"}).AddRow(false)) - - mock.ExpectPrepare("INSERT OR IGNORE INTO PrivmsgSubscriptions") - mock.ExpectExec("INSERT OR IGNORE INTO PrivmsgSubscriptions").WithArgs("target", "url").WillReturnResult(sqlmock.NewResult(1, 1)) + WillReturnRows(sqlmock.NewRows([]string{"exists"}).AddRow(true)) + mock.ExpectPrepare("^DELETE FROM PrivmsgSubscriptions WHERE Target = \\? AND URL = \\?$") + mock.ExpectExec("^DELETE FROM PrivmsgSubscriptions WHERE Target = \\? AND URL = \\?$"). + WithArgs("target", "url"). + WillReturnResult(sqlmock.NewResult(1, 1)) mock.ExpectCommit() // Call the function - result = webhook.SubscribePrivmsg("target", "url") + result := webhook.UnsubscribePrivmsg("target", "url") // Make sure all expectations were met require.NoError(t, mock.ExpectationsWereMet(), "There were unfulfilled expectations") @@ -87,3 +94,29 @@ func TestSubscribePrivmsgExistsAndDoesnt(t *testing.T) { // Check the result require.True(t, result, "Expected true") } + +func TestUnsubscribePrivmsgNotExists(t *testing.T) { + // Create a mock database + db, mock, err := sqlmock.New() + require.NoError(t, err, "An error was not expected when opening a stub database connection") + defer db.Close() + + // Set the mock database in the DB object + database.DB.SetDB(db) + + // Expectations + mock.ExpectBegin() + mock.ExpectQuery("^SELECT 1 FROM PrivmsgSubscriptions WHERE Target = \\? AND URL = \\?$"). + WithArgs("target", "url"). + WillReturnRows(sqlmock.NewRows([]string{"exists"}).AddRow(false)) + mock.ExpectRollback() + + // Call the function + result := webhook.UnsubscribePrivmsg("target", "url") + + // Make sure all expectations were met + require.NoError(t, mock.ExpectationsWereMet(), "There were unfulfilled expectations") + + // Check the result + require.False(t, result, "Expected false") +}