Chapter 8 User

#8.0 – #8.15

– 로그인하지 않은 사람들이 우리가 보호하려는 페이지로 이동하지 못하도록 방지

=> 미들웨어 사용 방지!

userRouter.route("/edit").all(protectorMiddleware).get(getEdit).post(postEdit);

– 미들웨어 사용 시 하나의 라우트에 get, post 등의 여러 함수를 붙이면 all()을 통해 미들웨어를 모두 적용할 수 있습니다!

const { session: { user: { id } } } = req;
const id = req.session.user.id;

– 둘 다 같은 내용!!

– 위의 방법을 이용하면 하나의 객체에서 다른 정보를 한번에 얻을 수 있어 편리합니다!

  • Model.findByIdAndUpdate()
    • 문서의 _id 필드를 사용하여 mongodb findAndModify 업데이트 명령을 실행합니다.
    • findByIdAndUpdate(id, …)는 findOneAndUpdate({ _id: id }, …)와 동일합니다.
    • Model.findByIdAndUpdate(id, { 이름: ‘제이슨 본’ }, 옵션, 콜백)


  • req.session.user에 내용을 전달합니다. 안에 있는 것을 꺼내
  • DB의 세션도 업데이트됩니다.
    • 데이터베이스와 세션이 모두 최신 상태로 유지됩니다.
  • 또는 그냥 새 사용자를 만들고 – updateUser를 만들고 기존 사용자를 이 사용자로 바꿉니다.
const updatedUser = await User.findByIdAndUpdate(
        _id,
        {
            name,
            email,
            username,
            location,
        },
        { new: true }
    );
    req.session.user = updatedUser;
  • findByIdAndUpdate는 업데이트되기 전에 데이터를 반환합니다.
  • new: true를 설정하면 findByIdAndUpdate가 업데이트된 데이터를 반환합니다.
  • 즉, 몽구스에게 마지막으로 업데이트된 객체를 원한다고 알려줍니다.
  • => 위의 하나씩 업데이트 하는 방법보다 훨씬 좋습니다~~
    • 이메일 주소를 변경하고 싶은데 이미 존재하는 경우 어떻게 하나요?
    • 양식 정보가 세션의 사용자 정보와 일치하는지 확인하십시오.
    • 이것은 사용자가 자신의 사용자 이름이나 이메일 주소를 변경하기를 원한다는 것을 알려줍니다.
    • 물론 Join에서 사용한 방법을 다시 사용하면 이전에 사용하던 방법이 있습니다.

– 본문의 사용자 이름 및 이메일 주소가 session.user의 사용자 이름 및 이메일 주소와 다른지 확인합니다.

– 비밀번호 변경 시 저장 시 비밀번호를 해시로 변환하는 미들웨어가 있습니다. 이것을 사용하기 위해

  • 미리 저장된 미들웨어(해시하는 미들웨어)를 반복하고 User.create를 사용합니다.
  • user.save()는 사전 저장 미들웨어를 트리거할 수도 있습니다.
    • save() 함수를 사용해야 하므로 세션에서 로그인한 사용자를 찾아야 합니다.

파일 업로드

block content
    form(method="POST")
        label(for="avatar") Avatar 
        input(type="file", id="avatar", name="avatar")
  • 사용자가 파일을 업로드할 수 있습니다.
  • 이렇게 하면 파일 형식이 지정되지 않아 목적에 맞지 않는 txt 파일을 업로드할 수 있습니다…
input(type="file", id="avatar", name="avatar", accept="image/*")
  • 수락으로 파일 형식을 지정하면 지정된 파일 형식만 업로드할 수 있습니다.
  • image/* : 이미지 파일만 선택 가능! png 또는 jpeg와 같은 것

어머니

– 사용자가 파일을 업로드하도록 허용

  • 여러 부분으로 구성된 양식Multer의 도움을 받으려면
form(method="POST", enctype="multipart/form-data")
  • 이는 양식이 다르게 코딩됨을 의미합니다.
    • 파일을 백엔드로 보내는 데 필요한 인코딩 유형(enctype)입니다.
  • 이것은 파일 업로드를 위한 유일한 조건입니다!
  • 미들웨어생성, 사용!
export const uploadFiles = multer({
    //req,res 사용하지 않고 multer 사용함!
    dest: "uploads/" //사용자가 보낸 파일을 uploads 폴더에 저장하도록 설정. 폴더 저절로 생성됨
})
  • 대상 또는 메모리
    • 수신된 파일을 배치할 위치 지정
userRouter.route("/edit").all(protectorMiddleware).get(getEdit).post(uploadFiles.single("avatar"), postEdit);

– 아바타 파일을 입력받아 uploads 폴더에 파일 저장 후 postEdit에 파일 정보 전달

  • 미들웨어는 왼쪽에서 오른쪽으로 작동하므로 multer 미들웨어가 먼저 실행된 다음 postEdit

– single은 하나의 파일만 업로드됨을 의미합니다.

더보기

const {
        session: { user: { _id },
        },
        body: { name, email, username, location },
        file,
    } = req; //로그인된 user의 정보를 업데이트. user ID를 가지고 있는 세션에게서 받음
    console.log(file);
User.findByIdAndUpdate(
        _id,
        {   
            avatarUrl: file? file.path: avatarUrl,
            name,
            email,
            username,
            location,
        },
        { new: true }
    );

– 사용자가 아바타를 바꾸지 않는다면…? 파일이 정의되지 않았기 때문에 경로를 찾을 수 없습니다.

– avatarUrl: 파일이 존재하지 않으면 file.pathpath를 사용할 수 없습니다.

– 파일이 있는 경우에만 file.path를 포함하고, 없으면 기존 avatarUrl을 포함합니다.

– 파일을 보내지 않아도 에러가 발생하지 않습니다!

*** DB에 파일을 저장하지 마세요!!!! 파일을 폴더에 저장하고 해당 파일의 위치만 DB에 저장합니다.

DB는 파일 저장용이 아닙니다.

더보기

export const postEdit = async (req, res) => {
    const {
        session: { user: { _id, avatarUrl },
        },
        body: { name, email, username, location },
        file,
    } = req; //로그인된 user의 정보를 업데이트. user ID를 가지고 있는 세션에게서 받음
    const updatedUser = await User.findByIdAndUpdate(
        _id,
        {
            avatarUrl: file ? file.path : avatarUrl,
            name,
            email,
            username,
            location,
        },
        { new: true }
    );
    req.session.user = updatedUser;
    return res.redirect("/users/edit");
};

* 정적 파일 제공

– 전체 폴더를 브라우저에서 사용할 수 있도록 합니다.

// server.js 파일
app.use("/uploads",express.static("uploads"))

– express.static() 에서 정적으로 노출될 파일명을 괄호 안에 넣습니다.

– 디렉토리에 파일 제공

– 누군가가 /uploads로 이동하려고 할 때 업로드 폴더의 내용을 표시하도록 Express에 지시하십시오!

* 현재 파일을 서버에 저장 => 서버가 계속 종료되고 다시 시작되므로 좋지 않음

* 비디오 업로드

– uploadFiles로 다시 업로드 받기

  • 파일 크기
    • 파일 업로드 크기를 제한할 수 있습니다.

* 업로드된 사용자와 동영상 연결

– 고유값 아이디로 연결하자!

  • 사용자가 업로드한 모든 동영상의 ID는 사용자에 저장됩니다.
  • 동영상의 경우 동영상을 올린 사용자의 ID가 저장됩니다.
owner: { type: mongoose.Schema.Types.ObjectId, required: true, ref: "User" },

– videoSchema에 콘텐츠 추가

  • mongoose에서 제공하는 유형을 사용하여 개체 ID를 저장하세요!
  • 참조 -> 참조
    • Mungo에게 ID를 소유자에 저장하도록 지시하십시오.
    • 연결할 모델을 말합니다. 어떤 모델 개체 ID인지 나타냅니다(여기서는 사용자 모델).

* 참조 사용

  • mongoose는 참조로 연결된 모델의 관계를 알고 있습니다.
  • 이를 이용하여 보다 편리하게 사용자 개체와 비디오 개체를 연결할 수 있습니다.

– 채우다

  • 연결된 부분(여기서는 id로 연결)을 실제 사용자 데이터로 채웁니다.
const video = await Video.findById(id).populate("owner");
  • 참조 부분의 populate() 괄호 안에 값의 이름을 넣어 다른 모델의 값을 가져옵니다.
  • 연결된 사용자의 가치도 알 수 있습니다.
  • 채우기(관계)
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 })
    //video의 owner id가 URL에 있는 id와 같은  video를 찾는다는 것
    console.log(videos);
    return res.render("users/profile", { pageTitle: `${user.name}'s Page`, user, videos })
}

– 동일한 사용자 및 소유자 ID를 가진 비디오 검색

– 사용자가 업로드한 모든 동영상을 찾아 화면에서 확인하세요!

  • 프로필의 동영상과 동일한 사용자 ID 및 소유자 ID를 가진 동영상만 가져옵니다.
  • user.id는 URL에서 찾은 ID입니다.

– 이 방법 외에도 사용자에 일련의 비디오를 저장하는 방법을 사용할 수 있습니다! 그게 낫다