directlx-dev/app.py

319 lines
13 KiB
Python

import os
from datetime import datetime
from flask import Flask, render_template, request, redirect, url_for, flash, jsonify
from slugify import slugify
from config import config
from models import db, User, BlogPost, ForumCategory, ForumTopic, ForumReply, ContactMessage
def create_app(config_name=None):
if config_name is None:
config_name = os.environ.get('FLASK_CONFIG', 'default')
app = Flask(__name__)
app.config.from_object(config[config_name])
db.init_app(app)
with app.app_context():
db.create_all()
seed_data()
# Context processor for templates
@app.context_processor
def inject_now():
return {'now': datetime.utcnow()}
# ==================== Company Pages ====================
@app.route('/')
def index():
latest_posts = BlogPost.query.filter_by(published=True)\
.order_by(BlogPost.created_at.desc())\
.limit(3).all()
return render_template('index.html', latest_posts=latest_posts)
@app.route('/about')
def about():
return render_template('about.html')
@app.route('/services')
def services():
return render_template('services.html')
@app.route('/contact')
def contact():
return render_template('contact.html')
@app.route('/contact/submit', methods=['POST'])
def contact_submit():
name = request.form.get('name')
email = request.form.get('email')
subject = request.form.get('subject')
message = request.form.get('message')
if not all([name, email, subject, message]):
return '<div class="p-4 bg-red-100 text-red-700 rounded-lg">Please fill in all fields.</div>'
contact_message = ContactMessage(
name=name,
email=email,
subject=subject,
message=message
)
db.session.add(contact_message)
db.session.commit()
return '''<div class="p-4 bg-green-100 text-green-700 rounded-lg">
<strong>Thank you!</strong> Your message has been sent. We'll get back to you soon.
</div>'''
# ==================== Blog ====================
@app.route('/blog')
def blog_index():
page = request.args.get('page', 1, type=int)
posts = BlogPost.query.filter_by(published=True)\
.order_by(BlogPost.created_at.desc())\
.paginate(page=page, per_page=10, error_out=False)
return render_template('blog/index.html', posts=posts.items)
@app.route('/blog/search')
def blog_search():
query = request.args.get('search', '')
if query:
posts = BlogPost.query.filter_by(published=True)\
.filter(BlogPost.title.ilike(f'%{query}%') | BlogPost.content.ilike(f'%{query}%'))\
.order_by(BlogPost.created_at.desc())\
.limit(10).all()
else:
posts = BlogPost.query.filter_by(published=True)\
.order_by(BlogPost.created_at.desc())\
.limit(10).all()
return render_template('blog/partials/post_list.html', posts=posts)
@app.route('/blog/load-more/<int:page>')
def blog_load_more(page):
posts = BlogPost.query.filter_by(published=True)\
.order_by(BlogPost.created_at.desc())\
.paginate(page=page, per_page=10, error_out=False)
return render_template('blog/partials/post_list.html', posts=posts.items)
@app.route('/blog/<slug>')
def blog_post(slug):
post = BlogPost.query.filter_by(slug=slug, published=True).first_or_404()
return render_template('blog/post.html', post=post)
# ==================== Forum ====================
@app.route('/forum')
def forum_index():
categories = ForumCategory.query.order_by(ForumCategory.order).all()
recent_topics = ForumTopic.query\
.order_by(ForumTopic.created_at.desc())\
.limit(5).all()
return render_template('forum/index.html', categories=categories, recent_topics=recent_topics)
@app.route('/forum/search')
def forum_search():
query = request.args.get('q', '')
if query:
topics = ForumTopic.query\
.filter(ForumTopic.title.ilike(f'%{query}%') | ForumTopic.content.ilike(f'%{query}%'))\
.order_by(ForumTopic.created_at.desc())\
.limit(10).all()
if topics:
html = '<div class="card mb-4"><h3 class="text-lg font-semibold mb-4">Search Results</h3><div class="space-y-2">'
for topic in topics:
html += f'''<a href="{url_for('forum_topic', category_slug=topic.category.slug, topic_id=topic.id)}"
class="block p-3 bg-gray-50 rounded-lg hover:bg-gray-100 transition-colors">
<div class="font-medium text-gray-900">{topic.title}</div>
<div class="text-sm text-gray-500">in {topic.category.name}</div>
</a>'''
html += '</div></div>'
return html
else:
return '<div class="card mb-4 text-center text-gray-500 py-4">No topics found matching your search.</div>'
return ''
@app.route('/forum/<slug>')
def forum_category(slug):
category = ForumCategory.query.filter_by(slug=slug).first_or_404()
page = request.args.get('page', 1, type=int)
topics = ForumTopic.query.filter_by(category_id=category.id)\
.order_by(ForumTopic.is_pinned.desc(), ForumTopic.created_at.desc())\
.paginate(page=page, per_page=20, error_out=False)
return render_template('forum/category.html', category=category, topics=topics)
@app.route('/forum/<category_slug>/new', methods=['POST'])
def forum_create_topic(category_slug):
category = ForumCategory.query.filter_by(slug=category_slug).first_or_404()
title = request.form.get('title')
content = request.form.get('content')
if not title or not content:
return '<div class="p-4 bg-red-100 text-red-700 rounded-lg mb-4">Please fill in all fields.</div>'
# Get or create a default user for demo purposes
user = User.query.first()
if not user:
user = User(username='Guest', email='guest@example.com')
user.set_password('guest')
db.session.add(user)
db.session.commit()
topic = ForumTopic(
title=title,
content=content,
category_id=category.id,
author_id=user.id
)
db.session.add(topic)
db.session.commit()
# Return updated topic list
topics = ForumTopic.query.filter_by(category_id=category.id)\
.order_by(ForumTopic.is_pinned.desc(), ForumTopic.created_at.desc())\
.paginate(page=1, per_page=20, error_out=False)
return render_template('forum/partials/topic_list.html', category=category, topics=topics)
@app.route('/forum/<category_slug>/<int:topic_id>')
def forum_topic(category_slug, topic_id):
topic = ForumTopic.query.get_or_404(topic_id)
replies = topic.replies.order_by(ForumReply.created_at.asc()).all()
return render_template('forum/topic.html', topic=topic, replies=replies)
@app.route('/forum/<category_slug>/<int:topic_id>/reply', methods=['POST'])
def forum_add_reply(category_slug, topic_id):
topic = ForumTopic.query.get_or_404(topic_id)
if topic.is_locked:
return '<div class="p-4 bg-red-100 text-red-700 rounded-lg">This topic is locked.</div>'
content = request.form.get('content')
if not content:
return '<div class="p-4 bg-red-100 text-red-700 rounded-lg">Please enter a reply.</div>'
# Get or create a default user for demo purposes
user = User.query.first()
if not user:
user = User(username='Guest', email='guest@example.com')
user.set_password('guest')
db.session.add(user)
db.session.commit()
reply = ForumReply(
content=content,
topic_id=topic.id,
author_id=user.id
)
db.session.add(reply)
db.session.commit()
# Return the new reply as HTML
return f'''<div class="card mb-4">
<div class="flex items-start">
<div class="w-10 h-10 bg-gray-100 rounded-full flex items-center justify-center text-gray-600 font-semibold flex-shrink-0">
{reply.author.username[0].upper()}
</div>
<div class="ml-4 flex-grow">
<div class="flex items-center justify-between mb-2">
<div class="font-medium text-gray-900">{reply.author.username}</div>
<div class="text-sm text-gray-500">{reply.created_at.strftime('%B %d, %Y at %H:%M')}</div>
</div>
<div class="prose prose-sm max-w-none text-gray-600">
{reply.content}
</div>
</div>
</div>
</div>'''
return app
def seed_data():
"""Seed the database with sample data if empty."""
if User.query.first() is None:
# Create admin user
admin = User(username='admin', email='admin@directlx.dev', is_admin=True)
admin.set_password('admin123')
db.session.add(admin)
# Create sample blog posts
posts = [
{
'title': 'Getting Started with Flask and HTMX',
'slug': 'getting-started-flask-htmx',
'excerpt': 'Learn how to build modern, interactive web applications using Flask and HTMX.',
'content': '''<p>Flask and HTMX make a powerful combination for building interactive web applications without the complexity of a JavaScript framework.</p>
<h2>Why HTMX?</h2>
<p>HTMX allows you to access modern browser features directly from HTML, making it easy to build dynamic user interfaces with minimal JavaScript.</p>
<h2>Getting Started</h2>
<p>First, create a new Flask project and install the required dependencies. Then, add HTMX to your templates and start building interactive features.</p>''',
'published': True
},
{
'title': 'Building Scalable APIs with Python',
'slug': 'building-scalable-apis-python',
'excerpt': 'Best practices for designing and building scalable REST APIs using Python.',
'content': '''<p>Building scalable APIs requires careful planning and adherence to best practices.</p>
<h2>Design Principles</h2>
<p>Follow REST principles, use proper HTTP methods, and design your endpoints to be intuitive and consistent.</p>
<h2>Performance Considerations</h2>
<p>Implement caching, pagination, and rate limiting to ensure your API can handle high traffic.</p>''',
'published': True
},
{
'title': 'The Future of Web Development',
'slug': 'future-web-development',
'excerpt': 'Exploring emerging trends and technologies shaping the future of web development.',
'content': '''<p>The web development landscape is constantly evolving. Let's explore what's next.</p>
<h2>Emerging Trends</h2>
<p>From WebAssembly to edge computing, new technologies are changing how we build web applications.</p>
<h2>What This Means for Developers</h2>
<p>Staying current with these trends will help you build better applications and advance your career.</p>''',
'published': True
}
]
for post_data in posts:
post = BlogPost(author_id=1, **post_data)
db.session.add(post)
# Create forum categories
categories = [
{'name': 'General Discussion', 'slug': 'general', 'description': 'General topics and discussions about software development.', 'order': 1},
{'name': 'Help & Support', 'slug': 'help', 'description': 'Get help with technical problems and questions.', 'order': 2},
{'name': 'Showcase', 'slug': 'showcase', 'description': 'Share your projects and get feedback from the community.', 'order': 3},
{'name': 'Off Topic', 'slug': 'off-topic', 'description': 'Everything else that doesn\'t fit elsewhere.', 'order': 4}
]
for cat_data in categories:
category = ForumCategory(**cat_data)
db.session.add(category)
db.session.commit()
# Create sample forum topics
general = ForumCategory.query.filter_by(slug='general').first()
if general:
topic = ForumTopic(
title='Welcome to the DirectLX Community!',
content='Welcome everyone! This is a place to discuss software development, share knowledge, and connect with other developers. Feel free to introduce yourself!',
category_id=general.id,
author_id=1,
is_pinned=True
)
db.session.add(topic)
db.session.commit()
# Create the application instance
app = create_app()
if __name__ == '__main__':
app.run(debug=True, port=5000)