아이콘 클래스의 사소한 오타로 조금 헤맴.
웹 페이지 만들기란 여러모로 진짜 손 많이 가고 골치 아픈 것이었다...
html 파일들은 제외하고 .py, .js만 올려둠.
from pymongo import MongoClient
import jwt
import datetime
import hashlib
from flask import Flask, render_template, jsonify, request, redirect, url_for
from werkzeug.utils import secure_filename
from datetime import datetime, timedelta
app = Flask(__name__)
app.config["TEMPLATES_AUTO_RELOAD"] = True
app.config['UPLOAD_FOLDER'] = "./static/profile_pics"
SECRET_KEY = 'SPARTA'
client = MongoClient('mongodb://3.35.8.148', 27017, username="test", password="test")
db = client.dbsparta_plus_week4
@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('/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 * 60 * 24) # 로그인 24시간 유지
}
token = jwt.encode(payload, SECRET_KEY, algorithm='HS256').decode('utf-8')
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'])
username = payload["id"]
name_receive = request.form["name_give"]
about_receive = request.form["about_give"]
new_doc = {
"profile_name": name_receive,
"profile_info": about_receive
}
if 'file_give' in request.files:
file = request.files["file_give"]
filename = secure_filename(file.filename)
extension = filename.split(".")[-1]
file_path = f"profile_pics/{username}.{extension}"
file.save("./static/"+file_path)
new_doc["profile_pic"] = filename
new_doc["profile_pic_real"] = file_path
db.users.update_one({'username': payload['id']}, {'$set':new_doc})
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"]})
comment_receive = request.form["comment_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"],
"comment": comment_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'])
# 포스팅 목록 받아오기
username_receive = request.args.get("username_give")
if username_receive == "":
posts = list(db.posts.find({}).sort("date", -1).limit(20))
else:
posts = list(db.posts.find({"username": username_receive}).sort("date", -1).limit(20))
for post in posts:
post["_id"] = str(post["_id"])
post["count_heart"] = db.likes.count_documents({"post_id": post["_id"], "type": "heart"})
post["heart_by_me"] = bool(db.likes.find_one({"post_id": post["_id"], "type": "heart", "username": payload["id"]}))
post["count_star"] = db.likes.count_documents({"post_id": post["_id"], "type": "star"})
post["star_by_me"] = bool(db.likes.find_one({"post_id": post["_id"], "type": "star", "username": payload["id"]}))
post["count_like"] = db.likes.count_documents({"post_id": post["_id"], "type": "like"})
post["like_by_me"] = bool(db.likes.find_one({"post_id": post["_id"], "type": "like", "username": payload["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'])
# 좋아요 수 변경
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)
count = db.likes.count_documents({"post_id": post_id_receive, "type": type_receive})
return jsonify({"result": "success", 'msg': 'updated', "count": count})
except (jwt.ExpiredSignatureError, jwt.exceptions.DecodeError):
return redirect(url_for("home"))
if __name__ == '__main__':
app.run('0.0.0.0', port=5000, debug=True)
function get_posts(username) {
if (username == undefined) {
username = ""
}
$("#post-box").empty()
$.ajax({
type: "GET",
url: `/get_posts?username_give=${username}`,
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 class_heart = post['heart_by_me'] ? "fa-heart" : "fa-heart-o"
let class_star = post['star_by_me'] ? "fa-star" : "fa-star-o"
let class_like = post['like_by_me'] ? "fa-thumbs-up" : "fa-thumbs-o-up"
let count_heart = num2str(post['count_heart'])
let count_star = num2str(post['count_star'])
let count_like = num2str(post['count_like'])
let html_temp = `<div class="box" id="${post["_id"]}">
<article class="media">
<div class="media-left">
<a class="image is-64x64" href="/user/${post['username']}">
<img class="is-rounded" src="/static/${post['profile_pic_real']}"
alt="Image">
</a>
</div>
<div class="media-content">
<div class="content">
<p>
<strong>${post['profile_name']}</strong> <small>@${post['username']}</small> <small>${time_before}</small>
<br>
${post['comment']}
</p>
</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 ${class_heart}"
aria-hidden="true"></i></span> <span class="like-num">${count_heart}</span>
</a>
<a class="level-item is-sparta" aria-label="star" onclick="toggle_like('${post['_id']}', 'star')">
<span class="icon is-small"><i class="fa ${class_star}"
aria-hidden="true"></i></span> <span class="star-num">${count_star}</span>
</a>
<a class="level-item is-sparta" aria-label="like" onclick="toggle_like('${post['_id']}', 'like')">
<span class="icon is-small"><i class="fa ${class_like}"
aria-hidden="true"></i></span> <span class="like-num">${count_like}</span>
</a>
</div>
</nav>
</div>
</article>
</div>`
$("#post-box").append(html_temp)
}
}
}
})
}
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 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
}
function post() {
let comment = $("#textarea-post").val()
let today = new Date().toISOString()
$.ajax({
type: "POST",
url: "/posting",
data: {
comment_give: comment,
date_give: today
},
success: function (response) {
$("#modal-post").removeClass("is-active")
window.location.reload()
}
})
}
function toggle_like(post_id, type) {
console.log(post_id, type)
let $a_like = $(`#${post_id} a[aria-label='${type}']`)
let $i_like = $a_like.find("i")
let class_s = {"heart": "fa-heart", "star": "fa-star", "like": "fa-thumbs-up"}
let class_o = {"heart": "fa-heart-o", "star": "fa-star-o", "like": "fa-thumbs-o-up"}
if ($i_like.hasClass(class_s[type])) {
$.ajax({
type: "POST",
url: "/update_like",
data: {
post_id_give: post_id,
type_give: type,
action_give: "unlike"
},
success: function (response) {
console.log("unlike")
$i_like.addClass(class_o[type]).removeClass(class_s[type])
$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) {
console.log("like")
$i_like.addClass(class_s[type]).removeClass(class_o[type])
$a_like.find("span.like-num").text(num2str(response["count"]))
}
})
}
}
function sign_out() {
$.removeCookie('mytoken', {path: '/'});
alert('로그아웃!')
window.location.href = "/login"
}
function update_profile() {
let name = $('#input-name').val()
let file = $('#input-pic')[0].files[0]
let about = $("#textarea-about").val()
let form_data = new FormData()
form_data.append("file_give", file)
form_data.append("name_give", name)
form_data.append("about_give", about)
console.log(name, file, about, form_data)
$.ajax({
type: "POST",
url: "/update_profile",
data: form_data,
cache: false,
contentType: false,
processData: false,
success: function (response) {
if (response["result"] == "success") {
alert(response["msg"])
window.location.reload()
}
}
});
}