Spaces:
Running
Running
| from flask import Flask, jsonify, render_template, request, redirect, url_for | |
| from flask_sqlalchemy import SQLAlchemy | |
| import os | |
| from werkzeug.utils import secure_filename | |
| app = Flask(__name__) | |
| app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///coursels.db' | |
| app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False | |
| UPLOAD_FOLDER = 'static/uploads' | |
| app.config['UPLOAD_FOLDER'] = UPLOAD_FOLDER | |
| if not os.path.exists(UPLOAD_FOLDER): | |
| os.makedirs(UPLOAD_FOLDER) | |
| db = SQLAlchemy(app) | |
| class Subject(db.Model): | |
| id = db.Column(db.Integer, primary_key=True) | |
| name = db.Column(db.String(100), nullable=False) | |
| icon_data = db.Column(db.LargeBinary, nullable=True) # Image data stored in DB | |
| icon_filename = db.Column(db.String(200), nullable=True) # Original filename | |
| icon_mimetype = db.Column(db.String(100), nullable=True) # MIME type | |
| categories = db.relationship('Category', backref='subject', lazy=True) | |
| class Category(db.Model): | |
| id = db.Column(db.Integer, primary_key=True) | |
| name = db.Column(db.String(100), nullable=False) | |
| subject_id = db.Column(db.Integer, db.ForeignKey('subject.id'), nullable=False) | |
| articles = db.relationship('Article', backref='category', lazy=True) | |
| class Article(db.Model): | |
| id = db.Column(db.Integer, primary_key=True) | |
| title = db.Column(db.String(200), nullable=False) | |
| content = db.Column(db.Text, nullable=False) | |
| category_id = db.Column(db.Integer, db.ForeignKey('category.id'), nullable=False) | |
| icon_data = db.Column(db.LargeBinary, nullable=True) # Image data stored in DB | |
| icon_filename = db.Column(db.String(200), nullable=True) # Original filename | |
| icon_mimetype = db.Column(db.String(100), nullable=True) # MIME type | |
| class Attachment(db.Model): | |
| id = db.Column(db.Integer, primary_key=True) | |
| data = db.Column(db.LargeBinary, nullable=False) | |
| filename = db.Column(db.String(200), nullable=False) | |
| mimetype = db.Column(db.String(100), nullable=False) | |
| def home(): | |
| subjects = Subject.query.all() | |
| # Add icon_url to each subject for template use | |
| for subject in subjects: | |
| if subject.icon_data: | |
| subject.icon_url = url_for('get_subject_icon', subject_id=subject.id) | |
| else: | |
| subject.icon_url = None | |
| return render_template('home.html', subjects=subjects) | |
| def categories(subject_id): | |
| subject = Subject.query.get_or_404(subject_id) | |
| categories = Category.query.filter_by(subject_id=subject_id).all() | |
| return render_template('categories.html', subject=subject, categories=categories) | |
| def articles(category_id): | |
| category = Category.query.get_or_404(category_id) | |
| articles = Article.query.filter_by(category_id=category_id).all() | |
| return render_template('articles.html', category=category, articles=articles) | |
| def article(article_id): | |
| article = Article.query.get_or_404(article_id) | |
| return render_template('article.html', article=article) | |
| # API endpoints for JSON if needed | |
| def api_subjects(): | |
| subjects = Subject.query.all() | |
| subject_list = [] | |
| for s in subjects: | |
| icon_url = url_for('get_subject_icon', subject_id=s.id) if s.icon_data else None | |
| subject_list.append({'id': s.id, 'name': s.name, 'icon': icon_url}) | |
| return jsonify(subject_list) | |
| def api_categories(subject_id): | |
| categories = Category.query.filter_by(subject_id=subject_id).all() | |
| return jsonify([{'id': c.id, 'name': c.name} for c in categories]) | |
| def api_articles(category_id): | |
| articles = Article.query.filter_by(category_id=category_id).all() | |
| return jsonify([{'id': a.id, 'title': a.title} for a in articles]) | |
| def api_article(article_id): | |
| article = Article.query.get_or_404(article_id) | |
| return jsonify({'id': article.id, 'title': article.title, 'content': article.content}) | |
| # Admin routes | |
| def admin_home(): | |
| return render_template('admin_home.html') | |
| def admin_articles(): | |
| articles = Article.query.all() | |
| return render_template('admin_articles.html', articles=articles) | |
| def admin_edit_article(article_id): | |
| article = Article.query.get_or_404(article_id) | |
| if request.method == 'POST': | |
| article.title = request.form['title'] | |
| article.content = request.form['content'] | |
| # Handle file upload if provided | |
| if 'icon' in request.files and request.files['icon'].filename: | |
| file = request.files['icon'] | |
| file_data = file.read() | |
| filename = secure_filename(file.filename) | |
| article.icon_data = file_data | |
| article.icon_filename = filename | |
| article.icon_mimetype = file.mimetype | |
| db.session.commit() | |
| return redirect(url_for('admin_articles')) | |
| return render_template('admin_edit_article.html', article=article) | |
| def admin_new_article(): | |
| if request.method == 'POST': | |
| title = request.form['title'] | |
| content = request.form['content'] | |
| category_id = request.form['category_id'] | |
| new_article = Article(title=title, content=content, category_id=category_id) | |
| db.session.add(new_article) | |
| db.session.commit() | |
| # Handle file upload if provided | |
| if 'icon' in request.files and request.files['icon'].filename: | |
| file = request.files['icon'] | |
| file_data = file.read() | |
| filename = secure_filename(file.filename) | |
| new_article.icon_data = file_data | |
| new_article.icon_filename = filename | |
| new_article.icon_mimetype = file.mimetype | |
| db.session.commit() | |
| return redirect(url_for('admin_articles')) | |
| categories = Category.query.all() | |
| return render_template('admin_new_article.html', categories=categories) | |
| def admin_delete_article(article_id): | |
| article = Article.query.get_or_404(article_id) | |
| db.session.delete(article) | |
| db.session.commit() | |
| return redirect(url_for('admin_articles')) | |
| def admin_subjects(): | |
| subjects = Subject.query.all() | |
| return render_template('admin_subjects.html', subjects=subjects) | |
| def admin_new_subject(): | |
| if request.method == 'POST': | |
| name = request.form['name'] | |
| new_subject = Subject(name=name) | |
| db.session.add(new_subject) | |
| db.session.commit() | |
| # Handle file upload if provided | |
| if 'icon' in request.files and request.files['icon'].filename: | |
| file = request.files['icon'] | |
| file_data = file.read() | |
| filename = secure_filename(file.filename) | |
| new_subject.icon_data = file_data | |
| new_subject.icon_filename = filename | |
| new_subject.icon_mimetype = file.mimetype | |
| db.session.commit() | |
| return redirect(url_for('admin_subjects')) | |
| return render_template('admin_new_subject.html') | |
| def admin_edit_subject(subject_id): | |
| subject = Subject.query.get_or_404(subject_id) | |
| if request.method == 'POST': | |
| subject.name = request.form['name'] | |
| # Handle file upload if provided | |
| if 'icon' in request.files and request.files['icon'].filename: | |
| file = request.files['icon'] | |
| file_data = file.read() | |
| filename = secure_filename(file.filename) | |
| subject.icon_data = file_data | |
| subject.icon_filename = filename | |
| subject.icon_mimetype = file.mimetype | |
| db.session.commit() | |
| return redirect(url_for('admin_subjects')) | |
| return render_template('admin_edit_subject.html', subject=subject) | |
| def admin_delete_subject(subject_id): | |
| subject = Subject.query.get_or_404(subject_id) | |
| db.session.delete(subject) | |
| db.session.commit() | |
| return redirect(url_for('admin_subjects')) | |
| def admin_categories(): | |
| categories = Category.query.all() | |
| return render_template('admin_categories.html', categories=categories) | |
| def admin_new_category(): | |
| if request.method == 'POST': | |
| name = request.form['name'] | |
| subject_id = request.form['subject_id'] | |
| new_category = Category(name=name, subject_id=subject_id) | |
| db.session.add(new_category) | |
| db.session.commit() | |
| return redirect(url_for('admin_categories')) | |
| subjects = Subject.query.all() | |
| return render_template('admin_new_category.html', subjects=subjects) | |
| def admin_edit_category(category_id): | |
| category = Category.query.get_or_404(category_id) | |
| if request.method == 'POST': | |
| category.name = request.form['name'] | |
| category.subject_id = request.form['subject_id'] | |
| db.session.commit() | |
| return redirect(url_for('admin_categories')) | |
| subjects = Subject.query.all() | |
| return render_template('admin_edit_category.html', category=category, subjects=subjects) | |
| def admin_delete_category(category_id): | |
| category = Category.query.get_or_404(category_id) | |
| db.session.delete(category) | |
| db.session.commit() | |
| return redirect(url_for('admin_categories')) | |
| def add_sample_data(): | |
| if Subject.query.count() == 0: | |
| math = Subject(name="Mathématiques") | |
| physics = Subject(name="Physique") | |
| db.session.add(math) | |
| db.session.add(physics) | |
| db.session.commit() | |
| algebra = Category(name="Algèbre", subject=math) | |
| geometry = Category(name="Géométrie", subject=math) | |
| mechanics = Category(name="Mécanique", subject=physics) | |
| db.session.add(algebra) | |
| db.session.add(geometry) | |
| db.session.add(mechanics) | |
| db.session.commit() | |
| Article(title="Équations linéaires", content="<p>Les équations linéaires sont de la forme ax + b = 0.</p>", category=algebra) | |
| Article(title="Triangles", content="<p>Un triangle a trois côtés.</p>", category=geometry) | |
| Article(title="Lois de Newton", content="<p>La première loi de Newton...</p>", category=mechanics) | |
| db.session.commit() | |
| def upload_subject_icon(subject_id): | |
| subject = Subject.query.get_or_404(subject_id) | |
| if 'file' not in request.files: | |
| return jsonify({'error': 'No file'}), 400 | |
| file = request.files['file'] | |
| if file.filename == '': | |
| return jsonify({'error': 'No selected file'}), 400 | |
| # Read file data | |
| file_data = file.read() | |
| filename = secure_filename(file.filename) | |
| # Store in database | |
| subject.icon_data = file_data | |
| subject.icon_filename = filename | |
| subject.icon_mimetype = file.mimetype | |
| db.session.commit() | |
| return jsonify({'success': True, 'filename': filename}) | |
| def upload_article_image(article_id): | |
| article = Article.query.get_or_404(article_id) | |
| if 'file' not in request.files: | |
| return jsonify({'error': 'No file'}), 400 | |
| file = request.files['file'] | |
| if file.filename == '': | |
| return jsonify({'error': 'No selected file'}), 400 | |
| # Read file data | |
| file_data = file.read() | |
| filename = secure_filename(file.filename) | |
| # Store in database | |
| article.icon_data = file_data | |
| article.icon_filename = filename | |
| article.icon_mimetype = file.mimetype | |
| db.session.commit() | |
| return jsonify({'success': True, 'filename': filename}) | |
| def upload_attachment(): | |
| if 'file' not in request.files: | |
| return jsonify({'error': 'No file'}), 400 | |
| file = request.files['file'] | |
| if file.filename == '': | |
| return jsonify({'error': 'No selected file'}), 400 | |
| # Read file data | |
| file_data = file.read() | |
| filename = secure_filename(file.filename) | |
| # Store in database | |
| attachment = Attachment(data=file_data, filename=filename, mimetype=file.mimetype) | |
| db.session.add(attachment) | |
| db.session.commit() | |
| url = url_for('get_attachment', attachment_id=attachment.id) | |
| return jsonify({'url': url}) | |
| def get_subject_icon(subject_id): | |
| subject = Subject.query.get_or_404(subject_id) | |
| if subject.icon_data: | |
| return subject.icon_data, 200, {'Content-Type': subject.icon_mimetype or 'image/png'} | |
| else: | |
| return '', 404 | |
| def get_article_image(article_id): | |
| article = Article.query.get_or_404(article_id) | |
| if article.icon_data: | |
| return article.icon_data, 200, {'Content-Type': article.icon_mimetype or 'image/png'} | |
| else: | |
| return '', 404 | |
| def get_attachment(attachment_id): | |
| attachment = Attachment.query.get_or_404(attachment_id) | |
| return attachment.data, 200, {'Content-Type': attachment.mimetype} | |
| if __name__ == '__main__': | |
| with app.app_context(): | |
| db.create_all() | |
| add_sample_data() | |
| app.run(debug=True) |