diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..8d9428f --- /dev/null +++ b/.gitignore @@ -0,0 +1,52 @@ +# 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/ + diff --git a/README.md b/README.md new file mode 100644 index 0000000..67ba027 --- /dev/null +++ b/README.md @@ -0,0 +1,19 @@ +## YellWOWPages + +Wownero yellow pages web-application - lookup the WOW address of users. + +### Installation + +```bash +git clone gitea@git.wownero.com:muchwowmining/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 +``` diff --git a/TODO b/TODO deleted file mode 100644 index 6b924b6..0000000 --- a/TODO +++ /dev/null @@ -1,5 +0,0 @@ -remove Constraints.client_secret before publishing and make a backup of it!! - -Register new application new login.wownero.com - client_id = yellwowpages - client url = /authenticate diff --git a/classes/constraints.py b/classes/constraints.py deleted file mode 100644 index c8c210f..0000000 --- a/classes/constraints.py +++ /dev/null @@ -1,8 +0,0 @@ -from starlette.templating import Jinja2Templates - - -class Constraints: - templates = Jinja2Templates(directory='frontend/templates') - client_id = '' - client_secret = '' - uri = 'sqlite:///users.db' diff --git a/classes/__init__.py b/data/.gitkeep similarity index 100% rename from classes/__init__.py rename to data/.gitkeep diff --git a/frontend/templates/about/api/index.html b/frontend/templates/about/api/index.html deleted file mode 100644 index eb911ca..0000000 --- a/frontend/templates/about/api/index.html +++ /dev/null @@ -1,108 +0,0 @@ - - - - - - - YellWOWPages - Sex and Drugs in the metaverse - - - - - - -
- -
-
-
-

About - Api

-

- Search user: /api/user/{username} -

- Get all users: /api/all -

-
-
- - - \ No newline at end of file diff --git a/frontend/templates/about/index.html b/frontend/templates/about/index.html deleted file mode 100644 index d1a4cf1..0000000 --- a/frontend/templates/about/index.html +++ /dev/null @@ -1,125 +0,0 @@ - - - - - - - YellWOWPages - Sex and Drugs in the metaverse - - - - - - -
- -
-
-
-

About

-

- Search for any Wownero sub-address you want by username and pay - the world! -
- This application uses Wownero's Centralized Authentication Service. -

-

- Other Wownero related stuff: -
- WebSite -
- SuchWow -
- Official Git -
- Discord server -

-

- Idea of: dsc_ -
- Made by NotMtth -

-
-
- - - \ No newline at end of file diff --git a/frontend/templates/dashboard/index.html b/frontend/templates/dashboard/index.html deleted file mode 100644 index bfada88..0000000 --- a/frontend/templates/dashboard/index.html +++ /dev/null @@ -1,100 +0,0 @@ - - - - - - - Such dashboard - - - - - - -
- -
-
-
-
- {% for username, address in user_data.items() %} -
Welcome back {{username}}!
- Current sub-address: -
- Change sub-address: -
- - -
-
- {% endfor %} -
-
-
- - - \ No newline at end of file diff --git a/frontend/templates/yellwow/index.html b/frontend/templates/yellwow/index.html deleted file mode 100644 index a937f51..0000000 --- a/frontend/templates/yellwow/index.html +++ /dev/null @@ -1,126 +0,0 @@ - - - - - - - YellWOWPages - Sex and Drugs in the metaverse - - - - - - -
- -
-
-
-
- - -
-
- {% for username, address in user_data.items() %} -
-
- {{username}} -
- {{address}} -
- {% endfor %} -
-
-
- - - \ No newline at end of file diff --git a/frontend/templates/yellwow/single_user/index.html b/frontend/templates/yellwow/single_user/index.html deleted file mode 100644 index 9c32b8a..0000000 --- a/frontend/templates/yellwow/single_user/index.html +++ /dev/null @@ -1,132 +0,0 @@ - - - - - - - YellWOWPages - Sex and Drugs in the metaverse - - - - - - -
- -
-
-
-
- - -
-
- Result: {{user_data|length}} - {% if not user_data|length %} - Nothing found... - {% else %} -
- {% for username, address in user_data.items() %} -
-
- {{username}} -
- {{address}} -
- {% endfor %} -
- {% endif %} -
-
- - - \ No newline at end of file diff --git a/main.py b/main.py deleted file mode 100644 index 4344355..0000000 --- a/main.py +++ /dev/null @@ -1,45 +0,0 @@ -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) diff --git a/requirements.txt b/requirements.txt index b9939be..847cf0c 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,30 +1,3 @@ -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 +peewee +quart +quart_session_openid diff --git a/routers/__init__.py b/routers/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/routers/api.py b/routers/api.py deleted file mode 100644 index cc8c8bc..0000000 --- a/routers/api.py +++ /dev/null @@ -1,32 +0,0 @@ -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}') diff --git a/routers/auth.py b/routers/auth.py deleted file mode 100644 index 600165e..0000000 --- a/routers/auth.py +++ /dev/null @@ -1,68 +0,0 @@ -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 diff --git a/routers/dashboard.py b/routers/dashboard.py deleted file mode 100644 index c2e13c5..0000000 --- a/routers/dashboard.py +++ /dev/null @@ -1,63 +0,0 @@ -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) - - diff --git a/routers/db.py b/routers/db.py deleted file mode 100644 index d938900..0000000 --- a/routers/db.py +++ /dev/null @@ -1,54 +0,0 @@ -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') diff --git a/routers/errors.py b/routers/errors.py deleted file mode 100644 index 86c3b6c..0000000 --- a/routers/errors.py +++ /dev/null @@ -1,2 +0,0 @@ -# stupid fastapi error handling drove me crazy for some hours, updating this asap -# the handler is in the main file diff --git a/routers/static.py b/routers/static.py deleted file mode 100644 index 232e23d..0000000 --- a/routers/static.py +++ /dev/null @@ -1,39 +0,0 @@ -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}) diff --git a/run.py b/run.py new file mode 100644 index 0000000..0bb343d --- /dev/null +++ b/run.py @@ -0,0 +1,5 @@ +from yellow.factory import create_app +import settings + +app = create_app() +app.run(settings.HOST, port=settings.PORT, debug=settings.DEBUG, use_reloader=False) diff --git a/settings.py_example b/settings.py_example new file mode 100644 index 0000000..0370f84 --- /dev/null +++ b/settings.py_example @@ -0,0 +1,23 @@ +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" +} + diff --git a/yellow/__init__.py b/yellow/__init__.py new file mode 100644 index 0000000..5d736d6 --- /dev/null +++ b/yellow/__init__.py @@ -0,0 +1,13 @@ +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 diff --git a/yellow/api.py b/yellow/api.py new file mode 100644 index 0000000..5db663b --- /dev/null +++ b/yellow/api.py @@ -0,0 +1,25 @@ +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(): + return jsonify([u.to_json(ignore_key='id') for u in User.select()]) + + +@bp_api.get('/user/') +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([]) diff --git a/yellow/auth.py b/yellow/auth.py new file mode 100644 index 0000000..6af89be --- /dev/null +++ b/yellow/auth.py @@ -0,0 +1,28 @@ +import peewee +from quart import session, redirect, url_for + +from yellow.factory import openid +from yellow.models import User + + +@openid.after_token() +async def handle_user_login(resp: dict): + access_token = resp["access_token"] + openid.verify_token(access_token) + + user = await openid.user_info(access_token) + username = user['preferred_username'] + uid = user['sub'] + + try: + user = User.select().where(User.id == uid).get() + except peewee.DoesNotExist: + user = None + + if not user: + # create new user if it does not exist yet + user = User.create(id=uid, username=username) + + # user is now logged in + session['user'] = user.to_json() + return redirect(url_for('bp_routes.root')) diff --git a/yellow/factory.py b/yellow/factory.py new file mode 100644 index 0000000..069a196 --- /dev/null +++ b/yellow/factory.py @@ -0,0 +1,80 @@ +import os +import logging +import asyncio + +from quart import Quart, url_for, jsonify, render_template, session +from quart_session_openid import OpenID +from quart_session import Session +import settings + + +app: Quart = None +peewee = None +cache = None +openid: OpenID = 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 openid + openid = OpenID(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__) + + app.logger.setLevel(logging.INFO) + app.secret_key = settings.APP_SECRET + + @app.context_processor + def template_variables(): + global openid + from yellow.models import User + current_user = session.get('user') + if current_user: + current_user = User(**current_user) + return dict(user=current_user, url_login=openid.endpoint_name_login) + + @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 diff --git a/yellow/models.py b/yellow/models.py new file mode 100644 index 0000000..7232ada --- /dev/null +++ b/yellow/models.py @@ -0,0 +1,37 @@ +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 = pw.DateTimeField(default=datetime.now) + username = pw.CharField(unique=True, null=False) + address = pw.CharField(null=True) + + @staticmethod + async def search(needle) -> List['User']: + needle = needle.replace("*", "") + if len(needle) <= 2: + raise Exception("need longer search term") + return User.select().where(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 diff --git a/yellow/routes.py b/yellow/routes.py new file mode 100644 index 0000000..d72655d --- /dev/null +++ b/yellow/routes.py @@ -0,0 +1,69 @@ +from quart import render_template, request, redirect, url_for, jsonify, Blueprint, abort, flash, send_from_directory, session + +from yellow import login_required +from yellow.factory import openid +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(): + return redirect(url_for(openid.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(): + # get FORM POST value 'address' + 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.route("/search") +async def search(): + needle = request.args.get('username') + if needle: + if len(needle) <= 2: + raise Exception("Search term needs to be longer") + + users = [u for u in await User.search(needle)] + if users: + return await render_template('search_results.html', users=users) + + users = [u for u in User.select()] + return await render_template('search.html', users=users) + + +@bp_routes.route("/about") +async def about(): + return await render_template('about.html') diff --git a/frontend/static/colors.css b/yellow/static/colors.css similarity index 100% rename from frontend/static/colors.css rename to yellow/static/colors.css diff --git a/frontend/static/icon.css b/yellow/static/icon.css similarity index 100% rename from frontend/static/icon.css rename to yellow/static/icon.css diff --git a/frontend/static/wownero.png b/yellow/static/wownero.png similarity index 100% rename from frontend/static/wownero.png rename to yellow/static/wownero.png diff --git a/yellow/templates/about.html b/yellow/templates/about.html new file mode 100644 index 0000000..871dbb6 --- /dev/null +++ b/yellow/templates/about.html @@ -0,0 +1,49 @@ +{% extends "base.html" %} +{% block content %} +
+{% block title %}YellWOWPages - About{% endblock %} +
+ +
+

About

+

+ Search for any Wownero address you want by username and pay + the world! +
+ This application uses Wownero's Centralized Authentication Service. +

+

+ Other Wownero related stuff: +
+ WebSite +
+ SuchWow +
+ Official Git +
+ Discord server +

+

+ Made by NotMtth and dsc +

+
+ + + +{% endblock %} \ No newline at end of file diff --git a/yellow/templates/api.html b/yellow/templates/api.html new file mode 100644 index 0000000..be6f155 --- /dev/null +++ b/yellow/templates/api.html @@ -0,0 +1,36 @@ +{% extends "base.html" %} +{% block content %} +
+{% block title %}YellWOWPages - API{% endblock %} +
+ +
+

API

+

+ Search user: /api/user/{username} +

+ Get all users: /api/user/ +

+
+ + + +{% endblock %} \ No newline at end of file diff --git a/frontend/templates/root/index.html b/yellow/templates/base.html similarity index 53% rename from frontend/templates/root/index.html rename to yellow/templates/base.html index 52bfe40..797b8ea 100644 --- a/frontend/templates/root/index.html +++ b/yellow/templates/base.html @@ -4,10 +4,11 @@ - YellWOWPages - Sex and Drugs in the metaverse + {% block title %}YellWOWPages - Sex and Drugs in the metaverse{% endblock %} + - - + + -
- -
-
-
-
- YellWOWPages -
-
- The first addresses library - - from the community to the community -
-
-
- +
+ {% include 'includes/nav.html' %} + + {% block content %} {% endblock %} +
+ + - \ No newline at end of file + diff --git a/yellow/templates/dashboard.html b/yellow/templates/dashboard.html new file mode 100644 index 0000000..ee72a3a --- /dev/null +++ b/yellow/templates/dashboard.html @@ -0,0 +1,40 @@ +{% extends "base.html" %} +{% block content %} +
+{% block title %}YellWOWPages - Dashboard{% endblock %} +
+ +
+
+
Welcome back {{user.username}}!
+ Current WOW address: +
+ Change WOW address: +
+ + +
+
+ +
+
+ + +{% endblock %} \ No newline at end of file diff --git a/frontend/templates/errors/index.html b/yellow/templates/error.html similarity index 89% rename from frontend/templates/errors/index.html rename to yellow/templates/error.html index f5b817d..a009ac9 100644 --- a/frontend/templates/errors/index.html +++ b/yellow/templates/error.html @@ -5,7 +5,7 @@ - Such error :( + Such {{code}} error :( @@ -23,7 +23,7 @@
-

Error: {{error}}

+

Error {{code}}: {{msg}}

diff --git a/yellow/templates/includes/nav.html b/yellow/templates/includes/nav.html new file mode 100644 index 0000000..2b42606 --- /dev/null +++ b/yellow/templates/includes/nav.html @@ -0,0 +1,25 @@ + diff --git a/yellow/templates/index.html b/yellow/templates/index.html new file mode 100644 index 0000000..502bd16 --- /dev/null +++ b/yellow/templates/index.html @@ -0,0 +1,17 @@ +{% extends "base.html" %} +{% block content %} +
+{% block title %}YellWOWPages - Sex and Drugs in the metaverse{% endblock %} +
+ +
+
+ YellWOWPages +
+
+ The first addresses library - + from the community to the community +
+
+ +{% endblock %} \ No newline at end of file diff --git a/yellow/templates/search.html b/yellow/templates/search.html new file mode 100644 index 0000000..f651820 --- /dev/null +++ b/yellow/templates/search.html @@ -0,0 +1,59 @@ +{% extends "base.html" %} +{% block content %} +
+{% block title %}YellWOWPages - Yellwow{% endblock %} +
+ +
+
+ +
+ +
+ {% for user in users %} +
+
+ {{user.username}} +
+ {{user.address}} +
+ {% endfor %} +
+
+ + + +{% endblock %} diff --git a/yellow/templates/search_results.html b/yellow/templates/search_results.html new file mode 100644 index 0000000..e8e798a --- /dev/null +++ b/yellow/templates/search_results.html @@ -0,0 +1,60 @@ +{% extends "base.html" %} +{% block content %} +
+{% block title %}YellWOWPages - User{% endblock %} +
+ +
+
+ +
+
+ Result(s): {{users|length}} + + {% if not users %} + Nothing found... + {% else %} +
+ {% for user in users %} +
+
+ {{user.username}} +
+ {{user.address}} +
+ {% endfor %} +
+ {% endif %} +
+ + + +{% endblock %} \ No newline at end of file