Compare commits

...

No commits in common. 'master' and 'master' have entirely different histories.

52
.gitignore vendored

@ -1,52 +0,0 @@
# Byte-compiled / optimized / DLL files
__pycache__/
*.py[cod]
# C extensions
*.so
# Distribution / packaging
.Python
env/
bin/
build/
develop-eggs/
dist/
eggs/
lib/
lib64/
parts/
sdist/
var/
*.egg-info/
.installed.cfg
*.egg
.idea
# Installer logs
pip-log.txt
pip-delete-this-directory.txt
# Unit test / coverage reports
htmlcov/
.tox/
.coverage
.cache
nosetests.xml
coverage.xml
# Translations
*.mo
.project
.pydevproject
# Rope
.ropeproject
# Django stuff:
*.log
*.pot
# Sphinx documentation
docs/_build/

@ -1,19 +0,0 @@
## YellWOWPages
Wownero yellow pages web-application - lookup the WOW address of users.
### Installation
```bash
git clone gitea@git.wownero.com:wownero/YellWOWPages.git
cd YellWOWPages
pip install -r requirements.txt
cp settings.py_example settings.py
```
Change `settings.py` to your liking. Then run the application:
```bash
python3 run.py
```

@ -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,0 +1,8 @@
from starlette.templating import Jinja2Templates
class Constraints:
templates = Jinja2Templates(directory='frontend/templates')
client_id = 'yellwowpagestesting11'
client_secret = '8284d868-f5a1-48f4-a287-8bdb18a7d3a1'
uri = 'sqlite:///users.db'

Before

Width:  |  Height:  |  Size: 12 KiB

After

Width:  |  Height:  |  Size: 12 KiB

@ -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>

@ -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>

@ -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>

@ -4,7 +4,8 @@
<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 {{code}} error :(</title>
<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">
@ -22,7 +23,7 @@
<body>
<div class="container-fluid">
<div id="main">
<p>Error {{code}}: {{msg}}</p>
<p>Error: {{error}}</p>
</div>
</div>
</body>

@ -4,12 +4,10 @@
<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>{% block title %}YellWOWPages - Sex and Drugs in the metaverse{% endblock %}</title>
<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="{{ url_for('static', filename='colors.css') }}">
<link rel="stylesheet" href="{{ url_for('static', filename='icon.css') }}">
<link rel="icon" href="{{ url_for('static', filename='1.svg') }}">
<link rel="stylesheet" href="../../static/colors.css">
<link rel="stylesheet" href="../../static/icon.css">
</head>
<style>
html, body{
@ -44,9 +42,6 @@
#dropdown:hover #dropdowncontent {
display: block;
}
#dropdowncontent a {
display: block;
}
#main{
width: 100%;
height: 80vh;
@ -57,19 +52,7 @@
font-size: bold;
font-size: 10rem;
}
#root{
display: flex;
gap: 1rem;
font-weight: 800;
font-size: 2rem;
align-items: center;
}
img{
width: 500px;
height: 500px;
object-fit: contain;
}
#wow{
width: 50px;
height: 50px;
object-fit: contain;
@ -81,19 +64,47 @@
}
@media (max-width: 800px) {
main{
font-size: 3rem;
font-size: 4rem;
}
}
</style>
<body>
<div class="container-fluid">
{% include 'includes/nav.html' %}
{% block content %} {% endblock %}
</div>
<div id="footer">
{{ year }} - ... [the future is w0w]
</div>
<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>
</html>

@ -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>

@ -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>

@ -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)

@ -1,5 +1,30 @@
peewee
quart
Quart-Keycloak
uvicorn
redis
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,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}')

@ -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=http://127.0.0.1:8080/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

@ -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)

@ -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')

@ -0,0 +1,2 @@
# stupid fastapi error handling drove me crazy for some hours, updating this asap
# the handler is in the main 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})

@ -1,5 +0,0 @@
from yellow.factory import create_app
import settings
app = create_app()
app.run(settings.HOST, port=settings.PORT, debug=settings.DEBUG, use_reloader=False)

@ -1,23 +0,0 @@
import os
cwd = os.path.dirname(os.path.realpath(__file__))
def bool_env(val):
return val is True or (isinstance(val, str) and (val.lower() == 'true' or val == '1'))
DEBUG = bool_env(os.environ.get("DEBUG", False))
HOST = os.environ.get("HOST", "127.0.0.1")
PORT = int(os.environ.get("PORT", 8080))
APP_SECRET = os.environ.get("APP_SECRET")
REDIS_URI = os.environ.get("REDIS_URI", "redis://localhost:6379")
DB_PATH = os.path.join(cwd, "data", "db.sqlite3")
OPENID_CFG = {
"client_id": "",
"client_secret": "",
"configuration": "https://login.wownero.com/auth/realms/master/.well-known/openid-configuration"
}

@ -1,13 +0,0 @@
from quart import session, abort
from functools import wraps
def login_required(func):
@wraps(func)
async def wrapper(*args, **kwargs):
user = session.get('user')
if not isinstance(user, dict):
abort(403)
return await func(*args, **kwargs)
return wrapper

@ -1,27 +0,0 @@
from quart import render_template, request, redirect, url_for, jsonify, Blueprint, abort, flash, send_from_directory, current_app
import settings
from yellow.models import User
bp_api = Blueprint('bp_api', __name__, url_prefix='/api')
@bp_api.get("/")
async def api_root():
return await render_template('api.html')
@bp_api.get('/user/')
async def api_all():
q = User.select()
q = q.where(User.address.is_null(False))
return jsonify([u.to_json(ignore_key='id') for u in q])
@bp_api.get('/user/<path:needle>')
async def api_search(needle: str):
try:
return jsonify([u.to_json(ignore_key='id') for u in await User.search(needle)])
except Exception as ex:
current_app.logger.error(ex)
return jsonify([])

@ -1,34 +0,0 @@
import re
import peewee
from quart import session, redirect, url_for, current_app
from quart_keycloak import Keycloak, KeycloakAuthToken, KeycloakLogoutRequest
from yellow.factory import keycloak
from yellow.models import User
@keycloak.after_login()
async def handle_user_login(auth_token: KeycloakAuthToken):
username = auth_token.username
uid = auth_token.sub
if not re.match(r"^[a-zA-Z0-9_\.-]+$", username):
raise Exception("bad username")
try:
user = User.select().where(User.username == username).get()
except Exception as ex:
user = None
if not user:
# create new user if it does not exist yet
current_app.logger.info(f'User {username} not found, creating')
try:
user = User.create(id=uid, username=username)
except Exception as ex:
current_app.logger.debug(f'User {username}, creation error')
raise
# user is now logged in
session['user'] = user.to_json()
return redirect(url_for('bp_routes.dashboard'))

@ -1,84 +0,0 @@
import os
import logging
from datetime import datetime
import asyncio
from quart import Quart, url_for, jsonify, render_template, session
from quart_session import Session
from quart_keycloak import Keycloak, KeycloakAuthToken, KeycloakLogoutRequest
from uvicorn.middleware.proxy_headers import ProxyHeadersMiddleware
import settings
app: Quart = None
peewee = None
cache = None
keycloak = None
async def _setup_database(app: Quart):
import peewee
import yellow.models
models = peewee.Model.__subclasses__()
for m in models:
m.create_table()
async def _setup_openid(app: Quart):
global keycloak
keycloak = Keycloak(app, **settings.OPENID_CFG)
from yellow.auth import handle_user_login
async def _setup_cache(app: Quart):
global cache
app.config['SESSION_TYPE'] = 'redis'
app.config['SESSION_URI'] = settings.REDIS_URI
Session(app)
async def _setup_error_handlers(app: Quart):
@app.errorhandler(500)
async def page_error(e):
return await render_template('error.html', code=500, msg="Error occurred"), 500
@app.errorhandler(403)
async def page_forbidden(e):
return await render_template('error.html', code=403, msg="Forbidden"), 403
@app.errorhandler(404)
async def page_not_found(e):
return await render_template('error.html', code=404, msg="Page not found"), 404
def create_app():
global app
app = Quart(__name__)
if settings.X_FORWARDED:
app.asgi_app = ProxyHeadersMiddleware(app.asgi_app, trusted_hosts=["127.0.0.1", "10.1.0.1"])
app.logger.setLevel(logging.INFO)
app.secret_key = settings.APP_SECRET
@app.context_processor
def template_variables():
from yellow.models import User
current_user = session.get('user')
if current_user:
current_user = User(**current_user)
now = datetime.now()
return dict(user=current_user, url_login=keycloak.endpoint_name_login, year=now.year)
@app.before_serving
async def startup():
await _setup_cache(app)
await _setup_openid(app)
await _setup_database(app)
await _setup_error_handlers(app)
from yellow.routes import bp_routes
from yellow.api import bp_api
app.register_blueprint(bp_routes)
app.register_blueprint(bp_api)
return app

@ -1,46 +0,0 @@
import os, re, random
from typing import Optional, List
from datetime import datetime
from peewee import SqliteDatabase, SQL, ForeignKeyField
import peewee as pw
import settings
db = SqliteDatabase(settings.DB_PATH)
class User(pw.Model):
id = pw.UUIDField(primary_key=True)
created: datetime = pw.DateTimeField(default=datetime.now)
username = pw.CharField(unique=True, null=False)
address = pw.CharField(null=True)
@property
def created_dt(self):
return self.created.strftime('%Y-%m-%d')
@staticmethod
async def search(needle) -> List['User']:
if not needle:
raise Exception("need search term")
needle = needle.replace("*", "")
needle = needle.lower()
return User.select().where(
User.address.is_null(False),
User.username % f"*{needle}*"
)
def to_json(self, ignore_key=None):
data = {
"id": self.id,
"username": self.username,
"address": self.address
}
if isinstance(ignore_key, str):
data.pop(ignore_key)
return data
class Meta:
database = db

@ -1,100 +0,0 @@
from quart import render_template, request, redirect, url_for, jsonify, Blueprint, abort, flash, send_from_directory, session
import re
from yellow import login_required
from yellow.models import User
bp_routes = Blueprint('bp_routes', __name__)
@bp_routes.get("/")
async def root():
return await render_template('index.html')
@bp_routes.route("/login")
async def login():
from yellow.factory import keycloak
return redirect(url_for(keycloak.endpoint_name_login))
@bp_routes.route("/logout")
@login_required
async def logout():
session['user'] = None
return redirect(url_for('bp_routes.root'))
@bp_routes.route("/dashboard")
@login_required
async def dashboard():
return await render_template('dashboard.html')
@bp_routes.post("/dashboard/address")
@login_required
async def dashboard_address_post():
form = await request.form
address = form.get('address')
if len(address) != 97:
raise Exception("Please submit a WOW address")
# update user
from yellow.models import User
user = User.select().filter(User.id == session['user']['id']).get()
user.address = address
user.save()
session['user'] = user.to_json()
return await render_template('dashboard.html')
@bp_routes.post("/dashboard/address/delete")
@login_required
async def dashboard_address_delete():
from yellow.models import User
user = User.select().filter(User.id == session['user']['id']).get()
user.address = None
user.save()
session['user'] = user.to_json()
return redirect(url_for("bp_routes.dashboard"))
@bp_routes.route("/search")
async def search():
needle = request.args.get('username')
if needle:
users = [u for u in await User.search(needle)]
if users:
return await render_template('search_results.html', users=users)
else:
return await render_template('search_results.html')
q = User.select()
q = q.where(User.address.is_null(False))
q = q.limit(100)
users = [u for u in q]
return await render_template('search.html', users=users)
@bp_routes.route("/user/<path:name>")
async def user_page(name: str):
if not name:
raise Exception("invalid name")
name = name.lower()
try:
_user = User.select().where(
User.username == name,
User.address.is_null(False)
).get()
except:
return abort(404)
return await render_template('user.html', users=[_user])
@bp_routes.route("/about")
async def about():
return await render_template('about.html')

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.4 KiB

@ -1,28 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="375pt" height="375pt" viewBox="0 0 375 375" version="1.1">
<g id="surface3">
<path style=" stroke:none;fill-rule:evenodd;fill:rgb(100%,16.470589%,83.137256%);fill-opacity:1;" d="M 99.648438 98.910156 L 99.648438 179.484375 C 99.648438 187.300781 105.941406 193.589844 113.753906 193.589844 L 242.765625 193.589844 C 250.578125 193.589844 256.871094 187.300781 256.871094 179.484375 L 256.871094 98.910156 L 221.128906 98.910156 L 221.128906 154.394531 L 178.261719 111.53125 L 135.398438 154.394531 L 135.398438 98.910156 Z M 99.648438 98.910156 "/>
<path style=" stroke:none;fill-rule:evenodd;fill:rgb(100%,80.000001%,0%);fill-opacity:1;" d="M 113.753906 36.371094 C 105.941406 36.371094 99.648438 42.660156 99.648438 50.476562 L 99.648438 85.464844 L 149.703125 85.464844 L 149.703125 120.382812 L 178.261719 91.820312 L 206.820312 120.382812 L 206.820312 85.464844 L 256.867188 85.464844 L 256.867188 50.476562 C 256.867188 42.660156 250.570312 36.371094 242.757812 36.371094 Z M 113.753906 36.371094 "/>
<path style=" stroke:none;fill-rule:evenodd;fill:rgb(100%,80.000001%,0%);fill-opacity:1;" d="M 268.632812 45.644531 C 272.359375 45.644531 275.359375 48.640625 275.359375 52.375 L 275.359375 79.082031 C 275.359375 82.8125 272.359375 85.8125 268.632812 85.8125 L 265.109375 85.8125 L 265.109375 45.644531 Z M 268.632812 45.644531 "/>
<path style=" stroke:none;fill-rule:evenodd;fill:rgb(100%,16.470589%,83.137256%);fill-opacity:1;" d="M 268.632812 94.898438 C 272.359375 94.898438 275.359375 97.898438 275.359375 101.632812 L 275.359375 128.339844 C 275.359375 132.066406 272.359375 135.070312 268.632812 135.070312 L 265.109375 135.070312 L 265.109375 94.898438 Z M 268.632812 94.898438 "/>
<path style=" stroke:none;fill-rule:evenodd;fill:rgb(100%,16.470589%,83.137256%);fill-opacity:1;" d="M 268.632812 144.15625 C 272.359375 144.15625 275.359375 147.15625 275.359375 150.882812 L 275.359375 177.59375 C 275.359375 181.324219 272.359375 184.328125 268.632812 184.328125 L 265.109375 184.328125 L 265.109375 144.15625 Z M 268.632812 144.15625 "/>
<path style=" stroke:none;fill-rule:nonzero;fill:rgb(100%,80.000001%,0%);fill-opacity:1;" d="M 31.40625 298.785156 L 38.140625 298.785156 L 38.140625 276.308594 L 61.617188 231.539062 L 54.242188 231.539062 L 34.683594 269.214844 L 15.570312 231.539062 L 8.109375 231.539062 L 31.40625 276.308594 Z M 31.40625 298.785156 "/>
<path style=" stroke:none;fill-rule:nonzero;fill:rgb(100%,80.000001%,0%);fill-opacity:1;" d="M 68.695312 298.785156 L 105.460938 298.785156 L 105.460938 292.691406 L 75.429688 292.691406 L 75.429688 267.847656 L 104.457031 267.847656 L 104.457031 261.75 L 75.429688 261.75 L 75.429688 237.636719 L 105.460938 237.636719 L 105.460938 231.539062 L 68.695312 231.539062 Z M 68.695312 298.785156 "/>
<path style=" stroke:none;fill-rule:nonzero;fill:rgb(100%,80.000001%,0%);fill-opacity:1;" d="M 117.484375 298.785156 L 152.066406 298.785156 L 152.066406 292.691406 L 124.21875 292.691406 L 124.21875 231.539062 L 117.484375 231.539062 Z M 117.484375 298.785156 "/>
<path style=" stroke:none;fill-rule:nonzero;fill:rgb(100%,80.000001%,0%);fill-opacity:1;" d="M 159.507812 298.785156 L 194.085938 298.785156 L 194.085938 292.691406 L 166.242188 292.691406 L 166.242188 231.539062 L 159.507812 231.539062 Z M 159.507812 298.785156 "/>
<path style=" stroke:none;fill-rule:nonzero;fill:rgb(100%,80.000001%,0%);fill-opacity:1;" d="M 230.054688 230.351562 C 210.761719 230.351562 194.472656 246.09375 194.472656 264.746094 C 194.472656 284.3125 210.308594 299.964844 230.140625 299.964844 C 249.527344 299.964844 265.542969 284.21875 265.542969 265.199219 C 265.542969 246 249.527344 230.351562 230.054688 230.351562 Z M 230.054688 236.539062 C 245.796875 236.539062 258.714844 249.550781 258.714844 265.292969 C 258.714844 280.855469 245.703125 293.773438 230.140625 293.773438 C 214.125 293.773438 201.292969 280.855469 201.292969 264.929688 C 201.292969 249.550781 214.492188 236.539062 230.054688 236.539062 Z M 230.054688 236.539062 "/>
<path style=" stroke:none;fill-rule:nonzero;fill:rgb(100%,80.000001%,0%);fill-opacity:1;" d="M 288.375 298.785156 L 297.109375 298.785156 L 311.851562 243.640625 L 326.773438 298.785156 L 335.421875 298.785156 L 354.707031 231.542969 L 347.792969 231.542969 L 331.230469 290.046875 L 315.125 231.542969 L 308.753906 231.542969 L 292.648438 290.046875 L 276.089844 231.542969 L 269.171875 231.542969 Z M 288.375 298.785156 "/>
<path style=" stroke:none;fill-rule:nonzero;fill:rgb(100%,80.000001%,0%);fill-opacity:1;" d="M 360.15625 298.785156 L 366.890625 298.785156 L 366.890625 287.320312 L 360.15625 287.320312 Z M 360.15625 298.785156 "/>
<path style=" stroke:none;fill-rule:nonzero;fill:rgb(100%,16.470589%,83.137256%);fill-opacity:1;" d="M 18.453125 338.078125 L 22.597656 338.078125 L 29.589844 311.917969 L 36.671875 338.078125 L 40.773438 338.078125 L 49.921875 306.175781 L 46.644531 306.175781 L 38.785156 333.9375 L 31.140625 306.175781 L 28.125 306.175781 L 20.484375 333.9375 L 12.621094 306.175781 L 9.34375 306.175781 Z M 18.453125 338.078125 "/>
<path style=" stroke:none;fill-rule:nonzero;fill:rgb(100%,16.470589%,83.137256%);fill-opacity:1;" d="M 68.515625 305.625 C 59.359375 305.625 51.636719 313.09375 51.636719 321.945312 C 51.636719 331.226562 59.144531 338.652344 68.558594 338.652344 C 77.753906 338.652344 85.351562 331.179688 85.351562 322.15625 C 85.351562 313.050781 77.753906 305.625 68.515625 305.625 Z M 68.515625 308.558594 C 75.980469 308.558594 82.113281 314.734375 82.113281 322.203125 C 82.113281 329.585938 75.941406 335.71875 68.558594 335.71875 C 60.960938 335.71875 54.875 329.585938 54.875 322.03125 C 54.875 314.734375 61.132812 308.558594 68.515625 308.558594 Z M 68.515625 308.558594 "/>
<path style=" stroke:none;fill-rule:nonzero;fill:rgb(100%,16.470589%,83.137256%);fill-opacity:1;" d="M 96.203125 338.078125 L 100.347656 338.078125 L 107.339844 311.917969 L 114.417969 338.078125 L 118.519531 338.078125 L 127.671875 306.175781 L 124.390625 306.175781 L 116.53125 333.9375 L 108.890625 306.175781 L 105.867188 306.175781 L 98.234375 333.9375 L 90.371094 306.175781 L 87.089844 306.175781 Z M 96.203125 338.078125 "/>
<path style=" stroke:none;fill-rule:nonzero;fill:rgb(100%,16.470589%,83.137256%);fill-opacity:1;" d="M 131.421875 338.078125 L 134.613281 338.078125 L 134.613281 310.019531 L 153.609375 338.078125 L 156.800781 338.078125 L 156.800781 306.175781 L 153.609375 306.175781 L 153.609375 332.636719 L 135.738281 306.175781 L 131.421875 306.175781 Z M 131.421875 338.078125 "/>
<path style=" stroke:none;fill-rule:nonzero;fill:rgb(100%,16.470589%,83.137256%);fill-opacity:1;" d="M 163.363281 338.078125 L 180.804688 338.078125 L 180.804688 335.1875 L 166.558594 335.1875 L 166.558594 323.398438 L 180.328125 323.398438 L 180.328125 320.507812 L 166.558594 320.507812 L 166.558594 309.066406 L 180.804688 309.066406 L 180.804688 306.175781 L 163.363281 306.175781 Z M 163.363281 338.078125 "/>
<path style=" stroke:none;fill-rule:nonzero;fill:rgb(100%,16.470589%,83.137256%);fill-opacity:1;" d="M 198.726562 326.148438 C 204.859375 325.5 208.140625 322.128906 208.140625 316.386719 C 208.140625 312.417969 206.453125 309.394531 203.34375 307.710938 C 201.363281 306.632812 198.636719 306.15625 194.410156 306.15625 L 186.507812 306.15625 L 186.507812 338.0625 L 189.703125 338.0625 L 189.703125 309.046875 L 194.195312 309.046875 C 197.558594 309.046875 199.804688 309.394531 201.53125 310.214844 C 203.691406 311.25 204.898438 313.40625 204.898438 316.304688 C 204.898438 319.925781 203.257812 322.21875 200.0625 323.039062 C 198.554688 323.429688 196.480469 323.597656 192.9375 323.597656 L 203.691406 338.0625 L 207.660156 338.0625 Z M 198.726562 326.148438 "/>
<path style=" stroke:none;fill-rule:nonzero;fill:rgb(100%,16.470589%,83.137256%);fill-opacity:1;" d="M 228.199219 305.625 C 219.042969 305.625 211.320312 313.09375 211.320312 321.945312 C 211.320312 331.226562 218.828125 338.652344 228.238281 338.652344 C 237.4375 338.652344 245.035156 331.179688 245.035156 322.15625 C 245.035156 313.050781 237.4375 305.625 228.195312 305.625 Z M 228.199219 308.558594 C 235.664062 308.558594 241.796875 314.734375 241.796875 322.203125 C 241.796875 329.585938 235.621094 335.71875 228.238281 335.71875 C 220.640625 335.71875 214.554688 329.585938 214.554688 322.03125 C 214.554688 314.734375 220.816406 308.558594 228.199219 308.558594 Z M 228.199219 308.558594 "/>
<path style=" stroke:none;fill-rule:nonzero;fill:rgb(100%,16.470589%,83.137256%);fill-opacity:1;" d="M 250.097656 338.078125 L 253.289062 338.078125 L 253.289062 332.636719 L 250.097656 332.636719 Z M 250.097656 338.078125 "/>
<path style=" stroke:none;fill-rule:nonzero;fill:rgb(100%,100%,100%);fill-opacity:1;" d="M 287.386719 329.710938 C 286.050781 331.398438 285.273438 332.257812 284.195312 333.078125 C 282.035156 334.761719 279.1875 335.710938 276.292969 335.710938 C 268.867188 335.710938 262.828125 329.625 262.828125 322.113281 C 262.828125 314.429688 268.609375 308.554688 276.25 308.554688 C 279.015625 308.554688 281.605469 309.292969 283.71875 310.71875 C 285.148438 311.621094 286.007812 312.574219 287.21875 314.472656 L 290.800781 314.472656 C 288.339844 308.988281 282.730469 305.621094 276.125 305.621094 C 266.625 305.621094 259.589844 312.699219 259.589844 322.242188 C 259.589844 331.609375 266.796875 338.648438 276.335938 338.648438 C 282.8125 338.648438 287.734375 335.625 290.929688 329.710938 Z M 287.386719 329.710938 "/>
<path style=" stroke:none;fill-rule:nonzero;fill:rgb(100%,100%,100%);fill-opacity:1;" d="M 310.894531 305.625 C 301.738281 305.625 294.015625 313.09375 294.015625 321.945312 C 294.015625 331.226562 301.523438 338.652344 310.9375 338.652344 C 320.132812 338.652344 327.730469 331.179688 327.730469 322.15625 C 327.730469 313.050781 320.132812 305.625 310.894531 305.625 Z M 310.894531 308.558594 C 318.359375 308.558594 324.492188 314.734375 324.492188 322.203125 C 324.492188 329.585938 318.320312 335.71875 310.9375 335.71875 C 303.339844 335.71875 297.25 329.585938 297.25 322.03125 C 297.25 314.734375 303.511719 308.558594 310.894531 308.558594 Z M 310.894531 308.558594 "/>
<path style=" stroke:none;fill-rule:nonzero;fill:rgb(100%,100%,100%);fill-opacity:1;" d="M 332.90625 338.078125 L 336.097656 338.078125 L 336.097656 309.671875 L 348.054688 338.078125 L 350.820312 338.078125 L 362.820312 309.671875 L 362.820312 338.078125 L 366.015625 338.078125 L 366.015625 306.175781 L 361.050781 306.175781 L 349.484375 333.328125 L 337.867188 306.175781 L 332.90625 306.175781 Z M 332.90625 338.078125 "/>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 14 KiB

@ -1,10 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="375pt" height="375pt" viewBox="0 0 375 375" version="1.1">
<g id="surface10">
<path style=" stroke:none;fill-rule:evenodd;fill:rgb(100%,16.470589%,83.137256%);fill-opacity:1;" d="M 32.453125 159.164062 L 32.453125 301.363281 C 32.453125 315.15625 43.554688 326.257812 57.347656 326.257812 L 285.03125 326.257812 C 298.828125 326.257812 309.925781 315.15625 309.925781 301.363281 L 309.925781 159.164062 L 246.84375 159.164062 L 246.84375 257.085938 L 171.195312 181.4375 L 95.546875 257.085938 L 95.546875 159.164062 Z M 32.453125 159.164062 "/>
<path style=" stroke:none;fill-rule:evenodd;fill:rgb(100%,80.000001%,0%);fill-opacity:1;" d="M 57.347656 48.785156 C 43.554688 48.785156 32.453125 59.882812 32.453125 73.679688 L 32.453125 135.429688 L 120.785156 135.429688 L 120.785156 197.054688 L 171.191406 146.644531 L 221.597656 197.054688 L 221.597656 135.429688 L 309.921875 135.429688 L 309.921875 73.679688 C 309.921875 59.882812 298.820312 48.785156 285.023438 48.785156 Z M 57.347656 48.785156 "/>
<path style=" stroke:none;fill-rule:evenodd;fill:rgb(100%,80.000001%,0%);fill-opacity:1;" d="M 330.6875 65.148438 C 337.269531 65.148438 342.5625 70.445312 342.5625 77.027344 L 342.5625 124.164062 C 342.5625 130.746094 337.269531 136.046875 330.6875 136.046875 L 324.472656 136.046875 L 324.472656 65.148438 Z M 330.6875 65.148438 "/>
<path style=" stroke:none;fill-rule:evenodd;fill:rgb(100%,16.470589%,83.137256%);fill-opacity:1;" d="M 330.6875 152.078125 C 337.269531 152.078125 342.5625 157.378906 342.5625 163.953125 L 342.5625 211.097656 C 342.5625 217.679688 337.269531 222.972656 330.6875 222.972656 L 324.472656 222.972656 L 324.472656 152.078125 Z M 330.6875 152.078125 "/>
<path style=" stroke:none;fill-rule:evenodd;fill:rgb(100%,16.470589%,83.137256%);fill-opacity:1;" d="M 330.6875 239.015625 C 337.269531 239.015625 342.5625 244.304688 342.5625 250.890625 L 342.5625 298.03125 C 342.5625 304.609375 337.269531 309.90625 330.6875 309.90625 L 324.472656 309.90625 L 324.472656 239.015625 Z M 330.6875 239.015625 "/>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 2.1 KiB

@ -1,49 +0,0 @@
{% extends "base.html" %}
{% block content %}
<div style="display:none">
{% block title %}YellWOWPages - About{% endblock %}
</div>
<div id="main">
<h1>About</h1>
<p>
Search for any Wownero <em>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>
Made by <a href="https://notmtth.xyz">NotMtth</a> and <code>dsc</code>
</p>
</div>
<style>
#main{
width: 100%;
height: 80vh;
display: grid;
place-content: center;
text-align: center;
}
form{
height: 50px;
}
@media (max-width: 800px) {
kbd{
width: 100vw;
}
}
</style>
{% endblock %}

@ -1,36 +0,0 @@
{% extends "base.html" %}
{% block content %}
<div style="display:none">
{% block title %}YellWOWPages - API{% endblock %}
</div>
<div id="main">
<h1>API</h1>
<p>
Search user: <code><a href="/api/user/dsc" data-tooltip="partial search supported">/api/user/{username}</a></code>
<br><br>
Get all users: <code><a href="/api/user/">/api/user/</a></code>
</p>
</div>
<style>
#main {
width: 100%;
height: 80vh;
display: grid;
place-content: center;
text-align: center;
}
form {
height: 50px;
}
@media (max-width: 800px) {
kbd {
width: 100vw;
}
}
</style>
{% endblock %}

@ -1,43 +0,0 @@
{% extends "base.html" %}
{% block content %}
<div style="display:none">
{% block title %}YellWOWPages - Dashboard{% endblock %}
</div>
<div id="main">
<article style="min-width: 620px">
<Header>Welcome back <em>{{user.username}}</em>!</Header>
Current <u>WOW address</u>: <label>
{% if user.address %}
<mark>{{user.address}}</mark>
{% else %}
<mark>empty</mark>
{% endif %}
</label>
<footer>
Change <u>WOW address</u>:
<form action="{{ url_for('bp_routes.dashboard_address_post') }}" method="POST">
<input type="text" name="address">
<button data-tooltip="Make sure it is correct!">Submit</button>
</form>
<form action="{{ url_for('bp_routes.dashboard_address_delete') }}" method="POST">
<button class="secondary" data-tooltip="Remove address from YelloWOWPages">Delete</button>
</form>
</footer>
</article>
</div>
<style>
#main {
width: 100%;
height: 85vh;
display: grid;
place-content: center;
}
@media (max-width: 800px) {
}
</style>
{% endblock %}

@ -1,27 +0,0 @@
<nav>
<ul>
<li>
<div id="dropdown">
<i class="icon icon-menu"></i>
<div id="dropdowncontent">
<a href="{{ url_for('bp_routes.root') }}">Home</a>
{% if not user %}
<a href="{{ url_for('bp_routes.login') }}">Login</a>
{% else %}
<a href="{{ url_for('bp_routes.dashboard') }}">My Profile</a>
{% endif %}
<a href="{{ url_for('bp_routes.search') }}">Search</a>
<a href="{{ url_for('bp_routes.about') }}">About</a>
<a href="{{ url_for('bp_api.api_root') }}">Api</a>
{% if user %}
<a href="{{ url_for('bp_routes.logout') }}">Logout</a>
{% endif %}
</div>
</div>
</li>
</ul>
<ul>
<li><a href="https://git.wownero.com/wownero/YellWOWPages"><i class="icon icon-edit"></i></a></li>
</ul>
</nav>

@ -1,3 +0,0 @@
<form action="{{ url_for('bp_routes.search') }}" method="GET">
<input type="text" name="username" placeholder="Search for an username...">
</form>

@ -1,11 +0,0 @@
<div id="addresses">
{% for user in users %}
<article>
<header>
<em><a href="{{ url_for('bp_routes.user_page', name=user.username) }}">{{user.username}}</a></em>
<small style="float: right">Added: {{ user.created_dt }}</small>
</header>
<kbd>{{user.address}}</kbd>
</article>
{% endfor %}
</div>

@ -1,24 +0,0 @@
{% extends "base.html" %}
{% block content %}
<div style="display:none">
{% block title %}YellWOWPages - Sex and Drugs in the metaverse{% endblock %}
</div>
<div id="main">
<div id="root">
<img src="{{ url_for('static', filename='1-ico.svg') }}" alt="">
<div style="flex-direction: column;">
<div>
The first <img src="{{ url_for('static', filename='wownero.png') }}" alt="" id="wow"> addresses library <br>
from the community, for the community.
</div>
<div>
<a style="text-decoration: none;" href="{{ url_for('bp_routes.search') }}">
<button style="max-width:320px;">start searching</button>
</a>
</div>
</div>
</div>
</div>
{% endblock %}

@ -1,42 +0,0 @@
{% extends "base.html" %}
{% block content %}
<div style="display:none">
{% block title %}YellWOWPages - Yellwow{% endblock %}
</div>
<div id="main">
{% include 'includes/search.html' %}
{% include 'includes/user_results.html' %}
</div>
<style>
#main {
width: 100%;
height: 80vh;
display: grid;
place-content: center;
}
form {
height: 80px;
}
#addresses {
width: 100%;
height: 54vh;
overflow-y: auto;
}
#addresses::-webkit-scrollbar {
display: none;
}
@media (max-width: 800px) {
kbd {
width: 100vw;
}
}
</style>
{% endblock %}

@ -1,45 +0,0 @@
{% extends "base.html" %}
{% block content %}
<div style="display:none">
{% block title %}YellWOWPages - User{% endblock %}
</div>
<div id="main">
{% include 'includes/search.html' %}
<br>
Result(s): {{users|length}}
{% if not users %}
<br>Nothing found...
{% else %}
{% include 'includes/user_results.html' %}
{% endif %}
</div>
<style>
#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;
}
@media (max-width: 800px) {
kbd{
width: 100vw;
}
}
</style>
{% endblock %}

@ -1,42 +0,0 @@
{% extends "base.html" %}
{% block content %}
<div style="display:none">
{% block title %}YellWOWPages - User{% endblock %}
</div>
<div id="main">
{% include 'includes/search.html' %}
{% if not users %}
<br>Nothing found...
{% else %}
{% include 'includes/user_results.html' %}
{% endif %}
</div>
<style>
#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;
}
@media (max-width: 800px) {
kbd{
width: 100vw;
}
}
</style>
{% endblock %}
Loading…
Cancel
Save