调整返回数据结构

This commit is contained in:
KingChan 2024-08-14 17:03:26 +08:00
parent 7e021a8700
commit 3d0a8c1c0a
15 changed files with 129 additions and 155 deletions

View File

@ -4,25 +4,22 @@
<option name="autoReloadType" value="SELECTIVE" />
</component>
<component name="ChangeListManager">
<list default="true" id="fc554a10-7837-4504-ac7d-04f725b153b1" name="Changes" comment="调整Database新增登录接口注册接口查询车站接口创建车站接口">
<change afterPath="$PROJECT_DIR$/presenter/error.py" afterDir="false" />
<change afterPath="$PROJECT_DIR$/presenter/mobile_code.py" afterDir="false" />
<change afterPath="$PROJECT_DIR$/utils/bank_server.py" afterDir="false" />
<change afterPath="$PROJECT_DIR$/utils/id_card_server.py" afterDir="false" />
<change afterPath="$PROJECT_DIR$/utils/state_code.py" afterDir="false" />
<list default="true" id="fc554a10-7837-4504-ac7d-04f725b153b1" name="Changes" comment="新增状态管理,调整返回数据结构">
<change afterPath="$PROJECT_DIR$/utils/response.py" afterDir="false" />
<change beforePath="$PROJECT_DIR$/.idea/workspace.xml" beforeDir="false" afterPath="$PROJECT_DIR$/.idea/workspace.xml" afterDir="false" />
<change beforePath="$PROJECT_DIR$/app/__init__.py" beforeDir="false" afterPath="$PROJECT_DIR$/app/__init__.py" afterDir="false" />
<change beforePath="$PROJECT_DIR$/app/login_manager.py" beforeDir="false" afterPath="$PROJECT_DIR$/app/login_manager.py" afterDir="false" />
<change beforePath="$PROJECT_DIR$/app/mobile_manager.py" beforeDir="false" afterPath="$PROJECT_DIR$/app/mobile_manager.py" afterDir="false" />
<change beforePath="$PROJECT_DIR$/app/models/passenger_lib.py" beforeDir="false" afterPath="$PROJECT_DIR$/app/models/passenger_lib.py" afterDir="false" />
<change beforePath="$PROJECT_DIR$/app/passenger_manager.py" beforeDir="false" afterPath="$PROJECT_DIR$/app/passenger_manager.py" afterDir="false" />
<change beforePath="$PROJECT_DIR$/app/query_manager.py" beforeDir="false" afterPath="$PROJECT_DIR$/app/query_manager.py" afterDir="false" />
<change beforePath="$PROJECT_DIR$/app/ticket_manager.py" beforeDir="false" afterPath="$PROJECT_DIR$/app/ticket_manager.py" afterDir="false" />
<change beforePath="$PROJECT_DIR$/presenter/__init__.py" beforeDir="false" afterPath="$PROJECT_DIR$/presenter/__init__.py" afterDir="false" />
<change beforePath="$PROJECT_DIR$/presenter/presenter.py" beforeDir="false" afterPath="$PROJECT_DIR$/presenter/presenter.py" afterDir="false" />
<change beforePath="$PROJECT_DIR$/requirements.txt" beforeDir="false" afterPath="$PROJECT_DIR$/requirements.txt" afterDir="false" />
<change beforePath="$PROJECT_DIR$/presenter/error.py" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/presenter/mobile_code.py" beforeDir="false" afterPath="$PROJECT_DIR$/presenter/mobile_code.py" afterDir="false" />
<change beforePath="$PROJECT_DIR$/presenter/passenger.py" beforeDir="false" afterPath="$PROJECT_DIR$/presenter/passenger.py" afterDir="false" />
<change beforePath="$PROJECT_DIR$/presenter/presenter.py" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/presenter/station.py" beforeDir="false" afterPath="$PROJECT_DIR$/presenter/station.py" afterDir="false" />
<change beforePath="$PROJECT_DIR$/utils/__init__.py" beforeDir="false" afterPath="$PROJECT_DIR$/utils/__init__.py" afterDir="false" />
<change beforePath="$PROJECT_DIR$/utils/mobile_server.py" beforeDir="false" afterPath="$PROJECT_DIR$/utils/mobile_server.py" afterDir="false" />
<change beforePath="$PROJECT_DIR$/utils/redis_client.py" beforeDir="false" afterPath="$PROJECT_DIR$/utils/redis_client.py" afterDir="false" />
<change beforePath="$PROJECT_DIR$/utils/state_code.py" beforeDir="false" />
</list>
<option name="SHOW_DIALOG" value="false" />
<option name="HIGHLIGHT_CONFLICTS" value="true" />
@ -83,9 +80,9 @@
<recent name="D:\Mini12306_python" />
</key>
<key name="MoveFile.RECENT_KEYS">
<recent name="D:\Mini12306_python\utils" />
<recent name="D:\Mini12306_python\app" />
<recent name="D:\Mini12306_python" />
<recent name="D:\Mini12306_python\utils" />
<recent name="D:\Mini12306_python\jwt" />
<recent name="D:\Mini12306_python\models" />
</key>
@ -127,7 +124,7 @@
<workItem from="1723423582377" duration="17938000" />
<workItem from="1723468349162" duration="7753000" />
<workItem from="1723509074827" duration="26219000" />
<workItem from="1723596634243" duration="15471000" />
<workItem from="1723596634243" duration="19031000" />
</task>
<task id="LOCAL-00001" summary="first init">
<option name="closed" value="true" />
@ -177,7 +174,15 @@
<option name="project" value="LOCAL" />
<updated>1723543058473</updated>
</task>
<option name="localTasksCounter" value="7" />
<task id="LOCAL-00007" summary="新增状态管理,调整返回数据结构">
<option name="closed" value="true" />
<created>1723622681330</created>
<option name="number" value="00007" />
<option name="presentableId" value="LOCAL-00007" />
<option name="project" value="LOCAL" />
<updated>1723622681330</updated>
</task>
<option name="localTasksCounter" value="8" />
<servers />
</component>
<component name="TypeScriptGeneratedFilesManager">
@ -190,9 +195,20 @@
<MESSAGE value="databases" />
<MESSAGE value="databases init" />
<MESSAGE value="调整Database新增登录接口注册接口查询车站接口创建车站接口" />
<option name="LAST_COMMIT_MESSAGE" value="调整Database新增登录接口注册接口查询车站接口创建车站接口" />
<MESSAGE value="新增状态管理,调整返回数据结构" />
<option name="LAST_COMMIT_MESSAGE" value="新增状态管理,调整返回数据结构" />
</component>
<component name="XDebuggerManager">
<breakpoint-manager>
<breakpoints>
<line-breakpoint enabled="true" suspend="THREAD" type="python-line">
<url>file://$PROJECT_DIR$/presenter/__init__.py</url>
<option name="timeStamp" value="4" />
</line-breakpoint>
</breakpoints>
</breakpoint-manager>
</component>
<component name="com.intellij.coverage.CoverageDataManagerImpl">
<SUITE FILE_PATH="coverage/Mini12306_python$Flask.coverage" NAME="Flask Coverage Results" MODIFIED="1723615977550" SOURCE_PROVIDER="com.intellij.coverage.DefaultCoverageFileProvider" RUNNER="coverage.py" COVERAGE_BY_TEST_ENABLED="false" COVERAGE_TRACING_ENABLED="false" WORKING_DIRECTORY="$PROJECT_DIR$" />
<SUITE FILE_PATH="coverage/Mini12306_python$Flask.coverage" NAME="Flask Coverage Results" MODIFIED="1723625998637" SOURCE_PROVIDER="com.intellij.coverage.DefaultCoverageFileProvider" RUNNER="coverage.py" COVERAGE_BY_TEST_ENABLED="false" COVERAGE_TRACING_ENABLED="false" WORKING_DIRECTORY="$PROJECT_DIR$" />
</component>
</project>

View File

@ -2,8 +2,8 @@
from flask import Blueprint, request, jsonify
from flask_jwt_extended import create_access_token
from app.models import Passenger
from presenter import PassengerPresenter, ErrorPresenter
from utils import StateCode
from presenter import PassengerPresenter
from utils import StateCode, create_response
login_bp = Blueprint('login', __name__)
@ -14,11 +14,11 @@ def login():
account = data.get('account')
password = data.get('password')
if not account or not password:
return jsonify(ErrorPresenter().present(StateCode.PARAMS_ERROR)), 400
return jsonify(create_response(StateCode.PARAMS_ERROR)), 400
user = Passenger.query.filter_by(account=account).first()
if user and user.check_password(password):
access_token = create_access_token(identity=user.id)
user_presenter = PassengerPresenter(user, {"token": access_token})
return jsonify(user_presenter.present(StateCode.SUCCESS)), 200
return jsonify({'message': '登录失败,账号或密码错误'}), 401
user_presenter = PassengerPresenter(user, {"token": access_token}).as_dict()
return jsonify(create_response(StateCode.SUCCESS,single_data=user_presenter)), 200
return jsonify(create_response(StateCode.PASSWORD_INCORRECT)), 401

View File

@ -2,8 +2,8 @@ import pdb
from flask import Blueprint, jsonify, request
from presenter import ErrorPresenter, MobileCodePresenter
from utils import getVerificationCode, checkMobile, StateCode
from presenter import MobileCodePresenter
from utils import getVerificationCode, checkMobile,create_response, StateCode
mobile_bp = Blueprint('mobiles', __name__)
@ -13,7 +13,8 @@ mobile_bp = Blueprint('mobiles', __name__)
def getOtp():
mobile_no = request.form.get('mobileNo')
if not checkMobile(mobile_no):
return jsonify(ErrorPresenter().present(StateCode.MOBILE_ERROR)), 400
return jsonify(create_response(StateCode.MOBILE_ERROR)), 400
sent_code = getVerificationCode(mobile_no)
mobile_present = MobileCodePresenter(sent_code)
return jsonify(mobile_present.present(StateCode.SUCCESS)), 200
mobile_present = MobileCodePresenter(sent_code).as_dict()
return jsonify(create_response(StateCode.SUCCESS, single_data=mobile_present)), 200

View File

@ -2,9 +2,8 @@ import pdb
from flask import Blueprint, request, jsonify
from flask_jwt_extended import create_access_token, jwt_required, get_jwt_identity
from app.models.passenger_lib import Passenger, isAvailable, createPassenger
from presenter import PassengerPresenter, ErrorPresenter
from utils import verifyOpt, checkBankCard, checkIdCard
from utils.state_code import StateCode
from presenter import PassengerPresenter
from utils import StateCode, create_response, verifyOpt, checkIdCard, checkBankCard
register_bp = Blueprint('register', __name__)
@ -19,25 +18,25 @@ def register():
id_card_no = data.get('idCardNo')
bank_card_no = data.get('BankcardNo')
if not account or not password:
return jsonify(ErrorPresenter().present(StateCode.PARAMS_ERROR)), 400
return jsonify(create_response(StateCode.PARAMS_ERROR)), 400
if not verifyOpt(mobile_no, mobile_code):
return jsonify(ErrorPresenter().present(StateCode.MOBILE_CODE_ERROR)), 400
return jsonify(create_response(StateCode.MOBILE_CODE_ERROR)), 400
if not checkIdCard(id_card_no):
return jsonify(ErrorPresenter().present(StateCode.ID_CARD_ERROR)), 400
return jsonify(create_response(StateCode.ID_CARD_ERROR)), 400
if isAvailable(account):
return jsonify(ErrorPresenter().present(StateCode.USER_ALREADY_EXISTS)), 400
return jsonify(create_response(StateCode.USER_ALREADY_EXISTS)), 400
if not checkBankCard(bank_card_no):
return jsonify(ErrorPresenter().present(StateCode.BANK_CARD_ERROR)), 400
return jsonify(create_response(StateCode.BANK_CARD_ERROR)), 400
new_passenger_data = Passenger(data=data)
new_passenger = createPassenger(new_passenger_data)
access_token = create_access_token(identity=new_passenger.id)
user_presenter = PassengerPresenter(new_passenger, {"token": access_token})
return jsonify(user_presenter.present(StateCode.SUCCESS)), 200
user_presenter = PassengerPresenter(new_passenger, {"token": access_token}).as_dict()
return jsonify(create_response(StateCode.SUCCESS, single_data=user_presenter)), 200
@register_bp.route('/auth', methods=['GET'])
@ -45,5 +44,5 @@ def register():
def auth():
current_user = get_jwt_identity()
user = Passenger.query.get(current_user)
user_presenter = PassengerPresenter(user)
return jsonify(user_presenter.present(StateCode.SUCCESS)), 200
user_presenter = PassengerPresenter(user).as_dict()
return jsonify(create_response(code=StateCode.SUCCESS, single_data=user_presenter)), 200

View File

@ -5,7 +5,7 @@ from flask import Blueprint, jsonify, request
from app import db
from app.models import Station
from presenter import StationPresenter
from utils import StateCode
from utils import create_response, StateCode
trains_bp = Blueprint('stations', __name__)
@ -18,10 +18,8 @@ def query_train():
@trains_bp.route('/stations', methods=['GET'])
def query_station():
stations = Station.query.all()
stations_presenters = [StationPresenter(station) for station in stations]
# 渲染所有车站为列表结构
stations_data = [station.present() for station in stations_presenters]
return jsonify(stations_data)
stations_presenters = [StationPresenter(station).as_dict() for station in stations]
return jsonify(create_response(StateCode.SUCCESS, multiple_data={"stations": stations_presenters})), 200
@trains_bp.route('/stations', methods=['POST'])
@ -30,5 +28,5 @@ def create_station():
new_station = Station(data=data)
db.session.add(new_station)
db.session.commit()
station_presenter = StationPresenter(new_station)
return jsonify(station_presenter.present(StateCode.SUCCESS)), 200
station_presenter = StationPresenter(new_station).as_dict()
return jsonify(create_response(StateCode.SUCCESS, single_data=station_presenter)), 200

View File

@ -2,30 +2,11 @@ from flask import Blueprint, request, jsonify
from app.models.ticket_lib import Ticket
from app import db
from app.models.order_lib import Order
from utils.jwt import decode_jwt_token
order_bp = Blueprint('book_ticket', __name__)
@order_bp.route('/book_ticket', methods=['POST'])
def book_ticket():
token = request.headers.get('Authorization')
if not token:
return jsonify({'message': 'Token is missing'}), 401
user_id = decode_jwt_token(token)
if not user_id:
return jsonify({'message': 'Invalid or expired token'}), 401
data = request.json
train_id = data.get('train_id')
if not train_id:
return jsonify({'message': 'Train ID is required'}), 400
order = Order(passenger_id=user_id)
ticket = Ticket(train_id=train_id, order=order)
db.session.add(order)
db.session.add(ticket)
db.session.commit()
return jsonify({'message': 'Ticket booked successfully'}), 201

View File

@ -1,5 +1,3 @@
from .presenter import Presenter
from .passenger import PassengerPresenter
from .station import StationPresenter
from .error import ErrorPresenter
from .mobile_code import MobileCodePresenter

View File

@ -1,11 +0,0 @@
from datetime import datetime
from presenter.presenter import Presenter
class ErrorPresenter(Presenter):
def __init__(self, aid_data=None):
super().__init__(aid_data)
def as_dict(self):
return None

View File

@ -1,11 +1,6 @@
from datetime import datetime
from presenter.presenter import Presenter
class MobileCodePresenter(Presenter):
def __init__(self, data, aid_data=None):
super().__init__(data, aid_data)
class MobileCodePresenter():
def __init__(self, data):
self.data = data
def as_dict(self):
return {

View File

@ -1,11 +1,8 @@
from datetime import datetime
from presenter.presenter import Presenter
class PassengerPresenter(Presenter):
def __init__(self, user, aid_data=None):
super().__init__(user, aid_data)
class PassengerPresenter:
def __init__(self, data, aid_data=None):
self.data = data
self.aid_data = aid_data
def as_dict(self):
return {
@ -16,5 +13,5 @@ class PassengerPresenter(Presenter):
"bankCardNo": self.data.bank_card_no,
"state": self.data.state,
"memberType": self.data.member_type
}
} | self.aid_data

View File

@ -1,22 +0,0 @@
from sqlalchemy.orm import state
from utils import StateCode, STATE_MESSAGES
class Presenter:
def __init__(self, data, aid_data=None):
if aid_data is None:
aid_data = {}
self.data = data
self.aid_data = aid_data
def as_dict(self):
raise NotImplementedError("Subclasses must implement the as_dict method")
def present(self, code: StateCode):
"""返回统一格式的响应字典"""
return {
"code": code.value,
"message": STATE_MESSAGES.get(code, "Unknown error"),
"data": self.as_dict()
} | self.aid_data

View File

@ -1,11 +1,6 @@
from datetime import datetime
from presenter.presenter import Presenter
class StationPresenter(Presenter):
def __init__(self, user, aid_data=None):
super().__init__(user, aid_data)
class StationPresenter:
def __init__(self, data):
self.data = data
def as_dict(self):
return {

View File

@ -1,4 +1,4 @@
from .mobile_server import checkMobile, getVerificationCode, verifyOpt
from .id_card_server import checkIdCard
from .bank_server import checkBankCard
from .state_code import StateCode, STATE_MESSAGES
from .response import create_response, StateCode

56
utils/response.py Normal file
View File

@ -0,0 +1,56 @@
from enum import Enum
from typing import Any, Dict, List, Union
class StateCode(Enum):
SUCCESS = 0
NOT_AUTHORIZED = 1002
PARAMS_ERROR = 1003
USER_NOT_FOUND = 2001
USER_ALREADY_EXISTS = 2002
PASSWORD_INCORRECT = 2003
MOBILE_CODE_ERROR = 2004
ID_CARD_ERROR = 2005
BANK_CARD_ERROR = 2006
MOBILE_ERROR = 2007
STATE_MESSAGES = {
StateCode.SUCCESS: "OK",
StateCode.PARAMS_ERROR: "缺少参数",
StateCode.NOT_AUTHORIZED: "未登录",
StateCode.USER_NOT_FOUND: "用户不存在",
StateCode.USER_ALREADY_EXISTS: "用户已存在",
StateCode.PASSWORD_INCORRECT: "密码错误",
StateCode.MOBILE_CODE_ERROR: "验证码错误",
StateCode.ID_CARD_ERROR: "身份证号验证失败",
StateCode.MOBILE_ERROR: "手机号格式有误",
StateCode.BANK_CARD_ERROR: "银行卡验证错误"
}
def create_response(
code: StateCode,
message: str = None,
single_data: Dict[str, Any] = None,
multiple_data: Dict[str, List[Dict[str, Any]]] = None
) -> Dict[str, Any]:
"""
创建统一的返回格式
:param code: ErrorCode 错误码
:param message: 错误信息可选如果不传递则使用默认的错误信息
:param single_data: 包含单个 Presenter 转换后的数据字典
:param multiple_data: 包含多个 Presenter 转换后的数据字典键为描述值为对象列表
:return: 返回统一格式的字典
"""
return {
"code": code.value,
"msg": message or STATE_MESSAGES.get(code, "Unknown error"),
"data": {
**(single_data or {}),
**(multiple_data or {})
}
}

View File

@ -1,29 +0,0 @@
from enum import Enum
class StateCode(Enum):
SUCCESS = 0
NOT_AUTHORIZED = 1002
PARAMS_ERROR = 1003
USER_NOT_FOUND = 2001
USER_ALREADY_EXISTS = 2002
PASSWORD_INCORRECT = 2003
MOBILE_CODE_ERROR = 2004
ID_CARD_ERROR = 2005
BANK_CARD_ERROR = 2006
MOBILE_ERROR = 2007
STATE_MESSAGES = {
StateCode.SUCCESS: "OK",
StateCode.PARAMS_ERROR: "缺少参数",
StateCode.NOT_AUTHORIZED: "未登录",
StateCode.USER_NOT_FOUND: "用户不存在",
StateCode.USER_ALREADY_EXISTS: "用户已存在",
StateCode.PASSWORD_INCORRECT: "密码错误",
StateCode.MOBILE_CODE_ERROR: "验证码错误",
StateCode.ID_CARD_ERROR: "身份证号验证失败",
StateCode.MOBILE_ERROR: "手机号格式有误",
StateCode.BANK_CARD_ERROR: "银行卡验证错误"
}