parent
3bc3f8ed5e
commit
4036ed0fff
@ -0,0 +1,3 @@
|
||||
.idea
|
||||
__pycache__/
|
||||
*.log
|
||||
@ -0,0 +1,7 @@
|
||||
FROM python:3.12.4-slim
|
||||
WORKDIR /app
|
||||
COPY requirements.txt requirements.txt
|
||||
RUN pip config set global.index-url http://mirrors.aliyun.com/pypi/simple && pip config set install.trusted-host mirrors.aliyun.com
|
||||
RUN pip install -r requirements.txt
|
||||
COPY . ./
|
||||
CMD ["gunicorn", "-w", "4", "--bind", "0.0.0.0:3002", "myapp:app" ]
|
||||
@ -0,0 +1,38 @@
|
||||
import re
|
||||
import datetime
|
||||
|
||||
from flask import Blueprint, jsonify, request
|
||||
|
||||
from app import LogService
|
||||
from utils import create_response, StateCode
|
||||
|
||||
bank_bp = Blueprint('bank_server', __name__)
|
||||
|
||||
|
||||
#校验银行卡号
|
||||
@bank_bp.route('/bank/card_verify', methods=['POST'])
|
||||
def bankCardVerify():
|
||||
pattern = r'^\d{13,19}$'
|
||||
# 确保银行卡号是一个完整的 13 到 19 位的数字字符串
|
||||
number = request.json.get('bankCard')
|
||||
state = {
|
||||
"result": bool(re.match(pattern, number))
|
||||
}
|
||||
LogService.log()
|
||||
return jsonify(create_response(StateCode.SUCCESS, data=state)), 200
|
||||
|
||||
|
||||
@bank_bp.route('/bank/pay', methods=['POST'])
|
||||
def pay():
|
||||
# 模拟支付成功,返回
|
||||
state = {"state": "successful", "pay_time": datetime.datetime.now()}
|
||||
LogService.log()
|
||||
return jsonify(create_response(StateCode.SUCCESS, data=state)), 200
|
||||
|
||||
|
||||
@bank_bp.route('/bank/query', methods=['POST'])
|
||||
def query():
|
||||
# 模拟验证成功,返回
|
||||
state = {"state": "successful", "pay_time": datetime.datetime.now()}
|
||||
LogService.log()
|
||||
return jsonify(create_response(StateCode.SUCCESS, data=state)), 200
|
||||
@ -0,0 +1,25 @@
|
||||
import re
|
||||
from flask import Blueprint, jsonify, request
|
||||
|
||||
from app import LogService
|
||||
from utils import create_response, StateCode
|
||||
|
||||
id_card_bp = Blueprint('id_card_server', __name__)
|
||||
|
||||
|
||||
#校验身份证号码
|
||||
@id_card_bp.route('/id_card/verify', methods=['POST'])
|
||||
def idCardVerify():
|
||||
print("idCardVerify() 被调用了")
|
||||
pattern = r'^\d{18}$'
|
||||
id_number = request.json.get('idCardNo')
|
||||
print(f"Received ID number: {id_number}") # 先打印看看
|
||||
state = {
|
||||
"result": bool(re.match(pattern, id_number))
|
||||
}
|
||||
LogService.log()
|
||||
return jsonify(create_response(StateCode.SUCCESS, data=state)), 200
|
||||
|
||||
|
||||
|
||||
|
||||
@ -0,0 +1,25 @@
|
||||
from flask import request
|
||||
from loguru import logger
|
||||
|
||||
|
||||
class LogService:
|
||||
@staticmethod
|
||||
def configure_logging():
|
||||
logger.remove() # 移除默认的日志配置
|
||||
logger.add(
|
||||
"logs/app.log", # 日志文件名
|
||||
rotation="1 week", # 每周轮换
|
||||
retention="1 month", # 保留一个月
|
||||
level="INFO", # 记录 INFO 及以上级别的日志
|
||||
format="{time} - {level} - {message}", # 日志格式
|
||||
backtrace=True, # 打印完整的异常堆栈
|
||||
diagnose=True # 打印详细的异常信息
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
def log():
|
||||
logger.info(f"Request Path: {request.path}")
|
||||
logger.info(f"Request Method: {request.method}")
|
||||
logger.info(f"Request Headers: {request.headers}")
|
||||
logger.info(f"Request args: {request.args}")
|
||||
logger.info(f"Request Body: {request.get_data(as_text=True)}")
|
||||
@ -0,0 +1,26 @@
|
||||
from flask import Blueprint, request, jsonify
|
||||
from flask_jwt_extended import create_access_token
|
||||
|
||||
from app import LogService
|
||||
from app.models import Passenger
|
||||
from presenter import PassengerPresenter
|
||||
from utils import StateCode, create_response
|
||||
|
||||
login_bp = Blueprint('login', __name__)
|
||||
|
||||
#登录模块
|
||||
@login_bp.route('/login', methods=['POST'])
|
||||
def login():
|
||||
data = request.json
|
||||
account = data.get('account')
|
||||
password = data.get('password')
|
||||
if not account or not password:
|
||||
return jsonify(create_response(StateCode.PARAMS_ERROR)), 400
|
||||
user = Passenger.verifyPassenger(account, password)
|
||||
if user:
|
||||
# 为新创建的乘客生成访问令牌
|
||||
access_token = create_access_token(identity=str(user.id))
|
||||
user_presenter = PassengerPresenter(user, {"token": access_token}).as_dict()
|
||||
LogService.log()
|
||||
return jsonify(create_response(StateCode.SUCCESS, data=user_presenter)), 200
|
||||
return jsonify(create_response(StateCode.PASSWORD_INCORRECT)), 400
|
||||
@ -0,0 +1,6 @@
|
||||
from app import db
|
||||
from .order_lib import Order
|
||||
from .passenger_lib import Passenger
|
||||
from .station_lib import Station
|
||||
from .train_lib import Train
|
||||
|
||||
@ -0,0 +1,45 @@
|
||||
import pdb
|
||||
from datetime import datetime
|
||||
from pypinyin import pinyin, Style
|
||||
from sqlalchemy import func
|
||||
|
||||
from app.models import db
|
||||
|
||||
|
||||
class Station(db.Model):
|
||||
__tablename__: str = 'station'
|
||||
|
||||
id = db.Column(db.Integer, primary_key=True)
|
||||
name = db.Column(db.String(120), unique=True, nullable=False, index=True)
|
||||
pinyin = db.Column(db.String(120))
|
||||
province = db.Column(db.String(120))
|
||||
city = db.Column(db.String(120))
|
||||
district = db.Column(db.String(120))
|
||||
created_at = db.Column(db.DateTime, default=func.now())
|
||||
updated_at = db.Column(db.DateTime, default=func.now())
|
||||
|
||||
def __repr__(self):
|
||||
return f'<Station {self.name}>'
|
||||
|
||||
@classmethod
|
||||
def create(cls, data):
|
||||
station = cls(
|
||||
name=data.get('name'),
|
||||
pinyin=''.join([item[0] for item in pinyin(data.get('name'), style=Style.NORMAL)]).upper(),
|
||||
province=data.get('province'),
|
||||
city=data.get('city'),
|
||||
created_at=datetime.now(),
|
||||
updated_at=datetime.now(),
|
||||
)
|
||||
db.session.add(station)
|
||||
db.session.commit()
|
||||
return station
|
||||
|
||||
@classmethod
|
||||
def destroy(cls, station_id):
|
||||
station = cls.query.get(station_id)
|
||||
if station:
|
||||
db.session.delete(station)
|
||||
db.session.commit()
|
||||
return True
|
||||
return False
|
||||
@ -0,0 +1,45 @@
|
||||
from sqlalchemy import func
|
||||
|
||||
from app.models import db
|
||||
|
||||
|
||||
class Ticket(db.Model):
|
||||
__tablename__: str = 'ticket'
|
||||
|
||||
id = db.Column(db.Integer, primary_key=True)
|
||||
seat_no = db.Column(db.String(120))
|
||||
seat_class = db.Column(db.String(120))
|
||||
price = db.Column(db.Numeric(8, 2))
|
||||
state = db.Column(db.Integer, default=0)
|
||||
train_no = db.Column(db.String(120), db.ForeignKey('train.train_no'), nullable=False, index=True)
|
||||
passenger_id = db.Column(db.Integer, db.ForeignKey('passenger.id'), nullable=False, index=True)
|
||||
order_id = db.Column(db.Integer, db.ForeignKey('order.id'), nullable=False, index=True)
|
||||
from_station = db.Column(db.String(120))
|
||||
to_station = db.Column(db.String(120))
|
||||
date = db.Column(db.String(120))
|
||||
departure_time = db.Column(db.DateTime)
|
||||
arrival_time = db.Column(db.DateTime)
|
||||
created_at = db.Column(db.DateTime, default=func.now())
|
||||
updated_at = db.Column(db.DateTime, default=func.now())
|
||||
order = db.relationship('Order', backref=db.backref('tickets'))
|
||||
passenger = db.relationship('Passenger', backref=db.backref('tickets'))
|
||||
|
||||
def __repr__(self):
|
||||
return f'<Ticket {self.id}>'
|
||||
|
||||
def updateState(self):
|
||||
self.state = 1
|
||||
return self
|
||||
|
||||
@classmethod
|
||||
def generateTicket(cls, item, passenger_id):
|
||||
# Create a new Ticket object
|
||||
ticket = Ticket(
|
||||
seat_class=item["seatClass"],
|
||||
train_no=item["trainNo"],
|
||||
from_station=item["from"],
|
||||
to_station=item["to"],
|
||||
date=item["date"],
|
||||
passenger_id=passenger_id
|
||||
)
|
||||
return ticket
|
||||
@ -0,0 +1,21 @@
|
||||
from sqlalchemy import func
|
||||
|
||||
from app.models import db
|
||||
|
||||
|
||||
class TrainStation(db.Model):
|
||||
__tablename__: str = 'train_station'
|
||||
|
||||
train_no = db.Column(db.String(120), db.ForeignKey('train.train_no'), primary_key=True, index=True)
|
||||
station_name = db.Column(db.String(120), db.ForeignKey('station.name'), primary_key=True)
|
||||
|
||||
price = db.Column(db.Numeric(8, 2))
|
||||
arrival_time = db.Column(db.DateTime)
|
||||
departure_time = db.Column(db.DateTime)
|
||||
index = db.Column(db.Integer, default=0)
|
||||
created_at = db.Column(db.DateTime, default=func.now())
|
||||
updated_at = db.Column(db.DateTime, default=func.now())
|
||||
|
||||
station = db.relationship('Station', backref=db.backref('train_stations'))
|
||||
train = db.relationship('Train', backref=db.backref('train_stations'))
|
||||
|
||||
@ -0,0 +1,53 @@
|
||||
import iso8601
|
||||
from flask import Blueprint, jsonify, request
|
||||
from flask_jwt_extended import get_jwt_identity, jwt_required
|
||||
|
||||
from app import LogService
|
||||
from app.models import Station
|
||||
from app.models.ticket_lib import Ticket
|
||||
from app.models.train_lib import Train
|
||||
from app.station_manager import station_bp
|
||||
from presenter import StationPresenter
|
||||
from presenter.ticket import TicketPresenter
|
||||
from presenter.train import TrainPresenter
|
||||
from utils import create_response, StateCode
|
||||
|
||||
query_bp = Blueprint('query', __name__)
|
||||
|
||||
|
||||
#控制层,接收前端的请求,调用服务层进行查询车次信息,封装结构并返回
|
||||
@query_bp.route('/trains/query_train', methods=['GET'])
|
||||
def queryTrains(): # 查询车次方法
|
||||
#获取起始站名
|
||||
from_station = request.args.get('from')
|
||||
#获取终点站名
|
||||
to_station = request.args.get('to')
|
||||
#获取日期并用iso8601解析
|
||||
date = iso8601.parse_date(request.args.get('date'))
|
||||
#判断参数是否为空
|
||||
if not from_station or not to_station or not date:
|
||||
return jsonify(create_response(StateCode.PARAMS_ERROR)), 400
|
||||
# 查询车次
|
||||
trains = Train.queryTrains(from_station, to_station, date)
|
||||
# 封装响应数据
|
||||
trains_presenters = [TrainPresenter(train).as_dict() for train in trains]
|
||||
LogService.log()
|
||||
return jsonify(create_response(StateCode.SUCCESS, data=trains_presenters)), 200
|
||||
|
||||
|
||||
@query_bp.route('/tickets', methods=['GET'])
|
||||
@jwt_required()
|
||||
def getTickets(): # 查询车票方法
|
||||
current_user = get_jwt_identity() # 解码JWT得到用户ID
|
||||
tickets = Ticket.query.filter_by(passenger_id=current_user).all()
|
||||
tickets_presenters = [TicketPresenter(ticket).as_dict() for ticket in tickets]
|
||||
LogService.log()
|
||||
return jsonify(create_response(StateCode.SUCCESS, data=tickets_presenters)), 200
|
||||
|
||||
|
||||
@station_bp.route('/stations', methods=['GET'])
|
||||
def queryStations(): # 查询站点方法
|
||||
stations = Station.query.all()
|
||||
stations_presenters = [StationPresenter(station).as_dict() for station in stations]
|
||||
LogService.log()
|
||||
return jsonify(create_response(StateCode.SUCCESS, data=stations_presenters)), 200
|
||||
@ -0,0 +1,26 @@
|
||||
from flask import request, jsonify, Blueprint
|
||||
from app import LogService
|
||||
from app.models import Station
|
||||
from presenter import StationPresenter
|
||||
from utils import create_response, StateCode
|
||||
|
||||
station_bp = Blueprint('stations', __name__)
|
||||
|
||||
|
||||
@station_bp.route('/stations', methods=['POST'])
|
||||
def createStation(): # 创建站点方法
|
||||
data = request.json
|
||||
new_station = Station.create(data=data)
|
||||
station_presenter = StationPresenter(new_station).as_dict()
|
||||
LogService.log()
|
||||
return jsonify(create_response(StateCode.SUCCESS, data=station_presenter)), 200
|
||||
|
||||
|
||||
@station_bp.route('/stations/quantity_create', methods=['POST'])
|
||||
def quantityCreate(): # 批量创建站点方法
|
||||
stations = request.json.get("stations")
|
||||
for name in stations:
|
||||
station_hash = {"name": name}
|
||||
Station.create(station_hash)
|
||||
LogService.log()
|
||||
return jsonify(create_response(StateCode.SUCCESS)), 200
|
||||
@ -0,0 +1,27 @@
|
||||
from flask import request, jsonify, Blueprint
|
||||
from app import db, LogService
|
||||
from app.models import Train
|
||||
from app.models.train_lib import buildTrain
|
||||
from presenter.train import TrainPresenter
|
||||
from utils import create_response, StateCode
|
||||
|
||||
trains_bp = Blueprint('trains', __name__)
|
||||
|
||||
|
||||
@trains_bp.route('/trains', methods=['GET'])
|
||||
def queryAllTrains():
|
||||
trains = Train.query.all()
|
||||
trains_presenters = [TrainPresenter(train).as_dict() for train in trains]
|
||||
LogService.log()
|
||||
return jsonify(create_response(StateCode.SUCCESS, data=trains_presenters)), 200
|
||||
|
||||
|
||||
@trains_bp.route('/trains', methods=['POST'])
|
||||
def createTrain():
|
||||
data = request.json
|
||||
new_train = buildTrain(data)
|
||||
db.session.add(new_train)
|
||||
db.session.commit()
|
||||
train_presenter = TrainPresenter(new_train).as_dict()
|
||||
LogService.log()
|
||||
return jsonify(create_response(StateCode.SUCCESS, data=train_presenter)), 200
|
||||
@ -0,0 +1,16 @@
|
||||
import os
|
||||
|
||||
|
||||
class Config:
|
||||
# SECRET_KEY = os.environ.get('SECRET_KEY') or 'your_secret_key'
|
||||
# SQLALCHEMY_TRACK_MODIFICATIONS = False
|
||||
|
||||
SECRET_KEY = '8665e31a29ab7e12cb0f92c1dbobj1e3a6a15230fb17'
|
||||
|
||||
# SQLALCHEMY_DATABASE_URI = os.environ.get('DATABASE_URL') or
|
||||
# 'postgresql://username:password@localhost:5432/your dbname'
|
||||
|
||||
SQLALCHEMY_DATABASE_URI = os.environ.get('DATABASE_URL') or 'mysql+pymysql://root:1625344721Qq%40@localhost/mini12306'
|
||||
SQLALCHEMY_TRACK_MODIFICATIONS = False
|
||||
|
||||
REDIS_URL = "redis://:123456@localhost:6379/0"
|
||||
@ -0,0 +1,87 @@
|
||||
# version: '3.8'
|
||||
# services:
|
||||
# python:
|
||||
# build:
|
||||
# context: ./
|
||||
# dockerfile: ./Dockerfile
|
||||
# restart: always
|
||||
# environment:
|
||||
# - DATABASE_URL=postgresql://postgres:postgres@db:5432/mini12306_python
|
||||
# - REDIS_URL=redis
|
||||
# - SERVER_LIB_URL=http://py12306.learnerhub.net
|
||||
# ports:
|
||||
# - "3002:3002"
|
||||
# depends_on:
|
||||
# - db
|
||||
# - redis
|
||||
# volumes:
|
||||
# - /var/log/mini12306_python:/app/logs
|
||||
#
|
||||
# redis:
|
||||
# image: redis:alpine
|
||||
# container_name: 12306_redis
|
||||
# volumes:
|
||||
# - redis_data:/data
|
||||
#
|
||||
# db:
|
||||
# image: postgres:15
|
||||
# container_name: 12306_postgres
|
||||
# restart: always
|
||||
# environment:
|
||||
# POSTGRES_USER: postgres
|
||||
# POSTGRES_PASSWORD: postgres
|
||||
# POSTGRES_DB: mini12306_python
|
||||
# volumes:
|
||||
# - postgres_data:/var/lib/postgresql/data
|
||||
#
|
||||
#
|
||||
# volumes:
|
||||
# postgres_data:
|
||||
# redis_data:
|
||||
|
||||
version: '3.8'
|
||||
services:
|
||||
python:
|
||||
build:
|
||||
context: ./
|
||||
dockerfile: ./Dockerfile
|
||||
restart: always
|
||||
environment:
|
||||
- DATABASE_URL=mysql+pymysql://root:123456@db:3306/mini12306_python # 修改数据库连接字符串
|
||||
- REDIS_URL=redis
|
||||
- SERVER_LIB_URL=http://py12306.learnerhub.net
|
||||
ports:
|
||||
- "3002:3002"
|
||||
depends_on:
|
||||
- db # 服务名保持不变,但已指向新的 MySQL 服务
|
||||
- redis
|
||||
volumes:
|
||||
- /var/log/mini12306_python:/app/logs
|
||||
|
||||
redis:
|
||||
image: redis:alpine
|
||||
container_name: 12306_redis
|
||||
volumes:
|
||||
- redis_data:/data
|
||||
|
||||
db: # 修改后的 MySQL 服务
|
||||
image: mysql:8.0 # 使用官方 MySQL 镜像
|
||||
container_name: 12306_mysql # 修改容器名称
|
||||
restart: always
|
||||
environment:
|
||||
MYSQL_ROOT_PASSWORD: 123456 # MySQL 根密码(建议修改)
|
||||
MYSQL_DATABASE: mini12306_python # 自动创建的数据库
|
||||
MYSQL_USER: app_user # 可选:创建专用用户
|
||||
MYSQL_PASSWORD: user123 # 可选用户密码
|
||||
volumes:
|
||||
- mysql_data:/var/lib/mysql # MySQL 数据存储路径
|
||||
# 建议添加的健康检查
|
||||
healthcheck:
|
||||
test: ["CMD", "mysqladmin", "ping", "-h", "localhost"]
|
||||
interval: 5s
|
||||
timeout: 5s
|
||||
retries: 5
|
||||
|
||||
volumes:
|
||||
mysql_data: # 修改卷名称
|
||||
redis_data:
|
||||
@ -0,0 +1 @@
|
||||
init folder
|
||||
@ -0,0 +1 @@
|
||||
Single-database configuration for Flask.
|
||||
@ -0,0 +1,50 @@
|
||||
# A generic, single database configuration.
|
||||
|
||||
[alembic]
|
||||
# template used to generate migration files
|
||||
# file_template = %%(rev)s_%%(slug)s
|
||||
|
||||
# set to 'true' to run the environment during
|
||||
# the 'revision' command, regardless of autogenerate
|
||||
# revision_environment = false
|
||||
|
||||
|
||||
# Logging configuration
|
||||
[loggers]
|
||||
keys = root,sqlalchemy,alembic,flask_migrate
|
||||
|
||||
[handlers]
|
||||
keys = console
|
||||
|
||||
[formatters]
|
||||
keys = generic
|
||||
|
||||
[logger_root]
|
||||
level = WARN
|
||||
handlers = console
|
||||
qualname =
|
||||
|
||||
[logger_sqlalchemy]
|
||||
level = WARN
|
||||
handlers =
|
||||
qualname = sqlalchemy.engine
|
||||
|
||||
[logger_alembic]
|
||||
level = INFO
|
||||
handlers =
|
||||
qualname = alembic
|
||||
|
||||
[logger_flask_migrate]
|
||||
level = INFO
|
||||
handlers =
|
||||
qualname = flask_migrate
|
||||
|
||||
[handler_console]
|
||||
class = StreamHandler
|
||||
args = (sys.stderr,)
|
||||
level = NOTSET
|
||||
formatter = generic
|
||||
|
||||
[formatter_generic]
|
||||
format = %(levelname)-5.5s [%(name)s] %(message)s
|
||||
datefmt = %H:%M:%S
|
||||
@ -0,0 +1,113 @@
|
||||
import logging
|
||||
from logging.config import fileConfig
|
||||
|
||||
from flask import current_app
|
||||
|
||||
from alembic import context
|
||||
|
||||
# this is the Alembic Config object, which provides
|
||||
# access to the values within the .ini file in use.
|
||||
config = context.config
|
||||
|
||||
# Interpret the config file for Python logging.
|
||||
# This line sets up loggers basically.
|
||||
fileConfig(config.config_file_name)
|
||||
logger = logging.getLogger('alembic.env')
|
||||
|
||||
|
||||
def get_engine():
|
||||
try:
|
||||
# this works with Flask-SQLAlchemy<3 and Alchemical
|
||||
return current_app.extensions['migrate'].db.get_engine()
|
||||
except (TypeError, AttributeError):
|
||||
# this works with Flask-SQLAlchemy>=3
|
||||
return current_app.extensions['migrate'].db.engine
|
||||
|
||||
|
||||
def get_engine_url():
|
||||
try:
|
||||
return get_engine().url.render_as_string(hide_password=False).replace(
|
||||
'%', '%%')
|
||||
except AttributeError:
|
||||
return str(get_engine().url).replace('%', '%%')
|
||||
|
||||
|
||||
# add your model's MetaData object here
|
||||
# for 'autogenerate' support
|
||||
# from myapp import mymodel
|
||||
# target_metadata = mymodel.Base.metadata
|
||||
config.set_main_option('sqlalchemy.url', get_engine_url())
|
||||
target_db = current_app.extensions['migrate'].db
|
||||
|
||||
# other values from the config, defined by the needs of env.py,
|
||||
# can be acquired:
|
||||
# my_important_option = config.get_main_option("my_important_option")
|
||||
# ... etc.
|
||||
|
||||
|
||||
def get_metadata():
|
||||
if hasattr(target_db, 'metadatas'):
|
||||
return target_db.metadatas[None]
|
||||
return target_db.metadata
|
||||
|
||||
|
||||
def run_migrations_offline():
|
||||
"""Run migrations in 'offline' mode.
|
||||
|
||||
This configures the context with just a URL
|
||||
and not an Engine, though an Engine is acceptable
|
||||
here as well. By skipping the Engine creation
|
||||
we don't even need a DBAPI to be available.
|
||||
|
||||
Calls to context.execute() here emit the given string to the
|
||||
script output.
|
||||
|
||||
"""
|
||||
url = config.get_main_option("sqlalchemy.url")
|
||||
context.configure(
|
||||
url=url, target_metadata=get_metadata(), literal_binds=True
|
||||
)
|
||||
|
||||
with context.begin_transaction():
|
||||
context.run_migrations()
|
||||
|
||||
|
||||
def run_migrations_online():
|
||||
"""Run migrations in 'online' mode.
|
||||
|
||||
In this scenario we need to create an Engine
|
||||
and associate a connection with the context.
|
||||
|
||||
"""
|
||||
|
||||
# this callback is used to prevent an auto-migration from being generated
|
||||
# when there are no changes to the schema
|
||||
# reference: http://alembic.zzzcomputing.com/en/latest/cookbook.html
|
||||
def process_revision_directives(context, revision, directives):
|
||||
if getattr(config.cmd_opts, 'autogenerate', False):
|
||||
script = directives[0]
|
||||
if script.upgrade_ops.is_empty():
|
||||
directives[:] = []
|
||||
logger.info('No changes in schema detected.')
|
||||
|
||||
conf_args = current_app.extensions['migrate'].configure_args
|
||||
if conf_args.get("process_revision_directives") is None:
|
||||
conf_args["process_revision_directives"] = process_revision_directives
|
||||
|
||||
connectable = get_engine()
|
||||
|
||||
with connectable.connect() as connection:
|
||||
context.configure(
|
||||
connection=connection,
|
||||
target_metadata=get_metadata(),
|
||||
**conf_args
|
||||
)
|
||||
|
||||
with context.begin_transaction():
|
||||
context.run_migrations()
|
||||
|
||||
|
||||
if context.is_offline_mode():
|
||||
run_migrations_offline()
|
||||
else:
|
||||
run_migrations_online()
|
||||
@ -0,0 +1,24 @@
|
||||
"""${message}
|
||||
|
||||
Revision ID: ${up_revision}
|
||||
Revises: ${down_revision | comma,n}
|
||||
Create Date: ${create_date}
|
||||
|
||||
"""
|
||||
from alembic import op
|
||||
import sqlalchemy as sa
|
||||
${imports if imports else ""}
|
||||
|
||||
# revision identifiers, used by Alembic.
|
||||
revision = ${repr(up_revision)}
|
||||
down_revision = ${repr(down_revision)}
|
||||
branch_labels = ${repr(branch_labels)}
|
||||
depends_on = ${repr(depends_on)}
|
||||
|
||||
|
||||
def upgrade():
|
||||
${upgrades if upgrades else "pass"}
|
||||
|
||||
|
||||
def downgrade():
|
||||
${downgrades if downgrades else "pass"}
|
||||
@ -0,0 +1,178 @@
|
||||
"""init databases
|
||||
|
||||
Revision ID: 1b3bc6809b30
|
||||
Revises:
|
||||
Create Date: 2024-08-15 15:09:26.124279
|
||||
|
||||
"""
|
||||
from alembic import op
|
||||
import sqlalchemy as sa
|
||||
|
||||
|
||||
# revision identifiers, used by Alembic.
|
||||
revision = '1b3bc6809b30'
|
||||
down_revision = None
|
||||
branch_labels = None
|
||||
depends_on = None
|
||||
|
||||
|
||||
def upgrade():
|
||||
# ### commands auto generated by Alembic - please adjust! ###
|
||||
op.create_table('log',
|
||||
sa.Column('id', sa.Integer(), nullable=False),
|
||||
sa.Column('log_user_agent', sa.String(length=120), nullable=True),
|
||||
sa.Column('log_method', sa.String(length=120), nullable=True),
|
||||
sa.Column('log_quest_path', sa.String(length=120), nullable=True),
|
||||
sa.Column('log_ip', sa.String(length=120), nullable=True),
|
||||
sa.Column('log_params', sa.String(length=120), nullable=True),
|
||||
sa.Column('log_controller', sa.String(length=120), nullable=True),
|
||||
sa.Column('log_controller_action', sa.String(length=120), nullable=True),
|
||||
sa.Column('log_controller_id', sa.String(length=120), nullable=True),
|
||||
sa.Column('account_id', sa.String(length=120), nullable=True),
|
||||
sa.Column('event_name', sa.String(length=120), nullable=True),
|
||||
sa.Column('event_content', sa.Text(), nullable=True),
|
||||
sa.Column('operator', sa.String(length=120), nullable=True),
|
||||
sa.Column('created_at', sa.DateTime(), nullable=True),
|
||||
sa.Column('updated_at', sa.DateTime(), nullable=True),
|
||||
sa.PrimaryKeyConstraint('id')
|
||||
)
|
||||
op.create_table('passenger',
|
||||
sa.Column('id', sa.Integer(), nullable=False),
|
||||
sa.Column('name', sa.String(length=120), nullable=True),
|
||||
sa.Column('account', sa.String(length=120), nullable=False),
|
||||
sa.Column('password_digest', sa.String(length=2000), nullable=False),
|
||||
sa.Column('id_card_no', sa.String(length=120), nullable=True),
|
||||
sa.Column('mobile_no', sa.String(length=120), nullable=True),
|
||||
sa.Column('bank_card_no', sa.String(length=120), nullable=True),
|
||||
sa.Column('state', sa.Integer(), nullable=True),
|
||||
sa.Column('member_type', sa.Integer(), nullable=True),
|
||||
sa.Column('last_login_time', sa.DateTime(), nullable=True),
|
||||
sa.Column('created_at', sa.DateTime(), nullable=True),
|
||||
sa.Column('updated_at', sa.DateTime(), nullable=True),
|
||||
sa.PrimaryKeyConstraint('id')
|
||||
)
|
||||
with op.batch_alter_table('passenger', schema=None) as batch_op:
|
||||
batch_op.create_index(batch_op.f('ix_passenger_account'), ['account'], unique=True)
|
||||
|
||||
op.create_table('station',
|
||||
sa.Column('id', sa.Integer(), nullable=False),
|
||||
sa.Column('name', sa.String(length=120), nullable=False),
|
||||
sa.Column('pinyin', sa.String(length=120), nullable=True),
|
||||
sa.Column('province', sa.String(length=120), nullable=True),
|
||||
sa.Column('city', sa.String(length=120), nullable=True),
|
||||
sa.Column('district', sa.String(length=120), nullable=True),
|
||||
sa.Column('created_at', sa.DateTime(), nullable=True),
|
||||
sa.Column('updated_at', sa.DateTime(), nullable=True),
|
||||
sa.PrimaryKeyConstraint('id')
|
||||
)
|
||||
with op.batch_alter_table('station', schema=None) as batch_op:
|
||||
batch_op.create_index(batch_op.f('ix_station_name'), ['name'], unique=True)
|
||||
|
||||
op.create_table('train',
|
||||
sa.Column('id', sa.Integer(), nullable=False),
|
||||
sa.Column('train_no', sa.String(length=120), nullable=False),
|
||||
sa.Column('departure_station', sa.String(length=120), nullable=True),
|
||||
sa.Column('arrival_station', sa.String(length=120), nullable=True),
|
||||
sa.Column('departure_time', sa.DateTime(), nullable=True),
|
||||
sa.Column('expiration_time', sa.DateTime(), nullable=True),
|
||||
sa.Column('effective_time', sa.DateTime(), nullable=True),
|
||||
sa.Column('arrival_time', sa.DateTime(), nullable=True),
|
||||
sa.Column('created_at', sa.DateTime(), nullable=True),
|
||||
sa.Column('updated_at', sa.DateTime(), nullable=True),
|
||||
sa.PrimaryKeyConstraint('id')
|
||||
)
|
||||
with op.batch_alter_table('train', schema=None) as batch_op:
|
||||
batch_op.create_index(batch_op.f('ix_train_train_no'), ['train_no'], unique=True)
|
||||
|
||||
op.create_table('order',
|
||||
sa.Column('id', sa.Integer(), nullable=False),
|
||||
sa.Column('order_no', sa.String(length=120), nullable=False),
|
||||
sa.Column('price', sa.Numeric(precision=8, scale=2), nullable=True),
|
||||
sa.Column('payment_time', sa.DateTime(), nullable=True),
|
||||
sa.Column('state', sa.Integer(), nullable=True),
|
||||
sa.Column('passenger_id', sa.Integer(), nullable=False),
|
||||
sa.Column('created_at', sa.DateTime(), nullable=True),
|
||||
sa.Column('updated_at', sa.DateTime(), nullable=True),
|
||||
sa.ForeignKeyConstraint(['passenger_id'], ['passenger.id'], ),
|
||||
sa.PrimaryKeyConstraint('id'),
|
||||
sa.UniqueConstraint('order_no')
|
||||
)
|
||||
with op.batch_alter_table('order', schema=None) as batch_op:
|
||||
batch_op.create_index(batch_op.f('ix_order_passenger_id'), ['passenger_id'], unique=False)
|
||||
|
||||
op.create_table('train_station',
|
||||
sa.Column('id', sa.Integer(), nullable=False),
|
||||
sa.Column('train_no', sa.String(length=120), nullable=False),
|
||||
sa.Column('station_name', sa.String(length=120), nullable=False),
|
||||
sa.Column('price', sa.Numeric(precision=8, scale=2), nullable=True),
|
||||
sa.Column('arrival_time', sa.DateTime(), nullable=True),
|
||||
sa.Column('departure_time', sa.DateTime(), nullable=True),
|
||||
sa.Column('index', sa.Integer(), nullable=True),
|
||||
sa.Column('created_at', sa.DateTime(), nullable=True),
|
||||
sa.Column('updated_at', sa.DateTime(), nullable=True),
|
||||
sa.ForeignKeyConstraint(['station_name'], ['station.name'], ),
|
||||
sa.ForeignKeyConstraint(['train_no'], ['train.train_no'], ),
|
||||
sa.PrimaryKeyConstraint('id', 'train_no', 'station_name')
|
||||
)
|
||||
with op.batch_alter_table('train_station', schema=None) as batch_op:
|
||||
batch_op.create_index(batch_op.f('ix_train_station_train_no'), ['train_no'], unique=False)
|
||||
|
||||
op.create_table('ticket',
|
||||
sa.Column('id', sa.Integer(), nullable=False),
|
||||
sa.Column('seat_no', sa.String(length=120), nullable=True),
|
||||
sa.Column('seat_class', sa.String(length=120), nullable=True),
|
||||
sa.Column('price', sa.Numeric(precision=8, scale=2), nullable=True),
|
||||
sa.Column('state', sa.Integer(), nullable=True),
|
||||
sa.Column('train_no', sa.String(length=120), nullable=False),
|
||||
sa.Column('passenger_id', sa.Integer(), nullable=False),
|
||||
sa.Column('order_id', sa.Integer(), nullable=False),
|
||||
sa.Column('from_station', sa.String(length=120), nullable=True),
|
||||
sa.Column('to_station', sa.String(length=120), nullable=True),
|
||||
sa.Column('date', sa.String(length=120), nullable=True),
|
||||
sa.Column('departure_time', sa.DateTime(), nullable=True),
|
||||
sa.Column('arrival_time', sa.DateTime(), nullable=True),
|
||||
sa.Column('created_at', sa.DateTime(), nullable=True),
|
||||
sa.Column('updated_at', sa.DateTime(), nullable=True),
|
||||
sa.ForeignKeyConstraint(['order_id'], ['order.id'], ),
|
||||
sa.ForeignKeyConstraint(['passenger_id'], ['passenger.id'], ),
|
||||
sa.ForeignKeyConstraint(['train_no'], ['train.train_no'], ),
|
||||
sa.PrimaryKeyConstraint('id')
|
||||
)
|
||||
with op.batch_alter_table('ticket', schema=None) as batch_op:
|
||||
batch_op.create_index(batch_op.f('ix_ticket_order_id'), ['order_id'], unique=False)
|
||||
batch_op.create_index(batch_op.f('ix_ticket_passenger_id'), ['passenger_id'], unique=False)
|
||||
batch_op.create_index(batch_op.f('ix_ticket_train_no'), ['train_no'], unique=False)
|
||||
|
||||
# ### end Alembic commands ###
|
||||
|
||||
|
||||
def downgrade():
|
||||
# ### commands auto generated by Alembic - please adjust! ###
|
||||
with op.batch_alter_table('ticket', schema=None) as batch_op:
|
||||
batch_op.drop_index(batch_op.f('ix_ticket_train_no'))
|
||||
batch_op.drop_index(batch_op.f('ix_ticket_passenger_id'))
|
||||
batch_op.drop_index(batch_op.f('ix_ticket_order_id'))
|
||||
|
||||
op.drop_table('ticket')
|
||||
with op.batch_alter_table('train_station', schema=None) as batch_op:
|
||||
batch_op.drop_index(batch_op.f('ix_train_station_train_no'))
|
||||
|
||||
op.drop_table('train_station')
|
||||
with op.batch_alter_table('order', schema=None) as batch_op:
|
||||
batch_op.drop_index(batch_op.f('ix_order_passenger_id'))
|
||||
|
||||
op.drop_table('order')
|
||||
with op.batch_alter_table('train', schema=None) as batch_op:
|
||||
batch_op.drop_index(batch_op.f('ix_train_train_no'))
|
||||
|
||||
op.drop_table('train')
|
||||
with op.batch_alter_table('station', schema=None) as batch_op:
|
||||
batch_op.drop_index(batch_op.f('ix_station_name'))
|
||||
|
||||
op.drop_table('station')
|
||||
with op.batch_alter_table('passenger', schema=None) as batch_op:
|
||||
batch_op.drop_index(batch_op.f('ix_passenger_account'))
|
||||
|
||||
op.drop_table('passenger')
|
||||
op.drop_table('log')
|
||||
# ### end Alembic commands ###
|
||||
@ -0,0 +1,32 @@
|
||||
"""remove TrainStation id
|
||||
|
||||
Revision ID: 7866a6e8a75b
|
||||
Revises: 1b3bc6809b30
|
||||
Create Date: 2024-08-15 15:29:40.410360
|
||||
|
||||
"""
|
||||
from alembic import op
|
||||
import sqlalchemy as sa
|
||||
|
||||
|
||||
# revision identifiers, used by Alembic.
|
||||
revision = '7866a6e8a75b'
|
||||
down_revision = '1b3bc6809b30'
|
||||
branch_labels = None
|
||||
depends_on = None
|
||||
|
||||
|
||||
def upgrade():
|
||||
# ### commands auto generated by Alembic - please adjust! ###
|
||||
with op.batch_alter_table('train_station', schema=None) as batch_op:
|
||||
batch_op.drop_column('id')
|
||||
|
||||
# ### end Alembic commands ###
|
||||
|
||||
|
||||
def downgrade():
|
||||
# ### commands auto generated by Alembic - please adjust! ###
|
||||
with op.batch_alter_table('train_station', schema=None) as batch_op:
|
||||
batch_op.add_column(sa.Column('id', sa.INTEGER(), autoincrement=False, nullable=False))
|
||||
|
||||
# ### end Alembic commands ###
|
||||
@ -0,0 +1,48 @@
|
||||
"""empty message
|
||||
|
||||
Revision ID: b1465436c340
|
||||
Revises: 7866a6e8a75b
|
||||
Create Date: 2025-02-21 16:47:25.383937
|
||||
|
||||
"""
|
||||
from alembic import op
|
||||
import sqlalchemy as sa
|
||||
from sqlalchemy.dialects import mysql
|
||||
|
||||
# revision identifiers, used by Alembic.
|
||||
revision = 'b1465436c340'
|
||||
down_revision = '7866a6e8a75b'
|
||||
branch_labels = None
|
||||
depends_on = None
|
||||
|
||||
|
||||
def upgrade():
|
||||
# ### commands auto generated by Alembic - please adjust! ###
|
||||
op.drop_table('log')
|
||||
# ### end Alembic commands ###
|
||||
|
||||
|
||||
def downgrade():
|
||||
# ### commands auto generated by Alembic - please adjust! ###
|
||||
op.create_table('log',
|
||||
sa.Column('id', mysql.INTEGER(), autoincrement=True, nullable=False),
|
||||
sa.Column('log_user_agent', mysql.VARCHAR(length=120), nullable=True),
|
||||
sa.Column('log_method', mysql.VARCHAR(length=120), nullable=True),
|
||||
sa.Column('log_quest_path', mysql.VARCHAR(length=120), nullable=True),
|
||||
sa.Column('log_ip', mysql.VARCHAR(length=120), nullable=True),
|
||||
sa.Column('log_params', mysql.VARCHAR(length=120), nullable=True),
|
||||
sa.Column('log_controller', mysql.VARCHAR(length=120), nullable=True),
|
||||
sa.Column('log_controller_action', mysql.VARCHAR(length=120), nullable=True),
|
||||
sa.Column('log_controller_id', mysql.VARCHAR(length=120), nullable=True),
|
||||
sa.Column('account_id', mysql.VARCHAR(length=120), nullable=True),
|
||||
sa.Column('event_name', mysql.VARCHAR(length=120), nullable=True),
|
||||
sa.Column('event_content', mysql.TEXT(), nullable=True),
|
||||
sa.Column('operator', mysql.VARCHAR(length=120), nullable=True),
|
||||
sa.Column('created_at', mysql.DATETIME(), nullable=True),
|
||||
sa.Column('updated_at', mysql.DATETIME(), nullable=True),
|
||||
sa.PrimaryKeyConstraint('id'),
|
||||
mysql_collate='utf8mb4_0900_ai_ci',
|
||||
mysql_default_charset='utf8mb4',
|
||||
mysql_engine='InnoDB'
|
||||
)
|
||||
# ### end Alembic commands ###
|
||||
@ -0,0 +1,3 @@
|
||||
from .passenger import PassengerPresenter
|
||||
from .station import StationPresenter
|
||||
from .mobile_code import MobileCodePresenter
|
||||
@ -0,0 +1,8 @@
|
||||
class MobileCodePresenter:
|
||||
def __init__(self, data):
|
||||
self.data = data
|
||||
|
||||
def as_dict(self):
|
||||
return {
|
||||
"code": self.data
|
||||
}
|
||||
@ -0,0 +1,16 @@
|
||||
from presenter.ticket import TicketPresenter
|
||||
|
||||
|
||||
class OrderPresenter:
|
||||
def __init__(self, data):
|
||||
self.data = data
|
||||
|
||||
def as_dict(self):
|
||||
return {
|
||||
"id": self.data.id,
|
||||
"orderNo": self.data.order_no,
|
||||
"price": self.data.price,
|
||||
"state": self.data.state,
|
||||
"paymentTime": self.data.payment_time,
|
||||
"tickets": [TicketPresenter(ticket).as_dict() for ticket in self.data.tickets]
|
||||
}
|
||||
@ -0,0 +1,17 @@
|
||||
|
||||
class PassengerPresenter:
|
||||
def __init__(self, data, aid_data=None):
|
||||
self.data = data
|
||||
self.aid_data = aid_data
|
||||
|
||||
def as_dict(self):
|
||||
return {
|
||||
"id": self.data.id,
|
||||
"account": self.data.account,
|
||||
"name": self.data.name,
|
||||
"idCardNo": self.data.id_card_no,
|
||||
"mobileNo": self.data.mobile_no,
|
||||
"bankCardNo": self.data.bank_card_no,
|
||||
"state": self.data.state,
|
||||
"memberType": self.data.member_type
|
||||
} | self.aid_data
|
||||
@ -0,0 +1,10 @@
|
||||
class StationPresenter:
|
||||
def __init__(self, data):
|
||||
self.data = data
|
||||
|
||||
def as_dict(self):
|
||||
return {
|
||||
"id": self.data.id,
|
||||
"name": self.data.name,
|
||||
"pinyin": self.data.pinyin,
|
||||
}
|
||||
@ -0,0 +1,19 @@
|
||||
class TicketPresenter:
|
||||
def __init__(self, data):
|
||||
self.data = data
|
||||
|
||||
def as_dict(self):
|
||||
return {
|
||||
"id": self.data.id,
|
||||
"seatNo": self.data.seat_no,
|
||||
"seatClass": self.data.seat_class,
|
||||
"price": self.data.price,
|
||||
"state": self.data.state,
|
||||
"trainNo": self.data.train_no,
|
||||
"from": self.data.from_station,
|
||||
"orderNo": self.data.order.order_no,
|
||||
"to": self.data.to_station,
|
||||
"date": self.data.date,
|
||||
"fromTime": self.data.departure_time,
|
||||
"toTime": self.data.arrival_time,
|
||||
}
|
||||
@ -0,0 +1,17 @@
|
||||
from presenter.train_station import TrainStationPresenter
|
||||
|
||||
|
||||
class TrainPresenter:
|
||||
def __init__(self, data):
|
||||
self.data = data
|
||||
|
||||
def as_dict(self):
|
||||
return {
|
||||
"id": self.data.id,
|
||||
"trainNo": self.data.train_no,
|
||||
"arrTime": self.data.arrival_time,
|
||||
"depTime": self.data.departure_time,
|
||||
"arr": self.data.arrival_station,
|
||||
"dep": self.data.departure_station,
|
||||
"stations": [TrainStationPresenter(station).as_dict() for station in self.data.train_stations]
|
||||
}
|
||||
@ -0,0 +1,13 @@
|
||||
class TrainStationPresenter:
|
||||
def __init__(self, data):
|
||||
self.data = data
|
||||
|
||||
def as_dict(self):
|
||||
return {
|
||||
"index": self.data.index,
|
||||
"trainNo": self.data.train_no,
|
||||
"name": self.data.station_name,
|
||||
"arrTime": self.data.arrival_time,
|
||||
"depTime": self.data.departure_time,
|
||||
"price": self.data.price,
|
||||
}
|
||||
@ -0,0 +1,2 @@
|
||||
from .response import create_response, StateCode
|
||||
from .server import checkMobile, checkIdCard, checkBankCard
|
||||
Loading…
Reference in new issue