웹개발

웹개발플러스- 스위터 5

RAN318 2021. 6. 21. 01:43
728x90
반응형

12. 프로필 페이지 모습 만들기 - 전체

  • 틀 만들기
    1. 프로필 페이지의 모습은 메인 페이지와 아주 비슷하기 때문에 우선 복사해오겠습니다.
      <body class="has-navbar-fixed-top">
        <nav class="navbar is-fixed-top is-white" role="navigation" aria-label="main navigation">
            <div class="navbar-brand">
                <a class="navbar-item" href="/">
                    <img src="{{ url_for('static', filename='logo.png') }}">
                    <strong class="is-sparta"
                            style="font-family: 'Stylish', sans-serif;font-size: larger;">SWEETER</strong>
                </a>
            </div>
        </nav>
        <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="무슨 생각을 하고 계신가요?"
                                   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">
                                        <textarea id="textarea-post" class="textarea"
                                                  placeholder="무슨 생각을 하고 계신가요?"></textarea>
                                    </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 id="post-box" class="container">
                <div class="box">
                    <article class="media">
                        <div class="media-left">
                            <a class="image is-64x64" href="#">
                                <img class="is-rounded"
                                     src={{ url_for("static", filename="profile_pics/profile_placeholder.png") }} alt="Image">
                            </a>
                        </div>
                        <div class="media-content">
                            <div class="content">
                                <p>
                                    <strong>홍길동</strong> <small>@username</small> <small>10분 전</small>
                                    <br>
                                    글을 적는 칸
                                </p>
                            </div>
                            <nav class="level is-mobile">
                                <div class="level-left">
                                    <a class="level-item is-sparta" aria-label="heart"
                                       onclick="toggle_like('', 'heart')">
                                        <span class="icon is-small"><i class="fa fa-heart"
                                                                       aria-hidden="true"></i></span>&nbsp;<span
                                            class="like-num">2.7k</span>
                                    </a>
                                </div>
      
                            </nav>
                        </div>
                    </article>
                </div>
      
            </div>
        </section>
      </body>​

      mystyle.css와 myjs.js 파일 임포트하는 것을 잊지 마세요!
    2. 페이지가 로딩되고 나면 포스팅 카드들을 띄워줍니다.
  • 프로필 영역 만들기
    1. 프로필 페이지에서는 각 사용자의 프로필이 보여야겠죠!
      hero 클래스와 media 클래스를 이용해 만들어보겠습니다.

      <section class="hero is-white">
          <div class="hero-body" style="padding-bottom:1rem;margin:auto;min-width: 400px">
              <article class="media">
      
                  <figure class="media-left" style="align-self: center">
                      <a class="image is-96x96" href="#">
                          <img class="is-rounded" src="{{ url_for('static', filename=user_info.profile_pic_real) }}">
                      </a>
                  </figure>
                  <div class="media-content">
                      <div class="content">
                          <p>
                              <strong>{{ user_info.profile_name }}</strong> <small>@{{ user_info.username }}</small>
                              <br>
                              {{ user_info.profile_info }}
                          </p>
                      </div>
      
                  </div>
              </article>
          </div>
      </section>​

위 코드 적용시 동작된 페에지


13. 프로필 페이지 모습 만들기 - 프로필 수정

 

  • 프로필 수정 & 로그아웃 버튼 만들기
    1. 내 프로필 페이지에 들어갔을 때에는 프로필 수정과 로그아웃 버튼이 보여야합니다.
      <nav id="btns-me" class="level is-mobile" style="margin-top:2rem">
          <a class="button level-item has-text-centered is-sparta" aria-label="edit"
             onclick='$("#modal-edit").addClass("is-active")'>
              프로필 수정&nbsp;&nbsp;&nbsp;<span class="icon is-small"><i class="fa fa-pencil"
                                                                     aria-hidden="true"></i></span>
          </a>
      
          <a class="button level-item has-text-centered is-sparta is-outlined" aria-label="logout"
             onclick="sign_out()">
              로그아웃&nbsp;&nbsp;&nbsp;<span class="icon is-small"><i class="fa fa-sign-out"
                                                                   aria-hidden="true"></i></span>
          </a>
      </nav>
    2. 로그아웃 기능은 이미 프로필 시작 코드에 다 들어있었죠? 로그아웃 버튼을 클릭하면 토큰을 삭제하고 로그인 페이지로 이동하면 끝!
      function sign_out() {
          $.removeCookie('mytoken', {path: '/'});
          alert('로그아웃!')
          window.location.href = "/login"
      }
  • 프로필 수정 모달 만들기

프로필 수정 버튼을 누르면 나오는 모달입니다.

<div class="modal" id="modal-edit">
    <div class="modal-background" onclick='$("#modal-edit").removeClass("is-active")'></div>
    <div class="modal-content">
        <div class="box">
            <article class="media">
                <div class="media-content">
                    <div class="field">
                        <label class="label" for="input-name">이름</label>

                        <p class="control">

                            <input id="input-name" class="input"
                                   placeholder="홍길동" value="{{ user_info.profile_name }}">
                        </p>
                    </div>
                    <div class="field">
                        <label class="label" for="input-pic">프로필 사진</label>

                        <div class="control is-expanded">
                            <div class="file has-name">
                                <label class="file-label" style="width:100%">
                                    <input id="input-pic" class="file-input" type="file"
                                           name="resume">
                                    <span class="file-cta"><span class="file-icon"><i
                                            class="fa fa-upload"></i></span>
                                <span class="file-label">파일 선택</span>
                            </span>
                                    <span id="file-name" class="file-name"
                                          style="width:100%;max-width:100%">{{ user_info.profile_pic }}</span>
                                </label>
                            </div>

                        </div>
                    </div>
                    <div class="field">
                        <label class="label" for="textarea-about">나는 누구?</label>

                        <p class="control">

                        <textarea id="textarea-about" class="textarea"
                                  placeholder="자기소개하기">{{ user_info.profile_info }}</textarea>
                        </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="update_profile()">업데이트</a>
                            </div>
                            <div class="level-item">
                                <a class="button is-sparta is-outlined"
                                   onclick='$("#modal-edit").removeClass("is-active")'>취소</a>
                            </div>
                        </div>
                    </nav>
                </div>
            </article>
        </div>
    </div>
    <button class="modal-close is-large" aria-label="close"
            onclick='$("#modal-edit").removeClass("is-active")'></button>
</div>​

 


14. 프로필 페이지 기능 만들기

  • 내 프로필에서만 프로필 수정기능 보이게 하기
    1. 프로필 수정 & 로그아웃 버튼은 내 프로필에 들어갔을 때만 보여야겠죠? 서버에서 보내준 status 파라미터를 이용해 내 프로필일 때만 해당 부분을 그리도록 jinja2 문법을 씁니다.
      {% if status %}
      
      <nav id="btns-me" class="level is-mobile" ...>
      <div class="modal" id="modal-edit" ...>
      
      {% endif %}​
    2. 글을 적는 포스팅 칸과 모달도 내 프로필에서만 보이게 해줍니다.
      {% if status %}
      
      <section id="section-post" class="section" ...>
      
      {% endif %}​

      이렇게 타인의 프로필가면 수정 버튼 없어진당
  • 프로필 수정 기능 만들기
    1. 프로필 수정 모달에서 이름을 바꾸거나 새 프로필 사진을 업로드하는 경우 파일을 받아 저장해주어야합니다. 프로필 업데이트 후에는 페이지를 새로고침하여 다시 정보를 받아옵니다
      // 프로필 수정 클라이언트
      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()
      
                  }
              }
          });
      }​
      //프로필 수정 서버
      @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"))​

      선생님이 업데이트 해보셨다
      선생님 프로필이 수정이되었다.  포스팅해도 변경된 프로필로 포스팅이 되어요
      *왜 제 화면이 아니냐구요? 코드오류가 났는데 아직 못 찾았어요^^,,,,

  • 해당 사용자 글만 보이게 하기
    1. 포스팅 카드들 중에 해당 사용자 글만 보여주게 해보겠습니다.
    2. 아까 만든 get_posts() 함수에 username을 변수로 받도록 바꿔볼까요?
      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") {
                      ...
                  }
              }
          })
      }​
    3. 이제 서버 쪽에서 username을 받아 해당 사용자의 글만 가져오도록 바꿔봅시다.
      @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": my_username}))        return jsonify({"result": "success", "msg": "포스팅을 가져왔습니다.", "posts": posts})
          except (jwt.ExpiredSignatureError, jwt.exceptions.DecodeError):
              return redirect(url_for("home"))​

위 html파일에  get post 불러와주는  script를 각 추가해주고 웹페이지로 가보면?

타인의 페이지로 아무것도 안뜸
본인의 페이지의 작성글은 뜸!

  • og태그, favicon 넣기
    1. 마지막 웹서비스도 Open Graph 태그와 favicon을 넣어서 완성해줍시다. ogimg는 로그인화면 배너를 스크린샷을 찍고 favicon은 아래 파일을 다운 받아 static 폴더에 넣어줄게요.
    2. HTML 파일들의 head에 링크를 첨부합니다. 내용은 각 페이지에 맞게 바꿔주어야겠죠?
      ```html
      <link rel="shortcut icon" href="{{ url_for('static', filename='favicon.ico') }}" type="image/x-icon">
      <link rel="icon" href="{{ url_for('static', filename='favicon.ico') }}" type="image/x-icon">
      <meta property="og:title" content="스위터 - 세상을 달달하게"/>
      <meta property="og:description" content="mini project for Web Plus"/>
      <meta property="og:image" content="{{ url_for('static', filename='ogimg.png') }}"/>
      ```​

 

728x90
반응형