프로필 페이지를 만들어보았다...!

개발 내용 개요

  • 로그인 & 회원가입 페이지
    1. 기본 화면으로 로그인 화면 보이기
    2. '회원가입하기' 버튼을 클릭하면 회원가입 화면으로 바뀌기
    3. '취소' 버튼을 클릭하면 로그인 화면으로 돌아오기
    4. 회원가입
      • 아이디 & 비밀번호 형식 확인
      • 아이디 중복 확인
      • DB에 아이디와 비밀번호 저장하여 회원가입 & 로그인 화면으로 전환
    5. 로그인
      • 아이디 & 비밀번호 입력 확인
      • 서버로 POST 요청을 보내 가입 정보가 존재하는지 확인
      • 회원일 경우 토큰 부여
  • 메인 페이지
    1. 모든 사람의 포스트를 시간 역순으로 보여주기
    2. 각 포스트에 좋아요/좋아요 취소 가능
      • 좋아요 누른 포스트는 찬 하트로 보여주기
    3. 포스팅 칸에 내 프로필 사진 보여주기
      • 프로필 사진 누르면 프로필 페이지로 이동
    4. 포스팅 칸 클릭하면 포스팅 모달 띄우기
      • 포스팅하기 버튼 클릭하면 포스트 DB에 저장
      • 새로고침하여 포스트 목록 다시 띄우기
  • 프로필 페이지
    1. 해당 사용자의 포스트만 시간 역순으로 보여주기
    2. 내 프로필이라면 프로필 수정 & 로그아웃 버튼 보여주기
    3. 내 프로필일 때만 포스팅 칸 보여주기
    4. 프로필 수정 버튼 클릭하면 프로필 수정 모달 보여주기
      • 기존의 저장되어 있는 값 보여주기
      • 수정 시 DB에 업데이트하고 새로고침해서 변경사항 적용
    5. 로그아웃 버튼 클릭하면 토큰 삭제하고 로그인 페이지로 이동

플라스크 서버에서 로그인 기능 구현하기

  • 로그인 시, 비밀번호를 해시함수(SHA256)으로 암호화한 후, DB에서 해당 아이디와 비밀번호를 갖는 회원이 있는지 찾는다. 회원 정보가 없는 경우 실패 메시지를 보내고, 찾은 경우 아이디와 토큰 만료 시간을 저장하는 토큰을 만들어 넘겨준다.
  • 로그인 성공 메시지를 받으면 건네받은 토큰을 쿠키로 저장하여 만료되기 전까지 갖고 있으면서, API 요청을 보낼 때마다 회원임을 확인받는다.
  • 로그아웃 시 해당 토큰을 삭제합니다.

내가 누른 좋아요와 다른 사람이 누른 좋아요를 구분하기

  1. 서버에서 '좋아요를 누른 포스트가 무엇인지, 내가 누른 포스트인지' 에 대해 정의한다.
@app.route('/update_like', methods=['POST'])
def update_like():
    token_receive = request.cookies.get('mytoken')
    try:
        payload = jwt.decode(token_receive, SECRET_KEY, algorithms=['HS256'])
        user_info = db.users.find_one({"username": payload["id"]})
        post_id_receive = request.form["post_id_give"]
        type_receive = request.form["type_give"]
        action_receive = request.form["action_give"]
        doc = {
            "post_id": post_id_receive,
            "username": user_info["username"],
            "type": type_receive
        }
        if action_receive == "like":
            db.likes.insert_one(doc)
        else:
            db.likes.delete_one(doc)
        ...
  1. 클라이언트에서 좋아요를 눌렀을때의 상황을 정의하는 함수를 만든다. - 좋아요가 눌러져있는 상황과, 안눌려져있는 상황을 분기하여 html을 다시 그리고 ajax를 다르게 호출한다.
function toggle_like(post_id, type) {
    let $a_like = $(`#${post_id} a[aria-label='heart']`)
    let $i_like = $a_like.find("i")
    if ($i_like.hasClass("fa-heart")) {
        $.ajax({
            type: "POST",
            url: "/update_like",
            data: {
                post_id_give: post_id,
                type_give: type,
                action_give: "unlike"
            },
            success: function (response) {
                $i_like.addClass("fa-heart-o").removeClass("fa-heart")
                $a_like.find("span.like-num").text(num2str(response["count"]))
            }
        })
    } else {
        $.ajax({
            type: "POST",
            url: "/update_like",
            data: {
                post_id_give: post_id,
                type_give: type,
                action_give: "like"
            },
            success: function (response) {
                $i_like.addClass("fa-heart").removeClass("fa-heart-o")
                $a_like.find("span.like-num").text(num2str(response["count"]))
            }
        })

    }
}
  1. 클라이언트에서 '${post['_id']}'를 인자로 받아서 해당 post의 db 기본 아이디 값을 알아낸다.
<a class="level-item is-sparta" aria-label="heart" onclick="toggle_like('${post['_id']}', 'heart')"></a>

그 밖에 깨알같은 구문들.

new Date().toISOString() // 날짜 받아오는 법
except (jwt.ExpiredSignatureError):
# 토큰 기한이 지났을때 예외 처리

except (jwt.exceptions.DecodeError):
# 디코딩할 토큰이 없을때 예외 처리 (로그인 안한채로 로그인이 필요한 페이지로 갔을때 막을 수 있는 예외 처리이다.)
// n분 전, n시간 전, n일 전 표현식
function time2str(date) {
    let today = new Date()
    let time = (today - date) / 1000 / 60  // 분

    if (time < 60) {
        return parseInt(time) + "분 전"
    }
    time = time / 60  // 시간
    if (time < 24) {
        return parseInt(time) + "시간 전"
    }
    time = time / 24
    if (time < 7) {
        return parseInt(time) + "일 전"
    }
    return `${date.getFullYear()}${date.getMonth() + 1}${date.getDate()}`
}
// 1000단위로 수를 표현하기
function num2str(count) {
    if (count > 10000) {
        return parseInt(count / 1000) + "k"
    }
    if (count > 500) {
        return parseInt(count / 100) / 10 + "k"
    }
    if (count == 0) {
        return ""
    }
    return count
}
.toggleClass("is-hidden") // .is-hidden이 #sign-up-box에 있으면 추가, 없으면 제거
// '아이디는 2-10자의 영문과 숫자와 일부 특수문자(._-)만 입력 가능합니다.' 관련 정규표현식
function is_nickname(asValue) {
  var regExp = /^(?=.*[a-zA-Z])[-a-zA-Z0-9_.]{2,10}$/;
  return regExp.test(asValue);
}
// '영문과 숫자 조합의 8-20자의 비밀번호를 설정해주세요. 특수문자(!@#$%^&*)도 사용 가능합니다.' 관련 정규표현식
function is_password(asValue) {
  var regExp = /^(?=.*\d)(?=.*[a-zA-Z])[0-9a-zA-Z!@#$%^&*]{8,20}$/;
  return regExp.test(asValue);
}
function enterkey() {
  if (window.event.keyCode === 13) {
    // 엔터키가 눌렸을 때 실행할 내용
    sign_in();
  }
}
profile
빠굥

0개의 댓글