Add development testing environment
Templates (8 basic templates): - base.html: Main layout with navigation, flash messages, responsive design - login.html: User login form with remember me option - register.html: User registration with validation - dashboard.html: Main dashboard with statistics cards and recent activity - players_list.html: Players list placeholder - add_player.html: Add player form - groups_list.html: Groups list placeholder - create_group.html: Create group form - content_list.html: Content list placeholder - upload_content.html: File upload form - admin.html: Admin panel with system overview Development Setup: - run_dev.sh: Automated development server setup script - Creates virtual environment - Installs dependencies - Initializes database - Creates default admin user (admin/admin123) - Runs Flask development server on port 5000 Static Files: - static/uploads/ directory with .gitkeep - Ready for media file uploads Testing Features: ✅ Basic navigation and routing ✅ Authentication flow (login/register/logout) ✅ Dashboard with statistics ✅ Flash message system ✅ Responsive design with clean UI ✅ Placeholder templates for all routes Ready for manual testing at http://localhost:5000
This commit is contained in:
1
app/static/uploads/.gitkeep
Normal file
1
app/static/uploads/.gitkeep
Normal file
@@ -0,0 +1 @@
|
||||
# This file ensures the uploads directory is tracked by git even when empty
|
||||
30
app/templates/add_player.html
Normal file
30
app/templates/add_player.html
Normal file
@@ -0,0 +1,30 @@
|
||||
{% extends "base.html" %}
|
||||
|
||||
{% block title %}Add Player - DigiServer v2{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<h1>Add Player</h1>
|
||||
<div class="card">
|
||||
<form method="POST">
|
||||
<div style="margin-bottom: 1rem;">
|
||||
<label>Name</label>
|
||||
<input type="text" name="name" required style="width: 100%; padding: 0.5rem;">
|
||||
</div>
|
||||
<div style="margin-bottom: 1rem;">
|
||||
<label>Location (optional)</label>
|
||||
<input type="text" name="location" style="width: 100%; padding: 0.5rem;">
|
||||
</div>
|
||||
<div style="margin-bottom: 1rem;">
|
||||
<label>Group (optional)</label>
|
||||
<select name="group_id" style="width: 100%; padding: 0.5rem;">
|
||||
<option value="">No Group</option>
|
||||
{% for group in groups %}
|
||||
<option value="{{ group.id }}">{{ group.name }}</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
</div>
|
||||
<button type="submit" class="btn btn-success">Create Player</button>
|
||||
<a href="{{ url_for('players.players_list') }}" class="btn">Cancel</a>
|
||||
</form>
|
||||
</div>
|
||||
{% endblock %}
|
||||
20
app/templates/admin.html
Normal file
20
app/templates/admin.html
Normal file
@@ -0,0 +1,20 @@
|
||||
{% extends "base.html" %}
|
||||
|
||||
{% block title %}Admin Panel - DigiServer v2{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<h1>Admin Panel</h1>
|
||||
<div class="card">
|
||||
<h2>System Overview</h2>
|
||||
<p>Total Users: {{ total_users or 0 }}</p>
|
||||
<p>Total Players: {{ total_players or 0 }}</p>
|
||||
<p>Total Groups: {{ total_groups or 0 }}</p>
|
||||
<p>Total Content: {{ total_content or 0 }}</p>
|
||||
<p>Storage Used: {{ storage_mb or 0 }} MB</p>
|
||||
</div>
|
||||
|
||||
<div class="card">
|
||||
<h2>User Management</h2>
|
||||
<p>User management features - Template in progress</p>
|
||||
</div>
|
||||
{% endblock %}
|
||||
145
app/templates/base.html
Normal file
145
app/templates/base.html
Normal file
@@ -0,0 +1,145 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>{% block title %}DigiServer v2{% endblock %}</title>
|
||||
<style>
|
||||
* { margin: 0; padding: 0; box-sizing: border-box; }
|
||||
body {
|
||||
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, sans-serif;
|
||||
line-height: 1.6;
|
||||
color: #333;
|
||||
background: #f5f5f5;
|
||||
}
|
||||
.container {
|
||||
max-width: 1200px;
|
||||
margin: 0 auto;
|
||||
padding: 20px;
|
||||
}
|
||||
header {
|
||||
background: #2c3e50;
|
||||
color: white;
|
||||
padding: 1rem 0;
|
||||
margin-bottom: 2rem;
|
||||
}
|
||||
header .container {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
}
|
||||
header h1 { font-size: 1.5rem; }
|
||||
nav a {
|
||||
color: white;
|
||||
text-decoration: none;
|
||||
margin-left: 1rem;
|
||||
padding: 0.5rem 1rem;
|
||||
border-radius: 4px;
|
||||
transition: background 0.3s;
|
||||
}
|
||||
nav a:hover { background: rgba(255,255,255,0.1); }
|
||||
.alert {
|
||||
padding: 1rem;
|
||||
margin-bottom: 1rem;
|
||||
border-radius: 4px;
|
||||
border-left: 4px solid;
|
||||
}
|
||||
.alert-success {
|
||||
background: #d4edda;
|
||||
border-color: #28a745;
|
||||
color: #155724;
|
||||
}
|
||||
.alert-danger {
|
||||
background: #f8d7da;
|
||||
border-color: #dc3545;
|
||||
color: #721c24;
|
||||
}
|
||||
.alert-warning {
|
||||
background: #fff3cd;
|
||||
border-color: #ffc107;
|
||||
color: #856404;
|
||||
}
|
||||
.alert-info {
|
||||
background: #d1ecf1;
|
||||
border-color: #17a2b8;
|
||||
color: #0c5460;
|
||||
}
|
||||
.card {
|
||||
background: white;
|
||||
border-radius: 8px;
|
||||
padding: 1.5rem;
|
||||
margin-bottom: 1rem;
|
||||
box-shadow: 0 2px 4px rgba(0,0,0,0.1);
|
||||
}
|
||||
.card h2 { margin-bottom: 1rem; color: #2c3e50; }
|
||||
.btn {
|
||||
display: inline-block;
|
||||
padding: 0.5rem 1rem;
|
||||
background: #3498db;
|
||||
color: white;
|
||||
text-decoration: none;
|
||||
border-radius: 4px;
|
||||
border: none;
|
||||
cursor: pointer;
|
||||
transition: background 0.3s;
|
||||
}
|
||||
.btn:hover { background: #2980b9; }
|
||||
.btn-danger { background: #e74c3c; }
|
||||
.btn-danger:hover { background: #c0392b; }
|
||||
.btn-success { background: #27ae60; }
|
||||
.btn-success:hover { background: #229954; }
|
||||
footer {
|
||||
margin-top: 2rem;
|
||||
padding: 1rem 0;
|
||||
text-align: center;
|
||||
color: #7f8c8d;
|
||||
font-size: 0.9rem;
|
||||
}
|
||||
</style>
|
||||
{% block extra_css %}{% endblock %}
|
||||
</head>
|
||||
<body>
|
||||
<header>
|
||||
<div class="container">
|
||||
<h1>📺 DigiServer v2</h1>
|
||||
<nav>
|
||||
{% if current_user.is_authenticated %}
|
||||
<a href="{{ url_for('main.dashboard') }}">Dashboard</a>
|
||||
<a href="{{ url_for('players.players_list') }}">Players</a>
|
||||
<a href="{{ url_for('groups.groups_list') }}">Groups</a>
|
||||
<a href="{{ url_for('content.content_list') }}">Content</a>
|
||||
{% if current_user.is_admin %}
|
||||
<a href="{{ url_for('admin.admin_panel') }}">Admin</a>
|
||||
{% endif %}
|
||||
<a href="{{ url_for('auth.logout') }}">Logout ({{ current_user.username }})</a>
|
||||
{% else %}
|
||||
<a href="{{ url_for('auth.login') }}">Login</a>
|
||||
<a href="{{ url_for('auth.register') }}">Register</a>
|
||||
{% endif %}
|
||||
</nav>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<div class="container">
|
||||
{% with messages = get_flashed_messages(with_categories=true) %}
|
||||
{% if messages %}
|
||||
{% for category, message in messages %}
|
||||
<div class="alert alert-{{ category }}">
|
||||
{{ message }}
|
||||
</div>
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
{% endwith %}
|
||||
|
||||
{% block content %}{% endblock %}
|
||||
</div>
|
||||
|
||||
<footer>
|
||||
<div class="container">
|
||||
DigiServer v2.0.0-alpha | Blueprint Architecture | {{ server_version if server_version else 'Development' }}
|
||||
</div>
|
||||
</footer>
|
||||
|
||||
{% block extra_js %}{% endblock %}
|
||||
</body>
|
||||
</html>
|
||||
11
app/templates/content_list.html
Normal file
11
app/templates/content_list.html
Normal file
@@ -0,0 +1,11 @@
|
||||
{% extends "base.html" %}
|
||||
|
||||
{% block title %}Content - DigiServer v2{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<h1>Content</h1>
|
||||
<div class="card">
|
||||
<p>Content list view - Template in progress</p>
|
||||
<a href="{{ url_for('content.upload_content') }}" class="btn btn-success">Upload Content</a>
|
||||
</div>
|
||||
{% endblock %}
|
||||
21
app/templates/create_group.html
Normal file
21
app/templates/create_group.html
Normal file
@@ -0,0 +1,21 @@
|
||||
{% extends "base.html" %}
|
||||
|
||||
{% block title %}Create Group - DigiServer v2{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<h1>Create Group</h1>
|
||||
<div class="card">
|
||||
<form method="POST">
|
||||
<div style="margin-bottom: 1rem;">
|
||||
<label>Group Name</label>
|
||||
<input type="text" name="name" required style="width: 100%; padding: 0.5rem;">
|
||||
</div>
|
||||
<div style="margin-bottom: 1rem;">
|
||||
<label>Description (optional)</label>
|
||||
<textarea name="description" rows="3" style="width: 100%; padding: 0.5rem;"></textarea>
|
||||
</div>
|
||||
<button type="submit" class="btn btn-success">Create Group</button>
|
||||
<a href="{{ url_for('groups.groups_list') }}" class="btn">Cancel</a>
|
||||
</form>
|
||||
</div>
|
||||
{% endblock %}
|
||||
69
app/templates/dashboard.html
Normal file
69
app/templates/dashboard.html
Normal file
@@ -0,0 +1,69 @@
|
||||
{% extends "base.html" %}
|
||||
|
||||
{% block title %}Dashboard - DigiServer v2{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<h1 style="margin-bottom: 2rem;">Dashboard</h1>
|
||||
|
||||
<div style="display: grid; grid-template-columns: repeat(auto-fit, minmax(250px, 1fr)); gap: 1rem; margin-bottom: 2rem;">
|
||||
<div class="card">
|
||||
<h3 style="color: #3498db; margin-bottom: 0.5rem;">👥 Players</h3>
|
||||
<p style="font-size: 2rem; font-weight: bold;">{{ total_players or 0 }}</p>
|
||||
<a href="{{ url_for('players.players_list') }}" class="btn" style="margin-top: 1rem;">View Players</a>
|
||||
</div>
|
||||
|
||||
<div class="card">
|
||||
<h3 style="color: #9b59b6; margin-bottom: 0.5rem;">📁 Groups</h3>
|
||||
<p style="font-size: 2rem; font-weight: bold;">{{ total_groups or 0 }}</p>
|
||||
<a href="{{ url_for('groups.groups_list') }}" class="btn" style="margin-top: 1rem;">View Groups</a>
|
||||
</div>
|
||||
|
||||
<div class="card">
|
||||
<h3 style="color: #e67e22; margin-bottom: 0.5rem;">🎬 Content</h3>
|
||||
<p style="font-size: 2rem; font-weight: bold;">{{ total_content or 0 }}</p>
|
||||
<a href="{{ url_for('content.content_list') }}" class="btn" style="margin-top: 1rem;">View Content</a>
|
||||
</div>
|
||||
|
||||
<div class="card">
|
||||
<h3 style="color: #27ae60; margin-bottom: 0.5rem;">💾 Storage</h3>
|
||||
<p style="font-size: 2rem; font-weight: bold;">{{ storage_mb or 0 }} MB</p>
|
||||
<a href="{{ url_for('content.upload_content') }}" class="btn btn-success" style="margin-top: 1rem;">Upload Content</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card">
|
||||
<h2>Quick Actions</h2>
|
||||
<div style="display: flex; gap: 1rem; flex-wrap: wrap; margin-top: 1rem;">
|
||||
<a href="{{ url_for('players.add_player') }}" class="btn btn-success">➕ Add Player</a>
|
||||
<a href="{{ url_for('groups.create_group') }}" class="btn btn-success">➕ Create Group</a>
|
||||
<a href="{{ url_for('content.upload_content') }}" class="btn btn-success">⬆️ Upload Content</a>
|
||||
{% if current_user.is_admin %}
|
||||
<a href="{{ url_for('admin.admin_panel') }}" class="btn">⚙️ Admin Panel</a>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{% if recent_logs %}
|
||||
<div class="card">
|
||||
<h2>Recent Activity</h2>
|
||||
<div style="margin-top: 1rem;">
|
||||
{% for log in recent_logs %}
|
||||
<div style="padding: 0.5rem; border-bottom: 1px solid #eee;">
|
||||
<span style="color: {% if log.level == 'error' %}#e74c3c{% elif log.level == 'warning' %}#f39c12{% else %}#27ae60{% endif %}; font-weight: bold;">
|
||||
[{{ log.level.upper() }}]
|
||||
</span>
|
||||
{{ log.message }}
|
||||
<small style="color: #7f8c8d; float: right;">{{ log.timestamp.strftime('%Y-%m-%d %H:%M:%S') }}</small>
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
<div class="card">
|
||||
<h2>System Status</h2>
|
||||
<p>✅ All systems operational</p>
|
||||
<p>🔄 Blueprint architecture active</p>
|
||||
<p>⚡ Flask {{ config.get('FLASK_VERSION', '3.1.0') }}</p>
|
||||
</div>
|
||||
{% endblock %}
|
||||
11
app/templates/groups_list.html
Normal file
11
app/templates/groups_list.html
Normal file
@@ -0,0 +1,11 @@
|
||||
{% extends "base.html" %}
|
||||
|
||||
{% block title %}Groups - DigiServer v2{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<h1>Groups</h1>
|
||||
<div class="card">
|
||||
<p>Groups list view - Template in progress</p>
|
||||
<a href="{{ url_for('groups.create_group') }}" class="btn btn-success">Create New Group</a>
|
||||
</div>
|
||||
{% endblock %}
|
||||
31
app/templates/login.html
Normal file
31
app/templates/login.html
Normal file
@@ -0,0 +1,31 @@
|
||||
{% extends "base.html" %}
|
||||
|
||||
{% block title %}Login - DigiServer v2{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<div class="card" style="max-width: 400px; margin: 2rem auto;">
|
||||
<h2>Login</h2>
|
||||
<form method="POST" action="{{ url_for('auth.login') }}">
|
||||
<div style="margin-bottom: 1rem;">
|
||||
<label for="username" style="display: block; margin-bottom: 0.5rem;">Username</label>
|
||||
<input type="text" id="username" name="username" required
|
||||
style="width: 100%; padding: 0.5rem; border: 1px solid #ddd; border-radius: 4px;">
|
||||
</div>
|
||||
<div style="margin-bottom: 1rem;">
|
||||
<label for="password" style="display: block; margin-bottom: 0.5rem;">Password</label>
|
||||
<input type="password" id="password" name="password" required
|
||||
style="width: 100%; padding: 0.5rem; border: 1px solid #ddd; border-radius: 4px;">
|
||||
</div>
|
||||
<div style="margin-bottom: 1rem;">
|
||||
<label>
|
||||
<input type="checkbox" name="remember" value="yes">
|
||||
Remember me
|
||||
</label>
|
||||
</div>
|
||||
<button type="submit" class="btn" style="width: 100%;">Login</button>
|
||||
</form>
|
||||
<p style="margin-top: 1rem; text-align: center;">
|
||||
Don't have an account? <a href="{{ url_for('auth.register') }}">Register here</a>
|
||||
</p>
|
||||
</div>
|
||||
{% endblock %}
|
||||
11
app/templates/players_list.html
Normal file
11
app/templates/players_list.html
Normal file
@@ -0,0 +1,11 @@
|
||||
{% extends "base.html" %}
|
||||
|
||||
{% block title %}Players - DigiServer v2{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<h1>Players</h1>
|
||||
<div class="card">
|
||||
<p>Players list view - Template in progress</p>
|
||||
<a href="{{ url_for('players.add_player') }}" class="btn btn-success">Add New Player</a>
|
||||
</div>
|
||||
{% endblock %}
|
||||
27
app/templates/register.html
Normal file
27
app/templates/register.html
Normal file
@@ -0,0 +1,27 @@
|
||||
{% extends "base.html" %}
|
||||
|
||||
{% block title %}Register - DigiServer v2{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<div class="card" style="max-width: 400px; margin: 2rem auto;">
|
||||
<h2>Register</h2>
|
||||
<form method="POST" action="{{ url_for('auth.register') }}">
|
||||
<div style="margin-bottom: 1rem;">
|
||||
<label for="username" style="display: block; margin-bottom: 0.5rem;">Username</label>
|
||||
<input type="text" id="username" name="username" required minlength="3"
|
||||
style="width: 100%; padding: 0.5rem; border: 1px solid #ddd; border-radius: 4px;">
|
||||
<small style="color: #7f8c8d;">Minimum 3 characters</small>
|
||||
</div>
|
||||
<div style="margin-bottom: 1rem;">
|
||||
<label for="password" style="display: block; margin-bottom: 0.5rem;">Password</label>
|
||||
<input type="password" id="password" name="password" required minlength="6"
|
||||
style="width: 100%; padding: 0.5rem; border: 1px solid #ddd; border-radius: 4px;">
|
||||
<small style="color: #7f8c8d;">Minimum 6 characters</small>
|
||||
</div>
|
||||
<button type="submit" class="btn btn-success" style="width: 100%;">Register</button>
|
||||
</form>
|
||||
<p style="margin-top: 1rem; text-align: center;">
|
||||
Already have an account? <a href="{{ url_for('auth.login') }}">Login here</a>
|
||||
</p>
|
||||
</div>
|
||||
{% endblock %}
|
||||
25
app/templates/upload_content.html
Normal file
25
app/templates/upload_content.html
Normal file
@@ -0,0 +1,25 @@
|
||||
{% extends "base.html" %}
|
||||
|
||||
{% block title %}Upload Content - DigiServer v2{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<h1>Upload Content</h1>
|
||||
<div class="card">
|
||||
<form method="POST" enctype="multipart/form-data">
|
||||
<div style="margin-bottom: 1rem;">
|
||||
<label>File</label>
|
||||
<input type="file" name="file" required style="width: 100%; padding: 0.5rem;">
|
||||
</div>
|
||||
<div style="margin-bottom: 1rem;">
|
||||
<label>Duration (seconds, for images)</label>
|
||||
<input type="number" name="duration" value="10" min="1" style="width: 100%; padding: 0.5rem;">
|
||||
</div>
|
||||
<div style="margin-bottom: 1rem;">
|
||||
<label>Description (optional)</label>
|
||||
<textarea name="description" rows="3" style="width: 100%; padding: 0.5rem;"></textarea>
|
||||
</div>
|
||||
<button type="submit" class="btn btn-success">Upload</button>
|
||||
<a href="{{ url_for('content.content_list') }}" class="btn">Cancel</a>
|
||||
</form>
|
||||
</div>
|
||||
{% endblock %}
|
||||
76
run_dev.sh
Executable file
76
run_dev.sh
Executable file
@@ -0,0 +1,76 @@
|
||||
#!/bin/bash
|
||||
|
||||
# DigiServer v2 - Development Test Runner
|
||||
# This script sets up and runs the application in development mode
|
||||
|
||||
set -e
|
||||
|
||||
echo "================================================"
|
||||
echo " DigiServer v2 - Development Environment"
|
||||
echo "================================================"
|
||||
echo ""
|
||||
|
||||
# Check if we're in the right directory
|
||||
if [ ! -f "requirements.txt" ]; then
|
||||
echo "❌ Error: requirements.txt not found. Run this from the digiserver-v2 directory."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Check if virtual environment exists
|
||||
if [ ! -d "venv" ]; then
|
||||
echo "📦 Creating virtual environment..."
|
||||
python3 -m venv venv
|
||||
echo "✅ Virtual environment created"
|
||||
else
|
||||
echo "✅ Virtual environment found"
|
||||
fi
|
||||
|
||||
# Activate virtual environment
|
||||
echo "🔄 Activating virtual environment..."
|
||||
source venv/bin/activate
|
||||
|
||||
# Install/update dependencies
|
||||
echo "📥 Installing dependencies..."
|
||||
pip install -q --upgrade pip
|
||||
pip install -q -r requirements.txt
|
||||
|
||||
echo "✅ Dependencies installed"
|
||||
echo ""
|
||||
|
||||
# Check if .env exists
|
||||
if [ ! -f ".env" ]; then
|
||||
echo "⚠️ Warning: .env file not found, using .env.example"
|
||||
cp .env.example .env
|
||||
fi
|
||||
|
||||
# Initialize database if it doesn't exist
|
||||
if [ ! -f "instance/dashboard.db" ]; then
|
||||
echo "🗄️ Initializing database..."
|
||||
export FLASK_APP=app.app:create_app
|
||||
flask init-db
|
||||
echo "✅ Database initialized"
|
||||
|
||||
echo "👤 Creating default admin user..."
|
||||
flask create-admin
|
||||
echo "✅ Admin user created (username: admin, password: admin123)"
|
||||
else
|
||||
echo "✅ Database found"
|
||||
fi
|
||||
|
||||
echo ""
|
||||
echo "================================================"
|
||||
echo " Starting Flask Development Server"
|
||||
echo "================================================"
|
||||
echo ""
|
||||
echo "🌐 Server will be available at: http://localhost:5000"
|
||||
echo "👤 Default admin: username=admin, password=admin123"
|
||||
echo ""
|
||||
echo "Press Ctrl+C to stop the server"
|
||||
echo ""
|
||||
|
||||
# Set Flask environment
|
||||
export FLASK_APP=app.app:create_app
|
||||
export FLASK_ENV=development
|
||||
|
||||
# Run Flask
|
||||
flask run --host=0.0.0.0 --port=5000
|
||||
Reference in New Issue
Block a user