개발 내용 개요
플라스크 서버에서 로그인 기능 구현하기
내가 누른 좋아요와 다른 사람이 누른 좋아요를 구분하기
@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)
        ...
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"]))
            }
        })
    }
}
<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();
  }
}