first commit

This commit is contained in:
Wensheng 2024-10-09 17:35:57 +08:00
commit e7b76acac9
14 changed files with 300 additions and 0 deletions

16
.gitignore vendored Normal file

@ -0,0 +1,16 @@
venv/
.venv/
env/
__pycache__/
*.pyc
*.db
*.sqlite
*.log
.env
.vscode/
.idea/
.DS_Store
Thumbs.db
config.py
secrets.json
personal_notes.txt

13
app.py Normal file

@ -0,0 +1,13 @@
from app import create_app, db
from app.utils import check_db_connection
app = create_app()
if __name__ == '__main__':
with app.app_context():
if check_db_connection():
db.create_all()
print("數據庫連接成功,並創建了所有表。")
else:
print("警告:無法連接到數據庫。請檢查你的數據庫設置。")
app.run(debug=True)

20
app/__init__.py Normal file

@ -0,0 +1,20 @@
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
from flask_login import LoginManager
from config import Config
db = SQLAlchemy()
login_manager = LoginManager()
login_manager.login_view = 'main.login'
def create_app():
app = Flask(__name__)
app.config.from_object(Config)
db.init_app(app)
login_manager.init_app(app)
from app.routes import bp as main_bp
app.register_blueprint(main_bp)
return app

18
app/models.py Normal file

@ -0,0 +1,18 @@
from app import db, login_manager
from flask_login import UserMixin
from werkzeug.security import generate_password_hash, check_password_hash
class User(UserMixin, db.Model):
id = db.Column(db.Integer, primary_key=True)
username = db.Column(db.String(80), unique=True, nullable=False)
password = db.Column(db.String(120), nullable=False)
def set_password(self, password):
self.password = generate_password_hash(password)
def check_password(self, password):
return check_password_hash(self.password, password)
@login_manager.user_loader
def load_user(user_id):
return User.query.get(int(user_id))

70
app/routes.py Normal file

@ -0,0 +1,70 @@
from flask import Blueprint, render_template, request, redirect, url_for, flash
from flask_login import login_user, login_required, logout_user, current_user
from app import db
from app.models import User
from app.utils import check_db_connection
bp = Blueprint('main', __name__)
@bp.route('/')
def index():
return render_template('index.html')
@bp.route('/about')
def about():
return render_template('about.html')
@bp.route('/contact')
def contact():
return render_template('contact.html')
@bp.route('/login', methods=['GET', 'POST'])
def login():
if not check_db_connection():
flash('無法連接到數據庫,請稍後再試。', 'danger')
return render_template('login.html')
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('登入成功!', 'success')
return redirect(url_for('main.index'))
else:
flash('登入失敗。請檢查您的用戶名和密碼。', 'danger')
return render_template('login.html')
@bp.route('/logout')
@login_required
def logout():
logout_user()
flash('您已成功登出。', 'success')
return redirect(url_for('main.index'))
@bp.route('/register', methods=['GET', 'POST'])
def register():
if not check_db_connection():
flash('無法連接到數據庫,請稍後再試。', 'danger')
return render_template('register.html')
if request.method == 'POST':
username = request.form.get('username')
password = request.form.get('password')
existing_user = User.query.filter_by(username=username).first()
if existing_user:
flash('該用戶名已被使用。', 'danger')
else:
new_user = User(username=username)
new_user.set_password(password)
db.session.add(new_user)
db.session.commit()
flash('註冊成功!請登入。', 'success')
return redirect(url_for('main.login'))
return render_template('register.html')

9
app/static/css/style.css Normal file

@ -0,0 +1,9 @@
body {
min-height: 100vh;
display: flex;
flex-direction: column;
}
main {
flex: 1;
}

BIN
app/static/images/logo.png Normal file

Binary file not shown.

After

(image error) Size: 62 KiB

8
app/templates/about.html Normal file

@ -0,0 +1,8 @@
{% extends "base.html" %}
{% block title %}關於我們{% endblock %}
{% block content %}
<h1>關於我們</h1>
<p>這是一個關於我們的介紹頁面。</p>
{% endblock %}

75
app/templates/base.html Normal file

@ -0,0 +1,75 @@
<!DOCTYPE html>
<html lang="zh">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>{% block title %}我的網站{% endblock %}</title>
<!-- Bootstrap CSS -->
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css" rel="stylesheet">
<!-- 自定義 CSS -->
<link rel="stylesheet" href="{{ url_for('static', filename='css/style.css') }}">
{% block extra_css %}{% endblock %}
</head>
<body>
<nav class="navbar navbar-expand-lg navbar-light bg-light">
<div class="container">
<a class="navbar-brand" href="{{ url_for('main.index') }}">
<img src="{{ url_for('static', filename='images/logo.png') }}" alt="Logo" width="30" height="30" class="d-inline-block align-top">
</a>
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarNav" aria-controls="navbarNav" aria-expanded="false" aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span>
</button>
<div class="collapse navbar-collapse" id="navbarNav">
<ul class="navbar-nav ms-auto">
<li class="nav-item">
<a class="nav-link" href="{{ url_for('main.index') }}">首頁</a>
</li>
<li class="nav-item">
<a class="nav-link" href="{{ url_for('main.about') }}">關於我們</a>
</li>
<li class="nav-item">
<a class="nav-link" href="{{ url_for('main.contact') }}">聯絡我們</a>
</li>
{% if current_user.is_authenticated %}
<li class="nav-item">
<a class="nav-link" href="{{ url_for('main.logout') }}">登出</a>
</li>
{% else %}
<li class="nav-item">
<a class="nav-link" href="{{ url_for('main.login') }}">登入</a>
</li>
<li class="nav-item">
<a class="nav-link" href="{{ url_for('main.register') }}">註冊</a>
</li>
{% endif %}
</ul>
</div>
</div>
</nav>
<main class="container mt-4">
{% with messages = get_flashed_messages(with_categories=true) %}
{% if messages %}
{% for category, message in messages %}
<div class="alert alert-{{ category }} alert-dismissible fade show" role="alert">
{{ message }}
<button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button>
</div>
{% endfor %}
{% endif %}
{% endwith %}
{% block content %}{% endblock %}
</main>
<footer class="footer mt-auto py-3 bg-light">
<div class="container text-center">
<span class="text-muted">&copy; 2024 我的網站. All rights reserved.</span>
</div>
</footer>
<!-- Bootstrap Bundle with Popper -->
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/js/bootstrap.bundle.min.js"></script>
{% block extra_js %}{% endblock %}
</body>
</html>

@ -0,0 +1,8 @@
{% extends "base.html" %}
{% block title %}聯絡我們{% endblock %}
{% block content %}
<h1>聯絡我們</h1>
<p>這裡是聯絡我們的資訊頁面。</p>
{% endblock %}

8
app/templates/index.html Normal file

@ -0,0 +1,8 @@
{% extends "base.html" %}
{% block title %}首頁{% endblock %}
{% block content %}
<h1>歡迎來到首頁</h1>
<p>這是我的網站首頁。</p>
{% endblock %}

23
app/templates/login.html Normal file

@ -0,0 +1,23 @@
{% extends "base.html" %}
{% block title %}登入 - 我的網站{% endblock %}
{% block content %}
<div class="row justify-content-center">
<div class="col-md-6">
<h2 class="mb-4">登入</h2>
<form method="POST">
<div class="mb-3">
<label for="username" class="form-label">用戶名</label>
<input type="text" class="form-control" id="username" name="username" required>
</div>
<div class="mb-3">
<label for="password" class="form-label">密碼</label>
<input type="password" class="form-control" id="password" name="password" required>
</div>
<button type="submit" class="btn btn-primary">登入</button>
</form>
<p class="mt-3">還沒有帳號?<a href="{{ url_for('main.register') }}">註冊</a></p>
</div>
</div>
{% endblock %}

@ -0,0 +1,23 @@
{% extends "base.html" %}
{% block title %}註冊 - 我的網站{% endblock %}
{% block content %}
<div class="row justify-content-center">
<div class="col-md-6">
<h2 class="mb-4">註冊</h2>
<form method="POST">
<div class="mb-3">
<label for="username" class="form-label">用戶名</label>
<input type="text" class="form-control" id="username" name="username" required>
</div>
<div class="mb-3">
<label for="password" class="form-label">密碼</label>
<input type="password" class="form-control" id="password" name="password" required>
</div>
<button type="submit" class="btn btn-primary">註冊</button>
</form>
<p class="mt-3">已有帳號?<a href="{{ url_for('main.login') }}">登入</a></p>
</div>
</div>
{% endblock %}

9
app/utils.py Normal file

@ -0,0 +1,9 @@
from app import db
from sqlalchemy.exc import SQLAlchemyError
def check_db_connection():
try:
db.session.query("1").from_statement("SELECT 1").all()
return True
except SQLAlchemyError:
return False