mirror of
https://git.wownero.com/wownero/YellWOWPages.git
synced 2024-08-15 01:03:25 +00:00
Commit
This commit is contained in:
commit
6b300fd304
22 changed files with 1082 additions and 0 deletions
5
TODO
Normal file
5
TODO
Normal file
|
@ -0,0 +1,5 @@
|
|||
remove Constraints.client_secret before publishing and make a backup of it!!
|
||||
|
||||
Register new application new login.wownero.com
|
||||
client_id = yellwowpages
|
||||
client url = <domain>/authenticate
|
0
classes/__init__.py
Normal file
0
classes/__init__.py
Normal file
8
classes/constraints.py
Normal file
8
classes/constraints.py
Normal file
|
@ -0,0 +1,8 @@
|
|||
from starlette.templating import Jinja2Templates
|
||||
|
||||
|
||||
class Constraints:
|
||||
templates = Jinja2Templates(directory='frontend/templates')
|
||||
client_id = ''
|
||||
client_secret = ''
|
||||
uri = 'sqlite:///users.db'
|
4
frontend/static/colors.css
Normal file
4
frontend/static/colors.css
Normal file
|
@ -0,0 +1,4 @@
|
|||
:root{
|
||||
--yellow: #ffcc00;
|
||||
--purple: #ff2ad4;
|
||||
}
|
1
frontend/static/icon.css
Normal file
1
frontend/static/icon.css
Normal file
File diff suppressed because one or more lines are too long
BIN
frontend/static/wownero.png
Normal file
BIN
frontend/static/wownero.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 12 KiB |
108
frontend/templates/about/api/index.html
Normal file
108
frontend/templates/about/api/index.html
Normal file
|
@ -0,0 +1,108 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en" data-theme="dark">
|
||||
<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">
|
||||
<title>YellWOWPages - Sex and Drugs in the metaverse</title>
|
||||
<link rel="stylesheet" href="https://unpkg.com/@picocss/pico@latest/css/pico.min.css">
|
||||
<link rel="stylesheet" href="../../static/colors.css">
|
||||
<link rel="stylesheet" href="../../static/icon.css">
|
||||
</head>
|
||||
<style>
|
||||
html, body{
|
||||
font-family: 'Courier New', Courier, monospace;
|
||||
overflow: hidden;
|
||||
}
|
||||
a{
|
||||
color: var(--yellow);
|
||||
}
|
||||
span{
|
||||
color: var(--purple);
|
||||
}
|
||||
.nav{
|
||||
border-color: var(--yellow);
|
||||
border: 2px;
|
||||
}
|
||||
#dropdown{
|
||||
position: relative;
|
||||
display: inline-block;
|
||||
}
|
||||
#dropdowncontent{
|
||||
display: none;
|
||||
top: 0;
|
||||
position: absolute;
|
||||
background-color: var(--table-border-color);
|
||||
min-width: 160px;
|
||||
box-shadow: 0px 8px 16px 0px rgba(0,0,0,0.2);
|
||||
padding: 30px 50px;
|
||||
color: var(--yellow);
|
||||
text-align: center;
|
||||
z-index: 1;
|
||||
}
|
||||
#dropdown:hover #dropdowncontent {
|
||||
display: block;
|
||||
}
|
||||
#main{
|
||||
width: 100%;
|
||||
height: 80vh;
|
||||
display: grid;
|
||||
place-content: center;
|
||||
text-align: center;
|
||||
}
|
||||
form{
|
||||
height: 50px;
|
||||
}
|
||||
#footer{
|
||||
height: 12vh;
|
||||
width: 100%;
|
||||
text-align: center;
|
||||
}
|
||||
@media (max-width: 800px) {
|
||||
kbd{
|
||||
width: 100vw;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
<body>
|
||||
<div class="container-fluid">
|
||||
<nav>
|
||||
<ul>
|
||||
<li>
|
||||
<div id="dropdown">
|
||||
<i class="icon icon-menu"></i>
|
||||
<div id="dropdowncontent">
|
||||
<p>
|
||||
<a href="/login">Login</a>
|
||||
<a href="/dashboard">Dashboard</a>
|
||||
<a href="/yellwowpage">Yell<span>WOW</span>Page</a>
|
||||
<a href="/about">About</a>
|
||||
<a href="/about/api">Api</a>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</li>
|
||||
</ul>
|
||||
<ul>
|
||||
<li><strong><a href="/">Yell<span>WOW</span>Pages</a></strong></li>
|
||||
</ul>
|
||||
<ul>
|
||||
<li><a href="https://git.wownero.com/muchwowmining/YellWOWPages"><i class="icon icon-edit"></i></a></li>
|
||||
</ul>
|
||||
</nav>
|
||||
</div>
|
||||
<div class="container-fluid">
|
||||
<div id="main">
|
||||
<h1>About - Api</h1>
|
||||
<p>
|
||||
Search user: <code><a href="/api/user/{username}" data-tooltip="no partial search yet">/api/user/{username}</a></code>
|
||||
<br><br>
|
||||
Get all users: <code><a href="/api/all">/api/all</a></code>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<div id="footer">
|
||||
2022 - ... [the future is w0w]
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
125
frontend/templates/about/index.html
Normal file
125
frontend/templates/about/index.html
Normal file
|
@ -0,0 +1,125 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en" data-theme="dark">
|
||||
<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">
|
||||
<title>YellWOWPages - Sex and Drugs in the metaverse</title>
|
||||
<link rel="stylesheet" href="https://unpkg.com/@picocss/pico@latest/css/pico.min.css">
|
||||
<link rel="stylesheet" href="../../static/colors.css">
|
||||
<link rel="stylesheet" href="../../static/icon.css">
|
||||
</head>
|
||||
<style>
|
||||
html, body{
|
||||
font-family: 'Courier New', Courier, monospace;
|
||||
overflow: hidden;
|
||||
}
|
||||
a{
|
||||
color: var(--yellow);
|
||||
}
|
||||
span{
|
||||
color: var(--purple);
|
||||
}
|
||||
.nav{
|
||||
border-color: var(--yellow);
|
||||
border: 2px;
|
||||
}
|
||||
#dropdown{
|
||||
position: relative;
|
||||
display: inline-block;
|
||||
}
|
||||
#dropdowncontent{
|
||||
display: none;
|
||||
top: 0;
|
||||
position: absolute;
|
||||
background-color: var(--table-border-color);
|
||||
min-width: 160px;
|
||||
box-shadow: 0px 8px 16px 0px rgba(0,0,0,0.2);
|
||||
padding: 30px 50px;
|
||||
color: var(--yellow);
|
||||
text-align: center;
|
||||
z-index: 1;
|
||||
}
|
||||
#dropdown:hover #dropdowncontent {
|
||||
display: block;
|
||||
}
|
||||
#main{
|
||||
width: 100%;
|
||||
height: 80vh;
|
||||
display: grid;
|
||||
place-content: center;
|
||||
text-align: center;
|
||||
}
|
||||
form{
|
||||
height: 50px;
|
||||
}
|
||||
#footer{
|
||||
height: 12vh;
|
||||
width: 100%;
|
||||
text-align: center;
|
||||
}
|
||||
@media (max-width: 800px) {
|
||||
kbd{
|
||||
width: 100vw;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
<body>
|
||||
<div class="container-fluid">
|
||||
<nav>
|
||||
<ul>
|
||||
<li>
|
||||
<div id="dropdown">
|
||||
<i class="icon icon-menu"></i>
|
||||
<div id="dropdowncontent">
|
||||
<p>
|
||||
<a href="/login">Login</a>
|
||||
<a href="/dashboard">Dashboard</a>
|
||||
<a href="/yellwowpage">Yell<span>WOW</span>Page</a>
|
||||
<a href="/about">About</a>
|
||||
<a href="/about/api">Api</a>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</li>
|
||||
</ul>
|
||||
<ul>
|
||||
<li><strong><a href="/">Yell<span>WOW</span>Pages</a></strong></li>
|
||||
</ul>
|
||||
<ul>
|
||||
<li><a href="https://git.wownero.com/muchwowmining/YellWOWPages"><i class="icon icon-edit"></i></a></li>
|
||||
</ul>
|
||||
</nav>
|
||||
</div>
|
||||
<div class="container-fluid">
|
||||
<div id="main">
|
||||
<h1>About</h1>
|
||||
<p>
|
||||
Search for any Wownero <em>sub-address</em> you want by username and pay
|
||||
the world!
|
||||
<br>
|
||||
This application uses <u>Wownero's Centralized Authentication Service.</u>
|
||||
</p>
|
||||
<p>
|
||||
Other Wownero related stuff:
|
||||
<br>
|
||||
<a href="https://wownero.org/">WebSite</a>
|
||||
<br>
|
||||
<a href="https://suchwow.xyz">SuchWow</a>
|
||||
<br>
|
||||
<a href="https://git.wownero.com">Official Git</a>
|
||||
<br>
|
||||
<a href="https://discord.com/invite/ykZyAzJhDK">Discord server</a>
|
||||
</p>
|
||||
<p>
|
||||
Idea of: dsc_
|
||||
<br>
|
||||
Made by <a href="https://notmtth.xyz">NotMtth</a>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<div id="footer">
|
||||
2022 - ... [the future is w0w]
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
100
frontend/templates/dashboard/index.html
Normal file
100
frontend/templates/dashboard/index.html
Normal file
|
@ -0,0 +1,100 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en" data-theme="dark">
|
||||
<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">
|
||||
<title>Such dashboard</title>
|
||||
<link rel="stylesheet" href="https://unpkg.com/@picocss/pico@latest/css/pico.min.css">
|
||||
<link rel="stylesheet" href="../../static/colors.css">
|
||||
<link rel="stylesheet" href="../../static/icon.css">
|
||||
</head>
|
||||
<style>
|
||||
html, body{
|
||||
font-family: 'Courier New', Courier, monospace;
|
||||
overflow: hidden;
|
||||
}
|
||||
a{
|
||||
color: var(--yellow);
|
||||
}
|
||||
span{
|
||||
color: var(--purple);
|
||||
}
|
||||
.nav{
|
||||
border-color: var(--yellow);
|
||||
border: 2px;
|
||||
}
|
||||
#dropdown{
|
||||
position: relative;
|
||||
display: inline-block;
|
||||
}
|
||||
#dropdowncontent{
|
||||
display: none;
|
||||
top: 0;
|
||||
position: absolute;
|
||||
background-color: var(--table-border-color);
|
||||
min-width: 160px;
|
||||
box-shadow: 0px 8px 16px 0px rgba(0,0,0,0.2);
|
||||
padding: 30px 50px;
|
||||
color: var(--yellow);
|
||||
text-align: center;
|
||||
z-index: 1;
|
||||
}
|
||||
#dropdown:hover #dropdowncontent {
|
||||
display: block;
|
||||
}
|
||||
#main{
|
||||
width: 100%;
|
||||
height: 85vh;
|
||||
display: grid;
|
||||
place-content: center;
|
||||
}
|
||||
@media (max-width: 800px) {}
|
||||
</style>
|
||||
<body>
|
||||
<div class="container-fluid">
|
||||
<nav>
|
||||
<ul>
|
||||
<li>
|
||||
<div id="dropdown">
|
||||
<i class="icon icon-menu"></i>
|
||||
<div id="dropdowncontent">
|
||||
<p>
|
||||
<a href="/login">Login</a>
|
||||
<a href="/dashboard">Dashboard</a>
|
||||
<a href="/yellwowpage">Yell<span>WOW</span>Page</a>
|
||||
<a href="/about">About</a>
|
||||
<a href="/about/api">Api</a>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</li>
|
||||
</ul>
|
||||
<ul>
|
||||
<li><strong><a href="/">Yell<span>WOW</span>Pages</a></strong></li>
|
||||
</ul>
|
||||
<ul>
|
||||
<li><a href="https://git.wownero.com/muchwowmining/YellWOWPages"><i class="icon icon-edit"></i></a></li>
|
||||
</ul>
|
||||
</nav>
|
||||
</div>
|
||||
<div class="container-fluid">
|
||||
<div id="main">
|
||||
<article>
|
||||
{% for username, address in user_data.items() %}
|
||||
<Header>Welcome back <em>{{username}}</em>!</Header>
|
||||
Current <u>sub-address</u>: <label><mark>{{address}}</mark></label>
|
||||
<footer>
|
||||
Change <u>sub-address</u>:
|
||||
<form action="/submit_address" method="POST">
|
||||
<input type="text" name="address">
|
||||
<button data-tooltip="Be sure it's correct">Submit</button>
|
||||
</form>
|
||||
</footer>
|
||||
{% endfor %}
|
||||
</article>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</body>
|
||||
</html>
|
30
frontend/templates/errors/index.html
Normal file
30
frontend/templates/errors/index.html
Normal file
|
@ -0,0 +1,30 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en" data-theme="dark">
|
||||
<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">
|
||||
<meta http-equiv="refresh" content="3; URL={{url}}">
|
||||
<title>Such error :(</title>
|
||||
<link rel="stylesheet" href="https://unpkg.com/@picocss/pico@latest/css/pico.min.css">
|
||||
<link rel="stylesheet" href="../../static/colors.css">
|
||||
<link rel="stylesheet" href="../../static/icon.css">
|
||||
</head>
|
||||
<style>
|
||||
html, body{
|
||||
font-family: 'Courier New', Courier, monospace;
|
||||
}
|
||||
#main{
|
||||
height: 100vh;
|
||||
display: grid;
|
||||
place-content: center;
|
||||
}
|
||||
</style>
|
||||
<body>
|
||||
<div class="container-fluid">
|
||||
<div id="main">
|
||||
<p>Error: {{error}}</p>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
110
frontend/templates/root/index.html
Normal file
110
frontend/templates/root/index.html
Normal file
|
@ -0,0 +1,110 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en" data-theme="dark">
|
||||
<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">
|
||||
<title>YellWOWPages - Sex and Drugs in the metaverse</title>
|
||||
<link rel="stylesheet" href="https://unpkg.com/@picocss/pico@latest/css/pico.min.css">
|
||||
<link rel="stylesheet" href="../../static/colors.css">
|
||||
<link rel="stylesheet" href="../../static/icon.css">
|
||||
</head>
|
||||
<style>
|
||||
html, body{
|
||||
font-family: 'Courier New', Courier, monospace;
|
||||
overflow-x: hidden;
|
||||
}
|
||||
a{
|
||||
color: var(--yellow);
|
||||
}
|
||||
span{
|
||||
color: var(--purple);
|
||||
}
|
||||
strong{
|
||||
color: var(--yellow);
|
||||
}
|
||||
#dropdown{
|
||||
position: relative;
|
||||
display: inline-block;
|
||||
}
|
||||
#dropdowncontent{
|
||||
display: none;
|
||||
top: 0;
|
||||
position: absolute;
|
||||
background-color: var(--table-border-color);
|
||||
min-width: 160px;
|
||||
box-shadow: 0px 8px 16px 0px rgba(0,0,0,0.2);
|
||||
padding: 30px 50px;
|
||||
color: var(--yellow);
|
||||
text-align: center;
|
||||
z-index: 1;
|
||||
}
|
||||
#dropdown:hover #dropdowncontent {
|
||||
display: block;
|
||||
}
|
||||
#main{
|
||||
width: 100%;
|
||||
height: 80vh;
|
||||
display: grid;
|
||||
place-content: center;
|
||||
}
|
||||
main{
|
||||
font-size: bold;
|
||||
font-size: 10rem;
|
||||
}
|
||||
img{
|
||||
width: 50px;
|
||||
height: 50px;
|
||||
object-fit: contain;
|
||||
}
|
||||
#footer{
|
||||
height: 12vh;
|
||||
width: 100%;
|
||||
text-align: center;
|
||||
}
|
||||
@media (max-width: 800px) {
|
||||
main{
|
||||
font-size: 4rem;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
<body>
|
||||
<div class="container-fluid">
|
||||
<nav>
|
||||
<ul>
|
||||
<li>
|
||||
<div id="dropdown">
|
||||
<i class="icon icon-menu"></i>
|
||||
<div id="dropdowncontent">
|
||||
<p>
|
||||
<a href="/login">Login</a>
|
||||
<a href="/dashboard">Dashboard</a>
|
||||
<a href="/yellwowpage">Yell<span>WOW</span>Page</a>
|
||||
<a href="/about">About</a>
|
||||
<a href="/about/api">Api</a>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</li>
|
||||
</ul>
|
||||
<ul>
|
||||
<li><a href="https://git.wownero.com/muchwowmining/YellWOWPages"><i class="icon icon-edit"></i></a></li>
|
||||
</ul>
|
||||
</nav>
|
||||
</div>
|
||||
<div class="container-fluid">
|
||||
<div id="main">
|
||||
<main>
|
||||
<strong>Yell<span>WOW</span>Pages</strong>
|
||||
</main>
|
||||
<div>
|
||||
The first <img src="../../static/wownero.png" alt=""> addresses library -
|
||||
from the community to the community
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div id="footer">
|
||||
2022 - ... [the future is w0w]
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
126
frontend/templates/yellwow/index.html
Normal file
126
frontend/templates/yellwow/index.html
Normal file
|
@ -0,0 +1,126 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en" data-theme="dark">
|
||||
<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">
|
||||
<title>YellWOWPages - Sex and Drugs in the metaverse</title>
|
||||
<link rel="stylesheet" href="https://unpkg.com/@picocss/pico@latest/css/pico.min.css">
|
||||
<link rel="stylesheet" href="../../static/colors.css">
|
||||
<link rel="stylesheet" href="../../static/icon.css">
|
||||
</head>
|
||||
<style>
|
||||
html, body{
|
||||
font-family: 'Courier New', Courier, monospace;
|
||||
overflow-x: hidden;
|
||||
}
|
||||
a{
|
||||
color: var(--yellow);
|
||||
}
|
||||
span{
|
||||
color: var(--purple);
|
||||
}
|
||||
.nav{
|
||||
border-color: var(--yellow);
|
||||
border: 2px;
|
||||
}
|
||||
#dropdown{
|
||||
position: relative;
|
||||
display: inline-block;
|
||||
}
|
||||
#dropdowncontent{
|
||||
display: none;
|
||||
top: 0;
|
||||
position: absolute;
|
||||
background-color: var(--table-border-color);
|
||||
min-width: 160px;
|
||||
box-shadow: 0px 8px 16px 0px rgba(0,0,0,0.2);
|
||||
padding: 30px 50px;
|
||||
color: var(--yellow);
|
||||
text-align: center;
|
||||
z-index: 1;
|
||||
}
|
||||
#dropdown:hover #dropdowncontent {
|
||||
display: block;
|
||||
}
|
||||
#main{
|
||||
width: 100%;
|
||||
height: 80vh;
|
||||
display: grid;
|
||||
place-content: center;
|
||||
}
|
||||
form{
|
||||
height: 80px;
|
||||
}
|
||||
#addresses{
|
||||
width: 100%;
|
||||
height: 50vh;
|
||||
overflow-y: auto;
|
||||
}
|
||||
#addresses::-webkit-scrollbar{
|
||||
display: none;
|
||||
}
|
||||
#footer{
|
||||
height: 12vh;
|
||||
width: 100%;
|
||||
text-align: center;
|
||||
}
|
||||
@media (max-width: 800px) {
|
||||
kbd{
|
||||
width: 100vw;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
<body>
|
||||
<div class="container-fluid">
|
||||
<nav>
|
||||
<ul>
|
||||
<li>
|
||||
<div id="dropdown">
|
||||
<i class="icon icon-menu"></i>
|
||||
<div id="dropdowncontent">
|
||||
<p>
|
||||
<a href="/login">Login</a>
|
||||
<a href="/dashboard">Dashboard</a>
|
||||
<a href="/yellwowpage">Yell<span>WOW</span>Page</a>
|
||||
<a href="/about">About</a>
|
||||
<a href="/about/api">Api</a>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</li>
|
||||
</ul>
|
||||
<ul>
|
||||
<li><strong><a href="/">Yell<span>WOW</span>Pages</a></strong></li>
|
||||
</ul>
|
||||
<ul>
|
||||
<li><a href="https://git.wownero.com/muchwowmining/YellWOWPages"><i class="icon icon-edit"></i></a></li>
|
||||
</ul>
|
||||
</nav>
|
||||
</div>
|
||||
<div class="container-fluid">
|
||||
<div id="main">
|
||||
<form action="/search" method="GET">
|
||||
<input type="text" name="username" placeholder="Username to search">
|
||||
<label for="switch">
|
||||
<input type="checkbox" name="switch" role="switch">
|
||||
<em data-tooltip="Search address with a part of username; get 3 results">Partial</em>
|
||||
</label>
|
||||
</form>
|
||||
<div id="addresses">
|
||||
{% for username, address in user_data.items() %}
|
||||
<article>
|
||||
<header>
|
||||
<em>{{username}}</em>
|
||||
</header>
|
||||
<kbd>{{address}}</kbd>
|
||||
</article>
|
||||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div id="footer">
|
||||
2022 - ... [the future is w0w]
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
132
frontend/templates/yellwow/single_user/index.html
Normal file
132
frontend/templates/yellwow/single_user/index.html
Normal file
|
@ -0,0 +1,132 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en" data-theme="dark">
|
||||
<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">
|
||||
<title>YellWOWPages - Sex and Drugs in the metaverse</title>
|
||||
<link rel="stylesheet" href="https://unpkg.com/@picocss/pico@latest/css/pico.min.css">
|
||||
<link rel="stylesheet" href="../../static/colors.css">
|
||||
<link rel="stylesheet" href="../../static/icon.css">
|
||||
</head>
|
||||
<style>
|
||||
html, body{
|
||||
font-family: 'Courier New', Courier, monospace;
|
||||
overflow: hidden;
|
||||
}
|
||||
a{
|
||||
color: var(--yellow);
|
||||
}
|
||||
span{
|
||||
color: var(--purple);
|
||||
}
|
||||
.nav{
|
||||
border-color: var(--yellow);
|
||||
border: 2px;
|
||||
}
|
||||
#dropdown{
|
||||
position: relative;
|
||||
display: inline-block;
|
||||
}
|
||||
#dropdowncontent{
|
||||
display: none;
|
||||
top: 0;
|
||||
position: absolute;
|
||||
background-color: var(--table-border-color);
|
||||
min-width: 160px;
|
||||
box-shadow: 0px 8px 16px 0px rgba(0,0,0,0.2);
|
||||
padding: 30px 50px;
|
||||
color: var(--yellow);
|
||||
text-align: center;
|
||||
z-index: 1;
|
||||
}
|
||||
#dropdown:hover #dropdowncontent {
|
||||
display: block;
|
||||
}
|
||||
#main{
|
||||
width: 100%;
|
||||
height: 80vh;
|
||||
display: grid;
|
||||
place-content: center;
|
||||
}
|
||||
form{
|
||||
height: 80px;
|
||||
}
|
||||
#addresses{
|
||||
width: 100%;
|
||||
height: 50vh;
|
||||
overflow-y: auto;
|
||||
}
|
||||
#addresses::-webkit-scrollbar{
|
||||
display: none;
|
||||
}
|
||||
#footer{
|
||||
height: 12vh;
|
||||
width: 100%;
|
||||
text-align: center;
|
||||
}
|
||||
@media (max-width: 800px) {
|
||||
kbd{
|
||||
width: 100vw;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
<body>
|
||||
<div class="container-fluid">
|
||||
<nav>
|
||||
<ul>
|
||||
<li>
|
||||
<div id="dropdown">
|
||||
<i class="icon icon-menu"></i>
|
||||
<div id="dropdowncontent">
|
||||
<p>
|
||||
<a href="/login">Login</a>
|
||||
<a href="/dashboard">Dashboard</a>
|
||||
<a href="/yellwowpage">Yell<span>WOW</span>Page</a>
|
||||
<a href="/about">About</a>
|
||||
<a href="/about/api">Api</a>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</li>
|
||||
</ul>
|
||||
<ul>
|
||||
<li><strong><a href="/">Yell<span>WOW</span>Pages</a></strong></li>
|
||||
</ul>
|
||||
<ul>
|
||||
<li><a href="https://git.wownero.com/muchwowmining/YellWOWPages"><i class="icon icon-edit"></i></a></li>
|
||||
</ul>
|
||||
</nav>
|
||||
</div>
|
||||
<div class="container-fluid">
|
||||
<div id="main">
|
||||
<form action="/search" method="GET">
|
||||
<input type="text" name="username" placeholder="Username to search">
|
||||
<label for="switch">
|
||||
<input type="checkbox" name="switch" role="switch">
|
||||
<em data-tooltip="Search address with a part of username; get 3 results">Partial</em>
|
||||
</label>
|
||||
</form>
|
||||
<br>
|
||||
Result: {{user_data|length}}
|
||||
{% if not user_data|length %}
|
||||
Nothing found...
|
||||
{% else %}
|
||||
<div id="addresses">
|
||||
{% for username, address in user_data.items() %}
|
||||
<article>
|
||||
<header>
|
||||
<em>{{username}}</em>
|
||||
</header>
|
||||
<kbd>{{address}}</kbd>
|
||||
</article>
|
||||
{% endfor %}
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
<div id="footer">
|
||||
2022 - ... [the future is w0w]
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
45
main.py
Normal file
45
main.py
Normal file
|
@ -0,0 +1,45 @@
|
|||
from fastapi import FastAPI, Request
|
||||
from fastapi.responses import HTMLResponse
|
||||
from fastapi.staticfiles import StaticFiles
|
||||
import uvicorn
|
||||
|
||||
from classes.constraints import Constraints
|
||||
|
||||
from starlette.exceptions import HTTPException as StarletteHTTPException
|
||||
|
||||
app = FastAPI(docs_url=None, redoc_url=None)
|
||||
|
||||
app.mount('/static', StaticFiles(directory='frontend/static'), name='static')
|
||||
|
||||
from routers import auth, static, dashboard, db, api
|
||||
|
||||
app.include_router(auth.router)
|
||||
app.include_router(dashboard.router)
|
||||
app.include_router(static.router)
|
||||
app.include_router(api.router)
|
||||
|
||||
|
||||
@app.get("/")
|
||||
@app.get('/root', response_class=HTMLResponse)
|
||||
async def root(request: Request):
|
||||
return Constraints.templates.TemplateResponse('/root/index.html', {'request': request})
|
||||
|
||||
|
||||
# shitty error handling
|
||||
@app.exception_handler(StarletteHTTPException)
|
||||
async def http_exception_handler(request, exc):
|
||||
if exc.status_code == 404:
|
||||
return Constraints.templates.TemplateResponse('/errors/index.html', {'request': request,
|
||||
'error': 'not found...',
|
||||
'url': '/root'})
|
||||
elif exc.status_code == 500:
|
||||
return Constraints.templates.TemplateResponse('/errors/index.html', {'request': request,
|
||||
'error': 'internal server error',
|
||||
'url': '/root'})
|
||||
return Constraints.templates.TemplateResponse('/errors/index.html', {'request': request,
|
||||
'error': exc.detail,
|
||||
'url': '/root'})
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
uvicorn.run(app, host='127.0.0.1', port=8080)
|
30
requirements.txt
Normal file
30
requirements.txt
Normal file
|
@ -0,0 +1,30 @@
|
|||
anyio==3.5.0
|
||||
asgiref==3.5.0
|
||||
asttokens==2.0.5
|
||||
certifi==2021.10.8
|
||||
charset-normalizer==2.0.12
|
||||
click==8.0.4
|
||||
colorama==0.4.4
|
||||
executing==0.8.3
|
||||
fastapi==0.75.0
|
||||
Flask==2.0.3
|
||||
Flask-SQLAlchemy==2.5.1
|
||||
greenlet==1.1.2
|
||||
h11==0.13.0
|
||||
icecream==2.1.2
|
||||
idna==3.3
|
||||
itsdangerous==2.1.1
|
||||
Jinja2==3.0.3
|
||||
MarkupSafe==2.1.0
|
||||
pydantic==1.9.0
|
||||
Pygments==2.11.2
|
||||
python-multipart==0.0.5
|
||||
requests==2.27.1
|
||||
six==1.16.0
|
||||
sniffio==1.2.0
|
||||
SQLAlchemy==1.4.32
|
||||
starlette==0.17.1
|
||||
typing-extensions==4.1.1
|
||||
urllib3==1.26.8
|
||||
uvicorn==0.17.5
|
||||
Werkzeug==2.0.3
|
0
routers/__init__.py
Normal file
0
routers/__init__.py
Normal file
32
routers/api.py
Normal file
32
routers/api.py
Normal file
|
@ -0,0 +1,32 @@
|
|||
from fastapi import APIRouter, Request, Form
|
||||
from fastapi.responses import RedirectResponse, HTMLResponse
|
||||
from icecream import ic
|
||||
|
||||
from classes.constraints import Constraints
|
||||
from .db import Database
|
||||
|
||||
router = APIRouter()
|
||||
|
||||
|
||||
# external api
|
||||
@router.get('/api/user/{username}')
|
||||
async def get_api(request: Request, username: str):
|
||||
if not Database.Users.get_address(username):
|
||||
return {'error': 'invalid user'}
|
||||
return Database.Users.get_address(username)
|
||||
|
||||
|
||||
@router.get('/api/all')
|
||||
async def get_api_all(request: Request):
|
||||
return Database.Users.get_all()
|
||||
|
||||
|
||||
# site search redirect
|
||||
@router.get('/search')
|
||||
async def search_api(request: Request):
|
||||
username = request.query_params['username']
|
||||
ic(request.query_params.get('switch', None) == 'on')
|
||||
if request.query_params.get('switch', None) == 'on':
|
||||
return RedirectResponse(f'/yellwowpage/matches/{username}')
|
||||
else:
|
||||
return RedirectResponse(f'/yellwowpage/user/{username}')
|
68
routers/auth.py
Normal file
68
routers/auth.py
Normal file
|
@ -0,0 +1,68 @@
|
|||
from fastapi import APIRouter, Request, Cookie
|
||||
from fastapi.responses import RedirectResponse, HTMLResponse
|
||||
import requests
|
||||
from icecream import ic
|
||||
import secrets
|
||||
|
||||
from classes.constraints import Constraints
|
||||
|
||||
router = APIRouter()
|
||||
|
||||
|
||||
@router.get('/login')
|
||||
async def get_login(request: Request):
|
||||
state = secrets.token_hex(10)
|
||||
response = RedirectResponse(
|
||||
'https://login.wownero.com/auth/realms/master/protocol/openid-connect/auth?'f'client_id='
|
||||
f'{Constraints.client_id}&redirect_uri=https://yellow.wownero.com/authenticate&'
|
||||
f'response_type=code&state={state}')
|
||||
response.set_cookie(key='state', value=state)
|
||||
return response
|
||||
|
||||
|
||||
@router.get('/authenticate')
|
||||
async def get_auth(request: Request, state: str = Cookie(None)):
|
||||
params = request.query_params
|
||||
if state is None:
|
||||
return Constraints.templates.TemplateResponse('/errors/index.html',
|
||||
{'request': request,
|
||||
'error': '`state` security code not found...',
|
||||
'url': '/login'})
|
||||
if params['state'] != state:
|
||||
return Constraints.templates.TemplateResponse('/errors/index.html',
|
||||
{'request': request,
|
||||
'error': '`state` security code is wrong',
|
||||
'url': '/login'})
|
||||
url = "https://login.wownero.com/auth/realms/master/protocol/openid-connect/token"
|
||||
data = {
|
||||
"grant_type": "authorization_code",
|
||||
"code": params["code"],
|
||||
"redirect_uri": "http://127.0.0.1:8080/authenticate",
|
||||
"client_id": f'{Constraints.client_id}',
|
||||
"client_secret": f'{Constraints.client_secret}',
|
||||
"state": params['state']
|
||||
}
|
||||
r = requests.post(url=url, data=data)
|
||||
response = r.json()
|
||||
|
||||
if response.get('error', None) is not None:
|
||||
return Constraints.templates.TemplateResponse('/errors/index.html',
|
||||
{'request': request, 'error': r.json()['error_description'],
|
||||
'url': '/login'})
|
||||
auth_code = response.get('access_token', None)
|
||||
|
||||
if auth_code is None:
|
||||
return Constraints.templates.TemplateResponse('/errors/index.html',
|
||||
{'request': request, 'error': 'invalid auth code',
|
||||
'url': '/login'})
|
||||
response = RedirectResponse('/dashboard')
|
||||
response.set_cookie(key='auth_code', value=auth_code)
|
||||
response.delete_cookie(key='state')
|
||||
return response
|
||||
|
||||
|
||||
@router.get('/logout')
|
||||
async def get_logout():
|
||||
response = RedirectResponse('/root')
|
||||
response.delete_cookie('auth_code')
|
||||
return response
|
63
routers/dashboard.py
Normal file
63
routers/dashboard.py
Normal file
|
@ -0,0 +1,63 @@
|
|||
from fastapi import APIRouter, Request, Cookie, Form
|
||||
from fastapi.responses import RedirectResponse, HTMLResponse
|
||||
import requests
|
||||
from icecream import ic
|
||||
|
||||
from classes.constraints import Constraints
|
||||
from .db import Database
|
||||
|
||||
router = APIRouter()
|
||||
|
||||
|
||||
@router.get('/dashboard', response_class=HTMLResponse)
|
||||
async def get_dashboard(request: Request, auth_code: str = Cookie(None)):
|
||||
if auth_code is None:
|
||||
return Constraints.templates.TemplateResponse('/errors/index.html', {'request': request,
|
||||
'error': 'not logged in',
|
||||
'url': '/login'})
|
||||
|
||||
url = "https://login.wownero.com/auth/realms/master/protocol/openid-connect/userinfo"
|
||||
response = requests.post(url, headers={"Authorization": f"Bearer {auth_code}"})
|
||||
user_profile = response.json()
|
||||
|
||||
if user_profile.get('preferred_username', None) is None:
|
||||
return Constraints.templates.TemplateResponse('/errors/index.html', {'request': request,
|
||||
'error': 'account not found...',
|
||||
'url': '/login'})
|
||||
user_name = user_profile.get('preferred_username', None)
|
||||
return Constraints.templates.TemplateResponse('/dashboard/index.html', {'request': request,
|
||||
'user_data': Database.Users.get_address(user_name)})
|
||||
|
||||
|
||||
@router.post('/submit_address')
|
||||
async def post_submit_address(request: Request, auth_code: str = Cookie(None), address: str = Form(None)):
|
||||
if auth_code is None:
|
||||
return Constraints.templates.TemplateResponse('/errors/index.html', {'request': request,
|
||||
'error': 'not logged in',
|
||||
'url': '/login'})
|
||||
if address is None:
|
||||
return Constraints.templates.TemplateResponse('/errors/index.html', {'request': request,
|
||||
'error': 'invalid address',
|
||||
'url': '/dashboard'})
|
||||
|
||||
if len(address) != 97:
|
||||
return Constraints.templates.TemplateResponse('/errors/index.html', {'request': request,
|
||||
'error': 'invalid address length',
|
||||
'url': '/dashboard'})
|
||||
|
||||
url = "https://login.wownero.com/auth/realms/master/protocol/openid-connect/userinfo"
|
||||
response = requests.post(url, headers={"Authorization": f"Bearer {auth_code}"})
|
||||
user_name = response.json().get('preferred_username', None)
|
||||
|
||||
if not Database.Users.get_address(user_name):
|
||||
new_user = Database.Users(username=user_name, address=address)
|
||||
Database.sqla.session.add(new_user)
|
||||
Database.sqla.session.commit()
|
||||
return RedirectResponse('/dashboard', status_code=303)
|
||||
|
||||
update_address = Database.Users.query.filter_by(username=user_name).first()
|
||||
update_address.address = address
|
||||
Database.sqla.session.commit()
|
||||
return RedirectResponse('/dashboard', status_code=303)
|
||||
|
||||
|
54
routers/db.py
Normal file
54
routers/db.py
Normal file
|
@ -0,0 +1,54 @@
|
|||
from flask import Flask
|
||||
from flask_sqlalchemy import SQLAlchemy
|
||||
|
||||
from icecream import install, ic
|
||||
|
||||
from classes.constraints import Constraints
|
||||
|
||||
app = Flask(__name__)
|
||||
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
|
||||
app.config['SQLALCHEMY_DATABASE_URI'] = Constraints.uri
|
||||
db = SQLAlchemy(app, session_options={'autocommit': False})
|
||||
|
||||
|
||||
class Users(db.Model):
|
||||
__tablename__ = 'wowusers'
|
||||
username = db.Column(db.VARCHAR(32), primary_key=True)
|
||||
address = db.Column(db.CHAR(97), nullable=False)
|
||||
|
||||
@staticmethod
|
||||
def get_address(username):
|
||||
user_data = {}
|
||||
try:
|
||||
user_data.update({Users.query.filter_by(username=username).first().username:
|
||||
Users.query.filter_by(username=username).first().address})
|
||||
except AttributeError:
|
||||
return user_data
|
||||
return user_data
|
||||
|
||||
@staticmethod
|
||||
def get_all():
|
||||
users_data = {}
|
||||
for user in Users.query.all():
|
||||
users_data.update({user.username: user.address})
|
||||
return users_data
|
||||
|
||||
@staticmethod
|
||||
def get_matches(username):
|
||||
user_data = {}
|
||||
try:
|
||||
for i in range(3):
|
||||
user = Users.query.filter(Database.Users.username.like(f'%{username}%'))[i]
|
||||
user_data.update({user.username: user.address})
|
||||
except IndexError:
|
||||
return user_data
|
||||
return user_data
|
||||
|
||||
|
||||
class Database:
|
||||
Users = Users
|
||||
sqla = db
|
||||
|
||||
|
||||
db.create_all()
|
||||
ic('db done')
|
2
routers/errors.py
Normal file
2
routers/errors.py
Normal file
|
@ -0,0 +1,2 @@
|
|||
# stupid fastapi error handling drove me crazy for some hours, updating this asap
|
||||
# the handler is in the main file
|
39
routers/static.py
Normal file
39
routers/static.py
Normal file
|
@ -0,0 +1,39 @@
|
|||
from fastapi import APIRouter, Request
|
||||
from fastapi.responses import RedirectResponse, HTMLResponse
|
||||
from icecream import ic
|
||||
|
||||
from classes.constraints import Constraints
|
||||
from .db import Database
|
||||
|
||||
router = APIRouter()
|
||||
|
||||
|
||||
@router.get('/yellwowpage')
|
||||
async def get_yellwowpage(request: Request):
|
||||
return Constraints.templates.TemplateResponse('/yellwow/index.html',
|
||||
{'request': request, 'user_data': Database.Users.get_all()})
|
||||
|
||||
|
||||
@router.get('/yellwowpage/user/{username}')
|
||||
async def get_yellwowpage(request: Request, username: str):
|
||||
return Constraints.templates.TemplateResponse('/yellwow/single_user/index.html',
|
||||
{'request': request,
|
||||
'user_data': Database.Users.get_address(username)})
|
||||
|
||||
|
||||
@router.get('/yellwowpage/matches/{username}')
|
||||
async def get_yellwowpage_matches(request: Request, username: str):
|
||||
ic(Database.Users.get_matches(username))
|
||||
return Constraints.templates.TemplateResponse('/yellwow/single_user/index.html',
|
||||
{'request': request,
|
||||
'user_data': Database.Users.get_matches(username)})
|
||||
|
||||
|
||||
@router.get('/about')
|
||||
async def get_about(request: Request):
|
||||
return Constraints.templates.TemplateResponse('/about/index.html', {'request': request})
|
||||
|
||||
|
||||
@router.get('/about/api')
|
||||
async def get_api_about(request: Request):
|
||||
return Constraints.templates.TemplateResponse('/about/api/index.html', {'request': request})
|
Loading…
Reference in a new issue