항해99 - 1주차 WIL
🤷 WIL 이란?
항해99를 하면서 처음으로 알게 된 것 중 하나입니다 ! Weekly I Learned의 약자로 일주일동안 내가 배우고 느낀걸 정리하고 회고하는 것입니다. 모르는 것도 많고 용어를 잘 못 알고 있는것도 많겠지만😂 저도.. 오늘부터 매주 열심히 써보려구요😁
미니 프로젝트에서 내가 배운것
4일동안 팀프로젝트로 만든 뿌듯하면서도 아쉬웠던 우리 항해99 2기 미니 프로젝트 오늘도 돼지런🐷
!! 이 미니프로젝트에서 내가 맡은 부분과 그걸 하면서 배운점을 정리해볼까 합니다!
오늘도 돼지런 구경하기!
github은 어메이징 정리꾼 우리팀장님 repository로!
📝 회원가입 기능
📌 내가 생각하는 특징적인 Point
항해99강의
를 정말 100% 활용했습니다!!!- 사용자가 입력한 정보는
ajax의 POST
형식으로 server에 전달해주고, server에서 받은 정보를 DB에 저장했습니다 - client 쪽은 ajax 사용을 위해
vanila JS
와Jquery
를 같이 사용했고 server 쪽은python
을 이용했습니다 - DB는
MongoDB
를 사용했습니다
📌 코드 부분
1. 회원가입 정보 입력하고 회원가입 버튼 누를 때
-
app.py
client에서 받아온 입력을
db.users.insert_one(doc)
을 통해doc={}
에서 정의하고 있는 형식으로 database에 저장해준다
@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()
nickname_receive = request.form['nickname_give']
doc = {
"username": username_receive, # 아이디
"nickname": nickname_receive, # 닉네임
"password": password_hash # 비밀번호
}
db.users.insert_one(doc)
return jsonify({'result': '돼지런 스타트!!'})
-
signup.js
client가 입력한 username, password, nickname을
ajax POST
방식으로 보내주고 성공하면 server에서 보내준result내용('돼지런 스타트!!')
을 alert창에 띄워줍니다!
$.ajax({
type: "POST",
url: "/sign_up/save",
data: {
username_give: username,
password_give: password,
nickname_give: nickname,
},
success: function (response) {
alert(response["result"]);
window.location.replace("/login");
},
});
2. ID 중복 확인 부분
-
app.py
client에서 받아온 입력을
db.users.find_one({"username": username_receive})
을bool
함수에 넣어서 중복되는 ID가 있으면True
없으면False
를exists
에 담아서 client단으로 보내줍니다!
@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})
-
signup.js
client에선 server로 부터 받은
exist
가True
이면이미 존재하는 아이디 입니다
,False
면사용할 수 있는 아이디 입니다
를 입력창 아래 안내 메세지로 띄어줍니다.
$.ajax({
type: "POST",
url: "/sign_up/check_dup",
data: {
username_give: username,
},
success: function (response) {
if (response["exists"]) {
helpId.innerText = "이미 존재하는 아이디입니다.";
helpId.classList.remove("is-safe");
helpId.classList.add("is-danger");
inputId.focus();
} else {
helpId.innerText = "사용할 수 있는 아이디입니다.";
helpId.classList.remove("is-danger");
helpId.classList.add("is-success");
}
helpId.classList.remove("is-loading");
},
});
3. ID와 비밀번호가 조건을 정의해주는 정규 표현식!
-
signup.js
사용자의 입력을
asValue
로 넣어주고 이 조건과 맞지 않으면 입력창 아래 경고 메세지를 띄우는 함수를 구현합니다!
const is_nickname = (asValue) => {
var regExp = /^(?=.*[a-zA-Z])[-a-zA-Z0-9_.]{2,10}$/;
return regExp.test(asValue);
};
const is_password = (asValue) => {
var regExp = /^(?=.*\d)(?=.*[a-zA-Z])[0-9a-zA-Z!@#$%^&*]{8,20}$/;
return regExp.test(asValue);
};
📌 회원가입 기능을 구현하면서 느낀점
-
프론트엔드만 담당하지 않고 server쪽 코드도 강의를 보면서 바로 바로 따라 만들어 봤는데, server와 client가 data를 어떻게 주고 받고 회원가입의 전체 적인 틀을 이해할 수 있어서 좋았습니다!
-
많은 활용은 아니었지만 강의내용을 참고 해서 아주 약간의 응용으로 nickname 입력값을 받고 입력하지 않은 상태로 회원가입 버튼을 누르면 id와 password 처럼 입력창 하단에 경고 메세지를 띄우도록 구현해보았습니다. 정말 일부분이지만 강의와 약간 다르게 해서 뿌듯(😂)했습니다.
📌 다음에 추가해보고 싶은 기능 & 아쉬운점
-
강의에서 들은 정규 표현식을 그대로 사용했는데 좀 더 내가 원하는 조건을 추가해서 새로운 식을 만들고 아이디와 비밀번호에 적용해 보고싶습니다.
-
회원가입 버튼을 눌려야 경고 메세지들이 뜨는데 입력후 다른 입력창으로 넘어갈때 (ex: 아이디를 입력하고 비밀번호를 입력하기 위해 비밀번호 입력창을 클릭할 때) 바로 경고메세지가 뜨도록 구현해보고 싶습니다.
💖 좋아요 기능
📌 내가 생각하는 특징적인 Point
항해99강의
를 정말 100% 활용했습니다!!!- 로그인 후에 좋아요 하트가 보이고 좋아요 버튼을 눌릴 수 있습니다.
- 종아요 기능을 구현하기 위해 체크해야 할 사항은
작성된 포스팅의 고유 id
,그 고유 id와 일치하는 포스팅이 몇개의 type:heart로 DB에 저장되어 있는지
,그 포스팅을 좋아요한 사용자 정보(username)
- main 페이지에 포스팅 카드를 구현할 때
jinja
를 사용합니다
📌 코드 부분
1. 로그인하면 main화면에 포스팅과 함께 ❤ 보여주기
-
app.py
1) client가 작성한 포스팅(코드에서는 diary) 각각에서, 그 포스팅의 id
diary["_id"] = str(diary["_id"])
와2) 그 포스팅 id와 일치하는 포스팅이 몇개의
type:heart
로 DB에 저장되어 있는지(diary["count_heart"] = db.likes.count_documents({"diary_id": diary["_id"], "type": "heart"})
) 확인하고3) 그 포스팅을 좋아요한 사용자 정보(username)
diary["heart_by_me"] = bool(db.likes.find_one({"diary_id": diary["_id"], "type": "heart", "username": payload['id']}))
확인한뒤4) 최종적으로 client에서
jinja
를 사용하기 위해data
에diaries
를 할당해서 보내줍니다!
@app.route('/')
def main():
token_receive = request.cookies.get('mytoken')
if token_receive:
try:
payload = jwt.decode(token_receive, SECRET_KEY, algorithms=['HS256'])
user_info = db.users.find_one({"username": payload["id"]})
diaries = list(db.articles.find({}))
for diary in diaries:
diary["_id"] = str(diary["_id"])
diary["count_heart"] = db.likes.count_documents({"diary_id": diary["_id"], "type": "heart"})
diary["heart_by_me"] = bool(db.likes.find_one({"diary_id": diary["_id"], "type": "heart", "username": payload['id']}))
diaries = reversed(diaries)
return render_template("index.html", data = diaries, user_info = user_info)
except (jwt.ExpiredSignatureError, jwt.exceptions.DecodeError):
return render_template("index.html")
else:
diaries = list(db.articles.find({}, {'_id': False}))
diaries = reversed(diaries)
return render_template("index.html", data = diaries)
-
index.html 에서 javascript부분
data로 받은 diaries각각을 diary라고 하고 그 diary 에서의 정보들
title
,place
,content
,date
을 보여주고,로그인 정보가 있을 때만
좋아요 기능을 보이게 구현합니다!
{% for diary in data %}
<div class="card" id="{{ diary._id }}">
<img class="card-img-top" src="../static/articleIMGs/{{ diary.img }}" alt="No images">
<div class="card-body">
<h5 class="card-title">{{diary.title}}</h5>
<h6 class="card-subtitle mb-2 text-muted">{{diary.place}}</h6>
<p class="card-text">{{diary.content}}</p>
<p class="date-time">{{diary.date}}</p>
{% if user_info %}
<nav class="level is-mobile">
<div class="level-left">
<a class="level-item is-sparta" aria-label="heart"
onclick="toggle_like('{{diary._id}}', 'heart')">
<span class="icon is-small">
{% if diary.heart_by_me %}
<i class="fa fa-heart" aria-hidden="true"></i>
{% else %}
<i class="fa fa-heart-o" aria-hidden="true"></i>
{% endif %}
</span>
<span class="like-num">{{diary.count_heart}}</span>
</a>
</div>
<button class="btn del" onclick="deletePage(`{{ diary._id }}`)">delete</button>
</nav>
{% endif %}
</div>
</div>
{% endfor %}
2. 좋아요 상태 업데이트 해주기
-
app.py
client에서 좋아요 버튼을 클릭했을 때
action_receive = request.form["action_give"]
그게 like인지 아닌지 체크해서 like면 DB에 추가하고 아니면 이미 like되어 있는 그 포스팅을 DB에서 삭제 합니다. 그 후에 업데이트 된 좋아요 수를 client로 보내줍니다!"count": count
@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"]})
diary_id_receive = request.form["diary_id_give"]
type_receive = request.form["type_give"]
action_receive = request.form["action_give"]
doc = {
"diary_id": diary_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({"diary_id": diary_id_receive, "type": "heart"})
return jsonify({"result": "success", 'msg': 'updated', "count": count})
except (jwt.ExpiredSignatureError, jwt.exceptions.DecodeError):
return render_template("index.html")
-
index.html 에서 javascript부분
ajax POST
형식으로 사용자의 action에 대한 정보 (diary_id
,type
,unlike or like
)를 보내주고 server에게 전송을 완료하면 🖤를 보여줄지 🤍를 보여줄지 결정하고 update된 좋아요 수를 표현해줍니다!
function toggle_like(diary_id, type) {
console.log(diary_id, type)
let $a_like = $(`#${diary_id} a[aria-label='heart']`)
let $i_like = $a_like.find("i")
console.log($i_like)
if ($i_like.hasClass("fa-heart")) {
$.ajax({
type: "POST",
url: "/update_like",
data: {
diary_id_give: diary_id,
type_give: type,
action_give: "unlike"
},
success: function (response) {
console.log("unlike")
$i_like.addClass("fa-heart-o").removeClass("fa-heart")
$a_like.find("span.like-num").text(response["count"])
}
})
} else {
$.ajax({
type: "POST",
url: "/update_like",
data: {
diary_id_give: diary_id,
type_give: type,
action_give: "like"
},
success: function (response) {
console.log("like")
$i_like.addClass("fa-heart").removeClass("fa-heart-o")
$a_like.find("span.like-num").text(response["count"])
}
})
}
}
📌 좋아요 기능을 구현하면서 느낀점
- 너무 어려웠습니다😂 다음에 다른데서 구현할 때 다시한번 이해해야 할것 같아요!
jinja
를 사용해서 어려웠지만 새로웠습니다. 처음에는 javascript로 구현했다가 변경하는 과정이 많이 헷갈렸지만 팀원 분과 함께 해서 완성할 수 있었습니다!!
📌 다음에 추가해보고 싶은 기능 & 아쉬운점
- 로그인은 안해도 좋아요 상태가 어떤지는 보여주고 좋아요 버튼을 눌렸을 때, "로그인 해주세요" 라는 경고창을 띄운 뒤 바로 로그인 페이지로 넘어가는 기능을 구현해 보고 싶습니다!!
- 얼른 리액트를 배워서 이 기능을 구현해 보고 싶습니당...
✨ Main 화면 Styling (CSS)
📌 FadeUp animation
.introduce {
width: 100%;
height: 80vh;
padding: 20px 40px;
display: flex;
align-items: center;
margin: 100px 0
}
.animate {
animation-duration: 1s;
animation-fill-mode: both;
}
.fadeUp-left {
animation-name: fadeUp-left;
}
@keyframes fadeUp-left {
from {
opacity: 0;
transform: translate3d(0, 100%, 0);
}
to {
opacity: 1;
transform: rotate(-10deg);
}
}
.fadeUp-right {
animation-name: fadeUp-right;
}
@keyframes fadeUp-right {
from {
opacity: 0;
transform: translate3d(0, 100%, 0);
}
to {
opacity: 1;
transform: rotate(10deg);
}
}
📌 Scroll Down
css로 애니메이션만 추가한거여서 버튼 눌렸을 때 자동으로 scroll down하는 기능도 추가하고 싶습니다!!
.scroll {
position: absolute;
top: 80%;
left: 50%;
height: 80px;
color: #cb9ca1;
}
.scroll_arrow {
position: absolute;
top: 85%;
left: 50%;
transform: translate(-50%, -50%);
}
.scroll_arrow span {
display: block;
width: 40px;
height: 40px;
border-radius: 2px;
border-bottom: 3px solid #cb9ca1;
border-right: 3px solid #cb9ca1;
transform: rotate(45deg);
margin: -10px;
animation: animate 2s infinite;
}
.scroll_arrow span:nth-child(1) {
animation-delay: -0.2s;
}
.scroll_arrow span:nth-child(2) {
animation-delay: -0.4s;
}
@keyframes animate {
0%
{
opacity: 0;
transform: rotate(45deg) translate(-20px, -20px);
}
50%
{
opacity: 1;
}
100%
{
opacity: 0;
transform: rotate(45deg) translate(20px, 20px);
}
}
🤔 미니 프로젝트 이후 느낀 점
처음에는 정말 어떻게 4일만에 사이트를 만들어ㅜㅜ
하면서 걱정과 불안이 가득했습니다. 그런데 정말로 팀원들이 괜찮다고 어떻게든 된다고 너무 조급해 하지 않아도 된다는 말이 정말 큰 위로가 됬습니다. 35조 감사해요😂😂
그리고 혼자서 공부하고 혼자서 프로젝트를 만들 때는 생각해보지 못했던 git과 github사용, 프로젝트 전 layout 짜고, api를 미리 정하는 부분 등 다양한 경험을 할 수 있었습니다 . 아 이래서... 팀 프로젝트를 해봐야 하는구나
하고 정말 많이 느꼈습니다!!
Author And Source
이 문제에 관하여(항해99 - 1주차 WIL), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://velog.io/@wjdalswn0530/항해99-1주차-WIL저자 귀속: 원작자 정보가 원작자 URL에 포함되어 있으며 저작권은 원작자 소유입니다.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)