
잘 되던 GET 함수가 아무것도 변경하지 않았는데 갑자기 되지 않습니다ㅠㅠ
DB에 저장도 잘 되고, get 함수 get_posts도 잘 되다가 어느순간 갑자기 작동을 하지 않습니다.
보고 계신 화면 전체를 캡처해 주시면, 튜터님들이 빠르게 상황을 상황을 이해할 수 있어요.


저 카드 자리에 원래 db에 들어가있는 내용들이 들어가야 하는데 정상적으로 작동이 안됩니다.

콘솔창에도 찍히는 내용은 없습니다ㅜㅜ
작성한 코드 및 에러 메세지
<!DOCTYPE html>
<html lang="en">
<head>
<title>Cookping</title>
<!-- Required meta tags -->
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<!-- Bulma CSS -->
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bulma@0.9.1/css/bulma.min.css">
<!-- JS -->
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery-cookie/1.4.1/jquery.cookie.js"></script>
<!--my CSS-->
<link href="{{ url_for('static', filename='mystyle.css') }}" rel="stylesheet">
<script>
// const getButton = document.querySelector("#getBtn");
// const youtubeUrl = document.querySelectorAll(".youtube-url");
// const thumbnailWrap = document.querySelector(".thumbnail-wrap");
// getButton.addEventListener('click', getThum);
const inputUrl = document.querySelector('.field input');
let preview = document.querySelector('.preview');
// let thumb = preview.querySelector('.thumb')
function post() {
let title = $("#title").val();
let comment = $("#comment").val();
let today = new Date().toISOString();
let form_data = new FormData();
let url = $("#url").val();
// preview.classList.add('current')
// https://www.youtube.com/watch?v=Xwlsq_-fmrg
// https://youtu.be/Xwlsq_-fmrg
// https://youtube.com/watch?v=Xwlsq_-fmrg
// https://www.youtu.be/Xwlsq_-fmrg
const pattern1 = 'https://www.youtube.com/watch?v='
const pattern2 = 'https://youtube.com/watch?v='
const pattern3 = 'https://youtu.be/'
const pattern4 = 'https://www.youtu.be/'
if (url.indexOf(pattern1) != -1 || url.indexOf(pattern2) != -1) {
let valid = url.split('watch?v=')[1].substring(0, 11);
var imageThumb = `https://img.youtube.com/vi/${valid}/hqdefault.jpg`
imageThumb
} else if (url.indexOf(pattern3) != -1 || url.indexOf(pattern4) != -1) {
let valid = url.split('be/')[1].substring(0, 11);
var imageThumb = `https://img.youtube.com/vi/${valid}/hqdefault.jpg`
} else {
imageThumb = ""
// preview.classList.remove('current')
}
form_data.append("title_give", title)
form_data.append("comment_give", comment)
form_data.append("url_give", url)
form_data.append("img_give", imageThumb)
form_data.append("date_give", today)
$.ajax({
type: "POST",
url: "/posting",
data: form_data,
cache: false,
contentType: false,
processData: false,
success: function (response) {
$("#modal-post").removeClass("is-active")
window.location.reload()
}
})
}
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()}일`
}
function get_posts() {
$("#post-box").empty()
$.ajax({
type: "GET",
url: "/get_posts",
data: {},
success: function (response) {
if (response["result"] == "success") {
let posts = response["posts"]
for (let i = 0; i < posts.length; i++) {
let post = posts[i]
let time_post = new Date(post["date"])
let time_before = time2str(time_post)
let html_temp = `<div class="container" id="${post["_id"]}">
<div class="card-image">
<figure class="image is-4by3">
<img src="${post['img']}" alt="Placeholder image">
</figure>
</div>
<div class="card-content">
<div class="media">
<div class="media-left">
<figure class="image is-48x48" href="/user/${post['username']}">
<img src="/static/${post['profile_pic_real']}" alt="Image">
</figure>
</div>
<div class="media-content">
<p class="title is-4">${post['title']}</p>
<p class="subtitle is-6">${post['profile_name']}</p>
</div>
</div>
<div class="content">
${post['comment']}
<br>
<a href="${post['url']}">YOUTUBE</a>
<br>
<time datetime="2016-1-1">${time_before}</time>
</div>
<nav class="level is-mobile">
<div class="level-left">
<a class="level-item is-sparta" aria-label="heart" onclick="toggle_like('${post['_id']}', 'heart')">
<span class="icon is-small"><i class="fa fa-heart"
aria-hidden="true"></i></span> <span class="like-num">2.7k</span>
</a>
</div>
</nav>
</div>
</div>`
$("#post-box").append(html_temp)
}
}
}
})
}
$(document).ready(function () {
get_posts()
})
// 로그아웃은 내가 가지고 있는 토큰만 쿠키에서 없애면 됩니다.
function logout() {
$.removeCookie('mytoken');
alert('로그아웃!')
window.location.href = '/login'
}
</script>
<!-- Favicon -->
<link href="../static/images/favicon.ico" rel="icon">
<!-- Google Web Fonts -->
<link rel="preconnect" href="https://fonts.gstatic.com">
<link href="https://fonts.googleapis.com/css2?family=Poppins:wght@400;500;600;700&display=swap" rel="stylesheet">
<!-- Font Awesome -->
<link href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.10.0/css/all.min.css" rel="stylesheet">
<!-- Libraries Stylesheet -->
<link href="../static/lib/owlcarousel/assets/owl.carousel.min.css" rel="stylesheet">
<link href="../static/lib/tempusdominus/css/tempusdominus-bootstrap-4.min.css" rel="stylesheet"/>
<!-- Customized Bootstrap Stylesheet -->
<link href="../static/css/style2.css" rel="stylesheet">
</head>
<body>
<!-- Topbar Start -->
<div class="container-fluid bg-light pt-3 d-none d-lg-block">
<div class="container">
<div class="row">
<div class="col-lg-6 text-center text-lg-left mb-2 mb-lg-0">
<div class="d-inline-flex align-items-center">
<!--<p><i class="fa fa-envelope mr-2"></i>info@example.com</p>
<p class="text-body px-3">|</p>
<p><i class="fa fa-phone-alt mr-2"></i>+012 345 6789</p> -->
</div>
</div>
<div class="col-lg-6 text-center text-lg-right">
<div class="d-inline-flex align-items-center">
</div>
</div>
</div>
</div>
</div>
<!-- Topbar End -->
<!-- Navbar Start -->
<div class="container-fluid position-relative nav-bar p-0">
<div class="container-lg position-relative p-0 px-lg-3" style="z-index: 9;">
<nav class="navbar navbar-expand-lg bg-light navbar-light shadow-lg py-3 py-lg-0 pl-3 pl-lg-5">
<a href="/"><img src="../static/images/cookpinglogo1.png" alt="로고이미지" width="200px"></a>
<!-- <a href="" class="navbar-brand">
<h1 class="m-0 text-primary">cookping</h1>
</a> -->
<button type="button" class="navbar-toggler" data-toggle="collapse" data-target="#navbarCollapse">
<span class="navbar-toggler-icon"></span>
</button>
<div class="collapse navbar-collapse justify-content-between px-3" id="navbarCollapse">
<div class="navbar-nav ml-auto py-0">
<a href="/" class="nav-item nav-link active">쿡핑레시피</a>
<a href="/about" class="nav-item nav-link">쿡핑이란?</a>
<a href="javascript:logout();" class="nav-item nav-link">로그아웃</a>
</div>
</div>
</nav>
</div>
</div>
<!-- Navbar End -->
<!-- Header Start -->
<div class="container-fluid page-header">
<div class="container">
<div class="d-flex flex-column align-items-center justify-content-center" style="min-height: 400px">
<h3 class="display-4 text-white text-uppercase">Cookping Recipe</h3>
<div class="d-inline-flex text-white">
<p class="m-0 text-uppercase">캠핑요리 레시피를 공유해 보아요</p>
</div>
</div>
</div>
</div>
<!-- Header End -->
<section class="section">
<article class="media">
<figure class="media-left" style="align-self: center">
<a class="image is-32x32" href="/user/{{ user_info.username }}">
<img class="is-rounded" src="{{ url_for('static', filename=user_info.profile_pic_real) }}">
</a>
</figure>
<div class="media-content">
<div class="field">
<p class="control">
<input id="input-post" class="input is-rounded" placeholder="Youtube Link 공유하기"
onclick='$("#modal-post").addClass("is-active")'></p>
</div>
</div>
</article>
<div class="modal" id="modal-post">
<div class="modal-background" onclick='$("#modal-post").removeClass("is-active")'></div>
<div class="modal-content">
<div class="box">
<article class="media">
<div class="media-content">
<div class="field">
<p class="control">
<input class="input is-normal" id="title" type="text"
placeholder="글 제목">
<textarea class="textarea" id="comment" placeholder="코멘트"></textarea>
<input class="input is-normal" id="url" type="text" placeholder="URL">
</p>
</div>
<nav class="level is-mobile">
<div class="level-left">
</div>
<div class="level-right">
<div class="level-item">
<a class="button is-sparta" onclick="post()">작성</a>
</div>
<div class="level-item">
<a class="button is-sparta is-outlined"
onclick='$("#modal-post").removeClass("is-active")'>취소</a>
</div>
</div>
</nav>
</div>
</article>
</div>
</div>
<button class="modal-close is-large" aria-label="close"
onclick='$("#modal-post").removeClass("is-active")'></button>
</div>
</section>
<section class="section">
<div class="container">
<div class="card">
<div class="card-image">
<figure class="image is-4by3">
<img src="https://bulma.io/images/placeholders/1280x960.png" alt="Placeholder image">
</figure>
</div>
<div class="card-content">
<div class="media">
<div class="media-left">
<figure class="image is-48x48">
<img src="https://bulma.io/images/placeholders/96x96.png" alt="Placeholder image">
</figure>
</div>
<div class="media-content">
<p class="title is-4">John Smith</p>
<p class="subtitle is-6">@johnsmith</p>
</div>
</div>
<div class="content">
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Phasellus nec iaculis mauris. <a>@bulmaio</a>.
<a href="#">#css</a> <a href="#">#responsive</a>
<br>
<time datetime="2016-1-1">11:09 PM - 1 Jan 2016</time>
</div>
</div>
</div>
</div>
</section>
<!-- Footer Start -->
<div class="container-fluid bg-dark text-white-50 py-5 px-sm-3 px-lg-5" style="margin-top: 90px;">
<div class="row pt-5">
<div class="col-lg-3 col-md-6 mb-5">
<a href="" class="navbar-brand">
<a href="/"><img src="../static/images\cookpinglogo2.png" alt="로고이미지" width="200px"></a>
</a>
<p>요즘엔 캠핑이 대세!🔥 <br> 캠핑가서 굽는 요리만 하기는 질렸다!😐😐<br>
캠핑, 여행, 펜션가서 할 수 있는 다양한 요리 레시피를 추천하고 공유하는 사이트입니다. 🍽</p>
</div>
<div class="col-lg-3 col-md-6 mb-5">
<h5 class="text-white text-uppercase mb-4" style="letter-spacing: 5px;">Cookping Recipe</h5>
<div class="d-flex flex-column justify-content-start">
<a class="text-white-50 mb-2" href="/"><i class="fa fa-angle-right mr-2"></i>쿡핑레시피</a>
</div>
</div>
<div class="col-lg-3 col-md-6 mb-5">
<h5 class="text-white text-uppercase mb-4" style="letter-spacing: 5px;">About us</h5>
<div class="d-flex flex-column justify-content-start">
<a class="text-white-50 mb-2" href="/about"><i class="fa fa-angle-right mr-2"></i>쿡핑이란?</a>
</div>
</div>
<div class="col-lg-3 col-md-6 mb-5">
<h5 class="text-white text-uppercase mb-4" style="letter-spacing: 5px;">Our Project
Info</h5>
<div class="d-flex flex-column justify-content-start">
<a class="text-white-50 mb-2" href="https://hightechsoon.tistory.com/15"><i
class="fa fa-angle-right mr-2"></i>Starting Assignment</a>
<a class="text-white-50 mb-2" href="https://github.com/Younddo/campinggabojago"><i
class="fa fa-angle-right mr-2"></i>Github</a>
<a class="text-white-50 mb-2" href="https://discord.gg/krQhXcZXmG"><i
class="fa fa-angle-right mr-2"></i>Discord</a>
</div>
</div>
</div>
</div>
<div class="container-fluid bg-dark text-white border-top py-4 px-sm-3 px-md-5"
style="border-color: rgba(256, 256, 256, .1) !important;">
<div class="row">
<div class="col-lg-6 text-center text-md-left mb-3 mb-md-0">
<p class="m-0 text-white-50">Copyright © <a href="#">항해99 9기 11조 풀스택미니프로젝트</a>. All
Rights
Reserved.</a>
</p>
</div>
<div class="col-lg-6 text-center text-md-right">
<p class="m-0 text-white-50">Designed by <a href="https://htmlcodex.com">HTML Codex</a>
</p>
</div>
</div>
</div>
<!-- Footer End -->
<!-- Back to Top -->
<a href="#" class="btn btn-lg btn-primary btn-lg-square back-to-top"><i
class="fa fa-angle-double-up"></i></a>
<!-- JavaScript Libraries -->
<script src="https://code.jquery.com/jquery-3.4.1.min.js"></script>
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/js/bootstrap.bundle.min.js"></script>
<script src="../static/lib/easing/easing.min.js"></script>
<script src="../static/lib/owlcarousel/owl.carousel.min.js"></script>
<script src="../static/lib/tempusdominus/js/moment.min.js"></script>
<script src="../static/lib/tempusdominus/js/moment-timezone.min.js"></script>
<script src="../static/lib/tempusdominus/js/tempusdominus-bootstrap-4.min.js"></script>
<!-- Contact Javascript File -->
<script src="../static/mail/jqBootstrapValidation.min.js"></script>
<script src="../static/mail/contact.js"></script>
<!-- Template Javascript -->
<script src="../static/js/main2.js"></script>
</body>
</html>
2.app.py
from flask import Flask, render_template, jsonify, request, session, redirect, url_for
import jwt
import datetime
from datetime import datetime, timedelta
import hashlib
from werkzeug.utils import secure_filename
from pymongo import MongoClient
import certifi
app = Flask(__name__)
ca = certifi.where()
client = MongoClient('mongodb+srv://test:sparta@cluster0.jetf0d5.mongodb.net/Cluster0?retryWrites=true&w=majority', tlsCAFile=ca)
db = client.dbsparta_cookping
# JWT 토큰을 만들 때 필요한 비밀문자열입니다. 아무거나 입력해도 괜찮습니다.
# 이 문자열은 서버만 알고있기 때문에, 내 서버에서만 토큰을 인코딩(=만들기)/디코딩(=풀기) 할 수 있습니다.
SECRET_KEY = 'SPARTA'
#################################
## HTML을 주는 부분 ##
#################################
@app.route('/')
def home():
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"]})
return render_template('index.html', user_info=user_info)
except jwt.ExpiredSignatureError:
return redirect(url_for("login", msg="로그인 시간이 만료되었습니다."))
except jwt.exceptions.DecodeError:
return redirect(url_for("login", msg="로그인 정보가 존재하지 않습니다."))
@app.route('/login')
def login():
msg = request.args.get("msg")
return render_template('login.html', msg=msg)
@app.route('/about')
def about():
msg = request.args.get("msg")
return render_template('about.html', msg=msg)
@app.route('/user/<username>')
def user(username):
# 각 사용자의 프로필과 글을 모아볼 수 있는 공간
token_receive = request.cookies.get('mytoken')
try:
payload = jwt.decode(token_receive, SECRET_KEY, algorithms=['HS256'])
status = (username == payload["id"]) # 내 프로필이면 True, 다른 사람 프로필 페이지면 False
user_info = db.users.find_one({"username": username}, {"_id": False})
return render_template('user.html', user_info=user_info, status=status)
except (jwt.ExpiredSignatureError, jwt.exceptions.DecodeError):
return redirect(url_for("home"))
@app.route('/sign_in', methods=['POST'])
def sign_in():
# 로그인
username_receive = request.form['username_give']
password_receive = request.form['password_give']
pw_hash = hashlib.sha256(password_receive.encode('utf-8')).hexdigest()
result = db.users.find_one({'username': username_receive, 'password': pw_hash})
if result is not None:
payload = {
'id': username_receive,
'exp': datetime.utcnow() + timedelta(seconds=60) # 로그인 60s유지
}
token = jwt.encode(payload, SECRET_KEY, algorithm='HS256')
return jsonify({'result': 'success', 'token': token})
# 찾지 못하면
else:
return jsonify({'result': 'fail', 'msg': '아이디/비밀번호가 일치하지 않습니다.'})
@app.route('/sign_up/save', methods=['POST'])
def sign_up():
username_receive = request.form['username_give']
password_receive = request.form['password_give']
password_hash = hashlib.sha256(password_receive.encode('utf-8')).hexdigest()
doc = {
"username": username_receive, # 아이디
"password": password_hash, # 비밀번호
"profile_name": username_receive, # 프로필 이름 기본값은 아이디
"profile_pic": "", # 프로필 사진 파일 이름
"profile_pic_real": "profile_pics/profile_placeholder.png", # 프로필 사진 기본 이미지
"profile_info": "" # 프로필 한 마디
}
db.users.insert_one(doc)
return jsonify({'result': 'success'})
@app.route('/sign_up/check_dup', methods=['POST'])
def check_dup():
username_receive = request.form['username_give']
exists = bool(db.users.find_one({"username": username_receive}))
return jsonify({'result': 'success', 'exists': exists})
@app.route('/update_profile', methods=['POST'])
def save_img():
token_receive = request.cookies.get('mytoken')
try:
payload = jwt.decode(token_receive, SECRET_KEY, algorithms=['HS256'])
# 프로필 업데이트
return jsonify({"result": "success", 'msg': '프로필을 업데이트했습니다.'})
except (jwt.ExpiredSignatureError, jwt.exceptions.DecodeError):
return redirect(url_for("home"))
@app.route('/posting', methods=['POST'])
def posting():
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"]})
# file = request.files["file_give"]
# extension = file.filename.split('.')[1]
#
# today = datetime.now()
# mytime = today.strftime('%Y-%m-%d-%H-%M-%S')
#
# filename = f'file-{mytime}'
# save_to = f'static/{filename}.{extension}'
# file.save(save_to)
title_receive = request.form["title_give"]
comment_receive = request.form["comment_give"]
url_receive = request.form["url_give"]
img_receive = request.form["img_give"]
date_receive = request.form["date_give"]
doc = {
"username": user_info["username"],
"profile_name": user_info["profile_name"],
"profile_pic_real": user_info["profile_pic_real"],
"title":title_receive,
"comment": comment_receive,
"url":url_receive,
"img":img_receive,
"date": date_receive
}
db.posts.insert_one(doc)
return jsonify({"result": "success", 'msg': '포스팅 성공'})
except (jwt.ExpiredSignatureError, jwt.exceptions.DecodeError):
return redirect(url_for("home"))
@app.route("/get_posts", methods=['GET'])
def get_posts():
token_receive = request.cookies.get('mytoken')
try:
payload = jwt.decode(token_receive, SECRET_KEY, algorithms=['HS256'])
posts = list(db.posts.find({}).sort("date", -1).limit(20))
for post in posts:
post["_id"] = str(post["_id"])
return jsonify({"result": "success", "msg": "포스팅을 가져왔습니다.","posts":posts})
except (jwt.ExpiredSignatureError, jwt.exceptions.DecodeError):
return redirect(url_for("home"))
@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'])
# 좋아요 수 변경
return jsonify({"result": "success", 'msg': 'updated'})
except (jwt.ExpiredSignatureError, jwt.exceptions.DecodeError):
return redirect(url_for("home"))
if __name__ == '__main__':
app.run('0.0.0.0', port=5000, debug=True)
