diff --git a/.gitignore b/.gitignore index 0609b8bb22547825937a521b476e35deeaddd9c4..11908f056a95c8b8d38c9f4bc714ec4dde2774ca 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ +/db/ tournament-website *.conf diff --git a/assets/static/css/style.css b/assets/static/css/style.css index 0eebde387b82b44945e64e90f4dfdd77760cae6d..cfd739ba3a122e3ee830e5960290995842c115de 100644 --- a/assets/static/css/style.css +++ b/assets/static/css/style.css @@ -4386,7 +4386,8 @@ ul.minicart .cart-price .new { .contact-area { background-image: url(../img/bg/bg.jpg); background-position: center; - background-size:cover + background-size:cover; + height:100vh; } .contact-area .form-container { background: #fff; @@ -4448,6 +4449,20 @@ ul.minicart .cart-price .new { line-height: 40px; padding-bottom: 10px; } +.contact-form select { + width: 100%; + border: none; + font-size: 15px; + border-bottom: 2px solid #eeeeee; + margin-bottom: 40px; + transition: .3s linear; + height: 40px; + line-height: 40px; + padding-bottom: 10px; +} +.contact-form select:focus { + border-color: #ff5917; +} .contact-form button { display: block; width: 100%; diff --git a/assets/templates/admin.tmpl b/assets/templates/admin.tmpl new file mode 100644 index 0000000000000000000000000000000000000000..121433499f6d8f60758abd6aa52f5de7f86009d8 --- /dev/null +++ b/assets/templates/admin.tmpl @@ -0,0 +1,100 @@ +{{template "top"}} +{{template "header" .}} +<!-- main-area --> +<main> + + <!-- slider-area --> + <section class="third-banner-bg"> + <div class="container custom-container"> + <div class="row"> + <div class="col-12"> + <div class="row"> + <div class="col-12 tournament-container"> + <div class="my-match-wrap"> + <!-- Turnuva 1 Başlangıç --> + <div class="my-match-box-wrap wow fadeInDown" data-wow-delay=".2s" + style="background-image: url('/static/img/bg/1.png');"> + <img src="/static/img/bg/my_match_box.png" alt="" class="match-box-bg"> + <ul> + <li> + <div class="tournament-image"> + + </div> + </li> + <li> + <div class="my-match-info"> + <a href="#" target="_blank" class="live-btn">Canlı Yayın!</a> + <!-- Canlı yayın butonu --> + <h5>AoV 1vs1 Turnuvası</h5> + <span>20 Kasım 2021 20:00</span> + </div> + </li> + <li> + <a href="/" target="_blank" class="watch-stream"><i + class="fas fa-pencil-alt"></i> Düzenle</a> + </li> + </ul> + </div> + <!-- Turnuva 1 Son --> + + <!-- Turnuva 2 Başlangıç --> + <div class="my-match-box-wrap wow fadeInDown" data-wow-delay=".4s" + style="background-image: url('/static/img/bg/2-box.png');"> + <img src="/static/img/bg/my_matchbox_2.png" alt="" class="match-box-bg"> + <ul> + <li> + <div class="tournament-image"> + + </div> + </li> + <li> + <div class="my-match-info"> + <h5>AoV 1vs1 Turnuvası</h5> + <span>20 Kasım 2021 20:00</span> + <span>Son Kayıt: 19 Kasım 23:59</span> + </div> + </li> + <li> + <a href="/" target="_blank" class="watch-stream"><i + class="fas fa-pencil-alt"></i> Düzenle</a> + </li> + </ul> + </div> + <!-- Turnuva 2 Son --> + + <!-- Turnuva 3 Başlangıç --> + <div class="my-match-box-wrap wow fadeInDown" data-wow-delay=".2s" + style="background-image: url('/static/img/bg/box-3.png');"> + <img src="/static/img/bg/my_matchbox_3.png" alt="" class="match-box-bg"> + <ul> + <li> + <div class="tournament-image"> + + </div> + </li> + <li> + <div class="my-match-info"> + <h5>AoV 1vs1 Turnuvası</h5> + <span>20 Kasım 2021 20:00</span> + <span>Son Kayıt: 19 Kasım 23:59</span> + </div> + </li> + <li> + <a href="/" target="_blank" class="watch-stream"><i + class="fas fa-pencil-alt"></i> Düzenle</a> + </li> + </ul> + </div> + <!-- Turnuva 3 Son --> + </div> + </div> + </div> + </div> + </div> + </div> + </section> + <!-- slider-area-end --> + +</main> +<!-- main-area-end --> +{{template "bottom"}} diff --git a/assets/templates/archetype.tmpl b/assets/templates/archetype.tmpl new file mode 100644 index 0000000000000000000000000000000000000000..9ca0de51a01c2afbee1a1107542d63434789cb95 --- /dev/null +++ b/assets/templates/archetype.tmpl @@ -0,0 +1,102 @@ +{{define "top"}} + <!doctype html> + <html class="no-js" lang="tr"> + <head> + <meta charset="utf-8"> + <meta http-equiv="x-ua-compatible" content="ie=edge"> + <title>Arena of Valor - Turnuva Kayıt</title> + <meta name="description" content=""> + <meta name="viewport" content="width=device-width, initial-scale=1"> + + <link rel="shortcut icon" type="image/x-icon" href="/static/img/favicon.png"> + + <link rel="stylesheet" href="/static/css/bootstrap.min.css"> + <link rel="stylesheet" href="/static/css/animate.min.css"> + <link rel="stylesheet" href="/static/css/magnific-popup.css"> + <link rel="stylesheet" href="/static/css/fontawesome-all.min.css"> + <link rel="stylesheet" href="/static/css/odometer.css"> + <link rel="stylesheet" href="/static/css/aos.css"> + <link rel="stylesheet" href="/static/css/owl.carousel.min.css"> + <link rel="stylesheet" href="/static/css/meanmenu.css"> + <link rel="stylesheet" href="/static/css/slick.css"> + <link rel="stylesheet" href="/static/css/default.css"> + <link rel="stylesheet" href="/static/css/style.css"> + <link rel="stylesheet" href="/static/css/responsive.css"> + </head> + <body> + + <!-- preloader --> + <div id="preloader"> + <div id="loading-center"> + <div id="loading-center-absolute"> + <img src="/static/img/logo/logo.svg" alt=""> + </div> + </div> + </div> + <!-- preloader-end --> +{{end}} + +{{define "header"}} + <!-- header-area --> + <header> + <div class="transparent-header"> + <div class="container"> + <div class="logo"> + <a href="/" style="text-align: center; width: 100%; display: block;"><img + src="/static/img/logo/logo.svg" + alt="Logo" + style="width: 160px;"></a> + </div> + </div> + <div class="container-fluid s-container-full-padding"> + <div class="row"> + <div class="col-12"> + <div class="main-menu menu-style-two"> + <nav> + <div id="mobile-menu" class="navbar-wrap d-none d-lg-flex"> + <ul> + <li class="show"><a href="#"> <i class="fas fa-home"></i> Anasayfa</a></li> + <li><a href="https://www.instagram.com/arenaofvalor.turkiye/"> <i + class="fab fa-instagram"></i> Instagram</a></li> + <li><a href="https://discord.gg/aovtr"> <i class="fab fa-discord"></i> + Discord</a> + <li><a href="{{.auth_ref}}"> <i class="fas fa-user"></i> {{.auth_text}}</a> + </li> + </ul> + </div> + + </nav> + </div> + <div class="mobile-menu"></div> + </div> + </div> + </div> + </div> + </header> + <!-- header-area-end --> +{{end}} + +{{define "bottom"}} + <!-- JS here --> + <script src="/static/js/vendor/jquery-3.4.1.min.js"></script> + <script src="/static/js/popper.min.js"></script> + <script src="/static/js/bootstrap.min.js"></script> + <script src="/static/js/isotope.pkgd.min.js"></script> + <script src="/static/js/slick.min.js"></script> + <script src="/static/js/jquery.meanmenu.min.js"></script> + <script src="/static/js/wow.min.js"></script> + <script src="/static/js/aos.js"></script> + <script src="/static/js/jquery.lettering.js"></script> + <script src="/static/js/jquery.textillate.js"></script> + <script src="/static/js/jquery.odometer.min.js"></script> + <script src="/static/js/jquery.appear.js"></script> + <script src="/static/js/owl.carousel.min.js"></script> + <script src="/static/js/jquery.countdown.min.js"></script> + <script src="/static/js/jquery.scrollUp.min.js"></script> + <script src="/static/js/imagesloaded.pkgd.min.js"></script> + <script src="/static/js/jquery.magnific-popup.min.js"></script> + <script src="/static/js/plugins.js"></script> + <script src="/static/js/main.js"></script> + </body> + </html> +{{end}} \ No newline at end of file diff --git a/assets/templates/form.tmpl b/assets/templates/form.tmpl index a20e0372f2092a6af670298e908bccc86cbc384f..652b9facb42d85f46f8b0320dfaafe8bff412b54 100644 --- a/assets/templates/form.tmpl +++ b/assets/templates/form.tmpl @@ -1,78 +1,5 @@ -<!doctype html> -<html class="no-js" lang=""> -<head> - <meta charset="utf-8"> - <meta http-equiv="x-ua-compatible" content="ie=edge"> - <title>Arena of Valor - Turnuva Kayıt</title> - <meta name="description" content=""> - <meta name="viewport" content="width=device-width, initial-scale=1"> - - <link rel="shortcut icon" type="image/x-icon" href="/static/img/favicon.png"> - <!-- Place favicon.ico in the root directory --> - - <!-- CSS here --> - <link rel="stylesheet" href="/static/css/bootstrap.min.css"> - <link rel="stylesheet" href="/static/css/animate.min.css"> - <link rel="stylesheet" href="/static/css/magnific-popup.css"> - <link rel="stylesheet" href="/static/css/fontawesome-all.min.css"> - <link rel="stylesheet" href="/static/css/odometer.css"> - <link rel="stylesheet" href="/static/css/aos.css"> - <link rel="stylesheet" href="/static/css/owl.carousel.min.css"> - <link rel="stylesheet" href="/static/css/meanmenu.css"> - <link rel="stylesheet" href="/static/css/slick.css"> - <link rel="stylesheet" href="/static/css/default.css"> - <link rel="stylesheet" href="/static/css/style.css"> - <link rel="stylesheet" href="/static/css/responsive.css"> -</head> -<body> - -<!-- preloader --> -<div id="preloader"> - <div id="loading-center"> - <div id="loading-center-absolute"> - <img src="/static/img/logo/logo.svg" alt=""> - </div> - </div> -</div> -<!-- preloader-end --> - -<!-- header-area --> -<header> - <div class="transparent-header"> - <div class="container"> - <div class="logo"> - <a href="/" style="text-align: center; width: 100%; display: block;"><img src="/static/img/logo/logo.svg" - alt="Logo" - style="width: 160px;"></a> - </div> - </div> - <div class="container-fluid s-container-full-padding"> - <div class="row"> - <div class="col-12"> - <div class="main-menu menu-style-two"> - <nav> - <div id="mobile-menu" class="navbar-wrap d-none d-lg-flex"> - <ul> - <li><a href="/"> <i class="fas fa-home"></i> Anasayfa</a> - <li class="show"><a href="/kayit"> <i class="fas fa-trophy"></i> Turnuva Kayıt</a> - </li> - <li><a href="https://www.instagram.com/arenaofvalor.turkiye/"> <i - class="fab fa-instagram"></i> Instagram</a></li> - <li><a href="https://discord.gg/aovtr"> <i class="fab fa-discord"></i> Discord</a> - </li> - </ul> - </div> - - </nav> - </div> - <div class="mobile-menu"></div> - </div> - </div> - </div> - </div> -</header> -<!-- header-area-end --> - +{{template "top"}} +{{template "header" .}} <!-- main-area --> <main> <!-- contact-area --> @@ -82,43 +9,36 @@ <div class="col-lg-6 col-xs-12 form-area"> <div class="form-container"> <div class="section-title title-style-three mb-20"> - <h2>TURNUVA KAYIT <span>FORMU</span></h2> + {{range .}} + <h2>{{.Name}} <span>FORMU</span></h2> </div> <div class="contact-form"> <form action="#"> <div class="row"> - <div class="col-md-12"> - <input name="teamName" type="text" placeholder="Takım Adınız"> - </div> + {{if .Team}} + <div class="col-md-12"> + <input name="teamName" type="text" placeholder="Takım Adınız"> + </div> + <div class="col-md-6"> + <input type="text" placeholder="Takım Kaptanınız"> + </div> + {{end}} <div class="col-md-6"> - <input type="text" placeholder="Takım Kaptanınız"> + <input type="text" placeholder="Adınız"> </div> <div class="col-md-6"> - <input type="text" placeholder="Takım Menajeriniz"> - </div> - <!-- oyuncular --> - <div class="col-md-6"> - <input type="text" placeholder="Oyuncu 1 Adı + Discord Etiketi"> - </div> - <div class="col-md-6"> - <input type="text" placeholder="Oyuncu 2 Adı + Discord Etiketi"> - </div> - <div class="col-md-6"> - <input type="text" placeholder="Oyuncu 3 Adı + Discord Etiketi"> - </div> - <div class="col-md-6"> - <input type="text" placeholder="Oyuncu 4 Adı + Discord Etiketi"> - </div> - <div class="col-md-6"> - <input type="text" placeholder="Oyuncu 5 Adı + Discord Etiketi"> - </div> - <div class="col-md-6"> - <input type="text" placeholder="Oyuncu 6 Adı + Discord Etiketi"> - </div> - <div class="col-md-12"> - <input type="text" placeholder="Oyuncu 7 Adı + Discord Etiketi"> + <input type="text" placeholder="Soyadınız"> </div> + + {{/* {{range $i := loop 1 .TeamSize}}*/}} + + {{/* <div class="col-md-6">*/}} + {{/* <input type="text" placeholder="Player {{ $i }} Name + UID">*/}} + {{/* </div>*/}} + + {{/* {{ end }}*/}} </div> + {{end}} <button>Gönder</button> </form> </div> @@ -130,28 +50,7 @@ <!-- contact-area-end --> </main> <!-- main-area-end --> - -<!-- JS here --> -<script src="/static/js/vendor/jquery-3.4.1.min.js"></script> -<script src="/static/js/popper.min.js"></script> -<script src="/static/js/bootstrap.min.js"></script> -<script src="/static/js/isotope.pkgd.min.js"></script> -<script src="/static/js/slick.min.js"></script> -<script src="/static/js/jquery.meanmenu.min.js"></script> -<script src="/static/js/wow.min.js"></script> -<script src="/static/js/aos.js"></script> -<script src="/static/js/jquery.lettering.js"></script> -<script src="/static/js/jquery.textillate.js"></script> -<script src="/static/js/jquery.odometer.min.js"></script> -<script src="/static/js/jquery.appear.js"></script> -<script src="/static/js/owl.carousel.min.js"></script> -<script src="/static/js/jquery.countdown.min.js"></script> -<script src="/static/js/jquery.scrollUp.min.js"></script> -<script src="/static/js/imagesloaded.pkgd.min.js"></script> -<script src="/static/js/jquery.magnific-popup.min.js"></script> <script src="https://maps.googleapis.com/maps/api/js?key=AIzaSyCIJ_QKHN-bi6_1C9f5eYE3pZs1zhQIo5o"></script> -<script src="/static/js/plugins.js"></script> -<script src="/static/js/main.js"></script> <script> function basicmap() { // Basic options for a simple Google Map @@ -249,5 +148,4 @@ google.maps.event.addDomListener(window, 'load', basicmap); } </script> -</body> -</html> +{{template "bottom"}} diff --git a/assets/templates/index.tmpl b/assets/templates/index.tmpl index 05877401eaf86382962038b3f18a191816e45313..b4d2a7eff49d811fe70143af80625f0ea9f9c6c1 100644 --- a/assets/templates/index.tmpl +++ b/assets/templates/index.tmpl @@ -1,77 +1,7 @@ -<!doctype html> -<html class="no-js" lang="tr"> -<head> - <meta charset="utf-8"> - <meta http-equiv="x-ua-compatible" content="ie=edge"> - <title>Arena of Valor - Turnuva Kayıt</title> - <meta name="description" content=""> - <meta name="viewport" content="width=device-width, initial-scale=1"> - - <link rel="shortcut icon" type="image/x-icon" href="/static/img/favicon.png"> - - <!-- CSS here --> - <link rel="stylesheet" href="/static/css/bootstrap.min.css"> - <link rel="stylesheet" href="/static/css/animate.min.css"> - <link rel="stylesheet" href="/static/css/magnific-popup.css"> - <link rel="stylesheet" href="/static/css/fontawesome-all.min.css"> - <link rel="stylesheet" href="/static/css/odometer.css"> - <link rel="stylesheet" href="/static/css/aos.css"> - <link rel="stylesheet" href="/static/css/owl.carousel.min.css"> - <link rel="stylesheet" href="/static/css/meanmenu.css"> - <link rel="stylesheet" href="/static/css/slick.css"> - <link rel="stylesheet" href="/static/css/default.css"> - <link rel="stylesheet" href="/static/css/style.css"> - <link rel="stylesheet" href="/static/css/responsive.css"> -</head> -<body> - -<!-- preloader --> -<div id="preloader"> - <div id="loading-center"> - <div id="loading-center-absolute"> - <img src="/static/img/logo/logo.svg" alt=""> - </div> - </div> -</div> -<!-- preloader-end --> -<!-- header-area --> -<header> - <div class="transparent-header"> - <div class="container"> - <div class="logo"> - <a href="/" style="text-align: center; width: 100%; display: block;"><img src="/static/img/logo/logo.svg" - alt="Logo" - style="width: 160px;"></a> - </div> - </div> - <div class="container-fluid s-container-full-padding"> - <div class="row"> - <div class="col-12"> - <div class="main-menu menu-style-two"> - <nav> - <div id="mobile-menu" class="navbar-wrap d-none d-lg-flex"> - <ul> - <li class="show"><a href="#"> <i class="fas fa-home"></i> Anasayfa</a></li> - <li><a href="/kayit"> <i class="fas fa-trophy"></i> Turnuva Kayıt</a> - <li><a href="https://www.instagram.com/arenaofvalor.turkiye/"> <i - class="fab fa-instagram"></i> Instagram</a></li> - <li><a href="https://discord.gg/aovtr"> <i class="fab fa-discord"></i> Discord</a> - </li> - </ul> - </div> - - </nav> - </div> - <div class="mobile-menu"></div> - </div> - </div> - </div> - </div> -</header> -<!-- header-area-end --> +{{template "top"}} +{{template "header" .}} <!-- main-area --> <main> - <!-- slider-area --> <section class="third-banner-bg"> <div class="container custom-container"> @@ -80,81 +10,31 @@ <div class="row"> <div class="col-12 tournament-container"> <div class="my-match-wrap"> - <!-- Turnuva 1 Başlangıç --> - <div class="my-match-box-wrap wow fadeInDown" data-wow-delay=".2s" - style="background-image: url('/static/img/bg/1.png');"> - <img src="/static/img/bg/my_match_box.png" alt="" class="match-box-bg"> - <ul> - <li> - <div class="tournament-image"> - - </div> - </li> - <li> - <div class="my-match-info"> - <a href="https://www.twitch.tv/arenaofvalortr" target="_blank" - class="live-btn">Canlı Yayın!</a> <!-- Canlı yayın butonu --> - <h5>AoV 1vs1 Turnuvası</h5> - <span>20 Kasım 2021 20:00</span> - </div> - </li> - <li> - <a href="/kayit" target="_blank" class="watch-stream"><i - class="fas fa-podcast"></i> Kayıt Ol</a> - </li> - </ul> - </div> - <!-- Turnuva 1 Son --> - - <!-- Turnuva 2 Başlangıç --> - <div class="my-match-box-wrap wow fadeInDown" data-wow-delay=".4s" - style="background-image: url('/static/img/bg/2-box.png');"> - <img src="/static/img/bg/my_matchbox_2.png" alt="" class="match-box-bg"> - <ul> - <li> - <div class="tournament-image"> - - </div> - </li> - <li> - <div class="my-match-info"> - <h5>AoV 1vs1 Turnuvası</h5> - <span>20 Kasım 2021 20:00</span> - <span>Son Kayıt: 19 Kasım 23:59</span> - </div> - </li> - <li> - <a href="/kayit" target="_blank" class="watch-stream"><i - class="fas fa-podcast"></i> Kayıt Ol</a> - </li> - </ul> - </div> - <!-- Turnuva 2 Son --> - - <!-- Turnuva 3 Başlangıç --> - <div class="my-match-box-wrap wow fadeInDown" data-wow-delay=".2s" - style="background-image: url('/static/img/bg/box-3.png');"> - <img src="/static/img/bg/my_matchbox_3.png" alt="" class="match-box-bg"> - <ul> - <li> - <div class="tournament-image"> - - </div> - </li> - <li> - <div class="my-match-info"> - <h5>AoV 1vs1 Turnuvası</h5> - <span>20 Kasım 2021 20:00</span> - <span>Son Kayıt: 19 Kasım 23:59</span> - </div> - </li> - <li> - <a href="/" target="_blank" class="watch-stream"><i - class="fas fa-podcast"></i> Kayıt Ol</a> - </li> - </ul> - </div> - <!-- Turnuva 3 Son --> + {{range .tournaments}} + <div class="my-match-box-wrap wow fadeInDown" data-wow-delay=".2s" + style="background-image: url('/static/img/bg/1.png');"> + <img src="/static/img/bg/my_match_box.png" alt="" class="match-box-bg"> + <ul> + <li> + <div class="tournament-image"> + + </div> + </li> + <li> + <div class="my-match-info"> + <a href="https://www.twitch.tv/arenaofvalortr" target="_blank" + class="live-btn">Canlı Yayın!</a> + <h5>{{.Name}}</h5> + <span>{{.Date}}</span> + </div> + </li> + <li> + <a href="/enroll/{{.ID}}" target="_blank" class="watch-stream"><i + class="fas fa-podcast"></i> Kayıt Ol</a> + </li> + </ul> + </div> + {{end}} </div> </div> </div> @@ -163,30 +43,6 @@ </div> </section> <!-- slider-area-end --> - </main> <!-- main-area-end --> - - -<!-- JS here --> -<script src="/static/js/vendor/jquery-3.4.1.min.js"></script> -<script src="/static/js/popper.min.js"></script> -<script src="/static/js/bootstrap.min.js"></script> -<script src="/static/js/isotope.pkgd.min.js"></script> -<script src="/static/js/slick.min.js"></script> -<script src="/static/js/jquery.meanmenu.min.js"></script> -<script src="/static/js/wow.min.js"></script> -<script src="/static/js/aos.js"></script> -<script src="/static/js/jquery.lettering.js"></script> -<script src="/static/js/jquery.textillate.js"></script> -<script src="/static/js/jquery.odometer.min.js"></script> -<script src="/static/js/jquery.appear.js"></script> -<script src="/static/js/owl.carousel.min.js"></script> -<script src="/static/js/jquery.countdown.min.js"></script> -<script src="/static/js/jquery.scrollUp.min.js"></script> -<script src="/static/js/imagesloaded.pkgd.min.js"></script> -<script src="/static/js/jquery.magnific-popup.min.js"></script> -<script src="/static/js/plugins.js"></script> -<script src="/static/js/main.js"></script> -</body> -</html> +{{template "bottom"}} diff --git a/assets/templates/tournament-config.tmpl b/assets/templates/tournament-config.tmpl new file mode 100644 index 0000000000000000000000000000000000000000..9f222cf4c03a24994ef6f2e08de9a0f6f46e1859 --- /dev/null +++ b/assets/templates/tournament-config.tmpl @@ -0,0 +1,150 @@ +{{template "top"}} +{{template "header" .}} +<!-- main-area --> +<main> + <!-- contact-area --> + <section class="contact-area pt-200 pb-120"> + <div class="container"> + <div class="row"> + <div class="col-lg-6 col-xs-12 form-area"> + <div class="form-container"> + <div class="section-title title-style-three mb-20"> + <h2>TURNUVA <span>EKLE</span></h2> + </div> + <div class="contact-form"> + <form action="#"> + <div class="row"> + <div class="col-md-12"> + <input type="text" placeholder="Turnuva Başlığı"> + </div> + <div class="col-md-6"> + <input type="date" placeholder="Turnuva Tarihi"> + </div> + <div class="col-md-6"> + <input type="text" placeholder="Son Kayıt Tarihi"> + </div> + <!-- oyuncular --> + <div class="col-md-6"> + <select id="cars" name="cars"> + <option value="volvo">1 v 1</option> + <option value="saab">2 v 2</option> + <option value="saab">3 v 3</option> + <option value="fiat">4 v 4</option> + <option value="audi">5 v 5</option> + </select> + </div> + <div class="col-md-6"> + <input type="text" placeholder="Turnuva Ödülü"> + </div> + </div> + <button>EKLE</button> + </form> + </div> + </div> + </div> + </div> + </div> + </section> + <!-- contact-area-end --> +</main> +<!-- main-area-end --> + +<script src="https://maps.googleapis.com/maps/api/js?key=AIzaSyCIJ_QKHN-bi6_1C9f5eYE3pZs1zhQIo5o"></script> +<script> + function basicmap() { + // Basic options for a simple Google Map + // For more options see: https://developers.google.com/maps/documentation/javascript/reference#MapOptions + var mapOptions = { + // How zoomed in you want the map to start at (always required) + zoom: 11, + scrollwheel: false, + // The latitude and longitude to center the map (always required) + center: new google.maps.LatLng(40.6700, -73.9400), // New York + // This is where you would paste any style found on Snazzy Maps. + styles: [{ + "featureType": "all", + "elementType": "geometry.fill", + "stylers": [{"weight": "2.00"}] + }, { + "featureType": "all", + "elementType": "geometry.stroke", + "stylers": [{"color": "#9c9c9c"}] + }, { + "featureType": "all", + "elementType": "labels.text", + "stylers": [{"visibility": "on"}] + }, { + "featureType": "landscape", + "elementType": "all", + "stylers": [{"color": "#f2f2f2"}] + }, { + "featureType": "landscape", + "elementType": "geometry.fill", + "stylers": [{"color": "#ffffff"}] + }, { + "featureType": "landscape.man_made", + "elementType": "geometry.fill", + "stylers": [{"color": "#ffffff"}] + }, {"featureType": "poi", "elementType": "all", "stylers": [{"visibility": "off"}]}, { + "featureType": "road", + "elementType": "all", + "stylers": [{"saturation": -100}, {"lightness": 45}] + }, { + "featureType": "road", + "elementType": "geometry.fill", + "stylers": [{"color": "#eeeeee"}] + }, { + "featureType": "road", + "elementType": "labels.text.fill", + "stylers": [{"color": "#7b7b7b"}] + }, { + "featureType": "road", + "elementType": "labels.text.stroke", + "stylers": [{"color": "#ffffff"}] + }, { + "featureType": "road.highway", + "elementType": "all", + "stylers": [{"visibility": "simplified"}] + }, { + "featureType": "road.arterial", + "elementType": "labels.icon", + "stylers": [{"visibility": "off"}] + }, { + "featureType": "transit", + "elementType": "all", + "stylers": [{"visibility": "off"}] + }, { + "featureType": "water", + "elementType": "all", + "stylers": [{"color": "#46bcec"}, {"visibility": "on"}] + }, { + "featureType": "water", + "elementType": "geometry.fill", + "stylers": [{"color": "#c8d7d4"}] + }, { + "featureType": "water", + "elementType": "labels.text.fill", + "stylers": [{"color": "#070707"}] + }, {"featureType": "water", "elementType": "labels.text.stroke", "stylers": [{"color": "#ffffff"}]}] + }; + // Get the HTML DOM element that will contain your map + // We are using a div with id="map" seen below in the <body> + var mapElement = document.getElementById('contact-map'); + + // Create the Google Map using our element and options defined above + var map = new google.maps.Map(mapElement, mapOptions); + + // Let's also add a marker while we're at it + var marker = new google.maps.Marker({ + position: new google.maps.LatLng(40.6700, -73.9400), + map: map, + icon: 'img/icon/map_marker.png', + title: 'Geco' + }); + } + + if ($('#contact-map').length != 0) { + google.maps.event.addDomListener(window, 'load', basicmap); + } +</script> +{{template "bottom"}} diff --git a/cleanup.go b/cleanup.go index 32c50d4afa93611aa917cf025b4660517e68ed4c..04a36bdefa258b27fa1d1e6d58fbb3e7589c935e 100644 --- a/cleanup.go +++ b/cleanup.go @@ -12,4 +12,6 @@ func cleanup() { if err := server.Shutdown(ctx); err != nil { log.Printf("error shutting down web server: %s", err) } + + closeDatabase() } diff --git a/config.go b/config.go index 4cdb61765f148cfeda9266619f9300cde63d46c8..cb7242651f8b499a2720b7415e4006b762d36da5 100644 --- a/config.go +++ b/config.go @@ -5,8 +5,11 @@ import ( "github.com/BurntSushi/toml" "log" "os" + "strconv" ) +var administrators map[string]bool + type conf struct { System systemConf `toml:"system"` Server serverConf `toml:"server"` @@ -29,8 +32,9 @@ type systemConf struct { } type discordConf struct { - ClientID string `toml:"client_id"` - ClientSecret string `toml:"client_secret"` + ClientID string `toml:"client_id"` + ClientSecret string `toml:"client_secret"` + Administrators []int `toml:"administrators"` } var ( @@ -67,6 +71,14 @@ func confLoad() { log.Printf("unused key in configuration file: %s", key.String()) } } + + if len(config.Discord.Administrators) != 0 && config.Discord.Administrators[0] != -1 { + administrators = make(map[string]bool) + + for _, id := range config.Discord.Administrators { + administrators[strconv.Itoa(id)] = true + } + } } var defConf = conf{ @@ -88,7 +100,8 @@ var defConf = conf{ Secret: "RANDOM_STRING", }, Discord: discordConf{ - ClientID: "", - ClientSecret: "", + ClientID: "", + ClientSecret: "", + Administrators: []int{-1}, }, } diff --git a/database.go b/database.go new file mode 100644 index 0000000000000000000000000000000000000000..8697a944b3dcf9f5db8b5c2cc4351f2dcf560550 --- /dev/null +++ b/database.go @@ -0,0 +1,33 @@ +package main + +import ( + "github.com/syndtr/goleveldb/leveldb" + "log" +) + +var ( + tournamentDB *leveldb.DB + userDB *leveldb.DB +) + +func openDatabase() { + if db, err := leveldb.OpenFile(config.System.Store+"/tournament", nil); err != nil { + log.Fatalf("error opening tournament database: %s", err) + } else { + tournamentDB = db + } + if db, err := leveldb.OpenFile(config.System.Store+"/user", nil); err != nil { + log.Fatalf("error opening user database: %s", err) + } else { + userDB = db + } +} + +func closeDatabase() { + if err := tournamentDB.Close(); err != nil { + log.Printf("error closing tournament database: %s", err) + } + if err := userDB.Close(); err != nil { + log.Printf("error closing user database: %s", err) + } +} diff --git a/go.mod b/go.mod index 8cc5bf98332218362fe912d0e2f6cc99fc6ed711..3ddd9ea0d0b65a6528109e2a555cfc25ef29740c 100644 --- a/go.mod +++ b/go.mod @@ -4,23 +4,26 @@ go 1.17 require ( github.com/BurntSushi/toml v0.4.1 + github.com/bwmarrin/discordgo v0.23.2 + github.com/gin-contrib/sessions v0.0.4 github.com/gin-gonic/gin v1.7.4 + github.com/google/uuid v1.3.0 + github.com/json-iterator/go v1.1.9 + github.com/syndtr/goleveldb v1.0.0 + golang.org/x/oauth2 v0.0.0-20211104180415-d3ed0bb246c8 ) require ( - github.com/bwmarrin/discordgo v0.23.2 // indirect - github.com/gin-contrib/sessions v0.0.4 // indirect github.com/gin-contrib/sse v0.1.0 // indirect github.com/go-playground/locales v0.13.0 // indirect github.com/go-playground/universal-translator v0.17.0 // indirect github.com/go-playground/validator/v10 v10.4.1 // indirect github.com/golang/protobuf v1.4.2 // indirect - github.com/google/uuid v1.3.0 // indirect + github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db // indirect github.com/gorilla/context v1.1.1 // indirect github.com/gorilla/securecookie v1.1.1 // indirect github.com/gorilla/sessions v1.2.0 // indirect github.com/gorilla/websocket v1.4.0 // indirect - github.com/json-iterator/go v1.1.9 // indirect github.com/leodido/go-urn v1.2.0 // indirect github.com/mattn/go-isatty v0.0.12 // indirect github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421 // indirect @@ -28,7 +31,6 @@ require ( github.com/ugorji/go/codec v1.1.7 // indirect golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9 // indirect golang.org/x/net v0.0.0-20200822124328-c89045814202 // indirect - golang.org/x/oauth2 v0.0.0-20211104180415-d3ed0bb246c8 // indirect golang.org/x/sys v0.0.0-20200803210538-64077c9b5642 // indirect google.golang.org/appengine v1.6.6 // indirect google.golang.org/protobuf v1.25.0 // indirect diff --git a/go.sum b/go.sum index ae6c3eba55d2cabeea0b688de49e8d1c1685ecb5..53c2e2fe8ba6a1881adfc8ca6afa580264a229d8 100644 --- a/go.sum +++ b/go.sum @@ -54,6 +54,7 @@ github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymF github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= +github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= github.com/gin-contrib/sessions v0.0.4 h1:gq4fNa1Zmp564iHP5G6EBuktilEos8VKhe2sza1KMgo= github.com/gin-contrib/sessions v0.0.4/go.mod h1:pQ3sIyviBBGcxgyR8mkeJuXbeV3h3NYmhJADQTq5+Vo= github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE= @@ -86,7 +87,6 @@ github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71 github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= -github.com/golang/protobuf v1.3.3 h1:gyjaxf+svBWX08ZjK86iN9geUJF0H6gp2IRKX6Nf6/I= github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= github.com/golang/protobuf v1.3.4/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= github.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk= @@ -98,6 +98,8 @@ github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvq github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8= github.com/golang/protobuf v1.4.2 h1:+Z5KGCizgyZCbGh1KZqA0fcLLkwbsjIzS4aV2v7wJX0= github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= +github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db h1:woRePGFeVFfLKN/pOkfl+p/TAqKOfFu+7KPlMVpok/w= +github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/gomodule/redigo v2.0.0+incompatible/go.mod h1:B4C85qUVwatsJoIUNIfCRsp7qO0iAmpGFZ4EELWSbC4= github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= @@ -107,6 +109,7 @@ github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMyw github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.1 h1:JFrFEBb2xKufg6XkJsJr+WbKb4FQlURi5RUcBveYu9k= github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= @@ -134,6 +137,8 @@ github.com/gorilla/websocket v1.4.0 h1:WDFjx/TMzVgy9VdMMQi2K2Emtwi2QcUQsztZ/zLaH github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI= +github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= github.com/json-iterator/go v1.1.9 h1:9yzud/Ht36ygwatGx56VwCZtlI/2AD15T1X2sjSuGns= github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= @@ -141,8 +146,10 @@ github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1 github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= github.com/kidstuff/mongostore v0.0.0-20181113001930-e650cd85ee4b/go.mod h1:g2nVr8KZVXJSS97Jo8pJ0jgq29P6H7dG0oplUA86MQw= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= +github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/leodido/go-urn v1.2.0 h1:hpXL4XnriNwQ/ABnpepYM/1vCLWNDfUNts8dX3xTG6Y= github.com/leodido/go-urn v1.2.0/go.mod h1:+8+nEpDfqqsY+g338gtMEUOtuK+4dEMhiQEgxpxOKII= @@ -154,6 +161,11 @@ github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421 h1:ZqeYNhU3OH github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742 h1:Esafd1046DLDQ0W1YjYsBW+p8U2u7vzgW2SQVmlNazg= github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.7.0 h1:WSHQ+IS43OoUrWtD1/bbclrwK8TTH5hzp+umCiuxHgs= +github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/gomega v1.4.3 h1:RE1xgDvH7imwFD45h+u2SgIfERHlS2yNG4DObb5BSKU= +github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= @@ -162,9 +174,11 @@ github.com/quasoft/memstore v0.0.0-20191010062613-2bce066d2b0b/go.mod h1:wTPjTep github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= -github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= +github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/syndtr/goleveldb v1.0.0 h1:fBdIW9lB4Iz0n9khmH8w27SJ3QEJ7+IgjPEwGSZiFdE= +github.com/syndtr/goleveldb v1.0.0/go.mod h1:ZVVdQEZoIme9iO1Ch2Jdy24qqXrMMOU6lpPAyBWyWuQ= github.com/ugorji/go v1.1.7 h1:/68gy2h+1mWMrwZFeD1kQialdSzAb432dtpeJ42ovdo= github.com/ugorji/go v1.1.7/go.mod h1:kZn38zHttfInRq0xu/PH0az30d+z6vm202qpg1oXVMw= github.com/ugorji/go/codec v1.1.7 h1:2SvQaVZ1ouYrrKKwoSk2pzd4A9evlKJb9oTL+OaLUSs= @@ -216,6 +230,7 @@ golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= @@ -257,6 +272,7 @@ golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -269,7 +285,6 @@ golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200116001909-b77594299b42 h1:vEOn+mP2zCOVzKckCZy6YsCtDblrpj/w7B9nxGNELpg= golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -288,6 +303,7 @@ golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fq golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= +golang.org/x/text v0.3.3 h1:cokOdA+Jmi5PJGXLlLllQSgYigAEfHXJAERHVMaCc2k= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= @@ -335,6 +351,7 @@ golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M= @@ -411,13 +428,19 @@ google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpAD google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4= google.golang.org/protobuf v1.25.0 h1:Ejskq+SyPohKW+1uil0JJMtmHCgJPJ/qWTxr8qp+R4c= google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= -gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= +gopkg.in/fsnotify.v1 v1.4.7 h1:xOHLXZwVvI9hhs+cLKq5+I5onOuwQLhQwiu63xxlHs4= +gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= +gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= +gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= +gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10= gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= diff --git a/main.go b/main.go index 459fdf2eb857ed0fb51d2d0cfc236e9dbe956a16..55933b72a36c992bbf923ae67adb0ea29c887af8 100644 --- a/main.go +++ b/main.go @@ -12,6 +12,7 @@ func main() { flag.Parse() confLoad() + openDatabase() webSetup() sig := make(chan os.Signal, 1) diff --git a/routes.go b/routes.go index 7e91f25c129a2bbf8f2e656e8c667124ea473ccb..7f77cabef142ed90be570e470326aa5235be2559 100644 --- a/routes.go +++ b/routes.go @@ -5,20 +5,116 @@ import ( "github.com/gin-contrib/sessions" "github.com/gin-gonic/gin" "github.com/google/uuid" + "log" "net/http" + "time" ) -const formPath = "/kayit" +type tournament struct { + Title string `json:"name"` + ID uuid.UUID `json:"id"` + StartTime time.Time `json:"start_time"` + EndTime time.Time `json:"end_time"` + TeamSize int `json:"team_size"` +} func registerRoutes() { router.GET("/", func(context *gin.Context) { - // TODO - context.HTML(http.StatusOK, "index.tmpl", gin.H{}) + authText, authRef := getAuthButton(oauth.GetSelf(context)) + if t, err := getTournaments(); err != nil { + log.Printf("error retrieving tournaments: %s", err) + context.String(http.StatusInternalServerError, "Internal Server Error") + return + } else { + context.HTML(http.StatusOK, "index.tmpl", gin.H{ + "auth_text": authText, + "auth_ref": authRef, + "tournaments": t, + }) + } + }) + + router.GET("/enroll/:id", func(context *gin.Context) { + user := oauth.GetSelf(context) + if user == nil { + context.Redirect(http.StatusTemporaryRedirect, "/auth/login") + return + } + + // TODO: consume user stuff here + + var t *tournament + if id, err := uuid.Parse(context.Param("id")); err != nil { + if config.System.Verbose { + log.Printf("error parsing UUID %s: %s", context.Param("id"), err) + } + context.Redirect(http.StatusTemporaryRedirect, "/") + return + } else { + if t, _, err = getTournament(id); err != nil { + if config.System.Verbose { + log.Printf("error fetching form %s: %s", id.String(), err) + } + context.Redirect(http.StatusTemporaryRedirect, "/") + return + } + } + + context.HTML(http.StatusOK, "form.tmpl", gin.H{ + "tournament": t, + }) + }) + + router.POST("/enroll/:id", func(context *gin.Context) { + user := oauth.GetSelf(context) + if user == nil { + context.Redirect(http.StatusTemporaryRedirect, "/auth/login") + return + } + + // TODO: handle form submit + }) + + router.GET("/admin", func(context *gin.Context) { + user := oauth.GetSelf(context) + if user == nil { + context.Redirect(http.StatusTemporaryRedirect, "/auth/login") + return + } + + if !administrators[user.ID] { + context.Redirect(http.StatusTemporaryRedirect, "/") + return + } + + authText, authRef := getAuthButton(user) + + if t, err := getTournaments(); err != nil { + log.Printf("error retrieving tournaments: %s", err) + context.String(http.StatusInternalServerError, "Internal Server Error") + return + } else { + context.HTML(http.StatusOK, "admin.tmpl", gin.H{ + "auth_text": authText, + "auth_ref": authRef, + "tournaments": t, + }) + } }) - router.GET(formPath, func(context *gin.Context) { - // TODO - context.HTML(http.StatusOK, "form.tmpl", gin.H{}) + router.POST("/admin", func(context *gin.Context) { + user := oauth.GetSelf(context) + if user == nil { + context.Redirect(http.StatusTemporaryRedirect, "/auth/login") + return + } + + if !administrators[user.ID] { + context.Redirect(http.StatusTemporaryRedirect, "/") + return + } + + // TODO: handle updates }) // OAuth @@ -51,6 +147,12 @@ func registerRoutes() { } oauth.StoreToken(context, token) _ = session.Save() - context.Redirect(http.StatusTemporaryRedirect, formPath) + context.Redirect(http.StatusTemporaryRedirect, "/") }) + + if config.System.Verbose { + router.GET("/auth/user", func(context *gin.Context) { + context.JSON(http.StatusOK, oauth.GetSelf(context)) + }) + } } diff --git a/tournament.go b/tournament.go new file mode 100644 index 0000000000000000000000000000000000000000..520b8dfc4f3aaf07017bee4e2597e9c8680a4ae3 --- /dev/null +++ b/tournament.go @@ -0,0 +1,154 @@ +package main + +import ( + "github.com/google/uuid" + json "github.com/json-iterator/go" + "sync" +) + +// TODO: leveldb.ErrNotFound + +var tournamentLock = sync.RWMutex{} + +var ( + tournamentsCache []*tournament + tournamentsCacheInvalid = true + tournamentCache map[string]*tournament +) + +func getTournaments() ([]*tournament, error) { + tournamentLock.RLock() + defer tournamentLock.RUnlock() + + if tournamentsCacheInvalid { + tournamentLock.RUnlock() + defer tournamentLock.RLock() + tournamentLock.Lock() + defer tournamentLock.Unlock() + + tournamentsCache = nil + iter := tournamentDB.NewIterator(nil, nil) + for iter.Next() { + var t tournament + payload := iter.Value() + if err := json.Unmarshal(payload, &t); err != nil { + return nil, err + } else { + tournamentsCache = append(tournamentsCache, &t) + tournamentCache[string(iter.Key())] = &t + } + } + iter.Release() + if err := iter.Error(); err != nil { + return nil, err + } + tournamentsCacheInvalid = false + } + return tournamentsCache, nil +} + +func getTournament(id uuid.UUID) (*tournament, []byte, error) { + tournamentLock.RLock() + defer tournamentLock.RUnlock() + + var b []byte + if payload, err := id.MarshalBinary(); err != nil { + return nil, nil, err + } else { + b = payload + } + + if t, ok := tournamentCache[string(b)]; !ok { + tournamentLock.RUnlock() + defer tournamentLock.RLock() + tournamentLock.Lock() + defer tournamentLock.Unlock() + + if payload, err := tournamentDB.Get(b, nil); err != nil { + return nil, nil, err + } else { + t = &tournament{} + if err = json.Unmarshal(payload, t); err != nil { + return nil, nil, err + } else { + tournamentCache[string(b)] = t + return t, b, nil + } + } + } else { + return t, b, nil + } +} + +func makeTournament(t *tournament) error { + t.ID = uuid.New() + + var b []byte + if payload, err := t.ID.MarshalBinary(); err != nil { + return err + } else { + b = payload + } + + tournamentLock.Lock() + defer tournamentLock.Unlock() + + if payload, err := json.Marshal(t); err != nil { + return err + } else { + if err = tournamentDB.Put(b, payload, nil); err != nil { + return err + } + + tournamentsCacheInvalid = true + tournamentCache[string(b)] = t + return nil + } +} + +func updateTournament(t *tournament) error { + var b []byte + if _, p, err := getTournament(t.ID); err != nil { + return err + } else { + b = p + } + + tournamentLock.Lock() + defer tournamentLock.Unlock() + + if payload, err := json.Marshal(t); err != nil { + return err + } else { + if err = tournamentDB.Put(b, payload, nil); err != nil { + return err + } + + tournamentsCacheInvalid = true + tournamentCache[string(b)] = t + return nil + } +} + +func destroyTournament(id uuid.UUID) error { + var b []byte + if _, p, err := getTournament(id); err != nil { + return err + } else { + b = p + } + + tournamentLock.Lock() + defer tournamentLock.Unlock() + + if err := tournamentDB.Delete(b, nil); err != nil { + return err + } + + if _, ok := tournamentCache[string(b)]; ok { + delete(tournamentCache, string(b)) + } + tournamentsCacheInvalid = true + + return nil +} diff --git a/user.go b/user.go new file mode 100644 index 0000000000000000000000000000000000000000..9626b9d6353b3c4c0348af41ef16b6e16d582880 --- /dev/null +++ b/user.go @@ -0,0 +1,18 @@ +package main + +import ( + "github.com/bwmarrin/discordgo" + "sync" +) + +var userLock = sync.RWMutex{} + +func getAuthButton(user *discordgo.User) (authText, authRef string) { + authText = "Login" + authRef = "/auth/login" + if user != nil { + authText = user.Username + " (Click to logout)" + authRef = "/auth/logout" + } + return +} diff --git a/web.go b/web.go index 8e4c1d82ec3390e1b0a998704d7b539bc3b38777..e7f75d44d05e5433c83c9d8d910cf82df30cd7d4 100644 --- a/web.go +++ b/web.go @@ -51,29 +51,6 @@ func webSetup() { context.Redirect(http.StatusTemporaryRedirect, "/") }) - if config.Server.Unix { - if l, err := net.Listen("unix", config.Server.Host); err != nil { - log.Fatalf("error listening on socket: %s", err) - } else { - listener = l - } - - if err := os.Chmod(config.Server.Host, 0777); err != nil { - log.Printf("error chmod: %s", err) - } - - log.Printf("web server listening on socket %s", config.Server.Host) - } else { - if l, err := net.Listen("tcp", config.Server.Host+":"+strconv.Itoa(int(config.Server.Port))); err != nil { - log.Fatalf("error listening on TCP port: %s", err) - } else { - listener = l - } - - log.Printf("web server listening on %s:%d", config.Server.Host, config.Server.Port) - } - server.Handler = router - if stat, err := os.Stat("assets/static"); err == nil && stat.IsDir() { log.Print("serving static assets from filesystem") router.Static("/static", "assets/static") @@ -102,9 +79,32 @@ func webSetup() { ClientSecret: config.Discord.ClientSecret, Endpoint: oauth.Endpoint(), RedirectURL: config.Server.BaseURL + "auth/callback", - Scopes: []string{oauth.ScopeIdentify, oauth.ScopeGuilds}, + Scopes: []string{oauth.ScopeIdentify}, } registerRoutes() + + if config.Server.Unix { + if l, err := net.Listen("unix", config.Server.Host); err != nil { + log.Fatalf("error listening on socket: %s", err) + } else { + listener = l + } + + if err := os.Chmod(config.Server.Host, 0777); err != nil { + log.Printf("error chmod: %s", err) + } + + log.Printf("web server listening on socket %s", config.Server.Host) + } else { + if l, err := net.Listen("tcp", config.Server.Host+":"+strconv.Itoa(int(config.Server.Port))); err != nil { + log.Fatalf("error listening on TCP port: %s", err) + } else { + listener = l + } + + log.Printf("web server listening on %s:%d", config.Server.Host, config.Server.Port) + } + server.Handler = router } func serve() {