SW-jungle/Week-00๐Ÿ’ก

Haein Leeยท2022๋…„ 9์›” 23์ผ
1

22/09/19~09/22

์ •๊ธ€ ์‹œ์ž‘!

์ •๊ธ€์— ๋“ค์–ด์˜ค๊ธฐ ์ „์—๋Š” ๋ฌด์–ธ๊ฐ€๋ฅผ ๊พธ์ค€ํ•˜๊ฒŒ ํ•ด๋ณธ ์ ์ด ๋ณ„๋กœ ์—†๋Š” ๊ฑฐ ๊ฐ™๋‹ค. ๊ทธ๋ฆฌ๊ณ  ๋‚ด๊ฐ€ ์ฐพ์•„์„œ ํ•œ๋‹ค๊ธฐ๋ณด๋‹ค๋Š” ๋ˆ„๊ฐ€ ์‹œ์ผœ์„œ ํ•œ ์ ์ด ๋งŽ์•˜๋Š”๋ฐ ์ด๋ฒˆ์—” ๋‚ด๊ฐ€ ์„ ํƒํ•œ ๊ธธ์ด๋‹ˆ๊นŒ ๋๊นŒ์ง€ ์—ด์‹ฌํžˆ ํ•ด๋ณด๊ณ  ์‹ถ๋‹ค.

์žฌ๋ฐŒ๊ฒŒ ์ฆ๊ธธ ์ˆ˜ ์žˆ๋‹ค๋ฉด ์ฆ๊ธฐ๋ฉด์„œ ์—ด์‹ฌํžˆ ํ•˜๋ฉด ์ž˜๋˜์ง€ ์•Š์„๊นŒ??! ์ง€๊ธˆ์€ ๊ตฌ๊ธ€ ์—†์ด๋Š” ์•„๋ฌด๊ฒƒ๋„ ํ•  ์ˆ˜ ์—†๋Š” ์ฝ”๋”ฉ ์–ด๋ฆฐ์ด์ง€๋งŒ 5๊ฐœ์›”์ด ์ง€๋‚˜๊ณ  ๋‚˜์„œ๋Š” ๊ทธ๋ž˜๋„ ์ง€๊ธˆ๊ณผ๋Š” ๋งŽ์ด ๋ฐ”๋€Œ์–ด์žˆ๊ธฐ๋ฅผ~~ :) ์•„์ž์•„์ž

์ •๊ธ€ 0์ฃผ์ฐจ:

์ž…ํ•™์‹œํ—˜ ๋•Œ ๋ฐฐ์šด ๊ธฐ์ˆ ๋“ค์„ ํ† ๋Œ€๋กœ, 3๋ฐ• 4์ผ๊ฐ„ ๋ฏธ๋‹ˆ ํ”„๋กœ์ ํŠธ๋ฅผ ์™„์„ฑ

ํ•„์ˆ˜ํฌํ•จ ์‚ฌํ•ญ
๋กœ๊ทธ์ธ ๊ธฐ๋Šฅ
Jinja2 ํ…œํ”Œ๋ฆฟ ์—”์ง„์„ ์ด์šฉํ•œ ์„œ๋ฒ„์‚ฌ์ด๋“œ ๋ Œ๋”๋ง
๋” ๊ณ ๋ฏผํ•ด๋ณผ ํ‚ค์›Œ๋“œ
Bootstrap์„ ๋Œ€์ฒดํ•  CSS ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ์‚ฌ์šฉํ•˜๊ธฐ (Bulma, Tailwind ๋“ฑ)
JWT ์ธ์ฆ ๋ฐฉ์‹์œผ๋กœ ๋กœ๊ทธ์ธ์„ ๊ตฌํ˜„ํ•˜๊ธฐ (์ฟ ํ‚ค/์„ธ์…˜ ๋Œ€๋น„ ๋“ฑ์žฅํ•˜๊ฒŒ ๋œ ๋ฐฐ๊ฒฝ์€?)

๋ฐœํ‘œ PPT





๋กœ๊ทธ์ธ

<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="UTF-8">
        <meta http-equiv="X-UA-Compatible" content="IE=edge">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <!-- Bootstrap CSS -->
        <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@4.6.0/dist/css/bootstrap.min.css"
        integrity="sha384-B0vP5xmATw1+K9KRQjQERJvTumQW0nPEzvF6L/Z6nronJ3oUOFUFpCjEUQouq2+l" crossorigin="anonymous">
        <link rel="stylesheet" href="{{ url_for('static', filename='styles.css') }}">
        <script src="https://code.jquery.com/jquery-3.5.1.js"></script>
        <script src="https://cdn.jsdelivr.net/npm/bootstrap@4.6.0/dist/js/bootstrap.bundle.min.js" integrity="sha384-Piv4xVNRyMGpqkS2by6br4gNJ7DXjqk09RmUpJ8jgGtD7zP9yug3goQfGII0yAns" crossorigin="anonymous"></script>
        <script src="https://kit.fontawesome.com/0d71430ac6.js" crossorigin="anonymous"></script>
        <title>SW ์‚ฌ๊ด€ํ•™๊ต ์ •๊ธ€ - ๋กœ๊ทธ์ธ </title>
        <script>    
            function post_login() {
                console.log('post login ์‹คํ–‰')

                let email = document.getElementById("email").value
                let pw = document.getElementById("pw").value
                if ( !email || !pw ) {
                    return alert("์ด๋ฉ”์ผ๊ณผ ๋น„๋ฐ€๋ฒˆํ˜ธ๋ฅผ ๋ชจ๋‘ ์ž…๋ ฅํ•ด์ฃผ์„ธ์š”!โ˜น๏ธ")
                }

                $.ajax({
                    type: "post",
                    url:"/login",
                    data:{email_give: email, pw_give: pw},
                    success: function(response){
                        if (response.msg == 'found') {
                            console.log(response.result.name)
                            alert("์›ฐ์ปด! ์˜ค๋Š˜๋„ ์—ด์ฝ” ํ•ฉ์‹œ๋‹ค! ๐Ÿ‘ป ")
                            window.location.href = "/";
                        } else if (response.msg == 'not_found') {
                            alert("์ด๋ฉ”์ผ๊ณผ ๋น„๋ฐ€๋ฒˆํ˜ธ๋ฅผ ๋‹ค์‹œ ํ™•์ธํ•ด์ฃผ์„ธ์š” ๐Ÿฅบ")
                            window.location.reload();
                            console.log(response.result.name)
                        }
                    } } )
                }
        </script>
</head>
<body>
    <section class="login-form">
        <h1>Login</h1>
        <div>
            <div class="int-area">
                <input type="email" name="email" id="email" autocomplete="off" required>
                <label for="email">EMAIL</label>
            </div>
            <div class="int-area">
                <input type="password" name="pw" id="pw" autocomplete="off" required>
                <label for="pw">PASSWORD</label>
            </div>
            <div class="btn-area">
                <button id="btn" type="submit" onclick="post_login()">LOGIN</button>
                <button id="sp" type="button" onclick="location.href='/signup'">ํšŒ์›๊ฐ€์ž…</button>
            </div>
    </section>
</body>
</html>

์ธ๋ฑ์Šค

          window.location.reload()
                } 
                }})}

        function makeCards(author,link,title,comment,category,image,like,created_at,liked_by) {
            let card_html = `
                <div class="card" style= "margin: 20px 10px; border-radius: 30px;width: 30%;">
                    <a href="${link}" target="_blank"> <img src="${image}" class="card-img-top" alt="..." style="height: 130px; object-fit: scale-down; border-bottom: 0.2px solid rgba(0,0,0,0.2);border-top-left-radius: 15px;border-top-right-radius: 15px;margin-top: 15px; padding-bottom :15px"> </a>
                    <div class="card-body">
                            <h5 class="card-title" id="card-title"> ${title} </h5>
                            <h6 class="card-subtitle mb-2 text-muted"> ${category} </h6>
                            <p class="card-text" id="card-text"> 
                                <span> ${author} :  </span>
                                <span> ${comment} </span>
                            </p>        
                            <div class="likes-holder" data-articleId=${created_at}>     
                                <button id="like-btn" type="button" class="btn btn-outline-success btn-sm" onclick="click_like_btn(this)"><i id="like-icon" class="fa-regular fa-heart fa-lg"></i></button>
                                <!-- <i class="fa-solid fa-heart"></i> -->
                                <span class="likes-total-num"> Likes: <span>${like}</span> </span>
                            </div>  
                    </div>
                </div>`
            $("#cards").append(card_html);
        
            const sessionId = document.getElementById("session-id").innerText
            const loggedinUser = sessionId

            index = liked_by.indexOf(loggedinUser)
            if (index>=0) {
                let btn = document.getElementById("cards").lastChild.lastElementChild.lastElementChild.firstElementChild
                btn.classList.add("btn-success");
                btn.classList.remove("btn-outline-success");
            }}

        function getMaterials() {
            $.ajax({
                type: "GET",
                url: "/materials",
                data: {},
                success: function (response) {
                    let materials = response.materials;
                    console.log(materials)
                    for (i = 0; i < materials.length; i++) {
                        makeCards(materials[i]['user'], materials[i]['link'], materials[i]['title'],materials[i]['comment'], materials[i]['category'], materials[i]['image'], materials[i]['like'], materials[i]['created_at'],materials[i]['liked_by'])
                    }
                } // success ์‹œ ํ•จ์ˆ˜ ๋ 
                }) // ajax ๋
        }    
    </script>
    <title> SW ์‚ฌ๊ด€ํ•™๊ต ์ •๊ธ€ - ํ•™์Šต ์ž๋ฃŒ ํ™•์ธํ•˜๊ธฐ </title>
</head>

<body>
    <header>
        {% if session['id'] %}<p id="session-id" style="display:none">{{session['id']}}</p> {% endif %} 
        {% set user_id = session['id'] %}   
        {% set user_name = session['name'] %}   

        <div id="header-logo">
            <a href="/"><img src="{{ url_for('static', filename='jungle_logo.png') }}"/></a>
        </div>
        <div id="header-user">
            <p> {{user_name}}๋‹˜ ์•ˆ๋…•ํ•˜์„ธ์š”! </p>
            <a href="/upload"><button type="button" class="btn btn-outline-danger" onclick="openEditForm(this)"> ์ž๋ฃŒ์ถ”๊ฐ€ </button></a>
            <button type="button" class="btn btn-outline-secondary" onclick="location.href='/logout'"> ๋กœ๊ทธ์•„์›ƒ </button>
        </div>
    </header>

    <main>
        <div id="cards" class="row"> </div>
    </main>
    
</body>
</html>

ํšŒ์›๊ฐ€์ž…

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@4.6.0/dist/css/bootstrap.min.css"
    integrity="sha384-B0vP5xmATw1+K9KRQjQERJvTumQW0nPEzvF6L/Z6nronJ3oUOFUFpCjEUQouq2+l" crossorigin="anonymous">
    <link rel="stylesheet" href="{{ url_for('static', filename='styles.css') }}">
    <script src="https://code.jquery.com/jquery-3.5.1.js"></script>
    <script src="https://cdn.jsdelivr.net/npm/bootstrap@4.6.0/dist/js/bootstrap.bundle.min.js" integrity="sha384-Piv4xVNRyMGpqkS2by6br4gNJ7DXjqk09RmUpJ8jgGtD7zP9yug3goQfGII0yAns" crossorigin="anonymous"></script>
    <script src="https://kit.fontawesome.com/0d71430ac6.js" crossorigin="anonymous"></script>
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
    
    <title>SW ์‚ฌ๊ด€ํ•™๊ต ์ •๊ธ€ - ํšŒ์› ๊ฐ€์ž…</title>
    <script> 
    function makeSignup(){

        console.log("makeSignup")
        let email = $('#email').val();
        let pw = $('#pw').val();
        let name = $('#name').val();
        let class1 = $('input[name=class1]:checked').val();
   
        let arr =[email, pw, name, class1];
        let count = 0;
        for(let i=0; i < arr.length; i++) {
            if(arr[i] == "" || arr[i] == undefined) {
                count +=1 ;
            }}
            
        if (count >=2){
            return alert("๋ชจ๋“  ๊ฐ’์„ ์ž…๋ ฅํ•ด์ฃผ์„ธ์š” ๐Ÿฅบ")
        } else if(arr[0] == ""){
            alert("์ด๋ฉ”์ผ์„ ์ž…๋ ฅํ•ด์ฃผ์„ธ์š” ๐Ÿฅบ")
        } else if(arr[1] == ""){
            alert("๋น„๋ฐ€๋ฒˆํ˜ธ๋ฅผ ์ž…๋ ฅํ•ด์ฃผ์„ธ์š” ๐Ÿฅบ")
        } else if(arr[2] == ""){
            alert("์ด๋ฆ„์„ ์ž…๋ ฅํ•ด์ฃผ์„ธ์š” ๐Ÿฅบ")
        } else if(arr[3] == undefined){
            alert("๋ฐ˜์„ ์ฒดํฌํ•ด์ฃผ์„ธ์š” ๐Ÿฅบ")
        } else {
            $.ajax({
                type: "POST",
                url:"/signup",
                data:{email_give: email, pw_give: pw, name_give: name , class_give: class1},
                success: function(response){
                    console.log(response.msg)
                    if (response.msg == 'existing') {
                        alert ("์ด๋ฏธ ์กด์žฌํ•˜๋Š” ์ด๋ฉ”์ผ ์ž…๋‹ˆ๋‹ค. ")
                        window.location.href = "/signup";
                    } else if (response.msg == 'not_found') {
                        alert ("์ •๊ธ€ 5๊ธฐ์ƒ์ด ์•„๋‹™๋‹ˆ๋‹ค. ๋ˆ„๊ตฌ๋ƒ ๋„Œ!")
                        window.location.href = "/signup";
                    } else {
                        alert ("ํšŒ์› ๊ฐ€์ž…์ด ์™„๋ฃŒ๋˜์—ˆ์Šต๋‹ˆ๋‹ค")
                        window.location.href = "/login";    
                    }}})
        } }
        </script>
   

</head>
<body>
  
    <section class="signup-form">
        <h3>ํšŒ์›๊ฐ€์ž…</h3>
        <div action="">
            <div class="int-area">
                <input type="email" name="email" id="email" autocomplete="off" required>
                <label for="email">EMAIL :</label>
            </div>
            <div class="int-area">
                <input type="password" name="pw" id="pw" autocomplete="off" required>
                <label for="pw">PASSWORD :</label>
            </div>
            <div class="int-area">
                <input type="text" name="name" id="name" autocomplete="off" required>
                <label for="name">NAME :</label>
            </div>
            <form>
                <input type="radio" name="class1"  value="a" /> A๋ฐ˜
                <input type="radio" name="class1"  value="b" /> B๋ฐ˜
            </form>
        <div class="btn-area">
            <button onclick="location.href='login'" id="btn" type="button" style="background-color: gray;">๋Œ์•„๊ฐ€๊ธฐ</button>
            <button onclick="makeSignup()" id="btn" type="button" >๊ฐ€์ž…ํ•˜๊ธฐ</button>
        </section>

</body>
</html>

์—…๋กœ๋“œ

<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="UTF-8">
        <meta http-equiv="X-UA-Compatible" content="IE=edge">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <!-- Bootstrap CSS -->
        <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@4.6.0/dist/css/bootstrap.min.css"
        integrity="sha384-B0vP5xmATw1+K9KRQjQERJvTumQW0nPEzvF6L/Z6nronJ3oUOFUFpCjEUQouq2+l" crossorigin="anonymous">
        <link rel="stylesheet" href="{{ url_for('static', filename='styles.css') }}">
        <style>  
            body {
                display:block;
                padding: 0 20%;
                margin-bottom: 50px;
                height: 110vh;
            }
        </style>
        <script src="https://code.jquery.com/jquery-3.5.1.js"></script>
        <script src="https://cdn.jsdelivr.net/npm/bootstrap@4.6.0/dist/js/bootstrap.bundle.min.js" integrity="sha384-Piv4xVNRyMGpqkS2by6br4gNJ7DXjqk09RmUpJ8jgGtD7zP9yug3goQfGII0yAns" crossorigin="anonymous"></script>
        <script src="https://kit.fontawesome.com/0d71430ac6.js" crossorigin="anonymous"></script>

        <title> SW ์‚ฌ๊ด€ํ•™๊ต ์ •๊ธ€ - ํ•™์Šต ์ž๋ฃŒ ์˜ฌ๋ฆฌ๊ธฐ </title>
        <script>
            function upload_url() {
                let user_id = $("#user").val();
                let link = $("#link").val();
                let title = $("#title").val();
                let comment = $("#comment").val();
                let category = $("#category").val();
             
                let arr =[user_id.length, link.length, title.length, comment.length, category.length];
                let count = 0;
                for(let i=0; i < arr.length; i++) {
                    if(arr[i] == 0) {
                        count +=1 ;
                    }}
                if (count >=2){
                    return alert("๋นˆ์นธ์„ ์ฑ„์›Œ์ฃผ์„ธ์š”")
                } else if(arr[0] == '0'){
                    alert("user_id๋ฅผ ์ฑ„์›Œ์ฃผ์„ธ์š”")
                } else if(arr[1] == '0'){
                    alert("๋งํฌ๋ฅผ ์ฑ„์›Œ์ฃผ์„ธ์š”")
                } else if(arr[2] == '0'){
                    alert("์ œ๋ชฉ์„ ์ฑ„์›Œ์ฃผ์„ธ์š”")
                } else if(arr[3] == '0'){
                    alert("์ฝ”๋ฉ˜ํŠธ๋ฅผ ์ฑ„์›Œ์ฃผ์„ธ์š”")
                } else if(arr[4] == '0'){
                    alert("์นดํ…Œ๊ณ ๋ฆฌ๋ฅผ ์ฑ„์›Œ์ฃผ์„ธ์š”")  
                } else {
                $.ajax({
                    type:"POST",
                    url: "/upload",
                    data: {user: user_id, link:link, category:category, comment:comment, title:title},
                    success: function (response) {
                        if (response["result"] == "success") {
                            alert("์—…๋กœ๋“œ ์™„๋ฃŒ ๐Ÿฅฐ !");
                            document.location.href = "/";
                        } else {
                            alert("์—…๋กœ๋“œ ์‹คํŒจ ๐Ÿ˜ฅ !");
                        } 
                    }})}}
        </script>
    </head>
<body>
    <header>
        {% if session['id'] %}<p id="session-id" style="display:none">{{session['id']}}</p> {% endif %} 
        {% set user_id = session['id'] %}   
        {% set user_name = session['name'] %}   

        <div id="header-logo">
            <a href="/"><img src="{{ url_for('static', filename='jungle_logo.png') }}"/></a>
        </div>
        <div id="header-user">
            <p> {{user_name}}๋‹˜ ์•ˆ๋…•ํ•˜์„ธ์š”! </p>
            <a href="/"><button type="button" class="btn btn-outline-success" onclick="openEditForm(this)"> ๋Œ์•„๊ฐ€๊ธฐ </button></a>
            <button type="button" class="btn btn-outline-secondary" onclick="location.href='/logout'"> ๋กœ๊ทธ์•„์›ƒ </button>
        </div>
    </header>


     

    <main>
        <h1>์ž๋ฃŒ ์˜ฌ๋ฆฌ๊ธฐ</h1>
        <div>
            <div class="form-group">
            <label for="user">์ž‘์„ฑ์ž</label>
            <input type="text" disabled class="form-control" id="user" value="{{user_name}}" >
            </div>
            <div class="form-group">
            <label for="link">๋งํฌ</label>
            <input type="text" class="form-control" id="link"  required>  
            </div>
            <div class="form-group">
                <label for="title">์ œ๋ชฉ</label>
                <input type="text" class="form-control" id="title"  required>
            </div>
            <div class="form-group">
                <label for="comment">์ฝ”๋ฉ˜ํŠธ</label>
                <input type="text" class="form-control" id="comment" required>
            </div>
            <div class="form-group">
                <label for="category">์นดํ…Œ๊ณ ๋ฆฌ</label>
                <input type="text" class="form-control" id="category" required>
            </div>
            <button type="submit" class="btn btn-primary" onclick="upload_url()">์ž๋ฃŒ ์ €์žฅ</button>
        </div>
    </main >
    
</body>
</html>

.py

from flask import Flask, json, request, render_template, jsonify, redirect, url_for, session
from array import array
import requests
from flask_cors import CORS
from datetime import datetime, date,timedelta
from bs4 import BeautifulSoup
from pymongo import MongoClient
from unicodedata import category
from requests.adapters import HTTPAdapter
from urllib3.util.retry import Retry
import bcrypt
import time

app = Flask(__name__)
app.secret_key = 'jungleweek00team5isfreakingsmartanddope'
app.config["PERMANENT_SESSION_LIFETIME"] = timedelta(minutes=60)

client = MongoClient('mongodb://haein:haein@43.200.3.162',27017)
db = client.jungle



@app.route('/')
def home():
    if 'id' in session:
            id = session['id']
            print("session id :", id)
            return render_template('index.html')
    else: 
        return redirect(url_for('show_login'))

@app.route('/login')
def show_login():
    if 'id' in session:
        return redirect(url_for('home'))
    else: 
        return render_template('login.html')

@app.route('/login', methods=['POST'])
def check_login():
    email_receive = request.form['email_give']
    pw_receive = request.form['pw_give']
    user_found = db.signup.find_one({'email': email_receive},{'_id': 0})
    if user_found : 
        if bcrypt.checkpw(pw_receive.encode('utf-8'), user_found['pw'].encode('utf-8')) : 
            print("let me log you in")
            session['id'] = user_found['email']
            session['name'] = user_found['name']
            return jsonify({'msg': 'found', 'result': user_found})
        else: 
            return jsonify({'msg': 'not_found'})
    else : 
         return jsonify({'msg': 'not_found'})

@app.route('/signup')
def show_signup():
    if 'id' in session:
        return redirect(url_for('home'))
    else: 
        return render_template('signup.html')

@app.route('/signup', methods=['POST'])
def write_signup():
    email_receive = request.form['email_give']
    pw_receive = request.form['pw_give']

    pw_encoded = pw_receive.encode('utf-8')
    hashed_password = bcrypt.hashpw(pw_encoded, bcrypt.gensalt())
    pw_decoded = hashed_password.decode('utf-8')

    name_receive = request.form['name_give']
    class_receive = request.form['class_give']
    
    if db.signup.find_one({'email': email_receive}):
        return jsonify({'msg': 'existing'})
    if not db.members.find_one({'email': email_receive,'name': name_receive,'class': class_receive},{'_id': 0}) :
        return jsonify({'msg': 'not_found'})
 
    # ๊ฐ€์ ธ์˜จ ๋ฐ์ดํ„ฐ๋ฅผ DB์— ์ €์žฅํ•˜๊ธฐ
    doc = {
        'email': email_receive,
        'pw': pw_decoded,
        'name': name_receive,
        'class' : class_receive,
        'likes' : [],
    }
    db.signup.insert_one(doc)
    return jsonify({'msg': '์ €์žฅ ์™„๋ฃŒ'})

@app.route('/materials', methods=['GET'])
def read_materials():
    print(session)
    result = list(db.materials.find({}, {'_id': 0}).sort("like",-1))
    return jsonify({'result': 'success', 'materials': result}) 
   
@app.route('/upload')
def upload():
    if 'id' in session: # ๋กœ๊ทธ์ธ๋œ ์ƒํƒœ์ด๋ฉด 
        return render_template('upload.html')
    else: 
        return redirect(url_for('show_login'))

@app.route('/upload', methods=['POST'])
def upload1():
    # h = 'http://'
    user = request.form['user']
    link = request.form['link']
    # if not (h in link):
        # link = h + link
    title = request.form['title']
    comment = request.form['comment']
    category = request.form['category']
    
    headers = {'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64)AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.86 Safari/537.36'}
    try: 
        data = requests.get(link, headers=headers)
    except: 
        time.sleep(1)
        data = requests.get(link, headers=headers)
    soup = BeautifulSoup(data.text, 'html.parser')
    og_image = soup.select_one('meta[property="og:image"]')
    print("og_image: ",og_image)
    if og_image == None:
        print("no og:image!")
        url_image = 'https://img.freepik.com/premium-vector/cute-monkey-character-swinging-and-holding-banana_324746-285.jpg?w=2000'
    else: 
        print("let's get the og_image")
        url_image = og_image['content']
    now = datetime.now().strftime("%d-%b-%Y-%H:%M:%S.%f") 
    liked_by = [] 
    upload_info = {'user':user, 'link':link, 'title':title,'comment':comment, 'category':category, 'image':url_image, 'like':0 , 'created_at': now, 'liked_by': liked_by}
    db.materials.insert_one(upload_info)
    return jsonify({'result': 'success'})








@app.route('/likes', methods=['POST'])
def change_likes():
    print("start!")
    id_received = request.form['created_at']
    material = db.materials.find_one({'created_at': id_received})
    loggedin_user = session['id']
    try:
        index_in_liked_by = material['liked_by'].index(loggedin_user)
    except:
        index_in_liked_by = -1 
    print("material['liked_by'] index is ", index_in_liked_by)

    if index_in_liked_by >= 0:
        print("# ๋ฐฐ์—ด์— ์กด์žฌํ•˜๋Š” ๊ฒฝ์šฐ -> ์ข‹์•„์š” ์ฐจ๊ฐ")
        new_like = material['like'] - 1
        new_liked_by = material['liked_by'].pop(index_in_liked_by) 
        db.materials.update_one({'created_at': id_received}, {'$set': {'like': new_like,'liked_by' : material['liked_by']}})
    else:
        print("# ๋ฐฐ์—ด์— ์กด์žฌํ•˜์ง€ ์•Š๋Š” ๊ฒฝ์šฐ -> ์ข‹์•„์š” ์ถ”๊ฐ€ ")
        new_like = material['like'] + 1
        new_liked_by = material['liked_by'].append(loggedin_user)  
        db.materials.update_one({'created_at': id_received}, {'$set': {'like': new_like,'liked_by' : material['liked_by']}})
    return jsonify({'result': 'success'})

@app.route('/logout')
def logout():
    session.pop('id',None)
    session.pop('name',None)
    return redirect(url_for('home'))

if __name__ == '__main__':
    app.run('0.0.0.0', port=5000, debug=True)


css

* {
    box-sizing: border-box;
    margin: 0;
    padding: 0;
    }

    body {
    font-family: 'Noto Sans KR', sans-serif;
    display: flex;
    justify-content: center;
    align-items: center;
    height: 100vh;
    }

    .login-form h1 {
    font-size: 32px;
    text-align: center;
    margin-bottom: 50px;
    }

    .int-area {
     width: 400px;
    position: relative;
    margin-top: 20px;
    }

    .int-area:first-child {
     margin-top: 0;
    }

    .int-area input {
     width: 100%;
    padding: 20px 10px 10px;
    background-color: transparent;
    border: none;
    border-bottom: 1px solid black;
    font-size: 18px;
    outline: none;
    }

    .int-area label {
    position: absolute;
    left: 10px;
    top: 15px;
    font-size: 18px;
    transition: top 0.5s ease;
    }

    .int-area label.warning {
     color: red !important;
    animation: warning 0.3s ease;
    animation-iteration-count: 3;
    }

    @keyframes warning {
     0% {
     transform: translateX(-8px);
    }
    25% {
     transform: translateX(8px);
    }
    50% {
    transform: translateX(-8px);
    }
    75% {
     transform: translateX(8px);
     }
    }

    .int-area input:focus + label,
    .int-area input:valid + label {
     top: -2px;
    font-size: 13px;
    color: #166caa;
    }

    .btn-area {
    margin-top: 20px;
    text-align: right;
    }

    .btn-area button {
    width: 30%;
    height: 50px;
    margin: 0px 10px;
    color: #fff;
    background: #008000;
    border: none;
    border-radius: 20px;
    font-size: 15px;
    cursor: pointer;
    
    }

    .caption {
    margin-top: 20px;
    text-align: center;
    }

    .caption a {
    margin: 0 20px;
    font-size: 15px;
    color: blue;
    text-decoration: none;
    }
    body {
    background-color: #f2f7fb
    }

    header {
    display: flex;
    justify-content: center;
    align-items: center;
    height: 25vh;
    border-bottom: 1px solid green;
    margin-bottom: 60px;
}

#header-logo{
    width: 80%;
    text-align: center;
}
#header-logo img {
        width: 40%;
        margin-left: 15%;
      }

#header-user  {
    width: 20%;
    display: flex;
    flex-direction: column;
    justify-content: space-between;
    align-items: center;
}

#header-user a{
    margin-bottom: 10px;    
}


.likes-total-num {
    color: green;
    font-size:medium;
    margin-left: 5px;
}
profile
๋ฉ‹์ง„ ๊ฐœ๋ฐœ์ž๊ฐ€ ๋ ๊ฑฐ์•ผ :)

0๊ฐœ์˜ ๋Œ“๊ธ€