[프로젝트-Stroll] Devlog-5

김대연·2020년 1월 19일
0

Project Stroll

목록 보기
5/7

POST /trails 에 이어 GET /trails도 작성했는데, 처음 로그인하고 나타나는 메인 페이지에서 이미 DB에 등록된 산책로들의 정보들을 가져오는 요청이다.

const jwt = require('jsonwebtoken');
const secretObj = require('../../config/jwt');
const {
  trails,
  users,
  locations,
  categories,
  images,
} = require('../../models');

module.exports = {
  /**
   * 로그인하고 myPage를 처음 산책로들을 render 할 때 보내는 요청.
   * -주의: trail에 있는 userId는 작성자의 정보, token 과 같이 들어오는 id는 현재 접속한 유저!
   */
  get: (req, res) => {
    const token = req.cookies.user;
    // 토큰 인증 절차 -> 없으면 401
    jwt.verify(token, secretObj.secret, async (err, decoded) => {
      // 토큰이 존재한다면,
      if (decoded) {
        // 테이블에서 쿼리한 값들을 모아 응답으로 보낼 배열.
        const trailsWithInfo = [];
        // 각 trail의 foreign key로 연결된 테이블들에서 username, location들, tag 를 가져와 배열에 요소로 추가한다.
        // eslint-disable-next-line no-await-in-loop
        const eachInfos = await trails
          .findAll({
            include: [ // 테이블들을 조인
              {
                model: users, // 원하는 테이블에서
                required: true,
                attributes: ['username'], // 원하는 요소만 select.
              },
              {
                model: locations,
                required: true,
                attributes: [
                  'location1',
                  'location2',
                  'location3',
                  'location4',
                  'location5',
                ],
              },
              {
                model: categories,
                required: true,
                attributes: ['tag'],
              },
            ],
            raw: true, // datavalues 만 가져오는 옵션
            nest: true, // 객체 형태로 구성
          })
          .catch((error) => {
            console.log(error);
            res.sendStatus(500);
          });
        // 각 가져온 값들에서 location들을 병합.
        for (let i = 0; i < eachInfos.length; i += 1) {
          trailsWithInfo.push(eachInfos[i]);
          trailsWithInfo[i].location = [
            eachInfos[i].location.location1,
            eachInfos[i].location.location2,
            eachInfos[i].location.location3,
            eachInfos[i].location.location4,
            eachInfos[i].location.location5,
          ];
        }
        if (!trailsWithInfo.length) {
          res.sendStatus(404);
        } else {
          res.status(200).json({ trails: trailsWithInfo });
        }
      } else {
        res.sendStatus(401);
      }
    });
  },
}

tag.js 는 req.params로 들어오는 태그를 이용하여, 해당 태그에 속한 trail들을 필터하여 응답으로 보내주는 파일이다. API 형식은 /trails/:tag 가 된다.

/* eslint-disable no-console */
/* eslint-disable object-shorthand */
const jwt = require('jsonwebtoken');
const secretObj = require('../../config/jwt');

const {
  trails,
  users,
  locations,
  categories,
} = require('../../models');

/**
 * ex) http://localhost:3000/trails/:tag
 * myPage 접속 후 태그를 클릭할 때마다 보내는 요청.
 * 필요한 데이터: token(decoded -> userId, email 포함)으로 인증, req.params.tag
 * -주의: trail에 있는 userId는 작성자의 정보, token 과 같이 들어오는 id는 현재 접속한 유저!
 */
module.exports = (req, res) => {
  // 선택한 tag
  const { tag } = req.params;
  const token = req.cookies.user;
  // 토큰 인증 절차 -> 없으면 401
  jwt.verify(token, secretObj.secret, async (err, decoded) => {
    // 토큰이 존재한다면,
    if (decoded) {
      // req.params.tag 와 같은 tagId를 체크
      const checkTag = await categories.findOne({
        where: {
          tag: tag,
        },
        raw: true,
      }).catch((error) => {
        console.error(error);
        res.sendStatus(500);
      });
      // 존재하지 않는 tag라면 404
      if (!checkTag) {
        res.sendStatus(404);
      }
      // checkTag에서 확인한 id를 이용하여 해당 id를 가진 trails를 findAll()
      const checkTrailsByTag = await trails.findAll({
        where: {
          categoryId: checkTag.id, // 필터할 query문
        },
        include: [ // 조인하여 가져올 테이블들
          {
            model: users, // 조인할 테이블
            required: true,
            attributes: ['username'], // 테이블에서 가져올 요소
          },
          {
            model: locations,
            required: true,
            attributes: ['location1', 'location2', 'location3', 'location4', 'location5'],
          },
          {
            model: categories,
            required: true,
            attributes: ['tag'],
          },
        ],
        raw: true,
        nest: true,
      }).catch((error) => {
        console.error(error);
        res.sendStatus(500);
      });
      // locations 하나로 병합 -> 5개의 각각의 키값으로 이루어진 좌표들을 하나의 배열에 포함시킨다.
      const combineTrailsLocation = [];
      for (let i = 0; i < checkTrailsByTag.length; i += 1) {
        combineTrailsLocation.push(checkTrailsByTag[i]);
        combineTrailsLocation[i].location = [
          checkTrailsByTag[i].location.location1,
          checkTrailsByTag[i].location.location2,
          checkTrailsByTag[i].location.location3,
          checkTrailsByTag[i].location.location4,
          checkTrailsByTag[i].location.location5,
        ];
      }
      // 해당 태그의 trail이 없다면 404
      if (!combineTrailsLocation) {
        res.sendState(404);
      }
      res.status(200).json(combineTrailsLocation);
    // token이 없다면 401
    } else {
      res.sendStatus(401);
    }
  });
};

0개의 댓글