flask web app (wip)

This commit is contained in:
Dobromir Popov 2024-10-13 00:39:46 +03:00
parent b9410f2986
commit 49384accf6
12 changed files with 234 additions and 36 deletions

View File

@ -1463,7 +1463,13 @@ async def main():
logging.info("Restarting wallet_watch_loop") logging.info("Restarting wallet_watch_loop")
await send_telegram_message("Restarting wallet_watch_loop") await send_telegram_message("Restarting wallet_watch_loop")
from modules.webui import init_app
async def run_flask(): async def run_flask():
# loop = asyncio.get_running_loop()
# await loop.run_in_executor(None, lambda: app.run(debug=False, port=3001, use_reloader=False))
app = init_app()
loop = asyncio.get_running_loop() loop = asyncio.get_running_loop()
await loop.run_in_executor(None, lambda: app.run(debug=False, port=3001, use_reloader=False)) await loop.run_in_executor(None, lambda: app.run(debug=False, port=3001, use_reloader=False))

View File

@ -1,11 +1,12 @@
from flask import Flask, jsonify, request from flask import Flask, jsonify, request, render_template, redirect, url_for
from flask_login import LoginManager, UserMixin, login_user, login_required, current_user from flask_login import LoginManager, UserMixin, login_user, login_required, logout_user, current_user
import secrets import secrets
from modules import storage # Import your storage module from modules import storage
app = Flask(__name__) app = Flask(__name__, template_folder='../templates', static_folder='../static')
app.config['SECRET_KEY'] = 'your-secret-key' app.config['SECRET_KEY'] = 'your-secret-key'
login_manager = LoginManager(app) login_manager = LoginManager(app)
login_manager.login_view = 'login'
class User(UserMixin): class User(UserMixin):
def __init__(self, id, username, email): def __init__(self, id, username, email):
@ -20,18 +21,34 @@ def load_user(user_id):
return User(id=user_data['id'], username=user_data['username'], email=user_data['email']) return User(id=user_data['id'], username=user_data['username'], email=user_data['email'])
return None return None
@app.route('/login', methods=['POST']) @app.route('/')
def login(): def index():
data = request.json return render_template('index.html')
username = data.get('username')
password = data.get('password')
user = storage.authenticate_user(username, password) @app.route('/login', methods=['GET', 'POST'])
if user: def login():
login_user(User(id=user['id'], username=user['username'], email=user['email'])) if request.method == 'POST':
return jsonify({'message': 'Login successful'}), 200 username = request.form.get('username')
else: password = request.form.get('password')
return jsonify({'message': 'Invalid credentials'}), 401
user = storage.authenticate_user(username, password)
if user:
login_user(User(id=user['id'], username=user['username'], email=user['email']))
return redirect(url_for('dashboard'))
else:
return render_template('login.html', error='Invalid credentials')
return render_template('login.html')
@app.route('/logout')
@login_required
def logout():
logout_user()
return redirect(url_for('index'))
@app.route('/dashboard')
@login_required
def dashboard():
return render_template('dashboard.html')
@app.route('/generate_api_key', methods=['POST']) @app.route('/generate_api_key', methods=['POST'])
@login_required @login_required

View File

@ -2,6 +2,7 @@ aiohttp==3.10.9
base58==2.1.1 base58==2.1.1
dexscreener==1.1 dexscreener==1.1
Flask==3.0.3 Flask==3.0.3
flask-login
jupiter_python_sdk==0.0.2.0 jupiter_python_sdk==0.0.2.0
python-dotenv==1.0.1 python-dotenv==1.0.1
python-telegram-bot==21.6 python-telegram-bot==21.6

View File

@ -0,0 +1,46 @@
/* Add your custom styles here */
body {
font-family: Arial, sans-serif;
line-height: 1.6;
margin: 0;
padding: 0;
}
header {
background-color: #4A90E2;
color: white;
padding: 1rem;
}
nav ul {
list-style-type: none;
padding: 0;
}
nav ul li {
display: inline;
margin-right: 1rem;
}
nav ul li a {
color: white;
text-decoration: none;
}
main {
padding: 2rem;
}
footer {
background-color: #333;
color: white;
text-align: center;
padding: 1rem;
position: fixed;
bottom: 0;
width: 100%;
}
@media (max-width: 768px) {
/* Add responsive styles for mobile devices */
}

View File

@ -1,3 +1,4 @@
document.getElementById('connectWallet').addEventListener('click', async () => { document.getElementById('connectWallet').addEventListener('click', async () => {
try { try {
const { solana } is window; const { solana } is window;
@ -26,3 +27,20 @@ document.getElementById('swapToken').addEventListener('click', () => {
.then(response => response.json()) .then(response => response.json())
.then(data => alert(data.message)); .then(data => alert(data.message));
}); });
// Add your custom JavaScript here
document.addEventListener('DOMContentLoaded', () => {
const generateApiKeyButton = document.getElementById('generate-api-key');
const apiKeyDisplay = document.getElementById('api-key-display');
if (generateApiKeyButton) {
generateApiKeyButton.addEventListener('click', async () => {
const response = await fetch('/generate_api_key', { method: 'POST' });
const data = await response.json();
apiKeyDisplay.textContent = `Your API Key: ${data.api_key}`;
});
}
// Add more JavaScript for fetching and displaying wallet data, transactions, and holdings
});

View File

@ -0,0 +1,20 @@
{
"name": "Crypto Portfolio Tracker",
"short_name": "CryptoTracker",
"start_url": "/",
"display": "standalone",
"background_color": "#ffffff",
"theme_color": "#4A90E2",
"icons": [
{
"src": "/static/images/logo-192x192.png",
"sizes": "192x192",
"type": "image/png"
},
{
"src": "/static/images/logo-512x512.png",
"sizes": "512x512",
"type": "image/png"
}
]
}

View File

@ -0,0 +1,8 @@
// Add service worker code for offline functionality and caching
self.addEventListener('install', (event) => {
// Perform install steps
});
self.addEventListener('fetch', (event) => {
// Handle fetch events
});

View File

@ -0,0 +1,36 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>{% block title %}Crypto Portfolio Tracker{% endblock %}</title>
<link rel="stylesheet" href="{{ url_for('static', filename='css/styles.css') }}">
<link rel="manifest" href="{{ url_for('static', filename='manifest.json') }}">
<meta name="theme-color" content="#4A90E2">
</head>
<body>
<header>
<nav>
<ul>
<li><a href="{{ url_for('index') }}">Home</a></li>
{% if current_user.is_authenticated %}
<li><a href="{{ url_for('dashboard') }}">Dashboard</a></li>
<li><a href="{{ url_for('logout') }}">Logout</a></li>
{% else %}
<li><a href="{{ url_for('login') }}">Login</a></li>
{% endif %}
</ul>
</nav>
</header>
<main>
{% block content %}{% endblock %}
</main>
<footer>
<p>&copy; 2023 Crypto Portfolio Tracker</p>
</footer>
<script src="{{ url_for('static', filename='js/app.js') }}"></script>
</body>
</html>

View File

@ -0,0 +1,23 @@
{% extends "base.html" %}
{% block content %}
<h1>Dashboard</h1>
<p>Welcome, {{ current_user.username }}!</p>
<h2>Your Wallets</h2>
<div id="wallets"></div>
<h2>Recent Transactions</h2>
<div id="transactions"></div>
<h2>Holdings</h2>
<div id="holdings"></div>
<button id="generate-api-key">Generate API Key</button>
<p id="api-key-display"></p>
<script>
// Add JavaScript to fetch and display wallet data, transactions, and holdings
// Also add functionality for generating API key
</script>
{% endblock %}

View File

@ -1,21 +1,6 @@
<!DOCTYPE html> {% extends "base.html" %}
<html lang="en">
<head> {% block content %}
<meta charset="UTF-8"> <h1>Welcome to Crypto Portfolio Tracker</h1>
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <p>Track your cryptocurrency investments with ease.</p>
<title>Token Swapper</title> {% endblock %}
</head>
<body>
<h1>Token Swapper</h1>
<div>
<button id="connectWallet">Connect Phantom Wallet</button>
</div>
<div>
<input type="text" id="tokenName" placeholder="Enter Token Name">
<input type="number" id="amount" placeholder="Enter Amount">
<button id="swapToken">Swap Token</button>
</div>
<script src="https://cdn.jsdelivr.net/npm/@solana/web3.js"></script>
<script src="app.js"></script>
</body>
</html>

View File

@ -0,0 +1,17 @@
{% extends "base.html" %}
{% block content %}
<h1>Login</h1>
<form method="POST" action="{{ url_for('login') }}">
<label for="username">Username:</label>
<input type="text" id="username" name="username" required>
<label for="password">Password:</label>
<input type="password" id="password" name="password" required>
<button type="submit">Login</button>
</form>
{% if error %}
<p class="error">{{ error }}</p>
{% endif %}
{% endblock %}

View File

@ -0,0 +1,21 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Token Swapper</title>
</head>
<body>
<h1>Token Swapper</h1>
<div>
<button id="connectWallet">Connect Phantom Wallet</button>
</div>
<div>
<input type="text" id="tokenName" placeholder="Enter Token Name">
<input type="number" id="amount" placeholder="Enter Amount">
<button id="swapToken">Swap Token</button>
</div>
<script src="https://cdn.jsdelivr.net/npm/@solana/web3.js"></script>
<script src="app.js"></script>
</body>
</html>