You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

MERN社交应用实现帖子公开/私密可见性功能技术问询

帖子可见性功能实现方案

1. 修正Post模型缩进问题(已初步实现)

你的Post模型中visibility字段缩进有误,修正后确保schema语法正确:

const mongoose = require("mongoose");

const postSchema = new mongoose.Schema({
  caption: String,
  image: {
    public_id: String,
    url: String,
  },
  owner: {
    type: mongoose.Schema.Types.ObjectId,
    ref: "User",
  },
  createdAt: {
    type: Date,
    default: Date.now,
  },
  likes: [
    {
      type: mongoose.Schema.Types.ObjectId,
      ref: "User",
    },
  ],
  comments: [
    {
      user: {
        type: mongoose.Schema.Types.ObjectId,
        ref: "User",
      },
      comment: {
        type: String,
        required: true,
      },
    },
  ],
  // 修正缩进,确保字段属于schema结构
  visibility: {
    type: String,
    enum: ["public", "private"],
    default: "public"
  },
});

module.exports = mongoose.model("Post", postSchema);

2. 更新创建帖子接口

在创建帖子时接收前端传入的可见性参数,默认使用public:

exports.createPost = async (req, res) => {
  try {
    const myCloud = await cloudinary.v2.uploader.upload(req.body.image, {
      folder: "posts",
    });
    const newPostData = {
      caption: req.body.caption,
      image: {
        public_id: myCloud.public_id,
        url: myCloud.secure_url,
      },
      owner: req.user._id,
      // 新增:接收前端传入的可见性参数,无则用默认值
      visibility: req.body.visibility || "public"
    };

    const post = await Post.create(newPostData);

    const user = await User.findById(req.user._id);
    user.posts.unshift(post._id);
    await user.save();

    res.status(201).json({
      success: true,
      message: "Post created",
      post
    });
  } catch (error) {
    res.status(500).json({
      success: false,
      message: error.message,
    });
  }
};

3. 实现帖子列表的权限过滤逻辑

根据不同场景返回符合权限的帖子:

场景一:获取当前用户的所有帖子

直接返回自己的全部帖子,不受可见性限制:

exports.getMyPosts = async (req, res) => {
  try {
    const posts = await Post.find({ owner: req.user._id })
      .populate("owner", "name avatar")
      .populate("likes", "name avatar")
      .populate("comments.user", "name avatar");

    res.status(200).json({
      success: true,
      posts
    });
  } catch (error) {
    res.status(500).json({
      success: false,
      message: error.message
    });
  }
};

场景二:获取他人的帖子列表

  • 若当前用户是对方的关注者或本人,返回所有帖子
  • 否则仅返回公开帖子:
exports.getUserPosts = async (req, res) => {
  try {
    const targetUser = await User.findById(req.params.id);
    if (!targetUser) {
      return res.status(404).json({
        success: false,
        message: "User not found"
      });
    }

    const isSelf = req.user._id.toString() === req.params.id;
    const isFollower = targetUser.followers.includes(req.user._id);
    
    let query = { owner: req.params.id };
    if (!isSelf && !isFollower) {
      query.visibility = "public";
    }

    const posts = await Post.find(query)
      .populate("owner", "name avatar")
      .populate("likes", "name avatar")
      .populate("comments.user", "name avatar");

    res.status(200).json({
      success: true,
      posts
    });
  } catch (error) {
    res.status(500).json({
      success: false,
      message: error.message
    });
  }
};

场景三:首页信息流(关注用户的帖子)

返回自己的所有帖子 + 关注用户的公开帖子(或关注用户的全部帖子,根据需求调整):

exports.getFeed = async (req, res) => {
  try {
    const currentUser = await User.findById(req.user._id);
    const followingIds = [...currentUser.following, req.user._id];

    const posts = await Post.find({ 
      owner: { $in: followingIds },
      $or: [
        { visibility: "public" },
        { owner: req.user._id }
      ]
    })
    .populate("owner", "name avatar")
    .populate("likes", "name avatar")
    .populate("comments.user", "name avatar")
    .sort({ createdAt: -1 });

    res.status(200).json({
      success: true,
      posts
    });
  } catch (error) {
    res.status(500).json({
      success: false,
      message: error.message
    });
  }
};

4. 点赞/评论的权限控制

确保只有有权限的用户才能操作私密帖子:

exports.likePost = async (req, res) => {
  try {
    const post = await Post.findById(req.params.id);
    if (!post) {
      return res.status(404).json({
        success: false,
        message: "Post not found"
      });
    }

    // 检查操作权限:公开帖所有人可操作,私密帖仅作者或关注者可操作
    const hasPermission = post.visibility === "public" 
      || post.owner.toString() === req.user._id.toString()
      || (await User.findById(post.owner)).followers.includes(req.user._id);

    if (!hasPermission) {
      return res.status(403).json({
        success: false,
        message: "You can't interact with this private post"
      });
    }

    // 原有点赞逻辑
    if (post.likes.includes(req.user._id)) {
      post.likes = post.likes.filter(id => id.toString() !== req.user._id.toString());
    } else {
      post.likes.push(req.user._id);
    }
    await post.save();

    res.status(200).json({
      success: true,
      message: post.likes.includes(req.user._id) ? "Post liked" : "Post unliked"
    });
  } catch (error) {
    res.status(500).json({
      success: false,
      message: error.message
    });
  }
};

5. 前端配合修改

  • 创建帖子页面添加下拉选择框,提供「公开」「私密」选项,提交时将visibility参数传给后端
  • 展示帖子时,根据visibility字段添加标识(如锁形图标)区分私密帖子
  • 访问他人主页时,若没有权限查看私密帖子,隐藏相关内容

内容的提问来源于stack exchange,提问作者Akash Das

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.16 22:50:41