fix: hide NSFW posts entirely when user hasn't enabled NSFW - backend filtering + Flutter safety net
This commit is contained in:
parent
b51c9ba90b
commit
25d3e213ea
|
|
@ -588,7 +588,15 @@ func (h *PostHandler) GetProfilePosts(c *gin.Context) {
|
||||||
viewerID = val.(string)
|
viewerID = val.(string)
|
||||||
}
|
}
|
||||||
|
|
||||||
posts, err := h.postRepo.GetPostsByAuthor(c.Request.Context(), authorID, viewerID, limit, offset, onlyChains)
|
// Check viewer's NSFW preference
|
||||||
|
showNSFW := false
|
||||||
|
if viewerID != "" {
|
||||||
|
if settings, err := h.userRepo.GetUserSettings(c.Request.Context(), viewerID); err == nil && settings.NSFWEnabled != nil {
|
||||||
|
showNSFW = *settings.NSFWEnabled
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
posts, err := h.postRepo.GetPostsByAuthor(c.Request.Context(), authorID, viewerID, limit, offset, onlyChains, showNSFW)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to fetch profile posts", "details": err.Error()})
|
c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to fetch profile posts", "details": err.Error()})
|
||||||
return
|
return
|
||||||
|
|
@ -835,7 +843,15 @@ func (h *PostHandler) GetSavedPosts(c *gin.Context) {
|
||||||
limit := utils.GetQueryInt(c, "limit", 20)
|
limit := utils.GetQueryInt(c, "limit", 20)
|
||||||
offset := utils.GetQueryInt(c, "offset", 0)
|
offset := utils.GetQueryInt(c, "offset", 0)
|
||||||
|
|
||||||
posts, err := h.postRepo.GetSavedPosts(c.Request.Context(), userID, limit, offset)
|
// Check viewer's NSFW preference
|
||||||
|
showNSFW := false
|
||||||
|
if viewerID, exists := c.Get("user_id"); exists {
|
||||||
|
if settings, err := h.userRepo.GetUserSettings(c.Request.Context(), viewerID.(string)); err == nil && settings.NSFWEnabled != nil {
|
||||||
|
showNSFW = *settings.NSFWEnabled
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
posts, err := h.postRepo.GetSavedPosts(c.Request.Context(), userID, limit, offset, showNSFW)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to fetch saved posts", "details": err.Error()})
|
c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to fetch saved posts", "details": err.Error()})
|
||||||
return
|
return
|
||||||
|
|
@ -861,7 +877,15 @@ func (h *PostHandler) GetLikedPosts(c *gin.Context) {
|
||||||
limit := utils.GetQueryInt(c, "limit", 20)
|
limit := utils.GetQueryInt(c, "limit", 20)
|
||||||
offset := utils.GetQueryInt(c, "offset", 0)
|
offset := utils.GetQueryInt(c, "offset", 0)
|
||||||
|
|
||||||
posts, err := h.postRepo.GetLikedPosts(c.Request.Context(), userID, limit, offset)
|
// Check viewer's NSFW preference
|
||||||
|
showNSFW := false
|
||||||
|
if viewerID, exists := c.Get("user_id"); exists {
|
||||||
|
if settings, err := h.userRepo.GetUserSettings(c.Request.Context(), viewerID.(string)); err == nil && settings.NSFWEnabled != nil {
|
||||||
|
showNSFW = *settings.NSFWEnabled
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
posts, err := h.postRepo.GetLikedPosts(c.Request.Context(), userID, limit, offset, showNSFW)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to fetch liked posts", "details": err.Error()})
|
c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to fetch liked posts", "details": err.Error()})
|
||||||
return
|
return
|
||||||
|
|
|
||||||
|
|
@ -255,7 +255,13 @@ func (h *UserHandler) GetSavedPosts(c *gin.Context) {
|
||||||
limit := utils.GetQueryInt(c, "limit", 20)
|
limit := utils.GetQueryInt(c, "limit", 20)
|
||||||
offset := utils.GetQueryInt(c, "offset", 0)
|
offset := utils.GetQueryInt(c, "offset", 0)
|
||||||
|
|
||||||
posts, err := h.postRepo.GetSavedPosts(c.Request.Context(), targetID, limit, offset)
|
// Check viewer's NSFW preference
|
||||||
|
showNSFW := false
|
||||||
|
if settings, err := h.repo.GetUserSettings(c.Request.Context(), currentUserID); err == nil && settings.NSFWEnabled != nil {
|
||||||
|
showNSFW = *settings.NSFWEnabled
|
||||||
|
}
|
||||||
|
|
||||||
|
posts, err := h.postRepo.GetSavedPosts(c.Request.Context(), targetID, limit, offset, showNSFW)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error().Err(err).Msg("Failed to fetch saved posts")
|
log.Error().Err(err).Msg("Failed to fetch saved posts")
|
||||||
c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to fetch saved posts"})
|
c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to fetch saved posts"})
|
||||||
|
|
@ -284,7 +290,13 @@ func (h *UserHandler) GetLikedPosts(c *gin.Context) {
|
||||||
limit := 20
|
limit := 20
|
||||||
offset := 0
|
offset := 0
|
||||||
|
|
||||||
posts, err := h.postRepo.GetLikedPosts(c.Request.Context(), userID, limit, offset)
|
// Check viewer's NSFW preference
|
||||||
|
showNSFW := false
|
||||||
|
if settings, err := h.repo.GetUserSettings(c.Request.Context(), userID); err == nil && settings.NSFWEnabled != nil {
|
||||||
|
showNSFW = *settings.NSFWEnabled
|
||||||
|
}
|
||||||
|
|
||||||
|
posts, err := h.postRepo.GetLikedPosts(c.Request.Context(), userID, limit, offset, showNSFW)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error().Err(err).Msg("Failed to fetch liked posts")
|
log.Error().Err(err).Msg("Failed to fetch liked posts")
|
||||||
c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to fetch liked posts"})
|
c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to fetch liked posts"})
|
||||||
|
|
|
||||||
|
|
@ -232,7 +232,7 @@ func (r *PostRepository) GetCategories(ctx context.Context) ([]models.Category,
|
||||||
return categories, nil
|
return categories, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *PostRepository) GetPostsByAuthor(ctx context.Context, authorID string, viewerID string, limit int, offset int, onlyChains bool) ([]models.Post, error) {
|
func (r *PostRepository) GetPostsByAuthor(ctx context.Context, authorID string, viewerID string, limit int, offset int, onlyChains bool, showNSFW bool) ([]models.Post, error) {
|
||||||
query := `
|
query := `
|
||||||
SELECT
|
SELECT
|
||||||
p.id, p.author_id, p.category_id, p.body,
|
p.id, p.author_id, p.category_id, p.body,
|
||||||
|
|
@ -268,10 +268,14 @@ func (r *PostRepository) GetPostsByAuthor(ctx context.Context, authorID string,
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
AND ($5 = FALSE OR p.chain_parent_id IS NOT NULL)
|
AND ($5 = FALSE OR p.chain_parent_id IS NOT NULL)
|
||||||
|
AND (
|
||||||
|
COALESCE(p.is_nsfw, FALSE) = FALSE
|
||||||
|
OR $6 = TRUE
|
||||||
|
)
|
||||||
ORDER BY p.created_at DESC
|
ORDER BY p.created_at DESC
|
||||||
LIMIT $2 OFFSET $3
|
LIMIT $2 OFFSET $3
|
||||||
`
|
`
|
||||||
rows, err := r.pool.Query(ctx, query, authorID, limit, offset, viewerID, onlyChains)
|
rows, err := r.pool.Query(ctx, query, authorID, limit, offset, viewerID, onlyChains, showNSFW)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
@ -549,7 +553,7 @@ func (r *PostRepository) GetNearbyBeacons(ctx context.Context, lat float64, long
|
||||||
return beacons, nil
|
return beacons, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *PostRepository) GetSavedPosts(ctx context.Context, userID string, limit int, offset int) ([]models.Post, error) {
|
func (r *PostRepository) GetSavedPosts(ctx context.Context, userID string, limit int, offset int, showNSFW bool) ([]models.Post, error) {
|
||||||
query := `
|
query := `
|
||||||
SELECT
|
SELECT
|
||||||
p.id, p.author_id, p.category_id, p.body,
|
p.id, p.author_id, p.category_id, p.body,
|
||||||
|
|
@ -569,10 +573,11 @@ func (r *PostRepository) GetSavedPosts(ctx context.Context, userID string, limit
|
||||||
JOIN public.profiles pr ON p.author_id = pr.id
|
JOIN public.profiles pr ON p.author_id = pr.id
|
||||||
LEFT JOIN public.post_metrics m ON p.id = m.post_id
|
LEFT JOIN public.post_metrics m ON p.id = m.post_id
|
||||||
WHERE ps.user_id = $1::uuid AND p.deleted_at IS NULL
|
WHERE ps.user_id = $1::uuid AND p.deleted_at IS NULL
|
||||||
|
AND (COALESCE(p.is_nsfw, FALSE) = FALSE OR $4 = TRUE)
|
||||||
ORDER BY ps.created_at DESC
|
ORDER BY ps.created_at DESC
|
||||||
LIMIT $2 OFFSET $3
|
LIMIT $2 OFFSET $3
|
||||||
`
|
`
|
||||||
rows, err := r.pool.Query(ctx, query, userID, limit, offset)
|
rows, err := r.pool.Query(ctx, query, userID, limit, offset, showNSFW)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
@ -601,7 +606,7 @@ func (r *PostRepository) GetSavedPosts(ctx context.Context, userID string, limit
|
||||||
return posts, nil
|
return posts, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *PostRepository) GetLikedPosts(ctx context.Context, userID string, limit int, offset int) ([]models.Post, error) {
|
func (r *PostRepository) GetLikedPosts(ctx context.Context, userID string, limit int, offset int, showNSFW bool) ([]models.Post, error) {
|
||||||
query := `
|
query := `
|
||||||
SELECT
|
SELECT
|
||||||
p.id, p.author_id, p.category_id, p.body,
|
p.id, p.author_id, p.category_id, p.body,
|
||||||
|
|
@ -621,10 +626,11 @@ func (r *PostRepository) GetLikedPosts(ctx context.Context, userID string, limit
|
||||||
JOIN public.profiles pr ON p.author_id = pr.id
|
JOIN public.profiles pr ON p.author_id = pr.id
|
||||||
LEFT JOIN public.post_metrics m ON p.id = m.post_id
|
LEFT JOIN public.post_metrics m ON p.id = m.post_id
|
||||||
WHERE pl.user_id = $1::uuid AND p.deleted_at IS NULL
|
WHERE pl.user_id = $1::uuid AND p.deleted_at IS NULL
|
||||||
|
AND (COALESCE(p.is_nsfw, FALSE) = FALSE OR $4 = TRUE)
|
||||||
ORDER BY pl.created_at DESC
|
ORDER BY pl.created_at DESC
|
||||||
LIMIT $2 OFFSET $3
|
LIMIT $2 OFFSET $3
|
||||||
`
|
`
|
||||||
rows, err := r.pool.Query(ctx, query, userID, limit, offset)
|
rows, err := r.pool.Query(ctx, query, userID, limit, offset, showNSFW)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -91,12 +91,18 @@ class _sojornPostCardState extends ConsumerState<sojornPostCard> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Whether to show NSFW blur overlay — respects user's blur preference
|
/// Whether NSFW post should be completely hidden (not shown at all)
|
||||||
|
bool get _shouldHideNsfw {
|
||||||
|
if (!post.isNsfw) return false;
|
||||||
|
final settings = ref.read(settingsProvider);
|
||||||
|
return !(settings.user?.nsfwEnabled ?? false);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Whether to show NSFW blur overlay — only applies when user HAS opted in
|
||||||
bool get _shouldBlurNsfw {
|
bool get _shouldBlurNsfw {
|
||||||
if (!post.isNsfw || _nsfwRevealed) return false;
|
if (!post.isNsfw || _nsfwRevealed) return false;
|
||||||
|
if (_shouldHideNsfw) return false; // Will be hidden entirely, no blur needed
|
||||||
final settings = ref.read(settingsProvider);
|
final settings = ref.read(settingsProvider);
|
||||||
// Always blur if user hasn't opted into NSFW content
|
|
||||||
if (!(settings.user?.nsfwEnabled ?? false)) return true;
|
|
||||||
// If opted in, respect the blur toggle
|
// If opted in, respect the blur toggle
|
||||||
return settings.user?.nsfwBlurEnabled ?? true;
|
return settings.user?.nsfwBlurEnabled ?? true;
|
||||||
}
|
}
|
||||||
|
|
@ -114,6 +120,9 @@ class _sojornPostCardState extends ConsumerState<sojornPostCard> {
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
|
// Completely hide NSFW posts when user hasn't enabled NSFW
|
||||||
|
if (_shouldHideNsfw) return const SizedBox.shrink();
|
||||||
|
|
||||||
return Material(
|
return Material(
|
||||||
color: Colors.transparent,
|
color: Colors.transparent,
|
||||||
child: Container(
|
child: Container(
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue