diff --git a/backend/api/internal/database/comment_queries.go b/backend/api/internal/database/comment_queries.go index 7e8f14c..f75607a 100644 --- a/backend/api/internal/database/comment_queries.go +++ b/backend/api/internal/database/comment_queries.go @@ -289,12 +289,25 @@ func QueryCommentsByCommentId(id int) ([]types.Comment, int, error) { // - int64: The ID of the newly created comment. // - error: An error if the operation fails. func QueryCreateCommentOnPost(comment types.Comment, postId int) (int64, error) { + tx, err := DB.Begin() + if err != nil { + return -1, fmt.Errorf("failed to begin transaction: %v", err) + } + + defer func() { + if err != nil { + tx.Rollback() + } else { + tx.Commit() + } + }() + currentTime := time.Now().UTC() query := `INSERT INTO Comments (user_id, content, parent_comment_id, likes, creation_date) VALUES (?, ?, ?, ?, ?);` - res, err := DB.Exec(query, comment.User, comment.Content, comment.ParentComment, 0, currentTime) + res, err := tx.Exec(query, comment.User, comment.Content, comment.ParentComment, 0, currentTime) if err != nil { return -1, fmt.Errorf("Failed to create comment: %v", err) @@ -308,7 +321,7 @@ func QueryCreateCommentOnPost(comment types.Comment, postId int) (int64, error) query = `INSERT INTO PostComments (user_id, post_id, comment_id) VALUES (?, ?, ?)` - res, err = DB.Exec(query, comment.User, postId, lastId) + _, err = tx.Exec(query, comment.User, postId, lastId) if err != nil { return -1, fmt.Errorf("Failed to link comment to post: %v", err) } @@ -326,12 +339,24 @@ func QueryCreateCommentOnPost(comment types.Comment, postId int) (int64, error) // - int64: The ID of the newly created comment. // - error: An error if the operation fails. func QueryCreateCommentOnProject(comment types.Comment, projectId int) (int64, error) { + tx, err := DB.Begin() + if err != nil { + return -1, fmt.Errorf("failed to begin transaction: %v", err) + } + + defer func() { + if err != nil { + tx.Rollback() + } else { + tx.Commit() + } + }() currentTime := time.Now().UTC() query := `INSERT INTO Comments (user_id, content, parent_comment_id, likes, creation_date) VALUES (?, ?, ?, ?, ?);` - res, err := DB.Exec(query, comment.User, comment.Content, comment.ParentComment, 0, currentTime) + res, err := tx.Exec(query, comment.User, comment.Content, comment.ParentComment, 0, currentTime) if err != nil { return -1, fmt.Errorf("Failed to create comment: %v", err) @@ -345,7 +370,7 @@ func QueryCreateCommentOnProject(comment types.Comment, projectId int) (int64, e query = `INSERT INTO ProjectComments (user_id, project_id, comment_id) VALUES (?, ?, ?)` - res, err = DB.Exec(query, comment.User, projectId, lastId) + _, err = tx.Exec(query, comment.User, projectId, lastId) if err != nil { return -1, fmt.Errorf("Failed to link comment to project: %v", err) } @@ -391,18 +416,31 @@ func QueryCreateCommentOnComment(comment types.Comment, commentId int) (int64, e // - int16: http status code // - error: An error if the operation fails. func QueryDeleteComment(id int) (int16, error) { - _, err := DB.Exec(`UPDATE PostComments SET user_id = -1 WHERE comment_id = ?`, id) + tx, err := DB.Begin() + if err != nil { + return -1, fmt.Errorf("failed to begin transaction: %v", err) + } + + defer func() { + if err != nil { + tx.Rollback() + } else { + tx.Commit() + } + }() + + _, err = tx.Exec(`UPDATE PostComments SET user_id = -1 WHERE comment_id = ?`, id) if err != nil { return http.StatusInternalServerError, fmt.Errorf("Failed to update PostComments for deleted comment: %v", err) } - _, err = DB.Exec(`UPDATE ProjectComments SET user_id = -1 WHERE comment_id = ?`, id) + _, err = tx.Exec(`UPDATE ProjectComments SET user_id = -1 WHERE comment_id = ?`, id) if err != nil { return http.StatusInternalServerError, fmt.Errorf("Failed to update ProjectComments for deleted comment: %v", err) } query := `UPDATE Comments SET user_id = -1, content = "This comment was deleted.", likes = 0, creation_date = ? WHERE id = ?` - res, err := DB.Exec(query, time.Date(1970, 1, 1, 0, 0, 0, 0, time.UTC), id) + res, err := tx.Exec(query, time.Date(1970, 1, 1, 0, 0, 0, 0, time.UTC), id) if err != nil { return http.StatusBadRequest, fmt.Errorf("Failed to soft delete comment `%v`: %v", id, err) } @@ -501,17 +539,29 @@ func CreateCommentLike(username string, strCommentId string) (int, error) { // like already exists, but we return success to keep it idempotent return http.StatusOK, nil } + tx, err := DB.Begin() + if err != nil { + return -1, fmt.Errorf("failed to begin transaction: %v", err) + } + + defer func() { + if err != nil { + tx.Rollback() + } else { + tx.Commit() + } + }() // insert the like insertQuery := `INSERT INTO CommentLikes (user_id, comment_id) VALUES (?, ?)` - _, err = DB.Exec(insertQuery, user_id, commentId) + _, err = tx.Exec(insertQuery, user_id, commentId) if err != nil { return http.StatusInternalServerError, fmt.Errorf("Failed to insert comment like: %v", err) } // update the likes column updateQuery := `UPDATE Comments SET likes = likes + 1 WHERE id = ?` - _, err = DB.Exec(updateQuery, commentId) + _, err = tx.Exec(updateQuery, commentId) if err != nil { return http.StatusInternalServerError, fmt.Errorf("Failed to update likes count: %v", err) } @@ -547,9 +597,22 @@ func RemoveCommentLike(username string, strCommentId string) (int, error) { return http.StatusInternalServerError, fmt.Errorf("An error occurred verifying the comment exists: %v", err) } + tx, err := DB.Begin() + if err != nil { + return -1, fmt.Errorf("failed to begin transaction: %v", err) + } + + defer func() { + if err != nil { + tx.Rollback() + } else { + tx.Commit() + } + }() + // perform the delete operation deleteQuery := `DELETE FROM CommentLikes WHERE user_id = ? AND comment_id = ?` - result, err := DB.Exec(deleteQuery, user_id, commentId) + result, err := tx.Exec(deleteQuery, user_id, commentId) if err != nil { return http.StatusInternalServerError, fmt.Errorf("Failed to delete comment like: %v", err) } @@ -567,7 +630,7 @@ func RemoveCommentLike(username string, strCommentId string) (int, error) { // update the likes column updateQuery := `UPDATE Comments SET likes = likes - 1 WHERE id = ?` - _, err = DB.Exec(updateQuery, commentId) + _, err = tx.Exec(updateQuery, commentId) if err != nil { return http.StatusInternalServerError, fmt.Errorf("Failed to update likes count: %v", err) } @@ -650,7 +713,7 @@ func QueryIsCommentEditable(strCommId string) (int, bool, error) { now := time.Now().UTC() // now check if the comment is older than 2 minutes if now.Sub(createdAt) > 2*time.Minute { - return http.StatusOK, false, nil + return http.StatusOK, false, nil } else { return http.StatusOK, true, nil } diff --git a/backend/api/internal/database/dev.sqlite3 b/backend/api/internal/database/dev.sqlite3 index a7652ec..0f0ccea 100644 Binary files a/backend/api/internal/database/dev.sqlite3 and b/backend/api/internal/database/dev.sqlite3 differ diff --git a/backend/api/internal/database/post_queries.go b/backend/api/internal/database/post_queries.go index 651934d..3981856 100644 --- a/backend/api/internal/database/post_queries.go +++ b/backend/api/internal/database/post_queries.go @@ -230,7 +230,7 @@ func CreatePostLike(username string, strPostId string) (int, error) { } // verify post exists - post, err := QueryPost(postId) + post, err := QueryPost(postId) if err != nil { return http.StatusInternalServerError, fmt.Errorf("An error occurred verifying the post exists: %v", err) } else if post == nil { @@ -250,17 +250,28 @@ func CreatePostLike(username string, strPostId string) (int, error) { // like already exists, but we return success to keep it idempotent return http.StatusOK, nil } + tx, err := DB.Begin() + if err != nil { + return -1, fmt.Errorf("failed to begin transaction: %v", err) + } + defer func() { + if err != nil { + tx.Rollback() + } else { + tx.Commit() + } + }() // insert the like insertQuery := `INSERT INTO PostLikes (user_id, post_id) VALUES (?, ?)` - _, err = DB.Exec(insertQuery, user_id, postId) + _, err = tx.Exec(insertQuery, user_id, postId) if err != nil { return http.StatusInternalServerError, fmt.Errorf("Failed to insert post like: %v", err) } // update the likes column updateQuery := `UPDATE Posts SET likes = likes + 1 WHERE id = ?` - _, err = DB.Exec(updateQuery, postId) + _, err = tx.Exec(updateQuery, postId) if err != nil { return http.StatusInternalServerError, fmt.Errorf("Failed to update likes count: %v", err) } @@ -295,10 +306,21 @@ func RemovePostLike(username string, strPostId string) (int, error) { if err != nil { return http.StatusInternalServerError, fmt.Errorf("An error occurred verifying the post exists: %v", err) } + tx, err := DB.Begin() + if err != nil { + return -1, fmt.Errorf("failed to begin transaction: %v", err) + } + defer func() { + if err != nil { + tx.Rollback() + } else { + tx.Commit() + } + }() // perform the delete operation deleteQuery := `DELETE FROM PostLikes WHERE user_id = ? AND post_id = ?` - result, err := DB.Exec(deleteQuery, user_id, postId) + result, err := tx.Exec(deleteQuery, user_id, postId) if err != nil { return http.StatusInternalServerError, fmt.Errorf("Failed to delete post like: %v", err) } @@ -316,7 +338,7 @@ func RemovePostLike(username string, strPostId string) (int, error) { // update the likes column updateQuery := `UPDATE Posts SET likes = likes - 1 WHERE id = ?` - _, err = DB.Exec(updateQuery, postId) + _, err = tx.Exec(updateQuery, postId) if err != nil { return http.StatusInternalServerError, fmt.Errorf("Failed to update likes count: %v", err) } diff --git a/backend/api/internal/database/project_queries.go b/backend/api/internal/database/project_queries.go index 4c25f7b..3d19eec 100644 --- a/backend/api/internal/database/project_queries.go +++ b/backend/api/internal/database/project_queries.go @@ -494,16 +494,29 @@ func CreateProjectLike(username string, strProjId string) (int, error) { return http.StatusOK, nil } + tx, err := DB.Begin() + if err != nil { + return -1, fmt.Errorf("failed to begin transaction: %v", err) + } + + defer func() { + if err != nil { + tx.Rollback() + } else { + tx.Commit() + } + }() + // insert the like insertQuery := `INSERT INTO ProjectLikes (user_id, project_id) VALUES (?, ?)` - _, err = DB.Exec(insertQuery, user_id, projId) + _, err = tx.Exec(insertQuery, user_id, projId) if err != nil { return http.StatusInternalServerError, fmt.Errorf("Failed to insert project like: %v", err) } // update the likes column updateQuery := `UPDATE Projects SET likes = likes + 1 WHERE id = ?` - _, err = DB.Exec(updateQuery, projId) + _, err = tx.Exec(updateQuery, projId) if err != nil { return http.StatusInternalServerError, fmt.Errorf("Failed to update likes count: %v", err) } @@ -543,9 +556,22 @@ func RemoveProjectLike(username string, strProjId string) (int, error) { return http.StatusNotFound, fmt.Errorf("Project with id %v does not exist", projId) } + tx, err := DB.Begin() + if err != nil { + return -1, fmt.Errorf("failed to begin transaction: %v", err) + } + + defer func() { + if err != nil { + tx.Rollback() + } else { + tx.Commit() + } + }() + // perform the delete operation deleteQuery := `DELETE FROM ProjectLikes WHERE user_id = ? AND project_id = ?` - result, err := DB.Exec(deleteQuery, user_id, projId) + result, err := tx.Exec(deleteQuery, user_id, projId) if err != nil { return http.StatusInternalServerError, fmt.Errorf("Failed to delete project like: %v", err) } @@ -563,7 +589,7 @@ func RemoveProjectLike(username string, strProjId string) (int, error) { // update the likes column updateQuery := `UPDATE Projects SET likes = likes - 1 WHERE id = ?` - _, err = DB.Exec(updateQuery, projId) + _, err = tx.Exec(updateQuery, projId) if err != nil { return http.StatusInternalServerError, fmt.Errorf("Failed to update likes count: %v", err) }