| |
| import os |
| from flask import Flask, render_template, request, redirect, url_for, flash, jsonify, send_file |
| from flask_sqlalchemy import SQLAlchemy |
| from flask_login import LoginManager, UserMixin, login_user, login_required, logout_user, current_user |
| from werkzeug.security import generate_password_hash, check_password_hash |
| from werkzeug.utils import secure_filename |
| from datetime import datetime |
|
|
| app = Flask(__name__) |
| app.config['SECRET_KEY'] = 'angkatan-rahasia-2024-2026' |
| app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///gallery.db' |
| app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False |
| app.config['UPLOAD_FOLDER'] = 'static/uploads' |
| app.config['MAX_CONTENT_LENGTH'] = 50 * 1024 * 1024 |
|
|
| |
| os.makedirs(app.config['UPLOAD_FOLDER'], exist_ok=True) |
|
|
| |
| db = SQLAlchemy(app) |
|
|
| |
| login_manager = LoginManager() |
| login_manager.init_app(app) |
| login_manager.login_view = 'login' |
|
|
| |
| class User(UserMixin, db.Model): |
| __tablename__ = 'users' |
| id = db.Column(db.Integer, primary_key=True) |
| username = db.Column(db.String(80), unique=True, nullable=False) |
| password_hash = db.Column(db.String(200), nullable=False) |
| is_admin = db.Column(db.Boolean, default=False) |
| created_at = db.Column(db.DateTime, default=datetime.utcnow) |
| |
| def set_password(self, password): |
| self.password_hash = generate_password_hash(password) |
| |
| def check_password(self, password): |
| return check_password_hash(self.password_hash, password) |
|
|
| class Photo(db.Model): |
| __tablename__ = 'photos' |
| id = db.Column(db.Integer, primary_key=True) |
| filename = db.Column(db.String(200), nullable=False) |
| caption = db.Column(db.String(500)) |
| upload_date = db.Column(db.DateTime, default=datetime.utcnow) |
| uploader_id = db.Column(db.Integer, db.ForeignKey('users.id'), nullable=False) |
| likes_count = db.Column(db.Integer, default=0) |
| |
| uploader = db.relationship('User', backref='photos') |
| likes = db.relationship('Like', backref='photo', cascade='all, delete-orphan') |
|
|
| class Like(db.Model): |
| __tablename__ = 'likes' |
| id = db.Column(db.Integer, primary_key=True) |
| user_id = db.Column(db.Integer, db.ForeignKey('users.id'), nullable=False) |
| photo_id = db.Column(db.Integer, db.ForeignKey('photos.id'), nullable=False) |
| created_at = db.Column(db.DateTime, default=datetime.utcnow) |
| |
| __table_args__ = (db.UniqueConstraint('user_id', 'photo_id'),) |
|
|
| @login_manager.user_loader |
| def load_user(user_id): |
| return User.query.get(int(user_id)) |
|
|
| |
| with app.app_context(): |
| db.create_all() |
| print("✅ Database siap!") |
| |
| admins = [ |
| {'username': 'Hilbraaaam', 'password': 'Ketua Angkatan 24-26'}, |
| {'username': 'Hudzaifahh', 'password': 'Wakil ketua Angkatan 24-26'}, |
| {'username': 'Rafasyahh', 'password': 'Humas Kesayangan'}, |
| {'username': 'Elazzam', 'password': 'Eos 800 D'}, |
| {'username': 'Azzam Diq', 'password': 'Shidiq'}, |
| {'username': 'Dzikrii', 'password': 'Bayar woe'}, |
| {'username': 'Ibrahim', 'password': 'Mboh'}, |
| {'username': 'Yusupp', 'password': 'Bangun'}, |
| {'username': 'Azzam JR', 'password': 'Saturn'}, |
| {'username': 'MK Azzam', 'password': 'Aneka Gold'}, |
| {'username': 'Sami abd', 'password': 'TamTam'} |
| ] |
| |
| for admin_data in admins: |
| existing = User.query.filter_by(username=admin_data['username']).first() |
| if not existing: |
| admin = User(username=admin_data['username'], is_admin=True) |
| admin.set_password(admin_data['password']) |
| db.session.add(admin) |
| print(f"✓ Admin: {admin_data['username']}") |
| |
| db.session.commit() |
| print(f"✅ Total admin: {User.query.filter_by(is_admin=True).count()}") |
|
|
| |
| @app.route('/') |
| def index(): |
| photos = Photo.query.order_by(Photo.upload_date.desc()).all() |
| trending = Photo.query.order_by(Photo.likes_count.desc()).limit(3).all() |
| return render_template('index.html', photos=photos, trending=trending) |
|
|
| @app.route('/login', methods=['GET', 'POST']) |
| def login(): |
| |
| if current_user.is_authenticated: |
| return redirect(url_for('index')) |
| |
| if request.method == 'POST': |
| username = request.form.get('username') |
| password = request.form.get('password') |
| |
| user = User.query.filter_by(username=username).first() |
| |
| if user and user.check_password(password): |
| login_user(user) |
| flash('Login berhasil!', 'success') |
| |
| |
| if user.is_admin: |
| return redirect(url_for('admin')) |
| return redirect(url_for('index')) |
| else: |
| flash('Username atau password salah!', 'error') |
| |
| return render_template('login.html') |
|
|
| @app.route('/logout') |
| def logout(): |
| logout_user() |
| flash('Anda telah logout', 'info') |
| return redirect(url_for('index')) |
|
|
| @app.route('/admin') |
| def admin(): |
| |
| if not current_user.is_authenticated: |
| flash('Silakan login dulu!', 'warning') |
| return redirect(url_for('login')) |
| |
| if not current_user.is_admin: |
| flash('Halaman khusus admin!', 'error') |
| return redirect(url_for('index')) |
| |
| photos = Photo.query.order_by(Photo.upload_date.desc()).all() |
| return render_template('admin.html', photos=photos) |
|
|
| @app.route('/upload', methods=['POST']) |
| def upload(): |
| |
| if not current_user.is_authenticated or not current_user.is_admin: |
| flash('Akses ditolak!', 'error') |
| return redirect(url_for('index')) |
| |
| if 'photo' not in request.files: |
| flash('Pilih file dulu!', 'error') |
| return redirect(url_for('admin')) |
| |
| file = request.files['photo'] |
| caption = request.form.get('caption', '') |
| |
| if file.filename == '': |
| flash('Pilih file dulu!', 'error') |
| return redirect(url_for('admin')) |
| |
| |
| filename = secure_filename(file.filename) |
| timestamp = datetime.now().strftime('%Y%m%d_%H%M%S_') |
| filename = timestamp + filename |
| file.save(os.path.join(app.config['UPLOAD_FOLDER'], filename)) |
| |
| |
| photo = Photo(filename=filename, caption=caption, uploader_id=current_user.id) |
| db.session.add(photo) |
| db.session.commit() |
| |
| flash('Foto berhasil diupload!', 'success') |
| return redirect(url_for('admin')) |
|
|
| @app.route('/delete/<int:photo_id>') |
| def delete(photo_id): |
| |
| if not current_user.is_authenticated or not current_user.is_admin: |
| flash('Akses ditolak!', 'error') |
| return redirect(url_for('index')) |
| |
| photo = Photo.query.get(photo_id) |
| if photo: |
| |
| filepath = os.path.join(app.config['UPLOAD_FOLDER'], photo.filename) |
| if os.path.exists(filepath): |
| os.remove(filepath) |
| |
| db.session.delete(photo) |
| db.session.commit() |
| flash('Foto dihapus!', 'success') |
| |
| return redirect(url_for('admin')) |
|
|
| @app.route('/like/<int:photo_id>', methods=['POST']) |
| def like(photo_id): |
| if not current_user.is_authenticated: |
| return jsonify({'error': 'Login dulu'}), 401 |
| |
| photo = Photo.query.get(photo_id) |
| if not photo: |
| return jsonify({'error': 'Foto tidak ada'}), 404 |
| |
| like = Like.query.filter_by(user_id=current_user.id, photo_id=photo_id).first() |
| |
| if like: |
| db.session.delete(like) |
| photo.likes_count -= 1 |
| liked = False |
| else: |
| like = Like(user_id=current_user.id, photo_id=photo_id) |
| db.session.add(like) |
| photo.likes_count += 1 |
| liked = True |
| |
| db.session.commit() |
| return jsonify({'liked': liked, 'likes': photo.likes_count}) |
|
|
| @app.route('/download/<int:photo_id>') |
| def download(photo_id): |
| photo = Photo.query.get(photo_id) |
| if photo: |
| filepath = os.path.join(app.config['UPLOAD_FOLDER'], photo.filename) |
| if os.path.exists(filepath): |
| return send_file(filepath, as_attachment=True, download_name=photo.filename) |
| |
| flash('File tidak ada!', 'error') |
| return redirect(url_for('index')) |
|
|
| @app.route('/slideshow') |
| def slideshow(): |
| photos = Photo.query.order_by(Photo.upload_date.desc()).limit(10).all() |
| return jsonify([{'filename': p.filename} for p in photos]) |
|
|
| @app.route('/cek_admin') |
| def cek_admin(): |
| admins = User.query.filter_by(is_admin=True).all() |
| return jsonify({ |
| 'total': len(admins), |
| 'usernames': [a.username for a in admins] |
| }) |
|
|
| if __name__ == '__main__': |
| port = int(os.environ.get('PORT', 7860)) |
| app.run(host='0.0.0.0', port=port, debug=False) |