- F201: Commentaires avec timestamp cliquable, modération mots-clés - F202: Likes privés (compteur visible créateur uniquement) - F203: Reposts de tracks sur le profil, bouton Repost, onglet Reposts - F204: Notifications (commentaire, repost), pas de gamification Backend: migrations 127/128, comment_moderation_service, track_repost_service, GetTrackLikes/GetTrack masquent like_count pour non-créateurs Frontend: LikeButton isCreator, RepostButton, Reposts tab profil, timestamp seek
44 lines
1.2 KiB
Go
44 lines
1.2 KiB
Go
package services
|
|
|
|
import (
|
|
"context"
|
|
"strings"
|
|
|
|
"gorm.io/gorm"
|
|
)
|
|
|
|
// moderationKeywordRow maps to moderation_keywords table for Pluck.
|
|
type moderationKeywordRow struct {
|
|
Word string `gorm:"column:word"`
|
|
}
|
|
|
|
// CommentModerationService provides deterministic keyword-based moderation (no ML).
|
|
// v0.10.3 F201: ORIGIN_REVISION_SUMMARY §2 "Modération : règles déterministes"
|
|
type CommentModerationService struct {
|
|
db *gorm.DB
|
|
}
|
|
|
|
// NewCommentModerationService creates a new comment moderation service.
|
|
func NewCommentModerationService(db *gorm.DB) *CommentModerationService {
|
|
return &CommentModerationService{db: db}
|
|
}
|
|
|
|
// ContainsBannedKeyword checks if content contains any banned keyword (case-insensitive).
|
|
// Returns true if content should be rejected.
|
|
func (s *CommentModerationService) ContainsBannedKeyword(ctx context.Context, content string) (bool, error) {
|
|
var rows []moderationKeywordRow
|
|
if err := s.db.WithContext(ctx).
|
|
Table("moderation_keywords").
|
|
Select("word").
|
|
Find(&rows).Error; err != nil {
|
|
return false, err
|
|
}
|
|
|
|
contentLower := strings.ToLower(content)
|
|
for _, row := range rows {
|
|
if strings.Contains(contentLower, strings.ToLower(row.Word)) {
|
|
return true, nil
|
|
}
|
|
}
|
|
return false, nil
|
|
}
|