From 9559c4860814d682462f41e23097853c34ace459 Mon Sep 17 00:00:00 2001 From: acture Date: Wed, 3 Dec 2025 19:19:43 +0800 Subject: [PATCH 1/3] feat(message): add deletion methods for related floor and hole messages - Introduced `DeleteMessageByRelatedFloorID` and `DeleteMessageByRelatedHoleID` methods to handle message deletions based on related floor or hole IDs. --- apis/message/apis.go | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/apis/message/apis.go b/apis/message/apis.go index 30d72c3..eb29be3 100644 --- a/apis/message/apis.go +++ b/apis/message/apis.go @@ -154,3 +154,21 @@ func DeleteMessage(c *fiber.Ctx) error { } return c.Status(204).JSON(nil) } + +func DeleteMessageByRelatedFloorID(floorID int) error { + result := DB.Exec(` + DELETE FROM message_user + WHERE related_floor_id = ?`, + floorID, + ) + return result.Error +} + +func DeleteMessageByRelatedHoleID(holeID int) error { + result := DB.Exec(` + DELETE FROM message_user + WHERE related_hole_id = ?`, + holeID, + ) + return result.Error +} From 91f19e6968bc1ff837fd061519a613694bd61793 Mon Sep 17 00:00:00 2001 From: acture Date: Wed, 3 Dec 2025 19:19:58 +0800 Subject: [PATCH 2/3] feat(notification): add related floor and hole IDs to notification model - Introduced `RelatedFloorID` and `RelatedHoleID` fields to the `Notification` model to improve context in messages. - Updated apis in `report` and `penalty` to populate these fields when creating notifications. - Enhanced sensitive content and modification notifications with related IDs for better traceability. - Improved message construction consistency across `floor` operations. --- apis/penalty/api.go | 14 +++++---- apis/report/apis.go | 8 ++++-- models/floor.go | 65 +++++++++++++++++++++++------------------- models/notification.go | 22 +++++++------- 4 files changed, 60 insertions(+), 49 deletions(-) diff --git a/apis/penalty/api.go b/apis/penalty/api.go index dc2a559..b8f8d47 100644 --- a/apis/penalty/api.go +++ b/apis/penalty/api.go @@ -115,9 +115,10 @@ func BanUser(c *fiber.Ctx) error { days, body.Reason, ), - Title: "处罚通知", - Type: MessageTypePermission, - URL: fmt.Sprintf("/api/floors/%d", floor.ID), + Title: "处罚通知", + Type: MessageTypePermission, + URL: fmt.Sprintf("/api/floors/%d", floor.ID), + RelatedFloorID: &floor.ID, } // send @@ -247,9 +248,10 @@ func BanUserForever(c *fiber.Ctx) error { days, body.Reason, ), - Title: "处罚通知", - Type: MessageTypePermission, - URL: fmt.Sprintf("/api/floors/%d", floor.ID), + Title: "处罚通知", + Type: MessageTypePermission, + URL: fmt.Sprintf("/api/floors/%d", floor.ID), + RelatedFloorID: &floor.ID, } // send diff --git a/apis/report/apis.go b/apis/report/apis.go index 1adfe35..4c18de0 100644 --- a/apis/report/apis.go +++ b/apis/report/apis.go @@ -256,9 +256,11 @@ func BanReporter(c *fiber.Ctx) error { days, body.Reason, ), - Title: "处罚通知", - Type: MessageTypePermission, - URL: fmt.Sprintf("/api/reports/%d", report.ID), + Title: "处罚通知", + Type: MessageTypePermission, + URL: fmt.Sprintf("/api/reports/%d", report.ID), + RelatedFloorID: &report.FloorID, + RelatedHoleID: &report.HoleID, } // send diff --git a/models/floor.go b/models/floor.go index d359238..cafd87a 100644 --- a/models/floor.go +++ b/models/floor.go @@ -513,12 +513,13 @@ func (floor *Floor) SendSubscription(tx *gorm.DB) Notification { // Construct Notification message := Notification{ - Data: floor, - Recipients: userIDs, - Description: floor.Content, - Title: "您关注的帖子有新回复", - Type: MessageTypeFavorite, - URL: fmt.Sprintf("/api/floors/%d", floor.ID), + Data: floor, + Recipients: userIDs, + Description: floor.Content, + Title: "您关注的帖子有新回复", + Type: MessageTypeFavorite, + URL: fmt.Sprintf("/api/floors/%d", floor.ID), + RelatedFloorID: &floor.ID, } return message @@ -540,12 +541,13 @@ func (floor *Floor) SendReply(tx *gorm.DB) Notification { // construct message message := Notification{ - Data: floor, - Recipients: userIDs, - Description: floor.Content, - Title: "您的内容有新回复", - Type: MessageTypeReply, - URL: fmt.Sprintf("/api/floors/%d", floor.ID), + Data: floor, + Recipients: userIDs, + Description: floor.Content, + Title: "您的内容有新回复", + Type: MessageTypeReply, + URL: fmt.Sprintf("/api/floors/%d", floor.ID), + RelatedFloorID: &floor.ID, } return message @@ -565,12 +567,13 @@ func (floor *Floor) SendMention(_ *gorm.DB) Notification { // construct message message := Notification{ - Data: floor, - Recipients: userIDs, - Description: floor.Content, - Title: "您的内容被引用了", - Type: MessageTypeMention, - URL: fmt.Sprintf("/api/floors/%d", floor.ID), + Data: floor, + Recipients: userIDs, + Description: floor.Content, + Title: "您的内容被引用了", + Type: MessageTypeMention, + URL: fmt.Sprintf("/api/floors/%d", floor.ID), + RelatedFloorID: &floor.ID, } return message @@ -582,12 +585,13 @@ func (floor *Floor) SendModify(_ *gorm.DB) error { // construct message message := Notification{ - Data: floor, - Recipients: userIDs, - Description: floor.Content, - Title: "您的内容被管理员修改了", - Type: MessageTypeModify, - URL: fmt.Sprintf("/api/floors/%d", floor.ID), + Data: floor, + Recipients: userIDs, + Description: floor.Content, + Title: "您的内容被管理员修改了", + Type: MessageTypeModify, + URL: fmt.Sprintf("/api/floors/%d", floor.ID), + RelatedFloorID: &floor.ID, } // send @@ -607,12 +611,13 @@ func (floor *Floor) SendSensitive(_ *gorm.DB) error { // construct message message := Notification{ - Data: floor, - Recipients: userIDs, - Description: "Sensitive Review Required", - Title: "您有待审核的内容", - Type: MessageTypeSensitive, - URL: fmt.Sprintf("/api/floors/%d", floor.ID), + Data: floor, + Recipients: userIDs, + Description: "Sensitive Review Required", + Title: "您有待审核的内容", + Type: MessageTypeSensitive, + URL: fmt.Sprintf("/api/floors/%d", floor.ID), + RelatedHoleID: &floor.ID, } // send diff --git a/models/notification.go b/models/notification.go index 531e1a6..5621916 100644 --- a/models/notification.go +++ b/models/notification.go @@ -34,12 +34,14 @@ type Notifications []Notification type Notification struct { // Should be same as CrateModel in notification project - Title string `json:"message"` - Description string `json:"description"` - Data any `json:"data"` - Type MessageType `json:"code"` - URL string `json:"url"` - Recipients []int `json:"recipients"` + Title string `json:"message"` + Description string `json:"description"` + Data any `json:"data"` + Type MessageType `json:"code"` + URL string `json:"url"` + Recipients []int `json:"recipients"` + RelatedFloorID *int `json:"related_floor_id,omitempty"` + RelatedHoleID *int `json:"related_hole_id,omitempty"` } func readRespNotification(body io.ReadCloser) Notification { @@ -155,7 +157,7 @@ func (message Notification) Send() (Message, error) { if config.Config.NotificationUrl == "" { return Message{}, nil } - message.Title = utils.StripContent(message.Title, 32) //varchar(32) + message.Title = utils.StripContent(message.Title, 32) //varchar(32) message.Description = utils.StripContent(cleanNotificationDescription(message.Description), 64) //varchar(64) body.Title = message.Title body.Description = message.Description @@ -266,7 +268,7 @@ func UpdateAdminList(ctx context.Context) { } var ( - reMention = regexp.MustCompile(`#{1,2}\d+`) + reMention = regexp.MustCompile(`#{1,2}\d+`) reFormula = regexp.MustCompile(`(?s)\${1,2}.*?\${1,2}`) reSticker = regexp.MustCompile(`!\[\]\(dx_\S+?\)`) reImage = regexp.MustCompile(`!\[.*?\]\(.*?\)`) @@ -275,8 +277,8 @@ var ( func cleanNotificationDescription(content string) string { newContent := reMention.ReplaceAllString(content, "") newContent = reFormula.ReplaceAllString(newContent, "[公式]") - newContent = reSticker.ReplaceAllString(newContent, "[表情]") - newContent = reImage.ReplaceAllString(newContent, "[图片]") + newContent = reSticker.ReplaceAllString(newContent, "[表情]") + newContent = reImage.ReplaceAllString(newContent, "[图片]") newContent = strings.ReplaceAll(newContent, "\n", "") if newContent == "" { return content From 0c943b85dfd03dd328bfd07dff28721122a4b410 Mon Sep 17 00:00:00 2001 From: acture Date: Wed, 3 Dec 2025 19:36:13 +0800 Subject: [PATCH 3/3] feat(hole, floor): integrate message deletion for related content - Added calls to `DeleteMessageByRelatedHoleID` and `DeleteMessageByRelatedFloorID` in hole and floor deletion logic. - Ensured proper error handling during message deletion for associated content. - Tidied up code formatting in affected areas for better readability. --- apis/floor/apis.go | 31 +++++++++++++++++++++---------- apis/hole/apis.go | 9 +++++++++ 2 files changed, 30 insertions(+), 10 deletions(-) diff --git a/apis/floor/apis.go b/apis/floor/apis.go index ec19f41..8753d61 100644 --- a/apis/floor/apis.go +++ b/apis/floor/apis.go @@ -4,6 +4,7 @@ import ( "fmt" "slices" "time" + "treehole_next/apis/message" "treehole_next/utils/sensitive" "github.com/opentreehole/go-common" @@ -624,6 +625,12 @@ func DeleteFloor(c *fiber.Ctx) error { floor.Deleted = true floor.Content = generateDeleteReason(body.Reason, user.ID == floor.UserID) + // TODO: 内容被删除后,向notification发请求,删除对应的通知 + err = message.DeleteMessageByRelatedFloorID(floor.ID) + if err != nil { + return err + } + return tx.Save(&floor).Error }) if err != nil { @@ -849,15 +856,15 @@ func GetPunishmentHistory(c *fiber.Ctx) error { // search DB for user punishment history punishments := make([]string, 0, 10) err = DB.Raw( - `SELECT f.content + `SELECT f.content FROM floor f WHERE f.id IN ( - SELECT distinct floor.id - FROM floor - JOIN floor_history ON floor.id = floor_history.floor_id - WHERE floor.user_id <> floor_history.user_id - AND floor.user_id = ? - AND floor.deleted = true + SELECT distinct floor.id + FROM floor + JOIN floor_history ON floor.id = floor_history.floor_id + WHERE floor.user_id <> floor_history.user_id + AND floor.user_id = ? + AND floor.deleted = true )`, userID).Scan(&punishments).Error if err != nil { return err @@ -1030,7 +1037,7 @@ func ModifyFloorSensitive(c *fiber.Ctx) (err error) { if err != nil { return err } - + // update CreatedAt and UpdatedAt to prevent new posts from being buried due to review delays if floor.Ranking == 0 { var hole Hole @@ -1038,7 +1045,7 @@ func ModifyFloorSensitive(c *fiber.Ctx) (err error) { if err != nil { return err } - + // ad-hoc logic: if the hole was created before 2024, don't update // ref: https://github.com/OpenTreeHole/treehole_next/issues/192 if hole.CreatedAt.Year() <= 2024 { @@ -1052,7 +1059,7 @@ func ModifyFloorSensitive(c *fiber.Ctx) (err error) { return err } } - + return nil } @@ -1061,6 +1068,10 @@ func ModifyFloorSensitive(c *fiber.Ctx) (err error) { if err != nil { return err } + err = message.DeleteMessageByRelatedFloorID(floor.ID) + if err != nil { + return err + } floor.Deleted = true floor.Content = generateDeleteReason(reason, false) diff --git a/apis/hole/apis.go b/apis/hole/apis.go index f044f7a..ede48a2 100644 --- a/apis/hole/apis.go +++ b/apis/hole/apis.go @@ -5,6 +5,7 @@ import ( "slices" "strconv" "time" + "treehole_next/apis/message" "treehole_next/utils/sensitive" "github.com/gofiber/fiber/v2" @@ -718,6 +719,10 @@ func HideHole(c *fiber.Ctx) error { var floors Floors _ = DB.Where("hole_id = ?", hole.ID).Find(&floors) go BulkDelete(Models2IDSlice(floors)) + err = message.DeleteMessageByRelatedHoleID(hole.ID) + if err != nil { + return err + } return c.Status(204).JSON(nil) } @@ -808,6 +813,10 @@ func DeleteHole(c *fiber.Ctx) error { if err != nil { log.Err(err).Msg("DeleteHole: delete cache divisions") } + err = message.DeleteMessageByRelatedHoleID(hole.ID) + if err != nil { + return err + } return c.Status(204).JSON(nil) }