firrst commit

This commit is contained in:
2025-01-04 19:57:22 +08:00
parent 638bd6536e
commit 71b54bae94
10 changed files with 343 additions and 0 deletions
+19
View File
@@ -0,0 +1,19 @@
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
from flask_bcrypt import Bcrypt
from flask_login import LoginManager
app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///site.db'
app.config['SECRET_KEY'] = 'supersecretkey'
db = SQLAlchemy(app)
bcrypt = Bcrypt(app)
login_manager = LoginManager(app)
login_manager.login_view = 'login'
from routes import *
from models import *
if __name__ == '__main__':
app.run(debug=True)
+36
View File
@@ -0,0 +1,36 @@
from app import db
from flask_login import UserMixin
class User(db.Model, UserMixin):
id = db.Column(db.Integer, primary_key=True)
email = db.Column(db.String(150), unique=True, nullable=False)
password = db.Column(db.String(60), nullable=False)
phone = db.Column(db.String(20), nullable=False)
is_host = db.Column(db.Boolean, default=False)
class Listing(db.Model):
id = db.Column(db.Integer, primary_key=True)
title = db.Column(db.String(150), nullable=False)
description = db.Column(db.Text, nullable=False)
price = db.Column(db.Float, nullable=False)
location = db.Column(db.String(150), nullable=False)
property_type = db.Column(db.String(50), nullable=False)
host_id = db.Column(db.Integer, db.ForeignKey('user.id'), nullable=False)
images = db.relationship('Image', backref='listing', lazy=True)
latitude = db.Column(db.Float, nullable=True)
longitude = db.Column(db.Float, nullable=True)
class Image(db.Model):
id = db.Column(db.Integer, primary_key=True)
url = db.Column(db.String(300), nullable=False)
listing_id = db.Column(db.Integer, db.ForeignKey('listing.id'), nullable=False)
class Booking(db.Model):
id = db.Column(db.Integer, primary_key=True)
guest_name = db.Column(db.String(100), nullable=False)
email = db.Column(db.String(120), nullable=False)
phone = db.Column(db.String(20), nullable=False)
listing_id = db.Column(db.Integer, db.ForeignKey('listing.id'), nullable=False)
check_in = db.Column(db.DateTime, nullable=False)
check_out = db.Column(db.DateTime, nullable=False)
guests = db.Column(db.Integer, nullable=False)
+94
View File
@@ -0,0 +1,94 @@
from flask import render_template, request, redirect, url_for
from flask_login import login_user, login_required, logout_user, current_user
from app import app, db, bcrypt, login_manager
from models import User, Listing, Booking, Image
from datetime import datetime
@login_manager.user_loader
def load_user(user_id):
return User.query.get(int(user_id))
@app.route('/')
def home():
property_type = request.args.get('property_type')
listings = Listing.query
available_listings = []
for listing in listings:
bookings = Booking.query.filter_by(listing_id=listing.id).all()
if all(datetime.strptime(booking.check_out, '%Y-%m-%d') < datetime.now() for booking in bookings):
available_listings.append(listing)
if property_type:
available_listings = [l for l in available_listings if l.property_type == property_type]
return render_template('index.html', listings=available_listings)
@app.route('/login', methods=['GET', 'POST'])
def login():
if request.method == 'POST':
email = request.form['email']
password = request.form['password']
user = User.query.filter_by(email=email).first()
if user and bcrypt.check_password_hash(user.password, password):
login_user(user)
return redirect(url_for('dashboard'))
return render_template('login.html')
@app.route('/register', methods=['GET', 'POST'])
def register():
if request.method == 'POST':
email = request.form['email']
password = bcrypt.generate_password_hash(request.form['password']).decode('utf-8')
phone = request.form['phone']
user = User(email=email, password=password, phone=phone)
db.session.add(user)
db.session.commit()
login_user(user)
return redirect(url_for('dashboard'))
return render_template('register.html')
@app.route('/dashboard')
@login_required
def dashboard():
if current_user.is_host:
listings = Listing.query.filter_by(host_id=current_user.id).all()
return render_template('dashboard.html', listings=listings)
return redirect(url_for('home'))
@app.route('/create-listing', methods=['GET', 'POST'])
@login_required
def create_listing():
if request.method == 'POST':
title = request.form['title']
description = request.form['description']
price = request.form['price']
location = request.form['location']
property_type = request.form['property_type']
latitude = request.form.get('latitude')
longitude = request.form.get('longitude')
listing = Listing(title=title, description=description, price=price, location=location, property_type=property_type, host_id=current_user.id, latitude=latitude, longitude=longitude)
db.session.add(listing)
db.session.flush()
image_urls = request.form.getlist('images')
for url in image_urls:
image = Image(url=url, listing_id=listing.id)
db.session.add(image)
db.session.commit()
return redirect(url_for('dashboard'))
return render_template('create_listing.html')
@app.route('/booking/<int:listing_id>', methods=['GET', 'POST'])
def booking(listing_id):
listing = Listing.query.get_or_404(listing_id)
if request.method == 'POST':
guest_name = request.form['name']
email = request.form['email']
phone = request.form['phone']
check_in = datetime.strptime(request.form['check_in'], '%Y-%m-%d')
check_out = datetime.strptime(request.form['check_out'], '%Y-%m-%d')
guests = request.form['guests']
booking = Booking(guest_name=guest_name, email=email, phone=phone, listing_id=listing_id, check_in=check_in, check_out=check_out, guests=guests)
db.session.add(booking)
db.session.commit()
return redirect(url_for('home'))
return render_template('booking.html', listing=listing)
+34
View File
@@ -0,0 +1,34 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>{% block title %}Booking System{% endblock %}</title>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet">
</head>
<body>
<nav class="navbar navbar-expand-lg navbar-light bg-light">
<div class="container-fluid">
<a class="navbar-brand" href="/">Booking System</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">
{% if current_user.is_authenticated %}
<li class="nav-item"><a class="nav-link" href="/dashboard">Dashboard</a></li>
<li class="nav-item"><a class="nav-link" href="/logout">Logout</a></li>
{% else %}
<li class="nav-item"><a class="nav-link" href="/login">Login</a></li>
<li class="nav-item"><a class="nav-link" href="/register">Register</a></li>
{% endif %}
</ul>
</div>
</div>
</nav>
<div class="container mt-4">
{% block content %}{% endblock %}
</div>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></script>
</body>
</html>
+37
View File
@@ -0,0 +1,37 @@
{% extends 'base.html' %}
{% block title %}Booking{% endblock %}
{% block content %}
<div class="row justify-content-center">
<div class="col-md-6">
<h1 class="text-center">Book {{ listing.title }}</h1>
<form method="POST">
<div class="mb-3">
<label for="name" class="form-label">Full Name</label>
<input type="text" class="form-control" id="name" name="name" required>
</div>
<div class="mb-3">
<label for="email" class="form-label">Email</label>
<input type="email" class="form-control" id="email" name="email" required>
</div>
<div class="mb-3">
<label for="phone" class="form-label">Phone</label>
<input type="text" class="form-control" id="phone" name="phone" required>
</div>
<div class="mb-3">
<label for="check_in" class="form-label">Check-in Date</label>
<input type="date" class="form-control" id="check_in" name="check_in" required>
</div>
<div class="mb-3">
<label for="check_out" class="form-label">Check-out Date</label>
<input type="date" class="form-control" id="check_out" name="check_out" required>
</div>
<div class="mb-3">
<label for="guests" class="form-label">Number of Guests</label>
<input type="number" class="form-control" id="guests" name="guests" required>
</div>
<button type="submit" class="btn btn-primary w-100">Confirm Booking</button>
</form>
</div>
</div>
{% endblock %}
+40
View File
@@ -0,0 +1,40 @@
{% extends 'base.html' %}
{% block title %}Create Listing{% endblock %}
{% block content %}
<div class="row justify-content-center">
<div class="col-md-6">
<h1 class="text-center">Create Listing</h1>
<form method="POST">
<div class="mb-3">
<label for="title" class="form-label">Title</label>
<input type="text" class="form-control" id="title" name="title" required>
</div>
<div class="mb-3">
<label for="description" class="form-label">Description</label>
<textarea class="form-control" id="description" name="description" rows="3" required></textarea>
</div>
<div class="mb-3">
<label for="price" class="form-label">Price</label>
<input type="number" class="form-control" id="price" name="price" required>
</div>
<div class="mb-3">
<label for="location" class="form-label">Location</label>
<input type="text" class="form-control" id="location" name="location" required>
</div>
<div class="mb-3">
<label for="property_type" class="form-label">Property Type</label>
<input type="text" class="form-control" id="property_type" name="property_type" required>
</div>
<div class="mb-3">
<label for="latitude" class="form-label">Latitude</label>
<input type="text" class="form-control" id="latitude" name="latitude">
</div>
<div class="mb-3">
<label for="longitude" class="form-label">Longitude</label>
<input type="text" class="form-control" id="longitude" name="longitude">
</div>
<button type="submit" class="btn btn-primary w-100">Create</button>
</form>
</div>
</div>
{% endblock %}
+20
View File
@@ -0,0 +1,20 @@
{% extends 'base.html' %}
{% block title %}Dashboard{% endblock %}
{% block content %}
<h1 class="text-center">Your Listings</h1>
<div class="row">
{% for listing in listings %}
<div class="col-md-4 mb-4">
<div class="card h-100">
<img src="/static/images/default.jpg" class="card-img-top" alt="...">
<div class="card-body">
<h5 class="card-title">{{ listing.title }}</h5>
<p class="card-text">{{ listing.description }}</p>
<a href="/edit-listing/{{ listing.id }}" class="btn btn-warning">Edit</a>
<a href="/delete-listing/{{ listing.id }}" class="btn btn-danger">Delete</a>
</div>
</div>
</div>
{% endfor %}
</div>
{% endblock %}
+19
View File
@@ -0,0 +1,19 @@
{% extends 'base.html' %}
{% block title %}Home{% endblock %}
{% block content %}
<h1 class="text-center">Available Listings</h1>
<div class="row">
{% for listing in listings %}
<div class="col-md-4 mb-4">
<div class="card h-100">
<img src="/static/images/default.jpg" class="card-img-top" alt="...">
<div class="card-body">
<h5 class="card-title">{{ listing.title }}</h5>
<p class="card-text">{{ listing.description }}</p>
<a href="/booking/{{ listing.id }}" class="btn btn-primary">Book Now</a>
</div>
</div>
</div>
{% endfor %}
</div>
{% endblock %}
+20
View File
@@ -0,0 +1,20 @@
{% extends 'base.html' %}
{% block title %}Login{% endblock %}
{% block content %}
<div class="row justify-content-center">
<div class="col-md-6">
<h1 class="text-center">Login</h1>
<form method="POST">
<div class="mb-3">
<label for="email" class="form-label">Email</label>
<input type="email" class="form-control" id="email" name="email" required>
</div>
<div class="mb-3">
<label for="password" class="form-label">Password</label>
<input type="password" class="form-control" id="password" name="password" required>
</div>
<button type="submit" class="btn btn-primary w-100">Login</button>
</form>
</div>
</div>
{% endblock %}
+24
View File
@@ -0,0 +1,24 @@
{% extends 'base.html' %}
{% block title %}Register{% endblock %}
{% block content %}
<div class="row justify-content-center">
<div class="col-md-6">
<h1 class="text-center">Register</h1>
<form method="POST">
<div class="mb-3">
<label for="email" class="form-label">Email</label>
<input type="email" class="form-control" id="email" name="email" required>
</div>
<div class="mb-3">
<label for="password" class="form-label">Password</label>
<input type="password" class="form-control" id="password" name="password" required>
</div>
<div class="mb-3">
<label for="phone" class="form-label">Phone</label>
<input type="text" class="form-control" id="phone" name="phone" required>
</div>
<button type="submit" class="btn btn-success w-100">Register</button>
</form>
</div>
</div>
{% endblock %}