Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 7 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,14 +26,14 @@

## Trạng thái dự án

| Tuần | Nội dung |
|--------|--------------------------------------|
| Tuần 1 | Khởi tạo dự án |
| Tuần | Nội dung |
|-----|----------|
| Tuần 1 | Khởi tạo dự án |
| Tuần 2 | Xác định các actor và use case chính |
| Tuần 3 | C4 Diagrams, ADRs |
| Tuần 4 | FONT - END |
| Tuần 5 | FONT - END + BACK END |

| Tuần 3 | C4 Diagrams, ADRs |
| Tuần 4 | FONT - END |
| Tuần 5 | BACK-END |
| Tuần 6 | BACK-END |

---

Expand Down
49 changes: 37 additions & 12 deletions backend/src/__init__.py
Original file line number Diff line number Diff line change
@@ -1,16 +1,41 @@
import os
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
app=Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = 'mysql+pymysql://root:08032005@localhost/event'
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
db=SQLAlchemy(app)
from backend.src.extensions import db, jwt

def create_app():
BASE_DIR = os.path.abspath(os.path.dirname(__file__))
TEMPLATE_DIR = os.path.join(BASE_DIR, '../../frontend/src/templates')
STATIC_DIR = os.path.join(BASE_DIR, '../../frontend/src')

app = Flask(
__name__,
template_folder=TEMPLATE_DIR,
static_folder=STATIC_DIR,
static_url_path=''
)

app.config['SQLALCHEMY_DATABASE_URI'] = 'mysql+pymysql://root:08032005@localhost/event2'
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
app.config['JWT_SECRET_KEY'] = 'event_ticketing_super_secret'

db.init_app(app)
jwt.init_app(app)

if __name__ == '__main__':
with app.app_context():
# Lệnh này sẽ xóa sạch các bảng cũ
db.drop_all()
# Lệnh này tạo lại các bảng dựa trên Model bạn đã khai báo
db.create_all()
print("--- Đã reset xong Database ticket! ---")
from backend.src import models

from backend.src.routes.admin_routes import admin_bp, admin_api_bp
from backend.src.routes.organizer_routes import organizer_bp
from backend.src.routes.api_auth_routes import api_auth_bp
from backend.src.routes.main_routes import main_bp

try:
app.register_blueprint(admin_bp)
app.register_blueprint(organizer_bp)
app.register_blueprint(api_auth_bp)
app.register_blueprint(main_bp)
app.register_blueprint(admin_api_bp)
except Exception as e:
pass

app.run(debug=True, port=8000)
return app
31 changes: 3 additions & 28 deletions backend/src/app.py
Original file line number Diff line number Diff line change
@@ -1,32 +1,7 @@
import os
from flask import Flask
# Import db từ models
from backend.src.models import db
from backend.src.__init__ import create_app

# Nạp các blueprint
from routes.admin_routes import admin_bp
from routes.organizer_routes import organizer_bp
from routes.api_auth_routes import api_auth_bp

# Set up đường dẫn thư mục
BASE_DIR = os.path.abspath(os.path.dirname(__file__))
TEMPLATE_DIR = os.path.join(BASE_DIR, '../../frontend/src/templates')
STATIC_DIR = os.path.join(BASE_DIR, '../../frontend/src')

# Khởi tạo Flask
app = Flask(__name__, template_folder=TEMPLATE_DIR, static_folder=STATIC_DIR, static_url_path='')

# CẤU HÌNH DATABASE CHUẨN XÁC NẰM Ở ĐÂY
app.config['SQLALCHEMY_DATABASE_URI'] = 'mysql+pymysql://root:08032005@localhost/event'
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False

# Móc nối db vào app
db.init_app(app)

# Đăng ký blueprint vào app chính
app.register_blueprint(admin_bp)
app.register_blueprint(organizer_bp)
app.register_blueprint(api_auth_bp)
app = create_app()

if __name__ == '__main__':

app.run(debug=True, port=8000)
5 changes: 5 additions & 0 deletions backend/src/extensions.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
from flask_sqlalchemy import SQLAlchemy
from flask_jwt_extended import JWTManager

db = SQLAlchemy()
jwt = JWTManager()
108 changes: 65 additions & 43 deletions backend/src/models.py
Original file line number Diff line number Diff line change
@@ -1,41 +1,41 @@
# File: backend/src/models.py
import enum
import sys

from flask_sqlalchemy import SQLAlchemy
from sqlalchemy import Column, Integer, String, Boolean, DateTime, DECIMAL, ForeignKey, Enum as SAEnum, Date
from sqlalchemy.sql import func

from backend.src.extensions import db

class EventStatusEnum(enum.Enum):
PENDING = 0
PUBLISHED = 1
CANCELLED = 2

db = SQLAlchemy()

# ==========================================
# 1. KHAI BÁO ENUM CHO CÁC TRẠNG THÁI & HẠNG
# ==========================================
class EventCategoryEnum(enum.Enum):
MUSIC = 0
WORKSHOP = 1
ENTERTAINMENT = 2

class EventStatusEnum(enum.Enum):
PENDING = 0 # Chờ Admin duyệt
PUBLISHED = 1 # Đã đăng bán
CANCELLED = 2 # Hủy bỏ

class SeatStatusEnum(enum.Enum):
AVAILABLE = 0 # Trống
LOCKED = 1 # Đang giữ chỗ
SOLD = 2 # Đã bán
AVAILABLE = 0
LOCKED = 1
SOLD = 2


class OrderStatusEnum(enum.Enum):
PENDING = 0 # Đang chờ thanh toán
PAID = 1 # Đã thanh toán
FAILED = 2 # Thất bại/Hết hạn
PENDING = 0
PAID = 1
FAILED = 2

class CustomerTierEnum(enum.Enum):
MEMBER = 0 # Thành viên mới
VIP = 1 # Khách quen
VVIP = 2 # Khách sộp

class CustomerTierEnum(enum.Enum):
MEMBER = 0
VIP = 1
VVIP = 2

# ==========================================
# 2. CẤP ĐỘ 1: LỚP BASE USER
# ==========================================

class User(db.Model):
__tablename__ = 'user'
Expand All @@ -46,21 +46,17 @@ class User(db.Model):
phone_number = Column(String(15), unique=True)
username = Column(String(50), nullable=False, unique=True)
password = Column(String(255), nullable=False)
status = Column(Boolean, default=True) # True: Active, False: Inactive
avatar = Column(String(500), default="https://default-avatar.com/user.png") # Cột avatar ông đã có sẵn nè
status = Column(Boolean, default=True)
avatar = Column(String(500), default="https://default-avatar.com/user.png")
dob = Column(Date, nullable=False)
type = Column(String(50)) # Cột phân loại Kế thừa
type = Column(String(50))

__mapper_args__ = {
'polymorphic_identity': 'user',
'polymorphic_on': type
}


# ==========================================
# 3. CẤP ĐỘ 2: CÁC ACTOR KẾ THỪA TỪ USER
# ==========================================

class Customer(User):
__tablename__ = 'customer'
id = Column(Integer, ForeignKey('user.id'), primary_key=True)
Expand All @@ -73,6 +69,7 @@ class Customer(User):

orders = db.relationship('Order', backref='customer', lazy=True)


class Organizer(User):
__tablename__ = 'organizer'
id = Column(Integer, ForeignKey('user.id'), primary_key=True)
Expand All @@ -86,6 +83,7 @@ class Organizer(User):

events = db.relationship('Event', backref='organizer', lazy=True)


class Admin(User):
__tablename__ = 'admin'
id = Column(Integer, ForeignKey('user.id'), primary_key=True)
Expand All @@ -97,53 +95,59 @@ class Admin(User):
}


# ==========================================
# 4. CÁC BẢNG NGHIỆP VỤ (Sự kiện, Vé, Đơn hàng)
# ==========================================

class Event(db.Model):
__tablename__ = 'events'

id = Column(Integer, primary_key=True, autoincrement=True)
organizer_id = Column(Integer, ForeignKey('organizer.id'), nullable=False)
title = Column(String(200), nullable=False)
thumbnail = Column(String(500), nullable=True)
description = Column(db.Text, nullable=True)
thumbnail = Column(String(500))
description = db.Column(db.Text)
location = Column(String(255), nullable=False)
start_time = Column(DateTime, nullable=False)

category = Column(SAEnum(EventCategoryEnum), default=EventCategoryEnum.MUSIC)
status = Column(SAEnum(EventStatusEnum), default=EventStatusEnum.PENDING)

ticket_types = db.relationship('TicketType', backref='event', lazy=True)
seats = db.relationship('Seat', backref='event', lazy=True)


class TicketType(db.Model):
__tablename__ = 'ticket_types'
id = Column(Integer, primary_key=True, autoincrement=True)

id = Column(Integer, primary_key=True)
event_id = Column(Integer, ForeignKey('events.id'), nullable=False)
name = Column(String(50), nullable=False)
price = Column(DECIMAL(10, 2), nullable=False)
total_quantity = Column(Integer, nullable=False)

__table_args__ = (
db.CheckConstraint('price >= 0', name='check_price_positive'),
db.CheckConstraint('total_quantity >= 0', name='check_quantity_positive'),
db.CheckConstraint('price >= 0'),
db.CheckConstraint('total_quantity >= 0'),
)


class Seat(db.Model):
__tablename__ = 'seats'
id = Column(Integer, primary_key=True, autoincrement=True)

id = Column(Integer, primary_key=True)
event_id = Column(Integer, ForeignKey('events.id'), nullable=False)
ticket_type_id = Column(Integer, ForeignKey('ticket_types.id'), nullable=False)
seat_name = Column(String(10), nullable=False)

status = Column(SAEnum(SeatStatusEnum), default=SeatStatusEnum.AVAILABLE)
locked_until = Column(DateTime, nullable=True)
locked_until = Column(DateTime)

__table_args__ = (
db.UniqueConstraint('event_id', 'seat_name'),
)

__table_args__ = (db.UniqueConstraint('event_id', 'seat_name', name='_event_seat_uc'),)

class Order(db.Model):
__tablename__ = 'orders'
id = Column(Integer, primary_key=True, autoincrement=True)

id = Column(Integer, primary_key=True)
customer_id = Column(Integer, ForeignKey('customer.id'), nullable=False)
event_id = Column(Integer, ForeignKey('events.id'), nullable=False)
total_amount = Column(DECIMAL(10, 2), nullable=False)
Expand All @@ -155,12 +159,30 @@ class Order(db.Model):

tickets = db.relationship('Ticket', backref='order', lazy=True)


class Ticket(db.Model):
__tablename__ = 'tickets'
id = Column(Integer, primary_key=True, autoincrement=True)

id = Column(Integer, primary_key=True)
order_id = Column(Integer, ForeignKey('orders.id'), nullable=False)
seat_id = Column(Integer, ForeignKey('seats.id'), nullable=False, unique=True)
ticket_code = Column(String(100), nullable=False, unique=True)
is_checked_in = Column(Boolean, default=False)


def create_db():
# Trick báo cho Python biết là file models đã được load rồi, tránh import vòng
sys.modules['backend.src.models'] = sys.modules[__name__]

from backend.src import create_app, db

app = create_app()

with app.app_context():
db.drop_all()
db.create_all()
print("Database created successfully!")


if __name__ == "__main__":
create_db()
Loading