본문 바로가기

내일 배움 캠프/소개위드미

소개위드미 ver.2

728x90

업데이트 내용

 

바뀐 기능

- 삭제하기 버튼 클릭 시 바로 삭제된다

- 수정하기 버튼 클릭 시 모달이 열리고 닉네임값은 받아오지 않는다.

 

새로운 기능

- 방명록에 작성 시간 표시

- 방명록 수정 시 작성 시간이 업데이트 됨

 

 

app.py

from flask import Flask, render_template, request, jsonify
app = Flask(__name__)

from pymongo import MongoClient
import certifi

from datetime import datetime, timezone, timedelta


ca = certifi.where()

client = MongoClient('mongodb+srv://sparta:test@cluster0.0uiki8z.mongodb.net/?retryWrites=true&w=majority', tlsCAFile=ca)
db = client.dbsparta


# localhost:5000을 입력하면 index.html 이 나오게 해라
# @app.route('/') = localhost:5000
@app.route('/')
def home():
    return render_template('index.html')

# POST 방식 : 받은 nickname_give comment_give 로 방명록 저장하기
# nowtime 변수를 지정하여 time 역시 저장한다.
@app.route('/comments', methods=["POST"])
def comments_post():
    nickname_receive = request.form['nickname_give']
    comment_receive = request.form['comment_give']
    kst = timezone(timedelta(hours=9))
    nowtime = str(datetime.now(tz=kst))
    doc = {
        'nickname':nickname_receive,
        'comment':comment_receive,
        'time':nowtime
        }
    


    db.comments.insert_one(doc)

    return jsonify({'msg': '방명록 저장 완료!'})
# jsonify : 사용자가 json data를 내보내도록 제공하는 flask의 함수.

# GET 방식 : 방명록 불러오기
@app.route('/comments', methods=['GET'])
def comments_get():
   all_comments = list(db.comments.find({},{'_id':False}))
   return jsonify({'result':all_comments})

# DELETE 방식 : 입력한 닉네임 값에 해당하는 방명록을 삭제합니다.
@app.route('/comments', methods=['DELETE'])
def comments_del():
   delnickname_receive = request.form['delnickname_give']
   db.comments.delete_one({'nickname': delnickname_receive})
   return jsonify({'msg': '방명록 삭제 완료!'})

# PUT 방식 : 입력한 닉네임값에 해당하는 방명록의 내용을 editcomment_give 로 받아서 수정합니다.
@app.route('/comments', methods=['PUT'])
def comments_put():
    editnickname_receive = request.form['editnickname_give']
    editcomment_receive = request.form['editcomment_give']
    kst = timezone(timedelta(hours=9))
    nowtime = str(datetime.now(tz=kst))
    db.comments.update_one({'nickname':editnickname_receive},{'$set':{'comment':editcomment_receive}})
    db.comments.update_one({'nickname':editnickname_receive},{'$set':{'time':nowtime}})
    return jsonify({'msg': '방명록 수정 완료!'})

if __name__ == '__main__':
    app.run('0.0.0.0', port=5000, debug=True)
    # debug=True 디버깅 모드 실행

 

index.html

<!doctype html>
<html lang="en">

<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">

  <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/css/bootstrap.min.css" rel="stylesheet"
    integrity="sha384-EVSTQN3/azprG1Anm3QDgpJLIm9Nao0Yz1ztcQTwFspd3yD65VohhpuuCOmLASjC" crossorigin="anonymous">
  <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
  <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/js/bootstrap.bundle.min.js"
    integrity="sha384-MrcW6ZMFYlzcLA8Nl+NtUVF0sA7MsXsP1UyJoMp4YLEuNSfAP+JcXn/tWtIaxVXM"
    crossorigin="anonymous"></script>

  <title>소개위드미</title>
  <link href="https://fonts.googleapis.com/css2?family=Gowun+Dodum&display=swap" rel="stylesheet">

  <!-- CSS -->

  <style>
    * {
      font-family: 'Gowun Dodum', sans-serif;
    }


    .title {
      display: flex;
      flex-direction: column;
      align-items: center;
      justify-content: center;
      margin-bottom: 40px;

    }

    .title>h1 {


      margin: 0px;
      padding: 0px;
      font-size: 80px;
      font-weight: bold;
      font-style: italic;
      margin-bottom: 8px;
    }

    .subtitle {
      color: gray
    }

    .title2>img {
      border-radius: 5px;
      width: 600px;
      height: 400px;
      margin: 20px 20px 20px 20px;

    }

    .title2 {
      margin: 0px 20px 20px 20px;
      display: flex;
      flex-direction: row;
      align-items: center;
      justify-content: center;

    }

    .desc {
      display: flex;
      align-items: center;
      font-size: 21px;
      margin-bottom: 60px;
    }

    .teamphoto {
      border-radius: 20px;
    }

    .ptitle {
      margin: 0px;
      padding: 0px;
      font-size: 30px;
      color: #2aad3c;
      font-weight: 400;
      margin-bottom: 16px;
      padding-bottom: 5px;
    }

    .ptitle2 {
      margin: 0px;
      padding: 0px;
      font-size: 20px;
      color: #2aad3c;
      font-weight: 400;
      margin-bottom: 16px;
      padding-bottom: 5px;
    }

    .paragraph {
      color: gray;
      font-size: 17px;
    }

    .desc img {
      width: 450px;
      margin-right: 30px;

    }

    .mycards {
      margin: 20px auto 0px auto;
      width: 1000px;
      max-width: 1500px;
    }

    .col {
      padding: 0px 10px 0px 0px;

    }

    .comment-list {
      margin: 20px auto 20px auto;
    }

    /* 아래로는 코멘트 박스 */
    .comment-box {
      width: 500px;
      flex-direction: column;
      align-items: center;
      justify-content: center;
      margin: 20px auto 0px auto;
    }

    .comment-box>h2 {
      text-align: center;
      font-size: 25px;
      font-weight: 300;
      color: #222;
      letter-spacing: 1px;
      text-transform: uppercase;
      margin-top: 60px;

      display: grid;
      grid-template-columns: 1fr max-content 1fr;
      grid-template-rows: 27px 0;
      grid-gap: 20px;
      align-items: center;
    }

    .comment-box>h2:after,
    .comment-box>h2:before {
      content: " ";
      display: block;
      border-bottom: 1px solid #2aad3c;
      border-top: 1px solid #2aad3c;
      height: 5px;
      background-color: #f8f8f8;
    }

    .reple {
      border-radius: 10px;
    }
  </style>
  <script>
    // 페이지를 열면 show_comment() 함수가 실행됩니다. 방명록 리스트가 나옵니다. 
    $(document).ready(function () {
      show_comment();
    });
    // POST 방식 : nickname_give, comment_give 에 방명록을 작성하기 위한 닉네임, 내용을 담아 보냅니다. 
    function save_comment() {
      let nickname = $('#nickname').val()
      let comment = $('#comment').val()


      let formData = new FormData();
      formData.append("nickname_give", nickname);
      formData.append("comment_give", comment);

      fetch('/comments', { method: "POST", body: formData }).then((res) => res.json()).then((data) => {
        alert(data["msg"]);
        window.location.reload()
      });
    }

    // GET 방식 : DB에 저장되어 있는 정보들을 가져옵니다.
    function show_comment() {
      fetch('/comments').then((res) => res.json()).then((data) => {
        let rows = data['result']
        rows.forEach((a) => {
          let nickname = a['nickname']
          let comment = a['comment']
          let date = a['time'].substr(0, 19)


          // temp_html 안에 모달을 넣어 수정 버튼을 누르면 입력 창이 뜨게 합니다.
          // 삭제하기 버튼을 누르면 바로 del_comment('${nickname}') 과 이어져 삭제되게 합니다.
          let temp_html = `<div class="card">
                                    <div class="card-body">
                                        <blockquote class="blockquote mb-0" id="blockquote">
                                            <p>${comment}</p>
                                            <p><small class="text-muted">작성자 : ${nickname}<br>작성 시간 : ${date}</small></p>
                                            <button type="button" class="btn btn-dark" onclick="del_comment('${nickname}')">삭제하기</button>
                                            <button type="button" class="btn btn-dark" data-bs-toggle="modal" data-bs-target="#exampleModal" data-bs-whatever="@getbootstrap">수정하기</button>
                                            <div class="modal fade" id="exampleModal" tabindex="-1" aria-labelledby="exampleModalLabel" aria-hidden="true">
                                            <div class="modal-dialog">
                                                <div class="modal-content">
                                                <div class="modal-header">
                                                    <h5 class="modal-title" id="exampleModalLabel">방명록 수정하기</h5>
                                                    <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
                                                </div>
                                                <div class="modal-body">
                                                    <form>
                                                   
                                                    <div class="mb-3">
                                                       
                                                        <label for="recipient-name" class="col-form-label" >수정할 방명록 내용</label>
                                                        <textarea class="form-control" id="editcomment"></textarea>
                                                
                                                    
                                                        </div>
                                                    </form>
                                                </div>
                                                <div class="modal-footer">
                                                    <button type="button" class="btn btn-secondary" data-bs-dismiss="modal">닫기</button>
                                                    <button type="button" class="btn btn-primary" onclick="edit_comment('${nickname}')">수정하기</button>
                                                </div>
                                                </div>
                                            </div>
                                            </div>
                                            `

          $('#comment-list').append(temp_html)
        });

      })

    }
    var exampleModal = document.getElementById('exampleModal')
    exampleModal.addEventListener('show.bs.modal', function (event) {
      // Button that triggered the modal
      var button = event.relatedTarget
      // Extract info from data-bs-* attributes
      var recipient = button.getAttribute('data-bs-whatever')
      // If necessary, you could initiate an AJAX request here
      // and then do the updating in a callback.
      //
      // Update the modal's content.
      var modalTitle = exampleModal.querySelector('.modal-title')
      var modalBodyInput = exampleModal.querySelector('.modal-body input')

      modalTitle.textContent = 'New message to ' + recipient
      modalBodyInput.value = recipient
    })


    // DELETE 방식 : 입력한 삭제할 닉네임 값을 delnickname_give에 담아 보냅니다.

    function del_comment(nickname) {
      let formData = new FormData();
      formData.append("delnickname_give", nickname);

      fetch('/comments', { method: "DELETE", body: formData }).then((res) => res.json()).then((data) => {

        alert(data["msg"]);
        window.location.reload()
      });
    }
    // PUT 방식 : 입력한 수정할 방명록의 닉네임값 editnickname_give 와 수정할 내용을 editcomment_give 에 담아 보냅니다.
    function edit_comment(nickname) {
      let editcomment = $('#editcomment').val()
      let formData = new FormData()
      formData.append("editnickname_give", nickname)
      formData.append("editcomment_give", editcomment)
      fetch("/comments", { method: "PUT", body: formData }).then(res => res.json()).then(data => {
        alert(data["msg"])
        window.location.reload()
      })
    }
  </script>

</head>

<body>

  <div class="title">
    <h1>소개 with me</h1>
    <p class="subtitle">Node.js A반 2조</p>
  </div>
  <div class="title2" id="title2">
    <div class="desc" id="desc">
      <img class="teamphoto" src="https://i.postimg.cc/PqKgCJbd/allteam.png" />
      <div class="descp" id="descp">
        <p class="ptitle">Team. 코딩위드미</p>
        <p class="paragraph">
          팀 소개 : 개발자가 되고 싶은 5명이 함께 협업을 배워나가요!<br>
          팀 목표 : 프로젝트 완성! <br>
          팀 약속 : 13:00 ~ 14:00 점심 시간 / 18:00 ~ 19:00 저녁 시간 <br>
        </p>
        <p class="ptitle2"> 팀 규칙 ! </p>
        <p class="paragraph">
          다영: 피드백을 요청하면 y/n에 관계없이 확실하게 답변을 준다. <br>
          상우: 누구 한명이라도 모르는 것이 있으면 짚고 넘어간다. <br>
          승현: 모르는 내용이 있다면 제일 먼저 검색해 본다. <br>
          성원: 정보 공유를 잘한다. <br>
          혜민: 모르는 게 있으면 물어보기.
        </p>
      </div>
    </div>
  </div>

  <!-- 멤버 카드 -->
  <div class="mycards">
    <div class="row row-cols-1 row-cols-md-5 g-5" id="cards-box">
      <div class="col">
        <div class="card h-100">
          <img src="https://i.postimg.cc/4x5ZLDB2/t043597jk8v-u055afalu9e-844e26a259ec-512-480.jpg"
            class="card-img-top">
          <div class="card-body">
            <h5>이다영</h5>
            <p>MBTI : INFJ</p>
            <p>프로젝트를 완성하는 날, <br>트랙을 완주하는 날까지<br> 최선을 다하겠습니다!</p>
            <button type="button" onclick="location.href='https://verdantjuly.github.io/withmedayoung/'"
              class="btn btn-success">Introduce</button>

          </div>
        </div>
      </div>
      <div class="col">
        <div class="card h-100">
          <img src="https://i.postimg.cc/Pr1dZpZj/t043597jk8v-u053jslhs8k-ece0e600acf6-512-480.jpg"
            class="card-img-top">
          <div class="card-body">
            <h5>이승현</h5>
            <p>MBTI : ENTJ</p>
            <p>열심히 캠프 참여해서 <br>어엿한 프로그램 <br>개발자로 거듭나겠습니다</p>
            <button type="button" onclick="location.href='https://jamjaemm.github.io/project_beginning/'"
              class="btn btn-success">Introduce</button>

          </div>
        </div>
      </div>
      <div class="col">
        <div class="card h-100">
          <img src="https://i.postimg.cc/1391qWsG/t043597jk8v-u051ukhdn83-cdd3648e9c6c-512-480.png"
            class="card-img-top">
          <div class="card-body">
            <h5>우성원</h5>
            <p>MBTI : ISFP</p>
            <p>포기하지않고 꾸준히 <br> 해서 성공한 개발자가 <br>되겠습니다.</p>
            <button type="button" onclick="location.href='https://sungwon93.github.io/mypage/'"
              class="btn btn-success">Introduce</button>

          </div>
        </div>
      </div>
      <div class="col">
        <div class="card h-100">
          <img src="https://i.postimg.cc/KY8bd0WG/t043597jk8v-u055gm324au-7084f39e2aa9-512-480.jpg"
            class="card-img-top">
          <div class="card-body">
            <h5>이상우</h5>
            <p>MBTI : INFP</p>
            <p>부트캠프를 수료하여 <br>멋진 개발자로 <br>거듭나겠습니다.</p>
            <button type="button" onclick="location.href='https://sangwoorhie.github.io/sangwoo/'"
              class="btn btn-success">Introduce</button>
          </div>
        </div>
      </div>
      <div class="col">
        <div class="card h-100">

          <img src="https://i.postimg.cc/3JY7pcfn/2023-05-15-22-55-19.png" class="card-img-top">
          <div class="card-body">
            <h5>서혜민</h5>
            <p>MBTI : INFP</p>
            <p>어엿한 개발자가 <br>될 수 있도록 <br>열심히 참여 하겠습니다.</p>
            <button type="button" onclick="location.href='https://ex-1008.tistory.com/'"
              class="btn btn-success">Introduce</button>

          </div>
        </div>
      </div>
    </div>
  </div>

  <!-- 방명록 -->

  <div class="comment-box">
    <h2 class="comment-title">Team.코딩위드미 응원하기</h2>
    <div class="form-floating mb-3">
      <input id="nickname" class="form-control" placeholder="닉네임">
      <label for="floatingInput">닉네임</label>
    </div>
    <div class="form-floating">
      <input id="comment" class="form-control" placeholder="응원 한 마디">
      <label for="floatingPassword">응원 한 마디</label>
    </div>
    <br>
    <button onclick="save_comment()" type="button" class="btn btn-outline-dark">저장</button>
    <div id="comment-list" class="comment-list" id="comment-list">

    </div>
  </div>

  </div>

</body>

</html>