웹개발 플러스 3주차 숙제

한동안 일이 바빠서 저녁에 시간이 없었다.
뒤늦게 3주차 완주.

3주차 수업 내용은 쉬웠지만,
숙제를 보고 당황할 것 같은 느낌이었다.

웹 개발은 정말 안 친해지는 느낌...
그래도 애매하게 알았던 것들이 좀 더 명확해진 거 같다.

app.py
from flask import Flask, render_template, request, jsonify, redirect, url_for
from pymongo import MongoClient


app = Flask(__name__)

client = MongoClient('3.34.132.207', 27017, username="test", password="test")
db = client.dbsparta_plus_week3


@app.route('/')
def main():
    return render_template("index.html")


@app.route('/matjip', methods=["GET"])
def get_matjip():
    # 맛집 목록을 반환하는 API
    matjip_list = list(db.matjips.find({}, {'_id': False}))
    # print(len(matjip_list))
    # matjip_list 라는 키 값에 맛집 목록을 담아 클라이언트에게 반환합니다.

    return jsonify({'result': 'success', 'matjip_list': matjip_list})


@app.route('/add_favorite', methods=["POST"])
def add_favorite():
    title = request.form["title"]
    address = request.form["address"]
    action = request.form["action"]

    if action == "like":
        db.matjips.update_one({"title": title, "address": address}, {"$set": {"liked": True}})
        print("added")
    else:
        db.matjips.update_one({"title": title, "address": address}, {"$unset": {"liked": False}})
        print("removed")
    return jsonify({'result': 'success'})


if __name__ == '__main__':
    app.run('0.0.0.0', port=5000, debug=True)
index.html
<!DOCTYPE html>
<html>

<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, maximum-scale=1.0, minimum-scale=1.0, user-scalable=no">
    <meta property="og:title" content="스파르타 맛집 지도"/>
    <meta property="og:description" content="mini project for Web Plus"/>
    <meta property="og:image" content="{{ url_for('static', filename='og_image.jpg') }}"/>
    <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">
    <title>스파르타코딩클럽 | 맛집 검색</title>
    <script type="text/javascript"
            src="https://openapi.map.naver.com/openapi/v3/maps.js?ncpClientId={CLIENT_ID}=geocoder"></script>

    <!-- Bootstrap CSS -->
    <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css"
          integrity="sha384-Gn5384xqQ1aoWXA+058RXPxPg6fy4IWvTNh0E263XmFcJlSAwiGgFAW/dAiS6JXm"
          crossorigin="anonymous">
    <link rel="preconnect" href="https://fonts.gstatic.com">
    <link href="https://fonts.googleapis.com/css2?family=Jua&display=swap" rel="stylesheet">
    <link href="//maxcdn.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css" rel="stylesheet">

    <!-- Optional JavaScript -->
    <!-- jQuery first, then Popper.js, then Bootstrap JS -->
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.12.9/umd/popper.min.js"
            integrity="sha384-ApNbgh9B+Y1QKtv3Rn7W3mgPxhU9K/ScQsAP7hUibX39j7fakFPskvXusvfa0b4Q"
            crossorigin="anonymous"></script>
    <script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/js/bootstrap.min.js"
            integrity="sha384-JZR6Spejh4U02d8jOt6vLEHfe/JQGiRRSQQxSfFWpi1MquVdAyjUar5+76PVCmYl"
            crossorigin="anonymous"></script>
    <style>
        .wrap {
            width: 90%;
            max-width: 750px;
            margin: 0 auto;
        }

        .banner {
            width: 100%;
            height: 20vh;
            background-image: url("{{ url_for('static', filename='banner.jpg') }}");
            background-position: center;
            background-size: contain;
            background-repeat: repeat;

        }

        h1.title {
            font-family: 'Jua', sans-serif;

            color: white;
            font-size: 3rem;
        }

        .matjip-list {
            overflow: scroll;
            width: 100%;
            height: calc(20vh - 30px);
            position: relative;
        }

        .card-title, .card-subtitle {
            display: inline;
        }

        h5 {
            font-family: 'Jua', sans-serif;
        }

        #map {
            width: 100%;
            height: 50vh;
            margin: 20px auto 20px auto;
        }

        .iw-inner {
            padding: 10px;
            font-size: smaller;
        }

        i {
            color: #e8344e;
        }

        i:hover {
            cursor: pointer;
        }
    </style>
    <script>
        let y_cen = 37.4981125   // lat
        let x_cen = 127.0379399  // long
        let map;
        let markers = [];
        let infowindows = [];

        $(document).ready(function () {
            map = new naver.maps.Map('map', {
                center: new naver.maps.LatLng(y_cen, x_cen),
                zoom: 12,
                zoomControl: true,
                zoomControlOptions: {
                    style: naver.maps.ZoomControlStyle.SMALL,
                    position: naver.maps.Position.TOP_RIGHT
                }
            });

            get_matjips();
        })

        function get_matjips() {
            $('#matjip-box').empty();
            $.ajax({
                type: "GET",
                url: '/matjip',
                data: {},
                success: function (response) {
                    let matjips = response["matjip_list"]
                    for (let i = 0; i < matjips.length; i++) {
                        let matjip = matjips[i]
                        // console.log(matjip)

                        make_card(i, matjip);
                        let marker = make_marker(matjip);
                        add_info(i, marker, matjip);
                    }
                }
            });
        }

        function make_card(i, matjip) {
            let html_temp = ``;
            if ("liked" in matjip) {
                html_temp = `<div class="card" id="card-${i}">
                                <div class="card-body">
                                    <h5 class="card-title"><a href="javascript:click2center(${i})" class="matjip-title">${matjip['title']}</a></h5>
                                    <h6 class="card-subtitle mb-2 text-muted">${matjip['category']}</h6>
                                    <i class="fa fa-bookmark" onclick="bookmark('${matjip['title']}', '${matjip['address']}', 'unlike')"></i>
                                    <p class="card-text">${matjip['address']}</p>
                                    <p class="card-text" style="color:blue;">${matjip['show']}</p>
                                </div>
                             </div>`;
            } else {
                html_temp = `<div class="card" id="card-${i}">
                                <div class="card-body">
                                    <h5 class="card-title"><a href="javascript:click2center(${i})" class="matjip-title">${matjip['title']}</a></h5>
                                    <h6 class="card-subtitle mb-2 text-muted">${matjip['category']}</h6>
                                    <i class="fa fa-bookmark-o" onclick="bookmark('${matjip['title']}', '${matjip['address']}', 'like')"></i>
                                    <p class="card-text">${matjip['address']}</p>
                                    <p class="card-text" style="color:blue;">${matjip['show']}</p>
                                </div>
                             </div>`;
            }
            $('#matjip-box').append(html_temp);
        }

        function make_marker(matjip) {
            let marker_img = '';
            if ("liked" in matjip) {
                marker_img = '{{ url_for("static", filename="marker-liked.png") }}'
            } else {
                marker_img = '{{ url_for("static", filename="marker-default.png") }}'
            }
            let marker = new naver.maps.Marker({
                position: new naver.maps.LatLng(matjip["mapy"], matjip["mapx"]),
                map: map,
                icon: marker_img
            });
            markers.push(marker);
            return marker
        }

        function add_info(i, marker, matjip) {
            let html_temp = `<div class="iw-inner">
                        <h5>${matjip['title']}</h5>
                        <p>${matjip['address']}
                        </div>`;
            let infowindow = new naver.maps.InfoWindow({
                content: html_temp,
                maxWidth: 200,
                backgroundColor: "#fff",
                borderColor: "#888",
                borderWidth: 2,
                anchorSize: new naver.maps.Size(15, 15),
                anchorSkew: true,
                anchorColor: "#fff",
                pixelOffset: new naver.maps.Point(10, -10)
            });
            infowindows.push(infowindow)
            naver.maps.Event.addListener(marker, "click", function (e) {
                if (infowindow.getMap()) {
                    infowindow.close();
                } else {
                    infowindow.open(map, marker);
                    map.setCenter(infowindow.position)
                    $("#matjip-box").animate({
                        scrollTop: $("#matjip-box").get(0).scrollTop + $(`#card-${i}`).position().top
                    }, 2000);
                }
            });
        }

        function click2center(i) {
            let marker = markers[i]
            let infowindow = infowindows[i]
            if (infowindow.getMap()) {
                infowindow.close();
            } else {
                infowindow.open(map, marker);
                map.setCenter(infowindow.position)
            }
        }

        function bookmark(title, address, action) {
            $.ajax({
                type: "POST",
                url: "/add_favorite",
                data: {
                    title: title,
                    address: address,
                    action: action
                },
                success: function (response) {
                    if (response["result"] == "success") {
                        get_matjips()
                    }
                }
            })
        }
    </script>

</head>

<body>
<div class="wrap">
    <div class="banner">
        <div class="d-flex flex-column align-items-center"
             style="background-color: rgba(0,0,0,0.5);width: 100%;height: 100%;">
            <h1 class="title mt-5 mb-2">스파르타 맛집 지도</h1>
        </div>
    </div>
    <div id="map"></div>

    <div class="matjip-list" id="matjip-box">

    </div>
</div>

</body>

</html>

좋은 웹페이지 즐겨찾기