User's Videos

0_CyberLover_0·2022년 7월 29일
0

Node.JS #06

목록 보기
3/3

전 파트에서 하던 것을 완성하도록 하겠다.

export const see = async (req, res) => {
  const { id } = req.params;
  const user = await User.findById(id);
  if (!user) {
    return res.status(404).render("404", { pageTitle: "User not found." });
  }
  const videos = await Video.find({ owner: user._id });

여기에서 하고 있는건 owneruser._id인 모든 영상들을 찾는 거다.

url에 있는 userid를 가지고 찾고 있다.

사실 이 코드만으로도 충분하다.

하지만 여기에 나온 방식을 사용해서 더 멋있게 코드를 만들어 보도록 한다.

어떤 유저가 업로드한 모든 영상들을 찾기 위해 populate를 쓸 수 있다.

  const videos = await Video.find({ owner: user._id });

현재 이 코드를 삭제를 한다.

return res.render("users/profile", {
    pageTitle: user.name,
    user,
  	videos,
  });

videos도 지워 준다.

return res.render("users/profile", {
    pageTitle: user.name,
    user,
  });

그러면 profile.pugvideos가 작동하지 않는다.

block content 
    each video in videos 
        +video(video)
    else    
        li Sorry nothing found.

이 부분이다.

그리고 DB를 초기화 했었기 때문에 로그인 상태가 아니다. 그러면 user없이 프로필 창에 들어 갈 수 없게 된다.

그래서 videosprofile로 보내지 않았기 때문에 작동하지 않게 된다.

그래도 한 번 더 좋게 고쳐 보도록 한다.

models폴더를 보면 video는 1개의 owner를 가지고 있다.

이전에도 살펴 봤듯이 video는 하나의 owner를 가지고 owner는 여러 videos를 가질 수 있다.

video는 하나의 user를 가지지만 user는 여러 videos를 가질 수 있다.

이 논리를 기반으로 user model안에 videos라는 array를 만들어 준다.

const userSchema = new mongoose.Schema({
  email: { type: String, required: true, unique: true },
  avatarUrl: String,
  socialOnly: { type: Boolean, default: false },
  username: { type: String, required: true, unique: true },
  password: { type: String },
  name: { type: String, required: true },
  location: String,
});

여기에 추가 해 준다.

const userSchema = new mongoose.Schema({
  email: { type: String, required: true, unique: true },
  avatarUrl: String,
  socialOnly: { type: Boolean, default: false },
  username: { type: String, required: true, unique: true },
  password: { type: String },
  name: { type: String, required: true },
  location: String,
  videos: [{ type: mongoose.Schema.Types.ObjectId, ref: "Video" }],
});

object가 아닌 array로 만들어 준다. 여러 개의 videos를 가지기 때문이다.

1개의 영상은 소유주가 1명이지만, 소유주는 여러 영상을 소유 할 수 있다.

그래서 array로 만들었다. 그리고 이 array에 무엇으로 채워 주냐면 object 이다.

그렇게 해서 objectId를 사용해 주었다.

  owner: { type: mongoose.Schema.Types.ObjectId, required: true, ref: "User" },

이 부분이다.

해당 코드를 그대로 사용하게 된다. 수정 할 부분을 수정해 준다.

이제 ObjectId를 가지는 array가 되는 거다.

required는 필요가 없다. refUser가 아니라 Video이다.

videosVideo model에 연결된 ObjectId로 구성된 array이다.

이건 array이니까 많은 video를 담을 수 있다.

이제 videoController를 수정해 줄 차례이다.

그 이유는 영상을 업로드 할때 추가적으로 해야 할 것이 있기 때문이다.

 const { title, description, hashtags } = req.body;
  try {
    await Video.create({
      title,
      description,
      fileUrl,
      owner: _id,
      hashtags: Video.formatHashtags(hashtags),
    });

여기서 Video owner에 사용자 _id를 저장하고 있다.

하지만 이제는 업로드 될 영상의 iduser model에도 저장해 줘야 한다.

Uservideos라는 array가 있다는걸 기억하고 있어야 한다.

그래서 새로 업로드 하는 영상의 iduser model에 저장해줄 거다.

현재 유저의 idVideoowner에 추가 하고 있다.

이제 다른 방식으로 해보도록 한다.

다행히 create()가 새로 만드는 videoreturn 해준다.

 await Video.create({
      title,
      description,
      fileUrl,
      owner: _id,
      hashtags: Video.formatHashtags(hashtags),
    });
   const newVideo = await Video.create({

이렇게 해준다. 이말은 현재 가지고 있는 id로 사용자를 검색 할수 있고

newVideoidUservideos array에 추가해 준다.

그리고 user를 찾아 보도록 한다.

const newVideo = await Video.create({
      title,
      description,
      fileUrl,
      owner: _id,
      hashtags: Video.formatHashtags(hashtags),
    });
    const user = await User.findById(_id);
    user.videos.push();

그리고 user.videos를 쓸거다. uservideos array가 있다는 걸 알기에 그렇다.

array에 요소를 추가 할때는 push를 사용하면 된다.

해당 작업 페이지로 가서 inspect > console에서 에시를 보도록 한다.

const hello = []
undefined
hello.push(1)
1
hello
[1]

위와 같은 원리로 user.videos.push(비디오 id)를 써보도록 한다.

    user.videos.push(newVideo._id);

이렇게 user.videos.push()를 쓰고 newVideoid를 써준다.

그리고 user.save()를 써준다.

user.videos.push(newVideo._id);
user.save();

그리고 다시 로그인을 해본다. 영상도 모두 삭제 되었으니 새로 올려 준다.

DB에서 모든 사용자를 검색해 보도록 한다.

db.users.find()
db.videos.find()

uservideos array가 추가 되어 있다. 그리고 모든 영상들도 검색해 본다.

전 단계에서 본 것 처럼 user에는 videos array가 있고,

video에는 owner id가 있다. 이렇게 해서 둘이 연결이 되었다.

이제 업로드 된 영상 소유자의 프로필 창을 들어가 본다.

videos가 정의되지 않아서 열리지 않고 있다고 한다.

userController를 수정해서 해결해 보도록 한다.

export const see = async (req, res) => {
  const { id } = req.params;
  const user = await User.findById(id);

먼저 see controllerconsole log(user)를 해서

export const see = async (req, res) => {
  const { id } = req.params;
  const user = await User.findById(id);
  console.log(user);

그 결과 값을 확인 해보도록 한다. 에러가 나오지만 중요한건 user이다.

보다시피 이 안에는 videos array가 존재 한다.

이제 이 videos arrayvideos정보를 다 가져올 수 있게 된다.

  const user = await User.findById(id);
  const user = await User.findById(id).populate("videos");

populate()를 써준다. 그리고 videospopulate해본다.

이제 Mongooseid를 가져다가 모든 영상들을 프로필 창에 보여줄거다.

새로고침을 해도 계속 에러가 나와있지만 console을 확인해 보면 videos정보가 로드 된걸 볼수 있다.

다시 한번 확인해 보면 videos라는 array를 만들었고 그 안에 ObjectId를 저장하고 있다.

그런데 videos를 가져왔다. 이전처럼 id만 가진 array가 아니고

Mongoose의 도움으로 video object로 구성된 array가 되었다.

이제 profile.pug만 수정해주면 된다.

block content 
    each video in videos 
        +video(video)
    else    
        li Sorry nothing found.

이제 each video in videos 대신에 each video in user.videos를 써준다.

block content 
    each video in user.videos 
        +video(video)
    else    
        li Sorry nothing found.

uservariableusers/profile로 보내고 있기 때문이다.

그리고 DB에서 찾은 uservideos를 가지고 있으니까 잘 작동하게 된다.

이 모든게 populate 한 줄로 정리가 되었다.

물론 populate를 하지 않으면 이전처럼 될거다.

이전에는 video id만 있었다. 그런데 object자체가 필요 하다.

그래서 그렇게 만들었다. 이렇게 populate를 쓰면 된다.

지금까지 relataionship에 대해서 배웠다.

이제 여러 개의 video와 어떻게 relationship을 구축하면 되는지 알게 되었다.

user는 여러 개의 video를 업로드 할수 있다는걸 반드시 기억해야 한다.

그리고 videoowner가 하나 뿐이다. 이렇게 relationship을 만들어 봤다.

video를 하나 더 만들어 보도록 한다.

그렇게 하면 프로필 창에 들어가면 두 영상을 모두 볼 수 있다.

바로 현재 유저가 영상의 소유자 이기 때문이다.

다음 파트에서는 여기에 몇 가지 condition들을 추가 해 보겠다.

Edit Video →
Delete Video →

왜냐하면 해당 버튼들을 안보이게만 만들었기 때문이다.

owner가 아닌 사람들이 수정할 수 있는 페이지를 볼 수 없게 만들어 본다.

현재는 누구나 수정 할수 있는 상태 이다. 이제 영상에는 owner가 있으니

owner만 수정 사능하도록 만들어 볼거다.

그리고 getEdit도 수정해서 영상 소유주만 form을 보고 제출 할수 있게 만들거다.

이런 것들을 보완해야 하고 video를 삭제하는 것도 owner만 가능하도록 만들거다.

userSchema.pre("save", async function () {
  this.password = await bcrypt.hash(this.password, 5);
});

현재 이 부분이 버그가 있는데 이 버그는 usersave를 할 때 마다

비밀번호를 반복적으로 hashing하고 있다. 좋지 않은 방법이다.

왜냐하면 videoController에서 영상을 업로드 할때 user.save()를 실행 하는데

그렇게 되면 비밀번호가 다시 한번 hash가 된다.

사용자가 다시 로그인 할수 없기 때문에 이 부분을 수정 해줘야 한다.

특정 조건에서만 비밀번호가 hash 되도록 만들어 줄거다.

항상 되는 것이 아니라 현재는 save()가 실행 될 때마다 hash가 일어나고 있다.

그로 인해 이 사용자는 비밀번호를 사용 할수 없게 된다. 더 이상 로그인을 할수 없는 거다.

다음 파트에서는 버그를 수정하고 보안을 신경 써보도록 한다.

보안은 영상 owner가 아닌 사람들이 영상을 수정/삭제 하지 못하게 만드는 것이고

위에 언급했던 버그도 수정하도록 하겠다.

그리고 다시 DB를 초기화 한 다음에 버그가 존재 한다는 것을 살펴 보도록 하겠다.

profile
꿈꾸는 개발자

0개의 댓글